2
* WPA Supplicant - wired Ethernet driver interface
3
* Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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.
16
#include <sys/ioctl.h>
17
#include <netpacket/packet.h>
22
#include "wpa_supplicant.h"
25
static const u8 pae_group_addr[ETH_ALEN] =
26
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
29
struct wpa_driver_wired_data {
32
char ifname[IFNAMSIZ + 1];
33
int membership, multi, iff_allmulti, iff_up;
37
static int wpa_driver_wired_set_wpa(void *priv, int enabled)
43
static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
50
static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
52
/* Report PAE group address as the "BSSID" for wired connection. */
53
memcpy(bssid, pae_group_addr, ETH_ALEN);
58
static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
63
s = socket(PF_INET, SOCK_DGRAM, 0);
69
memset(&ifr, 0, sizeof(ifr));
70
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
71
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
72
perror("ioctl[SIOCGIFFLAGS]");
77
*flags = ifr.ifr_flags & 0xffff;
82
static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
87
s = socket(PF_INET, SOCK_DGRAM, 0);
93
memset(&ifr, 0, sizeof(ifr));
94
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
95
ifr.ifr_flags = flags & 0xffff;
96
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
97
perror("ioctl[SIOCSIFFLAGS]");
106
static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
111
s = socket(PF_INET, SOCK_DGRAM, 0);
117
memset(&ifr, 0, sizeof(ifr));
118
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
119
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
120
memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
122
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
123
perror("ioctl[SIOC{ADD/DEL}MULTI]");
132
static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
133
const u8 *addr, int add)
136
struct packet_mreq mreq;
138
if (drv->pf_sock == -1)
141
memset(&mreq, 0, sizeof(mreq));
142
mreq.mr_ifindex = if_nametoindex(drv->ifname);
143
mreq.mr_type = PACKET_MR_MULTICAST;
144
mreq.mr_alen = ETH_ALEN;
145
memcpy(mreq.mr_address, addr, ETH_ALEN);
147
if (setsockopt(drv->pf_sock, SOL_PACKET,
148
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
149
&mreq, sizeof(mreq)) < 0) {
150
perror("setsockopt");
154
#else /* __linux__ */
156
#endif /* __linux__ */
160
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
162
struct wpa_driver_wired_data *drv;
165
drv = wpa_zalloc(sizeof(*drv));
168
strncpy(drv->ifname, ifname, sizeof(drv->ifname));
172
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
173
if (drv->pf_sock < 0)
174
perror("socket(PF_PACKET)");
179
if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
181
wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
185
if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) {
186
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
187
"packet socket", __func__);
189
} else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
190
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
191
"SIOCADDMULTI", __func__);
193
} else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
194
wpa_printf(MSG_INFO, "%s: Could not get interface "
198
} else if (flags & IFF_ALLMULTI) {
199
wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
200
"for multicast", __func__);
201
} else if (wpa_driver_wired_set_ifflags(ifname,
202
flags | IFF_ALLMULTI) < 0) {
203
wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
208
wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
210
drv->iff_allmulti = 1;
217
static void wpa_driver_wired_deinit(void *priv)
219
struct wpa_driver_wired_data *drv = priv;
222
if (drv->membership &&
223
wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) {
224
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
225
"group (PACKET)", __func__);
229
wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
230
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
231
"group (SIOCDELMULTI)", __func__);
234
if (drv->iff_allmulti &&
235
(wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
236
wpa_driver_wired_set_ifflags(drv->ifname,
237
flags & ~IFF_ALLMULTI) < 0)) {
238
wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
243
wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
245
wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
246
wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
250
if (drv->pf_sock != -1)
257
const struct wpa_driver_ops wpa_driver_wired_ops = {
259
.desc = "wpa_supplicant wired Ethernet driver",
260
.set_wpa = wpa_driver_wired_set_wpa,
261
.get_ssid = wpa_driver_wired_get_ssid,
262
.get_bssid = wpa_driver_wired_get_bssid,
263
.init = wpa_driver_wired_init,
264
.deinit = wpa_driver_wired_deinit,