blob: e530911d2fba1ea44b95b993c9519b89d21ccc00 [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);
181static void wpa_driver_nl80211_deinit(void *priv);
182
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700183struct i802_bss {
184 struct wpa_driver_nl80211_data *drv;
185 struct i802_bss *next;
186 int ifindex;
187 char ifname[IFNAMSIZ + 1];
188 char brname[IFNAMSIZ];
189 unsigned int beacon_set:1;
190 unsigned int added_if_into_bridge:1;
191 unsigned int added_bridge:1;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700192 unsigned int in_deinit:1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800193
194 u8 addr[ETH_ALEN];
195
196 int freq;
197
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800198 void *ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800199 struct nl_handle *nl_preq, *nl_mgmt;
200 struct nl_cb *nl_cb;
201
202 struct nl80211_wiphy_data *wiphy_data;
203 struct dl_list wiphy_list;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700204};
205
206struct wpa_driver_nl80211_data {
207 struct nl80211_global *global;
208 struct dl_list list;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800209 struct dl_list wiphy_list;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700210 char phyname[32];
211 void *ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700212 int ifindex;
213 int if_removed;
214 int if_disabled;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800215 int ignore_if_down_event;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700216 struct rfkill_data *rfkill;
217 struct wpa_driver_capa capa;
218 int has_capability;
219
220 int operstate;
221
222 int scan_complete_events;
223
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700224 struct nl_cb *nl_cb;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700225
226 u8 auth_bssid[ETH_ALEN];
227 u8 bssid[ETH_ALEN];
228 int associated;
229 u8 ssid[32];
230 size_t ssid_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800231 enum nl80211_iftype nlmode;
232 enum nl80211_iftype ap_scan_as_station;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700233 unsigned int assoc_freq;
234
235 int monitor_sock;
236 int monitor_ifidx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800237 int monitor_refcount;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700238
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800239 unsigned int disabled_11b_rates:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700240 unsigned int pending_remain_on_chan:1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800241 unsigned int in_interface_list:1;
242 unsigned int device_ap_sme:1;
243 unsigned int poll_command_supported:1;
244 unsigned int data_tx_status:1;
245 unsigned int scan_for_auth:1;
246 unsigned int retry_auth:1;
247 unsigned int use_monitor:1;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800248 unsigned int ignore_next_local_disconnect:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700249
250 u64 remain_on_chan_cookie;
251 u64 send_action_cookie;
252
253 unsigned int last_mgmt_freq;
254
255 struct wpa_driver_scan_filter *filter_ssids;
256 size_t num_filter_ssids;
257
258 struct i802_bss first_bss;
259
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800260 int eapol_tx_sock;
261
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700262#ifdef HOSTAPD
263 int eapol_sock; /* socket for EAPOL frames */
264
265 int default_if_indices[16];
266 int *if_indices;
267 int num_if_indices;
268
269 int last_freq;
270 int last_freq_ht;
271#endif /* HOSTAPD */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800272
273 /* From failed authentication command */
274 int auth_freq;
275 u8 auth_bssid_[ETH_ALEN];
276 u8 auth_ssid[32];
277 size_t auth_ssid_len;
278 int auth_alg;
279 u8 *auth_ie;
280 size_t auth_ie_len;
281 u8 auth_wep_key[4][16];
282 size_t auth_wep_key_len[4];
283 int auth_wep_tx_keyidx;
284 int auth_local_state_change;
285 int auth_p2p;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286};
287
288
289static 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 Shmidt8d520ff2011-05-09 14:06:53 -0700304static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800305#ifdef ANDROID
306static int android_pno_start(struct i802_bss *bss,
307 struct wpa_driver_scan_params *params);
308static int android_pno_stop(struct i802_bss *bss);
309#endif /* ANDROID */
310#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -0700311int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800312int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
Dmitry Shmidt6e933c12011-09-27 12:29:26 -0700313int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
314int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
315 const struct wpabuf *proberesp,
316 const struct wpabuf *assocresp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700317
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800318#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700319#ifdef HOSTAPD
320static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
321static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
322static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
323static int wpa_driver_nl80211_if_remove(void *priv,
324 enum wpa_driver_if_type type,
325 const char *ifname);
326#else /* HOSTAPD */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800327static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
328{
329}
330
331static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
332{
333}
334
335static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700336{
337 return 0;
338}
339#endif /* HOSTAPD */
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700340#ifdef ANDROID
341extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
342 size_t buf_len);
343#endif
344
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700345static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
346static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
347 int ifindex, int disabled);
348
349static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800350static int wpa_driver_nl80211_authenticate_retry(
351 struct wpa_driver_nl80211_data *drv);
352
353
354static int is_ap_interface(enum nl80211_iftype nlmode)
355{
356 return (nlmode == NL80211_IFTYPE_AP ||
357 nlmode == NL80211_IFTYPE_P2P_GO);
358}
359
360
361static int is_sta_interface(enum nl80211_iftype nlmode)
362{
363 return (nlmode == NL80211_IFTYPE_STATION ||
364 nlmode == NL80211_IFTYPE_P2P_CLIENT);
365}
366
367
368static int is_p2p_interface(enum nl80211_iftype nlmode)
369{
370 return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
371 nlmode == NL80211_IFTYPE_P2P_GO);
372}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700373
374
Jouni Malinen87fd2792011-05-16 18:35:42 +0300375struct nl80211_bss_info_arg {
376 struct wpa_driver_nl80211_data *drv;
377 struct wpa_scan_results *res;
378 unsigned int assoc_freq;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800379 u8 assoc_bssid[ETH_ALEN];
Jouni Malinen87fd2792011-05-16 18:35:42 +0300380};
381
382static int bss_info_handler(struct nl_msg *msg, void *arg);
383
384
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700385/* nl80211 code */
386static int ack_handler(struct nl_msg *msg, void *arg)
387{
388 int *err = arg;
389 *err = 0;
390 return NL_STOP;
391}
392
393static int finish_handler(struct nl_msg *msg, void *arg)
394{
395 int *ret = arg;
396 *ret = 0;
397 return NL_SKIP;
398}
399
400static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
401 void *arg)
402{
403 int *ret = arg;
404 *ret = err->error;
405 return NL_SKIP;
406}
407
408
409static int no_seq_check(struct nl_msg *msg, void *arg)
410{
411 return NL_OK;
412}
413
414
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800415static int send_and_recv(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700416 struct nl_handle *nl_handle, struct nl_msg *msg,
417 int (*valid_handler)(struct nl_msg *, void *),
418 void *valid_data)
419{
420 struct nl_cb *cb;
421 int err = -ENOMEM;
422
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800423 cb = nl_cb_clone(global->nl_cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700424 if (!cb)
425 goto out;
426
427 err = nl_send_auto_complete(nl_handle, msg);
428 if (err < 0)
429 goto out;
430
431 err = 1;
432
433 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
434 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
435 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
436
437 if (valid_handler)
438 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
439 valid_handler, valid_data);
440
441 while (err > 0)
442 nl_recvmsgs(nl_handle, cb);
443 out:
444 nl_cb_put(cb);
445 nlmsg_free(msg);
446 return err;
447}
448
449
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800450static int send_and_recv_msgs_global(struct nl80211_global *global,
451 struct nl_msg *msg,
452 int (*valid_handler)(struct nl_msg *, void *),
453 void *valid_data)
454{
455 return send_and_recv(global, global->nl, msg, valid_handler,
456 valid_data);
457}
458
Dmitry Shmidt04949592012-07-19 12:16:46 -0700459
Jouni Malinen80da0422012-08-09 15:29:25 -0700460#ifndef ANDROID
461static
462#endif
Dmitry Shmidt738a26e2011-07-07 14:22:14 -0700463int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700464 struct nl_msg *msg,
465 int (*valid_handler)(struct nl_msg *, void *),
466 void *valid_data)
467{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800468 return send_and_recv(drv->global, drv->global->nl, msg,
469 valid_handler, valid_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700470}
471
472
473struct family_data {
474 const char *group;
475 int id;
476};
477
478
479static int family_handler(struct nl_msg *msg, void *arg)
480{
481 struct family_data *res = arg;
482 struct nlattr *tb[CTRL_ATTR_MAX + 1];
483 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
484 struct nlattr *mcgrp;
485 int i;
486
487 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
488 genlmsg_attrlen(gnlh, 0), NULL);
489 if (!tb[CTRL_ATTR_MCAST_GROUPS])
490 return NL_SKIP;
491
492 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
493 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
494 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
495 nla_len(mcgrp), NULL);
496 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
497 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
498 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
499 res->group,
500 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
501 continue;
502 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
503 break;
504 };
505
506 return NL_SKIP;
507}
508
509
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800510static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700511 const char *family, const char *group)
512{
513 struct nl_msg *msg;
514 int ret = -1;
515 struct family_data res = { group, -ENOENT };
516
517 msg = nlmsg_alloc();
518 if (!msg)
519 return -ENOMEM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800520 genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700521 0, 0, CTRL_CMD_GETFAMILY, 0);
522 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
523
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800524 ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700525 msg = NULL;
526 if (ret == 0)
527 ret = res.id;
528
529nla_put_failure:
530 nlmsg_free(msg);
531 return ret;
532}
533
534
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800535static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
536 struct nl_msg *msg, int flags, uint8_t cmd)
537{
538 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
539 0, flags, cmd, 0);
540}
541
542
543struct wiphy_idx_data {
544 int wiphy_idx;
545};
546
547
548static int netdev_info_handler(struct nl_msg *msg, void *arg)
549{
550 struct nlattr *tb[NL80211_ATTR_MAX + 1];
551 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
552 struct wiphy_idx_data *info = arg;
553
554 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
555 genlmsg_attrlen(gnlh, 0), NULL);
556
557 if (tb[NL80211_ATTR_WIPHY])
558 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
559
560 return NL_SKIP;
561}
562
563
564static int nl80211_get_wiphy_index(struct i802_bss *bss)
565{
566 struct nl_msg *msg;
567 struct wiphy_idx_data data = {
568 .wiphy_idx = -1,
569 };
570
571 msg = nlmsg_alloc();
572 if (!msg)
573 return -1;
574
575 nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
576
577 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
578
579 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
580 return data.wiphy_idx;
581 msg = NULL;
582nla_put_failure:
583 nlmsg_free(msg);
584 return -1;
585}
586
587
588static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
589 struct nl80211_wiphy_data *w)
590{
591 struct nl_msg *msg;
592 int ret = -1;
593
594 msg = nlmsg_alloc();
595 if (!msg)
596 return -1;
597
598 nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
599
600 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
601
602 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
603 msg = NULL;
604 if (ret) {
605 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
606 "failed: ret=%d (%s)",
607 ret, strerror(-ret));
608 goto nla_put_failure;
609 }
610 ret = 0;
611nla_put_failure:
612 nlmsg_free(msg);
613 return ret;
614}
615
616
617static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
618{
619 struct nl80211_wiphy_data *w = eloop_ctx;
620
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800621 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800622
623 nl_recvmsgs(handle, w->nl_cb);
624}
625
626
627static int process_beacon_event(struct nl_msg *msg, void *arg)
628{
629 struct nl80211_wiphy_data *w = arg;
630 struct wpa_driver_nl80211_data *drv;
631 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
632 struct nlattr *tb[NL80211_ATTR_MAX + 1];
633 union wpa_event_data event;
634
635 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
636 genlmsg_attrlen(gnlh, 0), NULL);
637
638 if (gnlh->cmd != NL80211_CMD_FRAME) {
639 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
640 gnlh->cmd);
641 return NL_SKIP;
642 }
643
644 if (!tb[NL80211_ATTR_FRAME])
645 return NL_SKIP;
646
647 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
648 wiphy_list) {
649 os_memset(&event, 0, sizeof(event));
650 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
651 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
652 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
653 }
654
655 return NL_SKIP;
656}
657
658
659static struct nl80211_wiphy_data *
660nl80211_get_wiphy_data_ap(struct i802_bss *bss)
661{
662 static DEFINE_DL_LIST(nl80211_wiphys);
663 struct nl80211_wiphy_data *w;
664 int wiphy_idx, found = 0;
665 struct i802_bss *tmp_bss;
666
667 if (bss->wiphy_data != NULL)
668 return bss->wiphy_data;
669
670 wiphy_idx = nl80211_get_wiphy_index(bss);
671
672 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
673 if (w->wiphy_idx == wiphy_idx)
674 goto add;
675 }
676
677 /* alloc new one */
678 w = os_zalloc(sizeof(*w));
679 if (w == NULL)
680 return NULL;
681 w->wiphy_idx = wiphy_idx;
682 dl_list_init(&w->bsss);
683 dl_list_init(&w->drvs);
684
685 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
686 if (!w->nl_cb) {
687 os_free(w);
688 return NULL;
689 }
690 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
691 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
692 w);
693
694 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
695 "wiphy beacons");
696 if (w->nl_beacons == NULL) {
697 os_free(w);
698 return NULL;
699 }
700
701 if (nl80211_register_beacons(bss->drv, w)) {
702 nl_destroy_handles(&w->nl_beacons);
703 os_free(w);
704 return NULL;
705 }
706
707 eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
708 nl80211_recv_beacons, w, w->nl_beacons);
709
710 dl_list_add(&nl80211_wiphys, &w->list);
711
712add:
713 /* drv entry for this bss already there? */
714 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
715 if (tmp_bss->drv == bss->drv) {
716 found = 1;
717 break;
718 }
719 }
720 /* if not add it */
721 if (!found)
722 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
723
724 dl_list_add(&w->bsss, &bss->wiphy_list);
725 bss->wiphy_data = w;
726 return w;
727}
728
729
730static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
731{
732 struct nl80211_wiphy_data *w = bss->wiphy_data;
733 struct i802_bss *tmp_bss;
734 int found = 0;
735
736 if (w == NULL)
737 return;
738 bss->wiphy_data = NULL;
739 dl_list_del(&bss->wiphy_list);
740
741 /* still any for this drv present? */
742 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
743 if (tmp_bss->drv == bss->drv) {
744 found = 1;
745 break;
746 }
747 }
748 /* if not remove it */
749 if (!found)
750 dl_list_del(&bss->drv->wiphy_list);
751
752 if (!dl_list_empty(&w->bsss))
753 return;
754
755 eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
756
757 nl_cb_put(w->nl_cb);
758 nl_destroy_handles(&w->nl_beacons);
759 dl_list_del(&w->list);
760 os_free(w);
761}
762
763
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700764static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
765{
766 struct i802_bss *bss = priv;
767 struct wpa_driver_nl80211_data *drv = bss->drv;
768 if (!drv->associated)
769 return -1;
770 os_memcpy(bssid, drv->bssid, ETH_ALEN);
771 return 0;
772}
773
774
775static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
776{
777 struct i802_bss *bss = priv;
778 struct wpa_driver_nl80211_data *drv = bss->drv;
779 if (!drv->associated)
780 return -1;
781 os_memcpy(ssid, drv->ssid, drv->ssid_len);
782 return drv->ssid_len;
783}
784
785
786static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
787 char *buf, size_t len, int del)
788{
789 union wpa_event_data event;
790
791 os_memset(&event, 0, sizeof(event));
792 if (len > sizeof(event.interface_status.ifname))
793 len = sizeof(event.interface_status.ifname) - 1;
794 os_memcpy(event.interface_status.ifname, buf, len);
795 event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
796 EVENT_INTERFACE_ADDED;
797
798 wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
799 del ? "DEL" : "NEW",
800 event.interface_status.ifname,
801 del ? "removed" : "added");
802
803 if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700804 if (del) {
805 if (drv->if_removed) {
806 wpa_printf(MSG_DEBUG, "nl80211: if_removed "
807 "already set - ignore event");
808 return;
809 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700810 drv->if_removed = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700811 } else {
812 if (if_nametoindex(drv->first_bss.ifname) == 0) {
813 wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
814 "does not exist - ignore "
815 "RTM_NEWLINK",
816 drv->first_bss.ifname);
817 return;
818 }
819 if (!drv->if_removed) {
820 wpa_printf(MSG_DEBUG, "nl80211: if_removed "
821 "already cleared - ignore event");
822 return;
823 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700824 drv->if_removed = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700825 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700826 }
827
828 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
829}
830
831
832static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
833 u8 *buf, size_t len)
834{
835 int attrlen, rta_len;
836 struct rtattr *attr;
837
838 attrlen = len;
839 attr = (struct rtattr *) buf;
840
841 rta_len = RTA_ALIGN(sizeof(struct rtattr));
842 while (RTA_OK(attr, attrlen)) {
843 if (attr->rta_type == IFLA_IFNAME) {
844 if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
845 == 0)
846 return 1;
847 else
848 break;
849 }
850 attr = RTA_NEXT(attr, attrlen);
851 }
852
853 return 0;
854}
855
856
857static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
858 int ifindex, u8 *buf, size_t len)
859{
860 if (drv->ifindex == ifindex)
861 return 1;
862
863 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
864 drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
865 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
866 "interface");
867 wpa_driver_nl80211_finish_drv_init(drv);
868 return 1;
869 }
870
871 return 0;
872}
873
874
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800875static struct wpa_driver_nl80211_data *
876nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
877{
878 struct wpa_driver_nl80211_data *drv;
879 dl_list_for_each(drv, &global->interfaces,
880 struct wpa_driver_nl80211_data, list) {
881 if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
882 have_ifidx(drv, idx))
883 return drv;
884 }
885 return NULL;
886}
887
888
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700889static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
890 struct ifinfomsg *ifi,
891 u8 *buf, size_t len)
892{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800893 struct nl80211_global *global = ctx;
894 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700895 int attrlen, rta_len;
896 struct rtattr *attr;
897 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800898 char namebuf[IFNAMSIZ];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700899
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800900 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
901 if (!drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700902 wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
903 "ifindex %d", ifi->ifi_index);
904 return;
905 }
906
907 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
908 "(%s%s%s%s)",
909 drv->operstate, ifi->ifi_flags,
910 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
911 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
912 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
913 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
914
915 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800916 if (if_indextoname(ifi->ifi_index, namebuf) &&
917 linux_iface_up(drv->global->ioctl_sock,
918 drv->first_bss.ifname) > 0) {
919 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
920 "event since interface %s is up", namebuf);
921 return;
922 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700923 wpa_printf(MSG_DEBUG, "nl80211: Interface down");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800924 if (drv->ignore_if_down_event) {
925 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
926 "event generated by mode change");
927 drv->ignore_if_down_event = 0;
928 } else {
929 drv->if_disabled = 1;
930 wpa_supplicant_event(drv->ctx,
931 EVENT_INTERFACE_DISABLED, NULL);
932 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700933 }
934
935 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800936 if (if_indextoname(ifi->ifi_index, namebuf) &&
937 linux_iface_up(drv->global->ioctl_sock,
938 drv->first_bss.ifname) == 0) {
939 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
940 "event since interface %s is down",
941 namebuf);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700942 } else if (if_nametoindex(drv->first_bss.ifname) == 0) {
943 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
944 "event since interface %s does not exist",
945 drv->first_bss.ifname);
946 } else if (drv->if_removed) {
947 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
948 "event since interface %s is marked "
949 "removed", drv->first_bss.ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800950 } else {
951 wpa_printf(MSG_DEBUG, "nl80211: Interface up");
952 drv->if_disabled = 0;
953 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
954 NULL);
955 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700956 }
957
958 /*
959 * Some drivers send the association event before the operup event--in
960 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
961 * fails. This will hit us when wpa_supplicant does not need to do
962 * IEEE 802.1X authentication
963 */
964 if (drv->operstate == 1 &&
965 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
966 !(ifi->ifi_flags & IFF_RUNNING))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800967 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700968 -1, IF_OPER_UP);
969
970 attrlen = len;
971 attr = (struct rtattr *) buf;
972 rta_len = RTA_ALIGN(sizeof(struct rtattr));
973 while (RTA_OK(attr, attrlen)) {
974 if (attr->rta_type == IFLA_IFNAME) {
975 wpa_driver_nl80211_event_link(
976 drv,
977 ((char *) attr) + rta_len,
978 attr->rta_len - rta_len, 0);
979 } else if (attr->rta_type == IFLA_MASTER)
980 brid = nla_get_u32((struct nlattr *) attr);
981 attr = RTA_NEXT(attr, attrlen);
982 }
983
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700984 if (ifi->ifi_family == AF_BRIDGE && brid) {
985 /* device has been added to bridge */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700986 if_indextoname(brid, namebuf);
987 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
988 brid, namebuf);
989 add_ifidx(drv, brid);
990 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700991}
992
993
994static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
995 struct ifinfomsg *ifi,
996 u8 *buf, size_t len)
997{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800998 struct nl80211_global *global = ctx;
999 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001000 int attrlen, rta_len;
1001 struct rtattr *attr;
1002 u32 brid = 0;
1003
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001004 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
1005 if (!drv) {
1006 wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
1007 "foreign ifindex %d", ifi->ifi_index);
1008 return;
1009 }
1010
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001011 attrlen = len;
1012 attr = (struct rtattr *) buf;
1013
1014 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1015 while (RTA_OK(attr, attrlen)) {
1016 if (attr->rta_type == IFLA_IFNAME) {
1017 wpa_driver_nl80211_event_link(
1018 drv,
1019 ((char *) attr) + rta_len,
1020 attr->rta_len - rta_len, 1);
1021 } else if (attr->rta_type == IFLA_MASTER)
1022 brid = nla_get_u32((struct nlattr *) attr);
1023 attr = RTA_NEXT(attr, attrlen);
1024 }
1025
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001026 if (ifi->ifi_family == AF_BRIDGE && brid) {
1027 /* device has been removed from bridge */
1028 char namebuf[IFNAMSIZ];
1029 if_indextoname(brid, namebuf);
1030 wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
1031 "%s", brid, namebuf);
1032 del_ifidx(drv, brid);
1033 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001034}
1035
1036
1037static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
1038 const u8 *frame, size_t len)
1039{
1040 const struct ieee80211_mgmt *mgmt;
1041 union wpa_event_data event;
1042
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001043 wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001044 mgmt = (const struct ieee80211_mgmt *) frame;
1045 if (len < 24 + sizeof(mgmt->u.auth)) {
1046 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
1047 "frame");
1048 return;
1049 }
1050
1051 os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
1052 os_memset(&event, 0, sizeof(event));
1053 os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
1054 event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001055 event.auth.auth_transaction =
1056 le_to_host16(mgmt->u.auth.auth_transaction);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001057 event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
1058 if (len > 24 + sizeof(mgmt->u.auth)) {
1059 event.auth.ies = mgmt->u.auth.variable;
1060 event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
1061 }
1062
1063 wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
1064}
1065
1066
Jouni Malinen87fd2792011-05-16 18:35:42 +03001067static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1068{
1069 struct nl_msg *msg;
1070 int ret;
1071 struct nl80211_bss_info_arg arg;
1072
1073 os_memset(&arg, 0, sizeof(arg));
1074 msg = nlmsg_alloc();
1075 if (!msg)
1076 goto nla_put_failure;
1077
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001078 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001079 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1080
1081 arg.drv = drv;
1082 ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
1083 msg = NULL;
1084 if (ret == 0) {
1085 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
1086 "associated BSS from scan results: %u MHz",
1087 arg.assoc_freq);
1088 return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
1089 }
1090 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1091 "(%s)", ret, strerror(-ret));
1092nla_put_failure:
1093 nlmsg_free(msg);
1094 return drv->assoc_freq;
1095}
1096
1097
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001098static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
1099 const u8 *frame, size_t len)
1100{
1101 const struct ieee80211_mgmt *mgmt;
1102 union wpa_event_data event;
1103 u16 status;
1104
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001105 wpa_printf(MSG_DEBUG, "nl80211: Associate event");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001106 mgmt = (const struct ieee80211_mgmt *) frame;
1107 if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
1108 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
1109 "frame");
1110 return;
1111 }
1112
1113 status = le_to_host16(mgmt->u.assoc_resp.status_code);
1114 if (status != WLAN_STATUS_SUCCESS) {
1115 os_memset(&event, 0, sizeof(event));
1116 event.assoc_reject.bssid = mgmt->bssid;
1117 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
1118 event.assoc_reject.resp_ies =
1119 (u8 *) mgmt->u.assoc_resp.variable;
1120 event.assoc_reject.resp_ies_len =
1121 len - 24 - sizeof(mgmt->u.assoc_resp);
1122 }
1123 event.assoc_reject.status_code = status;
1124
1125 wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
1126 return;
1127 }
1128
1129 drv->associated = 1;
1130 os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
1131
1132 os_memset(&event, 0, sizeof(event));
1133 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
1134 event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
1135 event.assoc_info.resp_ies_len =
1136 len - 24 - sizeof(mgmt->u.assoc_resp);
1137 }
1138
1139 event.assoc_info.freq = drv->assoc_freq;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001140
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001141 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
1142}
1143
1144
1145static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
1146 enum nl80211_commands cmd, struct nlattr *status,
1147 struct nlattr *addr, struct nlattr *req_ie,
1148 struct nlattr *resp_ie)
1149{
1150 union wpa_event_data event;
1151
1152 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
1153 /*
1154 * Avoid reporting two association events that would confuse
1155 * the core code.
1156 */
1157 wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
1158 "when using userspace SME", cmd);
1159 return;
1160 }
1161
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001162 if (cmd == NL80211_CMD_CONNECT)
1163 wpa_printf(MSG_DEBUG, "nl80211: Connect event");
1164 else if (cmd == NL80211_CMD_ROAM)
1165 wpa_printf(MSG_DEBUG, "nl80211: Roam event");
1166
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001167 os_memset(&event, 0, sizeof(event));
1168 if (cmd == NL80211_CMD_CONNECT &&
1169 nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
1170 if (addr)
1171 event.assoc_reject.bssid = nla_data(addr);
1172 if (resp_ie) {
1173 event.assoc_reject.resp_ies = nla_data(resp_ie);
1174 event.assoc_reject.resp_ies_len = nla_len(resp_ie);
1175 }
1176 event.assoc_reject.status_code = nla_get_u16(status);
1177 wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
1178 return;
1179 }
1180
1181 drv->associated = 1;
1182 if (addr)
1183 os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
1184
1185 if (req_ie) {
1186 event.assoc_info.req_ies = nla_data(req_ie);
1187 event.assoc_info.req_ies_len = nla_len(req_ie);
1188 }
1189 if (resp_ie) {
1190 event.assoc_info.resp_ies = nla_data(resp_ie);
1191 event.assoc_info.resp_ies_len = nla_len(resp_ie);
1192 }
1193
Jouni Malinen87fd2792011-05-16 18:35:42 +03001194 event.assoc_info.freq = nl80211_get_assoc_freq(drv);
1195
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001196 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
1197}
1198
1199
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001200static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001201 struct nlattr *reason, struct nlattr *addr,
1202 struct nlattr *by_ap)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001203{
1204 union wpa_event_data data;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001205 unsigned int locally_generated = by_ap == NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001206
1207 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
1208 /*
1209 * Avoid reporting two disassociation events that could
1210 * confuse the core code.
1211 */
1212 wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
1213 "event when using userspace SME");
1214 return;
1215 }
1216
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001217 if (drv->ignore_next_local_disconnect) {
1218 drv->ignore_next_local_disconnect = 0;
1219 if (locally_generated) {
1220 wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
1221 "event triggered during reassociation");
1222 return;
1223 }
1224 wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
1225 "disconnect but got another disconnect "
1226 "event first");
1227 }
1228
1229 wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001230 drv->associated = 0;
1231 os_memset(&data, 0, sizeof(data));
1232 if (reason)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001233 data.deauth_info.reason_code = nla_get_u16(reason);
1234 data.deauth_info.locally_generated = by_ap == NULL;
1235 wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
1236}
1237
1238
1239static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
1240 struct nlattr *freq, struct nlattr *type)
1241{
1242 union wpa_event_data data;
1243 int ht_enabled = 1;
1244 int chan_offset = 0;
1245
1246 wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
1247
1248 if (!freq || !type)
1249 return;
1250
1251 switch (nla_get_u32(type)) {
1252 case NL80211_CHAN_NO_HT:
1253 ht_enabled = 0;
1254 break;
1255 case NL80211_CHAN_HT20:
1256 break;
1257 case NL80211_CHAN_HT40PLUS:
1258 chan_offset = 1;
1259 break;
1260 case NL80211_CHAN_HT40MINUS:
1261 chan_offset = -1;
1262 break;
1263 }
1264
1265 data.ch_switch.freq = nla_get_u32(freq);
1266 data.ch_switch.ht_enabled = ht_enabled;
1267 data.ch_switch.ch_offset = chan_offset;
1268
1269 wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001270}
1271
1272
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001273static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
1274 enum nl80211_commands cmd, struct nlattr *addr)
1275{
1276 union wpa_event_data event;
1277 enum wpa_event_type ev;
1278
1279 if (nla_len(addr) != ETH_ALEN)
1280 return;
1281
1282 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
1283 cmd, MAC2STR((u8 *) nla_data(addr)));
1284
1285 if (cmd == NL80211_CMD_AUTHENTICATE)
1286 ev = EVENT_AUTH_TIMED_OUT;
1287 else if (cmd == NL80211_CMD_ASSOCIATE)
1288 ev = EVENT_ASSOC_TIMED_OUT;
1289 else
1290 return;
1291
1292 os_memset(&event, 0, sizeof(event));
1293 os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
1294 wpa_supplicant_event(drv->ctx, ev, &event);
1295}
1296
1297
1298static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001299 struct nlattr *freq, struct nlattr *sig,
1300 const u8 *frame, size_t len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001301{
1302 const struct ieee80211_mgmt *mgmt;
1303 union wpa_event_data event;
1304 u16 fc, stype;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001305 int ssi_signal = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001306
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001307 wpa_printf(MSG_DEBUG, "nl80211: Frame event");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001308 mgmt = (const struct ieee80211_mgmt *) frame;
1309 if (len < 24) {
1310 wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
1311 return;
1312 }
1313
1314 fc = le_to_host16(mgmt->frame_control);
1315 stype = WLAN_FC_GET_STYPE(fc);
1316
Dmitry Shmidt04949592012-07-19 12:16:46 -07001317 if (sig)
1318 ssi_signal = (s32) nla_get_u32(sig);
1319
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001320 os_memset(&event, 0, sizeof(event));
1321 if (freq) {
1322 event.rx_action.freq = nla_get_u32(freq);
1323 drv->last_mgmt_freq = event.rx_action.freq;
1324 }
1325 if (stype == WLAN_FC_STYPE_ACTION) {
1326 event.rx_action.da = mgmt->da;
1327 event.rx_action.sa = mgmt->sa;
1328 event.rx_action.bssid = mgmt->bssid;
1329 event.rx_action.category = mgmt->u.action.category;
1330 event.rx_action.data = &mgmt->u.action.category + 1;
1331 event.rx_action.len = frame + len - event.rx_action.data;
1332 wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
1333 } else {
1334 event.rx_mgmt.frame = frame;
1335 event.rx_mgmt.frame_len = len;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001336 event.rx_mgmt.ssi_signal = ssi_signal;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001337 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
1338 }
1339}
1340
1341
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001342static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
1343 struct nlattr *cookie, const u8 *frame,
1344 size_t len, struct nlattr *ack)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001345{
1346 union wpa_event_data event;
1347 const struct ieee80211_hdr *hdr;
1348 u16 fc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001349
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001350 wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001351 if (!is_ap_interface(drv->nlmode)) {
1352 u64 cookie_val;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001353
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001354 if (!cookie)
1355 return;
1356
1357 cookie_val = nla_get_u64(cookie);
1358 wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
1359 " cookie=0%llx%s (ack=%d)",
1360 (long long unsigned int) cookie_val,
1361 cookie_val == drv->send_action_cookie ?
1362 " (match)" : " (unknown)", ack != NULL);
1363 if (cookie_val != drv->send_action_cookie)
1364 return;
1365 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001366
1367 hdr = (const struct ieee80211_hdr *) frame;
1368 fc = le_to_host16(hdr->frame_control);
1369
1370 os_memset(&event, 0, sizeof(event));
1371 event.tx_status.type = WLAN_FC_GET_TYPE(fc);
1372 event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
1373 event.tx_status.dst = hdr->addr1;
1374 event.tx_status.data = frame;
1375 event.tx_status.data_len = len;
1376 event.tx_status.ack = ack != NULL;
1377 wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
1378}
1379
1380
1381static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
1382 enum wpa_event_type type,
1383 const u8 *frame, size_t len)
1384{
1385 const struct ieee80211_mgmt *mgmt;
1386 union wpa_event_data event;
1387 const u8 *bssid = NULL;
1388 u16 reason_code = 0;
1389
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001390 if (type == EVENT_DEAUTH)
1391 wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
1392 else
1393 wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
1394
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001395 mgmt = (const struct ieee80211_mgmt *) frame;
1396 if (len >= 24) {
1397 bssid = mgmt->bssid;
1398
1399 if (drv->associated != 0 &&
1400 os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
1401 os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
1402 /*
1403 * We have presumably received this deauth as a
1404 * response to a clear_state_mismatch() outgoing
1405 * deauth. Don't let it take us offline!
1406 */
1407 wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
1408 "from Unknown BSSID " MACSTR " -- ignoring",
1409 MAC2STR(bssid));
1410 return;
1411 }
1412 }
1413
1414 drv->associated = 0;
1415 os_memset(&event, 0, sizeof(event));
1416
1417 /* Note: Same offset for Reason Code in both frame subtypes */
1418 if (len >= 24 + sizeof(mgmt->u.deauth))
1419 reason_code = le_to_host16(mgmt->u.deauth.reason_code);
1420
1421 if (type == EVENT_DISASSOC) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001422 event.disassoc_info.locally_generated =
1423 !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001424 event.disassoc_info.addr = bssid;
1425 event.disassoc_info.reason_code = reason_code;
1426 if (frame + len > mgmt->u.disassoc.variable) {
1427 event.disassoc_info.ie = mgmt->u.disassoc.variable;
1428 event.disassoc_info.ie_len = frame + len -
1429 mgmt->u.disassoc.variable;
1430 }
1431 } else {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001432 event.deauth_info.locally_generated =
1433 !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001434 event.deauth_info.addr = bssid;
1435 event.deauth_info.reason_code = reason_code;
1436 if (frame + len > mgmt->u.deauth.variable) {
1437 event.deauth_info.ie = mgmt->u.deauth.variable;
1438 event.deauth_info.ie_len = frame + len -
1439 mgmt->u.deauth.variable;
1440 }
1441 }
1442
1443 wpa_supplicant_event(drv->ctx, type, &event);
1444}
1445
1446
1447static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
1448 enum wpa_event_type type,
1449 const u8 *frame, size_t len)
1450{
1451 const struct ieee80211_mgmt *mgmt;
1452 union wpa_event_data event;
1453 u16 reason_code = 0;
1454
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001455 if (type == EVENT_UNPROT_DEAUTH)
1456 wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
1457 else
1458 wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
1459
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001460 if (len < 24)
1461 return;
1462
1463 mgmt = (const struct ieee80211_mgmt *) frame;
1464
1465 os_memset(&event, 0, sizeof(event));
1466 /* Note: Same offset for Reason Code in both frame subtypes */
1467 if (len >= 24 + sizeof(mgmt->u.deauth))
1468 reason_code = le_to_host16(mgmt->u.deauth.reason_code);
1469
1470 if (type == EVENT_UNPROT_DISASSOC) {
1471 event.unprot_disassoc.sa = mgmt->sa;
1472 event.unprot_disassoc.da = mgmt->da;
1473 event.unprot_disassoc.reason_code = reason_code;
1474 } else {
1475 event.unprot_deauth.sa = mgmt->sa;
1476 event.unprot_deauth.da = mgmt->da;
1477 event.unprot_deauth.reason_code = reason_code;
1478 }
1479
1480 wpa_supplicant_event(drv->ctx, type, &event);
1481}
1482
1483
1484static void mlme_event(struct wpa_driver_nl80211_data *drv,
1485 enum nl80211_commands cmd, struct nlattr *frame,
1486 struct nlattr *addr, struct nlattr *timed_out,
1487 struct nlattr *freq, struct nlattr *ack,
Dmitry Shmidt04949592012-07-19 12:16:46 -07001488 struct nlattr *cookie, struct nlattr *sig)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001489{
1490 if (timed_out && addr) {
1491 mlme_timeout_event(drv, cmd, addr);
1492 return;
1493 }
1494
1495 if (frame == NULL) {
1496 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
1497 "data", cmd);
1498 return;
1499 }
1500
1501 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
1502 wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
1503 nla_data(frame), nla_len(frame));
1504
1505 switch (cmd) {
1506 case NL80211_CMD_AUTHENTICATE:
1507 mlme_event_auth(drv, nla_data(frame), nla_len(frame));
1508 break;
1509 case NL80211_CMD_ASSOCIATE:
1510 mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
1511 break;
1512 case NL80211_CMD_DEAUTHENTICATE:
1513 mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
1514 nla_data(frame), nla_len(frame));
1515 break;
1516 case NL80211_CMD_DISASSOCIATE:
1517 mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
1518 nla_data(frame), nla_len(frame));
1519 break;
1520 case NL80211_CMD_FRAME:
Dmitry Shmidt04949592012-07-19 12:16:46 -07001521 mlme_event_mgmt(drv, freq, sig, nla_data(frame),
1522 nla_len(frame));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001523 break;
1524 case NL80211_CMD_FRAME_TX_STATUS:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001525 mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
1526 nla_len(frame), ack);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001527 break;
1528 case NL80211_CMD_UNPROT_DEAUTHENTICATE:
1529 mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
1530 nla_data(frame), nla_len(frame));
1531 break;
1532 case NL80211_CMD_UNPROT_DISASSOCIATE:
1533 mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
1534 nla_data(frame), nla_len(frame));
1535 break;
1536 default:
1537 break;
1538 }
1539}
1540
1541
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001542static void mlme_event_michael_mic_failure(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001543 struct nlattr *tb[])
1544{
1545 union wpa_event_data data;
1546
1547 wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
1548 os_memset(&data, 0, sizeof(data));
1549 if (tb[NL80211_ATTR_MAC]) {
1550 wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
1551 nla_data(tb[NL80211_ATTR_MAC]),
1552 nla_len(tb[NL80211_ATTR_MAC]));
1553 data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
1554 }
1555 if (tb[NL80211_ATTR_KEY_SEQ]) {
1556 wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
1557 nla_data(tb[NL80211_ATTR_KEY_SEQ]),
1558 nla_len(tb[NL80211_ATTR_KEY_SEQ]));
1559 }
1560 if (tb[NL80211_ATTR_KEY_TYPE]) {
1561 enum nl80211_key_type key_type =
1562 nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
1563 wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
1564 if (key_type == NL80211_KEYTYPE_PAIRWISE)
1565 data.michael_mic_failure.unicast = 1;
1566 } else
1567 data.michael_mic_failure.unicast = 1;
1568
1569 if (tb[NL80211_ATTR_KEY_IDX]) {
1570 u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
1571 wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
1572 }
1573
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001574 wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001575}
1576
1577
1578static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
1579 struct nlattr *tb[])
1580{
1581 if (tb[NL80211_ATTR_MAC] == NULL) {
1582 wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
1583 "event");
1584 return;
1585 }
1586 os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
1587 drv->associated = 1;
1588 wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
1589 MAC2STR(drv->bssid));
1590
1591 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1592}
1593
1594
1595static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
1596 int cancel_event, struct nlattr *tb[])
1597{
1598 unsigned int freq, chan_type, duration;
1599 union wpa_event_data data;
1600 u64 cookie;
1601
1602 if (tb[NL80211_ATTR_WIPHY_FREQ])
1603 freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1604 else
1605 freq = 0;
1606
1607 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
1608 chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1609 else
1610 chan_type = 0;
1611
1612 if (tb[NL80211_ATTR_DURATION])
1613 duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
1614 else
1615 duration = 0;
1616
1617 if (tb[NL80211_ATTR_COOKIE])
1618 cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
1619 else
1620 cookie = 0;
1621
1622 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
1623 "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
1624 cancel_event, freq, chan_type, duration,
1625 (long long unsigned int) cookie,
1626 cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
1627
1628 if (cookie != drv->remain_on_chan_cookie)
1629 return; /* not for us */
1630
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001631 if (cancel_event)
1632 drv->pending_remain_on_chan = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001633
1634 os_memset(&data, 0, sizeof(data));
1635 data.remain_on_channel.freq = freq;
1636 data.remain_on_channel.duration = duration;
1637 wpa_supplicant_event(drv->ctx, cancel_event ?
1638 EVENT_CANCEL_REMAIN_ON_CHANNEL :
1639 EVENT_REMAIN_ON_CHANNEL, &data);
1640}
1641
1642
1643static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
1644 struct nlattr *tb[])
1645{
1646 union wpa_event_data event;
1647 struct nlattr *nl;
1648 int rem;
1649 struct scan_info *info;
1650#define MAX_REPORT_FREQS 50
1651 int freqs[MAX_REPORT_FREQS];
1652 int num_freqs = 0;
1653
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001654 if (drv->scan_for_auth) {
1655 drv->scan_for_auth = 0;
1656 wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
1657 "cfg80211 BSS entry");
1658 wpa_driver_nl80211_authenticate_retry(drv);
1659 return;
1660 }
1661
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001662 os_memset(&event, 0, sizeof(event));
1663 info = &event.scan_info;
1664 info->aborted = aborted;
1665
1666 if (tb[NL80211_ATTR_SCAN_SSIDS]) {
1667 nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
1668 struct wpa_driver_scan_ssid *s =
1669 &info->ssids[info->num_ssids];
1670 s->ssid = nla_data(nl);
1671 s->ssid_len = nla_len(nl);
1672 info->num_ssids++;
1673 if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
1674 break;
1675 }
1676 }
1677 if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
1678 nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
1679 {
1680 freqs[num_freqs] = nla_get_u32(nl);
1681 num_freqs++;
1682 if (num_freqs == MAX_REPORT_FREQS - 1)
1683 break;
1684 }
1685 info->freqs = freqs;
1686 info->num_freqs = num_freqs;
1687 }
1688 wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
1689}
1690
1691
1692static int get_link_signal(struct nl_msg *msg, void *arg)
1693{
1694 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1695 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1696 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1697 static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
1698 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
1699 };
1700 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1701 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1702 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1703 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1704 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1705 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1706 };
1707 struct wpa_signal_info *sig_change = arg;
1708
1709 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1710 genlmsg_attrlen(gnlh, 0), NULL);
1711 if (!tb[NL80211_ATTR_STA_INFO] ||
1712 nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1713 tb[NL80211_ATTR_STA_INFO], policy))
1714 return NL_SKIP;
1715 if (!sinfo[NL80211_STA_INFO_SIGNAL])
1716 return NL_SKIP;
1717
1718 sig_change->current_signal =
1719 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1720
1721 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
1722 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1723 sinfo[NL80211_STA_INFO_TX_BITRATE],
1724 rate_policy)) {
1725 sig_change->current_txrate = 0;
1726 } else {
1727 if (rinfo[NL80211_RATE_INFO_BITRATE]) {
1728 sig_change->current_txrate =
1729 nla_get_u16(rinfo[
1730 NL80211_RATE_INFO_BITRATE]) * 100;
1731 }
1732 }
1733 }
1734
1735 return NL_SKIP;
1736}
1737
1738
1739static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
1740 struct wpa_signal_info *sig)
1741{
1742 struct nl_msg *msg;
1743
1744 sig->current_signal = -9999;
1745 sig->current_txrate = 0;
1746
1747 msg = nlmsg_alloc();
1748 if (!msg)
1749 return -ENOMEM;
1750
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001751 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001752
1753 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1754 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
1755
1756 return send_and_recv_msgs(drv, msg, get_link_signal, sig);
1757 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001758 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001759 return -ENOBUFS;
1760}
1761
1762
1763static int get_link_noise(struct nl_msg *msg, void *arg)
1764{
1765 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1766 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1767 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1768 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1769 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1770 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1771 };
1772 struct wpa_signal_info *sig_change = arg;
1773
1774 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1775 genlmsg_attrlen(gnlh, 0), NULL);
1776
1777 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1778 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1779 return NL_SKIP;
1780 }
1781
1782 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1783 tb[NL80211_ATTR_SURVEY_INFO],
1784 survey_policy)) {
1785 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1786 "attributes!");
1787 return NL_SKIP;
1788 }
1789
1790 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1791 return NL_SKIP;
1792
1793 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1794 sig_change->frequency)
1795 return NL_SKIP;
1796
1797 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1798 return NL_SKIP;
1799
1800 sig_change->current_noise =
1801 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1802
1803 return NL_SKIP;
1804}
1805
1806
1807static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1808 struct wpa_signal_info *sig_change)
1809{
1810 struct nl_msg *msg;
1811
1812 sig_change->current_noise = 9999;
1813 sig_change->frequency = drv->assoc_freq;
1814
1815 msg = nlmsg_alloc();
1816 if (!msg)
1817 return -ENOMEM;
1818
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001819 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001820
1821 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1822
1823 return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
1824 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001825 nlmsg_free(msg);
1826 return -ENOBUFS;
1827}
1828
1829
1830static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
1831{
1832 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1833 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1834 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1835 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1836 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1837 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1838 };
1839 struct wpa_scan_results *scan_results = arg;
1840 struct wpa_scan_res *scan_res;
1841 size_t i;
1842
1843 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1844 genlmsg_attrlen(gnlh, 0), NULL);
1845
1846 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1847 wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
1848 return NL_SKIP;
1849 }
1850
1851 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1852 tb[NL80211_ATTR_SURVEY_INFO],
1853 survey_policy)) {
1854 wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
1855 "attributes");
1856 return NL_SKIP;
1857 }
1858
1859 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1860 return NL_SKIP;
1861
1862 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1863 return NL_SKIP;
1864
1865 for (i = 0; i < scan_results->num; ++i) {
1866 scan_res = scan_results->res[i];
1867 if (!scan_res)
1868 continue;
1869 if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1870 scan_res->freq)
1871 continue;
1872 if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
1873 continue;
1874 scan_res->noise = (s8)
1875 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1876 scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
1877 }
1878
1879 return NL_SKIP;
1880}
1881
1882
1883static int nl80211_get_noise_for_scan_results(
1884 struct wpa_driver_nl80211_data *drv,
1885 struct wpa_scan_results *scan_res)
1886{
1887 struct nl_msg *msg;
1888
1889 msg = nlmsg_alloc();
1890 if (!msg)
1891 return -ENOMEM;
1892
1893 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
1894
1895 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1896
1897 return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
1898 scan_res);
1899 nla_put_failure:
1900 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001901 return -ENOBUFS;
1902}
1903
1904
1905static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
1906 struct nlattr *tb[])
1907{
1908 static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
1909 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
1910 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
1911 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
1912 [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
1913 };
1914 struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
1915 enum nl80211_cqm_rssi_threshold_event event;
1916 union wpa_event_data ed;
1917 struct wpa_signal_info sig;
1918 int res;
1919
1920 if (tb[NL80211_ATTR_CQM] == NULL ||
1921 nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
1922 cqm_policy)) {
1923 wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
1924 return;
1925 }
1926
1927 os_memset(&ed, 0, sizeof(ed));
1928
1929 if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
1930 if (!tb[NL80211_ATTR_MAC])
1931 return;
1932 os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
1933 ETH_ALEN);
1934 wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
1935 return;
1936 }
1937
1938 if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
1939 return;
1940 event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
1941
1942 if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
1943 wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
1944 "event: RSSI high");
1945 ed.signal_change.above_threshold = 1;
1946 } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
1947 wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
1948 "event: RSSI low");
1949 ed.signal_change.above_threshold = 0;
1950 } else
1951 return;
1952
1953 res = nl80211_get_link_signal(drv, &sig);
1954 if (res == 0) {
1955 ed.signal_change.current_signal = sig.current_signal;
1956 ed.signal_change.current_txrate = sig.current_txrate;
1957 wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
1958 sig.current_signal, sig.current_txrate);
1959 }
1960
1961 res = nl80211_get_link_noise(drv, &sig);
1962 if (res == 0) {
1963 ed.signal_change.current_noise = sig.current_noise;
1964 wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
1965 sig.current_noise);
1966 }
1967
1968 wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
1969}
1970
1971
1972static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
1973 struct nlattr **tb)
1974{
1975 u8 *addr;
1976 union wpa_event_data data;
1977
1978 if (tb[NL80211_ATTR_MAC] == NULL)
1979 return;
1980 addr = nla_data(tb[NL80211_ATTR_MAC]);
1981 wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001982
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001983 if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001984 u8 *ies = NULL;
1985 size_t ies_len = 0;
1986 if (tb[NL80211_ATTR_IE]) {
1987 ies = nla_data(tb[NL80211_ATTR_IE]);
1988 ies_len = nla_len(tb[NL80211_ATTR_IE]);
1989 }
1990 wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
1991 drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
1992 return;
1993 }
1994
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001995 if (drv->nlmode != NL80211_IFTYPE_ADHOC)
1996 return;
1997
1998 os_memset(&data, 0, sizeof(data));
1999 os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
2000 wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
2001}
2002
2003
2004static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
2005 struct nlattr **tb)
2006{
2007 u8 *addr;
2008 union wpa_event_data data;
2009
2010 if (tb[NL80211_ATTR_MAC] == NULL)
2011 return;
2012 addr = nla_data(tb[NL80211_ATTR_MAC]);
2013 wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
2014 MAC2STR(addr));
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002015
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002016 if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002017 drv_event_disassoc(drv->ctx, addr);
2018 return;
2019 }
2020
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002021 if (drv->nlmode != NL80211_IFTYPE_ADHOC)
2022 return;
2023
2024 os_memset(&data, 0, sizeof(data));
2025 os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
2026 wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
2027}
2028
2029
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002030static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
2031 struct nlattr **tb)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002032{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002033 struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
2034 static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
2035 [NL80211_REKEY_DATA_KEK] = {
2036 .minlen = NL80211_KEK_LEN,
2037 .maxlen = NL80211_KEK_LEN,
2038 },
2039 [NL80211_REKEY_DATA_KCK] = {
2040 .minlen = NL80211_KCK_LEN,
2041 .maxlen = NL80211_KCK_LEN,
2042 },
2043 [NL80211_REKEY_DATA_REPLAY_CTR] = {
2044 .minlen = NL80211_REPLAY_CTR_LEN,
2045 .maxlen = NL80211_REPLAY_CTR_LEN,
2046 },
2047 };
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002048 union wpa_event_data data;
2049
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002050 if (!tb[NL80211_ATTR_MAC])
2051 return;
2052 if (!tb[NL80211_ATTR_REKEY_DATA])
2053 return;
2054 if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
2055 tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
2056 return;
2057 if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
2058 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002059
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002060 os_memset(&data, 0, sizeof(data));
2061 data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
2062 wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
2063 MAC2STR(data.driver_gtk_rekey.bssid));
2064 data.driver_gtk_rekey.replay_ctr =
2065 nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
2066 wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
2067 data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
2068 wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
2069}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002070
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002071
2072static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
2073 struct nlattr **tb)
2074{
2075 struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
2076 static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
2077 [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
2078 [NL80211_PMKSA_CANDIDATE_BSSID] = {
2079 .minlen = ETH_ALEN,
2080 .maxlen = ETH_ALEN,
2081 },
2082 [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
2083 };
2084 union wpa_event_data data;
2085
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002086 wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
2087
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002088 if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
2089 return;
2090 if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
2091 tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
2092 return;
2093 if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
2094 !cand[NL80211_PMKSA_CANDIDATE_BSSID])
2095 return;
2096
2097 os_memset(&data, 0, sizeof(data));
2098 os_memcpy(data.pmkid_candidate.bssid,
2099 nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
2100 data.pmkid_candidate.index =
2101 nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
2102 data.pmkid_candidate.preauth =
2103 cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
2104 wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
2105}
2106
2107
2108static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
2109 struct nlattr **tb)
2110{
2111 union wpa_event_data data;
2112
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002113 wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
2114
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002115 if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
2116 return;
2117
2118 os_memset(&data, 0, sizeof(data));
2119 os_memcpy(data.client_poll.addr,
2120 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
2121
2122 wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
2123}
2124
2125
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002126static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
2127 struct nlattr **tb)
2128{
2129 union wpa_event_data data;
2130
2131 wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
2132
2133 if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
2134 return;
2135
2136 os_memset(&data, 0, sizeof(data));
2137 os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
2138 switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
2139 case NL80211_TDLS_SETUP:
2140 wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
2141 MACSTR, MAC2STR(data.tdls.peer));
2142 data.tdls.oper = TDLS_REQUEST_SETUP;
2143 break;
2144 case NL80211_TDLS_TEARDOWN:
2145 wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
2146 MACSTR, MAC2STR(data.tdls.peer));
2147 data.tdls.oper = TDLS_REQUEST_TEARDOWN;
2148 break;
2149 default:
2150 wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
2151 "event");
2152 return;
2153 }
2154 if (tb[NL80211_ATTR_REASON_CODE]) {
2155 data.tdls.reason_code =
2156 nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
2157 }
2158
2159 wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
2160}
2161
2162
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002163static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
2164 int wds)
2165{
2166 struct wpa_driver_nl80211_data *drv = bss->drv;
2167 union wpa_event_data event;
2168
2169 if (!tb[NL80211_ATTR_MAC])
2170 return;
2171
2172 os_memset(&event, 0, sizeof(event));
2173 event.rx_from_unknown.bssid = bss->addr;
2174 event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
2175 event.rx_from_unknown.wds = wds;
2176
2177 wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
2178}
2179
2180
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002181static void do_process_drv_event(struct i802_bss *bss, int cmd,
2182 struct nlattr **tb)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002183{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002184 struct wpa_driver_nl80211_data *drv = bss->drv;
2185
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002186 if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
2187 (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
2188 cmd == NL80211_CMD_SCAN_ABORTED)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002189 wpa_driver_nl80211_set_mode(&drv->first_bss,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002190 drv->ap_scan_as_station);
2191 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002192 }
2193
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002194 switch (cmd) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002195 case NL80211_CMD_TRIGGER_SCAN:
2196 wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
2197 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002198 case NL80211_CMD_START_SCHED_SCAN:
2199 wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
2200 break;
2201 case NL80211_CMD_SCHED_SCAN_STOPPED:
2202 wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
2203 wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
2204 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002205 case NL80211_CMD_NEW_SCAN_RESULTS:
2206 wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
2207 drv->scan_complete_events = 1;
2208 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
2209 drv->ctx);
2210 send_scan_event(drv, 0, tb);
2211 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002212 case NL80211_CMD_SCHED_SCAN_RESULTS:
2213 wpa_printf(MSG_DEBUG,
2214 "nl80211: New sched scan results available");
2215 send_scan_event(drv, 0, tb);
2216 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002217 case NL80211_CMD_SCAN_ABORTED:
2218 wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
2219 /*
2220 * Need to indicate that scan results are available in order
2221 * not to make wpa_supplicant stop its scanning.
2222 */
2223 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
2224 drv->ctx);
2225 send_scan_event(drv, 1, tb);
2226 break;
2227 case NL80211_CMD_AUTHENTICATE:
2228 case NL80211_CMD_ASSOCIATE:
2229 case NL80211_CMD_DEAUTHENTICATE:
2230 case NL80211_CMD_DISASSOCIATE:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002231 case NL80211_CMD_FRAME_TX_STATUS:
2232 case NL80211_CMD_UNPROT_DEAUTHENTICATE:
2233 case NL80211_CMD_UNPROT_DISASSOCIATE:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002234 mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002235 tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
2236 tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
Dmitry Shmidt04949592012-07-19 12:16:46 -07002237 tb[NL80211_ATTR_COOKIE],
2238 tb[NL80211_ATTR_RX_SIGNAL_DBM]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002239 break;
2240 case NL80211_CMD_CONNECT:
2241 case NL80211_CMD_ROAM:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002242 mlme_event_connect(drv, cmd,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002243 tb[NL80211_ATTR_STATUS_CODE],
2244 tb[NL80211_ATTR_MAC],
2245 tb[NL80211_ATTR_REQ_IE],
2246 tb[NL80211_ATTR_RESP_IE]);
2247 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002248 case NL80211_CMD_CH_SWITCH_NOTIFY:
2249 mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
2250 tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
2251 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002252 case NL80211_CMD_DISCONNECT:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002253 mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002254 tb[NL80211_ATTR_MAC],
2255 tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002256 break;
2257 case NL80211_CMD_MICHAEL_MIC_FAILURE:
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002258 mlme_event_michael_mic_failure(bss, tb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002259 break;
2260 case NL80211_CMD_JOIN_IBSS:
2261 mlme_event_join_ibss(drv, tb);
2262 break;
2263 case NL80211_CMD_REMAIN_ON_CHANNEL:
2264 mlme_event_remain_on_channel(drv, 0, tb);
2265 break;
2266 case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
2267 mlme_event_remain_on_channel(drv, 1, tb);
2268 break;
2269 case NL80211_CMD_NOTIFY_CQM:
2270 nl80211_cqm_event(drv, tb);
2271 break;
2272 case NL80211_CMD_REG_CHANGE:
2273 wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
2274 wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
2275 NULL);
2276 break;
2277 case NL80211_CMD_REG_BEACON_HINT:
2278 wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
2279 wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
2280 NULL);
2281 break;
2282 case NL80211_CMD_NEW_STATION:
2283 nl80211_new_station_event(drv, tb);
2284 break;
2285 case NL80211_CMD_DEL_STATION:
2286 nl80211_del_station_event(drv, tb);
2287 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002288 case NL80211_CMD_SET_REKEY_OFFLOAD:
2289 nl80211_rekey_offload_event(drv, tb);
2290 break;
2291 case NL80211_CMD_PMKSA_CANDIDATE:
2292 nl80211_pmksa_candidate_event(drv, tb);
2293 break;
2294 case NL80211_CMD_PROBE_CLIENT:
2295 nl80211_client_probe_event(drv, tb);
2296 break;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002297 case NL80211_CMD_TDLS_OPER:
2298 nl80211_tdls_oper_event(drv, tb);
2299 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002300 default:
2301 wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
2302 "(cmd=%d)", cmd);
2303 break;
2304 }
2305}
2306
2307
2308static int process_drv_event(struct nl_msg *msg, void *arg)
2309{
2310 struct wpa_driver_nl80211_data *drv = arg;
2311 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2312 struct nlattr *tb[NL80211_ATTR_MAX + 1];
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002313 struct i802_bss *bss;
2314 int ifidx = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002315
2316 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2317 genlmsg_attrlen(gnlh, 0), NULL);
2318
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002319 if (tb[NL80211_ATTR_IFINDEX])
2320 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2321
2322 for (bss = &drv->first_bss; bss; bss = bss->next) {
2323 if (ifidx == -1 || ifidx == bss->ifindex) {
2324 do_process_drv_event(bss, gnlh->cmd, tb);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002325 return NL_SKIP;
2326 }
2327 }
2328
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002329 wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
2330 "interface (ifindex %d)", gnlh->cmd, ifidx);
2331
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002332 return NL_SKIP;
2333}
2334
2335
2336static int process_global_event(struct nl_msg *msg, void *arg)
2337{
2338 struct nl80211_global *global = arg;
2339 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2340 struct nlattr *tb[NL80211_ATTR_MAX + 1];
Dmitry Shmidt04949592012-07-19 12:16:46 -07002341 struct wpa_driver_nl80211_data *drv, *tmp;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002342 int ifidx = -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002343 struct i802_bss *bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002344
2345 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2346 genlmsg_attrlen(gnlh, 0), NULL);
2347
2348 if (tb[NL80211_ATTR_IFINDEX])
2349 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2350
Dmitry Shmidt04949592012-07-19 12:16:46 -07002351 dl_list_for_each_safe(drv, tmp, &global->interfaces,
2352 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002353 for (bss = &drv->first_bss; bss; bss = bss->next) {
2354 if (ifidx == -1 || ifidx == bss->ifindex) {
2355 do_process_drv_event(bss, gnlh->cmd, tb);
2356 return NL_SKIP;
2357 }
2358 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002359 }
2360
2361 return NL_SKIP;
2362}
2363
2364
2365static int process_bss_event(struct nl_msg *msg, void *arg)
2366{
2367 struct i802_bss *bss = arg;
2368 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2369 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2370
2371 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2372 genlmsg_attrlen(gnlh, 0), NULL);
2373
2374 switch (gnlh->cmd) {
2375 case NL80211_CMD_FRAME:
2376 case NL80211_CMD_FRAME_TX_STATUS:
2377 mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
2378 tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
2379 tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
Dmitry Shmidt04949592012-07-19 12:16:46 -07002380 tb[NL80211_ATTR_COOKIE],
2381 tb[NL80211_ATTR_RX_SIGNAL_DBM]);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002382 break;
2383 case NL80211_CMD_UNEXPECTED_FRAME:
2384 nl80211_spurious_frame(bss, tb, 0);
2385 break;
2386 case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
2387 nl80211_spurious_frame(bss, tb, 1);
2388 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002389 default:
2390 wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
2391 "(cmd=%d)", gnlh->cmd);
2392 break;
2393 }
2394
2395 return NL_SKIP;
2396}
2397
2398
2399static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
2400 void *handle)
2401{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002402 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002403
2404 wpa_printf(MSG_DEBUG, "nl80211: Event message available");
2405
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002406 nl_recvmsgs(handle, cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002407}
2408
2409
2410/**
2411 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
2412 * @priv: driver_nl80211 private data
2413 * @alpha2_arg: country to which to switch to
2414 * Returns: 0 on success, -1 on failure
2415 *
2416 * This asks nl80211 to set the regulatory domain for given
2417 * country ISO / IEC alpha2.
2418 */
2419static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
2420{
2421 struct i802_bss *bss = priv;
2422 struct wpa_driver_nl80211_data *drv = bss->drv;
2423 char alpha2[3];
2424 struct nl_msg *msg;
2425
2426 msg = nlmsg_alloc();
2427 if (!msg)
2428 return -ENOMEM;
2429
2430 alpha2[0] = alpha2_arg[0];
2431 alpha2[1] = alpha2_arg[1];
2432 alpha2[2] = '\0';
2433
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002434 nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002435
2436 NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
2437 if (send_and_recv_msgs(drv, msg, NULL, NULL))
2438 return -EINVAL;
2439 return 0;
2440nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002441 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002442 return -EINVAL;
2443}
2444
2445
2446struct wiphy_info_data {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002447 struct wpa_driver_capa *capa;
2448
2449 unsigned int error:1;
2450 unsigned int device_ap_sme:1;
2451 unsigned int poll_command_supported:1;
2452 unsigned int data_tx_status:1;
2453 unsigned int monitor_supported:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002454};
2455
2456
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002457static unsigned int probe_resp_offload_support(int supp_protocols)
2458{
2459 unsigned int prot = 0;
2460
2461 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
2462 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
2463 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
2464 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
2465 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
2466 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
2467 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
2468 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
2469
2470 return prot;
2471}
2472
2473
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002474static int wiphy_info_handler(struct nl_msg *msg, void *arg)
2475{
2476 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2477 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2478 struct wiphy_info_data *info = arg;
2479 int p2p_go_supported = 0, p2p_client_supported = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002480 int p2p_concurrent = 0, p2p_multichan_concurrent = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002481 int auth_supported = 0, connect_supported = 0;
2482 struct wpa_driver_capa *capa = info->capa;
2483 static struct nla_policy
2484 iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
2485 [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
2486 [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
2487 [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
2488 [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
2489 },
2490 iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
2491 [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
2492 [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
2493 };
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002494
2495 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2496 genlmsg_attrlen(gnlh, 0), NULL);
2497
2498 if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002499 capa->max_scan_ssids =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002500 nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
2501
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002502 if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
2503 capa->max_sched_scan_ssids =
2504 nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
2505
2506 if (tb[NL80211_ATTR_MAX_MATCH_SETS])
2507 capa->max_match_sets =
2508 nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
2509
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002510 if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
2511 struct nlattr *nl_mode;
2512 int i;
2513 nla_for_each_nested(nl_mode,
2514 tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
2515 switch (nla_type(nl_mode)) {
2516 case NL80211_IFTYPE_AP:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002517 capa->flags |= WPA_DRIVER_FLAGS_AP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002518 break;
2519 case NL80211_IFTYPE_P2P_GO:
2520 p2p_go_supported = 1;
2521 break;
2522 case NL80211_IFTYPE_P2P_CLIENT:
2523 p2p_client_supported = 1;
2524 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002525 case NL80211_IFTYPE_MONITOR:
2526 info->monitor_supported = 1;
2527 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002528 }
2529 }
2530 }
2531
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002532 if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
2533 struct nlattr *nl_combi;
2534 int rem_combi;
2535
2536 nla_for_each_nested(nl_combi,
2537 tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
2538 rem_combi) {
2539 struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
2540 struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
2541 struct nlattr *nl_limit, *nl_mode;
2542 int err, rem_limit, rem_mode;
2543 int combination_has_p2p = 0, combination_has_mgd = 0;
2544
2545 err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
2546 nl_combi,
2547 iface_combination_policy);
2548 if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
2549 !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
2550 !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
2551 goto broken_combination;
2552
2553 nla_for_each_nested(nl_limit,
2554 tb_comb[NL80211_IFACE_COMB_LIMITS],
2555 rem_limit) {
2556 err = nla_parse_nested(tb_limit,
2557 MAX_NL80211_IFACE_LIMIT,
2558 nl_limit,
2559 iface_limit_policy);
2560 if (err ||
2561 !tb_limit[NL80211_IFACE_LIMIT_TYPES])
2562 goto broken_combination;
2563
2564 nla_for_each_nested(
2565 nl_mode,
2566 tb_limit[NL80211_IFACE_LIMIT_TYPES],
2567 rem_mode) {
2568 int ift = nla_type(nl_mode);
2569 if (ift == NL80211_IFTYPE_P2P_GO ||
2570 ift == NL80211_IFTYPE_P2P_CLIENT)
2571 combination_has_p2p = 1;
2572 if (ift == NL80211_IFTYPE_STATION)
2573 combination_has_mgd = 1;
2574 }
2575 if (combination_has_p2p && combination_has_mgd)
2576 break;
2577 }
2578
2579 if (combination_has_p2p && combination_has_mgd) {
2580 p2p_concurrent = 1;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002581 if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
2582 p2p_multichan_concurrent = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002583 break;
2584 }
2585
2586broken_combination:
2587 ;
2588 }
2589 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002590
2591 if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
2592 struct nlattr *nl_cmd;
2593 int i;
2594
2595 nla_for_each_nested(nl_cmd,
2596 tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002597 switch (nla_get_u32(nl_cmd)) {
2598 case NL80211_CMD_AUTHENTICATE:
2599 auth_supported = 1;
2600 break;
2601 case NL80211_CMD_CONNECT:
2602 connect_supported = 1;
2603 break;
2604 case NL80211_CMD_START_SCHED_SCAN:
2605 capa->sched_scan_supported = 1;
2606 break;
2607 case NL80211_CMD_PROBE_CLIENT:
2608 info->poll_command_supported = 1;
2609 break;
2610 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002611 }
2612 }
2613
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002614 if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
2615 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
2616 "off-channel TX");
2617 capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
2618 }
2619
2620 if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
2621 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
2622 capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
2623 }
2624
2625 /* default to 5000 since early versions of mac80211 don't set it */
2626 capa->max_remain_on_chan = 5000;
2627
2628 if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
2629 capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002630
2631 if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002632 capa->max_remain_on_chan =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002633 nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
2634
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002635 if (auth_supported)
2636 capa->flags |= WPA_DRIVER_FLAGS_SME;
2637 else if (!connect_supported) {
2638 wpa_printf(MSG_INFO, "nl80211: Driver does not support "
2639 "authentication/association or connect commands");
2640 info->error = 1;
2641 }
2642
2643 if (p2p_go_supported && p2p_client_supported)
2644 capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
2645 if (p2p_concurrent) {
2646 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
2647 "interface (driver advertised support)");
2648 capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
2649 capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002650
2651 if (p2p_multichan_concurrent) {
2652 wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
2653 "concurrent (driver advertised support)");
2654 capa->flags |=
2655 WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
2656 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002657 }
2658
2659 if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
2660 wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
2661 capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
2662
2663 if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
2664 wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
2665 capa->flags |=
2666 WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
2667 }
2668 }
Dmitry Shmidtad266fb2012-08-24 17:03:35 -07002669
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002670 if (tb[NL80211_ATTR_DEVICE_AP_SME])
2671 info->device_ap_sme = 1;
2672
2673 if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
2674 u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
2675
2676 if (flags & NL80211_FEATURE_SK_TX_STATUS)
2677 info->data_tx_status = 1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002678
2679 if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
2680 capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002681
2682 if (flags & NL80211_FEATURE_SAE)
2683 capa->flags |= WPA_DRIVER_FLAGS_SAE;
2684
2685 if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
2686 capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002687 }
2688
2689 if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
2690 int protocols =
2691 nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
2692 wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
2693 "offload in AP mode");
2694 capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
2695 capa->probe_resp_offloads =
2696 probe_resp_offload_support(protocols);
2697 }
2698
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002699 return NL_SKIP;
2700}
2701
2702
2703static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
2704 struct wiphy_info_data *info)
2705{
2706 struct nl_msg *msg;
2707
2708 os_memset(info, 0, sizeof(*info));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002709 info->capa = &drv->capa;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002710
2711 msg = nlmsg_alloc();
2712 if (!msg)
2713 return -1;
2714
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002715 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002716
2717 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
2718
2719 if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
2720 return 0;
2721 msg = NULL;
2722nla_put_failure:
2723 nlmsg_free(msg);
2724 return -1;
2725}
2726
2727
2728static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
2729{
2730 struct wiphy_info_data info;
2731 if (wpa_driver_nl80211_get_info(drv, &info))
2732 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002733
2734 if (info.error)
2735 return -1;
2736
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002737 drv->has_capability = 1;
2738 /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
2739 drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2740 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2741 WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2742 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
2743 drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
2744 WPA_DRIVER_CAPA_ENC_WEP104 |
2745 WPA_DRIVER_CAPA_ENC_TKIP |
2746 WPA_DRIVER_CAPA_ENC_CCMP;
2747 drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
2748 WPA_DRIVER_AUTH_SHARED |
2749 WPA_DRIVER_AUTH_LEAP;
2750
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002751 drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
2752 drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002753 drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
Dmitry Shmidtad266fb2012-08-24 17:03:35 -07002754
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002755 if (!info.device_ap_sme) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002756 drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002757
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002758 /*
2759 * No AP SME is currently assumed to also indicate no AP MLME
2760 * in the driver/firmware.
2761 */
2762 drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
2763 }
2764
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002765 drv->device_ap_sme = info.device_ap_sme;
2766 drv->poll_command_supported = info.poll_command_supported;
2767 drv->data_tx_status = info.data_tx_status;
2768
Dmitry Shmidt04949592012-07-19 12:16:46 -07002769#ifdef ANDROID_P2P
2770 if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
2771 /* Driver is new enough to support monitorless mode*/
2772 wpa_printf(MSG_DEBUG, "nl80211: Driver is new "
2773 "enough to support monitor-less mode");
2774 drv->use_monitor = 0;
2775 }
2776#else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002777 /*
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002778 * If poll command and tx status are supported, mac80211 is new enough
2779 * to have everything we need to not need monitor interfaces.
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002780 */
Dmitry Shmidtaa532512012-09-24 10:35:31 -07002781 drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002782#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002783
2784 if (drv->device_ap_sme && drv->use_monitor) {
2785 /*
2786 * Non-mac80211 drivers may not support monitor interface.
2787 * Make sure we do not get stuck with incorrect capability here
2788 * by explicitly testing this.
2789 */
2790 if (!info.monitor_supported) {
2791 wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
2792 "with device_ap_sme since no monitor mode "
2793 "support detected");
2794 drv->use_monitor = 0;
2795 }
2796 }
2797
2798 /*
2799 * If we aren't going to use monitor interfaces, but the
2800 * driver doesn't support data TX status, we won't get TX
2801 * status for EAPOL frames.
2802 */
2803 if (!drv->use_monitor && !info.data_tx_status)
2804 drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002805
2806 return 0;
2807}
2808
2809
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002810#ifdef ANDROID
2811static int android_genl_ctrl_resolve(struct nl_handle *handle,
2812 const char *name)
2813{
2814 /*
2815 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
2816 * need to work around that.
2817 */
2818 struct nl_cache *cache = NULL;
2819 struct genl_family *nl80211 = NULL;
2820 int id = -1;
2821
2822 if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
2823 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
2824 "netlink cache");
2825 goto fail;
2826 }
2827
2828 nl80211 = genl_ctrl_search_by_name(cache, name);
2829 if (nl80211 == NULL)
2830 goto fail;
2831
2832 id = genl_family_get_id(nl80211);
2833
2834fail:
2835 if (nl80211)
2836 genl_family_put(nl80211);
2837 if (cache)
2838 nl_cache_free(cache);
2839
2840 return id;
2841}
2842#define genl_ctrl_resolve android_genl_ctrl_resolve
2843#endif /* ANDROID */
2844
2845
2846static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002847{
2848 int ret;
2849
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002850 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2851 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002852 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
2853 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002854 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002855 }
2856
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002857 global->nl = nl_create_handle(global->nl_cb, "nl");
2858 if (global->nl == NULL)
2859 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002860
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002861 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
2862 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002863 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
2864 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002865 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002866 }
2867
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002868 global->nl_event = nl_create_handle(global->nl_cb, "event");
2869 if (global->nl_event == NULL)
2870 goto err;
2871
2872 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002873 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002874 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002875 if (ret < 0) {
2876 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
2877 "membership for scan events: %d (%s)",
2878 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002879 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002880 }
2881
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002882 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002883 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002884 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002885 if (ret < 0) {
2886 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
2887 "membership for mlme events: %d (%s)",
2888 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002889 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002890 }
2891
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002892 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002893 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002894 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002895 if (ret < 0) {
2896 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
2897 "membership for regulatory events: %d (%s)",
2898 ret, strerror(-ret));
2899 /* Continue without regulatory events */
2900 }
2901
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002902 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2903 no_seq_check, NULL);
2904 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2905 process_global_event, global);
2906
2907 eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
2908 wpa_driver_nl80211_event_receive,
2909 global->nl_cb, global->nl_event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002910
2911 return 0;
2912
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002913err:
2914 nl_destroy_handles(&global->nl_event);
2915 nl_destroy_handles(&global->nl);
2916 nl_cb_put(global->nl_cb);
2917 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002918 return -1;
2919}
2920
2921
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002922static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
2923{
2924 drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2925 if (!drv->nl_cb) {
2926 wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
2927 return -1;
2928 }
2929
2930 nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2931 no_seq_check, NULL);
2932 nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2933 process_drv_event, drv);
2934
2935 return 0;
2936}
2937
2938
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002939static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
2940{
2941 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
2942 /*
2943 * This may be for any interface; use ifdown event to disable
2944 * interface.
2945 */
2946}
2947
2948
2949static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
2950{
2951 struct wpa_driver_nl80211_data *drv = ctx;
2952 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002953 if (linux_set_iface_flags(drv->global->ioctl_sock,
2954 drv->first_bss.ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002955 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
2956 "after rfkill unblock");
2957 return;
2958 }
2959 /* rtnetlink ifup handler will report interface as enabled */
2960}
2961
2962
2963static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
2964{
2965 /* Find phy (radio) to which this interface belongs */
2966 char buf[90], *pos;
2967 int f, rv;
2968
2969 drv->phyname[0] = '\0';
2970 snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
2971 drv->first_bss.ifname);
2972 f = open(buf, O_RDONLY);
2973 if (f < 0) {
2974 wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
2975 buf, strerror(errno));
2976 return;
2977 }
2978
2979 rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
2980 close(f);
2981 if (rv < 0) {
2982 wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
2983 buf, strerror(errno));
2984 return;
2985 }
2986
2987 drv->phyname[rv] = '\0';
2988 pos = os_strchr(drv->phyname, '\n');
2989 if (pos)
2990 *pos = '\0';
2991 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
2992 drv->first_bss.ifname, drv->phyname);
2993}
2994
2995
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002996static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
2997 void *eloop_ctx,
2998 void *handle)
2999{
3000 struct wpa_driver_nl80211_data *drv = eloop_ctx;
3001 u8 data[2048];
3002 struct msghdr msg;
3003 struct iovec entry;
Dmitry Shmidt04949592012-07-19 12:16:46 -07003004 u8 control[512];
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003005 struct cmsghdr *cmsg;
3006 int res, found_ee = 0, found_wifi = 0, acked = 0;
3007 union wpa_event_data event;
3008
3009 memset(&msg, 0, sizeof(msg));
3010 msg.msg_iov = &entry;
3011 msg.msg_iovlen = 1;
3012 entry.iov_base = data;
3013 entry.iov_len = sizeof(data);
3014 msg.msg_control = &control;
3015 msg.msg_controllen = sizeof(control);
3016
3017 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
3018 /* if error or not fitting 802.3 header, return */
3019 if (res < 14)
3020 return;
3021
3022 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
3023 {
3024 if (cmsg->cmsg_level == SOL_SOCKET &&
3025 cmsg->cmsg_type == SCM_WIFI_STATUS) {
3026 int *ack;
3027
3028 found_wifi = 1;
3029 ack = (void *)CMSG_DATA(cmsg);
3030 acked = *ack;
3031 }
3032
3033 if (cmsg->cmsg_level == SOL_PACKET &&
3034 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
3035 struct sock_extended_err *err =
3036 (struct sock_extended_err *)CMSG_DATA(cmsg);
3037
3038 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
3039 found_ee = 1;
3040 }
3041 }
3042
3043 if (!found_ee || !found_wifi)
3044 return;
3045
3046 memset(&event, 0, sizeof(event));
3047 event.eapol_tx_status.dst = data;
3048 event.eapol_tx_status.data = data + 14;
3049 event.eapol_tx_status.data_len = res - 14;
3050 event.eapol_tx_status.ack = acked;
3051 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
3052}
3053
3054
3055static int nl80211_init_bss(struct i802_bss *bss)
3056{
3057 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
3058 if (!bss->nl_cb)
3059 return -1;
3060
3061 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
3062 no_seq_check, NULL);
3063 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
3064 process_bss_event, bss);
3065
3066 return 0;
3067}
3068
3069
3070static void nl80211_destroy_bss(struct i802_bss *bss)
3071{
3072 nl_cb_put(bss->nl_cb);
3073 bss->nl_cb = NULL;
3074}
3075
3076
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003077/**
3078 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
3079 * @ctx: context to be used when calling wpa_supplicant functions,
3080 * e.g., wpa_supplicant_event()
3081 * @ifname: interface name, e.g., wlan0
3082 * @global_priv: private driver global data from global_init()
3083 * Returns: Pointer to private data, %NULL on failure
3084 */
3085static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
3086 void *global_priv)
3087{
3088 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003089 struct rfkill_config *rcfg;
3090 struct i802_bss *bss;
3091
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003092 if (global_priv == NULL)
3093 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003094 drv = os_zalloc(sizeof(*drv));
3095 if (drv == NULL)
3096 return NULL;
3097 drv->global = global_priv;
3098 drv->ctx = ctx;
3099 bss = &drv->first_bss;
3100 bss->drv = drv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003101 bss->ctx = ctx;
3102
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003103 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
3104 drv->monitor_ifidx = -1;
3105 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003106 drv->eapol_tx_sock = -1;
3107 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003108
3109 if (wpa_driver_nl80211_init_nl(drv)) {
3110 os_free(drv);
3111 return NULL;
3112 }
3113
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003114 if (nl80211_init_bss(bss))
3115 goto failed;
3116
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003117 nl80211_get_phy_name(drv);
3118
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003119 rcfg = os_zalloc(sizeof(*rcfg));
3120 if (rcfg == NULL)
3121 goto failed;
3122 rcfg->ctx = drv;
3123 os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
3124 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
3125 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
3126 drv->rfkill = rfkill_init(rcfg);
3127 if (drv->rfkill == NULL) {
3128 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
3129 os_free(rcfg);
3130 }
3131
3132 if (wpa_driver_nl80211_finish_drv_init(drv))
3133 goto failed;
3134
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003135 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
3136 if (drv->eapol_tx_sock < 0)
3137 goto failed;
3138
3139 if (drv->data_tx_status) {
3140 int enabled = 1;
3141
3142 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
3143 &enabled, sizeof(enabled)) < 0) {
3144 wpa_printf(MSG_DEBUG,
3145 "nl80211: wifi status sockopt failed\n");
3146 drv->data_tx_status = 0;
3147 if (!drv->use_monitor)
3148 drv->capa.flags &=
3149 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
3150 } else {
3151 eloop_register_read_sock(drv->eapol_tx_sock,
3152 wpa_driver_nl80211_handle_eapol_tx_status,
3153 drv, NULL);
3154 }
3155 }
3156
3157 if (drv->global) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003158 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003159 drv->in_interface_list = 1;
3160 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003161
3162 return bss;
3163
3164failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003165 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003166 return NULL;
3167}
3168
3169
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003170static int nl80211_register_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003171 struct nl_handle *nl_handle,
3172 u16 type, const u8 *match, size_t match_len)
3173{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003174 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003175 struct nl_msg *msg;
3176 int ret = -1;
3177
3178 msg = nlmsg_alloc();
3179 if (!msg)
3180 return -1;
3181
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003182 wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
3183 type, nl_handle);
3184 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
3185 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003186
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003187 nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
3188
3189 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003190 NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
3191 NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
3192
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003193 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003194 msg = NULL;
3195 if (ret) {
3196 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
3197 "failed (type=%u): ret=%d (%s)",
3198 type, ret, strerror(-ret));
3199 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
3200 match, match_len);
3201 goto nla_put_failure;
3202 }
3203 ret = 0;
3204nla_put_failure:
3205 nlmsg_free(msg);
3206 return ret;
3207}
3208
3209
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003210static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
3211{
3212 struct wpa_driver_nl80211_data *drv = bss->drv;
3213
3214 if (bss->nl_mgmt) {
3215 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
3216 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
3217 return -1;
3218 }
3219
3220 bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
3221 if (bss->nl_mgmt == NULL)
3222 return -1;
3223
3224 eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
3225 wpa_driver_nl80211_event_receive, bss->nl_cb,
3226 bss->nl_mgmt);
3227
3228 return 0;
3229}
3230
3231
3232static int nl80211_register_action_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003233 const u8 *match, size_t match_len)
3234{
3235 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003236 return nl80211_register_frame(bss, bss->nl_mgmt,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003237 type, match, match_len);
3238}
3239
3240
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003241static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003242{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003243 struct wpa_driver_nl80211_data *drv = bss->drv;
3244
3245 if (nl80211_alloc_mgmt_handle(bss))
3246 return -1;
3247 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
3248 "handle %p", bss->nl_mgmt);
3249
3250#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003251 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003252 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003253 return -1;
3254 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003255 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003256 return -1;
3257 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003258 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003259 return -1;
3260 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003261 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003262 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003263#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
3264#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003265 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003266 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003267 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
3268 6) < 0)
3269 return -1;
3270 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003271 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003272 (u8 *) "\x7f\x50\x6f\x9a\x09",
3273 5) < 0)
3274 return -1;
3275#endif /* CONFIG_P2P */
3276#ifdef CONFIG_IEEE80211W
3277 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003278 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003279 return -1;
3280#endif /* CONFIG_IEEE80211W */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003281#ifdef CONFIG_TDLS
3282 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
3283 /* TDLS Discovery Response */
3284 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
3285 0)
3286 return -1;
3287 }
3288#endif /* CONFIG_TDLS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003289
3290 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003291 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003292 return -1;
3293 else
3294 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
3295 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
3296
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003297 /* WNM - BSS Transition Management Request */
3298 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
3299 return -1;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08003300 /* WNM-Sleep Mode Response */
3301 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
3302 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003303
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003304 return 0;
3305}
3306
3307
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003308static int nl80211_register_spurious_class3(struct i802_bss *bss)
3309{
3310 struct wpa_driver_nl80211_data *drv = bss->drv;
3311 struct nl_msg *msg;
3312 int ret = -1;
3313
3314 msg = nlmsg_alloc();
3315 if (!msg)
3316 return -1;
3317
3318 nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
3319
3320 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
3321
3322 ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
3323 msg = NULL;
3324 if (ret) {
3325 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
3326 "failed: ret=%d (%s)",
3327 ret, strerror(-ret));
3328 goto nla_put_failure;
3329 }
3330 ret = 0;
3331nla_put_failure:
3332 nlmsg_free(msg);
3333 return ret;
3334}
3335
3336
3337static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
3338{
3339 static const int stypes[] = {
3340 WLAN_FC_STYPE_AUTH,
3341 WLAN_FC_STYPE_ASSOC_REQ,
3342 WLAN_FC_STYPE_REASSOC_REQ,
3343 WLAN_FC_STYPE_DISASSOC,
3344 WLAN_FC_STYPE_DEAUTH,
3345 WLAN_FC_STYPE_ACTION,
3346 WLAN_FC_STYPE_PROBE_REQ,
3347/* Beacon doesn't work as mac80211 doesn't currently allow
3348 * it, but it wouldn't really be the right thing anyway as
3349 * it isn't per interface ... maybe just dump the scan
3350 * results periodically for OLBC?
3351 */
3352// WLAN_FC_STYPE_BEACON,
3353 };
3354 unsigned int i;
3355
3356 if (nl80211_alloc_mgmt_handle(bss))
3357 return -1;
3358 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
3359 "handle %p", bss->nl_mgmt);
3360
3361 for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
3362 if (nl80211_register_frame(bss, bss->nl_mgmt,
3363 (WLAN_FC_TYPE_MGMT << 2) |
3364 (stypes[i] << 4),
3365 NULL, 0) < 0) {
3366 goto out_err;
3367 }
3368 }
3369
3370 if (nl80211_register_spurious_class3(bss))
3371 goto out_err;
3372
3373 if (nl80211_get_wiphy_data_ap(bss) == NULL)
3374 goto out_err;
3375
3376 return 0;
3377
3378out_err:
3379 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3380 nl_destroy_handles(&bss->nl_mgmt);
3381 return -1;
3382}
3383
3384
3385static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
3386{
3387 if (nl80211_alloc_mgmt_handle(bss))
3388 return -1;
3389 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
3390 "handle %p (device SME)", bss->nl_mgmt);
3391
3392 if (nl80211_register_frame(bss, bss->nl_mgmt,
3393 (WLAN_FC_TYPE_MGMT << 2) |
3394 (WLAN_FC_STYPE_ACTION << 4),
3395 NULL, 0) < 0)
3396 goto out_err;
3397
3398 return 0;
3399
3400out_err:
3401 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3402 nl_destroy_handles(&bss->nl_mgmt);
3403 return -1;
3404}
3405
3406
3407static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
3408{
3409 if (bss->nl_mgmt == NULL)
3410 return;
3411 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
3412 "(%s)", bss->nl_mgmt, reason);
3413 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3414 nl_destroy_handles(&bss->nl_mgmt);
3415
3416 nl80211_put_wiphy_data_ap(bss);
3417}
3418
3419
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003420static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
3421{
3422 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
3423}
3424
3425
3426static int
3427wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
3428{
3429 struct i802_bss *bss = &drv->first_bss;
3430 int send_rfkill_event = 0;
3431
3432 drv->ifindex = if_nametoindex(bss->ifname);
3433 drv->first_bss.ifindex = drv->ifindex;
3434
3435#ifndef HOSTAPD
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003436 /*
3437 * Make sure the interface starts up in station mode unless this is a
3438 * dynamically added interface (e.g., P2P) that was already configured
3439 * with proper iftype.
3440 */
3441 if (drv->ifindex != drv->global->if_add_ifindex &&
3442 wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
3443 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003444 "use managed mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003445 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003446 }
3447
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003448 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003449 if (rfkill_is_blocked(drv->rfkill)) {
3450 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
3451 "interface '%s' due to rfkill",
3452 bss->ifname);
3453 drv->if_disabled = 1;
3454 send_rfkill_event = 1;
3455 } else {
3456 wpa_printf(MSG_ERROR, "nl80211: Could not set "
3457 "interface '%s' UP", bss->ifname);
3458 return -1;
3459 }
3460 }
3461
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003462 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003463 1, IF_OPER_DORMANT);
3464#endif /* HOSTAPD */
3465
3466 if (wpa_driver_nl80211_capa(drv))
3467 return -1;
3468
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003469 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3470 bss->addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003471 return -1;
3472
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003473 if (send_rfkill_event) {
3474 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
3475 drv, drv->ctx);
3476 }
3477
3478 return 0;
3479}
3480
3481
3482static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
3483{
3484 struct nl_msg *msg;
3485
3486 msg = nlmsg_alloc();
3487 if (!msg)
3488 return -ENOMEM;
3489
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003490 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003491 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3492
3493 return send_and_recv_msgs(drv, msg, NULL, NULL);
3494 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003495 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003496 return -ENOBUFS;
3497}
3498
3499
3500/**
3501 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
3502 * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
3503 *
3504 * Shut down driver interface and processing of driver events. Free
3505 * private data buffer if one was allocated in wpa_driver_nl80211_init().
3506 */
3507static void wpa_driver_nl80211_deinit(void *priv)
3508{
3509 struct i802_bss *bss = priv;
3510 struct wpa_driver_nl80211_data *drv = bss->drv;
3511
Dmitry Shmidt04949592012-07-19 12:16:46 -07003512 bss->in_deinit = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003513 if (drv->data_tx_status)
3514 eloop_unregister_read_sock(drv->eapol_tx_sock);
3515 if (drv->eapol_tx_sock >= 0)
3516 close(drv->eapol_tx_sock);
3517
3518 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003519 wpa_driver_nl80211_probe_req_report(bss, 0);
3520 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003521 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
3522 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003523 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3524 "interface %s from bridge %s: %s",
3525 bss->ifname, bss->brname, strerror(errno));
3526 }
3527 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003528 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003529 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3530 "bridge %s: %s",
3531 bss->brname, strerror(errno));
3532 }
3533
3534 nl80211_remove_monitor_interface(drv);
3535
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003536 if (is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003537 wpa_driver_nl80211_del_beacon(drv);
3538
3539#ifdef HOSTAPD
3540 if (drv->last_freq_ht) {
3541 /* Clear HT flags from the driver */
3542 struct hostapd_freq_params freq;
3543 os_memset(&freq, 0, sizeof(freq));
3544 freq.freq = drv->last_freq;
3545 i802_set_freq(priv, &freq);
3546 }
3547
3548 if (drv->eapol_sock >= 0) {
3549 eloop_unregister_read_sock(drv->eapol_sock);
3550 close(drv->eapol_sock);
3551 }
3552
3553 if (drv->if_indices != drv->default_if_indices)
3554 os_free(drv->if_indices);
3555#endif /* HOSTAPD */
3556
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003557 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003558 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3559
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003560 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
3561 IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003562 rfkill_deinit(drv->rfkill);
3563
3564 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3565
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003566 (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
3567 wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
3568 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003569
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003570 nl_cb_put(drv->nl_cb);
3571
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003572 nl80211_destroy_bss(&drv->first_bss);
3573
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003574 os_free(drv->filter_ssids);
3575
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003576 os_free(drv->auth_ie);
3577
3578 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003579 dl_list_del(&drv->list);
3580
3581 os_free(drv);
3582}
3583
3584
3585/**
3586 * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
3587 * @eloop_ctx: Driver private data
3588 * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
3589 *
3590 * This function can be used as registered timeout when starting a scan to
3591 * generate a scan completed event if the driver does not report this.
3592 */
3593static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
3594{
3595 struct wpa_driver_nl80211_data *drv = eloop_ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003596 if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003597 wpa_driver_nl80211_set_mode(&drv->first_bss,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003598 drv->ap_scan_as_station);
3599 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003600 }
3601 wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
3602 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
3603}
3604
3605
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003606static struct nl_msg *
3607nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
3608 struct wpa_driver_scan_params *params)
3609{
3610 struct nl_msg *msg;
3611 int err;
3612 size_t i;
3613
3614 msg = nlmsg_alloc();
3615 if (!msg)
3616 return NULL;
3617
3618 nl80211_cmd(drv, msg, 0, cmd);
3619
3620 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
3621 goto fail;
3622
3623 if (params->num_ssids) {
3624 struct nl_msg *ssids = nlmsg_alloc();
3625 if (ssids == NULL)
3626 goto fail;
3627 for (i = 0; i < params->num_ssids; i++) {
3628 wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
3629 params->ssids[i].ssid,
3630 params->ssids[i].ssid_len);
3631 if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
3632 params->ssids[i].ssid) < 0) {
3633 nlmsg_free(ssids);
3634 goto fail;
3635 }
3636 }
3637 err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
3638 nlmsg_free(ssids);
3639 if (err < 0)
3640 goto fail;
3641 }
3642
3643 if (params->extra_ies) {
3644 wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
3645 params->extra_ies, params->extra_ies_len);
3646 if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
3647 params->extra_ies) < 0)
3648 goto fail;
3649 }
3650
3651 if (params->freqs) {
3652 struct nl_msg *freqs = nlmsg_alloc();
3653 if (freqs == NULL)
3654 goto fail;
3655 for (i = 0; params->freqs[i]; i++) {
3656 wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
3657 "MHz", params->freqs[i]);
3658 if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
3659 nlmsg_free(freqs);
3660 goto fail;
3661 }
3662 }
3663 err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
3664 freqs);
3665 nlmsg_free(freqs);
3666 if (err < 0)
3667 goto fail;
3668 }
3669
3670 os_free(drv->filter_ssids);
3671 drv->filter_ssids = params->filter_ssids;
3672 params->filter_ssids = NULL;
3673 drv->num_filter_ssids = params->num_filter_ssids;
3674
3675 return msg;
3676
3677fail:
3678 nlmsg_free(msg);
3679 return NULL;
3680}
3681
3682
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003683/**
3684 * wpa_driver_nl80211_scan - Request the driver to initiate scan
3685 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3686 * @params: Scan parameters
3687 * Returns: 0 on success, -1 on failure
3688 */
3689static int wpa_driver_nl80211_scan(void *priv,
3690 struct wpa_driver_scan_params *params)
3691{
3692 struct i802_bss *bss = priv;
3693 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
3740 if (wpa_driver_nl80211_scan(drv, 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
4277static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
4278 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{
4283 struct i802_bss *bss = priv;
4284 struct wpa_driver_nl80211_data *drv = bss->drv;
4285 int ifindex = if_nametoindex(ifname);
4286 struct nl_msg *msg;
4287 int ret;
4288
4289 wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
4290 "set_tx=%d seq_len=%lu key_len=%lu",
4291 __func__, ifindex, alg, addr, key_idx, set_tx,
4292 (unsigned long) seq_len, (unsigned long) key_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004293#ifdef CONFIG_TDLS
4294 if (key_idx == -1)
4295 key_idx = 0;
4296#endif /* CONFIG_TDLS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004297
4298 msg = nlmsg_alloc();
4299 if (!msg)
4300 return -ENOMEM;
4301
4302 if (alg == WPA_ALG_NONE) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004303 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004304 } else {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004305 nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004306 NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
4307 switch (alg) {
4308 case WPA_ALG_WEP:
4309 if (key_len == 5)
4310 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4311 WLAN_CIPHER_SUITE_WEP40);
4312 else
4313 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4314 WLAN_CIPHER_SUITE_WEP104);
4315 break;
4316 case WPA_ALG_TKIP:
4317 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4318 WLAN_CIPHER_SUITE_TKIP);
4319 break;
4320 case WPA_ALG_CCMP:
4321 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4322 WLAN_CIPHER_SUITE_CCMP);
4323 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004324 case WPA_ALG_GCMP:
4325 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4326 WLAN_CIPHER_SUITE_GCMP);
4327 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004328 case WPA_ALG_IGTK:
4329 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4330 WLAN_CIPHER_SUITE_AES_CMAC);
4331 break;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004332 case WPA_ALG_SMS4:
4333 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4334 WLAN_CIPHER_SUITE_SMS4);
4335 break;
4336 case WPA_ALG_KRK:
4337 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4338 WLAN_CIPHER_SUITE_KRK);
4339 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004340 default:
4341 wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
4342 "algorithm %d", __func__, alg);
4343 nlmsg_free(msg);
4344 return -1;
4345 }
4346 }
4347
4348 if (seq && seq_len)
4349 NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
4350
4351 if (addr && !is_broadcast_ether_addr(addr)) {
4352 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
4353 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
4354
4355 if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
4356 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
4357 NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
4358 NL80211_KEYTYPE_GROUP);
4359 }
4360 } else if (addr && is_broadcast_ether_addr(addr)) {
4361 struct nl_msg *types;
4362 int err;
4363 wpa_printf(MSG_DEBUG, " broadcast key");
4364 types = nlmsg_alloc();
4365 if (!types)
4366 goto nla_put_failure;
4367 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
4368 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4369 types);
4370 nlmsg_free(types);
4371 if (err)
4372 goto nla_put_failure;
4373 }
4374 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
4375 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
4376
4377 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4378 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
4379 ret = 0;
4380 if (ret)
4381 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
4382 ret, strerror(-ret));
4383
4384 /*
4385 * If we failed or don't need to set the default TX key (below),
4386 * we're done here.
4387 */
4388 if (ret || !set_tx || alg == WPA_ALG_NONE)
4389 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004390 if (is_ap_interface(drv->nlmode) && addr &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004391 !is_broadcast_ether_addr(addr))
4392 return ret;
4393
4394 msg = nlmsg_alloc();
4395 if (!msg)
4396 return -ENOMEM;
4397
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004398 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004399 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
4400 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
4401 if (alg == WPA_ALG_IGTK)
4402 NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
4403 else
4404 NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
4405 if (addr && is_broadcast_ether_addr(addr)) {
4406 struct nl_msg *types;
4407 int err;
4408 types = nlmsg_alloc();
4409 if (!types)
4410 goto nla_put_failure;
4411 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
4412 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4413 types);
4414 nlmsg_free(types);
4415 if (err)
4416 goto nla_put_failure;
4417 } else if (addr) {
4418 struct nl_msg *types;
4419 int err;
4420 types = nlmsg_alloc();
4421 if (!types)
4422 goto nla_put_failure;
4423 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
4424 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4425 types);
4426 nlmsg_free(types);
4427 if (err)
4428 goto nla_put_failure;
4429 }
4430
4431 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4432 if (ret == -ENOENT)
4433 ret = 0;
4434 if (ret)
4435 wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
4436 "err=%d %s)", ret, strerror(-ret));
4437 return ret;
4438
4439nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004440 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004441 return -ENOBUFS;
4442}
4443
4444
4445static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
4446 int key_idx, int defkey,
4447 const u8 *seq, size_t seq_len,
4448 const u8 *key, size_t key_len)
4449{
4450 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
4451 if (!key_attr)
4452 return -1;
4453
4454 if (defkey && alg == WPA_ALG_IGTK)
4455 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
4456 else if (defkey)
4457 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
4458
4459 NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
4460
4461 switch (alg) {
4462 case WPA_ALG_WEP:
4463 if (key_len == 5)
4464 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4465 WLAN_CIPHER_SUITE_WEP40);
4466 else
4467 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4468 WLAN_CIPHER_SUITE_WEP104);
4469 break;
4470 case WPA_ALG_TKIP:
4471 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
4472 break;
4473 case WPA_ALG_CCMP:
4474 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
4475 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004476 case WPA_ALG_GCMP:
4477 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
4478 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004479 case WPA_ALG_IGTK:
4480 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4481 WLAN_CIPHER_SUITE_AES_CMAC);
4482 break;
4483 default:
4484 wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
4485 "algorithm %d", __func__, alg);
4486 return -1;
4487 }
4488
4489 if (seq && seq_len)
4490 NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
4491
4492 NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
4493
4494 nla_nest_end(msg, key_attr);
4495
4496 return 0;
4497 nla_put_failure:
4498 return -1;
4499}
4500
4501
4502static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
4503 struct nl_msg *msg)
4504{
4505 int i, privacy = 0;
4506 struct nlattr *nl_keys, *nl_key;
4507
4508 for (i = 0; i < 4; i++) {
4509 if (!params->wep_key[i])
4510 continue;
4511 privacy = 1;
4512 break;
4513 }
4514 if (params->wps == WPS_MODE_PRIVACY)
4515 privacy = 1;
4516 if (params->pairwise_suite &&
4517 params->pairwise_suite != WPA_CIPHER_NONE)
4518 privacy = 1;
4519
4520 if (!privacy)
4521 return 0;
4522
4523 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
4524
4525 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
4526 if (!nl_keys)
4527 goto nla_put_failure;
4528
4529 for (i = 0; i < 4; i++) {
4530 if (!params->wep_key[i])
4531 continue;
4532
4533 nl_key = nla_nest_start(msg, i);
4534 if (!nl_key)
4535 goto nla_put_failure;
4536
4537 NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
4538 params->wep_key[i]);
4539 if (params->wep_key_len[i] == 5)
4540 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4541 WLAN_CIPHER_SUITE_WEP40);
4542 else
4543 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4544 WLAN_CIPHER_SUITE_WEP104);
4545
4546 NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
4547
4548 if (i == params->wep_tx_keyidx)
4549 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
4550
4551 nla_nest_end(msg, nl_key);
4552 }
4553 nla_nest_end(msg, nl_keys);
4554
4555 return 0;
4556
4557nla_put_failure:
4558 return -ENOBUFS;
4559}
4560
4561
4562static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
4563 const u8 *addr, int cmd, u16 reason_code,
4564 int local_state_change)
4565{
4566 int ret = -1;
4567 struct nl_msg *msg;
4568
4569 msg = nlmsg_alloc();
4570 if (!msg)
4571 return -1;
4572
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004573 nl80211_cmd(drv, msg, 0, cmd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004574
4575 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4576 NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004577 if (addr)
4578 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004579 if (local_state_change)
4580 NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
4581
4582 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4583 msg = NULL;
4584 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004585 wpa_dbg(drv->ctx, MSG_DEBUG,
4586 "nl80211: MLME command failed: reason=%u ret=%d (%s)",
4587 reason_code, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004588 goto nla_put_failure;
4589 }
4590 ret = 0;
4591
4592nla_put_failure:
4593 nlmsg_free(msg);
4594 return ret;
4595}
4596
4597
4598static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004599 int reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004600{
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004601 wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004602 drv->associated = 0;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004603 drv->ignore_next_local_disconnect = 0;
4604 /* Disconnect command doesn't need BSSID - it uses cached value */
4605 return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004606 reason_code, 0);
4607}
4608
4609
4610static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
4611 int reason_code)
4612{
4613 struct i802_bss *bss = priv;
4614 struct wpa_driver_nl80211_data *drv = bss->drv;
4615 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004616 return wpa_driver_nl80211_disconnect(drv, reason_code);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004617 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
4618 __func__, MAC2STR(addr), reason_code);
4619 drv->associated = 0;
4620 if (drv->nlmode == NL80211_IFTYPE_ADHOC)
4621 return nl80211_leave_ibss(drv);
4622 return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
4623 reason_code, 0);
4624}
4625
4626
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004627static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
4628 struct wpa_driver_auth_params *params)
4629{
4630 int i;
4631
4632 drv->auth_freq = params->freq;
4633 drv->auth_alg = params->auth_alg;
4634 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
4635 drv->auth_local_state_change = params->local_state_change;
4636 drv->auth_p2p = params->p2p;
4637
4638 if (params->bssid)
4639 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
4640 else
4641 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
4642
4643 if (params->ssid) {
4644 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
4645 drv->auth_ssid_len = params->ssid_len;
4646 } else
4647 drv->auth_ssid_len = 0;
4648
4649
4650 os_free(drv->auth_ie);
4651 drv->auth_ie = NULL;
4652 drv->auth_ie_len = 0;
4653 if (params->ie) {
4654 drv->auth_ie = os_malloc(params->ie_len);
4655 if (drv->auth_ie) {
4656 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
4657 drv->auth_ie_len = params->ie_len;
4658 }
4659 }
4660
4661 for (i = 0; i < 4; i++) {
4662 if (params->wep_key[i] && params->wep_key_len[i] &&
4663 params->wep_key_len[i] <= 16) {
4664 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
4665 params->wep_key_len[i]);
4666 drv->auth_wep_key_len[i] = params->wep_key_len[i];
4667 } else
4668 drv->auth_wep_key_len[i] = 0;
4669 }
4670}
4671
4672
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004673static int wpa_driver_nl80211_authenticate(
4674 void *priv, struct wpa_driver_auth_params *params)
4675{
4676 struct i802_bss *bss = priv;
4677 struct wpa_driver_nl80211_data *drv = bss->drv;
4678 int ret = -1, i;
4679 struct nl_msg *msg;
4680 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004681 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004682 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004683 int is_retry;
4684
4685 is_retry = drv->retry_auth;
4686 drv->retry_auth = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004687
4688 drv->associated = 0;
4689 os_memset(drv->auth_bssid, 0, ETH_ALEN);
4690 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004691 nlmode = params->p2p ?
4692 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
4693 if (drv->nlmode != nlmode &&
4694 wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004695 return -1;
4696
4697retry:
4698 msg = nlmsg_alloc();
4699 if (!msg)
4700 return -1;
4701
4702 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
4703 drv->ifindex);
4704
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004705 nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004706
4707 for (i = 0; i < 4; i++) {
4708 if (!params->wep_key[i])
4709 continue;
4710 wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
4711 NULL, i,
4712 i == params->wep_tx_keyidx, NULL, 0,
4713 params->wep_key[i],
4714 params->wep_key_len[i]);
4715 if (params->wep_tx_keyidx != i)
4716 continue;
4717 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
4718 params->wep_key[i], params->wep_key_len[i])) {
4719 nlmsg_free(msg);
4720 return -1;
4721 }
4722 }
4723
4724 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4725 if (params->bssid) {
4726 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
4727 MAC2STR(params->bssid));
4728 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
4729 }
4730 if (params->freq) {
4731 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
4732 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
4733 }
4734 if (params->ssid) {
4735 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
4736 params->ssid, params->ssid_len);
4737 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
4738 params->ssid);
4739 }
4740 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
4741 if (params->ie)
4742 NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004743 if (params->sae_data) {
4744 wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data,
4745 params->sae_data_len);
4746 NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
4747 params->sae_data);
4748 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004749 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
4750 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
4751 else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
4752 type = NL80211_AUTHTYPE_SHARED_KEY;
4753 else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
4754 type = NL80211_AUTHTYPE_NETWORK_EAP;
4755 else if (params->auth_alg & WPA_AUTH_ALG_FT)
4756 type = NL80211_AUTHTYPE_FT;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08004757 else if (params->auth_alg & WPA_AUTH_ALG_SAE)
4758 type = NL80211_AUTHTYPE_SAE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004759 else
4760 goto nla_put_failure;
4761 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
4762 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
4763 if (params->local_state_change) {
4764 wpa_printf(MSG_DEBUG, " * Local state change only");
4765 NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
4766 }
4767
4768 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4769 msg = NULL;
4770 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004771 wpa_dbg(drv->ctx, MSG_DEBUG,
4772 "nl80211: MLME command failed (auth): ret=%d (%s)",
4773 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004774 count++;
4775 if (ret == -EALREADY && count == 1 && params->bssid &&
4776 !params->local_state_change) {
4777 /*
4778 * mac80211 does not currently accept new
4779 * authentication if we are already authenticated. As a
4780 * workaround, force deauthentication and try again.
4781 */
4782 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
4783 "after forced deauthentication");
4784 wpa_driver_nl80211_deauthenticate(
4785 bss, params->bssid,
4786 WLAN_REASON_PREV_AUTH_NOT_VALID);
4787 nlmsg_free(msg);
4788 goto retry;
4789 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004790
4791 if (ret == -ENOENT && params->freq && !is_retry) {
4792 /*
4793 * cfg80211 has likely expired the BSS entry even
4794 * though it was previously available in our internal
4795 * BSS table. To recover quickly, start a single
4796 * channel scan on the specified channel.
4797 */
4798 struct wpa_driver_scan_params scan;
4799 int freqs[2];
4800
4801 os_memset(&scan, 0, sizeof(scan));
4802 scan.num_ssids = 1;
4803 if (params->ssid) {
4804 scan.ssids[0].ssid = params->ssid;
4805 scan.ssids[0].ssid_len = params->ssid_len;
4806 }
4807 freqs[0] = params->freq;
4808 freqs[1] = 0;
4809 scan.freqs = freqs;
4810 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
4811 "channel scan to refresh cfg80211 BSS "
4812 "entry");
4813 ret = wpa_driver_nl80211_scan(bss, &scan);
4814 if (ret == 0) {
4815 nl80211_copy_auth_params(drv, params);
4816 drv->scan_for_auth = 1;
4817 }
4818 } else if (is_retry) {
4819 /*
4820 * Need to indicate this with an event since the return
4821 * value from the retry is not delivered to core code.
4822 */
4823 union wpa_event_data event;
4824 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
4825 "failed");
4826 os_memset(&event, 0, sizeof(event));
4827 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
4828 ETH_ALEN);
4829 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
4830 &event);
4831 }
4832
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004833 goto nla_put_failure;
4834 }
4835 ret = 0;
4836 wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
4837 "successfully");
4838
4839nla_put_failure:
4840 nlmsg_free(msg);
4841 return ret;
4842}
4843
4844
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004845static int wpa_driver_nl80211_authenticate_retry(
4846 struct wpa_driver_nl80211_data *drv)
4847{
4848 struct wpa_driver_auth_params params;
4849 struct i802_bss *bss = &drv->first_bss;
4850 int i;
4851
4852 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
4853
4854 os_memset(&params, 0, sizeof(params));
4855 params.freq = drv->auth_freq;
4856 params.auth_alg = drv->auth_alg;
4857 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
4858 params.local_state_change = drv->auth_local_state_change;
4859 params.p2p = drv->auth_p2p;
4860
4861 if (!is_zero_ether_addr(drv->auth_bssid_))
4862 params.bssid = drv->auth_bssid_;
4863
4864 if (drv->auth_ssid_len) {
4865 params.ssid = drv->auth_ssid;
4866 params.ssid_len = drv->auth_ssid_len;
4867 }
4868
4869 params.ie = drv->auth_ie;
4870 params.ie_len = drv->auth_ie_len;
4871
4872 for (i = 0; i < 4; i++) {
4873 if (drv->auth_wep_key_len[i]) {
4874 params.wep_key[i] = drv->auth_wep_key[i];
4875 params.wep_key_len[i] = drv->auth_wep_key_len[i];
4876 }
4877 }
4878
4879 drv->retry_auth = 1;
4880 return wpa_driver_nl80211_authenticate(bss, &params);
4881}
4882
4883
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004884struct phy_info_arg {
4885 u16 *num_modes;
4886 struct hostapd_hw_modes *modes;
4887};
4888
4889static int phy_info_handler(struct nl_msg *msg, void *arg)
4890{
4891 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
4892 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
4893 struct phy_info_arg *phy_info = arg;
4894
4895 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
4896
4897 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
4898 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
4899 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
4900 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
4901 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
4902 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
4903 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
4904 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
4905 };
4906
4907 struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
4908 static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
4909 [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
4910 [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
4911 };
4912
4913 struct nlattr *nl_band;
4914 struct nlattr *nl_freq;
4915 struct nlattr *nl_rate;
4916 int rem_band, rem_freq, rem_rate;
4917 struct hostapd_hw_modes *mode;
4918 int idx, mode_is_set;
4919
4920 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
4921 genlmsg_attrlen(gnlh, 0), NULL);
4922
4923 if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
4924 return NL_SKIP;
4925
4926 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004927 mode = os_realloc_array(phy_info->modes,
4928 *phy_info->num_modes + 1,
4929 sizeof(*mode));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004930 if (!mode)
4931 return NL_SKIP;
4932 phy_info->modes = mode;
4933
4934 mode_is_set = 0;
4935
4936 mode = &phy_info->modes[*(phy_info->num_modes)];
4937 memset(mode, 0, sizeof(*mode));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004938 mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004939 *(phy_info->num_modes) += 1;
4940
4941 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
4942 nla_len(nl_band), NULL);
4943
4944 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
4945 mode->ht_capab = nla_get_u16(
4946 tb_band[NL80211_BAND_ATTR_HT_CAPA]);
4947 }
4948
4949 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
4950 mode->a_mpdu_params |= nla_get_u8(
4951 tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
4952 0x03;
4953 }
4954
4955 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
4956 mode->a_mpdu_params |= nla_get_u8(
4957 tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
4958 2;
4959 }
4960
4961 if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
4962 nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
4963 u8 *mcs;
4964 mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
4965 os_memcpy(mode->mcs_set, mcs, 16);
4966 }
4967
Dmitry Shmidt04949592012-07-19 12:16:46 -07004968 if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
4969 mode->vht_capab = nla_get_u32(
4970 tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
4971 }
4972
4973 if (tb_band[NL80211_BAND_ATTR_VHT_MCS_SET] &&
4974 nla_len(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])) {
4975 u8 *mcs;
4976 mcs = nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
4977 os_memcpy(mode->vht_mcs_set, mcs, 8);
4978 }
4979
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004980 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
4981 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
4982 nla_len(nl_freq), freq_policy);
4983 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
4984 continue;
4985 mode->num_channels++;
4986 }
4987
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004988 mode->channels = os_calloc(mode->num_channels,
4989 sizeof(struct hostapd_channel_data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004990 if (!mode->channels)
4991 return NL_SKIP;
4992
4993 idx = 0;
4994
4995 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
4996 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
4997 nla_len(nl_freq), freq_policy);
4998 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
4999 continue;
5000
5001 mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
5002 mode->channels[idx].flag = 0;
5003
5004 if (!mode_is_set) {
5005 /* crude heuristic */
5006 if (mode->channels[idx].freq < 4000)
5007 mode->mode = HOSTAPD_MODE_IEEE80211B;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005008 else if (mode->channels[idx].freq > 50000)
5009 mode->mode = HOSTAPD_MODE_IEEE80211AD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005010 else
5011 mode->mode = HOSTAPD_MODE_IEEE80211A;
5012 mode_is_set = 1;
5013 }
5014
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005015 switch (mode->mode) {
5016 case HOSTAPD_MODE_IEEE80211AD:
5017 mode->channels[idx].chan =
5018 (mode->channels[idx].freq - 56160) /
5019 2160;
5020 break;
5021 case HOSTAPD_MODE_IEEE80211A:
5022 mode->channels[idx].chan =
5023 mode->channels[idx].freq / 5 - 1000;
5024 break;
5025 case HOSTAPD_MODE_IEEE80211B:
5026 case HOSTAPD_MODE_IEEE80211G:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005027 if (mode->channels[idx].freq == 2484)
5028 mode->channels[idx].chan = 14;
5029 else
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005030 mode->channels[idx].chan =
5031 (mode->channels[idx].freq -
5032 2407) / 5;
5033 break;
5034 default:
5035 break;
5036 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005037
5038 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
5039 mode->channels[idx].flag |=
5040 HOSTAPD_CHAN_DISABLED;
5041 if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
5042 mode->channels[idx].flag |=
5043 HOSTAPD_CHAN_PASSIVE_SCAN;
5044 if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
5045 mode->channels[idx].flag |=
5046 HOSTAPD_CHAN_NO_IBSS;
5047 if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
5048 mode->channels[idx].flag |=
5049 HOSTAPD_CHAN_RADAR;
5050
5051 if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
5052 !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
5053 mode->channels[idx].max_tx_power =
5054 nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
5055
5056 idx++;
5057 }
5058
5059 nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
5060 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
5061 nla_len(nl_rate), rate_policy);
5062 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
5063 continue;
5064 mode->num_rates++;
5065 }
5066
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005067 mode->rates = os_calloc(mode->num_rates, sizeof(int));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005068 if (!mode->rates)
5069 return NL_SKIP;
5070
5071 idx = 0;
5072
5073 nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
5074 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
5075 nla_len(nl_rate), rate_policy);
5076 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
5077 continue;
5078 mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
5079
5080 /* crude heuristic */
5081 if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
5082 mode->rates[idx] > 200)
5083 mode->mode = HOSTAPD_MODE_IEEE80211G;
5084
5085 idx++;
5086 }
5087 }
5088
5089 return NL_SKIP;
5090}
5091
5092static struct hostapd_hw_modes *
5093wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
5094{
5095 u16 m;
5096 struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
5097 int i, mode11g_idx = -1;
5098
5099 /* If only 802.11g mode is included, use it to construct matching
5100 * 802.11b mode data. */
5101
5102 for (m = 0; m < *num_modes; m++) {
5103 if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
5104 return modes; /* 802.11b already included */
5105 if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
5106 mode11g_idx = m;
5107 }
5108
5109 if (mode11g_idx < 0)
5110 return modes; /* 2.4 GHz band not supported at all */
5111
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005112 nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005113 if (nmodes == NULL)
5114 return modes; /* Could not add 802.11b mode */
5115
5116 mode = &nmodes[*num_modes];
5117 os_memset(mode, 0, sizeof(*mode));
5118 (*num_modes)++;
5119 modes = nmodes;
5120
5121 mode->mode = HOSTAPD_MODE_IEEE80211B;
5122
5123 mode11g = &modes[mode11g_idx];
5124 mode->num_channels = mode11g->num_channels;
5125 mode->channels = os_malloc(mode11g->num_channels *
5126 sizeof(struct hostapd_channel_data));
5127 if (mode->channels == NULL) {
5128 (*num_modes)--;
5129 return modes; /* Could not add 802.11b mode */
5130 }
5131 os_memcpy(mode->channels, mode11g->channels,
5132 mode11g->num_channels * sizeof(struct hostapd_channel_data));
5133
5134 mode->num_rates = 0;
5135 mode->rates = os_malloc(4 * sizeof(int));
5136 if (mode->rates == NULL) {
5137 os_free(mode->channels);
5138 (*num_modes)--;
5139 return modes; /* Could not add 802.11b mode */
5140 }
5141
5142 for (i = 0; i < mode11g->num_rates; i++) {
5143 if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
5144 mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
5145 continue;
5146 mode->rates[mode->num_rates] = mode11g->rates[i];
5147 mode->num_rates++;
5148 if (mode->num_rates == 4)
5149 break;
5150 }
5151
5152 if (mode->num_rates == 0) {
5153 os_free(mode->channels);
5154 os_free(mode->rates);
5155 (*num_modes)--;
5156 return modes; /* No 802.11b rates */
5157 }
5158
5159 wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
5160 "information");
5161
5162 return modes;
5163}
5164
5165
5166static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
5167 int end)
5168{
5169 int c;
5170
5171 for (c = 0; c < mode->num_channels; c++) {
5172 struct hostapd_channel_data *chan = &mode->channels[c];
5173 if (chan->freq - 10 >= start && chan->freq + 10 <= end)
5174 chan->flag |= HOSTAPD_CHAN_HT40;
5175 }
5176}
5177
5178
5179static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
5180 int end)
5181{
5182 int c;
5183
5184 for (c = 0; c < mode->num_channels; c++) {
5185 struct hostapd_channel_data *chan = &mode->channels[c];
5186 if (!(chan->flag & HOSTAPD_CHAN_HT40))
5187 continue;
5188 if (chan->freq - 30 >= start && chan->freq - 10 <= end)
5189 chan->flag |= HOSTAPD_CHAN_HT40MINUS;
5190 if (chan->freq + 10 >= start && chan->freq + 30 <= end)
5191 chan->flag |= HOSTAPD_CHAN_HT40PLUS;
5192 }
5193}
5194
5195
5196static void nl80211_reg_rule_ht40(struct nlattr *tb[],
5197 struct phy_info_arg *results)
5198{
5199 u32 start, end, max_bw;
5200 u16 m;
5201
5202 if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
5203 tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
5204 tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
5205 return;
5206
5207 start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
5208 end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
5209 max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
5210
5211 wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
5212 start, end, max_bw);
5213 if (max_bw < 40)
5214 return;
5215
5216 for (m = 0; m < *results->num_modes; m++) {
5217 if (!(results->modes[m].ht_capab &
5218 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
5219 continue;
5220 nl80211_set_ht40_mode(&results->modes[m], start, end);
5221 }
5222}
5223
5224
5225static void nl80211_reg_rule_sec(struct nlattr *tb[],
5226 struct phy_info_arg *results)
5227{
5228 u32 start, end, max_bw;
5229 u16 m;
5230
5231 if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
5232 tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
5233 tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
5234 return;
5235
5236 start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
5237 end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
5238 max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
5239
5240 if (max_bw < 20)
5241 return;
5242
5243 for (m = 0; m < *results->num_modes; m++) {
5244 if (!(results->modes[m].ht_capab &
5245 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
5246 continue;
5247 nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
5248 }
5249}
5250
5251
5252static int nl80211_get_reg(struct nl_msg *msg, void *arg)
5253{
5254 struct phy_info_arg *results = arg;
5255 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
5256 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
5257 struct nlattr *nl_rule;
5258 struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
5259 int rem_rule;
5260 static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
5261 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
5262 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
5263 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
5264 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
5265 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
5266 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
5267 };
5268
5269 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
5270 genlmsg_attrlen(gnlh, 0), NULL);
5271 if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
5272 !tb_msg[NL80211_ATTR_REG_RULES]) {
5273 wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
5274 "available");
5275 return NL_SKIP;
5276 }
5277
5278 wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
5279 (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
5280
5281 nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
5282 {
5283 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
5284 nla_data(nl_rule), nla_len(nl_rule), reg_policy);
5285 nl80211_reg_rule_ht40(tb_rule, results);
5286 }
5287
5288 nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
5289 {
5290 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
5291 nla_data(nl_rule), nla_len(nl_rule), reg_policy);
5292 nl80211_reg_rule_sec(tb_rule, results);
5293 }
5294
5295 return NL_SKIP;
5296}
5297
5298
5299static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
5300 struct phy_info_arg *results)
5301{
5302 struct nl_msg *msg;
5303
5304 msg = nlmsg_alloc();
5305 if (!msg)
5306 return -ENOMEM;
5307
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005308 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005309 return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
5310}
5311
5312
5313static struct hostapd_hw_modes *
5314wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
5315{
5316 struct i802_bss *bss = priv;
5317 struct wpa_driver_nl80211_data *drv = bss->drv;
5318 struct nl_msg *msg;
5319 struct phy_info_arg result = {
5320 .num_modes = num_modes,
5321 .modes = NULL,
5322 };
5323
5324 *num_modes = 0;
5325 *flags = 0;
5326
5327 msg = nlmsg_alloc();
5328 if (!msg)
5329 return NULL;
5330
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005331 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005332
5333 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
5334
5335 if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
5336 nl80211_set_ht40_flags(drv, &result);
5337 return wpa_driver_nl80211_add_11b(result.modes, num_modes);
5338 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005339 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005340 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005341 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005342 return NULL;
5343}
5344
5345
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005346static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
5347 const void *data, size_t len,
5348 int encrypt, int noack)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005349{
5350 __u8 rtap_hdr[] = {
5351 0x00, 0x00, /* radiotap version */
5352 0x0e, 0x00, /* radiotap length */
5353 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
5354 IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
5355 0x00, /* padding */
5356 0x00, 0x00, /* RX and TX flags to indicate that */
5357 0x00, 0x00, /* this is the injected frame directly */
5358 };
5359 struct iovec iov[2] = {
5360 {
5361 .iov_base = &rtap_hdr,
5362 .iov_len = sizeof(rtap_hdr),
5363 },
5364 {
5365 .iov_base = (void *) data,
5366 .iov_len = len,
5367 }
5368 };
5369 struct msghdr msg = {
5370 .msg_name = NULL,
5371 .msg_namelen = 0,
5372 .msg_iov = iov,
5373 .msg_iovlen = 2,
5374 .msg_control = NULL,
5375 .msg_controllen = 0,
5376 .msg_flags = 0,
5377 };
5378 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005379 u16 txflags = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005380
5381 if (encrypt)
5382 rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
5383
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07005384 if (drv->monitor_sock < 0) {
5385 wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
5386 "for %s", __func__);
5387 return -1;
5388 }
5389
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005390 if (noack)
5391 txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005392 WPA_PUT_LE16(&rtap_hdr[12], txflags);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005393
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005394 res = sendmsg(drv->monitor_sock, &msg, 0);
5395 if (res < 0) {
5396 wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
5397 return -1;
5398 }
5399 return 0;
5400}
5401
5402
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005403static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
5404 const void *data, size_t len,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005405 int encrypt, int noack,
5406 unsigned int freq, int no_cck,
5407 int offchanok, unsigned int wait_time)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005408{
5409 struct wpa_driver_nl80211_data *drv = bss->drv;
5410 u64 cookie;
5411
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005412 if (freq == 0)
5413 freq = bss->freq;
5414
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005415 if (drv->use_monitor)
5416 return wpa_driver_nl80211_send_mntr(drv, data, len,
5417 encrypt, noack);
5418
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005419 return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
5420 &cookie, no_cck, noack, offchanok);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005421}
5422
5423
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005424static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
5425 const u8 *data,
5426 size_t data_len, int noack,
5427 unsigned int freq, int no_cck,
5428 int offchanok,
5429 unsigned int wait_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005430{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005431 struct wpa_driver_nl80211_data *drv = bss->drv;
5432 struct ieee80211_mgmt *mgmt;
5433 int encrypt = 1;
5434 u16 fc;
5435
5436 mgmt = (struct ieee80211_mgmt *) data;
5437 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005438
5439 if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005440 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
5441 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
5442 /*
5443 * The use of last_mgmt_freq is a bit of a hack,
5444 * but it works due to the single-threaded nature
5445 * of wpa_supplicant.
5446 */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005447 if (freq == 0)
5448 freq = drv->last_mgmt_freq;
5449 return nl80211_send_frame_cmd(bss, freq, 0,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005450 data, data_len, NULL, 1, noack,
5451 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005452 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005453
5454 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005455 if (freq == 0)
5456 freq = bss->freq;
Dmitry Shmidt04949592012-07-19 12:16:46 -07005457 return nl80211_send_frame_cmd(bss, freq,
5458 (int) freq == bss->freq ? 0 :
5459 wait_time,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005460 data, data_len,
5461 &drv->send_action_cookie,
5462 no_cck, noack, offchanok);
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07005463 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07005464
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005465 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
5466 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
5467 /*
5468 * Only one of the authentication frame types is encrypted.
5469 * In order for static WEP encryption to work properly (i.e.,
5470 * to not encrypt the frame), we need to tell mac80211 about
5471 * the frames that must not be encrypted.
5472 */
5473 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
5474 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
5475 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
5476 encrypt = 0;
5477 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005478
5479 return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005480 noack, freq, no_cck, offchanok,
5481 wait_time);
5482}
5483
5484
5485static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
5486 size_t data_len, int noack)
5487{
5488 struct i802_bss *bss = priv;
5489 return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
5490 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005491}
5492
5493
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005494static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
5495 int slot, int ht_opmode, int ap_isolate,
5496 int *basic_rates)
5497{
5498 struct wpa_driver_nl80211_data *drv = bss->drv;
5499 struct nl_msg *msg;
5500
5501 msg = nlmsg_alloc();
5502 if (!msg)
5503 return -ENOMEM;
5504
5505 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
5506
5507 if (cts >= 0)
5508 NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
5509 if (preamble >= 0)
5510 NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
5511 if (slot >= 0)
5512 NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
5513 if (ht_opmode >= 0)
5514 NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
5515 if (ap_isolate >= 0)
5516 NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
5517
5518 if (basic_rates) {
5519 u8 rates[NL80211_MAX_SUPP_RATES];
5520 u8 rates_len = 0;
5521 int i;
5522
5523 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
5524 i++)
5525 rates[rates_len++] = basic_rates[i] / 5;
5526
5527 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
5528 }
5529
5530 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
5531
5532 return send_and_recv_msgs(drv, msg, NULL, NULL);
5533 nla_put_failure:
5534 nlmsg_free(msg);
5535 return -ENOBUFS;
5536}
5537
5538
5539static int wpa_driver_nl80211_set_ap(void *priv,
5540 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005541{
5542 struct i802_bss *bss = priv;
5543 struct wpa_driver_nl80211_data *drv = bss->drv;
5544 struct nl_msg *msg;
5545 u8 cmd = NL80211_CMD_NEW_BEACON;
5546 int ret;
5547 int beacon_set;
5548 int ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005549 int num_suites;
5550 u32 suites[10];
5551 u32 ver;
5552
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07005553 beacon_set = bss->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005554
5555 msg = nlmsg_alloc();
5556 if (!msg)
5557 return -ENOMEM;
5558
5559 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
5560 beacon_set);
5561 if (beacon_set)
5562 cmd = NL80211_CMD_SET_BEACON;
5563
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005564 nl80211_cmd(drv, msg, 0, cmd);
5565 NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
5566 NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005567 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005568 NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
5569 NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
5570 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
5571 params->ssid);
5572 if (params->proberesp && params->proberesp_len)
5573 NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
5574 params->proberesp);
5575 switch (params->hide_ssid) {
5576 case NO_SSID_HIDING:
5577 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5578 NL80211_HIDDEN_SSID_NOT_IN_USE);
5579 break;
5580 case HIDDEN_SSID_ZERO_LEN:
5581 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5582 NL80211_HIDDEN_SSID_ZERO_LEN);
5583 break;
5584 case HIDDEN_SSID_ZERO_CONTENTS:
5585 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5586 NL80211_HIDDEN_SSID_ZERO_CONTENTS);
5587 break;
5588 }
5589 if (params->privacy)
5590 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
5591 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
5592 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
5593 /* Leave out the attribute */
5594 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
5595 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
5596 NL80211_AUTHTYPE_SHARED_KEY);
5597 else
5598 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
5599 NL80211_AUTHTYPE_OPEN_SYSTEM);
5600
5601 ver = 0;
5602 if (params->wpa_version & WPA_PROTO_WPA)
5603 ver |= NL80211_WPA_VERSION_1;
5604 if (params->wpa_version & WPA_PROTO_RSN)
5605 ver |= NL80211_WPA_VERSION_2;
5606 if (ver)
5607 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
5608
5609 num_suites = 0;
5610 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
5611 suites[num_suites++] = WLAN_AKM_SUITE_8021X;
5612 if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
5613 suites[num_suites++] = WLAN_AKM_SUITE_PSK;
5614 if (num_suites) {
5615 NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
5616 num_suites * sizeof(u32), suites);
5617 }
5618
5619 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
5620 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
5621 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
5622
5623 num_suites = 0;
5624 if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
5625 suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005626 if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
5627 suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005628 if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
5629 suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
5630 if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
5631 suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
5632 if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
5633 suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
5634 if (num_suites) {
5635 NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
5636 num_suites * sizeof(u32), suites);
5637 }
5638
5639 switch (params->group_cipher) {
5640 case WPA_CIPHER_CCMP:
5641 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5642 WLAN_CIPHER_SUITE_CCMP);
5643 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005644 case WPA_CIPHER_GCMP:
5645 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5646 WLAN_CIPHER_SUITE_GCMP);
5647 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005648 case WPA_CIPHER_TKIP:
5649 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5650 WLAN_CIPHER_SUITE_TKIP);
5651 break;
5652 case WPA_CIPHER_WEP104:
5653 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5654 WLAN_CIPHER_SUITE_WEP104);
5655 break;
5656 case WPA_CIPHER_WEP40:
5657 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5658 WLAN_CIPHER_SUITE_WEP40);
5659 break;
5660 }
5661
5662 if (params->beacon_ies) {
5663 NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
5664 wpabuf_head(params->beacon_ies));
5665 }
5666 if (params->proberesp_ies) {
5667 NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
5668 wpabuf_len(params->proberesp_ies),
5669 wpabuf_head(params->proberesp_ies));
5670 }
5671 if (params->assocresp_ies) {
5672 NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
5673 wpabuf_len(params->assocresp_ies),
5674 wpabuf_head(params->assocresp_ies));
5675 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005676
Dmitry Shmidt04949592012-07-19 12:16:46 -07005677 if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
5678 NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
5679 params->ap_max_inactivity);
5680 }
5681
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005682 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5683 if (ret) {
5684 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
5685 ret, strerror(-ret));
5686 } else {
5687 bss->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005688 nl80211_set_bss(bss, params->cts_protect, params->preamble,
5689 params->short_slot_time, params->ht_opmode,
5690 params->isolate, params->basic_rates);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005691 }
5692 return ret;
5693 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005694 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005695 return -ENOBUFS;
5696}
5697
5698
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005699static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005700 struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005701{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005702 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005703 struct nl_msg *msg;
5704 int ret;
5705
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005706 wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
5707 " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
5708 freq->freq, freq->ht_enabled, freq->vht_enabled,
5709 freq->bandwidth, freq->center_freq1, freq->center_freq2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005710 msg = nlmsg_alloc();
5711 if (!msg)
5712 return -1;
5713
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005714 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005715
5716 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005717 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
5718 if (freq->vht_enabled) {
5719 switch (freq->bandwidth) {
5720 case 20:
5721 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5722 NL80211_CHAN_WIDTH_20);
5723 break;
5724 case 40:
5725 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5726 NL80211_CHAN_WIDTH_40);
5727 break;
5728 case 80:
5729 if (freq->center_freq2)
5730 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5731 NL80211_CHAN_WIDTH_80P80);
5732 else
5733 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5734 NL80211_CHAN_WIDTH_80);
5735 break;
5736 case 160:
5737 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
5738 NL80211_CHAN_WIDTH_160);
5739 break;
5740 default:
5741 return -1;
5742 }
5743 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
5744 if (freq->center_freq2)
5745 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
5746 freq->center_freq2);
5747 } else if (freq->ht_enabled) {
5748 switch (freq->sec_channel_offset) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005749 case -1:
5750 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5751 NL80211_CHAN_HT40MINUS);
5752 break;
5753 case 1:
5754 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5755 NL80211_CHAN_HT40PLUS);
5756 break;
5757 default:
5758 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5759 NL80211_CHAN_HT20);
5760 break;
5761 }
5762 }
5763
5764 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005765 msg = NULL;
5766 if (ret == 0) {
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005767 bss->freq = freq->freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005768 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005769 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005770 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005771 "%d (%s)", freq->freq, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005772nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005773 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005774 return -1;
5775}
5776
5777
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005778static u32 sta_flags_nl80211(int flags)
5779{
5780 u32 f = 0;
5781
5782 if (flags & WPA_STA_AUTHORIZED)
5783 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
5784 if (flags & WPA_STA_WMM)
5785 f |= BIT(NL80211_STA_FLAG_WME);
5786 if (flags & WPA_STA_SHORT_PREAMBLE)
5787 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
5788 if (flags & WPA_STA_MFP)
5789 f |= BIT(NL80211_STA_FLAG_MFP);
5790 if (flags & WPA_STA_TDLS_PEER)
5791 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
5792
5793 return f;
5794}
5795
5796
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005797static int wpa_driver_nl80211_sta_add(void *priv,
5798 struct hostapd_sta_add_params *params)
5799{
5800 struct i802_bss *bss = priv;
5801 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005802 struct nl_msg *msg, *wme = NULL;
5803 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005804 int ret = -ENOBUFS;
5805
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005806 if ((params->flags & WPA_STA_TDLS_PEER) &&
5807 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
5808 return -EOPNOTSUPP;
5809
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005810 msg = nlmsg_alloc();
5811 if (!msg)
5812 return -ENOMEM;
5813
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005814 nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
5815 NL80211_CMD_NEW_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005816
5817 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
5818 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005819 NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
5820 params->supp_rates);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005821 if (!params->set) {
5822 NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
5823 NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5824 params->listen_interval);
5825 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005826 if (params->ht_capabilities) {
5827 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
5828 sizeof(*params->ht_capabilities),
5829 params->ht_capabilities);
5830 }
5831
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005832 if (params->vht_capabilities) {
5833 NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
5834 sizeof(*params->vht_capabilities),
5835 params->vht_capabilities);
5836 }
5837
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005838 os_memset(&upd, 0, sizeof(upd));
5839 upd.mask = sta_flags_nl80211(params->flags);
5840 upd.set = upd.mask;
5841 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
5842
5843 if (params->flags & WPA_STA_WMM) {
5844 wme = nlmsg_alloc();
5845 if (!wme)
5846 goto nla_put_failure;
5847
5848 NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
5849 params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
5850 NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
5851 (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
5852 WMM_QOSINFO_STA_SP_MASK);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005853 if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
5854 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005855 }
5856
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005857 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005858 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005859 if (ret)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005860 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
5861 "result: %d (%s)", params->set ? "SET" : "NEW", ret,
5862 strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005863 if (ret == -EEXIST)
5864 ret = 0;
5865 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005866 nlmsg_free(wme);
5867 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005868 return ret;
5869}
5870
5871
5872static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
5873{
5874 struct i802_bss *bss = priv;
5875 struct wpa_driver_nl80211_data *drv = bss->drv;
5876 struct nl_msg *msg;
5877 int ret;
5878
5879 msg = nlmsg_alloc();
5880 if (!msg)
5881 return -ENOMEM;
5882
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005883 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005884
5885 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
5886 if_nametoindex(bss->ifname));
5887 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
5888
5889 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5890 if (ret == -ENOENT)
5891 return 0;
5892 return ret;
5893 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005894 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005895 return -ENOBUFS;
5896}
5897
5898
5899static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
5900 int ifidx)
5901{
5902 struct nl_msg *msg;
5903
5904 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
5905
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005906 /* stop listening for EAPOL on this interface */
5907 del_ifidx(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005908
5909 msg = nlmsg_alloc();
5910 if (!msg)
5911 goto nla_put_failure;
5912
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005913 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005914 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
5915
5916 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
5917 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005918 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005919 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005920 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005921 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
5922}
5923
5924
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005925static const char * nl80211_iftype_str(enum nl80211_iftype mode)
5926{
5927 switch (mode) {
5928 case NL80211_IFTYPE_ADHOC:
5929 return "ADHOC";
5930 case NL80211_IFTYPE_STATION:
5931 return "STATION";
5932 case NL80211_IFTYPE_AP:
5933 return "AP";
5934 case NL80211_IFTYPE_MONITOR:
5935 return "MONITOR";
5936 case NL80211_IFTYPE_P2P_CLIENT:
5937 return "P2P_CLIENT";
5938 case NL80211_IFTYPE_P2P_GO:
5939 return "P2P_GO";
5940 default:
5941 return "unknown";
5942 }
5943}
5944
5945
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005946static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
5947 const char *ifname,
5948 enum nl80211_iftype iftype,
5949 const u8 *addr, int wds)
5950{
5951 struct nl_msg *msg, *flags = NULL;
5952 int ifidx;
5953 int ret = -ENOBUFS;
5954
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005955 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
5956 iftype, nl80211_iftype_str(iftype));
5957
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005958 msg = nlmsg_alloc();
5959 if (!msg)
5960 return -1;
5961
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005962 nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005963 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
5964 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
5965 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
5966
5967 if (iftype == NL80211_IFTYPE_MONITOR) {
5968 int err;
5969
5970 flags = nlmsg_alloc();
5971 if (!flags)
5972 goto nla_put_failure;
5973
5974 NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
5975
5976 err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
5977
5978 nlmsg_free(flags);
5979
5980 if (err)
5981 goto nla_put_failure;
5982 } else if (wds) {
5983 NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
5984 }
5985
5986 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005987 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005988 if (ret) {
5989 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005990 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005991 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
5992 ifname, ret, strerror(-ret));
5993 return ret;
5994 }
5995
5996 ifidx = if_nametoindex(ifname);
5997 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
5998 ifname, ifidx);
5999
6000 if (ifidx <= 0)
6001 return -1;
6002
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006003 /* start listening for EAPOL on this interface */
6004 add_ifidx(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006005
6006 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006007 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006008 nl80211_remove_iface(drv, ifidx);
6009 return -1;
6010 }
6011
6012 return ifidx;
6013}
6014
6015
6016static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
6017 const char *ifname, enum nl80211_iftype iftype,
6018 const u8 *addr, int wds)
6019{
6020 int ret;
6021
6022 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
6023
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006024 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006025 if (ret == -ENFILE && if_nametoindex(ifname)) {
6026 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
6027
6028 /* Try to remove the interface that was already there. */
6029 nl80211_remove_iface(drv, if_nametoindex(ifname));
6030
6031 /* Try to create the interface again */
6032 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
6033 wds);
6034 }
6035
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006036 if (ret >= 0 && is_p2p_interface(iftype))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006037 nl80211_disable_11b_rates(drv, ret, 1);
6038
6039 return ret;
6040}
6041
6042
6043static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
6044{
6045 struct ieee80211_hdr *hdr;
6046 u16 fc;
6047 union wpa_event_data event;
6048
6049 hdr = (struct ieee80211_hdr *) buf;
6050 fc = le_to_host16(hdr->frame_control);
6051
6052 os_memset(&event, 0, sizeof(event));
6053 event.tx_status.type = WLAN_FC_GET_TYPE(fc);
6054 event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
6055 event.tx_status.dst = hdr->addr1;
6056 event.tx_status.data = buf;
6057 event.tx_status.data_len = len;
6058 event.tx_status.ack = ok;
6059 wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
6060}
6061
6062
6063static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
6064 u8 *buf, size_t len)
6065{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006066 struct ieee80211_hdr *hdr = (void *)buf;
6067 u16 fc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006068 union wpa_event_data event;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006069
6070 if (len < sizeof(*hdr))
6071 return;
6072
6073 fc = le_to_host16(hdr->frame_control);
6074
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006075 os_memset(&event, 0, sizeof(event));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006076 event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
6077 event.rx_from_unknown.addr = hdr->addr2;
6078 event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
6079 (WLAN_FC_FROMDS | WLAN_FC_TODS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006080 wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
6081}
6082
6083
6084static void handle_frame(struct wpa_driver_nl80211_data *drv,
6085 u8 *buf, size_t len, int datarate, int ssi_signal)
6086{
6087 struct ieee80211_hdr *hdr;
6088 u16 fc;
6089 union wpa_event_data event;
6090
6091 hdr = (struct ieee80211_hdr *) buf;
6092 fc = le_to_host16(hdr->frame_control);
6093
6094 switch (WLAN_FC_GET_TYPE(fc)) {
6095 case WLAN_FC_TYPE_MGMT:
6096 os_memset(&event, 0, sizeof(event));
6097 event.rx_mgmt.frame = buf;
6098 event.rx_mgmt.frame_len = len;
6099 event.rx_mgmt.datarate = datarate;
6100 event.rx_mgmt.ssi_signal = ssi_signal;
6101 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
6102 break;
6103 case WLAN_FC_TYPE_CTRL:
6104 /* can only get here with PS-Poll frames */
6105 wpa_printf(MSG_DEBUG, "CTRL");
6106 from_unknown_sta(drv, buf, len);
6107 break;
6108 case WLAN_FC_TYPE_DATA:
6109 from_unknown_sta(drv, buf, len);
6110 break;
6111 }
6112}
6113
6114
6115static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
6116{
6117 struct wpa_driver_nl80211_data *drv = eloop_ctx;
6118 int len;
6119 unsigned char buf[3000];
6120 struct ieee80211_radiotap_iterator iter;
6121 int ret;
6122 int datarate = 0, ssi_signal = 0;
6123 int injected = 0, failed = 0, rxflags = 0;
6124
6125 len = recv(sock, buf, sizeof(buf), 0);
6126 if (len < 0) {
6127 perror("recv");
6128 return;
6129 }
6130
6131 if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
6132 printf("received invalid radiotap frame\n");
6133 return;
6134 }
6135
6136 while (1) {
6137 ret = ieee80211_radiotap_iterator_next(&iter);
6138 if (ret == -ENOENT)
6139 break;
6140 if (ret) {
6141 printf("received invalid radiotap frame (%d)\n", ret);
6142 return;
6143 }
6144 switch (iter.this_arg_index) {
6145 case IEEE80211_RADIOTAP_FLAGS:
6146 if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
6147 len -= 4;
6148 break;
6149 case IEEE80211_RADIOTAP_RX_FLAGS:
6150 rxflags = 1;
6151 break;
6152 case IEEE80211_RADIOTAP_TX_FLAGS:
6153 injected = 1;
6154 failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
6155 IEEE80211_RADIOTAP_F_TX_FAIL;
6156 break;
6157 case IEEE80211_RADIOTAP_DATA_RETRIES:
6158 break;
6159 case IEEE80211_RADIOTAP_CHANNEL:
6160 /* TODO: convert from freq/flags to channel number */
6161 break;
6162 case IEEE80211_RADIOTAP_RATE:
6163 datarate = *iter.this_arg * 5;
6164 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006165 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
6166 ssi_signal = (s8) *iter.this_arg;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006167 break;
6168 }
6169 }
6170
6171 if (rxflags && injected)
6172 return;
6173
6174 if (!injected)
6175 handle_frame(drv, buf + iter.max_length,
6176 len - iter.max_length, datarate, ssi_signal);
6177 else
6178 handle_tx_callback(drv->ctx, buf + iter.max_length,
6179 len - iter.max_length, !failed);
6180}
6181
6182
6183/*
6184 * we post-process the filter code later and rewrite
6185 * this to the offset to the last instruction
6186 */
6187#define PASS 0xFF
6188#define FAIL 0xFE
6189
6190static struct sock_filter msock_filter_insns[] = {
6191 /*
6192 * do a little-endian load of the radiotap length field
6193 */
6194 /* load lower byte into A */
6195 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
6196 /* put it into X (== index register) */
6197 BPF_STMT(BPF_MISC| BPF_TAX, 0),
6198 /* load upper byte into A */
6199 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
6200 /* left-shift it by 8 */
6201 BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
6202 /* or with X */
6203 BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
6204 /* put result into X */
6205 BPF_STMT(BPF_MISC| BPF_TAX, 0),
6206
6207 /*
6208 * Allow management frames through, this also gives us those
6209 * management frames that we sent ourselves with status
6210 */
6211 /* load the lower byte of the IEEE 802.11 frame control field */
6212 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
6213 /* mask off frame type and version */
6214 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
6215 /* accept frame if it's both 0, fall through otherwise */
6216 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
6217
6218 /*
6219 * TODO: add a bit to radiotap RX flags that indicates
6220 * that the sending station is not associated, then
6221 * add a filter here that filters on our DA and that flag
6222 * to allow us to deauth frames to that bad station.
6223 *
6224 * For now allow all To DS data frames through.
6225 */
6226 /* load the IEEE 802.11 frame control field */
6227 BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
6228 /* mask off frame type, version and DS status */
6229 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
6230 /* accept frame if version 0, type 2 and To DS, fall through otherwise
6231 */
6232 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
6233
6234#if 0
6235 /*
6236 * drop non-data frames
6237 */
6238 /* load the lower byte of the frame control field */
6239 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
6240 /* mask off QoS bit */
6241 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
6242 /* drop non-data frames */
6243 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
6244#endif
6245 /* load the upper byte of the frame control field */
6246 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
6247 /* mask off toDS/fromDS */
6248 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
6249 /* accept WDS frames */
6250 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
6251
6252 /*
6253 * add header length to index
6254 */
6255 /* load the lower byte of the frame control field */
6256 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
6257 /* mask off QoS bit */
6258 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
6259 /* right shift it by 6 to give 0 or 2 */
6260 BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
6261 /* add data frame header length */
6262 BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
6263 /* add index, was start of 802.11 header */
6264 BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
6265 /* move to index, now start of LL header */
6266 BPF_STMT(BPF_MISC | BPF_TAX, 0),
6267
6268 /*
6269 * Accept empty data frames, we use those for
6270 * polling activity.
6271 */
6272 BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
6273 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
6274
6275 /*
6276 * Accept EAPOL frames
6277 */
6278 BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
6279 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
6280 BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
6281 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
6282
6283 /* keep these last two statements or change the code below */
6284 /* return 0 == "DROP" */
6285 BPF_STMT(BPF_RET | BPF_K, 0),
6286 /* return ~0 == "keep all" */
6287 BPF_STMT(BPF_RET | BPF_K, ~0),
6288};
6289
6290static struct sock_fprog msock_filter = {
6291 .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
6292 .filter = msock_filter_insns,
6293};
6294
6295
6296static int add_monitor_filter(int s)
6297{
6298 int idx;
6299
6300 /* rewrite all PASS/FAIL jump offsets */
6301 for (idx = 0; idx < msock_filter.len; idx++) {
6302 struct sock_filter *insn = &msock_filter_insns[idx];
6303
6304 if (BPF_CLASS(insn->code) == BPF_JMP) {
6305 if (insn->code == (BPF_JMP|BPF_JA)) {
6306 if (insn->k == PASS)
6307 insn->k = msock_filter.len - idx - 2;
6308 else if (insn->k == FAIL)
6309 insn->k = msock_filter.len - idx - 3;
6310 }
6311
6312 if (insn->jt == PASS)
6313 insn->jt = msock_filter.len - idx - 2;
6314 else if (insn->jt == FAIL)
6315 insn->jt = msock_filter.len - idx - 3;
6316
6317 if (insn->jf == PASS)
6318 insn->jf = msock_filter.len - idx - 2;
6319 else if (insn->jf == FAIL)
6320 insn->jf = msock_filter.len - idx - 3;
6321 }
6322 }
6323
6324 if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
6325 &msock_filter, sizeof(msock_filter))) {
6326 perror("SO_ATTACH_FILTER");
6327 return -1;
6328 }
6329
6330 return 0;
6331}
6332
6333
6334static void nl80211_remove_monitor_interface(
6335 struct wpa_driver_nl80211_data *drv)
6336{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006337 drv->monitor_refcount--;
6338 if (drv->monitor_refcount > 0)
6339 return;
6340
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006341 if (drv->monitor_ifidx >= 0) {
6342 nl80211_remove_iface(drv, drv->monitor_ifidx);
6343 drv->monitor_ifidx = -1;
6344 }
6345 if (drv->monitor_sock >= 0) {
6346 eloop_unregister_read_sock(drv->monitor_sock);
6347 close(drv->monitor_sock);
6348 drv->monitor_sock = -1;
6349 }
6350}
6351
6352
6353static int
6354nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
6355{
6356 char buf[IFNAMSIZ];
6357 struct sockaddr_ll ll;
6358 int optval;
6359 socklen_t optlen;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006360
6361 if (drv->monitor_ifidx >= 0) {
6362 drv->monitor_refcount++;
6363 return 0;
6364 }
6365
6366 if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
6367 /*
6368 * P2P interface name is of the format p2p-%s-%d. For monitor
6369 * interface name corresponding to P2P GO, replace "p2p-" with
6370 * "mon-" to retain the same interface name length and to
6371 * indicate that it is a monitor interface.
6372 */
6373 snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
6374 } else {
6375 /* Non-P2P interface with AP functionality. */
6376 snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
6377 }
6378
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006379 buf[IFNAMSIZ - 1] = '\0';
6380
6381 drv->monitor_ifidx =
6382 nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
6383 0);
6384
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006385 if (drv->monitor_ifidx == -EOPNOTSUPP) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006386 /*
6387 * This is backward compatibility for a few versions of
6388 * the kernel only that didn't advertise the right
6389 * attributes for the only driver that then supported
6390 * AP mode w/o monitor -- ath6kl.
6391 */
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006392 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
6393 "monitor interface type - try to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006394 drv->device_ap_sme = 1;
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006395 }
6396
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006397 if (drv->monitor_ifidx < 0)
6398 return -1;
6399
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006400 if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006401 goto error;
6402
6403 memset(&ll, 0, sizeof(ll));
6404 ll.sll_family = AF_PACKET;
6405 ll.sll_ifindex = drv->monitor_ifidx;
6406 drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
6407 if (drv->monitor_sock < 0) {
6408 perror("socket[PF_PACKET,SOCK_RAW]");
6409 goto error;
6410 }
6411
6412 if (add_monitor_filter(drv->monitor_sock)) {
6413 wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
6414 "interface; do filtering in user space");
6415 /* This works, but will cost in performance. */
6416 }
6417
6418 if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
6419 perror("monitor socket bind");
6420 goto error;
6421 }
6422
6423 optlen = sizeof(optval);
6424 optval = 20;
6425 if (setsockopt
6426 (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
6427 perror("Failed to set socket priority");
6428 goto error;
6429 }
6430
6431 if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
6432 drv, NULL)) {
6433 printf("Could not register monitor read socket\n");
6434 goto error;
6435 }
6436
6437 return 0;
6438 error:
6439 nl80211_remove_monitor_interface(drv);
6440 return -1;
6441}
6442
6443
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006444static int nl80211_setup_ap(struct i802_bss *bss)
6445{
6446 struct wpa_driver_nl80211_data *drv = bss->drv;
6447
6448 wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
6449 "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
6450
6451 /*
6452 * Disable Probe Request reporting unless we need it in this way for
6453 * devices that include the AP SME, in the other case (unless using
6454 * monitor iface) we'll get it through the nl_mgmt socket instead.
6455 */
6456 if (!drv->device_ap_sme)
6457 wpa_driver_nl80211_probe_req_report(bss, 0);
6458
6459 if (!drv->device_ap_sme && !drv->use_monitor)
6460 if (nl80211_mgmt_subscribe_ap(bss))
6461 return -1;
6462
6463 if (drv->device_ap_sme && !drv->use_monitor)
6464 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
6465 return -1;
6466
6467 if (!drv->device_ap_sme && drv->use_monitor &&
6468 nl80211_create_monitor_interface(drv) &&
6469 !drv->device_ap_sme)
Dmitry Shmidt04949592012-07-19 12:16:46 -07006470 return -1;
6471
6472#ifdef ANDROID_P2P
6473 if (drv->device_ap_sme && drv->use_monitor)
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006474 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
6475 return -1;
6476
6477 if (drv->use_monitor &&
6478 nl80211_create_monitor_interface(drv))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006479 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07006480#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006481
6482 if (drv->device_ap_sme &&
6483 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
6484 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
6485 "Probe Request frame reporting in AP mode");
6486 /* Try to survive without this */
6487 }
6488
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006489 return 0;
6490}
6491
6492
6493static void nl80211_teardown_ap(struct i802_bss *bss)
6494{
6495 struct wpa_driver_nl80211_data *drv = bss->drv;
6496
6497 if (drv->device_ap_sme) {
6498 wpa_driver_nl80211_probe_req_report(bss, 0);
6499 if (!drv->use_monitor)
6500 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
6501 } else if (drv->use_monitor)
6502 nl80211_remove_monitor_interface(drv);
6503 else
6504 nl80211_mgmt_unsubscribe(bss, "AP teardown");
6505
6506 bss->beacon_set = 0;
6507}
6508
6509
6510static int nl80211_send_eapol_data(struct i802_bss *bss,
6511 const u8 *addr, const u8 *data,
6512 size_t data_len)
6513{
6514 struct sockaddr_ll ll;
6515 int ret;
6516
6517 if (bss->drv->eapol_tx_sock < 0) {
6518 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
6519 return -1;
6520 }
6521
6522 os_memset(&ll, 0, sizeof(ll));
6523 ll.sll_family = AF_PACKET;
6524 ll.sll_ifindex = bss->ifindex;
6525 ll.sll_protocol = htons(ETH_P_PAE);
6526 ll.sll_halen = ETH_ALEN;
6527 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
6528 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
6529 (struct sockaddr *) &ll, sizeof(ll));
6530 if (ret < 0)
6531 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
6532 strerror(errno));
6533
6534 return ret;
6535}
6536
6537
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006538static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
6539
6540static int wpa_driver_nl80211_hapd_send_eapol(
6541 void *priv, const u8 *addr, const u8 *data,
6542 size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
6543{
6544 struct i802_bss *bss = priv;
6545 struct wpa_driver_nl80211_data *drv = bss->drv;
6546 struct ieee80211_hdr *hdr;
6547 size_t len;
6548 u8 *pos;
6549 int res;
6550 int qos = flags & WPA_STA_WMM;
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006551#ifndef ANDROID_P2P
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006552 if (drv->device_ap_sme || !drv->use_monitor)
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006553#else
6554 if (drv->device_ap_sme && !drv->use_monitor)
6555#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006556 return nl80211_send_eapol_data(bss, addr, data, data_len);
6557
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006558 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
6559 data_len;
6560 hdr = os_zalloc(len);
6561 if (hdr == NULL) {
6562 printf("malloc() failed for i802_send_data(len=%lu)\n",
6563 (unsigned long) len);
6564 return -1;
6565 }
6566
6567 hdr->frame_control =
6568 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
6569 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
6570 if (encrypt)
6571 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
6572 if (qos) {
6573 hdr->frame_control |=
6574 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
6575 }
6576
6577 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
6578 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
6579 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
6580 pos = (u8 *) (hdr + 1);
6581
6582 if (qos) {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07006583 /* Set highest priority in QoS header */
6584 pos[0] = 7;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006585 pos[1] = 0;
6586 pos += 2;
6587 }
6588
6589 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
6590 pos += sizeof(rfc1042_header);
6591 WPA_PUT_BE16(pos, ETH_P_PAE);
6592 pos += 2;
6593 memcpy(pos, data, data_len);
6594
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006595 res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
6596 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006597 if (res < 0) {
6598 wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
6599 "failed: %d (%s)",
6600 (unsigned long) len, errno, strerror(errno));
6601 }
6602 os_free(hdr);
6603
6604 return res;
6605}
6606
6607
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006608static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
6609 int total_flags,
6610 int flags_or, int flags_and)
6611{
6612 struct i802_bss *bss = priv;
6613 struct wpa_driver_nl80211_data *drv = bss->drv;
6614 struct nl_msg *msg, *flags = NULL;
6615 struct nl80211_sta_flag_update upd;
6616
6617 msg = nlmsg_alloc();
6618 if (!msg)
6619 return -ENOMEM;
6620
6621 flags = nlmsg_alloc();
6622 if (!flags) {
6623 nlmsg_free(msg);
6624 return -ENOMEM;
6625 }
6626
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006627 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006628
6629 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
6630 if_nametoindex(bss->ifname));
6631 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
6632
6633 /*
6634 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
6635 * can be removed eventually.
6636 */
6637 if (total_flags & WPA_STA_AUTHORIZED)
6638 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
6639
6640 if (total_flags & WPA_STA_WMM)
6641 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
6642
6643 if (total_flags & WPA_STA_SHORT_PREAMBLE)
6644 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
6645
6646 if (total_flags & WPA_STA_MFP)
6647 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
6648
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006649 if (total_flags & WPA_STA_TDLS_PEER)
6650 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
6651
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006652 if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
6653 goto nla_put_failure;
6654
6655 os_memset(&upd, 0, sizeof(upd));
6656 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
6657 upd.set = sta_flags_nl80211(flags_or);
6658 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
6659
6660 nlmsg_free(flags);
6661
6662 return send_and_recv_msgs(drv, msg, NULL, NULL);
6663 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006664 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006665 nlmsg_free(flags);
6666 return -ENOBUFS;
6667}
6668
6669
6670static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
6671 struct wpa_driver_associate_params *params)
6672{
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006673 enum nl80211_iftype nlmode, old_mode;
6674 struct hostapd_freq_params freq = {
6675 .freq = params->freq,
6676 };
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006677
6678 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006679 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
6680 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006681 nlmode = NL80211_IFTYPE_P2P_GO;
6682 } else
6683 nlmode = NL80211_IFTYPE_AP;
6684
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006685 old_mode = drv->nlmode;
6686 if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
6687 nl80211_remove_monitor_interface(drv);
6688 return -1;
6689 }
6690
6691 if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
6692 if (old_mode != nlmode)
6693 wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006694 nl80211_remove_monitor_interface(drv);
6695 return -1;
6696 }
6697
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006698 return 0;
6699}
6700
6701
6702static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
6703{
6704 struct nl_msg *msg;
6705 int ret = -1;
6706
6707 msg = nlmsg_alloc();
6708 if (!msg)
6709 return -1;
6710
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006711 nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006712 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6713 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6714 msg = NULL;
6715 if (ret) {
6716 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
6717 "(%s)", ret, strerror(-ret));
6718 goto nla_put_failure;
6719 }
6720
6721 ret = 0;
6722 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
6723
6724nla_put_failure:
6725 nlmsg_free(msg);
6726 return ret;
6727}
6728
6729
6730static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
6731 struct wpa_driver_associate_params *params)
6732{
6733 struct nl_msg *msg;
6734 int ret = -1;
6735 int count = 0;
6736
6737 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
6738
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006739 if (wpa_driver_nl80211_set_mode(&drv->first_bss,
6740 NL80211_IFTYPE_ADHOC)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006741 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6742 "IBSS mode");
6743 return -1;
6744 }
6745
6746retry:
6747 msg = nlmsg_alloc();
6748 if (!msg)
6749 return -1;
6750
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006751 nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006752 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6753
6754 if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
6755 goto nla_put_failure;
6756
6757 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
6758 params->ssid, params->ssid_len);
6759 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
6760 params->ssid);
6761 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6762 drv->ssid_len = params->ssid_len;
6763
6764 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
6765 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
6766
6767 ret = nl80211_set_conn_keys(params, msg);
6768 if (ret)
6769 goto nla_put_failure;
6770
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006771 if (params->bssid && params->fixed_bssid) {
6772 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
6773 MAC2STR(params->bssid));
6774 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
6775 }
6776
6777 if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
6778 params->key_mgmt_suite == KEY_MGMT_PSK ||
6779 params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 ||
6780 params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) {
6781 wpa_printf(MSG_DEBUG, " * control port");
6782 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
6783 }
6784
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006785 if (params->wpa_ie) {
6786 wpa_hexdump(MSG_DEBUG,
6787 " * Extra IEs for Beacon/Probe Response frames",
6788 params->wpa_ie, params->wpa_ie_len);
6789 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6790 params->wpa_ie);
6791 }
6792
6793 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6794 msg = NULL;
6795 if (ret) {
6796 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
6797 ret, strerror(-ret));
6798 count++;
6799 if (ret == -EALREADY && count == 1) {
6800 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
6801 "forced leave");
6802 nl80211_leave_ibss(drv);
6803 nlmsg_free(msg);
6804 goto retry;
6805 }
6806
6807 goto nla_put_failure;
6808 }
6809 ret = 0;
6810 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
6811
6812nla_put_failure:
6813 nlmsg_free(msg);
6814 return ret;
6815}
6816
6817
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006818static int wpa_driver_nl80211_try_connect(
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006819 struct wpa_driver_nl80211_data *drv,
6820 struct wpa_driver_associate_params *params)
6821{
6822 struct nl_msg *msg;
6823 enum nl80211_auth_type type;
6824 int ret = 0;
6825 int algs;
6826
6827 msg = nlmsg_alloc();
6828 if (!msg)
6829 return -1;
6830
6831 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006832 nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006833
6834 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6835 if (params->bssid) {
6836 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6837 MAC2STR(params->bssid));
6838 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
6839 }
6840 if (params->freq) {
6841 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
6842 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
6843 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07006844 if (params->bg_scan_period >= 0) {
6845 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
6846 params->bg_scan_period);
6847 NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
6848 params->bg_scan_period);
6849 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006850 if (params->ssid) {
6851 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
6852 params->ssid, params->ssid_len);
6853 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
6854 params->ssid);
6855 if (params->ssid_len > sizeof(drv->ssid))
6856 goto nla_put_failure;
6857 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6858 drv->ssid_len = params->ssid_len;
6859 }
6860 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
6861 if (params->wpa_ie)
6862 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6863 params->wpa_ie);
6864
6865 algs = 0;
6866 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6867 algs++;
6868 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6869 algs++;
6870 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6871 algs++;
6872 if (algs > 1) {
6873 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
6874 "selection");
6875 goto skip_auth_type;
6876 }
6877
6878 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6879 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
6880 else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6881 type = NL80211_AUTHTYPE_SHARED_KEY;
6882 else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6883 type = NL80211_AUTHTYPE_NETWORK_EAP;
6884 else if (params->auth_alg & WPA_AUTH_ALG_FT)
6885 type = NL80211_AUTHTYPE_FT;
6886 else
6887 goto nla_put_failure;
6888
6889 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
6890 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
6891
6892skip_auth_type:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006893 if (params->wpa_proto) {
6894 enum nl80211_wpa_versions ver = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006895
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006896 if (params->wpa_proto & WPA_PROTO_WPA)
6897 ver |= NL80211_WPA_VERSION_1;
6898 if (params->wpa_proto & WPA_PROTO_RSN)
6899 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006900
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006901 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006902 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
6903 }
6904
6905 if (params->pairwise_suite != CIPHER_NONE) {
6906 int cipher;
6907
6908 switch (params->pairwise_suite) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006909 case CIPHER_SMS4:
6910 cipher = WLAN_CIPHER_SUITE_SMS4;
6911 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006912 case CIPHER_WEP40:
6913 cipher = WLAN_CIPHER_SUITE_WEP40;
6914 break;
6915 case CIPHER_WEP104:
6916 cipher = WLAN_CIPHER_SUITE_WEP104;
6917 break;
6918 case CIPHER_CCMP:
6919 cipher = WLAN_CIPHER_SUITE_CCMP;
6920 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006921 case CIPHER_GCMP:
6922 cipher = WLAN_CIPHER_SUITE_GCMP;
6923 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006924 case CIPHER_TKIP:
6925 default:
6926 cipher = WLAN_CIPHER_SUITE_TKIP;
6927 break;
6928 }
6929 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
6930 }
6931
6932 if (params->group_suite != CIPHER_NONE) {
6933 int cipher;
6934
6935 switch (params->group_suite) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006936 case CIPHER_SMS4:
6937 cipher = WLAN_CIPHER_SUITE_SMS4;
6938 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006939 case CIPHER_WEP40:
6940 cipher = WLAN_CIPHER_SUITE_WEP40;
6941 break;
6942 case CIPHER_WEP104:
6943 cipher = WLAN_CIPHER_SUITE_WEP104;
6944 break;
6945 case CIPHER_CCMP:
6946 cipher = WLAN_CIPHER_SUITE_CCMP;
6947 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006948 case CIPHER_GCMP:
6949 cipher = WLAN_CIPHER_SUITE_GCMP;
6950 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006951 case CIPHER_TKIP:
6952 default:
6953 cipher = WLAN_CIPHER_SUITE_TKIP;
6954 break;
6955 }
6956 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
6957 }
6958
6959 if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006960 params->key_mgmt_suite == KEY_MGMT_PSK ||
6961 params->key_mgmt_suite == KEY_MGMT_CCKM) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006962 int mgmt = WLAN_AKM_SUITE_PSK;
6963
6964 switch (params->key_mgmt_suite) {
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08006965 case KEY_MGMT_CCKM:
6966 mgmt = WLAN_AKM_SUITE_CCKM;
6967 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006968 case KEY_MGMT_802_1X:
6969 mgmt = WLAN_AKM_SUITE_8021X;
6970 break;
6971 case KEY_MGMT_PSK:
6972 default:
6973 mgmt = WLAN_AKM_SUITE_PSK;
6974 break;
6975 }
6976 NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
6977 }
6978
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08006979#ifdef CONFIG_IEEE80211W
6980 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
6981 NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
6982#endif /* CONFIG_IEEE80211W */
6983
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006984 if (params->disable_ht)
6985 NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
6986
6987 if (params->htcaps && params->htcaps_mask) {
6988 int sz = sizeof(struct ieee80211_ht_capabilities);
6989 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
6990 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
6991 params->htcaps_mask);
6992 }
6993
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006994 ret = nl80211_set_conn_keys(params, msg);
6995 if (ret)
6996 goto nla_put_failure;
6997
6998 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6999 msg = NULL;
7000 if (ret) {
7001 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
7002 "(%s)", ret, strerror(-ret));
7003 goto nla_put_failure;
7004 }
7005 ret = 0;
7006 wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
7007
7008nla_put_failure:
7009 nlmsg_free(msg);
7010 return ret;
7011
7012}
7013
7014
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08007015static int wpa_driver_nl80211_connect(
7016 struct wpa_driver_nl80211_data *drv,
7017 struct wpa_driver_associate_params *params)
7018{
7019 int ret = wpa_driver_nl80211_try_connect(drv, params);
7020 if (ret == -EALREADY) {
7021 /*
7022 * cfg80211 does not currently accept new connections if
7023 * we are already connected. As a workaround, force
7024 * disconnection and try again.
7025 */
7026 wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
7027 "disconnecting before reassociation "
7028 "attempt");
7029 if (wpa_driver_nl80211_disconnect(
7030 drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
7031 return -1;
7032 /* Ignore the next local disconnect message. */
7033 drv->ignore_next_local_disconnect = 1;
7034 ret = wpa_driver_nl80211_try_connect(drv, params);
7035 }
7036 return ret;
7037}
7038
7039
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007040static int wpa_driver_nl80211_associate(
7041 void *priv, struct wpa_driver_associate_params *params)
7042{
7043 struct i802_bss *bss = priv;
7044 struct wpa_driver_nl80211_data *drv = bss->drv;
7045 int ret = -1;
7046 struct nl_msg *msg;
7047
7048 if (params->mode == IEEE80211_MODE_AP)
7049 return wpa_driver_nl80211_ap(drv, params);
7050
7051 if (params->mode == IEEE80211_MODE_IBSS)
7052 return wpa_driver_nl80211_ibss(drv, params);
7053
7054 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007055 enum nl80211_iftype nlmode = params->p2p ?
7056 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
7057
7058 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007059 return -1;
7060 return wpa_driver_nl80211_connect(drv, params);
7061 }
7062
7063 drv->associated = 0;
7064
7065 msg = nlmsg_alloc();
7066 if (!msg)
7067 return -1;
7068
7069 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
7070 drv->ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007071 nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007072
7073 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7074 if (params->bssid) {
7075 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
7076 MAC2STR(params->bssid));
7077 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
7078 }
7079 if (params->freq) {
7080 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
7081 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
7082 drv->assoc_freq = params->freq;
7083 } else
7084 drv->assoc_freq = 0;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007085 if (params->bg_scan_period >= 0) {
7086 wpa_printf(MSG_DEBUG, " * bg scan period=%d",
7087 params->bg_scan_period);
7088 NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
7089 params->bg_scan_period);
7090 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007091 if (params->ssid) {
7092 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
7093 params->ssid, params->ssid_len);
7094 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
7095 params->ssid);
7096 if (params->ssid_len > sizeof(drv->ssid))
7097 goto nla_put_failure;
7098 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
7099 drv->ssid_len = params->ssid_len;
7100 }
7101 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
7102 if (params->wpa_ie)
7103 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
7104 params->wpa_ie);
7105
7106 if (params->pairwise_suite != CIPHER_NONE) {
7107 int cipher;
7108
7109 switch (params->pairwise_suite) {
7110 case CIPHER_WEP40:
7111 cipher = WLAN_CIPHER_SUITE_WEP40;
7112 break;
7113 case CIPHER_WEP104:
7114 cipher = WLAN_CIPHER_SUITE_WEP104;
7115 break;
7116 case CIPHER_CCMP:
7117 cipher = WLAN_CIPHER_SUITE_CCMP;
7118 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007119 case CIPHER_GCMP:
7120 cipher = WLAN_CIPHER_SUITE_GCMP;
7121 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007122 case CIPHER_TKIP:
7123 default:
7124 cipher = WLAN_CIPHER_SUITE_TKIP;
7125 break;
7126 }
7127 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
7128 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
7129 }
7130
7131 if (params->group_suite != CIPHER_NONE) {
7132 int cipher;
7133
7134 switch (params->group_suite) {
7135 case CIPHER_WEP40:
7136 cipher = WLAN_CIPHER_SUITE_WEP40;
7137 break;
7138 case CIPHER_WEP104:
7139 cipher = WLAN_CIPHER_SUITE_WEP104;
7140 break;
7141 case CIPHER_CCMP:
7142 cipher = WLAN_CIPHER_SUITE_CCMP;
7143 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007144 case CIPHER_GCMP:
7145 cipher = WLAN_CIPHER_SUITE_GCMP;
7146 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007147 case CIPHER_TKIP:
7148 default:
7149 cipher = WLAN_CIPHER_SUITE_TKIP;
7150 break;
7151 }
7152 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
7153 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
7154 }
7155
7156#ifdef CONFIG_IEEE80211W
7157 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
7158 NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
7159#endif /* CONFIG_IEEE80211W */
7160
7161 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
7162
7163 if (params->prev_bssid) {
7164 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
7165 MAC2STR(params->prev_bssid));
7166 NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
7167 params->prev_bssid);
7168 }
7169
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007170 if (params->disable_ht)
7171 NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
7172
7173 if (params->htcaps && params->htcaps_mask) {
7174 int sz = sizeof(struct ieee80211_ht_capabilities);
7175 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
7176 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
7177 params->htcaps_mask);
7178 }
7179
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007180 if (params->p2p)
7181 wpa_printf(MSG_DEBUG, " * P2P group");
7182
7183 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
7184 msg = NULL;
7185 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007186 wpa_dbg(drv->ctx, MSG_DEBUG,
7187 "nl80211: MLME command failed (assoc): ret=%d (%s)",
7188 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007189 nl80211_dump_scan(drv);
7190 goto nla_put_failure;
7191 }
7192 ret = 0;
7193 wpa_printf(MSG_DEBUG, "nl80211: Association request send "
7194 "successfully");
7195
7196nla_put_failure:
7197 nlmsg_free(msg);
7198 return ret;
7199}
7200
7201
7202static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007203 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007204{
7205 struct nl_msg *msg;
7206 int ret = -ENOBUFS;
7207
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007208 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
7209 ifindex, mode, nl80211_iftype_str(mode));
7210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007211 msg = nlmsg_alloc();
7212 if (!msg)
7213 return -ENOMEM;
7214
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007215 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007216 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
7217 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
7218
7219 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007220 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007221 if (!ret)
7222 return 0;
7223nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007224 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007225 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
7226 " %d (%s)", ifindex, mode, ret, strerror(-ret));
7227 return ret;
7228}
7229
7230
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007231static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
7232 enum nl80211_iftype nlmode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007233{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007234 struct wpa_driver_nl80211_data *drv = bss->drv;
7235 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007236 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007237 int was_ap = is_ap_interface(drv->nlmode);
7238 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007239
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007240 res = nl80211_set_mode(drv, drv->ifindex, nlmode);
7241 if (res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007242 drv->nlmode = nlmode;
7243 ret = 0;
7244 goto done;
7245 }
7246
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007247 if (res == -ENODEV)
7248 return -1;
7249
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007250 if (nlmode == drv->nlmode) {
7251 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
7252 "requested mode - ignore error");
7253 ret = 0;
7254 goto done; /* Already in the requested mode */
7255 }
7256
7257 /* mac80211 doesn't allow mode changes while the device is up, so
7258 * take the device down, try to set the mode again, and bring the
7259 * device back up.
7260 */
7261 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
7262 "interface down");
7263 for (i = 0; i < 10; i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007264 res = linux_set_iface_flags(drv->global->ioctl_sock,
7265 bss->ifname, 0);
7266 if (res == -EACCES || res == -ENODEV)
7267 break;
7268 if (res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007269 /* Try to set the mode again while the interface is
7270 * down */
7271 ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007272 if (ret == -EACCES)
7273 break;
7274 res = linux_set_iface_flags(drv->global->ioctl_sock,
7275 bss->ifname, 1);
7276 if (res && !ret)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007277 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007278 else if (ret != -EBUSY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007279 break;
7280 } else
7281 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
7282 "interface down");
7283 os_sleep(0, 100000);
7284 }
7285
7286 if (!ret) {
7287 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
7288 "interface is down");
7289 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007290 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007291 }
7292
7293done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007294 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007295 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
7296 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007297 return ret;
7298 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007299
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007300 if (is_p2p_interface(nlmode))
7301 nl80211_disable_11b_rates(drv, drv->ifindex, 1);
7302 else if (drv->disabled_11b_rates)
7303 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
7304
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007305 if (is_ap_interface(nlmode)) {
7306 nl80211_mgmt_unsubscribe(bss, "start AP");
7307 /* Setup additional AP mode functionality if needed */
7308 if (nl80211_setup_ap(bss))
7309 return -1;
7310 } else if (was_ap) {
7311 /* Remove additional AP mode functionality */
7312 nl80211_teardown_ap(bss);
7313 } else {
7314 nl80211_mgmt_unsubscribe(bss, "mode change");
7315 }
7316
Dmitry Shmidt04949592012-07-19 12:16:46 -07007317 if (!bss->in_deinit && !is_ap_interface(nlmode) &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007318 nl80211_mgmt_subscribe_non_ap(bss) < 0)
7319 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
7320 "frame processing - ignore for now");
7321
7322 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007323}
7324
7325
7326static int wpa_driver_nl80211_get_capa(void *priv,
7327 struct wpa_driver_capa *capa)
7328{
7329 struct i802_bss *bss = priv;
7330 struct wpa_driver_nl80211_data *drv = bss->drv;
7331 if (!drv->has_capability)
7332 return -1;
7333 os_memcpy(capa, &drv->capa, sizeof(*capa));
7334 return 0;
7335}
7336
7337
7338static int wpa_driver_nl80211_set_operstate(void *priv, int state)
7339{
7340 struct i802_bss *bss = priv;
7341 struct wpa_driver_nl80211_data *drv = bss->drv;
7342
7343 wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
7344 __func__, drv->operstate, state, state ? "UP" : "DORMANT");
7345 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007346 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007347 state ? IF_OPER_UP : IF_OPER_DORMANT);
7348}
7349
7350
7351static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
7352{
7353 struct i802_bss *bss = priv;
7354 struct wpa_driver_nl80211_data *drv = bss->drv;
7355 struct nl_msg *msg;
7356 struct nl80211_sta_flag_update upd;
7357
7358 msg = nlmsg_alloc();
7359 if (!msg)
7360 return -ENOMEM;
7361
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007362 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007363
7364 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7365 if_nametoindex(bss->ifname));
7366 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
7367
7368 os_memset(&upd, 0, sizeof(upd));
7369 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
7370 if (authorized)
7371 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
7372 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
7373
7374 return send_and_recv_msgs(drv, msg, NULL, NULL);
7375 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007376 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007377 return -ENOBUFS;
7378}
7379
7380
Jouni Malinen75ecf522011-06-27 15:19:46 -07007381/* Set kernel driver on given frequency (MHz) */
7382static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007383{
Jouni Malinen75ecf522011-06-27 15:19:46 -07007384 struct i802_bss *bss = priv;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08007385 return wpa_driver_nl80211_set_freq(bss, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007386}
7387
7388
Jouni Malinen75ecf522011-06-27 15:19:46 -07007389#if defined(HOSTAPD) || defined(CONFIG_AP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007390
7391static inline int min_int(int a, int b)
7392{
7393 if (a < b)
7394 return a;
7395 return b;
7396}
7397
7398
7399static int get_key_handler(struct nl_msg *msg, void *arg)
7400{
7401 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7402 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7403
7404 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7405 genlmsg_attrlen(gnlh, 0), NULL);
7406
7407 /*
7408 * TODO: validate the key index and mac address!
7409 * Otherwise, there's a race condition as soon as
7410 * the kernel starts sending key notifications.
7411 */
7412
7413 if (tb[NL80211_ATTR_KEY_SEQ])
7414 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
7415 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
7416 return NL_SKIP;
7417}
7418
7419
7420static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
7421 int idx, u8 *seq)
7422{
7423 struct i802_bss *bss = priv;
7424 struct wpa_driver_nl80211_data *drv = bss->drv;
7425 struct nl_msg *msg;
7426
7427 msg = nlmsg_alloc();
7428 if (!msg)
7429 return -ENOMEM;
7430
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007431 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007432
7433 if (addr)
7434 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7435 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
7436 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
7437
7438 memset(seq, 0, 6);
7439
7440 return send_and_recv_msgs(drv, msg, get_key_handler, seq);
7441 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007442 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007443 return -ENOBUFS;
7444}
7445
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007446
7447static int i802_set_rts(void *priv, int rts)
7448{
7449 struct i802_bss *bss = priv;
7450 struct wpa_driver_nl80211_data *drv = bss->drv;
7451 struct nl_msg *msg;
7452 int ret = -ENOBUFS;
7453 u32 val;
7454
7455 msg = nlmsg_alloc();
7456 if (!msg)
7457 return -ENOMEM;
7458
7459 if (rts >= 2347)
7460 val = (u32) -1;
7461 else
7462 val = rts;
7463
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007464 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007465 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7466 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
7467
7468 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007469 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007470 if (!ret)
7471 return 0;
7472nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007473 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007474 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
7475 "%d (%s)", rts, ret, strerror(-ret));
7476 return ret;
7477}
7478
7479
7480static int i802_set_frag(void *priv, int frag)
7481{
7482 struct i802_bss *bss = priv;
7483 struct wpa_driver_nl80211_data *drv = bss->drv;
7484 struct nl_msg *msg;
7485 int ret = -ENOBUFS;
7486 u32 val;
7487
7488 msg = nlmsg_alloc();
7489 if (!msg)
7490 return -ENOMEM;
7491
7492 if (frag >= 2346)
7493 val = (u32) -1;
7494 else
7495 val = frag;
7496
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007497 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007498 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7499 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
7500
7501 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007502 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007503 if (!ret)
7504 return 0;
7505nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007506 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007507 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
7508 "%d: %d (%s)", frag, ret, strerror(-ret));
7509 return ret;
7510}
7511
7512
7513static int i802_flush(void *priv)
7514{
7515 struct i802_bss *bss = priv;
7516 struct wpa_driver_nl80211_data *drv = bss->drv;
7517 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007518 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007519
7520 msg = nlmsg_alloc();
7521 if (!msg)
7522 return -1;
7523
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007524 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007525
7526 /*
7527 * XXX: FIX! this needs to flush all VLANs too
7528 */
7529 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7530 if_nametoindex(bss->ifname));
7531
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007532 res = send_and_recv_msgs(drv, msg, NULL, NULL);
7533 if (res) {
7534 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
7535 "(%s)", res, strerror(-res));
7536 }
7537 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007538 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007539 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007540 return -ENOBUFS;
7541}
7542
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007543#endif /* HOSTAPD || CONFIG_AP */
7544
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007545
7546static int get_sta_handler(struct nl_msg *msg, void *arg)
7547{
7548 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7549 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7550 struct hostap_sta_driver_data *data = arg;
7551 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
7552 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
7553 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
7554 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
7555 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
7556 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
7557 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007558 [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007559 };
7560
7561 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7562 genlmsg_attrlen(gnlh, 0), NULL);
7563
7564 /*
7565 * TODO: validate the interface and mac address!
7566 * Otherwise, there's a race condition as soon as
7567 * the kernel starts sending station notifications.
7568 */
7569
7570 if (!tb[NL80211_ATTR_STA_INFO]) {
7571 wpa_printf(MSG_DEBUG, "sta stats missing!");
7572 return NL_SKIP;
7573 }
7574 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
7575 tb[NL80211_ATTR_STA_INFO],
7576 stats_policy)) {
7577 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
7578 return NL_SKIP;
7579 }
7580
7581 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
7582 data->inactive_msec =
7583 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
7584 if (stats[NL80211_STA_INFO_RX_BYTES])
7585 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
7586 if (stats[NL80211_STA_INFO_TX_BYTES])
7587 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
7588 if (stats[NL80211_STA_INFO_RX_PACKETS])
7589 data->rx_packets =
7590 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
7591 if (stats[NL80211_STA_INFO_TX_PACKETS])
7592 data->tx_packets =
7593 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007594 if (stats[NL80211_STA_INFO_TX_FAILED])
7595 data->tx_retry_failed =
7596 nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007597
7598 return NL_SKIP;
7599}
7600
7601static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
7602 const u8 *addr)
7603{
7604 struct i802_bss *bss = priv;
7605 struct wpa_driver_nl80211_data *drv = bss->drv;
7606 struct nl_msg *msg;
7607
7608 os_memset(data, 0, sizeof(*data));
7609 msg = nlmsg_alloc();
7610 if (!msg)
7611 return -ENOMEM;
7612
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007613 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007614
7615 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7616 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
7617
7618 return send_and_recv_msgs(drv, msg, get_sta_handler, data);
7619 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007620 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007621 return -ENOBUFS;
7622}
7623
7624
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03007625#if defined(HOSTAPD) || defined(CONFIG_AP)
7626
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007627static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
7628 int cw_min, int cw_max, int burst_time)
7629{
7630 struct i802_bss *bss = priv;
7631 struct wpa_driver_nl80211_data *drv = bss->drv;
7632 struct nl_msg *msg;
7633 struct nlattr *txq, *params;
7634
7635 msg = nlmsg_alloc();
7636 if (!msg)
7637 return -1;
7638
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007639 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007640
7641 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
7642
7643 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
7644 if (!txq)
7645 goto nla_put_failure;
7646
7647 /* We are only sending parameters for a single TXQ at a time */
7648 params = nla_nest_start(msg, 1);
7649 if (!params)
7650 goto nla_put_failure;
7651
7652 switch (queue) {
7653 case 0:
7654 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
7655 break;
7656 case 1:
7657 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
7658 break;
7659 case 2:
7660 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
7661 break;
7662 case 3:
7663 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
7664 break;
7665 }
7666 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
7667 * 32 usec, so need to convert the value here. */
7668 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
7669 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
7670 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
7671 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
7672
7673 nla_nest_end(msg, params);
7674
7675 nla_nest_end(msg, txq);
7676
7677 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
7678 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007679 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007680 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007681 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007682 return -1;
7683}
7684
7685
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007686static int i802_set_sta_vlan(void *priv, const u8 *addr,
7687 const char *ifname, int vlan_id)
7688{
7689 struct i802_bss *bss = priv;
7690 struct wpa_driver_nl80211_data *drv = bss->drv;
7691 struct nl_msg *msg;
7692 int ret = -ENOBUFS;
7693
7694 msg = nlmsg_alloc();
7695 if (!msg)
7696 return -ENOMEM;
7697
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007698 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007699
7700 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7701 if_nametoindex(bss->ifname));
7702 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7703 NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
7704 if_nametoindex(ifname));
7705
7706 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007707 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007708 if (ret < 0) {
7709 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
7710 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
7711 MAC2STR(addr), ifname, vlan_id, ret,
7712 strerror(-ret));
7713 }
7714 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007715 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007716 return ret;
7717}
7718
7719
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007720static int i802_get_inact_sec(void *priv, const u8 *addr)
7721{
7722 struct hostap_sta_driver_data data;
7723 int ret;
7724
7725 data.inactive_msec = (unsigned long) -1;
7726 ret = i802_read_sta_data(priv, &data, addr);
7727 if (ret || data.inactive_msec == (unsigned long) -1)
7728 return -1;
7729 return data.inactive_msec / 1000;
7730}
7731
7732
7733static int i802_sta_clear_stats(void *priv, const u8 *addr)
7734{
7735#if 0
7736 /* TODO */
7737#endif
7738 return 0;
7739}
7740
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007741
7742static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
7743 int reason)
7744{
7745 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007746 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007747 struct ieee80211_mgmt mgmt;
7748
Dmitry Shmidt04949592012-07-19 12:16:46 -07007749 if (drv->device_ap_sme)
7750 return wpa_driver_nl80211_sta_remove(bss, addr);
7751
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007752 memset(&mgmt, 0, sizeof(mgmt));
7753 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7754 WLAN_FC_STYPE_DEAUTH);
7755 memcpy(mgmt.da, addr, ETH_ALEN);
7756 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7757 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7758 mgmt.u.deauth.reason_code = host_to_le16(reason);
7759 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7760 IEEE80211_HDRLEN +
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007761 sizeof(mgmt.u.deauth), 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007762}
7763
7764
7765static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
7766 int reason)
7767{
7768 struct i802_bss *bss = priv;
Dmitry Shmidt04949592012-07-19 12:16:46 -07007769 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007770 struct ieee80211_mgmt mgmt;
7771
Dmitry Shmidt04949592012-07-19 12:16:46 -07007772 if (drv->device_ap_sme)
7773 return wpa_driver_nl80211_sta_remove(bss, addr);
7774
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007775 memset(&mgmt, 0, sizeof(mgmt));
7776 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7777 WLAN_FC_STYPE_DISASSOC);
7778 memcpy(mgmt.da, addr, ETH_ALEN);
7779 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7780 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7781 mgmt.u.disassoc.reason_code = host_to_le16(reason);
7782 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7783 IEEE80211_HDRLEN +
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007784 sizeof(mgmt.u.disassoc), 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007785}
7786
7787#endif /* HOSTAPD || CONFIG_AP */
7788
7789#ifdef HOSTAPD
7790
Jouni Malinen75ecf522011-06-27 15:19:46 -07007791static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7792{
7793 int i;
7794 int *old;
7795
7796 wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
7797 ifidx);
7798 for (i = 0; i < drv->num_if_indices; i++) {
7799 if (drv->if_indices[i] == 0) {
7800 drv->if_indices[i] = ifidx;
7801 return;
7802 }
7803 }
7804
7805 if (drv->if_indices != drv->default_if_indices)
7806 old = drv->if_indices;
7807 else
7808 old = NULL;
7809
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007810 drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
7811 sizeof(int));
Jouni Malinen75ecf522011-06-27 15:19:46 -07007812 if (!drv->if_indices) {
7813 if (!old)
7814 drv->if_indices = drv->default_if_indices;
7815 else
7816 drv->if_indices = old;
7817 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
7818 "interfaces");
7819 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
7820 return;
7821 } else if (!old)
7822 os_memcpy(drv->if_indices, drv->default_if_indices,
7823 sizeof(drv->default_if_indices));
7824 drv->if_indices[drv->num_if_indices] = ifidx;
7825 drv->num_if_indices++;
7826}
7827
7828
7829static void del_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 drv->if_indices[i] = 0;
7836 break;
7837 }
7838 }
7839}
7840
7841
7842static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7843{
7844 int i;
7845
7846 for (i = 0; i < drv->num_if_indices; i++)
7847 if (drv->if_indices[i] == ifidx)
7848 return 1;
7849
7850 return 0;
7851}
7852
7853
7854static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
7855 const char *bridge_ifname)
7856{
7857 struct i802_bss *bss = priv;
7858 struct wpa_driver_nl80211_data *drv = bss->drv;
7859 char name[IFNAMSIZ + 1];
7860
7861 os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
7862 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
7863 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
7864 if (val) {
7865 if (!if_nametoindex(name)) {
7866 if (nl80211_create_iface(drv, name,
7867 NL80211_IFTYPE_AP_VLAN,
7868 NULL, 1) < 0)
7869 return -1;
7870 if (bridge_ifname &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007871 linux_br_add_if(drv->global->ioctl_sock,
7872 bridge_ifname, name) < 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007873 return -1;
7874 }
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07007875 if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
7876 wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
7877 "interface %s up", name);
7878 }
Jouni Malinen75ecf522011-06-27 15:19:46 -07007879 return i802_set_sta_vlan(priv, addr, name, 0);
7880 } else {
Dmitry Shmidtaa532512012-09-24 10:35:31 -07007881 if (bridge_ifname)
7882 linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
7883 name);
7884
Jouni Malinen75ecf522011-06-27 15:19:46 -07007885 i802_set_sta_vlan(priv, addr, bss->ifname, 0);
7886 return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
7887 name);
7888 }
7889}
7890
7891
7892static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
7893{
7894 struct wpa_driver_nl80211_data *drv = eloop_ctx;
7895 struct sockaddr_ll lladdr;
7896 unsigned char buf[3000];
7897 int len;
7898 socklen_t fromlen = sizeof(lladdr);
7899
7900 len = recvfrom(sock, buf, sizeof(buf), 0,
7901 (struct sockaddr *)&lladdr, &fromlen);
7902 if (len < 0) {
7903 perror("recv");
7904 return;
7905 }
7906
7907 if (have_ifidx(drv, lladdr.sll_ifindex))
7908 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
7909}
7910
7911
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007912static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
7913 struct i802_bss *bss,
7914 const char *brname, const char *ifname)
7915{
7916 int ifindex;
7917 char in_br[IFNAMSIZ];
7918
7919 os_strlcpy(bss->brname, brname, IFNAMSIZ);
7920 ifindex = if_nametoindex(brname);
7921 if (ifindex == 0) {
7922 /*
7923 * Bridge was configured, but the bridge device does
7924 * not exist. Try to add it now.
7925 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007926 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007927 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
7928 "bridge interface %s: %s",
7929 brname, strerror(errno));
7930 return -1;
7931 }
7932 bss->added_bridge = 1;
7933 add_ifidx(drv, if_nametoindex(brname));
7934 }
7935
7936 if (linux_br_get(in_br, ifname) == 0) {
7937 if (os_strcmp(in_br, brname) == 0)
7938 return 0; /* already in the bridge */
7939
7940 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
7941 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007942 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
7943 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007944 wpa_printf(MSG_ERROR, "nl80211: Failed to "
7945 "remove interface %s from bridge "
7946 "%s: %s",
7947 ifname, brname, strerror(errno));
7948 return -1;
7949 }
7950 }
7951
7952 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
7953 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007954 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007955 wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
7956 "into bridge %s: %s",
7957 ifname, brname, strerror(errno));
7958 return -1;
7959 }
7960 bss->added_if_into_bridge = 1;
7961
7962 return 0;
7963}
7964
7965
7966static void *i802_init(struct hostapd_data *hapd,
7967 struct wpa_init_params *params)
7968{
7969 struct wpa_driver_nl80211_data *drv;
7970 struct i802_bss *bss;
7971 size_t i;
7972 char brname[IFNAMSIZ];
7973 int ifindex, br_ifindex;
7974 int br_added = 0;
7975
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007976 bss = wpa_driver_nl80211_init(hapd, params->ifname,
7977 params->global_priv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007978 if (bss == NULL)
7979 return NULL;
7980
7981 drv = bss->drv;
7982 drv->nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007983 drv->eapol_sock = -1;
7984
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007985 if (linux_br_get(brname, params->ifname) == 0) {
7986 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
7987 params->ifname, brname);
7988 br_ifindex = if_nametoindex(brname);
7989 } else {
7990 brname[0] = '\0';
7991 br_ifindex = 0;
7992 }
7993
7994 drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
7995 drv->if_indices = drv->default_if_indices;
7996 for (i = 0; i < params->num_bridge; i++) {
7997 if (params->bridge[i]) {
7998 ifindex = if_nametoindex(params->bridge[i]);
7999 if (ifindex)
8000 add_ifidx(drv, ifindex);
8001 if (ifindex == br_ifindex)
8002 br_added = 1;
8003 }
8004 }
8005 if (!br_added && br_ifindex &&
8006 (params->num_bridge == 0 || !params->bridge[0]))
8007 add_ifidx(drv, br_ifindex);
8008
8009 /* start listening for EAPOL on the default AP interface */
8010 add_ifidx(drv, drv->ifindex);
8011
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008012 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008013 goto failed;
8014
8015 if (params->bssid) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008016 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008017 params->bssid))
8018 goto failed;
8019 }
8020
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008021 if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008022 wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
8023 "into AP mode", bss->ifname);
8024 goto failed;
8025 }
8026
8027 if (params->num_bridge && params->bridge[0] &&
8028 i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
8029 goto failed;
8030
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008031 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008032 goto failed;
8033
8034 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
8035 if (drv->eapol_sock < 0) {
8036 perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
8037 goto failed;
8038 }
8039
8040 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
8041 {
8042 printf("Could not register read socket for eapol\n");
8043 goto failed;
8044 }
8045
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008046 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8047 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008048 goto failed;
8049
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008050 memcpy(bss->addr, params->own_addr, ETH_ALEN);
8051
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008052 return bss;
8053
8054failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008055 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008056 return NULL;
8057}
8058
8059
8060static void i802_deinit(void *priv)
8061{
8062 wpa_driver_nl80211_deinit(priv);
8063}
8064
8065#endif /* HOSTAPD */
8066
8067
8068static enum nl80211_iftype wpa_driver_nl80211_if_type(
8069 enum wpa_driver_if_type type)
8070{
8071 switch (type) {
8072 case WPA_IF_STATION:
8073 return NL80211_IFTYPE_STATION;
8074 case WPA_IF_P2P_CLIENT:
8075 case WPA_IF_P2P_GROUP:
8076 return NL80211_IFTYPE_P2P_CLIENT;
8077 case WPA_IF_AP_VLAN:
8078 return NL80211_IFTYPE_AP_VLAN;
8079 case WPA_IF_AP_BSS:
8080 return NL80211_IFTYPE_AP;
8081 case WPA_IF_P2P_GO:
8082 return NL80211_IFTYPE_P2P_GO;
8083 }
8084 return -1;
8085}
8086
8087
8088#ifdef CONFIG_P2P
8089
8090static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
8091{
8092 struct wpa_driver_nl80211_data *drv;
8093 dl_list_for_each(drv, &global->interfaces,
8094 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008095 if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008096 return 1;
8097 }
8098 return 0;
8099}
8100
8101
8102static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
8103 u8 *new_addr)
8104{
8105 unsigned int idx;
8106
8107 if (!drv->global)
8108 return -1;
8109
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008110 os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008111 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008112 new_addr[0] = drv->first_bss.addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008113 new_addr[0] ^= idx << 2;
8114 if (!nl80211_addr_in_use(drv->global, new_addr))
8115 break;
8116 }
8117 if (idx == 64)
8118 return -1;
8119
8120 wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
8121 MACSTR, MAC2STR(new_addr));
8122
8123 return 0;
8124}
8125
8126#endif /* CONFIG_P2P */
8127
8128
8129static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
8130 const char *ifname, const u8 *addr,
8131 void *bss_ctx, void **drv_priv,
8132 char *force_ifname, u8 *if_addr,
8133 const char *bridge)
8134{
8135 struct i802_bss *bss = priv;
8136 struct wpa_driver_nl80211_data *drv = bss->drv;
8137 int ifidx;
8138#ifdef HOSTAPD
8139 struct i802_bss *new_bss = NULL;
8140
8141 if (type == WPA_IF_AP_BSS) {
8142 new_bss = os_zalloc(sizeof(*new_bss));
8143 if (new_bss == NULL)
8144 return -1;
8145 }
8146#endif /* HOSTAPD */
8147
8148 if (addr)
8149 os_memcpy(if_addr, addr, ETH_ALEN);
8150 ifidx = nl80211_create_iface(drv, ifname,
8151 wpa_driver_nl80211_if_type(type), addr,
8152 0);
8153 if (ifidx < 0) {
8154#ifdef HOSTAPD
8155 os_free(new_bss);
8156#endif /* HOSTAPD */
8157 return -1;
8158 }
8159
8160 if (!addr &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008161 linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8162 if_addr) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008163 nl80211_remove_iface(drv, ifidx);
8164 return -1;
8165 }
8166
8167#ifdef CONFIG_P2P
8168 if (!addr &&
8169 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
8170 type == WPA_IF_P2P_GO)) {
8171 /* Enforce unique P2P Interface Address */
8172 u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
8173
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008174 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
8175 own_addr) < 0 ||
8176 linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
8177 new_addr) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008178 nl80211_remove_iface(drv, ifidx);
8179 return -1;
8180 }
8181 if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
8182 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
8183 "for P2P group interface");
8184 if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
8185 nl80211_remove_iface(drv, ifidx);
8186 return -1;
8187 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008188 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008189 new_addr) < 0) {
8190 nl80211_remove_iface(drv, ifidx);
8191 return -1;
8192 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008193 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008194 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008195 }
8196#endif /* CONFIG_P2P */
8197
8198#ifdef HOSTAPD
8199 if (bridge &&
8200 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
8201 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
8202 "interface %s to a bridge %s", ifname, bridge);
8203 nl80211_remove_iface(drv, ifidx);
8204 os_free(new_bss);
8205 return -1;
8206 }
8207
8208 if (type == WPA_IF_AP_BSS) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008209 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
8210 {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008211 nl80211_remove_iface(drv, ifidx);
8212 os_free(new_bss);
8213 return -1;
8214 }
8215 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008216 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008217 new_bss->ifindex = ifidx;
8218 new_bss->drv = drv;
8219 new_bss->next = drv->first_bss.next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008220 new_bss->freq = drv->first_bss.freq;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08008221 new_bss->ctx = bss_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008222 drv->first_bss.next = new_bss;
8223 if (drv_priv)
8224 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008225 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008226
8227 /* Subscribe management frames for this WPA_IF_AP_BSS */
8228 if (nl80211_setup_ap(new_bss))
8229 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008230 }
8231#endif /* HOSTAPD */
8232
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008233 if (drv->global)
8234 drv->global->if_add_ifindex = ifidx;
8235
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008236 return 0;
8237}
8238
8239
8240static int wpa_driver_nl80211_if_remove(void *priv,
8241 enum wpa_driver_if_type type,
8242 const char *ifname)
8243{
8244 struct i802_bss *bss = priv;
8245 struct wpa_driver_nl80211_data *drv = bss->drv;
8246 int ifindex = if_nametoindex(ifname);
8247
8248 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
8249 __func__, type, ifname, ifindex);
8250 if (ifindex <= 0)
8251 return -1;
8252
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008253 nl80211_remove_iface(drv, ifindex);
8254
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008255#ifdef HOSTAPD
Dmitry Shmidtaa532512012-09-24 10:35:31 -07008256 if (type != WPA_IF_AP_BSS)
8257 return 0;
8258
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008259 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008260 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
8261 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008262 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8263 "interface %s from bridge %s: %s",
8264 bss->ifname, bss->brname, strerror(errno));
8265 }
8266 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008267 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008268 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
8269 "bridge %s: %s",
8270 bss->brname, strerror(errno));
8271 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008272
8273 if (bss != &drv->first_bss) {
8274 struct i802_bss *tbss;
8275
8276 for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
8277 if (tbss->next == bss) {
8278 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008279 /* Unsubscribe management frames */
8280 nl80211_teardown_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008281 nl80211_destroy_bss(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008282 os_free(bss);
8283 bss = NULL;
8284 break;
8285 }
8286 }
8287 if (bss)
8288 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
8289 "BSS %p in the list", __func__, bss);
8290 }
8291#endif /* HOSTAPD */
8292
8293 return 0;
8294}
8295
8296
8297static int cookie_handler(struct nl_msg *msg, void *arg)
8298{
8299 struct nlattr *tb[NL80211_ATTR_MAX + 1];
8300 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8301 u64 *cookie = arg;
8302 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8303 genlmsg_attrlen(gnlh, 0), NULL);
8304 if (tb[NL80211_ATTR_COOKIE])
8305 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
8306 return NL_SKIP;
8307}
8308
8309
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008310static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008311 unsigned int freq, unsigned int wait,
8312 const u8 *buf, size_t buf_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008313 u64 *cookie_out, int no_cck, int no_ack,
8314 int offchanok)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008315{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008316 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008317 struct nl_msg *msg;
8318 u64 cookie;
8319 int ret = -1;
8320
8321 msg = nlmsg_alloc();
8322 if (!msg)
8323 return -1;
8324
Dmitry Shmidt04949592012-07-19 12:16:46 -07008325 wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
8326 "no_ack=%d offchanok=%d",
8327 freq, wait, no_cck, no_ack, offchanok);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008328 nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008329
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008330 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008331 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008332 if (wait)
8333 NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008334 if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008335 NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
8336 if (no_cck)
8337 NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
8338 if (no_ack)
8339 NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
8340
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008341 NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
8342
8343 cookie = 0;
8344 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
8345 msg = NULL;
8346 if (ret) {
8347 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008348 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
8349 freq, wait);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008350 goto nla_put_failure;
8351 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008352 wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
8353 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
8354 (long long unsigned int) cookie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008355
8356 if (cookie_out)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008357 *cookie_out = no_ack ? (u64) -1 : cookie;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008358
8359nla_put_failure:
8360 nlmsg_free(msg);
8361 return ret;
8362}
8363
8364
8365static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
8366 unsigned int wait_time,
8367 const u8 *dst, const u8 *src,
8368 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008369 const u8 *data, size_t data_len,
8370 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008371{
8372 struct i802_bss *bss = priv;
8373 struct wpa_driver_nl80211_data *drv = bss->drv;
8374 int ret = -1;
8375 u8 *buf;
8376 struct ieee80211_hdr *hdr;
8377
8378 wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008379 "freq=%u MHz wait=%d ms no_cck=%d)",
8380 drv->ifindex, freq, wait_time, no_cck);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008381
8382 buf = os_zalloc(24 + data_len);
8383 if (buf == NULL)
8384 return ret;
8385 os_memcpy(buf + 24, data, data_len);
8386 hdr = (struct ieee80211_hdr *) buf;
8387 hdr->frame_control =
8388 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
8389 os_memcpy(hdr->addr1, dst, ETH_ALEN);
8390 os_memcpy(hdr->addr2, src, ETH_ALEN);
8391 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
8392
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008393 if (is_ap_interface(drv->nlmode))
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008394 ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
8395 24 + data_len,
8396 0, freq, no_cck, 1,
8397 wait_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008398 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008399 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008400 24 + data_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008401 &drv->send_action_cookie,
8402 no_cck, 0, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008403
8404 os_free(buf);
8405 return ret;
8406}
8407
8408
8409static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
8410{
8411 struct i802_bss *bss = priv;
8412 struct wpa_driver_nl80211_data *drv = bss->drv;
8413 struct nl_msg *msg;
8414 int ret;
8415
8416 msg = nlmsg_alloc();
8417 if (!msg)
8418 return;
8419
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008420 nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008421
8422 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8423 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
8424
8425 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8426 msg = NULL;
8427 if (ret)
8428 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
8429 "(%s)", ret, strerror(-ret));
8430
8431 nla_put_failure:
8432 nlmsg_free(msg);
8433}
8434
8435
8436static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
8437 unsigned int duration)
8438{
8439 struct i802_bss *bss = priv;
8440 struct wpa_driver_nl80211_data *drv = bss->drv;
8441 struct nl_msg *msg;
8442 int ret;
8443 u64 cookie;
8444
8445 msg = nlmsg_alloc();
8446 if (!msg)
8447 return -1;
8448
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008449 nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008450
8451 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8452 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
8453 NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
8454
8455 cookie = 0;
8456 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008457 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008458 if (ret == 0) {
8459 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
8460 "0x%llx for freq=%u MHz duration=%u",
8461 (long long unsigned int) cookie, freq, duration);
8462 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008463 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008464 return 0;
8465 }
8466 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
8467 "(freq=%d duration=%u): %d (%s)",
8468 freq, duration, ret, strerror(-ret));
8469nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008470 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008471 return -1;
8472}
8473
8474
8475static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
8476{
8477 struct i802_bss *bss = priv;
8478 struct wpa_driver_nl80211_data *drv = bss->drv;
8479 struct nl_msg *msg;
8480 int ret;
8481
8482 if (!drv->pending_remain_on_chan) {
8483 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
8484 "to cancel");
8485 return -1;
8486 }
8487
8488 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
8489 "0x%llx",
8490 (long long unsigned int) drv->remain_on_chan_cookie);
8491
8492 msg = nlmsg_alloc();
8493 if (!msg)
8494 return -1;
8495
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008496 nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008497
8498 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8499 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
8500
8501 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008502 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008503 if (ret == 0)
8504 return 0;
8505 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
8506 "%d (%s)", ret, strerror(-ret));
8507nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008508 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008509 return -1;
8510}
8511
8512
8513static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
8514{
8515 struct i802_bss *bss = priv;
8516 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008517
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008518 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008519 if (bss->nl_preq && drv->device_ap_sme &&
8520 is_ap_interface(drv->nlmode)) {
8521 /*
8522 * Do not disable Probe Request reporting that was
8523 * enabled in nl80211_setup_ap().
8524 */
8525 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
8526 "Probe Request reporting nl_preq=%p while "
8527 "in AP mode", bss->nl_preq);
8528 } else if (bss->nl_preq) {
8529 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
8530 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008531 eloop_unregister_read_sock(
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008532 nl_socket_get_fd(bss->nl_preq));
8533 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008534 }
8535 return 0;
8536 }
8537
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008538 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008539 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008540 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008541 return 0;
8542 }
8543
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008544 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
8545 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008546 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008547 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
8548 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008549
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008550 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008551 (WLAN_FC_TYPE_MGMT << 2) |
8552 (WLAN_FC_STYPE_PROBE_REQ << 4),
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008553 NULL, 0) < 0)
8554 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07008555
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008556 eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
8557 wpa_driver_nl80211_event_receive, bss->nl_cb,
8558 bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008559
8560 return 0;
8561
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008562 out_err:
8563 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008564 return -1;
8565}
8566
8567
8568static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
8569 int ifindex, int disabled)
8570{
8571 struct nl_msg *msg;
8572 struct nlattr *bands, *band;
8573 int ret;
8574
8575 msg = nlmsg_alloc();
8576 if (!msg)
8577 return -1;
8578
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008579 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008580 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
8581
8582 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
8583 if (!bands)
8584 goto nla_put_failure;
8585
8586 /*
8587 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
8588 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
8589 * rates. All 5 GHz rates are left enabled.
8590 */
8591 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
8592 if (!band)
8593 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008594 if (disabled) {
8595 NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
8596 "\x0c\x12\x18\x24\x30\x48\x60\x6c");
8597 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008598 nla_nest_end(msg, band);
8599
8600 nla_nest_end(msg, bands);
8601
8602 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8603 msg = NULL;
8604 if (ret) {
8605 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
8606 "(%s)", ret, strerror(-ret));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008607 } else
8608 drv->disabled_11b_rates = disabled;
8609
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008610 return ret;
8611
8612nla_put_failure:
8613 nlmsg_free(msg);
8614 return -1;
8615}
8616
8617
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008618static int wpa_driver_nl80211_deinit_ap(void *priv)
8619{
8620 struct i802_bss *bss = priv;
8621 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008622 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008623 return -1;
8624 wpa_driver_nl80211_del_beacon(drv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008625 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008626}
8627
8628
Dmitry Shmidt04949592012-07-19 12:16:46 -07008629static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
8630{
8631 struct i802_bss *bss = priv;
8632 struct wpa_driver_nl80211_data *drv = bss->drv;
8633 if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
8634 return -1;
8635 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
8636}
8637
8638
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008639static void wpa_driver_nl80211_resume(void *priv)
8640{
8641 struct i802_bss *bss = priv;
8642 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008643 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008644 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
8645 "resume event");
8646 }
8647}
8648
8649
8650static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
8651 const u8 *ies, size_t ies_len)
8652{
8653 struct i802_bss *bss = priv;
8654 struct wpa_driver_nl80211_data *drv = bss->drv;
8655 int ret;
8656 u8 *data, *pos;
8657 size_t data_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008658 const u8 *own_addr = bss->addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008659
8660 if (action != 1) {
8661 wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
8662 "action %d", action);
8663 return -1;
8664 }
8665
8666 /*
8667 * Action frame payload:
8668 * Category[1] = 6 (Fast BSS Transition)
8669 * Action[1] = 1 (Fast BSS Transition Request)
8670 * STA Address
8671 * Target AP Address
8672 * FT IEs
8673 */
8674
8675 data_len = 2 + 2 * ETH_ALEN + ies_len;
8676 data = os_malloc(data_len);
8677 if (data == NULL)
8678 return -1;
8679 pos = data;
8680 *pos++ = 0x06; /* FT Action category */
8681 *pos++ = action;
8682 os_memcpy(pos, own_addr, ETH_ALEN);
8683 pos += ETH_ALEN;
8684 os_memcpy(pos, target_ap, ETH_ALEN);
8685 pos += ETH_ALEN;
8686 os_memcpy(pos, ies, ies_len);
8687
8688 ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
8689 drv->bssid, own_addr, drv->bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008690 data, data_len, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008691 os_free(data);
8692
8693 return ret;
8694}
8695
8696
8697static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
8698{
8699 struct i802_bss *bss = priv;
8700 struct wpa_driver_nl80211_data *drv = bss->drv;
8701 struct nl_msg *msg, *cqm = NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008702 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008703
8704 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
8705 "hysteresis=%d", threshold, hysteresis);
8706
8707 msg = nlmsg_alloc();
8708 if (!msg)
8709 return -1;
8710
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008711 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008712
8713 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8714
8715 cqm = nlmsg_alloc();
8716 if (cqm == NULL)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008717 goto nla_put_failure;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008718
8719 NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
8720 NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008721 if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
8722 goto nla_put_failure;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008723
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008724 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008725 msg = NULL;
8726
8727nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008728 nlmsg_free(cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008729 nlmsg_free(msg);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07008730 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008731}
8732
8733
8734static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
8735{
8736 struct i802_bss *bss = priv;
8737 struct wpa_driver_nl80211_data *drv = bss->drv;
8738 int res;
8739
8740 os_memset(si, 0, sizeof(*si));
8741 res = nl80211_get_link_signal(drv, si);
8742 if (res != 0)
8743 return res;
8744
8745 return nl80211_get_link_noise(drv, si);
8746}
8747
8748
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008749static int wpa_driver_nl80211_shared_freq(void *priv)
8750{
8751 struct i802_bss *bss = priv;
8752 struct wpa_driver_nl80211_data *drv = bss->drv;
8753 struct wpa_driver_nl80211_data *driver;
8754 int freq = 0;
8755
8756 /*
8757 * If the same PHY is in connected state with some other interface,
8758 * then retrieve the assoc freq.
8759 */
8760 wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
8761 drv->phyname);
8762
8763 dl_list_for_each(driver, &drv->global->interfaces,
8764 struct wpa_driver_nl80211_data, list) {
8765 if (drv == driver ||
8766 os_strcmp(drv->phyname, driver->phyname) != 0 ||
8767#ifdef ANDROID_P2P
8768 (!driver->associated && !is_ap_interface(driver->nlmode)))
8769#else
8770 !driver->associated)
8771#endif
8772 continue;
8773
8774 wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
8775 MACSTR,
8776 driver->phyname, driver->first_bss.ifname,
8777 MAC2STR(driver->first_bss.addr));
Dmitry Shmidt04949592012-07-19 12:16:46 -07008778 if (is_ap_interface(driver->nlmode))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008779 freq = driver->first_bss.freq;
8780 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008781 freq = nl80211_get_assoc_freq(driver);
8782 wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
8783 drv->phyname, freq);
8784 }
8785
8786 if (!freq)
8787 wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
8788 "PHY (%s) in associated state", drv->phyname);
8789
8790 return freq;
8791}
8792
8793
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008794static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
8795 int encrypt)
8796{
8797 struct i802_bss *bss = priv;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008798 return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
8799 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008800}
8801
8802
8803static int nl80211_set_param(void *priv, const char *param)
8804{
8805 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
8806 if (param == NULL)
8807 return 0;
8808
8809#ifdef CONFIG_P2P
8810 if (os_strstr(param, "use_p2p_group_interface=1")) {
8811 struct i802_bss *bss = priv;
8812 struct wpa_driver_nl80211_data *drv = bss->drv;
8813
8814 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
8815 "interface");
8816 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
8817 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
8818 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008819#ifdef ANDROID_P2P
8820 if(os_strstr(param, "use_multi_chan_concurrent=1")) {
8821 struct i802_bss *bss = priv;
8822 struct wpa_driver_nl80211_data *drv = bss->drv;
8823 wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
8824 "concurrency");
8825 drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
8826 }
8827#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008828#endif /* CONFIG_P2P */
8829
8830 return 0;
8831}
8832
8833
8834static void * nl80211_global_init(void)
8835{
8836 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008837 struct netlink_config *cfg;
8838
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008839 global = os_zalloc(sizeof(*global));
8840 if (global == NULL)
8841 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008842 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008843 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008844 global->if_add_ifindex = -1;
8845
8846 cfg = os_zalloc(sizeof(*cfg));
8847 if (cfg == NULL)
8848 goto err;
8849
8850 cfg->ctx = global;
8851 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
8852 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
8853 global->netlink = netlink_init(cfg);
8854 if (global->netlink == NULL) {
8855 os_free(cfg);
8856 goto err;
8857 }
8858
8859 if (wpa_driver_nl80211_init_nl_global(global) < 0)
8860 goto err;
8861
8862 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
8863 if (global->ioctl_sock < 0) {
8864 perror("socket(PF_INET,SOCK_DGRAM)");
8865 goto err;
8866 }
8867
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008868 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008869
8870err:
8871 nl80211_global_deinit(global);
8872 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008873}
8874
8875
8876static void nl80211_global_deinit(void *priv)
8877{
8878 struct nl80211_global *global = priv;
8879 if (global == NULL)
8880 return;
8881 if (!dl_list_empty(&global->interfaces)) {
8882 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
8883 "nl80211_global_deinit",
8884 dl_list_len(&global->interfaces));
8885 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008886
8887 if (global->netlink)
8888 netlink_deinit(global->netlink);
8889
8890 nl_destroy_handles(&global->nl);
8891
8892 if (global->nl_event) {
8893 eloop_unregister_read_sock(
8894 nl_socket_get_fd(global->nl_event));
8895 nl_destroy_handles(&global->nl_event);
8896 }
8897
8898 nl_cb_put(global->nl_cb);
8899
8900 if (global->ioctl_sock >= 0)
8901 close(global->ioctl_sock);
8902
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008903 os_free(global);
8904}
8905
8906
8907static const char * nl80211_get_radio_name(void *priv)
8908{
8909 struct i802_bss *bss = priv;
8910 struct wpa_driver_nl80211_data *drv = bss->drv;
8911 return drv->phyname;
8912}
8913
8914
Jouni Malinen75ecf522011-06-27 15:19:46 -07008915static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
8916 const u8 *pmkid)
8917{
8918 struct nl_msg *msg;
8919
8920 msg = nlmsg_alloc();
8921 if (!msg)
8922 return -ENOMEM;
8923
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008924 nl80211_cmd(bss->drv, msg, 0, cmd);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008925
8926 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
8927 if (pmkid)
8928 NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
8929 if (bssid)
8930 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
8931
8932 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
8933 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008934 nlmsg_free(msg);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008935 return -ENOBUFS;
8936}
8937
8938
8939static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
8940{
8941 struct i802_bss *bss = priv;
8942 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
8943 return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
8944}
8945
8946
8947static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
8948{
8949 struct i802_bss *bss = priv;
8950 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
8951 MAC2STR(bssid));
8952 return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
8953}
8954
8955
8956static int nl80211_flush_pmkid(void *priv)
8957{
8958 struct i802_bss *bss = priv;
8959 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
8960 return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
8961}
8962
8963
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008964static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
8965 const u8 *replay_ctr)
8966{
8967 struct i802_bss *bss = priv;
8968 struct wpa_driver_nl80211_data *drv = bss->drv;
8969 struct nlattr *replay_nested;
8970 struct nl_msg *msg;
8971
8972 msg = nlmsg_alloc();
8973 if (!msg)
8974 return;
8975
8976 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
8977
8978 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8979
8980 replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
8981 if (!replay_nested)
8982 goto nla_put_failure;
8983
8984 NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
8985 NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
8986 NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
8987 replay_ctr);
8988
8989 nla_nest_end(msg, replay_nested);
8990
8991 send_and_recv_msgs(drv, msg, NULL, NULL);
8992 return;
8993 nla_put_failure:
8994 nlmsg_free(msg);
8995}
8996
8997
8998static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
8999 const u8 *addr, int qos)
9000{
9001 /* send data frame to poll STA and check whether
9002 * this frame is ACKed */
9003 struct {
9004 struct ieee80211_hdr hdr;
9005 u16 qos_ctl;
9006 } STRUCT_PACKED nulldata;
9007 size_t size;
9008
9009 /* Send data frame to poll STA and check whether this frame is ACKed */
9010
9011 os_memset(&nulldata, 0, sizeof(nulldata));
9012
9013 if (qos) {
9014 nulldata.hdr.frame_control =
9015 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9016 WLAN_FC_STYPE_QOS_NULL);
9017 size = sizeof(nulldata);
9018 } else {
9019 nulldata.hdr.frame_control =
9020 IEEE80211_FC(WLAN_FC_TYPE_DATA,
9021 WLAN_FC_STYPE_NULLFUNC);
9022 size = sizeof(struct ieee80211_hdr);
9023 }
9024
9025 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
9026 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
9027 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
9028 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
9029
9030 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
9031 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
9032 "send poll frame");
9033}
9034
9035static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
9036 int qos)
9037{
9038 struct i802_bss *bss = priv;
9039 struct wpa_driver_nl80211_data *drv = bss->drv;
9040 struct nl_msg *msg;
9041
9042 if (!drv->poll_command_supported) {
9043 nl80211_send_null_frame(bss, own_addr, addr, qos);
9044 return;
9045 }
9046
9047 msg = nlmsg_alloc();
9048 if (!msg)
9049 return;
9050
9051 nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
9052
9053 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
9054 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
9055
9056 send_and_recv_msgs(drv, msg, NULL, NULL);
9057 return;
9058 nla_put_failure:
9059 nlmsg_free(msg);
9060}
9061
9062
9063static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
9064{
9065 struct nl_msg *msg;
9066
9067 msg = nlmsg_alloc();
9068 if (!msg)
9069 return -ENOMEM;
9070
9071 nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
9072 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
9073 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
9074 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
9075 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
9076nla_put_failure:
9077 nlmsg_free(msg);
9078 return -ENOBUFS;
9079}
9080
9081
9082static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
9083 int ctwindow)
9084{
9085 struct i802_bss *bss = priv;
9086
9087 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
9088 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
9089
9090 if (opp_ps != -1 || ctwindow != -1)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009091#ifdef ANDROID_P2P
9092 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
9093#else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009094 return -1; /* Not yet supported */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08009095#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009096
9097 if (legacy_ps == -1)
9098 return 0;
9099 if (legacy_ps != 0 && legacy_ps != 1)
9100 return -1; /* Not yet supported */
9101
9102 return nl80211_set_power_save(bss, legacy_ps);
9103}
9104
9105
9106#ifdef CONFIG_TDLS
9107
9108static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
9109 u8 dialog_token, u16 status_code,
9110 const u8 *buf, size_t len)
9111{
9112 struct i802_bss *bss = priv;
9113 struct wpa_driver_nl80211_data *drv = bss->drv;
9114 struct nl_msg *msg;
9115
9116 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9117 return -EOPNOTSUPP;
9118
9119 if (!dst)
9120 return -EINVAL;
9121
9122 msg = nlmsg_alloc();
9123 if (!msg)
9124 return -ENOMEM;
9125
9126 nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
9127 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
9128 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
9129 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
9130 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
9131 NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
9132 NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
9133
9134 return send_and_recv_msgs(drv, msg, NULL, NULL);
9135
9136nla_put_failure:
9137 nlmsg_free(msg);
9138 return -ENOBUFS;
9139}
9140
9141
9142static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
9143{
9144 struct i802_bss *bss = priv;
9145 struct wpa_driver_nl80211_data *drv = bss->drv;
9146 struct nl_msg *msg;
9147 enum nl80211_tdls_operation nl80211_oper;
9148
9149 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
9150 return -EOPNOTSUPP;
9151
9152 switch (oper) {
9153 case TDLS_DISCOVERY_REQ:
9154 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
9155 break;
9156 case TDLS_SETUP:
9157 nl80211_oper = NL80211_TDLS_SETUP;
9158 break;
9159 case TDLS_TEARDOWN:
9160 nl80211_oper = NL80211_TDLS_TEARDOWN;
9161 break;
9162 case TDLS_ENABLE_LINK:
9163 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
9164 break;
9165 case TDLS_DISABLE_LINK:
9166 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
9167 break;
9168 case TDLS_ENABLE:
9169 return 0;
9170 case TDLS_DISABLE:
9171 return 0;
9172 default:
9173 return -EINVAL;
9174 }
9175
9176 msg = nlmsg_alloc();
9177 if (!msg)
9178 return -ENOMEM;
9179
9180 nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
9181 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
9182 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
9183 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
9184
9185 return send_and_recv_msgs(drv, msg, NULL, NULL);
9186
9187nla_put_failure:
9188 nlmsg_free(msg);
9189 return -ENOBUFS;
9190}
9191
9192#endif /* CONFIG TDLS */
9193
9194
9195#ifdef ANDROID
9196
9197typedef struct android_wifi_priv_cmd {
9198 char *buf;
9199 int used_len;
9200 int total_len;
9201} android_wifi_priv_cmd;
9202
9203static int drv_errors = 0;
9204
9205static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
9206{
9207 drv_errors++;
9208 if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
9209 drv_errors = 0;
9210 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
9211 }
9212}
9213
9214
9215static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
9216{
9217 struct wpa_driver_nl80211_data *drv = bss->drv;
9218 struct ifreq ifr;
9219 android_wifi_priv_cmd priv_cmd;
9220 char buf[MAX_DRV_CMD_SIZE];
9221 int ret;
9222
9223 os_memset(&ifr, 0, sizeof(ifr));
9224 os_memset(&priv_cmd, 0, sizeof(priv_cmd));
9225 os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
9226
9227 os_memset(buf, 0, sizeof(buf));
9228 os_strlcpy(buf, cmd, sizeof(buf));
9229
9230 priv_cmd.buf = buf;
9231 priv_cmd.used_len = sizeof(buf);
9232 priv_cmd.total_len = sizeof(buf);
9233 ifr.ifr_data = &priv_cmd;
9234
9235 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
9236 if (ret < 0) {
9237 wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
9238 __func__);
9239 wpa_driver_send_hang_msg(drv);
9240 return ret;
9241 }
9242
9243 drv_errors = 0;
9244 return 0;
9245}
9246
9247
9248static int android_pno_start(struct i802_bss *bss,
9249 struct wpa_driver_scan_params *params)
9250{
9251 struct wpa_driver_nl80211_data *drv = bss->drv;
9252 struct ifreq ifr;
9253 android_wifi_priv_cmd priv_cmd;
9254 int ret = 0, i = 0, bp;
9255 char buf[WEXT_PNO_MAX_COMMAND_SIZE];
9256
9257 bp = WEXT_PNOSETUP_HEADER_SIZE;
9258 os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
9259 buf[bp++] = WEXT_PNO_TLV_PREFIX;
9260 buf[bp++] = WEXT_PNO_TLV_VERSION;
9261 buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
9262 buf[bp++] = WEXT_PNO_TLV_RESERVED;
9263
9264 while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
9265 /* Check that there is enough space needed for 1 more SSID, the
9266 * other sections and null termination */
9267 if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
9268 WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
9269 break;
9270 wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
9271 params->ssids[i].ssid,
9272 params->ssids[i].ssid_len);
9273 buf[bp++] = WEXT_PNO_SSID_SECTION;
9274 buf[bp++] = params->ssids[i].ssid_len;
9275 os_memcpy(&buf[bp], params->ssids[i].ssid,
9276 params->ssids[i].ssid_len);
9277 bp += params->ssids[i].ssid_len;
9278 i++;
9279 }
9280
9281 buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
9282 os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
9283 WEXT_PNO_SCAN_INTERVAL);
9284 bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
9285
9286 buf[bp++] = WEXT_PNO_REPEAT_SECTION;
9287 os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
9288 WEXT_PNO_REPEAT);
9289 bp += WEXT_PNO_REPEAT_LENGTH;
9290
9291 buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
9292 os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
9293 WEXT_PNO_MAX_REPEAT);
9294 bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
9295
9296 memset(&ifr, 0, sizeof(ifr));
9297 memset(&priv_cmd, 0, sizeof(priv_cmd));
9298 os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
9299
9300 priv_cmd.buf = buf;
9301 priv_cmd.used_len = bp;
9302 priv_cmd.total_len = bp;
9303 ifr.ifr_data = &priv_cmd;
9304
9305 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
9306
9307 if (ret < 0) {
9308 wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
9309 ret);
9310 wpa_driver_send_hang_msg(drv);
9311 return ret;
9312 }
9313
9314 drv_errors = 0;
9315
9316 return android_priv_cmd(bss, "PNOFORCE 1");
9317}
9318
9319
9320static int android_pno_stop(struct i802_bss *bss)
9321{
9322 return android_priv_cmd(bss, "PNOFORCE 0");
9323}
9324
9325#endif /* ANDROID */
9326
9327
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009328const struct wpa_driver_ops wpa_driver_nl80211_ops = {
9329 .name = "nl80211",
9330 .desc = "Linux nl80211/cfg80211",
9331 .get_bssid = wpa_driver_nl80211_get_bssid,
9332 .get_ssid = wpa_driver_nl80211_get_ssid,
9333 .set_key = wpa_driver_nl80211_set_key,
9334 .scan2 = wpa_driver_nl80211_scan,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009335 .sched_scan = wpa_driver_nl80211_sched_scan,
9336 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009337 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
9338 .deauthenticate = wpa_driver_nl80211_deauthenticate,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009339 .authenticate = wpa_driver_nl80211_authenticate,
9340 .associate = wpa_driver_nl80211_associate,
9341 .global_init = nl80211_global_init,
9342 .global_deinit = nl80211_global_deinit,
9343 .init2 = wpa_driver_nl80211_init,
9344 .deinit = wpa_driver_nl80211_deinit,
9345 .get_capa = wpa_driver_nl80211_get_capa,
9346 .set_operstate = wpa_driver_nl80211_set_operstate,
9347 .set_supp_port = wpa_driver_nl80211_set_supp_port,
9348 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009349 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009350 .if_add = wpa_driver_nl80211_if_add,
9351 .if_remove = wpa_driver_nl80211_if_remove,
9352 .send_mlme = wpa_driver_nl80211_send_mlme,
9353 .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
9354 .sta_add = wpa_driver_nl80211_sta_add,
9355 .sta_remove = wpa_driver_nl80211_sta_remove,
9356 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
9357 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
9358#ifdef HOSTAPD
9359 .hapd_init = i802_init,
9360 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -07009361 .set_wds_sta = i802_set_wds_sta,
9362#endif /* HOSTAPD */
9363#if defined(HOSTAPD) || defined(CONFIG_AP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009364 .get_seqnum = i802_get_seqnum,
9365 .flush = i802_flush,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009366 .get_inact_sec = i802_get_inact_sec,
9367 .sta_clear_stats = i802_sta_clear_stats,
9368 .set_rts = i802_set_rts,
9369 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009370 .set_tx_queue_params = i802_set_tx_queue_params,
9371 .set_sta_vlan = i802_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009372 .sta_deauth = i802_sta_deauth,
9373 .sta_disassoc = i802_sta_disassoc,
9374#endif /* HOSTAPD || CONFIG_AP */
Jouni Malinen1e6c57f2012-09-05 17:07:03 +03009375 .read_sta_data = i802_read_sta_data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009376 .set_freq = i802_set_freq,
9377 .send_action = wpa_driver_nl80211_send_action,
9378 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
9379 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
9380 .cancel_remain_on_channel =
9381 wpa_driver_nl80211_cancel_remain_on_channel,
9382 .probe_req_report = wpa_driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009383 .deinit_ap = wpa_driver_nl80211_deinit_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -07009384 .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009385 .resume = wpa_driver_nl80211_resume,
9386 .send_ft_action = nl80211_send_ft_action,
9387 .signal_monitor = nl80211_signal_monitor,
9388 .signal_poll = nl80211_signal_poll,
9389 .send_frame = nl80211_send_frame,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009390 .shared_freq = wpa_driver_nl80211_shared_freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009391 .set_param = nl80211_set_param,
9392 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -07009393 .add_pmkid = nl80211_add_pmkid,
9394 .remove_pmkid = nl80211_remove_pmkid,
9395 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009396 .set_rekey_info = nl80211_set_rekey_info,
9397 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009398 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009399#ifdef CONFIG_TDLS
9400 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
9401 .tdls_oper = nl80211_tdls_oper,
9402#endif /* CONFIG_TDLS */
9403#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009404 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009405 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009406 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
9407#endif
Dmitry Shmidt738a26e2011-07-07 14:22:14 -07009408#ifdef ANDROID
9409 .driver_cmd = wpa_driver_nl80211_driver_cmd,
9410#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009411};