Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / usr.sbin / 802_11 / wpa_supplicant / driver_dragonfly.c
1 /*
2  * WPA Supplicant - driver interaction with BSD net80211 layer
3  * Copyright (c) 2004, Sam Leffler <sam@errno.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  *
14  * $FreeBSD: src/usr.sbin/wpa/wpa_supplicant/driver_freebsd.c,v 1.14 2007/06/11 03:57:46 sam Exp $
15  * $DragonFly: src/usr.sbin/802_11/wpa_supplicant/driver_dragonfly.c,v 1.3 2008/01/19 07:03:55 sephe Exp $
16  */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/ioctl.h>
23 #include <errno.h>
24
25 #include "common.h"
26 #include "driver.h"
27 #include "eloop.h"
28 #include "wpa_supplicant.h"
29 #include "l2_packet.h"
30 #include "wpa.h"                        /* XXX for RSN_INFO_ELEM */
31
32 #include <sys/socket.h>
33 #include <net/if.h>
34 #include <net/ethernet.h>
35
36 #include <netproto/802_11/ieee80211.h>
37 #include <netproto/802_11/ieee80211_crypto.h>
38 #include <netproto/802_11/ieee80211_ioctl.h>
39
40 struct wpa_driver_bsd_data {
41         int     sock;                   /* open socket for 802.11 ioctls */
42         int     route;                  /* routing socket for events */
43         char    ifname[IFNAMSIZ+1];     /* interface name */
44         unsigned int ifindex;           /* interface index */
45         void    *ctx;
46         int     prev_roaming;           /* roaming state to restore on deinit */
47         int     prev_privacy;           /* privacy state to restore on deinit */
48         int     prev_wpa;               /* wpa state to restore on deinit */
49 };
50
51 static int
52 set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
53 {
54         struct ieee80211req ireq;
55
56         memset(&ireq, 0, sizeof(ireq));
57         strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
58         ireq.i_type = op;
59         ireq.i_len = arg_len;
60         ireq.i_data = (void *) arg;
61
62         if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
63                 fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n",
64                         op, arg_len, strerror(errno));
65                 return -1;
66         }
67         return 0;
68 }
69
70 static int
71 get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
72 {
73         struct ieee80211req ireq;
74
75         memset(&ireq, 0, sizeof(ireq));
76         strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
77         ireq.i_type = op;
78         ireq.i_len = arg_len;
79         ireq.i_data = arg;
80
81         if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
82                 fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n",
83                         op, arg_len, strerror(errno));
84                 return -1;
85         }
86         return ireq.i_len;
87 }
88
89 static int
90 set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
91 {
92         struct ieee80211req ireq;
93
94         memset(&ireq, 0, sizeof(ireq));
95         strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
96         ireq.i_type = op;
97         ireq.i_val = arg;
98
99         if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
100                 fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
101                         op, arg, strerror(errno));
102                 return -1;
103         }
104         return 0;
105 }
106
107 static int
108 get80211param(struct wpa_driver_bsd_data *drv, int op)
109 {
110         struct ieee80211req ireq;
111
112         memset(&ireq, 0, sizeof(ireq));
113         strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
114         ireq.i_type = op;
115
116         if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
117                 fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
118                         op, strerror(errno));
119                 return -1;
120         }
121         return ireq.i_val;
122 }
123
124 static int
125 getifflags(struct wpa_driver_bsd_data *drv, int *flags)
126 {
127         struct ifreq ifr;
128
129         memset(&ifr, 0, sizeof(ifr));
130         strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
131         if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
132                 perror("SIOCGIFFLAGS");
133                 return errno;
134         }
135         *flags = ifr.ifr_flags & 0xffff;
136         return 0;
137 }
138
139 static int
140 setifflags(struct wpa_driver_bsd_data *drv, int flags)
141 {
142         struct ifreq ifr;
143
144         memset(&ifr, 0, sizeof(ifr));
145         strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
146         ifr.ifr_flags = flags & 0xffff;
147         if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
148                 perror("SIOCSIFFLAGS");
149                 return errno;
150         }
151         return 0;
152 }
153
154 static int
155 wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
156 {
157         struct wpa_driver_bsd_data *drv = priv;
158
159         return get80211var(drv, IEEE80211_IOC_BSSID,
160                 bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
161 }
162
163 #if 0
164 static int
165 wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
166 {
167         struct wpa_driver_bsd_data *drv = priv;
168
169         return set80211var(drv, IEEE80211_IOC_BSSID,
170                 bssid, IEEE80211_ADDR_LEN);
171 }
172 #endif
173
174 static int
175 wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
176 {
177         struct wpa_driver_bsd_data *drv = priv;
178
179         return get80211var(drv, IEEE80211_IOC_SSID,
180                 ssid, IEEE80211_NWID_LEN);
181 }
182
183 static int
184 wpa_driver_bsd_set_ssid(void *priv, const char *ssid,
185                              size_t ssid_len)
186 {
187         struct wpa_driver_bsd_data *drv = priv;
188
189         return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
190 }
191
192 static int
193 wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
194         const char *wpa_ie, size_t wpa_ie_len)
195 {
196         return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
197 }
198
199 static int
200 wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
201 {
202         struct wpa_driver_bsd_data *drv = priv;
203         int ret = 0;
204
205         wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
206                 __FUNCTION__, wpa, privacy);
207
208         if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
209                 ret = -1;
210         if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
211                 ret = -1;
212         if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
213                 ret = -1;
214
215         return ret;
216 }
217
218 static int
219 wpa_driver_bsd_set_wpa(void *priv, int enabled)
220 {
221         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
222
223         return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
224 }
225
226 static int
227 wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
228                        const unsigned char *addr)
229 {
230         struct ieee80211req_del_key wk;
231
232         memset(&wk, 0, sizeof(wk));
233         if (addr != NULL &&
234             bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
235                 struct ether_addr ea;
236
237                 memcpy(&ea, addr, IEEE80211_ADDR_LEN);
238                 wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
239                         __func__, ether_ntoa(&ea), key_idx);
240                 memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
241                 wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
242         } else {
243                 wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
244                 wk.idk_keyix = key_idx;
245         }
246         return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
247 }
248
249 static int
250 wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
251                        const unsigned char *addr, int key_idx, int set_tx,
252                        const u8 *seq, size_t seq_len,
253                        const u8 *key, size_t key_len)
254 {
255         struct wpa_driver_bsd_data *drv = priv;
256         struct ieee80211req_key wk;
257         struct ether_addr ea;
258         char *alg_name;
259         uint8_t cipher;
260
261         if (alg == WPA_ALG_NONE)
262                 return wpa_driver_bsd_del_key(drv, key_idx, addr);
263
264         switch (alg) {
265         case WPA_ALG_WEP:
266                 alg_name = "WEP";
267                 cipher = IEEE80211_CIPHER_WEP;
268                 break;
269         case WPA_ALG_TKIP:
270                 alg_name = "TKIP";
271                 cipher = IEEE80211_CIPHER_TKIP;
272                 break;
273         case WPA_ALG_CCMP:
274                 alg_name = "CCMP";
275                 cipher = IEEE80211_CIPHER_AES_CCM;
276                 break;
277         default:
278                 wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
279                         __func__, alg);
280                 return -1;
281         }
282
283         memcpy(&ea, addr, IEEE80211_ADDR_LEN);
284         wpa_printf(MSG_DEBUG,
285                 "%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
286                 __func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
287                 seq_len, key_len);
288
289         if (seq_len > sizeof(uint64_t)) {
290                 wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
291                         __func__, seq_len);
292                 return -2;
293         }
294         if (key_len > sizeof(wk.ik_keydata)) {
295                 wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
296                         __func__, key_len);
297                 return -3;
298         }
299
300         memset(&wk, 0, sizeof(wk));
301         wk.ik_type = cipher;
302         wk.ik_flags = IEEE80211_KEY_RECV;
303         if (set_tx)
304                 wk.ik_flags |= IEEE80211_KEY_XMIT;
305         memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
306         /*
307          * Deduce whether group/global or unicast key by checking
308          * the address (yech).  Note also that we can only mark global
309          * keys default; doing this for a unicast key is an error.
310          */
311         if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
312                 wk.ik_flags |= IEEE80211_KEY_GROUP;
313                 wk.ik_keyix = key_idx;
314         } else {
315                 wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
316         }
317         if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
318                 wk.ik_flags |= IEEE80211_KEY_DEFAULT;
319         wk.ik_keylen = key_len;
320         memcpy(&wk.ik_keyrsc, seq, seq_len);
321         wk.ik_keyrsc = le64toh(wk.ik_keyrsc);
322         memcpy(wk.ik_keydata, key, key_len);
323
324         return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
325 }
326
327 static int
328 wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
329 {
330         struct wpa_driver_bsd_data *drv = priv;
331
332         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
333         return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
334 }
335
336
337 static int
338 wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
339 {
340         struct wpa_driver_bsd_data *drv = priv;
341
342         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
343         return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
344 }
345
346 static int
347 wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
348 {
349         struct wpa_driver_bsd_data *drv = priv;
350         struct ieee80211req_mlme mlme;
351
352         wpa_printf(MSG_DEBUG, "%s", __func__);
353         memset(&mlme, 0, sizeof(mlme));
354         mlme.im_op = IEEE80211_MLME_DEAUTH;
355         mlme.im_reason = reason_code;
356         memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
357         return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
358 }
359
360 static int
361 wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
362 {
363         struct wpa_driver_bsd_data *drv = priv;
364         struct ieee80211req_mlme mlme;
365
366         wpa_printf(MSG_DEBUG, "%s", __func__);
367         memset(&mlme, 0, sizeof(mlme));
368         mlme.im_op = IEEE80211_MLME_DISASSOC;
369         mlme.im_reason = reason_code;
370         memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
371         return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
372 }
373
374 static int
375 wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
376 {
377         struct wpa_driver_bsd_data *drv = priv;
378         struct ieee80211req_mlme mlme;
379         int privacy;
380
381         wpa_printf(MSG_DEBUG,
382                 "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
383                 , __func__
384                 , params->ssid_len, params->ssid
385                 , params->wpa_ie_len
386                 , params->pairwise_suite
387                 , params->group_suite
388                 , params->key_mgmt_suite
389         );
390
391         /* XXX error handling is wrong but unclear what to do... */
392         if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
393                 return -1;
394
395         privacy = !(params->pairwise_suite == CIPHER_NONE &&
396             params->group_suite == CIPHER_NONE &&
397             params->key_mgmt_suite == KEY_MGMT_NONE &&
398             params->wpa_ie_len == 0);
399         wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
400
401         if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
402                 return -1;
403
404         if (params->wpa_ie_len &&
405             set80211param(drv, IEEE80211_IOC_WPA,
406                           params->wpa_ie[0] == RSN_INFO_ELEM ? 2 : 1) < 0)
407                 return -1;
408
409         memset(&mlme, 0, sizeof(mlme));
410         mlme.im_op = IEEE80211_MLME_ASSOC;
411         if (params->ssid != NULL)
412                 memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
413         mlme.im_ssid_len = params->ssid_len;
414         if (params->bssid != NULL)
415                 memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
416         if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
417                 return -1;
418         return 0;
419 }
420
421 static int
422 wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
423 {
424         struct wpa_driver_bsd_data *drv = priv;
425         int authmode;
426
427         if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
428             (auth_alg & AUTH_ALG_SHARED_KEY))
429                 authmode = IEEE80211_AUTH_AUTO;
430         else if (auth_alg & AUTH_ALG_SHARED_KEY)
431                 authmode = IEEE80211_AUTH_SHARED;
432         else
433                 authmode = IEEE80211_AUTH_OPEN;
434
435         wpa_printf(MSG_DEBUG, "%s alg 0x%x authmode %u",
436                 __func__, auth_alg, authmode);
437
438         return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
439 }
440
441 static int
442 wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
443 {
444         struct wpa_driver_bsd_data *drv = priv;
445         int flags;
446
447         /* NB: interface must be marked UP to do a scan */
448         if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
449                 return -1;
450
451         /* set desired ssid before scan */
452         if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
453                 return -1;
454
455         /* NB: net80211 delivers a scan complete event so no need to poll */
456         return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
457 }
458
459 #include <net/route.h>
460 #include <netproto/802_11/ieee80211_dragonfly.h>
461
462 static void
463 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
464 {
465         struct wpa_driver_bsd_data *drv = sock_ctx;
466         char buf[2048];
467         struct if_announcemsghdr *ifan;
468         struct if_msghdr *ifm;
469         struct rt_msghdr *rtm;
470         union wpa_event_data event;
471         struct ieee80211_michael_event *mic;
472         int n;
473
474         n = read(sock, buf, sizeof(buf));
475         if (n < 0) {
476                 if (errno != EINTR && errno != EAGAIN)
477                         perror("read(PF_ROUTE)");
478                 return;
479         }
480
481         rtm = (struct rt_msghdr *) buf;
482         if (rtm->rtm_version != RTM_VERSION) {
483                 wpa_printf(MSG_DEBUG, "Routing message version %d not "
484                         "understood\n", rtm->rtm_version);
485                 return;
486         }
487         memset(&event, 0, sizeof(event));
488         switch (rtm->rtm_type) {
489         case RTM_IFANNOUNCE:
490                 ifan = (struct if_announcemsghdr *) rtm;
491                 if (ifan->ifan_index != drv->ifindex)
492                         break;
493                 strlcpy(event.interface_status.ifname, drv->ifname,
494                         sizeof(event.interface_status.ifname));
495                 switch (ifan->ifan_what) {
496                 case IFAN_DEPARTURE:
497                         event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
498                 default:
499                         return;
500                 }
501                 wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
502                            event.interface_status.ifname,
503                            ifan->ifan_what == IFAN_DEPARTURE ?
504                                 "removed" : "added");
505                 wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
506                 break;
507         case RTM_IEEE80211:
508                 ifan = (struct if_announcemsghdr *) rtm;
509                 if (ifan->ifan_index != drv->ifindex)
510                         break;
511                 switch (ifan->ifan_what) {
512                 case RTM_IEEE80211_ASSOC:
513                 case RTM_IEEE80211_REASSOC:
514                         wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
515                         break;
516                 case RTM_IEEE80211_DISASSOC:
517                         wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
518                         break;
519                 case RTM_IEEE80211_SCAN:
520                         wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
521                         break;
522                 case RTM_IEEE80211_REPLAY:
523                         /* ignore */
524                         break;
525                 case RTM_IEEE80211_MICHAEL:
526                         mic = (struct ieee80211_michael_event *) &ifan[1];
527                         wpa_printf(MSG_DEBUG,
528                                 "Michael MIC failure wireless event: "
529                                 "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
530                                 MAC2STR(mic->iev_src));
531
532                         memset(&event, 0, sizeof(event));
533                         event.michael_mic_failure.unicast =
534                                 !IEEE80211_IS_MULTICAST(mic->iev_dst);
535                         wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
536                                 &event);
537                         break;
538                 }
539                 break;
540         case RTM_IFINFO:
541                 ifm = (struct if_msghdr *) rtm;
542                 if (ifm->ifm_index != drv->ifindex)
543                         break;
544                 if ((rtm->rtm_flags & RTF_UP) == 0) {
545                         strlcpy(event.interface_status.ifname, drv->ifname,
546                                 sizeof(event.interface_status.ifname));
547                         event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
548                         wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
549                                    event.interface_status.ifname);
550                         wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
551                 }
552                 break;
553         }
554 }
555
556 /* Compare function for sorting scan results. Return >0 if @b is consider
557  * better. */
558 static int
559 wpa_scan_result_compar(const void *a, const void *b)
560 {
561         const struct wpa_scan_result *wa = a;
562         const struct wpa_scan_result *wb = b;
563
564         /* WPA/WPA2 support preferred */
565         if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
566             !(wa->wpa_ie_len || wa->rsn_ie_len))
567                 return 1;
568         if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
569             (wa->wpa_ie_len || wa->rsn_ie_len))
570                 return -1;
571
572         /* privacy support preferred */
573         if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
574             (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
575                 return 1;
576         if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
577             (wb->caps & IEEE80211_CAPINFO_PRIVACY))
578                 return -1;
579
580         /* best/max rate preferred if signal level close enough XXX */
581         if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
582                 return wb->maxrate - wa->maxrate;
583
584         /* use freq for channel preference */
585
586         /* all things being equal, use signal level */
587         return wb->level - wa->level;
588 }
589
590 static int
591 getmaxrate(const uint8_t rates[15], uint8_t nrates)
592 {
593         int i, maxrate = -1;
594
595         for (i = 0; i < nrates; i++) {
596                 int rate = rates[i] & IEEE80211_RATE_VAL;
597                 if (rate > maxrate)
598                         rate = maxrate;
599         }
600         return maxrate;
601 }
602
603 /* unalligned little endian access */     
604 #define LE_READ_4(p)                                    \
605         ((uint32_t)                                     \
606          ((((const uint8_t *)(p))[0]      ) |           \
607           (((const uint8_t *)(p))[1] <<  8) |           \
608           (((const uint8_t *)(p))[2] << 16) |           \
609           (((const uint8_t *)(p))[3] << 24)))
610
611 static int __inline
612 iswpaoui(const uint8_t *frm)
613 {
614         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
615 }
616
617 static int
618 wpa_driver_bsd_get_scan_results(void *priv,
619                                      struct wpa_scan_result *results,
620                                      size_t max_size)
621 {
622 #define min(a,b)        ((a)>(b)?(b):(a))
623         struct wpa_driver_bsd_data *drv = priv;
624         uint8_t buf[24*1024];
625         const uint8_t *cp, *vp;
626         const struct ieee80211req_scan_result *sr;
627         struct wpa_scan_result *wsr;
628         int len, ielen;
629
630         memset(results, 0, max_size * sizeof(struct wpa_scan_result));
631
632         len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
633         if (len < 0)
634                 return -1;
635         cp = buf;
636         wsr = results;
637         while (len >= sizeof(struct ieee80211req_scan_result)) {
638                 sr = (const struct ieee80211req_scan_result *) cp;
639                 memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
640                 wsr->ssid_len = sr->isr_ssid_len;
641                 wsr->freq = sr->isr_freq;
642                 wsr->noise = sr->isr_noise;
643                 wsr->qual = sr->isr_rssi;
644                 wsr->level = 0;         /* XXX? */
645                 wsr->caps = sr->isr_capinfo2;
646                 wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
647                 vp = (uint8_t *)(sr+1);
648                 memcpy(wsr->ssid, vp, sr->isr_ssid_len);
649                 if (sr->isr_ie_len > 0) {
650                         vp += sr->isr_ssid_len;
651                         ielen = sr->isr_ie_len;
652                         while (ielen > 0) {
653                                 switch (vp[0]) {
654                                 case IEEE80211_ELEMID_VENDOR:
655                                         if (!iswpaoui(vp))
656                                                 break;
657                                         wsr->wpa_ie_len =
658                                             min(2+vp[1], SSID_MAX_WPA_IE_LEN);
659                                         memcpy(wsr->wpa_ie, vp, wsr->wpa_ie_len);
660                                         break;
661                                 case IEEE80211_ELEMID_RSN:
662                                         wsr->rsn_ie_len =
663                                             min(2+vp[1], SSID_MAX_WPA_IE_LEN);
664                                         memcpy(wsr->rsn_ie, vp, wsr->rsn_ie_len);
665                                         break;
666                                 }
667                                 ielen -= 2+vp[1];
668                                 vp += 2+vp[1];
669                         }
670                 }
671
672                 cp += sr->isr_len, len -= sr->isr_len;
673                 wsr++;
674         }
675         qsort(results, wsr - results, sizeof(struct wpa_scan_result),
676               wpa_scan_result_compar);
677
678         wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
679                    len, wsr - results);
680
681         return wsr - results;
682 #undef min
683 }
684
685 static void *
686 wpa_driver_bsd_init(void *ctx, const char *ifname)
687 {
688 #define GETPARAM(drv, param, v) \
689         (((v) = get80211param(drv, param)) != -1)
690         struct wpa_driver_bsd_data *drv;
691
692         drv = malloc(sizeof(*drv));
693         if (drv == NULL)
694                 return NULL;
695         memset(drv, 0, sizeof(*drv));
696         /*
697          * NB: We require the interface name be mappable to an index.
698          *     This implies we do not support having wpa_supplicant
699          *     wait for an interface to appear.  This seems ok; that
700          *     doesn't belong here; it's really the job of devd.
701          */
702         drv->ifindex = if_nametoindex(ifname);
703         if (drv->ifindex == 0) {
704                 wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
705                            __func__, ifname);
706                 goto fail1;
707         }
708         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
709         if (drv->sock < 0)
710                 goto fail1;
711         drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
712         if (drv->route < 0)
713                 goto fail;
714         eloop_register_read_sock(drv->route,
715                 wpa_driver_bsd_event_receive, ctx, drv);
716
717         drv->ctx = ctx;
718         strncpy(drv->ifname, ifname, sizeof(drv->ifname));
719
720         if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
721                 wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
722                         __func__, strerror(errno));
723                 goto fail;
724         }
725         if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
726                 wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
727                         __func__, strerror(errno));
728                 goto fail;
729         }
730         if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
731                 wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
732                         __func__, strerror(errno));
733                 goto fail;
734         }
735         if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
736                 wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
737                            "roaming: %s", __func__, strerror(errno));
738                 goto fail;
739         }
740
741         if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
742                 wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
743                            __func__, strerror(errno));
744                 goto fail;
745         }
746
747         return drv;
748 fail:
749         close(drv->sock);
750 fail1:
751         free(drv);
752         return NULL;
753 #undef GETPARAM
754 }
755
756 static void
757 wpa_driver_bsd_deinit(void *priv)
758 {
759         struct wpa_driver_bsd_data *drv = priv;
760         int flags;
761
762         /* NB: mark interface down */
763         if (getifflags(drv, &flags) == 0)
764                 (void) setifflags(drv, flags &~ IFF_UP);
765
766         wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
767         if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
768                 wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
769                         __func__);
770
771         (void) close(drv->route);               /* ioctl socket */
772         (void) close(drv->sock);                /* event socket */
773         free(drv);
774 }
775
776
777 struct wpa_driver_ops wpa_driver_bsd_ops = {
778         .name                   = "bsd",
779         .desc                   = "BSD 802.11 support (Atheros, etc.)",
780         .init                   = wpa_driver_bsd_init,
781         .deinit                 = wpa_driver_bsd_deinit,
782         .get_bssid              = wpa_driver_bsd_get_bssid,
783         .get_ssid               = wpa_driver_bsd_get_ssid,
784         .set_wpa                = wpa_driver_bsd_set_wpa,
785         .set_key                = wpa_driver_bsd_set_key,
786         .set_countermeasures    = wpa_driver_bsd_set_countermeasures,
787         .set_drop_unencrypted   = wpa_driver_bsd_set_drop_unencrypted,
788         .scan                   = wpa_driver_bsd_scan,
789         .get_scan_results       = wpa_driver_bsd_get_scan_results,
790         .deauthenticate         = wpa_driver_bsd_deauthenticate,
791         .disassociate           = wpa_driver_bsd_disassociate,
792         .associate              = wpa_driver_bsd_associate,
793         .set_auth_alg           = wpa_driver_bsd_set_auth_alg,
794 };