netlink.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Netlink helper functions for driver wrappers
  3. * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  4. *
  5. * This software may be distributed under the terms of the BSD license.
  6. * See README for more details.
  7. */
  8. #include "includes.h"
  9. #include "common.h"
  10. #include "eloop.h"
  11. #include "priv_netlink.h"
  12. #include "netlink.h"
  13. struct netlink_data {
  14. struct netlink_config *cfg;
  15. int sock;
  16. };
  17. static void netlink_receive_link(struct netlink_data *netlink,
  18. void (*cb)(void *ctx, struct ifinfomsg *ifi,
  19. u8 *buf, size_t len),
  20. struct nlmsghdr *h)
  21. {
  22. if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
  23. return;
  24. cb(netlink->cfg->ctx, NLMSG_DATA(h),
  25. (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
  26. NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
  27. }
  28. static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
  29. {
  30. struct netlink_data *netlink = eloop_ctx;
  31. char buf[8192];
  32. int left;
  33. struct sockaddr_nl from;
  34. socklen_t fromlen;
  35. struct nlmsghdr *h;
  36. int max_events = 10;
  37. try_again:
  38. fromlen = sizeof(from);
  39. left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
  40. (struct sockaddr *) &from, &fromlen);
  41. if (left < 0) {
  42. if (errno != EINTR && errno != EAGAIN)
  43. wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
  44. strerror(errno));
  45. return;
  46. }
  47. h = (struct nlmsghdr *) buf;
  48. while (NLMSG_OK(h, left)) {
  49. switch (h->nlmsg_type) {
  50. case RTM_NEWLINK:
  51. netlink_receive_link(netlink, netlink->cfg->newlink_cb,
  52. h);
  53. break;
  54. case RTM_DELLINK:
  55. netlink_receive_link(netlink, netlink->cfg->dellink_cb,
  56. h);
  57. break;
  58. }
  59. h = NLMSG_NEXT(h, left);
  60. }
  61. if (left > 0) {
  62. wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
  63. "netlink message", left);
  64. }
  65. if (--max_events > 0) {
  66. /*
  67. * Try to receive all events in one eloop call in order to
  68. * limit race condition on cases where AssocInfo event, Assoc
  69. * event, and EAPOL frames are received more or less at the
  70. * same time. We want to process the event messages first
  71. * before starting EAPOL processing.
  72. */
  73. goto try_again;
  74. }
  75. }
  76. struct netlink_data * netlink_init(struct netlink_config *cfg)
  77. {
  78. struct netlink_data *netlink;
  79. struct sockaddr_nl local;
  80. netlink = os_zalloc(sizeof(*netlink));
  81. if (netlink == NULL)
  82. return NULL;
  83. netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  84. if (netlink->sock < 0) {
  85. wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
  86. "socket: %s", strerror(errno));
  87. netlink_deinit(netlink);
  88. return NULL;
  89. }
  90. os_memset(&local, 0, sizeof(local));
  91. local.nl_family = AF_NETLINK;
  92. local.nl_groups = RTMGRP_LINK;
  93. if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
  94. {
  95. wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
  96. "socket: %s", strerror(errno));
  97. netlink_deinit(netlink);
  98. return NULL;
  99. }
  100. eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
  101. NULL);
  102. netlink->cfg = cfg;
  103. return netlink;
  104. }
  105. void netlink_deinit(struct netlink_data *netlink)
  106. {
  107. if (netlink == NULL)
  108. return;
  109. if (netlink->sock >= 0) {
  110. eloop_unregister_read_sock(netlink->sock);
  111. close(netlink->sock);
  112. }
  113. os_free(netlink->cfg);
  114. os_free(netlink);
  115. }
  116. static const char * linkmode_str(int mode)
  117. {
  118. switch (mode) {
  119. case -1:
  120. return "no change";
  121. case 0:
  122. return "kernel-control";
  123. case 1:
  124. return "userspace-control";
  125. }
  126. return "?";
  127. }
  128. static const char * operstate_str(int state)
  129. {
  130. switch (state) {
  131. case -1:
  132. return "no change";
  133. case IF_OPER_DORMANT:
  134. return "IF_OPER_DORMANT";
  135. case IF_OPER_UP:
  136. return "IF_OPER_UP";
  137. }
  138. return "?";
  139. }
  140. int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
  141. int linkmode, int operstate)
  142. {
  143. struct {
  144. struct nlmsghdr hdr;
  145. struct ifinfomsg ifinfo;
  146. char opts[16];
  147. } req;
  148. struct rtattr *rta;
  149. static int nl_seq;
  150. ssize_t ret;
  151. os_memset(&req, 0, sizeof(req));
  152. req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  153. req.hdr.nlmsg_type = RTM_SETLINK;
  154. req.hdr.nlmsg_flags = NLM_F_REQUEST;
  155. req.hdr.nlmsg_seq = ++nl_seq;
  156. req.hdr.nlmsg_pid = 0;
  157. req.ifinfo.ifi_family = AF_UNSPEC;
  158. req.ifinfo.ifi_type = 0;
  159. req.ifinfo.ifi_index = ifindex;
  160. req.ifinfo.ifi_flags = 0;
  161. req.ifinfo.ifi_change = 0;
  162. if (linkmode != -1) {
  163. rta = aliasing_hide_typecast(
  164. ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
  165. struct rtattr);
  166. rta->rta_type = IFLA_LINKMODE;
  167. rta->rta_len = RTA_LENGTH(sizeof(char));
  168. *((char *) RTA_DATA(rta)) = linkmode;
  169. req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
  170. }
  171. if (operstate != -1) {
  172. rta = aliasing_hide_typecast(
  173. ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
  174. struct rtattr);
  175. rta->rta_type = IFLA_OPERSTATE;
  176. rta->rta_len = RTA_LENGTH(sizeof(char));
  177. *((char *) RTA_DATA(rta)) = operstate;
  178. req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
  179. }
  180. wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)",
  181. ifindex, linkmode, linkmode_str(linkmode),
  182. operstate, operstate_str(operstate));
  183. ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
  184. if (ret < 0) {
  185. wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
  186. "failed: %s (assume operstate is not supported)",
  187. strerror(errno));
  188. }
  189. return ret < 0 ? -1 : 0;
  190. }