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