]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/drivers/driver_nl80211.c
SME: Add processing for rejected associations
[thirdparty/hostap.git] / src / drivers / driver_nl80211.c
CommitLineData
3f5285e8
JM
1/*
2 * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
3 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16#include <sys/ioctl.h>
17#include <net/if_arp.h>
18#include <netlink/genl/genl.h>
19#include <netlink/genl/family.h>
20#include <netlink/genl/ctrl.h>
7e45830a 21#include "nl80211_copy.h"
3f5285e8 22#include "wireless_copy.h"
625f587b 23
3f5285e8
JM
24#include "common.h"
25#include "driver.h"
26#include "eloop.h"
27#include "ieee802_11_defs.h"
28
29#ifndef IFF_LOWER_UP
30#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
31#endif
32#ifndef IFF_DORMANT
33#define IFF_DORMANT 0x20000 /* driver signals dormant */
34#endif
35
36#ifndef IF_OPER_DORMANT
37#define IF_OPER_DORMANT 5
38#endif
39#ifndef IF_OPER_UP
40#define IF_OPER_UP 6
41#endif
42
43
44struct wpa_driver_nl80211_data {
45 void *ctx;
d8816397 46 int link_event_sock;
3f5285e8
JM
47 int ioctl_sock;
48 char ifname[IFNAMSIZ + 1];
49 int ifindex;
7524cfb1 50 int if_removed;
c2a04078
JM
51 struct wpa_driver_capa capa;
52 int has_capability;
c2a04078 53
3f5285e8
JM
54 int operstate;
55
3f5285e8
JM
56 int scan_complete_events;
57
58 struct nl_handle *nl_handle;
59 struct nl_cache *nl_cache;
60 struct nl_cb *nl_cb;
61 struct genl_family *nl80211;
1c873584 62
c2a04078
JM
63 u8 bssid[ETH_ALEN];
64 int associated;
fd05d64e
JM
65 u8 ssid[32];
66 size_t ssid_len;
3f5285e8
JM
67};
68
69
70static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
71 void *timeout_ctx);
36b15723
JM
72static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
73 int mode);
362f781e 74static int
7524cfb1
JM
75wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
76
3f5285e8 77
6241fcb1
JM
78/* nl80211 code */
79static int ack_handler(struct nl_msg *msg, void *arg)
80{
81 int *err = arg;
82 *err = 0;
83 return NL_STOP;
84}
85
86static int finish_handler(struct nl_msg *msg, void *arg)
87{
8e8df255
JM
88 int *ret = arg;
89 *ret = 0;
6241fcb1
JM
90 return NL_SKIP;
91}
92
93static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
94 void *arg)
95{
96 int *ret = arg;
97 *ret = err->error;
98 return NL_SKIP;
99}
100
101static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
102 struct nl_msg *msg,
103 int (*valid_handler)(struct nl_msg *, void *),
104 void *valid_data)
105{
106 struct nl_cb *cb;
107 int err = -ENOMEM;
108
109 cb = nl_cb_clone(drv->nl_cb);
110 if (!cb)
111 goto out;
112
113 err = nl_send_auto_complete(drv->nl_handle, msg);
114 if (err < 0)
115 goto out;
116
117 err = 1;
118
119 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
8e8df255 120 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
6241fcb1
JM
121 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
122
123 if (valid_handler)
124 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
125 valid_handler, valid_data);
126
127 while (err > 0)
128 nl_recvmsgs(drv->nl_handle, cb);
129 out:
130 nl_cb_put(cb);
131 nlmsg_free(msg);
132 return err;
133}
134
135
97865538
JM
136struct family_data {
137 const char *group;
138 int id;
139};
140
141
142static int family_handler(struct nl_msg *msg, void *arg)
143{
144 struct family_data *res = arg;
145 struct nlattr *tb[CTRL_ATTR_MAX + 1];
146 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
147 struct nlattr *mcgrp;
148 int i;
149
150 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
151 genlmsg_attrlen(gnlh, 0), NULL);
152 if (!tb[CTRL_ATTR_MCAST_GROUPS])
153 return NL_SKIP;
154
155 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
156 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
157 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
158 nla_len(mcgrp), NULL);
159 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
160 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
161 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
162 res->group,
163 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
164 continue;
165 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
166 break;
167 };
168
169 return NL_SKIP;
170}
171
172
173static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
174 const char *family, const char *group)
175{
176 struct nl_msg *msg;
177 int ret = -1;
178 struct family_data res = { group, -ENOENT };
179
180 msg = nlmsg_alloc();
181 if (!msg)
182 return -ENOMEM;
183 genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
184 0, 0, CTRL_CMD_GETFAMILY, 0);
185 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
186
187 ret = send_and_recv_msgs(drv, msg, family_handler, &res);
188 msg = NULL;
189 if (ret == 0)
190 ret = res.id;
191
192nla_put_failure:
193 nlmsg_free(msg);
194 return ret;
195}
196
197
3f5285e8
JM
198static int wpa_driver_nl80211_send_oper_ifla(
199 struct wpa_driver_nl80211_data *drv,
200 int linkmode, int operstate)
201{
202 struct {
203 struct nlmsghdr hdr;
204 struct ifinfomsg ifinfo;
205 char opts[16];
206 } req;
207 struct rtattr *rta;
208 static int nl_seq;
209 ssize_t ret;
210
211 os_memset(&req, 0, sizeof(req));
212
213 req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
214 req.hdr.nlmsg_type = RTM_SETLINK;
215 req.hdr.nlmsg_flags = NLM_F_REQUEST;
216 req.hdr.nlmsg_seq = ++nl_seq;
217 req.hdr.nlmsg_pid = 0;
218
219 req.ifinfo.ifi_family = AF_UNSPEC;
220 req.ifinfo.ifi_type = 0;
221 req.ifinfo.ifi_index = drv->ifindex;
222 req.ifinfo.ifi_flags = 0;
223 req.ifinfo.ifi_change = 0;
224
225 if (linkmode != -1) {
226 rta = (struct rtattr *)
227 ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
228 rta->rta_type = IFLA_LINKMODE;
229 rta->rta_len = RTA_LENGTH(sizeof(char));
230 *((char *) RTA_DATA(rta)) = linkmode;
231 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
232 RTA_LENGTH(sizeof(char));
233 }
234 if (operstate != -1) {
235 rta = (struct rtattr *)
236 ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
237 rta->rta_type = IFLA_OPERSTATE;
238 rta->rta_len = RTA_LENGTH(sizeof(char));
239 *((char *) RTA_DATA(rta)) = operstate;
240 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
241 RTA_LENGTH(sizeof(char));
242 }
243
244 wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
245 linkmode, operstate);
246
d8816397 247 ret = send(drv->link_event_sock, &req, req.hdr.nlmsg_len, 0);
3f5285e8
JM
248 if (ret < 0) {
249 wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
250 "%s (assume operstate is not supported)",
251 strerror(errno));
252 }
253
254 return ret < 0 ? -1 : 0;
255}
256
257
258static int wpa_driver_nl80211_set_auth_param(
259 struct wpa_driver_nl80211_data *drv, int idx, u32 value)
260{
261 struct iwreq iwr;
262 int ret = 0;
263
264 os_memset(&iwr, 0, sizeof(iwr));
265 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
266 iwr.u.param.flags = idx & IW_AUTH_INDEX;
267 iwr.u.param.value = value;
268
269 if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
270 if (errno != EOPNOTSUPP) {
271 wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
272 "value 0x%x) failed: %s)",
273 idx, value, strerror(errno));
274 }
275 ret = errno == EOPNOTSUPP ? -2 : -1;
276 }
277
278 return ret;
279}
280
281
282static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
283{
284 struct wpa_driver_nl80211_data *drv = priv;
c2a04078
JM
285 if (!drv->associated)
286 return -1;
287 os_memcpy(bssid, drv->bssid, ETH_ALEN);
288 return 0;
3f5285e8
JM
289}
290
291
3f5285e8
JM
292static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
293{
294 struct wpa_driver_nl80211_data *drv = priv;
fd05d64e
JM
295 if (!drv->associated)
296 return -1;
297 os_memcpy(ssid, drv->ssid, drv->ssid_len);
298 return drv->ssid_len;
3f5285e8
JM
299}
300
301
7524cfb1
JM
302static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
303 void *ctx, char *buf, size_t len,
304 int del)
3f5285e8
JM
305{
306 union wpa_event_data event;
307
308 os_memset(&event, 0, sizeof(event));
309 if (len > sizeof(event.interface_status.ifname))
310 len = sizeof(event.interface_status.ifname) - 1;
311 os_memcpy(event.interface_status.ifname, buf, len);
312 event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
313 EVENT_INTERFACE_ADDED;
314
315 wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
316 del ? "DEL" : "NEW",
317 event.interface_status.ifname,
318 del ? "removed" : "added");
319
7524cfb1
JM
320 if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
321 if (del)
322 drv->if_removed = 1;
323 else
324 drv->if_removed = 0;
325 }
326
3f5285e8
JM
327 wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
328}
329
330
7524cfb1
JM
331static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
332 struct nlmsghdr *h)
333{
334 struct ifinfomsg *ifi;
335 int attrlen, _nlmsg_len, rta_len;
336 struct rtattr *attr;
337
338 ifi = NLMSG_DATA(h);
339
340 _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
341
342 attrlen = h->nlmsg_len - _nlmsg_len;
343 if (attrlen < 0)
344 return 0;
345
346 attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
347
348 rta_len = RTA_ALIGN(sizeof(struct rtattr));
349 while (RTA_OK(attr, attrlen)) {
350 if (attr->rta_type == IFLA_IFNAME) {
351 if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
352 == 0)
353 return 1;
354 else
355 break;
356 }
357 attr = RTA_NEXT(attr, attrlen);
358 }
359
360 return 0;
361}
362
363
364static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
365 int ifindex, struct nlmsghdr *h)
366{
367 if (drv->ifindex == ifindex)
368 return 1;
369
370 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, h)) {
371 drv->ifindex = if_nametoindex(drv->ifname);
372 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
373 "interface");
374 wpa_driver_nl80211_finish_drv_init(drv);
375 return 1;
376 }
377
378 return 0;
379}
380
381
3f5285e8
JM
382static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
383 void *ctx, struct nlmsghdr *h,
384 size_t len)
385{
386 struct ifinfomsg *ifi;
387 int attrlen, _nlmsg_len, rta_len;
388 struct rtattr * attr;
389
390 if (len < sizeof(*ifi))
391 return;
392
393 ifi = NLMSG_DATA(h);
394
7524cfb1 395 if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, h)) {
3f5285e8
JM
396 wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
397 ifi->ifi_index);
398 return;
399 }
400
401 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
402 "(%s%s%s%s)",
403 drv->operstate, ifi->ifi_flags,
404 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
405 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
406 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
407 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
408 /*
409 * Some drivers send the association event before the operup event--in
410 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
411 * fails. This will hit us when wpa_supplicant does not need to do
412 * IEEE 802.1X authentication
413 */
414 if (drv->operstate == 1 &&
415 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
416 !(ifi->ifi_flags & IFF_RUNNING))
417 wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP);
418
419 _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
420
421 attrlen = h->nlmsg_len - _nlmsg_len;
422 if (attrlen < 0)
423 return;
424
425 attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
426
427 rta_len = RTA_ALIGN(sizeof(struct rtattr));
428 while (RTA_OK(attr, attrlen)) {
d8816397 429 if (attr->rta_type == IFLA_IFNAME) {
7524cfb1
JM
430 wpa_driver_nl80211_event_link(
431 drv, ctx,
432 ((char *) attr) + rta_len,
433 attr->rta_len - rta_len, 0);
3f5285e8
JM
434 }
435 attr = RTA_NEXT(attr, attrlen);
436 }
437}
438
439
440static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv,
441 void *ctx, struct nlmsghdr *h,
442 size_t len)
443{
444 struct ifinfomsg *ifi;
445 int attrlen, _nlmsg_len, rta_len;
446 struct rtattr * attr;
447
448 if (len < sizeof(*ifi))
449 return;
450
451 ifi = NLMSG_DATA(h);
452
453 _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
454
455 attrlen = h->nlmsg_len - _nlmsg_len;
456 if (attrlen < 0)
457 return;
458
459 attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
460
461 rta_len = RTA_ALIGN(sizeof(struct rtattr));
462 while (RTA_OK(attr, attrlen)) {
463 if (attr->rta_type == IFLA_IFNAME) {
7524cfb1
JM
464 wpa_driver_nl80211_event_link(
465 drv, ctx,
466 ((char *) attr) + rta_len,
467 attr->rta_len - rta_len, 1);
3f5285e8
JM
468 }
469 attr = RTA_NEXT(attr, attrlen);
470 }
471}
472
473
d8816397 474static void wpa_driver_nl80211_event_receive_link(int sock, void *eloop_ctx,
97865538 475 void *sock_ctx)
3f5285e8
JM
476{
477 char buf[8192];
478 int left;
479 struct sockaddr_nl from;
480 socklen_t fromlen;
481 struct nlmsghdr *h;
482 int max_events = 10;
483
484try_again:
485 fromlen = sizeof(from);
486 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
487 (struct sockaddr *) &from, &fromlen);
488 if (left < 0) {
489 if (errno != EINTR && errno != EAGAIN)
490 perror("recvfrom(netlink)");
491 return;
492 }
493
494 h = (struct nlmsghdr *) buf;
495 while (left >= (int) sizeof(*h)) {
496 int len, plen;
497
498 len = h->nlmsg_len;
499 plen = len - sizeof(*h);
500 if (len > left || plen < 0) {
501 wpa_printf(MSG_DEBUG, "Malformed netlink message: "
502 "len=%d left=%d plen=%d",
503 len, left, plen);
504 break;
505 }
506
507 switch (h->nlmsg_type) {
508 case RTM_NEWLINK:
509 wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx,
510 h, plen);
511 break;
512 case RTM_DELLINK:
513 wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx,
514 h, plen);
515 break;
516 }
517
518 len = NLMSG_ALIGN(len);
519 left -= len;
520 h = (struct nlmsghdr *) ((char *) h + len);
521 }
522
523 if (left > 0) {
524 wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
525 "message", left);
526 }
527
528 if (--max_events > 0) {
529 /*
530 * Try to receive all events in one eloop call in order to
531 * limit race condition on cases where AssocInfo event, Assoc
532 * event, and EAPOL frames are received more or less at the
533 * same time. We want to process the event messages first
534 * before starting EAPOL processing.
535 */
536 goto try_again;
537 }
538}
539
540
97865538
JM
541static int no_seq_check(struct nl_msg *msg, void *arg)
542{
543 return NL_OK;
544}
545
546
c2a04078
JM
547static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
548 const u8 *frame, size_t len)
549{
550 const struct ieee80211_mgmt *mgmt;
551 union wpa_event_data event;
552
553 mgmt = (const struct ieee80211_mgmt *) frame;
554 if (len < 24 + sizeof(mgmt->u.auth)) {
555 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
556 "frame");
557 return;
558 }
559
560 os_memset(&event, 0, sizeof(event));
561 os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
562 event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
563 event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
564 if (len > 24 + sizeof(mgmt->u.auth)) {
565 event.auth.ies = mgmt->u.auth.variable;
566 event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
567 }
568
569 wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
570}
571
572
573static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
574 const u8 *frame, size_t len)
575{
576 const struct ieee80211_mgmt *mgmt;
577 union wpa_event_data event;
578 u16 status;
579
580 mgmt = (const struct ieee80211_mgmt *) frame;
581 if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
582 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
583 "frame");
584 return;
585 }
586
587 status = le_to_host16(mgmt->u.assoc_resp.status_code);
588 if (status != WLAN_STATUS_SUCCESS) {
efa46078
JM
589 os_memset(&event, 0, sizeof(event));
590 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
591 event.assoc_reject.resp_ies =
592 (u8 *) mgmt->u.assoc_resp.variable;
593 event.assoc_reject.resp_ies_len =
594 len - 24 - sizeof(mgmt->u.assoc_resp);
595 }
596 event.assoc_reject.status_code = status;
597
598 wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
c2a04078
JM
599 return;
600 }
601
602 drv->associated = 1;
603 os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
604
605 os_memset(&event, 0, sizeof(event));
606 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
607 event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
608 event.assoc_info.resp_ies_len =
efa46078 609 len - 24 - sizeof(mgmt->u.assoc_resp);
c2a04078
JM
610 }
611
612 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
613}
614
615
616static void mlme_event(struct wpa_driver_nl80211_data *drv,
617 enum nl80211_commands cmd, struct nlattr *frame)
618{
619 if (frame == NULL) {
620 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
621 "data", cmd);
622 return;
623 }
624
625 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
626 wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
627 nla_data(frame), nla_len(frame));
628
629 switch (cmd) {
630 case NL80211_CMD_AUTHENTICATE:
631 mlme_event_auth(drv, nla_data(frame), nla_len(frame));
632 break;
633 case NL80211_CMD_ASSOCIATE:
634 mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
635 break;
636 case NL80211_CMD_DEAUTHENTICATE:
637 drv->associated = 0;
638 wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, NULL);
639 break;
640 case NL80211_CMD_DISASSOCIATE:
641 drv->associated = 0;
642 wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
643 break;
644 default:
645 break;
646 }
647}
648
649
97865538
JM
650static int process_event(struct nl_msg *msg, void *arg)
651{
652 struct wpa_driver_nl80211_data *drv = arg;
653 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
654 struct nlattr *tb[NL80211_ATTR_MAX + 1];
655
656 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
657 genlmsg_attrlen(gnlh, 0), NULL);
658
659 if (tb[NL80211_ATTR_IFINDEX]) {
660 int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
661 if (ifindex != drv->ifindex) {
662 wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
663 " for foreign interface (ifindex %d)",
664 gnlh->cmd, ifindex);
665 return NL_SKIP;
666 }
667 }
668
669 switch (gnlh->cmd) {
670 case NL80211_CMD_NEW_SCAN_RESULTS:
671 wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
672 drv->scan_complete_events = 1;
673 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
674 drv->ctx);
675 wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
676 break;
677 case NL80211_CMD_SCAN_ABORTED:
678 wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
679 /*
680 * Need to indicate that scan results are available in order
681 * not to make wpa_supplicant stop its scanning.
682 */
683 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
684 drv->ctx);
685 wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
686 break;
c2a04078
JM
687 case NL80211_CMD_AUTHENTICATE:
688 case NL80211_CMD_ASSOCIATE:
689 case NL80211_CMD_DEAUTHENTICATE:
690 case NL80211_CMD_DISASSOCIATE:
691 mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME]);
692 break;
97865538 693 default:
c2a04078
JM
694 wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
695 "(cmd=%d)", gnlh->cmd);
97865538
JM
696 break;
697 }
698
699 return NL_SKIP;
700}
701
702
703static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
704 void *sock_ctx)
705{
706 struct nl_cb *cb;
707 struct wpa_driver_nl80211_data *drv = eloop_ctx;
708
709 wpa_printf(MSG_DEBUG, "nl80211: Event message available");
710
711 cb = nl_cb_clone(drv->nl_cb);
712 if (!cb)
713 return;
714 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
715 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
716 nl_recvmsgs(drv->nl_handle, cb);
717 nl_cb_put(cb);
718}
719
720
3f5285e8
JM
721static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv,
722 const char *ifname, int *flags)
723{
724 struct ifreq ifr;
725
726 os_memset(&ifr, 0, sizeof(ifr));
727 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
728 if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
729 perror("ioctl[SIOCGIFFLAGS]");
730 return -1;
731 }
732 *flags = ifr.ifr_flags & 0xffff;
733 return 0;
734}
735
736
737/**
738 * wpa_driver_nl80211_get_ifflags - Get interface flags (SIOCGIFFLAGS)
739 * @drv: driver_nl80211 private data
740 * @flags: Pointer to returned flags value
741 * Returns: 0 on success, -1 on failure
742 */
743static int wpa_driver_nl80211_get_ifflags(struct wpa_driver_nl80211_data *drv,
744 int *flags)
745{
746 return wpa_driver_nl80211_get_ifflags_ifname(drv, drv->ifname, flags);
747}
748
749
750static int wpa_driver_nl80211_set_ifflags_ifname(
751 struct wpa_driver_nl80211_data *drv,
752 const char *ifname, int flags)
753{
754 struct ifreq ifr;
755
756 os_memset(&ifr, 0, sizeof(ifr));
757 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
758 ifr.ifr_flags = flags & 0xffff;
759 if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
760 perror("SIOCSIFFLAGS");
761 return -1;
762 }
763 return 0;
764}
765
766
767/**
768 * wpa_driver_nl80211_set_ifflags - Set interface flags (SIOCSIFFLAGS)
769 * @drv: driver_nl80211 private data
770 * @flags: New value for flags
771 * Returns: 0 on success, -1 on failure
772 */
773static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
774 int flags)
775{
776 return wpa_driver_nl80211_set_ifflags_ifname(drv, drv->ifname, flags);
777}
778
779
6d158490
LR
780/**
781 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
782 * @priv: driver_nl80211 private data
783 * @alpha2_arg: country to which to switch to
784 * Returns: 0 on success, -1 on failure
785 *
786 * This asks nl80211 to set the regulatory domain for given
787 * country ISO / IEC alpha2.
788 */
789static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
790{
791 struct wpa_driver_nl80211_data *drv = priv;
792 char alpha2[3];
793 struct nl_msg *msg;
794
795 msg = nlmsg_alloc();
796 if (!msg)
797 goto nla_put_failure;
798
799 alpha2[0] = alpha2_arg[0];
800 alpha2[1] = alpha2_arg[1];
801 alpha2[2] = '\0';
802
803 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
804 0, NL80211_CMD_REQ_SET_REG, 0);
805
806 NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
807 if (send_and_recv_msgs(drv, msg, NULL, NULL))
808 return -EINVAL;
809 return 0;
810nla_put_failure:
811 return -EINVAL;
812}
813
814
80bc75f1
JM
815struct wiphy_info_data {
816 int max_scan_ssids;
1581b38b 817 int ap_supported;
80bc75f1
JM
818};
819
820
821static int wiphy_info_handler(struct nl_msg *msg, void *arg)
822{
823 struct nlattr *tb[NL80211_ATTR_MAX + 1];
824 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
825 struct wiphy_info_data *info = arg;
826
827 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
828 genlmsg_attrlen(gnlh, 0), NULL);
829
830 if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
831 info->max_scan_ssids =
832 nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
833
1581b38b
JM
834 if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
835 struct nlattr *nl_mode;
836 int i;
837 nla_for_each_nested(nl_mode,
838 tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
839 if (nl_mode->nla_type == NL80211_IFTYPE_AP) {
840 info->ap_supported = 1;
841 break;
842 }
843 }
844 }
845
80bc75f1
JM
846 return NL_SKIP;
847}
848
849
850static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
851 struct wiphy_info_data *info)
852{
853 struct nl_msg *msg;
854
855 os_memset(info, 0, sizeof(*info));
856 msg = nlmsg_alloc();
857 if (!msg)
858 return -1;
859
860 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
861 0, NL80211_CMD_GET_WIPHY, 0);
862
863 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
864
865 if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
866 return 0;
867 msg = NULL;
868nla_put_failure:
869 nlmsg_free(msg);
870 return -1;
871}
872
873
874static void wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
875{
876 struct wiphy_info_data info;
877 if (wpa_driver_nl80211_get_info(drv, &info))
878 return;
879 drv->has_capability = 1;
1b2a72e8
JM
880 /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
881 drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
882 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
883 WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
884 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
885 drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
886 WPA_DRIVER_CAPA_ENC_WEP104 |
887 WPA_DRIVER_CAPA_ENC_TKIP |
888 WPA_DRIVER_CAPA_ENC_CCMP;
889
80bc75f1 890 drv->capa.max_scan_ssids = info.max_scan_ssids;
1581b38b
JM
891 if (info.ap_supported)
892 drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
80bc75f1
JM
893}
894
895
3f5285e8 896/**
7e5ba1b9 897 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
3f5285e8
JM
898 * @ctx: context to be used when calling wpa_supplicant functions,
899 * e.g., wpa_supplicant_event()
900 * @ifname: interface name, e.g., wlan0
901 * Returns: Pointer to private data, %NULL on failure
902 */
7e5ba1b9 903static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
3f5285e8 904{
97865538 905 int s, ret;
3f5285e8
JM
906 struct sockaddr_nl local;
907 struct wpa_driver_nl80211_data *drv;
908
909 drv = os_zalloc(sizeof(*drv));
910 if (drv == NULL)
911 return NULL;
912 drv->ctx = ctx;
913 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
914
915 drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
916 if (drv->nl_cb == NULL) {
917 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
918 "callbacks");
919 goto err1;
920 }
921
922 drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
923 if (drv->nl_handle == NULL) {
924 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
925 "callbacks");
926 goto err2;
927 }
928
929 if (genl_connect(drv->nl_handle)) {
930 wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
931 "netlink");
932 goto err3;
933 }
934
935 drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
936 if (drv->nl_cache == NULL) {
937 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
938 "netlink cache");
939 goto err3;
940 }
941
942 drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
943 if (drv->nl80211 == NULL) {
944 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
945 "found");
946 goto err4;
947 }
948
97865538
JM
949 ret = nl_get_multicast_id(drv, "nl80211", "scan");
950 if (ret >= 0)
951 ret = nl_socket_add_membership(drv->nl_handle, ret);
952 if (ret < 0) {
953 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
954 "membership for scan events: %d (%s)",
955 ret, strerror(-ret));
956 goto err4;
957 }
c2a04078
JM
958
959 ret = nl_get_multicast_id(drv, "nl80211", "mlme");
960 if (ret >= 0)
961 ret = nl_socket_add_membership(drv->nl_handle, ret);
c2a04078
JM
962 if (ret < 0) {
963 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
964 "membership for mlme events: %d (%s)",
965 ret, strerror(-ret));
966 goto err4;
967 }
968 drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
c2a04078 969
97865538
JM
970 eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle),
971 wpa_driver_nl80211_event_receive, drv, ctx);
972
3f5285e8
JM
973 drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
974 if (drv->ioctl_sock < 0) {
975 perror("socket(PF_INET,SOCK_DGRAM)");
976 goto err5;
977 }
978
979 s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
980 if (s < 0) {
981 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
982 goto err6;
983 }
984
985 os_memset(&local, 0, sizeof(local));
986 local.nl_family = AF_NETLINK;
987 local.nl_groups = RTMGRP_LINK;
988 if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
989 perror("bind(netlink)");
990 close(s);
991 goto err6;
992 }
993
d8816397 994 eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_link, drv,
3f5285e8 995 ctx);
d8816397 996 drv->link_event_sock = s;
3f5285e8 997
362f781e
JM
998 if (wpa_driver_nl80211_finish_drv_init(drv))
999 goto err7;
7524cfb1
JM
1000
1001 return drv;
1002
362f781e 1003err7:
d8816397
JM
1004 eloop_unregister_read_sock(drv->link_event_sock);
1005 close(drv->link_event_sock);
7524cfb1
JM
1006err6:
1007 close(drv->ioctl_sock);
1008err5:
1009 genl_family_put(drv->nl80211);
1010err4:
1011 nl_cache_free(drv->nl_cache);
1012err3:
1013 nl_handle_destroy(drv->nl_handle);
1014err2:
1015 nl_cb_put(drv->nl_cb);
1016err1:
1017 os_free(drv);
1018 return NULL;
1019}
1020
1021
362f781e 1022static int
7524cfb1
JM
1023wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
1024{
1025 int flags;
1026
a87c9d96
JM
1027 drv->ifindex = if_nametoindex(drv->ifname);
1028
1029 if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
1030 wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
1031 "use managed mode");
1032 }
1033
362f781e
JM
1034 if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0) {
1035 wpa_printf(MSG_ERROR, "Could not get interface '%s' flags",
1036 drv->ifname);
1037 return -1;
1038 }
1039 if (!(flags & IFF_UP)) {
3f5285e8 1040 if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
362f781e
JM
1041 wpa_printf(MSG_ERROR, "Could not set interface '%s' "
1042 "UP", drv->ifname);
1043 return -1;
3f5285e8
JM
1044 }
1045 }
1046
80bc75f1
JM
1047 wpa_driver_nl80211_capa(drv);
1048
3f5285e8 1049 wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
362f781e
JM
1050
1051 return 0;
3f5285e8
JM
1052}
1053
1054
1055/**
7e5ba1b9
JM
1056 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
1057 * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
3f5285e8
JM
1058 *
1059 * Shut down driver interface and processing of driver events. Free
1060 * private data buffer if one was allocated in wpa_driver_nl80211_init().
1061 */
7e5ba1b9 1062static void wpa_driver_nl80211_deinit(void *priv)
3f5285e8
JM
1063{
1064 struct wpa_driver_nl80211_data *drv = priv;
1065 int flags;
1066
1067 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
1068
36b15723 1069 wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, 0);
3f5285e8
JM
1070
1071 wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
1072
d8816397 1073 eloop_unregister_read_sock(drv->link_event_sock);
3f5285e8
JM
1074
1075 if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
1076 (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
1581b38b 1077 wpa_driver_nl80211_set_mode(drv, 0);
3f5285e8 1078
d8816397 1079 close(drv->link_event_sock);
3f5285e8 1080 close(drv->ioctl_sock);
3f5285e8 1081
97865538 1082 eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
3f5285e8
JM
1083 genl_family_put(drv->nl80211);
1084 nl_cache_free(drv->nl_cache);
1085 nl_handle_destroy(drv->nl_handle);
1086 nl_cb_put(drv->nl_cb);
1087
1088 os_free(drv);
1089}
1090
1091
1092/**
1093 * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
1094 * @eloop_ctx: Unused
1095 * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
1096 *
1097 * This function can be used as registered timeout when starting a scan to
1098 * generate a scan completed event if the driver does not report this.
1099 */
1100static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
1101{
1102 wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
1103 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
1104}
1105
1106
1107/**
1108 * wpa_driver_nl80211_scan - Request the driver to initiate scan
1109 * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
6a1063e0 1110 * @params: Scan parameters
3f5285e8
JM
1111 * Returns: 0 on success, -1 on failure
1112 */
6a1063e0
JM
1113static int wpa_driver_nl80211_scan(void *priv,
1114 struct wpa_driver_scan_params *params)
3f5285e8
JM
1115{
1116 struct wpa_driver_nl80211_data *drv = priv;
3f5285e8 1117 int ret = 0, timeout;
d3a98225 1118 struct nl_msg *msg, *ssids, *freqs;
6a1063e0 1119 size_t i;
3f5285e8 1120
0e75527f
JM
1121 msg = nlmsg_alloc();
1122 ssids = nlmsg_alloc();
d3a98225
JM
1123 freqs = nlmsg_alloc();
1124 if (!msg || !ssids || !freqs) {
0e75527f
JM
1125 nlmsg_free(msg);
1126 nlmsg_free(ssids);
d3a98225 1127 nlmsg_free(freqs);
3f5285e8
JM
1128 return -1;
1129 }
1130
0e75527f
JM
1131 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
1132 NL80211_CMD_TRIGGER_SCAN, 0);
1133
1134 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3f5285e8 1135
6a1063e0
JM
1136 for (i = 0; i < params->num_ssids; i++) {
1137 NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
1138 params->ssids[i].ssid);
3f5285e8 1139 }
6a1063e0
JM
1140 if (params->num_ssids)
1141 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
3f5285e8 1142
d173df52
JM
1143 if (params->extra_ies) {
1144 NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
1145 params->extra_ies);
1146 }
1147
d3a98225
JM
1148 if (params->freqs) {
1149 for (i = 0; params->freqs[i]; i++)
1150 NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
1151 nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
1152 }
1153
0e75527f
JM
1154 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
1155 msg = NULL;
1156 if (ret) {
1157 wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
1158 "(%s)", ret, strerror(-ret));
1159 goto nla_put_failure;
3f5285e8
JM
1160 }
1161
1162 /* Not all drivers generate "scan completed" wireless event, so try to
1163 * read results after a timeout. */
0e75527f 1164 timeout = 10;
3f5285e8
JM
1165 if (drv->scan_complete_events) {
1166 /*
d173df52
JM
1167 * The driver seems to deliver events to notify when scan is
1168 * complete, so use longer timeout to avoid race conditions
1169 * with scanning and following association request.
3f5285e8
JM
1170 */
1171 timeout = 30;
1172 }
1173 wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
1174 "seconds", ret, timeout);
1175 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
0e75527f
JM
1176 eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
1177 drv, drv->ctx);
3f5285e8 1178
0e75527f
JM
1179nla_put_failure:
1180 nlmsg_free(ssids);
1181 nlmsg_free(msg);
d3a98225 1182 nlmsg_free(freqs);
3f5285e8
JM
1183 return ret;
1184}
1185
1186
b3db1e1c 1187static int bss_info_handler(struct nl_msg *msg, void *arg)
3f5285e8 1188{
b3db1e1c
JM
1189 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1190 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1191 struct nlattr *bss[NL80211_BSS_MAX + 1];
1192 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1193 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
1194 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1195 [NL80211_BSS_TSF] = { .type = NLA_U64 },
1196 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
1197 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
1198 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
1199 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
1200 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
1201 };
1202 struct wpa_scan_results *res = arg;
3f5285e8
JM
1203 struct wpa_scan_res **tmp;
1204 struct wpa_scan_res *r;
b3db1e1c
JM
1205 const u8 *ie;
1206 size_t ie_len;
3f5285e8 1207
b3db1e1c
JM
1208 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1209 genlmsg_attrlen(gnlh, 0), NULL);
1210 if (!tb[NL80211_ATTR_BSS])
1211 return NL_SKIP;
1212 if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
1213 bss_policy))
1214 return NL_SKIP;
1215 if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
1216 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1217 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1218 } else {
1219 ie = NULL;
1220 ie_len = 0;
1221 }
3f5285e8 1222
b3db1e1c 1223 r = os_zalloc(sizeof(*r) + ie_len);
3f5285e8 1224 if (r == NULL)
b3db1e1c
JM
1225 return NL_SKIP;
1226 if (bss[NL80211_BSS_BSSID])
1227 os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
1228 ETH_ALEN);
1229 if (bss[NL80211_BSS_FREQUENCY])
1230 r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1231 if (bss[NL80211_BSS_BEACON_INTERVAL])
1232 r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
1233 if (bss[NL80211_BSS_CAPABILITY])
1234 r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
7c2849d2
JM
1235 r->flags |= WPA_SCAN_NOISE_INVALID;
1236 if (bss[NL80211_BSS_SIGNAL_MBM]) {
b3db1e1c 1237 r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
7c2849d2
JM
1238 r->level /= 100; /* mBm to dBm */
1239 r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
1240 } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
1241 r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
1242 r->flags |= WPA_SCAN_LEVEL_INVALID;
1243 } else
1244 r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
b3db1e1c
JM
1245 if (bss[NL80211_BSS_TSF])
1246 r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
1247 r->ie_len = ie_len;
1248 if (ie)
1249 os_memcpy(r + 1, ie, ie_len);
3f5285e8
JM
1250
1251 tmp = os_realloc(res->res,
1252 (res->num + 1) * sizeof(struct wpa_scan_res *));
1253 if (tmp == NULL) {
1254 os_free(r);
b3db1e1c 1255 return NL_SKIP;
3f5285e8
JM
1256 }
1257 tmp[res->num++] = r;
1258 res->res = tmp;
b3db1e1c
JM
1259
1260 return NL_SKIP;
3f5285e8 1261}
b3db1e1c 1262
3f5285e8
JM
1263
1264/**
1265 * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
1266 * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
1267 * Returns: Scan results on success, -1 on failure
1268 */
7e5ba1b9
JM
1269static struct wpa_scan_results *
1270wpa_driver_nl80211_get_scan_results(void *priv)
3f5285e8
JM
1271{
1272 struct wpa_driver_nl80211_data *drv = priv;
b3db1e1c 1273 struct nl_msg *msg;
3f5285e8 1274 struct wpa_scan_results *res;
b3db1e1c 1275 int ret;
3f5285e8
JM
1276
1277 res = os_zalloc(sizeof(*res));
b3db1e1c
JM
1278 if (res == NULL)
1279 return 0;
1280 msg = nlmsg_alloc();
1281 if (!msg)
1282 goto nla_put_failure;
3f5285e8 1283
b3db1e1c
JM
1284 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
1285 NL80211_CMD_GET_SCAN, 0);
1286 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3f5285e8 1287
b3db1e1c
JM
1288 ret = send_and_recv_msgs(drv, msg, bss_info_handler, res);
1289 msg = NULL;
1290 if (ret == 0) {
1291 wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
1292 (unsigned long) res->num);
1293 return res;
3f5285e8 1294 }
b3db1e1c
JM
1295 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1296 "(%s)", ret, strerror(-ret));
1297nla_put_failure:
1298 nlmsg_free(msg);
1299 wpa_scan_results_free(res);
1300 return NULL;
3f5285e8
JM
1301}
1302
1303
3f5285e8
JM
1304static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
1305 const u8 *addr, int key_idx,
1306 int set_tx, const u8 *seq,
1307 size_t seq_len,
1308 const u8 *key, size_t key_len)
1309{
1310 struct wpa_driver_nl80211_data *drv = priv;
6241fcb1 1311 int err;
3f5285e8
JM
1312 struct nl_msg *msg;
1313
1314 wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
1315 "seq_len=%lu key_len=%lu",
1316 __func__, alg, addr, key_idx, set_tx,
1317 (unsigned long) seq_len, (unsigned long) key_len);
1318
1319 msg = nlmsg_alloc();
1320 if (msg == NULL)
1321 return -1;
1322
1323 if (alg == WPA_ALG_NONE) {
1324 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
1325 NL80211_CMD_DEL_KEY, 0);
1326 } else {
1327 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
1328 NL80211_CMD_NEW_KEY, 0);
1329 NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
1330 switch (alg) {
1331 case WPA_ALG_WEP:
1332 if (key_len == 5)
1333 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
1334 0x000FAC01);
1335 else
1336 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
1337 0x000FAC05);
1338 break;
1339 case WPA_ALG_TKIP:
1340 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
1341 break;
1342 case WPA_ALG_CCMP:
1343 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
1344 break;
1345 default:
1346 nlmsg_free(msg);
1347 return -1;
1348 }
1349 }
1350
1351 if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
1352 {
1353 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
1354 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
1355 }
1356 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
1357 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1358
6241fcb1
JM
1359 err = send_and_recv_msgs(drv, msg, NULL, NULL);
1360 if (err) {
3f5285e8 1361 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err);
3f5285e8
JM
1362 return -1;
1363 }
1364
1365 if (set_tx && alg != WPA_ALG_NONE) {
3f5285e8
JM
1366 msg = nlmsg_alloc();
1367 if (msg == NULL)
1368 return -1;
1369
1370 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
1371 0, NL80211_CMD_SET_KEY, 0);
1372 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
1373 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1374 NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
1375
6241fcb1
JM
1376 err = send_and_recv_msgs(drv, msg, NULL, NULL);
1377 if (err) {
3f5285e8
JM
1378 wpa_printf(MSG_DEBUG, "nl80211: set default key "
1379 "failed; err=%d", err);
3f5285e8
JM
1380 return -1;
1381 }
1382 }
1383
6241fcb1 1384 return 0;
3f5285e8
JM
1385
1386nla_put_failure:
6241fcb1 1387 return -ENOBUFS;
3f5285e8
JM
1388}
1389
1390
c2a04078
JM
1391static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
1392 const u8 *addr, int cmd, u16 reason_code)
1393{
1394 int ret = -1;
1395 struct nl_msg *msg;
1396
1397 msg = nlmsg_alloc();
1398 if (!msg)
1399 return -1;
1400
1401 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
1402
1403 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1404 NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
1405 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
1406
1407 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
1408 msg = NULL;
1409 if (ret) {
1410 wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
1411 "(%s)", ret, strerror(-ret));
1412 goto nla_put_failure;
1413 }
1414 ret = 0;
1415
1416nla_put_failure:
1417 nlmsg_free(msg);
1418 return ret;
1419}
3f5285e8
JM
1420
1421
1422static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
c2a04078 1423 int reason_code)
3f5285e8
JM
1424{
1425 struct wpa_driver_nl80211_data *drv = priv;
c2a04078 1426 wpa_printf(MSG_DEBUG, "%s", __func__);
c2a04078
JM
1427 return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
1428 reason_code);
3f5285e8
JM
1429}
1430
1431
1432static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
c2a04078 1433 int reason_code)
3f5285e8
JM
1434{
1435 struct wpa_driver_nl80211_data *drv = priv;
c2a04078 1436 wpa_printf(MSG_DEBUG, "%s", __func__);
c2a04078
JM
1437 return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
1438 reason_code);
3f5285e8
JM
1439}
1440
1441
c2a04078
JM
1442static int wpa_driver_nl80211_authenticate(
1443 void *priv, struct wpa_driver_auth_params *params)
1444{
1445 struct wpa_driver_nl80211_data *drv = priv;
1446 int ret = -1;
1447 struct nl_msg *msg;
1448 enum nl80211_auth_type type;
1449
1450 drv->associated = 0;
1451
1452 msg = nlmsg_alloc();
1453 if (!msg)
1454 return -1;
1455
1456 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
1457 drv->ifindex);
1458 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
1459 NL80211_CMD_AUTHENTICATE, 0);
1460
1461 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1462 if (params->bssid) {
1463 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
1464 MAC2STR(params->bssid));
1465 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
1466 }
1467 if (params->freq) {
1468 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
1469 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
1470 }
1471 if (params->ssid) {
1472 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
1473 params->ssid, params->ssid_len);
1474 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
1475 params->ssid);
1476 }
1477 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
1478 if (params->ie)
1479 NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
1480 /*
1481 * TODO: if multiple auth_alg options enabled, try them one by one if
1482 * the AP rejects authentication due to unknown auth alg
1483 */
1484 if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
1485 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
1486 else if (params->auth_alg & AUTH_ALG_SHARED_KEY)
1487 type = NL80211_AUTHTYPE_SHARED_KEY;
1488 else if (params->auth_alg & AUTH_ALG_LEAP)
1489 type = NL80211_AUTHTYPE_NETWORK_EAP;
1490 else if (params->auth_alg & AUTH_ALG_FT)
1491 type = NL80211_AUTHTYPE_FT;
1492 else
1493 goto nla_put_failure;
1494 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
1495 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
1496
1497 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
1498 msg = NULL;
1499 if (ret) {
1500 wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
1501 "(%s)", ret, strerror(-ret));
1502 goto nla_put_failure;
1503 }
1504 ret = 0;
1505 wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
1506 "successfully");
1507
1508nla_put_failure:
1509 nlmsg_free(msg);
1510 return ret;
1511}
1512
1513
1581b38b
JM
1514#ifdef CONFIG_AP
1515static int wpa_driver_nl80211_set_freq2(
1516 struct wpa_driver_nl80211_data *drv,
1517 struct wpa_driver_associate_params *params)
1518{
1519 struct nl_msg *msg;
1520
1521 msg = nlmsg_alloc();
1522 if (!msg)
1523 return -1;
1524
1525 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
1526 NL80211_CMD_SET_WIPHY, 0);
1527
1528 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1529
1530 /* TODO: proper channel configuration */
1531 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, 2437);
1532
1533 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
1534 return 0;
1535nla_put_failure:
1536 return -1;
1537}
1538
1539
1540static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
1541 struct wpa_driver_associate_params *params)
1542{
1543 if (wpa_driver_nl80211_set_mode(drv, params->mode) ||
1544 wpa_driver_nl80211_set_freq2(drv, params))
1545 return -1;
1546
1547 /* TODO: setup monitor interface (and add code somewhere to remove this
1548 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
1549 /* TODO: setup beacon */
1550
1551 return 0;
1552}
1553#endif /* CONFIG_AP */
1554
1555
c2a04078
JM
1556static int wpa_driver_nl80211_associate(
1557 void *priv, struct wpa_driver_associate_params *params)
1558{
1559 struct wpa_driver_nl80211_data *drv = priv;
1560 int ret = -1;
1561 struct nl_msg *msg;
1562
1581b38b
JM
1563#ifdef CONFIG_AP
1564 if (params->mode == 2)
1565 return wpa_driver_nl80211_ap(drv, params);
1566#endif /* CONFIG_AP */
1567
36b15723
JM
1568 wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
1569 params->drop_unencrypted);
1570
c2a04078
JM
1571 drv->associated = 0;
1572
1573 msg = nlmsg_alloc();
1574 if (!msg)
1575 return -1;
1576
1577 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
1578 drv->ifindex);
1579 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
1580 NL80211_CMD_ASSOCIATE, 0);
1581
1582 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1583 if (params->bssid) {
1584 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
1585 MAC2STR(params->bssid));
1586 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
1587 }
1588 if (params->freq) {
1589 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
1590 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
1591 }
1592 if (params->ssid) {
1593 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
1594 params->ssid, params->ssid_len);
1595 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
1596 params->ssid);
fd05d64e
JM
1597 if (params->ssid_len > sizeof(drv->ssid))
1598 goto nla_put_failure;
1599 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
1600 drv->ssid_len = params->ssid_len;
c2a04078
JM
1601 }
1602 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
1603 if (params->wpa_ie)
1604 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
1605 params->wpa_ie);
1606
1607 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
1608 msg = NULL;
1609 if (ret) {
1610 wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
1611 "(%s)", ret, strerror(-ret));
1612 goto nla_put_failure;
1613 }
1614 ret = 0;
1615 wpa_printf(MSG_DEBUG, "nl80211: Association request send "
1616 "successfully");
1617
1618nla_put_failure:
1619 nlmsg_free(msg);
1620 return ret;
1621}
3f5285e8
JM
1622
1623
1624/**
d61f48ba 1625 * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc)
36b15723 1626 * @drv: Pointer to private driver data from wpa_driver_nl80211_init()
3f5285e8
JM
1627 * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
1628 * Returns: 0 on success, -1 on failure
1629 */
36b15723
JM
1630static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
1631 int mode)
3f5285e8 1632{
3f5285e8
JM
1633 int ret = -1, flags;
1634 struct nl_msg *msg;
1581b38b
JM
1635 int nlmode;
1636
1637 switch (mode) {
1638 case 0:
1639 nlmode = NL80211_IFTYPE_STATION;
1640 break;
1641 case 1:
1642 nlmode = NL80211_IFTYPE_ADHOC;
1643 break;
1644 case 2:
1645 nlmode = NL80211_IFTYPE_AP;
1646 break;
1647 default:
1648 return -1;
1649 }
3f5285e8
JM
1650
1651 msg = nlmsg_alloc();
1652 if (!msg)
1653 return -1;
1654
1655 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
1656 0, NL80211_CMD_SET_INTERFACE, 0);
1657 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1581b38b 1658 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode);
3f5285e8 1659
6241fcb1
JM
1660 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
1661 if (!ret)
1662 return 0;
1663 else
3f5285e8
JM
1664 goto try_again;
1665
3f5285e8 1666nla_put_failure:
a87c9d96
JM
1667 wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)",
1668 ret, strerror(-ret));
3f5285e8
JM
1669 return -1;
1670
1671try_again:
1672 /* mac80211 doesn't allow mode changes while the device is up, so
1673 * take the device down, try to set the mode again, and bring the
1674 * device back up.
1675 */
1676 if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) {
1677 (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
1678
1679 /* Try to set the mode again while the interface is down */
6241fcb1
JM
1680 msg = nlmsg_alloc();
1681 if (!msg)
1682 return -1;
1683
1684 genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
1685 0, NL80211_CMD_SET_INTERFACE, 0);
1686 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1581b38b 1687 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode);
6241fcb1
JM
1688 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
1689 if (ret) {
3f5285e8 1690 wpa_printf(MSG_ERROR, "Failed to set interface %s "
a87c9d96
JM
1691 "mode(try_again): %d (%s)",
1692 drv->ifname, ret, strerror(-ret));
6241fcb1 1693 }
3f5285e8
JM
1694
1695 /* Ignore return value of get_ifflags to ensure that the device
1696 * is always up like it was before this function was called.
1697 */
1698 (void) wpa_driver_nl80211_get_ifflags(drv, &flags);
1699 (void) wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP);
1700 }
1701
3f5285e8
JM
1702 return ret;
1703}
1704
1705
3f5285e8
JM
1706static int wpa_driver_nl80211_get_capa(void *priv,
1707 struct wpa_driver_capa *capa)
1708{
1709 struct wpa_driver_nl80211_data *drv = priv;
1710 if (!drv->has_capability)
1711 return -1;
1712 os_memcpy(capa, &drv->capa, sizeof(*capa));
1713 return 0;
1714}
1715
1716
1717static int wpa_driver_nl80211_set_operstate(void *priv, int state)
1718{
1719 struct wpa_driver_nl80211_data *drv = priv;
1720
1721 wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
1722 __func__, drv->operstate, state, state ? "UP" : "DORMANT");
1723 drv->operstate = state;
1724 return wpa_driver_nl80211_send_oper_ifla(
1725 drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
1726}
1727
1728
1729const struct wpa_driver_ops wpa_driver_nl80211_ops = {
1730 .name = "nl80211",
1731 .desc = "Linux nl80211/cfg80211",
1732 .get_bssid = wpa_driver_nl80211_get_bssid,
1733 .get_ssid = wpa_driver_nl80211_get_ssid,
3f5285e8 1734 .set_key = wpa_driver_nl80211_set_key,
6a1063e0 1735 .scan2 = wpa_driver_nl80211_scan,
3f5285e8
JM
1736 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
1737 .deauthenticate = wpa_driver_nl80211_deauthenticate,
1738 .disassociate = wpa_driver_nl80211_disassociate,
c2a04078 1739 .authenticate = wpa_driver_nl80211_authenticate,
3f5285e8 1740 .associate = wpa_driver_nl80211_associate,
3f5285e8
JM
1741 .init = wpa_driver_nl80211_init,
1742 .deinit = wpa_driver_nl80211_deinit,
3f5285e8
JM
1743 .get_capa = wpa_driver_nl80211_get_capa,
1744 .set_operstate = wpa_driver_nl80211_set_operstate,
6d158490 1745 .set_country = wpa_driver_nl80211_set_country,
3f5285e8 1746};