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