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