- Add usr.sbin/802_11 to hold wpa_supplicant and other 802.11 related
[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.5.2.4 2006/03/24 01:43:18 sam Exp $
15  * $DragonFly: src/usr.sbin/802_11/wpa_supplicant/driver_dragonfly.c,v 1.1 2006/06/24 07:29:44 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                 perror("ioctl[SIOCS80211]");
101                 fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
102                         op, arg, strerror(errno));
103                 return -1;
104         }
105         return 0;
106 }
107
108 static int
109 get80211param(struct wpa_driver_bsd_data *drv, int op)
110 {
111         struct ieee80211req ireq;
112
113         memset(&ireq, 0, sizeof(ireq));
114         strncpy(ireq.i_name, drv->ifname, IFNAMSIZ);
115         ireq.i_type = op;
116
117         if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
118                 perror("ioctl[SIOCG80211]");
119                 fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
120                         op, strerror(errno));
121                 return -1;
122         }
123         return ireq.i_val;
124 }
125
126 static int
127 getifflags(struct wpa_driver_bsd_data *drv, int *flags)
128 {
129         struct ifreq ifr;
130
131         memset(&ifr, 0, sizeof(ifr));
132         strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
133         if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
134                 perror("SIOCGIFFLAGS");
135                 return errno;
136         }
137         *flags = ifr.ifr_flags & 0xffff;
138         return 0;
139 }
140
141 static int
142 setifflags(struct wpa_driver_bsd_data *drv, int flags)
143 {
144         struct ifreq ifr;
145
146         memset(&ifr, 0, sizeof(ifr));
147         strncpy(ifr.ifr_name, drv->ifname, sizeof (ifr.ifr_name));
148         ifr.ifr_flags = flags & 0xffff;
149         if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
150                 perror("SIOCSIFFLAGS");
151                 return errno;
152         }
153         return 0;
154 }
155
156 static int
157 wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
158 {
159         struct wpa_driver_bsd_data *drv = priv;
160
161         return get80211var(drv, IEEE80211_IOC_BSSID,
162                 bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
163 }
164
165 #if 0
166 static int
167 wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
168 {
169         struct wpa_driver_bsd_data *drv = priv;
170
171         return set80211var(drv, IEEE80211_IOC_BSSID,
172                 bssid, IEEE80211_ADDR_LEN);
173 }
174 #endif
175
176 static int
177 wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
178 {
179         struct wpa_driver_bsd_data *drv = priv;
180
181         return get80211var(drv, IEEE80211_IOC_SSID,
182                 ssid, IEEE80211_NWID_LEN);
183 }
184
185 static int
186 wpa_driver_bsd_set_ssid(void *priv, const char *ssid,
187                              size_t ssid_len)
188 {
189         struct wpa_driver_bsd_data *drv = priv;
190
191         return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
192 }
193
194 static int
195 wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
196         const char *wpa_ie, size_t wpa_ie_len)
197 {
198         return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
199 }
200
201 static int
202 wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
203 {
204         struct wpa_driver_bsd_data *drv = priv;
205         int ret = 0;
206
207         wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
208                 __FUNCTION__, wpa, privacy);
209
210         if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
211                 ret = -1;
212         if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
213                 ret = -1;
214         if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
215                 ret = -1;
216
217         return ret;
218 }
219
220 static int
221 wpa_driver_bsd_set_wpa(void *priv, int enabled)
222 {
223         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
224
225         return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
226 }
227
228 static int
229 wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
230                        const unsigned char *addr)
231 {
232         struct ieee80211req_del_key wk;
233
234         memset(&wk, 0, sizeof(wk));
235         if (addr != NULL &&
236             bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
237                 struct ether_addr ea;
238
239                 memcpy(&ea, addr, IEEE80211_ADDR_LEN);
240                 wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
241                         __func__, ether_ntoa(&ea), key_idx);
242                 memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
243                 wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
244         } else {
245                 wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
246                 wk.idk_keyix = key_idx;
247         }
248         return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
249 }
250
251 static int
252 wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
253                        const unsigned char *addr, int key_idx, int set_tx,
254                        const u8 *seq, size_t seq_len,
255                        const u8 *key, size_t key_len)
256 {
257         struct wpa_driver_bsd_data *drv = priv;
258         struct ieee80211req_key wk;
259         struct ether_addr ea;
260         char *alg_name;
261         u_int8_t cipher;
262
263         if (alg == WPA_ALG_NONE)
264                 return wpa_driver_bsd_del_key(drv, key_idx, addr);
265
266         switch (alg) {
267         case WPA_ALG_WEP:
268                 alg_name = "WEP";
269                 cipher = IEEE80211_CIPHER_WEP;
270                 break;
271         case WPA_ALG_TKIP:
272                 alg_name = "TKIP";
273                 cipher = IEEE80211_CIPHER_TKIP;
274                 break;
275         case WPA_ALG_CCMP:
276                 alg_name = "CCMP";
277                 cipher = IEEE80211_CIPHER_AES_CCM;
278                 break;
279         default:
280                 wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
281                         __func__, alg);
282                 return -1;
283         }
284
285         memcpy(&ea, addr, IEEE80211_ADDR_LEN);
286         wpa_printf(MSG_DEBUG,
287                 "%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
288                 __func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
289                 seq_len, key_len);
290
291         if (seq_len > sizeof(u_int64_t)) {
292                 wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
293                         __func__, seq_len);
294                 return -2;
295         }
296         if (key_len > sizeof(wk.ik_keydata)) {
297                 wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
298                         __func__, key_len);
299                 return -3;
300         }
301
302         memset(&wk, 0, sizeof(wk));
303         wk.ik_type = cipher;
304         wk.ik_flags = IEEE80211_KEY_RECV;
305         if (set_tx)
306                 wk.ik_flags |= IEEE80211_KEY_XMIT;
307         memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
308         /*
309          * Deduce whether group/global or unicast key by checking
310          * the address (yech).  Note also that we can only mark global
311          * keys default; doing this for a unicast key is an error.
312          */
313         if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
314                 wk.ik_flags |= IEEE80211_KEY_GROUP;
315                 wk.ik_keyix = key_idx;
316         } else {
317                 wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
318         }
319         if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
320                 wk.ik_flags |= IEEE80211_KEY_DEFAULT;
321         wk.ik_keylen = key_len;
322         memcpy(&wk.ik_keyrsc, seq, seq_len);
323         memcpy(wk.ik_keydata, key, key_len);
324
325         return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
326 }
327
328 static int
329 wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
330 {
331         struct wpa_driver_bsd_data *drv = priv;
332
333         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
334         return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
335 }
336
337
338 static int
339 wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
340 {
341         struct wpa_driver_bsd_data *drv = priv;
342
343         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
344         return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
345 }
346
347 static int
348 wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
349 {
350         struct wpa_driver_bsd_data *drv = priv;
351         struct ieee80211req_mlme mlme;
352
353         wpa_printf(MSG_DEBUG, "%s", __func__);
354         memset(&mlme, 0, sizeof(mlme));
355         mlme.im_op = IEEE80211_MLME_DEAUTH;
356         mlme.im_reason = reason_code;
357         memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
358         return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
359 }
360
361 static int
362 wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
363 {
364         struct wpa_driver_bsd_data *drv = priv;
365         struct ieee80211req_mlme mlme;
366
367         wpa_printf(MSG_DEBUG, "%s", __func__);
368         memset(&mlme, 0, sizeof(mlme));
369         mlme.im_op = IEEE80211_MLME_DISASSOC;
370         mlme.im_reason = reason_code;
371         memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
372         return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
373 }
374
375 static int
376 wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
377 {
378         struct wpa_driver_bsd_data *drv = priv;
379         struct ieee80211req_mlme mlme;
380         int privacy;
381
382         wpa_printf(MSG_DEBUG,
383                 "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
384                 , __func__
385                 , params->ssid_len, params->ssid
386                 , params->wpa_ie_len
387                 , params->pairwise_suite
388                 , params->group_suite
389                 , params->key_mgmt_suite
390         );
391
392         /* XXX error handling is wrong but unclear what to do... */
393         if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
394                 return -1;
395
396         privacy = !(params->pairwise_suite == CIPHER_NONE &&
397             params->group_suite == CIPHER_NONE &&
398             params->key_mgmt_suite == KEY_MGMT_NONE &&
399             params->wpa_ie_len == 0);
400         wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
401
402         if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
403                 return -1;
404
405         if (params->wpa_ie_len &&
406             set80211param(drv, IEEE80211_IOC_WPA,
407                           params->wpa_ie[0] == RSN_INFO_ELEM ? 2 : 1) < 0)
408                 return -1;
409
410         memset(&mlme, 0, sizeof(mlme));
411         mlme.im_op = IEEE80211_MLME_ASSOC;
412         if (params->ssid != NULL)
413                 memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
414         mlme.im_ssid_len = params->ssid_len;
415         if (params->bssid != NULL)
416                 memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
417         if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
418                 return -1;
419         return 0;
420 }
421
422 static int
423 wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
424 {
425         struct wpa_driver_bsd_data *drv = priv;
426         int authmode;
427
428         if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
429             (auth_alg & AUTH_ALG_SHARED_KEY))
430                 authmode = IEEE80211_AUTH_AUTO;
431         else if (auth_alg & AUTH_ALG_SHARED_KEY)
432                 authmode = IEEE80211_AUTH_SHARED;
433         else
434                 authmode = IEEE80211_AUTH_OPEN;
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 <netproto/802_11/ieee80211_dragonfly.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 };