736fc4ac61cb9b87d1f1510048032707b9f78b83
[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 "l2_packet.h"
29 #include "ieee802_11_defs.h"
30
31 #include <sys/socket.h>
32 #include <net/if.h>
33 #include <net/ethernet.h>
34
35 #include <netproto/802_11/ieee80211.h>
36 #include <netproto/802_11/ieee80211_crypto.h>
37 #include <netproto/802_11/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         uint8_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(uint64_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         wk.ik_keyrsc = le64toh(wk.ik_keyrsc);
321         memcpy(wk.ik_keydata, key, key_len);
322
323         return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
324 }
325
326 static int
327 wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
328 {
329         struct wpa_driver_bsd_data *drv = priv;
330
331         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
332         return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
333 }
334
335
336 static int
337 wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
338 {
339         struct wpa_driver_bsd_data *drv = priv;
340
341         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
342         return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
343 }
344
345 static int
346 wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
347 {
348         struct wpa_driver_bsd_data *drv = priv;
349         struct ieee80211req_mlme mlme;
350
351         wpa_printf(MSG_DEBUG, "%s", __func__);
352         memset(&mlme, 0, sizeof(mlme));
353         mlme.im_op = IEEE80211_MLME_DEAUTH;
354         mlme.im_reason = reason_code;
355         memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
356         return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
357 }
358
359 static int
360 wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
361 {
362         struct wpa_driver_bsd_data *drv = priv;
363         struct ieee80211req_mlme mlme;
364
365         wpa_printf(MSG_DEBUG, "%s", __func__);
366         memset(&mlme, 0, sizeof(mlme));
367         mlme.im_op = IEEE80211_MLME_DISASSOC;
368         mlme.im_reason = reason_code;
369         memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
370         return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
371 }
372
373 static int
374 wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
375 {
376         struct wpa_driver_bsd_data *drv = priv;
377         struct ieee80211req_mlme mlme;
378         int privacy;
379
380         wpa_printf(MSG_DEBUG,
381                 "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
382                 , __func__
383                 , params->ssid_len, params->ssid
384                 , params->wpa_ie_len
385                 , params->pairwise_suite
386                 , params->group_suite
387                 , params->key_mgmt_suite
388         );
389
390         /* XXX error handling is wrong but unclear what to do... */
391         if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
392                 return -1;
393
394         privacy = !(params->pairwise_suite == CIPHER_NONE &&
395             params->group_suite == CIPHER_NONE &&
396             params->key_mgmt_suite == KEY_MGMT_NONE &&
397             params->wpa_ie_len == 0);
398         wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
399
400         if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
401                 return -1;
402
403         if (params->wpa_ie_len &&
404             set80211param(drv, IEEE80211_IOC_WPA,
405                           params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
406                 return -1;
407
408         memset(&mlme, 0, sizeof(mlme));
409         mlme.im_op = IEEE80211_MLME_ASSOC;
410         if (params->ssid != NULL)
411                 memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
412         mlme.im_ssid_len = params->ssid_len;
413         if (params->bssid != NULL)
414                 memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
415         if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
416                 return -1;
417         return 0;
418 }
419
420 static int
421 wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
422 {
423         struct wpa_driver_bsd_data *drv = priv;
424         int authmode;
425
426         if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
427             (auth_alg & AUTH_ALG_SHARED_KEY))
428                 authmode = IEEE80211_AUTH_AUTO;
429         else if (auth_alg & AUTH_ALG_SHARED_KEY)
430                 authmode = IEEE80211_AUTH_SHARED;
431         else
432                 authmode = IEEE80211_AUTH_OPEN;
433
434         wpa_printf(MSG_DEBUG, "%s alg 0x%x authmode %u",
435                 __func__, auth_alg, authmode);
436
437         return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
438 }
439
440 static int
441 wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
442 {
443         struct wpa_driver_bsd_data *drv = priv;
444         int flags;
445
446         /* NB: interface must be marked UP to do a scan */
447         if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
448                 return -1;
449
450         /* set desired ssid before scan */
451         if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
452                 return -1;
453
454         /* NB: net80211 delivers a scan complete event so no need to poll */
455         return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
456 }
457
458 #include <net/route.h>
459 #include <netproto/802_11/ieee80211_dragonfly.h>
460
461 static void
462 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
463 {
464         struct wpa_driver_bsd_data *drv = sock_ctx;
465         char buf[2048];
466         struct if_announcemsghdr *ifan;
467         struct if_msghdr *ifm;
468         struct rt_msghdr *rtm;
469         union wpa_event_data event;
470         struct ieee80211_michael_event *mic;
471         int n;
472
473         n = read(sock, buf, sizeof(buf));
474         if (n < 0) {
475                 if (errno != EINTR && errno != EAGAIN)
476                         perror("read(PF_ROUTE)");
477                 return;
478         }
479
480         rtm = (struct rt_msghdr *) buf;
481         if (rtm->rtm_version != RTM_VERSION) {
482                 wpa_printf(MSG_DEBUG, "Routing message version %d not "
483                         "understood\n", rtm->rtm_version);
484                 return;
485         }
486         memset(&event, 0, sizeof(event));
487         switch (rtm->rtm_type) {
488         case RTM_IFANNOUNCE:
489                 ifan = (struct if_announcemsghdr *) rtm;
490                 if (ifan->ifan_index != drv->ifindex)
491                         break;
492                 strlcpy(event.interface_status.ifname, drv->ifname,
493                         sizeof(event.interface_status.ifname));
494                 switch (ifan->ifan_what) {
495                 case IFAN_DEPARTURE:
496                         event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
497                 default:
498                         return;
499                 }
500                 wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
501                            event.interface_status.ifname,
502                            ifan->ifan_what == IFAN_DEPARTURE ?
503                                 "removed" : "added");
504                 wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
505                 break;
506         case RTM_IEEE80211:
507                 ifan = (struct if_announcemsghdr *) rtm;
508                 if (ifan->ifan_index != drv->ifindex)
509                         break;
510                 switch (ifan->ifan_what) {
511                 case RTM_IEEE80211_ASSOC:
512                 case RTM_IEEE80211_REASSOC:
513                         wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
514                         break;
515                 case RTM_IEEE80211_DISASSOC:
516                         wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
517                         break;
518                 case RTM_IEEE80211_SCAN:
519                         wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
520                         break;
521                 case RTM_IEEE80211_REPLAY:
522                         /* ignore */
523                         break;
524                 case RTM_IEEE80211_MICHAEL:
525                         mic = (struct ieee80211_michael_event *) &ifan[1];
526                         wpa_printf(MSG_DEBUG,
527                                 "Michael MIC failure wireless event: "
528                                 "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
529                                 MAC2STR(mic->iev_src));
530
531                         memset(&event, 0, sizeof(event));
532                         event.michael_mic_failure.unicast =
533                                 !IEEE80211_IS_MULTICAST(mic->iev_dst);
534                         wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
535                                 &event);
536                         break;
537                 }
538                 break;
539         case RTM_IFINFO:
540                 ifm = (struct if_msghdr *) rtm;
541                 if (ifm->ifm_index != drv->ifindex)
542                         break;
543                 if ((rtm->rtm_flags & RTF_UP) == 0) {
544                         strlcpy(event.interface_status.ifname, drv->ifname,
545                                 sizeof(event.interface_status.ifname));
546                         event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
547                         wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
548                                    event.interface_status.ifname);
549                         wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
550                 }
551                 break;
552         }
553 }
554
555 /* Compare function for sorting scan results. Return >0 if @b is consider
556  * better. */
557 static int
558 wpa_scan_result_compar(const void *a, const void *b)
559 {
560         const struct wpa_scan_result *wa = a;
561         const struct wpa_scan_result *wb = b;
562
563         /* WPA/WPA2 support preferred */
564         if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
565             !(wa->wpa_ie_len || wa->rsn_ie_len))
566                 return 1;
567         if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
568             (wa->wpa_ie_len || wa->rsn_ie_len))
569                 return -1;
570
571         /* privacy support preferred */
572         if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
573             (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
574                 return 1;
575         if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
576             (wb->caps & IEEE80211_CAPINFO_PRIVACY))
577                 return -1;
578
579         /* best/max rate preferred if signal level close enough XXX */
580         if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
581                 return wb->maxrate - wa->maxrate;
582
583         /* use freq for channel preference */
584
585         /* all things being equal, use signal level */
586         return wb->level - wa->level;
587 }
588
589 static int
590 getmaxrate(const uint8_t rates[15], uint8_t nrates)
591 {
592         int i, maxrate = -1;
593
594         for (i = 0; i < nrates; i++) {
595                 int rate = rates[i] & IEEE80211_RATE_VAL;
596                 if (rate > maxrate)
597                         rate = maxrate;
598         }
599         return maxrate;
600 }
601
602 /* unalligned little endian access */     
603 #define LE_READ_4(p)                                    \
604         ((uint32_t)                                     \
605          ((((const uint8_t *)(p))[0]      ) |           \
606           (((const uint8_t *)(p))[1] <<  8) |           \
607           (((const uint8_t *)(p))[2] << 16) |           \
608           (((const uint8_t *)(p))[3] << 24)))
609
610 static int __inline
611 iswpaoui(const uint8_t *frm)
612 {
613         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
614 }
615
616 static int
617 wpa_driver_bsd_get_scan_results(void *priv,
618                                      struct wpa_scan_result *results,
619                                      size_t max_size)
620 {
621 #define min(a,b)        ((a)>(b)?(b):(a))
622         struct wpa_driver_bsd_data *drv = priv;
623         uint8_t buf[24*1024];
624         const uint8_t *cp, *vp;
625         const struct ieee80211req_scan_result *sr;
626         struct wpa_scan_result *wsr;
627         int len, ielen;
628
629         memset(results, 0, max_size * sizeof(struct wpa_scan_result));
630
631         len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
632         if (len < 0)
633                 return -1;
634         cp = buf;
635         wsr = results;
636         while (len >= sizeof(struct ieee80211req_scan_result)) {
637                 sr = (const struct ieee80211req_scan_result *) cp;
638                 memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
639                 wsr->ssid_len = sr->isr_ssid_len;
640                 wsr->freq = sr->isr_freq;
641                 wsr->noise = sr->isr_noise;
642                 wsr->qual = sr->isr_rssi;
643                 wsr->level = 0;         /* XXX? */
644                 wsr->caps = sr->isr_capinfo2;
645                 wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
646                 vp = (uint8_t *)(sr+1);
647                 memcpy(wsr->ssid, vp, sr->isr_ssid_len);
648                 if (sr->isr_ie_len > 0) {
649                         vp += sr->isr_ssid_len;
650                         ielen = sr->isr_ie_len;
651                         while (ielen > 0) {
652                                 switch (vp[0]) {
653                                 case IEEE80211_ELEMID_VENDOR:
654                                         if (!iswpaoui(vp))
655                                                 break;
656                                         wsr->wpa_ie_len =
657                                             min(2+vp[1], SSID_MAX_WPA_IE_LEN);
658                                         memcpy(wsr->wpa_ie, vp, wsr->wpa_ie_len);
659                                         break;
660                                 case IEEE80211_ELEMID_RSN:
661                                         wsr->rsn_ie_len =
662                                             min(2+vp[1], SSID_MAX_WPA_IE_LEN);
663                                         memcpy(wsr->rsn_ie, vp, wsr->rsn_ie_len);
664                                         break;
665                                 }
666                                 ielen -= 2+vp[1];
667                                 vp += 2+vp[1];
668                         }
669                 }
670
671                 cp += sr->isr_len, len -= sr->isr_len;
672                 wsr++;
673         }
674         qsort(results, wsr - results, sizeof(struct wpa_scan_result),
675               wpa_scan_result_compar);
676
677         wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
678                    len, wsr - results);
679
680         return wsr - results;
681 #undef min
682 }
683
684 static void *
685 wpa_driver_bsd_init(void *ctx, const char *ifname)
686 {
687 #define GETPARAM(drv, param, v) \
688         (((v) = get80211param(drv, param)) != -1)
689         struct wpa_driver_bsd_data *drv;
690
691         drv = malloc(sizeof(*drv));
692         if (drv == NULL)
693                 return NULL;
694         memset(drv, 0, sizeof(*drv));
695         /*
696          * NB: We require the interface name be mappable to an index.
697          *     This implies we do not support having wpa_supplicant
698          *     wait for an interface to appear.  This seems ok; that
699          *     doesn't belong here; it's really the job of devd.
700          */
701         drv->ifindex = if_nametoindex(ifname);
702         if (drv->ifindex == 0) {
703                 wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
704                            __func__, ifname);
705                 goto fail1;
706         }
707         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
708         if (drv->sock < 0)
709                 goto fail1;
710         drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
711         if (drv->route < 0)
712                 goto fail;
713         eloop_register_read_sock(drv->route,
714                 wpa_driver_bsd_event_receive, ctx, drv);
715
716         drv->ctx = ctx;
717         strncpy(drv->ifname, ifname, sizeof(drv->ifname));
718
719         if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
720                 wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
721                         __func__, strerror(errno));
722                 goto fail;
723         }
724         if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
725                 wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
726                         __func__, strerror(errno));
727                 goto fail;
728         }
729         if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
730                 wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
731                         __func__, strerror(errno));
732                 goto fail;
733         }
734         if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
735                 wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
736                            "roaming: %s", __func__, strerror(errno));
737                 goto fail;
738         }
739
740         if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
741                 wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
742                            __func__, strerror(errno));
743                 goto fail;
744         }
745
746         return drv;
747 fail:
748         close(drv->sock);
749 fail1:
750         free(drv);
751         return NULL;
752 #undef GETPARAM
753 }
754
755 static void
756 wpa_driver_bsd_deinit(void *priv)
757 {
758         struct wpa_driver_bsd_data *drv = priv;
759         int flags;
760
761         /* NB: mark interface down */
762         if (getifflags(drv, &flags) == 0)
763                 (void) setifflags(drv, flags &~ IFF_UP);
764
765         wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
766         if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
767                 wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
768                         __func__);
769
770         (void) close(drv->route);               /* ioctl socket */
771         (void) close(drv->sock);                /* event socket */
772         free(drv);
773 }
774
775
776 struct wpa_driver_ops wpa_driver_bsd_ops = {
777         .name                   = "bsd",
778         .desc                   = "BSD 802.11 support (Atheros, etc.)",
779         .init                   = wpa_driver_bsd_init,
780         .deinit                 = wpa_driver_bsd_deinit,
781         .get_bssid              = wpa_driver_bsd_get_bssid,
782         .get_ssid               = wpa_driver_bsd_get_ssid,
783         .set_wpa                = wpa_driver_bsd_set_wpa,
784         .set_key                = wpa_driver_bsd_set_key,
785         .set_countermeasures    = wpa_driver_bsd_set_countermeasures,
786         .set_drop_unencrypted   = wpa_driver_bsd_set_drop_unencrypted,
787         .scan                   = wpa_driver_bsd_scan,
788         .get_scan_results       = wpa_driver_bsd_get_scan_results,
789         .deauthenticate         = wpa_driver_bsd_deauthenticate,
790         .disassociate           = wpa_driver_bsd_disassociate,
791         .associate              = wpa_driver_bsd_associate,
792         .set_auth_alg           = wpa_driver_bsd_set_auth_alg,
793 };