2 * WPA Supplicant - wired Ethernet driver interface
3 * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include <sys/ioctl.h>
20 #include <net/if_dl.h>
24 #include "wpa_supplicant.h"
26 static const u8 pae_group_addr[ETH_ALEN] =
27 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
29 struct wpa_driver_wired_data {
31 char ifname[IFNAMSIZ + 1];
38 getifflags(struct wpa_driver_wired_data *drv, int *flags)
42 memset(&ifr, 0, sizeof(ifr));
43 strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
44 if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
45 perror("SIOCGIFFLAGS");
48 *flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
53 setifflags(struct wpa_driver_wired_data *drv, int flags)
57 memset(&ifr, 0, sizeof(ifr));
58 strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
59 ifr.ifr_flags = flags & 0xffff;
60 ifr.ifr_flagshigh = flags >> 16;
61 if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
62 perror("SIOCSIFFLAGS");
69 wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
76 wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
78 /* Report PAE group address as the "BSSID" for wired connection. */
79 os_memcpy(bssid, pae_group_addr, ETH_ALEN);
84 siocmulti(struct wpa_driver_wired_data *drv, int op, const u8 *addr)
87 struct sockaddr_dl *dlp;
89 os_memset(&ifr, 0, sizeof(ifr));
90 os_strncpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
91 dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
92 dlp->sdl_len = sizeof(struct sockaddr_dl);
93 dlp->sdl_family = AF_LINK;
96 dlp->sdl_alen = ETH_ALEN;
98 os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
99 if (ioctl(drv->sock, op, (caddr_t) &ifr) < 0) {
100 wpa_printf(MSG_INFO, "ioctl[%s]: %s", op == SIOCADDMULTI ?
101 "SIOCADDMULTI" : "SIOCDELMULTI", strerror(errno));
108 wpa_driver_wired_init(void *ctx, const char *ifname)
110 struct wpa_driver_wired_data *drv;
113 drv = os_zalloc(sizeof(*drv));
116 os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
117 drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
122 if (getifflags(drv, &drv->flags) < 0) {
123 wpa_printf(MSG_INFO, "%s: Unable to get interface flags",
127 flags = drv->flags | IFF_UP; /* NB: force interface up */
130 * Arrange to receive PAE mcast frames. Try to add an
131 * explicit mcast address. If that fails, fallback to
132 * the all multicast mechanism.
134 if (siocmulti(drv, SIOCADDMULTI, pae_group_addr) == 0) {
135 wpa_printf(MSG_DEBUG, "%s: Added PAE multicast address",
138 } else if ((drv->flags & IFF_ALLMULTI) == 0)
139 flags |= IFF_ALLMULTI;
141 if (flags != drv->flags) {
142 if (setifflags(drv, flags) < 0) {
143 wpa_printf(MSG_INFO, "%s: Failed to set interface flags",
147 if ((flags ^ drv->flags) & IFF_ALLMULTI)
148 wpa_printf(MSG_DEBUG, "%s: Enabled all-multi mode",
160 wpa_driver_wired_deinit(void *priv)
162 struct wpa_driver_wired_data *drv = priv;
165 if (siocmulti(drv, SIOCDELMULTI, pae_group_addr) < 0) {
166 wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE "
167 "multicast " "group (SIOCDELMULTI)", __func__);
170 if (setifflags(drv, drv->flags) < 0) {
171 wpa_printf(MSG_INFO, "%s: Failed to restore interface flags",
174 (void) close(drv->sock);
178 const struct wpa_driver_ops wpa_driver_wired_ops = {
180 .desc = "BSD wired Ethernet driver",
181 .get_ssid = wpa_driver_wired_get_ssid,
182 .get_bssid = wpa_driver_wired_get_bssid,
183 .init = wpa_driver_wired_init,
184 .deinit = wpa_driver_wired_deinit,