blob: d133bad0062b679ee8024eb230ff570e1aa30f12 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * Driver interaction with Linux nl80211/cfg80211
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08003 * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 * Copyright (c) 2003-2004, Instant802 Networks, Inc.
5 * Copyright (c) 2005-2006, Devicescape Software, Inc.
6 * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
7 * Copyright (c) 2009-2010, Atheros Communications
8 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009 * This software may be distributed under the terms of the BSD license.
10 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070011 */
12
13#include "includes.h"
14#include <sys/ioctl.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <net/if.h>
19#include <netlink/genl/genl.h>
20#include <netlink/genl/family.h>
21#include <netlink/genl/ctrl.h>
22#include <linux/rtnetlink.h>
23#include <netpacket/packet.h>
24#include <linux/filter.h>
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080025#include <linux/errqueue.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026#include "nl80211_copy.h"
27
28#include "common.h"
29#include "eloop.h"
30#include "utils/list.h"
31#include "common/ieee802_11_defs.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080032#include "common/ieee802_11_common.h"
33#include "l2_packet/l2_packet.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034#include "netlink.h"
35#include "linux_ioctl.h"
36#include "radiotap.h"
37#include "radiotap_iter.h"
38#include "rfkill.h"
39#include "driver.h"
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -080040
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080041#ifndef SO_WIFI_STATUS
42# if defined(__sparc__)
43# define SO_WIFI_STATUS 0x0025
44# elif defined(__parisc__)
45# define SO_WIFI_STATUS 0x4022
46# else
47# define SO_WIFI_STATUS 41
48# endif
49
50# define SCM_WIFI_STATUS SO_WIFI_STATUS
51#endif
52
53#ifndef SO_EE_ORIGIN_TXSTATUS
54#define SO_EE_ORIGIN_TXSTATUS 4
55#endif
56
57#ifndef PACKET_TX_TIMESTAMP
58#define PACKET_TX_TIMESTAMP 16
59#endif
60
61#ifdef ANDROID
62#include "android_drv.h"
63#endif /* ANDROID */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070064#ifdef CONFIG_LIBNL20
65/* libnl 2.0 compatibility code */
66#define nl_handle nl_sock
67#define nl80211_handle_alloc nl_socket_alloc_cb
68#define nl80211_handle_destroy nl_socket_free
69#else
70/*
71 * libnl 1.1 has a bug, it tries to allocate socket numbers densely
72 * but when you free a socket again it will mess up its bitmap and
73 * and use the wrong number the next time it needs a socket ID.
74 * Therefore, we wrap the handle alloc/destroy and add our own pid
75 * accounting.
76 */
77static uint32_t port_bitmap[32] = { 0 };
78
79static struct nl_handle *nl80211_handle_alloc(void *cb)
80{
81 struct nl_handle *handle;
82 uint32_t pid = getpid() & 0x3FFFFF;
83 int i;
84
85 handle = nl_handle_alloc_cb(cb);
86
87 for (i = 0; i < 1024; i++) {
88 if (port_bitmap[i / 32] & (1 << (i % 32)))
89 continue;
90 port_bitmap[i / 32] |= 1 << (i % 32);
91 pid += i << 22;
92 break;
93 }
94
95 nl_socket_set_local_port(handle, pid);
96
97 return handle;
98}
99
100static void nl80211_handle_destroy(struct nl_handle *handle)
101{
102 uint32_t port = nl_socket_get_local_port(handle);
103
104 port >>= 22;
105 port_bitmap[port / 32] &= ~(1 << (port % 32));
106
107 nl_handle_destroy(handle);
108}
109#endif /* CONFIG_LIBNL20 */
110
111
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800112static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
113{
114 struct nl_handle *handle;
115
116 handle = nl80211_handle_alloc(cb);
117 if (handle == NULL) {
118 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
119 "callbacks (%s)", dbg);
120 return NULL;
121 }
122
123 if (genl_connect(handle)) {
124 wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
125 "netlink (%s)", dbg);
126 nl80211_handle_destroy(handle);
127 return NULL;
128 }
129
130 return handle;
131}
132
133
134static void nl_destroy_handles(struct nl_handle **handle)
135{
136 if (*handle == NULL)
137 return;
138 nl80211_handle_destroy(*handle);
139 *handle = NULL;
140}
141
142
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700143#ifndef IFF_LOWER_UP
144#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
145#endif
146#ifndef IFF_DORMANT
147#define IFF_DORMANT 0x20000 /* driver signals dormant */
148#endif
149
150#ifndef IF_OPER_DORMANT
151#define IF_OPER_DORMANT 5
152#endif
153#ifndef IF_OPER_UP
154#define IF_OPER_UP 6
155#endif
156
157struct nl80211_global {
158 struct dl_list interfaces;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800159 int if_add_ifindex;
160 struct netlink_data *netlink;
161 struct nl_cb *nl_cb;
162 struct nl_handle *nl;
163 int nl80211_id;
164 int ioctl_sock; /* socket for ioctl() use */
165
166 struct nl_handle *nl_event;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700167};
168
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800169struct nl80211_wiphy_data {
170 struct dl_list list;
171 struct dl_list bsss;
172 struct dl_list drvs;
173
174 struct nl_handle *nl_beacons;
175 struct nl_cb *nl_cb;
176
177 int wiphy_idx;
178};
179
180static void nl80211_global_deinit(void *priv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800181
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700182struct i802_bss {
183 struct wpa_driver_nl80211_data *drv;
184 struct i802_bss *next;
185 int ifindex;
186 char ifname[IFNAMSIZ + 1];
187 char brname[IFNAMSIZ];
188 unsigned int beacon_set:1;
189 unsigned int added_if_into_bridge:1;
190 unsigned int added_bridge:1;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700191 unsigned int in_deinit:1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800192
193 u8 addr[ETH_ALEN];
194
195 int freq;
196
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800197 void *ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800198 struct nl_handle *nl_preq, *nl_mgmt;
199 struct nl_cb *nl_cb;
200
201 struct nl80211_wiphy_data *wiphy_data;
202 struct dl_list wiphy_list;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700203};
204
205struct wpa_driver_nl80211_data {
206 struct nl80211_global *global;
207 struct dl_list list;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800208 struct dl_list wiphy_list;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700209 char phyname[32];
210 void *ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700211 int ifindex;
212 int if_removed;
213 int if_disabled;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800214 int ignore_if_down_event;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700215 struct rfkill_data *rfkill;
216 struct wpa_driver_capa capa;
217 int has_capability;
218
219 int operstate;
220
221 int scan_complete_events;
222
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223 struct nl_cb *nl_cb;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700224
225 u8 auth_bssid[ETH_ALEN];
226 u8 bssid[ETH_ALEN];
227 int associated;
228 u8 ssid[32];
229 size_t ssid_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800230 enum nl80211_iftype nlmode;
231 enum nl80211_iftype ap_scan_as_station;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700232 unsigned int assoc_freq;
233
234 int monitor_sock;
235 int monitor_ifidx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800236 int monitor_refcount;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700237
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800238 unsigned int disabled_11b_rates:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700239 unsigned int pending_remain_on_chan:1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800240 unsigned int in_interface_list:1;
241 unsigned int device_ap_sme:1;
242 unsigned int poll_command_supported:1;
243 unsigned int data_tx_status:1;
244 unsigned int scan_for_auth:1;
245 unsigned int retry_auth:1;
246 unsigned int use_monitor:1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800247 unsigned int ignore_next_local_disconnect:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700248
249 u64 remain_on_chan_cookie;
250 u64 send_action_cookie;
251
252 unsigned int last_mgmt_freq;
253
254 struct wpa_driver_scan_filter *filter_ssids;
255 size_t num_filter_ssids;
256
257 struct i802_bss first_bss;
258
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800259 int eapol_tx_sock;
260
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700261#ifdef HOSTAPD
262 int eapol_sock; /* socket for EAPOL frames */
263
264 int default_if_indices[16];
265 int *if_indices;
266 int num_if_indices;
267
268 int last_freq;
269 int last_freq_ht;
270#endif /* HOSTAPD */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800271
272 /* From failed authentication command */
273 int auth_freq;
274 u8 auth_bssid_[ETH_ALEN];
275 u8 auth_ssid[32];
276 size_t auth_ssid_len;
277 int auth_alg;
278 u8 *auth_ie;
279 size_t auth_ie_len;
280 u8 auth_wep_key[4][16];
281 size_t auth_wep_key_len[4];
282 int auth_wep_tx_keyidx;
283 int auth_local_state_change;
284 int auth_p2p;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700285};
286
287
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800288static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700289static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
290 void *timeout_ctx);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800291static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
292 enum nl80211_iftype nlmode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700293static int
294wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
295static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
296 const u8 *addr, int cmd, u16 reason_code,
297 int local_state_change);
298static void nl80211_remove_monitor_interface(
299 struct wpa_driver_nl80211_data *drv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800300static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700301 unsigned int freq, unsigned int wait,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800302 const u8 *buf, size_t buf_len, u64 *cookie,
303 int no_cck, int no_ack, int offchanok);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800304static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
305 int report);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800306#ifdef ANDROID
307static int android_pno_start(struct i802_bss *bss,
308 struct wpa_driver_scan_params *params);
309static int android_pno_stop(struct i802_bss *bss);
310#endif /* ANDROID */
311#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -0700312int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800313int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
Dmitry Shmidt6e933c12011-09-27 12:29:26 -0700314int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
315int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
316 const struct wpabuf *proberesp,
317 const struct wpabuf *assocresp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700318
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800319#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700320#ifdef HOSTAPD
321static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
322static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
323static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800324static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700325 enum wpa_driver_if_type type,
326 const char *ifname);
327#else /* HOSTAPD */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800328static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
329{
330}
331
332static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
333{
334}
335
336static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700337{
338 return 0;
339}
340#endif /* HOSTAPD */
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700341#ifdef ANDROID
342extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
343 size_t buf_len);
344#endif
345
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -0800346static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
347 struct hostapd_freq_params *freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
349 int ifindex, int disabled);
350
351static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800352static int wpa_driver_nl80211_authenticate_retry(
353 struct wpa_driver_nl80211_data *drv);
354
355
356static int is_ap_interface(enum nl80211_iftype nlmode)
357{
358 return (nlmode == NL80211_IFTYPE_AP ||
359 nlmode == NL80211_IFTYPE_P2P_GO);
360}
361
362
363static int is_sta_interface(enum nl80211_iftype nlmode)
364{
365 return (nlmode == NL80211_IFTYPE_STATION ||
366 nlmode == NL80211_IFTYPE_P2P_CLIENT);
367}
368
369
370static int is_p2p_interface(enum nl80211_iftype nlmode)
371{
372 return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
373 nlmode == NL80211_IFTYPE_P2P_GO);
374}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700375
376
Jouni Malinen87fd2792011-05-16 18:35:42 +0300377struct nl80211_bss_info_arg {
378 struct wpa_driver_nl80211_data *drv;
379 struct wpa_scan_results *res;
380 unsigned int assoc_freq;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800381 u8 assoc_bssid[ETH_ALEN];
Jouni Malinen87fd2792011-05-16 18:35:42 +0300382};
383
384static int bss_info_handler(struct nl_msg *msg, void *arg);
385
386
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700387/* nl80211 code */
388static int ack_handler(struct nl_msg *msg, void *arg)
389{
390 int *err = arg;
391 *err = 0;
392 return NL_STOP;
393}
394
395static int finish_handler(struct nl_msg *msg, void *arg)
396{
397 int *ret = arg;
398 *ret = 0;
399 return NL_SKIP;
400}
401
402static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
403 void *arg)
404{
405 int *ret = arg;
406 *ret = err->error;
407 return NL_SKIP;
408}
409
410
411static int no_seq_check(struct nl_msg *msg, void *arg)
412{
413 return NL_OK;
414}
415
416
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800417static int send_and_recv(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700418 struct nl_handle *nl_handle, struct nl_msg *msg,
419 int (*valid_handler)(struct nl_msg *, void *),
420 void *valid_data)
421{
422 struct nl_cb *cb;
423 int err = -ENOMEM;
424
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800425 cb = nl_cb_clone(global->nl_cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700426 if (!cb)
427 goto out;
428
429 err = nl_send_auto_complete(nl_handle, msg);
430 if (err < 0)
431 goto out;
432
433 err = 1;
434
435 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
436 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
437 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
438
439 if (valid_handler)
440 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
441 valid_handler, valid_data);
442
443 while (err > 0)
444 nl_recvmsgs(nl_handle, cb);
445 out:
446 nl_cb_put(cb);
447 nlmsg_free(msg);
448 return err;
449}
450
451
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800452static int send_and_recv_msgs_global(struct nl80211_global *global,
453 struct nl_msg *msg,
454 int (*valid_handler)(struct nl_msg *, void *),
455 void *valid_data)
456{
457 return send_and_recv(global, global->nl, msg, valid_handler,
458 valid_data);
459}
460
Dmitry Shmidt04949592012-07-19 12:16:46 -0700461
Jouni Malinen80da0422012-08-09 15:29:25 -0700462#ifndef ANDROID
463static
464#endif
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700465int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466 struct nl_msg *msg,
467 int (*valid_handler)(struct nl_msg *, void *),
468 void *valid_data)
469{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800470 return send_and_recv(drv->global, drv->global->nl, msg,
471 valid_handler, valid_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700472}
473
474
475struct family_data {
476 const char *group;
477 int id;
478};
479
480
481static int family_handler(struct nl_msg *msg, void *arg)
482{
483 struct family_data *res = arg;
484 struct nlattr *tb[CTRL_ATTR_MAX + 1];
485 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
486 struct nlattr *mcgrp;
487 int i;
488
489 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
490 genlmsg_attrlen(gnlh, 0), NULL);
491 if (!tb[CTRL_ATTR_MCAST_GROUPS])
492 return NL_SKIP;
493
494 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
495 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
496 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
497 nla_len(mcgrp), NULL);
498 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
499 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
500 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
501 res->group,
502 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
503 continue;
504 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
505 break;
506 };
507
508 return NL_SKIP;
509}
510
511
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800512static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700513 const char *family, const char *group)
514{
515 struct nl_msg *msg;
516 int ret = -1;
517 struct family_data res = { group, -ENOENT };
518
519 msg = nlmsg_alloc();
520 if (!msg)
521 return -ENOMEM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800522 genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700523 0, 0, CTRL_CMD_GETFAMILY, 0);
524 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
525
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800526 ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700527 msg = NULL;
528 if (ret == 0)
529 ret = res.id;
530
531nla_put_failure:
532 nlmsg_free(msg);
533 return ret;
534}
535
536
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800537static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
538 struct nl_msg *msg, int flags, uint8_t cmd)
539{
540 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
541 0, flags, cmd, 0);
542}
543
544
545struct wiphy_idx_data {
546 int wiphy_idx;
547};
548
549
550static int netdev_info_handler(struct nl_msg *msg, void *arg)
551{
552 struct nlattr *tb[NL80211_ATTR_MAX + 1];
553 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
554 struct wiphy_idx_data *info = arg;
555
556 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
557 genlmsg_attrlen(gnlh, 0), NULL);
558
559 if (tb[NL80211_ATTR_WIPHY])
560 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
561
562 return NL_SKIP;
563}
564
565
566static int nl80211_get_wiphy_index(struct i802_bss *bss)
567{
568 struct nl_msg *msg;
569 struct wiphy_idx_data data = {
570 .wiphy_idx = -1,
571 };
572
573 msg = nlmsg_alloc();
574 if (!msg)
575 return -1;
576
577 nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
578
579 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
580
581 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
582 return data.wiphy_idx;
583 msg = NULL;
584nla_put_failure:
585 nlmsg_free(msg);
586 return -1;
587}
588
589
590static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
591 struct nl80211_wiphy_data *w)
592{
593 struct nl_msg *msg;
594 int ret = -1;
595
596 msg = nlmsg_alloc();
597 if (!msg)
598 return -1;
599
600 nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
601
602 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
603
604 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
605 msg = NULL;
606 if (ret) {
607 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
608 "failed: ret=%d (%s)",
609 ret, strerror(-ret));
610 goto nla_put_failure;
611 }
612 ret = 0;
613nla_put_failure:
614 nlmsg_free(msg);
615 return ret;
616}
617
618
619static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
620{
621 struct nl80211_wiphy_data *w = eloop_ctx;
622
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800623 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800624
625 nl_recvmsgs(handle, w->nl_cb);
626}
627
628
629static int process_beacon_event(struct nl_msg *msg, void *arg)
630{
631 struct nl80211_wiphy_data *w = arg;
632 struct wpa_driver_nl80211_data *drv;
633 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
634 struct nlattr *tb[NL80211_ATTR_MAX + 1];
635 union wpa_event_data event;
636
637 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
638 genlmsg_attrlen(gnlh, 0), NULL);
639
640 if (gnlh->cmd != NL80211_CMD_FRAME) {
641 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
642 gnlh->cmd);
643 return NL_SKIP;
644 }
645
646 if (!tb[NL80211_ATTR_FRAME])
647 return NL_SKIP;
648
649 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
650 wiphy_list) {
651 os_memset(&event, 0, sizeof(event));
652 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
653 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
654 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
655 }
656
657 return NL_SKIP;
658}
659
660
661static struct nl80211_wiphy_data *
662nl80211_get_wiphy_data_ap(struct i802_bss *bss)
663{
664 static DEFINE_DL_LIST(nl80211_wiphys);
665 struct nl80211_wiphy_data *w;
666 int wiphy_idx, found = 0;
667 struct i802_bss *tmp_bss;
668
669 if (bss->wiphy_data != NULL)
670 return bss->wiphy_data;
671
672 wiphy_idx = nl80211_get_wiphy_index(bss);
673
674 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
675 if (w->wiphy_idx == wiphy_idx)
676 goto add;
677 }
678
679 /* alloc new one */
680 w = os_zalloc(sizeof(*w));
681 if (w == NULL)
682 return NULL;
683 w->wiphy_idx = wiphy_idx;
684 dl_list_init(&w->bsss);
685 dl_list_init(&w->drvs);
686
687 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
688 if (!w->nl_cb) {
689 os_free(w);
690 return NULL;
691 }
692 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
693 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
694 w);
695
696 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
697 "wiphy beacons");
698 if (w->nl_beacons == NULL) {
699 os_free(w);
700 return NULL;
701 }
702
703 if (nl80211_register_beacons(bss->drv, w)) {
704 nl_destroy_handles(&w->nl_beacons);
705 os_free(w);
706 return NULL;
707 }
708
709 eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
710 nl80211_recv_beacons, w, w->nl_beacons);
711
712 dl_list_add(&nl80211_wiphys, &w->list);
713
714add:
715 /* drv entry for this bss already there? */
716 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
717 if (tmp_bss->drv == bss->drv) {
718 found = 1;
719 break;
720 }
721 }
722 /* if not add it */
723 if (!found)
724 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
725
726 dl_list_add(&w->bsss, &bss->wiphy_list);
727 bss->wiphy_data = w;
728 return w;
729}
730
731
732static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
733{
734 struct nl80211_wiphy_data *w = bss->wiphy_data;
735 struct i802_bss *tmp_bss;
736 int found = 0;
737
738 if (w == NULL)
739 return;
740 bss->wiphy_data = NULL;
741 dl_list_del(&bss->wiphy_list);
742
743 /* still any for this drv present? */
744 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
745 if (tmp_bss->drv == bss->drv) {
746 found = 1;
747 break;
748 }
749 }
750 /* if not remove it */
751 if (!found)
752 dl_list_del(&bss->drv->wiphy_list);
753
754 if (!dl_list_empty(&w->bsss))
755 return;
756
757 eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
758
759 nl_cb_put(w->nl_cb);
760 nl_destroy_handles(&w->nl_beacons);
761 dl_list_del(&w->list);
762 os_free(w);
763}
764
765
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700766static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
767{
768 struct i802_bss *bss = priv;
769 struct wpa_driver_nl80211_data *drv = bss->drv;
770 if (!drv->associated)
771 return -1;
772 os_memcpy(bssid, drv->bssid, ETH_ALEN);
773 return 0;
774}
775
776
777static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
778{
779 struct i802_bss *bss = priv;
780 struct wpa_driver_nl80211_data *drv = bss->drv;
781 if (!drv->associated)
782 return -1;
783 os_memcpy(ssid, drv->ssid, drv->ssid_len);
784 return drv->ssid_len;
785}
786
787
788static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
789 char *buf, size_t len, int del)
790{
791 union wpa_event_data event;
792
793 os_memset(&event, 0, sizeof(event));
794 if (len > sizeof(event.interface_status.ifname))
795 len = sizeof(event.interface_status.ifname) - 1;
796 os_memcpy(event.interface_status.ifname, buf, len);
797 event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
798 EVENT_INTERFACE_ADDED;
799
800 wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
801 del ? "DEL" : "NEW",
802 event.interface_status.ifname,
803 del ? "removed" : "added");
804
805 if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700806 if (del) {
807 if (drv->if_removed) {
808 wpa_printf(MSG_DEBUG, "nl80211: if_removed "
809 "already set - ignore event");
810 return;
811 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700812 drv->if_removed = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700813 } else {
814 if (if_nametoindex(drv->first_bss.ifname) == 0) {
815 wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
816 "does not exist - ignore "
817 "RTM_NEWLINK",
818 drv->first_bss.ifname);
819 return;
820 }
821 if (!drv->if_removed) {
822 wpa_printf(MSG_DEBUG, "nl80211: if_removed "
823 "already cleared - ignore event");
824 return;
825 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700826 drv->if_removed = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700827 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700828 }
829
830 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
831}
832
833
834static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
835 u8 *buf, size_t len)
836{
837 int attrlen, rta_len;
838 struct rtattr *attr;
839
840 attrlen = len;
841 attr = (struct rtattr *) buf;
842
843 rta_len = RTA_ALIGN(sizeof(struct rtattr));
844 while (RTA_OK(attr, attrlen)) {
845 if (attr->rta_type == IFLA_IFNAME) {
846 if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
847 == 0)
848 return 1;
849 else
850 break;
851 }
852 attr = RTA_NEXT(attr, attrlen);
853 }
854
855 return 0;
856}
857
858
859static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
860 int ifindex, u8 *buf, size_t len)
861{
862 if (drv->ifindex == ifindex)
863 return 1;
864
865 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
866 drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
867 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
868 "interface");
869 wpa_driver_nl80211_finish_drv_init(drv);
870 return 1;
871 }
872
873 return 0;
874}
875
876
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800877static struct wpa_driver_nl80211_data *
878nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
879{
880 struct wpa_driver_nl80211_data *drv;
881 dl_list_for_each(drv, &global->interfaces,
882 struct wpa_driver_nl80211_data, list) {
883 if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
884 have_ifidx(drv, idx))
885 return drv;
886 }
887 return NULL;
888}
889
890
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700891static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
892 struct ifinfomsg *ifi,
893 u8 *buf, size_t len)
894{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800895 struct nl80211_global *global = ctx;
896 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700897 int attrlen, rta_len;
898 struct rtattr *attr;
899 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800900 char namebuf[IFNAMSIZ];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700901
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800902 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
903 if (!drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700904 wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
905 "ifindex %d", ifi->ifi_index);
906 return;
907 }
908
909 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
910 "(%s%s%s%s)",
911 drv->operstate, ifi->ifi_flags,
912 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
913 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
914 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
915 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
916
917 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800918 if (if_indextoname(ifi->ifi_index, namebuf) &&
919 linux_iface_up(drv->global->ioctl_sock,
920 drv->first_bss.ifname) > 0) {
921 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
922 "event since interface %s is up", namebuf);
923 return;
924 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700925 wpa_printf(MSG_DEBUG, "nl80211: Interface down");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800926 if (drv->ignore_if_down_event) {
927 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
928 "event generated by mode change");
929 drv->ignore_if_down_event = 0;
930 } else {
931 drv->if_disabled = 1;
932 wpa_supplicant_event(drv->ctx,
933 EVENT_INTERFACE_DISABLED, NULL);
934 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700935 }
936
937 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800938 if (if_indextoname(ifi->ifi_index, namebuf) &&
939 linux_iface_up(drv->global->ioctl_sock,
940 drv->first_bss.ifname) == 0) {
941 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
942 "event since interface %s is down",
943 namebuf);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700944 } else if (if_nametoindex(drv->first_bss.ifname) == 0) {
945 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
946 "event since interface %s does not exist",
947 drv->first_bss.ifname);
948 } else if (drv->if_removed) {
949 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
950 "event since interface %s is marked "
951 "removed", drv->first_bss.ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800952 } else {
953 wpa_printf(MSG_DEBUG, "nl80211: Interface up");
954 drv->if_disabled = 0;
955 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
956 NULL);
957 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700958 }
959
960 /*
961 * Some drivers send the association event before the operup event--in
962 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
963 * fails. This will hit us when wpa_supplicant does not need to do
964 * IEEE 802.1X authentication
965 */
966 if (drv->operstate == 1 &&
967 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
968 !(ifi->ifi_flags & IFF_RUNNING))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800969 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700970 -1, IF_OPER_UP);
971
972 attrlen = len;
973 attr = (struct rtattr *) buf;
974 rta_len = RTA_ALIGN(sizeof(struct rtattr));
975 while (RTA_OK(attr, attrlen)) {
976 if (attr->rta_type == IFLA_IFNAME) {
977 wpa_driver_nl80211_event_link(
978 drv,
979 ((char *) attr) + rta_len,
980 attr->rta_len - rta_len, 0);
981 } else if (attr->rta_type == IFLA_MASTER)
982 brid = nla_get_u32((struct nlattr *) attr);
983 attr = RTA_NEXT(attr, attrlen);
984 }
985
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700986 if (ifi->ifi_family == AF_BRIDGE && brid) {
987 /* device has been added to bridge */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700988 if_indextoname(brid, namebuf);
989 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
990 brid, namebuf);
991 add_ifidx(drv, brid);
992 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700993}
994
995
996static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
997 struct ifinfomsg *ifi,
998 u8 *buf, size_t len)
999{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001000 struct nl80211_global *global = ctx;
1001 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001002 int attrlen, rta_len;
1003 struct rtattr *attr;
1004 u32 brid = 0;
1005
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001006 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
1007 if (!drv) {
1008 wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
1009 "foreign ifindex %d", ifi->ifi_index);
1010 return;
1011 }
1012
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001013 attrlen = len;
1014 attr = (struct rtattr *) buf;
1015
1016 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1017 while (RTA_OK(attr, attrlen)) {
1018 if (attr->rta_type == IFLA_IFNAME) {
1019 wpa_driver_nl80211_event_link(
1020 drv,
1021 ((char *) attr) + rta_len,
1022 attr->rta_len - rta_len, 1);
1023 } else if (attr->rta_type == IFLA_MASTER)
1024 brid = nla_get_u32((struct nlattr *) attr);
1025 attr = RTA_NEXT(attr, attrlen);
1026 }
1027
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001028 if (ifi->ifi_family == AF_BRIDGE && brid) {
1029 /* device has been removed from bridge */
1030 char namebuf[IFNAMSIZ];
1031 if_indextoname(brid, namebuf);
1032 wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
1033 "%s", brid, namebuf);
1034 del_ifidx(drv, brid);
1035 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001036}
1037
1038
1039static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
1040 const u8 *frame, size_t len)
1041{
1042 const struct ieee80211_mgmt *mgmt;
1043 union wpa_event_data event;
1044
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001045 wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001046 mgmt = (const struct ieee80211_mgmt *) frame;
1047 if (len < 24 + sizeof(mgmt->u.auth)) {
1048 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
1049 "frame");
1050 return;
1051 }
1052
1053 os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
1054 os_memset(&event, 0, sizeof(event));
1055 os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
1056 event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001057 event.auth.auth_transaction =
1058 le_to_host16(mgmt->u.auth.auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001059 event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
1060 if (len > 24 + sizeof(mgmt->u.auth)) {
1061 event.auth.ies = mgmt->u.auth.variable;
1062 event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
1063 }
1064
1065 wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
1066}
1067
1068
Jouni Malinen87fd2792011-05-16 18:35:42 +03001069static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1070{
1071 struct nl_msg *msg;
1072 int ret;
1073 struct nl80211_bss_info_arg arg;
1074
1075 os_memset(&arg, 0, sizeof(arg));
1076 msg = nlmsg_alloc();
1077 if (!msg)
1078 goto nla_put_failure;
1079
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001080 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001081 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1082
1083 arg.drv = drv;
1084 ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
1085 msg = NULL;
1086 if (ret == 0) {
1087 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
1088 "associated BSS from scan results: %u MHz",
1089 arg.assoc_freq);
1090 return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
1091 }
1092 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1093 "(%s)", ret, strerror(-ret));
1094nla_put_failure:
1095 nlmsg_free(msg);
1096 return drv->assoc_freq;
1097}
1098
1099
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001100static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
1101 const u8 *frame, size_t len)
1102{
1103 const struct ieee80211_mgmt *mgmt;
1104 union wpa_event_data event;
1105 u16 status;
1106
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001107 wpa_printf(MSG_DEBUG, "nl80211: Associate event");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001108 mgmt = (const struct ieee80211_mgmt *) frame;
1109 if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
1110 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
1111 "frame");
1112 return;
1113 }
1114
1115 status = le_to_host16(mgmt->u.assoc_resp.status_code);
1116 if (status != WLAN_STATUS_SUCCESS) {
1117 os_memset(&event, 0, sizeof(event));
1118 event.assoc_reject.bssid = mgmt->bssid;
1119 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
1120 event.assoc_reject.resp_ies =
1121 (u8 *) mgmt->u.assoc_resp.variable;
1122 event.assoc_reject.resp_ies_len =
1123 len - 24 - sizeof(mgmt->u.assoc_resp);
1124 }
1125 event.assoc_reject.status_code = status;
1126
1127 wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
1128 return;
1129 }
1130
1131 drv->associated = 1;
1132 os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
1133
1134 os_memset(&event, 0, sizeof(event));
1135 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
1136 event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
1137 event.assoc_info.resp_ies_len =
1138 len - 24 - sizeof(mgmt->u.assoc_resp);
1139 }
1140
1141 event.assoc_info.freq = drv->assoc_freq;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001142
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001143 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
1144}
1145
1146
1147static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
1148 enum nl80211_commands cmd, struct nlattr *status,
1149 struct nlattr *addr, struct nlattr *req_ie,
1150 struct nlattr *resp_ie)
1151{
1152 union wpa_event_data event;
1153
1154 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
1155 /*
1156 * Avoid reporting two association events that would confuse
1157 * the core code.
1158 */
1159 wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
1160 "when using userspace SME", cmd);
1161 return;
1162 }
1163
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001164 if (cmd == NL80211_CMD_CONNECT)
1165 wpa_printf(MSG_DEBUG, "nl80211: Connect event");
1166 else if (cmd == NL80211_CMD_ROAM)
1167 wpa_printf(MSG_DEBUG, "nl80211: Roam event");
1168
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001169 os_memset(&event, 0, sizeof(event));
1170 if (cmd == NL80211_CMD_CONNECT &&
1171 nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
1172 if (addr)
1173 event.assoc_reject.bssid = nla_data(addr);
1174 if (resp_ie) {
1175 event.assoc_reject.resp_ies = nla_data(resp_ie);
1176 event.assoc_reject.resp_ies_len = nla_len(resp_ie);
1177 }
1178 event.assoc_reject.status_code = nla_get_u16(status);
1179 wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
1180 return;
1181 }
1182
1183 drv->associated = 1;
1184 if (addr)
1185 os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
1186
1187 if (req_ie) {
1188 event.assoc_info.req_ies = nla_data(req_ie);
1189 event.assoc_info.req_ies_len = nla_len(req_ie);
1190 }
1191 if (resp_ie) {
1192 event.assoc_info.resp_ies = nla_data(resp_ie);
1193 event.assoc_info.resp_ies_len = nla_len(resp_ie);
1194 }
1195
Jouni Malinen87fd2792011-05-16 18:35:42 +03001196 event.assoc_info.freq = nl80211_get_assoc_freq(drv);
1197
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001198 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
1199}
1200
1201
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001202static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001203 struct nlattr *reason, struct nlattr *addr,
1204 struct nlattr *by_ap)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001205{
1206 union wpa_event_data data;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001207 unsigned int locally_generated = by_ap == NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001208
1209 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
1210 /*
1211 * Avoid reporting two disassociation events that could
1212 * confuse the core code.
1213 */
1214 wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
1215 "event when using userspace SME");
1216 return;
1217 }
1218
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001219 if (drv->ignore_next_local_disconnect) {
1220 drv->ignore_next_local_disconnect = 0;
1221 if (locally_generated) {
1222 wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
1223 "event triggered during reassociation");
1224 return;
1225 }
1226 wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
1227 "disconnect but got another disconnect "
1228 "event first");
1229 }
1230
1231 wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001232 drv->associated = 0;
1233 os_memset(&data, 0, sizeof(data));
1234 if (reason)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001235 data.deauth_info.reason_code = nla_get_u16(reason);
1236 data.deauth_info.locally_generated = by_ap == NULL;
1237 wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
1238}
1239
1240
1241static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
1242 struct nlattr *freq, struct nlattr *type)
1243{
1244 union wpa_event_data data;
1245 int ht_enabled = 1;
1246 int chan_offset = 0;
1247
1248 wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
1249
1250 if (!freq || !type)
1251 return;
1252
1253 switch (nla_get_u32(type)) {
1254 case NL80211_CHAN_NO_HT:
1255 ht_enabled = 0;
1256 break;
1257 case NL80211_CHAN_HT20:
1258 break;
1259 case NL80211_CHAN_HT40PLUS:
1260 chan_offset = 1;
1261 break;
1262 case NL80211_CHAN_HT40MINUS:
1263 chan_offset = -1;
1264 break;
1265 }
1266
1267 data.ch_switch.freq = nla_get_u32(freq);
1268 data.ch_switch.ht_enabled = ht_enabled;
1269 data.ch_switch.ch_offset = chan_offset;
1270
1271 wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001272}
1273
1274
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001275static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
1276 enum nl80211_commands cmd, struct nlattr *addr)
1277{
1278 union wpa_event_data event;
1279 enum wpa_event_type ev;
1280
1281 if (nla_len(addr) != ETH_ALEN)
1282 return;
1283
1284 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
1285 cmd, MAC2STR((u8 *) nla_data(addr)));
1286
1287 if (cmd == NL80211_CMD_AUTHENTICATE)
1288 ev = EVENT_AUTH_TIMED_OUT;
1289 else if (cmd == NL80211_CMD_ASSOCIATE)
1290 ev = EVENT_ASSOC_TIMED_OUT;
1291 else
1292 return;
1293
1294 os_memset(&event, 0, sizeof(event));
1295 os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
1296 wpa_supplicant_event(drv->ctx, ev, &event);
1297}
1298
1299
1300static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001301 struct nlattr *freq, struct nlattr *sig,
1302 const u8 *frame, size_t len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001303{
1304 const struct ieee80211_mgmt *mgmt;
1305 union wpa_event_data event;
1306 u16 fc, stype;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001307 int ssi_signal = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001308
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001309 wpa_printf(MSG_DEBUG, "nl80211: Frame event");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001310 mgmt = (const struct ieee80211_mgmt *) frame;
1311 if (len < 24) {
1312 wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
1313 return;
1314 }
1315
1316 fc = le_to_host16(mgmt->frame_control);
1317 stype = WLAN_FC_GET_STYPE(fc);
1318
Dmitry Shmidt04949592012-07-19 12:16:46 -07001319 if (sig)
1320 ssi_signal = (s32) nla_get_u32(sig);
1321
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001322 os_memset(&event, 0, sizeof(event));
1323 if (freq) {
1324 event.rx_action.freq = nla_get_u32(freq);
1325 drv->last_mgmt_freq = event.rx_action.freq;
1326 }
1327 if (stype == WLAN_FC_STYPE_ACTION) {
1328 event.rx_action.da = mgmt->da;
1329 event.rx_action.sa = mgmt->sa;
1330 event.rx_action.bssid = mgmt->bssid;
1331 event.rx_action.category = mgmt->u.action.category;
1332 event.rx_action.data = &mgmt->u.action.category + 1;
1333 event.rx_action.len = frame + len - event.rx_action.data;
1334 wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
1335 } else {
1336 event.rx_mgmt.frame = frame;
1337 event.rx_mgmt.frame_len = len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001338 event.rx_mgmt.ssi_signal = ssi_signal;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001339 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
1340 }
1341}
1342
1343
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001344static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
1345 struct nlattr *cookie, const u8 *frame,
1346 size_t len, struct nlattr *ack)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001347{
1348 union wpa_event_data event;
1349 const struct ieee80211_hdr *hdr;
1350 u16 fc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001351
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001352 wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001353 if (!is_ap_interface(drv->nlmode)) {
1354 u64 cookie_val;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001355
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001356 if (!cookie)
1357 return;
1358
1359 cookie_val = nla_get_u64(cookie);
1360 wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
1361 " cookie=0%llx%s (ack=%d)",
1362 (long long unsigned int) cookie_val,
1363 cookie_val == drv->send_action_cookie ?
1364 " (match)" : " (unknown)", ack != NULL);
1365 if (cookie_val != drv->send_action_cookie)
1366 return;
1367 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001368
1369 hdr = (const struct ieee80211_hdr *) frame;
1370 fc = le_to_host16(hdr->frame_control);
1371
1372 os_memset(&event, 0, sizeof(event));
1373 event.tx_status.type = WLAN_FC_GET_TYPE(fc);
1374 event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
1375 event.tx_status.dst = hdr->addr1;
1376 event.tx_status.data = frame;
1377 event.tx_status.data_len = len;
1378 event.tx_status.ack = ack != NULL;
1379 wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
1380}
1381
1382
1383static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
1384 enum wpa_event_type type,
1385 const u8 *frame, size_t len)
1386{
1387 const struct ieee80211_mgmt *mgmt;
1388 union wpa_event_data event;
1389 const u8 *bssid = NULL;
1390 u16 reason_code = 0;
1391
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001392 if (type == EVENT_DEAUTH)
1393 wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
1394 else
1395 wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
1396
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001397 mgmt = (const struct ieee80211_mgmt *) frame;
1398 if (len >= 24) {
1399 bssid = mgmt->bssid;
1400
1401 if (drv->associated != 0 &&
1402 os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
1403 os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
1404 /*
1405 * We have presumably received this deauth as a
1406 * response to a clear_state_mismatch() outgoing
1407 * deauth. Don't let it take us offline!
1408 */
1409 wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
1410 "from Unknown BSSID " MACSTR " -- ignoring",
1411 MAC2STR(bssid));
1412 return;
1413 }
1414 }
1415
1416 drv->associated = 0;
1417 os_memset(&event, 0, sizeof(event));
1418
1419 /* Note: Same offset for Reason Code in both frame subtypes */
1420 if (len >= 24 + sizeof(mgmt->u.deauth))
1421 reason_code = le_to_host16(mgmt->u.deauth.reason_code);
1422
1423 if (type == EVENT_DISASSOC) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001424 event.disassoc_info.locally_generated =
1425 !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001426 event.disassoc_info.addr = bssid;
1427 event.disassoc_info.reason_code = reason_code;
1428 if (frame + len > mgmt->u.disassoc.variable) {
1429 event.disassoc_info.ie = mgmt->u.disassoc.variable;
1430 event.disassoc_info.ie_len = frame + len -
1431 mgmt->u.disassoc.variable;
1432 }
1433 } else {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001434 event.deauth_info.locally_generated =
1435 !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001436 event.deauth_info.addr = bssid;
1437 event.deauth_info.reason_code = reason_code;
1438 if (frame + len > mgmt->u.deauth.variable) {
1439 event.deauth_info.ie = mgmt->u.deauth.variable;
1440 event.deauth_info.ie_len = frame + len -
1441 mgmt->u.deauth.variable;
1442 }
1443 }
1444
1445 wpa_supplicant_event(drv->ctx, type, &event);
1446}
1447
1448
1449static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
1450 enum wpa_event_type type,
1451 const u8 *frame, size_t len)
1452{
1453 const struct ieee80211_mgmt *mgmt;
1454 union wpa_event_data event;
1455 u16 reason_code = 0;
1456
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001457 if (type == EVENT_UNPROT_DEAUTH)
1458 wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
1459 else
1460 wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
1461
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001462 if (len < 24)
1463 return;
1464
1465 mgmt = (const struct ieee80211_mgmt *) frame;
1466
1467 os_memset(&event, 0, sizeof(event));
1468 /* Note: Same offset for Reason Code in both frame subtypes */
1469 if (len >= 24 + sizeof(mgmt->u.deauth))
1470 reason_code = le_to_host16(mgmt->u.deauth.reason_code);
1471
1472 if (type == EVENT_UNPROT_DISASSOC) {
1473 event.unprot_disassoc.sa = mgmt->sa;
1474 event.unprot_disassoc.da = mgmt->da;
1475 event.unprot_disassoc.reason_code = reason_code;
1476 } else {
1477 event.unprot_deauth.sa = mgmt->sa;
1478 event.unprot_deauth.da = mgmt->da;
1479 event.unprot_deauth.reason_code = reason_code;
1480 }
1481
1482 wpa_supplicant_event(drv->ctx, type, &event);
1483}
1484
1485
1486static void mlme_event(struct wpa_driver_nl80211_data *drv,
1487 enum nl80211_commands cmd, struct nlattr *frame,
1488 struct nlattr *addr, struct nlattr *timed_out,
1489 struct nlattr *freq, struct nlattr *ack,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001490 struct nlattr *cookie, struct nlattr *sig)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001491{
1492 if (timed_out && addr) {
1493 mlme_timeout_event(drv, cmd, addr);
1494 return;
1495 }
1496
1497 if (frame == NULL) {
1498 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
1499 "data", cmd);
1500 return;
1501 }
1502
1503 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
1504 wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
1505 nla_data(frame), nla_len(frame));
1506
1507 switch (cmd) {
1508 case NL80211_CMD_AUTHENTICATE:
1509 mlme_event_auth(drv, nla_data(frame), nla_len(frame));
1510 break;
1511 case NL80211_CMD_ASSOCIATE:
1512 mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
1513 break;
1514 case NL80211_CMD_DEAUTHENTICATE:
1515 mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
1516 nla_data(frame), nla_len(frame));
1517 break;
1518 case NL80211_CMD_DISASSOCIATE:
1519 mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
1520 nla_data(frame), nla_len(frame));
1521 break;
1522 case NL80211_CMD_FRAME:
Dmitry Shmidt04949592012-07-19 12:16:46 -07001523 mlme_event_mgmt(drv, freq, sig, nla_data(frame),
1524 nla_len(frame));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001525 break;
1526 case NL80211_CMD_FRAME_TX_STATUS:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001527 mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
1528 nla_len(frame), ack);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001529 break;
1530 case NL80211_CMD_UNPROT_DEAUTHENTICATE:
1531 mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
1532 nla_data(frame), nla_len(frame));
1533 break;
1534 case NL80211_CMD_UNPROT_DISASSOCIATE:
1535 mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
1536 nla_data(frame), nla_len(frame));
1537 break;
1538 default:
1539 break;
1540 }
1541}
1542
1543
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001544static void mlme_event_michael_mic_failure(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001545 struct nlattr *tb[])
1546{
1547 union wpa_event_data data;
1548
1549 wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
1550 os_memset(&data, 0, sizeof(data));
1551 if (tb[NL80211_ATTR_MAC]) {
1552 wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
1553 nla_data(tb[NL80211_ATTR_MAC]),
1554 nla_len(tb[NL80211_ATTR_MAC]));
1555 data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
1556 }
1557 if (tb[NL80211_ATTR_KEY_SEQ]) {
1558 wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
1559 nla_data(tb[NL80211_ATTR_KEY_SEQ]),
1560 nla_len(tb[NL80211_ATTR_KEY_SEQ]));
1561 }
1562 if (tb[NL80211_ATTR_KEY_TYPE]) {
1563 enum nl80211_key_type key_type =
1564 nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
1565 wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
1566 if (key_type == NL80211_KEYTYPE_PAIRWISE)
1567 data.michael_mic_failure.unicast = 1;
1568 } else
1569 data.michael_mic_failure.unicast = 1;
1570
1571 if (tb[NL80211_ATTR_KEY_IDX]) {
1572 u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
1573 wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
1574 }
1575
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001576 wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001577}
1578
1579
1580static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
1581 struct nlattr *tb[])
1582{
1583 if (tb[NL80211_ATTR_MAC] == NULL) {
1584 wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
1585 "event");
1586 return;
1587 }
1588 os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
1589 drv->associated = 1;
1590 wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
1591 MAC2STR(drv->bssid));
1592
1593 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1594}
1595
1596
1597static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
1598 int cancel_event, struct nlattr *tb[])
1599{
1600 unsigned int freq, chan_type, duration;
1601 union wpa_event_data data;
1602 u64 cookie;
1603
1604 if (tb[NL80211_ATTR_WIPHY_FREQ])
1605 freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1606 else
1607 freq = 0;
1608
1609 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
1610 chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1611 else
1612 chan_type = 0;
1613
1614 if (tb[NL80211_ATTR_DURATION])
1615 duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
1616 else
1617 duration = 0;
1618
1619 if (tb[NL80211_ATTR_COOKIE])
1620 cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
1621 else
1622 cookie = 0;
1623
1624 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
1625 "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
1626 cancel_event, freq, chan_type, duration,
1627 (long long unsigned int) cookie,
1628 cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
1629
1630 if (cookie != drv->remain_on_chan_cookie)
1631 return; /* not for us */
1632
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001633 if (cancel_event)
1634 drv->pending_remain_on_chan = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001635
1636 os_memset(&data, 0, sizeof(data));
1637 data.remain_on_channel.freq = freq;
1638 data.remain_on_channel.duration = duration;
1639 wpa_supplicant_event(drv->ctx, cancel_event ?
1640 EVENT_CANCEL_REMAIN_ON_CHANNEL :
1641 EVENT_REMAIN_ON_CHANNEL, &data);
1642}
1643
1644
1645static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
1646 struct nlattr *tb[])
1647{
1648 union wpa_event_data event;
1649 struct nlattr *nl;
1650 int rem;
1651 struct scan_info *info;
1652#define MAX_REPORT_FREQS 50
1653 int freqs[MAX_REPORT_FREQS];
1654 int num_freqs = 0;
1655
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001656 if (drv->scan_for_auth) {
1657 drv->scan_for_auth = 0;
1658 wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
1659 "cfg80211 BSS entry");
1660 wpa_driver_nl80211_authenticate_retry(drv);
1661 return;
1662 }
1663
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001664 os_memset(&event, 0, sizeof(event));
1665 info = &event.scan_info;
1666 info->aborted = aborted;
1667
1668 if (tb[NL80211_ATTR_SCAN_SSIDS]) {
1669 nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
1670 struct wpa_driver_scan_ssid *s =
1671 &info->ssids[info->num_ssids];
1672 s->ssid = nla_data(nl);
1673 s->ssid_len = nla_len(nl);
1674 info->num_ssids++;
1675 if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
1676 break;
1677 }
1678 }
1679 if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
1680 nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
1681 {
1682 freqs[num_freqs] = nla_get_u32(nl);
1683 num_freqs++;
1684 if (num_freqs == MAX_REPORT_FREQS - 1)
1685 break;
1686 }
1687 info->freqs = freqs;
1688 info->num_freqs = num_freqs;
1689 }
1690 wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
1691}
1692
1693
1694static int get_link_signal(struct nl_msg *msg, void *arg)
1695{
1696 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1697 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1698 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1699 static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
1700 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
1701 };
1702 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1703 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1704 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1705 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1706 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1707 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1708 };
1709 struct wpa_signal_info *sig_change = arg;
1710
1711 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1712 genlmsg_attrlen(gnlh, 0), NULL);
1713 if (!tb[NL80211_ATTR_STA_INFO] ||
1714 nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1715 tb[NL80211_ATTR_STA_INFO], policy))
1716 return NL_SKIP;
1717 if (!sinfo[NL80211_STA_INFO_SIGNAL])
1718 return NL_SKIP;
1719
1720 sig_change->current_signal =
1721 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1722
1723 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
1724 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1725 sinfo[NL80211_STA_INFO_TX_BITRATE],
1726 rate_policy)) {
1727 sig_change->current_txrate = 0;
1728 } else {
1729 if (rinfo[NL80211_RATE_INFO_BITRATE]) {
1730 sig_change->current_txrate =
1731 nla_get_u16(rinfo[
1732 NL80211_RATE_INFO_BITRATE]) * 100;
1733 }
1734 }
1735 }
1736
1737 return NL_SKIP;
1738}
1739
1740
1741static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
1742 struct wpa_signal_info *sig)
1743{
1744 struct nl_msg *msg;
1745
1746 sig->current_signal = -9999;
1747 sig->current_txrate = 0;
1748
1749 msg = nlmsg_alloc();
1750 if (!msg)
1751 return -ENOMEM;
1752
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001753 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001754
1755 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1756 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
1757
1758 return send_and_recv_msgs(drv, msg, get_link_signal, sig);
1759 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001760 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001761 return -ENOBUFS;
1762}
1763
1764
1765static int get_link_noise(struct nl_msg *msg, void *arg)
1766{
1767 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1768 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1769 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1770 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1771 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1772 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1773 };
1774 struct wpa_signal_info *sig_change = arg;
1775
1776 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1777 genlmsg_attrlen(gnlh, 0), NULL);
1778
1779 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1780 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1781 return NL_SKIP;
1782 }
1783
1784 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1785 tb[NL80211_ATTR_SURVEY_INFO],
1786 survey_policy)) {
1787 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1788 "attributes!");
1789 return NL_SKIP;
1790 }
1791
1792 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1793 return NL_SKIP;
1794
1795 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1796 sig_change->frequency)
1797 return NL_SKIP;
1798
1799 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1800 return NL_SKIP;
1801
1802 sig_change->current_noise =
1803 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1804
1805 return NL_SKIP;
1806}
1807
1808
1809static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1810 struct wpa_signal_info *sig_change)
1811{
1812 struct nl_msg *msg;
1813
1814 sig_change->current_noise = 9999;
1815 sig_change->frequency = drv->assoc_freq;
1816
1817 msg = nlmsg_alloc();
1818 if (!msg)
1819 return -ENOMEM;
1820
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001821 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001822
1823 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1824
1825 return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
1826 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001827 nlmsg_free(msg);
1828 return -ENOBUFS;
1829}
1830
1831
1832static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
1833{
1834 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1835 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1836 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1837 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1838 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1839 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1840 };
1841 struct wpa_scan_results *scan_results = arg;
1842 struct wpa_scan_res *scan_res;
1843 size_t i;
1844
1845 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1846 genlmsg_attrlen(gnlh, 0), NULL);
1847
1848 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1849 wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
1850 return NL_SKIP;
1851 }
1852
1853 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1854 tb[NL80211_ATTR_SURVEY_INFO],
1855 survey_policy)) {
1856 wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
1857 "attributes");
1858 return NL_SKIP;
1859 }
1860
1861 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1862 return NL_SKIP;
1863
1864 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1865 return NL_SKIP;
1866
1867 for (i = 0; i < scan_results->num; ++i) {
1868 scan_res = scan_results->res[i];
1869 if (!scan_res)
1870 continue;
1871 if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1872 scan_res->freq)
1873 continue;
1874 if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
1875 continue;
1876 scan_res->noise = (s8)
1877 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1878 scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
1879 }
1880
1881 return NL_SKIP;
1882}
1883
1884
1885static int nl80211_get_noise_for_scan_results(
1886 struct wpa_driver_nl80211_data *drv,
1887 struct wpa_scan_results *scan_res)
1888{
1889 struct nl_msg *msg;
1890
1891 msg = nlmsg_alloc();
1892 if (!msg)
1893 return -ENOMEM;
1894
1895 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
1896
1897 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1898
1899 return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
1900 scan_res);
1901 nla_put_failure:
1902 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001903 return -ENOBUFS;
1904}
1905
1906
1907static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
1908 struct nlattr *tb[])
1909{
1910 static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
1911 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
1912 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
1913 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
1914 [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
1915 };
1916 struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
1917 enum nl80211_cqm_rssi_threshold_event event;
1918 union wpa_event_data ed;
1919 struct wpa_signal_info sig;
1920 int res;
1921
1922 if (tb[NL80211_ATTR_CQM] == NULL ||
1923 nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
1924 cqm_policy)) {
1925 wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
1926 return;
1927 }
1928
1929 os_memset(&ed, 0, sizeof(ed));
1930
1931 if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
1932 if (!tb[NL80211_ATTR_MAC])
1933 return;
1934 os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
1935 ETH_ALEN);
1936 wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
1937 return;
1938 }
1939
1940 if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
1941 return;
1942 event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
1943
1944 if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
1945 wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
1946 "event: RSSI high");
1947 ed.signal_change.above_threshold = 1;
1948 } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
1949 wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
1950 "event: RSSI low");
1951 ed.signal_change.above_threshold = 0;
1952 } else
1953 return;
1954
1955 res = nl80211_get_link_signal(drv, &sig);
1956 if (res == 0) {
1957 ed.signal_change.current_signal = sig.current_signal;
1958 ed.signal_change.current_txrate = sig.current_txrate;
1959 wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
1960 sig.current_signal, sig.current_txrate);
1961 }
1962
1963 res = nl80211_get_link_noise(drv, &sig);
1964 if (res == 0) {
1965 ed.signal_change.current_noise = sig.current_noise;
1966 wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
1967 sig.current_noise);
1968 }
1969
1970 wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
1971}
1972
1973
1974static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
1975 struct nlattr **tb)
1976{
1977 u8 *addr;
1978 union wpa_event_data data;
1979
1980 if (tb[NL80211_ATTR_MAC] == NULL)
1981 return;
1982 addr = nla_data(tb[NL80211_ATTR_MAC]);
1983 wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001984
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001985 if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001986 u8 *ies = NULL;
1987 size_t ies_len = 0;
1988 if (tb[NL80211_ATTR_IE]) {
1989 ies = nla_data(tb[NL80211_ATTR_IE]);
1990 ies_len = nla_len(tb[NL80211_ATTR_IE]);
1991 }
1992 wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
1993 drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
1994 return;
1995 }
1996
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001997 if (drv->nlmode != NL80211_IFTYPE_ADHOC)
1998 return;
1999
2000 os_memset(&data, 0, sizeof(data));
2001 os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
2002 wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
2003}
2004
2005
2006static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
2007 struct nlattr **tb)
2008{
2009 u8 *addr;
2010 union wpa_event_data data;
2011
2012 if (tb[NL80211_ATTR_MAC] == NULL)
2013 return;
2014 addr = nla_data(tb[NL80211_ATTR_MAC]);
2015 wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
2016 MAC2STR(addr));
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002017
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002018 if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002019 drv_event_disassoc(drv->ctx, addr);
2020 return;
2021 }
2022
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002023 if (drv->nlmode != NL80211_IFTYPE_ADHOC)
2024 return;
2025
2026 os_memset(&data, 0, sizeof(data));
2027 os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
2028 wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
2029}
2030
2031
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002032static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
2033 struct nlattr **tb)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002034{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002035 struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
2036 static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
2037 [NL80211_REKEY_DATA_KEK] = {
2038 .minlen = NL80211_KEK_LEN,
2039 .maxlen = NL80211_KEK_LEN,
2040 },
2041 [NL80211_REKEY_DATA_KCK] = {
2042 .minlen = NL80211_KCK_LEN,
2043 .maxlen = NL80211_KCK_LEN,
2044 },
2045 [NL80211_REKEY_DATA_REPLAY_CTR] = {
2046 .minlen = NL80211_REPLAY_CTR_LEN,
2047 .maxlen = NL80211_REPLAY_CTR_LEN,
2048 },
2049 };
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002050 union wpa_event_data data;
2051
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002052 if (!tb[NL80211_ATTR_MAC])
2053 return;
2054 if (!tb[NL80211_ATTR_REKEY_DATA])
2055 return;
2056 if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
2057 tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
2058 return;
2059 if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
2060 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002061
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002062 os_memset(&data, 0, sizeof(data));
2063 data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
2064 wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
2065 MAC2STR(data.driver_gtk_rekey.bssid));
2066 data.driver_gtk_rekey.replay_ctr =
2067 nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
2068 wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
2069 data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
2070 wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
2071}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002072
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002073
2074static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
2075 struct nlattr **tb)
2076{
2077 struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
2078 static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
2079 [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
2080 [NL80211_PMKSA_CANDIDATE_BSSID] = {
2081 .minlen = ETH_ALEN,
2082 .maxlen = ETH_ALEN,
2083 },
2084 [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
2085 };
2086 union wpa_event_data data;
2087
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002088 wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
2089
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002090 if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
2091 return;
2092 if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
2093 tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
2094 return;
2095 if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
2096 !cand[NL80211_PMKSA_CANDIDATE_BSSID])
2097 return;
2098
2099 os_memset(&data, 0, sizeof(data));
2100 os_memcpy(data.pmkid_candidate.bssid,
2101 nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
2102 data.pmkid_candidate.index =
2103 nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
2104 data.pmkid_candidate.preauth =
2105 cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
2106 wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
2107}
2108
2109
2110static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
2111 struct nlattr **tb)
2112{
2113 union wpa_event_data data;
2114
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002115 wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
2116
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002117 if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
2118 return;
2119
2120 os_memset(&data, 0, sizeof(data));
2121 os_memcpy(data.client_poll.addr,
2122 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
2123
2124 wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
2125}
2126
2127
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002128static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
2129 struct nlattr **tb)
2130{
2131 union wpa_event_data data;
2132
2133 wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
2134
2135 if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
2136 return;
2137
2138 os_memset(&data, 0, sizeof(data));
2139 os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
2140 switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
2141 case NL80211_TDLS_SETUP:
2142 wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
2143 MACSTR, MAC2STR(data.tdls.peer));
2144 data.tdls.oper = TDLS_REQUEST_SETUP;
2145 break;
2146 case NL80211_TDLS_TEARDOWN:
2147 wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
2148 MACSTR, MAC2STR(data.tdls.peer));
2149 data.tdls.oper = TDLS_REQUEST_TEARDOWN;
2150 break;
2151 default:
2152 wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
2153 "event");
2154 return;
2155 }
2156 if (tb[NL80211_ATTR_REASON_CODE]) {
2157 data.tdls.reason_code =
2158 nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
2159 }
2160
2161 wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
2162}
2163
2164
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002165static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
2166 int wds)
2167{
2168 struct wpa_driver_nl80211_data *drv = bss->drv;
2169 union wpa_event_data event;
2170
2171 if (!tb[NL80211_ATTR_MAC])
2172 return;
2173
2174 os_memset(&event, 0, sizeof(event));
2175 event.rx_from_unknown.bssid = bss->addr;
2176 event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
2177 event.rx_from_unknown.wds = wds;
2178
2179 wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
2180}
2181
2182
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002183static void do_process_drv_event(struct i802_bss *bss, int cmd,
2184 struct nlattr **tb)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002185{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002186 struct wpa_driver_nl80211_data *drv = bss->drv;
2187
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002188 if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
2189 (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
2190 cmd == NL80211_CMD_SCAN_ABORTED)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002191 wpa_driver_nl80211_set_mode(&drv->first_bss,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002192 drv->ap_scan_as_station);
2193 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002194 }
2195
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002196 switch (cmd) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002197 case NL80211_CMD_TRIGGER_SCAN:
2198 wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
2199 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002200 case NL80211_CMD_START_SCHED_SCAN:
2201 wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
2202 break;
2203 case NL80211_CMD_SCHED_SCAN_STOPPED:
2204 wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
2205 wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
2206 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002207 case NL80211_CMD_NEW_SCAN_RESULTS:
2208 wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
2209 drv->scan_complete_events = 1;
2210 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
2211 drv->ctx);
2212 send_scan_event(drv, 0, tb);
2213 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002214 case NL80211_CMD_SCHED_SCAN_RESULTS:
2215 wpa_printf(MSG_DEBUG,
2216 "nl80211: New sched scan results available");
2217 send_scan_event(drv, 0, tb);
2218 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002219 case NL80211_CMD_SCAN_ABORTED:
2220 wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
2221 /*
2222 * Need to indicate that scan results are available in order
2223 * not to make wpa_supplicant stop its scanning.
2224 */
2225 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
2226 drv->ctx);
2227 send_scan_event(drv, 1, tb);
2228 break;
2229 case NL80211_CMD_AUTHENTICATE:
2230 case NL80211_CMD_ASSOCIATE:
2231 case NL80211_CMD_DEAUTHENTICATE:
2232 case NL80211_CMD_DISASSOCIATE:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002233 case NL80211_CMD_FRAME_TX_STATUS:
2234 case NL80211_CMD_UNPROT_DEAUTHENTICATE:
2235 case NL80211_CMD_UNPROT_DISASSOCIATE:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002236 mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002237 tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
2238 tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
Dmitry Shmidt04949592012-07-19 12:16:46 -07002239 tb[NL80211_ATTR_COOKIE],
2240 tb[NL80211_ATTR_RX_SIGNAL_DBM]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002241 break;
2242 case NL80211_CMD_CONNECT:
2243 case NL80211_CMD_ROAM:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002244 mlme_event_connect(drv, cmd,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002245 tb[NL80211_ATTR_STATUS_CODE],
2246 tb[NL80211_ATTR_MAC],
2247 tb[NL80211_ATTR_REQ_IE],
2248 tb[NL80211_ATTR_RESP_IE]);
2249 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002250 case NL80211_CMD_CH_SWITCH_NOTIFY:
2251 mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
2252 tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2253 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002254 case NL80211_CMD_DISCONNECT:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002255 mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002256 tb[NL80211_ATTR_MAC],
2257 tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002258 break;
2259 case NL80211_CMD_MICHAEL_MIC_FAILURE:
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002260 mlme_event_michael_mic_failure(bss, tb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002261 break;
2262 case NL80211_CMD_JOIN_IBSS:
2263 mlme_event_join_ibss(drv, tb);
2264 break;
2265 case NL80211_CMD_REMAIN_ON_CHANNEL:
2266 mlme_event_remain_on_channel(drv, 0, tb);
2267 break;
2268 case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
2269 mlme_event_remain_on_channel(drv, 1, tb);
2270 break;
2271 case NL80211_CMD_NOTIFY_CQM:
2272 nl80211_cqm_event(drv, tb);
2273 break;
2274 case NL80211_CMD_REG_CHANGE:
2275 wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
2276 wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
2277 NULL);
2278 break;
2279 case NL80211_CMD_REG_BEACON_HINT:
2280 wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
2281 wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
2282 NULL);
2283 break;
2284 case NL80211_CMD_NEW_STATION:
2285 nl80211_new_station_event(drv, tb);
2286 break;
2287 case NL80211_CMD_DEL_STATION:
2288 nl80211_del_station_event(drv, tb);
2289 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002290 case NL80211_CMD_SET_REKEY_OFFLOAD:
2291 nl80211_rekey_offload_event(drv, tb);
2292 break;
2293 case NL80211_CMD_PMKSA_CANDIDATE:
2294 nl80211_pmksa_candidate_event(drv, tb);
2295 break;
2296 case NL80211_CMD_PROBE_CLIENT:
2297 nl80211_client_probe_event(drv, tb);
2298 break;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002299 case NL80211_CMD_TDLS_OPER:
2300 nl80211_tdls_oper_event(drv, tb);
2301 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002302 default:
2303 wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
2304 "(cmd=%d)", cmd);
2305 break;
2306 }
2307}
2308
2309
2310static int process_drv_event(struct nl_msg *msg, void *arg)
2311{
2312 struct wpa_driver_nl80211_data *drv = arg;
2313 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2314 struct nlattr *tb[NL80211_ATTR_MAX + 1];
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002315 struct i802_bss *bss;
2316 int ifidx = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002317
2318 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2319 genlmsg_attrlen(gnlh, 0), NULL);
2320
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002321 if (tb[NL80211_ATTR_IFINDEX])
2322 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2323
2324 for (bss = &drv->first_bss; bss; bss = bss->next) {
2325 if (ifidx == -1 || ifidx == bss->ifindex) {
2326 do_process_drv_event(bss, gnlh->cmd, tb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002327 return NL_SKIP;
2328 }
2329 }
2330
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002331 wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
2332 "interface (ifindex %d)", gnlh->cmd, ifidx);
2333
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002334 return NL_SKIP;
2335}
2336
2337
2338static int process_global_event(struct nl_msg *msg, void *arg)
2339{
2340 struct nl80211_global *global = arg;
2341 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2342 struct nlattr *tb[NL80211_ATTR_MAX + 1];
Dmitry Shmidt04949592012-07-19 12:16:46 -07002343 struct wpa_driver_nl80211_data *drv, *tmp;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002344 int ifidx = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002345 struct i802_bss *bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002346
2347 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2348 genlmsg_attrlen(gnlh, 0), NULL);
2349
2350 if (tb[NL80211_ATTR_IFINDEX])
2351 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2352
Dmitry Shmidt04949592012-07-19 12:16:46 -07002353 dl_list_for_each_safe(drv, tmp, &global->interfaces,
2354 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002355 for (bss = &drv->first_bss; bss; bss = bss->next) {
2356 if (ifidx == -1 || ifidx == bss->ifindex) {
2357 do_process_drv_event(bss, gnlh->cmd, tb);
2358 return NL_SKIP;
2359 }
2360 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002361 }
2362
2363 return NL_SKIP;
2364}
2365
2366
2367static int process_bss_event(struct nl_msg *msg, void *arg)
2368{
2369 struct i802_bss *bss = arg;
2370 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2371 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2372
2373 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2374 genlmsg_attrlen(gnlh, 0), NULL);
2375
2376 switch (gnlh->cmd) {
2377 case NL80211_CMD_FRAME:
2378 case NL80211_CMD_FRAME_TX_STATUS:
2379 mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
2380 tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
2381 tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
Dmitry Shmidt04949592012-07-19 12:16:46 -07002382 tb[NL80211_ATTR_COOKIE],
2383 tb[NL80211_ATTR_RX_SIGNAL_DBM]);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002384 break;
2385 case NL80211_CMD_UNEXPECTED_FRAME:
2386 nl80211_spurious_frame(bss, tb, 0);
2387 break;
2388 case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
2389 nl80211_spurious_frame(bss, tb, 1);
2390 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002391 default:
2392 wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
2393 "(cmd=%d)", gnlh->cmd);
2394 break;
2395 }
2396
2397 return NL_SKIP;
2398}
2399
2400
2401static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
2402 void *handle)
2403{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002404 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002405
2406 wpa_printf(MSG_DEBUG, "nl80211: Event message available");
2407
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002408 nl_recvmsgs(handle, cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002409}
2410
2411
2412/**
2413 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
2414 * @priv: driver_nl80211 private data
2415 * @alpha2_arg: country to which to switch to
2416 * Returns: 0 on success, -1 on failure
2417 *
2418 * This asks nl80211 to set the regulatory domain for given
2419 * country ISO / IEC alpha2.
2420 */
2421static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
2422{
2423 struct i802_bss *bss = priv;
2424 struct wpa_driver_nl80211_data *drv = bss->drv;
2425 char alpha2[3];
2426 struct nl_msg *msg;
2427
2428 msg = nlmsg_alloc();
2429 if (!msg)
2430 return -ENOMEM;
2431
2432 alpha2[0] = alpha2_arg[0];
2433 alpha2[1] = alpha2_arg[1];
2434 alpha2[2] = '\0';
2435
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002436 nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002437
2438 NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
2439 if (send_and_recv_msgs(drv, msg, NULL, NULL))
2440 return -EINVAL;
2441 return 0;
2442nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002443 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002444 return -EINVAL;
2445}
2446
2447
2448struct wiphy_info_data {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002449 struct wpa_driver_capa *capa;
2450
2451 unsigned int error:1;
2452 unsigned int device_ap_sme:1;
2453 unsigned int poll_command_supported:1;
2454 unsigned int data_tx_status:1;
2455 unsigned int monitor_supported:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002456};
2457
2458
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002459static unsigned int probe_resp_offload_support(int supp_protocols)
2460{
2461 unsigned int prot = 0;
2462
2463 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
2464 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
2465 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
2466 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
2467 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
2468 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
2469 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
2470 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
2471
2472 return prot;
2473}
2474
2475
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002476static int wiphy_info_handler(struct nl_msg *msg, void *arg)
2477{
2478 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2479 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2480 struct wiphy_info_data *info = arg;
2481 int p2p_go_supported = 0, p2p_client_supported = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002482 int p2p_concurrent = 0, p2p_multichan_concurrent = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002483 int auth_supported = 0, connect_supported = 0;
2484 struct wpa_driver_capa *capa = info->capa;
2485 static struct nla_policy
2486 iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
2487 [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
2488 [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
2489 [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
2490 [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
2491 },
2492 iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
2493 [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
2494 [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
2495 };
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002496
2497 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2498 genlmsg_attrlen(gnlh, 0), NULL);
2499
2500 if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002501 capa->max_scan_ssids =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002502 nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
2503
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002504 if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
2505 capa->max_sched_scan_ssids =
2506 nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
2507
2508 if (tb[NL80211_ATTR_MAX_MATCH_SETS])
2509 capa->max_match_sets =
2510 nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
2511
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002512 if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
2513 struct nlattr *nl_mode;
2514 int i;
2515 nla_for_each_nested(nl_mode,
2516 tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
2517 switch (nla_type(nl_mode)) {
2518 case NL80211_IFTYPE_AP:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002519 capa->flags |= WPA_DRIVER_FLAGS_AP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002520 break;
2521 case NL80211_IFTYPE_P2P_GO:
2522 p2p_go_supported = 1;
2523 break;
2524 case NL80211_IFTYPE_P2P_CLIENT:
2525 p2p_client_supported = 1;
2526 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002527 case NL80211_IFTYPE_MONITOR:
2528 info->monitor_supported = 1;
2529 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002530 }
2531 }
2532 }
2533
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002534 if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
2535 struct nlattr *nl_combi;
2536 int rem_combi;
2537
2538 nla_for_each_nested(nl_combi,
2539 tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
2540 rem_combi) {
2541 struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
2542 struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
2543 struct nlattr *nl_limit, *nl_mode;
2544 int err, rem_limit, rem_mode;
2545 int combination_has_p2p = 0, combination_has_mgd = 0;
2546
2547 err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
2548 nl_combi,
2549 iface_combination_policy);
2550 if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
2551 !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
2552 !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
2553 goto broken_combination;
2554
2555 nla_for_each_nested(nl_limit,
2556 tb_comb[NL80211_IFACE_COMB_LIMITS],
2557 rem_limit) {
2558 err = nla_parse_nested(tb_limit,
2559 MAX_NL80211_IFACE_LIMIT,
2560 nl_limit,
2561 iface_limit_policy);
2562 if (err ||
2563 !tb_limit[NL80211_IFACE_LIMIT_TYPES])
2564 goto broken_combination;
2565
2566 nla_for_each_nested(
2567 nl_mode,
2568 tb_limit[NL80211_IFACE_LIMIT_TYPES],
2569 rem_mode) {
2570 int ift = nla_type(nl_mode);
2571 if (ift == NL80211_IFTYPE_P2P_GO ||
2572 ift == NL80211_IFTYPE_P2P_CLIENT)
2573 combination_has_p2p = 1;
2574 if (ift == NL80211_IFTYPE_STATION)
2575 combination_has_mgd = 1;
2576 }
2577 if (combination_has_p2p && combination_has_mgd)
2578 break;
2579 }
2580
2581 if (combination_has_p2p && combination_has_mgd) {
2582 p2p_concurrent = 1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002583 if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
2584 p2p_multichan_concurrent = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002585 break;
2586 }
2587
2588broken_combination:
2589 ;
2590 }
2591 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002592
2593 if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
2594 struct nlattr *nl_cmd;
2595 int i;
2596
2597 nla_for_each_nested(nl_cmd,
2598 tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002599 switch (nla_get_u32(nl_cmd)) {
2600 case NL80211_CMD_AUTHENTICATE:
2601 auth_supported = 1;
2602 break;
2603 case NL80211_CMD_CONNECT:
2604 connect_supported = 1;
2605 break;
2606 case NL80211_CMD_START_SCHED_SCAN:
2607 capa->sched_scan_supported = 1;
2608 break;
2609 case NL80211_CMD_PROBE_CLIENT:
2610 info->poll_command_supported = 1;
2611 break;
2612 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002613 }
2614 }
2615
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002616 if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
2617 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
2618 "off-channel TX");
2619 capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
2620 }
2621
2622 if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
2623 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
2624 capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
2625 }
2626
2627 /* default to 5000 since early versions of mac80211 don't set it */
2628 capa->max_remain_on_chan = 5000;
2629
2630 if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
2631 capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002632
2633 if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002634 capa->max_remain_on_chan =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002635 nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
2636
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002637 if (auth_supported)
2638 capa->flags |= WPA_DRIVER_FLAGS_SME;
2639 else if (!connect_supported) {
2640 wpa_printf(MSG_INFO, "nl80211: Driver does not support "
2641 "authentication/association or connect commands");
2642 info->error = 1;
2643 }
2644
2645 if (p2p_go_supported && p2p_client_supported)
2646 capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
2647 if (p2p_concurrent) {
2648 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
2649 "interface (driver advertised support)");
2650 capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
2651 capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002652
2653 if (p2p_multichan_concurrent) {
2654 wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
2655 "concurrent (driver advertised support)");
2656 capa->flags |=
2657 WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
2658 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002659 }
2660
2661 if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
2662 wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
2663 capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
2664
2665 if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
2666 wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
2667 capa->flags |=
2668 WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
2669 }
2670 }
Dmitry Shmidtad266fb2012-08-24 17:03:35 -07002671
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002672 if (tb[NL80211_ATTR_DEVICE_AP_SME])
2673 info->device_ap_sme = 1;
2674
2675 if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
2676 u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
2677
2678 if (flags & NL80211_FEATURE_SK_TX_STATUS)
2679 info->data_tx_status = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002680
2681 if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
2682 capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002683
2684 if (flags & NL80211_FEATURE_SAE)
2685 capa->flags |= WPA_DRIVER_FLAGS_SAE;
2686
2687 if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
2688 capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002689 }
2690
2691 if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
2692 int protocols =
2693 nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
2694 wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
2695 "offload in AP mode");
2696 capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
2697 capa->probe_resp_offloads =
2698 probe_resp_offload_support(protocols);
2699 }
2700
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002701 return NL_SKIP;
2702}
2703
2704
2705static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
2706 struct wiphy_info_data *info)
2707{
2708 struct nl_msg *msg;
2709
2710 os_memset(info, 0, sizeof(*info));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002711 info->capa = &drv->capa;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002712
2713 msg = nlmsg_alloc();
2714 if (!msg)
2715 return -1;
2716
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002717 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002718
2719 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
2720
2721 if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
2722 return 0;
2723 msg = NULL;
2724nla_put_failure:
2725 nlmsg_free(msg);
2726 return -1;
2727}
2728
2729
2730static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
2731{
2732 struct wiphy_info_data info;
2733 if (wpa_driver_nl80211_get_info(drv, &info))
2734 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002735
2736 if (info.error)
2737 return -1;
2738
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002739 drv->has_capability = 1;
2740 /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
2741 drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2742 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2743 WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2744 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
2745 drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
2746 WPA_DRIVER_CAPA_ENC_WEP104 |
2747 WPA_DRIVER_CAPA_ENC_TKIP |
2748 WPA_DRIVER_CAPA_ENC_CCMP;
2749 drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
2750 WPA_DRIVER_AUTH_SHARED |
2751 WPA_DRIVER_AUTH_LEAP;
2752
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002753 drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
2754 drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002755 drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
Dmitry Shmidtad266fb2012-08-24 17:03:35 -07002756
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002757 if (!info.device_ap_sme) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002758 drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002759
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002760 /*
2761 * No AP SME is currently assumed to also indicate no AP MLME
2762 * in the driver/firmware.
2763 */
2764 drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
2765 }
2766
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002767 drv->device_ap_sme = info.device_ap_sme;
2768 drv->poll_command_supported = info.poll_command_supported;
2769 drv->data_tx_status = info.data_tx_status;
2770
Dmitry Shmidt04949592012-07-19 12:16:46 -07002771#ifdef ANDROID_P2P
2772 if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
2773 /* Driver is new enough to support monitorless mode*/
2774 wpa_printf(MSG_DEBUG, "nl80211: Driver is new "
2775 "enough to support monitor-less mode");
2776 drv->use_monitor = 0;
2777 }
2778#else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002779 /*
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002780 * If poll command and tx status are supported, mac80211 is new enough
2781 * to have everything we need to not need monitor interfaces.
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002782 */
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002783 drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002784#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002785
2786 if (drv->device_ap_sme && drv->use_monitor) {
2787 /*
2788 * Non-mac80211 drivers may not support monitor interface.
2789 * Make sure we do not get stuck with incorrect capability here
2790 * by explicitly testing this.
2791 */
2792 if (!info.monitor_supported) {
2793 wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
2794 "with device_ap_sme since no monitor mode "
2795 "support detected");
2796 drv->use_monitor = 0;
2797 }
2798 }
2799
2800 /*
2801 * If we aren't going to use monitor interfaces, but the
2802 * driver doesn't support data TX status, we won't get TX
2803 * status for EAPOL frames.
2804 */
2805 if (!drv->use_monitor && !info.data_tx_status)
2806 drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002807
2808 return 0;
2809}
2810
2811
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002812#ifdef ANDROID
2813static int android_genl_ctrl_resolve(struct nl_handle *handle,
2814 const char *name)
2815{
2816 /*
2817 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
2818 * need to work around that.
2819 */
2820 struct nl_cache *cache = NULL;
2821 struct genl_family *nl80211 = NULL;
2822 int id = -1;
2823
2824 if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
2825 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
2826 "netlink cache");
2827 goto fail;
2828 }
2829
2830 nl80211 = genl_ctrl_search_by_name(cache, name);
2831 if (nl80211 == NULL)
2832 goto fail;
2833
2834 id = genl_family_get_id(nl80211);
2835
2836fail:
2837 if (nl80211)
2838 genl_family_put(nl80211);
2839 if (cache)
2840 nl_cache_free(cache);
2841
2842 return id;
2843}
2844#define genl_ctrl_resolve android_genl_ctrl_resolve
2845#endif /* ANDROID */
2846
2847
2848static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002849{
2850 int ret;
2851
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002852 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2853 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002854 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
2855 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002856 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002857 }
2858
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002859 global->nl = nl_create_handle(global->nl_cb, "nl");
2860 if (global->nl == NULL)
2861 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002862
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002863 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
2864 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002865 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
2866 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002867 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002868 }
2869
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002870 global->nl_event = nl_create_handle(global->nl_cb, "event");
2871 if (global->nl_event == NULL)
2872 goto err;
2873
2874 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002875 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002876 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002877 if (ret < 0) {
2878 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
2879 "membership for scan events: %d (%s)",
2880 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002881 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002882 }
2883
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002884 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002885 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002886 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002887 if (ret < 0) {
2888 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
2889 "membership for mlme events: %d (%s)",
2890 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002891 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002892 }
2893
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002894 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002895 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002896 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002897 if (ret < 0) {
2898 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
2899 "membership for regulatory events: %d (%s)",
2900 ret, strerror(-ret));
2901 /* Continue without regulatory events */
2902 }
2903
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002904 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2905 no_seq_check, NULL);
2906 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2907 process_global_event, global);
2908
2909 eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
2910 wpa_driver_nl80211_event_receive,
2911 global->nl_cb, global->nl_event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002912
2913 return 0;
2914
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002915err:
2916 nl_destroy_handles(&global->nl_event);
2917 nl_destroy_handles(&global->nl);
2918 nl_cb_put(global->nl_cb);
2919 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002920 return -1;
2921}
2922
2923
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002924static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
2925{
2926 drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2927 if (!drv->nl_cb) {
2928 wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
2929 return -1;
2930 }
2931
2932 nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2933 no_seq_check, NULL);
2934 nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2935 process_drv_event, drv);
2936
2937 return 0;
2938}
2939
2940
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002941static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
2942{
2943 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
2944 /*
2945 * This may be for any interface; use ifdown event to disable
2946 * interface.
2947 */
2948}
2949
2950
2951static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
2952{
2953 struct wpa_driver_nl80211_data *drv = ctx;
2954 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002955 if (linux_set_iface_flags(drv->global->ioctl_sock,
2956 drv->first_bss.ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002957 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
2958 "after rfkill unblock");
2959 return;
2960 }
2961 /* rtnetlink ifup handler will report interface as enabled */
2962}
2963
2964
2965static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
2966{
2967 /* Find phy (radio) to which this interface belongs */
2968 char buf[90], *pos;
2969 int f, rv;
2970
2971 drv->phyname[0] = '\0';
2972 snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
2973 drv->first_bss.ifname);
2974 f = open(buf, O_RDONLY);
2975 if (f < 0) {
2976 wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
2977 buf, strerror(errno));
2978 return;
2979 }
2980
2981 rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
2982 close(f);
2983 if (rv < 0) {
2984 wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
2985 buf, strerror(errno));
2986 return;
2987 }
2988
2989 drv->phyname[rv] = '\0';
2990 pos = os_strchr(drv->phyname, '\n');
2991 if (pos)
2992 *pos = '\0';
2993 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
2994 drv->first_bss.ifname, drv->phyname);
2995}
2996
2997
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002998static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
2999 void *eloop_ctx,
3000 void *handle)
3001{
3002 struct wpa_driver_nl80211_data *drv = eloop_ctx;
3003 u8 data[2048];
3004 struct msghdr msg;
3005 struct iovec entry;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003006 u8 control[512];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003007 struct cmsghdr *cmsg;
3008 int res, found_ee = 0, found_wifi = 0, acked = 0;
3009 union wpa_event_data event;
3010
3011 memset(&msg, 0, sizeof(msg));
3012 msg.msg_iov = &entry;
3013 msg.msg_iovlen = 1;
3014 entry.iov_base = data;
3015 entry.iov_len = sizeof(data);
3016 msg.msg_control = &control;
3017 msg.msg_controllen = sizeof(control);
3018
3019 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
3020 /* if error or not fitting 802.3 header, return */
3021 if (res < 14)
3022 return;
3023
3024 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
3025 {
3026 if (cmsg->cmsg_level == SOL_SOCKET &&
3027 cmsg->cmsg_type == SCM_WIFI_STATUS) {
3028 int *ack;
3029
3030 found_wifi = 1;
3031 ack = (void *)CMSG_DATA(cmsg);
3032 acked = *ack;
3033 }
3034
3035 if (cmsg->cmsg_level == SOL_PACKET &&
3036 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
3037 struct sock_extended_err *err =
3038 (struct sock_extended_err *)CMSG_DATA(cmsg);
3039
3040 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
3041 found_ee = 1;
3042 }
3043 }
3044
3045 if (!found_ee || !found_wifi)
3046 return;
3047
3048 memset(&event, 0, sizeof(event));
3049 event.eapol_tx_status.dst = data;
3050 event.eapol_tx_status.data = data + 14;
3051 event.eapol_tx_status.data_len = res - 14;
3052 event.eapol_tx_status.ack = acked;
3053 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
3054}
3055
3056
3057static int nl80211_init_bss(struct i802_bss *bss)
3058{
3059 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
3060 if (!bss->nl_cb)
3061 return -1;
3062
3063 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
3064 no_seq_check, NULL);
3065 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
3066 process_bss_event, bss);
3067
3068 return 0;
3069}
3070
3071
3072static void nl80211_destroy_bss(struct i802_bss *bss)
3073{
3074 nl_cb_put(bss->nl_cb);
3075 bss->nl_cb = NULL;
3076}
3077
3078
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003079/**
3080 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
3081 * @ctx: context to be used when calling wpa_supplicant functions,
3082 * e.g., wpa_supplicant_event()
3083 * @ifname: interface name, e.g., wlan0
3084 * @global_priv: private driver global data from global_init()
3085 * Returns: Pointer to private data, %NULL on failure
3086 */
3087static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
3088 void *global_priv)
3089{
3090 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003091 struct rfkill_config *rcfg;
3092 struct i802_bss *bss;
3093
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003094 if (global_priv == NULL)
3095 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003096 drv = os_zalloc(sizeof(*drv));
3097 if (drv == NULL)
3098 return NULL;
3099 drv->global = global_priv;
3100 drv->ctx = ctx;
3101 bss = &drv->first_bss;
3102 bss->drv = drv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003103 bss->ctx = ctx;
3104
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003105 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
3106 drv->monitor_ifidx = -1;
3107 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003108 drv->eapol_tx_sock = -1;
3109 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003110
3111 if (wpa_driver_nl80211_init_nl(drv)) {
3112 os_free(drv);
3113 return NULL;
3114 }
3115
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003116 if (nl80211_init_bss(bss))
3117 goto failed;
3118
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003119 nl80211_get_phy_name(drv);
3120
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003121 rcfg = os_zalloc(sizeof(*rcfg));
3122 if (rcfg == NULL)
3123 goto failed;
3124 rcfg->ctx = drv;
3125 os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
3126 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
3127 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
3128 drv->rfkill = rfkill_init(rcfg);
3129 if (drv->rfkill == NULL) {
3130 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
3131 os_free(rcfg);
3132 }
3133
3134 if (wpa_driver_nl80211_finish_drv_init(drv))
3135 goto failed;
3136
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003137 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
3138 if (drv->eapol_tx_sock < 0)
3139 goto failed;
3140
3141 if (drv->data_tx_status) {
3142 int enabled = 1;
3143
3144 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
3145 &enabled, sizeof(enabled)) < 0) {
3146 wpa_printf(MSG_DEBUG,
3147 "nl80211: wifi status sockopt failed\n");
3148 drv->data_tx_status = 0;
3149 if (!drv->use_monitor)
3150 drv->capa.flags &=
3151 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
3152 } else {
3153 eloop_register_read_sock(drv->eapol_tx_sock,
3154 wpa_driver_nl80211_handle_eapol_tx_status,
3155 drv, NULL);
3156 }
3157 }
3158
3159 if (drv->global) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003160 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003161 drv->in_interface_list = 1;
3162 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003163
3164 return bss;
3165
3166failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003167 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003168 return NULL;
3169}
3170
3171
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003172static int nl80211_register_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003173 struct nl_handle *nl_handle,
3174 u16 type, const u8 *match, size_t match_len)
3175{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003176 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003177 struct nl_msg *msg;
3178 int ret = -1;
3179
3180 msg = nlmsg_alloc();
3181 if (!msg)
3182 return -1;
3183
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003184 wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
3185 type, nl_handle);
3186 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
3187 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003188
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003189 nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
3190
3191 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003192 NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
3193 NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
3194
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003195 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003196 msg = NULL;
3197 if (ret) {
3198 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
3199 "failed (type=%u): ret=%d (%s)",
3200 type, ret, strerror(-ret));
3201 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
3202 match, match_len);
3203 goto nla_put_failure;
3204 }
3205 ret = 0;
3206nla_put_failure:
3207 nlmsg_free(msg);
3208 return ret;
3209}
3210
3211
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003212static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
3213{
3214 struct wpa_driver_nl80211_data *drv = bss->drv;
3215
3216 if (bss->nl_mgmt) {
3217 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
3218 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
3219 return -1;
3220 }
3221
3222 bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
3223 if (bss->nl_mgmt == NULL)
3224 return -1;
3225
3226 eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
3227 wpa_driver_nl80211_event_receive, bss->nl_cb,
3228 bss->nl_mgmt);
3229
3230 return 0;
3231}
3232
3233
3234static int nl80211_register_action_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003235 const u8 *match, size_t match_len)
3236{
3237 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003238 return nl80211_register_frame(bss, bss->nl_mgmt,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003239 type, match, match_len);
3240}
3241
3242
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003243static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003244{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003245 struct wpa_driver_nl80211_data *drv = bss->drv;
3246
3247 if (nl80211_alloc_mgmt_handle(bss))
3248 return -1;
3249 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
3250 "handle %p", bss->nl_mgmt);
3251
3252#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003253 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003254 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003255 return -1;
3256 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003257 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003258 return -1;
3259 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003260 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003261 return -1;
3262 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003263 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003264 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003265#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
3266#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003267 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003268 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003269 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
3270 6) < 0)
3271 return -1;
3272 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003273 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003274 (u8 *) "\x7f\x50\x6f\x9a\x09",
3275 5) < 0)
3276 return -1;
3277#endif /* CONFIG_P2P */
3278#ifdef CONFIG_IEEE80211W
3279 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003280 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003281 return -1;
3282#endif /* CONFIG_IEEE80211W */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003283#ifdef CONFIG_TDLS
3284 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
3285 /* TDLS Discovery Response */
3286 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
3287 0)
3288 return -1;
3289 }
3290#endif /* CONFIG_TDLS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003291
3292 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003293 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003294 return -1;
3295 else
3296 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
3297 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
3298
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003299 /* WNM - BSS Transition Management Request */
3300 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
3301 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003302 /* WNM-Sleep Mode Response */
3303 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
3304 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003305
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003306 return 0;
3307}
3308
3309
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003310static int nl80211_register_spurious_class3(struct i802_bss *bss)
3311{
3312 struct wpa_driver_nl80211_data *drv = bss->drv;
3313 struct nl_msg *msg;
3314 int ret = -1;
3315
3316 msg = nlmsg_alloc();
3317 if (!msg)
3318 return -1;
3319
3320 nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
3321
3322 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
3323
3324 ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
3325 msg = NULL;
3326 if (ret) {
3327 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
3328 "failed: ret=%d (%s)",
3329 ret, strerror(-ret));
3330 goto nla_put_failure;
3331 }
3332 ret = 0;
3333nla_put_failure:
3334 nlmsg_free(msg);
3335 return ret;
3336}
3337
3338
3339static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
3340{
3341 static const int stypes[] = {
3342 WLAN_FC_STYPE_AUTH,
3343 WLAN_FC_STYPE_ASSOC_REQ,
3344 WLAN_FC_STYPE_REASSOC_REQ,
3345 WLAN_FC_STYPE_DISASSOC,
3346 WLAN_FC_STYPE_DEAUTH,
3347 WLAN_FC_STYPE_ACTION,
3348 WLAN_FC_STYPE_PROBE_REQ,
3349/* Beacon doesn't work as mac80211 doesn't currently allow
3350 * it, but it wouldn't really be the right thing anyway as
3351 * it isn't per interface ... maybe just dump the scan
3352 * results periodically for OLBC?
3353 */
3354// WLAN_FC_STYPE_BEACON,
3355 };
3356 unsigned int i;
3357
3358 if (nl80211_alloc_mgmt_handle(bss))
3359 return -1;
3360 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
3361 "handle %p", bss->nl_mgmt);
3362
3363 for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
3364 if (nl80211_register_frame(bss, bss->nl_mgmt,
3365 (WLAN_FC_TYPE_MGMT << 2) |
3366 (stypes[i] << 4),
3367 NULL, 0) < 0) {
3368 goto out_err;
3369 }
3370 }
3371
3372 if (nl80211_register_spurious_class3(bss))
3373 goto out_err;
3374
3375 if (nl80211_get_wiphy_data_ap(bss) == NULL)
3376 goto out_err;
3377
3378 return 0;
3379
3380out_err:
3381 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3382 nl_destroy_handles(&bss->nl_mgmt);
3383 return -1;
3384}
3385
3386
3387static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
3388{
3389 if (nl80211_alloc_mgmt_handle(bss))
3390 return -1;
3391 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
3392 "handle %p (device SME)", bss->nl_mgmt);
3393
3394 if (nl80211_register_frame(bss, bss->nl_mgmt,
3395 (WLAN_FC_TYPE_MGMT << 2) |
3396 (WLAN_FC_STYPE_ACTION << 4),
3397 NULL, 0) < 0)
3398 goto out_err;
3399
3400 return 0;
3401
3402out_err:
3403 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3404 nl_destroy_handles(&bss->nl_mgmt);
3405 return -1;
3406}
3407
3408
3409static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
3410{
3411 if (bss->nl_mgmt == NULL)
3412 return;
3413 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
3414 "(%s)", bss->nl_mgmt, reason);
3415 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3416 nl_destroy_handles(&bss->nl_mgmt);
3417
3418 nl80211_put_wiphy_data_ap(bss);
3419}
3420
3421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003422static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
3423{
3424 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
3425}
3426
3427
3428static int
3429wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
3430{
3431 struct i802_bss *bss = &drv->first_bss;
3432 int send_rfkill_event = 0;
3433
3434 drv->ifindex = if_nametoindex(bss->ifname);
3435 drv->first_bss.ifindex = drv->ifindex;
3436
3437#ifndef HOSTAPD
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003438 /*
3439 * Make sure the interface starts up in station mode unless this is a
3440 * dynamically added interface (e.g., P2P) that was already configured
3441 * with proper iftype.
3442 */
3443 if (drv->ifindex != drv->global->if_add_ifindex &&
3444 wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
3445 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003446 "use managed mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003447 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003448 }
3449
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003450 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003451 if (rfkill_is_blocked(drv->rfkill)) {
3452 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
3453 "interface '%s' due to rfkill",
3454 bss->ifname);
3455 drv->if_disabled = 1;
3456 send_rfkill_event = 1;
3457 } else {
3458 wpa_printf(MSG_ERROR, "nl80211: Could not set "
3459 "interface '%s' UP", bss->ifname);
3460 return -1;
3461 }
3462 }
3463
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003464 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003465 1, IF_OPER_DORMANT);
3466#endif /* HOSTAPD */
3467
3468 if (wpa_driver_nl80211_capa(drv))
3469 return -1;
3470
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003471 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3472 bss->addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003473 return -1;
3474
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003475 if (send_rfkill_event) {
3476 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
3477 drv, drv->ctx);
3478 }
3479
3480 return 0;
3481}
3482
3483
3484static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
3485{
3486 struct nl_msg *msg;
3487
3488 msg = nlmsg_alloc();
3489 if (!msg)
3490 return -ENOMEM;
3491
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003492 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003493 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3494
3495 return send_and_recv_msgs(drv, msg, NULL, NULL);
3496 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003497 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003498 return -ENOBUFS;
3499}
3500
3501
3502/**
3503 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003504 * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003505 *
3506 * Shut down driver interface and processing of driver events. Free
3507 * private data buffer if one was allocated in wpa_driver_nl80211_init().
3508 */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003509static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003510{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003511 struct wpa_driver_nl80211_data *drv = bss->drv;
3512
Dmitry Shmidt04949592012-07-19 12:16:46 -07003513 bss->in_deinit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003514 if (drv->data_tx_status)
3515 eloop_unregister_read_sock(drv->eapol_tx_sock);
3516 if (drv->eapol_tx_sock >= 0)
3517 close(drv->eapol_tx_sock);
3518
3519 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003520 wpa_driver_nl80211_probe_req_report(bss, 0);
3521 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003522 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
3523 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003524 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3525 "interface %s from bridge %s: %s",
3526 bss->ifname, bss->brname, strerror(errno));
3527 }
3528 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003529 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003530 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3531 "bridge %s: %s",
3532 bss->brname, strerror(errno));
3533 }
3534
3535 nl80211_remove_monitor_interface(drv);
3536
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003537 if (is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003538 wpa_driver_nl80211_del_beacon(drv);
3539
3540#ifdef HOSTAPD
3541 if (drv->last_freq_ht) {
3542 /* Clear HT flags from the driver */
3543 struct hostapd_freq_params freq;
3544 os_memset(&freq, 0, sizeof(freq));
3545 freq.freq = drv->last_freq;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003546 wpa_driver_nl80211_set_freq(bss, &freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003547 }
3548
3549 if (drv->eapol_sock >= 0) {
3550 eloop_unregister_read_sock(drv->eapol_sock);
3551 close(drv->eapol_sock);
3552 }
3553
3554 if (drv->if_indices != drv->default_if_indices)
3555 os_free(drv->if_indices);
3556#endif /* HOSTAPD */
3557
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003558 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003559 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3560
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003561 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
3562 IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003563 rfkill_deinit(drv->rfkill);
3564
3565 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3566
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003567 (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
3568 wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
3569 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003570
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003571 nl_cb_put(drv->nl_cb);
3572
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003573 nl80211_destroy_bss(&drv->first_bss);
3574
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003575 os_free(drv->filter_ssids);
3576
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003577 os_free(drv->auth_ie);
3578
3579 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003580 dl_list_del(&drv->list);
3581
3582 os_free(drv);
3583}
3584
3585
3586/**
3587 * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
3588 * @eloop_ctx: Driver private data
3589 * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
3590 *
3591 * This function can be used as registered timeout when starting a scan to
3592 * generate a scan completed event if the driver does not report this.
3593 */
3594static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
3595{
3596 struct wpa_driver_nl80211_data *drv = eloop_ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003597 if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003598 wpa_driver_nl80211_set_mode(&drv->first_bss,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003599 drv->ap_scan_as_station);
3600 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003601 }
3602 wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
3603 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
3604}
3605
3606
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003607static struct nl_msg *
3608nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
3609 struct wpa_driver_scan_params *params)
3610{
3611 struct nl_msg *msg;
3612 int err;
3613 size_t i;
3614
3615 msg = nlmsg_alloc();
3616 if (!msg)
3617 return NULL;
3618
3619 nl80211_cmd(drv, msg, 0, cmd);
3620
3621 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
3622 goto fail;
3623
3624 if (params->num_ssids) {
3625 struct nl_msg *ssids = nlmsg_alloc();
3626 if (ssids == NULL)
3627 goto fail;
3628 for (i = 0; i < params->num_ssids; i++) {
3629 wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
3630 params->ssids[i].ssid,
3631 params->ssids[i].ssid_len);
3632 if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
3633 params->ssids[i].ssid) < 0) {
3634 nlmsg_free(ssids);
3635 goto fail;
3636 }
3637 }
3638 err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
3639 nlmsg_free(ssids);
3640 if (err < 0)
3641 goto fail;
3642 }
3643
3644 if (params->extra_ies) {
3645 wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
3646 params->extra_ies, params->extra_ies_len);
3647 if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
3648 params->extra_ies) < 0)
3649 goto fail;
3650 }
3651
3652 if (params->freqs) {
3653 struct nl_msg *freqs = nlmsg_alloc();
3654 if (freqs == NULL)
3655 goto fail;
3656 for (i = 0; params->freqs[i]; i++) {
3657 wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
3658 "MHz", params->freqs[i]);
3659 if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
3660 nlmsg_free(freqs);
3661 goto fail;
3662 }
3663 }
3664 err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
3665 freqs);
3666 nlmsg_free(freqs);
3667 if (err < 0)
3668 goto fail;
3669 }
3670
3671 os_free(drv->filter_ssids);
3672 drv->filter_ssids = params->filter_ssids;
3673 params->filter_ssids = NULL;
3674 drv->num_filter_ssids = params->num_filter_ssids;
3675
3676 return msg;
3677
3678fail:
3679 nlmsg_free(msg);
3680 return NULL;
3681}
3682
3683
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003684/**
3685 * wpa_driver_nl80211_scan - Request the driver to initiate scan
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003686 * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003687 * @params: Scan parameters
3688 * Returns: 0 on success, -1 on failure
3689 */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003690static int wpa_driver_nl80211_scan(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003691 struct wpa_driver_scan_params *params)
3692{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003693 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003694 int ret = -1, timeout;
3695 struct nl_msg *msg, *rates = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003696
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003697 drv->scan_for_auth = 0;
3698
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003699 msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
3700 if (!msg)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003701 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003702
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003703 if (params->p2p_probe) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07003704 wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
3705
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003706 rates = nlmsg_alloc();
3707 if (rates == NULL)
3708 goto nla_put_failure;
3709
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003710 /*
3711 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
3712 * by masking out everything else apart from the OFDM rates 6,
3713 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
3714 * rates are left enabled.
3715 */
3716 NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
3717 "\x0c\x12\x18\x24\x30\x48\x60\x6c");
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003718 if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
3719 0)
3720 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003721
3722 NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
3723 }
3724
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003725 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3726 msg = NULL;
3727 if (ret) {
3728 wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
3729 "(%s)", ret, strerror(-ret));
3730#ifdef HOSTAPD
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003731 if (is_ap_interface(drv->nlmode)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003732 /*
3733 * mac80211 does not allow scan requests in AP mode, so
3734 * try to do this in station mode.
3735 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003736 if (wpa_driver_nl80211_set_mode(
3737 bss, NL80211_IFTYPE_STATION))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003738 goto nla_put_failure;
3739
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08003740 if (wpa_driver_nl80211_scan(bss, params)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003741 wpa_driver_nl80211_set_mode(bss, drv->nlmode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003742 goto nla_put_failure;
3743 }
3744
3745 /* Restore AP mode when processing scan results */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003746 drv->ap_scan_as_station = drv->nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003747 ret = 0;
3748 } else
3749 goto nla_put_failure;
3750#else /* HOSTAPD */
3751 goto nla_put_failure;
3752#endif /* HOSTAPD */
3753 }
3754
3755 /* Not all drivers generate "scan completed" wireless event, so try to
3756 * read results after a timeout. */
3757 timeout = 10;
3758 if (drv->scan_complete_events) {
3759 /*
3760 * The driver seems to deliver events to notify when scan is
3761 * complete, so use longer timeout to avoid race conditions
3762 * with scanning and following association request.
3763 */
3764 timeout = 30;
3765 }
3766 wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
3767 "seconds", ret, timeout);
3768 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3769 eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
3770 drv, drv->ctx);
3771
3772nla_put_failure:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003773 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003774 nlmsg_free(rates);
3775 return ret;
3776}
3777
3778
3779/**
3780 * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
3781 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3782 * @params: Scan parameters
3783 * @interval: Interval between scan cycles in milliseconds
3784 * Returns: 0 on success, -1 on failure or if not supported
3785 */
3786static int wpa_driver_nl80211_sched_scan(void *priv,
3787 struct wpa_driver_scan_params *params,
3788 u32 interval)
3789{
3790 struct i802_bss *bss = priv;
3791 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003792 int ret = -1;
3793 struct nl_msg *msg;
3794 struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
3795 struct nl_msg *match_set_rssi = NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003796 size_t i;
3797
3798#ifdef ANDROID
3799 if (!drv->capa.sched_scan_supported)
3800 return android_pno_start(bss, params);
3801#endif /* ANDROID */
3802
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003803 msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
3804 if (!msg)
3805 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003806
3807 NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
3808
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003809 if ((drv->num_filter_ssids &&
3810 (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
3811 params->filter_rssi) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003812 match_sets = nlmsg_alloc();
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003813 if (match_sets == NULL)
3814 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003815
3816 for (i = 0; i < drv->num_filter_ssids; i++) {
3817 wpa_hexdump_ascii(MSG_MSGDUMP,
3818 "nl80211: Sched scan filter SSID",
3819 drv->filter_ssids[i].ssid,
3820 drv->filter_ssids[i].ssid_len);
3821
3822 match_set_ssid = nlmsg_alloc();
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003823 if (match_set_ssid == NULL)
3824 goto nla_put_failure;
3825 NLA_PUT(match_set_ssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003826 NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
3827 drv->filter_ssids[i].ssid_len,
3828 drv->filter_ssids[i].ssid);
3829
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003830 if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
3831 0)
3832 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003833 }
3834
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003835 if (params->filter_rssi) {
3836 match_set_rssi = nlmsg_alloc();
3837 if (match_set_rssi == NULL)
3838 goto nla_put_failure;
3839 NLA_PUT_U32(match_set_rssi,
3840 NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
3841 params->filter_rssi);
3842 wpa_printf(MSG_MSGDUMP,
3843 "nl80211: Sched scan RSSI filter %d dBm",
3844 params->filter_rssi);
3845 if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
3846 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003847 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003848
3849 if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
3850 match_sets) < 0)
3851 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003852 }
3853
3854 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3855
3856 /* TODO: if we get an error here, we should fall back to normal scan */
3857
3858 msg = NULL;
3859 if (ret) {
3860 wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
3861 "ret=%d (%s)", ret, strerror(-ret));
3862 goto nla_put_failure;
3863 }
3864
3865 wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
3866 "scan interval %d msec", ret, interval);
3867
3868nla_put_failure:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003869 nlmsg_free(match_set_ssid);
3870 nlmsg_free(match_sets);
3871 nlmsg_free(match_set_rssi);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003872 nlmsg_free(msg);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003873 return ret;
3874}
3875
3876
3877/**
3878 * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
3879 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3880 * Returns: 0 on success, -1 on failure or if not supported
3881 */
3882static int wpa_driver_nl80211_stop_sched_scan(void *priv)
3883{
3884 struct i802_bss *bss = priv;
3885 struct wpa_driver_nl80211_data *drv = bss->drv;
3886 int ret = 0;
3887 struct nl_msg *msg;
3888
3889#ifdef ANDROID
3890 if (!drv->capa.sched_scan_supported)
3891 return android_pno_stop(bss);
3892#endif /* ANDROID */
3893
3894 msg = nlmsg_alloc();
3895 if (!msg)
3896 return -1;
3897
3898 nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
3899
3900 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3901
3902 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3903 msg = NULL;
3904 if (ret) {
3905 wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
3906 "ret=%d (%s)", ret, strerror(-ret));
3907 goto nla_put_failure;
3908 }
3909
3910 wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
3911
3912nla_put_failure:
3913 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003914 return ret;
3915}
3916
3917
3918static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
3919{
3920 const u8 *end, *pos;
3921
3922 if (ies == NULL)
3923 return NULL;
3924
3925 pos = ies;
3926 end = ies + ies_len;
3927
3928 while (pos + 1 < end) {
3929 if (pos + 2 + pos[1] > end)
3930 break;
3931 if (pos[0] == ie)
3932 return pos;
3933 pos += 2 + pos[1];
3934 }
3935
3936 return NULL;
3937}
3938
3939
3940static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
3941 const u8 *ie, size_t ie_len)
3942{
3943 const u8 *ssid;
3944 size_t i;
3945
3946 if (drv->filter_ssids == NULL)
3947 return 0;
3948
3949 ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
3950 if (ssid == NULL)
3951 return 1;
3952
3953 for (i = 0; i < drv->num_filter_ssids; i++) {
3954 if (ssid[1] == drv->filter_ssids[i].ssid_len &&
3955 os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
3956 0)
3957 return 0;
3958 }
3959
3960 return 1;
3961}
3962
3963
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003964static int bss_info_handler(struct nl_msg *msg, void *arg)
3965{
3966 struct nlattr *tb[NL80211_ATTR_MAX + 1];
3967 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
3968 struct nlattr *bss[NL80211_BSS_MAX + 1];
3969 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
3970 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
3971 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
3972 [NL80211_BSS_TSF] = { .type = NLA_U64 },
3973 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
3974 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
3975 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
3976 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
3977 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
3978 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
3979 [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
3980 [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
3981 };
3982 struct nl80211_bss_info_arg *_arg = arg;
3983 struct wpa_scan_results *res = _arg->res;
3984 struct wpa_scan_res **tmp;
3985 struct wpa_scan_res *r;
3986 const u8 *ie, *beacon_ie;
3987 size_t ie_len, beacon_ie_len;
3988 u8 *pos;
Jouni Malinen87fd2792011-05-16 18:35:42 +03003989 size_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003990
3991 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
3992 genlmsg_attrlen(gnlh, 0), NULL);
3993 if (!tb[NL80211_ATTR_BSS])
3994 return NL_SKIP;
3995 if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
3996 bss_policy))
3997 return NL_SKIP;
Jouni Malinen87fd2792011-05-16 18:35:42 +03003998 if (bss[NL80211_BSS_STATUS]) {
3999 enum nl80211_bss_status status;
4000 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
4001 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
4002 bss[NL80211_BSS_FREQUENCY]) {
4003 _arg->assoc_freq =
4004 nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
4005 wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
4006 _arg->assoc_freq);
4007 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004008 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
4009 bss[NL80211_BSS_BSSID]) {
4010 os_memcpy(_arg->assoc_bssid,
4011 nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
4012 wpa_printf(MSG_DEBUG, "nl80211: Associated with "
4013 MACSTR, MAC2STR(_arg->assoc_bssid));
4014 }
Jouni Malinen87fd2792011-05-16 18:35:42 +03004015 }
4016 if (!res)
4017 return NL_SKIP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004018 if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
4019 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
4020 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
4021 } else {
4022 ie = NULL;
4023 ie_len = 0;
4024 }
4025 if (bss[NL80211_BSS_BEACON_IES]) {
4026 beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
4027 beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
4028 } else {
4029 beacon_ie = NULL;
4030 beacon_ie_len = 0;
4031 }
4032
4033 if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
4034 ie ? ie_len : beacon_ie_len))
4035 return NL_SKIP;
4036
4037 r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
4038 if (r == NULL)
4039 return NL_SKIP;
4040 if (bss[NL80211_BSS_BSSID])
4041 os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
4042 ETH_ALEN);
4043 if (bss[NL80211_BSS_FREQUENCY])
4044 r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
4045 if (bss[NL80211_BSS_BEACON_INTERVAL])
4046 r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
4047 if (bss[NL80211_BSS_CAPABILITY])
4048 r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
4049 r->flags |= WPA_SCAN_NOISE_INVALID;
4050 if (bss[NL80211_BSS_SIGNAL_MBM]) {
4051 r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
4052 r->level /= 100; /* mBm to dBm */
4053 r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
4054 } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
4055 r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004056 r->flags |= WPA_SCAN_QUAL_INVALID;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004057 } else
4058 r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
4059 if (bss[NL80211_BSS_TSF])
4060 r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
4061 if (bss[NL80211_BSS_SEEN_MS_AGO])
4062 r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
4063 r->ie_len = ie_len;
4064 pos = (u8 *) (r + 1);
4065 if (ie) {
4066 os_memcpy(pos, ie, ie_len);
4067 pos += ie_len;
4068 }
4069 r->beacon_ie_len = beacon_ie_len;
4070 if (beacon_ie)
4071 os_memcpy(pos, beacon_ie, beacon_ie_len);
4072
4073 if (bss[NL80211_BSS_STATUS]) {
4074 enum nl80211_bss_status status;
4075 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
4076 switch (status) {
4077 case NL80211_BSS_STATUS_AUTHENTICATED:
4078 r->flags |= WPA_SCAN_AUTHENTICATED;
4079 break;
4080 case NL80211_BSS_STATUS_ASSOCIATED:
4081 r->flags |= WPA_SCAN_ASSOCIATED;
4082 break;
4083 default:
4084 break;
4085 }
4086 }
4087
Jouni Malinen87fd2792011-05-16 18:35:42 +03004088 /*
4089 * cfg80211 maintains separate BSS table entries for APs if the same
4090 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
4091 * not use frequency as a separate key in the BSS table, so filter out
4092 * duplicated entries. Prefer associated BSS entry in such a case in
4093 * order to get the correct frequency into the BSS table.
4094 */
4095 for (i = 0; i < res->num; i++) {
4096 const u8 *s1, *s2;
4097 if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
4098 continue;
4099
4100 s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
4101 res->res[i]->ie_len, WLAN_EID_SSID);
4102 s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
4103 if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
4104 os_memcmp(s1, s2, 2 + s1[1]) != 0)
4105 continue;
4106
4107 /* Same BSSID,SSID was already included in scan results */
4108 wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
4109 "for " MACSTR, MAC2STR(r->bssid));
4110
4111 if ((r->flags & WPA_SCAN_ASSOCIATED) &&
4112 !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) {
4113 os_free(res->res[i]);
4114 res->res[i] = r;
4115 } else
4116 os_free(r);
4117 return NL_SKIP;
4118 }
4119
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004120 tmp = os_realloc_array(res->res, res->num + 1,
4121 sizeof(struct wpa_scan_res *));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004122 if (tmp == NULL) {
4123 os_free(r);
4124 return NL_SKIP;
4125 }
4126 tmp[res->num++] = r;
4127 res->res = tmp;
4128
4129 return NL_SKIP;
4130}
4131
4132
4133static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
4134 const u8 *addr)
4135{
4136 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
4137 wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
4138 "mismatch (" MACSTR ")", MAC2STR(addr));
4139 wpa_driver_nl80211_mlme(drv, addr,
4140 NL80211_CMD_DEAUTHENTICATE,
4141 WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
4142 }
4143}
4144
4145
4146static void wpa_driver_nl80211_check_bss_status(
4147 struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
4148{
4149 size_t i;
4150
4151 for (i = 0; i < res->num; i++) {
4152 struct wpa_scan_res *r = res->res[i];
4153 if (r->flags & WPA_SCAN_AUTHENTICATED) {
4154 wpa_printf(MSG_DEBUG, "nl80211: Scan results "
4155 "indicates BSS status with " MACSTR
4156 " as authenticated",
4157 MAC2STR(r->bssid));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004158 if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004159 os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
4160 os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
4161 0) {
4162 wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
4163 " in local state (auth=" MACSTR
4164 " assoc=" MACSTR ")",
4165 MAC2STR(drv->auth_bssid),
4166 MAC2STR(drv->bssid));
4167 clear_state_mismatch(drv, r->bssid);
4168 }
4169 }
4170
4171 if (r->flags & WPA_SCAN_ASSOCIATED) {
4172 wpa_printf(MSG_DEBUG, "nl80211: Scan results "
4173 "indicate BSS status with " MACSTR
4174 " as associated",
4175 MAC2STR(r->bssid));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004176 if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004177 !drv->associated) {
4178 wpa_printf(MSG_DEBUG, "nl80211: Local state "
4179 "(not associated) does not match "
4180 "with BSS state");
4181 clear_state_mismatch(drv, r->bssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004182 } else if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004183 os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
4184 0) {
4185 wpa_printf(MSG_DEBUG, "nl80211: Local state "
4186 "(associated with " MACSTR ") does "
4187 "not match with BSS state",
4188 MAC2STR(drv->bssid));
4189 clear_state_mismatch(drv, r->bssid);
4190 clear_state_mismatch(drv, drv->bssid);
4191 }
4192 }
4193 }
4194}
4195
4196
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004197static struct wpa_scan_results *
4198nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
4199{
4200 struct nl_msg *msg;
4201 struct wpa_scan_results *res;
4202 int ret;
4203 struct nl80211_bss_info_arg arg;
4204
4205 res = os_zalloc(sizeof(*res));
4206 if (res == NULL)
4207 return NULL;
4208 msg = nlmsg_alloc();
4209 if (!msg)
4210 goto nla_put_failure;
4211
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004212 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004213 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4214
4215 arg.drv = drv;
4216 arg.res = res;
4217 ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
4218 msg = NULL;
4219 if (ret == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004220 wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
4221 "BSSes)", (unsigned long) res->num);
4222 nl80211_get_noise_for_scan_results(drv, res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004223 return res;
4224 }
4225 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
4226 "(%s)", ret, strerror(-ret));
4227nla_put_failure:
4228 nlmsg_free(msg);
4229 wpa_scan_results_free(res);
4230 return NULL;
4231}
4232
4233
4234/**
4235 * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
4236 * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
4237 * Returns: Scan results on success, -1 on failure
4238 */
4239static struct wpa_scan_results *
4240wpa_driver_nl80211_get_scan_results(void *priv)
4241{
4242 struct i802_bss *bss = priv;
4243 struct wpa_driver_nl80211_data *drv = bss->drv;
4244 struct wpa_scan_results *res;
4245
4246 res = nl80211_get_scan_results(drv);
4247 if (res)
4248 wpa_driver_nl80211_check_bss_status(drv, res);
4249 return res;
4250}
4251
4252
4253static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
4254{
4255 struct wpa_scan_results *res;
4256 size_t i;
4257
4258 res = nl80211_get_scan_results(drv);
4259 if (res == NULL) {
4260 wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
4261 return;
4262 }
4263
4264 wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
4265 for (i = 0; i < res->num; i++) {
4266 struct wpa_scan_res *r = res->res[i];
4267 wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
4268 (int) i, (int) res->num, MAC2STR(r->bssid),
4269 r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
4270 r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
4271 }
4272
4273 wpa_scan_results_free(res);
4274}
4275
4276
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004277static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004278 enum wpa_alg alg, const u8 *addr,
4279 int key_idx, int set_tx,
4280 const u8 *seq, size_t seq_len,
4281 const u8 *key, size_t key_len)
4282{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004283 struct wpa_driver_nl80211_data *drv = bss->drv;
4284 int ifindex = if_nametoindex(ifname);
4285 struct nl_msg *msg;
4286 int ret;
4287
4288 wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
4289 "set_tx=%d seq_len=%lu key_len=%lu",
4290 __func__, ifindex, alg, addr, key_idx, set_tx,
4291 (unsigned long) seq_len, (unsigned long) key_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004292#ifdef CONFIG_TDLS
4293 if (key_idx == -1)
4294 key_idx = 0;
4295#endif /* CONFIG_TDLS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004296
4297 msg = nlmsg_alloc();
4298 if (!msg)
4299 return -ENOMEM;
4300
4301 if (alg == WPA_ALG_NONE) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004302 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004303 } else {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004304 nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004305 NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
4306 switch (alg) {
4307 case WPA_ALG_WEP:
4308 if (key_len == 5)
4309 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4310 WLAN_CIPHER_SUITE_WEP40);
4311 else
4312 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4313 WLAN_CIPHER_SUITE_WEP104);
4314 break;
4315 case WPA_ALG_TKIP:
4316 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4317 WLAN_CIPHER_SUITE_TKIP);
4318 break;
4319 case WPA_ALG_CCMP:
4320 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4321 WLAN_CIPHER_SUITE_CCMP);
4322 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004323 case WPA_ALG_GCMP:
4324 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4325 WLAN_CIPHER_SUITE_GCMP);
4326 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004327 case WPA_ALG_IGTK:
4328 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4329 WLAN_CIPHER_SUITE_AES_CMAC);
4330 break;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004331 case WPA_ALG_SMS4:
4332 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4333 WLAN_CIPHER_SUITE_SMS4);
4334 break;
4335 case WPA_ALG_KRK:
4336 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4337 WLAN_CIPHER_SUITE_KRK);
4338 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004339 default:
4340 wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
4341 "algorithm %d", __func__, alg);
4342 nlmsg_free(msg);
4343 return -1;
4344 }
4345 }
4346
4347 if (seq && seq_len)
4348 NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
4349
4350 if (addr && !is_broadcast_ether_addr(addr)) {
4351 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
4352 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
4353
4354 if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
4355 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
4356 NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
4357 NL80211_KEYTYPE_GROUP);
4358 }
4359 } else if (addr && is_broadcast_ether_addr(addr)) {
4360 struct nl_msg *types;
4361 int err;
4362 wpa_printf(MSG_DEBUG, " broadcast key");
4363 types = nlmsg_alloc();
4364 if (!types)
4365 goto nla_put_failure;
4366 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
4367 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4368 types);
4369 nlmsg_free(types);
4370 if (err)
4371 goto nla_put_failure;
4372 }
4373 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
4374 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
4375
4376 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4377 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
4378 ret = 0;
4379 if (ret)
4380 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
4381 ret, strerror(-ret));
4382
4383 /*
4384 * If we failed or don't need to set the default TX key (below),
4385 * we're done here.
4386 */
4387 if (ret || !set_tx || alg == WPA_ALG_NONE)
4388 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004389 if (is_ap_interface(drv->nlmode) && addr &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004390 !is_broadcast_ether_addr(addr))
4391 return ret;
4392
4393 msg = nlmsg_alloc();
4394 if (!msg)
4395 return -ENOMEM;
4396
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004397 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004398 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
4399 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
4400 if (alg == WPA_ALG_IGTK)
4401 NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
4402 else
4403 NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
4404 if (addr && is_broadcast_ether_addr(addr)) {
4405 struct nl_msg *types;
4406 int err;
4407 types = nlmsg_alloc();
4408 if (!types)
4409 goto nla_put_failure;
4410 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
4411 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4412 types);
4413 nlmsg_free(types);
4414 if (err)
4415 goto nla_put_failure;
4416 } else if (addr) {
4417 struct nl_msg *types;
4418 int err;
4419 types = nlmsg_alloc();
4420 if (!types)
4421 goto nla_put_failure;
4422 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
4423 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4424 types);
4425 nlmsg_free(types);
4426 if (err)
4427 goto nla_put_failure;
4428 }
4429
4430 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4431 if (ret == -ENOENT)
4432 ret = 0;
4433 if (ret)
4434 wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
4435 "err=%d %s)", ret, strerror(-ret));
4436 return ret;
4437
4438nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004439 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004440 return -ENOBUFS;
4441}
4442
4443
4444static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
4445 int key_idx, int defkey,
4446 const u8 *seq, size_t seq_len,
4447 const u8 *key, size_t key_len)
4448{
4449 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
4450 if (!key_attr)
4451 return -1;
4452
4453 if (defkey && alg == WPA_ALG_IGTK)
4454 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
4455 else if (defkey)
4456 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
4457
4458 NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
4459
4460 switch (alg) {
4461 case WPA_ALG_WEP:
4462 if (key_len == 5)
4463 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4464 WLAN_CIPHER_SUITE_WEP40);
4465 else
4466 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4467 WLAN_CIPHER_SUITE_WEP104);
4468 break;
4469 case WPA_ALG_TKIP:
4470 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
4471 break;
4472 case WPA_ALG_CCMP:
4473 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
4474 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004475 case WPA_ALG_GCMP:
4476 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
4477 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004478 case WPA_ALG_IGTK:
4479 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4480 WLAN_CIPHER_SUITE_AES_CMAC);
4481 break;
4482 default:
4483 wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
4484 "algorithm %d", __func__, alg);
4485 return -1;
4486 }
4487
4488 if (seq && seq_len)
4489 NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
4490
4491 NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
4492
4493 nla_nest_end(msg, key_attr);
4494
4495 return 0;
4496 nla_put_failure:
4497 return -1;
4498}
4499
4500
4501static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
4502 struct nl_msg *msg)
4503{
4504 int i, privacy = 0;
4505 struct nlattr *nl_keys, *nl_key;
4506
4507 for (i = 0; i < 4; i++) {
4508 if (!params->wep_key[i])
4509 continue;
4510 privacy = 1;
4511 break;
4512 }
4513 if (params->wps == WPS_MODE_PRIVACY)
4514 privacy = 1;
4515 if (params->pairwise_suite &&
4516 params->pairwise_suite != WPA_CIPHER_NONE)
4517 privacy = 1;
4518
4519 if (!privacy)
4520 return 0;
4521
4522 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
4523
4524 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
4525 if (!nl_keys)
4526 goto nla_put_failure;
4527
4528 for (i = 0; i < 4; i++) {
4529 if (!params->wep_key[i])
4530 continue;
4531
4532 nl_key = nla_nest_start(msg, i);
4533 if (!nl_key)
4534 goto nla_put_failure;
4535
4536 NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
4537 params->wep_key[i]);
4538 if (params->wep_key_len[i] == 5)
4539 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4540 WLAN_CIPHER_SUITE_WEP40);
4541 else
4542 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4543 WLAN_CIPHER_SUITE_WEP104);
4544
4545 NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
4546
4547 if (i == params->wep_tx_keyidx)
4548 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
4549
4550 nla_nest_end(msg, nl_key);
4551 }
4552 nla_nest_end(msg, nl_keys);
4553
4554 return 0;
4555
4556nla_put_failure:
4557 return -ENOBUFS;
4558}
4559
4560
4561static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
4562 const u8 *addr, int cmd, u16 reason_code,
4563 int local_state_change)
4564{
4565 int ret = -1;
4566 struct nl_msg *msg;
4567
4568 msg = nlmsg_alloc();
4569 if (!msg)
4570 return -1;
4571
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004572 nl80211_cmd(drv, msg, 0, cmd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004573
4574 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4575 NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004576 if (addr)
4577 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004578 if (local_state_change)
4579 NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
4580
4581 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4582 msg = NULL;
4583 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004584 wpa_dbg(drv->ctx, MSG_DEBUG,
4585 "nl80211: MLME command failed: reason=%u ret=%d (%s)",
4586 reason_code, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004587 goto nla_put_failure;
4588 }
4589 ret = 0;
4590
4591nla_put_failure:
4592 nlmsg_free(msg);
4593 return ret;
4594}
4595
4596
4597static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004598 int reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004599{
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004600 wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004601 drv->associated = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004602 drv->ignore_next_local_disconnect = 0;
4603 /* Disconnect command doesn't need BSSID - it uses cached value */
4604 return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004605 reason_code, 0);
4606}
4607
4608
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004609static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
4610 const u8 *addr, int reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004611{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004612 struct wpa_driver_nl80211_data *drv = bss->drv;
4613 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004614 return wpa_driver_nl80211_disconnect(drv, reason_code);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004615 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
4616 __func__, MAC2STR(addr), reason_code);
4617 drv->associated = 0;
4618 if (drv->nlmode == NL80211_IFTYPE_ADHOC)
4619 return nl80211_leave_ibss(drv);
4620 return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
4621 reason_code, 0);
4622}
4623
4624
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004625static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
4626 struct wpa_driver_auth_params *params)
4627{
4628 int i;
4629
4630 drv->auth_freq = params->freq;
4631 drv->auth_alg = params->auth_alg;
4632 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
4633 drv->auth_local_state_change = params->local_state_change;
4634 drv->auth_p2p = params->p2p;
4635
4636 if (params->bssid)
4637 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
4638 else
4639 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
4640
4641 if (params->ssid) {
4642 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
4643 drv->auth_ssid_len = params->ssid_len;
4644 } else
4645 drv->auth_ssid_len = 0;
4646
4647
4648 os_free(drv->auth_ie);
4649 drv->auth_ie = NULL;
4650 drv->auth_ie_len = 0;
4651 if (params->ie) {
4652 drv->auth_ie = os_malloc(params->ie_len);
4653 if (drv->auth_ie) {
4654 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
4655 drv->auth_ie_len = params->ie_len;
4656 }
4657 }
4658
4659 for (i = 0; i < 4; i++) {
4660 if (params->wep_key[i] && params->wep_key_len[i] &&
4661 params->wep_key_len[i] <= 16) {
4662 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
4663 params->wep_key_len[i]);
4664 drv->auth_wep_key_len[i] = params->wep_key_len[i];
4665 } else
4666 drv->auth_wep_key_len[i] = 0;
4667 }
4668}
4669
4670
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004671static int wpa_driver_nl80211_authenticate(
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004672 struct i802_bss *bss, struct wpa_driver_auth_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004673{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004674 struct wpa_driver_nl80211_data *drv = bss->drv;
4675 int ret = -1, i;
4676 struct nl_msg *msg;
4677 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004678 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004679 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004680 int is_retry;
4681
4682 is_retry = drv->retry_auth;
4683 drv->retry_auth = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004684
4685 drv->associated = 0;
4686 os_memset(drv->auth_bssid, 0, ETH_ALEN);
4687 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004688 nlmode = params->p2p ?
4689 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
4690 if (drv->nlmode != nlmode &&
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004691 wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004692 return -1;
4693
4694retry:
4695 msg = nlmsg_alloc();
4696 if (!msg)
4697 return -1;
4698
4699 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
4700 drv->ifindex);
4701
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004702 nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004703
4704 for (i = 0; i < 4; i++) {
4705 if (!params->wep_key[i])
4706 continue;
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08004707 wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004708 NULL, i,
4709 i == params->wep_tx_keyidx, NULL, 0,
4710 params->wep_key[i],
4711 params->wep_key_len[i]);
4712 if (params->wep_tx_keyidx != i)
4713 continue;
4714 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
4715 params->wep_key[i], params->wep_key_len[i])) {
4716 nlmsg_free(msg);
4717 return -1;
4718 }
4719 }
4720
4721 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4722 if (params->bssid) {
4723 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
4724 MAC2STR(params->bssid));
4725 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
4726 }
4727 if (params->freq) {
4728 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
4729 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
4730 }
4731 if (params->ssid) {
4732 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
4733 params->ssid, params->ssid_len);
4734 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
4735 params->ssid);
4736 }
4737 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
4738 if (params->ie)
4739 NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004740 if (params->sae_data) {
4741 wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data,
4742 params->sae_data_len);
4743 NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
4744 params->sae_data);
4745 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004746 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
4747 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
4748 else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
4749 type = NL80211_AUTHTYPE_SHARED_KEY;
4750 else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
4751 type = NL80211_AUTHTYPE_NETWORK_EAP;
4752 else if (params->auth_alg & WPA_AUTH_ALG_FT)
4753 type = NL80211_AUTHTYPE_FT;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004754 else if (params->auth_alg & WPA_AUTH_ALG_SAE)
4755 type = NL80211_AUTHTYPE_SAE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004756 else
4757 goto nla_put_failure;
4758 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
4759 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
4760 if (params->local_state_change) {
4761 wpa_printf(MSG_DEBUG, " * Local state change only");
4762 NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
4763 }
4764
4765 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4766 msg = NULL;
4767 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004768 wpa_dbg(drv->ctx, MSG_DEBUG,
4769 "nl80211: MLME command failed (auth): ret=%d (%s)",
4770 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004771 count++;
4772 if (ret == -EALREADY && count == 1 && params->bssid &&
4773 !params->local_state_change) {
4774 /*
4775 * mac80211 does not currently accept new
4776 * authentication if we are already authenticated. As a
4777 * workaround, force deauthentication and try again.
4778 */
4779 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
4780 "after forced deauthentication");
4781 wpa_driver_nl80211_deauthenticate(
4782 bss, params->bssid,
4783 WLAN_REASON_PREV_AUTH_NOT_VALID);
4784 nlmsg_free(msg);
4785 goto retry;
4786 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004787
4788 if (ret == -ENOENT && params->freq && !is_retry) {
4789 /*
4790 * cfg80211 has likely expired the BSS entry even
4791 * though it was previously available in our internal
4792 * BSS table. To recover quickly, start a single
4793 * channel scan on the specified channel.
4794 */
4795 struct wpa_driver_scan_params scan;
4796 int freqs[2];
4797
4798 os_memset(&scan, 0, sizeof(scan));
4799 scan.num_ssids = 1;
4800 if (params->ssid) {
4801 scan.ssids[0].ssid = params->ssid;
4802 scan.ssids[0].ssid_len = params->ssid_len;
4803 }
4804 freqs[0] = params->freq;
4805 freqs[1] = 0;
4806 scan.freqs = freqs;
4807 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
4808 "channel scan to refresh cfg80211 BSS "
4809 "entry");
4810 ret = wpa_driver_nl80211_scan(bss, &scan);
4811 if (ret == 0) {
4812 nl80211_copy_auth_params(drv, params);
4813 drv->scan_for_auth = 1;
4814 }
4815 } else if (is_retry) {
4816 /*
4817 * Need to indicate this with an event since the return
4818 * value from the retry is not delivered to core code.
4819 */
4820 union wpa_event_data event;
4821 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
4822 "failed");
4823 os_memset(&event, 0, sizeof(event));
4824 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
4825 ETH_ALEN);
4826 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
4827 &event);
4828 }
4829
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004830 goto nla_put_failure;
4831 }
4832 ret = 0;
4833 wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
4834 "successfully");
4835
4836nla_put_failure:
4837 nlmsg_free(msg);
4838 return ret;
4839}
4840
4841
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004842static int wpa_driver_nl80211_authenticate_retry(
4843 struct wpa_driver_nl80211_data *drv)
4844{
4845 struct wpa_driver_auth_params params;
4846 struct i802_bss *bss = &drv->first_bss;
4847 int i;
4848
4849 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
4850
4851 os_memset(&params, 0, sizeof(params));
4852 params.freq = drv->auth_freq;
4853 params.auth_alg = drv->auth_alg;
4854 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
4855 params.local_state_change = drv->auth_local_state_change;
4856 params.p2p = drv->auth_p2p;
4857
4858 if (!is_zero_ether_addr(drv->auth_bssid_))
4859 params.bssid = drv->auth_bssid_;
4860
4861 if (drv->auth_ssid_len) {
4862 params.ssid = drv->auth_ssid;
4863 params.ssid_len = drv->auth_ssid_len;
4864 }
4865
4866 params.ie = drv->auth_ie;
4867 params.ie_len = drv->auth_ie_len;
4868
4869 for (i = 0; i < 4; i++) {
4870 if (drv->auth_wep_key_len[i]) {
4871 params.wep_key[i] = drv->auth_wep_key[i];
4872 params.wep_key_len[i] = drv->auth_wep_key_len[i];
4873 }
4874 }
4875
4876 drv->retry_auth = 1;
4877 return wpa_driver_nl80211_authenticate(bss, &params);
4878}
4879
4880
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004881struct phy_info_arg {
4882 u16 *num_modes;
4883 struct hostapd_hw_modes *modes;
4884};
4885
4886static int phy_info_handler(struct nl_msg *msg, void *arg)
4887{
4888 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
4889 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
4890 struct phy_info_arg *phy_info = arg;
4891
4892 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
4893
4894 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
4895 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
4896 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
4897 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
4898 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
4899 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
4900 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
4901 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
4902 };
4903
4904 struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
4905 static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
4906 [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
4907 [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
4908 };
4909
4910 struct nlattr *nl_band;
4911 struct nlattr *nl_freq;
4912 struct nlattr *nl_rate;
4913 int rem_band, rem_freq, rem_rate;
4914 struct hostapd_hw_modes *mode;
4915 int idx, mode_is_set;
4916
4917 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
4918 genlmsg_attrlen(gnlh, 0), NULL);
4919
4920 if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
4921 return NL_SKIP;
4922
4923 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004924 mode = os_realloc_array(phy_info->modes,
4925 *phy_info->num_modes + 1,
4926 sizeof(*mode));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004927 if (!mode)
4928 return NL_SKIP;
4929 phy_info->modes = mode;
4930
4931 mode_is_set = 0;
4932
4933 mode = &phy_info->modes[*(phy_info->num_modes)];
4934 memset(mode, 0, sizeof(*mode));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004935 mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004936 *(phy_info->num_modes) += 1;
4937
4938 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
4939 nla_len(nl_band), NULL);
4940
4941 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
4942 mode->ht_capab = nla_get_u16(
4943 tb_band[NL80211_BAND_ATTR_HT_CAPA]);
4944 }
4945
4946 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
4947 mode->a_mpdu_params |= nla_get_u8(
4948 tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
4949 0x03;
4950 }
4951
4952 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
4953 mode->a_mpdu_params |= nla_get_u8(
4954 tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
4955 2;
4956 }
4957
4958 if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
4959 nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
4960 u8 *mcs;
4961 mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
4962 os_memcpy(mode->mcs_set, mcs, 16);
4963 }
4964
Dmitry Shmidt04949592012-07-19 12:16:46 -07004965 if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
4966 mode->vht_capab = nla_get_u32(
4967 tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
4968 }
4969
4970 if (tb_band[NL80211_BAND_ATTR_VHT_MCS_SET] &&
4971 nla_len(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])) {
4972 u8 *mcs;
4973 mcs = nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
4974 os_memcpy(mode->vht_mcs_set, mcs, 8);
4975 }
4976
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004977 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
4978 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
4979 nla_len(nl_freq), freq_policy);
4980 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
4981 continue;
4982 mode->num_channels++;
4983 }
4984
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004985 mode->channels = os_calloc(mode->num_channels,
4986 sizeof(struct hostapd_channel_data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004987 if (!mode->channels)
4988 return NL_SKIP;
4989
4990 idx = 0;
4991
4992 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
4993 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
4994 nla_len(nl_freq), freq_policy);
4995 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
4996 continue;
4997
4998 mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
4999 mode->channels[idx].flag = 0;
5000
5001 if (!mode_is_set) {
5002 /* crude heuristic */
5003 if (mode->channels[idx].freq < 4000)
5004 mode->mode = HOSTAPD_MODE_IEEE80211B;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005005 else if (mode->channels[idx].freq > 50000)
5006 mode->mode = HOSTAPD_MODE_IEEE80211AD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005007 else
5008 mode->mode = HOSTAPD_MODE_IEEE80211A;
5009 mode_is_set = 1;
5010 }
5011
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005012 switch (mode->mode) {
5013 case HOSTAPD_MODE_IEEE80211AD:
5014 mode->channels[idx].chan =
5015 (mode->channels[idx].freq - 56160) /
5016 2160;
5017 break;
5018 case HOSTAPD_MODE_IEEE80211A:
5019 mode->channels[idx].chan =
5020 mode->channels[idx].freq / 5 - 1000;
5021 break;
5022 case HOSTAPD_MODE_IEEE80211B:
5023 case HOSTAPD_MODE_IEEE80211G:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005024 if (mode->channels[idx].freq == 2484)
5025 mode->channels[idx].chan = 14;
5026 else
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005027 mode->channels[idx].chan =
5028 (mode->channels[idx].freq -
5029 2407) / 5;
5030 break;
5031 default:
5032 break;
5033 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005034
5035 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
5036 mode->channels[idx].flag |=
5037 HOSTAPD_CHAN_DISABLED;
5038 if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
5039 mode->channels[idx].flag |=
5040 HOSTAPD_CHAN_PASSIVE_SCAN;
5041 if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
5042 mode->channels[idx].flag |=
5043 HOSTAPD_CHAN_NO_IBSS;
5044 if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
5045 mode->channels[idx].flag |=
5046 HOSTAPD_CHAN_RADAR;
5047
5048 if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
5049 !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
5050 mode->channels[idx].max_tx_power =
5051 nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
5052
5053 idx++;
5054 }
5055
5056 nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
5057 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
5058 nla_len(nl_rate), rate_policy);
5059 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
5060 continue;
5061 mode->num_rates++;
5062 }
5063
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005064 mode->rates = os_calloc(mode->num_rates, sizeof(int));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005065 if (!mode->rates)
5066 return NL_SKIP;
5067
5068 idx = 0;
5069
5070 nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
5071 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
5072 nla_len(nl_rate), rate_policy);
5073 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
5074 continue;
5075 mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
5076
5077 /* crude heuristic */
5078 if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
5079 mode->rates[idx] > 200)
5080 mode->mode = HOSTAPD_MODE_IEEE80211G;
5081
5082 idx++;
5083 }
5084 }
5085
5086 return NL_SKIP;
5087}
5088
5089static struct hostapd_hw_modes *
5090wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
5091{
5092 u16 m;
5093 struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
5094 int i, mode11g_idx = -1;
5095
5096 /* If only 802.11g mode is included, use it to construct matching
5097 * 802.11b mode data. */
5098
5099 for (m = 0; m < *num_modes; m++) {
5100 if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
5101 return modes; /* 802.11b already included */
5102 if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
5103 mode11g_idx = m;
5104 }
5105
5106 if (mode11g_idx < 0)
5107 return modes; /* 2.4 GHz band not supported at all */
5108
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005109 nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005110 if (nmodes == NULL)
5111 return modes; /* Could not add 802.11b mode */
5112
5113 mode = &nmodes[*num_modes];
5114 os_memset(mode, 0, sizeof(*mode));
5115 (*num_modes)++;
5116 modes = nmodes;
5117
5118 mode->mode = HOSTAPD_MODE_IEEE80211B;
5119
5120 mode11g = &modes[mode11g_idx];
5121 mode->num_channels = mode11g->num_channels;
5122 mode->channels = os_malloc(mode11g->num_channels *
5123 sizeof(struct hostapd_channel_data));
5124 if (mode->channels == NULL) {
5125 (*num_modes)--;
5126 return modes; /* Could not add 802.11b mode */
5127 }
5128 os_memcpy(mode->channels, mode11g->channels,
5129 mode11g->num_channels * sizeof(struct hostapd_channel_data));
5130
5131 mode->num_rates = 0;
5132 mode->rates = os_malloc(4 * sizeof(int));
5133 if (mode->rates == NULL) {
5134 os_free(mode->channels);
5135 (*num_modes)--;
5136 return modes; /* Could not add 802.11b mode */
5137 }
5138
5139 for (i = 0; i < mode11g->num_rates; i++) {
5140 if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
5141 mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
5142 continue;
5143 mode->rates[mode->num_rates] = mode11g->rates[i];
5144 mode->num_rates++;
5145 if (mode->num_rates == 4)
5146 break;
5147 }
5148
5149 if (mode->num_rates == 0) {
5150 os_free(mode->channels);
5151 os_free(mode->rates);
5152 (*num_modes)--;
5153 return modes; /* No 802.11b rates */
5154 }
5155
5156 wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
5157 "information");
5158
5159 return modes;
5160}
5161
5162
5163static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
5164 int end)
5165{
5166 int c;
5167
5168 for (c = 0; c < mode->num_channels; c++) {
5169 struct hostapd_channel_data *chan = &mode->channels[c];
5170 if (chan->freq - 10 >= start && chan->freq + 10 <= end)
5171 chan->flag |= HOSTAPD_CHAN_HT40;
5172 }
5173}
5174
5175
5176static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
5177 int end)
5178{
5179 int c;
5180
5181 for (c = 0; c < mode->num_channels; c++) {
5182 struct hostapd_channel_data *chan = &mode->channels[c];
5183 if (!(chan->flag & HOSTAPD_CHAN_HT40))
5184 continue;
5185 if (chan->freq - 30 >= start && chan->freq - 10 <= end)
5186 chan->flag |= HOSTAPD_CHAN_HT40MINUS;
5187 if (chan->freq + 10 >= start && chan->freq + 30 <= end)
5188 chan->flag |= HOSTAPD_CHAN_HT40PLUS;
5189 }
5190}
5191
5192
5193static void nl80211_reg_rule_ht40(struct nlattr *tb[],
5194 struct phy_info_arg *results)
5195{
5196 u32 start, end, max_bw;
5197 u16 m;
5198
5199 if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
5200 tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
5201 tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
5202 return;
5203
5204 start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
5205 end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
5206 max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
5207
5208 wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
5209 start, end, max_bw);
5210 if (max_bw < 40)
5211 return;
5212
5213 for (m = 0; m < *results->num_modes; m++) {
5214 if (!(results->modes[m].ht_capab &
5215 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
5216 continue;
5217 nl80211_set_ht40_mode(&results->modes[m], start, end);
5218 }
5219}
5220
5221
5222static void nl80211_reg_rule_sec(struct nlattr *tb[],
5223 struct phy_info_arg *results)
5224{
5225 u32 start, end, max_bw;
5226 u16 m;
5227
5228 if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
5229 tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
5230 tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
5231 return;
5232
5233 start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
5234 end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
5235 max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
5236
5237 if (max_bw < 20)
5238 return;
5239
5240 for (m = 0; m < *results->num_modes; m++) {
5241 if (!(results->modes[m].ht_capab &
5242 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
5243 continue;
5244 nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
5245 }
5246}
5247
5248
5249static int nl80211_get_reg(struct nl_msg *msg, void *arg)
5250{
5251 struct phy_info_arg *results = arg;
5252 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
5253 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
5254 struct nlattr *nl_rule;
5255 struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
5256 int rem_rule;
5257 static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
5258 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
5259 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
5260 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
5261 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
5262 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
5263 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
5264 };
5265
5266 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
5267 genlmsg_attrlen(gnlh, 0), NULL);
5268 if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
5269 !tb_msg[NL80211_ATTR_REG_RULES]) {
5270 wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
5271 "available");
5272 return NL_SKIP;
5273 }
5274
5275 wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
5276 (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
5277
5278 nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
5279 {
5280 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
5281 nla_data(nl_rule), nla_len(nl_rule), reg_policy);
5282 nl80211_reg_rule_ht40(tb_rule, results);
5283 }
5284
5285 nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
5286 {
5287 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
5288 nla_data(nl_rule), nla_len(nl_rule), reg_policy);
5289 nl80211_reg_rule_sec(tb_rule, results);
5290 }
5291
5292 return NL_SKIP;
5293}
5294
5295
5296static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
5297 struct phy_info_arg *results)
5298{
5299 struct nl_msg *msg;
5300
5301 msg = nlmsg_alloc();
5302 if (!msg)
5303 return -ENOMEM;
5304
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005305 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005306 return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
5307}
5308
5309
5310static struct hostapd_hw_modes *
5311wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
5312{
5313 struct i802_bss *bss = priv;
5314 struct wpa_driver_nl80211_data *drv = bss->drv;
5315 struct nl_msg *msg;
5316 struct phy_info_arg result = {
5317 .num_modes = num_modes,
5318 .modes = NULL,
5319 };
5320
5321 *num_modes = 0;
5322 *flags = 0;
5323
5324 msg = nlmsg_alloc();
5325 if (!msg)
5326 return NULL;
5327
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005328 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005329
5330 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
5331
5332 if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
5333 nl80211_set_ht40_flags(drv, &result);
5334 return wpa_driver_nl80211_add_11b(result.modes, num_modes);
5335 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005336 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005337 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005338 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005339 return NULL;
5340}
5341
5342
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005343static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
5344 const void *data, size_t len,
5345 int encrypt, int noack)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005346{
5347 __u8 rtap_hdr[] = {
5348 0x00, 0x00, /* radiotap version */
5349 0x0e, 0x00, /* radiotap length */
5350 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
5351 IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
5352 0x00, /* padding */
5353 0x00, 0x00, /* RX and TX flags to indicate that */
5354 0x00, 0x00, /* this is the injected frame directly */
5355 };
5356 struct iovec iov[2] = {
5357 {
5358 .iov_base = &rtap_hdr,
5359 .iov_len = sizeof(rtap_hdr),
5360 },
5361 {
5362 .iov_base = (void *) data,
5363 .iov_len = len,
5364 }
5365 };
5366 struct msghdr msg = {
5367 .msg_name = NULL,
5368 .msg_namelen = 0,
5369 .msg_iov = iov,
5370 .msg_iovlen = 2,
5371 .msg_control = NULL,
5372 .msg_controllen = 0,
5373 .msg_flags = 0,
5374 };
5375 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005376 u16 txflags = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005377
5378 if (encrypt)
5379 rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
5380
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07005381 if (drv->monitor_sock < 0) {
5382 wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
5383 "for %s", __func__);
5384 return -1;
5385 }
5386
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005387 if (noack)
5388 txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005389 WPA_PUT_LE16(&rtap_hdr[12], txflags);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005390
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005391 res = sendmsg(drv->monitor_sock, &msg, 0);
5392 if (res < 0) {
5393 wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
5394 return -1;
5395 }
5396 return 0;
5397}
5398
5399
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005400static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
5401 const void *data, size_t len,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005402 int encrypt, int noack,
5403 unsigned int freq, int no_cck,
5404 int offchanok, unsigned int wait_time)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005405{
5406 struct wpa_driver_nl80211_data *drv = bss->drv;
5407 u64 cookie;
5408
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005409 if (freq == 0)
5410 freq = bss->freq;
5411
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005412 if (drv->use_monitor)
5413 return wpa_driver_nl80211_send_mntr(drv, data, len,
5414 encrypt, noack);
5415
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005416 return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
5417 &cookie, no_cck, noack, offchanok);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005418}
5419
5420
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005421static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
5422 size_t data_len, int noack,
5423 unsigned int freq, int no_cck,
5424 int offchanok,
5425 unsigned int wait_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005426{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005427 struct wpa_driver_nl80211_data *drv = bss->drv;
5428 struct ieee80211_mgmt *mgmt;
5429 int encrypt = 1;
5430 u16 fc;
5431
5432 mgmt = (struct ieee80211_mgmt *) data;
5433 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005434
5435 if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005436 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
5437 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
5438 /*
5439 * The use of last_mgmt_freq is a bit of a hack,
5440 * but it works due to the single-threaded nature
5441 * of wpa_supplicant.
5442 */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005443 if (freq == 0)
5444 freq = drv->last_mgmt_freq;
5445 return nl80211_send_frame_cmd(bss, freq, 0,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005446 data, data_len, NULL, 1, noack,
5447 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005448 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005449
5450 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005451 if (freq == 0)
5452 freq = bss->freq;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005453 return nl80211_send_frame_cmd(bss, freq,
5454 (int) freq == bss->freq ? 0 :
5455 wait_time,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005456 data, data_len,
5457 &drv->send_action_cookie,
5458 no_cck, noack, offchanok);
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07005459 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07005460
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005461 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
5462 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
5463 /*
5464 * Only one of the authentication frame types is encrypted.
5465 * In order for static WEP encryption to work properly (i.e.,
5466 * to not encrypt the frame), we need to tell mac80211 about
5467 * the frames that must not be encrypted.
5468 */
5469 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
5470 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
5471 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
5472 encrypt = 0;
5473 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005474
5475 return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005476 noack, freq, no_cck, offchanok,
5477 wait_time);
5478}
5479
5480
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005481static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
5482 int slot, int ht_opmode, int ap_isolate,
5483 int *basic_rates)
5484{
5485 struct wpa_driver_nl80211_data *drv = bss->drv;
5486 struct nl_msg *msg;
5487
5488 msg = nlmsg_alloc();
5489 if (!msg)
5490 return -ENOMEM;
5491
5492 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
5493
5494 if (cts >= 0)
5495 NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
5496 if (preamble >= 0)
5497 NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
5498 if (slot >= 0)
5499 NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
5500 if (ht_opmode >= 0)
5501 NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
5502 if (ap_isolate >= 0)
5503 NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
5504
5505 if (basic_rates) {
5506 u8 rates[NL80211_MAX_SUPP_RATES];
5507 u8 rates_len = 0;
5508 int i;
5509
5510 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
5511 i++)
5512 rates[rates_len++] = basic_rates[i] / 5;
5513
5514 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
5515 }
5516
5517 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
5518
5519 return send_and_recv_msgs(drv, msg, NULL, NULL);
5520 nla_put_failure:
5521 nlmsg_free(msg);
5522 return -ENOBUFS;
5523}
5524
5525
5526static int wpa_driver_nl80211_set_ap(void *priv,
5527 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005528{
5529 struct i802_bss *bss = priv;
5530 struct wpa_driver_nl80211_data *drv = bss->drv;
5531 struct nl_msg *msg;
5532 u8 cmd = NL80211_CMD_NEW_BEACON;
5533 int ret;
5534 int beacon_set;
5535 int ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005536 int num_suites;
5537 u32 suites[10];
5538 u32 ver;
5539
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07005540 beacon_set = bss->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005541
5542 msg = nlmsg_alloc();
5543 if (!msg)
5544 return -ENOMEM;
5545
5546 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
5547 beacon_set);
5548 if (beacon_set)
5549 cmd = NL80211_CMD_SET_BEACON;
5550
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005551 nl80211_cmd(drv, msg, 0, cmd);
5552 NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
5553 NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005554 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005555 NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
5556 NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
5557 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
5558 params->ssid);
5559 if (params->proberesp && params->proberesp_len)
5560 NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
5561 params->proberesp);
5562 switch (params->hide_ssid) {
5563 case NO_SSID_HIDING:
5564 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5565 NL80211_HIDDEN_SSID_NOT_IN_USE);
5566 break;
5567 case HIDDEN_SSID_ZERO_LEN:
5568 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5569 NL80211_HIDDEN_SSID_ZERO_LEN);
5570 break;
5571 case HIDDEN_SSID_ZERO_CONTENTS:
5572 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5573 NL80211_HIDDEN_SSID_ZERO_CONTENTS);
5574 break;
5575 }
5576 if (params->privacy)
5577 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
5578 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
5579 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
5580 /* Leave out the attribute */
5581 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
5582 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
5583 NL80211_AUTHTYPE_SHARED_KEY);
5584 else
5585 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
5586 NL80211_AUTHTYPE_OPEN_SYSTEM);
5587
5588 ver = 0;
5589 if (params->wpa_version & WPA_PROTO_WPA)
5590 ver |= NL80211_WPA_VERSION_1;
5591 if (params->wpa_version & WPA_PROTO_RSN)
5592 ver |= NL80211_WPA_VERSION_2;
5593 if (ver)
5594 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
5595
5596 num_suites = 0;
5597 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
5598 suites[num_suites++] = WLAN_AKM_SUITE_8021X;
5599 if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
5600 suites[num_suites++] = WLAN_AKM_SUITE_PSK;
5601 if (num_suites) {
5602 NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
5603 num_suites * sizeof(u32), suites);
5604 }
5605
5606 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
5607 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
5608 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
5609
5610 num_suites = 0;
5611 if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
5612 suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005613 if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
5614 suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005615 if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
5616 suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
5617 if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
5618 suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
5619 if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
5620 suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
5621 if (num_suites) {
5622 NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
5623 num_suites * sizeof(u32), suites);
5624 }
5625
5626 switch (params->group_cipher) {
5627 case WPA_CIPHER_CCMP:
5628 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5629 WLAN_CIPHER_SUITE_CCMP);
5630 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005631 case WPA_CIPHER_GCMP:
5632 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5633 WLAN_CIPHER_SUITE_GCMP);
5634 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005635 case WPA_CIPHER_TKIP:
5636 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5637 WLAN_CIPHER_SUITE_TKIP);
5638 break;
5639 case WPA_CIPHER_WEP104:
5640 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5641 WLAN_CIPHER_SUITE_WEP104);
5642 break;
5643 case WPA_CIPHER_WEP40:
5644 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5645 WLAN_CIPHER_SUITE_WEP40);
5646 break;
5647 }
5648
5649 if (params->beacon_ies) {
5650 NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
5651 wpabuf_head(params->beacon_ies));
5652 }
5653 if (params->proberesp_ies) {
5654 NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
5655 wpabuf_len(params->proberesp_ies),
5656 wpabuf_head(params->proberesp_ies));
5657 }
5658 if (params->assocresp_ies) {
5659 NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
5660 wpabuf_len(params->assocresp_ies),
5661 wpabuf_head(params->assocresp_ies));
5662 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005663
Dmitry Shmidt04949592012-07-19 12:16:46 -07005664 if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
5665 NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
5666 params->ap_max_inactivity);
5667 }
5668
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005669 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5670 if (ret) {
5671 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
5672 ret, strerror(-ret));
5673 } else {
5674 bss->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005675 nl80211_set_bss(bss, params->cts_protect, params->preamble,
5676 params->short_slot_time, params->ht_opmode,
5677 params->isolate, params->basic_rates);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005678 }
5679 return ret;
5680 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005681 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005682 return -ENOBUFS;
5683}
5684
5685
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005686static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005687 struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005688{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005689 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005690 struct nl_msg *msg;
5691 int ret;
5692
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005693 wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
5694 " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
5695 freq->freq, freq->ht_enabled, freq->vht_enabled,
5696 freq->bandwidth, freq->center_freq1, freq->center_freq2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005697 msg = nlmsg_alloc();
5698 if (!msg)
5699 return -1;
5700
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005701 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005702
5703 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005704 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
5705 if (freq->vht_enabled) {
5706 switch (freq->bandwidth) {
5707 case 20:
5708 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5709 NL80211_CHAN_WIDTH_20);
5710 break;
5711 case 40:
5712 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5713 NL80211_CHAN_WIDTH_40);
5714 break;
5715 case 80:
5716 if (freq->center_freq2)
5717 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5718 NL80211_CHAN_WIDTH_80P80);
5719 else
5720 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5721 NL80211_CHAN_WIDTH_80);
5722 break;
5723 case 160:
5724 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5725 NL80211_CHAN_WIDTH_160);
5726 break;
5727 default:
5728 return -1;
5729 }
5730 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
5731 if (freq->center_freq2)
5732 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
5733 freq->center_freq2);
5734 } else if (freq->ht_enabled) {
5735 switch (freq->sec_channel_offset) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005736 case -1:
5737 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5738 NL80211_CHAN_HT40MINUS);
5739 break;
5740 case 1:
5741 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5742 NL80211_CHAN_HT40PLUS);
5743 break;
5744 default:
5745 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5746 NL80211_CHAN_HT20);
5747 break;
5748 }
5749 }
5750
5751 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005752 msg = NULL;
5753 if (ret == 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005754 bss->freq = freq->freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005755 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005756 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005757 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005758 "%d (%s)", freq->freq, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005759nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005760 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005761 return -1;
5762}
5763
5764
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005765static u32 sta_flags_nl80211(int flags)
5766{
5767 u32 f = 0;
5768
5769 if (flags & WPA_STA_AUTHORIZED)
5770 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
5771 if (flags & WPA_STA_WMM)
5772 f |= BIT(NL80211_STA_FLAG_WME);
5773 if (flags & WPA_STA_SHORT_PREAMBLE)
5774 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
5775 if (flags & WPA_STA_MFP)
5776 f |= BIT(NL80211_STA_FLAG_MFP);
5777 if (flags & WPA_STA_TDLS_PEER)
5778 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
5779
5780 return f;
5781}
5782
5783
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005784static int wpa_driver_nl80211_sta_add(void *priv,
5785 struct hostapd_sta_add_params *params)
5786{
5787 struct i802_bss *bss = priv;
5788 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005789 struct nl_msg *msg, *wme = NULL;
5790 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005791 int ret = -ENOBUFS;
5792
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005793 if ((params->flags & WPA_STA_TDLS_PEER) &&
5794 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
5795 return -EOPNOTSUPP;
5796
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005797 msg = nlmsg_alloc();
5798 if (!msg)
5799 return -ENOMEM;
5800
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005801 nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
5802 NL80211_CMD_NEW_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005803
5804 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
5805 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005806 NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
5807 params->supp_rates);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005808 if (!params->set) {
5809 NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
5810 NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5811 params->listen_interval);
5812 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005813 if (params->ht_capabilities) {
5814 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
5815 sizeof(*params->ht_capabilities),
5816 params->ht_capabilities);
5817 }
5818
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005819 if (params->vht_capabilities) {
5820 NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
5821 sizeof(*params->vht_capabilities),
5822 params->vht_capabilities);
5823 }
5824
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005825 os_memset(&upd, 0, sizeof(upd));
5826 upd.mask = sta_flags_nl80211(params->flags);
5827 upd.set = upd.mask;
5828 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
5829
5830 if (params->flags & WPA_STA_WMM) {
5831 wme = nlmsg_alloc();
5832 if (!wme)
5833 goto nla_put_failure;
5834
5835 NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
5836 params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
5837 NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
5838 (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
5839 WMM_QOSINFO_STA_SP_MASK);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005840 if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
5841 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005842 }
5843
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005844 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005845 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005846 if (ret)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005847 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
5848 "result: %d (%s)", params->set ? "SET" : "NEW", ret,
5849 strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005850 if (ret == -EEXIST)
5851 ret = 0;
5852 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005853 nlmsg_free(wme);
5854 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005855 return ret;
5856}
5857
5858
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08005859static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005860{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005861 struct wpa_driver_nl80211_data *drv = bss->drv;
5862 struct nl_msg *msg;
5863 int ret;
5864
5865 msg = nlmsg_alloc();
5866 if (!msg)
5867 return -ENOMEM;
5868
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005869 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005870
5871 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
5872 if_nametoindex(bss->ifname));
5873 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
5874
5875 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5876 if (ret == -ENOENT)
5877 return 0;
5878 return ret;
5879 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005880 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005881 return -ENOBUFS;
5882}
5883
5884
5885static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
5886 int ifidx)
5887{
5888 struct nl_msg *msg;
5889
5890 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
5891
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005892 /* stop listening for EAPOL on this interface */
5893 del_ifidx(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005894
5895 msg = nlmsg_alloc();
5896 if (!msg)
5897 goto nla_put_failure;
5898
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005899 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005900 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
5901
5902 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
5903 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005904 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005905 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005906 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005907 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
5908}
5909
5910
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005911static const char * nl80211_iftype_str(enum nl80211_iftype mode)
5912{
5913 switch (mode) {
5914 case NL80211_IFTYPE_ADHOC:
5915 return "ADHOC";
5916 case NL80211_IFTYPE_STATION:
5917 return "STATION";
5918 case NL80211_IFTYPE_AP:
5919 return "AP";
5920 case NL80211_IFTYPE_MONITOR:
5921 return "MONITOR";
5922 case NL80211_IFTYPE_P2P_CLIENT:
5923 return "P2P_CLIENT";
5924 case NL80211_IFTYPE_P2P_GO:
5925 return "P2P_GO";
5926 default:
5927 return "unknown";
5928 }
5929}
5930
5931
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005932static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
5933 const char *ifname,
5934 enum nl80211_iftype iftype,
5935 const u8 *addr, int wds)
5936{
5937 struct nl_msg *msg, *flags = NULL;
5938 int ifidx;
5939 int ret = -ENOBUFS;
5940
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005941 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
5942 iftype, nl80211_iftype_str(iftype));
5943
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005944 msg = nlmsg_alloc();
5945 if (!msg)
5946 return -1;
5947
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005948 nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005949 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
5950 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
5951 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
5952
5953 if (iftype == NL80211_IFTYPE_MONITOR) {
5954 int err;
5955
5956 flags = nlmsg_alloc();
5957 if (!flags)
5958 goto nla_put_failure;
5959
5960 NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
5961
5962 err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
5963
5964 nlmsg_free(flags);
5965
5966 if (err)
5967 goto nla_put_failure;
5968 } else if (wds) {
5969 NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
5970 }
5971
5972 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005973 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005974 if (ret) {
5975 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005976 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005977 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
5978 ifname, ret, strerror(-ret));
5979 return ret;
5980 }
5981
5982 ifidx = if_nametoindex(ifname);
5983 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
5984 ifname, ifidx);
5985
5986 if (ifidx <= 0)
5987 return -1;
5988
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005989 /* start listening for EAPOL on this interface */
5990 add_ifidx(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005991
5992 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005993 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005994 nl80211_remove_iface(drv, ifidx);
5995 return -1;
5996 }
5997
5998 return ifidx;
5999}
6000
6001
6002static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
6003 const char *ifname, enum nl80211_iftype iftype,
6004 const u8 *addr, int wds)
6005{
6006 int ret;
6007
6008 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
6009
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006010 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006011 if (ret == -ENFILE && if_nametoindex(ifname)) {
6012 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
6013
6014 /* Try to remove the interface that was already there. */
6015 nl80211_remove_iface(drv, if_nametoindex(ifname));
6016
6017 /* Try to create the interface again */
6018 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
6019 wds);
6020 }
6021
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006022 if (ret >= 0 && is_p2p_interface(iftype))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006023 nl80211_disable_11b_rates(drv, ret, 1);
6024
6025 return ret;
6026}
6027
6028
6029static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
6030{
6031 struct ieee80211_hdr *hdr;
6032 u16 fc;
6033 union wpa_event_data event;
6034
6035 hdr = (struct ieee80211_hdr *) buf;
6036 fc = le_to_host16(hdr->frame_control);
6037
6038 os_memset(&event, 0, sizeof(event));
6039 event.tx_status.type = WLAN_FC_GET_TYPE(fc);
6040 event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
6041 event.tx_status.dst = hdr->addr1;
6042 event.tx_status.data = buf;
6043 event.tx_status.data_len = len;
6044 event.tx_status.ack = ok;
6045 wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
6046}
6047
6048
6049static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
6050 u8 *buf, size_t len)
6051{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006052 struct ieee80211_hdr *hdr = (void *)buf;
6053 u16 fc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006054 union wpa_event_data event;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006055
6056 if (len < sizeof(*hdr))
6057 return;
6058
6059 fc = le_to_host16(hdr->frame_control);
6060
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006061 os_memset(&event, 0, sizeof(event));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006062 event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
6063 event.rx_from_unknown.addr = hdr->addr2;
6064 event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
6065 (WLAN_FC_FROMDS | WLAN_FC_TODS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006066 wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
6067}
6068
6069
6070static void handle_frame(struct wpa_driver_nl80211_data *drv,
6071 u8 *buf, size_t len, int datarate, int ssi_signal)
6072{
6073 struct ieee80211_hdr *hdr;
6074 u16 fc;
6075 union wpa_event_data event;
6076
6077 hdr = (struct ieee80211_hdr *) buf;
6078 fc = le_to_host16(hdr->frame_control);
6079
6080 switch (WLAN_FC_GET_TYPE(fc)) {
6081 case WLAN_FC_TYPE_MGMT:
6082 os_memset(&event, 0, sizeof(event));
6083 event.rx_mgmt.frame = buf;
6084 event.rx_mgmt.frame_len = len;
6085 event.rx_mgmt.datarate = datarate;
6086 event.rx_mgmt.ssi_signal = ssi_signal;
6087 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
6088 break;
6089 case WLAN_FC_TYPE_CTRL:
6090 /* can only get here with PS-Poll frames */
6091 wpa_printf(MSG_DEBUG, "CTRL");
6092 from_unknown_sta(drv, buf, len);
6093 break;
6094 case WLAN_FC_TYPE_DATA:
6095 from_unknown_sta(drv, buf, len);
6096 break;
6097 }
6098}
6099
6100
6101static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
6102{
6103 struct wpa_driver_nl80211_data *drv = eloop_ctx;
6104 int len;
6105 unsigned char buf[3000];
6106 struct ieee80211_radiotap_iterator iter;
6107 int ret;
6108 int datarate = 0, ssi_signal = 0;
6109 int injected = 0, failed = 0, rxflags = 0;
6110
6111 len = recv(sock, buf, sizeof(buf), 0);
6112 if (len < 0) {
6113 perror("recv");
6114 return;
6115 }
6116
6117 if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
6118 printf("received invalid radiotap frame\n");
6119 return;
6120 }
6121
6122 while (1) {
6123 ret = ieee80211_radiotap_iterator_next(&iter);
6124 if (ret == -ENOENT)
6125 break;
6126 if (ret) {
6127 printf("received invalid radiotap frame (%d)\n", ret);
6128 return;
6129 }
6130 switch (iter.this_arg_index) {
6131 case IEEE80211_RADIOTAP_FLAGS:
6132 if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
6133 len -= 4;
6134 break;
6135 case IEEE80211_RADIOTAP_RX_FLAGS:
6136 rxflags = 1;
6137 break;
6138 case IEEE80211_RADIOTAP_TX_FLAGS:
6139 injected = 1;
6140 failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
6141 IEEE80211_RADIOTAP_F_TX_FAIL;
6142 break;
6143 case IEEE80211_RADIOTAP_DATA_RETRIES:
6144 break;
6145 case IEEE80211_RADIOTAP_CHANNEL:
6146 /* TODO: convert from freq/flags to channel number */
6147 break;
6148 case IEEE80211_RADIOTAP_RATE:
6149 datarate = *iter.this_arg * 5;
6150 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006151 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
6152 ssi_signal = (s8) *iter.this_arg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006153 break;
6154 }
6155 }
6156
6157 if (rxflags && injected)
6158 return;
6159
6160 if (!injected)
6161 handle_frame(drv, buf + iter.max_length,
6162 len - iter.max_length, datarate, ssi_signal);
6163 else
6164 handle_tx_callback(drv->ctx, buf + iter.max_length,
6165 len - iter.max_length, !failed);
6166}
6167
6168
6169/*
6170 * we post-process the filter code later and rewrite
6171 * this to the offset to the last instruction
6172 */
6173#define PASS 0xFF
6174#define FAIL 0xFE
6175
6176static struct sock_filter msock_filter_insns[] = {
6177 /*
6178 * do a little-endian load of the radiotap length field
6179 */
6180 /* load lower byte into A */
6181 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
6182 /* put it into X (== index register) */
6183 BPF_STMT(BPF_MISC| BPF_TAX, 0),
6184 /* load upper byte into A */
6185 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
6186 /* left-shift it by 8 */
6187 BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
6188 /* or with X */
6189 BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
6190 /* put result into X */
6191 BPF_STMT(BPF_MISC| BPF_TAX, 0),
6192
6193 /*
6194 * Allow management frames through, this also gives us those
6195 * management frames that we sent ourselves with status
6196 */
6197 /* load the lower byte of the IEEE 802.11 frame control field */
6198 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
6199 /* mask off frame type and version */
6200 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
6201 /* accept frame if it's both 0, fall through otherwise */
6202 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
6203
6204 /*
6205 * TODO: add a bit to radiotap RX flags that indicates
6206 * that the sending station is not associated, then
6207 * add a filter here that filters on our DA and that flag
6208 * to allow us to deauth frames to that bad station.
6209 *
6210 * For now allow all To DS data frames through.
6211 */
6212 /* load the IEEE 802.11 frame control field */
6213 BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
6214 /* mask off frame type, version and DS status */
6215 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
6216 /* accept frame if version 0, type 2 and To DS, fall through otherwise
6217 */
6218 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
6219
6220#if 0
6221 /*
6222 * drop non-data frames
6223 */
6224 /* load the lower byte of the frame control field */
6225 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
6226 /* mask off QoS bit */
6227 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
6228 /* drop non-data frames */
6229 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
6230#endif
6231 /* load the upper byte of the frame control field */
6232 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
6233 /* mask off toDS/fromDS */
6234 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
6235 /* accept WDS frames */
6236 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
6237
6238 /*
6239 * add header length to index
6240 */
6241 /* load the lower byte of the frame control field */
6242 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
6243 /* mask off QoS bit */
6244 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
6245 /* right shift it by 6 to give 0 or 2 */
6246 BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
6247 /* add data frame header length */
6248 BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
6249 /* add index, was start of 802.11 header */
6250 BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
6251 /* move to index, now start of LL header */
6252 BPF_STMT(BPF_MISC | BPF_TAX, 0),
6253
6254 /*
6255 * Accept empty data frames, we use those for
6256 * polling activity.
6257 */
6258 BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
6259 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
6260
6261 /*
6262 * Accept EAPOL frames
6263 */
6264 BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
6265 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
6266 BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
6267 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
6268
6269 /* keep these last two statements or change the code below */
6270 /* return 0 == "DROP" */
6271 BPF_STMT(BPF_RET | BPF_K, 0),
6272 /* return ~0 == "keep all" */
6273 BPF_STMT(BPF_RET | BPF_K, ~0),
6274};
6275
6276static struct sock_fprog msock_filter = {
6277 .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
6278 .filter = msock_filter_insns,
6279};
6280
6281
6282static int add_monitor_filter(int s)
6283{
6284 int idx;
6285
6286 /* rewrite all PASS/FAIL jump offsets */
6287 for (idx = 0; idx < msock_filter.len; idx++) {
6288 struct sock_filter *insn = &msock_filter_insns[idx];
6289
6290 if (BPF_CLASS(insn->code) == BPF_JMP) {
6291 if (insn->code == (BPF_JMP|BPF_JA)) {
6292 if (insn->k == PASS)
6293 insn->k = msock_filter.len - idx - 2;
6294 else if (insn->k == FAIL)
6295 insn->k = msock_filter.len - idx - 3;
6296 }
6297
6298 if (insn->jt == PASS)
6299 insn->jt = msock_filter.len - idx - 2;
6300 else if (insn->jt == FAIL)
6301 insn->jt = msock_filter.len - idx - 3;
6302
6303 if (insn->jf == PASS)
6304 insn->jf = msock_filter.len - idx - 2;
6305 else if (insn->jf == FAIL)
6306 insn->jf = msock_filter.len - idx - 3;
6307 }
6308 }
6309
6310 if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
6311 &msock_filter, sizeof(msock_filter))) {
6312 perror("SO_ATTACH_FILTER");
6313 return -1;
6314 }
6315
6316 return 0;
6317}
6318
6319
6320static void nl80211_remove_monitor_interface(
6321 struct wpa_driver_nl80211_data *drv)
6322{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006323 drv->monitor_refcount--;
6324 if (drv->monitor_refcount > 0)
6325 return;
6326
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006327 if (drv->monitor_ifidx >= 0) {
6328 nl80211_remove_iface(drv, drv->monitor_ifidx);
6329 drv->monitor_ifidx = -1;
6330 }
6331 if (drv->monitor_sock >= 0) {
6332 eloop_unregister_read_sock(drv->monitor_sock);
6333 close(drv->monitor_sock);
6334 drv->monitor_sock = -1;
6335 }
6336}
6337
6338
6339static int
6340nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
6341{
6342 char buf[IFNAMSIZ];
6343 struct sockaddr_ll ll;
6344 int optval;
6345 socklen_t optlen;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006346
6347 if (drv->monitor_ifidx >= 0) {
6348 drv->monitor_refcount++;
6349 return 0;
6350 }
6351
6352 if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
6353 /*
6354 * P2P interface name is of the format p2p-%s-%d. For monitor
6355 * interface name corresponding to P2P GO, replace "p2p-" with
6356 * "mon-" to retain the same interface name length and to
6357 * indicate that it is a monitor interface.
6358 */
6359 snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
6360 } else {
6361 /* Non-P2P interface with AP functionality. */
6362 snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
6363 }
6364
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006365 buf[IFNAMSIZ - 1] = '\0';
6366
6367 drv->monitor_ifidx =
6368 nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
6369 0);
6370
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006371 if (drv->monitor_ifidx == -EOPNOTSUPP) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006372 /*
6373 * This is backward compatibility for a few versions of
6374 * the kernel only that didn't advertise the right
6375 * attributes for the only driver that then supported
6376 * AP mode w/o monitor -- ath6kl.
6377 */
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006378 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
6379 "monitor interface type - try to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006380 drv->device_ap_sme = 1;
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006381 }
6382
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006383 if (drv->monitor_ifidx < 0)
6384 return -1;
6385
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006386 if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006387 goto error;
6388
6389 memset(&ll, 0, sizeof(ll));
6390 ll.sll_family = AF_PACKET;
6391 ll.sll_ifindex = drv->monitor_ifidx;
6392 drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
6393 if (drv->monitor_sock < 0) {
6394 perror("socket[PF_PACKET,SOCK_RAW]");
6395 goto error;
6396 }
6397
6398 if (add_monitor_filter(drv->monitor_sock)) {
6399 wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
6400 "interface; do filtering in user space");
6401 /* This works, but will cost in performance. */
6402 }
6403
6404 if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
6405 perror("monitor socket bind");
6406 goto error;
6407 }
6408
6409 optlen = sizeof(optval);
6410 optval = 20;
6411 if (setsockopt
6412 (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
6413 perror("Failed to set socket priority");
6414 goto error;
6415 }
6416
6417 if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
6418 drv, NULL)) {
6419 printf("Could not register monitor read socket\n");
6420 goto error;
6421 }
6422
6423 return 0;
6424 error:
6425 nl80211_remove_monitor_interface(drv);
6426 return -1;
6427}
6428
6429
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006430static int nl80211_setup_ap(struct i802_bss *bss)
6431{
6432 struct wpa_driver_nl80211_data *drv = bss->drv;
6433
6434 wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
6435 "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
6436
6437 /*
6438 * Disable Probe Request reporting unless we need it in this way for
6439 * devices that include the AP SME, in the other case (unless using
6440 * monitor iface) we'll get it through the nl_mgmt socket instead.
6441 */
6442 if (!drv->device_ap_sme)
6443 wpa_driver_nl80211_probe_req_report(bss, 0);
6444
6445 if (!drv->device_ap_sme && !drv->use_monitor)
6446 if (nl80211_mgmt_subscribe_ap(bss))
6447 return -1;
6448
6449 if (drv->device_ap_sme && !drv->use_monitor)
6450 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
6451 return -1;
6452
6453 if (!drv->device_ap_sme && drv->use_monitor &&
6454 nl80211_create_monitor_interface(drv) &&
6455 !drv->device_ap_sme)
Dmitry Shmidt04949592012-07-19 12:16:46 -07006456 return -1;
6457
6458#ifdef ANDROID_P2P
6459 if (drv->device_ap_sme && drv->use_monitor)
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006460 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
6461 return -1;
6462
6463 if (drv->use_monitor &&
6464 nl80211_create_monitor_interface(drv))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006465 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006466#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006467
6468 if (drv->device_ap_sme &&
6469 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
6470 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
6471 "Probe Request frame reporting in AP mode");
6472 /* Try to survive without this */
6473 }
6474
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006475 return 0;
6476}
6477
6478
6479static void nl80211_teardown_ap(struct i802_bss *bss)
6480{
6481 struct wpa_driver_nl80211_data *drv = bss->drv;
6482
6483 if (drv->device_ap_sme) {
6484 wpa_driver_nl80211_probe_req_report(bss, 0);
6485 if (!drv->use_monitor)
6486 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
6487 } else if (drv->use_monitor)
6488 nl80211_remove_monitor_interface(drv);
6489 else
6490 nl80211_mgmt_unsubscribe(bss, "AP teardown");
6491
6492 bss->beacon_set = 0;
6493}
6494
6495
6496static int nl80211_send_eapol_data(struct i802_bss *bss,
6497 const u8 *addr, const u8 *data,
6498 size_t data_len)
6499{
6500 struct sockaddr_ll ll;
6501 int ret;
6502
6503 if (bss->drv->eapol_tx_sock < 0) {
6504 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
6505 return -1;
6506 }
6507
6508 os_memset(&ll, 0, sizeof(ll));
6509 ll.sll_family = AF_PACKET;
6510 ll.sll_ifindex = bss->ifindex;
6511 ll.sll_protocol = htons(ETH_P_PAE);
6512 ll.sll_halen = ETH_ALEN;
6513 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
6514 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
6515 (struct sockaddr *) &ll, sizeof(ll));
6516 if (ret < 0)
6517 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
6518 strerror(errno));
6519
6520 return ret;
6521}
6522
6523
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006524static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
6525
6526static int wpa_driver_nl80211_hapd_send_eapol(
6527 void *priv, const u8 *addr, const u8 *data,
6528 size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
6529{
6530 struct i802_bss *bss = priv;
6531 struct wpa_driver_nl80211_data *drv = bss->drv;
6532 struct ieee80211_hdr *hdr;
6533 size_t len;
6534 u8 *pos;
6535 int res;
6536 int qos = flags & WPA_STA_WMM;
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006537#ifndef ANDROID_P2P
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006538 if (drv->device_ap_sme || !drv->use_monitor)
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006539#else
6540 if (drv->device_ap_sme && !drv->use_monitor)
6541#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006542 return nl80211_send_eapol_data(bss, addr, data, data_len);
6543
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006544 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
6545 data_len;
6546 hdr = os_zalloc(len);
6547 if (hdr == NULL) {
6548 printf("malloc() failed for i802_send_data(len=%lu)\n",
6549 (unsigned long) len);
6550 return -1;
6551 }
6552
6553 hdr->frame_control =
6554 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
6555 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
6556 if (encrypt)
6557 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
6558 if (qos) {
6559 hdr->frame_control |=
6560 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
6561 }
6562
6563 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
6564 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
6565 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
6566 pos = (u8 *) (hdr + 1);
6567
6568 if (qos) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006569 /* Set highest priority in QoS header */
6570 pos[0] = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006571 pos[1] = 0;
6572 pos += 2;
6573 }
6574
6575 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
6576 pos += sizeof(rfc1042_header);
6577 WPA_PUT_BE16(pos, ETH_P_PAE);
6578 pos += 2;
6579 memcpy(pos, data, data_len);
6580
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006581 res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
6582 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006583 if (res < 0) {
6584 wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
6585 "failed: %d (%s)",
6586 (unsigned long) len, errno, strerror(errno));
6587 }
6588 os_free(hdr);
6589
6590 return res;
6591}
6592
6593
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006594static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
6595 int total_flags,
6596 int flags_or, int flags_and)
6597{
6598 struct i802_bss *bss = priv;
6599 struct wpa_driver_nl80211_data *drv = bss->drv;
6600 struct nl_msg *msg, *flags = NULL;
6601 struct nl80211_sta_flag_update upd;
6602
6603 msg = nlmsg_alloc();
6604 if (!msg)
6605 return -ENOMEM;
6606
6607 flags = nlmsg_alloc();
6608 if (!flags) {
6609 nlmsg_free(msg);
6610 return -ENOMEM;
6611 }
6612
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006613 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006614
6615 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
6616 if_nametoindex(bss->ifname));
6617 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
6618
6619 /*
6620 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
6621 * can be removed eventually.
6622 */
6623 if (total_flags & WPA_STA_AUTHORIZED)
6624 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
6625
6626 if (total_flags & WPA_STA_WMM)
6627 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
6628
6629 if (total_flags & WPA_STA_SHORT_PREAMBLE)
6630 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
6631
6632 if (total_flags & WPA_STA_MFP)
6633 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
6634
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006635 if (total_flags & WPA_STA_TDLS_PEER)
6636 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
6637
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006638 if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
6639 goto nla_put_failure;
6640
6641 os_memset(&upd, 0, sizeof(upd));
6642 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
6643 upd.set = sta_flags_nl80211(flags_or);
6644 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
6645
6646 nlmsg_free(flags);
6647
6648 return send_and_recv_msgs(drv, msg, NULL, NULL);
6649 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006650 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006651 nlmsg_free(flags);
6652 return -ENOBUFS;
6653}
6654
6655
6656static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
6657 struct wpa_driver_associate_params *params)
6658{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006659 enum nl80211_iftype nlmode, old_mode;
6660 struct hostapd_freq_params freq = {
6661 .freq = params->freq,
6662 };
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006663
6664 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006665 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
6666 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006667 nlmode = NL80211_IFTYPE_P2P_GO;
6668 } else
6669 nlmode = NL80211_IFTYPE_AP;
6670
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006671 old_mode = drv->nlmode;
6672 if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
6673 nl80211_remove_monitor_interface(drv);
6674 return -1;
6675 }
6676
6677 if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
6678 if (old_mode != nlmode)
6679 wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006680 nl80211_remove_monitor_interface(drv);
6681 return -1;
6682 }
6683
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006684 return 0;
6685}
6686
6687
6688static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
6689{
6690 struct nl_msg *msg;
6691 int ret = -1;
6692
6693 msg = nlmsg_alloc();
6694 if (!msg)
6695 return -1;
6696
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006697 nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006698 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6699 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6700 msg = NULL;
6701 if (ret) {
6702 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
6703 "(%s)", ret, strerror(-ret));
6704 goto nla_put_failure;
6705 }
6706
6707 ret = 0;
6708 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
6709
6710nla_put_failure:
6711 nlmsg_free(msg);
6712 return ret;
6713}
6714
6715
6716static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
6717 struct wpa_driver_associate_params *params)
6718{
6719 struct nl_msg *msg;
6720 int ret = -1;
6721 int count = 0;
6722
6723 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
6724
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006725 if (wpa_driver_nl80211_set_mode(&drv->first_bss,
6726 NL80211_IFTYPE_ADHOC)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006727 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6728 "IBSS mode");
6729 return -1;
6730 }
6731
6732retry:
6733 msg = nlmsg_alloc();
6734 if (!msg)
6735 return -1;
6736
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006737 nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006738 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6739
6740 if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
6741 goto nla_put_failure;
6742
6743 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
6744 params->ssid, params->ssid_len);
6745 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
6746 params->ssid);
6747 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6748 drv->ssid_len = params->ssid_len;
6749
6750 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
6751 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
6752
6753 ret = nl80211_set_conn_keys(params, msg);
6754 if (ret)
6755 goto nla_put_failure;
6756
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006757 if (params->bssid && params->fixed_bssid) {
6758 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
6759 MAC2STR(params->bssid));
6760 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
6761 }
6762
6763 if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
6764 params->key_mgmt_suite == KEY_MGMT_PSK ||
6765 params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 ||
6766 params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) {
6767 wpa_printf(MSG_DEBUG, " * control port");
6768 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
6769 }
6770
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006771 if (params->wpa_ie) {
6772 wpa_hexdump(MSG_DEBUG,
6773 " * Extra IEs for Beacon/Probe Response frames",
6774 params->wpa_ie, params->wpa_ie_len);
6775 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6776 params->wpa_ie);
6777 }
6778
6779 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6780 msg = NULL;
6781 if (ret) {
6782 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
6783 ret, strerror(-ret));
6784 count++;
6785 if (ret == -EALREADY && count == 1) {
6786 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
6787 "forced leave");
6788 nl80211_leave_ibss(drv);
6789 nlmsg_free(msg);
6790 goto retry;
6791 }
6792
6793 goto nla_put_failure;
6794 }
6795 ret = 0;
6796 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
6797
6798nla_put_failure:
6799 nlmsg_free(msg);
6800 return ret;
6801}
6802
6803
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006804static int wpa_driver_nl80211_try_connect(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006805 struct wpa_driver_nl80211_data *drv,
6806 struct wpa_driver_associate_params *params)
6807{
6808 struct nl_msg *msg;
6809 enum nl80211_auth_type type;
6810 int ret = 0;
6811 int algs;
6812
6813 msg = nlmsg_alloc();
6814 if (!msg)
6815 return -1;
6816
6817 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006818 nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006819
6820 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6821 if (params->bssid) {
6822 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6823 MAC2STR(params->bssid));
6824 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
6825 }
6826 if (params->freq) {
6827 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
6828 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
6829 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07006830 if (params->bg_scan_period >= 0) {
6831 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
6832 params->bg_scan_period);
6833 NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
6834 params->bg_scan_period);
6835 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006836 if (params->ssid) {
6837 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
6838 params->ssid, params->ssid_len);
6839 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
6840 params->ssid);
6841 if (params->ssid_len > sizeof(drv->ssid))
6842 goto nla_put_failure;
6843 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6844 drv->ssid_len = params->ssid_len;
6845 }
6846 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
6847 if (params->wpa_ie)
6848 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6849 params->wpa_ie);
6850
6851 algs = 0;
6852 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6853 algs++;
6854 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6855 algs++;
6856 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6857 algs++;
6858 if (algs > 1) {
6859 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
6860 "selection");
6861 goto skip_auth_type;
6862 }
6863
6864 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6865 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
6866 else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6867 type = NL80211_AUTHTYPE_SHARED_KEY;
6868 else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6869 type = NL80211_AUTHTYPE_NETWORK_EAP;
6870 else if (params->auth_alg & WPA_AUTH_ALG_FT)
6871 type = NL80211_AUTHTYPE_FT;
6872 else
6873 goto nla_put_failure;
6874
6875 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
6876 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
6877
6878skip_auth_type:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006879 if (params->wpa_proto) {
6880 enum nl80211_wpa_versions ver = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006881
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006882 if (params->wpa_proto & WPA_PROTO_WPA)
6883 ver |= NL80211_WPA_VERSION_1;
6884 if (params->wpa_proto & WPA_PROTO_RSN)
6885 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006886
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006887 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006888 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
6889 }
6890
6891 if (params->pairwise_suite != CIPHER_NONE) {
6892 int cipher;
6893
6894 switch (params->pairwise_suite) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006895 case CIPHER_SMS4:
6896 cipher = WLAN_CIPHER_SUITE_SMS4;
6897 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006898 case CIPHER_WEP40:
6899 cipher = WLAN_CIPHER_SUITE_WEP40;
6900 break;
6901 case CIPHER_WEP104:
6902 cipher = WLAN_CIPHER_SUITE_WEP104;
6903 break;
6904 case CIPHER_CCMP:
6905 cipher = WLAN_CIPHER_SUITE_CCMP;
6906 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006907 case CIPHER_GCMP:
6908 cipher = WLAN_CIPHER_SUITE_GCMP;
6909 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006910 case CIPHER_TKIP:
6911 default:
6912 cipher = WLAN_CIPHER_SUITE_TKIP;
6913 break;
6914 }
6915 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
6916 }
6917
6918 if (params->group_suite != CIPHER_NONE) {
6919 int cipher;
6920
6921 switch (params->group_suite) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006922 case CIPHER_SMS4:
6923 cipher = WLAN_CIPHER_SUITE_SMS4;
6924 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006925 case CIPHER_WEP40:
6926 cipher = WLAN_CIPHER_SUITE_WEP40;
6927 break;
6928 case CIPHER_WEP104:
6929 cipher = WLAN_CIPHER_SUITE_WEP104;
6930 break;
6931 case CIPHER_CCMP:
6932 cipher = WLAN_CIPHER_SUITE_CCMP;
6933 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006934 case CIPHER_GCMP:
6935 cipher = WLAN_CIPHER_SUITE_GCMP;
6936 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006937 case CIPHER_TKIP:
6938 default:
6939 cipher = WLAN_CIPHER_SUITE_TKIP;
6940 break;
6941 }
6942 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
6943 }
6944
6945 if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006946 params->key_mgmt_suite == KEY_MGMT_PSK ||
6947 params->key_mgmt_suite == KEY_MGMT_CCKM) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006948 int mgmt = WLAN_AKM_SUITE_PSK;
6949
6950 switch (params->key_mgmt_suite) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006951 case KEY_MGMT_CCKM:
6952 mgmt = WLAN_AKM_SUITE_CCKM;
6953 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006954 case KEY_MGMT_802_1X:
6955 mgmt = WLAN_AKM_SUITE_8021X;
6956 break;
6957 case KEY_MGMT_PSK:
6958 default:
6959 mgmt = WLAN_AKM_SUITE_PSK;
6960 break;
6961 }
6962 NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
6963 }
6964
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006965#ifdef CONFIG_IEEE80211W
6966 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
6967 NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
6968#endif /* CONFIG_IEEE80211W */
6969
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006970 if (params->disable_ht)
6971 NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
6972
6973 if (params->htcaps && params->htcaps_mask) {
6974 int sz = sizeof(struct ieee80211_ht_capabilities);
6975 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
6976 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
6977 params->htcaps_mask);
6978 }
6979
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006980 ret = nl80211_set_conn_keys(params, msg);
6981 if (ret)
6982 goto nla_put_failure;
6983
6984 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6985 msg = NULL;
6986 if (ret) {
6987 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
6988 "(%s)", ret, strerror(-ret));
6989 goto nla_put_failure;
6990 }
6991 ret = 0;
6992 wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
6993
6994nla_put_failure:
6995 nlmsg_free(msg);
6996 return ret;
6997
6998}
6999
7000
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007001static int wpa_driver_nl80211_connect(
7002 struct wpa_driver_nl80211_data *drv,
7003 struct wpa_driver_associate_params *params)
7004{
7005 int ret = wpa_driver_nl80211_try_connect(drv, params);
7006 if (ret == -EALREADY) {
7007 /*
7008 * cfg80211 does not currently accept new connections if
7009 * we are already connected. As a workaround, force
7010 * disconnection and try again.
7011 */
7012 wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
7013 "disconnecting before reassociation "
7014 "attempt");
7015 if (wpa_driver_nl80211_disconnect(
7016 drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
7017 return -1;
7018 /* Ignore the next local disconnect message. */
7019 drv->ignore_next_local_disconnect = 1;
7020 ret = wpa_driver_nl80211_try_connect(drv, params);
7021 }
7022 return ret;
7023}
7024
7025
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007026static int wpa_driver_nl80211_associate(
7027 void *priv, struct wpa_driver_associate_params *params)
7028{
7029 struct i802_bss *bss = priv;
7030 struct wpa_driver_nl80211_data *drv = bss->drv;
7031 int ret = -1;
7032 struct nl_msg *msg;
7033
7034 if (params->mode == IEEE80211_MODE_AP)
7035 return wpa_driver_nl80211_ap(drv, params);
7036
7037 if (params->mode == IEEE80211_MODE_IBSS)
7038 return wpa_driver_nl80211_ibss(drv, params);
7039
7040 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007041 enum nl80211_iftype nlmode = params->p2p ?
7042 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
7043
7044 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007045 return -1;
7046 return wpa_driver_nl80211_connect(drv, params);
7047 }
7048
7049 drv->associated = 0;
7050
7051 msg = nlmsg_alloc();
7052 if (!msg)
7053 return -1;
7054
7055 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
7056 drv->ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007057 nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007058
7059 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7060 if (params->bssid) {
7061 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
7062 MAC2STR(params->bssid));
7063 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
7064 }
7065 if (params->freq) {
7066 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
7067 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
7068 drv->assoc_freq = params->freq;
7069 } else
7070 drv->assoc_freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007071 if (params->bg_scan_period >= 0) {
7072 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
7073 params->bg_scan_period);
7074 NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
7075 params->bg_scan_period);
7076 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007077 if (params->ssid) {
7078 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
7079 params->ssid, params->ssid_len);
7080 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
7081 params->ssid);
7082 if (params->ssid_len > sizeof(drv->ssid))
7083 goto nla_put_failure;
7084 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
7085 drv->ssid_len = params->ssid_len;
7086 }
7087 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
7088 if (params->wpa_ie)
7089 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
7090 params->wpa_ie);
7091
7092 if (params->pairwise_suite != CIPHER_NONE) {
7093 int cipher;
7094
7095 switch (params->pairwise_suite) {
7096 case CIPHER_WEP40:
7097 cipher = WLAN_CIPHER_SUITE_WEP40;
7098 break;
7099 case CIPHER_WEP104:
7100 cipher = WLAN_CIPHER_SUITE_WEP104;
7101 break;
7102 case CIPHER_CCMP:
7103 cipher = WLAN_CIPHER_SUITE_CCMP;
7104 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007105 case CIPHER_GCMP:
7106 cipher = WLAN_CIPHER_SUITE_GCMP;
7107 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007108 case CIPHER_TKIP:
7109 default:
7110 cipher = WLAN_CIPHER_SUITE_TKIP;
7111 break;
7112 }
7113 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
7114 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
7115 }
7116
7117 if (params->group_suite != CIPHER_NONE) {
7118 int cipher;
7119
7120 switch (params->group_suite) {
7121 case CIPHER_WEP40:
7122 cipher = WLAN_CIPHER_SUITE_WEP40;
7123 break;
7124 case CIPHER_WEP104:
7125 cipher = WLAN_CIPHER_SUITE_WEP104;
7126 break;
7127 case CIPHER_CCMP:
7128 cipher = WLAN_CIPHER_SUITE_CCMP;
7129 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007130 case CIPHER_GCMP:
7131 cipher = WLAN_CIPHER_SUITE_GCMP;
7132 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007133 case CIPHER_TKIP:
7134 default:
7135 cipher = WLAN_CIPHER_SUITE_TKIP;
7136 break;
7137 }
7138 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
7139 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
7140 }
7141
7142#ifdef CONFIG_IEEE80211W
7143 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
7144 NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
7145#endif /* CONFIG_IEEE80211W */
7146
7147 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
7148
7149 if (params->prev_bssid) {
7150 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
7151 MAC2STR(params->prev_bssid));
7152 NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
7153 params->prev_bssid);
7154 }
7155
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007156 if (params->disable_ht)
7157 NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
7158
7159 if (params->htcaps && params->htcaps_mask) {
7160 int sz = sizeof(struct ieee80211_ht_capabilities);
7161 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
7162 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
7163 params->htcaps_mask);
7164 }
7165
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007166 if (params->p2p)
7167 wpa_printf(MSG_DEBUG, " * P2P group");
7168
7169 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
7170 msg = NULL;
7171 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007172 wpa_dbg(drv->ctx, MSG_DEBUG,
7173 "nl80211: MLME command failed (assoc): ret=%d (%s)",
7174 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007175 nl80211_dump_scan(drv);
7176 goto nla_put_failure;
7177 }
7178 ret = 0;
7179 wpa_printf(MSG_DEBUG, "nl80211: Association request send "
7180 "successfully");
7181
7182nla_put_failure:
7183 nlmsg_free(msg);
7184 return ret;
7185}
7186
7187
7188static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007189 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007190{
7191 struct nl_msg *msg;
7192 int ret = -ENOBUFS;
7193
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007194 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
7195 ifindex, mode, nl80211_iftype_str(mode));
7196
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007197 msg = nlmsg_alloc();
7198 if (!msg)
7199 return -ENOMEM;
7200
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007201 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007202 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
7203 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
7204
7205 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007206 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007207 if (!ret)
7208 return 0;
7209nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007210 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007211 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
7212 " %d (%s)", ifindex, mode, ret, strerror(-ret));
7213 return ret;
7214}
7215
7216
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007217static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
7218 enum nl80211_iftype nlmode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007219{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007220 struct wpa_driver_nl80211_data *drv = bss->drv;
7221 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007222 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007223 int was_ap = is_ap_interface(drv->nlmode);
7224 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007225
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007226 res = nl80211_set_mode(drv, drv->ifindex, nlmode);
7227 if (res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007228 drv->nlmode = nlmode;
7229 ret = 0;
7230 goto done;
7231 }
7232
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007233 if (res == -ENODEV)
7234 return -1;
7235
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007236 if (nlmode == drv->nlmode) {
7237 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
7238 "requested mode - ignore error");
7239 ret = 0;
7240 goto done; /* Already in the requested mode */
7241 }
7242
7243 /* mac80211 doesn't allow mode changes while the device is up, so
7244 * take the device down, try to set the mode again, and bring the
7245 * device back up.
7246 */
7247 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
7248 "interface down");
7249 for (i = 0; i < 10; i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007250 res = linux_set_iface_flags(drv->global->ioctl_sock,
7251 bss->ifname, 0);
7252 if (res == -EACCES || res == -ENODEV)
7253 break;
7254 if (res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007255 /* Try to set the mode again while the interface is
7256 * down */
7257 ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007258 if (ret == -EACCES)
7259 break;
7260 res = linux_set_iface_flags(drv->global->ioctl_sock,
7261 bss->ifname, 1);
7262 if (res && !ret)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007263 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007264 else if (ret != -EBUSY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007265 break;
7266 } else
7267 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
7268 "interface down");
7269 os_sleep(0, 100000);
7270 }
7271
7272 if (!ret) {
7273 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
7274 "interface is down");
7275 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007276 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007277 }
7278
7279done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007280 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007281 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
7282 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007283 return ret;
7284 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007285
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007286 if (is_p2p_interface(nlmode))
7287 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
7288 else if (drv->disabled_11b_rates)
7289 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
7290
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007291 if (is_ap_interface(nlmode)) {
7292 nl80211_mgmt_unsubscribe(bss, "start AP");
7293 /* Setup additional AP mode functionality if needed */
7294 if (nl80211_setup_ap(bss))
7295 return -1;
7296 } else if (was_ap) {
7297 /* Remove additional AP mode functionality */
7298 nl80211_teardown_ap(bss);
7299 } else {
7300 nl80211_mgmt_unsubscribe(bss, "mode change");
7301 }
7302
Dmitry Shmidt04949592012-07-19 12:16:46 -07007303 if (!bss->in_deinit && !is_ap_interface(nlmode) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007304 nl80211_mgmt_subscribe_non_ap(bss) < 0)
7305 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
7306 "frame processing - ignore for now");
7307
7308 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007309}
7310
7311
7312static int wpa_driver_nl80211_get_capa(void *priv,
7313 struct wpa_driver_capa *capa)
7314{
7315 struct i802_bss *bss = priv;
7316 struct wpa_driver_nl80211_data *drv = bss->drv;
7317 if (!drv->has_capability)
7318 return -1;
7319 os_memcpy(capa, &drv->capa, sizeof(*capa));
7320 return 0;
7321}
7322
7323
7324static int wpa_driver_nl80211_set_operstate(void *priv, int state)
7325{
7326 struct i802_bss *bss = priv;
7327 struct wpa_driver_nl80211_data *drv = bss->drv;
7328
7329 wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
7330 __func__, drv->operstate, state, state ? "UP" : "DORMANT");
7331 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007332 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007333 state ? IF_OPER_UP : IF_OPER_DORMANT);
7334}
7335
7336
7337static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
7338{
7339 struct i802_bss *bss = priv;
7340 struct wpa_driver_nl80211_data *drv = bss->drv;
7341 struct nl_msg *msg;
7342 struct nl80211_sta_flag_update upd;
7343
7344 msg = nlmsg_alloc();
7345 if (!msg)
7346 return -ENOMEM;
7347
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007348 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007349
7350 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7351 if_nametoindex(bss->ifname));
7352 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
7353
7354 os_memset(&upd, 0, sizeof(upd));
7355 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
7356 if (authorized)
7357 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
7358 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
7359
7360 return send_and_recv_msgs(drv, msg, NULL, NULL);
7361 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007362 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007363 return -ENOBUFS;
7364}
7365
7366
Jouni Malinen75ecf522011-06-27 15:19:46 -07007367/* Set kernel driver on given frequency (MHz) */
7368static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007369{
Jouni Malinen75ecf522011-06-27 15:19:46 -07007370 struct i802_bss *bss = priv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08007371 return wpa_driver_nl80211_set_freq(bss, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007372}
7373
7374
Jouni Malinen75ecf522011-06-27 15:19:46 -07007375#if defined(HOSTAPD) || defined(CONFIG_AP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007376
7377static inline int min_int(int a, int b)
7378{
7379 if (a < b)
7380 return a;
7381 return b;
7382}
7383
7384
7385static int get_key_handler(struct nl_msg *msg, void *arg)
7386{
7387 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7388 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7389
7390 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7391 genlmsg_attrlen(gnlh, 0), NULL);
7392
7393 /*
7394 * TODO: validate the key index and mac address!
7395 * Otherwise, there's a race condition as soon as
7396 * the kernel starts sending key notifications.
7397 */
7398
7399 if (tb[NL80211_ATTR_KEY_SEQ])
7400 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
7401 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
7402 return NL_SKIP;
7403}
7404
7405
7406static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
7407 int idx, u8 *seq)
7408{
7409 struct i802_bss *bss = priv;
7410 struct wpa_driver_nl80211_data *drv = bss->drv;
7411 struct nl_msg *msg;
7412
7413 msg = nlmsg_alloc();
7414 if (!msg)
7415 return -ENOMEM;
7416
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007417 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007418
7419 if (addr)
7420 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7421 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
7422 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
7423
7424 memset(seq, 0, 6);
7425
7426 return send_and_recv_msgs(drv, msg, get_key_handler, seq);
7427 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007428 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007429 return -ENOBUFS;
7430}
7431
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007432
7433static int i802_set_rts(void *priv, int rts)
7434{
7435 struct i802_bss *bss = priv;
7436 struct wpa_driver_nl80211_data *drv = bss->drv;
7437 struct nl_msg *msg;
7438 int ret = -ENOBUFS;
7439 u32 val;
7440
7441 msg = nlmsg_alloc();
7442 if (!msg)
7443 return -ENOMEM;
7444
7445 if (rts >= 2347)
7446 val = (u32) -1;
7447 else
7448 val = rts;
7449
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007450 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007451 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7452 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
7453
7454 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007455 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007456 if (!ret)
7457 return 0;
7458nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007459 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007460 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
7461 "%d (%s)", rts, ret, strerror(-ret));
7462 return ret;
7463}
7464
7465
7466static int i802_set_frag(void *priv, int frag)
7467{
7468 struct i802_bss *bss = priv;
7469 struct wpa_driver_nl80211_data *drv = bss->drv;
7470 struct nl_msg *msg;
7471 int ret = -ENOBUFS;
7472 u32 val;
7473
7474 msg = nlmsg_alloc();
7475 if (!msg)
7476 return -ENOMEM;
7477
7478 if (frag >= 2346)
7479 val = (u32) -1;
7480 else
7481 val = frag;
7482
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007483 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007484 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7485 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
7486
7487 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007488 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007489 if (!ret)
7490 return 0;
7491nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007492 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007493 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
7494 "%d: %d (%s)", frag, ret, strerror(-ret));
7495 return ret;
7496}
7497
7498
7499static int i802_flush(void *priv)
7500{
7501 struct i802_bss *bss = priv;
7502 struct wpa_driver_nl80211_data *drv = bss->drv;
7503 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007504 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007505
7506 msg = nlmsg_alloc();
7507 if (!msg)
7508 return -1;
7509
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007510 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007511
7512 /*
7513 * XXX: FIX! this needs to flush all VLANs too
7514 */
7515 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7516 if_nametoindex(bss->ifname));
7517
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007518 res = send_and_recv_msgs(drv, msg, NULL, NULL);
7519 if (res) {
7520 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
7521 "(%s)", res, strerror(-res));
7522 }
7523 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007524 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007525 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007526 return -ENOBUFS;
7527}
7528
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007529#endif /* HOSTAPD || CONFIG_AP */
7530
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007531
7532static int get_sta_handler(struct nl_msg *msg, void *arg)
7533{
7534 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7535 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7536 struct hostap_sta_driver_data *data = arg;
7537 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
7538 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
7539 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
7540 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
7541 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
7542 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
7543 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007544 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007545 };
7546
7547 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7548 genlmsg_attrlen(gnlh, 0), NULL);
7549
7550 /*
7551 * TODO: validate the interface and mac address!
7552 * Otherwise, there's a race condition as soon as
7553 * the kernel starts sending station notifications.
7554 */
7555
7556 if (!tb[NL80211_ATTR_STA_INFO]) {
7557 wpa_printf(MSG_DEBUG, "sta stats missing!");
7558 return NL_SKIP;
7559 }
7560 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
7561 tb[NL80211_ATTR_STA_INFO],
7562 stats_policy)) {
7563 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
7564 return NL_SKIP;
7565 }
7566
7567 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
7568 data->inactive_msec =
7569 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
7570 if (stats[NL80211_STA_INFO_RX_BYTES])
7571 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
7572 if (stats[NL80211_STA_INFO_TX_BYTES])
7573 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
7574 if (stats[NL80211_STA_INFO_RX_PACKETS])
7575 data->rx_packets =
7576 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
7577 if (stats[NL80211_STA_INFO_TX_PACKETS])
7578 data->tx_packets =
7579 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007580 if (stats[NL80211_STA_INFO_TX_FAILED])
7581 data->tx_retry_failed =
7582 nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007583
7584 return NL_SKIP;
7585}
7586
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007587static int i802_read_sta_data(struct i802_bss *bss,
7588 struct hostap_sta_driver_data *data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007589 const u8 *addr)
7590{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007591 struct wpa_driver_nl80211_data *drv = bss->drv;
7592 struct nl_msg *msg;
7593
7594 os_memset(data, 0, sizeof(*data));
7595 msg = nlmsg_alloc();
7596 if (!msg)
7597 return -ENOMEM;
7598
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007599 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007600
7601 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7602 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
7603
7604 return send_and_recv_msgs(drv, msg, get_sta_handler, data);
7605 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007606 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007607 return -ENOBUFS;
7608}
7609
7610
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007611#if defined(HOSTAPD) || defined(CONFIG_AP)
7612
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007613static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
7614 int cw_min, int cw_max, int burst_time)
7615{
7616 struct i802_bss *bss = priv;
7617 struct wpa_driver_nl80211_data *drv = bss->drv;
7618 struct nl_msg *msg;
7619 struct nlattr *txq, *params;
7620
7621 msg = nlmsg_alloc();
7622 if (!msg)
7623 return -1;
7624
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007625 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007626
7627 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
7628
7629 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
7630 if (!txq)
7631 goto nla_put_failure;
7632
7633 /* We are only sending parameters for a single TXQ at a time */
7634 params = nla_nest_start(msg, 1);
7635 if (!params)
7636 goto nla_put_failure;
7637
7638 switch (queue) {
7639 case 0:
7640 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
7641 break;
7642 case 1:
7643 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
7644 break;
7645 case 2:
7646 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
7647 break;
7648 case 3:
7649 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
7650 break;
7651 }
7652 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
7653 * 32 usec, so need to convert the value here. */
7654 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
7655 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
7656 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
7657 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
7658
7659 nla_nest_end(msg, params);
7660
7661 nla_nest_end(msg, txq);
7662
7663 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
7664 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007665 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007666 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007667 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007668 return -1;
7669}
7670
7671
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007672static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007673 const char *ifname, int vlan_id)
7674{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007675 struct wpa_driver_nl80211_data *drv = bss->drv;
7676 struct nl_msg *msg;
7677 int ret = -ENOBUFS;
7678
7679 msg = nlmsg_alloc();
7680 if (!msg)
7681 return -ENOMEM;
7682
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007683 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007684
7685 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7686 if_nametoindex(bss->ifname));
7687 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7688 NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
7689 if_nametoindex(ifname));
7690
7691 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007692 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007693 if (ret < 0) {
7694 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
7695 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
7696 MAC2STR(addr), ifname, vlan_id, ret,
7697 strerror(-ret));
7698 }
7699 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007700 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007701 return ret;
7702}
7703
7704
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007705static int i802_get_inact_sec(void *priv, const u8 *addr)
7706{
7707 struct hostap_sta_driver_data data;
7708 int ret;
7709
7710 data.inactive_msec = (unsigned long) -1;
7711 ret = i802_read_sta_data(priv, &data, addr);
7712 if (ret || data.inactive_msec == (unsigned long) -1)
7713 return -1;
7714 return data.inactive_msec / 1000;
7715}
7716
7717
7718static int i802_sta_clear_stats(void *priv, const u8 *addr)
7719{
7720#if 0
7721 /* TODO */
7722#endif
7723 return 0;
7724}
7725
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007726
7727static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
7728 int reason)
7729{
7730 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007731 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007732 struct ieee80211_mgmt mgmt;
7733
Dmitry Shmidt04949592012-07-19 12:16:46 -07007734 if (drv->device_ap_sme)
7735 return wpa_driver_nl80211_sta_remove(bss, addr);
7736
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007737 memset(&mgmt, 0, sizeof(mgmt));
7738 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7739 WLAN_FC_STYPE_DEAUTH);
7740 memcpy(mgmt.da, addr, ETH_ALEN);
7741 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7742 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7743 mgmt.u.deauth.reason_code = host_to_le16(reason);
7744 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7745 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007746 sizeof(mgmt.u.deauth), 0, 0, 0, 0,
7747 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007748}
7749
7750
7751static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
7752 int reason)
7753{
7754 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007755 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007756 struct ieee80211_mgmt mgmt;
7757
Dmitry Shmidt04949592012-07-19 12:16:46 -07007758 if (drv->device_ap_sme)
7759 return wpa_driver_nl80211_sta_remove(bss, addr);
7760
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007761 memset(&mgmt, 0, sizeof(mgmt));
7762 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7763 WLAN_FC_STYPE_DISASSOC);
7764 memcpy(mgmt.da, addr, ETH_ALEN);
7765 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7766 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7767 mgmt.u.disassoc.reason_code = host_to_le16(reason);
7768 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7769 IEEE80211_HDRLEN +
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08007770 sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
7771 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007772}
7773
7774#endif /* HOSTAPD || CONFIG_AP */
7775
7776#ifdef HOSTAPD
7777
Jouni Malinen75ecf522011-06-27 15:19:46 -07007778static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7779{
7780 int i;
7781 int *old;
7782
7783 wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
7784 ifidx);
7785 for (i = 0; i < drv->num_if_indices; i++) {
7786 if (drv->if_indices[i] == 0) {
7787 drv->if_indices[i] = ifidx;
7788 return;
7789 }
7790 }
7791
7792 if (drv->if_indices != drv->default_if_indices)
7793 old = drv->if_indices;
7794 else
7795 old = NULL;
7796
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007797 drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
7798 sizeof(int));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007799 if (!drv->if_indices) {
7800 if (!old)
7801 drv->if_indices = drv->default_if_indices;
7802 else
7803 drv->if_indices = old;
7804 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
7805 "interfaces");
7806 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
7807 return;
7808 } else if (!old)
7809 os_memcpy(drv->if_indices, drv->default_if_indices,
7810 sizeof(drv->default_if_indices));
7811 drv->if_indices[drv->num_if_indices] = ifidx;
7812 drv->num_if_indices++;
7813}
7814
7815
7816static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7817{
7818 int i;
7819
7820 for (i = 0; i < drv->num_if_indices; i++) {
7821 if (drv->if_indices[i] == ifidx) {
7822 drv->if_indices[i] = 0;
7823 break;
7824 }
7825 }
7826}
7827
7828
7829static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7830{
7831 int i;
7832
7833 for (i = 0; i < drv->num_if_indices; i++)
7834 if (drv->if_indices[i] == ifidx)
7835 return 1;
7836
7837 return 0;
7838}
7839
7840
7841static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
7842 const char *bridge_ifname)
7843{
7844 struct i802_bss *bss = priv;
7845 struct wpa_driver_nl80211_data *drv = bss->drv;
7846 char name[IFNAMSIZ + 1];
7847
7848 os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
7849 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
7850 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
7851 if (val) {
7852 if (!if_nametoindex(name)) {
7853 if (nl80211_create_iface(drv, name,
7854 NL80211_IFTYPE_AP_VLAN,
7855 NULL, 1) < 0)
7856 return -1;
7857 if (bridge_ifname &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007858 linux_br_add_if(drv->global->ioctl_sock,
7859 bridge_ifname, name) < 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007860 return -1;
7861 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007862 if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
7863 wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
7864 "interface %s up", name);
7865 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007866 return i802_set_sta_vlan(priv, addr, name, 0);
7867 } else {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007868 if (bridge_ifname)
7869 linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
7870 name);
7871
Jouni Malinen75ecf522011-06-27 15:19:46 -07007872 i802_set_sta_vlan(priv, addr, bss->ifname, 0);
7873 return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
7874 name);
7875 }
7876}
7877
7878
7879static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
7880{
7881 struct wpa_driver_nl80211_data *drv = eloop_ctx;
7882 struct sockaddr_ll lladdr;
7883 unsigned char buf[3000];
7884 int len;
7885 socklen_t fromlen = sizeof(lladdr);
7886
7887 len = recvfrom(sock, buf, sizeof(buf), 0,
7888 (struct sockaddr *)&lladdr, &fromlen);
7889 if (len < 0) {
7890 perror("recv");
7891 return;
7892 }
7893
7894 if (have_ifidx(drv, lladdr.sll_ifindex))
7895 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
7896}
7897
7898
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007899static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
7900 struct i802_bss *bss,
7901 const char *brname, const char *ifname)
7902{
7903 int ifindex;
7904 char in_br[IFNAMSIZ];
7905
7906 os_strlcpy(bss->brname, brname, IFNAMSIZ);
7907 ifindex = if_nametoindex(brname);
7908 if (ifindex == 0) {
7909 /*
7910 * Bridge was configured, but the bridge device does
7911 * not exist. Try to add it now.
7912 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007913 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007914 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
7915 "bridge interface %s: %s",
7916 brname, strerror(errno));
7917 return -1;
7918 }
7919 bss->added_bridge = 1;
7920 add_ifidx(drv, if_nametoindex(brname));
7921 }
7922
7923 if (linux_br_get(in_br, ifname) == 0) {
7924 if (os_strcmp(in_br, brname) == 0)
7925 return 0; /* already in the bridge */
7926
7927 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
7928 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007929 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
7930 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007931 wpa_printf(MSG_ERROR, "nl80211: Failed to "
7932 "remove interface %s from bridge "
7933 "%s: %s",
7934 ifname, brname, strerror(errno));
7935 return -1;
7936 }
7937 }
7938
7939 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
7940 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007941 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007942 wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
7943 "into bridge %s: %s",
7944 ifname, brname, strerror(errno));
7945 return -1;
7946 }
7947 bss->added_if_into_bridge = 1;
7948
7949 return 0;
7950}
7951
7952
7953static void *i802_init(struct hostapd_data *hapd,
7954 struct wpa_init_params *params)
7955{
7956 struct wpa_driver_nl80211_data *drv;
7957 struct i802_bss *bss;
7958 size_t i;
7959 char brname[IFNAMSIZ];
7960 int ifindex, br_ifindex;
7961 int br_added = 0;
7962
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007963 bss = wpa_driver_nl80211_init(hapd, params->ifname,
7964 params->global_priv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007965 if (bss == NULL)
7966 return NULL;
7967
7968 drv = bss->drv;
7969 drv->nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007970 drv->eapol_sock = -1;
7971
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007972 if (linux_br_get(brname, params->ifname) == 0) {
7973 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
7974 params->ifname, brname);
7975 br_ifindex = if_nametoindex(brname);
7976 } else {
7977 brname[0] = '\0';
7978 br_ifindex = 0;
7979 }
7980
7981 drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
7982 drv->if_indices = drv->default_if_indices;
7983 for (i = 0; i < params->num_bridge; i++) {
7984 if (params->bridge[i]) {
7985 ifindex = if_nametoindex(params->bridge[i]);
7986 if (ifindex)
7987 add_ifidx(drv, ifindex);
7988 if (ifindex == br_ifindex)
7989 br_added = 1;
7990 }
7991 }
7992 if (!br_added && br_ifindex &&
7993 (params->num_bridge == 0 || !params->bridge[0]))
7994 add_ifidx(drv, br_ifindex);
7995
7996 /* start listening for EAPOL on the default AP interface */
7997 add_ifidx(drv, drv->ifindex);
7998
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007999 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008000 goto failed;
8001
8002 if (params->bssid) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008003 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008004 params->bssid))
8005 goto failed;
8006 }
8007
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008008 if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008009 wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
8010 "into AP mode", bss->ifname);
8011 goto failed;
8012 }
8013
8014 if (params->num_bridge && params->bridge[0] &&
8015 i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
8016 goto failed;
8017
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008018 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008019 goto failed;
8020
8021 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
8022 if (drv->eapol_sock < 0) {
8023 perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
8024 goto failed;
8025 }
8026
8027 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
8028 {
8029 printf("Could not register read socket for eapol\n");
8030 goto failed;
8031 }
8032
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008033 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8034 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008035 goto failed;
8036
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008037 memcpy(bss->addr, params->own_addr, ETH_ALEN);
8038
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008039 return bss;
8040
8041failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008042 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008043 return NULL;
8044}
8045
8046
8047static void i802_deinit(void *priv)
8048{
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008049 struct i802_bss *bss = priv;
8050 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008051}
8052
8053#endif /* HOSTAPD */
8054
8055
8056static enum nl80211_iftype wpa_driver_nl80211_if_type(
8057 enum wpa_driver_if_type type)
8058{
8059 switch (type) {
8060 case WPA_IF_STATION:
8061 return NL80211_IFTYPE_STATION;
8062 case WPA_IF_P2P_CLIENT:
8063 case WPA_IF_P2P_GROUP:
8064 return NL80211_IFTYPE_P2P_CLIENT;
8065 case WPA_IF_AP_VLAN:
8066 return NL80211_IFTYPE_AP_VLAN;
8067 case WPA_IF_AP_BSS:
8068 return NL80211_IFTYPE_AP;
8069 case WPA_IF_P2P_GO:
8070 return NL80211_IFTYPE_P2P_GO;
8071 }
8072 return -1;
8073}
8074
8075
8076#ifdef CONFIG_P2P
8077
8078static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
8079{
8080 struct wpa_driver_nl80211_data *drv;
8081 dl_list_for_each(drv, &global->interfaces,
8082 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008083 if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008084 return 1;
8085 }
8086 return 0;
8087}
8088
8089
8090static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
8091 u8 *new_addr)
8092{
8093 unsigned int idx;
8094
8095 if (!drv->global)
8096 return -1;
8097
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008098 os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008099 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008100 new_addr[0] = drv->first_bss.addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008101 new_addr[0] ^= idx << 2;
8102 if (!nl80211_addr_in_use(drv->global, new_addr))
8103 break;
8104 }
8105 if (idx == 64)
8106 return -1;
8107
8108 wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
8109 MACSTR, MAC2STR(new_addr));
8110
8111 return 0;
8112}
8113
8114#endif /* CONFIG_P2P */
8115
8116
8117static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
8118 const char *ifname, const u8 *addr,
8119 void *bss_ctx, void **drv_priv,
8120 char *force_ifname, u8 *if_addr,
8121 const char *bridge)
8122{
8123 struct i802_bss *bss = priv;
8124 struct wpa_driver_nl80211_data *drv = bss->drv;
8125 int ifidx;
8126#ifdef HOSTAPD
8127 struct i802_bss *new_bss = NULL;
8128
8129 if (type == WPA_IF_AP_BSS) {
8130 new_bss = os_zalloc(sizeof(*new_bss));
8131 if (new_bss == NULL)
8132 return -1;
8133 }
8134#endif /* HOSTAPD */
8135
8136 if (addr)
8137 os_memcpy(if_addr, addr, ETH_ALEN);
8138 ifidx = nl80211_create_iface(drv, ifname,
8139 wpa_driver_nl80211_if_type(type), addr,
8140 0);
8141 if (ifidx < 0) {
8142#ifdef HOSTAPD
8143 os_free(new_bss);
8144#endif /* HOSTAPD */
8145 return -1;
8146 }
8147
8148 if (!addr &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008149 linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8150 if_addr) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008151 nl80211_remove_iface(drv, ifidx);
8152 return -1;
8153 }
8154
8155#ifdef CONFIG_P2P
8156 if (!addr &&
8157 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
8158 type == WPA_IF_P2P_GO)) {
8159 /* Enforce unique P2P Interface Address */
8160 u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
8161
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008162 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8163 own_addr) < 0 ||
8164 linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
8165 new_addr) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008166 nl80211_remove_iface(drv, ifidx);
8167 return -1;
8168 }
8169 if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
8170 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
8171 "for P2P group interface");
8172 if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
8173 nl80211_remove_iface(drv, ifidx);
8174 return -1;
8175 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008176 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008177 new_addr) < 0) {
8178 nl80211_remove_iface(drv, ifidx);
8179 return -1;
8180 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008181 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008182 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008183 }
8184#endif /* CONFIG_P2P */
8185
8186#ifdef HOSTAPD
8187 if (bridge &&
8188 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
8189 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
8190 "interface %s to a bridge %s", ifname, bridge);
8191 nl80211_remove_iface(drv, ifidx);
8192 os_free(new_bss);
8193 return -1;
8194 }
8195
8196 if (type == WPA_IF_AP_BSS) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008197 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
8198 {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008199 nl80211_remove_iface(drv, ifidx);
8200 os_free(new_bss);
8201 return -1;
8202 }
8203 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008204 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008205 new_bss->ifindex = ifidx;
8206 new_bss->drv = drv;
8207 new_bss->next = drv->first_bss.next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008208 new_bss->freq = drv->first_bss.freq;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08008209 new_bss->ctx = bss_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008210 drv->first_bss.next = new_bss;
8211 if (drv_priv)
8212 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008213 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008214
8215 /* Subscribe management frames for this WPA_IF_AP_BSS */
8216 if (nl80211_setup_ap(new_bss))
8217 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008218 }
8219#endif /* HOSTAPD */
8220
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008221 if (drv->global)
8222 drv->global->if_add_ifindex = ifidx;
8223
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008224 return 0;
8225}
8226
8227
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008228static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008229 enum wpa_driver_if_type type,
8230 const char *ifname)
8231{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008232 struct wpa_driver_nl80211_data *drv = bss->drv;
8233 int ifindex = if_nametoindex(ifname);
8234
8235 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
8236 __func__, type, ifname, ifindex);
8237 if (ifindex <= 0)
8238 return -1;
8239
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008240 nl80211_remove_iface(drv, ifindex);
8241
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008242#ifdef HOSTAPD
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008243 if (type != WPA_IF_AP_BSS)
8244 return 0;
8245
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008246 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008247 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
8248 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008249 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8250 "interface %s from bridge %s: %s",
8251 bss->ifname, bss->brname, strerror(errno));
8252 }
8253 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008254 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008255 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8256 "bridge %s: %s",
8257 bss->brname, strerror(errno));
8258 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008259
8260 if (bss != &drv->first_bss) {
8261 struct i802_bss *tbss;
8262
8263 for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
8264 if (tbss->next == bss) {
8265 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008266 /* Unsubscribe management frames */
8267 nl80211_teardown_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008268 nl80211_destroy_bss(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008269 os_free(bss);
8270 bss = NULL;
8271 break;
8272 }
8273 }
8274 if (bss)
8275 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
8276 "BSS %p in the list", __func__, bss);
8277 }
8278#endif /* HOSTAPD */
8279
8280 return 0;
8281}
8282
8283
8284static int cookie_handler(struct nl_msg *msg, void *arg)
8285{
8286 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8287 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8288 u64 *cookie = arg;
8289 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8290 genlmsg_attrlen(gnlh, 0), NULL);
8291 if (tb[NL80211_ATTR_COOKIE])
8292 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
8293 return NL_SKIP;
8294}
8295
8296
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008297static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008298 unsigned int freq, unsigned int wait,
8299 const u8 *buf, size_t buf_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008300 u64 *cookie_out, int no_cck, int no_ack,
8301 int offchanok)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008302{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008303 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008304 struct nl_msg *msg;
8305 u64 cookie;
8306 int ret = -1;
8307
8308 msg = nlmsg_alloc();
8309 if (!msg)
8310 return -1;
8311
Dmitry Shmidt04949592012-07-19 12:16:46 -07008312 wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
8313 "no_ack=%d offchanok=%d",
8314 freq, wait, no_cck, no_ack, offchanok);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008315 nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008316
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008317 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008318 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008319 if (wait)
8320 NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008321 if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008322 NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
8323 if (no_cck)
8324 NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
8325 if (no_ack)
8326 NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
8327
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008328 NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
8329
8330 cookie = 0;
8331 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
8332 msg = NULL;
8333 if (ret) {
8334 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008335 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
8336 freq, wait);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008337 goto nla_put_failure;
8338 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008339 wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
8340 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
8341 (long long unsigned int) cookie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008342
8343 if (cookie_out)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008344 *cookie_out = no_ack ? (u64) -1 : cookie;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008345
8346nla_put_failure:
8347 nlmsg_free(msg);
8348 return ret;
8349}
8350
8351
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008352static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
8353 unsigned int freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008354 unsigned int wait_time,
8355 const u8 *dst, const u8 *src,
8356 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008357 const u8 *data, size_t data_len,
8358 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008359{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008360 struct wpa_driver_nl80211_data *drv = bss->drv;
8361 int ret = -1;
8362 u8 *buf;
8363 struct ieee80211_hdr *hdr;
8364
8365 wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008366 "freq=%u MHz wait=%d ms no_cck=%d)",
8367 drv->ifindex, freq, wait_time, no_cck);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008368
8369 buf = os_zalloc(24 + data_len);
8370 if (buf == NULL)
8371 return ret;
8372 os_memcpy(buf + 24, data, data_len);
8373 hdr = (struct ieee80211_hdr *) buf;
8374 hdr->frame_control =
8375 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
8376 os_memcpy(hdr->addr1, dst, ETH_ALEN);
8377 os_memcpy(hdr->addr2, src, ETH_ALEN);
8378 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
8379
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008380 if (is_ap_interface(drv->nlmode))
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008381 ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
8382 0, freq, no_cck, 1,
8383 wait_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008384 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008385 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008386 24 + data_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008387 &drv->send_action_cookie,
8388 no_cck, 0, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008389
8390 os_free(buf);
8391 return ret;
8392}
8393
8394
8395static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
8396{
8397 struct i802_bss *bss = priv;
8398 struct wpa_driver_nl80211_data *drv = bss->drv;
8399 struct nl_msg *msg;
8400 int ret;
8401
8402 msg = nlmsg_alloc();
8403 if (!msg)
8404 return;
8405
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008406 nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008407
8408 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8409 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
8410
8411 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8412 msg = NULL;
8413 if (ret)
8414 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
8415 "(%s)", ret, strerror(-ret));
8416
8417 nla_put_failure:
8418 nlmsg_free(msg);
8419}
8420
8421
8422static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
8423 unsigned int duration)
8424{
8425 struct i802_bss *bss = priv;
8426 struct wpa_driver_nl80211_data *drv = bss->drv;
8427 struct nl_msg *msg;
8428 int ret;
8429 u64 cookie;
8430
8431 msg = nlmsg_alloc();
8432 if (!msg)
8433 return -1;
8434
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008435 nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008436
8437 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8438 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
8439 NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
8440
8441 cookie = 0;
8442 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008443 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008444 if (ret == 0) {
8445 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
8446 "0x%llx for freq=%u MHz duration=%u",
8447 (long long unsigned int) cookie, freq, duration);
8448 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008449 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008450 return 0;
8451 }
8452 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
8453 "(freq=%d duration=%u): %d (%s)",
8454 freq, duration, ret, strerror(-ret));
8455nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008456 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008457 return -1;
8458}
8459
8460
8461static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
8462{
8463 struct i802_bss *bss = priv;
8464 struct wpa_driver_nl80211_data *drv = bss->drv;
8465 struct nl_msg *msg;
8466 int ret;
8467
8468 if (!drv->pending_remain_on_chan) {
8469 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
8470 "to cancel");
8471 return -1;
8472 }
8473
8474 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
8475 "0x%llx",
8476 (long long unsigned int) drv->remain_on_chan_cookie);
8477
8478 msg = nlmsg_alloc();
8479 if (!msg)
8480 return -1;
8481
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008482 nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008483
8484 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8485 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
8486
8487 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008488 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008489 if (ret == 0)
8490 return 0;
8491 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
8492 "%d (%s)", ret, strerror(-ret));
8493nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008494 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008495 return -1;
8496}
8497
8498
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08008499static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008500{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008501 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008502
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008503 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008504 if (bss->nl_preq && drv->device_ap_sme &&
8505 is_ap_interface(drv->nlmode)) {
8506 /*
8507 * Do not disable Probe Request reporting that was
8508 * enabled in nl80211_setup_ap().
8509 */
8510 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
8511 "Probe Request reporting nl_preq=%p while "
8512 "in AP mode", bss->nl_preq);
8513 } else if (bss->nl_preq) {
8514 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
8515 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008516 eloop_unregister_read_sock(
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008517 nl_socket_get_fd(bss->nl_preq));
8518 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008519 }
8520 return 0;
8521 }
8522
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008523 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008524 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008525 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008526 return 0;
8527 }
8528
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008529 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
8530 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008531 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008532 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
8533 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008534
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008535 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008536 (WLAN_FC_TYPE_MGMT << 2) |
8537 (WLAN_FC_STYPE_PROBE_REQ << 4),
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008538 NULL, 0) < 0)
8539 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07008540
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008541 eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
8542 wpa_driver_nl80211_event_receive, bss->nl_cb,
8543 bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008544
8545 return 0;
8546
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008547 out_err:
8548 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008549 return -1;
8550}
8551
8552
8553static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
8554 int ifindex, int disabled)
8555{
8556 struct nl_msg *msg;
8557 struct nlattr *bands, *band;
8558 int ret;
8559
8560 msg = nlmsg_alloc();
8561 if (!msg)
8562 return -1;
8563
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008564 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008565 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
8566
8567 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
8568 if (!bands)
8569 goto nla_put_failure;
8570
8571 /*
8572 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
8573 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
8574 * rates. All 5 GHz rates are left enabled.
8575 */
8576 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
8577 if (!band)
8578 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008579 if (disabled) {
8580 NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
8581 "\x0c\x12\x18\x24\x30\x48\x60\x6c");
8582 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008583 nla_nest_end(msg, band);
8584
8585 nla_nest_end(msg, bands);
8586
8587 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8588 msg = NULL;
8589 if (ret) {
8590 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
8591 "(%s)", ret, strerror(-ret));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008592 } else
8593 drv->disabled_11b_rates = disabled;
8594
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008595 return ret;
8596
8597nla_put_failure:
8598 nlmsg_free(msg);
8599 return -1;
8600}
8601
8602
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008603static int wpa_driver_nl80211_deinit_ap(void *priv)
8604{
8605 struct i802_bss *bss = priv;
8606 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008607 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008608 return -1;
8609 wpa_driver_nl80211_del_beacon(drv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008610 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008611}
8612
8613
Dmitry Shmidt04949592012-07-19 12:16:46 -07008614static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
8615{
8616 struct i802_bss *bss = priv;
8617 struct wpa_driver_nl80211_data *drv = bss->drv;
8618 if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
8619 return -1;
8620 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
8621}
8622
8623
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008624static void wpa_driver_nl80211_resume(void *priv)
8625{
8626 struct i802_bss *bss = priv;
8627 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008628 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008629 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
8630 "resume event");
8631 }
8632}
8633
8634
8635static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
8636 const u8 *ies, size_t ies_len)
8637{
8638 struct i802_bss *bss = priv;
8639 struct wpa_driver_nl80211_data *drv = bss->drv;
8640 int ret;
8641 u8 *data, *pos;
8642 size_t data_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008643 const u8 *own_addr = bss->addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008644
8645 if (action != 1) {
8646 wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
8647 "action %d", action);
8648 return -1;
8649 }
8650
8651 /*
8652 * Action frame payload:
8653 * Category[1] = 6 (Fast BSS Transition)
8654 * Action[1] = 1 (Fast BSS Transition Request)
8655 * STA Address
8656 * Target AP Address
8657 * FT IEs
8658 */
8659
8660 data_len = 2 + 2 * ETH_ALEN + ies_len;
8661 data = os_malloc(data_len);
8662 if (data == NULL)
8663 return -1;
8664 pos = data;
8665 *pos++ = 0x06; /* FT Action category */
8666 *pos++ = action;
8667 os_memcpy(pos, own_addr, ETH_ALEN);
8668 pos += ETH_ALEN;
8669 os_memcpy(pos, target_ap, ETH_ALEN);
8670 pos += ETH_ALEN;
8671 os_memcpy(pos, ies, ies_len);
8672
8673 ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
8674 drv->bssid, own_addr, drv->bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008675 data, data_len, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008676 os_free(data);
8677
8678 return ret;
8679}
8680
8681
8682static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
8683{
8684 struct i802_bss *bss = priv;
8685 struct wpa_driver_nl80211_data *drv = bss->drv;
8686 struct nl_msg *msg, *cqm = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008687 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008688
8689 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
8690 "hysteresis=%d", threshold, hysteresis);
8691
8692 msg = nlmsg_alloc();
8693 if (!msg)
8694 return -1;
8695
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008696 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008697
8698 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8699
8700 cqm = nlmsg_alloc();
8701 if (cqm == NULL)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008702 goto nla_put_failure;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008703
8704 NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
8705 NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008706 if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
8707 goto nla_put_failure;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008708
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008709 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008710 msg = NULL;
8711
8712nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008713 nlmsg_free(cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008714 nlmsg_free(msg);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008715 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008716}
8717
8718
8719static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
8720{
8721 struct i802_bss *bss = priv;
8722 struct wpa_driver_nl80211_data *drv = bss->drv;
8723 int res;
8724
8725 os_memset(si, 0, sizeof(*si));
8726 res = nl80211_get_link_signal(drv, si);
8727 if (res != 0)
8728 return res;
8729
8730 return nl80211_get_link_noise(drv, si);
8731}
8732
8733
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008734static int wpa_driver_nl80211_shared_freq(void *priv)
8735{
8736 struct i802_bss *bss = priv;
8737 struct wpa_driver_nl80211_data *drv = bss->drv;
8738 struct wpa_driver_nl80211_data *driver;
8739 int freq = 0;
8740
8741 /*
8742 * If the same PHY is in connected state with some other interface,
8743 * then retrieve the assoc freq.
8744 */
8745 wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
8746 drv->phyname);
8747
8748 dl_list_for_each(driver, &drv->global->interfaces,
8749 struct wpa_driver_nl80211_data, list) {
8750 if (drv == driver ||
8751 os_strcmp(drv->phyname, driver->phyname) != 0 ||
8752#ifdef ANDROID_P2P
8753 (!driver->associated && !is_ap_interface(driver->nlmode)))
8754#else
8755 !driver->associated)
8756#endif
8757 continue;
8758
8759 wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
8760 MACSTR,
8761 driver->phyname, driver->first_bss.ifname,
8762 MAC2STR(driver->first_bss.addr));
Dmitry Shmidt04949592012-07-19 12:16:46 -07008763 if (is_ap_interface(driver->nlmode))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008764 freq = driver->first_bss.freq;
8765 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008766 freq = nl80211_get_assoc_freq(driver);
8767 wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
8768 drv->phyname, freq);
8769 }
8770
8771 if (!freq)
8772 wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
8773 "PHY (%s) in associated state", drv->phyname);
8774
8775 return freq;
8776}
8777
8778
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008779static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
8780 int encrypt)
8781{
8782 struct i802_bss *bss = priv;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008783 return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
8784 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008785}
8786
8787
8788static int nl80211_set_param(void *priv, const char *param)
8789{
8790 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
8791 if (param == NULL)
8792 return 0;
8793
8794#ifdef CONFIG_P2P
8795 if (os_strstr(param, "use_p2p_group_interface=1")) {
8796 struct i802_bss *bss = priv;
8797 struct wpa_driver_nl80211_data *drv = bss->drv;
8798
8799 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
8800 "interface");
8801 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
8802 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
8803 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008804#ifdef ANDROID_P2P
8805 if(os_strstr(param, "use_multi_chan_concurrent=1")) {
8806 struct i802_bss *bss = priv;
8807 struct wpa_driver_nl80211_data *drv = bss->drv;
8808 wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
8809 "concurrency");
8810 drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
8811 }
8812#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008813#endif /* CONFIG_P2P */
8814
8815 return 0;
8816}
8817
8818
8819static void * nl80211_global_init(void)
8820{
8821 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008822 struct netlink_config *cfg;
8823
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008824 global = os_zalloc(sizeof(*global));
8825 if (global == NULL)
8826 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008827 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008828 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008829 global->if_add_ifindex = -1;
8830
8831 cfg = os_zalloc(sizeof(*cfg));
8832 if (cfg == NULL)
8833 goto err;
8834
8835 cfg->ctx = global;
8836 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
8837 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
8838 global->netlink = netlink_init(cfg);
8839 if (global->netlink == NULL) {
8840 os_free(cfg);
8841 goto err;
8842 }
8843
8844 if (wpa_driver_nl80211_init_nl_global(global) < 0)
8845 goto err;
8846
8847 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
8848 if (global->ioctl_sock < 0) {
8849 perror("socket(PF_INET,SOCK_DGRAM)");
8850 goto err;
8851 }
8852
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008853 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008854
8855err:
8856 nl80211_global_deinit(global);
8857 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008858}
8859
8860
8861static void nl80211_global_deinit(void *priv)
8862{
8863 struct nl80211_global *global = priv;
8864 if (global == NULL)
8865 return;
8866 if (!dl_list_empty(&global->interfaces)) {
8867 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
8868 "nl80211_global_deinit",
8869 dl_list_len(&global->interfaces));
8870 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008871
8872 if (global->netlink)
8873 netlink_deinit(global->netlink);
8874
8875 nl_destroy_handles(&global->nl);
8876
8877 if (global->nl_event) {
8878 eloop_unregister_read_sock(
8879 nl_socket_get_fd(global->nl_event));
8880 nl_destroy_handles(&global->nl_event);
8881 }
8882
8883 nl_cb_put(global->nl_cb);
8884
8885 if (global->ioctl_sock >= 0)
8886 close(global->ioctl_sock);
8887
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008888 os_free(global);
8889}
8890
8891
8892static const char * nl80211_get_radio_name(void *priv)
8893{
8894 struct i802_bss *bss = priv;
8895 struct wpa_driver_nl80211_data *drv = bss->drv;
8896 return drv->phyname;
8897}
8898
8899
Jouni Malinen75ecf522011-06-27 15:19:46 -07008900static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
8901 const u8 *pmkid)
8902{
8903 struct nl_msg *msg;
8904
8905 msg = nlmsg_alloc();
8906 if (!msg)
8907 return -ENOMEM;
8908
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008909 nl80211_cmd(bss->drv, msg, 0, cmd);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008910
8911 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
8912 if (pmkid)
8913 NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
8914 if (bssid)
8915 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
8916
8917 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
8918 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008919 nlmsg_free(msg);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008920 return -ENOBUFS;
8921}
8922
8923
8924static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
8925{
8926 struct i802_bss *bss = priv;
8927 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
8928 return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
8929}
8930
8931
8932static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
8933{
8934 struct i802_bss *bss = priv;
8935 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
8936 MAC2STR(bssid));
8937 return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
8938}
8939
8940
8941static int nl80211_flush_pmkid(void *priv)
8942{
8943 struct i802_bss *bss = priv;
8944 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
8945 return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
8946}
8947
8948
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008949static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
8950 const u8 *replay_ctr)
8951{
8952 struct i802_bss *bss = priv;
8953 struct wpa_driver_nl80211_data *drv = bss->drv;
8954 struct nlattr *replay_nested;
8955 struct nl_msg *msg;
8956
8957 msg = nlmsg_alloc();
8958 if (!msg)
8959 return;
8960
8961 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
8962
8963 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8964
8965 replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
8966 if (!replay_nested)
8967 goto nla_put_failure;
8968
8969 NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
8970 NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
8971 NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
8972 replay_ctr);
8973
8974 nla_nest_end(msg, replay_nested);
8975
8976 send_and_recv_msgs(drv, msg, NULL, NULL);
8977 return;
8978 nla_put_failure:
8979 nlmsg_free(msg);
8980}
8981
8982
8983static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
8984 const u8 *addr, int qos)
8985{
8986 /* send data frame to poll STA and check whether
8987 * this frame is ACKed */
8988 struct {
8989 struct ieee80211_hdr hdr;
8990 u16 qos_ctl;
8991 } STRUCT_PACKED nulldata;
8992 size_t size;
8993
8994 /* Send data frame to poll STA and check whether this frame is ACKed */
8995
8996 os_memset(&nulldata, 0, sizeof(nulldata));
8997
8998 if (qos) {
8999 nulldata.hdr.frame_control =
9000 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9001 WLAN_FC_STYPE_QOS_NULL);
9002 size = sizeof(nulldata);
9003 } else {
9004 nulldata.hdr.frame_control =
9005 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9006 WLAN_FC_STYPE_NULLFUNC);
9007 size = sizeof(struct ieee80211_hdr);
9008 }
9009
9010 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
9011 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
9012 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
9013 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
9014
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009015 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
9016 0, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009017 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
9018 "send poll frame");
9019}
9020
9021static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
9022 int qos)
9023{
9024 struct i802_bss *bss = priv;
9025 struct wpa_driver_nl80211_data *drv = bss->drv;
9026 struct nl_msg *msg;
9027
9028 if (!drv->poll_command_supported) {
9029 nl80211_send_null_frame(bss, own_addr, addr, qos);
9030 return;
9031 }
9032
9033 msg = nlmsg_alloc();
9034 if (!msg)
9035 return;
9036
9037 nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
9038
9039 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
9040 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
9041
9042 send_and_recv_msgs(drv, msg, NULL, NULL);
9043 return;
9044 nla_put_failure:
9045 nlmsg_free(msg);
9046}
9047
9048
9049static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
9050{
9051 struct nl_msg *msg;
9052
9053 msg = nlmsg_alloc();
9054 if (!msg)
9055 return -ENOMEM;
9056
9057 nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
9058 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
9059 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
9060 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
9061 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
9062nla_put_failure:
9063 nlmsg_free(msg);
9064 return -ENOBUFS;
9065}
9066
9067
9068static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
9069 int ctwindow)
9070{
9071 struct i802_bss *bss = priv;
9072
9073 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
9074 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
9075
9076 if (opp_ps != -1 || ctwindow != -1)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009077#ifdef ANDROID_P2P
9078 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
9079#else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009080 return -1; /* Not yet supported */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009081#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009082
9083 if (legacy_ps == -1)
9084 return 0;
9085 if (legacy_ps != 0 && legacy_ps != 1)
9086 return -1; /* Not yet supported */
9087
9088 return nl80211_set_power_save(bss, legacy_ps);
9089}
9090
9091
9092#ifdef CONFIG_TDLS
9093
9094static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
9095 u8 dialog_token, u16 status_code,
9096 const u8 *buf, size_t len)
9097{
9098 struct i802_bss *bss = priv;
9099 struct wpa_driver_nl80211_data *drv = bss->drv;
9100 struct nl_msg *msg;
9101
9102 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9103 return -EOPNOTSUPP;
9104
9105 if (!dst)
9106 return -EINVAL;
9107
9108 msg = nlmsg_alloc();
9109 if (!msg)
9110 return -ENOMEM;
9111
9112 nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
9113 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
9114 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
9115 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
9116 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
9117 NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
9118 NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
9119
9120 return send_and_recv_msgs(drv, msg, NULL, NULL);
9121
9122nla_put_failure:
9123 nlmsg_free(msg);
9124 return -ENOBUFS;
9125}
9126
9127
9128static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
9129{
9130 struct i802_bss *bss = priv;
9131 struct wpa_driver_nl80211_data *drv = bss->drv;
9132 struct nl_msg *msg;
9133 enum nl80211_tdls_operation nl80211_oper;
9134
9135 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9136 return -EOPNOTSUPP;
9137
9138 switch (oper) {
9139 case TDLS_DISCOVERY_REQ:
9140 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
9141 break;
9142 case TDLS_SETUP:
9143 nl80211_oper = NL80211_TDLS_SETUP;
9144 break;
9145 case TDLS_TEARDOWN:
9146 nl80211_oper = NL80211_TDLS_TEARDOWN;
9147 break;
9148 case TDLS_ENABLE_LINK:
9149 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
9150 break;
9151 case TDLS_DISABLE_LINK:
9152 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
9153 break;
9154 case TDLS_ENABLE:
9155 return 0;
9156 case TDLS_DISABLE:
9157 return 0;
9158 default:
9159 return -EINVAL;
9160 }
9161
9162 msg = nlmsg_alloc();
9163 if (!msg)
9164 return -ENOMEM;
9165
9166 nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
9167 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
9168 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
9169 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
9170
9171 return send_and_recv_msgs(drv, msg, NULL, NULL);
9172
9173nla_put_failure:
9174 nlmsg_free(msg);
9175 return -ENOBUFS;
9176}
9177
9178#endif /* CONFIG TDLS */
9179
9180
9181#ifdef ANDROID
9182
9183typedef struct android_wifi_priv_cmd {
9184 char *buf;
9185 int used_len;
9186 int total_len;
9187} android_wifi_priv_cmd;
9188
9189static int drv_errors = 0;
9190
9191static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
9192{
9193 drv_errors++;
9194 if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
9195 drv_errors = 0;
9196 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
9197 }
9198}
9199
9200
9201static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
9202{
9203 struct wpa_driver_nl80211_data *drv = bss->drv;
9204 struct ifreq ifr;
9205 android_wifi_priv_cmd priv_cmd;
9206 char buf[MAX_DRV_CMD_SIZE];
9207 int ret;
9208
9209 os_memset(&ifr, 0, sizeof(ifr));
9210 os_memset(&priv_cmd, 0, sizeof(priv_cmd));
9211 os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
9212
9213 os_memset(buf, 0, sizeof(buf));
9214 os_strlcpy(buf, cmd, sizeof(buf));
9215
9216 priv_cmd.buf = buf;
9217 priv_cmd.used_len = sizeof(buf);
9218 priv_cmd.total_len = sizeof(buf);
9219 ifr.ifr_data = &priv_cmd;
9220
9221 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
9222 if (ret < 0) {
9223 wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
9224 __func__);
9225 wpa_driver_send_hang_msg(drv);
9226 return ret;
9227 }
9228
9229 drv_errors = 0;
9230 return 0;
9231}
9232
9233
9234static int android_pno_start(struct i802_bss *bss,
9235 struct wpa_driver_scan_params *params)
9236{
9237 struct wpa_driver_nl80211_data *drv = bss->drv;
9238 struct ifreq ifr;
9239 android_wifi_priv_cmd priv_cmd;
9240 int ret = 0, i = 0, bp;
9241 char buf[WEXT_PNO_MAX_COMMAND_SIZE];
9242
9243 bp = WEXT_PNOSETUP_HEADER_SIZE;
9244 os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
9245 buf[bp++] = WEXT_PNO_TLV_PREFIX;
9246 buf[bp++] = WEXT_PNO_TLV_VERSION;
9247 buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
9248 buf[bp++] = WEXT_PNO_TLV_RESERVED;
9249
9250 while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
9251 /* Check that there is enough space needed for 1 more SSID, the
9252 * other sections and null termination */
9253 if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
9254 WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
9255 break;
9256 wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
9257 params->ssids[i].ssid,
9258 params->ssids[i].ssid_len);
9259 buf[bp++] = WEXT_PNO_SSID_SECTION;
9260 buf[bp++] = params->ssids[i].ssid_len;
9261 os_memcpy(&buf[bp], params->ssids[i].ssid,
9262 params->ssids[i].ssid_len);
9263 bp += params->ssids[i].ssid_len;
9264 i++;
9265 }
9266
9267 buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
9268 os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
9269 WEXT_PNO_SCAN_INTERVAL);
9270 bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
9271
9272 buf[bp++] = WEXT_PNO_REPEAT_SECTION;
9273 os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
9274 WEXT_PNO_REPEAT);
9275 bp += WEXT_PNO_REPEAT_LENGTH;
9276
9277 buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
9278 os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
9279 WEXT_PNO_MAX_REPEAT);
9280 bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
9281
9282 memset(&ifr, 0, sizeof(ifr));
9283 memset(&priv_cmd, 0, sizeof(priv_cmd));
9284 os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
9285
9286 priv_cmd.buf = buf;
9287 priv_cmd.used_len = bp;
9288 priv_cmd.total_len = bp;
9289 ifr.ifr_data = &priv_cmd;
9290
9291 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
9292
9293 if (ret < 0) {
9294 wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
9295 ret);
9296 wpa_driver_send_hang_msg(drv);
9297 return ret;
9298 }
9299
9300 drv_errors = 0;
9301
9302 return android_priv_cmd(bss, "PNOFORCE 1");
9303}
9304
9305
9306static int android_pno_stop(struct i802_bss *bss)
9307{
9308 return android_priv_cmd(bss, "PNOFORCE 0");
9309}
9310
9311#endif /* ANDROID */
9312
9313
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009314static int driver_nl80211_set_key(const char *ifname, void *priv,
9315 enum wpa_alg alg, const u8 *addr,
9316 int key_idx, int set_tx,
9317 const u8 *seq, size_t seq_len,
9318 const u8 *key, size_t key_len)
9319{
9320 struct i802_bss *bss = priv;
9321 return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
9322 set_tx, seq, seq_len, key, key_len);
9323}
9324
9325
9326static int driver_nl80211_scan2(void *priv,
9327 struct wpa_driver_scan_params *params)
9328{
9329 struct i802_bss *bss = priv;
9330 return wpa_driver_nl80211_scan(bss, params);
9331}
9332
9333
9334static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
9335 int reason_code)
9336{
9337 struct i802_bss *bss = priv;
9338 return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
9339}
9340
9341
9342static int driver_nl80211_authenticate(void *priv,
9343 struct wpa_driver_auth_params *params)
9344{
9345 struct i802_bss *bss = priv;
9346 return wpa_driver_nl80211_authenticate(bss, params);
9347}
9348
9349
9350static void driver_nl80211_deinit(void *priv)
9351{
9352 struct i802_bss *bss = priv;
9353 wpa_driver_nl80211_deinit(bss);
9354}
9355
9356
9357static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
9358 const char *ifname)
9359{
9360 struct i802_bss *bss = priv;
9361 return wpa_driver_nl80211_if_remove(bss, type, ifname);
9362}
9363
9364
9365static int driver_nl80211_send_mlme(void *priv, const u8 *data,
9366 size_t data_len, int noack)
9367{
9368 struct i802_bss *bss = priv;
9369 return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
9370 0, 0, 0, 0);
9371}
9372
9373
9374static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
9375{
9376 struct i802_bss *bss = priv;
9377 return wpa_driver_nl80211_sta_remove(bss, addr);
9378}
9379
9380
9381#if defined(HOSTAPD) || defined(CONFIG_AP)
9382static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
9383 const char *ifname, int vlan_id)
9384{
9385 struct i802_bss *bss = priv;
9386 return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
9387}
9388#endif /* HOSTAPD || CONFIG_AP */
9389
9390
9391static int driver_nl80211_read_sta_data(void *priv,
9392 struct hostap_sta_driver_data *data,
9393 const u8 *addr)
9394{
9395 struct i802_bss *bss = priv;
9396 return i802_read_sta_data(bss, data, addr);
9397}
9398
9399
9400static int driver_nl80211_send_action(void *priv, unsigned int freq,
9401 unsigned int wait_time,
9402 const u8 *dst, const u8 *src,
9403 const u8 *bssid,
9404 const u8 *data, size_t data_len,
9405 int no_cck)
9406{
9407 struct i802_bss *bss = priv;
9408 return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
9409 bssid, data, data_len, no_cck);
9410}
9411
9412
9413static int driver_nl80211_probe_req_report(void *priv, int report)
9414{
9415 struct i802_bss *bss = priv;
9416 return wpa_driver_nl80211_probe_req_report(bss, report);
9417}
9418
9419
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009420const struct wpa_driver_ops wpa_driver_nl80211_ops = {
9421 .name = "nl80211",
9422 .desc = "Linux nl80211/cfg80211",
9423 .get_bssid = wpa_driver_nl80211_get_bssid,
9424 .get_ssid = wpa_driver_nl80211_get_ssid,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009425 .set_key = driver_nl80211_set_key,
9426 .scan2 = driver_nl80211_scan2,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009427 .sched_scan = wpa_driver_nl80211_sched_scan,
9428 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009429 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009430 .deauthenticate = driver_nl80211_deauthenticate,
9431 .authenticate = driver_nl80211_authenticate,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009432 .associate = wpa_driver_nl80211_associate,
9433 .global_init = nl80211_global_init,
9434 .global_deinit = nl80211_global_deinit,
9435 .init2 = wpa_driver_nl80211_init,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009436 .deinit = driver_nl80211_deinit,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009437 .get_capa = wpa_driver_nl80211_get_capa,
9438 .set_operstate = wpa_driver_nl80211_set_operstate,
9439 .set_supp_port = wpa_driver_nl80211_set_supp_port,
9440 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009441 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009442 .if_add = wpa_driver_nl80211_if_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009443 .if_remove = driver_nl80211_if_remove,
9444 .send_mlme = driver_nl80211_send_mlme,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009445 .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
9446 .sta_add = wpa_driver_nl80211_sta_add,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009447 .sta_remove = driver_nl80211_sta_remove,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009448 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
9449 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
9450#ifdef HOSTAPD
9451 .hapd_init = i802_init,
9452 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -07009453 .set_wds_sta = i802_set_wds_sta,
9454#endif /* HOSTAPD */
9455#if defined(HOSTAPD) || defined(CONFIG_AP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009456 .get_seqnum = i802_get_seqnum,
9457 .flush = i802_flush,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009458 .get_inact_sec = i802_get_inact_sec,
9459 .sta_clear_stats = i802_sta_clear_stats,
9460 .set_rts = i802_set_rts,
9461 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009462 .set_tx_queue_params = i802_set_tx_queue_params,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009463 .set_sta_vlan = driver_nl80211_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009464 .sta_deauth = i802_sta_deauth,
9465 .sta_disassoc = i802_sta_disassoc,
9466#endif /* HOSTAPD || CONFIG_AP */
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009467 .read_sta_data = driver_nl80211_read_sta_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009468 .set_freq = i802_set_freq,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009469 .send_action = driver_nl80211_send_action,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009470 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
9471 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
9472 .cancel_remain_on_channel =
9473 wpa_driver_nl80211_cancel_remain_on_channel,
Dmitry Shmidt4b9d52f2013-02-05 17:44:43 -08009474 .probe_req_report = driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009475 .deinit_ap = wpa_driver_nl80211_deinit_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -07009476 .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009477 .resume = wpa_driver_nl80211_resume,
9478 .send_ft_action = nl80211_send_ft_action,
9479 .signal_monitor = nl80211_signal_monitor,
9480 .signal_poll = nl80211_signal_poll,
9481 .send_frame = nl80211_send_frame,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009482 .shared_freq = wpa_driver_nl80211_shared_freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009483 .set_param = nl80211_set_param,
9484 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -07009485 .add_pmkid = nl80211_add_pmkid,
9486 .remove_pmkid = nl80211_remove_pmkid,
9487 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009488 .set_rekey_info = nl80211_set_rekey_info,
9489 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009490 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009491#ifdef CONFIG_TDLS
9492 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
9493 .tdls_oper = nl80211_tdls_oper,
9494#endif /* CONFIG_TDLS */
9495#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009496 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009497 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009498 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
9499#endif
Dmitry Shmidt738a26e2011-07-07 14:22:14 -07009500#ifdef ANDROID
9501 .driver_cmd = wpa_driver_nl80211_driver_cmd,
9502#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009503};