13157ba21SRui Paulo /* 2e28a4053SRui Paulo * Wired Ethernet driver interface 3e28a4053SRui Paulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * Copyright (c) 2004, Gunter Burchardt <tira@isx.de> 53157ba21SRui Paulo * 6f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 7f05cddf9SRui Paulo * See README for more details. 83157ba21SRui Paulo */ 93157ba21SRui Paulo 103157ba21SRui Paulo #include "includes.h" 11780fb4a2SCy Schubert 12780fb4a2SCy Schubert #include "common.h" 13780fb4a2SCy Schubert #include "eloop.h" 14780fb4a2SCy Schubert #include "driver.h" 1585732ac8SCy Schubert #include "driver_wired_common.h" 16780fb4a2SCy Schubert 173157ba21SRui Paulo #include <sys/ioctl.h> 18780fb4a2SCy Schubert #undef IFNAMSIZ 193157ba21SRui Paulo #include <net/if.h> 203157ba21SRui Paulo #ifdef __linux__ 213157ba21SRui Paulo #include <netpacket/packet.h> 22e28a4053SRui Paulo #include <net/if_arp.h> 233157ba21SRui Paulo #endif /* __linux__ */ 24e28a4053SRui Paulo #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 253157ba21SRui Paulo #include <net/if_dl.h> 2643673d4bSRui Paulo #include <net/if_media.h> 27e28a4053SRui Paulo #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ 28f05cddf9SRui Paulo #ifdef __sun__ 29f05cddf9SRui Paulo #include <sys/sockio.h> 30f05cddf9SRui Paulo #endif /* __sun__ */ 313157ba21SRui Paulo 32e28a4053SRui Paulo #ifdef _MSC_VER 33e28a4053SRui Paulo #pragma pack(push, 1) 34e28a4053SRui Paulo #endif /* _MSC_VER */ 35e28a4053SRui Paulo 36e28a4053SRui Paulo struct ieee8023_hdr { 37e28a4053SRui Paulo u8 dest[6]; 38e28a4053SRui Paulo u8 src[6]; 39e28a4053SRui Paulo u16 ethertype; 40e28a4053SRui Paulo } STRUCT_PACKED; 41e28a4053SRui Paulo 42e28a4053SRui Paulo #ifdef _MSC_VER 43e28a4053SRui Paulo #pragma pack(pop) 44e28a4053SRui Paulo #endif /* _MSC_VER */ 453157ba21SRui Paulo 463157ba21SRui Paulo 473157ba21SRui Paulo struct wpa_driver_wired_data { 4885732ac8SCy Schubert struct driver_wired_common_data common; 49e28a4053SRui Paulo 50e28a4053SRui Paulo int dhcp_sock; /* socket for dhcp packets */ 51e28a4053SRui Paulo int use_pae_group_addr; 523157ba21SRui Paulo }; 533157ba21SRui Paulo 543157ba21SRui Paulo 55e28a4053SRui Paulo /* TODO: detecting new devices should eventually be changed from using DHCP 56e28a4053SRui Paulo * snooping to trigger on any packet from a new layer 2 MAC address, e.g., 57e28a4053SRui Paulo * based on ebtables, etc. */ 58e28a4053SRui Paulo 59e28a4053SRui Paulo struct dhcp_message { 60e28a4053SRui Paulo u_int8_t op; 61e28a4053SRui Paulo u_int8_t htype; 62e28a4053SRui Paulo u_int8_t hlen; 63e28a4053SRui Paulo u_int8_t hops; 64e28a4053SRui Paulo u_int32_t xid; 65e28a4053SRui Paulo u_int16_t secs; 66e28a4053SRui Paulo u_int16_t flags; 67e28a4053SRui Paulo u_int32_t ciaddr; 68e28a4053SRui Paulo u_int32_t yiaddr; 69e28a4053SRui Paulo u_int32_t siaddr; 70e28a4053SRui Paulo u_int32_t giaddr; 71e28a4053SRui Paulo u_int8_t chaddr[16]; 72e28a4053SRui Paulo u_int8_t sname[64]; 73e28a4053SRui Paulo u_int8_t file[128]; 74e28a4053SRui Paulo u_int32_t cookie; 75e28a4053SRui Paulo u_int8_t options[308]; /* 312 - cookie */ 76e28a4053SRui Paulo }; 77e28a4053SRui Paulo 78e28a4053SRui Paulo 79e28a4053SRui Paulo #ifdef __linux__ 80e28a4053SRui Paulo static void handle_data(void *ctx, unsigned char *buf, size_t len) 81e28a4053SRui Paulo { 82e28a4053SRui Paulo #ifdef HOSTAPD 83e28a4053SRui Paulo struct ieee8023_hdr *hdr; 84e28a4053SRui Paulo u8 *pos, *sa; 85e28a4053SRui Paulo size_t left; 86e28a4053SRui Paulo union wpa_event_data event; 87e28a4053SRui Paulo 88e28a4053SRui Paulo /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, 89e28a4053SRui Paulo * 2 byte ethertype */ 90e28a4053SRui Paulo if (len < 14) { 91e28a4053SRui Paulo wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", 92e28a4053SRui Paulo (unsigned long) len); 93e28a4053SRui Paulo return; 94e28a4053SRui Paulo } 95e28a4053SRui Paulo 96e28a4053SRui Paulo hdr = (struct ieee8023_hdr *) buf; 97e28a4053SRui Paulo 98e28a4053SRui Paulo switch (ntohs(hdr->ethertype)) { 99e28a4053SRui Paulo case ETH_P_PAE: 100e28a4053SRui Paulo wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); 101e28a4053SRui Paulo sa = hdr->src; 102e28a4053SRui Paulo os_memset(&event, 0, sizeof(event)); 103e28a4053SRui Paulo event.new_sta.addr = sa; 104e28a4053SRui Paulo wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); 105e28a4053SRui Paulo 106e28a4053SRui Paulo pos = (u8 *) (hdr + 1); 107e28a4053SRui Paulo left = len - sizeof(*hdr); 108e28a4053SRui Paulo drv_event_eapol_rx(ctx, sa, pos, left); 109e28a4053SRui Paulo break; 110e28a4053SRui Paulo 111e28a4053SRui Paulo default: 112e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", 113e28a4053SRui Paulo ntohs(hdr->ethertype)); 114e28a4053SRui Paulo break; 115e28a4053SRui Paulo } 116e28a4053SRui Paulo #endif /* HOSTAPD */ 117e28a4053SRui Paulo } 118e28a4053SRui Paulo 119e28a4053SRui Paulo 120e28a4053SRui Paulo static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) 121e28a4053SRui Paulo { 122e28a4053SRui Paulo int len; 123e28a4053SRui Paulo unsigned char buf[3000]; 124e28a4053SRui Paulo 125e28a4053SRui Paulo len = recv(sock, buf, sizeof(buf), 0); 126e28a4053SRui Paulo if (len < 0) { 1275b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recv: %s", strerror(errno)); 128e28a4053SRui Paulo return; 129e28a4053SRui Paulo } 130e28a4053SRui Paulo 131e28a4053SRui Paulo handle_data(eloop_ctx, buf, len); 132e28a4053SRui Paulo } 133e28a4053SRui Paulo 134e28a4053SRui Paulo 135e28a4053SRui Paulo static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) 136e28a4053SRui Paulo { 137e28a4053SRui Paulo int len; 138e28a4053SRui Paulo unsigned char buf[3000]; 139e28a4053SRui Paulo struct dhcp_message *msg; 140e28a4053SRui Paulo u8 *mac_address; 141e28a4053SRui Paulo union wpa_event_data event; 142e28a4053SRui Paulo 143e28a4053SRui Paulo len = recv(sock, buf, sizeof(buf), 0); 144e28a4053SRui Paulo if (len < 0) { 1455b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recv: %s", strerror(errno)); 146e28a4053SRui Paulo return; 147e28a4053SRui Paulo } 148e28a4053SRui Paulo 149e28a4053SRui Paulo /* must contain at least dhcp_message->chaddr */ 150e28a4053SRui Paulo if (len < 44) { 151e28a4053SRui Paulo wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); 152e28a4053SRui Paulo return; 153e28a4053SRui Paulo } 154e28a4053SRui Paulo 155e28a4053SRui Paulo msg = (struct dhcp_message *) buf; 156e28a4053SRui Paulo mac_address = (u8 *) &(msg->chaddr); 157e28a4053SRui Paulo 158e28a4053SRui Paulo wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, 159e28a4053SRui Paulo MAC2STR(mac_address)); 160e28a4053SRui Paulo 161e28a4053SRui Paulo os_memset(&event, 0, sizeof(event)); 162e28a4053SRui Paulo event.new_sta.addr = mac_address; 163e28a4053SRui Paulo wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event); 164e28a4053SRui Paulo } 165e28a4053SRui Paulo #endif /* __linux__ */ 166e28a4053SRui Paulo 167e28a4053SRui Paulo 168e28a4053SRui Paulo static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) 169e28a4053SRui Paulo { 170e28a4053SRui Paulo #ifdef __linux__ 171e28a4053SRui Paulo struct ifreq ifr; 172e28a4053SRui Paulo struct sockaddr_ll addr; 173e28a4053SRui Paulo struct sockaddr_in addr2; 174e28a4053SRui Paulo int n = 1; 175e28a4053SRui Paulo 17685732ac8SCy Schubert drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); 17785732ac8SCy Schubert if (drv->common.sock < 0) { 1785b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s", 1795b9c547cSRui Paulo strerror(errno)); 180e28a4053SRui Paulo return -1; 181e28a4053SRui Paulo } 182e28a4053SRui Paulo 18385732ac8SCy Schubert if (eloop_register_read_sock(drv->common.sock, handle_read, 18485732ac8SCy Schubert drv->common.ctx, NULL)) { 1855b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not register read socket"); 186e28a4053SRui Paulo return -1; 187e28a4053SRui Paulo } 188e28a4053SRui Paulo 189e28a4053SRui Paulo os_memset(&ifr, 0, sizeof(ifr)); 19085732ac8SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name)); 19185732ac8SCy Schubert if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) { 1925b9c547cSRui Paulo wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s", 1935b9c547cSRui Paulo strerror(errno)); 194e28a4053SRui Paulo return -1; 195e28a4053SRui Paulo } 196e28a4053SRui Paulo 197e28a4053SRui Paulo os_memset(&addr, 0, sizeof(addr)); 198e28a4053SRui Paulo addr.sll_family = AF_PACKET; 199e28a4053SRui Paulo addr.sll_ifindex = ifr.ifr_ifindex; 200e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", 201e28a4053SRui Paulo addr.sll_ifindex); 202e28a4053SRui Paulo 20385732ac8SCy Schubert if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) 20485732ac8SCy Schubert { 2055b9c547cSRui Paulo wpa_printf(MSG_ERROR, "bind: %s", strerror(errno)); 206e28a4053SRui Paulo return -1; 207e28a4053SRui Paulo } 208e28a4053SRui Paulo 209e28a4053SRui Paulo /* filter multicast address */ 21085732ac8SCy Schubert if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex, 211e28a4053SRui Paulo pae_group_addr, 1) < 0) { 212e28a4053SRui Paulo wpa_printf(MSG_ERROR, "wired: Failed to add multicast group " 213e28a4053SRui Paulo "membership"); 214e28a4053SRui Paulo return -1; 215e28a4053SRui Paulo } 216e28a4053SRui Paulo 217e28a4053SRui Paulo os_memset(&ifr, 0, sizeof(ifr)); 21885732ac8SCy Schubert os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name)); 21985732ac8SCy Schubert if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) { 2205b9c547cSRui Paulo wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s", 2215b9c547cSRui Paulo strerror(errno)); 222e28a4053SRui Paulo return -1; 223e28a4053SRui Paulo } 224e28a4053SRui Paulo 225e28a4053SRui Paulo if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 2265b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x", 227e28a4053SRui Paulo ifr.ifr_hwaddr.sa_family); 228e28a4053SRui Paulo return -1; 229e28a4053SRui Paulo } 230e28a4053SRui Paulo os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 231e28a4053SRui Paulo 232e28a4053SRui Paulo /* setup dhcp listen socket for sta detection */ 233e28a4053SRui Paulo if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 2345b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket call failed for dhcp: %s", 2355b9c547cSRui Paulo strerror(errno)); 236e28a4053SRui Paulo return -1; 237e28a4053SRui Paulo } 238e28a4053SRui Paulo 23985732ac8SCy Schubert if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, 24085732ac8SCy Schubert drv->common.ctx, NULL)) { 2415b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not register read socket"); 242e28a4053SRui Paulo return -1; 243e28a4053SRui Paulo } 244e28a4053SRui Paulo 245e28a4053SRui Paulo os_memset(&addr2, 0, sizeof(addr2)); 246e28a4053SRui Paulo addr2.sin_family = AF_INET; 247e28a4053SRui Paulo addr2.sin_port = htons(67); 248e28a4053SRui Paulo addr2.sin_addr.s_addr = INADDR_ANY; 249e28a4053SRui Paulo 250e28a4053SRui Paulo if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, 251e28a4053SRui Paulo sizeof(n)) == -1) { 2525b9c547cSRui Paulo wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_REUSEADDR]: %s", 2535b9c547cSRui Paulo strerror(errno)); 254e28a4053SRui Paulo return -1; 255e28a4053SRui Paulo } 256e28a4053SRui Paulo if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, 257e28a4053SRui Paulo sizeof(n)) == -1) { 2585b9c547cSRui Paulo wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_BROADCAST]: %s", 2595b9c547cSRui Paulo strerror(errno)); 260e28a4053SRui Paulo return -1; 261e28a4053SRui Paulo } 262e28a4053SRui Paulo 263e28a4053SRui Paulo os_memset(&ifr, 0, sizeof(ifr)); 26485732ac8SCy Schubert os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->common.ifname, IFNAMSIZ); 265e28a4053SRui Paulo if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, 266e28a4053SRui Paulo (char *) &ifr, sizeof(ifr)) < 0) { 2675b9c547cSRui Paulo wpa_printf(MSG_ERROR, 2685b9c547cSRui Paulo "setsockopt[SOL_SOCKET,SO_BINDTODEVICE]: %s", 2695b9c547cSRui Paulo strerror(errno)); 270e28a4053SRui Paulo return -1; 271e28a4053SRui Paulo } 272e28a4053SRui Paulo 273e28a4053SRui Paulo if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, 274e28a4053SRui Paulo sizeof(struct sockaddr)) == -1) { 2755b9c547cSRui Paulo wpa_printf(MSG_ERROR, "bind: %s", strerror(errno)); 276e28a4053SRui Paulo return -1; 277e28a4053SRui Paulo } 278e28a4053SRui Paulo 279e28a4053SRui Paulo return 0; 280e28a4053SRui Paulo #else /* __linux__ */ 281e28a4053SRui Paulo return -1; 282e28a4053SRui Paulo #endif /* __linux__ */ 283e28a4053SRui Paulo } 284e28a4053SRui Paulo 285e28a4053SRui Paulo 286e28a4053SRui Paulo static int wired_send_eapol(void *priv, const u8 *addr, 287e28a4053SRui Paulo const u8 *data, size_t data_len, int encrypt, 288*a90b9d01SCy Schubert const u8 *own_addr, u32 flags, int link_id) 289e28a4053SRui Paulo { 290e28a4053SRui Paulo struct wpa_driver_wired_data *drv = priv; 291e28a4053SRui Paulo struct ieee8023_hdr *hdr; 292e28a4053SRui Paulo size_t len; 293e28a4053SRui Paulo u8 *pos; 294e28a4053SRui Paulo int res; 295e28a4053SRui Paulo 296e28a4053SRui Paulo len = sizeof(*hdr) + data_len; 297e28a4053SRui Paulo hdr = os_zalloc(len); 298e28a4053SRui Paulo if (hdr == NULL) { 2995b9c547cSRui Paulo wpa_printf(MSG_INFO, 3005b9c547cSRui Paulo "malloc() failed for wired_send_eapol(len=%lu)", 301e28a4053SRui Paulo (unsigned long) len); 302e28a4053SRui Paulo return -1; 303e28a4053SRui Paulo } 304e28a4053SRui Paulo 305e28a4053SRui Paulo os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, 306e28a4053SRui Paulo ETH_ALEN); 307e28a4053SRui Paulo os_memcpy(hdr->src, own_addr, ETH_ALEN); 308e28a4053SRui Paulo hdr->ethertype = htons(ETH_P_PAE); 309e28a4053SRui Paulo 310e28a4053SRui Paulo pos = (u8 *) (hdr + 1); 311e28a4053SRui Paulo os_memcpy(pos, data, data_len); 312e28a4053SRui Paulo 31385732ac8SCy Schubert res = send(drv->common.sock, (u8 *) hdr, len, 0); 314e28a4053SRui Paulo os_free(hdr); 315e28a4053SRui Paulo 316e28a4053SRui Paulo if (res < 0) { 3175b9c547cSRui Paulo wpa_printf(MSG_ERROR, 3185b9c547cSRui Paulo "wired_send_eapol - packet len: %lu - failed: send: %s", 3195b9c547cSRui Paulo (unsigned long) len, strerror(errno)); 320e28a4053SRui Paulo } 321e28a4053SRui Paulo 322e28a4053SRui Paulo return res; 323e28a4053SRui Paulo } 324e28a4053SRui Paulo 325e28a4053SRui Paulo 326e28a4053SRui Paulo static void * wired_driver_hapd_init(struct hostapd_data *hapd, 327e28a4053SRui Paulo struct wpa_init_params *params) 328e28a4053SRui Paulo { 329e28a4053SRui Paulo struct wpa_driver_wired_data *drv; 330e28a4053SRui Paulo 331e28a4053SRui Paulo drv = os_zalloc(sizeof(struct wpa_driver_wired_data)); 332e28a4053SRui Paulo if (drv == NULL) { 3335b9c547cSRui Paulo wpa_printf(MSG_INFO, 3345b9c547cSRui Paulo "Could not allocate memory for wired driver data"); 335e28a4053SRui Paulo return NULL; 336e28a4053SRui Paulo } 337e28a4053SRui Paulo 33885732ac8SCy Schubert drv->common.ctx = hapd; 33985732ac8SCy Schubert os_strlcpy(drv->common.ifname, params->ifname, 34085732ac8SCy Schubert sizeof(drv->common.ifname)); 341e28a4053SRui Paulo drv->use_pae_group_addr = params->use_pae_group_addr; 342e28a4053SRui Paulo 343e28a4053SRui Paulo if (wired_init_sockets(drv, params->own_addr)) { 344e28a4053SRui Paulo os_free(drv); 345e28a4053SRui Paulo return NULL; 346e28a4053SRui Paulo } 347e28a4053SRui Paulo 348e28a4053SRui Paulo return drv; 349e28a4053SRui Paulo } 350e28a4053SRui Paulo 351e28a4053SRui Paulo 352e28a4053SRui Paulo static void wired_driver_hapd_deinit(void *priv) 353e28a4053SRui Paulo { 354e28a4053SRui Paulo struct wpa_driver_wired_data *drv = priv; 355e28a4053SRui Paulo 35685732ac8SCy Schubert if (drv->common.sock >= 0) { 35785732ac8SCy Schubert eloop_unregister_read_sock(drv->common.sock); 35885732ac8SCy Schubert close(drv->common.sock); 3595b9c547cSRui Paulo } 360e28a4053SRui Paulo 3615b9c547cSRui Paulo if (drv->dhcp_sock >= 0) { 3625b9c547cSRui Paulo eloop_unregister_read_sock(drv->dhcp_sock); 363e28a4053SRui Paulo close(drv->dhcp_sock); 3645b9c547cSRui Paulo } 365e28a4053SRui Paulo 366e28a4053SRui Paulo os_free(drv); 367e28a4053SRui Paulo } 368e28a4053SRui Paulo 369e28a4053SRui Paulo 3703157ba21SRui Paulo static void * wpa_driver_wired_init(void *ctx, const char *ifname) 3713157ba21SRui Paulo { 3723157ba21SRui Paulo struct wpa_driver_wired_data *drv; 3733157ba21SRui Paulo 3743157ba21SRui Paulo drv = os_zalloc(sizeof(*drv)); 3753157ba21SRui Paulo if (drv == NULL) 3763157ba21SRui Paulo return NULL; 3773157ba21SRui Paulo 37885732ac8SCy Schubert if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) { 3793157ba21SRui Paulo os_free(drv); 3803157ba21SRui Paulo return NULL; 3813157ba21SRui Paulo } 3823157ba21SRui Paulo 3833157ba21SRui Paulo return drv; 3843157ba21SRui Paulo } 3853157ba21SRui Paulo 3863157ba21SRui Paulo 3873157ba21SRui Paulo static void wpa_driver_wired_deinit(void *priv) 3883157ba21SRui Paulo { 3893157ba21SRui Paulo struct wpa_driver_wired_data *drv = priv; 3903157ba21SRui Paulo 39185732ac8SCy Schubert driver_wired_deinit_common(&drv->common); 3923157ba21SRui Paulo os_free(drv); 3933157ba21SRui Paulo } 3943157ba21SRui Paulo 3953157ba21SRui Paulo 3963157ba21SRui Paulo const struct wpa_driver_ops wpa_driver_wired_ops = { 3973157ba21SRui Paulo .name = "wired", 398e28a4053SRui Paulo .desc = "Wired Ethernet driver", 399e28a4053SRui Paulo .hapd_init = wired_driver_hapd_init, 400e28a4053SRui Paulo .hapd_deinit = wired_driver_hapd_deinit, 401e28a4053SRui Paulo .hapd_send_eapol = wired_send_eapol, 40285732ac8SCy Schubert .get_ssid = driver_wired_get_ssid, 40385732ac8SCy Schubert .get_bssid = driver_wired_get_bssid, 40485732ac8SCy Schubert .get_capa = driver_wired_get_capa, 4053157ba21SRui Paulo .init = wpa_driver_wired_init, 4063157ba21SRui Paulo .deinit = wpa_driver_wired_deinit, 4073157ba21SRui Paulo }; 408