blob: 3c504666d892af10653898e7782e572303b1abc9 [file] [log] [blame]
The Android Open Source Project845e0122009-03-03 19:31:34 -08001/*
2 * WPA Supplicant - driver interaction with generic Linux Wireless Extensions
3 * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 *
14 * 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 <net/if_arp.h>
Dmitry Shmidtcc4db602009-05-06 08:50:56 -070024#include <net/if.h>
The Android Open Source Project845e0122009-03-03 19:31:34 -080025
26#include "wireless_copy.h"
27#include "common.h"
28#include "driver.h"
29#include "l2_packet.h"
30#include "eloop.h"
31#include "wpa_supplicant.h"
32#include "priv_netlink.h"
33#include "driver_wext.h"
34#include "wpa.h"
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -070035#include "wpa_ctrl.h"
Dmitry Shmidt872ebd72009-07-30 14:16:44 -070036#include "wpa_supplicant_i.h"
37#include "config_ssid.h"
The Android Open Source Project845e0122009-03-03 19:31:34 -080038
39#ifdef CONFIG_CLIENT_MLME
40#include <netpacket/packet.h>
41#include <hostapd_ioctl.h>
42#include <ieee80211_common.h>
43/* from net/mac80211.h */
44enum {
45 MODE_IEEE80211A = 0 /* IEEE 802.11a */,
46 MODE_IEEE80211B = 1 /* IEEE 802.11b only */,
47 MODE_ATHEROS_TURBO = 2 /* Atheros Turbo mode (2x.11a at 5 GHz) */,
48 MODE_IEEE80211G = 3 /* IEEE 802.11g (and 802.11b compatibility) */,
49 MODE_ATHEROS_TURBOG = 4 /* Atheros Turbo mode (2x.11g at 2.4 GHz) */,
50 NUM_IEEE80211_MODES = 5
51};
52
53#include "mlme.h"
54
55#ifndef ETH_P_ALL
56#define ETH_P_ALL 0x0003
57#endif
58#endif /* CONFIG_CLIENT_MLME */
59
60
61struct wpa_driver_wext_data {
62 void *ctx;
63 int event_sock;
64 int ioctl_sock;
65 int mlme_sock;
66 char ifname[IFNAMSIZ + 1];
67 int ifindex;
68 int ifindex2;
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -070069 int if_removed;
The Android Open Source Project845e0122009-03-03 19:31:34 -080070 u8 *assoc_req_ies;
71 size_t assoc_req_ies_len;
72 u8 *assoc_resp_ies;
73 size_t assoc_resp_ies_len;
74 struct wpa_driver_capa capa;
75 int has_capability;
76 int we_version_compiled;
77
78 /* for set_auth_alg fallback */
79 int use_crypt;
80 int auth_alg_fallback;
81
82 int operstate;
83
84 char mlmedev[IFNAMSIZ + 1];
85
86 int scan_complete_events;
Dmitry Shmidtaea96d82009-11-24 10:32:41 -080087 int errors;
The Android Open Source Project845e0122009-03-03 19:31:34 -080088};
89
90
91static int wpa_driver_wext_flush_pmkid(void *priv);
92static int wpa_driver_wext_get_range(void *priv);
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -070093static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
94
The Android Open Source Project845e0122009-03-03 19:31:34 -080095
96static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
97 int linkmode, int operstate)
98{
99 struct {
100 struct nlmsghdr hdr;
101 struct ifinfomsg ifinfo;
102 char opts[16];
103 } req;
104 struct rtattr *rta;
105 static int nl_seq;
106 ssize_t ret;
107
108 req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
109 req.hdr.nlmsg_type = RTM_SETLINK;
110 req.hdr.nlmsg_flags = NLM_F_REQUEST;
111 req.hdr.nlmsg_seq = ++nl_seq;
112 req.hdr.nlmsg_pid = 0;
113
114 req.ifinfo.ifi_family = AF_UNSPEC;
115 req.ifinfo.ifi_type = 0;
116 req.ifinfo.ifi_index = drv->ifindex;
117 req.ifinfo.ifi_flags = 0;
118 req.ifinfo.ifi_change = 0;
119
120 if (linkmode != -1) {
121 rta = (struct rtattr *)
122 ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
123 rta->rta_type = IFLA_LINKMODE;
124 rta->rta_len = RTA_LENGTH(sizeof(char));
125 *((char *) RTA_DATA(rta)) = linkmode;
126 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
127 RTA_LENGTH(sizeof(char));
128 }
129 if (operstate != -1) {
130 rta = (struct rtattr *)
131 ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
132 rta->rta_type = IFLA_OPERSTATE;
133 rta->rta_len = RTA_LENGTH(sizeof(char));
134 *((char *) RTA_DATA(rta)) = operstate;
135 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
136 RTA_LENGTH(sizeof(char));
137 }
138
139 wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
140 linkmode, operstate);
141
142 ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
143 if (ret < 0) {
144 wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
145 "%s (assume operstate is not supported)",
146 strerror(errno));
147 }
148
149 return ret < 0 ? -1 : 0;
150}
151
152
153static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
154 int idx, u32 value)
155{
156 struct iwreq iwr;
157 int ret = 0;
158
159 os_memset(&iwr, 0, sizeof(iwr));
160 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
161 iwr.u.param.flags = idx & IW_AUTH_INDEX;
162 iwr.u.param.value = value;
163
164 if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700165 if (errno != EOPNOTSUPP) {
166 wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
167 "value 0x%x) failed: %s)",
168 idx, value, strerror(errno));
169 }
The Android Open Source Project845e0122009-03-03 19:31:34 -0800170 ret = errno == EOPNOTSUPP ? -2 : -1;
171 }
172
173 return ret;
174}
175
176
177/**
178 * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP
179 * @priv: Pointer to private wext data from wpa_driver_wext_init()
180 * @bssid: Buffer for BSSID
181 * Returns: 0 on success, -1 on failure
182 */
183int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
184{
185 struct wpa_driver_wext_data *drv = priv;
186 struct iwreq iwr;
187 int ret = 0;
188
189 os_memset(&iwr, 0, sizeof(iwr));
190 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
191
192 if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
193 perror("ioctl[SIOCGIWAP]");
194 ret = -1;
195 }
196 os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
197
198 return ret;
199}
200
201
202/**
203 * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP
204 * @priv: Pointer to private wext data from wpa_driver_wext_init()
205 * @bssid: BSSID
206 * Returns: 0 on success, -1 on failure
207 */
208int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
209{
210 struct wpa_driver_wext_data *drv = priv;
211 struct iwreq iwr;
212 int ret = 0;
213
214 os_memset(&iwr, 0, sizeof(iwr));
215 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
216 iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
217 if (bssid)
218 os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
219 else
220 os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
221
222 if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
223 perror("ioctl[SIOCSIWAP]");
224 ret = -1;
225 }
226
227 return ret;
228}
229
230
231/**
232 * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID
233 * @priv: Pointer to private wext data from wpa_driver_wext_init()
234 * @ssid: Buffer for the SSID; must be at least 32 bytes long
235 * Returns: SSID length on success, -1 on failure
236 */
237int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
238{
239 struct wpa_driver_wext_data *drv = priv;
240 struct iwreq iwr;
241 int ret = 0;
242
243 os_memset(&iwr, 0, sizeof(iwr));
244 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
245 iwr.u.essid.pointer = (caddr_t) ssid;
246 iwr.u.essid.length = 32;
247
248 if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
249 perror("ioctl[SIOCGIWESSID]");
250 ret = -1;
251 } else {
252 ret = iwr.u.essid.length;
253 if (ret > 32)
254 ret = 32;
255 /* Some drivers include nul termination in the SSID, so let's
256 * remove it here before further processing. WE-21 changes this
257 * to explicitly require the length _not_ to include nul
258 * termination. */
259 if (ret > 0 && ssid[ret - 1] == '\0' &&
260 drv->we_version_compiled < 21)
261 ret--;
262 }
263
264 return ret;
265}
266
267
268/**
269 * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID
270 * @priv: Pointer to private wext data from wpa_driver_wext_init()
271 * @ssid: SSID
272 * @ssid_len: Length of SSID (0..32)
273 * Returns: 0 on success, -1 on failure
274 */
275int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
276{
277 struct wpa_driver_wext_data *drv = priv;
278 struct iwreq iwr;
279 int ret = 0;
280 char buf[33];
281
282 if (ssid_len > 32)
283 return -1;
284
285 os_memset(&iwr, 0, sizeof(iwr));
286 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
287 /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
288 iwr.u.essid.flags = (ssid_len != 0);
289 os_memset(buf, 0, sizeof(buf));
290 os_memcpy(buf, ssid, ssid_len);
291 iwr.u.essid.pointer = (caddr_t) buf;
292 if (drv->we_version_compiled < 21) {
293 /* For historic reasons, set SSID length to include one extra
294 * character, C string nul termination, even though SSID is
295 * really an octet string that should not be presented as a C
296 * string. Some Linux drivers decrement the length by one and
297 * can thus end up missing the last octet of the SSID if the
298 * length is not incremented here. WE-21 changes this to
299 * explicitly require the length _not_ to include nul
300 * termination. */
301 if (ssid_len)
302 ssid_len++;
303 }
304 iwr.u.essid.length = ssid_len;
305
306 if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
307 perror("ioctl[SIOCSIWESSID]");
308 ret = -1;
309 }
310
311 return ret;
312}
313
314
315/**
316 * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ
317 * @priv: Pointer to private wext data from wpa_driver_wext_init()
318 * @freq: Frequency in MHz
319 * Returns: 0 on success, -1 on failure
320 */
321int wpa_driver_wext_set_freq(void *priv, int freq)
322{
323 struct wpa_driver_wext_data *drv = priv;
324 struct iwreq iwr;
325 int ret = 0;
326
327 os_memset(&iwr, 0, sizeof(iwr));
328 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
329 iwr.u.freq.m = freq * 100000;
330 iwr.u.freq.e = 1;
331
332 if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
333 perror("ioctl[SIOCSIWFREQ]");
334 ret = -1;
335 }
336
337 return ret;
338}
339
340
341static void
342wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
343{
344 union wpa_event_data data;
345
346 wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
347 custom);
348
349 os_memset(&data, 0, sizeof(data));
350 /* Host AP driver */
351 if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
352 data.michael_mic_failure.unicast =
353 os_strstr(custom, " unicast ") != NULL;
354 /* TODO: parse parameters(?) */
355 wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
356 } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
357 char *spos;
358 int bytes;
359
360 spos = custom + 17;
361
362 bytes = strspn(spos, "0123456789abcdefABCDEF");
363 if (!bytes || (bytes & 1))
364 return;
365 bytes /= 2;
366
367 data.assoc_info.req_ies = os_malloc(bytes);
368 if (data.assoc_info.req_ies == NULL)
369 return;
370
371 data.assoc_info.req_ies_len = bytes;
372 hexstr2bin(spos, data.assoc_info.req_ies, bytes);
373
374 spos += bytes * 2;
375
376 data.assoc_info.resp_ies = NULL;
377 data.assoc_info.resp_ies_len = 0;
378
379 if (os_strncmp(spos, " RespIEs=", 9) == 0) {
380 spos += 9;
381
382 bytes = strspn(spos, "0123456789abcdefABCDEF");
383 if (!bytes || (bytes & 1))
384 goto done;
385 bytes /= 2;
386
387 data.assoc_info.resp_ies = os_malloc(bytes);
388 if (data.assoc_info.resp_ies == NULL)
389 goto done;
390
391 data.assoc_info.resp_ies_len = bytes;
392 hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
393 }
394
395 wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
396
397 done:
398 os_free(data.assoc_info.resp_ies);
399 os_free(data.assoc_info.req_ies);
400#ifdef CONFIG_PEERKEY
401 } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
402 if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
403 wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
404 "STKSTART.request '%s'", custom + 17);
405 return;
406 }
407 wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
408#endif /* CONFIG_PEERKEY */
Dmitry Shmidt872ebd72009-07-30 14:16:44 -0700409#ifdef ANDROID
410 } else if (os_strncmp(custom, "STOP", 4) == 0) {
411 wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
412 } else if (os_strncmp(custom, "START", 5) == 0) {
413 wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
414#endif /* ANDROID */
The Android Open Source Project845e0122009-03-03 19:31:34 -0800415 }
416}
417
418
419static int wpa_driver_wext_event_wireless_michaelmicfailure(
420 void *ctx, const char *ev, size_t len)
421{
422 const struct iw_michaelmicfailure *mic;
423 union wpa_event_data data;
424
425 if (len < sizeof(*mic))
426 return -1;
427
428 mic = (const struct iw_michaelmicfailure *) ev;
429
430 wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
431 "flags=0x%x src_addr=" MACSTR, mic->flags,
432 MAC2STR(mic->src_addr.sa_data));
433
434 os_memset(&data, 0, sizeof(data));
435 data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
436 wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
437
438 return 0;
439}
440
441
442static int wpa_driver_wext_event_wireless_pmkidcand(
443 struct wpa_driver_wext_data *drv, const char *ev, size_t len)
444{
445 const struct iw_pmkid_cand *cand;
446 union wpa_event_data data;
447 const u8 *addr;
448
449 if (len < sizeof(*cand))
450 return -1;
451
452 cand = (const struct iw_pmkid_cand *) ev;
453 addr = (const u8 *) cand->bssid.sa_data;
454
455 wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
456 "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
457 cand->index, MAC2STR(addr));
458
459 os_memset(&data, 0, sizeof(data));
460 os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
461 data.pmkid_candidate.index = cand->index;
462 data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
463 wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
464
465 return 0;
466}
467
468
469static int wpa_driver_wext_event_wireless_assocreqie(
470 struct wpa_driver_wext_data *drv, const char *ev, int len)
471{
472 if (len < 0)
473 return -1;
474
475 wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
476 len);
477 os_free(drv->assoc_req_ies);
478 drv->assoc_req_ies = os_malloc(len);
479 if (drv->assoc_req_ies == NULL) {
480 drv->assoc_req_ies_len = 0;
481 return -1;
482 }
483 os_memcpy(drv->assoc_req_ies, ev, len);
484 drv->assoc_req_ies_len = len;
485
486 return 0;
487}
488
489
490static int wpa_driver_wext_event_wireless_assocrespie(
491 struct wpa_driver_wext_data *drv, const char *ev, int len)
492{
493 if (len < 0)
494 return -1;
495
496 wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
497 len);
498 os_free(drv->assoc_resp_ies);
499 drv->assoc_resp_ies = os_malloc(len);
500 if (drv->assoc_resp_ies == NULL) {
501 drv->assoc_resp_ies_len = 0;
502 return -1;
503 }
504 os_memcpy(drv->assoc_resp_ies, ev, len);
505 drv->assoc_resp_ies_len = len;
506
507 return 0;
508}
509
510
511static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
512{
513 union wpa_event_data data;
514
515 if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
516 return;
517
518 os_memset(&data, 0, sizeof(data));
519 if (drv->assoc_req_ies) {
520 data.assoc_info.req_ies = drv->assoc_req_ies;
521 drv->assoc_req_ies = NULL;
522 data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
523 }
524 if (drv->assoc_resp_ies) {
525 data.assoc_info.resp_ies = drv->assoc_resp_ies;
526 drv->assoc_resp_ies = NULL;
527 data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
528 }
529
530 wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
531
532 os_free(data.assoc_info.req_ies);
533 os_free(data.assoc_info.resp_ies);
534}
535
536
537static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
538 void *ctx, char *data, int len)
539{
540 struct iw_event iwe_buf, *iwe = &iwe_buf;
541 char *pos, *end, *custom, *buf;
542
543 pos = data;
544 end = data + len;
545
546 while (pos + IW_EV_LCP_LEN <= end) {
547 /* Event data may be unaligned, so make a local, aligned copy
548 * before processing. */
549 os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
550 wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
551 iwe->cmd, iwe->len);
552 if (iwe->len <= IW_EV_LCP_LEN)
553 return;
554
555 custom = pos + IW_EV_POINT_LEN;
556 if (drv->we_version_compiled > 18 &&
557 (iwe->cmd == IWEVMICHAELMICFAILURE ||
558 iwe->cmd == IWEVCUSTOM ||
559 iwe->cmd == IWEVASSOCREQIE ||
560 iwe->cmd == IWEVASSOCRESPIE ||
561 iwe->cmd == IWEVPMKIDCAND)) {
562 /* WE-19 removed the pointer from struct iw_point */
563 char *dpos = (char *) &iwe_buf.u.data.length;
564 int dlen = dpos - (char *) &iwe_buf;
565 os_memcpy(dpos, pos + IW_EV_LCP_LEN,
566 sizeof(struct iw_event) - dlen);
567 } else {
568 os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
569 custom += IW_EV_POINT_OFF;
570 }
571
572 switch (iwe->cmd) {
573 case SIOCGIWAP:
574 wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
575 MACSTR,
576 MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
577 if (os_memcmp(iwe->u.ap_addr.sa_data,
578 "\x00\x00\x00\x00\x00\x00", ETH_ALEN) ==
579 0 ||
580 os_memcmp(iwe->u.ap_addr.sa_data,
581 "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
582 0) {
583 os_free(drv->assoc_req_ies);
584 drv->assoc_req_ies = NULL;
585 os_free(drv->assoc_resp_ies);
586 drv->assoc_resp_ies = NULL;
587 wpa_supplicant_event(ctx, EVENT_DISASSOC,
588 NULL);
589
590 } else {
591 wpa_driver_wext_event_assoc_ies(drv);
592 wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
593 }
594 break;
595 case IWEVMICHAELMICFAILURE:
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700596 if (custom + iwe->u.data.length > end) {
597 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
598 "IWEVMICHAELMICFAILURE length");
599 return;
600 }
The Android Open Source Project845e0122009-03-03 19:31:34 -0800601 wpa_driver_wext_event_wireless_michaelmicfailure(
602 ctx, custom, iwe->u.data.length);
603 break;
604 case IWEVCUSTOM:
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700605 if (custom + iwe->u.data.length > end) {
606 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
607 "IWEVCUSTOM length");
The Android Open Source Project845e0122009-03-03 19:31:34 -0800608 return;
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700609 }
The Android Open Source Project845e0122009-03-03 19:31:34 -0800610 buf = os_malloc(iwe->u.data.length + 1);
611 if (buf == NULL)
612 return;
613 os_memcpy(buf, custom, iwe->u.data.length);
614 buf[iwe->u.data.length] = '\0';
615 wpa_driver_wext_event_wireless_custom(ctx, buf);
616 os_free(buf);
617 break;
618 case SIOCGIWSCAN:
619 drv->scan_complete_events = 1;
620 eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
621 drv, ctx);
622 wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
623 break;
624 case IWEVASSOCREQIE:
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700625 if (custom + iwe->u.data.length > end) {
626 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
627 "IWEVASSOCREQIE length");
628 return;
629 }
The Android Open Source Project845e0122009-03-03 19:31:34 -0800630 wpa_driver_wext_event_wireless_assocreqie(
631 drv, custom, iwe->u.data.length);
632 break;
633 case IWEVASSOCRESPIE:
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700634 if (custom + iwe->u.data.length > end) {
635 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
636 "IWEVASSOCRESPIE length");
637 return;
638 }
The Android Open Source Project845e0122009-03-03 19:31:34 -0800639 wpa_driver_wext_event_wireless_assocrespie(
640 drv, custom, iwe->u.data.length);
641 break;
642 case IWEVPMKIDCAND:
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700643 if (custom + iwe->u.data.length > end) {
644 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
645 "IWEVPMKIDCAND length");
646 return;
647 }
The Android Open Source Project845e0122009-03-03 19:31:34 -0800648 wpa_driver_wext_event_wireless_pmkidcand(
649 drv, custom, iwe->u.data.length);
650 break;
651 }
652
653 pos += iwe->len;
654 }
655}
656
657
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700658static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
659 void *ctx, char *buf, size_t len,
The Android Open Source Project845e0122009-03-03 19:31:34 -0800660 int del)
661{
662 union wpa_event_data event;
663
664 os_memset(&event, 0, sizeof(event));
665 if (len > sizeof(event.interface_status.ifname))
666 len = sizeof(event.interface_status.ifname) - 1;
667 os_memcpy(event.interface_status.ifname, buf, len);
668 event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
669 EVENT_INTERFACE_ADDED;
670
671 wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
672 del ? "DEL" : "NEW",
673 event.interface_status.ifname,
674 del ? "removed" : "added");
675
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700676 if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
677 if (del)
678 drv->if_removed = 1;
679 else
680 drv->if_removed = 0;
681 }
682
The Android Open Source Project845e0122009-03-03 19:31:34 -0800683 wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
684}
685
686
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700687static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
688 struct nlmsghdr *h)
689{
690 struct ifinfomsg *ifi;
691 int attrlen, nlmsg_len, rta_len;
692 struct rtattr *attr;
693
694 ifi = NLMSG_DATA(h);
695
696 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
697
698 attrlen = h->nlmsg_len - nlmsg_len;
699 if (attrlen < 0)
700 return 0;
701
702 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
703
704 rta_len = RTA_ALIGN(sizeof(struct rtattr));
705 while (RTA_OK(attr, attrlen)) {
706 if (attr->rta_type == IFLA_IFNAME) {
707 if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
708 == 0)
709 return 1;
710 else
711 break;
712 }
713 attr = RTA_NEXT(attr, attrlen);
714 }
715
716 return 0;
717}
718
719
720static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
721 int ifindex, struct nlmsghdr *h)
722{
723 if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
724 return 1;
725
726 if (drv->if_removed && wpa_driver_wext_own_ifname(drv, h)) {
727 drv->ifindex = if_nametoindex(drv->ifname);
728 wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
729 "interface");
730 wpa_driver_wext_finish_drv_init(drv);
731 return 1;
732 }
733
734 return 0;
735}
736
737
The Android Open Source Project845e0122009-03-03 19:31:34 -0800738static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
739 void *ctx, struct nlmsghdr *h,
740 size_t len)
741{
742 struct ifinfomsg *ifi;
743 int attrlen, nlmsg_len, rta_len;
744 struct rtattr * attr;
745
746 if (len < sizeof(*ifi))
747 return;
748
749 ifi = NLMSG_DATA(h);
750
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700751 if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, h)) {
The Android Open Source Project845e0122009-03-03 19:31:34 -0800752 wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
753 ifi->ifi_index);
754 return;
755 }
756
757 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
758 "(%s%s%s%s)",
759 drv->operstate, ifi->ifi_flags,
760 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
761 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
762 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700763 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
The Android Open Source Project845e0122009-03-03 19:31:34 -0800764 /*
765 * Some drivers send the association event before the operup event--in
766 * this case, lifting operstate in wpa_driver_wext_set_operstate()
767 * fails. This will hit us when wpa_supplicant does not need to do
768 * IEEE 802.1X authentication
769 */
770 if (drv->operstate == 1 &&
771 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
772 !(ifi->ifi_flags & IFF_RUNNING))
773 wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP);
774
775 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
776
777 attrlen = h->nlmsg_len - nlmsg_len;
778 if (attrlen < 0)
779 return;
780
781 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
782
783 rta_len = RTA_ALIGN(sizeof(struct rtattr));
784 while (RTA_OK(attr, attrlen)) {
785 if (attr->rta_type == IFLA_WIRELESS) {
786 wpa_driver_wext_event_wireless(
787 drv, ctx, ((char *) attr) + rta_len,
788 attr->rta_len - rta_len);
789 } else if (attr->rta_type == IFLA_IFNAME) {
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700790 wpa_driver_wext_event_link(drv, ctx,
The Android Open Source Project845e0122009-03-03 19:31:34 -0800791 ((char *) attr) + rta_len,
792 attr->rta_len - rta_len, 0);
793 }
794 attr = RTA_NEXT(attr, attrlen);
795 }
796}
797
798
799static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
800 void *ctx, struct nlmsghdr *h,
801 size_t len)
802{
803 struct ifinfomsg *ifi;
804 int attrlen, nlmsg_len, rta_len;
805 struct rtattr * attr;
806
807 if (len < sizeof(*ifi))
808 return;
809
810 ifi = NLMSG_DATA(h);
811
812 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
813
814 attrlen = h->nlmsg_len - nlmsg_len;
815 if (attrlen < 0)
816 return;
817
818 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
819
820 rta_len = RTA_ALIGN(sizeof(struct rtattr));
821 while (RTA_OK(attr, attrlen)) {
822 if (attr->rta_type == IFLA_IFNAME) {
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700823 wpa_driver_wext_event_link(drv, ctx,
The Android Open Source Project845e0122009-03-03 19:31:34 -0800824 ((char *) attr) + rta_len,
825 attr->rta_len - rta_len, 1);
826 }
827 attr = RTA_NEXT(attr, attrlen);
828 }
829}
830
831
832static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
833 void *sock_ctx)
834{
835 char buf[8192];
836 int left;
837 struct sockaddr_nl from;
838 socklen_t fromlen;
839 struct nlmsghdr *h;
840 int max_events = 10;
841
842try_again:
843 fromlen = sizeof(from);
844 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
845 (struct sockaddr *) &from, &fromlen);
846 if (left < 0) {
847 if (errno != EINTR && errno != EAGAIN)
848 perror("recvfrom(netlink)");
849 return;
850 }
851
852 h = (struct nlmsghdr *) buf;
853 while (left >= (int) sizeof(*h)) {
854 int len, plen;
855
856 len = h->nlmsg_len;
857 plen = len - sizeof(*h);
858 if (len > left || plen < 0) {
859 wpa_printf(MSG_DEBUG, "Malformed netlink message: "
860 "len=%d left=%d plen=%d",
861 len, left, plen);
862 break;
863 }
864
865 switch (h->nlmsg_type) {
866 case RTM_NEWLINK:
867 wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx,
868 h, plen);
869 break;
870 case RTM_DELLINK:
871 wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx,
872 h, plen);
873 break;
874 }
875
876 len = NLMSG_ALIGN(len);
877 left -= len;
878 h = (struct nlmsghdr *) ((char *) h + len);
879 }
880
881 if (left > 0) {
882 wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
883 "message", left);
884 }
885
886 if (--max_events > 0) {
887 /*
888 * Try to receive all events in one eloop call in order to
889 * limit race condition on cases where AssocInfo event, Assoc
890 * event, and EAPOL frames are received more or less at the
891 * same time. We want to process the event messages first
892 * before starting EAPOL processing.
893 */
894 goto try_again;
895 }
896}
897
898
899static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
900 const char *ifname, int *flags)
901{
902 struct ifreq ifr;
903
904 os_memset(&ifr, 0, sizeof(ifr));
905 os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
906 if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
907 perror("ioctl[SIOCGIFFLAGS]");
908 return -1;
909 }
910 *flags = ifr.ifr_flags & 0xffff;
911 return 0;
912}
913
914
915/**
916 * wpa_driver_wext_get_ifflags - Get interface flags (SIOCGIFFLAGS)
917 * @drv: driver_wext private data
918 * @flags: Pointer to returned flags value
919 * Returns: 0 on success, -1 on failure
920 */
921int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags)
922{
923 return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags);
924}
925
926
927static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv,
928 const char *ifname, int flags)
929{
930 struct ifreq ifr;
931
932 os_memset(&ifr, 0, sizeof(ifr));
933 os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
934 ifr.ifr_flags = flags & 0xffff;
935 if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
936 perror("SIOCSIFFLAGS");
937 return -1;
938 }
939 return 0;
940}
941
942
943/**
944 * wpa_driver_wext_set_ifflags - Set interface flags (SIOCSIFFLAGS)
945 * @drv: driver_wext private data
946 * @flags: New value for flags
947 * Returns: 0 on success, -1 on failure
948 */
949int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
950{
951 return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags);
952}
953
954
955/**
956 * wpa_driver_wext_init - Initialize WE driver interface
957 * @ctx: context to be used when calling wpa_supplicant functions,
958 * e.g., wpa_supplicant_event()
959 * @ifname: interface name, e.g., wlan0
960 * Returns: Pointer to private data, %NULL on failure
961 */
962void * wpa_driver_wext_init(void *ctx, const char *ifname)
963{
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -0700964 int s;
The Android Open Source Project845e0122009-03-03 19:31:34 -0800965 struct sockaddr_nl local;
966 struct wpa_driver_wext_data *drv;
967
968 drv = os_zalloc(sizeof(*drv));
969 if (drv == NULL)
970 return NULL;
971 drv->ctx = ctx;
972 os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
973
974 drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
975 if (drv->ioctl_sock < 0) {
976 perror("socket(PF_INET,SOCK_DGRAM)");
977 os_free(drv);
978 return NULL;
979 }
980
981 s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
982 if (s < 0) {
983 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
984 close(drv->ioctl_sock);
985 os_free(drv);
986 return NULL;
987 }
988
989 os_memset(&local, 0, sizeof(local));
990 local.nl_family = AF_NETLINK;
991 local.nl_groups = RTMGRP_LINK;
992 if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
993 perror("bind(netlink)");
994 close(s);
995 close(drv->ioctl_sock);
996 os_free(drv);
997 return NULL;
998 }
999
1000 eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx);
1001 drv->event_sock = s;
1002
1003 drv->mlme_sock = -1;
1004
Dmitry Shmidtaea96d82009-11-24 10:32:41 -08001005 drv->errors = 0;
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07001006 wpa_driver_wext_finish_drv_init(drv);
1007
1008 return drv;
1009}
1010
1011
1012static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
1013{
1014 int flags;
1015
Dmitry Shmidt42255242009-06-10 14:53:57 -07001016 if (wpa_driver_wext_get_ifflags(drv, &flags) != 0 ||
1017 wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
1018 printf("Could not set interface '%s' UP\n", drv->ifname);
1019 }
1020#ifdef ANDROID
Dmitry Shmidt61149872009-08-20 12:10:19 -07001021 os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
Dmitry Shmidt42255242009-06-10 14:53:57 -07001022#endif
The Android Open Source Project845e0122009-03-03 19:31:34 -08001023 /*
1024 * Make sure that the driver does not have any obsolete PMKID entries.
1025 */
1026 wpa_driver_wext_flush_pmkid(drv);
1027
1028 if (wpa_driver_wext_set_mode(drv, 0) < 0) {
1029 printf("Could not configure driver to use managed mode\n");
1030 }
1031
The Android Open Source Project845e0122009-03-03 19:31:34 -08001032 wpa_driver_wext_get_range(drv);
1033
1034 drv->ifindex = if_nametoindex(drv->ifname);
1035
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07001036 if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
The Android Open Source Project845e0122009-03-03 19:31:34 -08001037 /*
1038 * Host AP driver may use both wlan# and wifi# interface in
1039 * wireless events. Since some of the versions included WE-18
1040 * support, let's add the alternative ifindex also from
1041 * driver_wext.c for the time being. This may be removed at
1042 * some point once it is believed that old versions of the
1043 * driver are not in use anymore.
1044 */
1045 char ifname2[IFNAMSIZ + 1];
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07001046 os_strncpy(ifname2, drv->ifname, sizeof(ifname2));
The Android Open Source Project845e0122009-03-03 19:31:34 -08001047 os_memcpy(ifname2, "wifi", 4);
1048 wpa_driver_wext_alternative_ifindex(drv, ifname2);
1049 }
1050
1051 wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
The Android Open Source Project845e0122009-03-03 19:31:34 -08001052}
1053
1054
1055/**
1056 * wpa_driver_wext_deinit - Deinitialize WE driver interface
1057 * @priv: Pointer to private wext data from wpa_driver_wext_init()
1058 *
1059 * Shut down driver interface and processing of driver events. Free
1060 * private data buffer if one was allocated in wpa_driver_wext_init().
1061 */
1062void wpa_driver_wext_deinit(void *priv)
1063{
1064 struct wpa_driver_wext_data *drv = priv;
1065 int flags;
1066
1067 eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
1068
1069 /*
1070 * Clear possibly configured driver parameters in order to make it
1071 * easier to use the driver after wpa_supplicant has been terminated.
1072 */
1073 wpa_driver_wext_set_bssid(drv, (u8 *) "\x00\x00\x00\x00\x00\x00");
1074
1075 wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
1076
1077 eloop_unregister_read_sock(drv->event_sock);
1078 if (drv->mlme_sock >= 0)
1079 eloop_unregister_read_sock(drv->mlme_sock);
1080
1081 if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
1082 (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
1083
1084#ifdef CONFIG_CLIENT_MLME
1085 if (drv->mlmedev[0] &&
1086 wpa_driver_wext_get_ifflags_ifname(drv, drv->mlmedev, &flags) == 0)
1087 (void) wpa_driver_wext_set_ifflags_ifname(drv, drv->mlmedev,
1088 flags & ~IFF_UP);
1089#endif /* CONFIG_CLIENT_MLME */
1090
1091 close(drv->event_sock);
1092 close(drv->ioctl_sock);
1093 if (drv->mlme_sock >= 0)
1094 close(drv->mlme_sock);
1095 os_free(drv->assoc_req_ies);
1096 os_free(drv->assoc_resp_ies);
1097 os_free(drv);
1098}
1099
1100
1101/**
1102 * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion
1103 * @eloop_ctx: Unused
1104 * @timeout_ctx: ctx argument given to wpa_driver_wext_init()
1105 *
1106 * This function can be used as registered timeout when starting a scan to
1107 * generate a scan completed event if the driver does not report this.
1108 */
1109void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
1110{
1111 wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
1112 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
1113}
1114
1115
1116/**
1117 * wpa_driver_wext_scan - Request the driver to initiate scan
1118 * @priv: Pointer to private wext data from wpa_driver_wext_init()
1119 * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
1120 * all SSIDs (either active scan with broadcast SSID or passive
1121 * scan
1122 * @ssid_len: Length of the SSID
1123 * Returns: 0 on success, -1 on failure
1124 */
1125int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len)
1126{
1127 struct wpa_driver_wext_data *drv = priv;
1128 struct iwreq iwr;
1129 int ret = 0, timeout;
1130 struct iw_scan_req req;
Dmitry Shmidt0ebb71c2009-11-17 09:52:44 -08001131#ifdef ANDROID
1132 struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
1133 int scan_probe_flag = 0;
1134#endif
The Android Open Source Project845e0122009-03-03 19:31:34 -08001135
1136 if (ssid_len > IW_ESSID_MAX_SIZE) {
1137 wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
1138 __FUNCTION__, (unsigned long) ssid_len);
1139 return -1;
1140 }
1141
1142 os_memset(&iwr, 0, sizeof(iwr));
1143 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1144
Dmitry Shmidt0ebb71c2009-11-17 09:52:44 -08001145#ifdef ANDROID
1146 if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) {
1147 scan_probe_flag = wpa_s->prev_scan_ssid->scan_ssid;
1148 }
1149 if (scan_probe_flag && (ssid && ssid_len)) {
1150#else
The Android Open Source Project845e0122009-03-03 19:31:34 -08001151 if (ssid && ssid_len) {
Dmitry Shmidt0ebb71c2009-11-17 09:52:44 -08001152#endif
The Android Open Source Project845e0122009-03-03 19:31:34 -08001153 os_memset(&req, 0, sizeof(req));
1154 req.essid_len = ssid_len;
1155 req.bssid.sa_family = ARPHRD_ETHER;
1156 os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
1157 os_memcpy(req.essid, ssid, ssid_len);
1158 iwr.u.data.pointer = (caddr_t) &req;
1159 iwr.u.data.length = sizeof(req);
1160 iwr.u.data.flags = IW_SCAN_THIS_ESSID;
1161 }
1162
1163 if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
1164 perror("ioctl[SIOCSIWSCAN]");
1165 ret = -1;
1166 }
1167
1168 /* Not all drivers generate "scan completed" wireless event, so try to
1169 * read results after a timeout. */
1170 timeout = 5;
1171 if (drv->scan_complete_events) {
1172 /*
1173 * The driver seems to deliver SIOCGIWSCAN events to notify
1174 * when scan is complete, so use longer timeout to avoid race
1175 * conditions with scanning and following association request.
1176 */
1177 timeout = 30;
1178 }
1179 wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
1180 "seconds", ret, timeout);
1181 eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
1182 eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
1183 drv->ctx);
1184
1185 return ret;
1186}
1187
1188
1189/* Compare function for sorting scan results. Return >0 if @b is considered
1190 * better. */
1191static int wpa_scan_result_compar(const void *a, const void *b)
1192{
1193 const struct wpa_scan_result *wa = a;
1194 const struct wpa_scan_result *wb = b;
1195
1196 /* WPA/WPA2 support preferred */
1197 if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
1198 !(wa->wpa_ie_len || wa->rsn_ie_len))
1199 return 1;
1200 if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
1201 (wa->wpa_ie_len || wa->rsn_ie_len))
1202 return -1;
1203
1204 /* privacy support preferred */
1205 if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
1206 (wb->caps & IEEE80211_CAP_PRIVACY))
1207 return 1;
1208 if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
1209 (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
1210 return -1;
1211
1212 /* best/max rate preferred if signal level close enough XXX */
1213 if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
1214 return wb->maxrate - wa->maxrate;
1215
1216 /* use freq for channel preference */
1217
1218 /* all things being equal, use signal level; if signal levels are
1219 * identical, use quality values since some drivers may only report
1220 * that value and leave the signal level zero */
1221 if (wb->level == wa->level)
1222 return wb->qual - wa->qual;
1223 return wb->level - wa->level;
1224}
1225
1226
1227/**
1228 * wpa_driver_wext_get_scan_results - Fetch the latest scan results
1229 * @priv: Pointer to private wext data from wpa_driver_wext_init()
1230 * @results: Pointer to buffer for scan results
1231 * @max_size: Maximum number of entries (buffer size)
1232 * Returns: Number of scan result entries used on success, -1 on
1233 * failure
1234 *
1235 * If scan results include more than max_size BSSes, max_size will be
1236 * returned and the remaining entries will not be included in the
1237 * buffer.
1238 */
1239int wpa_driver_wext_get_scan_results(void *priv,
1240 struct wpa_scan_result *results,
1241 size_t max_size)
1242{
1243 struct wpa_driver_wext_data *drv = priv;
1244 struct iwreq iwr;
1245 size_t ap_num = 0;
1246 int first, maxrate;
1247 u8 *res_buf;
1248 struct iw_event iwe_buf, *iwe = &iwe_buf;
1249 char *pos, *end, *custom, *genie, *gpos, *gend;
1250 struct iw_param p;
1251 size_t len, clen, res_buf_len;
1252
1253 os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
Dmitry Shmidt61149872009-08-20 12:10:19 -07001254#ifdef ANDROID
1255 /* To make sure correctly parse scan results which is impacted by wext
1256 * version, first check range->we_version, if it is default value (0),
1257 * update again here */
1258 if (drv->we_version_compiled == 0)
1259 wpa_driver_wext_get_range(drv);
1260#endif
The Android Open Source Project845e0122009-03-03 19:31:34 -08001261 res_buf_len = IW_SCAN_MAX_DATA;
1262 for (;;) {
1263 res_buf = os_malloc(res_buf_len);
1264 if (res_buf == NULL)
1265 return -1;
1266 os_memset(&iwr, 0, sizeof(iwr));
1267 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1268 iwr.u.data.pointer = res_buf;
1269 iwr.u.data.length = res_buf_len;
1270
1271 if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
1272 break;
1273
1274 if (errno == E2BIG && res_buf_len < 100000) {
1275 os_free(res_buf);
1276 res_buf = NULL;
1277 res_buf_len *= 2;
1278 wpa_printf(MSG_DEBUG, "Scan results did not fit - "
1279 "trying larger buffer (%lu bytes)",
1280 (unsigned long) res_buf_len);
1281 } else {
1282 perror("ioctl[SIOCGIWSCAN]");
1283 os_free(res_buf);
1284 return -1;
1285 }
1286 }
1287
1288 len = iwr.u.data.length;
1289 ap_num = 0;
1290 first = 1;
1291
1292 pos = (char *) res_buf;
1293 end = (char *) res_buf + len;
1294
1295 while (pos + IW_EV_LCP_LEN <= end) {
1296 int ssid_len;
1297 /* Event data may be unaligned, so make a local, aligned copy
1298 * before processing. */
1299 os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
1300 if (iwe->len <= IW_EV_LCP_LEN)
1301 break;
1302
1303 custom = pos + IW_EV_POINT_LEN;
1304 if (drv->we_version_compiled > 18 &&
1305 (iwe->cmd == SIOCGIWESSID ||
1306 iwe->cmd == SIOCGIWENCODE ||
1307 iwe->cmd == IWEVGENIE ||
1308 iwe->cmd == IWEVCUSTOM)) {
1309 /* WE-19 removed the pointer from struct iw_point */
1310 char *dpos = (char *) &iwe_buf.u.data.length;
1311 int dlen = dpos - (char *) &iwe_buf;
1312 os_memcpy(dpos, pos + IW_EV_LCP_LEN,
1313 sizeof(struct iw_event) - dlen);
1314 } else {
1315 os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
1316 custom += IW_EV_POINT_OFF;
1317 }
1318
1319 switch (iwe->cmd) {
1320 case SIOCGIWAP:
1321 if (!first)
1322 ap_num++;
1323 first = 0;
1324 if (ap_num < max_size) {
1325 os_memcpy(results[ap_num].bssid,
1326 iwe->u.ap_addr.sa_data, ETH_ALEN);
1327 }
1328 break;
1329 case SIOCGIWMODE:
1330 if (ap_num >= max_size)
1331 break;
1332 if (iwe->u.mode == IW_MODE_ADHOC)
1333 results[ap_num].caps |= IEEE80211_CAP_IBSS;
1334 else if (iwe->u.mode == IW_MODE_MASTER ||
1335 iwe->u.mode == IW_MODE_INFRA)
1336 results[ap_num].caps |= IEEE80211_CAP_ESS;
1337 break;
1338 case SIOCGIWESSID:
1339 ssid_len = iwe->u.essid.length;
1340 if (custom + ssid_len > end)
1341 break;
1342 if (iwe->u.essid.flags &&
1343 ssid_len > 0 &&
1344 ssid_len <= IW_ESSID_MAX_SIZE) {
1345 if (ap_num < max_size) {
1346 os_memcpy(results[ap_num].ssid, custom,
1347 ssid_len);
1348 results[ap_num].ssid_len = ssid_len;
1349 }
1350 }
1351 break;
1352 case SIOCGIWFREQ:
1353 if (ap_num < max_size) {
1354 int divi = 1000000, i;
1355 if (iwe->u.freq.e == 0) {
1356 /*
1357 * Some drivers do not report
1358 * frequency, but a channel. Try to map
1359 * this to frequency by assuming they
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07001360 * are using IEEE 802.11b/g. But don't
1361 * overwrite a previously parsed
1362 * frequency if the driver sends both
1363 * frequency and channel, since the
1364 * driver may be sending an A-band
1365 * channel that we don't handle here.
The Android Open Source Project845e0122009-03-03 19:31:34 -08001366 */
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07001367
1368 if (results[ap_num].freq)
1369 break;
1370
The Android Open Source Project845e0122009-03-03 19:31:34 -08001371 if (iwe->u.freq.m >= 1 &&
1372 iwe->u.freq.m <= 13) {
1373 results[ap_num].freq =
1374 2407 +
1375 5 * iwe->u.freq.m;
1376 break;
1377 } else if (iwe->u.freq.m == 14) {
1378 results[ap_num].freq = 2484;
1379 break;
1380 }
1381 }
1382 if (iwe->u.freq.e > 6) {
1383 wpa_printf(
1384 MSG_DEBUG, "Invalid freq "
1385 "in scan results (BSSID="
1386 MACSTR ": m=%d e=%d\n",
1387 MAC2STR(results[ap_num].bssid),
1388 iwe->u.freq.m, iwe->u.freq.e);
1389 break;
1390 }
1391 for (i = 0; i < iwe->u.freq.e; i++)
1392 divi /= 10;
1393 results[ap_num].freq = iwe->u.freq.m / divi;
1394 }
1395 break;
1396 case IWEVQUAL:
1397 if (ap_num < max_size) {
1398 results[ap_num].qual = iwe->u.qual.qual;
1399 results[ap_num].noise = iwe->u.qual.noise;
1400 results[ap_num].level = iwe->u.qual.level;
1401 }
1402 break;
1403 case SIOCGIWENCODE:
1404 if (ap_num < max_size &&
1405 !(iwe->u.data.flags & IW_ENCODE_DISABLED))
1406 results[ap_num].caps |= IEEE80211_CAP_PRIVACY;
1407 break;
1408 case SIOCGIWRATE:
1409 custom = pos + IW_EV_LCP_LEN;
1410 clen = iwe->len;
1411 if (custom + clen > end)
1412 break;
1413 maxrate = 0;
1414 while (((ssize_t) clen) >=
1415 (ssize_t) sizeof(struct iw_param)) {
1416 /* Note: may be misaligned, make a local,
1417 * aligned copy */
1418 os_memcpy(&p, custom, sizeof(struct iw_param));
1419 if (p.value > maxrate)
1420 maxrate = p.value;
1421 clen -= sizeof(struct iw_param);
1422 custom += sizeof(struct iw_param);
1423 }
1424 if (ap_num < max_size)
1425 results[ap_num].maxrate = maxrate;
1426 break;
1427 case IWEVGENIE:
1428 if (ap_num >= max_size)
1429 break;
1430 gpos = genie = custom;
1431 gend = genie + iwe->u.data.length;
1432 if (gend > end) {
1433 wpa_printf(MSG_INFO, "IWEVGENIE overflow");
1434 break;
1435 }
1436 while (gpos + 1 < gend &&
1437 gpos + 2 + (u8) gpos[1] <= gend) {
1438 u8 ie = gpos[0], ielen = gpos[1] + 2;
1439 if (ielen > SSID_MAX_WPA_IE_LEN) {
1440 gpos += ielen;
1441 continue;
1442 }
1443 switch (ie) {
1444 case GENERIC_INFO_ELEM:
1445 if (ielen < 2 + 4 ||
1446 os_memcmp(&gpos[2],
1447 "\x00\x50\xf2\x01", 4) !=
1448 0)
1449 break;
1450 os_memcpy(results[ap_num].wpa_ie, gpos,
1451 ielen);
1452 results[ap_num].wpa_ie_len = ielen;
1453 break;
1454 case RSN_INFO_ELEM:
1455 os_memcpy(results[ap_num].rsn_ie, gpos,
1456 ielen);
1457 results[ap_num].rsn_ie_len = ielen;
1458 break;
1459 }
1460 gpos += ielen;
1461 }
1462 break;
1463 case IWEVCUSTOM:
1464 clen = iwe->u.data.length;
1465 if (custom + clen > end)
1466 break;
1467 if (clen > 7 &&
1468 os_strncmp(custom, "wpa_ie=", 7) == 0 &&
1469 ap_num < max_size) {
1470 char *spos;
1471 int bytes;
1472 spos = custom + 7;
1473 bytes = custom + clen - spos;
1474 if (bytes & 1)
1475 break;
1476 bytes /= 2;
1477 if (bytes > SSID_MAX_WPA_IE_LEN) {
1478 wpa_printf(MSG_INFO, "Too long WPA IE "
1479 "(%d)", bytes);
1480 break;
1481 }
1482 hexstr2bin(spos, results[ap_num].wpa_ie,
1483 bytes);
1484 results[ap_num].wpa_ie_len = bytes;
1485 } else if (clen > 7 &&
1486 os_strncmp(custom, "rsn_ie=", 7) == 0 &&
1487 ap_num < max_size) {
1488 char *spos;
1489 int bytes;
1490 spos = custom + 7;
1491 bytes = custom + clen - spos;
1492 if (bytes & 1)
1493 break;
1494 bytes /= 2;
1495 if (bytes > SSID_MAX_WPA_IE_LEN) {
1496 wpa_printf(MSG_INFO, "Too long RSN IE "
1497 "(%d)", bytes);
1498 break;
1499 }
1500 hexstr2bin(spos, results[ap_num].rsn_ie,
1501 bytes);
1502 results[ap_num].rsn_ie_len = bytes;
1503 }
1504 break;
1505 }
1506
1507 pos += iwe->len;
1508 }
1509 os_free(res_buf);
1510 res_buf = NULL;
1511 if (!first)
1512 ap_num++;
1513 if (ap_num > max_size) {
1514 wpa_printf(MSG_DEBUG, "Too small scan result buffer - "
1515 "%lu BSSes but room only for %lu",
1516 (unsigned long) ap_num,
1517 (unsigned long) max_size);
1518 ap_num = max_size;
1519 }
1520 qsort(results, ap_num, sizeof(struct wpa_scan_result),
1521 wpa_scan_result_compar);
1522
1523 wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
1524 (unsigned long) len, (unsigned long) ap_num);
1525
1526 return ap_num;
1527}
1528
1529
1530static int wpa_driver_wext_get_range(void *priv)
1531{
1532 struct wpa_driver_wext_data *drv = priv;
1533 struct iw_range *range;
1534 struct iwreq iwr;
1535 int minlen;
1536 size_t buflen;
1537
1538 /*
1539 * Use larger buffer than struct iw_range in order to allow the
1540 * structure to grow in the future.
1541 */
1542 buflen = sizeof(struct iw_range) + 500;
1543 range = os_zalloc(buflen);
1544 if (range == NULL)
1545 return -1;
1546
1547 os_memset(&iwr, 0, sizeof(iwr));
1548 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1549 iwr.u.data.pointer = (caddr_t) range;
1550 iwr.u.data.length = buflen;
1551
1552 minlen = ((char *) &range->enc_capa) - (char *) range +
1553 sizeof(range->enc_capa);
1554
1555 if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
1556 perror("ioctl[SIOCGIWRANGE]");
1557 os_free(range);
1558 return -1;
1559 } else if (iwr.u.data.length >= minlen &&
1560 range->we_version_compiled >= 18) {
1561 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
1562 "WE(source)=%d enc_capa=0x%x",
1563 range->we_version_compiled,
1564 range->we_version_source,
1565 range->enc_capa);
1566 drv->has_capability = 1;
1567 drv->we_version_compiled = range->we_version_compiled;
1568 if (range->enc_capa & IW_ENC_CAPA_WPA) {
1569 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1570 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
1571 }
1572 if (range->enc_capa & IW_ENC_CAPA_WPA2) {
1573 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1574 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
1575 }
1576 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
1577 WPA_DRIVER_CAPA_ENC_WEP104;
1578 if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
1579 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
1580 if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
1581 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
1582 wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x",
1583 drv->capa.key_mgmt, drv->capa.enc);
1584 } else {
1585 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
1586 "assuming WPA is not supported");
1587 }
1588
1589 os_free(range);
1590 return 0;
1591}
1592
1593
1594static int wpa_driver_wext_set_wpa(void *priv, int enabled)
1595{
1596 struct wpa_driver_wext_data *drv = priv;
1597 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1598
1599 return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
1600 enabled);
1601}
1602
1603
1604static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
1605 const u8 *addr, int key_idx,
1606 int set_tx, const u8 *seq,
1607 size_t seq_len,
1608 const u8 *key, size_t key_len)
1609{
1610 struct wpa_driver_wext_data *drv = priv;
1611 struct iwreq iwr;
1612 int ret = 0;
1613 struct iw_encode_ext *ext;
1614
1615 if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
1616 wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
1617 __FUNCTION__, (unsigned long) seq_len);
1618 return -1;
1619 }
1620
1621 ext = os_zalloc(sizeof(*ext) + key_len);
1622 if (ext == NULL)
1623 return -1;
1624 os_memset(&iwr, 0, sizeof(iwr));
1625 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1626 iwr.u.encoding.flags = key_idx + 1;
1627 if (alg == WPA_ALG_NONE)
1628 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
1629 iwr.u.encoding.pointer = (caddr_t) ext;
1630 iwr.u.encoding.length = sizeof(*ext) + key_len;
1631
1632 if (addr == NULL ||
1633 os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
1634 ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
1635 if (set_tx)
1636 ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
1637
1638 ext->addr.sa_family = ARPHRD_ETHER;
1639 if (addr)
1640 os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
1641 else
1642 os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
1643 if (key && key_len) {
1644 os_memcpy(ext + 1, key, key_len);
1645 ext->key_len = key_len;
1646 }
1647 switch (alg) {
1648 case WPA_ALG_NONE:
1649 ext->alg = IW_ENCODE_ALG_NONE;
1650 break;
1651 case WPA_ALG_WEP:
1652 ext->alg = IW_ENCODE_ALG_WEP;
1653 break;
1654 case WPA_ALG_TKIP:
1655 ext->alg = IW_ENCODE_ALG_TKIP;
1656 break;
1657 case WPA_ALG_CCMP:
1658 ext->alg = IW_ENCODE_ALG_CCMP;
1659 break;
1660 default:
1661 wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
1662 __FUNCTION__, alg);
1663 os_free(ext);
1664 return -1;
1665 }
1666
1667 if (seq && seq_len) {
1668 ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
1669 os_memcpy(ext->rx_seq, seq, seq_len);
1670 }
1671
1672 if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
1673 ret = errno == EOPNOTSUPP ? -2 : -1;
1674 if (errno == ENODEV) {
1675 /*
1676 * ndiswrapper seems to be returning incorrect error
1677 * code.. */
1678 ret = -2;
1679 }
1680
1681 perror("ioctl[SIOCSIWENCODEEXT]");
1682 }
1683
1684 os_free(ext);
1685 return ret;
1686}
1687
1688
1689/**
1690 * wpa_driver_wext_set_key - Configure encryption key
1691 * @priv: Pointer to private wext data from wpa_driver_wext_init()
1692 * @priv: Private driver interface data
1693 * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
1694 * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
1695 * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
1696 * broadcast/default keys
1697 * @key_idx: key index (0..3), usually 0 for unicast keys
1698 * @set_tx: Configure this key as the default Tx key (only used when
1699 * driver does not support separate unicast/individual key
1700 * @seq: Sequence number/packet number, seq_len octets, the next
1701 * packet number to be used for in replay protection; configured
1702 * for Rx keys (in most cases, this is only used with broadcast
1703 * keys and set to zero for unicast keys)
1704 * @seq_len: Length of the seq, depends on the algorithm:
1705 * TKIP: 6 octets, CCMP: 6 octets
1706 * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
1707 * 8-byte Rx Mic Key
1708 * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
1709 * TKIP: 32, CCMP: 16)
1710 * Returns: 0 on success, -1 on failure
1711 *
1712 * This function uses SIOCSIWENCODEEXT by default, but tries to use
1713 * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
1714 */
1715int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
1716 const u8 *addr, int key_idx,
1717 int set_tx, const u8 *seq, size_t seq_len,
1718 const u8 *key, size_t key_len)
1719{
1720 struct wpa_driver_wext_data *drv = priv;
1721 struct iwreq iwr;
1722 int ret = 0;
1723
1724 wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
1725 "key_len=%lu",
1726 __FUNCTION__, alg, key_idx, set_tx,
1727 (unsigned long) seq_len, (unsigned long) key_len);
1728
1729 ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
1730 seq, seq_len, key, key_len);
1731 if (ret == 0)
1732 return 0;
1733
1734 if (ret == -2 &&
1735 (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
1736 wpa_printf(MSG_DEBUG, "Driver did not support "
1737 "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
1738 ret = 0;
1739 } else {
1740 wpa_printf(MSG_DEBUG, "Driver did not support "
1741 "SIOCSIWENCODEEXT");
1742 return ret;
1743 }
1744
1745 os_memset(&iwr, 0, sizeof(iwr));
1746 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1747 iwr.u.encoding.flags = key_idx + 1;
1748 if (alg == WPA_ALG_NONE)
1749 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
1750 iwr.u.encoding.pointer = (caddr_t) key;
1751 iwr.u.encoding.length = key_len;
1752
1753 if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
1754 perror("ioctl[SIOCSIWENCODE]");
1755 ret = -1;
1756 }
1757
1758 if (set_tx && alg != WPA_ALG_NONE) {
1759 os_memset(&iwr, 0, sizeof(iwr));
1760 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1761 iwr.u.encoding.flags = key_idx + 1;
1762 iwr.u.encoding.pointer = (caddr_t) NULL;
1763 iwr.u.encoding.length = 0;
1764 if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
1765 perror("ioctl[SIOCSIWENCODE] (set_tx)");
1766 ret = -1;
1767 }
1768 }
1769
1770 return ret;
1771}
1772
1773
1774static int wpa_driver_wext_set_countermeasures(void *priv,
1775 int enabled)
1776{
1777 struct wpa_driver_wext_data *drv = priv;
1778 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1779 return wpa_driver_wext_set_auth_param(drv,
1780 IW_AUTH_TKIP_COUNTERMEASURES,
1781 enabled);
1782}
1783
1784
1785static int wpa_driver_wext_set_drop_unencrypted(void *priv,
1786 int enabled)
1787{
1788 struct wpa_driver_wext_data *drv = priv;
1789 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1790 drv->use_crypt = enabled;
1791 return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
1792 enabled);
1793}
1794
1795
1796static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
1797 const u8 *addr, int cmd, int reason_code)
1798{
1799 struct iwreq iwr;
1800 struct iw_mlme mlme;
1801 int ret = 0;
1802
1803 os_memset(&iwr, 0, sizeof(iwr));
1804 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1805 os_memset(&mlme, 0, sizeof(mlme));
1806 mlme.cmd = cmd;
1807 mlme.reason_code = reason_code;
1808 mlme.addr.sa_family = ARPHRD_ETHER;
1809 os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
1810 iwr.u.data.pointer = (caddr_t) &mlme;
1811 iwr.u.data.length = sizeof(mlme);
1812
1813 if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
1814 perror("ioctl[SIOCSIWMLME]");
1815 ret = -1;
1816 }
1817
1818 return ret;
1819}
1820
1821
1822static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
1823 int reason_code)
1824{
1825 struct wpa_driver_wext_data *drv = priv;
1826 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1827 return wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
1828}
1829
1830
1831static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
1832 int reason_code)
1833{
1834 struct wpa_driver_wext_data *drv = priv;
1835 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1836 return wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC,
1837 reason_code);
1838}
1839
1840
1841static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
1842 size_t ie_len)
1843{
1844 struct wpa_driver_wext_data *drv = priv;
1845 struct iwreq iwr;
1846 int ret = 0;
1847
1848 os_memset(&iwr, 0, sizeof(iwr));
1849 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1850 iwr.u.data.pointer = (caddr_t) ie;
1851 iwr.u.data.length = ie_len;
1852
1853 if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
1854 perror("ioctl[SIOCSIWGENIE]");
1855 ret = -1;
1856 }
1857
1858 return ret;
1859}
1860
1861
1862static int wpa_driver_wext_cipher2wext(int cipher)
1863{
1864 switch (cipher) {
1865 case CIPHER_NONE:
1866 return IW_AUTH_CIPHER_NONE;
1867 case CIPHER_WEP40:
1868 return IW_AUTH_CIPHER_WEP40;
1869 case CIPHER_TKIP:
1870 return IW_AUTH_CIPHER_TKIP;
1871 case CIPHER_CCMP:
1872 return IW_AUTH_CIPHER_CCMP;
1873 case CIPHER_WEP104:
1874 return IW_AUTH_CIPHER_WEP104;
1875 default:
1876 return 0;
1877 }
1878}
1879
1880
1881static int wpa_driver_wext_keymgmt2wext(int keymgmt)
1882{
1883 switch (keymgmt) {
1884 case KEY_MGMT_802_1X:
1885 case KEY_MGMT_802_1X_NO_WPA:
1886 return IW_AUTH_KEY_MGMT_802_1X;
1887 case KEY_MGMT_PSK:
1888 return IW_AUTH_KEY_MGMT_PSK;
1889 default:
1890 return 0;
1891 }
1892}
1893
1894
1895static int
1896wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
1897 struct wpa_driver_associate_params *params)
1898{
1899 struct iwreq iwr;
1900 int ret = 0;
1901
1902 wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
1903 "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
1904
1905 os_memset(&iwr, 0, sizeof(iwr));
1906 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
1907 /* Just changing mode, not actual keys */
1908 iwr.u.encoding.flags = 0;
1909 iwr.u.encoding.pointer = (caddr_t) NULL;
1910 iwr.u.encoding.length = 0;
1911
1912 /*
1913 * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
1914 * different things. Here they are used to indicate Open System vs.
1915 * Shared Key authentication algorithm. However, some drivers may use
1916 * them to select between open/restricted WEP encrypted (open = allow
1917 * both unencrypted and encrypted frames; restricted = only allow
1918 * encrypted frames).
1919 */
1920
1921 if (!drv->use_crypt) {
1922 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
1923 } else {
1924 if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
1925 iwr.u.encoding.flags |= IW_ENCODE_OPEN;
1926 if (params->auth_alg & AUTH_ALG_SHARED_KEY)
1927 iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
1928 }
1929
1930 if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
1931 perror("ioctl[SIOCSIWENCODE]");
1932 ret = -1;
1933 }
1934
1935 return ret;
1936}
1937
1938
1939static int
1940wpa_driver_wext_associate(void *priv,
1941 struct wpa_driver_associate_params *params)
1942{
1943 struct wpa_driver_wext_data *drv = priv;
1944 int ret = 0;
1945 int allow_unencrypted_eapol;
Dmitry Shmidt4866d772009-09-29 16:14:34 -07001946 int value, flags;
The Android Open Source Project845e0122009-03-03 19:31:34 -08001947
1948 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
1949
Dmitry Shmidt4866d772009-09-29 16:14:34 -07001950 if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
1951 if (!(flags & IFF_UP)) {
1952 wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
1953 }
1954 }
1955
The Android Open Source Project845e0122009-03-03 19:31:34 -08001956 /*
1957 * If the driver did not support SIOCSIWAUTH, fallback to
1958 * SIOCSIWENCODE here.
1959 */
1960 if (drv->auth_alg_fallback &&
1961 wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
1962 ret = -1;
1963
1964 if (!params->bssid &&
1965 wpa_driver_wext_set_bssid(drv, NULL) < 0)
1966 ret = -1;
1967
1968 if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
1969 ret = -1;
1970 /* TODO: should consider getting wpa version and cipher/key_mgmt suites
1971 * from configuration, not from here, where only the selected suite is
1972 * available */
1973 if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
1974 < 0)
1975 ret = -1;
1976 if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
1977 value = IW_AUTH_WPA_VERSION_DISABLED;
1978 else if (params->wpa_ie[0] == RSN_INFO_ELEM)
1979 value = IW_AUTH_WPA_VERSION_WPA2;
1980 else
1981 value = IW_AUTH_WPA_VERSION_WPA;
1982 if (wpa_driver_wext_set_auth_param(drv,
1983 IW_AUTH_WPA_VERSION, value) < 0)
1984 ret = -1;
1985 value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
1986 if (wpa_driver_wext_set_auth_param(drv,
1987 IW_AUTH_CIPHER_PAIRWISE, value) < 0)
1988 ret = -1;
1989 value = wpa_driver_wext_cipher2wext(params->group_suite);
1990 if (wpa_driver_wext_set_auth_param(drv,
1991 IW_AUTH_CIPHER_GROUP, value) < 0)
1992 ret = -1;
1993 value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
1994 if (wpa_driver_wext_set_auth_param(drv,
1995 IW_AUTH_KEY_MGMT, value) < 0)
1996 ret = -1;
1997 value = params->key_mgmt_suite != KEY_MGMT_NONE ||
1998 params->pairwise_suite != CIPHER_NONE ||
1999 params->group_suite != CIPHER_NONE ||
2000 params->wpa_ie_len;
2001 if (wpa_driver_wext_set_auth_param(drv,
2002 IW_AUTH_PRIVACY_INVOKED, value) < 0)
2003 ret = -1;
2004
2005 /* Allow unencrypted EAPOL messages even if pairwise keys are set when
2006 * not using WPA. IEEE 802.1X specifies that these frames are not
2007 * encrypted, but WPA encrypts them when pairwise keys are in use. */
2008 if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
2009 params->key_mgmt_suite == KEY_MGMT_PSK)
2010 allow_unencrypted_eapol = 0;
2011 else
2012 allow_unencrypted_eapol = 1;
2013
2014 if (wpa_driver_wext_set_auth_param(drv,
2015 IW_AUTH_RX_UNENCRYPTED_EAPOL,
2016 allow_unencrypted_eapol) < 0)
2017 ret = -1;
2018 if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
2019 ret = -1;
2020 if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
2021 ret = -1;
2022 if (params->bssid &&
2023 wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
2024 ret = -1;
2025
2026 return ret;
2027}
2028
2029
2030static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
2031{
2032 struct wpa_driver_wext_data *drv = priv;
2033 int algs = 0, res;
2034
2035 if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
2036 algs |= IW_AUTH_ALG_OPEN_SYSTEM;
2037 if (auth_alg & AUTH_ALG_SHARED_KEY)
2038 algs |= IW_AUTH_ALG_SHARED_KEY;
2039 if (auth_alg & AUTH_ALG_LEAP)
2040 algs |= IW_AUTH_ALG_LEAP;
2041 if (algs == 0) {
2042 /* at least one algorithm should be set */
2043 algs = IW_AUTH_ALG_OPEN_SYSTEM;
2044 }
2045
2046 res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
2047 algs);
2048 drv->auth_alg_fallback = res == -2;
2049 return res;
2050}
2051
2052
2053/**
2054 * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
2055 * @priv: Pointer to private wext data from wpa_driver_wext_init()
2056 * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
2057 * Returns: 0 on success, -1 on failure
2058 */
2059int wpa_driver_wext_set_mode(void *priv, int mode)
2060{
2061 struct wpa_driver_wext_data *drv = priv;
2062 struct iwreq iwr;
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07002063 int ret = -1, flags;
2064 unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
The Android Open Source Project845e0122009-03-03 19:31:34 -08002065
2066 os_memset(&iwr, 0, sizeof(iwr));
2067 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07002068 iwr.u.mode = new_mode;
2069 if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
2070 ret = 0;
2071 goto done;
The Android Open Source Project845e0122009-03-03 19:31:34 -08002072 }
2073
Dmitry Shmidtdc9507e2009-04-16 11:38:56 -07002074 if (errno != EBUSY) {
2075 perror("ioctl[SIOCSIWMODE]");
2076 goto done;
2077 }
2078
2079 /* mac80211 doesn't allow mode changes while the device is up, so if
2080 * the device isn't in the mode we're about to change to, take device
2081 * down, try to set the mode again, and bring it back up.
2082 */
2083 if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
2084 perror("ioctl[SIOCGIWMODE]");
2085 goto done;
2086 }
2087
2088 if (iwr.u.mode == new_mode) {
2089 ret = 0;
2090 goto done;
2091 }
2092
2093 if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
2094 (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
2095
2096 /* Try to set the mode again while the interface is down */
2097 iwr.u.mode = new_mode;
2098 if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
2099 perror("ioctl[SIOCSIWMODE]");
2100 else
2101 ret = 0;
2102
2103 /* Ignore return value of get_ifflags to ensure that the device
2104 * is always up like it was before this function was called.
2105 */
2106 (void) wpa_driver_wext_get_ifflags(drv, &flags);
2107 (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
2108 }
2109
2110done:
The Android Open Source Project845e0122009-03-03 19:31:34 -08002111 return ret;
2112}
2113
2114
2115static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
2116 u32 cmd, const u8 *bssid, const u8 *pmkid)
2117{
2118 struct iwreq iwr;
2119 struct iw_pmksa pmksa;
2120 int ret = 0;
2121
2122 os_memset(&iwr, 0, sizeof(iwr));
2123 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
2124 os_memset(&pmksa, 0, sizeof(pmksa));
2125 pmksa.cmd = cmd;
2126 pmksa.bssid.sa_family = ARPHRD_ETHER;
2127 if (bssid)
2128 os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
2129 if (pmkid)
2130 os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
2131 iwr.u.data.pointer = (caddr_t) &pmksa;
2132 iwr.u.data.length = sizeof(pmksa);
2133
2134 if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
2135 if (errno != EOPNOTSUPP)
2136 perror("ioctl[SIOCSIWPMKSA]");
2137 ret = -1;
2138 }
2139
2140 return ret;
2141}
2142
2143
2144static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
2145 const u8 *pmkid)
2146{
2147 struct wpa_driver_wext_data *drv = priv;
2148 return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
2149}
2150
2151
2152static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
2153 const u8 *pmkid)
2154{
2155 struct wpa_driver_wext_data *drv = priv;
2156 return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
2157}
2158
2159
2160static int wpa_driver_wext_flush_pmkid(void *priv)
2161{
2162 struct wpa_driver_wext_data *drv = priv;
2163 return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
2164}
2165
2166
2167static int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
2168{
2169 struct wpa_driver_wext_data *drv = priv;
2170 if (!drv->has_capability)
2171 return -1;
2172 os_memcpy(capa, &drv->capa, sizeof(*capa));
2173 return 0;
2174}
2175
2176
2177int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
2178 const char *ifname)
2179{
2180 if (ifname == NULL) {
2181 drv->ifindex2 = -1;
2182 return 0;
2183 }
2184
2185 drv->ifindex2 = if_nametoindex(ifname);
2186 if (drv->ifindex2 <= 0)
2187 return -1;
2188
2189 wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
2190 "wireless events", drv->ifindex2, ifname);
2191
2192 return 0;
2193}
2194
2195
2196int wpa_driver_wext_set_operstate(void *priv, int state)
2197{
2198 struct wpa_driver_wext_data *drv = priv;
2199
2200 wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
2201 __func__, drv->operstate, state, state ? "UP" : "DORMANT");
2202 drv->operstate = state;
2203 return wpa_driver_wext_send_oper_ifla(
2204 drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
2205}
2206
2207
2208#ifdef CONFIG_CLIENT_MLME
2209static int hostapd_ioctl(struct wpa_driver_wext_data *drv,
2210 struct prism2_hostapd_param *param, int len)
2211{
2212 struct iwreq iwr;
2213
2214 os_memset(&iwr, 0, sizeof(iwr));
2215 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
2216 iwr.u.data.pointer = (caddr_t) param;
2217 iwr.u.data.length = len;
2218
2219 if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
2220 perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
2221 return -1;
2222 }
2223
2224 return 0;
2225}
2226
2227
2228static struct wpa_hw_modes *
2229wpa_driver_wext_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
2230{
2231 struct wpa_driver_wext_data *drv = priv;
2232 struct prism2_hostapd_param *param;
2233 u8 *pos, *end;
2234 struct wpa_hw_modes *modes = NULL;
2235 int i;
2236
2237 param = os_zalloc(PRISM2_HOSTAPD_MAX_BUF_SIZE);
2238 if (param == NULL)
2239 return NULL;
2240 param->cmd = PRISM2_HOSTAPD_GET_HW_FEATURES;
2241
2242 if (hostapd_ioctl(drv, param, PRISM2_HOSTAPD_MAX_BUF_SIZE) < 0) {
2243 perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
2244 goto out;
2245 }
2246
2247 *num_modes = param->u.hw_features.num_modes;
2248 *flags = param->u.hw_features.flags;
2249
2250 pos = param->u.hw_features.data;
2251 end = pos + PRISM2_HOSTAPD_MAX_BUF_SIZE -
2252 (param->u.hw_features.data - (u8 *) param);
2253
2254 modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes));
2255 if (modes == NULL)
2256 goto out;
2257
2258 for (i = 0; i < *num_modes; i++) {
2259 struct hostapd_ioctl_hw_modes_hdr *hdr;
2260 struct wpa_hw_modes *feature;
2261 int clen, rlen;
2262
2263 hdr = (struct hostapd_ioctl_hw_modes_hdr *) pos;
2264 pos = (u8 *) (hdr + 1);
2265 clen = hdr->num_channels * sizeof(struct wpa_channel_data);
2266 rlen = hdr->num_rates * sizeof(struct wpa_rate_data);
2267
2268 feature = &modes[i];
2269 switch (hdr->mode) {
2270 case MODE_IEEE80211A:
2271 feature->mode = WPA_MODE_IEEE80211A;
2272 break;
2273 case MODE_IEEE80211B:
2274 feature->mode = WPA_MODE_IEEE80211B;
2275 break;
2276 case MODE_IEEE80211G:
2277 feature->mode = WPA_MODE_IEEE80211G;
2278 break;
2279 case MODE_ATHEROS_TURBO:
2280 case MODE_ATHEROS_TURBOG:
2281 wpa_printf(MSG_ERROR, "Skip unsupported hw_mode=%d in "
2282 "get_hw_features data", hdr->mode);
2283 pos += clen + rlen;
2284 continue;
2285 default:
2286 wpa_printf(MSG_ERROR, "Unknown hw_mode=%d in "
2287 "get_hw_features data", hdr->mode);
2288 ieee80211_sta_free_hw_features(modes, *num_modes);
2289 modes = NULL;
2290 break;
2291 }
2292 feature->num_channels = hdr->num_channels;
2293 feature->num_rates = hdr->num_rates;
2294
2295 feature->channels = os_malloc(clen);
2296 feature->rates = os_malloc(rlen);
2297 if (!feature->channels || !feature->rates ||
2298 pos + clen + rlen > end) {
2299 ieee80211_sta_free_hw_features(modes, *num_modes);
2300 modes = NULL;
2301 break;
2302 }
2303
2304 os_memcpy(feature->channels, pos, clen);
2305 pos += clen;
2306 os_memcpy(feature->rates, pos, rlen);
2307 pos += rlen;
2308 }
2309
2310out:
2311 os_free(param);
2312 return modes;
2313}
2314
2315
2316int wpa_driver_wext_set_channel(void *priv, wpa_hw_mode phymode, int chan,
2317 int freq)
2318{
2319 return wpa_driver_wext_set_freq(priv, freq);
2320}
2321
2322
2323static void wpa_driver_wext_mlme_read(int sock, void *eloop_ctx,
2324 void *sock_ctx)
2325{
2326 struct wpa_driver_wext_data *drv = eloop_ctx;
2327 int len;
2328 unsigned char buf[3000];
2329 struct ieee80211_frame_info *fi;
2330 struct ieee80211_rx_status rx_status;
2331
2332 len = recv(sock, buf, sizeof(buf), 0);
2333 if (len < 0) {
2334 perror("recv[MLME]");
2335 return;
2336 }
2337
2338 if (len < (int) sizeof(struct ieee80211_frame_info)) {
2339 wpa_printf(MSG_DEBUG, "WEXT: Too short MLME frame (len=%d)",
2340 len);
2341 return;
2342 }
2343
2344 fi = (struct ieee80211_frame_info *) buf;
2345 if (ntohl(fi->version) != IEEE80211_FI_VERSION) {
2346 wpa_printf(MSG_DEBUG, "WEXT: Invalid MLME frame info version "
2347 "0x%x", ntohl(fi->version));
2348 return;
2349 }
2350
2351 os_memset(&rx_status, 0, sizeof(rx_status));
2352 rx_status.ssi = ntohl(fi->ssi_signal);
2353 rx_status.channel = ntohl(fi->channel);
2354
2355 ieee80211_sta_rx(drv->ctx, buf + sizeof(struct ieee80211_frame_info),
2356 len - sizeof(struct ieee80211_frame_info),
2357 &rx_status);
2358}
2359
2360
2361static int wpa_driver_wext_open_mlme(struct wpa_driver_wext_data *drv)
2362{
2363 int flags, ifindex, s, *i;
2364 struct sockaddr_ll addr;
2365 struct iwreq iwr;
2366
2367 os_memset(&iwr, 0, sizeof(iwr));
2368 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
2369 i = (int *) iwr.u.name;
2370 *i++ = PRISM2_PARAM_USER_SPACE_MLME;
2371 *i++ = 1;
2372
2373 if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
2374 wpa_printf(MSG_ERROR, "WEXT: Failed to configure driver to "
2375 "use user space MLME");
2376 return -1;
2377 }
2378
2379 ifindex = if_nametoindex(drv->mlmedev);
2380 if (ifindex == 0) {
2381 wpa_printf(MSG_ERROR, "WEXT: mlmedev='%s' not found",
2382 drv->mlmedev);
2383 return -1;
2384 }
2385
2386 if (wpa_driver_wext_get_ifflags_ifname(drv, drv->mlmedev, &flags) != 0
2387 || wpa_driver_wext_set_ifflags_ifname(drv, drv->mlmedev,
2388 flags | IFF_UP) != 0) {
2389 wpa_printf(MSG_ERROR, "WEXT: Could not set interface "
2390 "'%s' UP", drv->mlmedev);
2391 return -1;
2392 }
2393
2394 s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
2395 if (s < 0) {
2396 perror("socket[PF_PACKET,SOCK_RAW]");
2397 return -1;
2398 }
2399
2400 os_memset(&addr, 0, sizeof(addr));
2401 addr.sll_family = AF_PACKET;
2402 addr.sll_ifindex = ifindex;
2403
2404 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
2405 perror("bind(MLME)");
2406 return -1;
2407 }
2408
2409 if (eloop_register_read_sock(s, wpa_driver_wext_mlme_read, drv, NULL))
2410 {
2411 wpa_printf(MSG_ERROR, "WEXT: Could not register MLME read "
2412 "socket");
2413 close(s);
2414 return -1;
2415 }
2416
2417 return s;
2418}
2419
2420
2421static int wpa_driver_wext_send_mlme(void *priv, const u8 *data,
2422 size_t data_len)
2423{
2424 struct wpa_driver_wext_data *drv = priv;
2425 int ret;
2426
2427 ret = send(drv->mlme_sock, data, data_len, 0);
2428 if (ret < 0) {
2429 perror("send[MLME]");
2430 return -1;
2431 }
2432
2433 return 0;
2434}
2435
2436
2437static int wpa_driver_wext_mlme_add_sta(void *priv, const u8 *addr,
2438 const u8 *supp_rates,
2439 size_t supp_rates_len)
2440{
2441 struct wpa_driver_wext_data *drv = priv;
2442 struct prism2_hostapd_param param;
2443 size_t len;
2444
2445 os_memset(&param, 0, sizeof(param));
2446 param.cmd = PRISM2_HOSTAPD_ADD_STA;
2447 os_memcpy(param.sta_addr, addr, ETH_ALEN);
2448 len = supp_rates_len;
2449 if (len > sizeof(param.u.add_sta.supp_rates))
2450 len = sizeof(param.u.add_sta.supp_rates);
2451 os_memcpy(param.u.add_sta.supp_rates, supp_rates, len);
2452 return hostapd_ioctl(drv, &param, sizeof(param));
2453}
2454
2455
2456static int wpa_driver_wext_mlme_remove_sta(void *priv, const u8 *addr)
2457{
2458 struct wpa_driver_wext_data *drv = priv;
2459 struct prism2_hostapd_param param;
2460
2461 os_memset(&param, 0, sizeof(param));
2462 param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
2463 os_memcpy(param.sta_addr, addr, ETH_ALEN);
2464 return hostapd_ioctl(drv, &param, sizeof(param));
2465}
2466
2467#endif /* CONFIG_CLIENT_MLME */
2468
2469
2470static int wpa_driver_wext_set_param(void *priv, const char *param)
2471{
2472#ifdef CONFIG_CLIENT_MLME
2473 struct wpa_driver_wext_data *drv = priv;
2474 const char *pos, *pos2;
2475 size_t len;
2476
2477 if (param == NULL)
2478 return 0;
2479
2480 wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
2481
2482 pos = os_strstr(param, "mlmedev=");
2483 if (pos) {
2484 pos += 8;
2485 pos2 = os_strchr(pos, ' ');
2486 if (pos2)
2487 len = pos2 - pos;
2488 else
2489 len = os_strlen(pos);
2490 if (len + 1 > sizeof(drv->mlmedev))
2491 return -1;
2492 os_memcpy(drv->mlmedev, pos, len);
2493 drv->mlmedev[len] = '\0';
2494 wpa_printf(MSG_DEBUG, "WEXT: Using user space MLME with "
2495 "mlmedev='%s'", drv->mlmedev);
2496 drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
2497
2498 drv->mlme_sock = wpa_driver_wext_open_mlme(drv);
2499 if (drv->mlme_sock < 0)
2500 return -1;
2501 }
2502#endif /* CONFIG_CLIENT_MLME */
2503
2504 return 0;
2505}
2506
2507
2508int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
2509{
2510 return drv->we_version_compiled;
2511}
2512
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002513#ifdef ANDROID
Dmitry Shmidt4b3af3f2009-11-03 14:41:57 -08002514static char *wpa_driver_get_country_code(int channels)
2515{
2516 char *country = "US"; /* WEXT_NUMBER_SCAN_CHANNELS_FCC */
2517
2518 if (channels == WEXT_NUMBER_SCAN_CHANNELS_ETSI)
2519 country = "EU";
2520 else if( channels == WEXT_NUMBER_SCAN_CHANNELS_MKK1)
2521 country = "JP";
2522 return country;
2523}
2524
Dmitry Shmidtc7da28c2009-11-20 18:21:55 -08002525static int wpa_driver_priv_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len)
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002526{
2527 struct wpa_driver_wext_data *drv = priv;
Dmitry Shmidt872ebd72009-07-30 14:16:44 -07002528 struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002529 struct iwreq iwr;
Dmitry Shmidtc7da28c2009-11-20 18:21:55 -08002530 int ret = 0, flags;
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002531
2532 wpa_printf(MSG_DEBUG, "%s %s len = %d", __func__, cmd, buf_len);
2533
Dmitry Shmidt872ebd72009-07-30 14:16:44 -07002534 if (os_strcasecmp(cmd, "RSSI-APPROX") == 0) {
Dmitry Shmidtf02dfc22009-11-03 15:53:04 -08002535 os_strncpy(cmd, "RSSI", MAX_DRV_CMD_SIZE);
Dmitry Shmidt872ebd72009-07-30 14:16:44 -07002536 }
Dmitry Shmidt4b3af3f2009-11-03 14:41:57 -08002537 else if( os_strncasecmp(cmd, "SCAN-CHANNELS", 13) == 0 ) {
2538 int no_of_chan;
Dmitry Shmidt872ebd72009-07-30 14:16:44 -07002539
Dmitry Shmidt4b3af3f2009-11-03 14:41:57 -08002540 no_of_chan = atoi(cmd + 13);
2541 os_snprintf(cmd, MAX_DRV_CMD_SIZE, "COUNTRY %s",
2542 wpa_driver_get_country_code(no_of_chan));
2543 }
Dmitry Shmidtc7da28c2009-11-20 18:21:55 -08002544 else if (os_strcasecmp(cmd, "STOP") == 0) {
2545 if ((wpa_driver_wext_get_ifflags(drv, &flags) == 0) &&
2546 (flags & IFF_UP)) {
Dmitry Shmidtaea96d82009-11-24 10:32:41 -08002547 wpa_printf(MSG_ERROR, "WEXT: %s when iface is UP", cmd);
Dmitry Shmidtc7da28c2009-11-20 18:21:55 -08002548 wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
2549 }
2550 }
Dmitry Shmidtaea96d82009-11-24 10:32:41 -08002551 else if( os_strcasecmp(cmd, "RELOAD") == 0 ) {
2552 wpa_printf(MSG_DEBUG,"Reload command");
2553 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
2554 return ret;
2555 }
Dmitry Shmidtc7da28c2009-11-20 18:21:55 -08002556
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002557 os_memset(&iwr, 0, sizeof(iwr));
2558 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
2559 os_memcpy(buf, cmd, strlen(cmd) + 1);
2560 iwr.u.data.pointer = buf;
2561 iwr.u.data.length = buf_len;
2562
2563 if ((ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)) < 0) {
2564 perror("ioctl[SIOCSIWPRIV]");
2565 }
2566
Dmitry Shmidtaea96d82009-11-24 10:32:41 -08002567 if (ret < 0) {
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002568 wpa_printf(MSG_ERROR, "%s failed", __func__);
Dmitry Shmidtaea96d82009-11-24 10:32:41 -08002569 drv->errors++;
2570 if (drv->errors > WEXT_NUMBER_SEQUENTIAL_ERRORS) {
2571 drv->errors = 0;
2572 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
2573 }
2574 }
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002575 else {
Dmitry Shmidtaea96d82009-11-24 10:32:41 -08002576 drv->errors = 0;
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002577 ret = 0;
2578 if ((os_strcasecmp(cmd, "RSSI") == 0) ||
2579 (os_strcasecmp(cmd, "LINKSPEED") == 0) ||
2580 (os_strcasecmp(cmd, "MACADDR") == 0)) {
2581 ret = strlen(buf);
2582 }
Dmitry Shmidt872ebd72009-07-30 14:16:44 -07002583/* else if (os_strcasecmp(cmd, "START") == 0) {
Dmitry Shmidt61149872009-08-20 12:10:19 -07002584 os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002585 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
2586 }
2587 else if (os_strcasecmp(cmd, "STOP") == 0) {
2588 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
Dmitry Shmidt872ebd72009-07-30 14:16:44 -07002589 }*/
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002590 wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
2591 }
2592 return ret;
2593}
2594#endif
The Android Open Source Project845e0122009-03-03 19:31:34 -08002595
2596const struct wpa_driver_ops wpa_driver_wext_ops = {
2597 .name = "wext",
2598 .desc = "Linux wireless extensions (generic)",
2599 .get_bssid = wpa_driver_wext_get_bssid,
2600 .get_ssid = wpa_driver_wext_get_ssid,
2601 .set_wpa = wpa_driver_wext_set_wpa,
2602 .set_key = wpa_driver_wext_set_key,
2603 .set_countermeasures = wpa_driver_wext_set_countermeasures,
2604 .set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
2605 .scan = wpa_driver_wext_scan,
2606 .get_scan_results = wpa_driver_wext_get_scan_results,
2607 .deauthenticate = wpa_driver_wext_deauthenticate,
2608 .disassociate = wpa_driver_wext_disassociate,
2609 .associate = wpa_driver_wext_associate,
2610 .set_auth_alg = wpa_driver_wext_set_auth_alg,
2611 .init = wpa_driver_wext_init,
2612 .deinit = wpa_driver_wext_deinit,
2613 .set_param = wpa_driver_wext_set_param,
2614 .add_pmkid = wpa_driver_wext_add_pmkid,
2615 .remove_pmkid = wpa_driver_wext_remove_pmkid,
2616 .flush_pmkid = wpa_driver_wext_flush_pmkid,
2617 .get_capa = wpa_driver_wext_get_capa,
2618 .set_operstate = wpa_driver_wext_set_operstate,
2619#ifdef CONFIG_CLIENT_MLME
2620 .get_hw_feature_data = wpa_driver_wext_get_hw_feature_data,
2621 .set_channel = wpa_driver_wext_set_channel,
2622 .set_ssid = wpa_driver_wext_set_ssid,
2623 .set_bssid = wpa_driver_wext_set_bssid,
2624 .send_mlme = wpa_driver_wext_send_mlme,
2625 .mlme_add_sta = wpa_driver_wext_mlme_add_sta,
2626 .mlme_remove_sta = wpa_driver_wext_mlme_remove_sta,
2627#endif /* CONFIG_CLIENT_MLME */
Dmitry Shmidt79cbd5c2009-06-11 15:23:45 -07002628#ifdef ANDROID
2629 .driver_cmd = wpa_driver_priv_driver_cmd,
2630#endif
The Android Open Source Project845e0122009-03-03 19:31:34 -08002631};