1/* 2 * lib/genl/mngt.c Generic Netlink Management 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup genl 14 * @defgroup genl_mngt Management 15 * 16 * @par 1) Registering a generic netlink module 17 * @code 18 * #include <netlink/genl/mngt.h> 19 * 20 * // First step is to define all the commands being used in 21 * // particular generic netlink family. The ID and name are 22 * // mandatory to be filled out. A callback function and 23 * // most the attribute policy that comes with it must be 24 * // defined for commands expected to be issued towards 25 * // userspace. 26 * static struct genl_cmd foo_cmds[] = { 27 * { 28 * .c_id = FOO_CMD_NEW, 29 * .c_name = "NEWFOO" , 30 * .c_maxattr = FOO_ATTR_MAX, 31 * .c_attr_policy = foo_policy, 32 * .c_msg_parser = foo_msg_parser, 33 * }, 34 * { 35 * .c_id = FOO_CMD_DEL, 36 * .c_name = "DELFOO" , 37 * }, 38 * }; 39 * 40 * // The list of commands must then be integrated into a 41 * // struct genl_ops serving as handle for this particular 42 * // family. 43 * static struct genl_ops my_genl_ops = { 44 * .o_cmds = foo_cmds, 45 * .o_ncmds = ARRAY_SIZE(foo_cmds), 46 * }; 47 * 48 * // Using the above struct genl_ops an arbitary number of 49 * // cache handles can be associated to it. 50 * // 51 * // The macro GENL_HDRSIZE() must be used to specify the 52 * // length of the header to automatically take headers on 53 * // generic layers into account. 54 * // 55 * // The macro GENL_FAMILY() is used to represent the generic 56 * // netlink family id. 57 * static struct nl_cache_ops genl_foo_ops = { 58 * .co_name = "genl/foo", 59 * .co_hdrsize = GENL_HDRSIZE(sizeof(struct my_hdr)), 60 * .co_msgtypes = GENL_FAMILY(GENL_ID_GENERATE, "foo"), 61 * .co_genl = &my_genl_ops, 62 * .co_protocol = NETLINK_GENERIC, 63 * .co_request_update = foo_request_update, 64 * .co_obj_ops = &genl_foo_ops, 65 * }; 66 * 67 * // Finally each cache handle for a generic netlink family 68 * // must be registered using genl_register(). 69 * static void __init foo_init(void) 70 * { 71 * genl_register(&genl_foo_ops); 72 * } 73 * 74 * // ... respectively unregsted again. 75 * static void __exit foo_exit(void) 76 * { 77 * genl_unregister(&genl_foo_ops); 78 * } 79 * @endcode 80 * @{ 81 */ 82 83#include <netlink-generic.h> 84#include <netlink/netlink.h> 85#include <netlink/genl/genl.h> 86#include <netlink/genl/mngt.h> 87#include <netlink/genl/family.h> 88#include <netlink/genl/ctrl.h> 89#include <netlink/utils.h> 90 91static NL_LIST_HEAD(genl_ops_list); 92 93static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 94 struct nlmsghdr *nlh, struct nl_parser_param *pp) 95{ 96 int i, err; 97 struct genlmsghdr *ghdr; 98 struct genl_cmd *cmd; 99 100 ghdr = nlmsg_data(nlh); 101 102 if (ops->co_genl == NULL) 103 BUG(); 104 105 for (i = 0; i < ops->co_genl->o_ncmds; i++) { 106 cmd = &ops->co_genl->o_cmds[i]; 107 if (cmd->c_id == ghdr->cmd) 108 goto found; 109 } 110 111 err = -NLE_MSGTYPE_NOSUPPORT; 112 goto errout; 113 114found: 115 if (cmd->c_msg_parser == NULL) 116 err = -NLE_OPNOTSUPP; 117 else { 118 struct nlattr *tb[cmd->c_maxattr + 1]; 119 struct genl_info info = { 120 .who = who, 121 .nlh = nlh, 122 .genlhdr = ghdr, 123 .userhdr = genlmsg_data(ghdr), 124 .attrs = tb, 125 }; 126 127 err = nlmsg_parse(nlh, ops->co_hdrsize, tb, cmd->c_maxattr, 128 cmd->c_attr_policy); 129 if (err < 0) 130 goto errout; 131 132 err = cmd->c_msg_parser(ops, cmd, &info, pp); 133 } 134errout: 135 return err; 136 137} 138 139char *genl_op2name(int family, int op, char *buf, size_t len) 140{ 141 struct genl_ops *ops; 142 int i; 143 144 nl_list_for_each_entry(ops, &genl_ops_list, o_list) { 145 if (ops->o_family == family) { 146 for (i = 0; i < ops->o_ncmds; i++) { 147 struct genl_cmd *cmd; 148 cmd = &ops->o_cmds[i]; 149 150 if (cmd->c_id == op) { 151 strncpy(buf, cmd->c_name, len - 1); 152 return buf; 153 } 154 } 155 } 156 } 157 158 strncpy(buf, "unknown", len - 1); 159 return NULL; 160} 161 162 163/** 164 * @name Register/Unregister 165 * @{ 166 */ 167 168/** 169 * Register generic netlink operations 170 * @arg ops cache operations 171 */ 172int genl_register(struct nl_cache_ops *ops) 173{ 174 int err; 175 176 if (ops->co_protocol != NETLINK_GENERIC) { 177 err = -NLE_PROTO_MISMATCH; 178 goto errout; 179 } 180 181 if (ops->co_hdrsize < GENL_HDRSIZE(0)) { 182 err = -NLE_INVAL; 183 goto errout; 184 } 185 186 if (ops->co_genl == NULL) { 187 err = -NLE_INVAL; 188 goto errout; 189 } 190 191 ops->co_genl->o_cache_ops = ops; 192 ops->co_genl->o_name = ops->co_msgtypes[0].mt_name; 193 ops->co_genl->o_family = ops->co_msgtypes[0].mt_id; 194 ops->co_msg_parser = genl_msg_parser; 195 196 /* FIXME: check for dup */ 197 198 nl_list_add_tail(&ops->co_genl->o_list, &genl_ops_list); 199 200 err = nl_cache_mngt_register(ops); 201errout: 202 return err; 203} 204 205/** 206 * Unregister generic netlink operations 207 * @arg ops cache operations 208 */ 209void genl_unregister(struct nl_cache_ops *ops) 210{ 211 nl_cache_mngt_unregister(ops); 212 nl_list_del(&ops->co_genl->o_list); 213} 214 215/** @} */ 216 217/** 218 * @name Resolving ID/Name 219 * @{ 220 */ 221 222static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops) 223{ 224 struct genl_family *family; 225 226 family = genl_ctrl_search_by_name(ctrl, ops->o_name); 227 if (family != NULL) { 228 ops->o_id = genl_family_get_id(family); 229 genl_family_put(family); 230 231 return 0; 232 } 233 234 return -NLE_OBJ_NOTFOUND; 235} 236 237int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops) 238{ 239 struct nl_cache *ctrl; 240 int err; 241 242 if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) 243 goto errout; 244 245 err = __genl_ops_resolve(ctrl, ops); 246 247 nl_cache_free(ctrl); 248errout: 249 return err; 250} 251 252int genl_mngt_resolve(struct nl_sock *sk) 253{ 254 struct nl_cache *ctrl; 255 struct genl_ops *ops; 256 int err = 0; 257 258 if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) 259 goto errout; 260 261 nl_list_for_each_entry(ops, &genl_ops_list, o_list) { 262 err = __genl_ops_resolve(ctrl, ops); 263 } 264 265 nl_cache_free(ctrl); 266errout: 267 return err; 268} 269 270/** @} */ 271 272 273/** @} */ 274