Branch data Line data Source code
1 : : /*
2 : : * Driver interaction with generic Linux Wireless Extensions
3 : : * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : *
8 : : * This file implements a driver interface for the Linux Wireless Extensions.
9 : : * When used with WE-18 or newer, this interface can be used as-is with number
10 : : * of drivers. In addition to this, some of the common functions in this file
11 : : * can be used by other driver interface implementations that use generic WE
12 : : * ioctls, but require private ioctls for some of the functionality.
13 : : */
14 : :
15 : : #include "includes.h"
16 : : #include <sys/ioctl.h>
17 : : #include <sys/types.h>
18 : : #include <sys/stat.h>
19 : : #include <fcntl.h>
20 : : #include <net/if_arp.h>
21 : :
22 : : #include "linux_wext.h"
23 : : #include "common.h"
24 : : #include "eloop.h"
25 : : #include "common/ieee802_11_defs.h"
26 : : #include "common/wpa_common.h"
27 : : #include "priv_netlink.h"
28 : : #include "netlink.h"
29 : : #include "linux_ioctl.h"
30 : : #include "rfkill.h"
31 : : #include "driver.h"
32 : : #include "driver_wext.h"
33 : :
34 : : static int wpa_driver_wext_flush_pmkid(void *priv);
35 : : static int wpa_driver_wext_get_range(void *priv);
36 : : static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
37 : : static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
38 : : static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
39 : :
40 : :
41 : 0 : int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
42 : : int idx, u32 value)
43 : : {
44 : : struct iwreq iwr;
45 : 0 : int ret = 0;
46 : :
47 : 0 : os_memset(&iwr, 0, sizeof(iwr));
48 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
49 : 0 : iwr.u.param.flags = idx & IW_AUTH_INDEX;
50 : 0 : iwr.u.param.value = value;
51 : :
52 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
53 [ # # ]: 0 : if (errno != EOPNOTSUPP) {
54 : 0 : wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
55 : : "value 0x%x) failed: %s)",
56 : 0 : idx, value, strerror(errno));
57 : : }
58 [ # # ]: 0 : ret = errno == EOPNOTSUPP ? -2 : -1;
59 : : }
60 : :
61 : 0 : return ret;
62 : : }
63 : :
64 : :
65 : : /**
66 : : * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP
67 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
68 : : * @bssid: Buffer for BSSID
69 : : * Returns: 0 on success, -1 on failure
70 : : */
71 : 0 : int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
72 : : {
73 : 0 : struct wpa_driver_wext_data *drv = priv;
74 : : struct iwreq iwr;
75 : 0 : int ret = 0;
76 : :
77 : 0 : os_memset(&iwr, 0, sizeof(iwr));
78 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
79 : :
80 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
81 : 0 : perror("ioctl[SIOCGIWAP]");
82 : 0 : ret = -1;
83 : : }
84 : 0 : os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
85 : :
86 : 0 : return ret;
87 : : }
88 : :
89 : :
90 : : /**
91 : : * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP
92 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
93 : : * @bssid: BSSID
94 : : * Returns: 0 on success, -1 on failure
95 : : */
96 : 0 : int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
97 : : {
98 : 0 : struct wpa_driver_wext_data *drv = priv;
99 : : struct iwreq iwr;
100 : 0 : int ret = 0;
101 : :
102 : 0 : os_memset(&iwr, 0, sizeof(iwr));
103 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
104 : 0 : iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
105 [ # # ]: 0 : if (bssid)
106 : 0 : os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
107 : : else
108 : 0 : os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
109 : :
110 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
111 : 0 : perror("ioctl[SIOCSIWAP]");
112 : 0 : ret = -1;
113 : : }
114 : :
115 : 0 : return ret;
116 : : }
117 : :
118 : :
119 : : /**
120 : : * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID
121 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
122 : : * @ssid: Buffer for the SSID; must be at least 32 bytes long
123 : : * Returns: SSID length on success, -1 on failure
124 : : */
125 : 0 : int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
126 : : {
127 : 0 : struct wpa_driver_wext_data *drv = priv;
128 : : struct iwreq iwr;
129 : 0 : int ret = 0;
130 : :
131 : 0 : os_memset(&iwr, 0, sizeof(iwr));
132 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
133 : 0 : iwr.u.essid.pointer = (caddr_t) ssid;
134 : 0 : iwr.u.essid.length = 32;
135 : :
136 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
137 : 0 : perror("ioctl[SIOCGIWESSID]");
138 : 0 : ret = -1;
139 : : } else {
140 : 0 : ret = iwr.u.essid.length;
141 [ # # ]: 0 : if (ret > 32)
142 : 0 : ret = 32;
143 : : /* Some drivers include nul termination in the SSID, so let's
144 : : * remove it here before further processing. WE-21 changes this
145 : : * to explicitly require the length _not_ to include nul
146 : : * termination. */
147 [ # # ][ # # ]: 0 : if (ret > 0 && ssid[ret - 1] == '\0' &&
[ # # ]
148 : 0 : drv->we_version_compiled < 21)
149 : 0 : ret--;
150 : : }
151 : :
152 : 0 : return ret;
153 : : }
154 : :
155 : :
156 : : /**
157 : : * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID
158 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
159 : : * @ssid: SSID
160 : : * @ssid_len: Length of SSID (0..32)
161 : : * Returns: 0 on success, -1 on failure
162 : : */
163 : 0 : int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
164 : : {
165 : 0 : struct wpa_driver_wext_data *drv = priv;
166 : : struct iwreq iwr;
167 : 0 : int ret = 0;
168 : : char buf[33];
169 : :
170 [ # # ]: 0 : if (ssid_len > 32)
171 : 0 : return -1;
172 : :
173 : 0 : os_memset(&iwr, 0, sizeof(iwr));
174 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
175 : : /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
176 : 0 : iwr.u.essid.flags = (ssid_len != 0);
177 : 0 : os_memset(buf, 0, sizeof(buf));
178 : 0 : os_memcpy(buf, ssid, ssid_len);
179 : 0 : iwr.u.essid.pointer = (caddr_t) buf;
180 [ # # ]: 0 : if (drv->we_version_compiled < 21) {
181 : : /* For historic reasons, set SSID length to include one extra
182 : : * character, C string nul termination, even though SSID is
183 : : * really an octet string that should not be presented as a C
184 : : * string. Some Linux drivers decrement the length by one and
185 : : * can thus end up missing the last octet of the SSID if the
186 : : * length is not incremented here. WE-21 changes this to
187 : : * explicitly require the length _not_ to include nul
188 : : * termination. */
189 [ # # ]: 0 : if (ssid_len)
190 : 0 : ssid_len++;
191 : : }
192 : 0 : iwr.u.essid.length = ssid_len;
193 : :
194 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
195 : 0 : perror("ioctl[SIOCSIWESSID]");
196 : 0 : ret = -1;
197 : : }
198 : :
199 : 0 : return ret;
200 : : }
201 : :
202 : :
203 : : /**
204 : : * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ
205 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
206 : : * @freq: Frequency in MHz
207 : : * Returns: 0 on success, -1 on failure
208 : : */
209 : 0 : int wpa_driver_wext_set_freq(void *priv, int freq)
210 : : {
211 : 0 : struct wpa_driver_wext_data *drv = priv;
212 : : struct iwreq iwr;
213 : 0 : int ret = 0;
214 : :
215 : 0 : os_memset(&iwr, 0, sizeof(iwr));
216 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
217 : 0 : iwr.u.freq.m = freq * 100000;
218 : 0 : iwr.u.freq.e = 1;
219 : :
220 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
221 : 0 : perror("ioctl[SIOCSIWFREQ]");
222 : 0 : ret = -1;
223 : : }
224 : :
225 : 0 : return ret;
226 : : }
227 : :
228 : :
229 : : static void
230 : 0 : wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
231 : : {
232 : : union wpa_event_data data;
233 : :
234 : 0 : wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
235 : : custom);
236 : :
237 : 0 : os_memset(&data, 0, sizeof(data));
238 : : /* Host AP driver */
239 [ # # ]: 0 : if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
240 : 0 : data.michael_mic_failure.unicast =
241 : 0 : os_strstr(custom, " unicast ") != NULL;
242 : : /* TODO: parse parameters(?) */
243 : 0 : wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
244 [ # # ]: 0 : } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
245 : : char *spos;
246 : : int bytes;
247 : 0 : u8 *req_ies = NULL, *resp_ies = NULL;
248 : :
249 : 0 : spos = custom + 17;
250 : :
251 : 0 : bytes = strspn(spos, "0123456789abcdefABCDEF");
252 [ # # ][ # # ]: 0 : if (!bytes || (bytes & 1))
253 : 0 : return;
254 : 0 : bytes /= 2;
255 : :
256 : 0 : req_ies = os_malloc(bytes);
257 [ # # # # ]: 0 : if (req_ies == NULL ||
258 : 0 : hexstr2bin(spos, req_ies, bytes) < 0)
259 : : goto done;
260 : 0 : data.assoc_info.req_ies = req_ies;
261 : 0 : data.assoc_info.req_ies_len = bytes;
262 : :
263 : 0 : spos += bytes * 2;
264 : :
265 : 0 : data.assoc_info.resp_ies = NULL;
266 : 0 : data.assoc_info.resp_ies_len = 0;
267 : :
268 [ # # ]: 0 : if (os_strncmp(spos, " RespIEs=", 9) == 0) {
269 : 0 : spos += 9;
270 : :
271 : 0 : bytes = strspn(spos, "0123456789abcdefABCDEF");
272 [ # # ][ # # ]: 0 : if (!bytes || (bytes & 1))
273 : : goto done;
274 : 0 : bytes /= 2;
275 : :
276 : 0 : resp_ies = os_malloc(bytes);
277 [ # # # # ]: 0 : if (resp_ies == NULL ||
278 : 0 : hexstr2bin(spos, resp_ies, bytes) < 0)
279 : : goto done;
280 : 0 : data.assoc_info.resp_ies = resp_ies;
281 : 0 : data.assoc_info.resp_ies_len = bytes;
282 : : }
283 : :
284 : 0 : wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
285 : :
286 : : done:
287 : 0 : os_free(resp_ies);
288 : 0 : os_free(req_ies);
289 : : #ifdef CONFIG_PEERKEY
290 [ # # ]: 0 : } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
291 [ # # ]: 0 : if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
292 : 0 : wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
293 : : "STKSTART.request '%s'", custom + 17);
294 : 0 : return;
295 : : }
296 : 0 : wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
297 : : #endif /* CONFIG_PEERKEY */
298 : : }
299 : : }
300 : :
301 : :
302 : 0 : static int wpa_driver_wext_event_wireless_michaelmicfailure(
303 : : void *ctx, const char *ev, size_t len)
304 : : {
305 : : const struct iw_michaelmicfailure *mic;
306 : : union wpa_event_data data;
307 : :
308 [ # # ]: 0 : if (len < sizeof(*mic))
309 : 0 : return -1;
310 : :
311 : 0 : mic = (const struct iw_michaelmicfailure *) ev;
312 : :
313 : 0 : wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
314 : : "flags=0x%x src_addr=" MACSTR, mic->flags,
315 : 0 : MAC2STR(mic->src_addr.sa_data));
316 : :
317 : 0 : os_memset(&data, 0, sizeof(data));
318 : 0 : data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
319 : 0 : wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
320 : :
321 : 0 : return 0;
322 : : }
323 : :
324 : :
325 : 0 : static int wpa_driver_wext_event_wireless_pmkidcand(
326 : : struct wpa_driver_wext_data *drv, const char *ev, size_t len)
327 : : {
328 : : const struct iw_pmkid_cand *cand;
329 : : union wpa_event_data data;
330 : : const u8 *addr;
331 : :
332 [ # # ]: 0 : if (len < sizeof(*cand))
333 : 0 : return -1;
334 : :
335 : 0 : cand = (const struct iw_pmkid_cand *) ev;
336 : 0 : addr = (const u8 *) cand->bssid.sa_data;
337 : :
338 : 0 : wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
339 : : "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
340 : 0 : cand->index, MAC2STR(addr));
341 : :
342 : 0 : os_memset(&data, 0, sizeof(data));
343 : 0 : os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
344 : 0 : data.pmkid_candidate.index = cand->index;
345 : 0 : data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
346 : 0 : wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
347 : :
348 : 0 : return 0;
349 : : }
350 : :
351 : :
352 : 0 : static int wpa_driver_wext_event_wireless_assocreqie(
353 : : struct wpa_driver_wext_data *drv, const char *ev, int len)
354 : : {
355 [ # # ]: 0 : if (len < 0)
356 : 0 : return -1;
357 : :
358 : 0 : wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
359 : : len);
360 : 0 : os_free(drv->assoc_req_ies);
361 : 0 : drv->assoc_req_ies = os_malloc(len);
362 [ # # ]: 0 : if (drv->assoc_req_ies == NULL) {
363 : 0 : drv->assoc_req_ies_len = 0;
364 : 0 : return -1;
365 : : }
366 : 0 : os_memcpy(drv->assoc_req_ies, ev, len);
367 : 0 : drv->assoc_req_ies_len = len;
368 : :
369 : 0 : return 0;
370 : : }
371 : :
372 : :
373 : 0 : static int wpa_driver_wext_event_wireless_assocrespie(
374 : : struct wpa_driver_wext_data *drv, const char *ev, int len)
375 : : {
376 [ # # ]: 0 : if (len < 0)
377 : 0 : return -1;
378 : :
379 : 0 : wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
380 : : len);
381 : 0 : os_free(drv->assoc_resp_ies);
382 : 0 : drv->assoc_resp_ies = os_malloc(len);
383 [ # # ]: 0 : if (drv->assoc_resp_ies == NULL) {
384 : 0 : drv->assoc_resp_ies_len = 0;
385 : 0 : return -1;
386 : : }
387 : 0 : os_memcpy(drv->assoc_resp_ies, ev, len);
388 : 0 : drv->assoc_resp_ies_len = len;
389 : :
390 : 0 : return 0;
391 : : }
392 : :
393 : :
394 : 0 : static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
395 : : {
396 : : union wpa_event_data data;
397 : :
398 [ # # ][ # # ]: 0 : if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
399 : 0 : return;
400 : :
401 : 0 : os_memset(&data, 0, sizeof(data));
402 [ # # ]: 0 : if (drv->assoc_req_ies) {
403 : 0 : data.assoc_info.req_ies = drv->assoc_req_ies;
404 : 0 : data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
405 : : }
406 [ # # ]: 0 : if (drv->assoc_resp_ies) {
407 : 0 : data.assoc_info.resp_ies = drv->assoc_resp_ies;
408 : 0 : data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
409 : : }
410 : :
411 : 0 : wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
412 : :
413 : 0 : os_free(drv->assoc_req_ies);
414 : 0 : drv->assoc_req_ies = NULL;
415 : 0 : os_free(drv->assoc_resp_ies);
416 : 0 : drv->assoc_resp_ies = NULL;
417 : : }
418 : :
419 : :
420 : 0 : static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
421 : : char *data, int len)
422 : : {
423 : 0 : struct iw_event iwe_buf, *iwe = &iwe_buf;
424 : : char *pos, *end, *custom, *buf;
425 : :
426 : 0 : pos = data;
427 : 0 : end = data + len;
428 : :
429 [ # # ]: 0 : while (pos + IW_EV_LCP_LEN <= end) {
430 : : /* Event data may be unaligned, so make a local, aligned copy
431 : : * before processing. */
432 : 0 : os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
433 : 0 : wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
434 : 0 : iwe->cmd, iwe->len);
435 [ # # ]: 0 : if (iwe->len <= IW_EV_LCP_LEN)
436 : 0 : return;
437 : :
438 : 0 : custom = pos + IW_EV_POINT_LEN;
439 [ # # ][ # # ]: 0 : if (drv->we_version_compiled > 18 &&
440 [ # # ]: 0 : (iwe->cmd == IWEVMICHAELMICFAILURE ||
441 [ # # ]: 0 : iwe->cmd == IWEVCUSTOM ||
442 [ # # ]: 0 : iwe->cmd == IWEVASSOCREQIE ||
443 [ # # ]: 0 : iwe->cmd == IWEVASSOCRESPIE ||
444 : 0 : iwe->cmd == IWEVPMKIDCAND)) {
445 : : /* WE-19 removed the pointer from struct iw_point */
446 : 0 : char *dpos = (char *) &iwe_buf.u.data.length;
447 : 0 : int dlen = dpos - (char *) &iwe_buf;
448 : 0 : os_memcpy(dpos, pos + IW_EV_LCP_LEN,
449 : : sizeof(struct iw_event) - dlen);
450 : : } else {
451 : 0 : os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
452 : 0 : custom += IW_EV_POINT_OFF;
453 : : }
454 : :
455 [ # # # # : 0 : switch (iwe->cmd) {
# # # # ]
456 : : case SIOCGIWAP:
457 : 0 : wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
458 : : MACSTR,
459 : 0 : MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
460 [ # # ]: 0 : if (is_zero_ether_addr(
461 [ # # ]: 0 : (const u8 *) iwe->u.ap_addr.sa_data) ||
462 : 0 : os_memcmp(iwe->u.ap_addr.sa_data,
463 : : "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
464 : : 0) {
465 : 0 : os_free(drv->assoc_req_ies);
466 : 0 : drv->assoc_req_ies = NULL;
467 : 0 : os_free(drv->assoc_resp_ies);
468 : 0 : drv->assoc_resp_ies = NULL;
469 : 0 : wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
470 : : NULL);
471 : :
472 : : } else {
473 : 0 : wpa_driver_wext_event_assoc_ies(drv);
474 : 0 : wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
475 : : NULL);
476 : : }
477 : 0 : break;
478 : : case IWEVMICHAELMICFAILURE:
479 [ # # ]: 0 : if (custom + iwe->u.data.length > end) {
480 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Invalid "
481 : : "IWEVMICHAELMICFAILURE length");
482 : 0 : return;
483 : : }
484 : 0 : wpa_driver_wext_event_wireless_michaelmicfailure(
485 : 0 : drv->ctx, custom, iwe->u.data.length);
486 : 0 : break;
487 : : case IWEVCUSTOM:
488 [ # # ]: 0 : if (custom + iwe->u.data.length > end) {
489 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Invalid "
490 : : "IWEVCUSTOM length");
491 : 0 : return;
492 : : }
493 : 0 : buf = dup_binstr(custom, iwe->u.data.length);
494 [ # # ]: 0 : if (buf == NULL)
495 : 0 : return;
496 : 0 : wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
497 : 0 : os_free(buf);
498 : 0 : break;
499 : : case SIOCGIWSCAN:
500 : 0 : drv->scan_complete_events = 1;
501 : 0 : eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
502 : : drv, drv->ctx);
503 : 0 : wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
504 : : NULL);
505 : 0 : break;
506 : : case IWEVASSOCREQIE:
507 [ # # ]: 0 : if (custom + iwe->u.data.length > end) {
508 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Invalid "
509 : : "IWEVASSOCREQIE length");
510 : 0 : return;
511 : : }
512 : 0 : wpa_driver_wext_event_wireless_assocreqie(
513 : 0 : drv, custom, iwe->u.data.length);
514 : 0 : break;
515 : : case IWEVASSOCRESPIE:
516 [ # # ]: 0 : if (custom + iwe->u.data.length > end) {
517 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Invalid "
518 : : "IWEVASSOCRESPIE length");
519 : 0 : return;
520 : : }
521 : 0 : wpa_driver_wext_event_wireless_assocrespie(
522 : 0 : drv, custom, iwe->u.data.length);
523 : 0 : break;
524 : : case IWEVPMKIDCAND:
525 [ # # ]: 0 : if (custom + iwe->u.data.length > end) {
526 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Invalid "
527 : : "IWEVPMKIDCAND length");
528 : 0 : return;
529 : : }
530 : 0 : wpa_driver_wext_event_wireless_pmkidcand(
531 : 0 : drv, custom, iwe->u.data.length);
532 : 0 : break;
533 : : }
534 : :
535 : 0 : pos += iwe->len;
536 : : }
537 : : }
538 : :
539 : :
540 : 0 : static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
541 : : char *buf, size_t len, int del)
542 : : {
543 : : union wpa_event_data event;
544 : :
545 : 0 : os_memset(&event, 0, sizeof(event));
546 [ # # ]: 0 : if (len > sizeof(event.interface_status.ifname))
547 : 0 : len = sizeof(event.interface_status.ifname) - 1;
548 : 0 : os_memcpy(event.interface_status.ifname, buf, len);
549 : 0 : event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
550 : : EVENT_INTERFACE_ADDED;
551 : :
552 [ # # ][ # # ]: 0 : wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
553 : : del ? "DEL" : "NEW",
554 : : event.interface_status.ifname,
555 : : del ? "removed" : "added");
556 : :
557 [ # # ]: 0 : if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
558 [ # # ]: 0 : if (del) {
559 [ # # ]: 0 : if (drv->if_removed) {
560 : 0 : wpa_printf(MSG_DEBUG, "WEXT: if_removed "
561 : : "already set - ignore event");
562 : 0 : return;
563 : : }
564 : 0 : drv->if_removed = 1;
565 : : } else {
566 [ # # ]: 0 : if (if_nametoindex(drv->ifname) == 0) {
567 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Interface %s "
568 : : "does not exist - ignore "
569 : : "RTM_NEWLINK",
570 : 0 : drv->ifname);
571 : 0 : return;
572 : : }
573 [ # # ]: 0 : if (!drv->if_removed) {
574 : 0 : wpa_printf(MSG_DEBUG, "WEXT: if_removed "
575 : : "already cleared - ignore event");
576 : 0 : return;
577 : : }
578 : 0 : drv->if_removed = 0;
579 : : }
580 : : }
581 : :
582 : 0 : wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
583 : : }
584 : :
585 : :
586 : 0 : static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
587 : : u8 *buf, size_t len)
588 : : {
589 : : int attrlen, rta_len;
590 : : struct rtattr *attr;
591 : :
592 : 0 : attrlen = len;
593 : 0 : attr = (struct rtattr *) buf;
594 : :
595 : 0 : rta_len = RTA_ALIGN(sizeof(struct rtattr));
596 [ # # ][ # # ]: 0 : while (RTA_OK(attr, attrlen)) {
[ # # ]
597 [ # # ]: 0 : if (attr->rta_type == IFLA_IFNAME) {
598 [ # # ]: 0 : if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
599 : : == 0)
600 : 0 : return 1;
601 : : else
602 : 0 : break;
603 : : }
604 : 0 : attr = RTA_NEXT(attr, attrlen);
605 : : }
606 : :
607 : 0 : return 0;
608 : : }
609 : :
610 : :
611 : 0 : static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
612 : : int ifindex, u8 *buf, size_t len)
613 : : {
614 [ # # ][ # # ]: 0 : if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
615 : 0 : return 1;
616 : :
617 [ # # ][ # # ]: 0 : if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) {
618 : 0 : drv->ifindex = if_nametoindex(drv->ifname);
619 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
620 : : "interface");
621 : 0 : wpa_driver_wext_finish_drv_init(drv);
622 : 0 : return 1;
623 : : }
624 : :
625 : 0 : return 0;
626 : : }
627 : :
628 : :
629 : 0 : static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
630 : : u8 *buf, size_t len)
631 : : {
632 : 0 : struct wpa_driver_wext_data *drv = ctx;
633 : : int attrlen, rta_len;
634 : : struct rtattr *attr;
635 : : char namebuf[IFNAMSIZ];
636 : :
637 [ # # ]: 0 : if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
638 : 0 : wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
639 : : ifi->ifi_index);
640 : 0 : return;
641 : : }
642 : :
643 [ # # ][ # # ]: 0 : wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
[ # # ][ # # ]
644 : : "(%s%s%s%s)",
645 : : drv->operstate, ifi->ifi_flags,
646 : 0 : (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
647 : 0 : (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
648 : 0 : (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
649 : 0 : (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
650 : :
651 [ # # ][ # # ]: 0 : if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
652 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Interface down");
653 : 0 : drv->if_disabled = 1;
654 : 0 : wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
655 : : }
656 : :
657 [ # # ][ # # ]: 0 : if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
658 [ # # # # ]: 0 : if (if_indextoname(ifi->ifi_index, namebuf) &&
659 : 0 : linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) {
660 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
661 : : "event since interface %s is down",
662 : : namebuf);
663 [ # # ]: 0 : } else if (if_nametoindex(drv->ifname) == 0) {
664 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
665 : : "event since interface %s does not exist",
666 : 0 : drv->ifname);
667 [ # # ]: 0 : } else if (drv->if_removed) {
668 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
669 : : "event since interface %s is marked "
670 : 0 : "removed", drv->ifname);
671 : : } else {
672 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Interface up");
673 : 0 : drv->if_disabled = 0;
674 : 0 : wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
675 : : NULL);
676 : : }
677 : : }
678 : :
679 : : /*
680 : : * Some drivers send the association event before the operup event--in
681 : : * this case, lifting operstate in wpa_driver_wext_set_operstate()
682 : : * fails. This will hit us when wpa_supplicant does not need to do
683 : : * IEEE 802.1X authentication
684 : : */
685 [ # # ][ # # ]: 0 : if (drv->operstate == 1 &&
686 [ # # ]: 0 : (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
687 : 0 : !(ifi->ifi_flags & IFF_RUNNING))
688 : 0 : netlink_send_oper_ifla(drv->netlink, drv->ifindex,
689 : : -1, IF_OPER_UP);
690 : :
691 : 0 : attrlen = len;
692 : 0 : attr = (struct rtattr *) buf;
693 : :
694 : 0 : rta_len = RTA_ALIGN(sizeof(struct rtattr));
695 [ # # ][ # # ]: 0 : while (RTA_OK(attr, attrlen)) {
[ # # ]
696 [ # # ]: 0 : if (attr->rta_type == IFLA_WIRELESS) {
697 : 0 : wpa_driver_wext_event_wireless(
698 : 0 : drv, ((char *) attr) + rta_len,
699 : 0 : attr->rta_len - rta_len);
700 [ # # ]: 0 : } else if (attr->rta_type == IFLA_IFNAME) {
701 : 0 : wpa_driver_wext_event_link(drv,
702 : 0 : ((char *) attr) + rta_len,
703 : 0 : attr->rta_len - rta_len, 0);
704 : : }
705 : 0 : attr = RTA_NEXT(attr, attrlen);
706 : : }
707 : : }
708 : :
709 : :
710 : 0 : static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
711 : : u8 *buf, size_t len)
712 : : {
713 : 0 : struct wpa_driver_wext_data *drv = ctx;
714 : : int attrlen, rta_len;
715 : : struct rtattr *attr;
716 : :
717 : 0 : attrlen = len;
718 : 0 : attr = (struct rtattr *) buf;
719 : :
720 : 0 : rta_len = RTA_ALIGN(sizeof(struct rtattr));
721 [ # # ][ # # ]: 0 : while (RTA_OK(attr, attrlen)) {
[ # # ]
722 [ # # ]: 0 : if (attr->rta_type == IFLA_IFNAME) {
723 : 0 : wpa_driver_wext_event_link(drv,
724 : 0 : ((char *) attr) + rta_len,
725 : 0 : attr->rta_len - rta_len, 1);
726 : : }
727 : 0 : attr = RTA_NEXT(attr, attrlen);
728 : : }
729 : 0 : }
730 : :
731 : :
732 : 0 : static void wpa_driver_wext_rfkill_blocked(void *ctx)
733 : : {
734 : 0 : wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked");
735 : : /*
736 : : * This may be for any interface; use ifdown event to disable
737 : : * interface.
738 : : */
739 : 0 : }
740 : :
741 : :
742 : 0 : static void wpa_driver_wext_rfkill_unblocked(void *ctx)
743 : : {
744 : 0 : struct wpa_driver_wext_data *drv = ctx;
745 : 0 : wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked");
746 [ # # ]: 0 : if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
747 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP "
748 : : "after rfkill unblock");
749 : 0 : return;
750 : : }
751 : : /* rtnetlink ifup handler will report interface as enabled */
752 : : }
753 : :
754 : :
755 : 0 : static void wext_get_phy_name(struct wpa_driver_wext_data *drv)
756 : : {
757 : : /* Find phy (radio) to which this interface belongs */
758 : : char buf[90], *pos;
759 : : int f, rv;
760 : :
761 : 0 : drv->phyname[0] = '\0';
762 : 0 : snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
763 : 0 : drv->ifname);
764 : 0 : f = open(buf, O_RDONLY);
765 [ # # ]: 0 : if (f < 0) {
766 : 0 : wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
767 : 0 : buf, strerror(errno));
768 : 0 : return;
769 : : }
770 : :
771 : 0 : rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
772 : 0 : close(f);
773 [ # # ]: 0 : if (rv < 0) {
774 : 0 : wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
775 : 0 : buf, strerror(errno));
776 : 0 : return;
777 : : }
778 : :
779 : 0 : drv->phyname[rv] = '\0';
780 : 0 : pos = os_strchr(drv->phyname, '\n');
781 [ # # ]: 0 : if (pos)
782 : 0 : *pos = '\0';
783 : 0 : wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s",
784 : 0 : drv->ifname, drv->phyname);
785 : : }
786 : :
787 : :
788 : : /**
789 : : * wpa_driver_wext_init - Initialize WE driver interface
790 : : * @ctx: context to be used when calling wpa_supplicant functions,
791 : : * e.g., wpa_supplicant_event()
792 : : * @ifname: interface name, e.g., wlan0
793 : : * Returns: Pointer to private data, %NULL on failure
794 : : */
795 : 0 : void * wpa_driver_wext_init(void *ctx, const char *ifname)
796 : : {
797 : : struct wpa_driver_wext_data *drv;
798 : : struct netlink_config *cfg;
799 : : struct rfkill_config *rcfg;
800 : : char path[128];
801 : : struct stat buf;
802 : :
803 : 0 : drv = os_zalloc(sizeof(*drv));
804 [ # # ]: 0 : if (drv == NULL)
805 : 0 : return NULL;
806 : 0 : drv->ctx = ctx;
807 : 0 : os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
808 : :
809 : 0 : os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
810 [ # # ]: 0 : if (stat(path, &buf) == 0) {
811 : 0 : wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
812 : 0 : drv->cfg80211 = 1;
813 : 0 : wext_get_phy_name(drv);
814 : : }
815 : :
816 : 0 : drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
817 [ # # ]: 0 : if (drv->ioctl_sock < 0) {
818 : 0 : perror("socket(PF_INET,SOCK_DGRAM)");
819 : 0 : goto err1;
820 : : }
821 : :
822 : 0 : cfg = os_zalloc(sizeof(*cfg));
823 [ # # ]: 0 : if (cfg == NULL)
824 : 0 : goto err1;
825 : 0 : cfg->ctx = drv;
826 : 0 : cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
827 : 0 : cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
828 : 0 : drv->netlink = netlink_init(cfg);
829 [ # # ]: 0 : if (drv->netlink == NULL) {
830 : 0 : os_free(cfg);
831 : 0 : goto err2;
832 : : }
833 : :
834 : 0 : rcfg = os_zalloc(sizeof(*rcfg));
835 [ # # ]: 0 : if (rcfg == NULL)
836 : 0 : goto err3;
837 : 0 : rcfg->ctx = drv;
838 : 0 : os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
839 : 0 : rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked;
840 : 0 : rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked;
841 : 0 : drv->rfkill = rfkill_init(rcfg);
842 [ # # ]: 0 : if (drv->rfkill == NULL) {
843 : 0 : wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");
844 : 0 : os_free(rcfg);
845 : : }
846 : :
847 : 0 : drv->mlme_sock = -1;
848 : :
849 [ # # ]: 0 : if (wpa_driver_wext_finish_drv_init(drv) < 0)
850 : 0 : goto err3;
851 : :
852 : 0 : wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
853 : :
854 : 0 : return drv;
855 : :
856 : : err3:
857 : 0 : rfkill_deinit(drv->rfkill);
858 : 0 : netlink_deinit(drv->netlink);
859 : : err2:
860 : 0 : close(drv->ioctl_sock);
861 : : err1:
862 : 0 : os_free(drv);
863 : 0 : return NULL;
864 : : }
865 : :
866 : :
867 : 0 : static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
868 : : {
869 : 0 : wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
870 : 0 : }
871 : :
872 : :
873 : 0 : static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
874 : : {
875 : 0 : int send_rfkill_event = 0;
876 : :
877 [ # # ]: 0 : if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) {
878 [ # # ]: 0 : if (rfkill_is_blocked(drv->rfkill)) {
879 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable "
880 : : "interface '%s' due to rfkill",
881 : 0 : drv->ifname);
882 : 0 : drv->if_disabled = 1;
883 : 0 : send_rfkill_event = 1;
884 : : } else {
885 : 0 : wpa_printf(MSG_ERROR, "WEXT: Could not set "
886 : 0 : "interface '%s' UP", drv->ifname);
887 : 0 : return -1;
888 : : }
889 : : }
890 : :
891 : : /*
892 : : * Make sure that the driver does not have any obsolete PMKID entries.
893 : : */
894 : 0 : wpa_driver_wext_flush_pmkid(drv);
895 : :
896 [ # # ]: 0 : if (wpa_driver_wext_set_mode(drv, 0) < 0) {
897 : 0 : wpa_printf(MSG_DEBUG, "Could not configure driver to use "
898 : : "managed mode");
899 : : /* Try to use it anyway */
900 : : }
901 : :
902 : 0 : wpa_driver_wext_get_range(drv);
903 : :
904 : : /*
905 : : * Unlock the driver's BSSID and force to a random SSID to clear any
906 : : * previous association the driver might have when the supplicant
907 : : * starts up.
908 : : */
909 : 0 : wpa_driver_wext_disconnect(drv);
910 : :
911 : 0 : drv->ifindex = if_nametoindex(drv->ifname);
912 : :
913 [ # # ]: 0 : if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
914 : : /*
915 : : * Host AP driver may use both wlan# and wifi# interface in
916 : : * wireless events. Since some of the versions included WE-18
917 : : * support, let's add the alternative ifindex also from
918 : : * driver_wext.c for the time being. This may be removed at
919 : : * some point once it is believed that old versions of the
920 : : * driver are not in use anymore.
921 : : */
922 : : char ifname2[IFNAMSIZ + 1];
923 : 0 : os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
924 : 0 : os_memcpy(ifname2, "wifi", 4);
925 : 0 : wpa_driver_wext_alternative_ifindex(drv, ifname2);
926 : : }
927 : :
928 : 0 : netlink_send_oper_ifla(drv->netlink, drv->ifindex,
929 : : 1, IF_OPER_DORMANT);
930 : :
931 [ # # ]: 0 : if (send_rfkill_event) {
932 : 0 : eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill,
933 : : drv, drv->ctx);
934 : : }
935 : :
936 : 0 : return 0;
937 : : }
938 : :
939 : :
940 : : /**
941 : : * wpa_driver_wext_deinit - Deinitialize WE driver interface
942 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
943 : : *
944 : : * Shut down driver interface and processing of driver events. Free
945 : : * private data buffer if one was allocated in wpa_driver_wext_init().
946 : : */
947 : 0 : void wpa_driver_wext_deinit(void *priv)
948 : : {
949 : 0 : struct wpa_driver_wext_data *drv = priv;
950 : :
951 : 0 : wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
952 : :
953 : 0 : eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
954 : :
955 : : /*
956 : : * Clear possibly configured driver parameters in order to make it
957 : : * easier to use the driver after wpa_supplicant has been terminated.
958 : : */
959 : 0 : wpa_driver_wext_disconnect(drv);
960 : :
961 : 0 : netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
962 : 0 : netlink_deinit(drv->netlink);
963 : 0 : rfkill_deinit(drv->rfkill);
964 : :
965 [ # # ]: 0 : if (drv->mlme_sock >= 0)
966 : 0 : eloop_unregister_read_sock(drv->mlme_sock);
967 : :
968 : 0 : (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
969 : :
970 : 0 : close(drv->ioctl_sock);
971 [ # # ]: 0 : if (drv->mlme_sock >= 0)
972 : 0 : close(drv->mlme_sock);
973 : 0 : os_free(drv->assoc_req_ies);
974 : 0 : os_free(drv->assoc_resp_ies);
975 : 0 : os_free(drv);
976 : 0 : }
977 : :
978 : :
979 : : /**
980 : : * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion
981 : : * @eloop_ctx: Unused
982 : : * @timeout_ctx: ctx argument given to wpa_driver_wext_init()
983 : : *
984 : : * This function can be used as registered timeout when starting a scan to
985 : : * generate a scan completed event if the driver does not report this.
986 : : */
987 : 0 : void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
988 : : {
989 : 0 : wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
990 : 0 : wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
991 : 0 : }
992 : :
993 : :
994 : : /**
995 : : * wpa_driver_wext_scan - Request the driver to initiate scan
996 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
997 : : * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.)
998 : : * Returns: 0 on success, -1 on failure
999 : : */
1000 : 0 : int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
1001 : : {
1002 : 0 : struct wpa_driver_wext_data *drv = priv;
1003 : : struct iwreq iwr;
1004 : 0 : int ret = 0, timeout;
1005 : : struct iw_scan_req req;
1006 : 0 : const u8 *ssid = params->ssids[0].ssid;
1007 : 0 : size_t ssid_len = params->ssids[0].ssid_len;
1008 : :
1009 [ # # ]: 0 : if (ssid_len > IW_ESSID_MAX_SIZE) {
1010 : 0 : wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
1011 : : __FUNCTION__, (unsigned long) ssid_len);
1012 : 0 : return -1;
1013 : : }
1014 : :
1015 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1016 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1017 : :
1018 [ # # ][ # # ]: 0 : if (ssid && ssid_len) {
1019 : 0 : os_memset(&req, 0, sizeof(req));
1020 : 0 : req.essid_len = ssid_len;
1021 : 0 : req.bssid.sa_family = ARPHRD_ETHER;
1022 : 0 : os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
1023 : 0 : os_memcpy(req.essid, ssid, ssid_len);
1024 : 0 : iwr.u.data.pointer = (caddr_t) &req;
1025 : 0 : iwr.u.data.length = sizeof(req);
1026 : 0 : iwr.u.data.flags = IW_SCAN_THIS_ESSID;
1027 : : }
1028 : :
1029 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
1030 : 0 : perror("ioctl[SIOCSIWSCAN]");
1031 : 0 : ret = -1;
1032 : : }
1033 : :
1034 : : /* Not all drivers generate "scan completed" wireless event, so try to
1035 : : * read results after a timeout. */
1036 : 0 : timeout = 10;
1037 [ # # ]: 0 : if (drv->scan_complete_events) {
1038 : : /*
1039 : : * The driver seems to deliver SIOCGIWSCAN events to notify
1040 : : * when scan is complete, so use longer timeout to avoid race
1041 : : * conditions with scanning and following association request.
1042 : : */
1043 : 0 : timeout = 30;
1044 : : }
1045 : 0 : wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
1046 : : "seconds", ret, timeout);
1047 : 0 : eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
1048 : 0 : eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
1049 : : drv->ctx);
1050 : :
1051 : 0 : return ret;
1052 : : }
1053 : :
1054 : :
1055 : 0 : static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv,
1056 : : size_t *len)
1057 : : {
1058 : : struct iwreq iwr;
1059 : : u8 *res_buf;
1060 : : size_t res_buf_len;
1061 : :
1062 : 0 : res_buf_len = IW_SCAN_MAX_DATA;
1063 : : for (;;) {
1064 : 0 : res_buf = os_malloc(res_buf_len);
1065 [ # # ]: 0 : if (res_buf == NULL)
1066 : 0 : return NULL;
1067 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1068 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1069 : 0 : iwr.u.data.pointer = res_buf;
1070 : 0 : iwr.u.data.length = res_buf_len;
1071 : :
1072 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
1073 : 0 : break;
1074 : :
1075 [ # # ][ # # ]: 0 : if (errno == E2BIG && res_buf_len < 65535) {
1076 : 0 : os_free(res_buf);
1077 : 0 : res_buf = NULL;
1078 : 0 : res_buf_len *= 2;
1079 [ # # ]: 0 : if (res_buf_len > 65535)
1080 : 0 : res_buf_len = 65535; /* 16-bit length field */
1081 : 0 : wpa_printf(MSG_DEBUG, "Scan results did not fit - "
1082 : : "trying larger buffer (%lu bytes)",
1083 : : (unsigned long) res_buf_len);
1084 : : } else {
1085 : 0 : perror("ioctl[SIOCGIWSCAN]");
1086 : 0 : os_free(res_buf);
1087 : 0 : return NULL;
1088 : : }
1089 : 0 : }
1090 : :
1091 [ # # ]: 0 : if (iwr.u.data.length > res_buf_len) {
1092 : 0 : os_free(res_buf);
1093 : 0 : return NULL;
1094 : : }
1095 : 0 : *len = iwr.u.data.length;
1096 : :
1097 : 0 : return res_buf;
1098 : : }
1099 : :
1100 : :
1101 : : /*
1102 : : * Data structure for collecting WEXT scan results. This is needed to allow
1103 : : * the various methods of reporting IEs to be combined into a single IE buffer.
1104 : : */
1105 : : struct wext_scan_data {
1106 : : struct wpa_scan_res res;
1107 : : u8 *ie;
1108 : : size_t ie_len;
1109 : : u8 ssid[32];
1110 : : size_t ssid_len;
1111 : : int maxrate;
1112 : : };
1113 : :
1114 : :
1115 : 0 : static void wext_get_scan_mode(struct iw_event *iwe,
1116 : : struct wext_scan_data *res)
1117 : : {
1118 [ # # ]: 0 : if (iwe->u.mode == IW_MODE_ADHOC)
1119 : 0 : res->res.caps |= IEEE80211_CAP_IBSS;
1120 [ # # ][ # # ]: 0 : else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
1121 : 0 : res->res.caps |= IEEE80211_CAP_ESS;
1122 : 0 : }
1123 : :
1124 : :
1125 : 0 : static void wext_get_scan_ssid(struct iw_event *iwe,
1126 : : struct wext_scan_data *res, char *custom,
1127 : : char *end)
1128 : : {
1129 : 0 : int ssid_len = iwe->u.essid.length;
1130 [ # # ]: 0 : if (custom + ssid_len > end)
1131 : 0 : return;
1132 [ # # ][ # # ]: 0 : if (iwe->u.essid.flags &&
1133 [ # # ]: 0 : ssid_len > 0 &&
1134 : : ssid_len <= IW_ESSID_MAX_SIZE) {
1135 : 0 : os_memcpy(res->ssid, custom, ssid_len);
1136 : 0 : res->ssid_len = ssid_len;
1137 : : }
1138 : : }
1139 : :
1140 : :
1141 : 0 : static void wext_get_scan_freq(struct iw_event *iwe,
1142 : : struct wext_scan_data *res)
1143 : : {
1144 : 0 : int divi = 1000000, i;
1145 : :
1146 [ # # ]: 0 : if (iwe->u.freq.e == 0) {
1147 : : /*
1148 : : * Some drivers do not report frequency, but a channel.
1149 : : * Try to map this to frequency by assuming they are using
1150 : : * IEEE 802.11b/g. But don't overwrite a previously parsed
1151 : : * frequency if the driver sends both frequency and channel,
1152 : : * since the driver may be sending an A-band channel that we
1153 : : * don't handle here.
1154 : : */
1155 : :
1156 [ # # ]: 0 : if (res->res.freq)
1157 : 0 : return;
1158 : :
1159 [ # # ][ # # ]: 0 : if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
1160 : 0 : res->res.freq = 2407 + 5 * iwe->u.freq.m;
1161 : 0 : return;
1162 [ # # ]: 0 : } else if (iwe->u.freq.m == 14) {
1163 : 0 : res->res.freq = 2484;
1164 : 0 : return;
1165 : : }
1166 : : }
1167 : :
1168 [ # # ]: 0 : if (iwe->u.freq.e > 6) {
1169 : 0 : wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
1170 : : MACSTR " m=%d e=%d)",
1171 : 0 : MAC2STR(res->res.bssid), iwe->u.freq.m,
1172 : 0 : iwe->u.freq.e);
1173 : 0 : return;
1174 : : }
1175 : :
1176 [ # # ]: 0 : for (i = 0; i < iwe->u.freq.e; i++)
1177 : 0 : divi /= 10;
1178 : 0 : res->res.freq = iwe->u.freq.m / divi;
1179 : : }
1180 : :
1181 : :
1182 : 0 : static void wext_get_scan_qual(struct wpa_driver_wext_data *drv,
1183 : : struct iw_event *iwe,
1184 : : struct wext_scan_data *res)
1185 : : {
1186 : 0 : res->res.qual = iwe->u.qual.qual;
1187 : 0 : res->res.noise = iwe->u.qual.noise;
1188 : 0 : res->res.level = iwe->u.qual.level;
1189 [ # # ]: 0 : if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID)
1190 : 0 : res->res.flags |= WPA_SCAN_QUAL_INVALID;
1191 [ # # ]: 0 : if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID)
1192 : 0 : res->res.flags |= WPA_SCAN_LEVEL_INVALID;
1193 [ # # ]: 0 : if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID)
1194 : 0 : res->res.flags |= WPA_SCAN_NOISE_INVALID;
1195 [ # # ]: 0 : if (iwe->u.qual.updated & IW_QUAL_DBM)
1196 : 0 : res->res.flags |= WPA_SCAN_LEVEL_DBM;
1197 [ # # ][ # # ]: 0 : if ((iwe->u.qual.updated & IW_QUAL_DBM) ||
1198 [ # # ]: 0 : ((iwe->u.qual.level != 0) &&
1199 : 0 : (iwe->u.qual.level > drv->max_level))) {
1200 [ # # ]: 0 : if (iwe->u.qual.level >= 64)
1201 : 0 : res->res.level -= 0x100;
1202 [ # # ]: 0 : if (iwe->u.qual.noise >= 64)
1203 : 0 : res->res.noise -= 0x100;
1204 : : }
1205 : 0 : }
1206 : :
1207 : :
1208 : 0 : static void wext_get_scan_encode(struct iw_event *iwe,
1209 : : struct wext_scan_data *res)
1210 : : {
1211 [ # # ]: 0 : if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
1212 : 0 : res->res.caps |= IEEE80211_CAP_PRIVACY;
1213 : 0 : }
1214 : :
1215 : :
1216 : 0 : static void wext_get_scan_rate(struct iw_event *iwe,
1217 : : struct wext_scan_data *res, char *pos,
1218 : : char *end)
1219 : : {
1220 : : int maxrate;
1221 : 0 : char *custom = pos + IW_EV_LCP_LEN;
1222 : : struct iw_param p;
1223 : : size_t clen;
1224 : :
1225 : 0 : clen = iwe->len;
1226 [ # # ]: 0 : if (custom + clen > end)
1227 : 0 : return;
1228 : 0 : maxrate = 0;
1229 [ # # ]: 0 : while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
1230 : : /* Note: may be misaligned, make a local, aligned copy */
1231 : 0 : os_memcpy(&p, custom, sizeof(struct iw_param));
1232 [ # # ]: 0 : if (p.value > maxrate)
1233 : 0 : maxrate = p.value;
1234 : 0 : clen -= sizeof(struct iw_param);
1235 : 0 : custom += sizeof(struct iw_param);
1236 : : }
1237 : :
1238 : : /* Convert the maxrate from WE-style (b/s units) to
1239 : : * 802.11 rates (500000 b/s units).
1240 : : */
1241 : 0 : res->maxrate = maxrate / 500000;
1242 : : }
1243 : :
1244 : :
1245 : 0 : static void wext_get_scan_iwevgenie(struct iw_event *iwe,
1246 : : struct wext_scan_data *res, char *custom,
1247 : : char *end)
1248 : : {
1249 : : char *genie, *gpos, *gend;
1250 : : u8 *tmp;
1251 : :
1252 [ # # ]: 0 : if (iwe->u.data.length == 0)
1253 : 0 : return;
1254 : :
1255 : 0 : gpos = genie = custom;
1256 : 0 : gend = genie + iwe->u.data.length;
1257 [ # # ]: 0 : if (gend > end) {
1258 : 0 : wpa_printf(MSG_INFO, "IWEVGENIE overflow");
1259 : 0 : return;
1260 : : }
1261 : :
1262 : 0 : tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
1263 [ # # ]: 0 : if (tmp == NULL)
1264 : 0 : return;
1265 : 0 : os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
1266 : 0 : res->ie = tmp;
1267 : 0 : res->ie_len += gend - gpos;
1268 : : }
1269 : :
1270 : :
1271 : 0 : static void wext_get_scan_custom(struct iw_event *iwe,
1272 : : struct wext_scan_data *res, char *custom,
1273 : : char *end)
1274 : : {
1275 : : size_t clen;
1276 : : u8 *tmp;
1277 : :
1278 : 0 : clen = iwe->u.data.length;
1279 [ # # ]: 0 : if (custom + clen > end)
1280 : 0 : return;
1281 : :
1282 [ # # ][ # # ]: 0 : if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
1283 : : char *spos;
1284 : : int bytes;
1285 : 0 : spos = custom + 7;
1286 : 0 : bytes = custom + clen - spos;
1287 [ # # ][ # # ]: 0 : if (bytes & 1 || bytes == 0)
1288 : 0 : return;
1289 : 0 : bytes /= 2;
1290 : 0 : tmp = os_realloc(res->ie, res->ie_len + bytes);
1291 [ # # ]: 0 : if (tmp == NULL)
1292 : 0 : return;
1293 : 0 : res->ie = tmp;
1294 [ # # ]: 0 : if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
1295 : 0 : return;
1296 : 0 : res->ie_len += bytes;
1297 [ # # ][ # # ]: 0 : } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
1298 : : char *spos;
1299 : : int bytes;
1300 : 0 : spos = custom + 7;
1301 : 0 : bytes = custom + clen - spos;
1302 [ # # ][ # # ]: 0 : if (bytes & 1 || bytes == 0)
1303 : 0 : return;
1304 : 0 : bytes /= 2;
1305 : 0 : tmp = os_realloc(res->ie, res->ie_len + bytes);
1306 [ # # ]: 0 : if (tmp == NULL)
1307 : 0 : return;
1308 : 0 : res->ie = tmp;
1309 [ # # ]: 0 : if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
1310 : 0 : return;
1311 : 0 : res->ie_len += bytes;
1312 [ # # ][ # # ]: 0 : } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
1313 : : char *spos;
1314 : : int bytes;
1315 : : u8 bin[8];
1316 : 0 : spos = custom + 4;
1317 : 0 : bytes = custom + clen - spos;
1318 [ # # ]: 0 : if (bytes != 16) {
1319 : 0 : wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
1320 : 0 : return;
1321 : : }
1322 : 0 : bytes /= 2;
1323 [ # # ]: 0 : if (hexstr2bin(spos, bin, bytes) < 0) {
1324 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value");
1325 : 0 : return;
1326 : : }
1327 : 0 : res->res.tsf += WPA_GET_BE64(bin);
1328 : : }
1329 : : }
1330 : :
1331 : :
1332 : 0 : static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd)
1333 : : {
1334 [ # # ][ # # ]: 0 : return drv->we_version_compiled > 18 &&
1335 [ # # ][ # # ]: 0 : (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
1336 [ # # ]: 0 : cmd == IWEVGENIE || cmd == IWEVCUSTOM);
1337 : : }
1338 : :
1339 : :
1340 : 0 : static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
1341 : : struct wext_scan_data *data)
1342 : : {
1343 : : struct wpa_scan_res **tmp;
1344 : : struct wpa_scan_res *r;
1345 : : size_t extra_len;
1346 : 0 : u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
1347 : :
1348 : : /* Figure out whether we need to fake any IEs */
1349 : 0 : pos = data->ie;
1350 : 0 : end = pos + data->ie_len;
1351 [ # # ][ # # ]: 0 : while (pos && pos + 1 < end) {
1352 [ # # ]: 0 : if (pos + 2 + pos[1] > end)
1353 : 0 : break;
1354 [ # # ]: 0 : if (pos[0] == WLAN_EID_SSID)
1355 : 0 : ssid_ie = pos;
1356 [ # # ]: 0 : else if (pos[0] == WLAN_EID_SUPP_RATES)
1357 : 0 : rate_ie = pos;
1358 [ # # ]: 0 : else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
1359 : 0 : rate_ie = pos;
1360 : 0 : pos += 2 + pos[1];
1361 : : }
1362 : :
1363 : 0 : extra_len = 0;
1364 [ # # ]: 0 : if (ssid_ie == NULL)
1365 : 0 : extra_len += 2 + data->ssid_len;
1366 [ # # ][ # # ]: 0 : if (rate_ie == NULL && data->maxrate)
1367 : 0 : extra_len += 3;
1368 : :
1369 : 0 : r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
1370 [ # # ]: 0 : if (r == NULL)
1371 : 0 : return;
1372 : 0 : os_memcpy(r, &data->res, sizeof(*r));
1373 : 0 : r->ie_len = extra_len + data->ie_len;
1374 : 0 : pos = (u8 *) (r + 1);
1375 [ # # ]: 0 : if (ssid_ie == NULL) {
1376 : : /*
1377 : : * Generate a fake SSID IE since the driver did not report
1378 : : * a full IE list.
1379 : : */
1380 : 0 : *pos++ = WLAN_EID_SSID;
1381 : 0 : *pos++ = data->ssid_len;
1382 : 0 : os_memcpy(pos, data->ssid, data->ssid_len);
1383 : 0 : pos += data->ssid_len;
1384 : : }
1385 [ # # ][ # # ]: 0 : if (rate_ie == NULL && data->maxrate) {
1386 : : /*
1387 : : * Generate a fake Supported Rates IE since the driver did not
1388 : : * report a full IE list.
1389 : : */
1390 : 0 : *pos++ = WLAN_EID_SUPP_RATES;
1391 : 0 : *pos++ = 1;
1392 : 0 : *pos++ = data->maxrate;
1393 : : }
1394 [ # # ]: 0 : if (data->ie)
1395 : 0 : os_memcpy(pos, data->ie, data->ie_len);
1396 : :
1397 : 0 : tmp = os_realloc_array(res->res, res->num + 1,
1398 : : sizeof(struct wpa_scan_res *));
1399 [ # # ]: 0 : if (tmp == NULL) {
1400 : 0 : os_free(r);
1401 : 0 : return;
1402 : : }
1403 : 0 : tmp[res->num++] = r;
1404 : 0 : res->res = tmp;
1405 : : }
1406 : :
1407 : :
1408 : : /**
1409 : : * wpa_driver_wext_get_scan_results - Fetch the latest scan results
1410 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
1411 : : * Returns: Scan results on success, -1 on failure
1412 : : */
1413 : 0 : struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
1414 : : {
1415 : 0 : struct wpa_driver_wext_data *drv = priv;
1416 : : size_t len;
1417 : : int first;
1418 : : u8 *res_buf;
1419 : 0 : struct iw_event iwe_buf, *iwe = &iwe_buf;
1420 : : char *pos, *end, *custom;
1421 : : struct wpa_scan_results *res;
1422 : : struct wext_scan_data data;
1423 : :
1424 : 0 : res_buf = wpa_driver_wext_giwscan(drv, &len);
1425 [ # # ]: 0 : if (res_buf == NULL)
1426 : 0 : return NULL;
1427 : :
1428 : 0 : first = 1;
1429 : :
1430 : 0 : res = os_zalloc(sizeof(*res));
1431 [ # # ]: 0 : if (res == NULL) {
1432 : 0 : os_free(res_buf);
1433 : 0 : return NULL;
1434 : : }
1435 : :
1436 : 0 : pos = (char *) res_buf;
1437 : 0 : end = (char *) res_buf + len;
1438 : 0 : os_memset(&data, 0, sizeof(data));
1439 : :
1440 [ # # ]: 0 : while (pos + IW_EV_LCP_LEN <= end) {
1441 : : /* Event data may be unaligned, so make a local, aligned copy
1442 : : * before processing. */
1443 : 0 : os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
1444 [ # # ]: 0 : if (iwe->len <= IW_EV_LCP_LEN)
1445 : 0 : break;
1446 : :
1447 : 0 : custom = pos + IW_EV_POINT_LEN;
1448 [ # # ]: 0 : if (wext_19_iw_point(drv, iwe->cmd)) {
1449 : : /* WE-19 removed the pointer from struct iw_point */
1450 : 0 : char *dpos = (char *) &iwe_buf.u.data.length;
1451 : 0 : int dlen = dpos - (char *) &iwe_buf;
1452 : 0 : os_memcpy(dpos, pos + IW_EV_LCP_LEN,
1453 : : sizeof(struct iw_event) - dlen);
1454 : : } else {
1455 : 0 : os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
1456 : 0 : custom += IW_EV_POINT_OFF;
1457 : : }
1458 : :
1459 [ # # # # : 0 : switch (iwe->cmd) {
# # # # #
# ]
1460 : : case SIOCGIWAP:
1461 [ # # ]: 0 : if (!first)
1462 : 0 : wpa_driver_wext_add_scan_entry(res, &data);
1463 : 0 : first = 0;
1464 : 0 : os_free(data.ie);
1465 : 0 : os_memset(&data, 0, sizeof(data));
1466 : 0 : os_memcpy(data.res.bssid,
1467 : : iwe->u.ap_addr.sa_data, ETH_ALEN);
1468 : 0 : break;
1469 : : case SIOCGIWMODE:
1470 : 0 : wext_get_scan_mode(iwe, &data);
1471 : 0 : break;
1472 : : case SIOCGIWESSID:
1473 : 0 : wext_get_scan_ssid(iwe, &data, custom, end);
1474 : 0 : break;
1475 : : case SIOCGIWFREQ:
1476 : 0 : wext_get_scan_freq(iwe, &data);
1477 : 0 : break;
1478 : : case IWEVQUAL:
1479 : 0 : wext_get_scan_qual(drv, iwe, &data);
1480 : 0 : break;
1481 : : case SIOCGIWENCODE:
1482 : 0 : wext_get_scan_encode(iwe, &data);
1483 : 0 : break;
1484 : : case SIOCGIWRATE:
1485 : 0 : wext_get_scan_rate(iwe, &data, pos, end);
1486 : 0 : break;
1487 : : case IWEVGENIE:
1488 : 0 : wext_get_scan_iwevgenie(iwe, &data, custom, end);
1489 : 0 : break;
1490 : : case IWEVCUSTOM:
1491 : 0 : wext_get_scan_custom(iwe, &data, custom, end);
1492 : 0 : break;
1493 : : }
1494 : :
1495 : 0 : pos += iwe->len;
1496 : : }
1497 : 0 : os_free(res_buf);
1498 : 0 : res_buf = NULL;
1499 [ # # ]: 0 : if (!first)
1500 : 0 : wpa_driver_wext_add_scan_entry(res, &data);
1501 : 0 : os_free(data.ie);
1502 : :
1503 : 0 : wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
1504 : : (unsigned long) len, (unsigned long) res->num);
1505 : :
1506 : 0 : return res;
1507 : : }
1508 : :
1509 : :
1510 : 0 : static int wpa_driver_wext_get_range(void *priv)
1511 : : {
1512 : 0 : struct wpa_driver_wext_data *drv = priv;
1513 : : struct iw_range *range;
1514 : : struct iwreq iwr;
1515 : : int minlen;
1516 : : size_t buflen;
1517 : :
1518 : : /*
1519 : : * Use larger buffer than struct iw_range in order to allow the
1520 : : * structure to grow in the future.
1521 : : */
1522 : 0 : buflen = sizeof(struct iw_range) + 500;
1523 : 0 : range = os_zalloc(buflen);
1524 [ # # ]: 0 : if (range == NULL)
1525 : 0 : return -1;
1526 : :
1527 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1528 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1529 : 0 : iwr.u.data.pointer = (caddr_t) range;
1530 : 0 : iwr.u.data.length = buflen;
1531 : :
1532 : 0 : minlen = ((char *) &range->enc_capa) - (char *) range +
1533 : : sizeof(range->enc_capa);
1534 : :
1535 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
1536 : 0 : perror("ioctl[SIOCGIWRANGE]");
1537 : 0 : os_free(range);
1538 : 0 : return -1;
1539 [ # # ][ # # ]: 0 : } else if (iwr.u.data.length >= minlen &&
1540 : 0 : range->we_version_compiled >= 18) {
1541 : 0 : wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
1542 : : "WE(source)=%d enc_capa=0x%x",
1543 : 0 : range->we_version_compiled,
1544 : 0 : range->we_version_source,
1545 : : range->enc_capa);
1546 : 0 : drv->has_capability = 1;
1547 : 0 : drv->we_version_compiled = range->we_version_compiled;
1548 [ # # ]: 0 : if (range->enc_capa & IW_ENC_CAPA_WPA) {
1549 : 0 : drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1550 : : WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1551 : : }
1552 [ # # ]: 0 : if (range->enc_capa & IW_ENC_CAPA_WPA2) {
1553 : 0 : drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1554 : : WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1555 : : }
1556 : 0 : drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
1557 : : WPA_DRIVER_CAPA_ENC_WEP104;
1558 : 0 : drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128;
1559 [ # # ]: 0 : if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
1560 : 0 : drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1561 [ # # ]: 0 : if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
1562 : 0 : drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1563 [ # # ]: 0 : if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
1564 : 0 : drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
1565 : 0 : drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
1566 : : WPA_DRIVER_AUTH_SHARED |
1567 : : WPA_DRIVER_AUTH_LEAP;
1568 : 0 : drv->capa.max_scan_ssids = 1;
1569 : :
1570 : 0 : wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
1571 : : "flags 0x%x",
1572 : : drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
1573 : : } else {
1574 : 0 : wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
1575 : : "assuming WPA is not supported");
1576 : : }
1577 : :
1578 : 0 : drv->max_level = range->max_qual.level;
1579 : :
1580 : 0 : os_free(range);
1581 : 0 : return 0;
1582 : : }
1583 : :
1584 : :
1585 : 0 : static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
1586 : : const u8 *psk)
1587 : : {
1588 : : struct iw_encode_ext *ext;
1589 : : struct iwreq iwr;
1590 : : int ret;
1591 : :
1592 : 0 : wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1593 : :
1594 [ # # ]: 0 : if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
1595 : 0 : return 0;
1596 : :
1597 [ # # ]: 0 : if (!psk)
1598 : 0 : return 0;
1599 : :
1600 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1601 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1602 : :
1603 : 0 : ext = os_zalloc(sizeof(*ext) + PMK_LEN);
1604 [ # # ]: 0 : if (ext == NULL)
1605 : 0 : return -1;
1606 : :
1607 : 0 : iwr.u.encoding.pointer = (caddr_t) ext;
1608 : 0 : iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
1609 : 0 : ext->key_len = PMK_LEN;
1610 : 0 : os_memcpy(&ext->key, psk, ext->key_len);
1611 : 0 : ext->alg = IW_ENCODE_ALG_PMK;
1612 : :
1613 : 0 : ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
1614 [ # # ]: 0 : if (ret < 0)
1615 : 0 : perror("ioctl[SIOCSIWENCODEEXT] PMK");
1616 : 0 : os_free(ext);
1617 : :
1618 : 0 : return ret;
1619 : : }
1620 : :
1621 : :
1622 : 0 : static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
1623 : : const u8 *addr, int key_idx,
1624 : : int set_tx, const u8 *seq,
1625 : : size_t seq_len,
1626 : : const u8 *key, size_t key_len)
1627 : : {
1628 : 0 : struct wpa_driver_wext_data *drv = priv;
1629 : : struct iwreq iwr;
1630 : 0 : int ret = 0;
1631 : : struct iw_encode_ext *ext;
1632 : :
1633 [ # # ]: 0 : if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
1634 : 0 : wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
1635 : : __FUNCTION__, (unsigned long) seq_len);
1636 : 0 : return -1;
1637 : : }
1638 : :
1639 : 0 : ext = os_zalloc(sizeof(*ext) + key_len);
1640 [ # # ]: 0 : if (ext == NULL)
1641 : 0 : return -1;
1642 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1643 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1644 : 0 : iwr.u.encoding.flags = key_idx + 1;
1645 : 0 : iwr.u.encoding.flags |= IW_ENCODE_TEMP;
1646 [ # # ]: 0 : if (alg == WPA_ALG_NONE)
1647 : 0 : iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
1648 : 0 : iwr.u.encoding.pointer = (caddr_t) ext;
1649 : 0 : iwr.u.encoding.length = sizeof(*ext) + key_len;
1650 : :
1651 [ # # ][ # # ]: 0 : if (addr == NULL || is_broadcast_ether_addr(addr))
1652 : 0 : ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
1653 [ # # ]: 0 : if (set_tx)
1654 : 0 : ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
1655 : :
1656 : 0 : ext->addr.sa_family = ARPHRD_ETHER;
1657 [ # # ]: 0 : if (addr)
1658 : 0 : os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
1659 : : else
1660 : 0 : os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
1661 [ # # ][ # # ]: 0 : if (key && key_len) {
1662 : 0 : os_memcpy(ext + 1, key, key_len);
1663 : 0 : ext->key_len = key_len;
1664 : : }
1665 [ # # # # : 0 : switch (alg) {
# # # ]
1666 : : case WPA_ALG_NONE:
1667 : 0 : ext->alg = IW_ENCODE_ALG_NONE;
1668 : 0 : break;
1669 : : case WPA_ALG_WEP:
1670 : 0 : ext->alg = IW_ENCODE_ALG_WEP;
1671 : 0 : break;
1672 : : case WPA_ALG_TKIP:
1673 : 0 : ext->alg = IW_ENCODE_ALG_TKIP;
1674 : 0 : break;
1675 : : case WPA_ALG_CCMP:
1676 : 0 : ext->alg = IW_ENCODE_ALG_CCMP;
1677 : 0 : break;
1678 : : case WPA_ALG_PMK:
1679 : 0 : ext->alg = IW_ENCODE_ALG_PMK;
1680 : 0 : break;
1681 : : #ifdef CONFIG_IEEE80211W
1682 : : case WPA_ALG_IGTK:
1683 : 0 : ext->alg = IW_ENCODE_ALG_AES_CMAC;
1684 : 0 : break;
1685 : : #endif /* CONFIG_IEEE80211W */
1686 : : default:
1687 : 0 : wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
1688 : : __FUNCTION__, alg);
1689 : 0 : os_free(ext);
1690 : 0 : return -1;
1691 : : }
1692 : :
1693 [ # # ][ # # ]: 0 : if (seq && seq_len) {
1694 : 0 : ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
1695 : 0 : os_memcpy(ext->rx_seq, seq, seq_len);
1696 : : }
1697 : :
1698 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
1699 [ # # ]: 0 : ret = errno == EOPNOTSUPP ? -2 : -1;
1700 [ # # ]: 0 : if (errno == ENODEV) {
1701 : : /*
1702 : : * ndiswrapper seems to be returning incorrect error
1703 : : * code.. */
1704 : 0 : ret = -2;
1705 : : }
1706 : :
1707 : 0 : perror("ioctl[SIOCSIWENCODEEXT]");
1708 : : }
1709 : :
1710 : 0 : os_free(ext);
1711 : 0 : return ret;
1712 : : }
1713 : :
1714 : :
1715 : : /**
1716 : : * wpa_driver_wext_set_key - Configure encryption key
1717 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
1718 : : * @priv: Private driver interface data
1719 : : * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
1720 : : * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
1721 : : * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
1722 : : * broadcast/default keys
1723 : : * @key_idx: key index (0..3), usually 0 for unicast keys
1724 : : * @set_tx: Configure this key as the default Tx key (only used when
1725 : : * driver does not support separate unicast/individual key
1726 : : * @seq: Sequence number/packet number, seq_len octets, the next
1727 : : * packet number to be used for in replay protection; configured
1728 : : * for Rx keys (in most cases, this is only used with broadcast
1729 : : * keys and set to zero for unicast keys)
1730 : : * @seq_len: Length of the seq, depends on the algorithm:
1731 : : * TKIP: 6 octets, CCMP: 6 octets
1732 : : * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
1733 : : * 8-byte Rx Mic Key
1734 : : * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
1735 : : * TKIP: 32, CCMP: 16)
1736 : : * Returns: 0 on success, -1 on failure
1737 : : *
1738 : : * This function uses SIOCSIWENCODEEXT by default, but tries to use
1739 : : * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
1740 : : */
1741 : 0 : int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
1742 : : const u8 *addr, int key_idx,
1743 : : int set_tx, const u8 *seq, size_t seq_len,
1744 : : const u8 *key, size_t key_len)
1745 : : {
1746 : 0 : struct wpa_driver_wext_data *drv = priv;
1747 : : struct iwreq iwr;
1748 : 0 : int ret = 0;
1749 : :
1750 : 0 : wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
1751 : : "key_len=%lu",
1752 : : __FUNCTION__, alg, key_idx, set_tx,
1753 : : (unsigned long) seq_len, (unsigned long) key_len);
1754 : :
1755 : 0 : ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
1756 : : seq, seq_len, key, key_len);
1757 [ # # ]: 0 : if (ret == 0)
1758 : 0 : return 0;
1759 : :
1760 [ # # ][ # # ]: 0 : if (ret == -2 &&
1761 [ # # ]: 0 : (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
1762 : 0 : wpa_printf(MSG_DEBUG, "Driver did not support "
1763 : : "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
1764 : 0 : ret = 0;
1765 : : } else {
1766 : 0 : wpa_printf(MSG_DEBUG, "Driver did not support "
1767 : : "SIOCSIWENCODEEXT");
1768 : 0 : return ret;
1769 : : }
1770 : :
1771 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1772 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1773 : 0 : iwr.u.encoding.flags = key_idx + 1;
1774 : 0 : iwr.u.encoding.flags |= IW_ENCODE_TEMP;
1775 [ # # ]: 0 : if (alg == WPA_ALG_NONE)
1776 : 0 : iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
1777 : 0 : iwr.u.encoding.pointer = (caddr_t) key;
1778 : 0 : iwr.u.encoding.length = key_len;
1779 : :
1780 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
1781 : 0 : perror("ioctl[SIOCSIWENCODE]");
1782 : 0 : ret = -1;
1783 : : }
1784 : :
1785 [ # # ][ # # ]: 0 : if (set_tx && alg != WPA_ALG_NONE) {
1786 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1787 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1788 : 0 : iwr.u.encoding.flags = key_idx + 1;
1789 : 0 : iwr.u.encoding.flags |= IW_ENCODE_TEMP;
1790 : 0 : iwr.u.encoding.pointer = (caddr_t) NULL;
1791 : 0 : iwr.u.encoding.length = 0;
1792 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
1793 : 0 : perror("ioctl[SIOCSIWENCODE] (set_tx)");
1794 : 0 : ret = -1;
1795 : : }
1796 : : }
1797 : :
1798 : 0 : return ret;
1799 : : }
1800 : :
1801 : :
1802 : 0 : static int wpa_driver_wext_set_countermeasures(void *priv,
1803 : : int enabled)
1804 : : {
1805 : 0 : struct wpa_driver_wext_data *drv = priv;
1806 : 0 : wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1807 : 0 : return wpa_driver_wext_set_auth_param(drv,
1808 : : IW_AUTH_TKIP_COUNTERMEASURES,
1809 : : enabled);
1810 : : }
1811 : :
1812 : :
1813 : 0 : static int wpa_driver_wext_set_drop_unencrypted(void *priv,
1814 : : int enabled)
1815 : : {
1816 : 0 : struct wpa_driver_wext_data *drv = priv;
1817 : 0 : wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1818 : 0 : drv->use_crypt = enabled;
1819 : 0 : return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
1820 : : enabled);
1821 : : }
1822 : :
1823 : :
1824 : 0 : static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
1825 : : const u8 *addr, int cmd, int reason_code)
1826 : : {
1827 : : struct iwreq iwr;
1828 : : struct iw_mlme mlme;
1829 : 0 : int ret = 0;
1830 : :
1831 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1832 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1833 : 0 : os_memset(&mlme, 0, sizeof(mlme));
1834 : 0 : mlme.cmd = cmd;
1835 : 0 : mlme.reason_code = reason_code;
1836 : 0 : mlme.addr.sa_family = ARPHRD_ETHER;
1837 : 0 : os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
1838 : 0 : iwr.u.data.pointer = (caddr_t) &mlme;
1839 : 0 : iwr.u.data.length = sizeof(mlme);
1840 : :
1841 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
1842 : 0 : perror("ioctl[SIOCSIWMLME]");
1843 : 0 : ret = -1;
1844 : : }
1845 : :
1846 : 0 : return ret;
1847 : : }
1848 : :
1849 : :
1850 : 0 : static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
1851 : : {
1852 : : struct iwreq iwr;
1853 : 0 : const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
1854 : : u8 ssid[32];
1855 : : int i;
1856 : :
1857 : : /*
1858 : : * Only force-disconnect when the card is in infrastructure mode,
1859 : : * otherwise the driver might interpret the cleared BSSID and random
1860 : : * SSID as an attempt to create a new ad-hoc network.
1861 : : */
1862 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1863 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1864 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
1865 : 0 : perror("ioctl[SIOCGIWMODE]");
1866 : 0 : iwr.u.mode = IW_MODE_INFRA;
1867 : : }
1868 : :
1869 [ # # ]: 0 : if (iwr.u.mode == IW_MODE_INFRA) {
1870 : : /* Clear the BSSID selection */
1871 [ # # ]: 0 : if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
1872 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
1873 : : "selection on disconnect");
1874 : : }
1875 : :
1876 [ # # ]: 0 : if (drv->cfg80211) {
1877 : : /*
1878 : : * cfg80211 supports SIOCSIWMLME commands, so there is
1879 : : * no need for the random SSID hack, but clear the
1880 : : * SSID.
1881 : : */
1882 [ # # ]: 0 : if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
1883 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
1884 : : "SSID on disconnect");
1885 : : }
1886 : 0 : return;
1887 : : }
1888 : :
1889 : : /*
1890 : : * Set a random SSID to make sure the driver will not be trying
1891 : : * to associate with something even if it does not understand
1892 : : * SIOCSIWMLME commands (or tries to associate automatically
1893 : : * after deauth/disassoc).
1894 : : */
1895 [ # # ]: 0 : for (i = 0; i < 32; i++)
1896 : 0 : ssid[i] = rand() & 0xFF;
1897 [ # # ]: 0 : if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
1898 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
1899 : : "SSID to disconnect");
1900 : : }
1901 : : }
1902 : : }
1903 : :
1904 : :
1905 : 0 : static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
1906 : : int reason_code)
1907 : : {
1908 : 0 : struct wpa_driver_wext_data *drv = priv;
1909 : : int ret;
1910 : 0 : wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1911 : 0 : ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
1912 : 0 : wpa_driver_wext_disconnect(drv);
1913 : 0 : return ret;
1914 : : }
1915 : :
1916 : :
1917 : 0 : static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
1918 : : size_t ie_len)
1919 : : {
1920 : 0 : struct wpa_driver_wext_data *drv = priv;
1921 : : struct iwreq iwr;
1922 : 0 : int ret = 0;
1923 : :
1924 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1925 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1926 : 0 : iwr.u.data.pointer = (caddr_t) ie;
1927 : 0 : iwr.u.data.length = ie_len;
1928 : :
1929 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
1930 : 0 : perror("ioctl[SIOCSIWGENIE]");
1931 : 0 : ret = -1;
1932 : : }
1933 : :
1934 : 0 : return ret;
1935 : : }
1936 : :
1937 : :
1938 : 0 : int wpa_driver_wext_cipher2wext(int cipher)
1939 : : {
1940 [ # # # # : 0 : switch (cipher) {
# # ]
1941 : : case WPA_CIPHER_NONE:
1942 : 0 : return IW_AUTH_CIPHER_NONE;
1943 : : case WPA_CIPHER_WEP40:
1944 : 0 : return IW_AUTH_CIPHER_WEP40;
1945 : : case WPA_CIPHER_TKIP:
1946 : 0 : return IW_AUTH_CIPHER_TKIP;
1947 : : case WPA_CIPHER_CCMP:
1948 : 0 : return IW_AUTH_CIPHER_CCMP;
1949 : : case WPA_CIPHER_WEP104:
1950 : 0 : return IW_AUTH_CIPHER_WEP104;
1951 : : default:
1952 : 0 : return 0;
1953 : : }
1954 : : }
1955 : :
1956 : :
1957 : 0 : int wpa_driver_wext_keymgmt2wext(int keymgmt)
1958 : : {
1959 [ # # # ]: 0 : switch (keymgmt) {
1960 : : case WPA_KEY_MGMT_IEEE8021X:
1961 : : case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
1962 : 0 : return IW_AUTH_KEY_MGMT_802_1X;
1963 : : case WPA_KEY_MGMT_PSK:
1964 : 0 : return IW_AUTH_KEY_MGMT_PSK;
1965 : : default:
1966 : 0 : return 0;
1967 : : }
1968 : : }
1969 : :
1970 : :
1971 : : static int
1972 : 0 : wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
1973 : : struct wpa_driver_associate_params *params)
1974 : : {
1975 : : struct iwreq iwr;
1976 : 0 : int ret = 0;
1977 : :
1978 : 0 : wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
1979 : : "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
1980 : :
1981 : 0 : os_memset(&iwr, 0, sizeof(iwr));
1982 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1983 : : /* Just changing mode, not actual keys */
1984 : 0 : iwr.u.encoding.flags = 0;
1985 : 0 : iwr.u.encoding.pointer = (caddr_t) NULL;
1986 : 0 : iwr.u.encoding.length = 0;
1987 : :
1988 : : /*
1989 : : * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
1990 : : * different things. Here they are used to indicate Open System vs.
1991 : : * Shared Key authentication algorithm. However, some drivers may use
1992 : : * them to select between open/restricted WEP encrypted (open = allow
1993 : : * both unencrypted and encrypted frames; restricted = only allow
1994 : : * encrypted frames).
1995 : : */
1996 : :
1997 [ # # ]: 0 : if (!drv->use_crypt) {
1998 : 0 : iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
1999 : : } else {
2000 [ # # ]: 0 : if (params->auth_alg & WPA_AUTH_ALG_OPEN)
2001 : 0 : iwr.u.encoding.flags |= IW_ENCODE_OPEN;
2002 [ # # ]: 0 : if (params->auth_alg & WPA_AUTH_ALG_SHARED)
2003 : 0 : iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
2004 : : }
2005 : :
2006 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
2007 : 0 : perror("ioctl[SIOCSIWENCODE]");
2008 : 0 : ret = -1;
2009 : : }
2010 : :
2011 : 0 : return ret;
2012 : : }
2013 : :
2014 : :
2015 : 0 : int wpa_driver_wext_associate(void *priv,
2016 : : struct wpa_driver_associate_params *params)
2017 : : {
2018 : 0 : struct wpa_driver_wext_data *drv = priv;
2019 : 0 : int ret = 0;
2020 : : int allow_unencrypted_eapol;
2021 : : int value;
2022 : :
2023 : 0 : wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
2024 : :
2025 [ # # ]: 0 : if (drv->cfg80211) {
2026 : : /*
2027 : : * Stop cfg80211 from trying to associate before we are done
2028 : : * with all parameters.
2029 : : */
2030 : 0 : wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
2031 : : }
2032 : :
2033 [ # # ]: 0 : if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
2034 : : < 0)
2035 : 0 : ret = -1;
2036 [ # # ]: 0 : if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
2037 : 0 : ret = -1;
2038 [ # # ]: 0 : if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
2039 : 0 : ret = -1;
2040 : :
2041 : : /*
2042 : : * If the driver did not support SIOCSIWAUTH, fallback to
2043 : : * SIOCSIWENCODE here.
2044 : : */
2045 [ # # # # ]: 0 : if (drv->auth_alg_fallback &&
2046 : 0 : wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
2047 : 0 : ret = -1;
2048 : :
2049 [ # # # # ]: 0 : if (!params->bssid &&
2050 : 0 : wpa_driver_wext_set_bssid(drv, NULL) < 0)
2051 : 0 : ret = -1;
2052 : :
2053 : : /* TODO: should consider getting wpa version and cipher/key_mgmt suites
2054 : : * from configuration, not from here, where only the selected suite is
2055 : : * available */
2056 [ # # ]: 0 : if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
2057 : : < 0)
2058 : 0 : ret = -1;
2059 [ # # ][ # # ]: 0 : if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
2060 : 0 : value = IW_AUTH_WPA_VERSION_DISABLED;
2061 [ # # ]: 0 : else if (params->wpa_ie[0] == WLAN_EID_RSN)
2062 : 0 : value = IW_AUTH_WPA_VERSION_WPA2;
2063 : : else
2064 : 0 : value = IW_AUTH_WPA_VERSION_WPA;
2065 [ # # ]: 0 : if (wpa_driver_wext_set_auth_param(drv,
2066 : : IW_AUTH_WPA_VERSION, value) < 0)
2067 : 0 : ret = -1;
2068 : 0 : value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
2069 [ # # ]: 0 : if (wpa_driver_wext_set_auth_param(drv,
2070 : : IW_AUTH_CIPHER_PAIRWISE, value) < 0)
2071 : 0 : ret = -1;
2072 : 0 : value = wpa_driver_wext_cipher2wext(params->group_suite);
2073 [ # # ]: 0 : if (wpa_driver_wext_set_auth_param(drv,
2074 : : IW_AUTH_CIPHER_GROUP, value) < 0)
2075 : 0 : ret = -1;
2076 : 0 : value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
2077 [ # # ]: 0 : if (wpa_driver_wext_set_auth_param(drv,
2078 : : IW_AUTH_KEY_MGMT, value) < 0)
2079 : 0 : ret = -1;
2080 [ # # ][ # # ]: 0 : value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE ||
2081 [ # # ]: 0 : params->pairwise_suite != WPA_CIPHER_NONE ||
2082 [ # # ]: 0 : params->group_suite != WPA_CIPHER_NONE ||
2083 : 0 : params->wpa_ie_len;
2084 [ # # ]: 0 : if (wpa_driver_wext_set_auth_param(drv,
2085 : : IW_AUTH_PRIVACY_INVOKED, value) < 0)
2086 : 0 : ret = -1;
2087 : :
2088 : : /* Allow unencrypted EAPOL messages even if pairwise keys are set when
2089 : : * not using WPA. IEEE 802.1X specifies that these frames are not
2090 : : * encrypted, but WPA encrypts them when pairwise keys are in use. */
2091 [ # # ][ # # ]: 0 : if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
2092 : 0 : params->key_mgmt_suite == WPA_KEY_MGMT_PSK)
2093 : 0 : allow_unencrypted_eapol = 0;
2094 : : else
2095 : 0 : allow_unencrypted_eapol = 1;
2096 : :
2097 [ # # ]: 0 : if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
2098 : 0 : ret = -1;
2099 [ # # ]: 0 : if (wpa_driver_wext_set_auth_param(drv,
2100 : : IW_AUTH_RX_UNENCRYPTED_EAPOL,
2101 : : allow_unencrypted_eapol) < 0)
2102 : 0 : ret = -1;
2103 : : #ifdef CONFIG_IEEE80211W
2104 [ # # # # ]: 0 : switch (params->mgmt_frame_protection) {
2105 : : case NO_MGMT_FRAME_PROTECTION:
2106 : 0 : value = IW_AUTH_MFP_DISABLED;
2107 : 0 : break;
2108 : : case MGMT_FRAME_PROTECTION_OPTIONAL:
2109 : 0 : value = IW_AUTH_MFP_OPTIONAL;
2110 : 0 : break;
2111 : : case MGMT_FRAME_PROTECTION_REQUIRED:
2112 : 0 : value = IW_AUTH_MFP_REQUIRED;
2113 : 0 : break;
2114 : : };
2115 [ # # ]: 0 : if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
2116 : 0 : ret = -1;
2117 : : #endif /* CONFIG_IEEE80211W */
2118 [ # # ][ # # ]: 0 : if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
2119 : 0 : ret = -1;
2120 [ # # # # ]: 0 : if (!drv->cfg80211 &&
2121 : 0 : wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
2122 : 0 : ret = -1;
2123 [ # # # # ]: 0 : if (params->bssid &&
2124 : 0 : wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
2125 : 0 : ret = -1;
2126 [ # # # # ]: 0 : if (drv->cfg80211 &&
2127 : 0 : wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
2128 : 0 : ret = -1;
2129 : :
2130 : 0 : return ret;
2131 : : }
2132 : :
2133 : :
2134 : 0 : static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
2135 : : {
2136 : 0 : struct wpa_driver_wext_data *drv = priv;
2137 : 0 : int algs = 0, res;
2138 : :
2139 [ # # ]: 0 : if (auth_alg & WPA_AUTH_ALG_OPEN)
2140 : 0 : algs |= IW_AUTH_ALG_OPEN_SYSTEM;
2141 [ # # ]: 0 : if (auth_alg & WPA_AUTH_ALG_SHARED)
2142 : 0 : algs |= IW_AUTH_ALG_SHARED_KEY;
2143 [ # # ]: 0 : if (auth_alg & WPA_AUTH_ALG_LEAP)
2144 : 0 : algs |= IW_AUTH_ALG_LEAP;
2145 [ # # ]: 0 : if (algs == 0) {
2146 : : /* at least one algorithm should be set */
2147 : 0 : algs = IW_AUTH_ALG_OPEN_SYSTEM;
2148 : : }
2149 : :
2150 : 0 : res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
2151 : : algs);
2152 : 0 : drv->auth_alg_fallback = res == -2;
2153 : 0 : return res;
2154 : : }
2155 : :
2156 : :
2157 : : /**
2158 : : * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
2159 : : * @priv: Pointer to private wext data from wpa_driver_wext_init()
2160 : : * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
2161 : : * Returns: 0 on success, -1 on failure
2162 : : */
2163 : 0 : int wpa_driver_wext_set_mode(void *priv, int mode)
2164 : : {
2165 : 0 : struct wpa_driver_wext_data *drv = priv;
2166 : : struct iwreq iwr;
2167 : 0 : int ret = -1;
2168 [ # # ]: 0 : unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
2169 : :
2170 : 0 : os_memset(&iwr, 0, sizeof(iwr));
2171 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
2172 : 0 : iwr.u.mode = new_mode;
2173 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
2174 : 0 : ret = 0;
2175 : 0 : goto done;
2176 : : }
2177 : :
2178 [ # # ]: 0 : if (errno != EBUSY) {
2179 : 0 : perror("ioctl[SIOCSIWMODE]");
2180 : 0 : goto done;
2181 : : }
2182 : :
2183 : : /* mac80211 doesn't allow mode changes while the device is up, so if
2184 : : * the device isn't in the mode we're about to change to, take device
2185 : : * down, try to set the mode again, and bring it back up.
2186 : : */
2187 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
2188 : 0 : perror("ioctl[SIOCGIWMODE]");
2189 : 0 : goto done;
2190 : : }
2191 : :
2192 [ # # ]: 0 : if (iwr.u.mode == new_mode) {
2193 : 0 : ret = 0;
2194 : 0 : goto done;
2195 : : }
2196 : :
2197 [ # # ]: 0 : if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
2198 : : /* Try to set the mode again while the interface is down */
2199 : 0 : iwr.u.mode = new_mode;
2200 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
2201 : 0 : perror("ioctl[SIOCSIWMODE]");
2202 : : else
2203 : 0 : ret = 0;
2204 : :
2205 : 0 : (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
2206 : : }
2207 : :
2208 : : done:
2209 : 0 : return ret;
2210 : : }
2211 : :
2212 : :
2213 : 0 : static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
2214 : : u32 cmd, const u8 *bssid, const u8 *pmkid)
2215 : : {
2216 : : struct iwreq iwr;
2217 : : struct iw_pmksa pmksa;
2218 : 0 : int ret = 0;
2219 : :
2220 : 0 : os_memset(&iwr, 0, sizeof(iwr));
2221 : 0 : os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
2222 : 0 : os_memset(&pmksa, 0, sizeof(pmksa));
2223 : 0 : pmksa.cmd = cmd;
2224 : 0 : pmksa.bssid.sa_family = ARPHRD_ETHER;
2225 [ # # ]: 0 : if (bssid)
2226 : 0 : os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
2227 [ # # ]: 0 : if (pmkid)
2228 : 0 : os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
2229 : 0 : iwr.u.data.pointer = (caddr_t) &pmksa;
2230 : 0 : iwr.u.data.length = sizeof(pmksa);
2231 : :
2232 [ # # ]: 0 : if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
2233 [ # # ]: 0 : if (errno != EOPNOTSUPP)
2234 : 0 : perror("ioctl[SIOCSIWPMKSA]");
2235 : 0 : ret = -1;
2236 : : }
2237 : :
2238 : 0 : return ret;
2239 : : }
2240 : :
2241 : :
2242 : 0 : static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
2243 : : const u8 *pmkid)
2244 : : {
2245 : 0 : struct wpa_driver_wext_data *drv = priv;
2246 : 0 : return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
2247 : : }
2248 : :
2249 : :
2250 : 0 : static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
2251 : : const u8 *pmkid)
2252 : : {
2253 : 0 : struct wpa_driver_wext_data *drv = priv;
2254 : 0 : return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
2255 : : }
2256 : :
2257 : :
2258 : 0 : static int wpa_driver_wext_flush_pmkid(void *priv)
2259 : : {
2260 : 0 : struct wpa_driver_wext_data *drv = priv;
2261 : 0 : return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
2262 : : }
2263 : :
2264 : :
2265 : 0 : int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
2266 : : {
2267 : 0 : struct wpa_driver_wext_data *drv = priv;
2268 [ # # ]: 0 : if (!drv->has_capability)
2269 : 0 : return -1;
2270 : 0 : os_memcpy(capa, &drv->capa, sizeof(*capa));
2271 : 0 : return 0;
2272 : : }
2273 : :
2274 : :
2275 : 0 : int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
2276 : : const char *ifname)
2277 : : {
2278 [ # # ]: 0 : if (ifname == NULL) {
2279 : 0 : drv->ifindex2 = -1;
2280 : 0 : return 0;
2281 : : }
2282 : :
2283 : 0 : drv->ifindex2 = if_nametoindex(ifname);
2284 [ # # ]: 0 : if (drv->ifindex2 <= 0)
2285 : 0 : return -1;
2286 : :
2287 : 0 : wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
2288 : : "wireless events", drv->ifindex2, ifname);
2289 : :
2290 : 0 : return 0;
2291 : : }
2292 : :
2293 : :
2294 : 0 : int wpa_driver_wext_set_operstate(void *priv, int state)
2295 : : {
2296 : 0 : struct wpa_driver_wext_data *drv = priv;
2297 : :
2298 [ # # ]: 0 : wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
2299 : : __func__, drv->operstate, state, state ? "UP" : "DORMANT");
2300 : 0 : drv->operstate = state;
2301 [ # # ]: 0 : return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
2302 : : state ? IF_OPER_UP : IF_OPER_DORMANT);
2303 : : }
2304 : :
2305 : :
2306 : 0 : int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
2307 : : {
2308 : 0 : return drv->we_version_compiled;
2309 : : }
2310 : :
2311 : :
2312 : 0 : static const char * wext_get_radio_name(void *priv)
2313 : : {
2314 : 0 : struct wpa_driver_wext_data *drv = priv;
2315 : 0 : return drv->phyname;
2316 : : }
2317 : :
2318 : :
2319 : : const struct wpa_driver_ops wpa_driver_wext_ops = {
2320 : : .name = "wext",
2321 : : .desc = "Linux wireless extensions (generic)",
2322 : : .get_bssid = wpa_driver_wext_get_bssid,
2323 : : .get_ssid = wpa_driver_wext_get_ssid,
2324 : : .set_key = wpa_driver_wext_set_key,
2325 : : .set_countermeasures = wpa_driver_wext_set_countermeasures,
2326 : : .scan2 = wpa_driver_wext_scan,
2327 : : .get_scan_results2 = wpa_driver_wext_get_scan_results,
2328 : : .deauthenticate = wpa_driver_wext_deauthenticate,
2329 : : .associate = wpa_driver_wext_associate,
2330 : : .init = wpa_driver_wext_init,
2331 : : .deinit = wpa_driver_wext_deinit,
2332 : : .add_pmkid = wpa_driver_wext_add_pmkid,
2333 : : .remove_pmkid = wpa_driver_wext_remove_pmkid,
2334 : : .flush_pmkid = wpa_driver_wext_flush_pmkid,
2335 : : .get_capa = wpa_driver_wext_get_capa,
2336 : : .set_operstate = wpa_driver_wext_set_operstate,
2337 : : .get_radio_name = wext_get_radio_name,
2338 : : };
|