00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <netlink-generic.h>
00021 #include <netlink/netlink.h>
00022 #include <netlink/genl/genl.h>
00023 #include <netlink/genl/family.h>
00024 #include <netlink/genl/mngt.h>
00025 #include <netlink/genl/ctrl.h>
00026 #include <netlink/utils.h>
00027
00028
00029 #define CTRL_VERSION 0x0001
00030
00031 static struct nl_cache_ops genl_ctrl_ops;
00032
00033
00034 static int ctrl_request_update(struct nl_cache *c, struct nl_handle *h)
00035 {
00036 return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
00037 CTRL_VERSION, NLM_F_DUMP);
00038 }
00039
00040 static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
00041 [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
00042 [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING,
00043 .maxlen = GENL_NAMSIZ },
00044 [CTRL_ATTR_VERSION] = { .type = NLA_U32 },
00045 [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 },
00046 [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 },
00047 [CTRL_ATTR_OPS] = { .type = NLA_NESTED },
00048 };
00049
00050 static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
00051 [CTRL_ATTR_OP_ID] = { .type = NLA_U32 },
00052 [CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 },
00053 };
00054
00055 static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
00056 struct genl_info *info, void *arg)
00057 {
00058 struct genl_family *family;
00059 struct nl_parser_param *pp = arg;
00060 int err;
00061
00062 family = genl_family_alloc();
00063 if (family == NULL) {
00064 err = nl_errno(ENOMEM);
00065 goto errout;
00066 }
00067
00068 if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
00069 err = nl_error(EINVAL, "Missing family name TLV");
00070 goto errout;
00071 }
00072
00073 if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
00074 err = nl_error(EINVAL, "Missing family id TLV");
00075 goto errout;
00076 }
00077
00078 family->ce_msgtype = info->nlh->nlmsg_type;
00079 genl_family_set_id(family,
00080 nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
00081 genl_family_set_name(family,
00082 nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
00083
00084 if (info->attrs[CTRL_ATTR_VERSION]) {
00085 uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
00086 genl_family_set_version(family, version);
00087 }
00088
00089 if (info->attrs[CTRL_ATTR_HDRSIZE]) {
00090 uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
00091 genl_family_set_hdrsize(family, hdrsize);
00092 }
00093
00094 if (info->attrs[CTRL_ATTR_MAXATTR]) {
00095 uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
00096 genl_family_set_maxattr(family, maxattr);
00097 }
00098
00099 if (info->attrs[CTRL_ATTR_OPS]) {
00100 struct nlattr *nla, *nla_ops;
00101 int remaining;
00102
00103 nla_ops = info->attrs[CTRL_ATTR_OPS];
00104 nla_for_each_nested(nla, nla_ops, remaining) {
00105 struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
00106 int flags = 0, id;
00107
00108 err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
00109 family_op_policy);
00110 if (err < 0)
00111 goto errout;
00112
00113 if (tb[CTRL_ATTR_OP_ID] == NULL) {
00114 err = nl_errno(EINVAL);
00115 goto errout;
00116 }
00117
00118 id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
00119
00120 if (tb[CTRL_ATTR_OP_FLAGS])
00121 flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
00122
00123 err = genl_family_add_op(family, id, flags);
00124 if (err < 0)
00125 goto errout;
00126
00127 }
00128 }
00129
00130 err = pp->pp_cb((struct nl_object *) family, pp);
00131 if (err < 0)
00132 goto errout;
00133
00134 err = P_ACCEPT;
00135
00136 errout:
00137 genl_family_put(family);
00138 return err;
00139 }
00140
00141
00142
00143
00144
00145
00146 struct nl_cache *genl_ctrl_alloc_cache(struct nl_handle *handle)
00147 {
00148 struct nl_cache * cache;
00149
00150 cache = nl_cache_alloc(&genl_ctrl_ops);
00151 if (cache == NULL)
00152 return NULL;
00153
00154 if (handle && nl_cache_refill(handle, cache) < 0) {
00155 nl_cache_free(cache);
00156 return NULL;
00157 }
00158
00159 return cache;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
00175 {
00176 struct genl_family *fam;
00177
00178 if (cache->c_ops != &genl_ctrl_ops)
00179 BUG();
00180
00181 nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
00182 if (fam->gf_id == id) {
00183 nl_object_get((struct nl_object *) fam);
00184 return fam;
00185 }
00186 }
00187
00188 return NULL;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
00209 const char *name)
00210 {
00211 struct genl_family *fam;
00212
00213 if (cache->c_ops != &genl_ctrl_ops)
00214 BUG();
00215
00216 nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
00217 if (!strcmp(name, fam->gf_name)) {
00218 nl_object_get((struct nl_object *) fam);
00219 return fam;
00220 }
00221 }
00222
00223 return NULL;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 int genl_ctrl_resolve(struct nl_handle *handle, const char *name)
00239 {
00240 struct nl_cache *cache;
00241 struct genl_family *family;
00242 int err;
00243
00244 cache = genl_ctrl_alloc_cache(handle);
00245 if (cache == NULL)
00246 return nl_get_errno();
00247
00248 family = genl_ctrl_search_by_name(cache, name);
00249 if (family == NULL) {
00250 err = nl_error(ENOENT, "Generic Netlink Family not found");
00251 goto errout;
00252 }
00253
00254 err = genl_family_get_id(family);
00255 genl_family_put(family);
00256 errout:
00257 nl_cache_free(cache);
00258
00259 return err;
00260 }
00261
00262
00263
00264 static struct genl_cmd genl_cmds[] = {
00265 {
00266 .c_id = CTRL_CMD_NEWFAMILY,
00267 .c_name = "NEWFAMILY" ,
00268 .c_maxattr = CTRL_ATTR_MAX,
00269 .c_attr_policy = ctrl_policy,
00270 .c_msg_parser = ctrl_msg_parser,
00271 },
00272 {
00273 .c_id = CTRL_CMD_DELFAMILY,
00274 .c_name = "DELFAMILY" ,
00275 },
00276 {
00277 .c_id = CTRL_CMD_GETFAMILY,
00278 .c_name = "GETFAMILY" ,
00279 },
00280 {
00281 .c_id = CTRL_CMD_NEWOPS,
00282 .c_name = "NEWOPS" ,
00283 },
00284 {
00285 .c_id = CTRL_CMD_DELOPS,
00286 .c_name = "DELOPS" ,
00287 },
00288 };
00289
00290 static struct genl_ops genl_ops = {
00291 .o_cmds = genl_cmds,
00292 .o_ncmds = ARRAY_SIZE(genl_cmds),
00293 };
00294
00295
00296 extern struct nl_object_ops genl_family_ops;
00297
00298
00299 static struct nl_cache_ops genl_ctrl_ops = {
00300 .co_name = "genl/family",
00301 .co_hdrsize = GENL_HDRSIZE(0),
00302 .co_msgtypes = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
00303 .co_genl = &genl_ops,
00304 .co_protocol = NETLINK_GENERIC,
00305 .co_request_update = ctrl_request_update,
00306 .co_obj_ops = &genl_family_ops,
00307 };
00308
00309 static void __init ctrl_init(void)
00310 {
00311 genl_register(&genl_ctrl_ops);
00312 }
00313
00314 static void __exit ctrl_exit(void)
00315 {
00316 genl_unregister(&genl_ctrl_ops);
00317 }
00318
00319