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