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