1/* 2 * Wired Ethernet driver interface 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 10#include "includes.h" 11#include <sys/ioctl.h> 12#include <net/if.h> 13#ifdef __linux__ 14#include <netpacket/packet.h> 15#include <net/if_arp.h> 16#include <net/if.h> 17#endif /* __linux__ */ 18#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 19#include <net/if_dl.h> 20#include <net/if_media.h> 21#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ 22#ifdef __sun__ 23#include <sys/sockio.h> 24#endif /* __sun__ */ 25 26#include "common.h" 27#include "eloop.h" 28#include "driver.h" 29 30#ifdef _MSC_VER 31#pragma pack(push, 1) 32#endif /* _MSC_VER */ 33 34struct ieee8023_hdr { 35 u8 dest[6]; 36 u8 src[6]; 37 u16 ethertype; 38} STRUCT_PACKED; 39 40#ifdef _MSC_VER 41#pragma pack(pop) 42#endif /* _MSC_VER */ 43 44static const u8 pae_group_addr[ETH_ALEN] = 45{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; 46 47 48struct wpa_driver_wired_data { 49 char ifname[IFNAMSIZ + 1]; 50 void *ctx; 51 52 int sock; /* raw packet socket for driver access */ 53 int dhcp_sock; /* socket for dhcp packets */ 54 int use_pae_group_addr; 55 56 int pf_sock; 57 int membership, multi, iff_allmulti, iff_up; 58}; 59 60 61/* TODO: detecting new devices should eventually be changed from using DHCP 62 * snooping to trigger on any packet from a new layer 2 MAC address, e.g., 63 * based on ebtables, etc. */ 64 65struct dhcp_message { 66 u_int8_t op; 67 u_int8_t htype; 68 u_int8_t hlen; 69 u_int8_t hops; 70 u_int32_t xid; 71 u_int16_t secs; 72 u_int16_t flags; 73 u_int32_t ciaddr; 74 u_int32_t yiaddr; 75 u_int32_t siaddr; 76 u_int32_t giaddr; 77 u_int8_t chaddr[16]; 78 u_int8_t sname[64]; 79 u_int8_t file[128]; 80 u_int32_t cookie; 81 u_int8_t options[308]; /* 312 - cookie */ 82}; 83 84 85static int wired_multicast_membership(int sock, int ifindex, 86 const u8 *addr, int add) 87{ 88#ifdef __linux__ 89 struct packet_mreq mreq; 90 91 if (sock < 0) 92 return -1; 93 94 os_memset(&mreq, 0, sizeof(mreq)); 95 mreq.mr_ifindex = ifindex; 96 mreq.mr_type = PACKET_MR_MULTICAST; 97 mreq.mr_alen = ETH_ALEN; 98 os_memcpy(mreq.mr_address, addr, ETH_ALEN); 99 100 if (setsockopt(sock, SOL_PACKET, 101 add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, 102 &mreq, sizeof(mreq)) < 0) { 103 perror("setsockopt"); 104 return -1; 105 } 106 return 0; 107#else /* __linux__ */ 108 return -1; 109#endif /* __linux__ */ 110} 111 112 113#ifdef __linux__ 114static void handle_data(void *ctx, unsigned char *buf, size_t len) 115{ 116#ifdef HOSTAPD 117 struct ieee8023_hdr *hdr; 118 u8 *pos, *sa; 119 size_t left; 120 union wpa_event_data event; 121 122 /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, 123 * 2 byte ethertype */ 124 if (len < 14) { 125 wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", 126 (unsigned long) len); 127 return; 128 } 129 130 hdr = (struct ieee8023_hdr *) buf; 131 132 switch (ntohs(hdr->ethertype)) { 133 case ETH_P_PAE: 134 wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); 135 sa = hdr->src; 136 os_memset(&event, 0, sizeof(event)); 137 event.new_sta.addr = sa; 138 wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); 139 140 pos = (u8 *) (hdr + 1); 141 left = len - sizeof(*hdr); 142 drv_event_eapol_rx(ctx, sa, pos, left); 143 break; 144 145 default: 146 wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", 147 ntohs(hdr->ethertype)); 148 break; 149 } 150#endif /* HOSTAPD */ 151} 152 153 154static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) 155{ 156 int len; 157 unsigned char buf[3000]; 158 159 len = recv(sock, buf, sizeof(buf), 0); 160 if (len < 0) { 161 perror("recv"); 162 return; 163 } 164 165 handle_data(eloop_ctx, buf, len); 166} 167 168 169static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) 170{ 171 int len; 172 unsigned char buf[3000]; 173 struct dhcp_message *msg; 174 u8 *mac_address; 175 union wpa_event_data event; 176 177 len = recv(sock, buf, sizeof(buf), 0); 178 if (len < 0) { 179 perror("recv"); 180 return; 181 } 182 183 /* must contain at least dhcp_message->chaddr */ 184 if (len < 44) { 185 wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); 186 return; 187 } 188 189 msg = (struct dhcp_message *) buf; 190 mac_address = (u8 *) &(msg->chaddr); 191 192 wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, 193 MAC2STR(mac_address)); 194 195 os_memset(&event, 0, sizeof(event)); 196 event.new_sta.addr = mac_address; 197 wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event); 198} 199#endif /* __linux__ */ 200 201 202static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) 203{ 204#ifdef __linux__ 205 struct ifreq ifr; 206 struct sockaddr_ll addr; 207 struct sockaddr_in addr2; 208 int n = 1; 209 210 drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); 211 if (drv->sock < 0) { 212 perror("socket[PF_PACKET,SOCK_RAW]"); 213 return -1; 214 } 215 216 if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) { 217 printf("Could not register read socket\n"); 218 return -1; 219 } 220 221 os_memset(&ifr, 0, sizeof(ifr)); 222 os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 223 if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { 224 perror("ioctl(SIOCGIFINDEX)"); 225 return -1; 226 } 227 228 os_memset(&addr, 0, sizeof(addr)); 229 addr.sll_family = AF_PACKET; 230 addr.sll_ifindex = ifr.ifr_ifindex; 231 wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", 232 addr.sll_ifindex); 233 234 if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 235 perror("bind"); 236 return -1; 237 } 238 239 /* filter multicast address */ 240 if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex, 241 pae_group_addr, 1) < 0) { 242 wpa_printf(MSG_ERROR, "wired: Failed to add multicast group " 243 "membership"); 244 return -1; 245 } 246 247 os_memset(&ifr, 0, sizeof(ifr)); 248 os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 249 if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { 250 perror("ioctl(SIOCGIFHWADDR)"); 251 return -1; 252 } 253 254 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 255 printf("Invalid HW-addr family 0x%04x\n", 256 ifr.ifr_hwaddr.sa_family); 257 return -1; 258 } 259 os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 260 261 /* setup dhcp listen socket for sta detection */ 262 if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 263 perror("socket call failed for dhcp"); 264 return -1; 265 } 266 267 if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx, 268 NULL)) { 269 printf("Could not register read socket\n"); 270 return -1; 271 } 272 273 os_memset(&addr2, 0, sizeof(addr2)); 274 addr2.sin_family = AF_INET; 275 addr2.sin_port = htons(67); 276 addr2.sin_addr.s_addr = INADDR_ANY; 277 278 if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, 279 sizeof(n)) == -1) { 280 perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]"); 281 return -1; 282 } 283 if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, 284 sizeof(n)) == -1) { 285 perror("setsockopt[SOL_SOCKET,SO_BROADCAST]"); 286 return -1; 287 } 288 289 os_memset(&ifr, 0, sizeof(ifr)); 290 os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ); 291 if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, 292 (char *) &ifr, sizeof(ifr)) < 0) { 293 perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]"); 294 return -1; 295 } 296 297 if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, 298 sizeof(struct sockaddr)) == -1) { 299 perror("bind"); 300 return -1; 301 } 302 303 return 0; 304#else /* __linux__ */ 305 return -1; 306#endif /* __linux__ */ 307} 308 309 310static int wired_send_eapol(void *priv, const u8 *addr, 311 const u8 *data, size_t data_len, int encrypt, 312 const u8 *own_addr, u32 flags) 313{ 314 struct wpa_driver_wired_data *drv = priv; 315 struct ieee8023_hdr *hdr; 316 size_t len; 317 u8 *pos; 318 int res; 319 320 len = sizeof(*hdr) + data_len; 321 hdr = os_zalloc(len); 322 if (hdr == NULL) { 323 printf("malloc() failed for wired_send_eapol(len=%lu)\n", 324 (unsigned long) len); 325 return -1; 326 } 327 328 os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, 329 ETH_ALEN); 330 os_memcpy(hdr->src, own_addr, ETH_ALEN); 331 hdr->ethertype = htons(ETH_P_PAE); 332 333 pos = (u8 *) (hdr + 1); 334 os_memcpy(pos, data, data_len); 335 336 res = send(drv->sock, (u8 *) hdr, len, 0); 337 os_free(hdr); 338 339 if (res < 0) { 340 perror("wired_send_eapol: send"); 341 printf("wired_send_eapol - packet len: %lu - failed\n", 342 (unsigned long) len); 343 } 344 345 return res; 346} 347 348 349static void * wired_driver_hapd_init(struct hostapd_data *hapd, 350 struct wpa_init_params *params) 351{ 352 struct wpa_driver_wired_data *drv; 353 354 drv = os_zalloc(sizeof(struct wpa_driver_wired_data)); 355 if (drv == NULL) { 356 printf("Could not allocate memory for wired driver data\n"); 357 return NULL; 358 } 359 360 drv->ctx = hapd; 361 os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); 362 drv->use_pae_group_addr = params->use_pae_group_addr; 363 364 if (wired_init_sockets(drv, params->own_addr)) { 365 os_free(drv); 366 return NULL; 367 } 368 369 return drv; 370} 371 372 373static void wired_driver_hapd_deinit(void *priv) 374{ 375 struct wpa_driver_wired_data *drv = priv; 376 377 if (drv->sock >= 0) 378 close(drv->sock); 379 380 if (drv->dhcp_sock >= 0) 381 close(drv->dhcp_sock); 382 383 os_free(drv); 384} 385 386 387static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid) 388{ 389 ssid[0] = 0; 390 return 0; 391} 392 393 394static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid) 395{ 396 /* Report PAE group address as the "BSSID" for wired connection. */ 397 os_memcpy(bssid, pae_group_addr, ETH_ALEN); 398 return 0; 399} 400 401 402static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa) 403{ 404 os_memset(capa, 0, sizeof(*capa)); 405 capa->flags = WPA_DRIVER_FLAGS_WIRED; 406 return 0; 407} 408 409 410static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags) 411{ 412 struct ifreq ifr; 413 int s; 414 415 s = socket(PF_INET, SOCK_DGRAM, 0); 416 if (s < 0) { 417 perror("socket"); 418 return -1; 419 } 420 421 os_memset(&ifr, 0, sizeof(ifr)); 422 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 423 if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 424 perror("ioctl[SIOCGIFFLAGS]"); 425 close(s); 426 return -1; 427 } 428 close(s); 429 *flags = ifr.ifr_flags & 0xffff; 430 return 0; 431} 432 433 434static int wpa_driver_wired_set_ifflags(const char *ifname, int flags) 435{ 436 struct ifreq ifr; 437 int s; 438 439 s = socket(PF_INET, SOCK_DGRAM, 0); 440 if (s < 0) { 441 perror("socket"); 442 return -1; 443 } 444 445 os_memset(&ifr, 0, sizeof(ifr)); 446 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 447 ifr.ifr_flags = flags & 0xffff; 448 if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 449 perror("ioctl[SIOCSIFFLAGS]"); 450 close(s); 451 return -1; 452 } 453 close(s); 454 return 0; 455} 456 457 458#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 459static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status) 460{ 461 struct ifmediareq ifmr; 462 int s; 463 464 s = socket(PF_INET, SOCK_DGRAM, 0); 465 if (s < 0) { 466 perror("socket"); 467 return -1; 468 } 469 470 os_memset(&ifmr, 0, sizeof(ifmr)); 471 os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ); 472 if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) { 473 perror("ioctl[SIOCGIFMEDIA]"); 474 close(s); 475 return -1; 476 } 477 close(s); 478 *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) == 479 (IFM_ACTIVE | IFM_AVALID); 480 481 return 0; 482} 483#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ 484 485 486static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) 487{ 488 struct ifreq ifr; 489 int s; 490 491#ifdef __sun__ 492 return -1; 493#endif /* __sun__ */ 494 495 s = socket(PF_INET, SOCK_DGRAM, 0); 496 if (s < 0) { 497 perror("socket"); 498 return -1; 499 } 500 501 os_memset(&ifr, 0, sizeof(ifr)); 502 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 503#ifdef __linux__ 504 ifr.ifr_hwaddr.sa_family = AF_UNSPEC; 505 os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); 506#endif /* __linux__ */ 507#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 508 { 509 struct sockaddr_dl *dlp; 510 dlp = (struct sockaddr_dl *) &ifr.ifr_addr; 511 dlp->sdl_len = sizeof(struct sockaddr_dl); 512 dlp->sdl_family = AF_LINK; 513 dlp->sdl_index = 0; 514 dlp->sdl_nlen = 0; 515 dlp->sdl_alen = ETH_ALEN; 516 dlp->sdl_slen = 0; 517 os_memcpy(LLADDR(dlp), addr, ETH_ALEN); 518 } 519#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ 520#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) 521 { 522 struct sockaddr *sap; 523 sap = (struct sockaddr *) &ifr.ifr_addr; 524 sap->sa_len = sizeof(struct sockaddr); 525 sap->sa_family = AF_UNSPEC; 526 os_memcpy(sap->sa_data, addr, ETH_ALEN); 527 } 528#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */ 529 530 if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) { 531 perror("ioctl[SIOC{ADD/DEL}MULTI]"); 532 close(s); 533 return -1; 534 } 535 close(s); 536 return 0; 537} 538 539 540static void * wpa_driver_wired_init(void *ctx, const char *ifname) 541{ 542 struct wpa_driver_wired_data *drv; 543 int flags; 544 545 drv = os_zalloc(sizeof(*drv)); 546 if (drv == NULL) 547 return NULL; 548 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 549 drv->ctx = ctx; 550 551#ifdef __linux__ 552 drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0); 553 if (drv->pf_sock < 0) 554 perror("socket(PF_PACKET)"); 555#else /* __linux__ */ 556 drv->pf_sock = -1; 557#endif /* __linux__ */ 558 559 if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 && 560 !(flags & IFF_UP) && 561 wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) { 562 drv->iff_up = 1; 563 } 564 565 if (wired_multicast_membership(drv->pf_sock, 566 if_nametoindex(drv->ifname), 567 pae_group_addr, 1) == 0) { 568 wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " 569 "packet socket", __func__); 570 drv->membership = 1; 571 } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) { 572 wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " 573 "SIOCADDMULTI", __func__); 574 drv->multi = 1; 575 } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) { 576 wpa_printf(MSG_INFO, "%s: Could not get interface " 577 "flags", __func__); 578 os_free(drv); 579 return NULL; 580 } else if (flags & IFF_ALLMULTI) { 581 wpa_printf(MSG_DEBUG, "%s: Interface is already configured " 582 "for multicast", __func__); 583 } else if (wpa_driver_wired_set_ifflags(ifname, 584 flags | IFF_ALLMULTI) < 0) { 585 wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", 586 __func__); 587 os_free(drv); 588 return NULL; 589 } else { 590 wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", 591 __func__); 592 drv->iff_allmulti = 1; 593 } 594#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 595 { 596 int status; 597 wpa_printf(MSG_DEBUG, "%s: waiting for link to become active", 598 __func__); 599 while (wpa_driver_wired_get_ifstatus(ifname, &status) == 0 && 600 status == 0) 601 sleep(1); 602 } 603#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ 604 605 return drv; 606} 607 608 609static void wpa_driver_wired_deinit(void *priv) 610{ 611 struct wpa_driver_wired_data *drv = priv; 612 int flags; 613 614 if (drv->membership && 615 wired_multicast_membership(drv->pf_sock, 616 if_nametoindex(drv->ifname), 617 pae_group_addr, 0) < 0) { 618 wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " 619 "group (PACKET)", __func__); 620 } 621 622 if (drv->multi && 623 wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) { 624 wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " 625 "group (SIOCDELMULTI)", __func__); 626 } 627 628 if (drv->iff_allmulti && 629 (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 || 630 wpa_driver_wired_set_ifflags(drv->ifname, 631 flags & ~IFF_ALLMULTI) < 0)) { 632 wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode", 633 __func__); 634 } 635 636 if (drv->iff_up && 637 wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 && 638 (flags & IFF_UP) && 639 wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) { 640 wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down", 641 __func__); 642 } 643 644 if (drv->pf_sock != -1) 645 close(drv->pf_sock); 646 647 os_free(drv); 648} 649 650 651const struct wpa_driver_ops wpa_driver_wired_ops = { 652 .name = "wired", 653 .desc = "Wired Ethernet driver", 654 .hapd_init = wired_driver_hapd_init, 655 .hapd_deinit = wired_driver_hapd_deinit, 656 .hapd_send_eapol = wired_send_eapol, 657 .get_ssid = wpa_driver_wired_get_ssid, 658 .get_bssid = wpa_driver_wired_get_bssid, 659 .get_capa = wpa_driver_wired_get_capa, 660 .init = wpa_driver_wired_init, 661 .deinit = wpa_driver_wired_deinit, 662}; 663