Home | History | Annotate | Download | only in genl
      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