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