genl.c 6.6 KB

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