mngt.c 8.0 KB

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