libnl 1.1
lib/genl/mngt.c
00001 /*
00002  * lib/genl/mngt.c              Generic Netlink Management
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
00014  * @defgroup genl_mngt Management
00015  *
00016  * @par 1) Registering a generic netlink module
00017  * @code
00018  * #include <netlink/genl/mngt.h>
00019  *
00020  * // First step is to define all the commands being used in
00021  * // particular generic netlink family. The ID and name are
00022  * // mandatory to be filled out. A callback function and
00023  * // most the attribute policy that comes with it must be
00024  * // defined for commands expected to be issued towards
00025  * // userspace.
00026  * static struct genl_cmd foo_cmds[] = {
00027  *      {
00028  *              .c_id           = FOO_CMD_NEW,
00029  *              .c_name         = "NEWFOO" ,
00030  *              .c_maxattr      = FOO_ATTR_MAX,
00031  *              .c_attr_policy  = foo_policy,
00032  *              .c_msg_parser   = foo_msg_parser,
00033  *      },
00034  *      {
00035  *              .c_id           = FOO_CMD_DEL,
00036  *              .c_name         = "DELFOO" ,
00037  *      },
00038  * };
00039  *
00040  * // The list of commands must then be integrated into a
00041  * // struct genl_ops serving as handle for this particular
00042  * // family.
00043  * static struct genl_ops my_genl_ops = {
00044  *      .o_cmds                 = foo_cmds,
00045  *      .o_ncmds                = ARRAY_SIZE(foo_cmds),
00046  * };
00047  *
00048  * // Using the above struct genl_ops an arbitary number of
00049  * // cache handles can be associated to it.
00050  * //
00051  * // The macro GENL_HDRSIZE() must be used to specify the
00052  * // length of the header to automatically take headers on
00053  * // generic layers into account.
00054  * //
00055  * // The macro GENL_FAMILY() is used to represent the generic
00056  * // netlink family id.
00057  * static struct nl_cache_ops genl_foo_ops = {
00058  *      .co_name                = "genl/foo",
00059  *      .co_hdrsize             = GENL_HDRSIZE(sizeof(struct my_hdr)),
00060  *      .co_msgtypes            = GENL_FAMILY(GENL_ID_GENERATE, "foo"),
00061  *      .co_genl                = &my_genl_ops,
00062  *      .co_protocol            = NETLINK_GENERIC,
00063  *      .co_request_update      = foo_request_update,
00064  *      .co_obj_ops             = &genl_foo_ops,
00065  * };
00066  *
00067  * // Finally each cache handle for a generic netlink family
00068  * // must be registered using genl_register().
00069  * static void __init foo_init(void)
00070  * {
00071  *      genl_register(&genl_foo_ops);
00072  * }
00073  *
00074  * // ... respectively unregsted again.
00075  * static void __exit foo_exit(void)
00076  * {
00077  *      genl_unregister(&genl_foo_ops);
00078  * }
00079  * @endcode
00080  * @{
00081  */
00082 
00083 #include <netlink-generic.h>
00084 #include <netlink/netlink.h>
00085 #include <netlink/genl/genl.h>
00086 #include <netlink/genl/mngt.h>
00087 #include <netlink/genl/family.h>
00088 #include <netlink/genl/ctrl.h>
00089 #include <netlink/utils.h>
00090 
00091 static NL_LIST_HEAD(genl_ops_list);
00092 
00093 static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00094                            struct nlmsghdr *nlh, struct nl_parser_param *pp)
00095 {
00096         int i, err;
00097         struct genlmsghdr *ghdr;
00098         struct genl_cmd *cmd;
00099 
00100         ghdr = nlmsg_data(nlh);
00101 
00102         if (ops->co_genl == NULL)
00103                 BUG();
00104 
00105         for (i = 0; i < ops->co_genl->o_ncmds; i++) {
00106                 cmd = &ops->co_genl->o_cmds[i];
00107                 if (cmd->c_id == ghdr->cmd)
00108                         goto found;
00109         }
00110 
00111         err = nl_errno(ENOENT);
00112         goto errout;
00113 
00114 found:
00115         if (cmd->c_msg_parser == NULL)
00116                 err = nl_error(EOPNOTSUPP, "No message parser found.");
00117         else {
00118                 struct nlattr *tb[cmd->c_maxattr + 1];
00119                 struct genl_info info = {
00120                         .who = who,
00121                         .nlh = nlh,
00122                         .genlhdr = ghdr,
00123                         .userhdr = genlmsg_data(ghdr),
00124                         .attrs = tb,
00125                 };
00126 
00127                 err = nlmsg_parse(nlh, ops->co_hdrsize, tb, cmd->c_maxattr,
00128                                   cmd->c_attr_policy);
00129                 if (err < 0)
00130                         goto errout;
00131 
00132                 err = cmd->c_msg_parser(ops, cmd, &info, pp);
00133         }
00134 errout:
00135         return err;
00136 
00137 }
00138 
00139 char *genl_op2name(int family, int op, char *buf, size_t len)
00140 {
00141         struct genl_ops *ops;
00142         int i;
00143 
00144         nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
00145                 if (ops->o_family == family) {
00146                         for (i = 0; i < ops->o_ncmds; i++) {
00147                                 struct genl_cmd *cmd;
00148                                 cmd = &ops->o_cmds[i];
00149 
00150                                 if (cmd->c_id == op) {
00151                                         strncpy(buf, cmd->c_name, len - 1);
00152                                         return buf;
00153                                 }
00154                         }
00155                 }
00156         }
00157 
00158         strncpy(buf, "unknown", len - 1);
00159         return NULL;
00160 }
00161 
00162 
00163 /**
00164  * @name Register/Unregister
00165  * @{
00166  */
00167 
00168 /**
00169  * Register generic netlink operations
00170  * @arg ops             cache operations
00171  */
00172 int genl_register(struct nl_cache_ops *ops)
00173 {
00174         int err;
00175 
00176         if (ops->co_protocol != NETLINK_GENERIC) {
00177                 err = nl_error(EINVAL, "cache operations not for protocol " \
00178                                "NETLINK_GENERIC (protocol=%s)",
00179                                ops->co_protocol);
00180                 goto errout;
00181         }
00182 
00183         if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
00184                 err = nl_error(EINVAL, "co_hdrsize too short, probably " \
00185                                "not including genlmsghdr, minsize=%d",
00186                                GENL_HDRSIZE(0));
00187                 goto errout;
00188         }
00189 
00190         if (ops->co_genl == NULL) {
00191                 err = nl_error(EINVAL, "co_genl is NULL, must provide " \
00192                                "valid genl operations");
00193                 goto errout;
00194         }
00195 
00196         ops->co_genl->o_cache_ops = ops;
00197         ops->co_genl->o_name = ops->co_msgtypes[0].mt_name;
00198         ops->co_genl->o_family = ops->co_msgtypes[0].mt_id;
00199         ops->co_msg_parser = genl_msg_parser;
00200 
00201         /* FIXME: check for dup */
00202 
00203         nl_list_add_tail(&ops->co_genl->o_list, &genl_ops_list);
00204 
00205         err = nl_cache_mngt_register(ops);
00206 errout:
00207         return err;
00208 }
00209 
00210 /**
00211  * Unregister generic netlink operations
00212  * @arg ops             cache operations
00213  */
00214 void genl_unregister(struct nl_cache_ops *ops)
00215 {
00216         nl_cache_mngt_unregister(ops);
00217         nl_list_del(&ops->co_genl->o_list);
00218 }
00219 
00220 /** @} */
00221 
00222 /**
00223  * @name Resolving ID/Name
00224  * @{
00225  */
00226 
00227 static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
00228 {
00229         struct genl_family *family;
00230 
00231         family = genl_ctrl_search_by_name(ctrl, ops->o_name);
00232         if (family != NULL) {
00233                 ops->o_id = genl_family_get_id(family);
00234                 genl_family_put(family);
00235 
00236                 return 0;
00237         }
00238 
00239         return nl_error(ENOENT, "Unable to find generic netlink family \"%s\"",
00240                         ops->o_name);
00241 }
00242 
00243 int genl_ops_resolve(struct nl_handle *handle, struct genl_ops *ops)
00244 {
00245         struct nl_cache *ctrl;
00246         int err;
00247 
00248         ctrl = genl_ctrl_alloc_cache(handle);
00249         if (ctrl == NULL) {
00250                 err = nl_get_errno();
00251                 goto errout;
00252         }
00253 
00254         err = __genl_ops_resolve(ctrl, ops);
00255 
00256         nl_cache_free(ctrl);
00257 errout:
00258         return err;
00259 }
00260 
00261 int genl_mngt_resolve(struct nl_handle *handle)
00262 {
00263         struct nl_cache *ctrl;
00264         struct genl_ops *ops;
00265         int err = 0;
00266 
00267         ctrl = genl_ctrl_alloc_cache(handle);
00268         if (ctrl == NULL) {
00269                 err = nl_get_errno();
00270                 goto errout;
00271         }
00272 
00273         nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
00274                 err = __genl_ops_resolve(ctrl, ops);
00275         }
00276 
00277         nl_cache_free(ctrl);
00278 errout:
00279         return err;
00280 }
00281 
00282 /** @} */
00283 
00284 
00285 /** @} */