driver_wired.c
Go to the documentation of this file.
00001 /*
00002  * Wired Ethernet driver interface
00003  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
00004  * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License version 2 as
00008  * published by the Free Software Foundation.
00009  *
00010  * Alternatively, this software may be distributed under the terms of BSD
00011  * license.
00012  *
00013  * See README and COPYING for more details.
00014  */
00015 
00016 #include "includes.h"
00017 #include <sys/ioctl.h>
00018 #include <net/if.h>
00019 #ifdef __linux__
00020 #include <netpacket/packet.h>
00021 #include <net/if_arp.h>
00022 #include <net/if.h>
00023 #endif /* __linux__ */
00024 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
00025 #include <net/if_dl.h>
00026 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
00027 
00028 #include "common.h"
00029 #include "eloop.h"
00030 #include "driver.h"
00031 
00032 #ifdef _MSC_VER
00033 #pragma pack(push, 1)
00034 #endif /* _MSC_VER */
00035 
00036 struct ieee8023_hdr {
00037         u8 dest[6];
00038         u8 src[6];
00039         u16 ethertype;
00040 } STRUCT_PACKED;
00041 
00042 #ifdef _MSC_VER
00043 #pragma pack(pop)
00044 #endif /* _MSC_VER */
00045 
00046 static const u8 pae_group_addr[ETH_ALEN] =
00047 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
00048 
00049 
00050 struct wpa_driver_wired_data {
00051         char ifname[IFNAMSIZ + 1];
00052         void *ctx;
00053 
00054         int sock; /* raw packet socket for driver access */
00055         int dhcp_sock; /* socket for dhcp packets */
00056         int use_pae_group_addr;
00057 
00058         int pf_sock;
00059         int membership, multi, iff_allmulti, iff_up;
00060 };
00061 
00062 
00063 /* TODO: detecting new devices should eventually be changed from using DHCP
00064  * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
00065  * based on ebtables, etc. */
00066 
00067 struct dhcp_message {
00068         u_int8_t op;
00069         u_int8_t htype;
00070         u_int8_t hlen;
00071         u_int8_t hops;
00072         u_int32_t xid;
00073         u_int16_t secs;
00074         u_int16_t flags;
00075         u_int32_t ciaddr;
00076         u_int32_t yiaddr;
00077         u_int32_t siaddr;
00078         u_int32_t giaddr;
00079         u_int8_t chaddr[16];
00080         u_int8_t sname[64];
00081         u_int8_t file[128];
00082         u_int32_t cookie;
00083         u_int8_t options[308]; /* 312 - cookie */
00084 };
00085 
00086 
00087 static int wired_multicast_membership(int sock, int ifindex,
00088                                       const u8 *addr, int add)
00089 {
00090 #ifdef __linux__
00091         struct packet_mreq mreq;
00092 
00093         if (sock < 0)
00094                 return -1;
00095 
00096         os_memset(&mreq, 0, sizeof(mreq));
00097         mreq.mr_ifindex = ifindex;
00098         mreq.mr_type = PACKET_MR_MULTICAST;
00099         mreq.mr_alen = ETH_ALEN;
00100         os_memcpy(mreq.mr_address, addr, ETH_ALEN);
00101 
00102         if (setsockopt(sock, SOL_PACKET,
00103                        add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
00104                        &mreq, sizeof(mreq)) < 0) {
00105                 perror("setsockopt");
00106                 return -1;
00107         }
00108         return 0;
00109 #else /* __linux__ */
00110         return -1;
00111 #endif /* __linux__ */
00112 }
00113 
00114 
00115 #ifdef __linux__
00116 static void handle_data(void *ctx, unsigned char *buf, size_t len)
00117 {
00118 #ifdef HOSTAPD
00119         struct ieee8023_hdr *hdr;
00120         u8 *pos, *sa;
00121         size_t left;
00122         union wpa_event_data event;
00123 
00124         /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
00125          * 2 byte ethertype */
00126         if (len < 14) {
00127                 wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)",
00128                            (unsigned long) len);
00129                 return;
00130         }
00131 
00132         hdr = (struct ieee8023_hdr *) buf;
00133 
00134         switch (ntohs(hdr->ethertype)) {
00135                 case ETH_P_PAE:
00136                         wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
00137                         sa = hdr->src;
00138                         os_memset(&event, 0, sizeof(event));
00139                         event.new_sta.addr = sa;
00140                         wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
00141 
00142                         pos = (u8 *) (hdr + 1);
00143                         left = len - sizeof(*hdr);
00144                         drv_event_eapol_rx(ctx, sa, pos, left);
00145                 break;
00146 
00147         default:
00148                 wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
00149                            ntohs(hdr->ethertype));
00150                 break;
00151         }
00152 #endif /* HOSTAPD */
00153 }
00154 
00155 
00156 static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
00157 {
00158         int len;
00159         unsigned char buf[3000];
00160 
00161         len = recv(sock, buf, sizeof(buf), 0);
00162         if (len < 0) {
00163                 perror("recv");
00164                 return;
00165         }
00166 
00167         handle_data(eloop_ctx, buf, len);
00168 }
00169 
00170 
00171 static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
00172 {
00173         int len;
00174         unsigned char buf[3000];
00175         struct dhcp_message *msg;
00176         u8 *mac_address;
00177         union wpa_event_data event;
00178 
00179         len = recv(sock, buf, sizeof(buf), 0);
00180         if (len < 0) {
00181                 perror("recv");
00182                 return;
00183         }
00184 
00185         /* must contain at least dhcp_message->chaddr */
00186         if (len < 44) {
00187                 wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len);
00188                 return;
00189         }
00190 
00191         msg = (struct dhcp_message *) buf;
00192         mac_address = (u8 *) &(msg->chaddr);
00193 
00194         wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR,
00195                    MAC2STR(mac_address));
00196 
00197         os_memset(&event, 0, sizeof(event));
00198         event.new_sta.addr = mac_address;
00199         wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event);
00200 }
00201 #endif /* __linux__ */
00202 
00203 
00204 static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
00205 {
00206 #ifdef __linux__
00207         struct ifreq ifr;
00208         struct sockaddr_ll addr;
00209         struct sockaddr_in addr2;
00210         int n = 1;
00211 
00212         drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
00213         if (drv->sock < 0) {
00214                 perror("socket[PF_PACKET,SOCK_RAW]");
00215                 return -1;
00216         }
00217 
00218         if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
00219                 printf("Could not register read socket\n");
00220                 return -1;
00221         }
00222 
00223         os_memset(&ifr, 0, sizeof(ifr));
00224         os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
00225         if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
00226                 perror("ioctl(SIOCGIFINDEX)");
00227                 return -1;
00228         }
00229 
00230         os_memset(&addr, 0, sizeof(addr));
00231         addr.sll_family = AF_PACKET;
00232         addr.sll_ifindex = ifr.ifr_ifindex;
00233         wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
00234                    addr.sll_ifindex);
00235 
00236         if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00237                 perror("bind");
00238                 return -1;
00239         }
00240 
00241         /* filter multicast address */
00242         if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
00243                                        pae_group_addr, 1) < 0) {
00244                 wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
00245                            "membership");
00246                 return -1;
00247         }
00248 
00249         os_memset(&ifr, 0, sizeof(ifr));
00250         os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
00251         if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
00252                 perror("ioctl(SIOCGIFHWADDR)");
00253                 return -1;
00254         }
00255 
00256         if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
00257                 printf("Invalid HW-addr family 0x%04x\n",
00258                        ifr.ifr_hwaddr.sa_family);
00259                 return -1;
00260         }
00261         os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
00262 
00263         /* setup dhcp listen socket for sta detection */
00264         if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
00265                 perror("socket call failed for dhcp");
00266                 return -1;
00267         }
00268 
00269         if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
00270                                      NULL)) {
00271                 printf("Could not register read socket\n");
00272                 return -1;
00273         }
00274 
00275         os_memset(&addr2, 0, sizeof(addr2));
00276         addr2.sin_family = AF_INET;
00277         addr2.sin_port = htons(67);
00278         addr2.sin_addr.s_addr = INADDR_ANY;
00279 
00280         if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
00281                        sizeof(n)) == -1) {
00282                 perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
00283                 return -1;
00284         }
00285         if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
00286                        sizeof(n)) == -1) {
00287                 perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
00288                 return -1;
00289         }
00290 
00291         os_memset(&ifr, 0, sizeof(ifr));
00292         os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
00293         if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
00294                        (char *) &ifr, sizeof(ifr)) < 0) {
00295                 perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
00296                 return -1;
00297         }
00298 
00299         if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
00300                  sizeof(struct sockaddr)) == -1) {
00301                 perror("bind");
00302                 return -1;
00303         }
00304 
00305         return 0;
00306 #else /* __linux__ */
00307         return -1;
00308 #endif /* __linux__ */
00309 }
00310 
00311 
00312 static int wired_send_eapol(void *priv, const u8 *addr,
00313                             const u8 *data, size_t data_len, int encrypt,
00314                             const u8 *own_addr)
00315 {
00316         struct wpa_driver_wired_data *drv = priv;
00317         struct ieee8023_hdr *hdr;
00318         size_t len;
00319         u8 *pos;
00320         int res;
00321 
00322         len = sizeof(*hdr) + data_len;
00323         hdr = os_zalloc(len);
00324         if (hdr == NULL) {
00325                 printf("malloc() failed for wired_send_eapol(len=%lu)\n",
00326                        (unsigned long) len);
00327                 return -1;
00328         }
00329 
00330         os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
00331                   ETH_ALEN);
00332         os_memcpy(hdr->src, own_addr, ETH_ALEN);
00333         hdr->ethertype = htons(ETH_P_PAE);
00334 
00335         pos = (u8 *) (hdr + 1);
00336         os_memcpy(pos, data, data_len);
00337 
00338         res = send(drv->sock, (u8 *) hdr, len, 0);
00339         os_free(hdr);
00340 
00341         if (res < 0) {
00342                 perror("wired_send_eapol: send");
00343                 printf("wired_send_eapol - packet len: %lu - failed\n",
00344                        (unsigned long) len);
00345         }
00346 
00347         return res;
00348 }
00349 
00350 
00351 static void * wired_driver_hapd_init(struct hostapd_data *hapd,
00352                                      struct wpa_init_params *params)
00353 {
00354         struct wpa_driver_wired_data *drv;
00355 
00356         drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
00357         if (drv == NULL) {
00358                 printf("Could not allocate memory for wired driver data\n");
00359                 return NULL;
00360         }
00361 
00362         drv->ctx = hapd;
00363         os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
00364         drv->use_pae_group_addr = params->use_pae_group_addr;
00365 
00366         if (wired_init_sockets(drv, params->own_addr)) {
00367                 os_free(drv);
00368                 return NULL;
00369         }
00370 
00371         return drv;
00372 }
00373 
00374 
00375 static void wired_driver_hapd_deinit(void *priv)
00376 {
00377         struct wpa_driver_wired_data *drv = priv;
00378 
00379         if (drv->sock >= 0)
00380                 close(drv->sock);
00381 
00382         if (drv->dhcp_sock >= 0)
00383                 close(drv->dhcp_sock);
00384 
00385         os_free(drv);
00386 }
00387 
00388 
00389 static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
00390 {
00391         ssid[0] = 0;
00392         return 0;
00393 }
00394 
00395 
00396 static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
00397 {
00398         /* Report PAE group address as the "BSSID" for wired connection. */
00399         os_memcpy(bssid, pae_group_addr, ETH_ALEN);
00400         return 0;
00401 }
00402 
00403 
00404 static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
00405 {
00406         os_memset(capa, 0, sizeof(*capa));
00407         capa->flags = WPA_DRIVER_FLAGS_WIRED;
00408         return 0;
00409 }
00410 
00411 
00412 static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
00413 {
00414         struct ifreq ifr;
00415         int s;
00416 
00417         s = socket(PF_INET, SOCK_DGRAM, 0);
00418         if (s < 0) {
00419                 perror("socket");
00420                 return -1;
00421         }
00422 
00423         os_memset(&ifr, 0, sizeof(ifr));
00424         os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
00425         if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
00426                 perror("ioctl[SIOCGIFFLAGS]");
00427                 close(s);
00428                 return -1;
00429         }
00430         close(s);
00431         *flags = ifr.ifr_flags & 0xffff;
00432         return 0;
00433 }
00434 
00435 
00436 static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
00437 {
00438         struct ifreq ifr;
00439         int s;
00440 
00441         s = socket(PF_INET, SOCK_DGRAM, 0);
00442         if (s < 0) {
00443                 perror("socket");
00444                 return -1;
00445         }
00446 
00447         os_memset(&ifr, 0, sizeof(ifr));
00448         os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
00449         ifr.ifr_flags = flags & 0xffff;
00450         if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
00451                 perror("ioctl[SIOCSIFFLAGS]");
00452                 close(s);
00453                 return -1;
00454         }
00455         close(s);
00456         return 0;
00457 }
00458 
00459 
00460 static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
00461 {
00462         struct ifreq ifr;
00463         int s;
00464 
00465         s = socket(PF_INET, SOCK_DGRAM, 0);
00466         if (s < 0) {
00467                 perror("socket");
00468                 return -1;
00469         }
00470 
00471         os_memset(&ifr, 0, sizeof(ifr));
00472         os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
00473 #ifdef __linux__
00474         ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
00475         os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
00476 #endif /* __linux__ */
00477 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
00478         {
00479                 struct sockaddr_dl *dlp;
00480                 dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
00481                 dlp->sdl_len = sizeof(struct sockaddr_dl);
00482                 dlp->sdl_family = AF_LINK;
00483                 dlp->sdl_index = 0;
00484                 dlp->sdl_nlen = 0;
00485                 dlp->sdl_alen = ETH_ALEN;
00486                 dlp->sdl_slen = 0;
00487                 os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
00488         }
00489 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
00490 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
00491         {
00492                 struct sockaddr *sap;
00493                 sap = (struct sockaddr *) &ifr.ifr_addr;
00494                 sap->sa_len = sizeof(struct sockaddr);
00495                 sap->sa_family = AF_UNSPEC;
00496                 os_memcpy(sap->sa_data, addr, ETH_ALEN);
00497         }
00498 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
00499 
00500         if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
00501                 perror("ioctl[SIOC{ADD/DEL}MULTI]");
00502                 close(s);
00503                 return -1;
00504         }
00505         close(s);
00506         return 0;
00507 }
00508 
00509 
00510 static void * wpa_driver_wired_init(void *ctx, const char *ifname)
00511 {
00512         struct wpa_driver_wired_data *drv;
00513         int flags;
00514 
00515         drv = os_zalloc(sizeof(*drv));
00516         if (drv == NULL)
00517                 return NULL;
00518         os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
00519         drv->ctx = ctx;
00520 
00521 #ifdef __linux__
00522         drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
00523         if (drv->pf_sock < 0)
00524                 perror("socket(PF_PACKET)");
00525 #else /* __linux__ */
00526         drv->pf_sock = -1;
00527 #endif /* __linux__ */
00528 
00529         if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
00530             !(flags & IFF_UP) &&
00531             wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
00532                 drv->iff_up = 1;
00533         }
00534 
00535         if (wired_multicast_membership(drv->pf_sock,
00536                                        if_nametoindex(drv->ifname),
00537                                        pae_group_addr, 1) == 0) {
00538                 wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
00539                            "packet socket", __func__);
00540                 drv->membership = 1;
00541         } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
00542                 wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
00543                            "SIOCADDMULTI", __func__);
00544                 drv->multi = 1;
00545         } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
00546                 wpa_printf(MSG_INFO, "%s: Could not get interface "
00547                            "flags", __func__);
00548                 os_free(drv);
00549                 return NULL;
00550         } else if (flags & IFF_ALLMULTI) {
00551                 wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
00552                            "for multicast", __func__);
00553         } else if (wpa_driver_wired_set_ifflags(ifname,
00554                                                 flags | IFF_ALLMULTI) < 0) {
00555                 wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
00556                            __func__);
00557                 os_free(drv);
00558                 return NULL;
00559         } else {
00560                 wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
00561                            __func__);
00562                 drv->iff_allmulti = 1;
00563         }
00564 
00565         return drv;
00566 }
00567 
00568 
00569 static void wpa_driver_wired_deinit(void *priv)
00570 {
00571         struct wpa_driver_wired_data *drv = priv;
00572         int flags;
00573 
00574         if (drv->membership &&
00575             wired_multicast_membership(drv->pf_sock,
00576                                        if_nametoindex(drv->ifname),
00577                                        pae_group_addr, 0) < 0) {
00578                 wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
00579                            "group (PACKET)", __func__);
00580         }
00581 
00582         if (drv->multi &&
00583             wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
00584                 wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
00585                            "group (SIOCDELMULTI)", __func__);
00586         }
00587 
00588         if (drv->iff_allmulti &&
00589             (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
00590              wpa_driver_wired_set_ifflags(drv->ifname,
00591                                           flags & ~IFF_ALLMULTI) < 0)) {
00592                 wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
00593                            __func__);
00594         }
00595 
00596         if (drv->iff_up &&
00597             wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
00598             (flags & IFF_UP) &&
00599             wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
00600                 wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
00601                            __func__);
00602         }
00603 
00604         if (drv->pf_sock != -1)
00605                 close(drv->pf_sock);
00606 
00607         os_free(drv);
00608 }
00609 
00610 
00611 const struct wpa_driver_ops wpa_driver_wired_ops = {
00612         .name = "wired",
00613         .desc = "Wired Ethernet driver",
00614         .hapd_init = wired_driver_hapd_init,
00615         .hapd_deinit = wired_driver_hapd_deinit,
00616         .hapd_send_eapol = wired_send_eapol,
00617         .get_ssid = wpa_driver_wired_get_ssid,
00618         .get_bssid = wpa_driver_wired_get_bssid,
00619         .get_capa = wpa_driver_wired_get_capa,
00620         .init = wpa_driver_wired_init,
00621         .deinit = wpa_driver_wired_deinit,
00622 };


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:37