]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/wpa/wpa_supplicant/driver_wired.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.sbin / wpa / wpa_supplicant / driver_wired.c
1 /*
2  * WPA Supplicant - wired Ethernet driver interface
3  * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  *
14  * $FreeBSD$
15  */
16
17 #include "includes.h"
18 #include <sys/ioctl.h>
19 #include <net/if.h>
20 #include <net/if_dl.h>
21
22 #include "common.h"
23 #include "driver.h"
24 #include "wpa.h"
25
26 static const u8 pae_group_addr[ETH_ALEN] =
27 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
28
29 struct wpa_driver_wired_data {
30         int     sock;
31         char    ifname[IFNAMSIZ + 1];
32         int     multi;
33         int     flags;
34         void    *ctx;
35 };
36
37 static int
38 getifflags(struct wpa_driver_wired_data *drv, int *flags)
39 {
40         struct ifreq ifr;
41
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");
46                 return errno;
47         }
48         *flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
49         return 0;
50 }
51
52 static int
53 setifflags(struct wpa_driver_wired_data *drv, int flags)
54 {
55         struct ifreq ifr;
56
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");
63                 return errno;
64         }
65         return 0;
66 }
67
68 static int
69 wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
70 {
71         ssid[0] = 0;
72         return 0;
73 }
74
75 static int
76 wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
77 {
78         /* Report PAE group address as the "BSSID" for wired connection. */
79         os_memcpy(bssid, pae_group_addr, ETH_ALEN);
80         return 0;
81 }
82
83 static int
84 siocmulti(struct wpa_driver_wired_data *drv, int op, const u8 *addr)
85 {
86         struct ifreq ifr;
87         struct sockaddr_dl *dlp;
88
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;
94         dlp->sdl_index = 0;
95         dlp->sdl_nlen = 0;
96         dlp->sdl_alen = ETH_ALEN;
97         dlp->sdl_slen = 0;
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));
102                 return -1;
103         }
104         return 0;
105 }
106
107 static void *
108 wpa_driver_wired_init(void *ctx, const char *ifname)
109 {
110         struct wpa_driver_wired_data *drv;
111         int flags;
112
113         drv = os_zalloc(sizeof(*drv));
114         if (drv == NULL)
115                 return NULL;
116         os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
117         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
118         if (drv->sock < 0)
119                 goto fail1;
120         drv->ctx = ctx;
121
122         if (getifflags(drv, &drv->flags) < 0) {
123                 wpa_printf(MSG_INFO, "%s: Unable to get interface flags",
124                     __func__);
125                 goto fail;
126         }
127         flags = drv->flags | IFF_UP;            /* NB: force interface up */
128
129         /* 
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.
133          */
134         if (siocmulti(drv, SIOCADDMULTI, pae_group_addr) == 0) {
135                 wpa_printf(MSG_DEBUG, "%s: Added PAE multicast address",
136                     __func__);
137                 drv->multi = 1;
138         } else if ((drv->flags & IFF_ALLMULTI) == 0)
139                 flags |= IFF_ALLMULTI;
140
141         if (flags != drv->flags) {
142                 if (setifflags(drv, flags) < 0) {
143                         wpa_printf(MSG_INFO, "%s: Failed to set interface flags",
144                             __func__);
145                         goto fail;
146                 }
147                 if ((flags ^ drv->flags) & IFF_ALLMULTI)
148                         wpa_printf(MSG_DEBUG, "%s: Enabled all-multi mode",
149                             __func__);
150         }
151         return drv;
152 fail:
153         close(drv->sock);
154 fail1:
155         free(drv);
156         return NULL;
157 }
158
159 static void
160 wpa_driver_wired_deinit(void *priv)
161 {
162         struct wpa_driver_wired_data *drv = priv;
163
164         if (drv->multi) {
165                 if (siocmulti(drv, SIOCDELMULTI, pae_group_addr) < 0) {
166                         wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE "
167                             "multicast " "group (SIOCDELMULTI)", __func__);
168                 }
169         }
170         if (setifflags(drv, drv->flags) < 0) {
171                 wpa_printf(MSG_INFO, "%s: Failed to restore interface flags",
172                            __func__);
173         }
174         (void) close(drv->sock);
175         os_free(drv);
176 }
177
178 const struct wpa_driver_ops wpa_driver_wired_ops = {
179         .name           = "wired",
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,
185 };