1
0

genl.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * lib/genl/genl.c Generic Netlink
  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. * @defgroup genl Generic Netlink
  13. *
  14. * @par Message Format
  15. * @code
  16. * <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
  17. * +----------------------------+- - -+- - - - - - - - - - -+- - -+
  18. * | Header | Pad | Payload | Pad |
  19. * | struct nlmsghdr | | | |
  20. * +----------------------------+- - -+- - - - - - - - - - -+- - -+
  21. * @endcode
  22. * @code
  23. * <-------- GENL_HDRLEN -------> <--- hdrlen -->
  24. * <------- genlmsg_len(ghdr) ------>
  25. * +------------------------+- - -+---------------+- - -+------------+
  26. * | Generic Netlink Header | Pad | Family Header | Pad | Attributes |
  27. * | struct genlmsghdr | | | | |
  28. * +------------------------+- - -+---------------+- - -+------------+
  29. * genlmsg_data(ghdr)--------------^ ^
  30. * genlmsg_attrdata(ghdr, hdrlen)-------------------------
  31. * @endcode
  32. *
  33. * @par Example
  34. * @code
  35. * #include <netlink/netlink.h>
  36. * #include <netlink/genl/genl.h>
  37. * #include <netlink/genl/ctrl.h>
  38. *
  39. * struct nl_sock *sock;
  40. * struct nl_msg *msg;
  41. * int family;
  42. *
  43. * // Allocate a new netlink socket
  44. * sock = nl_socket_alloc();
  45. *
  46. * // Connect to generic netlink socket on kernel side
  47. * genl_connect(sock);
  48. *
  49. * // Ask kernel to resolve family name to family id
  50. * family = genl_ctrl_resolve(sock, "generic_netlink_family_name");
  51. *
  52. * // Construct a generic netlink by allocating a new message, fill in
  53. * // the header and append a simple integer attribute.
  54. * msg = nlmsg_alloc();
  55. * genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO,
  56. * CMD_FOO_GET, FOO_VERSION);
  57. * nla_put_u32(msg, ATTR_FOO, 123);
  58. *
  59. * // Send message over netlink socket
  60. * nl_send_auto_complete(sock, msg);
  61. *
  62. * // Free message
  63. * nlmsg_free(msg);
  64. *
  65. * // Prepare socket to receive the answer by specifying the callback
  66. * // function to be called for valid messages.
  67. * nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
  68. *
  69. * // Wait for the answer and receive it
  70. * nl_recvmsgs_default(sock);
  71. *
  72. * static int parse_cb(struct nl_msg *msg, void *arg)
  73. * {
  74. * struct nlmsghdr *nlh = nlmsg_hdr(msg);
  75. * struct nlattr *attrs[ATTR_MAX+1];
  76. *
  77. * // Validate message and parse attributes
  78. * genlmsg_parse(nlh, 0, attrs, ATTR_MAX, policy);
  79. *
  80. * if (attrs[ATTR_FOO]) {
  81. * uint32_t value = nla_get_u32(attrs[ATTR_FOO]);
  82. * ...
  83. * }
  84. *
  85. * return 0;
  86. * }
  87. * @endcode
  88. * @{
  89. */
  90. #include <netlink-generic.h>
  91. #include <netlink/netlink.h>
  92. #include <netlink/genl/genl.h>
  93. #include <netlink/utils.h>
  94. /**
  95. * @name Socket Creating
  96. * @{
  97. */
  98. int genl_connect(struct nl_sock *sk)
  99. {
  100. return nl_connect(sk, NETLINK_GENERIC);
  101. }
  102. /** @} */
  103. /**
  104. * @name Sending
  105. * @{
  106. */
  107. /**
  108. * Send trivial generic netlink message
  109. * @arg sk Netlink socket.
  110. * @arg family Generic netlink family
  111. * @arg cmd Command
  112. * @arg version Version
  113. * @arg flags Additional netlink message flags.
  114. *
  115. * Fills out a routing netlink request message and sends it out
  116. * using nl_send_simple().
  117. *
  118. * @return 0 on success or a negative error code.
  119. */
  120. int genl_send_simple(struct nl_sock *sk, int family, int cmd,
  121. int version, int flags)
  122. {
  123. struct genlmsghdr hdr = {
  124. .cmd = cmd,
  125. .version = version,
  126. };
  127. return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr));
  128. }
  129. /** @} */
  130. /**
  131. * @name Message Parsing
  132. * @{
  133. */
  134. int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
  135. {
  136. struct genlmsghdr *ghdr;
  137. if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
  138. return 0;
  139. ghdr = nlmsg_data(nlh);
  140. if ((unsigned) genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
  141. return 0;
  142. return 1;
  143. }
  144. int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
  145. const struct nla_policy *policy)
  146. {
  147. struct genlmsghdr *ghdr;
  148. if (!genlmsg_valid_hdr(nlh, hdrlen))
  149. return -NLE_MSG_TOOSHORT;
  150. ghdr = nlmsg_data(nlh);
  151. return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
  152. genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
  153. }
  154. int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
  155. int maxtype, const struct nla_policy *policy)
  156. {
  157. struct genlmsghdr *ghdr;
  158. if (!genlmsg_valid_hdr(nlh, hdrlen))
  159. return -NLE_MSG_TOOSHORT;
  160. ghdr = nlmsg_data(nlh);
  161. return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
  162. genlmsg_attrlen(ghdr, hdrlen), policy);
  163. }
  164. /**
  165. * Get head of message payload
  166. * @arg gnlh genetlink messsage header
  167. */
  168. void *genlmsg_data(const struct genlmsghdr *gnlh)
  169. {
  170. return ((unsigned char *) gnlh + GENL_HDRLEN);
  171. }
  172. /**
  173. * Get lenght of message payload
  174. * @arg gnlh genetlink message header
  175. */
  176. int genlmsg_len(const struct genlmsghdr *gnlh)
  177. {
  178. struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh -
  179. NLMSG_HDRLEN);
  180. return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
  181. }
  182. /**
  183. * Get head of attribute data
  184. * @arg gnlh generic netlink message header
  185. * @arg hdrlen length of family specific header
  186. */
  187. struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
  188. {
  189. return genlmsg_data(gnlh) + NLMSG_ALIGN(hdrlen);
  190. }
  191. /**
  192. * Get length of attribute data
  193. * @arg gnlh generic netlink message header
  194. * @arg hdrlen length of family specific header
  195. */
  196. int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
  197. {
  198. return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
  199. }
  200. /** @} */
  201. /**
  202. * @name Message Building
  203. * @{
  204. */
  205. /**
  206. * Add generic netlink header to netlink message
  207. * @arg msg netlink message
  208. * @arg pid netlink process id or NL_AUTO_PID
  209. * @arg seq sequence number of message or NL_AUTO_SEQ
  210. * @arg family generic netlink family
  211. * @arg hdrlen length of user specific header
  212. * @arg flags message flags
  213. * @arg cmd generic netlink command
  214. * @arg version protocol version
  215. *
  216. * Returns pointer to user specific header.
  217. */
  218. void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
  219. int hdrlen, int flags, uint8_t cmd, uint8_t version)
  220. {
  221. struct nlmsghdr *nlh;
  222. struct genlmsghdr hdr = {
  223. .cmd = cmd,
  224. .version = version,
  225. };
  226. nlh = nlmsg_put(msg, pid, seq, family, GENL_HDRLEN + hdrlen, flags);
  227. if (nlh == NULL)
  228. return NULL;
  229. memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
  230. NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
  231. msg, cmd, version);
  232. return nlmsg_data(nlh) + GENL_HDRLEN;
  233. }
  234. /** @} */
  235. /** @} */