$search
00001 /* 00002 * Wired Ethernet driver interface 00003 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 00004 * Copyright (c) 2004, Gunter Burchardt <tira@isx.de> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License version 2 as 00008 * published by the Free Software Foundation. 00009 * 00010 * Alternatively, this software may be distributed under the terms of BSD 00011 * license. 00012 * 00013 * See README and COPYING for more details. 00014 */ 00015 00016 #include "includes.h" 00017 #include <sys/ioctl.h> 00018 #include <net/if.h> 00019 #ifdef __linux__ 00020 #include <netpacket/packet.h> 00021 #include <net/if_arp.h> 00022 #include <net/if.h> 00023 #endif /* __linux__ */ 00024 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 00025 #include <net/if_dl.h> 00026 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ 00027 00028 #include "common.h" 00029 #include "eloop.h" 00030 #include "driver.h" 00031 00032 #ifdef _MSC_VER 00033 #pragma pack(push, 1) 00034 #endif /* _MSC_VER */ 00035 00036 struct ieee8023_hdr { 00037 u8 dest[6]; 00038 u8 src[6]; 00039 u16 ethertype; 00040 } STRUCT_PACKED; 00041 00042 #ifdef _MSC_VER 00043 #pragma pack(pop) 00044 #endif /* _MSC_VER */ 00045 00046 static const u8 pae_group_addr[ETH_ALEN] = 00047 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; 00048 00049 00050 struct wpa_driver_wired_data { 00051 char ifname[IFNAMSIZ + 1]; 00052 void *ctx; 00053 00054 int sock; /* raw packet socket for driver access */ 00055 int dhcp_sock; /* socket for dhcp packets */ 00056 int use_pae_group_addr; 00057 00058 int pf_sock; 00059 int membership, multi, iff_allmulti, iff_up; 00060 }; 00061 00062 00063 /* TODO: detecting new devices should eventually be changed from using DHCP 00064 * snooping to trigger on any packet from a new layer 2 MAC address, e.g., 00065 * based on ebtables, etc. */ 00066 00067 struct dhcp_message { 00068 u_int8_t op; 00069 u_int8_t htype; 00070 u_int8_t hlen; 00071 u_int8_t hops; 00072 u_int32_t xid; 00073 u_int16_t secs; 00074 u_int16_t flags; 00075 u_int32_t ciaddr; 00076 u_int32_t yiaddr; 00077 u_int32_t siaddr; 00078 u_int32_t giaddr; 00079 u_int8_t chaddr[16]; 00080 u_int8_t sname[64]; 00081 u_int8_t file[128]; 00082 u_int32_t cookie; 00083 u_int8_t options[308]; /* 312 - cookie */ 00084 }; 00085 00086 00087 static int wired_multicast_membership(int sock, int ifindex, 00088 const u8 *addr, int add) 00089 { 00090 #ifdef __linux__ 00091 struct packet_mreq mreq; 00092 00093 if (sock < 0) 00094 return -1; 00095 00096 os_memset(&mreq, 0, sizeof(mreq)); 00097 mreq.mr_ifindex = ifindex; 00098 mreq.mr_type = PACKET_MR_MULTICAST; 00099 mreq.mr_alen = ETH_ALEN; 00100 os_memcpy(mreq.mr_address, addr, ETH_ALEN); 00101 00102 if (setsockopt(sock, SOL_PACKET, 00103 add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, 00104 &mreq, sizeof(mreq)) < 0) { 00105 perror("setsockopt"); 00106 return -1; 00107 } 00108 return 0; 00109 #else /* __linux__ */ 00110 return -1; 00111 #endif /* __linux__ */ 00112 } 00113 00114 00115 #ifdef __linux__ 00116 static void handle_data(void *ctx, unsigned char *buf, size_t len) 00117 { 00118 #ifdef HOSTAPD 00119 struct ieee8023_hdr *hdr; 00120 u8 *pos, *sa; 00121 size_t left; 00122 union wpa_event_data event; 00123 00124 /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, 00125 * 2 byte ethertype */ 00126 if (len < 14) { 00127 wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", 00128 (unsigned long) len); 00129 return; 00130 } 00131 00132 hdr = (struct ieee8023_hdr *) buf; 00133 00134 switch (ntohs(hdr->ethertype)) { 00135 case ETH_P_PAE: 00136 wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); 00137 sa = hdr->src; 00138 os_memset(&event, 0, sizeof(event)); 00139 event.new_sta.addr = sa; 00140 wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); 00141 00142 pos = (u8 *) (hdr + 1); 00143 left = len - sizeof(*hdr); 00144 drv_event_eapol_rx(ctx, sa, pos, left); 00145 break; 00146 00147 default: 00148 wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", 00149 ntohs(hdr->ethertype)); 00150 break; 00151 } 00152 #endif /* HOSTAPD */ 00153 } 00154 00155 00156 static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) 00157 { 00158 int len; 00159 unsigned char buf[3000]; 00160 00161 len = recv(sock, buf, sizeof(buf), 0); 00162 if (len < 0) { 00163 perror("recv"); 00164 return; 00165 } 00166 00167 handle_data(eloop_ctx, buf, len); 00168 } 00169 00170 00171 static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) 00172 { 00173 int len; 00174 unsigned char buf[3000]; 00175 struct dhcp_message *msg; 00176 u8 *mac_address; 00177 union wpa_event_data event; 00178 00179 len = recv(sock, buf, sizeof(buf), 0); 00180 if (len < 0) { 00181 perror("recv"); 00182 return; 00183 } 00184 00185 /* must contain at least dhcp_message->chaddr */ 00186 if (len < 44) { 00187 wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); 00188 return; 00189 } 00190 00191 msg = (struct dhcp_message *) buf; 00192 mac_address = (u8 *) &(msg->chaddr); 00193 00194 wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, 00195 MAC2STR(mac_address)); 00196 00197 os_memset(&event, 0, sizeof(event)); 00198 event.new_sta.addr = mac_address; 00199 wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event); 00200 } 00201 #endif /* __linux__ */ 00202 00203 00204 static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) 00205 { 00206 #ifdef __linux__ 00207 struct ifreq ifr; 00208 struct sockaddr_ll addr; 00209 struct sockaddr_in addr2; 00210 int n = 1; 00211 00212 drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); 00213 if (drv->sock < 0) { 00214 perror("socket[PF_PACKET,SOCK_RAW]"); 00215 return -1; 00216 } 00217 00218 if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) { 00219 printf("Could not register read socket\n"); 00220 return -1; 00221 } 00222 00223 os_memset(&ifr, 0, sizeof(ifr)); 00224 os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 00225 if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { 00226 perror("ioctl(SIOCGIFINDEX)"); 00227 return -1; 00228 } 00229 00230 os_memset(&addr, 0, sizeof(addr)); 00231 addr.sll_family = AF_PACKET; 00232 addr.sll_ifindex = ifr.ifr_ifindex; 00233 wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", 00234 addr.sll_ifindex); 00235 00236 if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 00237 perror("bind"); 00238 return -1; 00239 } 00240 00241 /* filter multicast address */ 00242 if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex, 00243 pae_group_addr, 1) < 0) { 00244 wpa_printf(MSG_ERROR, "wired: Failed to add multicast group " 00245 "membership"); 00246 return -1; 00247 } 00248 00249 os_memset(&ifr, 0, sizeof(ifr)); 00250 os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 00251 if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { 00252 perror("ioctl(SIOCGIFHWADDR)"); 00253 return -1; 00254 } 00255 00256 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 00257 printf("Invalid HW-addr family 0x%04x\n", 00258 ifr.ifr_hwaddr.sa_family); 00259 return -1; 00260 } 00261 os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 00262 00263 /* setup dhcp listen socket for sta detection */ 00264 if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 00265 perror("socket call failed for dhcp"); 00266 return -1; 00267 } 00268 00269 if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx, 00270 NULL)) { 00271 printf("Could not register read socket\n"); 00272 return -1; 00273 } 00274 00275 os_memset(&addr2, 0, sizeof(addr2)); 00276 addr2.sin_family = AF_INET; 00277 addr2.sin_port = htons(67); 00278 addr2.sin_addr.s_addr = INADDR_ANY; 00279 00280 if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, 00281 sizeof(n)) == -1) { 00282 perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]"); 00283 return -1; 00284 } 00285 if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, 00286 sizeof(n)) == -1) { 00287 perror("setsockopt[SOL_SOCKET,SO_BROADCAST]"); 00288 return -1; 00289 } 00290 00291 os_memset(&ifr, 0, sizeof(ifr)); 00292 os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ); 00293 if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, 00294 (char *) &ifr, sizeof(ifr)) < 0) { 00295 perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]"); 00296 return -1; 00297 } 00298 00299 if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, 00300 sizeof(struct sockaddr)) == -1) { 00301 perror("bind"); 00302 return -1; 00303 } 00304 00305 return 0; 00306 #else /* __linux__ */ 00307 return -1; 00308 #endif /* __linux__ */ 00309 } 00310 00311 00312 static int wired_send_eapol(void *priv, const u8 *addr, 00313 const u8 *data, size_t data_len, int encrypt, 00314 const u8 *own_addr) 00315 { 00316 struct wpa_driver_wired_data *drv = priv; 00317 struct ieee8023_hdr *hdr; 00318 size_t len; 00319 u8 *pos; 00320 int res; 00321 00322 len = sizeof(*hdr) + data_len; 00323 hdr = os_zalloc(len); 00324 if (hdr == NULL) { 00325 printf("malloc() failed for wired_send_eapol(len=%lu)\n", 00326 (unsigned long) len); 00327 return -1; 00328 } 00329 00330 os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, 00331 ETH_ALEN); 00332 os_memcpy(hdr->src, own_addr, ETH_ALEN); 00333 hdr->ethertype = htons(ETH_P_PAE); 00334 00335 pos = (u8 *) (hdr + 1); 00336 os_memcpy(pos, data, data_len); 00337 00338 res = send(drv->sock, (u8 *) hdr, len, 0); 00339 os_free(hdr); 00340 00341 if (res < 0) { 00342 perror("wired_send_eapol: send"); 00343 printf("wired_send_eapol - packet len: %lu - failed\n", 00344 (unsigned long) len); 00345 } 00346 00347 return res; 00348 } 00349 00350 00351 static void * wired_driver_hapd_init(struct hostapd_data *hapd, 00352 struct wpa_init_params *params) 00353 { 00354 struct wpa_driver_wired_data *drv; 00355 00356 drv = os_zalloc(sizeof(struct wpa_driver_wired_data)); 00357 if (drv == NULL) { 00358 printf("Could not allocate memory for wired driver data\n"); 00359 return NULL; 00360 } 00361 00362 drv->ctx = hapd; 00363 os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); 00364 drv->use_pae_group_addr = params->use_pae_group_addr; 00365 00366 if (wired_init_sockets(drv, params->own_addr)) { 00367 os_free(drv); 00368 return NULL; 00369 } 00370 00371 return drv; 00372 } 00373 00374 00375 static void wired_driver_hapd_deinit(void *priv) 00376 { 00377 struct wpa_driver_wired_data *drv = priv; 00378 00379 if (drv->sock >= 0) 00380 close(drv->sock); 00381 00382 if (drv->dhcp_sock >= 0) 00383 close(drv->dhcp_sock); 00384 00385 os_free(drv); 00386 } 00387 00388 00389 static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid) 00390 { 00391 ssid[0] = 0; 00392 return 0; 00393 } 00394 00395 00396 static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid) 00397 { 00398 /* Report PAE group address as the "BSSID" for wired connection. */ 00399 os_memcpy(bssid, pae_group_addr, ETH_ALEN); 00400 return 0; 00401 } 00402 00403 00404 static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa) 00405 { 00406 os_memset(capa, 0, sizeof(*capa)); 00407 capa->flags = WPA_DRIVER_FLAGS_WIRED; 00408 return 0; 00409 } 00410 00411 00412 static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags) 00413 { 00414 struct ifreq ifr; 00415 int s; 00416 00417 s = socket(PF_INET, SOCK_DGRAM, 0); 00418 if (s < 0) { 00419 perror("socket"); 00420 return -1; 00421 } 00422 00423 os_memset(&ifr, 0, sizeof(ifr)); 00424 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 00425 if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 00426 perror("ioctl[SIOCGIFFLAGS]"); 00427 close(s); 00428 return -1; 00429 } 00430 close(s); 00431 *flags = ifr.ifr_flags & 0xffff; 00432 return 0; 00433 } 00434 00435 00436 static int wpa_driver_wired_set_ifflags(const char *ifname, int flags) 00437 { 00438 struct ifreq ifr; 00439 int s; 00440 00441 s = socket(PF_INET, SOCK_DGRAM, 0); 00442 if (s < 0) { 00443 perror("socket"); 00444 return -1; 00445 } 00446 00447 os_memset(&ifr, 0, sizeof(ifr)); 00448 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 00449 ifr.ifr_flags = flags & 0xffff; 00450 if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 00451 perror("ioctl[SIOCSIFFLAGS]"); 00452 close(s); 00453 return -1; 00454 } 00455 close(s); 00456 return 0; 00457 } 00458 00459 00460 static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) 00461 { 00462 struct ifreq ifr; 00463 int s; 00464 00465 s = socket(PF_INET, SOCK_DGRAM, 0); 00466 if (s < 0) { 00467 perror("socket"); 00468 return -1; 00469 } 00470 00471 os_memset(&ifr, 0, sizeof(ifr)); 00472 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 00473 #ifdef __linux__ 00474 ifr.ifr_hwaddr.sa_family = AF_UNSPEC; 00475 os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); 00476 #endif /* __linux__ */ 00477 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 00478 { 00479 struct sockaddr_dl *dlp; 00480 dlp = (struct sockaddr_dl *) &ifr.ifr_addr; 00481 dlp->sdl_len = sizeof(struct sockaddr_dl); 00482 dlp->sdl_family = AF_LINK; 00483 dlp->sdl_index = 0; 00484 dlp->sdl_nlen = 0; 00485 dlp->sdl_alen = ETH_ALEN; 00486 dlp->sdl_slen = 0; 00487 os_memcpy(LLADDR(dlp), addr, ETH_ALEN); 00488 } 00489 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ 00490 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) 00491 { 00492 struct sockaddr *sap; 00493 sap = (struct sockaddr *) &ifr.ifr_addr; 00494 sap->sa_len = sizeof(struct sockaddr); 00495 sap->sa_family = AF_UNSPEC; 00496 os_memcpy(sap->sa_data, addr, ETH_ALEN); 00497 } 00498 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */ 00499 00500 if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) { 00501 perror("ioctl[SIOC{ADD/DEL}MULTI]"); 00502 close(s); 00503 return -1; 00504 } 00505 close(s); 00506 return 0; 00507 } 00508 00509 00510 static void * wpa_driver_wired_init(void *ctx, const char *ifname) 00511 { 00512 struct wpa_driver_wired_data *drv; 00513 int flags; 00514 00515 drv = os_zalloc(sizeof(*drv)); 00516 if (drv == NULL) 00517 return NULL; 00518 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 00519 drv->ctx = ctx; 00520 00521 #ifdef __linux__ 00522 drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0); 00523 if (drv->pf_sock < 0) 00524 perror("socket(PF_PACKET)"); 00525 #else /* __linux__ */ 00526 drv->pf_sock = -1; 00527 #endif /* __linux__ */ 00528 00529 if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 && 00530 !(flags & IFF_UP) && 00531 wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) { 00532 drv->iff_up = 1; 00533 } 00534 00535 if (wired_multicast_membership(drv->pf_sock, 00536 if_nametoindex(drv->ifname), 00537 pae_group_addr, 1) == 0) { 00538 wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " 00539 "packet socket", __func__); 00540 drv->membership = 1; 00541 } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) { 00542 wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " 00543 "SIOCADDMULTI", __func__); 00544 drv->multi = 1; 00545 } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) { 00546 wpa_printf(MSG_INFO, "%s: Could not get interface " 00547 "flags", __func__); 00548 os_free(drv); 00549 return NULL; 00550 } else if (flags & IFF_ALLMULTI) { 00551 wpa_printf(MSG_DEBUG, "%s: Interface is already configured " 00552 "for multicast", __func__); 00553 } else if (wpa_driver_wired_set_ifflags(ifname, 00554 flags | IFF_ALLMULTI) < 0) { 00555 wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", 00556 __func__); 00557 os_free(drv); 00558 return NULL; 00559 } else { 00560 wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", 00561 __func__); 00562 drv->iff_allmulti = 1; 00563 } 00564 00565 return drv; 00566 } 00567 00568 00569 static void wpa_driver_wired_deinit(void *priv) 00570 { 00571 struct wpa_driver_wired_data *drv = priv; 00572 int flags; 00573 00574 if (drv->membership && 00575 wired_multicast_membership(drv->pf_sock, 00576 if_nametoindex(drv->ifname), 00577 pae_group_addr, 0) < 0) { 00578 wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " 00579 "group (PACKET)", __func__); 00580 } 00581 00582 if (drv->multi && 00583 wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) { 00584 wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " 00585 "group (SIOCDELMULTI)", __func__); 00586 } 00587 00588 if (drv->iff_allmulti && 00589 (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 || 00590 wpa_driver_wired_set_ifflags(drv->ifname, 00591 flags & ~IFF_ALLMULTI) < 0)) { 00592 wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode", 00593 __func__); 00594 } 00595 00596 if (drv->iff_up && 00597 wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 && 00598 (flags & IFF_UP) && 00599 wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) { 00600 wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down", 00601 __func__); 00602 } 00603 00604 if (drv->pf_sock != -1) 00605 close(drv->pf_sock); 00606 00607 os_free(drv); 00608 } 00609 00610 00611 const struct wpa_driver_ops wpa_driver_wired_ops = { 00612 .name = "wired", 00613 .desc = "Wired Ethernet driver", 00614 .hapd_init = wired_driver_hapd_init, 00615 .hapd_deinit = wired_driver_hapd_deinit, 00616 .hapd_send_eapol = wired_send_eapol, 00617 .get_ssid = wpa_driver_wired_get_ssid, 00618 .get_bssid = wpa_driver_wired_get_bssid, 00619 .get_capa = wpa_driver_wired_get_capa, 00620 .init = wpa_driver_wired_init, 00621 .deinit = wpa_driver_wired_deinit, 00622 };