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