driver_wired_common.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Common functions for Wired Ethernet driver interfaces
  3. * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
  4. * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
  5. *
  6. * This software may be distributed under the terms of the BSD license.
  7. * See README for more details.
  8. */
  9. #include "includes.h"
  10. #include "common.h"
  11. #include "eloop.h"
  12. #include "driver.h"
  13. #include "driver_wired_common.h"
  14. #include <sys/ioctl.h>
  15. #include <net/if.h>
  16. #ifdef __linux__
  17. #include <netpacket/packet.h>
  18. #include <net/if_arp.h>
  19. #include <net/if.h>
  20. #endif /* __linux__ */
  21. #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
  22. #include <net/if_dl.h>
  23. #include <net/if_media.h>
  24. #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
  25. #ifdef __sun__
  26. #include <sys/sockio.h>
  27. #endif /* __sun__ */
  28. static int driver_wired_get_ifflags(const char *ifname, int *flags)
  29. {
  30. struct ifreq ifr;
  31. int s;
  32. s = socket(PF_INET, SOCK_DGRAM, 0);
  33. if (s < 0) {
  34. wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
  35. return -1;
  36. }
  37. os_memset(&ifr, 0, sizeof(ifr));
  38. os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
  39. if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
  40. wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
  41. strerror(errno));
  42. close(s);
  43. return -1;
  44. }
  45. close(s);
  46. *flags = ifr.ifr_flags & 0xffff;
  47. return 0;
  48. }
  49. static int driver_wired_set_ifflags(const char *ifname, int flags)
  50. {
  51. struct ifreq ifr;
  52. int s;
  53. s = socket(PF_INET, SOCK_DGRAM, 0);
  54. if (s < 0) {
  55. wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
  56. return -1;
  57. }
  58. os_memset(&ifr, 0, sizeof(ifr));
  59. os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
  60. ifr.ifr_flags = flags & 0xffff;
  61. if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
  62. wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
  63. strerror(errno));
  64. close(s);
  65. return -1;
  66. }
  67. close(s);
  68. return 0;
  69. }
  70. static int driver_wired_multi(const char *ifname, const u8 *addr, int add)
  71. {
  72. struct ifreq ifr;
  73. int s;
  74. #ifdef __sun__
  75. return -1;
  76. #endif /* __sun__ */
  77. s = socket(PF_INET, SOCK_DGRAM, 0);
  78. if (s < 0) {
  79. wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
  80. return -1;
  81. }
  82. os_memset(&ifr, 0, sizeof(ifr));
  83. os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
  84. #ifdef __linux__
  85. ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
  86. os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
  87. #endif /* __linux__ */
  88. #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
  89. {
  90. struct sockaddr_dl *dlp;
  91. dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
  92. dlp->sdl_len = sizeof(struct sockaddr_dl);
  93. dlp->sdl_family = AF_LINK;
  94. dlp->sdl_index = 0;
  95. dlp->sdl_nlen = 0;
  96. dlp->sdl_alen = ETH_ALEN;
  97. dlp->sdl_slen = 0;
  98. os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
  99. }
  100. #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
  101. #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
  102. {
  103. struct sockaddr *sap;
  104. sap = (struct sockaddr *) &ifr.ifr_addr;
  105. sap->sa_len = sizeof(struct sockaddr);
  106. sap->sa_family = AF_UNSPEC;
  107. os_memcpy(sap->sa_data, addr, ETH_ALEN);
  108. }
  109. #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
  110. if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
  111. wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
  112. strerror(errno));
  113. close(s);
  114. return -1;
  115. }
  116. close(s);
  117. return 0;
  118. }
  119. int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add)
  120. {
  121. #ifdef __linux__
  122. struct packet_mreq mreq;
  123. if (sock < 0)
  124. return -1;
  125. os_memset(&mreq, 0, sizeof(mreq));
  126. mreq.mr_ifindex = ifindex;
  127. mreq.mr_type = PACKET_MR_MULTICAST;
  128. mreq.mr_alen = ETH_ALEN;
  129. os_memcpy(mreq.mr_address, addr, ETH_ALEN);
  130. if (setsockopt(sock, SOL_PACKET,
  131. add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
  132. &mreq, sizeof(mreq)) < 0) {
  133. wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
  134. return -1;
  135. }
  136. return 0;
  137. #else /* __linux__ */
  138. return -1;
  139. #endif /* __linux__ */
  140. }
  141. int driver_wired_get_ssid(void *priv, u8 *ssid)
  142. {
  143. ssid[0] = 0;
  144. return 0;
  145. }
  146. int driver_wired_get_bssid(void *priv, u8 *bssid)
  147. {
  148. /* Report PAE group address as the "BSSID" for wired connection. */
  149. os_memcpy(bssid, pae_group_addr, ETH_ALEN);
  150. return 0;
  151. }
  152. int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
  153. {
  154. os_memset(capa, 0, sizeof(*capa));
  155. capa->flags = WPA_DRIVER_FLAGS_WIRED;
  156. return 0;
  157. }
  158. #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
  159. static int driver_wired_get_ifstatus(const char *ifname, int *status)
  160. {
  161. struct ifmediareq ifmr;
  162. int s;
  163. s = socket(PF_INET, SOCK_DGRAM, 0);
  164. if (s < 0) {
  165. wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
  166. return -1;
  167. }
  168. os_memset(&ifmr, 0, sizeof(ifmr));
  169. os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
  170. if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
  171. wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
  172. strerror(errno));
  173. close(s);
  174. return -1;
  175. }
  176. close(s);
  177. *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
  178. (IFM_ACTIVE | IFM_AVALID);
  179. return 0;
  180. }
  181. #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
  182. int driver_wired_init_common(struct driver_wired_common_data *common,
  183. const char *ifname, void *ctx)
  184. {
  185. int flags;
  186. os_strlcpy(common->ifname, ifname, sizeof(common->ifname));
  187. common->ctx = ctx;
  188. #ifdef __linux__
  189. common->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
  190. if (common->pf_sock < 0)
  191. wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
  192. #else /* __linux__ */
  193. common->pf_sock = -1;
  194. #endif /* __linux__ */
  195. if (driver_wired_get_ifflags(ifname, &flags) == 0 &&
  196. !(flags & IFF_UP) &&
  197. driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0)
  198. common->iff_up = 1;
  199. if (wired_multicast_membership(common->pf_sock,
  200. if_nametoindex(common->ifname),
  201. pae_group_addr, 1) == 0) {
  202. wpa_printf(MSG_DEBUG,
  203. "%s: Added multicast membership with packet socket",
  204. __func__);
  205. common->membership = 1;
  206. } else if (driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
  207. wpa_printf(MSG_DEBUG,
  208. "%s: Added multicast membership with SIOCADDMULTI",
  209. __func__);
  210. common->multi = 1;
  211. } else if (driver_wired_get_ifflags(ifname, &flags) < 0) {
  212. wpa_printf(MSG_INFO, "%s: Could not get interface flags",
  213. __func__);
  214. return -1;
  215. } else if (flags & IFF_ALLMULTI) {
  216. wpa_printf(MSG_DEBUG,
  217. "%s: Interface is already configured for multicast",
  218. __func__);
  219. } else if (driver_wired_set_ifflags(ifname,
  220. flags | IFF_ALLMULTI) < 0) {
  221. wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", __func__);
  222. return -1;
  223. } else {
  224. wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
  225. common->iff_allmulti = 1;
  226. }
  227. #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
  228. {
  229. int status;
  230. wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
  231. __func__);
  232. while (driver_wired_get_ifstatus(ifname, &status) == 0 &&
  233. status == 0)
  234. sleep(1);
  235. }
  236. #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
  237. return 0;
  238. }
  239. void driver_wired_deinit_common(struct driver_wired_common_data *common)
  240. {
  241. int flags;
  242. if (common->membership &&
  243. wired_multicast_membership(common->pf_sock,
  244. if_nametoindex(common->ifname),
  245. pae_group_addr, 0) < 0) {
  246. wpa_printf(MSG_DEBUG,
  247. "%s: Failed to remove PAE multicast group (PACKET)",
  248. __func__);
  249. }
  250. if (common->multi &&
  251. driver_wired_multi(common->ifname, pae_group_addr, 0) < 0) {
  252. wpa_printf(MSG_DEBUG,
  253. "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
  254. __func__);
  255. }
  256. if (common->iff_allmulti &&
  257. (driver_wired_get_ifflags(common->ifname, &flags) < 0 ||
  258. driver_wired_set_ifflags(common->ifname,
  259. flags & ~IFF_ALLMULTI) < 0)) {
  260. wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
  261. __func__);
  262. }
  263. if (common->iff_up &&
  264. driver_wired_get_ifflags(common->ifname, &flags) == 0 &&
  265. (flags & IFF_UP) &&
  266. driver_wired_set_ifflags(common->ifname, flags & ~IFF_UP) < 0) {
  267. wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
  268. __func__);
  269. }
  270. if (common->pf_sock != -1)
  271. close(common->pf_sock);
  272. }