libnl  3.2.3
/build/buildd/libnl3-3.2.3/lib/genl/ctrl.c
00001 /*
00002  * lib/genl/ctrl.c              Generic Netlink Controller
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup genl_mngt
00014  * @defgroup ctrl Controller
00015  * @brief
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 /** @cond SKIP */
00029 #define CTRL_VERSION            0x0001
00030 
00031 static struct nl_cache_ops genl_ctrl_ops;
00032 /** @endcond */
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  * @name Cache Management
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  * Look up generic netlink family by id in the provided cache.
00188  * @arg cache           Generic netlink family cache.
00189  * @arg id              Family identifier.
00190  *
00191  * Searches through the cache looking for a registered family
00192  * matching the specified identifier. The caller will own a
00193  * reference on the returned object which needs to be given
00194  * back after usage using genl_family_put().
00195  *
00196  * @return Generic netlink family object or NULL if no match was found.
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  * @name Resolver
00217  * @{
00218  */
00219 
00220 /**
00221  * Look up generic netlink family by family name in the provided cache.
00222  * @arg cache           Generic netlink family cache.
00223  * @arg name            Family name.
00224  *
00225  * Searches through the cache looking for a registered family
00226  * matching the specified name. The caller will own a reference
00227  * on the returned object which needs to be given back after
00228  * usage using genl_family_put().
00229  *
00230  * @return Generic netlink family object or NULL if no match was found.
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  * Resolve generic netlink family name to its identifier
00254  * @arg sk              Netlink socket.
00255  * @arg name            Name of generic netlink family
00256  *
00257  * Resolves the generic netlink family name to its identifer and returns
00258  * it.
00259  *
00260  * @return A positive identifier or a negative error code.
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 -NLE_OBJ_NOTFOUND;
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 /** @cond SKIP */
00357 extern struct nl_object_ops genl_family_ops;
00358 /** @endcond */
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 /** @} */