libnl
3.2.3
|
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 /** @} */