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_sock *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 [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
00049 };
00050
00051 static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
00052 [CTRL_ATTR_OP_ID] = { .type = NLA_U32 },
00053 [CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 },
00054 };
00055
00056 static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
00057 [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
00058 [CTRL_ATTR_MCAST_GRP_ID] = { .type = NLA_U32 },
00059 };
00060
00061 static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
00062 struct genl_info *info, void *arg)
00063 {
00064 struct genl_family *family;
00065 struct nl_parser_param *pp = arg;
00066 int err;
00067
00068 family = genl_family_alloc();
00069 if (family == NULL) {
00070 err = -NLE_NOMEM;
00071 goto errout;
00072 }
00073
00074 if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
00075 err = -NLE_MISSING_ATTR;
00076 goto errout;
00077 }
00078
00079 if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
00080 err = -NLE_MISSING_ATTR;
00081 goto errout;
00082 }
00083
00084 family->ce_msgtype = info->nlh->nlmsg_type;
00085 genl_family_set_id(family,
00086 nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
00087 genl_family_set_name(family,
00088 nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
00089
00090 if (info->attrs[CTRL_ATTR_VERSION]) {
00091 uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
00092 genl_family_set_version(family, version);
00093 }
00094
00095 if (info->attrs[CTRL_ATTR_HDRSIZE]) {
00096 uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
00097 genl_family_set_hdrsize(family, hdrsize);
00098 }
00099
00100 if (info->attrs[CTRL_ATTR_MAXATTR]) {
00101 uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
00102 genl_family_set_maxattr(family, maxattr);
00103 }
00104
00105 if (info->attrs[CTRL_ATTR_OPS]) {
00106 struct nlattr *nla, *nla_ops;
00107 int remaining;
00108
00109 nla_ops = info->attrs[CTRL_ATTR_OPS];
00110 nla_for_each_nested(nla, nla_ops, remaining) {
00111 struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
00112 int flags = 0, id;
00113
00114 err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
00115 family_op_policy);
00116 if (err < 0)
00117 goto errout;
00118
00119 if (tb[CTRL_ATTR_OP_ID] == NULL) {
00120 err = -NLE_MISSING_ATTR;
00121 goto errout;
00122 }
00123
00124 id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
00125
00126 if (tb[CTRL_ATTR_OP_FLAGS])
00127 flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
00128
00129 err = genl_family_add_op(family, id, flags);
00130 if (err < 0)
00131 goto errout;
00132
00133 }
00134 }
00135
00136 if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
00137 struct nlattr *nla, *nla_grps;
00138 int remaining;
00139
00140 nla_grps = info->attrs[CTRL_ATTR_MCAST_GROUPS];
00141 nla_for_each_nested(nla, nla_grps, remaining) {
00142 struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
00143 int id;
00144 const char * name;
00145
00146 err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
00147 family_grp_policy);
00148 if (err < 0)
00149 goto errout;
00150
00151 if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
00152 err = -NLE_MISSING_ATTR;
00153 goto errout;
00154 }
00155 id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
00156
00157 if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
00158 err = -NLE_MISSING_ATTR;
00159 goto errout;
00160 }
00161 name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
00162
00163 err = genl_family_add_grp(family, id, name);
00164 if (err < 0)
00165 goto errout;
00166 }
00167
00168 }
00169
00170 err = pp->pp_cb((struct nl_object *) family, pp);
00171 errout:
00172 genl_family_put(family);
00173 return err;
00174 }
00175
00176
00177
00178
00179
00180
00181 int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
00182 {
00183 return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
00199 {
00200 struct genl_family *fam;
00201
00202 if (cache->c_ops != &genl_ctrl_ops)
00203 BUG();
00204
00205 nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
00206 if (fam->gf_id == id) {
00207 nl_object_get((struct nl_object *) fam);
00208 return fam;
00209 }
00210 }
00211
00212 return NULL;
00213 }
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
00233 const char *name)
00234 {
00235 struct genl_family *fam;
00236
00237 if (cache->c_ops != &genl_ctrl_ops)
00238 BUG();
00239
00240 nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
00241 if (!strcmp(name, fam->gf_name)) {
00242 nl_object_get((struct nl_object *) fam);
00243 return fam;
00244 }
00245 }
00246
00247 return NULL;
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
00263 {
00264 struct nl_cache *cache;
00265 struct genl_family *family;
00266 int err;
00267
00268 if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
00269 return err;
00270
00271 family = genl_ctrl_search_by_name(cache, name);
00272 if (family == NULL) {
00273 err = -NLE_OBJ_NOTFOUND;
00274 goto errout;
00275 }
00276
00277 err = genl_family_get_id(family);
00278 genl_family_put(family);
00279 errout:
00280 nl_cache_free(cache);
00281
00282 return err;
00283 }
00284
00285 static int genl_ctrl_grp_by_name(const struct genl_family *family,
00286 const char *grp_name)
00287 {
00288 struct genl_family_grp *grp;
00289
00290 nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
00291 if (!strcmp(grp->name, grp_name)) {
00292 return grp->id;
00293 }
00294 }
00295
00296 return 0;
00297 }
00298
00299 int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
00300 const char *grp_name)
00301 {
00302 struct nl_cache *cache;
00303 struct genl_family *family;
00304 int err;
00305
00306 if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
00307 return err;
00308
00309 family = genl_ctrl_search_by_name(cache, family_name);
00310 if (family == NULL) {
00311 err = -NLE_OBJ_NOTFOUND;
00312 goto errout;
00313 }
00314
00315 err = genl_ctrl_grp_by_name(family, grp_name);
00316 genl_family_put(family);
00317 errout:
00318 nl_cache_free(cache);
00319
00320 return err;
00321 }
00322
00323
00324
00325 static struct genl_cmd genl_cmds[] = {
00326 {
00327 .c_id = CTRL_CMD_NEWFAMILY,
00328 .c_name = "NEWFAMILY" ,
00329 .c_maxattr = CTRL_ATTR_MAX,
00330 .c_attr_policy = ctrl_policy,
00331 .c_msg_parser = ctrl_msg_parser,
00332 },
00333 {
00334 .c_id = CTRL_CMD_DELFAMILY,
00335 .c_name = "DELFAMILY" ,
00336 },
00337 {
00338 .c_id = CTRL_CMD_GETFAMILY,
00339 .c_name = "GETFAMILY" ,
00340 },
00341 {
00342 .c_id = CTRL_CMD_NEWOPS,
00343 .c_name = "NEWOPS" ,
00344 },
00345 {
00346 .c_id = CTRL_CMD_DELOPS,
00347 .c_name = "DELOPS" ,
00348 },
00349 };
00350
00351 static struct genl_ops genl_ops = {
00352 .o_cmds = genl_cmds,
00353 .o_ncmds = ARRAY_SIZE(genl_cmds),
00354 };
00355
00356
00357 extern struct nl_object_ops genl_family_ops;
00358
00359
00360 static struct nl_cache_ops genl_ctrl_ops = {
00361 .co_name = "genl/family",
00362 .co_hdrsize = GENL_HDRSIZE(0),
00363 .co_msgtypes = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
00364 .co_genl = &genl_ops,
00365 .co_protocol = NETLINK_GENERIC,
00366 .co_request_update = ctrl_request_update,
00367 .co_obj_ops = &genl_family_ops,
00368 };
00369
00370 static void __init ctrl_init(void)
00371 {
00372 genl_register(&genl_ctrl_ops);
00373 }
00374
00375 static void __exit ctrl_exit(void)
00376 {
00377 genl_unregister(&genl_ctrl_ops);
00378 }
00379
00380