1*85732ac8SCy Schubert /* 2*85732ac8SCy Schubert * Common functions for Wired Ethernet driver interfaces 3*85732ac8SCy Schubert * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4*85732ac8SCy Schubert * Copyright (c) 2004, Gunter Burchardt <tira@isx.de> 5*85732ac8SCy Schubert * 6*85732ac8SCy Schubert * This software may be distributed under the terms of the BSD license. 7*85732ac8SCy Schubert * See README for more details. 8*85732ac8SCy Schubert */ 9*85732ac8SCy Schubert 10*85732ac8SCy Schubert #include "includes.h" 11*85732ac8SCy Schubert 12*85732ac8SCy Schubert #include "common.h" 13*85732ac8SCy Schubert #include "eloop.h" 14*85732ac8SCy Schubert #include "driver.h" 15*85732ac8SCy Schubert #include "driver_wired_common.h" 16*85732ac8SCy Schubert 17*85732ac8SCy Schubert #include <sys/ioctl.h> 18*85732ac8SCy Schubert #include <net/if.h> 19*85732ac8SCy Schubert #ifdef __linux__ 20*85732ac8SCy Schubert #include <netpacket/packet.h> 21*85732ac8SCy Schubert #include <net/if_arp.h> 22*85732ac8SCy Schubert #include <net/if.h> 23*85732ac8SCy Schubert #endif /* __linux__ */ 24*85732ac8SCy Schubert #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 25*85732ac8SCy Schubert #include <net/if_dl.h> 26*85732ac8SCy Schubert #include <net/if_media.h> 27*85732ac8SCy Schubert #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ 28*85732ac8SCy Schubert #ifdef __sun__ 29*85732ac8SCy Schubert #include <sys/sockio.h> 30*85732ac8SCy Schubert #endif /* __sun__ */ 31*85732ac8SCy Schubert 32*85732ac8SCy Schubert 33*85732ac8SCy Schubert static int driver_wired_get_ifflags(const char *ifname, int *flags) 34*85732ac8SCy Schubert { 35*85732ac8SCy Schubert struct ifreq ifr; 36*85732ac8SCy Schubert int s; 37*85732ac8SCy Schubert 38*85732ac8SCy Schubert s = socket(PF_INET, SOCK_DGRAM, 0); 39*85732ac8SCy Schubert if (s < 0) { 40*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "socket: %s", strerror(errno)); 41*85732ac8SCy Schubert return -1; 42*85732ac8SCy Schubert } 43*85732ac8SCy Schubert 44*85732ac8SCy Schubert os_memset(&ifr, 0, sizeof(ifr)); 45*85732ac8SCy Schubert os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 46*85732ac8SCy Schubert if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { 47*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s", 48*85732ac8SCy Schubert strerror(errno)); 49*85732ac8SCy Schubert close(s); 50*85732ac8SCy Schubert return -1; 51*85732ac8SCy Schubert } 52*85732ac8SCy Schubert close(s); 53*85732ac8SCy Schubert *flags = ifr.ifr_flags & 0xffff; 54*85732ac8SCy Schubert return 0; 55*85732ac8SCy Schubert } 56*85732ac8SCy Schubert 57*85732ac8SCy Schubert 58*85732ac8SCy Schubert static int driver_wired_set_ifflags(const char *ifname, int flags) 59*85732ac8SCy Schubert { 60*85732ac8SCy Schubert struct ifreq ifr; 61*85732ac8SCy Schubert int s; 62*85732ac8SCy Schubert 63*85732ac8SCy Schubert s = socket(PF_INET, SOCK_DGRAM, 0); 64*85732ac8SCy Schubert if (s < 0) { 65*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "socket: %s", strerror(errno)); 66*85732ac8SCy Schubert return -1; 67*85732ac8SCy Schubert } 68*85732ac8SCy Schubert 69*85732ac8SCy Schubert os_memset(&ifr, 0, sizeof(ifr)); 70*85732ac8SCy Schubert os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 71*85732ac8SCy Schubert ifr.ifr_flags = flags & 0xffff; 72*85732ac8SCy Schubert if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { 73*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s", 74*85732ac8SCy Schubert strerror(errno)); 75*85732ac8SCy Schubert close(s); 76*85732ac8SCy Schubert return -1; 77*85732ac8SCy Schubert } 78*85732ac8SCy Schubert close(s); 79*85732ac8SCy Schubert return 0; 80*85732ac8SCy Schubert } 81*85732ac8SCy Schubert 82*85732ac8SCy Schubert 83*85732ac8SCy Schubert static int driver_wired_multi(const char *ifname, const u8 *addr, int add) 84*85732ac8SCy Schubert { 85*85732ac8SCy Schubert struct ifreq ifr; 86*85732ac8SCy Schubert int s; 87*85732ac8SCy Schubert 88*85732ac8SCy Schubert #ifdef __sun__ 89*85732ac8SCy Schubert return -1; 90*85732ac8SCy Schubert #endif /* __sun__ */ 91*85732ac8SCy Schubert 92*85732ac8SCy Schubert s = socket(PF_INET, SOCK_DGRAM, 0); 93*85732ac8SCy Schubert if (s < 0) { 94*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "socket: %s", strerror(errno)); 95*85732ac8SCy Schubert return -1; 96*85732ac8SCy Schubert } 97*85732ac8SCy Schubert 98*85732ac8SCy Schubert os_memset(&ifr, 0, sizeof(ifr)); 99*85732ac8SCy Schubert os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 100*85732ac8SCy Schubert #ifdef __linux__ 101*85732ac8SCy Schubert ifr.ifr_hwaddr.sa_family = AF_UNSPEC; 102*85732ac8SCy Schubert os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); 103*85732ac8SCy Schubert #endif /* __linux__ */ 104*85732ac8SCy Schubert #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 105*85732ac8SCy Schubert { 106*85732ac8SCy Schubert struct sockaddr_dl *dlp; 107*85732ac8SCy Schubert 108*85732ac8SCy Schubert dlp = (struct sockaddr_dl *) &ifr.ifr_addr; 109*85732ac8SCy Schubert dlp->sdl_len = sizeof(struct sockaddr_dl); 110*85732ac8SCy Schubert dlp->sdl_family = AF_LINK; 111*85732ac8SCy Schubert dlp->sdl_index = 0; 112*85732ac8SCy Schubert dlp->sdl_nlen = 0; 113*85732ac8SCy Schubert dlp->sdl_alen = ETH_ALEN; 114*85732ac8SCy Schubert dlp->sdl_slen = 0; 115*85732ac8SCy Schubert os_memcpy(LLADDR(dlp), addr, ETH_ALEN); 116*85732ac8SCy Schubert } 117*85732ac8SCy Schubert #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ 118*85732ac8SCy Schubert #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) 119*85732ac8SCy Schubert { 120*85732ac8SCy Schubert struct sockaddr *sap; 121*85732ac8SCy Schubert 122*85732ac8SCy Schubert sap = (struct sockaddr *) &ifr.ifr_addr; 123*85732ac8SCy Schubert sap->sa_len = sizeof(struct sockaddr); 124*85732ac8SCy Schubert sap->sa_family = AF_UNSPEC; 125*85732ac8SCy Schubert os_memcpy(sap->sa_data, addr, ETH_ALEN); 126*85732ac8SCy Schubert } 127*85732ac8SCy Schubert #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */ 128*85732ac8SCy Schubert 129*85732ac8SCy Schubert if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) { 130*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s", 131*85732ac8SCy Schubert strerror(errno)); 132*85732ac8SCy Schubert close(s); 133*85732ac8SCy Schubert return -1; 134*85732ac8SCy Schubert } 135*85732ac8SCy Schubert close(s); 136*85732ac8SCy Schubert return 0; 137*85732ac8SCy Schubert } 138*85732ac8SCy Schubert 139*85732ac8SCy Schubert 140*85732ac8SCy Schubert int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add) 141*85732ac8SCy Schubert { 142*85732ac8SCy Schubert #ifdef __linux__ 143*85732ac8SCy Schubert struct packet_mreq mreq; 144*85732ac8SCy Schubert 145*85732ac8SCy Schubert if (sock < 0) 146*85732ac8SCy Schubert return -1; 147*85732ac8SCy Schubert 148*85732ac8SCy Schubert os_memset(&mreq, 0, sizeof(mreq)); 149*85732ac8SCy Schubert mreq.mr_ifindex = ifindex; 150*85732ac8SCy Schubert mreq.mr_type = PACKET_MR_MULTICAST; 151*85732ac8SCy Schubert mreq.mr_alen = ETH_ALEN; 152*85732ac8SCy Schubert os_memcpy(mreq.mr_address, addr, ETH_ALEN); 153*85732ac8SCy Schubert 154*85732ac8SCy Schubert if (setsockopt(sock, SOL_PACKET, 155*85732ac8SCy Schubert add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, 156*85732ac8SCy Schubert &mreq, sizeof(mreq)) < 0) { 157*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno)); 158*85732ac8SCy Schubert return -1; 159*85732ac8SCy Schubert } 160*85732ac8SCy Schubert return 0; 161*85732ac8SCy Schubert #else /* __linux__ */ 162*85732ac8SCy Schubert return -1; 163*85732ac8SCy Schubert #endif /* __linux__ */ 164*85732ac8SCy Schubert } 165*85732ac8SCy Schubert 166*85732ac8SCy Schubert 167*85732ac8SCy Schubert int driver_wired_get_ssid(void *priv, u8 *ssid) 168*85732ac8SCy Schubert { 169*85732ac8SCy Schubert ssid[0] = 0; 170*85732ac8SCy Schubert return 0; 171*85732ac8SCy Schubert } 172*85732ac8SCy Schubert 173*85732ac8SCy Schubert 174*85732ac8SCy Schubert int driver_wired_get_bssid(void *priv, u8 *bssid) 175*85732ac8SCy Schubert { 176*85732ac8SCy Schubert /* Report PAE group address as the "BSSID" for wired connection. */ 177*85732ac8SCy Schubert os_memcpy(bssid, pae_group_addr, ETH_ALEN); 178*85732ac8SCy Schubert return 0; 179*85732ac8SCy Schubert } 180*85732ac8SCy Schubert 181*85732ac8SCy Schubert 182*85732ac8SCy Schubert int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa) 183*85732ac8SCy Schubert { 184*85732ac8SCy Schubert os_memset(capa, 0, sizeof(*capa)); 185*85732ac8SCy Schubert capa->flags = WPA_DRIVER_FLAGS_WIRED; 186*85732ac8SCy Schubert return 0; 187*85732ac8SCy Schubert } 188*85732ac8SCy Schubert 189*85732ac8SCy Schubert 190*85732ac8SCy Schubert #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 191*85732ac8SCy Schubert static int driver_wired_get_ifstatus(const char *ifname, int *status) 192*85732ac8SCy Schubert { 193*85732ac8SCy Schubert struct ifmediareq ifmr; 194*85732ac8SCy Schubert int s; 195*85732ac8SCy Schubert 196*85732ac8SCy Schubert s = socket(PF_INET, SOCK_DGRAM, 0); 197*85732ac8SCy Schubert if (s < 0) { 198*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "socket: %s", strerror(errno)); 199*85732ac8SCy Schubert return -1; 200*85732ac8SCy Schubert } 201*85732ac8SCy Schubert 202*85732ac8SCy Schubert os_memset(&ifmr, 0, sizeof(ifmr)); 203*85732ac8SCy Schubert os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ); 204*85732ac8SCy Schubert if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) { 205*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s", 206*85732ac8SCy Schubert strerror(errno)); 207*85732ac8SCy Schubert close(s); 208*85732ac8SCy Schubert return -1; 209*85732ac8SCy Schubert } 210*85732ac8SCy Schubert close(s); 211*85732ac8SCy Schubert *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) == 212*85732ac8SCy Schubert (IFM_ACTIVE | IFM_AVALID); 213*85732ac8SCy Schubert 214*85732ac8SCy Schubert return 0; 215*85732ac8SCy Schubert } 216*85732ac8SCy Schubert #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ 217*85732ac8SCy Schubert 218*85732ac8SCy Schubert 219*85732ac8SCy Schubert int driver_wired_init_common(struct driver_wired_common_data *common, 220*85732ac8SCy Schubert const char *ifname, void *ctx) 221*85732ac8SCy Schubert { 222*85732ac8SCy Schubert int flags; 223*85732ac8SCy Schubert 224*85732ac8SCy Schubert os_strlcpy(common->ifname, ifname, sizeof(common->ifname)); 225*85732ac8SCy Schubert common->ctx = ctx; 226*85732ac8SCy Schubert 227*85732ac8SCy Schubert #ifdef __linux__ 228*85732ac8SCy Schubert common->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0); 229*85732ac8SCy Schubert if (common->pf_sock < 0) 230*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno)); 231*85732ac8SCy Schubert #else /* __linux__ */ 232*85732ac8SCy Schubert common->pf_sock = -1; 233*85732ac8SCy Schubert #endif /* __linux__ */ 234*85732ac8SCy Schubert 235*85732ac8SCy Schubert if (driver_wired_get_ifflags(ifname, &flags) == 0 && 236*85732ac8SCy Schubert !(flags & IFF_UP) && 237*85732ac8SCy Schubert driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) 238*85732ac8SCy Schubert common->iff_up = 1; 239*85732ac8SCy Schubert 240*85732ac8SCy Schubert if (wired_multicast_membership(common->pf_sock, 241*85732ac8SCy Schubert if_nametoindex(common->ifname), 242*85732ac8SCy Schubert pae_group_addr, 1) == 0) { 243*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 244*85732ac8SCy Schubert "%s: Added multicast membership with packet socket", 245*85732ac8SCy Schubert __func__); 246*85732ac8SCy Schubert common->membership = 1; 247*85732ac8SCy Schubert } else if (driver_wired_multi(ifname, pae_group_addr, 1) == 0) { 248*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 249*85732ac8SCy Schubert "%s: Added multicast membership with SIOCADDMULTI", 250*85732ac8SCy Schubert __func__); 251*85732ac8SCy Schubert common->multi = 1; 252*85732ac8SCy Schubert } else if (driver_wired_get_ifflags(ifname, &flags) < 0) { 253*85732ac8SCy Schubert wpa_printf(MSG_INFO, "%s: Could not get interface flags", 254*85732ac8SCy Schubert __func__); 255*85732ac8SCy Schubert return -1; 256*85732ac8SCy Schubert } else if (flags & IFF_ALLMULTI) { 257*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 258*85732ac8SCy Schubert "%s: Interface is already configured for multicast", 259*85732ac8SCy Schubert __func__); 260*85732ac8SCy Schubert } else if (driver_wired_set_ifflags(ifname, 261*85732ac8SCy Schubert flags | IFF_ALLMULTI) < 0) { 262*85732ac8SCy Schubert wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", __func__); 263*85732ac8SCy Schubert return -1; 264*85732ac8SCy Schubert } else { 265*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__); 266*85732ac8SCy Schubert common->iff_allmulti = 1; 267*85732ac8SCy Schubert } 268*85732ac8SCy Schubert #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) 269*85732ac8SCy Schubert { 270*85732ac8SCy Schubert int status; 271*85732ac8SCy Schubert 272*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: waiting for link to become active", 273*85732ac8SCy Schubert __func__); 274*85732ac8SCy Schubert while (driver_wired_get_ifstatus(ifname, &status) == 0 && 275*85732ac8SCy Schubert status == 0) 276*85732ac8SCy Schubert sleep(1); 277*85732ac8SCy Schubert } 278*85732ac8SCy Schubert #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ 279*85732ac8SCy Schubert 280*85732ac8SCy Schubert return 0; 281*85732ac8SCy Schubert } 282*85732ac8SCy Schubert 283*85732ac8SCy Schubert 284*85732ac8SCy Schubert void driver_wired_deinit_common(struct driver_wired_common_data *common) 285*85732ac8SCy Schubert { 286*85732ac8SCy Schubert int flags; 287*85732ac8SCy Schubert 288*85732ac8SCy Schubert if (common->membership && 289*85732ac8SCy Schubert wired_multicast_membership(common->pf_sock, 290*85732ac8SCy Schubert if_nametoindex(common->ifname), 291*85732ac8SCy Schubert pae_group_addr, 0) < 0) { 292*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 293*85732ac8SCy Schubert "%s: Failed to remove PAE multicast group (PACKET)", 294*85732ac8SCy Schubert __func__); 295*85732ac8SCy Schubert } 296*85732ac8SCy Schubert 297*85732ac8SCy Schubert if (common->multi && 298*85732ac8SCy Schubert driver_wired_multi(common->ifname, pae_group_addr, 0) < 0) { 299*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 300*85732ac8SCy Schubert "%s: Failed to remove PAE multicast group (SIOCDELMULTI)", 301*85732ac8SCy Schubert __func__); 302*85732ac8SCy Schubert } 303*85732ac8SCy Schubert 304*85732ac8SCy Schubert if (common->iff_allmulti && 305*85732ac8SCy Schubert (driver_wired_get_ifflags(common->ifname, &flags) < 0 || 306*85732ac8SCy Schubert driver_wired_set_ifflags(common->ifname, 307*85732ac8SCy Schubert flags & ~IFF_ALLMULTI) < 0)) { 308*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode", 309*85732ac8SCy Schubert __func__); 310*85732ac8SCy Schubert } 311*85732ac8SCy Schubert 312*85732ac8SCy Schubert if (common->iff_up && 313*85732ac8SCy Schubert driver_wired_get_ifflags(common->ifname, &flags) == 0 && 314*85732ac8SCy Schubert (flags & IFF_UP) && 315*85732ac8SCy Schubert driver_wired_set_ifflags(common->ifname, flags & ~IFF_UP) < 0) { 316*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down", 317*85732ac8SCy Schubert __func__); 318*85732ac8SCy Schubert } 319*85732ac8SCy Schubert 320*85732ac8SCy Schubert if (common->pf_sock != -1) 321*85732ac8SCy Schubert close(common->pf_sock); 322*85732ac8SCy Schubert } 323