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-2012 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup genl 14 * @defgroup genl_mngt Family and Command Registration 15 * 16 * Registering Generic Netlink Families and Commands 17 * 18 * @{ 19 */ 20 21 #include <netlink-private/genl.h> 22 #include <netlink/netlink.h> 23 #include <netlink/genl/genl.h> 24 #include <netlink/genl/mngt.h> 25 #include <netlink/genl/family.h> 26 #include <netlink/genl/ctrl.h> 27 #include <netlink/utils.h> 28 29 /** @cond SKIP */ 30 31 static NL_LIST_HEAD(genl_ops_list); 32 33 static struct genl_cmd *lookup_cmd(struct genl_ops *ops, int cmd_id) 34 { 35 struct genl_cmd *cmd; 36 int i; 37 38 for (i = 0; i < ops->o_ncmds; i++) { 39 cmd = &ops->o_cmds[i]; 40 if (cmd->c_id == cmd_id) 41 return cmd; 42 } 43 44 return NULL; 45 } 46 47 static int cmd_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh, 48 struct genl_ops *ops, struct nl_cache_ops *cache_ops, void *arg) 49 { 50 int err; 51 struct genlmsghdr *ghdr; 52 struct genl_cmd *cmd; 53 54 ghdr = genlmsg_hdr(nlh); 55 56 if (!(cmd = lookup_cmd(ops, ghdr->cmd))) { 57 err = -NLE_MSGTYPE_NOSUPPORT; 58 goto errout; 59 } 60 61 if (cmd->c_msg_parser == NULL) 62 err = -NLE_OPNOTSUPP; 63 else { 64 struct nlattr *tb[cmd->c_maxattr + 1]; 65 struct genl_info info = { 66 .who = who, 67 .nlh = nlh, 68 .genlhdr = ghdr, 69 .userhdr = genlmsg_user_hdr(ghdr), 70 .attrs = tb, 71 }; 72 73 err = nlmsg_parse(nlh, GENL_HDRSIZE(ops->o_hdrsize), tb, cmd->c_maxattr, 74 cmd->c_attr_policy); 75 if (err < 0) 76 goto errout; 77 78 err = cmd->c_msg_parser(cache_ops, cmd, &info, arg); 79 } 80 errout: 81 return err; 82 83 } 84 85 static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 86 struct nlmsghdr *nlh, struct nl_parser_param *pp) 87 { 88 if (ops->co_genl == NULL) 89 BUG(); 90 91 return cmd_msg_parser(who, nlh, ops->co_genl, ops, pp); 92 } 93 94 static struct genl_ops *lookup_family(int family) 95 { 96 struct genl_ops *ops; 97 98 nl_list_for_each_entry(ops, &genl_ops_list, o_list) { 99 if (ops->o_id == family) 100 return ops; 101 } 102 103 return NULL; 104 } 105 106 static struct genl_ops *lookup_family_by_name(const char *name) 107 { 108 struct genl_ops *ops; 109 110 nl_list_for_each_entry(ops, &genl_ops_list, o_list) { 111 if (!strcmp(ops->o_name, name)) 112 return ops; 113 } 114 115 return NULL; 116 } 117 118 char *genl_op2name(int family, int op, char *buf, size_t len) 119 { 120 struct genl_ops *ops; 121 int i; 122 123 if ((ops = lookup_family(family))) { 124 for (i = 0; i < ops->o_ncmds; i++) { 125 struct genl_cmd *cmd; 126 cmd = &ops->o_cmds[i]; 127 128 if (cmd->c_id == op) { 129 strncpy(buf, cmd->c_name, len - 1); 130 return buf; 131 } 132 } 133 } 134 135 strncpy(buf, "unknown", len - 1); 136 return NULL; 137 } 138 139 /** @endcond */ 140 141 /** 142 * @name Registration 143 * @{ 144 */ 145 146 /** 147 * Register Generic Netlink family and associated commands 148 * @arg ops Generic Netlink family definition 149 * 150 * Registers the specified Generic Netlink family definition together with 151 * all associated commands. After registration, received Generic Netlink 152 * messages can be passed to genl_handle_msg() which will validate the 153 * messages, look for a matching command and call the respective callback 154 * function automatically. 155 * 156 * @note Consider using genl_register() if the family is used to implement a 157 * cacheable type. 158 * 159 * @see genl_unregister_family(); 160 * @see genl_register(); 161 * 162 * @return 0 on success or a negative error code. 163 */ 164 int genl_register_family(struct genl_ops *ops) 165 { 166 if (!ops->o_name) 167 return -NLE_INVAL; 168 169 if (ops->o_cmds && ops->o_ncmds <= 0) 170 return -NLE_INVAL; 171 172 if (ops->o_id && lookup_family(ops->o_id)) 173 return -NLE_EXIST; 174 175 if (lookup_family_by_name(ops->o_name)) 176 return -NLE_EXIST; 177 178 nl_list_add_tail(&ops->o_list, &genl_ops_list); 179 180 return 0; 181 } 182 183 /** 184 * Unregister Generic Netlink family 185 * @arg ops Generic Netlink family definition 186 * 187 * Unregisters a family and all associated commands that were previously 188 * registered using genl_register_family(). 189 * 190 * @see genl_register_family() 191 * 192 * @return 0 on success or a negative error code. 193 */ 194 int genl_unregister_family(struct genl_ops *ops) 195 { 196 nl_list_del(&ops->o_list); 197 198 return 0; 199 } 200 201 /** 202 * Run a received message through the demultiplexer 203 * @arg msg Generic Netlink message 204 * @arg arg Argument passed on to the message handler callback 205 * 206 * @return 0 on success or a negative error code. 207 */ 208 int genl_handle_msg(struct nl_msg *msg, void *arg) 209 { 210 struct nlmsghdr *nlh = nlmsg_hdr(msg); 211 struct genl_ops *ops; 212 213 if (!genlmsg_valid_hdr(nlh, 0)) 214 return -NLE_INVAL; 215 216 if (!(ops = lookup_family(nlh->nlmsg_type))) 217 return -NLE_MSGTYPE_NOSUPPORT; 218 219 return cmd_msg_parser(nlmsg_get_src(msg), nlh, ops, NULL, arg); 220 } 221 222 /** @} */ 223 224 /** 225 * @name Registration of Cache Operations 226 * @{ 227 */ 228 229 /** 230 * Register Generic Netlink family backed cache 231 * @arg ops Cache operations definition 232 * 233 * Same as genl_register_family() but additionally registers the specified 234 * cache operations using nl_cache_mngt_register() and associates it with 235 * the Generic Netlink family. 236 * 237 * @see genl_register_family() 238 * 239 * @return 0 on success or a negative error code. 240 */ 241 int genl_register(struct nl_cache_ops *ops) 242 { 243 int err; 244 245 if (ops->co_protocol != NETLINK_GENERIC) { 246 err = -NLE_PROTO_MISMATCH; 247 goto errout; 248 } 249 250 if (ops->co_hdrsize < GENL_HDRSIZE(0)) { 251 err = -NLE_INVAL; 252 goto errout; 253 } 254 255 if (ops->co_genl == NULL) { 256 err = -NLE_INVAL; 257 goto errout; 258 } 259 260 ops->co_genl->o_cache_ops = ops; 261 ops->co_genl->o_hdrsize = ops->co_hdrsize - GENL_HDRLEN; 262 ops->co_genl->o_name = ops->co_msgtypes[0].mt_name; 263 ops->co_genl->o_id = ops->co_msgtypes[0].mt_id; 264 ops->co_msg_parser = genl_msg_parser; 265 266 if ((err = genl_register_family(ops->co_genl)) < 0) 267 goto errout; 268 269 err = nl_cache_mngt_register(ops); 270 errout: 271 return err; 272 } 273 274 /** 275 * Unregister cache based Generic Netlink family 276 * @arg ops Cache operations definition 277 */ 278 void genl_unregister(struct nl_cache_ops *ops) 279 { 280 if (!ops) 281 return; 282 283 nl_cache_mngt_unregister(ops); 284 285 genl_unregister_family(ops->co_genl); 286 } 287 288 /** @} */ 289 290 /** @cond SKIP */ 291 static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops) 292 { 293 struct genl_family *family; 294 295 family = genl_ctrl_search_by_name(ctrl, ops->o_name); 296 if (family != NULL) { 297 ops->o_id = genl_family_get_id(family); 298 299 if (ops->o_cache_ops) 300 ops->o_cache_ops->co_msgtypes[0].mt_id = ops->o_id; 301 302 genl_family_put(family); 303 304 return 0; 305 } 306 307 return -NLE_OBJ_NOTFOUND; 308 } 309 310 int genl_resolve_id(struct genl_ops *ops) 311 { 312 struct nl_sock *sk; 313 int err = 0; 314 315 /* Check if resolved already */ 316 if (ops->o_id != GENL_ID_GENERATE) 317 return 0; 318 319 if (!ops->o_name) 320 return -NLE_INVAL; 321 322 if (!(sk = nl_socket_alloc())) 323 return -NLE_NOMEM; 324 325 if ((err = genl_connect(sk)) < 0) 326 goto errout_free; 327 328 err = genl_ops_resolve(sk, ops); 329 330 errout_free: 331 nl_socket_free(sk); 332 333 return err; 334 } 335 /** @endcond */ 336 337 /** 338 * @name Resolving the name of registered families 339 * @{ 340 */ 341 342 /** 343 * Resolve a single Generic Netlink family 344 * @arg sk Generic Netlink socket 345 * @arg ops Generic Netlink family definition 346 * 347 * Resolves the family name to its numeric identifier. 348 * 349 * @return 0 on success or a negative error code. 350 */ 351 int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops) 352 { 353 struct nl_cache *ctrl; 354 int err; 355 356 if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) 357 goto errout; 358 359 err = __genl_ops_resolve(ctrl, ops); 360 361 nl_cache_free(ctrl); 362 errout: 363 return err; 364 } 365 366 /** 367 * Resolve all registered Generic Netlink families 368 * @arg sk Generic Netlink socket 369 * 370 * Walks through all local Generic Netlink families that have been registered 371 * using genl_register() and resolves the name of each family to the 372 * corresponding numeric identifier. 373 * 374 * @see genl_register() 375 * @see genl_ops_resolve() 376 * 377 * @return 0 on success or a negative error code. 378 */ 379 int genl_mngt_resolve(struct nl_sock *sk) 380 { 381 struct nl_cache *ctrl; 382 struct genl_ops *ops; 383 int err = 0; 384 385 if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0) 386 goto errout; 387 388 nl_list_for_each_entry(ops, &genl_ops_list, o_list) { 389 err = __genl_ops_resolve(ctrl, ops); 390 } 391 392 nl_cache_free(ctrl); 393 errout: 394 return err; 395 } 396 397 /** @} */ 398 399 /** @} */ 400