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