libnl
3.2.3
|
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-2008 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 = -NLE_MSGTYPE_NOSUPPORT; 00112 goto errout; 00113 00114 found: 00115 if (cmd->c_msg_parser == NULL) 00116 err = -NLE_OPNOTSUPP; 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 = -NLE_PROTO_MISMATCH; 00178 goto errout; 00179 } 00180 00181 if (ops->co_hdrsize < GENL_HDRSIZE(0)) { 00182 err = -NLE_INVAL; 00183 goto errout; 00184 } 00185 00186 if (ops->co_genl == NULL) { 00187 err = -NLE_INVAL; 00188 goto errout; 00189 } 00190 00191 ops->co_genl->o_cache_ops = ops; 00192 ops->co_genl->o_name = ops->co_msgtypes[0].mt_name; 00193 ops->co_genl->o_family = ops->co_msgtypes[0].mt_id; 00194 ops->co_msg_parser = genl_msg_parser; 00195 00196 /* FIXME: check for dup */ 00197 00198 nl_list_add_tail(&ops->co_genl->o_list, &genl_ops_list); 00199 00200 err = nl_cache_mngt_register(ops); 00201 errout: 00202 return err; 00203 } 00204 00205 /** 00206 * Unregister generic netlink operations 00207 * @arg ops cache operations 00208 */ 00209 void genl_unregister(struct nl_cache_ops *ops) 00210 { 00211 nl_cache_mngt_unregister(ops); 00212 nl_list_del(&ops->co_genl->o_list); 00213 } 00214 00215 /** @} */ 00216 00217 /** 00218 * @name Resolving ID/Name 00219 * @{ 00220 */ 00221 00222 static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops) 00223 { 00224 struct genl_family *family; 00225 00226 family = genl_ctrl_search_by_name(ctrl, ops->o_name); 00227 if (family != NULL) { 00228 ops->o_id = genl_family_get_id(family); 00229 genl_family_put(family); 00230 00231 return 0; 00232 } 00233 00234 return -NLE_OBJ_NOTFOUND; 00235 } 00236 00237 int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops) 00238 { 00239 struct nl_cache *ctrl; 00240 int err; 00241 00242 if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) 00243 goto errout; 00244 00245 err = __genl_ops_resolve(ctrl, ops); 00246 00247 nl_cache_free(ctrl); 00248 errout: 00249 return err; 00250 } 00251 00252 int genl_mngt_resolve(struct nl_sock *sk) 00253 { 00254 struct nl_cache *ctrl; 00255 struct genl_ops *ops; 00256 int err = 0; 00257 00258 if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) 00259 goto errout; 00260 00261 nl_list_for_each_entry(ops, &genl_ops_list, o_list) { 00262 err = __genl_ops_resolve(ctrl, ops); 00263 } 00264 00265 nl_cache_free(ctrl); 00266 errout: 00267 return err; 00268 } 00269 00270 /** @} */ 00271 00272 00273 /** @} */