libnl 1.1
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-2006 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_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  * @name Cache Management
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  * Look up generic netlink family by id in the provided cache.
00164  * @arg cache           Generic netlink family cache.
00165  * @arg id              Family identifier.
00166  *
00167  * Searches through the cache looking for a registered family
00168  * matching the specified identifier. The caller will own a
00169  * reference on the returned object which needs to be given
00170  * back after usage using genl_family_put().
00171  *
00172  * @return Generic netlink family object or NULL if no match was found.
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  * @name Resolver
00193  * @{
00194  */
00195 
00196 /**
00197  * Look up generic netlink family by family name in the provided cache.
00198  * @arg cache           Generic netlink family cache.
00199  * @arg name            Family name.
00200  *
00201  * Searches through the cache looking for a registered family
00202  * matching the specified name. The caller will own a reference
00203  * on the returned object which needs to be given back after
00204  * usage using genl_family_put().
00205  *
00206  * @return Generic netlink family object or NULL if no match was found.
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  * Resolve generic netlink family name to its identifier
00230  * @arg handle          Netlink Handle
00231  * @arg name            Name of generic netlink family
00232  *
00233  * Resolves the generic netlink family name to its identifer and returns
00234  * it.
00235  *
00236  * @return A positive identifier or a negative error code.
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 /** @cond SKIP */
00296 extern struct nl_object_ops genl_family_ops;
00297 /** @endcond */
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 /** @} */