blob: 8795104117f20550cf3773032d4ce8e872a680dd [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 Shmidt1f69aa52012-01-24 16:10:04 -0800192
193 u8 addr[ETH_ALEN];
194
195 int freq;
196
197 struct nl_handle *nl_preq, *nl_mgmt;
198 struct nl_cb *nl_cb;
199
200 struct nl80211_wiphy_data *wiphy_data;
201 struct dl_list wiphy_list;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700202};
203
204struct wpa_driver_nl80211_data {
205 struct nl80211_global *global;
206 struct dl_list list;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800207 struct dl_list wiphy_list;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700208 char phyname[32];
209 void *ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700210 int ifindex;
211 int if_removed;
212 int if_disabled;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800213 int ignore_if_down_event;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700214 struct rfkill_data *rfkill;
215 struct wpa_driver_capa capa;
216 int has_capability;
217
218 int operstate;
219
220 int scan_complete_events;
221
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700222 struct nl_cb *nl_cb;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223
224 u8 auth_bssid[ETH_ALEN];
225 u8 bssid[ETH_ALEN];
226 int associated;
227 u8 ssid[32];
228 size_t ssid_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800229 enum nl80211_iftype nlmode;
230 enum nl80211_iftype ap_scan_as_station;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700231 unsigned int assoc_freq;
232
233 int monitor_sock;
234 int monitor_ifidx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800235 int monitor_refcount;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700236
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800237 unsigned int disabled_11b_rates:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700238 unsigned int pending_remain_on_chan:1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800239 unsigned int in_interface_list:1;
240 unsigned int device_ap_sme:1;
241 unsigned int poll_command_supported:1;
242 unsigned int data_tx_status:1;
243 unsigned int scan_for_auth:1;
244 unsigned int retry_auth:1;
245 unsigned int use_monitor:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246
247 u64 remain_on_chan_cookie;
248 u64 send_action_cookie;
249
250 unsigned int last_mgmt_freq;
251
252 struct wpa_driver_scan_filter *filter_ssids;
253 size_t num_filter_ssids;
254
255 struct i802_bss first_bss;
256
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800257 int eapol_tx_sock;
258
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700259#ifdef HOSTAPD
260 int eapol_sock; /* socket for EAPOL frames */
261
262 int default_if_indices[16];
263 int *if_indices;
264 int num_if_indices;
265
266 int last_freq;
267 int last_freq_ht;
268#endif /* HOSTAPD */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800269
270 /* From failed authentication command */
271 int auth_freq;
272 u8 auth_bssid_[ETH_ALEN];
273 u8 auth_ssid[32];
274 size_t auth_ssid_len;
275 int auth_alg;
276 u8 *auth_ie;
277 size_t auth_ie_len;
278 u8 auth_wep_key[4][16];
279 size_t auth_wep_key_len[4];
280 int auth_wep_tx_keyidx;
281 int auth_local_state_change;
282 int auth_p2p;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700283};
284
285
286static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
287 void *timeout_ctx);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800288static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
289 enum nl80211_iftype nlmode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700290static int
291wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
292static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
293 const u8 *addr, int cmd, u16 reason_code,
294 int local_state_change);
295static void nl80211_remove_monitor_interface(
296 struct wpa_driver_nl80211_data *drv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800297static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700298 unsigned int freq, unsigned int wait,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800299 const u8 *buf, size_t buf_len, u64 *cookie,
300 int no_cck, int no_ack, int offchanok);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700301static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800302#ifdef ANDROID
303static int android_pno_start(struct i802_bss *bss,
304 struct wpa_driver_scan_params *params);
305static int android_pno_stop(struct i802_bss *bss);
306#endif /* ANDROID */
307#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -0700308static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
309 enum wpa_event_type type,
310 const u8 *frame, size_t len);
311int 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 Shmidt738a26e2011-07-07 14:22:14 -0700459int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700460 struct nl_msg *msg,
461 int (*valid_handler)(struct nl_msg *, void *),
462 void *valid_data)
463{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800464 return send_and_recv(drv->global, drv->global->nl, msg,
465 valid_handler, valid_data);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700466}
467
468
469struct family_data {
470 const char *group;
471 int id;
472};
473
474
475static int family_handler(struct nl_msg *msg, void *arg)
476{
477 struct family_data *res = arg;
478 struct nlattr *tb[CTRL_ATTR_MAX + 1];
479 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
480 struct nlattr *mcgrp;
481 int i;
482
483 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
484 genlmsg_attrlen(gnlh, 0), NULL);
485 if (!tb[CTRL_ATTR_MCAST_GROUPS])
486 return NL_SKIP;
487
488 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
489 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
490 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
491 nla_len(mcgrp), NULL);
492 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
493 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
494 os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
495 res->group,
496 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
497 continue;
498 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
499 break;
500 };
501
502 return NL_SKIP;
503}
504
505
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800506static int nl_get_multicast_id(struct nl80211_global *global,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700507 const char *family, const char *group)
508{
509 struct nl_msg *msg;
510 int ret = -1;
511 struct family_data res = { group, -ENOENT };
512
513 msg = nlmsg_alloc();
514 if (!msg)
515 return -ENOMEM;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800516 genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700517 0, 0, CTRL_CMD_GETFAMILY, 0);
518 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
519
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800520 ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700521 msg = NULL;
522 if (ret == 0)
523 ret = res.id;
524
525nla_put_failure:
526 nlmsg_free(msg);
527 return ret;
528}
529
530
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800531static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
532 struct nl_msg *msg, int flags, uint8_t cmd)
533{
534 return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
535 0, flags, cmd, 0);
536}
537
538
539struct wiphy_idx_data {
540 int wiphy_idx;
541};
542
543
544static int netdev_info_handler(struct nl_msg *msg, void *arg)
545{
546 struct nlattr *tb[NL80211_ATTR_MAX + 1];
547 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
548 struct wiphy_idx_data *info = arg;
549
550 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
551 genlmsg_attrlen(gnlh, 0), NULL);
552
553 if (tb[NL80211_ATTR_WIPHY])
554 info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
555
556 return NL_SKIP;
557}
558
559
560static int nl80211_get_wiphy_index(struct i802_bss *bss)
561{
562 struct nl_msg *msg;
563 struct wiphy_idx_data data = {
564 .wiphy_idx = -1,
565 };
566
567 msg = nlmsg_alloc();
568 if (!msg)
569 return -1;
570
571 nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
572
573 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
574
575 if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
576 return data.wiphy_idx;
577 msg = NULL;
578nla_put_failure:
579 nlmsg_free(msg);
580 return -1;
581}
582
583
584static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
585 struct nl80211_wiphy_data *w)
586{
587 struct nl_msg *msg;
588 int ret = -1;
589
590 msg = nlmsg_alloc();
591 if (!msg)
592 return -1;
593
594 nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
595
596 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
597
598 ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
599 msg = NULL;
600 if (ret) {
601 wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
602 "failed: ret=%d (%s)",
603 ret, strerror(-ret));
604 goto nla_put_failure;
605 }
606 ret = 0;
607nla_put_failure:
608 nlmsg_free(msg);
609 return ret;
610}
611
612
613static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
614{
615 struct nl80211_wiphy_data *w = eloop_ctx;
616
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800617 wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800618
619 nl_recvmsgs(handle, w->nl_cb);
620}
621
622
623static int process_beacon_event(struct nl_msg *msg, void *arg)
624{
625 struct nl80211_wiphy_data *w = arg;
626 struct wpa_driver_nl80211_data *drv;
627 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
628 struct nlattr *tb[NL80211_ATTR_MAX + 1];
629 union wpa_event_data event;
630
631 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
632 genlmsg_attrlen(gnlh, 0), NULL);
633
634 if (gnlh->cmd != NL80211_CMD_FRAME) {
635 wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
636 gnlh->cmd);
637 return NL_SKIP;
638 }
639
640 if (!tb[NL80211_ATTR_FRAME])
641 return NL_SKIP;
642
643 dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
644 wiphy_list) {
645 os_memset(&event, 0, sizeof(event));
646 event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
647 event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
648 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
649 }
650
651 return NL_SKIP;
652}
653
654
655static struct nl80211_wiphy_data *
656nl80211_get_wiphy_data_ap(struct i802_bss *bss)
657{
658 static DEFINE_DL_LIST(nl80211_wiphys);
659 struct nl80211_wiphy_data *w;
660 int wiphy_idx, found = 0;
661 struct i802_bss *tmp_bss;
662
663 if (bss->wiphy_data != NULL)
664 return bss->wiphy_data;
665
666 wiphy_idx = nl80211_get_wiphy_index(bss);
667
668 dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
669 if (w->wiphy_idx == wiphy_idx)
670 goto add;
671 }
672
673 /* alloc new one */
674 w = os_zalloc(sizeof(*w));
675 if (w == NULL)
676 return NULL;
677 w->wiphy_idx = wiphy_idx;
678 dl_list_init(&w->bsss);
679 dl_list_init(&w->drvs);
680
681 w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
682 if (!w->nl_cb) {
683 os_free(w);
684 return NULL;
685 }
686 nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
687 nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
688 w);
689
690 w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
691 "wiphy beacons");
692 if (w->nl_beacons == NULL) {
693 os_free(w);
694 return NULL;
695 }
696
697 if (nl80211_register_beacons(bss->drv, w)) {
698 nl_destroy_handles(&w->nl_beacons);
699 os_free(w);
700 return NULL;
701 }
702
703 eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
704 nl80211_recv_beacons, w, w->nl_beacons);
705
706 dl_list_add(&nl80211_wiphys, &w->list);
707
708add:
709 /* drv entry for this bss already there? */
710 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
711 if (tmp_bss->drv == bss->drv) {
712 found = 1;
713 break;
714 }
715 }
716 /* if not add it */
717 if (!found)
718 dl_list_add(&w->drvs, &bss->drv->wiphy_list);
719
720 dl_list_add(&w->bsss, &bss->wiphy_list);
721 bss->wiphy_data = w;
722 return w;
723}
724
725
726static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
727{
728 struct nl80211_wiphy_data *w = bss->wiphy_data;
729 struct i802_bss *tmp_bss;
730 int found = 0;
731
732 if (w == NULL)
733 return;
734 bss->wiphy_data = NULL;
735 dl_list_del(&bss->wiphy_list);
736
737 /* still any for this drv present? */
738 dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
739 if (tmp_bss->drv == bss->drv) {
740 found = 1;
741 break;
742 }
743 }
744 /* if not remove it */
745 if (!found)
746 dl_list_del(&bss->drv->wiphy_list);
747
748 if (!dl_list_empty(&w->bsss))
749 return;
750
751 eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
752
753 nl_cb_put(w->nl_cb);
754 nl_destroy_handles(&w->nl_beacons);
755 dl_list_del(&w->list);
756 os_free(w);
757}
758
759
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700760static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
761{
762 struct i802_bss *bss = priv;
763 struct wpa_driver_nl80211_data *drv = bss->drv;
764 if (!drv->associated)
765 return -1;
766 os_memcpy(bssid, drv->bssid, ETH_ALEN);
767 return 0;
768}
769
770
771static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
772{
773 struct i802_bss *bss = priv;
774 struct wpa_driver_nl80211_data *drv = bss->drv;
775 if (!drv->associated)
776 return -1;
777 os_memcpy(ssid, drv->ssid, drv->ssid_len);
778 return drv->ssid_len;
779}
780
781
782static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
783 char *buf, size_t len, int del)
784{
785 union wpa_event_data event;
786
787 os_memset(&event, 0, sizeof(event));
788 if (len > sizeof(event.interface_status.ifname))
789 len = sizeof(event.interface_status.ifname) - 1;
790 os_memcpy(event.interface_status.ifname, buf, len);
791 event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
792 EVENT_INTERFACE_ADDED;
793
794 wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
795 del ? "DEL" : "NEW",
796 event.interface_status.ifname,
797 del ? "removed" : "added");
798
799 if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
800 if (del)
801 drv->if_removed = 1;
802 else
803 drv->if_removed = 0;
804 }
805
806 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
807}
808
809
810static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
811 u8 *buf, size_t len)
812{
813 int attrlen, rta_len;
814 struct rtattr *attr;
815
816 attrlen = len;
817 attr = (struct rtattr *) buf;
818
819 rta_len = RTA_ALIGN(sizeof(struct rtattr));
820 while (RTA_OK(attr, attrlen)) {
821 if (attr->rta_type == IFLA_IFNAME) {
822 if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
823 == 0)
824 return 1;
825 else
826 break;
827 }
828 attr = RTA_NEXT(attr, attrlen);
829 }
830
831 return 0;
832}
833
834
835static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
836 int ifindex, u8 *buf, size_t len)
837{
838 if (drv->ifindex == ifindex)
839 return 1;
840
841 if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
842 drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
843 wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
844 "interface");
845 wpa_driver_nl80211_finish_drv_init(drv);
846 return 1;
847 }
848
849 return 0;
850}
851
852
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800853static struct wpa_driver_nl80211_data *
854nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
855{
856 struct wpa_driver_nl80211_data *drv;
857 dl_list_for_each(drv, &global->interfaces,
858 struct wpa_driver_nl80211_data, list) {
859 if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
860 have_ifidx(drv, idx))
861 return drv;
862 }
863 return NULL;
864}
865
866
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700867static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
868 struct ifinfomsg *ifi,
869 u8 *buf, size_t len)
870{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800871 struct nl80211_global *global = ctx;
872 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700873 int attrlen, rta_len;
874 struct rtattr *attr;
875 u32 brid = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800876 char namebuf[IFNAMSIZ];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700877
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800878 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
879 if (!drv) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700880 wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
881 "ifindex %d", ifi->ifi_index);
882 return;
883 }
884
885 wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
886 "(%s%s%s%s)",
887 drv->operstate, ifi->ifi_flags,
888 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
889 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
890 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
891 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
892
893 if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800894 if (if_indextoname(ifi->ifi_index, namebuf) &&
895 linux_iface_up(drv->global->ioctl_sock,
896 drv->first_bss.ifname) > 0) {
897 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
898 "event since interface %s is up", namebuf);
899 return;
900 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700901 wpa_printf(MSG_DEBUG, "nl80211: Interface down");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800902 if (drv->ignore_if_down_event) {
903 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
904 "event generated by mode change");
905 drv->ignore_if_down_event = 0;
906 } else {
907 drv->if_disabled = 1;
908 wpa_supplicant_event(drv->ctx,
909 EVENT_INTERFACE_DISABLED, NULL);
910 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700911 }
912
913 if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800914 if (if_indextoname(ifi->ifi_index, namebuf) &&
915 linux_iface_up(drv->global->ioctl_sock,
916 drv->first_bss.ifname) == 0) {
917 wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
918 "event since interface %s is down",
919 namebuf);
920 } else {
921 wpa_printf(MSG_DEBUG, "nl80211: Interface up");
922 drv->if_disabled = 0;
923 wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
924 NULL);
925 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700926 }
927
928 /*
929 * Some drivers send the association event before the operup event--in
930 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
931 * fails. This will hit us when wpa_supplicant does not need to do
932 * IEEE 802.1X authentication
933 */
934 if (drv->operstate == 1 &&
935 (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
936 !(ifi->ifi_flags & IFF_RUNNING))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800937 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700938 -1, IF_OPER_UP);
939
940 attrlen = len;
941 attr = (struct rtattr *) buf;
942 rta_len = RTA_ALIGN(sizeof(struct rtattr));
943 while (RTA_OK(attr, attrlen)) {
944 if (attr->rta_type == IFLA_IFNAME) {
945 wpa_driver_nl80211_event_link(
946 drv,
947 ((char *) attr) + rta_len,
948 attr->rta_len - rta_len, 0);
949 } else if (attr->rta_type == IFLA_MASTER)
950 brid = nla_get_u32((struct nlattr *) attr);
951 attr = RTA_NEXT(attr, attrlen);
952 }
953
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700954 if (ifi->ifi_family == AF_BRIDGE && brid) {
955 /* device has been added to bridge */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700956 if_indextoname(brid, namebuf);
957 wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
958 brid, namebuf);
959 add_ifidx(drv, brid);
960 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700961}
962
963
964static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
965 struct ifinfomsg *ifi,
966 u8 *buf, size_t len)
967{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800968 struct nl80211_global *global = ctx;
969 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700970 int attrlen, rta_len;
971 struct rtattr *attr;
972 u32 brid = 0;
973
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800974 drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
975 if (!drv) {
976 wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
977 "foreign ifindex %d", ifi->ifi_index);
978 return;
979 }
980
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700981 attrlen = len;
982 attr = (struct rtattr *) buf;
983
984 rta_len = RTA_ALIGN(sizeof(struct rtattr));
985 while (RTA_OK(attr, attrlen)) {
986 if (attr->rta_type == IFLA_IFNAME) {
987 wpa_driver_nl80211_event_link(
988 drv,
989 ((char *) attr) + rta_len,
990 attr->rta_len - rta_len, 1);
991 } else if (attr->rta_type == IFLA_MASTER)
992 brid = nla_get_u32((struct nlattr *) attr);
993 attr = RTA_NEXT(attr, attrlen);
994 }
995
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700996 if (ifi->ifi_family == AF_BRIDGE && brid) {
997 /* device has been removed from bridge */
998 char namebuf[IFNAMSIZ];
999 if_indextoname(brid, namebuf);
1000 wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
1001 "%s", brid, namebuf);
1002 del_ifidx(drv, brid);
1003 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001004}
1005
1006
1007static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
1008 const u8 *frame, size_t len)
1009{
1010 const struct ieee80211_mgmt *mgmt;
1011 union wpa_event_data event;
1012
1013 mgmt = (const struct ieee80211_mgmt *) frame;
1014 if (len < 24 + sizeof(mgmt->u.auth)) {
1015 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
1016 "frame");
1017 return;
1018 }
1019
1020 os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
1021 os_memset(&event, 0, sizeof(event));
1022 os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
1023 event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
1024 event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
1025 if (len > 24 + sizeof(mgmt->u.auth)) {
1026 event.auth.ies = mgmt->u.auth.variable;
1027 event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
1028 }
1029
1030 wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
1031}
1032
1033
Jouni Malinen87fd2792011-05-16 18:35:42 +03001034static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
1035{
1036 struct nl_msg *msg;
1037 int ret;
1038 struct nl80211_bss_info_arg arg;
1039
1040 os_memset(&arg, 0, sizeof(arg));
1041 msg = nlmsg_alloc();
1042 if (!msg)
1043 goto nla_put_failure;
1044
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001045 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Jouni Malinen87fd2792011-05-16 18:35:42 +03001046 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1047
1048 arg.drv = drv;
1049 ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
1050 msg = NULL;
1051 if (ret == 0) {
1052 wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
1053 "associated BSS from scan results: %u MHz",
1054 arg.assoc_freq);
1055 return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
1056 }
1057 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
1058 "(%s)", ret, strerror(-ret));
1059nla_put_failure:
1060 nlmsg_free(msg);
1061 return drv->assoc_freq;
1062}
1063
1064
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001065static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
1066 const u8 *frame, size_t len)
1067{
1068 const struct ieee80211_mgmt *mgmt;
1069 union wpa_event_data event;
1070 u16 status;
1071
1072 mgmt = (const struct ieee80211_mgmt *) frame;
1073 if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
1074 wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
1075 "frame");
1076 return;
1077 }
1078
1079 status = le_to_host16(mgmt->u.assoc_resp.status_code);
1080 if (status != WLAN_STATUS_SUCCESS) {
1081 os_memset(&event, 0, sizeof(event));
1082 event.assoc_reject.bssid = mgmt->bssid;
1083 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
1084 event.assoc_reject.resp_ies =
1085 (u8 *) mgmt->u.assoc_resp.variable;
1086 event.assoc_reject.resp_ies_len =
1087 len - 24 - sizeof(mgmt->u.assoc_resp);
1088 }
1089 event.assoc_reject.status_code = status;
1090
1091 wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
1092 return;
1093 }
1094
1095 drv->associated = 1;
1096 os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
1097
1098 os_memset(&event, 0, sizeof(event));
1099 if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
1100 event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
1101 event.assoc_info.resp_ies_len =
1102 len - 24 - sizeof(mgmt->u.assoc_resp);
1103 }
1104
1105 event.assoc_info.freq = drv->assoc_freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001106 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
1107}
1108
1109
1110static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
1111 enum nl80211_commands cmd, struct nlattr *status,
1112 struct nlattr *addr, struct nlattr *req_ie,
1113 struct nlattr *resp_ie)
1114{
1115 union wpa_event_data event;
1116
1117 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
1118 /*
1119 * Avoid reporting two association events that would confuse
1120 * the core code.
1121 */
1122 wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
1123 "when using userspace SME", cmd);
1124 return;
1125 }
1126
1127 os_memset(&event, 0, sizeof(event));
1128 if (cmd == NL80211_CMD_CONNECT &&
1129 nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
1130 if (addr)
1131 event.assoc_reject.bssid = nla_data(addr);
1132 if (resp_ie) {
1133 event.assoc_reject.resp_ies = nla_data(resp_ie);
1134 event.assoc_reject.resp_ies_len = nla_len(resp_ie);
1135 }
1136 event.assoc_reject.status_code = nla_get_u16(status);
1137 wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
1138 return;
1139 }
1140
1141 drv->associated = 1;
1142 if (addr)
1143 os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
1144
1145 if (req_ie) {
1146 event.assoc_info.req_ies = nla_data(req_ie);
1147 event.assoc_info.req_ies_len = nla_len(req_ie);
1148 }
1149 if (resp_ie) {
1150 event.assoc_info.resp_ies = nla_data(resp_ie);
1151 event.assoc_info.resp_ies_len = nla_len(resp_ie);
1152 }
1153
Jouni Malinen87fd2792011-05-16 18:35:42 +03001154 event.assoc_info.freq = nl80211_get_assoc_freq(drv);
1155
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001156 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
1157}
1158
1159
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001160static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001161 struct nlattr *reason, struct nlattr *addr,
1162 struct nlattr *by_ap)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001163{
1164 union wpa_event_data data;
1165
1166 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
1167 /*
1168 * Avoid reporting two disassociation events that could
1169 * confuse the core code.
1170 */
1171 wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
1172 "event when using userspace SME");
1173 return;
1174 }
1175
1176 drv->associated = 0;
1177 os_memset(&data, 0, sizeof(data));
1178 if (reason)
1179 data.disassoc_info.reason_code = nla_get_u16(reason);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001180 data.disassoc_info.locally_generated = by_ap == NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001181 wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
1182}
1183
1184
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001185static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
1186 enum nl80211_commands cmd, struct nlattr *addr)
1187{
1188 union wpa_event_data event;
1189 enum wpa_event_type ev;
1190
1191 if (nla_len(addr) != ETH_ALEN)
1192 return;
1193
1194 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
1195 cmd, MAC2STR((u8 *) nla_data(addr)));
1196
1197 if (cmd == NL80211_CMD_AUTHENTICATE)
1198 ev = EVENT_AUTH_TIMED_OUT;
1199 else if (cmd == NL80211_CMD_ASSOCIATE)
1200 ev = EVENT_ASSOC_TIMED_OUT;
1201 else
1202 return;
1203
1204 os_memset(&event, 0, sizeof(event));
1205 os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
1206 wpa_supplicant_event(drv->ctx, ev, &event);
1207}
1208
1209
1210static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
1211 struct nlattr *freq, const u8 *frame, size_t len)
1212{
1213 const struct ieee80211_mgmt *mgmt;
1214 union wpa_event_data event;
1215 u16 fc, stype;
1216
1217 mgmt = (const struct ieee80211_mgmt *) frame;
1218 if (len < 24) {
1219 wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
1220 return;
1221 }
1222
1223 fc = le_to_host16(mgmt->frame_control);
1224 stype = WLAN_FC_GET_STYPE(fc);
1225
1226 os_memset(&event, 0, sizeof(event));
1227 if (freq) {
1228 event.rx_action.freq = nla_get_u32(freq);
1229 drv->last_mgmt_freq = event.rx_action.freq;
1230 }
1231 if (stype == WLAN_FC_STYPE_ACTION) {
1232 event.rx_action.da = mgmt->da;
1233 event.rx_action.sa = mgmt->sa;
1234 event.rx_action.bssid = mgmt->bssid;
1235 event.rx_action.category = mgmt->u.action.category;
1236 event.rx_action.data = &mgmt->u.action.category + 1;
1237 event.rx_action.len = frame + len - event.rx_action.data;
1238 wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
1239 } else {
1240 event.rx_mgmt.frame = frame;
1241 event.rx_mgmt.frame_len = len;
1242 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
1243 }
1244}
1245
1246
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001247static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
1248 struct nlattr *cookie, const u8 *frame,
1249 size_t len, struct nlattr *ack)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001250{
1251 union wpa_event_data event;
1252 const struct ieee80211_hdr *hdr;
1253 u16 fc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001254
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001255 if (!is_ap_interface(drv->nlmode)) {
1256 u64 cookie_val;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001257
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001258 if (!cookie)
1259 return;
1260
1261 cookie_val = nla_get_u64(cookie);
1262 wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
1263 " cookie=0%llx%s (ack=%d)",
1264 (long long unsigned int) cookie_val,
1265 cookie_val == drv->send_action_cookie ?
1266 " (match)" : " (unknown)", ack != NULL);
1267 if (cookie_val != drv->send_action_cookie)
1268 return;
1269 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001270
1271 hdr = (const struct ieee80211_hdr *) frame;
1272 fc = le_to_host16(hdr->frame_control);
1273
1274 os_memset(&event, 0, sizeof(event));
1275 event.tx_status.type = WLAN_FC_GET_TYPE(fc);
1276 event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
1277 event.tx_status.dst = hdr->addr1;
1278 event.tx_status.data = frame;
1279 event.tx_status.data_len = len;
1280 event.tx_status.ack = ack != NULL;
1281 wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
1282}
1283
1284
1285static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
1286 enum wpa_event_type type,
1287 const u8 *frame, size_t len)
1288{
1289 const struct ieee80211_mgmt *mgmt;
1290 union wpa_event_data event;
1291 const u8 *bssid = NULL;
1292 u16 reason_code = 0;
1293
1294 mgmt = (const struct ieee80211_mgmt *) frame;
1295 if (len >= 24) {
1296 bssid = mgmt->bssid;
1297
1298 if (drv->associated != 0 &&
1299 os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
1300 os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
1301 /*
1302 * We have presumably received this deauth as a
1303 * response to a clear_state_mismatch() outgoing
1304 * deauth. Don't let it take us offline!
1305 */
1306 wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
1307 "from Unknown BSSID " MACSTR " -- ignoring",
1308 MAC2STR(bssid));
1309 return;
1310 }
1311 }
1312
1313 drv->associated = 0;
1314 os_memset(&event, 0, sizeof(event));
1315
1316 /* Note: Same offset for Reason Code in both frame subtypes */
1317 if (len >= 24 + sizeof(mgmt->u.deauth))
1318 reason_code = le_to_host16(mgmt->u.deauth.reason_code);
1319
1320 if (type == EVENT_DISASSOC) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001321 event.disassoc_info.locally_generated =
1322 !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001323 event.disassoc_info.addr = bssid;
1324 event.disassoc_info.reason_code = reason_code;
1325 if (frame + len > mgmt->u.disassoc.variable) {
1326 event.disassoc_info.ie = mgmt->u.disassoc.variable;
1327 event.disassoc_info.ie_len = frame + len -
1328 mgmt->u.disassoc.variable;
1329 }
1330 } else {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001331 event.deauth_info.locally_generated =
1332 !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001333 event.deauth_info.addr = bssid;
1334 event.deauth_info.reason_code = reason_code;
1335 if (frame + len > mgmt->u.deauth.variable) {
1336 event.deauth_info.ie = mgmt->u.deauth.variable;
1337 event.deauth_info.ie_len = frame + len -
1338 mgmt->u.deauth.variable;
1339 }
1340 }
1341
1342 wpa_supplicant_event(drv->ctx, type, &event);
1343}
1344
1345
1346static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
1347 enum wpa_event_type type,
1348 const u8 *frame, size_t len)
1349{
1350 const struct ieee80211_mgmt *mgmt;
1351 union wpa_event_data event;
1352 u16 reason_code = 0;
1353
1354 if (len < 24)
1355 return;
1356
1357 mgmt = (const struct ieee80211_mgmt *) frame;
1358
1359 os_memset(&event, 0, sizeof(event));
1360 /* Note: Same offset for Reason Code in both frame subtypes */
1361 if (len >= 24 + sizeof(mgmt->u.deauth))
1362 reason_code = le_to_host16(mgmt->u.deauth.reason_code);
1363
1364 if (type == EVENT_UNPROT_DISASSOC) {
1365 event.unprot_disassoc.sa = mgmt->sa;
1366 event.unprot_disassoc.da = mgmt->da;
1367 event.unprot_disassoc.reason_code = reason_code;
1368 } else {
1369 event.unprot_deauth.sa = mgmt->sa;
1370 event.unprot_deauth.da = mgmt->da;
1371 event.unprot_deauth.reason_code = reason_code;
1372 }
1373
1374 wpa_supplicant_event(drv->ctx, type, &event);
1375}
1376
1377
1378static void mlme_event(struct wpa_driver_nl80211_data *drv,
1379 enum nl80211_commands cmd, struct nlattr *frame,
1380 struct nlattr *addr, struct nlattr *timed_out,
1381 struct nlattr *freq, struct nlattr *ack,
1382 struct nlattr *cookie)
1383{
1384 if (timed_out && addr) {
1385 mlme_timeout_event(drv, cmd, addr);
1386 return;
1387 }
1388
1389 if (frame == NULL) {
1390 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
1391 "data", cmd);
1392 return;
1393 }
1394
1395 wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
1396 wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
1397 nla_data(frame), nla_len(frame));
1398
1399 switch (cmd) {
1400 case NL80211_CMD_AUTHENTICATE:
1401 mlme_event_auth(drv, nla_data(frame), nla_len(frame));
1402 break;
1403 case NL80211_CMD_ASSOCIATE:
1404 mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
1405 break;
1406 case NL80211_CMD_DEAUTHENTICATE:
1407 mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
1408 nla_data(frame), nla_len(frame));
1409 break;
1410 case NL80211_CMD_DISASSOCIATE:
1411 mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
1412 nla_data(frame), nla_len(frame));
1413 break;
1414 case NL80211_CMD_FRAME:
1415 mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
1416 break;
1417 case NL80211_CMD_FRAME_TX_STATUS:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001418 mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
1419 nla_len(frame), ack);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001420 break;
1421 case NL80211_CMD_UNPROT_DEAUTHENTICATE:
1422 mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
1423 nla_data(frame), nla_len(frame));
1424 break;
1425 case NL80211_CMD_UNPROT_DISASSOCIATE:
1426 mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
1427 nla_data(frame), nla_len(frame));
1428 break;
1429 default:
1430 break;
1431 }
1432}
1433
1434
1435static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
1436 struct nlattr *tb[])
1437{
1438 union wpa_event_data data;
1439
1440 wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
1441 os_memset(&data, 0, sizeof(data));
1442 if (tb[NL80211_ATTR_MAC]) {
1443 wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
1444 nla_data(tb[NL80211_ATTR_MAC]),
1445 nla_len(tb[NL80211_ATTR_MAC]));
1446 data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
1447 }
1448 if (tb[NL80211_ATTR_KEY_SEQ]) {
1449 wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
1450 nla_data(tb[NL80211_ATTR_KEY_SEQ]),
1451 nla_len(tb[NL80211_ATTR_KEY_SEQ]));
1452 }
1453 if (tb[NL80211_ATTR_KEY_TYPE]) {
1454 enum nl80211_key_type key_type =
1455 nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
1456 wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
1457 if (key_type == NL80211_KEYTYPE_PAIRWISE)
1458 data.michael_mic_failure.unicast = 1;
1459 } else
1460 data.michael_mic_failure.unicast = 1;
1461
1462 if (tb[NL80211_ATTR_KEY_IDX]) {
1463 u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
1464 wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
1465 }
1466
1467 wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
1468}
1469
1470
1471static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
1472 struct nlattr *tb[])
1473{
1474 if (tb[NL80211_ATTR_MAC] == NULL) {
1475 wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
1476 "event");
1477 return;
1478 }
1479 os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
1480 drv->associated = 1;
1481 wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
1482 MAC2STR(drv->bssid));
1483
1484 wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
1485}
1486
1487
1488static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
1489 int cancel_event, struct nlattr *tb[])
1490{
1491 unsigned int freq, chan_type, duration;
1492 union wpa_event_data data;
1493 u64 cookie;
1494
1495 if (tb[NL80211_ATTR_WIPHY_FREQ])
1496 freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
1497 else
1498 freq = 0;
1499
1500 if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
1501 chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1502 else
1503 chan_type = 0;
1504
1505 if (tb[NL80211_ATTR_DURATION])
1506 duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
1507 else
1508 duration = 0;
1509
1510 if (tb[NL80211_ATTR_COOKIE])
1511 cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
1512 else
1513 cookie = 0;
1514
1515 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
1516 "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
1517 cancel_event, freq, chan_type, duration,
1518 (long long unsigned int) cookie,
1519 cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
1520
1521 if (cookie != drv->remain_on_chan_cookie)
1522 return; /* not for us */
1523
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001524 if (cancel_event)
1525 drv->pending_remain_on_chan = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001526
1527 os_memset(&data, 0, sizeof(data));
1528 data.remain_on_channel.freq = freq;
1529 data.remain_on_channel.duration = duration;
1530 wpa_supplicant_event(drv->ctx, cancel_event ?
1531 EVENT_CANCEL_REMAIN_ON_CHANNEL :
1532 EVENT_REMAIN_ON_CHANNEL, &data);
1533}
1534
1535
1536static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
1537 struct nlattr *tb[])
1538{
1539 union wpa_event_data event;
1540 struct nlattr *nl;
1541 int rem;
1542 struct scan_info *info;
1543#define MAX_REPORT_FREQS 50
1544 int freqs[MAX_REPORT_FREQS];
1545 int num_freqs = 0;
1546
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001547 if (drv->scan_for_auth) {
1548 drv->scan_for_auth = 0;
1549 wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
1550 "cfg80211 BSS entry");
1551 wpa_driver_nl80211_authenticate_retry(drv);
1552 return;
1553 }
1554
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001555 os_memset(&event, 0, sizeof(event));
1556 info = &event.scan_info;
1557 info->aborted = aborted;
1558
1559 if (tb[NL80211_ATTR_SCAN_SSIDS]) {
1560 nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
1561 struct wpa_driver_scan_ssid *s =
1562 &info->ssids[info->num_ssids];
1563 s->ssid = nla_data(nl);
1564 s->ssid_len = nla_len(nl);
1565 info->num_ssids++;
1566 if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
1567 break;
1568 }
1569 }
1570 if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
1571 nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
1572 {
1573 freqs[num_freqs] = nla_get_u32(nl);
1574 num_freqs++;
1575 if (num_freqs == MAX_REPORT_FREQS - 1)
1576 break;
1577 }
1578 info->freqs = freqs;
1579 info->num_freqs = num_freqs;
1580 }
1581 wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
1582}
1583
1584
1585static int get_link_signal(struct nl_msg *msg, void *arg)
1586{
1587 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1588 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1589 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1590 static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
1591 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
1592 };
1593 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1594 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1595 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1596 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1597 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1598 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1599 };
1600 struct wpa_signal_info *sig_change = arg;
1601
1602 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1603 genlmsg_attrlen(gnlh, 0), NULL);
1604 if (!tb[NL80211_ATTR_STA_INFO] ||
1605 nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1606 tb[NL80211_ATTR_STA_INFO], policy))
1607 return NL_SKIP;
1608 if (!sinfo[NL80211_STA_INFO_SIGNAL])
1609 return NL_SKIP;
1610
1611 sig_change->current_signal =
1612 (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1613
1614 if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
1615 if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1616 sinfo[NL80211_STA_INFO_TX_BITRATE],
1617 rate_policy)) {
1618 sig_change->current_txrate = 0;
1619 } else {
1620 if (rinfo[NL80211_RATE_INFO_BITRATE]) {
1621 sig_change->current_txrate =
1622 nla_get_u16(rinfo[
1623 NL80211_RATE_INFO_BITRATE]) * 100;
1624 }
1625 }
1626 }
1627
1628 return NL_SKIP;
1629}
1630
1631
1632static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
1633 struct wpa_signal_info *sig)
1634{
1635 struct nl_msg *msg;
1636
1637 sig->current_signal = -9999;
1638 sig->current_txrate = 0;
1639
1640 msg = nlmsg_alloc();
1641 if (!msg)
1642 return -ENOMEM;
1643
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001644 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001645
1646 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1647 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
1648
1649 return send_and_recv_msgs(drv, msg, get_link_signal, sig);
1650 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001651 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001652 return -ENOBUFS;
1653}
1654
1655
1656static int get_link_noise(struct nl_msg *msg, void *arg)
1657{
1658 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1659 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1660 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1661 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1662 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1663 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1664 };
1665 struct wpa_signal_info *sig_change = arg;
1666
1667 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1668 genlmsg_attrlen(gnlh, 0), NULL);
1669
1670 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1671 wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
1672 return NL_SKIP;
1673 }
1674
1675 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1676 tb[NL80211_ATTR_SURVEY_INFO],
1677 survey_policy)) {
1678 wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
1679 "attributes!");
1680 return NL_SKIP;
1681 }
1682
1683 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1684 return NL_SKIP;
1685
1686 if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1687 sig_change->frequency)
1688 return NL_SKIP;
1689
1690 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1691 return NL_SKIP;
1692
1693 sig_change->current_noise =
1694 (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1695
1696 return NL_SKIP;
1697}
1698
1699
1700static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
1701 struct wpa_signal_info *sig_change)
1702{
1703 struct nl_msg *msg;
1704
1705 sig_change->current_noise = 9999;
1706 sig_change->frequency = drv->assoc_freq;
1707
1708 msg = nlmsg_alloc();
1709 if (!msg)
1710 return -ENOMEM;
1711
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001712 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001713
1714 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1715
1716 return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
1717 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001718 nlmsg_free(msg);
1719 return -ENOBUFS;
1720}
1721
1722
1723static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
1724{
1725 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1726 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1727 struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
1728 static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
1729 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1730 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1731 };
1732 struct wpa_scan_results *scan_results = arg;
1733 struct wpa_scan_res *scan_res;
1734 size_t i;
1735
1736 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1737 genlmsg_attrlen(gnlh, 0), NULL);
1738
1739 if (!tb[NL80211_ATTR_SURVEY_INFO]) {
1740 wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
1741 return NL_SKIP;
1742 }
1743
1744 if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
1745 tb[NL80211_ATTR_SURVEY_INFO],
1746 survey_policy)) {
1747 wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
1748 "attributes");
1749 return NL_SKIP;
1750 }
1751
1752 if (!sinfo[NL80211_SURVEY_INFO_NOISE])
1753 return NL_SKIP;
1754
1755 if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
1756 return NL_SKIP;
1757
1758 for (i = 0; i < scan_results->num; ++i) {
1759 scan_res = scan_results->res[i];
1760 if (!scan_res)
1761 continue;
1762 if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
1763 scan_res->freq)
1764 continue;
1765 if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
1766 continue;
1767 scan_res->noise = (s8)
1768 nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
1769 scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
1770 }
1771
1772 return NL_SKIP;
1773}
1774
1775
1776static int nl80211_get_noise_for_scan_results(
1777 struct wpa_driver_nl80211_data *drv,
1778 struct wpa_scan_results *scan_res)
1779{
1780 struct nl_msg *msg;
1781
1782 msg = nlmsg_alloc();
1783 if (!msg)
1784 return -ENOMEM;
1785
1786 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
1787
1788 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
1789
1790 return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
1791 scan_res);
1792 nla_put_failure:
1793 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001794 return -ENOBUFS;
1795}
1796
1797
1798static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
1799 struct nlattr *tb[])
1800{
1801 static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
1802 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
1803 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
1804 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
1805 [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
1806 };
1807 struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
1808 enum nl80211_cqm_rssi_threshold_event event;
1809 union wpa_event_data ed;
1810 struct wpa_signal_info sig;
1811 int res;
1812
1813 if (tb[NL80211_ATTR_CQM] == NULL ||
1814 nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
1815 cqm_policy)) {
1816 wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
1817 return;
1818 }
1819
1820 os_memset(&ed, 0, sizeof(ed));
1821
1822 if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
1823 if (!tb[NL80211_ATTR_MAC])
1824 return;
1825 os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
1826 ETH_ALEN);
1827 wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
1828 return;
1829 }
1830
1831 if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
1832 return;
1833 event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
1834
1835 if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
1836 wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
1837 "event: RSSI high");
1838 ed.signal_change.above_threshold = 1;
1839 } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
1840 wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
1841 "event: RSSI low");
1842 ed.signal_change.above_threshold = 0;
1843 } else
1844 return;
1845
1846 res = nl80211_get_link_signal(drv, &sig);
1847 if (res == 0) {
1848 ed.signal_change.current_signal = sig.current_signal;
1849 ed.signal_change.current_txrate = sig.current_txrate;
1850 wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
1851 sig.current_signal, sig.current_txrate);
1852 }
1853
1854 res = nl80211_get_link_noise(drv, &sig);
1855 if (res == 0) {
1856 ed.signal_change.current_noise = sig.current_noise;
1857 wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
1858 sig.current_noise);
1859 }
1860
1861 wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
1862}
1863
1864
1865static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
1866 struct nlattr **tb)
1867{
1868 u8 *addr;
1869 union wpa_event_data data;
1870
1871 if (tb[NL80211_ATTR_MAC] == NULL)
1872 return;
1873 addr = nla_data(tb[NL80211_ATTR_MAC]);
1874 wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001875
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001876 if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001877 u8 *ies = NULL;
1878 size_t ies_len = 0;
1879 if (tb[NL80211_ATTR_IE]) {
1880 ies = nla_data(tb[NL80211_ATTR_IE]);
1881 ies_len = nla_len(tb[NL80211_ATTR_IE]);
1882 }
1883 wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
1884 drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
1885 return;
1886 }
1887
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001888 if (drv->nlmode != NL80211_IFTYPE_ADHOC)
1889 return;
1890
1891 os_memset(&data, 0, sizeof(data));
1892 os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
1893 wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
1894}
1895
1896
1897static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
1898 struct nlattr **tb)
1899{
1900 u8 *addr;
1901 union wpa_event_data data;
1902
1903 if (tb[NL80211_ATTR_MAC] == NULL)
1904 return;
1905 addr = nla_data(tb[NL80211_ATTR_MAC]);
1906 wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
1907 MAC2STR(addr));
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001908
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001909 if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001910 drv_event_disassoc(drv->ctx, addr);
1911 return;
1912 }
1913
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001914 if (drv->nlmode != NL80211_IFTYPE_ADHOC)
1915 return;
1916
1917 os_memset(&data, 0, sizeof(data));
1918 os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
1919 wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
1920}
1921
1922
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001923static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
1924 struct nlattr **tb)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001925{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001926 struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
1927 static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
1928 [NL80211_REKEY_DATA_KEK] = {
1929 .minlen = NL80211_KEK_LEN,
1930 .maxlen = NL80211_KEK_LEN,
1931 },
1932 [NL80211_REKEY_DATA_KCK] = {
1933 .minlen = NL80211_KCK_LEN,
1934 .maxlen = NL80211_KCK_LEN,
1935 },
1936 [NL80211_REKEY_DATA_REPLAY_CTR] = {
1937 .minlen = NL80211_REPLAY_CTR_LEN,
1938 .maxlen = NL80211_REPLAY_CTR_LEN,
1939 },
1940 };
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001941 union wpa_event_data data;
1942
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001943 if (!tb[NL80211_ATTR_MAC])
1944 return;
1945 if (!tb[NL80211_ATTR_REKEY_DATA])
1946 return;
1947 if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
1948 tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
1949 return;
1950 if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
1951 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001952
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001953 os_memset(&data, 0, sizeof(data));
1954 data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
1955 wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
1956 MAC2STR(data.driver_gtk_rekey.bssid));
1957 data.driver_gtk_rekey.replay_ctr =
1958 nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
1959 wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
1960 data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
1961 wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
1962}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001963
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001964
1965static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
1966 struct nlattr **tb)
1967{
1968 struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
1969 static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
1970 [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
1971 [NL80211_PMKSA_CANDIDATE_BSSID] = {
1972 .minlen = ETH_ALEN,
1973 .maxlen = ETH_ALEN,
1974 },
1975 [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
1976 };
1977 union wpa_event_data data;
1978
1979 if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
1980 return;
1981 if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
1982 tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
1983 return;
1984 if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
1985 !cand[NL80211_PMKSA_CANDIDATE_BSSID])
1986 return;
1987
1988 os_memset(&data, 0, sizeof(data));
1989 os_memcpy(data.pmkid_candidate.bssid,
1990 nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
1991 data.pmkid_candidate.index =
1992 nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
1993 data.pmkid_candidate.preauth =
1994 cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
1995 wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
1996}
1997
1998
1999static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
2000 struct nlattr **tb)
2001{
2002 union wpa_event_data data;
2003
2004 if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
2005 return;
2006
2007 os_memset(&data, 0, sizeof(data));
2008 os_memcpy(data.client_poll.addr,
2009 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
2010
2011 wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
2012}
2013
2014
2015static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
2016 int wds)
2017{
2018 struct wpa_driver_nl80211_data *drv = bss->drv;
2019 union wpa_event_data event;
2020
2021 if (!tb[NL80211_ATTR_MAC])
2022 return;
2023
2024 os_memset(&event, 0, sizeof(event));
2025 event.rx_from_unknown.bssid = bss->addr;
2026 event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
2027 event.rx_from_unknown.wds = wds;
2028
2029 wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
2030}
2031
2032
2033static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
2034 int cmd, struct nlattr **tb)
2035{
2036 if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
2037 (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
2038 cmd == NL80211_CMD_SCAN_ABORTED)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002039 wpa_driver_nl80211_set_mode(&drv->first_bss,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002040 drv->ap_scan_as_station);
2041 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002042 }
2043
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002044 switch (cmd) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002045 case NL80211_CMD_TRIGGER_SCAN:
2046 wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
2047 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002048 case NL80211_CMD_START_SCHED_SCAN:
2049 wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
2050 break;
2051 case NL80211_CMD_SCHED_SCAN_STOPPED:
2052 wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
2053 wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
2054 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002055 case NL80211_CMD_NEW_SCAN_RESULTS:
2056 wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
2057 drv->scan_complete_events = 1;
2058 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
2059 drv->ctx);
2060 send_scan_event(drv, 0, tb);
2061 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002062 case NL80211_CMD_SCHED_SCAN_RESULTS:
2063 wpa_printf(MSG_DEBUG,
2064 "nl80211: New sched scan results available");
2065 send_scan_event(drv, 0, tb);
2066 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002067 case NL80211_CMD_SCAN_ABORTED:
2068 wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
2069 /*
2070 * Need to indicate that scan results are available in order
2071 * not to make wpa_supplicant stop its scanning.
2072 */
2073 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
2074 drv->ctx);
2075 send_scan_event(drv, 1, tb);
2076 break;
2077 case NL80211_CMD_AUTHENTICATE:
2078 case NL80211_CMD_ASSOCIATE:
2079 case NL80211_CMD_DEAUTHENTICATE:
2080 case NL80211_CMD_DISASSOCIATE:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002081 case NL80211_CMD_FRAME_TX_STATUS:
2082 case NL80211_CMD_UNPROT_DEAUTHENTICATE:
2083 case NL80211_CMD_UNPROT_DISASSOCIATE:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002084 mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002085 tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
2086 tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
2087 tb[NL80211_ATTR_COOKIE]);
2088 break;
2089 case NL80211_CMD_CONNECT:
2090 case NL80211_CMD_ROAM:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002091 mlme_event_connect(drv, cmd,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002092 tb[NL80211_ATTR_STATUS_CODE],
2093 tb[NL80211_ATTR_MAC],
2094 tb[NL80211_ATTR_REQ_IE],
2095 tb[NL80211_ATTR_RESP_IE]);
2096 break;
2097 case NL80211_CMD_DISCONNECT:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002098 mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002099 tb[NL80211_ATTR_MAC],
2100 tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002101 break;
2102 case NL80211_CMD_MICHAEL_MIC_FAILURE:
2103 mlme_event_michael_mic_failure(drv, tb);
2104 break;
2105 case NL80211_CMD_JOIN_IBSS:
2106 mlme_event_join_ibss(drv, tb);
2107 break;
2108 case NL80211_CMD_REMAIN_ON_CHANNEL:
2109 mlme_event_remain_on_channel(drv, 0, tb);
2110 break;
2111 case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
2112 mlme_event_remain_on_channel(drv, 1, tb);
2113 break;
2114 case NL80211_CMD_NOTIFY_CQM:
2115 nl80211_cqm_event(drv, tb);
2116 break;
2117 case NL80211_CMD_REG_CHANGE:
2118 wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
2119 wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
2120 NULL);
2121 break;
2122 case NL80211_CMD_REG_BEACON_HINT:
2123 wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
2124 wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
2125 NULL);
2126 break;
2127 case NL80211_CMD_NEW_STATION:
2128 nl80211_new_station_event(drv, tb);
2129 break;
2130 case NL80211_CMD_DEL_STATION:
2131 nl80211_del_station_event(drv, tb);
2132 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002133 case NL80211_CMD_SET_REKEY_OFFLOAD:
2134 nl80211_rekey_offload_event(drv, tb);
2135 break;
2136 case NL80211_CMD_PMKSA_CANDIDATE:
2137 nl80211_pmksa_candidate_event(drv, tb);
2138 break;
2139 case NL80211_CMD_PROBE_CLIENT:
2140 nl80211_client_probe_event(drv, tb);
2141 break;
2142 default:
2143 wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
2144 "(cmd=%d)", cmd);
2145 break;
2146 }
2147}
2148
2149
2150static int process_drv_event(struct nl_msg *msg, void *arg)
2151{
2152 struct wpa_driver_nl80211_data *drv = arg;
2153 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2154 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2155
2156 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2157 genlmsg_attrlen(gnlh, 0), NULL);
2158
2159 if (tb[NL80211_ATTR_IFINDEX]) {
2160 int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2161 if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
2162 wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
2163 " for foreign interface (ifindex %d)",
2164 gnlh->cmd, ifindex);
2165 return NL_SKIP;
2166 }
2167 }
2168
2169 do_process_drv_event(drv, gnlh->cmd, tb);
2170 return NL_SKIP;
2171}
2172
2173
2174static int process_global_event(struct nl_msg *msg, void *arg)
2175{
2176 struct nl80211_global *global = arg;
2177 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2178 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2179 struct wpa_driver_nl80211_data *drv;
2180 int ifidx = -1;
2181
2182 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2183 genlmsg_attrlen(gnlh, 0), NULL);
2184
2185 if (tb[NL80211_ATTR_IFINDEX])
2186 ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2187
2188 dl_list_for_each(drv, &global->interfaces,
2189 struct wpa_driver_nl80211_data, list) {
2190 if (ifidx == -1 || ifidx == drv->ifindex ||
Dmitry Shmidt6e95f5f2012-05-30 17:00:15 -07002191 have_ifidx(drv, ifidx)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002192 do_process_drv_event(drv, gnlh->cmd, tb);
Dmitry Shmidt98f9e762012-05-30 11:18:46 -07002193#ifdef ANDROID_P2P
2194 break;
2195#endif
Dmitry Shmidt6e95f5f2012-05-30 17:00:15 -07002196 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002197 }
2198
2199 return NL_SKIP;
2200}
2201
2202
2203static int process_bss_event(struct nl_msg *msg, void *arg)
2204{
2205 struct i802_bss *bss = arg;
2206 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2207 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2208
2209 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2210 genlmsg_attrlen(gnlh, 0), NULL);
2211
2212 switch (gnlh->cmd) {
2213 case NL80211_CMD_FRAME:
2214 case NL80211_CMD_FRAME_TX_STATUS:
2215 mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
2216 tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
2217 tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
2218 tb[NL80211_ATTR_COOKIE]);
2219 break;
2220 case NL80211_CMD_UNEXPECTED_FRAME:
2221 nl80211_spurious_frame(bss, tb, 0);
2222 break;
2223 case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
2224 nl80211_spurious_frame(bss, tb, 1);
2225 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002226 default:
2227 wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
2228 "(cmd=%d)", gnlh->cmd);
2229 break;
2230 }
2231
2232 return NL_SKIP;
2233}
2234
2235
2236static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
2237 void *handle)
2238{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002239 struct nl_cb *cb = eloop_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002240
2241 wpa_printf(MSG_DEBUG, "nl80211: Event message available");
2242
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002243 nl_recvmsgs(handle, cb);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002244}
2245
2246
2247/**
2248 * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
2249 * @priv: driver_nl80211 private data
2250 * @alpha2_arg: country to which to switch to
2251 * Returns: 0 on success, -1 on failure
2252 *
2253 * This asks nl80211 to set the regulatory domain for given
2254 * country ISO / IEC alpha2.
2255 */
2256static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
2257{
2258 struct i802_bss *bss = priv;
2259 struct wpa_driver_nl80211_data *drv = bss->drv;
2260 char alpha2[3];
2261 struct nl_msg *msg;
2262
2263 msg = nlmsg_alloc();
2264 if (!msg)
2265 return -ENOMEM;
2266
2267 alpha2[0] = alpha2_arg[0];
2268 alpha2[1] = alpha2_arg[1];
2269 alpha2[2] = '\0';
2270
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002271 nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002272
2273 NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
2274 if (send_and_recv_msgs(drv, msg, NULL, NULL))
2275 return -EINVAL;
2276 return 0;
2277nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002278 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002279 return -EINVAL;
2280}
2281
2282
2283struct wiphy_info_data {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002284 struct wpa_driver_capa *capa;
2285
2286 unsigned int error:1;
2287 unsigned int device_ap_sme:1;
2288 unsigned int poll_command_supported:1;
2289 unsigned int data_tx_status:1;
2290 unsigned int monitor_supported:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002291};
2292
2293
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002294static unsigned int probe_resp_offload_support(int supp_protocols)
2295{
2296 unsigned int prot = 0;
2297
2298 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
2299 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
2300 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
2301 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
2302 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
2303 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
2304 if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
2305 prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
2306
2307 return prot;
2308}
2309
2310
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002311static int wiphy_info_handler(struct nl_msg *msg, void *arg)
2312{
2313 struct nlattr *tb[NL80211_ATTR_MAX + 1];
2314 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2315 struct wiphy_info_data *info = arg;
2316 int p2p_go_supported = 0, p2p_client_supported = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002317 int p2p_concurrent = 0;
2318 int auth_supported = 0, connect_supported = 0;
2319 struct wpa_driver_capa *capa = info->capa;
2320 static struct nla_policy
2321 iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
2322 [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
2323 [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
2324 [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
2325 [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
2326 },
2327 iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
2328 [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
2329 [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
2330 };
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002331
2332 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2333 genlmsg_attrlen(gnlh, 0), NULL);
2334
2335 if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002336 capa->max_scan_ssids =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002337 nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
2338
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002339 if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
2340 capa->max_sched_scan_ssids =
2341 nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
2342
2343 if (tb[NL80211_ATTR_MAX_MATCH_SETS])
2344 capa->max_match_sets =
2345 nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
2346
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002347 if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
2348 struct nlattr *nl_mode;
2349 int i;
2350 nla_for_each_nested(nl_mode,
2351 tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
2352 switch (nla_type(nl_mode)) {
2353 case NL80211_IFTYPE_AP:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002354 capa->flags |= WPA_DRIVER_FLAGS_AP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002355 break;
2356 case NL80211_IFTYPE_P2P_GO:
2357 p2p_go_supported = 1;
2358 break;
2359 case NL80211_IFTYPE_P2P_CLIENT:
2360 p2p_client_supported = 1;
2361 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002362 case NL80211_IFTYPE_MONITOR:
2363 info->monitor_supported = 1;
2364 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002365 }
2366 }
2367 }
2368
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002369 if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
2370 struct nlattr *nl_combi;
2371 int rem_combi;
2372
2373 nla_for_each_nested(nl_combi,
2374 tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
2375 rem_combi) {
2376 struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
2377 struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
2378 struct nlattr *nl_limit, *nl_mode;
2379 int err, rem_limit, rem_mode;
2380 int combination_has_p2p = 0, combination_has_mgd = 0;
2381
2382 err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
2383 nl_combi,
2384 iface_combination_policy);
2385 if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
2386 !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
2387 !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
2388 goto broken_combination;
2389
2390 nla_for_each_nested(nl_limit,
2391 tb_comb[NL80211_IFACE_COMB_LIMITS],
2392 rem_limit) {
2393 err = nla_parse_nested(tb_limit,
2394 MAX_NL80211_IFACE_LIMIT,
2395 nl_limit,
2396 iface_limit_policy);
2397 if (err ||
2398 !tb_limit[NL80211_IFACE_LIMIT_TYPES])
2399 goto broken_combination;
2400
2401 nla_for_each_nested(
2402 nl_mode,
2403 tb_limit[NL80211_IFACE_LIMIT_TYPES],
2404 rem_mode) {
2405 int ift = nla_type(nl_mode);
2406 if (ift == NL80211_IFTYPE_P2P_GO ||
2407 ift == NL80211_IFTYPE_P2P_CLIENT)
2408 combination_has_p2p = 1;
2409 if (ift == NL80211_IFTYPE_STATION)
2410 combination_has_mgd = 1;
2411 }
2412 if (combination_has_p2p && combination_has_mgd)
2413 break;
2414 }
2415
2416 if (combination_has_p2p && combination_has_mgd) {
2417 p2p_concurrent = 1;
2418 break;
2419 }
2420
2421broken_combination:
2422 ;
2423 }
2424 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002425
2426 if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
2427 struct nlattr *nl_cmd;
2428 int i;
2429
2430 nla_for_each_nested(nl_cmd,
2431 tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002432 switch (nla_get_u32(nl_cmd)) {
2433 case NL80211_CMD_AUTHENTICATE:
2434 auth_supported = 1;
2435 break;
2436 case NL80211_CMD_CONNECT:
2437 connect_supported = 1;
2438 break;
2439 case NL80211_CMD_START_SCHED_SCAN:
2440 capa->sched_scan_supported = 1;
2441 break;
2442 case NL80211_CMD_PROBE_CLIENT:
2443 info->poll_command_supported = 1;
2444 break;
2445 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002446 }
2447 }
2448
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002449 if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
2450 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
2451 "off-channel TX");
2452 capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
2453 }
2454
2455 if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
2456 wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
2457 capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
2458 }
2459
2460 /* default to 5000 since early versions of mac80211 don't set it */
2461 capa->max_remain_on_chan = 5000;
2462
2463 if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
2464 capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002465
2466 if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002467 capa->max_remain_on_chan =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002468 nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
2469
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002470 if (auth_supported)
2471 capa->flags |= WPA_DRIVER_FLAGS_SME;
2472 else if (!connect_supported) {
2473 wpa_printf(MSG_INFO, "nl80211: Driver does not support "
2474 "authentication/association or connect commands");
2475 info->error = 1;
2476 }
2477
2478 if (p2p_go_supported && p2p_client_supported)
2479 capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
2480 if (p2p_concurrent) {
2481 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
2482 "interface (driver advertised support)");
2483 capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
2484 capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
2485 }
2486
2487 if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
2488 wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
2489 capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
2490
2491 if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
2492 wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
2493 capa->flags |=
2494 WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
2495 }
2496 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07002497#ifndef ANDROID_P2P
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002498 if (tb[NL80211_ATTR_DEVICE_AP_SME])
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07002499#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002500 info->device_ap_sme = 1;
2501
2502 if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
2503 u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
2504
2505 if (flags & NL80211_FEATURE_SK_TX_STATUS)
2506 info->data_tx_status = 1;
2507 }
2508
2509 if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
2510 int protocols =
2511 nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
2512 wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
2513 "offload in AP mode");
2514 capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
2515 capa->probe_resp_offloads =
2516 probe_resp_offload_support(protocols);
2517 }
2518
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002519 return NL_SKIP;
2520}
2521
2522
2523static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
2524 struct wiphy_info_data *info)
2525{
2526 struct nl_msg *msg;
2527
2528 os_memset(info, 0, sizeof(*info));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002529 info->capa = &drv->capa;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002530
2531 msg = nlmsg_alloc();
2532 if (!msg)
2533 return -1;
2534
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002535 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002536
2537 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
2538
2539 if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
2540 return 0;
2541 msg = NULL;
2542nla_put_failure:
2543 nlmsg_free(msg);
2544 return -1;
2545}
2546
2547
2548static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
2549{
2550 struct wiphy_info_data info;
2551 if (wpa_driver_nl80211_get_info(drv, &info))
2552 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002553
2554 if (info.error)
2555 return -1;
2556
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002557 drv->has_capability = 1;
2558 /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
2559 drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2560 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2561 WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2562 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
2563 drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
2564 WPA_DRIVER_CAPA_ENC_WEP104 |
2565 WPA_DRIVER_CAPA_ENC_TKIP |
2566 WPA_DRIVER_CAPA_ENC_CCMP;
2567 drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
2568 WPA_DRIVER_AUTH_SHARED |
2569 WPA_DRIVER_AUTH_LEAP;
2570
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002571 drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
2572 drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002573 drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002574 drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
2575
2576 drv->device_ap_sme = info.device_ap_sme;
2577 drv->poll_command_supported = info.poll_command_supported;
2578 drv->data_tx_status = info.data_tx_status;
2579
2580 /*
2581 * If poll command is supported mac80211 is new enough to
2582 * have everything we need to not need monitor interfaces.
2583 */
2584 drv->use_monitor = !info.poll_command_supported;
2585
2586 if (drv->device_ap_sme && drv->use_monitor) {
2587 /*
2588 * Non-mac80211 drivers may not support monitor interface.
2589 * Make sure we do not get stuck with incorrect capability here
2590 * by explicitly testing this.
2591 */
2592 if (!info.monitor_supported) {
2593 wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
2594 "with device_ap_sme since no monitor mode "
2595 "support detected");
2596 drv->use_monitor = 0;
2597 }
2598 }
2599
2600 /*
2601 * If we aren't going to use monitor interfaces, but the
2602 * driver doesn't support data TX status, we won't get TX
2603 * status for EAPOL frames.
2604 */
2605 if (!drv->use_monitor && !info.data_tx_status)
2606 drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002607
2608 return 0;
2609}
2610
2611
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002612#ifdef ANDROID
2613static int android_genl_ctrl_resolve(struct nl_handle *handle,
2614 const char *name)
2615{
2616 /*
2617 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
2618 * need to work around that.
2619 */
2620 struct nl_cache *cache = NULL;
2621 struct genl_family *nl80211 = NULL;
2622 int id = -1;
2623
2624 if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
2625 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
2626 "netlink cache");
2627 goto fail;
2628 }
2629
2630 nl80211 = genl_ctrl_search_by_name(cache, name);
2631 if (nl80211 == NULL)
2632 goto fail;
2633
2634 id = genl_family_get_id(nl80211);
2635
2636fail:
2637 if (nl80211)
2638 genl_family_put(nl80211);
2639 if (cache)
2640 nl_cache_free(cache);
2641
2642 return id;
2643}
2644#define genl_ctrl_resolve android_genl_ctrl_resolve
2645#endif /* ANDROID */
2646
2647
2648static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002649{
2650 int ret;
2651
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002652 global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2653 if (global->nl_cb == NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002654 wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
2655 "callbacks");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002656 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002657 }
2658
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002659 global->nl = nl_create_handle(global->nl_cb, "nl");
2660 if (global->nl == NULL)
2661 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002662
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002663 global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
2664 if (global->nl80211_id < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002665 wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
2666 "found");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002667 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002668 }
2669
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002670 global->nl_event = nl_create_handle(global->nl_cb, "event");
2671 if (global->nl_event == NULL)
2672 goto err;
2673
2674 ret = nl_get_multicast_id(global, "nl80211", "scan");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002675 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002676 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002677 if (ret < 0) {
2678 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
2679 "membership for scan events: %d (%s)",
2680 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002681 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002682 }
2683
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002684 ret = nl_get_multicast_id(global, "nl80211", "mlme");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002685 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002686 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002687 if (ret < 0) {
2688 wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
2689 "membership for mlme events: %d (%s)",
2690 ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002691 goto err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002692 }
2693
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002694 ret = nl_get_multicast_id(global, "nl80211", "regulatory");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002695 if (ret >= 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002696 ret = nl_socket_add_membership(global->nl_event, ret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002697 if (ret < 0) {
2698 wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
2699 "membership for regulatory events: %d (%s)",
2700 ret, strerror(-ret));
2701 /* Continue without regulatory events */
2702 }
2703
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002704 nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2705 no_seq_check, NULL);
2706 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2707 process_global_event, global);
2708
2709 eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
2710 wpa_driver_nl80211_event_receive,
2711 global->nl_cb, global->nl_event);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002712
2713 return 0;
2714
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002715err:
2716 nl_destroy_handles(&global->nl_event);
2717 nl_destroy_handles(&global->nl);
2718 nl_cb_put(global->nl_cb);
2719 global->nl_cb = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002720 return -1;
2721}
2722
2723
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002724static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
2725{
2726 drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2727 if (!drv->nl_cb) {
2728 wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
2729 return -1;
2730 }
2731
2732 nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2733 no_seq_check, NULL);
2734 nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2735 process_drv_event, drv);
2736
2737 return 0;
2738}
2739
2740
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002741static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
2742{
2743 wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
2744 /*
2745 * This may be for any interface; use ifdown event to disable
2746 * interface.
2747 */
2748}
2749
2750
2751static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
2752{
2753 struct wpa_driver_nl80211_data *drv = ctx;
2754 wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002755 if (linux_set_iface_flags(drv->global->ioctl_sock,
2756 drv->first_bss.ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002757 wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
2758 "after rfkill unblock");
2759 return;
2760 }
2761 /* rtnetlink ifup handler will report interface as enabled */
2762}
2763
2764
2765static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
2766{
2767 /* Find phy (radio) to which this interface belongs */
2768 char buf[90], *pos;
2769 int f, rv;
2770
2771 drv->phyname[0] = '\0';
2772 snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
2773 drv->first_bss.ifname);
2774 f = open(buf, O_RDONLY);
2775 if (f < 0) {
2776 wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
2777 buf, strerror(errno));
2778 return;
2779 }
2780
2781 rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
2782 close(f);
2783 if (rv < 0) {
2784 wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
2785 buf, strerror(errno));
2786 return;
2787 }
2788
2789 drv->phyname[rv] = '\0';
2790 pos = os_strchr(drv->phyname, '\n');
2791 if (pos)
2792 *pos = '\0';
2793 wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
2794 drv->first_bss.ifname, drv->phyname);
2795}
2796
2797
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002798static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
2799 void *eloop_ctx,
2800 void *handle)
2801{
2802 struct wpa_driver_nl80211_data *drv = eloop_ctx;
2803 u8 data[2048];
2804 struct msghdr msg;
2805 struct iovec entry;
2806 struct {
2807 struct cmsghdr cm;
2808 char control[512];
2809 } control;
2810 struct cmsghdr *cmsg;
2811 int res, found_ee = 0, found_wifi = 0, acked = 0;
2812 union wpa_event_data event;
2813
2814 memset(&msg, 0, sizeof(msg));
2815 msg.msg_iov = &entry;
2816 msg.msg_iovlen = 1;
2817 entry.iov_base = data;
2818 entry.iov_len = sizeof(data);
2819 msg.msg_control = &control;
2820 msg.msg_controllen = sizeof(control);
2821
2822 res = recvmsg(sock, &msg, MSG_ERRQUEUE);
2823 /* if error or not fitting 802.3 header, return */
2824 if (res < 14)
2825 return;
2826
2827 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
2828 {
2829 if (cmsg->cmsg_level == SOL_SOCKET &&
2830 cmsg->cmsg_type == SCM_WIFI_STATUS) {
2831 int *ack;
2832
2833 found_wifi = 1;
2834 ack = (void *)CMSG_DATA(cmsg);
2835 acked = *ack;
2836 }
2837
2838 if (cmsg->cmsg_level == SOL_PACKET &&
2839 cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
2840 struct sock_extended_err *err =
2841 (struct sock_extended_err *)CMSG_DATA(cmsg);
2842
2843 if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
2844 found_ee = 1;
2845 }
2846 }
2847
2848 if (!found_ee || !found_wifi)
2849 return;
2850
2851 memset(&event, 0, sizeof(event));
2852 event.eapol_tx_status.dst = data;
2853 event.eapol_tx_status.data = data + 14;
2854 event.eapol_tx_status.data_len = res - 14;
2855 event.eapol_tx_status.ack = acked;
2856 wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
2857}
2858
2859
2860static int nl80211_init_bss(struct i802_bss *bss)
2861{
2862 bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
2863 if (!bss->nl_cb)
2864 return -1;
2865
2866 nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
2867 no_seq_check, NULL);
2868 nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
2869 process_bss_event, bss);
2870
2871 return 0;
2872}
2873
2874
2875static void nl80211_destroy_bss(struct i802_bss *bss)
2876{
2877 nl_cb_put(bss->nl_cb);
2878 bss->nl_cb = NULL;
2879}
2880
2881
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002882/**
2883 * wpa_driver_nl80211_init - Initialize nl80211 driver interface
2884 * @ctx: context to be used when calling wpa_supplicant functions,
2885 * e.g., wpa_supplicant_event()
2886 * @ifname: interface name, e.g., wlan0
2887 * @global_priv: private driver global data from global_init()
2888 * Returns: Pointer to private data, %NULL on failure
2889 */
2890static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
2891 void *global_priv)
2892{
2893 struct wpa_driver_nl80211_data *drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002894 struct rfkill_config *rcfg;
2895 struct i802_bss *bss;
2896
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002897 if (global_priv == NULL)
2898 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002899 drv = os_zalloc(sizeof(*drv));
2900 if (drv == NULL)
2901 return NULL;
2902 drv->global = global_priv;
2903 drv->ctx = ctx;
2904 bss = &drv->first_bss;
2905 bss->drv = drv;
2906 os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
2907 drv->monitor_ifidx = -1;
2908 drv->monitor_sock = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002909 drv->eapol_tx_sock = -1;
2910 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002911
2912 if (wpa_driver_nl80211_init_nl(drv)) {
2913 os_free(drv);
2914 return NULL;
2915 }
2916
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002917 if (nl80211_init_bss(bss))
2918 goto failed;
2919
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002920 nl80211_get_phy_name(drv);
2921
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002922 rcfg = os_zalloc(sizeof(*rcfg));
2923 if (rcfg == NULL)
2924 goto failed;
2925 rcfg->ctx = drv;
2926 os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
2927 rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
2928 rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
2929 drv->rfkill = rfkill_init(rcfg);
2930 if (drv->rfkill == NULL) {
2931 wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
2932 os_free(rcfg);
2933 }
2934
2935 if (wpa_driver_nl80211_finish_drv_init(drv))
2936 goto failed;
2937
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002938 drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
2939 if (drv->eapol_tx_sock < 0)
2940 goto failed;
2941
2942 if (drv->data_tx_status) {
2943 int enabled = 1;
2944
2945 if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
2946 &enabled, sizeof(enabled)) < 0) {
2947 wpa_printf(MSG_DEBUG,
2948 "nl80211: wifi status sockopt failed\n");
2949 drv->data_tx_status = 0;
2950 if (!drv->use_monitor)
2951 drv->capa.flags &=
2952 ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
2953 } else {
2954 eloop_register_read_sock(drv->eapol_tx_sock,
2955 wpa_driver_nl80211_handle_eapol_tx_status,
2956 drv, NULL);
2957 }
2958 }
2959
2960 if (drv->global) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002961 dl_list_add(&drv->global->interfaces, &drv->list);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002962 drv->in_interface_list = 1;
2963 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002964
2965 return bss;
2966
2967failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002968 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002969 return NULL;
2970}
2971
2972
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002973static int nl80211_register_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002974 struct nl_handle *nl_handle,
2975 u16 type, const u8 *match, size_t match_len)
2976{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002977 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002978 struct nl_msg *msg;
2979 int ret = -1;
2980
2981 msg = nlmsg_alloc();
2982 if (!msg)
2983 return -1;
2984
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002985 wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
2986 type, nl_handle);
2987 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
2988 match, match_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002989
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002990 nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
2991
2992 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002993 NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
2994 NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
2995
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002996 ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002997 msg = NULL;
2998 if (ret) {
2999 wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
3000 "failed (type=%u): ret=%d (%s)",
3001 type, ret, strerror(-ret));
3002 wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
3003 match, match_len);
3004 goto nla_put_failure;
3005 }
3006 ret = 0;
3007nla_put_failure:
3008 nlmsg_free(msg);
3009 return ret;
3010}
3011
3012
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003013static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
3014{
3015 struct wpa_driver_nl80211_data *drv = bss->drv;
3016
3017 if (bss->nl_mgmt) {
3018 wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
3019 "already on! (nl_mgmt=%p)", bss->nl_mgmt);
3020 return -1;
3021 }
3022
3023 bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
3024 if (bss->nl_mgmt == NULL)
3025 return -1;
3026
3027 eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
3028 wpa_driver_nl80211_event_receive, bss->nl_cb,
3029 bss->nl_mgmt);
3030
3031 return 0;
3032}
3033
3034
3035static int nl80211_register_action_frame(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003036 const u8 *match, size_t match_len)
3037{
3038 u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003039 return nl80211_register_frame(bss, bss->nl_mgmt,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003040 type, match, match_len);
3041}
3042
3043
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003044static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003045{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003046 struct wpa_driver_nl80211_data *drv = bss->drv;
3047
3048 if (nl80211_alloc_mgmt_handle(bss))
3049 return -1;
3050 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
3051 "handle %p", bss->nl_mgmt);
3052
3053#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003054 /* GAS Initial Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003055 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003056 return -1;
3057 /* GAS Initial Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003058 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003059 return -1;
3060 /* GAS Comeback Request */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003061 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003062 return -1;
3063 /* GAS Comeback Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003064 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003065 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003066#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
3067#ifdef CONFIG_P2P
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003068 /* P2P Public Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003069 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003070 (u8 *) "\x04\x09\x50\x6f\x9a\x09",
3071 6) < 0)
3072 return -1;
3073 /* P2P Action */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003074 if (nl80211_register_action_frame(bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003075 (u8 *) "\x7f\x50\x6f\x9a\x09",
3076 5) < 0)
3077 return -1;
3078#endif /* CONFIG_P2P */
3079#ifdef CONFIG_IEEE80211W
3080 /* SA Query Response */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003081 if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003082 return -1;
3083#endif /* CONFIG_IEEE80211W */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003084#ifdef CONFIG_TDLS
3085 if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
3086 /* TDLS Discovery Response */
3087 if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
3088 0)
3089 return -1;
3090 }
3091#endif /* CONFIG_TDLS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003092
3093 /* FT Action frames */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003094 if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003095 return -1;
3096 else
3097 drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
3098 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
3099
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003100 /* WNM - BSS Transition Management Request */
3101 if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
3102 return -1;
3103
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003104 return 0;
3105}
3106
3107
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003108static int nl80211_register_spurious_class3(struct i802_bss *bss)
3109{
3110 struct wpa_driver_nl80211_data *drv = bss->drv;
3111 struct nl_msg *msg;
3112 int ret = -1;
3113
3114 msg = nlmsg_alloc();
3115 if (!msg)
3116 return -1;
3117
3118 nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
3119
3120 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
3121
3122 ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
3123 msg = NULL;
3124 if (ret) {
3125 wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
3126 "failed: ret=%d (%s)",
3127 ret, strerror(-ret));
3128 goto nla_put_failure;
3129 }
3130 ret = 0;
3131nla_put_failure:
3132 nlmsg_free(msg);
3133 return ret;
3134}
3135
3136
3137static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
3138{
3139 static const int stypes[] = {
3140 WLAN_FC_STYPE_AUTH,
3141 WLAN_FC_STYPE_ASSOC_REQ,
3142 WLAN_FC_STYPE_REASSOC_REQ,
3143 WLAN_FC_STYPE_DISASSOC,
3144 WLAN_FC_STYPE_DEAUTH,
3145 WLAN_FC_STYPE_ACTION,
3146 WLAN_FC_STYPE_PROBE_REQ,
3147/* Beacon doesn't work as mac80211 doesn't currently allow
3148 * it, but it wouldn't really be the right thing anyway as
3149 * it isn't per interface ... maybe just dump the scan
3150 * results periodically for OLBC?
3151 */
3152// WLAN_FC_STYPE_BEACON,
3153 };
3154 unsigned int i;
3155
3156 if (nl80211_alloc_mgmt_handle(bss))
3157 return -1;
3158 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
3159 "handle %p", bss->nl_mgmt);
3160
3161 for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
3162 if (nl80211_register_frame(bss, bss->nl_mgmt,
3163 (WLAN_FC_TYPE_MGMT << 2) |
3164 (stypes[i] << 4),
3165 NULL, 0) < 0) {
3166 goto out_err;
3167 }
3168 }
3169
3170 if (nl80211_register_spurious_class3(bss))
3171 goto out_err;
3172
3173 if (nl80211_get_wiphy_data_ap(bss) == NULL)
3174 goto out_err;
3175
3176 return 0;
3177
3178out_err:
3179 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3180 nl_destroy_handles(&bss->nl_mgmt);
3181 return -1;
3182}
3183
3184
3185static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
3186{
3187 if (nl80211_alloc_mgmt_handle(bss))
3188 return -1;
3189 wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
3190 "handle %p (device SME)", bss->nl_mgmt);
3191
3192 if (nl80211_register_frame(bss, bss->nl_mgmt,
3193 (WLAN_FC_TYPE_MGMT << 2) |
3194 (WLAN_FC_STYPE_ACTION << 4),
3195 NULL, 0) < 0)
3196 goto out_err;
3197
3198 return 0;
3199
3200out_err:
3201 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3202 nl_destroy_handles(&bss->nl_mgmt);
3203 return -1;
3204}
3205
3206
3207static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
3208{
3209 if (bss->nl_mgmt == NULL)
3210 return;
3211 wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
3212 "(%s)", bss->nl_mgmt, reason);
3213 eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
3214 nl_destroy_handles(&bss->nl_mgmt);
3215
3216 nl80211_put_wiphy_data_ap(bss);
3217}
3218
3219
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003220static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
3221{
3222 wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
3223}
3224
3225
3226static int
3227wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
3228{
3229 struct i802_bss *bss = &drv->first_bss;
3230 int send_rfkill_event = 0;
3231
3232 drv->ifindex = if_nametoindex(bss->ifname);
3233 drv->first_bss.ifindex = drv->ifindex;
3234
3235#ifndef HOSTAPD
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003236 /*
3237 * Make sure the interface starts up in station mode unless this is a
3238 * dynamically added interface (e.g., P2P) that was already configured
3239 * with proper iftype.
3240 */
3241 if (drv->ifindex != drv->global->if_add_ifindex &&
3242 wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
3243 wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003244 "use managed mode");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003245 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003246 }
3247
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003248 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003249 if (rfkill_is_blocked(drv->rfkill)) {
3250 wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
3251 "interface '%s' due to rfkill",
3252 bss->ifname);
3253 drv->if_disabled = 1;
3254 send_rfkill_event = 1;
3255 } else {
3256 wpa_printf(MSG_ERROR, "nl80211: Could not set "
3257 "interface '%s' UP", bss->ifname);
3258 return -1;
3259 }
3260 }
3261
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003262 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003263 1, IF_OPER_DORMANT);
3264#endif /* HOSTAPD */
3265
3266 if (wpa_driver_nl80211_capa(drv))
3267 return -1;
3268
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003269 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
3270 bss->addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003271 return -1;
3272
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003273 if (send_rfkill_event) {
3274 eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
3275 drv, drv->ctx);
3276 }
3277
3278 return 0;
3279}
3280
3281
3282static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
3283{
3284 struct nl_msg *msg;
3285
3286 msg = nlmsg_alloc();
3287 if (!msg)
3288 return -ENOMEM;
3289
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003290 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003291 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3292
3293 return send_and_recv_msgs(drv, msg, NULL, NULL);
3294 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003295 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003296 return -ENOBUFS;
3297}
3298
3299
3300/**
3301 * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
3302 * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
3303 *
3304 * Shut down driver interface and processing of driver events. Free
3305 * private data buffer if one was allocated in wpa_driver_nl80211_init().
3306 */
3307static void wpa_driver_nl80211_deinit(void *priv)
3308{
3309 struct i802_bss *bss = priv;
3310 struct wpa_driver_nl80211_data *drv = bss->drv;
3311
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003312 if (drv->data_tx_status)
3313 eloop_unregister_read_sock(drv->eapol_tx_sock);
3314 if (drv->eapol_tx_sock >= 0)
3315 close(drv->eapol_tx_sock);
3316
3317 if (bss->nl_preq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003318 wpa_driver_nl80211_probe_req_report(bss, 0);
3319 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003320 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
3321 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003322 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3323 "interface %s from bridge %s: %s",
3324 bss->ifname, bss->brname, strerror(errno));
3325 }
3326 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003327 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003328 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
3329 "bridge %s: %s",
3330 bss->brname, strerror(errno));
3331 }
3332
3333 nl80211_remove_monitor_interface(drv);
3334
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003335 if (is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003336 wpa_driver_nl80211_del_beacon(drv);
3337
3338#ifdef HOSTAPD
3339 if (drv->last_freq_ht) {
3340 /* Clear HT flags from the driver */
3341 struct hostapd_freq_params freq;
3342 os_memset(&freq, 0, sizeof(freq));
3343 freq.freq = drv->last_freq;
3344 i802_set_freq(priv, &freq);
3345 }
3346
3347 if (drv->eapol_sock >= 0) {
3348 eloop_unregister_read_sock(drv->eapol_sock);
3349 close(drv->eapol_sock);
3350 }
3351
3352 if (drv->if_indices != drv->default_if_indices)
3353 os_free(drv->if_indices);
3354#endif /* HOSTAPD */
3355
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003356 if (drv->disabled_11b_rates)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003357 nl80211_disable_11b_rates(drv, drv->ifindex, 0);
3358
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003359 netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
3360 IF_OPER_UP);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003361 rfkill_deinit(drv->rfkill);
3362
3363 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3364
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003365 (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
3366 wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
3367 nl80211_mgmt_unsubscribe(bss, "deinit");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003368
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003369 nl_cb_put(drv->nl_cb);
3370
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003371 nl80211_destroy_bss(&drv->first_bss);
3372
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003373 os_free(drv->filter_ssids);
3374
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003375 os_free(drv->auth_ie);
3376
3377 if (drv->in_interface_list)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003378 dl_list_del(&drv->list);
3379
3380 os_free(drv);
3381}
3382
3383
3384/**
3385 * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
3386 * @eloop_ctx: Driver private data
3387 * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
3388 *
3389 * This function can be used as registered timeout when starting a scan to
3390 * generate a scan completed event if the driver does not report this.
3391 */
3392static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
3393{
3394 struct wpa_driver_nl80211_data *drv = eloop_ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003395 if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003396 wpa_driver_nl80211_set_mode(&drv->first_bss,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003397 drv->ap_scan_as_station);
3398 drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003399 }
3400 wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
3401 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
3402}
3403
3404
3405/**
3406 * wpa_driver_nl80211_scan - Request the driver to initiate scan
3407 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3408 * @params: Scan parameters
3409 * Returns: 0 on success, -1 on failure
3410 */
3411static int wpa_driver_nl80211_scan(void *priv,
3412 struct wpa_driver_scan_params *params)
3413{
3414 struct i802_bss *bss = priv;
3415 struct wpa_driver_nl80211_data *drv = bss->drv;
3416 int ret = 0, timeout;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003417 struct nl_msg *msg, *ssids, *freqs, *rates;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003418 size_t i;
3419
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003420 drv->scan_for_auth = 0;
3421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003422 msg = nlmsg_alloc();
3423 ssids = nlmsg_alloc();
3424 freqs = nlmsg_alloc();
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003425 rates = nlmsg_alloc();
3426 if (!msg || !ssids || !freqs || !rates) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003427 nlmsg_free(msg);
3428 nlmsg_free(ssids);
3429 nlmsg_free(freqs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003430 nlmsg_free(rates);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003431 return -1;
3432 }
3433
3434 os_free(drv->filter_ssids);
3435 drv->filter_ssids = params->filter_ssids;
3436 params->filter_ssids = NULL;
3437 drv->num_filter_ssids = params->num_filter_ssids;
3438
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003439 nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003440
3441 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3442
3443 for (i = 0; i < params->num_ssids; i++) {
3444 wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
3445 params->ssids[i].ssid,
3446 params->ssids[i].ssid_len);
3447 NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
3448 params->ssids[i].ssid);
3449 }
3450 if (params->num_ssids)
3451 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
3452
3453 if (params->extra_ies) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003454 wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
3455 params->extra_ies, params->extra_ies_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003456 NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
3457 params->extra_ies);
3458 }
3459
3460 if (params->freqs) {
3461 for (i = 0; params->freqs[i]; i++) {
3462 wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
3463 "MHz", params->freqs[i]);
3464 NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
3465 }
3466 nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
3467 }
3468
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003469 if (params->p2p_probe) {
3470 /*
3471 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
3472 * by masking out everything else apart from the OFDM rates 6,
3473 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
3474 * rates are left enabled.
3475 */
3476 NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
3477 "\x0c\x12\x18\x24\x30\x48\x60\x6c");
3478 nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
3479
3480 NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
3481 }
3482
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003483 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3484 msg = NULL;
3485 if (ret) {
3486 wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
3487 "(%s)", ret, strerror(-ret));
3488#ifdef HOSTAPD
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003489 if (is_ap_interface(drv->nlmode)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003490 /*
3491 * mac80211 does not allow scan requests in AP mode, so
3492 * try to do this in station mode.
3493 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003494 if (wpa_driver_nl80211_set_mode(
3495 bss, NL80211_IFTYPE_STATION))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003496 goto nla_put_failure;
3497
3498 if (wpa_driver_nl80211_scan(drv, params)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003499 wpa_driver_nl80211_set_mode(bss, drv->nlmode);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003500 goto nla_put_failure;
3501 }
3502
3503 /* Restore AP mode when processing scan results */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003504 drv->ap_scan_as_station = drv->nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003505 ret = 0;
3506 } else
3507 goto nla_put_failure;
3508#else /* HOSTAPD */
3509 goto nla_put_failure;
3510#endif /* HOSTAPD */
3511 }
3512
3513 /* Not all drivers generate "scan completed" wireless event, so try to
3514 * read results after a timeout. */
3515 timeout = 10;
3516 if (drv->scan_complete_events) {
3517 /*
3518 * The driver seems to deliver events to notify when scan is
3519 * complete, so use longer timeout to avoid race conditions
3520 * with scanning and following association request.
3521 */
3522 timeout = 30;
3523 }
3524 wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
3525 "seconds", ret, timeout);
3526 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
3527 eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
3528 drv, drv->ctx);
3529
3530nla_put_failure:
3531 nlmsg_free(ssids);
3532 nlmsg_free(msg);
3533 nlmsg_free(freqs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003534 nlmsg_free(rates);
3535 return ret;
3536}
3537
3538
3539/**
3540 * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
3541 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3542 * @params: Scan parameters
3543 * @interval: Interval between scan cycles in milliseconds
3544 * Returns: 0 on success, -1 on failure or if not supported
3545 */
3546static int wpa_driver_nl80211_sched_scan(void *priv,
3547 struct wpa_driver_scan_params *params,
3548 u32 interval)
3549{
3550 struct i802_bss *bss = priv;
3551 struct wpa_driver_nl80211_data *drv = bss->drv;
3552 int ret = 0;
3553 struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
3554 size_t i;
3555
3556#ifdef ANDROID
3557 if (!drv->capa.sched_scan_supported)
3558 return android_pno_start(bss, params);
3559#endif /* ANDROID */
3560
3561 msg = nlmsg_alloc();
3562 ssids = nlmsg_alloc();
3563 freqs = nlmsg_alloc();
3564 if (!msg || !ssids || !freqs) {
3565 nlmsg_free(msg);
3566 nlmsg_free(ssids);
3567 nlmsg_free(freqs);
3568 return -1;
3569 }
3570
3571 os_free(drv->filter_ssids);
3572 drv->filter_ssids = params->filter_ssids;
3573 params->filter_ssids = NULL;
3574 drv->num_filter_ssids = params->num_filter_ssids;
3575
3576 nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
3577
3578 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3579
3580 NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
3581
3582 if (drv->num_filter_ssids &&
3583 (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
3584 match_sets = nlmsg_alloc();
3585
3586 for (i = 0; i < drv->num_filter_ssids; i++) {
3587 wpa_hexdump_ascii(MSG_MSGDUMP,
3588 "nl80211: Sched scan filter SSID",
3589 drv->filter_ssids[i].ssid,
3590 drv->filter_ssids[i].ssid_len);
3591
3592 match_set_ssid = nlmsg_alloc();
3593 nla_put(match_set_ssid,
3594 NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
3595 drv->filter_ssids[i].ssid_len,
3596 drv->filter_ssids[i].ssid);
3597
3598 nla_put_nested(match_sets, i + 1, match_set_ssid);
3599
3600 nlmsg_free(match_set_ssid);
3601 }
3602
3603 nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
3604 match_sets);
3605 nlmsg_free(match_sets);
3606 }
3607
3608 for (i = 0; i < params->num_ssids; i++) {
3609 wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
3610 params->ssids[i].ssid,
3611 params->ssids[i].ssid_len);
3612 NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
3613 params->ssids[i].ssid);
3614 }
3615 if (params->num_ssids)
3616 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
3617
3618 if (params->extra_ies) {
3619 wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
3620 params->extra_ies, params->extra_ies_len);
3621 NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
3622 params->extra_ies);
3623 }
3624
3625 if (params->freqs) {
3626 for (i = 0; params->freqs[i]; i++) {
3627 wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
3628 "MHz", params->freqs[i]);
3629 NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
3630 }
3631 nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
3632 }
3633
3634 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3635
3636 /* TODO: if we get an error here, we should fall back to normal scan */
3637
3638 msg = NULL;
3639 if (ret) {
3640 wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
3641 "ret=%d (%s)", ret, strerror(-ret));
3642 goto nla_put_failure;
3643 }
3644
3645 wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
3646 "scan interval %d msec", ret, interval);
3647
3648nla_put_failure:
3649 nlmsg_free(ssids);
3650 nlmsg_free(msg);
3651 nlmsg_free(freqs);
3652 return ret;
3653}
3654
3655
3656/**
3657 * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
3658 * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
3659 * Returns: 0 on success, -1 on failure or if not supported
3660 */
3661static int wpa_driver_nl80211_stop_sched_scan(void *priv)
3662{
3663 struct i802_bss *bss = priv;
3664 struct wpa_driver_nl80211_data *drv = bss->drv;
3665 int ret = 0;
3666 struct nl_msg *msg;
3667
3668#ifdef ANDROID
3669 if (!drv->capa.sched_scan_supported)
3670 return android_pno_stop(bss);
3671#endif /* ANDROID */
3672
3673 msg = nlmsg_alloc();
3674 if (!msg)
3675 return -1;
3676
3677 nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
3678
3679 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3680
3681 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3682 msg = NULL;
3683 if (ret) {
3684 wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
3685 "ret=%d (%s)", ret, strerror(-ret));
3686 goto nla_put_failure;
3687 }
3688
3689 wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
3690
3691nla_put_failure:
3692 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003693 return ret;
3694}
3695
3696
3697static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
3698{
3699 const u8 *end, *pos;
3700
3701 if (ies == NULL)
3702 return NULL;
3703
3704 pos = ies;
3705 end = ies + ies_len;
3706
3707 while (pos + 1 < end) {
3708 if (pos + 2 + pos[1] > end)
3709 break;
3710 if (pos[0] == ie)
3711 return pos;
3712 pos += 2 + pos[1];
3713 }
3714
3715 return NULL;
3716}
3717
3718
3719static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
3720 const u8 *ie, size_t ie_len)
3721{
3722 const u8 *ssid;
3723 size_t i;
3724
3725 if (drv->filter_ssids == NULL)
3726 return 0;
3727
3728 ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
3729 if (ssid == NULL)
3730 return 1;
3731
3732 for (i = 0; i < drv->num_filter_ssids; i++) {
3733 if (ssid[1] == drv->filter_ssids[i].ssid_len &&
3734 os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
3735 0)
3736 return 0;
3737 }
3738
3739 return 1;
3740}
3741
3742
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003743static int bss_info_handler(struct nl_msg *msg, void *arg)
3744{
3745 struct nlattr *tb[NL80211_ATTR_MAX + 1];
3746 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
3747 struct nlattr *bss[NL80211_BSS_MAX + 1];
3748 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
3749 [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
3750 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
3751 [NL80211_BSS_TSF] = { .type = NLA_U64 },
3752 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
3753 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
3754 [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
3755 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
3756 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
3757 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
3758 [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
3759 [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
3760 };
3761 struct nl80211_bss_info_arg *_arg = arg;
3762 struct wpa_scan_results *res = _arg->res;
3763 struct wpa_scan_res **tmp;
3764 struct wpa_scan_res *r;
3765 const u8 *ie, *beacon_ie;
3766 size_t ie_len, beacon_ie_len;
3767 u8 *pos;
Jouni Malinen87fd2792011-05-16 18:35:42 +03003768 size_t i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003769
3770 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
3771 genlmsg_attrlen(gnlh, 0), NULL);
3772 if (!tb[NL80211_ATTR_BSS])
3773 return NL_SKIP;
3774 if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
3775 bss_policy))
3776 return NL_SKIP;
Jouni Malinen87fd2792011-05-16 18:35:42 +03003777 if (bss[NL80211_BSS_STATUS]) {
3778 enum nl80211_bss_status status;
3779 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
3780 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
3781 bss[NL80211_BSS_FREQUENCY]) {
3782 _arg->assoc_freq =
3783 nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
3784 wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
3785 _arg->assoc_freq);
3786 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003787 if (status == NL80211_BSS_STATUS_ASSOCIATED &&
3788 bss[NL80211_BSS_BSSID]) {
3789 os_memcpy(_arg->assoc_bssid,
3790 nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
3791 wpa_printf(MSG_DEBUG, "nl80211: Associated with "
3792 MACSTR, MAC2STR(_arg->assoc_bssid));
3793 }
Jouni Malinen87fd2792011-05-16 18:35:42 +03003794 }
3795 if (!res)
3796 return NL_SKIP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003797 if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
3798 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
3799 ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
3800 } else {
3801 ie = NULL;
3802 ie_len = 0;
3803 }
3804 if (bss[NL80211_BSS_BEACON_IES]) {
3805 beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
3806 beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
3807 } else {
3808 beacon_ie = NULL;
3809 beacon_ie_len = 0;
3810 }
3811
3812 if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
3813 ie ? ie_len : beacon_ie_len))
3814 return NL_SKIP;
3815
3816 r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
3817 if (r == NULL)
3818 return NL_SKIP;
3819 if (bss[NL80211_BSS_BSSID])
3820 os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
3821 ETH_ALEN);
3822 if (bss[NL80211_BSS_FREQUENCY])
3823 r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
3824 if (bss[NL80211_BSS_BEACON_INTERVAL])
3825 r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
3826 if (bss[NL80211_BSS_CAPABILITY])
3827 r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
3828 r->flags |= WPA_SCAN_NOISE_INVALID;
3829 if (bss[NL80211_BSS_SIGNAL_MBM]) {
3830 r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
3831 r->level /= 100; /* mBm to dBm */
3832 r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
3833 } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
3834 r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003835 r->flags |= WPA_SCAN_QUAL_INVALID;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003836 } else
3837 r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
3838 if (bss[NL80211_BSS_TSF])
3839 r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
3840 if (bss[NL80211_BSS_SEEN_MS_AGO])
3841 r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
3842 r->ie_len = ie_len;
3843 pos = (u8 *) (r + 1);
3844 if (ie) {
3845 os_memcpy(pos, ie, ie_len);
3846 pos += ie_len;
3847 }
3848 r->beacon_ie_len = beacon_ie_len;
3849 if (beacon_ie)
3850 os_memcpy(pos, beacon_ie, beacon_ie_len);
3851
3852 if (bss[NL80211_BSS_STATUS]) {
3853 enum nl80211_bss_status status;
3854 status = nla_get_u32(bss[NL80211_BSS_STATUS]);
3855 switch (status) {
3856 case NL80211_BSS_STATUS_AUTHENTICATED:
3857 r->flags |= WPA_SCAN_AUTHENTICATED;
3858 break;
3859 case NL80211_BSS_STATUS_ASSOCIATED:
3860 r->flags |= WPA_SCAN_ASSOCIATED;
3861 break;
3862 default:
3863 break;
3864 }
3865 }
3866
Jouni Malinen87fd2792011-05-16 18:35:42 +03003867 /*
3868 * cfg80211 maintains separate BSS table entries for APs if the same
3869 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
3870 * not use frequency as a separate key in the BSS table, so filter out
3871 * duplicated entries. Prefer associated BSS entry in such a case in
3872 * order to get the correct frequency into the BSS table.
3873 */
3874 for (i = 0; i < res->num; i++) {
3875 const u8 *s1, *s2;
3876 if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
3877 continue;
3878
3879 s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
3880 res->res[i]->ie_len, WLAN_EID_SSID);
3881 s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
3882 if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
3883 os_memcmp(s1, s2, 2 + s1[1]) != 0)
3884 continue;
3885
3886 /* Same BSSID,SSID was already included in scan results */
3887 wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
3888 "for " MACSTR, MAC2STR(r->bssid));
3889
3890 if ((r->flags & WPA_SCAN_ASSOCIATED) &&
3891 !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) {
3892 os_free(res->res[i]);
3893 res->res[i] = r;
3894 } else
3895 os_free(r);
3896 return NL_SKIP;
3897 }
3898
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003899 tmp = os_realloc(res->res,
3900 (res->num + 1) * sizeof(struct wpa_scan_res *));
3901 if (tmp == NULL) {
3902 os_free(r);
3903 return NL_SKIP;
3904 }
3905 tmp[res->num++] = r;
3906 res->res = tmp;
3907
3908 return NL_SKIP;
3909}
3910
3911
3912static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
3913 const u8 *addr)
3914{
3915 if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
3916 wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
3917 "mismatch (" MACSTR ")", MAC2STR(addr));
3918 wpa_driver_nl80211_mlme(drv, addr,
3919 NL80211_CMD_DEAUTHENTICATE,
3920 WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
3921 }
3922}
3923
3924
3925static void wpa_driver_nl80211_check_bss_status(
3926 struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
3927{
3928 size_t i;
3929
3930 for (i = 0; i < res->num; i++) {
3931 struct wpa_scan_res *r = res->res[i];
3932 if (r->flags & WPA_SCAN_AUTHENTICATED) {
3933 wpa_printf(MSG_DEBUG, "nl80211: Scan results "
3934 "indicates BSS status with " MACSTR
3935 " as authenticated",
3936 MAC2STR(r->bssid));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003937 if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003938 os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
3939 os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
3940 0) {
3941 wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
3942 " in local state (auth=" MACSTR
3943 " assoc=" MACSTR ")",
3944 MAC2STR(drv->auth_bssid),
3945 MAC2STR(drv->bssid));
3946 clear_state_mismatch(drv, r->bssid);
3947 }
3948 }
3949
3950 if (r->flags & WPA_SCAN_ASSOCIATED) {
3951 wpa_printf(MSG_DEBUG, "nl80211: Scan results "
3952 "indicate BSS status with " MACSTR
3953 " as associated",
3954 MAC2STR(r->bssid));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003955 if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003956 !drv->associated) {
3957 wpa_printf(MSG_DEBUG, "nl80211: Local state "
3958 "(not associated) does not match "
3959 "with BSS state");
3960 clear_state_mismatch(drv, r->bssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003961 } else if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003962 os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
3963 0) {
3964 wpa_printf(MSG_DEBUG, "nl80211: Local state "
3965 "(associated with " MACSTR ") does "
3966 "not match with BSS state",
3967 MAC2STR(drv->bssid));
3968 clear_state_mismatch(drv, r->bssid);
3969 clear_state_mismatch(drv, drv->bssid);
3970 }
3971 }
3972 }
3973}
3974
3975
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003976static struct wpa_scan_results *
3977nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
3978{
3979 struct nl_msg *msg;
3980 struct wpa_scan_results *res;
3981 int ret;
3982 struct nl80211_bss_info_arg arg;
3983
3984 res = os_zalloc(sizeof(*res));
3985 if (res == NULL)
3986 return NULL;
3987 msg = nlmsg_alloc();
3988 if (!msg)
3989 goto nla_put_failure;
3990
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003991 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003992 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
3993
3994 arg.drv = drv;
3995 arg.res = res;
3996 ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
3997 msg = NULL;
3998 if (ret == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08003999 wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
4000 "BSSes)", (unsigned long) res->num);
4001 nl80211_get_noise_for_scan_results(drv, res);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004002 return res;
4003 }
4004 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
4005 "(%s)", ret, strerror(-ret));
4006nla_put_failure:
4007 nlmsg_free(msg);
4008 wpa_scan_results_free(res);
4009 return NULL;
4010}
4011
4012
4013/**
4014 * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
4015 * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
4016 * Returns: Scan results on success, -1 on failure
4017 */
4018static struct wpa_scan_results *
4019wpa_driver_nl80211_get_scan_results(void *priv)
4020{
4021 struct i802_bss *bss = priv;
4022 struct wpa_driver_nl80211_data *drv = bss->drv;
4023 struct wpa_scan_results *res;
4024
4025 res = nl80211_get_scan_results(drv);
4026 if (res)
4027 wpa_driver_nl80211_check_bss_status(drv, res);
4028 return res;
4029}
4030
4031
4032static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
4033{
4034 struct wpa_scan_results *res;
4035 size_t i;
4036
4037 res = nl80211_get_scan_results(drv);
4038 if (res == NULL) {
4039 wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
4040 return;
4041 }
4042
4043 wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
4044 for (i = 0; i < res->num; i++) {
4045 struct wpa_scan_res *r = res->res[i];
4046 wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
4047 (int) i, (int) res->num, MAC2STR(r->bssid),
4048 r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
4049 r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
4050 }
4051
4052 wpa_scan_results_free(res);
4053}
4054
4055
4056static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
4057 enum wpa_alg alg, const u8 *addr,
4058 int key_idx, int set_tx,
4059 const u8 *seq, size_t seq_len,
4060 const u8 *key, size_t key_len)
4061{
4062 struct i802_bss *bss = priv;
4063 struct wpa_driver_nl80211_data *drv = bss->drv;
4064 int ifindex = if_nametoindex(ifname);
4065 struct nl_msg *msg;
4066 int ret;
4067
4068 wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
4069 "set_tx=%d seq_len=%lu key_len=%lu",
4070 __func__, ifindex, alg, addr, key_idx, set_tx,
4071 (unsigned long) seq_len, (unsigned long) key_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004072#ifdef CONFIG_TDLS
4073 if (key_idx == -1)
4074 key_idx = 0;
4075#endif /* CONFIG_TDLS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004076
4077 msg = nlmsg_alloc();
4078 if (!msg)
4079 return -ENOMEM;
4080
4081 if (alg == WPA_ALG_NONE) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004082 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004083 } else {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004084 nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004085 NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
4086 switch (alg) {
4087 case WPA_ALG_WEP:
4088 if (key_len == 5)
4089 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4090 WLAN_CIPHER_SUITE_WEP40);
4091 else
4092 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4093 WLAN_CIPHER_SUITE_WEP104);
4094 break;
4095 case WPA_ALG_TKIP:
4096 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4097 WLAN_CIPHER_SUITE_TKIP);
4098 break;
4099 case WPA_ALG_CCMP:
4100 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4101 WLAN_CIPHER_SUITE_CCMP);
4102 break;
4103 case WPA_ALG_IGTK:
4104 NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4105 WLAN_CIPHER_SUITE_AES_CMAC);
4106 break;
4107 default:
4108 wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
4109 "algorithm %d", __func__, alg);
4110 nlmsg_free(msg);
4111 return -1;
4112 }
4113 }
4114
4115 if (seq && seq_len)
4116 NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
4117
4118 if (addr && !is_broadcast_ether_addr(addr)) {
4119 wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
4120 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
4121
4122 if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
4123 wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
4124 NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
4125 NL80211_KEYTYPE_GROUP);
4126 }
4127 } else if (addr && is_broadcast_ether_addr(addr)) {
4128 struct nl_msg *types;
4129 int err;
4130 wpa_printf(MSG_DEBUG, " broadcast key");
4131 types = nlmsg_alloc();
4132 if (!types)
4133 goto nla_put_failure;
4134 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
4135 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4136 types);
4137 nlmsg_free(types);
4138 if (err)
4139 goto nla_put_failure;
4140 }
4141 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
4142 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
4143
4144 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4145 if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
4146 ret = 0;
4147 if (ret)
4148 wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
4149 ret, strerror(-ret));
4150
4151 /*
4152 * If we failed or don't need to set the default TX key (below),
4153 * we're done here.
4154 */
4155 if (ret || !set_tx || alg == WPA_ALG_NONE)
4156 return ret;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004157 if (is_ap_interface(drv->nlmode) && addr &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004158 !is_broadcast_ether_addr(addr))
4159 return ret;
4160
4161 msg = nlmsg_alloc();
4162 if (!msg)
4163 return -ENOMEM;
4164
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004165 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004166 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
4167 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
4168 if (alg == WPA_ALG_IGTK)
4169 NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
4170 else
4171 NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
4172 if (addr && is_broadcast_ether_addr(addr)) {
4173 struct nl_msg *types;
4174 int err;
4175 types = nlmsg_alloc();
4176 if (!types)
4177 goto nla_put_failure;
4178 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
4179 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4180 types);
4181 nlmsg_free(types);
4182 if (err)
4183 goto nla_put_failure;
4184 } else if (addr) {
4185 struct nl_msg *types;
4186 int err;
4187 types = nlmsg_alloc();
4188 if (!types)
4189 goto nla_put_failure;
4190 NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
4191 err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
4192 types);
4193 nlmsg_free(types);
4194 if (err)
4195 goto nla_put_failure;
4196 }
4197
4198 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4199 if (ret == -ENOENT)
4200 ret = 0;
4201 if (ret)
4202 wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
4203 "err=%d %s)", ret, strerror(-ret));
4204 return ret;
4205
4206nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004207 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004208 return -ENOBUFS;
4209}
4210
4211
4212static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
4213 int key_idx, int defkey,
4214 const u8 *seq, size_t seq_len,
4215 const u8 *key, size_t key_len)
4216{
4217 struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
4218 if (!key_attr)
4219 return -1;
4220
4221 if (defkey && alg == WPA_ALG_IGTK)
4222 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
4223 else if (defkey)
4224 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
4225
4226 NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
4227
4228 switch (alg) {
4229 case WPA_ALG_WEP:
4230 if (key_len == 5)
4231 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4232 WLAN_CIPHER_SUITE_WEP40);
4233 else
4234 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4235 WLAN_CIPHER_SUITE_WEP104);
4236 break;
4237 case WPA_ALG_TKIP:
4238 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
4239 break;
4240 case WPA_ALG_CCMP:
4241 NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
4242 break;
4243 case WPA_ALG_IGTK:
4244 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4245 WLAN_CIPHER_SUITE_AES_CMAC);
4246 break;
4247 default:
4248 wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
4249 "algorithm %d", __func__, alg);
4250 return -1;
4251 }
4252
4253 if (seq && seq_len)
4254 NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
4255
4256 NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
4257
4258 nla_nest_end(msg, key_attr);
4259
4260 return 0;
4261 nla_put_failure:
4262 return -1;
4263}
4264
4265
4266static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
4267 struct nl_msg *msg)
4268{
4269 int i, privacy = 0;
4270 struct nlattr *nl_keys, *nl_key;
4271
4272 for (i = 0; i < 4; i++) {
4273 if (!params->wep_key[i])
4274 continue;
4275 privacy = 1;
4276 break;
4277 }
4278 if (params->wps == WPS_MODE_PRIVACY)
4279 privacy = 1;
4280 if (params->pairwise_suite &&
4281 params->pairwise_suite != WPA_CIPHER_NONE)
4282 privacy = 1;
4283
4284 if (!privacy)
4285 return 0;
4286
4287 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
4288
4289 nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
4290 if (!nl_keys)
4291 goto nla_put_failure;
4292
4293 for (i = 0; i < 4; i++) {
4294 if (!params->wep_key[i])
4295 continue;
4296
4297 nl_key = nla_nest_start(msg, i);
4298 if (!nl_key)
4299 goto nla_put_failure;
4300
4301 NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
4302 params->wep_key[i]);
4303 if (params->wep_key_len[i] == 5)
4304 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4305 WLAN_CIPHER_SUITE_WEP40);
4306 else
4307 NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
4308 WLAN_CIPHER_SUITE_WEP104);
4309
4310 NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
4311
4312 if (i == params->wep_tx_keyidx)
4313 NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
4314
4315 nla_nest_end(msg, nl_key);
4316 }
4317 nla_nest_end(msg, nl_keys);
4318
4319 return 0;
4320
4321nla_put_failure:
4322 return -ENOBUFS;
4323}
4324
4325
4326static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
4327 const u8 *addr, int cmd, u16 reason_code,
4328 int local_state_change)
4329{
4330 int ret = -1;
4331 struct nl_msg *msg;
4332
4333 msg = nlmsg_alloc();
4334 if (!msg)
4335 return -1;
4336
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004337 nl80211_cmd(drv, msg, 0, cmd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004338
4339 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4340 NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
4341 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
4342 if (local_state_change)
4343 NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
4344
4345 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4346 msg = NULL;
4347 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004348 wpa_dbg(drv->ctx, MSG_DEBUG,
4349 "nl80211: MLME command failed: reason=%u ret=%d (%s)",
4350 reason_code, ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004351 goto nla_put_failure;
4352 }
4353 ret = 0;
4354
4355nla_put_failure:
4356 nlmsg_free(msg);
4357 return ret;
4358}
4359
4360
4361static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
4362 const u8 *addr, int reason_code)
4363{
4364 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
4365 __func__, MAC2STR(addr), reason_code);
4366 drv->associated = 0;
4367 return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
4368 reason_code, 0);
4369}
4370
4371
4372static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
4373 int reason_code)
4374{
4375 struct i802_bss *bss = priv;
4376 struct wpa_driver_nl80211_data *drv = bss->drv;
4377 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
4378 return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
4379 wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
4380 __func__, MAC2STR(addr), reason_code);
4381 drv->associated = 0;
4382 if (drv->nlmode == NL80211_IFTYPE_ADHOC)
4383 return nl80211_leave_ibss(drv);
4384 return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
4385 reason_code, 0);
4386}
4387
4388
4389static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
4390 int reason_code)
4391{
4392 struct i802_bss *bss = priv;
4393 struct wpa_driver_nl80211_data *drv = bss->drv;
4394 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
4395 return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
4396 wpa_printf(MSG_DEBUG, "%s", __func__);
4397 drv->associated = 0;
4398 return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
4399 reason_code, 0);
4400}
4401
4402
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004403static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
4404 struct wpa_driver_auth_params *params)
4405{
4406 int i;
4407
4408 drv->auth_freq = params->freq;
4409 drv->auth_alg = params->auth_alg;
4410 drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
4411 drv->auth_local_state_change = params->local_state_change;
4412 drv->auth_p2p = params->p2p;
4413
4414 if (params->bssid)
4415 os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
4416 else
4417 os_memset(drv->auth_bssid_, 0, ETH_ALEN);
4418
4419 if (params->ssid) {
4420 os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
4421 drv->auth_ssid_len = params->ssid_len;
4422 } else
4423 drv->auth_ssid_len = 0;
4424
4425
4426 os_free(drv->auth_ie);
4427 drv->auth_ie = NULL;
4428 drv->auth_ie_len = 0;
4429 if (params->ie) {
4430 drv->auth_ie = os_malloc(params->ie_len);
4431 if (drv->auth_ie) {
4432 os_memcpy(drv->auth_ie, params->ie, params->ie_len);
4433 drv->auth_ie_len = params->ie_len;
4434 }
4435 }
4436
4437 for (i = 0; i < 4; i++) {
4438 if (params->wep_key[i] && params->wep_key_len[i] &&
4439 params->wep_key_len[i] <= 16) {
4440 os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
4441 params->wep_key_len[i]);
4442 drv->auth_wep_key_len[i] = params->wep_key_len[i];
4443 } else
4444 drv->auth_wep_key_len[i] = 0;
4445 }
4446}
4447
4448
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004449static int wpa_driver_nl80211_authenticate(
4450 void *priv, struct wpa_driver_auth_params *params)
4451{
4452 struct i802_bss *bss = priv;
4453 struct wpa_driver_nl80211_data *drv = bss->drv;
4454 int ret = -1, i;
4455 struct nl_msg *msg;
4456 enum nl80211_auth_type type;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004457 enum nl80211_iftype nlmode;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004458 int count = 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004459 int is_retry;
4460
4461 is_retry = drv->retry_auth;
4462 drv->retry_auth = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004463
4464 drv->associated = 0;
4465 os_memset(drv->auth_bssid, 0, ETH_ALEN);
4466 /* FIX: IBSS mode */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004467 nlmode = params->p2p ?
4468 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
4469 if (drv->nlmode != nlmode &&
4470 wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004471 return -1;
4472
4473retry:
4474 msg = nlmsg_alloc();
4475 if (!msg)
4476 return -1;
4477
4478 wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
4479 drv->ifindex);
4480
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004481 nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004482
4483 for (i = 0; i < 4; i++) {
4484 if (!params->wep_key[i])
4485 continue;
4486 wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
4487 NULL, i,
4488 i == params->wep_tx_keyidx, NULL, 0,
4489 params->wep_key[i],
4490 params->wep_key_len[i]);
4491 if (params->wep_tx_keyidx != i)
4492 continue;
4493 if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
4494 params->wep_key[i], params->wep_key_len[i])) {
4495 nlmsg_free(msg);
4496 return -1;
4497 }
4498 }
4499
4500 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
4501 if (params->bssid) {
4502 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
4503 MAC2STR(params->bssid));
4504 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
4505 }
4506 if (params->freq) {
4507 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
4508 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
4509 }
4510 if (params->ssid) {
4511 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
4512 params->ssid, params->ssid_len);
4513 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
4514 params->ssid);
4515 }
4516 wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
4517 if (params->ie)
4518 NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
4519 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
4520 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
4521 else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
4522 type = NL80211_AUTHTYPE_SHARED_KEY;
4523 else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
4524 type = NL80211_AUTHTYPE_NETWORK_EAP;
4525 else if (params->auth_alg & WPA_AUTH_ALG_FT)
4526 type = NL80211_AUTHTYPE_FT;
4527 else
4528 goto nla_put_failure;
4529 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
4530 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
4531 if (params->local_state_change) {
4532 wpa_printf(MSG_DEBUG, " * Local state change only");
4533 NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
4534 }
4535
4536 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
4537 msg = NULL;
4538 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004539 wpa_dbg(drv->ctx, MSG_DEBUG,
4540 "nl80211: MLME command failed (auth): ret=%d (%s)",
4541 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004542 count++;
4543 if (ret == -EALREADY && count == 1 && params->bssid &&
4544 !params->local_state_change) {
4545 /*
4546 * mac80211 does not currently accept new
4547 * authentication if we are already authenticated. As a
4548 * workaround, force deauthentication and try again.
4549 */
4550 wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
4551 "after forced deauthentication");
4552 wpa_driver_nl80211_deauthenticate(
4553 bss, params->bssid,
4554 WLAN_REASON_PREV_AUTH_NOT_VALID);
4555 nlmsg_free(msg);
4556 goto retry;
4557 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004558
4559 if (ret == -ENOENT && params->freq && !is_retry) {
4560 /*
4561 * cfg80211 has likely expired the BSS entry even
4562 * though it was previously available in our internal
4563 * BSS table. To recover quickly, start a single
4564 * channel scan on the specified channel.
4565 */
4566 struct wpa_driver_scan_params scan;
4567 int freqs[2];
4568
4569 os_memset(&scan, 0, sizeof(scan));
4570 scan.num_ssids = 1;
4571 if (params->ssid) {
4572 scan.ssids[0].ssid = params->ssid;
4573 scan.ssids[0].ssid_len = params->ssid_len;
4574 }
4575 freqs[0] = params->freq;
4576 freqs[1] = 0;
4577 scan.freqs = freqs;
4578 wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
4579 "channel scan to refresh cfg80211 BSS "
4580 "entry");
4581 ret = wpa_driver_nl80211_scan(bss, &scan);
4582 if (ret == 0) {
4583 nl80211_copy_auth_params(drv, params);
4584 drv->scan_for_auth = 1;
4585 }
4586 } else if (is_retry) {
4587 /*
4588 * Need to indicate this with an event since the return
4589 * value from the retry is not delivered to core code.
4590 */
4591 union wpa_event_data event;
4592 wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
4593 "failed");
4594 os_memset(&event, 0, sizeof(event));
4595 os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
4596 ETH_ALEN);
4597 wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
4598 &event);
4599 }
4600
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004601 goto nla_put_failure;
4602 }
4603 ret = 0;
4604 wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
4605 "successfully");
4606
4607nla_put_failure:
4608 nlmsg_free(msg);
4609 return ret;
4610}
4611
4612
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004613static int wpa_driver_nl80211_authenticate_retry(
4614 struct wpa_driver_nl80211_data *drv)
4615{
4616 struct wpa_driver_auth_params params;
4617 struct i802_bss *bss = &drv->first_bss;
4618 int i;
4619
4620 wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
4621
4622 os_memset(&params, 0, sizeof(params));
4623 params.freq = drv->auth_freq;
4624 params.auth_alg = drv->auth_alg;
4625 params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
4626 params.local_state_change = drv->auth_local_state_change;
4627 params.p2p = drv->auth_p2p;
4628
4629 if (!is_zero_ether_addr(drv->auth_bssid_))
4630 params.bssid = drv->auth_bssid_;
4631
4632 if (drv->auth_ssid_len) {
4633 params.ssid = drv->auth_ssid;
4634 params.ssid_len = drv->auth_ssid_len;
4635 }
4636
4637 params.ie = drv->auth_ie;
4638 params.ie_len = drv->auth_ie_len;
4639
4640 for (i = 0; i < 4; i++) {
4641 if (drv->auth_wep_key_len[i]) {
4642 params.wep_key[i] = drv->auth_wep_key[i];
4643 params.wep_key_len[i] = drv->auth_wep_key_len[i];
4644 }
4645 }
4646
4647 drv->retry_auth = 1;
4648 return wpa_driver_nl80211_authenticate(bss, &params);
4649}
4650
4651
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004652struct phy_info_arg {
4653 u16 *num_modes;
4654 struct hostapd_hw_modes *modes;
4655};
4656
4657static int phy_info_handler(struct nl_msg *msg, void *arg)
4658{
4659 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
4660 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
4661 struct phy_info_arg *phy_info = arg;
4662
4663 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
4664
4665 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
4666 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
4667 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
4668 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
4669 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
4670 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
4671 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
4672 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
4673 };
4674
4675 struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
4676 static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
4677 [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
4678 [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
4679 };
4680
4681 struct nlattr *nl_band;
4682 struct nlattr *nl_freq;
4683 struct nlattr *nl_rate;
4684 int rem_band, rem_freq, rem_rate;
4685 struct hostapd_hw_modes *mode;
4686 int idx, mode_is_set;
4687
4688 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
4689 genlmsg_attrlen(gnlh, 0), NULL);
4690
4691 if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
4692 return NL_SKIP;
4693
4694 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
4695 mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
4696 if (!mode)
4697 return NL_SKIP;
4698 phy_info->modes = mode;
4699
4700 mode_is_set = 0;
4701
4702 mode = &phy_info->modes[*(phy_info->num_modes)];
4703 memset(mode, 0, sizeof(*mode));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004704 mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004705 *(phy_info->num_modes) += 1;
4706
4707 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
4708 nla_len(nl_band), NULL);
4709
4710 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
4711 mode->ht_capab = nla_get_u16(
4712 tb_band[NL80211_BAND_ATTR_HT_CAPA]);
4713 }
4714
4715 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
4716 mode->a_mpdu_params |= nla_get_u8(
4717 tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
4718 0x03;
4719 }
4720
4721 if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
4722 mode->a_mpdu_params |= nla_get_u8(
4723 tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
4724 2;
4725 }
4726
4727 if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
4728 nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
4729 u8 *mcs;
4730 mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
4731 os_memcpy(mode->mcs_set, mcs, 16);
4732 }
4733
4734 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
4735 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
4736 nla_len(nl_freq), freq_policy);
4737 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
4738 continue;
4739 mode->num_channels++;
4740 }
4741
4742 mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
4743 if (!mode->channels)
4744 return NL_SKIP;
4745
4746 idx = 0;
4747
4748 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
4749 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
4750 nla_len(nl_freq), freq_policy);
4751 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
4752 continue;
4753
4754 mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
4755 mode->channels[idx].flag = 0;
4756
4757 if (!mode_is_set) {
4758 /* crude heuristic */
4759 if (mode->channels[idx].freq < 4000)
4760 mode->mode = HOSTAPD_MODE_IEEE80211B;
4761 else
4762 mode->mode = HOSTAPD_MODE_IEEE80211A;
4763 mode_is_set = 1;
4764 }
4765
4766 /* crude heuristic */
4767 if (mode->channels[idx].freq < 4000)
4768 if (mode->channels[idx].freq == 2484)
4769 mode->channels[idx].chan = 14;
4770 else
4771 mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
4772 else
4773 mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
4774
4775 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
4776 mode->channels[idx].flag |=
4777 HOSTAPD_CHAN_DISABLED;
4778 if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
4779 mode->channels[idx].flag |=
4780 HOSTAPD_CHAN_PASSIVE_SCAN;
4781 if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
4782 mode->channels[idx].flag |=
4783 HOSTAPD_CHAN_NO_IBSS;
4784 if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
4785 mode->channels[idx].flag |=
4786 HOSTAPD_CHAN_RADAR;
4787
4788 if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
4789 !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
4790 mode->channels[idx].max_tx_power =
4791 nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
4792
4793 idx++;
4794 }
4795
4796 nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
4797 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
4798 nla_len(nl_rate), rate_policy);
4799 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
4800 continue;
4801 mode->num_rates++;
4802 }
4803
4804 mode->rates = os_zalloc(mode->num_rates * sizeof(int));
4805 if (!mode->rates)
4806 return NL_SKIP;
4807
4808 idx = 0;
4809
4810 nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
4811 nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
4812 nla_len(nl_rate), rate_policy);
4813 if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
4814 continue;
4815 mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
4816
4817 /* crude heuristic */
4818 if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
4819 mode->rates[idx] > 200)
4820 mode->mode = HOSTAPD_MODE_IEEE80211G;
4821
4822 idx++;
4823 }
4824 }
4825
4826 return NL_SKIP;
4827}
4828
4829static struct hostapd_hw_modes *
4830wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
4831{
4832 u16 m;
4833 struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
4834 int i, mode11g_idx = -1;
4835
4836 /* If only 802.11g mode is included, use it to construct matching
4837 * 802.11b mode data. */
4838
4839 for (m = 0; m < *num_modes; m++) {
4840 if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
4841 return modes; /* 802.11b already included */
4842 if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
4843 mode11g_idx = m;
4844 }
4845
4846 if (mode11g_idx < 0)
4847 return modes; /* 2.4 GHz band not supported at all */
4848
4849 nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
4850 if (nmodes == NULL)
4851 return modes; /* Could not add 802.11b mode */
4852
4853 mode = &nmodes[*num_modes];
4854 os_memset(mode, 0, sizeof(*mode));
4855 (*num_modes)++;
4856 modes = nmodes;
4857
4858 mode->mode = HOSTAPD_MODE_IEEE80211B;
4859
4860 mode11g = &modes[mode11g_idx];
4861 mode->num_channels = mode11g->num_channels;
4862 mode->channels = os_malloc(mode11g->num_channels *
4863 sizeof(struct hostapd_channel_data));
4864 if (mode->channels == NULL) {
4865 (*num_modes)--;
4866 return modes; /* Could not add 802.11b mode */
4867 }
4868 os_memcpy(mode->channels, mode11g->channels,
4869 mode11g->num_channels * sizeof(struct hostapd_channel_data));
4870
4871 mode->num_rates = 0;
4872 mode->rates = os_malloc(4 * sizeof(int));
4873 if (mode->rates == NULL) {
4874 os_free(mode->channels);
4875 (*num_modes)--;
4876 return modes; /* Could not add 802.11b mode */
4877 }
4878
4879 for (i = 0; i < mode11g->num_rates; i++) {
4880 if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
4881 mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
4882 continue;
4883 mode->rates[mode->num_rates] = mode11g->rates[i];
4884 mode->num_rates++;
4885 if (mode->num_rates == 4)
4886 break;
4887 }
4888
4889 if (mode->num_rates == 0) {
4890 os_free(mode->channels);
4891 os_free(mode->rates);
4892 (*num_modes)--;
4893 return modes; /* No 802.11b rates */
4894 }
4895
4896 wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
4897 "information");
4898
4899 return modes;
4900}
4901
4902
4903static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
4904 int end)
4905{
4906 int c;
4907
4908 for (c = 0; c < mode->num_channels; c++) {
4909 struct hostapd_channel_data *chan = &mode->channels[c];
4910 if (chan->freq - 10 >= start && chan->freq + 10 <= end)
4911 chan->flag |= HOSTAPD_CHAN_HT40;
4912 }
4913}
4914
4915
4916static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
4917 int end)
4918{
4919 int c;
4920
4921 for (c = 0; c < mode->num_channels; c++) {
4922 struct hostapd_channel_data *chan = &mode->channels[c];
4923 if (!(chan->flag & HOSTAPD_CHAN_HT40))
4924 continue;
4925 if (chan->freq - 30 >= start && chan->freq - 10 <= end)
4926 chan->flag |= HOSTAPD_CHAN_HT40MINUS;
4927 if (chan->freq + 10 >= start && chan->freq + 30 <= end)
4928 chan->flag |= HOSTAPD_CHAN_HT40PLUS;
4929 }
4930}
4931
4932
4933static void nl80211_reg_rule_ht40(struct nlattr *tb[],
4934 struct phy_info_arg *results)
4935{
4936 u32 start, end, max_bw;
4937 u16 m;
4938
4939 if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
4940 tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
4941 tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
4942 return;
4943
4944 start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
4945 end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
4946 max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
4947
4948 wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
4949 start, end, max_bw);
4950 if (max_bw < 40)
4951 return;
4952
4953 for (m = 0; m < *results->num_modes; m++) {
4954 if (!(results->modes[m].ht_capab &
4955 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
4956 continue;
4957 nl80211_set_ht40_mode(&results->modes[m], start, end);
4958 }
4959}
4960
4961
4962static void nl80211_reg_rule_sec(struct nlattr *tb[],
4963 struct phy_info_arg *results)
4964{
4965 u32 start, end, max_bw;
4966 u16 m;
4967
4968 if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
4969 tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
4970 tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
4971 return;
4972
4973 start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
4974 end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
4975 max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
4976
4977 if (max_bw < 20)
4978 return;
4979
4980 for (m = 0; m < *results->num_modes; m++) {
4981 if (!(results->modes[m].ht_capab &
4982 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
4983 continue;
4984 nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
4985 }
4986}
4987
4988
4989static int nl80211_get_reg(struct nl_msg *msg, void *arg)
4990{
4991 struct phy_info_arg *results = arg;
4992 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
4993 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
4994 struct nlattr *nl_rule;
4995 struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
4996 int rem_rule;
4997 static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
4998 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
4999 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
5000 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
5001 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
5002 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
5003 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
5004 };
5005
5006 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
5007 genlmsg_attrlen(gnlh, 0), NULL);
5008 if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
5009 !tb_msg[NL80211_ATTR_REG_RULES]) {
5010 wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
5011 "available");
5012 return NL_SKIP;
5013 }
5014
5015 wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
5016 (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
5017
5018 nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
5019 {
5020 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
5021 nla_data(nl_rule), nla_len(nl_rule), reg_policy);
5022 nl80211_reg_rule_ht40(tb_rule, results);
5023 }
5024
5025 nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
5026 {
5027 nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
5028 nla_data(nl_rule), nla_len(nl_rule), reg_policy);
5029 nl80211_reg_rule_sec(tb_rule, results);
5030 }
5031
5032 return NL_SKIP;
5033}
5034
5035
5036static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
5037 struct phy_info_arg *results)
5038{
5039 struct nl_msg *msg;
5040
5041 msg = nlmsg_alloc();
5042 if (!msg)
5043 return -ENOMEM;
5044
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005045 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005046 return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
5047}
5048
5049
5050static struct hostapd_hw_modes *
5051wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
5052{
5053 struct i802_bss *bss = priv;
5054 struct wpa_driver_nl80211_data *drv = bss->drv;
5055 struct nl_msg *msg;
5056 struct phy_info_arg result = {
5057 .num_modes = num_modes,
5058 .modes = NULL,
5059 };
5060
5061 *num_modes = 0;
5062 *flags = 0;
5063
5064 msg = nlmsg_alloc();
5065 if (!msg)
5066 return NULL;
5067
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005068 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005069
5070 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
5071
5072 if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
5073 nl80211_set_ht40_flags(drv, &result);
5074 return wpa_driver_nl80211_add_11b(result.modes, num_modes);
5075 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005076 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005077 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005078 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005079 return NULL;
5080}
5081
5082
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005083static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
5084 const void *data, size_t len,
5085 int encrypt, int noack)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005086{
5087 __u8 rtap_hdr[] = {
5088 0x00, 0x00, /* radiotap version */
5089 0x0e, 0x00, /* radiotap length */
5090 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
5091 IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
5092 0x00, /* padding */
5093 0x00, 0x00, /* RX and TX flags to indicate that */
5094 0x00, 0x00, /* this is the injected frame directly */
5095 };
5096 struct iovec iov[2] = {
5097 {
5098 .iov_base = &rtap_hdr,
5099 .iov_len = sizeof(rtap_hdr),
5100 },
5101 {
5102 .iov_base = (void *) data,
5103 .iov_len = len,
5104 }
5105 };
5106 struct msghdr msg = {
5107 .msg_name = NULL,
5108 .msg_namelen = 0,
5109 .msg_iov = iov,
5110 .msg_iovlen = 2,
5111 .msg_control = NULL,
5112 .msg_controllen = 0,
5113 .msg_flags = 0,
5114 };
5115 int res;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005116 u16 txflags = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005117
5118 if (encrypt)
5119 rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
5120
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07005121 if (drv->monitor_sock < 0) {
5122 wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
5123 "for %s", __func__);
5124 return -1;
5125 }
5126
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005127 if (noack)
5128 txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
5129 *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
5130
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005131 res = sendmsg(drv->monitor_sock, &msg, 0);
5132 if (res < 0) {
5133 wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
5134 return -1;
5135 }
5136 return 0;
5137}
5138
5139
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005140static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
5141 const void *data, size_t len,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005142 int encrypt, int noack,
5143 unsigned int freq, int no_cck,
5144 int offchanok, unsigned int wait_time)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005145{
5146 struct wpa_driver_nl80211_data *drv = bss->drv;
5147 u64 cookie;
5148
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005149 if (freq == 0)
5150 freq = bss->freq;
5151
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005152 if (drv->use_monitor)
5153 return wpa_driver_nl80211_send_mntr(drv, data, len,
5154 encrypt, noack);
5155
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005156 return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
5157 &cookie, no_cck, noack, offchanok);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005158}
5159
5160
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005161static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
5162 const u8 *data,
5163 size_t data_len, int noack,
5164 unsigned int freq, int no_cck,
5165 int offchanok,
5166 unsigned int wait_time)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005167{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005168 struct wpa_driver_nl80211_data *drv = bss->drv;
5169 struct ieee80211_mgmt *mgmt;
5170 int encrypt = 1;
5171 u16 fc;
5172
5173 mgmt = (struct ieee80211_mgmt *) data;
5174 fc = le_to_host16(mgmt->frame_control);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005175
5176 if (is_sta_interface(drv->nlmode) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005177 WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
5178 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
5179 /*
5180 * The use of last_mgmt_freq is a bit of a hack,
5181 * but it works due to the single-threaded nature
5182 * of wpa_supplicant.
5183 */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005184 if (freq == 0)
5185 freq = drv->last_mgmt_freq;
5186 return nl80211_send_frame_cmd(bss, freq, 0,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005187 data, data_len, NULL, 1, noack,
5188 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005189 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005190
5191 if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005192 if (freq == 0)
5193 freq = bss->freq;
5194 return nl80211_send_frame_cmd(bss, freq, 0,
5195 data, data_len,
5196 &drv->send_action_cookie,
5197 no_cck, noack, offchanok);
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07005198 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07005199
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005200 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
5201 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
5202 /*
5203 * Only one of the authentication frame types is encrypted.
5204 * In order for static WEP encryption to work properly (i.e.,
5205 * to not encrypt the frame), we need to tell mac80211 about
5206 * the frames that must not be encrypted.
5207 */
5208 u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
5209 u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
5210 if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
5211 encrypt = 0;
5212 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005213
5214 return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005215 noack, freq, no_cck, offchanok,
5216 wait_time);
5217}
5218
5219
5220static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
5221 size_t data_len, int noack)
5222{
5223 struct i802_bss *bss = priv;
5224 return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
5225 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005226}
5227
5228
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005229static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
5230 int slot, int ht_opmode, int ap_isolate,
5231 int *basic_rates)
5232{
5233 struct wpa_driver_nl80211_data *drv = bss->drv;
5234 struct nl_msg *msg;
5235
5236 msg = nlmsg_alloc();
5237 if (!msg)
5238 return -ENOMEM;
5239
5240 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
5241
5242 if (cts >= 0)
5243 NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
5244 if (preamble >= 0)
5245 NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
5246 if (slot >= 0)
5247 NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
5248 if (ht_opmode >= 0)
5249 NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
5250 if (ap_isolate >= 0)
5251 NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
5252
5253 if (basic_rates) {
5254 u8 rates[NL80211_MAX_SUPP_RATES];
5255 u8 rates_len = 0;
5256 int i;
5257
5258 for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
5259 i++)
5260 rates[rates_len++] = basic_rates[i] / 5;
5261
5262 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
5263 }
5264
5265 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
5266
5267 return send_and_recv_msgs(drv, msg, NULL, NULL);
5268 nla_put_failure:
5269 nlmsg_free(msg);
5270 return -ENOBUFS;
5271}
5272
5273
5274static int wpa_driver_nl80211_set_ap(void *priv,
5275 struct wpa_driver_ap_params *params)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005276{
5277 struct i802_bss *bss = priv;
5278 struct wpa_driver_nl80211_data *drv = bss->drv;
5279 struct nl_msg *msg;
5280 u8 cmd = NL80211_CMD_NEW_BEACON;
5281 int ret;
5282 int beacon_set;
5283 int ifindex = if_nametoindex(bss->ifname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005284 int num_suites;
5285 u32 suites[10];
5286 u32 ver;
5287
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07005288 beacon_set = bss->beacon_set;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005289
5290 msg = nlmsg_alloc();
5291 if (!msg)
5292 return -ENOMEM;
5293
5294 wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
5295 beacon_set);
5296 if (beacon_set)
5297 cmd = NL80211_CMD_SET_BEACON;
5298
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005299 nl80211_cmd(drv, msg, 0, cmd);
5300 NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
5301 NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005302 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005303 NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
5304 NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
5305 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
5306 params->ssid);
5307 if (params->proberesp && params->proberesp_len)
5308 NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
5309 params->proberesp);
5310 switch (params->hide_ssid) {
5311 case NO_SSID_HIDING:
5312 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5313 NL80211_HIDDEN_SSID_NOT_IN_USE);
5314 break;
5315 case HIDDEN_SSID_ZERO_LEN:
5316 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5317 NL80211_HIDDEN_SSID_ZERO_LEN);
5318 break;
5319 case HIDDEN_SSID_ZERO_CONTENTS:
5320 NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
5321 NL80211_HIDDEN_SSID_ZERO_CONTENTS);
5322 break;
5323 }
5324 if (params->privacy)
5325 NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
5326 if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
5327 (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
5328 /* Leave out the attribute */
5329 } else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
5330 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
5331 NL80211_AUTHTYPE_SHARED_KEY);
5332 else
5333 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
5334 NL80211_AUTHTYPE_OPEN_SYSTEM);
5335
5336 ver = 0;
5337 if (params->wpa_version & WPA_PROTO_WPA)
5338 ver |= NL80211_WPA_VERSION_1;
5339 if (params->wpa_version & WPA_PROTO_RSN)
5340 ver |= NL80211_WPA_VERSION_2;
5341 if (ver)
5342 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
5343
5344 num_suites = 0;
5345 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
5346 suites[num_suites++] = WLAN_AKM_SUITE_8021X;
5347 if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
5348 suites[num_suites++] = WLAN_AKM_SUITE_PSK;
5349 if (num_suites) {
5350 NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
5351 num_suites * sizeof(u32), suites);
5352 }
5353
5354 if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
5355 params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
5356 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
5357
5358 num_suites = 0;
5359 if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
5360 suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
5361 if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
5362 suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
5363 if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
5364 suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
5365 if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
5366 suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
5367 if (num_suites) {
5368 NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
5369 num_suites * sizeof(u32), suites);
5370 }
5371
5372 switch (params->group_cipher) {
5373 case WPA_CIPHER_CCMP:
5374 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5375 WLAN_CIPHER_SUITE_CCMP);
5376 break;
5377 case WPA_CIPHER_TKIP:
5378 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5379 WLAN_CIPHER_SUITE_TKIP);
5380 break;
5381 case WPA_CIPHER_WEP104:
5382 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5383 WLAN_CIPHER_SUITE_WEP104);
5384 break;
5385 case WPA_CIPHER_WEP40:
5386 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
5387 WLAN_CIPHER_SUITE_WEP40);
5388 break;
5389 }
5390
5391 if (params->beacon_ies) {
5392 NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
5393 wpabuf_head(params->beacon_ies));
5394 }
5395 if (params->proberesp_ies) {
5396 NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
5397 wpabuf_len(params->proberesp_ies),
5398 wpabuf_head(params->proberesp_ies));
5399 }
5400 if (params->assocresp_ies) {
5401 NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
5402 wpabuf_len(params->assocresp_ies),
5403 wpabuf_head(params->assocresp_ies));
5404 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005405
5406 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5407 if (ret) {
5408 wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
5409 ret, strerror(-ret));
5410 } else {
5411 bss->beacon_set = 1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005412 nl80211_set_bss(bss, params->cts_protect, params->preamble,
5413 params->short_slot_time, params->ht_opmode,
5414 params->isolate, params->basic_rates);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005415 }
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07005416
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005417 return ret;
5418 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005419 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005420 return -ENOBUFS;
5421}
5422
5423
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005424static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005425 int freq, int ht_enabled,
5426 int sec_channel_offset)
5427{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005428 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005429 struct nl_msg *msg;
5430 int ret;
5431
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005432 wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
5433 "sec_channel_offset=%d)",
5434 freq, ht_enabled, sec_channel_offset);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005435 msg = nlmsg_alloc();
5436 if (!msg)
5437 return -1;
5438
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005439 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005440
5441 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
5442 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
5443 if (ht_enabled) {
5444 switch (sec_channel_offset) {
5445 case -1:
5446 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5447 NL80211_CHAN_HT40MINUS);
5448 break;
5449 case 1:
5450 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5451 NL80211_CHAN_HT40PLUS);
5452 break;
5453 default:
5454 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
5455 NL80211_CHAN_HT20);
5456 break;
5457 }
5458 }
5459
5460 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005461 msg = NULL;
5462 if (ret == 0) {
5463 bss->freq = freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005464 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005465 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005466 wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
5467 "%d (%s)", freq, ret, strerror(-ret));
5468nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005469 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005470 return -1;
5471}
5472
5473
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005474static u32 sta_flags_nl80211(int flags)
5475{
5476 u32 f = 0;
5477
5478 if (flags & WPA_STA_AUTHORIZED)
5479 f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
5480 if (flags & WPA_STA_WMM)
5481 f |= BIT(NL80211_STA_FLAG_WME);
5482 if (flags & WPA_STA_SHORT_PREAMBLE)
5483 f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
5484 if (flags & WPA_STA_MFP)
5485 f |= BIT(NL80211_STA_FLAG_MFP);
5486 if (flags & WPA_STA_TDLS_PEER)
5487 f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
5488
5489 return f;
5490}
5491
5492
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005493static int wpa_driver_nl80211_sta_add(void *priv,
5494 struct hostapd_sta_add_params *params)
5495{
5496 struct i802_bss *bss = priv;
5497 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005498 struct nl_msg *msg, *wme = NULL;
5499 struct nl80211_sta_flag_update upd;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005500 int ret = -ENOBUFS;
5501
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005502 if ((params->flags & WPA_STA_TDLS_PEER) &&
5503 !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
5504 return -EOPNOTSUPP;
5505
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005506 msg = nlmsg_alloc();
5507 if (!msg)
5508 return -ENOMEM;
5509
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005510 nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
5511 NL80211_CMD_NEW_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005512
5513 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
5514 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005515 NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
5516 params->supp_rates);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005517 if (!params->set) {
5518 NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
5519 NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
5520 params->listen_interval);
5521 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005522 if (params->ht_capabilities) {
5523 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
5524 sizeof(*params->ht_capabilities),
5525 params->ht_capabilities);
5526 }
5527
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005528 os_memset(&upd, 0, sizeof(upd));
5529 upd.mask = sta_flags_nl80211(params->flags);
5530 upd.set = upd.mask;
5531 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
5532
5533 if (params->flags & WPA_STA_WMM) {
5534 wme = nlmsg_alloc();
5535 if (!wme)
5536 goto nla_put_failure;
5537
5538 NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
5539 params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
5540 NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
5541 (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
5542 WMM_QOSINFO_STA_SP_MASK);
5543 nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
5544 }
5545
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005546 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005547 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005548 if (ret)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005549 wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
5550 "result: %d (%s)", params->set ? "SET" : "NEW", ret,
5551 strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005552 if (ret == -EEXIST)
5553 ret = 0;
5554 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005555 nlmsg_free(wme);
5556 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005557 return ret;
5558}
5559
5560
5561static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
5562{
5563 struct i802_bss *bss = priv;
5564 struct wpa_driver_nl80211_data *drv = bss->drv;
5565 struct nl_msg *msg;
5566 int ret;
5567
5568 msg = nlmsg_alloc();
5569 if (!msg)
5570 return -ENOMEM;
5571
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005572 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005573
5574 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
5575 if_nametoindex(bss->ifname));
5576 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
5577
5578 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5579 if (ret == -ENOENT)
5580 return 0;
5581 return ret;
5582 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005583 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005584 return -ENOBUFS;
5585}
5586
5587
5588static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
5589 int ifidx)
5590{
5591 struct nl_msg *msg;
5592
5593 wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
5594
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005595 /* stop listening for EAPOL on this interface */
5596 del_ifidx(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005597
5598 msg = nlmsg_alloc();
5599 if (!msg)
5600 goto nla_put_failure;
5601
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005602 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005603 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
5604
5605 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
5606 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005607 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005608 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005609 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005610 wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
5611}
5612
5613
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005614static const char * nl80211_iftype_str(enum nl80211_iftype mode)
5615{
5616 switch (mode) {
5617 case NL80211_IFTYPE_ADHOC:
5618 return "ADHOC";
5619 case NL80211_IFTYPE_STATION:
5620 return "STATION";
5621 case NL80211_IFTYPE_AP:
5622 return "AP";
5623 case NL80211_IFTYPE_MONITOR:
5624 return "MONITOR";
5625 case NL80211_IFTYPE_P2P_CLIENT:
5626 return "P2P_CLIENT";
5627 case NL80211_IFTYPE_P2P_GO:
5628 return "P2P_GO";
5629 default:
5630 return "unknown";
5631 }
5632}
5633
5634
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005635static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
5636 const char *ifname,
5637 enum nl80211_iftype iftype,
5638 const u8 *addr, int wds)
5639{
5640 struct nl_msg *msg, *flags = NULL;
5641 int ifidx;
5642 int ret = -ENOBUFS;
5643
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005644 wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
5645 iftype, nl80211_iftype_str(iftype));
5646
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005647 msg = nlmsg_alloc();
5648 if (!msg)
5649 return -1;
5650
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005651 nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005652 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
5653 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
5654 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
5655
5656 if (iftype == NL80211_IFTYPE_MONITOR) {
5657 int err;
5658
5659 flags = nlmsg_alloc();
5660 if (!flags)
5661 goto nla_put_failure;
5662
5663 NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
5664
5665 err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
5666
5667 nlmsg_free(flags);
5668
5669 if (err)
5670 goto nla_put_failure;
5671 } else if (wds) {
5672 NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
5673 }
5674
5675 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005676 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005677 if (ret) {
5678 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005679 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005680 wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
5681 ifname, ret, strerror(-ret));
5682 return ret;
5683 }
5684
5685 ifidx = if_nametoindex(ifname);
5686 wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
5687 ifname, ifidx);
5688
5689 if (ifidx <= 0)
5690 return -1;
5691
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005692 /* start listening for EAPOL on this interface */
5693 add_ifidx(drv, ifidx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005694
5695 if (addr && iftype != NL80211_IFTYPE_MONITOR &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005696 linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005697 nl80211_remove_iface(drv, ifidx);
5698 return -1;
5699 }
5700
5701 return ifidx;
5702}
5703
5704
5705static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
5706 const char *ifname, enum nl80211_iftype iftype,
5707 const u8 *addr, int wds)
5708{
5709 int ret;
5710
5711 ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
5712
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005713 /* if error occurred and interface exists already */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005714 if (ret == -ENFILE && if_nametoindex(ifname)) {
5715 wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
5716
5717 /* Try to remove the interface that was already there. */
5718 nl80211_remove_iface(drv, if_nametoindex(ifname));
5719
5720 /* Try to create the interface again */
5721 ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
5722 wds);
5723 }
5724
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005725 if (ret >= 0 && is_p2p_interface(iftype))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005726 nl80211_disable_11b_rates(drv, ret, 1);
5727
5728 return ret;
5729}
5730
5731
5732static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
5733{
5734 struct ieee80211_hdr *hdr;
5735 u16 fc;
5736 union wpa_event_data event;
5737
5738 hdr = (struct ieee80211_hdr *) buf;
5739 fc = le_to_host16(hdr->frame_control);
5740
5741 os_memset(&event, 0, sizeof(event));
5742 event.tx_status.type = WLAN_FC_GET_TYPE(fc);
5743 event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
5744 event.tx_status.dst = hdr->addr1;
5745 event.tx_status.data = buf;
5746 event.tx_status.data_len = len;
5747 event.tx_status.ack = ok;
5748 wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
5749}
5750
5751
5752static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
5753 u8 *buf, size_t len)
5754{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005755 struct ieee80211_hdr *hdr = (void *)buf;
5756 u16 fc;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005757 union wpa_event_data event;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005758
5759 if (len < sizeof(*hdr))
5760 return;
5761
5762 fc = le_to_host16(hdr->frame_control);
5763
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005764 os_memset(&event, 0, sizeof(event));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08005765 event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
5766 event.rx_from_unknown.addr = hdr->addr2;
5767 event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
5768 (WLAN_FC_FROMDS | WLAN_FC_TODS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005769 wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
5770}
5771
5772
5773static void handle_frame(struct wpa_driver_nl80211_data *drv,
5774 u8 *buf, size_t len, int datarate, int ssi_signal)
5775{
5776 struct ieee80211_hdr *hdr;
5777 u16 fc;
5778 union wpa_event_data event;
5779
5780 hdr = (struct ieee80211_hdr *) buf;
5781 fc = le_to_host16(hdr->frame_control);
5782
5783 switch (WLAN_FC_GET_TYPE(fc)) {
5784 case WLAN_FC_TYPE_MGMT:
5785 os_memset(&event, 0, sizeof(event));
5786 event.rx_mgmt.frame = buf;
5787 event.rx_mgmt.frame_len = len;
5788 event.rx_mgmt.datarate = datarate;
5789 event.rx_mgmt.ssi_signal = ssi_signal;
5790 wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
5791 break;
5792 case WLAN_FC_TYPE_CTRL:
5793 /* can only get here with PS-Poll frames */
5794 wpa_printf(MSG_DEBUG, "CTRL");
5795 from_unknown_sta(drv, buf, len);
5796 break;
5797 case WLAN_FC_TYPE_DATA:
5798 from_unknown_sta(drv, buf, len);
5799 break;
5800 }
5801}
5802
5803
5804static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
5805{
5806 struct wpa_driver_nl80211_data *drv = eloop_ctx;
5807 int len;
5808 unsigned char buf[3000];
5809 struct ieee80211_radiotap_iterator iter;
5810 int ret;
5811 int datarate = 0, ssi_signal = 0;
5812 int injected = 0, failed = 0, rxflags = 0;
5813
5814 len = recv(sock, buf, sizeof(buf), 0);
5815 if (len < 0) {
5816 perror("recv");
5817 return;
5818 }
5819
5820 if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
5821 printf("received invalid radiotap frame\n");
5822 return;
5823 }
5824
5825 while (1) {
5826 ret = ieee80211_radiotap_iterator_next(&iter);
5827 if (ret == -ENOENT)
5828 break;
5829 if (ret) {
5830 printf("received invalid radiotap frame (%d)\n", ret);
5831 return;
5832 }
5833 switch (iter.this_arg_index) {
5834 case IEEE80211_RADIOTAP_FLAGS:
5835 if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
5836 len -= 4;
5837 break;
5838 case IEEE80211_RADIOTAP_RX_FLAGS:
5839 rxflags = 1;
5840 break;
5841 case IEEE80211_RADIOTAP_TX_FLAGS:
5842 injected = 1;
5843 failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
5844 IEEE80211_RADIOTAP_F_TX_FAIL;
5845 break;
5846 case IEEE80211_RADIOTAP_DATA_RETRIES:
5847 break;
5848 case IEEE80211_RADIOTAP_CHANNEL:
5849 /* TODO: convert from freq/flags to channel number */
5850 break;
5851 case IEEE80211_RADIOTAP_RATE:
5852 datarate = *iter.this_arg * 5;
5853 break;
5854 case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
5855 ssi_signal = *iter.this_arg;
5856 break;
5857 }
5858 }
5859
5860 if (rxflags && injected)
5861 return;
5862
5863 if (!injected)
5864 handle_frame(drv, buf + iter.max_length,
5865 len - iter.max_length, datarate, ssi_signal);
5866 else
5867 handle_tx_callback(drv->ctx, buf + iter.max_length,
5868 len - iter.max_length, !failed);
5869}
5870
5871
5872/*
5873 * we post-process the filter code later and rewrite
5874 * this to the offset to the last instruction
5875 */
5876#define PASS 0xFF
5877#define FAIL 0xFE
5878
5879static struct sock_filter msock_filter_insns[] = {
5880 /*
5881 * do a little-endian load of the radiotap length field
5882 */
5883 /* load lower byte into A */
5884 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
5885 /* put it into X (== index register) */
5886 BPF_STMT(BPF_MISC| BPF_TAX, 0),
5887 /* load upper byte into A */
5888 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
5889 /* left-shift it by 8 */
5890 BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
5891 /* or with X */
5892 BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
5893 /* put result into X */
5894 BPF_STMT(BPF_MISC| BPF_TAX, 0),
5895
5896 /*
5897 * Allow management frames through, this also gives us those
5898 * management frames that we sent ourselves with status
5899 */
5900 /* load the lower byte of the IEEE 802.11 frame control field */
5901 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
5902 /* mask off frame type and version */
5903 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
5904 /* accept frame if it's both 0, fall through otherwise */
5905 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
5906
5907 /*
5908 * TODO: add a bit to radiotap RX flags that indicates
5909 * that the sending station is not associated, then
5910 * add a filter here that filters on our DA and that flag
5911 * to allow us to deauth frames to that bad station.
5912 *
5913 * For now allow all To DS data frames through.
5914 */
5915 /* load the IEEE 802.11 frame control field */
5916 BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
5917 /* mask off frame type, version and DS status */
5918 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
5919 /* accept frame if version 0, type 2 and To DS, fall through otherwise
5920 */
5921 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
5922
5923#if 0
5924 /*
5925 * drop non-data frames
5926 */
5927 /* load the lower byte of the frame control field */
5928 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
5929 /* mask off QoS bit */
5930 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
5931 /* drop non-data frames */
5932 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
5933#endif
5934 /* load the upper byte of the frame control field */
5935 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
5936 /* mask off toDS/fromDS */
5937 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
5938 /* accept WDS frames */
5939 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
5940
5941 /*
5942 * add header length to index
5943 */
5944 /* load the lower byte of the frame control field */
5945 BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
5946 /* mask off QoS bit */
5947 BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
5948 /* right shift it by 6 to give 0 or 2 */
5949 BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
5950 /* add data frame header length */
5951 BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
5952 /* add index, was start of 802.11 header */
5953 BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
5954 /* move to index, now start of LL header */
5955 BPF_STMT(BPF_MISC | BPF_TAX, 0),
5956
5957 /*
5958 * Accept empty data frames, we use those for
5959 * polling activity.
5960 */
5961 BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
5962 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
5963
5964 /*
5965 * Accept EAPOL frames
5966 */
5967 BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
5968 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
5969 BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
5970 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
5971
5972 /* keep these last two statements or change the code below */
5973 /* return 0 == "DROP" */
5974 BPF_STMT(BPF_RET | BPF_K, 0),
5975 /* return ~0 == "keep all" */
5976 BPF_STMT(BPF_RET | BPF_K, ~0),
5977};
5978
5979static struct sock_fprog msock_filter = {
5980 .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
5981 .filter = msock_filter_insns,
5982};
5983
5984
5985static int add_monitor_filter(int s)
5986{
5987 int idx;
5988
5989 /* rewrite all PASS/FAIL jump offsets */
5990 for (idx = 0; idx < msock_filter.len; idx++) {
5991 struct sock_filter *insn = &msock_filter_insns[idx];
5992
5993 if (BPF_CLASS(insn->code) == BPF_JMP) {
5994 if (insn->code == (BPF_JMP|BPF_JA)) {
5995 if (insn->k == PASS)
5996 insn->k = msock_filter.len - idx - 2;
5997 else if (insn->k == FAIL)
5998 insn->k = msock_filter.len - idx - 3;
5999 }
6000
6001 if (insn->jt == PASS)
6002 insn->jt = msock_filter.len - idx - 2;
6003 else if (insn->jt == FAIL)
6004 insn->jt = msock_filter.len - idx - 3;
6005
6006 if (insn->jf == PASS)
6007 insn->jf = msock_filter.len - idx - 2;
6008 else if (insn->jf == FAIL)
6009 insn->jf = msock_filter.len - idx - 3;
6010 }
6011 }
6012
6013 if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
6014 &msock_filter, sizeof(msock_filter))) {
6015 perror("SO_ATTACH_FILTER");
6016 return -1;
6017 }
6018
6019 return 0;
6020}
6021
6022
6023static void nl80211_remove_monitor_interface(
6024 struct wpa_driver_nl80211_data *drv)
6025{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006026 drv->monitor_refcount--;
6027 if (drv->monitor_refcount > 0)
6028 return;
6029
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006030 if (drv->monitor_ifidx >= 0) {
6031 nl80211_remove_iface(drv, drv->monitor_ifidx);
6032 drv->monitor_ifidx = -1;
6033 }
6034 if (drv->monitor_sock >= 0) {
6035 eloop_unregister_read_sock(drv->monitor_sock);
6036 close(drv->monitor_sock);
6037 drv->monitor_sock = -1;
6038 }
6039}
6040
6041
6042static int
6043nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
6044{
6045 char buf[IFNAMSIZ];
6046 struct sockaddr_ll ll;
6047 int optval;
6048 socklen_t optlen;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006049
6050 if (drv->monitor_ifidx >= 0) {
6051 drv->monitor_refcount++;
6052 return 0;
6053 }
6054
6055 if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
6056 /*
6057 * P2P interface name is of the format p2p-%s-%d. For monitor
6058 * interface name corresponding to P2P GO, replace "p2p-" with
6059 * "mon-" to retain the same interface name length and to
6060 * indicate that it is a monitor interface.
6061 */
6062 snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
6063 } else {
6064 /* Non-P2P interface with AP functionality. */
6065 snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
6066 }
6067
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006068 buf[IFNAMSIZ - 1] = '\0';
6069
6070 drv->monitor_ifidx =
6071 nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
6072 0);
6073
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006074 if (drv->monitor_ifidx == -EOPNOTSUPP) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006075 /*
6076 * This is backward compatibility for a few versions of
6077 * the kernel only that didn't advertise the right
6078 * attributes for the only driver that then supported
6079 * AP mode w/o monitor -- ath6kl.
6080 */
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006081 wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
6082 "monitor interface type - try to run without it");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006083 drv->device_ap_sme = 1;
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07006084 }
6085
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006086 if (drv->monitor_ifidx < 0)
6087 return -1;
6088
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006089 if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006090 goto error;
6091
6092 memset(&ll, 0, sizeof(ll));
6093 ll.sll_family = AF_PACKET;
6094 ll.sll_ifindex = drv->monitor_ifidx;
6095 drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
6096 if (drv->monitor_sock < 0) {
6097 perror("socket[PF_PACKET,SOCK_RAW]");
6098 goto error;
6099 }
6100
6101 if (add_monitor_filter(drv->monitor_sock)) {
6102 wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
6103 "interface; do filtering in user space");
6104 /* This works, but will cost in performance. */
6105 }
6106
6107 if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
6108 perror("monitor socket bind");
6109 goto error;
6110 }
6111
6112 optlen = sizeof(optval);
6113 optval = 20;
6114 if (setsockopt
6115 (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
6116 perror("Failed to set socket priority");
6117 goto error;
6118 }
6119
6120 if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
6121 drv, NULL)) {
6122 printf("Could not register monitor read socket\n");
6123 goto error;
6124 }
6125
6126 return 0;
6127 error:
6128 nl80211_remove_monitor_interface(drv);
6129 return -1;
6130}
6131
6132
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006133static int nl80211_setup_ap(struct i802_bss *bss)
6134{
6135 struct wpa_driver_nl80211_data *drv = bss->drv;
6136
6137 wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
6138 "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
6139
6140 /*
6141 * Disable Probe Request reporting unless we need it in this way for
6142 * devices that include the AP SME, in the other case (unless using
6143 * monitor iface) we'll get it through the nl_mgmt socket instead.
6144 */
6145 if (!drv->device_ap_sme)
6146 wpa_driver_nl80211_probe_req_report(bss, 0);
6147
6148 if (!drv->device_ap_sme && !drv->use_monitor)
6149 if (nl80211_mgmt_subscribe_ap(bss))
6150 return -1;
6151
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006152#ifndef ANDROID_P2P
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006153 if (drv->device_ap_sme && !drv->use_monitor)
6154 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
6155 return -1;
6156
6157 if (!drv->device_ap_sme && drv->use_monitor &&
6158 nl80211_create_monitor_interface(drv) &&
6159 !drv->device_ap_sme)
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006160#else
6161 if (drv->device_ap_sme)
6162 if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
6163 return -1;
6164
6165 if (drv->use_monitor &&
6166 nl80211_create_monitor_interface(drv))
6167#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006168 return -1;
6169
6170 if (drv->device_ap_sme &&
6171 wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
6172 wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
6173 "Probe Request frame reporting in AP mode");
6174 /* Try to survive without this */
6175 }
6176
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006177 return 0;
6178}
6179
6180
6181static void nl80211_teardown_ap(struct i802_bss *bss)
6182{
6183 struct wpa_driver_nl80211_data *drv = bss->drv;
6184
6185 if (drv->device_ap_sme) {
6186 wpa_driver_nl80211_probe_req_report(bss, 0);
6187 if (!drv->use_monitor)
6188 nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
6189 } else if (drv->use_monitor)
6190 nl80211_remove_monitor_interface(drv);
6191 else
6192 nl80211_mgmt_unsubscribe(bss, "AP teardown");
6193
6194 bss->beacon_set = 0;
6195}
6196
6197
6198static int nl80211_send_eapol_data(struct i802_bss *bss,
6199 const u8 *addr, const u8 *data,
6200 size_t data_len)
6201{
6202 struct sockaddr_ll ll;
6203 int ret;
6204
6205 if (bss->drv->eapol_tx_sock < 0) {
6206 wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
6207 return -1;
6208 }
6209
6210 os_memset(&ll, 0, sizeof(ll));
6211 ll.sll_family = AF_PACKET;
6212 ll.sll_ifindex = bss->ifindex;
6213 ll.sll_protocol = htons(ETH_P_PAE);
6214 ll.sll_halen = ETH_ALEN;
6215 os_memcpy(ll.sll_addr, addr, ETH_ALEN);
6216 ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
6217 (struct sockaddr *) &ll, sizeof(ll));
6218 if (ret < 0)
6219 wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
6220 strerror(errno));
6221
6222 return ret;
6223}
6224
6225
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006226static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
6227
6228static int wpa_driver_nl80211_hapd_send_eapol(
6229 void *priv, const u8 *addr, const u8 *data,
6230 size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
6231{
6232 struct i802_bss *bss = priv;
6233 struct wpa_driver_nl80211_data *drv = bss->drv;
6234 struct ieee80211_hdr *hdr;
6235 size_t len;
6236 u8 *pos;
6237 int res;
6238 int qos = flags & WPA_STA_WMM;
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006239#ifndef ANDROID_P2P
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006240 if (drv->device_ap_sme || !drv->use_monitor)
Dmitry Shmidtb638fe72012-03-20 12:51:25 -07006241#else
6242 if (drv->device_ap_sme && !drv->use_monitor)
6243#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006244 return nl80211_send_eapol_data(bss, addr, data, data_len);
6245
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006246 len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
6247 data_len;
6248 hdr = os_zalloc(len);
6249 if (hdr == NULL) {
6250 printf("malloc() failed for i802_send_data(len=%lu)\n",
6251 (unsigned long) len);
6252 return -1;
6253 }
6254
6255 hdr->frame_control =
6256 IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
6257 hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
6258 if (encrypt)
6259 hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
6260 if (qos) {
6261 hdr->frame_control |=
6262 host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
6263 }
6264
6265 memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
6266 memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
6267 memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
6268 pos = (u8 *) (hdr + 1);
6269
6270 if (qos) {
6271 /* add an empty QoS header if needed */
6272 pos[0] = 0;
6273 pos[1] = 0;
6274 pos += 2;
6275 }
6276
6277 memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
6278 pos += sizeof(rfc1042_header);
6279 WPA_PUT_BE16(pos, ETH_P_PAE);
6280 pos += 2;
6281 memcpy(pos, data, data_len);
6282
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006283 res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
6284 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006285 if (res < 0) {
6286 wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
6287 "failed: %d (%s)",
6288 (unsigned long) len, errno, strerror(errno));
6289 }
6290 os_free(hdr);
6291
6292 return res;
6293}
6294
6295
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006296static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
6297 int total_flags,
6298 int flags_or, int flags_and)
6299{
6300 struct i802_bss *bss = priv;
6301 struct wpa_driver_nl80211_data *drv = bss->drv;
6302 struct nl_msg *msg, *flags = NULL;
6303 struct nl80211_sta_flag_update upd;
6304
6305 msg = nlmsg_alloc();
6306 if (!msg)
6307 return -ENOMEM;
6308
6309 flags = nlmsg_alloc();
6310 if (!flags) {
6311 nlmsg_free(msg);
6312 return -ENOMEM;
6313 }
6314
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006315 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006316
6317 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
6318 if_nametoindex(bss->ifname));
6319 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
6320
6321 /*
6322 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
6323 * can be removed eventually.
6324 */
6325 if (total_flags & WPA_STA_AUTHORIZED)
6326 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
6327
6328 if (total_flags & WPA_STA_WMM)
6329 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
6330
6331 if (total_flags & WPA_STA_SHORT_PREAMBLE)
6332 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
6333
6334 if (total_flags & WPA_STA_MFP)
6335 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
6336
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006337 if (total_flags & WPA_STA_TDLS_PEER)
6338 NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
6339
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006340 if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
6341 goto nla_put_failure;
6342
6343 os_memset(&upd, 0, sizeof(upd));
6344 upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
6345 upd.set = sta_flags_nl80211(flags_or);
6346 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
6347
6348 nlmsg_free(flags);
6349
6350 return send_and_recv_msgs(drv, msg, NULL, NULL);
6351 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006352 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006353 nlmsg_free(flags);
6354 return -ENOBUFS;
6355}
6356
6357
6358static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
6359 struct wpa_driver_associate_params *params)
6360{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006361 enum nl80211_iftype nlmode;
6362
6363 if (params->p2p) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006364 wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
6365 "group (GO)");
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006366 nlmode = NL80211_IFTYPE_P2P_GO;
6367 } else
6368 nlmode = NL80211_IFTYPE_AP;
6369
6370 if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
6371 wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006372 nl80211_remove_monitor_interface(drv);
6373 return -1;
6374 }
6375
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006376 return 0;
6377}
6378
6379
6380static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
6381{
6382 struct nl_msg *msg;
6383 int ret = -1;
6384
6385 msg = nlmsg_alloc();
6386 if (!msg)
6387 return -1;
6388
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006389 nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006390 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6391 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6392 msg = NULL;
6393 if (ret) {
6394 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
6395 "(%s)", ret, strerror(-ret));
6396 goto nla_put_failure;
6397 }
6398
6399 ret = 0;
6400 wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
6401
6402nla_put_failure:
6403 nlmsg_free(msg);
6404 return ret;
6405}
6406
6407
6408static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
6409 struct wpa_driver_associate_params *params)
6410{
6411 struct nl_msg *msg;
6412 int ret = -1;
6413 int count = 0;
6414
6415 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
6416
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006417 if (wpa_driver_nl80211_set_mode(&drv->first_bss,
6418 NL80211_IFTYPE_ADHOC)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006419 wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
6420 "IBSS mode");
6421 return -1;
6422 }
6423
6424retry:
6425 msg = nlmsg_alloc();
6426 if (!msg)
6427 return -1;
6428
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006429 nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006430 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6431
6432 if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
6433 goto nla_put_failure;
6434
6435 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
6436 params->ssid, params->ssid_len);
6437 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
6438 params->ssid);
6439 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6440 drv->ssid_len = params->ssid_len;
6441
6442 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
6443 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
6444
6445 ret = nl80211_set_conn_keys(params, msg);
6446 if (ret)
6447 goto nla_put_failure;
6448
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006449 if (params->bssid && params->fixed_bssid) {
6450 wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
6451 MAC2STR(params->bssid));
6452 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
6453 }
6454
6455 if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
6456 params->key_mgmt_suite == KEY_MGMT_PSK ||
6457 params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 ||
6458 params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) {
6459 wpa_printf(MSG_DEBUG, " * control port");
6460 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
6461 }
6462
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006463 if (params->wpa_ie) {
6464 wpa_hexdump(MSG_DEBUG,
6465 " * Extra IEs for Beacon/Probe Response frames",
6466 params->wpa_ie, params->wpa_ie_len);
6467 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6468 params->wpa_ie);
6469 }
6470
6471 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6472 msg = NULL;
6473 if (ret) {
6474 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
6475 ret, strerror(-ret));
6476 count++;
6477 if (ret == -EALREADY && count == 1) {
6478 wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
6479 "forced leave");
6480 nl80211_leave_ibss(drv);
6481 nlmsg_free(msg);
6482 goto retry;
6483 }
6484
6485 goto nla_put_failure;
6486 }
6487 ret = 0;
6488 wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
6489
6490nla_put_failure:
6491 nlmsg_free(msg);
6492 return ret;
6493}
6494
6495
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006496static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
6497 u8 *bssid)
6498{
6499 struct nl_msg *msg;
6500 int ret;
6501 struct nl80211_bss_info_arg arg;
6502
6503 os_memset(&arg, 0, sizeof(arg));
6504 msg = nlmsg_alloc();
6505 if (!msg)
6506 goto nla_put_failure;
6507
6508 nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
6509 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6510
6511 arg.drv = drv;
6512 ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
6513 msg = NULL;
6514 if (ret == 0) {
6515 if (is_zero_ether_addr(arg.assoc_bssid))
6516 return -ENOTCONN;
6517 os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
6518 return 0;
6519 }
6520 wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
6521 "(%s)", ret, strerror(-ret));
6522nla_put_failure:
6523 nlmsg_free(msg);
6524 return drv->assoc_freq;
6525}
6526
6527
6528static int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
6529 const u8 *bssid)
6530{
6531 u8 addr[ETH_ALEN];
6532
6533 if (bssid == NULL) {
6534 int res = nl80211_get_assoc_bssid(drv, addr);
6535 if (res)
6536 return res;
6537 bssid = addr;
6538 }
6539
6540 return wpa_driver_nl80211_disconnect(drv, bssid,
6541 WLAN_REASON_PREV_AUTH_NOT_VALID);
6542}
6543
6544
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006545static int wpa_driver_nl80211_connect(
6546 struct wpa_driver_nl80211_data *drv,
6547 struct wpa_driver_associate_params *params)
6548{
6549 struct nl_msg *msg;
6550 enum nl80211_auth_type type;
6551 int ret = 0;
6552 int algs;
6553
6554 msg = nlmsg_alloc();
6555 if (!msg)
6556 return -1;
6557
6558 wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006559 nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006560
6561 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6562 if (params->bssid) {
6563 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6564 MAC2STR(params->bssid));
6565 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
6566 }
6567 if (params->freq) {
6568 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
6569 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
6570 }
6571 if (params->ssid) {
6572 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
6573 params->ssid, params->ssid_len);
6574 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
6575 params->ssid);
6576 if (params->ssid_len > sizeof(drv->ssid))
6577 goto nla_put_failure;
6578 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6579 drv->ssid_len = params->ssid_len;
6580 }
6581 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
6582 if (params->wpa_ie)
6583 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6584 params->wpa_ie);
6585
6586 algs = 0;
6587 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6588 algs++;
6589 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6590 algs++;
6591 if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6592 algs++;
6593 if (algs > 1) {
6594 wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic "
6595 "selection");
6596 goto skip_auth_type;
6597 }
6598
6599 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
6600 type = NL80211_AUTHTYPE_OPEN_SYSTEM;
6601 else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
6602 type = NL80211_AUTHTYPE_SHARED_KEY;
6603 else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
6604 type = NL80211_AUTHTYPE_NETWORK_EAP;
6605 else if (params->auth_alg & WPA_AUTH_ALG_FT)
6606 type = NL80211_AUTHTYPE_FT;
6607 else
6608 goto nla_put_failure;
6609
6610 wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
6611 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
6612
6613skip_auth_type:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006614 if (params->wpa_proto) {
6615 enum nl80211_wpa_versions ver = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006616
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006617 if (params->wpa_proto & WPA_PROTO_WPA)
6618 ver |= NL80211_WPA_VERSION_1;
6619 if (params->wpa_proto & WPA_PROTO_RSN)
6620 ver |= NL80211_WPA_VERSION_2;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006621
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006622 wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006623 NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
6624 }
6625
6626 if (params->pairwise_suite != CIPHER_NONE) {
6627 int cipher;
6628
6629 switch (params->pairwise_suite) {
6630 case CIPHER_WEP40:
6631 cipher = WLAN_CIPHER_SUITE_WEP40;
6632 break;
6633 case CIPHER_WEP104:
6634 cipher = WLAN_CIPHER_SUITE_WEP104;
6635 break;
6636 case CIPHER_CCMP:
6637 cipher = WLAN_CIPHER_SUITE_CCMP;
6638 break;
6639 case CIPHER_TKIP:
6640 default:
6641 cipher = WLAN_CIPHER_SUITE_TKIP;
6642 break;
6643 }
6644 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
6645 }
6646
6647 if (params->group_suite != CIPHER_NONE) {
6648 int cipher;
6649
6650 switch (params->group_suite) {
6651 case CIPHER_WEP40:
6652 cipher = WLAN_CIPHER_SUITE_WEP40;
6653 break;
6654 case CIPHER_WEP104:
6655 cipher = WLAN_CIPHER_SUITE_WEP104;
6656 break;
6657 case CIPHER_CCMP:
6658 cipher = WLAN_CIPHER_SUITE_CCMP;
6659 break;
6660 case CIPHER_TKIP:
6661 default:
6662 cipher = WLAN_CIPHER_SUITE_TKIP;
6663 break;
6664 }
6665 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
6666 }
6667
6668 if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
6669 params->key_mgmt_suite == KEY_MGMT_PSK) {
6670 int mgmt = WLAN_AKM_SUITE_PSK;
6671
6672 switch (params->key_mgmt_suite) {
6673 case KEY_MGMT_802_1X:
6674 mgmt = WLAN_AKM_SUITE_8021X;
6675 break;
6676 case KEY_MGMT_PSK:
6677 default:
6678 mgmt = WLAN_AKM_SUITE_PSK;
6679 break;
6680 }
6681 NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
6682 }
6683
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006684 if (params->disable_ht)
6685 NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
6686
6687 if (params->htcaps && params->htcaps_mask) {
6688 int sz = sizeof(struct ieee80211_ht_capabilities);
6689 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
6690 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
6691 params->htcaps_mask);
6692 }
6693
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006694 ret = nl80211_set_conn_keys(params, msg);
6695 if (ret)
6696 goto nla_put_failure;
6697
6698 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6699 msg = NULL;
6700 if (ret) {
6701 wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
6702 "(%s)", ret, strerror(-ret));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006703 /*
6704 * cfg80211 does not currently accept new connection if we are
6705 * already connected. As a workaround, force disconnection and
6706 * try again once the driver indicates it completed
6707 * disconnection.
6708 */
6709 if (ret == -EALREADY)
6710 nl80211_disconnect(drv, params->bssid);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006711 goto nla_put_failure;
6712 }
6713 ret = 0;
6714 wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
6715
6716nla_put_failure:
6717 nlmsg_free(msg);
6718 return ret;
6719
6720}
6721
6722
6723static int wpa_driver_nl80211_associate(
6724 void *priv, struct wpa_driver_associate_params *params)
6725{
6726 struct i802_bss *bss = priv;
6727 struct wpa_driver_nl80211_data *drv = bss->drv;
6728 int ret = -1;
6729 struct nl_msg *msg;
6730
6731 if (params->mode == IEEE80211_MODE_AP)
6732 return wpa_driver_nl80211_ap(drv, params);
6733
6734 if (params->mode == IEEE80211_MODE_IBSS)
6735 return wpa_driver_nl80211_ibss(drv, params);
6736
6737 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006738 enum nl80211_iftype nlmode = params->p2p ?
6739 NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
6740
6741 if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006742 return -1;
6743 return wpa_driver_nl80211_connect(drv, params);
6744 }
6745
6746 drv->associated = 0;
6747
6748 msg = nlmsg_alloc();
6749 if (!msg)
6750 return -1;
6751
6752 wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
6753 drv->ifindex);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006754 nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006755
6756 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6757 if (params->bssid) {
6758 wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
6759 MAC2STR(params->bssid));
6760 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
6761 }
6762 if (params->freq) {
6763 wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
6764 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
6765 drv->assoc_freq = params->freq;
6766 } else
6767 drv->assoc_freq = 0;
6768 if (params->ssid) {
6769 wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
6770 params->ssid, params->ssid_len);
6771 NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
6772 params->ssid);
6773 if (params->ssid_len > sizeof(drv->ssid))
6774 goto nla_put_failure;
6775 os_memcpy(drv->ssid, params->ssid, params->ssid_len);
6776 drv->ssid_len = params->ssid_len;
6777 }
6778 wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
6779 if (params->wpa_ie)
6780 NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
6781 params->wpa_ie);
6782
6783 if (params->pairwise_suite != CIPHER_NONE) {
6784 int cipher;
6785
6786 switch (params->pairwise_suite) {
6787 case CIPHER_WEP40:
6788 cipher = WLAN_CIPHER_SUITE_WEP40;
6789 break;
6790 case CIPHER_WEP104:
6791 cipher = WLAN_CIPHER_SUITE_WEP104;
6792 break;
6793 case CIPHER_CCMP:
6794 cipher = WLAN_CIPHER_SUITE_CCMP;
6795 break;
6796 case CIPHER_TKIP:
6797 default:
6798 cipher = WLAN_CIPHER_SUITE_TKIP;
6799 break;
6800 }
6801 wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
6802 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
6803 }
6804
6805 if (params->group_suite != CIPHER_NONE) {
6806 int cipher;
6807
6808 switch (params->group_suite) {
6809 case CIPHER_WEP40:
6810 cipher = WLAN_CIPHER_SUITE_WEP40;
6811 break;
6812 case CIPHER_WEP104:
6813 cipher = WLAN_CIPHER_SUITE_WEP104;
6814 break;
6815 case CIPHER_CCMP:
6816 cipher = WLAN_CIPHER_SUITE_CCMP;
6817 break;
6818 case CIPHER_TKIP:
6819 default:
6820 cipher = WLAN_CIPHER_SUITE_TKIP;
6821 break;
6822 }
6823 wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
6824 NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
6825 }
6826
6827#ifdef CONFIG_IEEE80211W
6828 if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
6829 NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
6830#endif /* CONFIG_IEEE80211W */
6831
6832 NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
6833
6834 if (params->prev_bssid) {
6835 wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
6836 MAC2STR(params->prev_bssid));
6837 NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
6838 params->prev_bssid);
6839 }
6840
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08006841 if (params->disable_ht)
6842 NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
6843
6844 if (params->htcaps && params->htcaps_mask) {
6845 int sz = sizeof(struct ieee80211_ht_capabilities);
6846 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
6847 NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
6848 params->htcaps_mask);
6849 }
6850
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006851 if (params->p2p)
6852 wpa_printf(MSG_DEBUG, " * P2P group");
6853
6854 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6855 msg = NULL;
6856 if (ret) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006857 wpa_dbg(drv->ctx, MSG_DEBUG,
6858 "nl80211: MLME command failed (assoc): ret=%d (%s)",
6859 ret, strerror(-ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006860 nl80211_dump_scan(drv);
6861 goto nla_put_failure;
6862 }
6863 ret = 0;
6864 wpa_printf(MSG_DEBUG, "nl80211: Association request send "
6865 "successfully");
6866
6867nla_put_failure:
6868 nlmsg_free(msg);
6869 return ret;
6870}
6871
6872
6873static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006874 int ifindex, enum nl80211_iftype mode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006875{
6876 struct nl_msg *msg;
6877 int ret = -ENOBUFS;
6878
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006879 wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
6880 ifindex, mode, nl80211_iftype_str(mode));
6881
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006882 msg = nlmsg_alloc();
6883 if (!msg)
6884 return -ENOMEM;
6885
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006886 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006887 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
6888 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
6889
6890 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006891 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006892 if (!ret)
6893 return 0;
6894nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006895 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006896 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
6897 " %d (%s)", ifindex, mode, ret, strerror(-ret));
6898 return ret;
6899}
6900
6901
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006902static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
6903 enum nl80211_iftype nlmode)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006904{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006905 struct wpa_driver_nl80211_data *drv = bss->drv;
6906 int ret = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006907 int i;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006908 int was_ap = is_ap_interface(drv->nlmode);
6909 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006910
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006911 res = nl80211_set_mode(drv, drv->ifindex, nlmode);
6912 if (res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006913 drv->nlmode = nlmode;
6914 ret = 0;
6915 goto done;
6916 }
6917
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006918 if (res == -ENODEV)
6919 return -1;
6920
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006921 if (nlmode == drv->nlmode) {
6922 wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
6923 "requested mode - ignore error");
6924 ret = 0;
6925 goto done; /* Already in the requested mode */
6926 }
6927
6928 /* mac80211 doesn't allow mode changes while the device is up, so
6929 * take the device down, try to set the mode again, and bring the
6930 * device back up.
6931 */
6932 wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
6933 "interface down");
6934 for (i = 0; i < 10; i++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006935 res = linux_set_iface_flags(drv->global->ioctl_sock,
6936 bss->ifname, 0);
6937 if (res == -EACCES || res == -ENODEV)
6938 break;
6939 if (res == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006940 /* Try to set the mode again while the interface is
6941 * down */
6942 ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006943 if (ret == -EACCES)
6944 break;
6945 res = linux_set_iface_flags(drv->global->ioctl_sock,
6946 bss->ifname, 1);
6947 if (res && !ret)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006948 ret = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006949 else if (ret != -EBUSY)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006950 break;
6951 } else
6952 wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
6953 "interface down");
6954 os_sleep(0, 100000);
6955 }
6956
6957 if (!ret) {
6958 wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
6959 "interface is down");
6960 drv->nlmode = nlmode;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006961 drv->ignore_if_down_event = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006962 }
6963
6964done:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006965 if (ret) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006966 wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
6967 "from %d failed", nlmode, drv->nlmode);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006968 return ret;
6969 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006970
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08006971 if (is_ap_interface(nlmode)) {
6972 nl80211_mgmt_unsubscribe(bss, "start AP");
6973 /* Setup additional AP mode functionality if needed */
6974 if (nl80211_setup_ap(bss))
6975 return -1;
6976 } else if (was_ap) {
6977 /* Remove additional AP mode functionality */
6978 nl80211_teardown_ap(bss);
6979 } else {
6980 nl80211_mgmt_unsubscribe(bss, "mode change");
6981 }
6982
6983 if (!is_ap_interface(nlmode) &&
6984 nl80211_mgmt_subscribe_non_ap(bss) < 0)
6985 wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
6986 "frame processing - ignore for now");
6987
6988 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006989}
6990
6991
6992static int wpa_driver_nl80211_get_capa(void *priv,
6993 struct wpa_driver_capa *capa)
6994{
6995 struct i802_bss *bss = priv;
6996 struct wpa_driver_nl80211_data *drv = bss->drv;
6997 if (!drv->has_capability)
6998 return -1;
6999 os_memcpy(capa, &drv->capa, sizeof(*capa));
7000 return 0;
7001}
7002
7003
7004static int wpa_driver_nl80211_set_operstate(void *priv, int state)
7005{
7006 struct i802_bss *bss = priv;
7007 struct wpa_driver_nl80211_data *drv = bss->drv;
7008
7009 wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
7010 __func__, drv->operstate, state, state ? "UP" : "DORMANT");
7011 drv->operstate = state;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007012 return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007013 state ? IF_OPER_UP : IF_OPER_DORMANT);
7014}
7015
7016
7017static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
7018{
7019 struct i802_bss *bss = priv;
7020 struct wpa_driver_nl80211_data *drv = bss->drv;
7021 struct nl_msg *msg;
7022 struct nl80211_sta_flag_update upd;
7023
7024 msg = nlmsg_alloc();
7025 if (!msg)
7026 return -ENOMEM;
7027
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007028 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007029
7030 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7031 if_nametoindex(bss->ifname));
7032 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
7033
7034 os_memset(&upd, 0, sizeof(upd));
7035 upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
7036 if (authorized)
7037 upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
7038 NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
7039
7040 return send_and_recv_msgs(drv, msg, NULL, NULL);
7041 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007042 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007043 return -ENOBUFS;
7044}
7045
7046
Jouni Malinen75ecf522011-06-27 15:19:46 -07007047/* Set kernel driver on given frequency (MHz) */
7048static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007049{
Jouni Malinen75ecf522011-06-27 15:19:46 -07007050 struct i802_bss *bss = priv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007051 return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
Jouni Malinen75ecf522011-06-27 15:19:46 -07007052 freq->sec_channel_offset);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007053}
7054
7055
Jouni Malinen75ecf522011-06-27 15:19:46 -07007056#if defined(HOSTAPD) || defined(CONFIG_AP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007057
7058static inline int min_int(int a, int b)
7059{
7060 if (a < b)
7061 return a;
7062 return b;
7063}
7064
7065
7066static int get_key_handler(struct nl_msg *msg, void *arg)
7067{
7068 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7069 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7070
7071 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7072 genlmsg_attrlen(gnlh, 0), NULL);
7073
7074 /*
7075 * TODO: validate the key index and mac address!
7076 * Otherwise, there's a race condition as soon as
7077 * the kernel starts sending key notifications.
7078 */
7079
7080 if (tb[NL80211_ATTR_KEY_SEQ])
7081 memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
7082 min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
7083 return NL_SKIP;
7084}
7085
7086
7087static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
7088 int idx, u8 *seq)
7089{
7090 struct i802_bss *bss = priv;
7091 struct wpa_driver_nl80211_data *drv = bss->drv;
7092 struct nl_msg *msg;
7093
7094 msg = nlmsg_alloc();
7095 if (!msg)
7096 return -ENOMEM;
7097
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007098 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007099
7100 if (addr)
7101 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7102 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
7103 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
7104
7105 memset(seq, 0, 6);
7106
7107 return send_and_recv_msgs(drv, msg, get_key_handler, seq);
7108 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007109 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007110 return -ENOBUFS;
7111}
7112
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007113
7114static int i802_set_rts(void *priv, int rts)
7115{
7116 struct i802_bss *bss = priv;
7117 struct wpa_driver_nl80211_data *drv = bss->drv;
7118 struct nl_msg *msg;
7119 int ret = -ENOBUFS;
7120 u32 val;
7121
7122 msg = nlmsg_alloc();
7123 if (!msg)
7124 return -ENOMEM;
7125
7126 if (rts >= 2347)
7127 val = (u32) -1;
7128 else
7129 val = rts;
7130
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007131 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007132 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7133 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
7134
7135 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007136 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007137 if (!ret)
7138 return 0;
7139nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007140 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007141 wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
7142 "%d (%s)", rts, ret, strerror(-ret));
7143 return ret;
7144}
7145
7146
7147static int i802_set_frag(void *priv, int frag)
7148{
7149 struct i802_bss *bss = priv;
7150 struct wpa_driver_nl80211_data *drv = bss->drv;
7151 struct nl_msg *msg;
7152 int ret = -ENOBUFS;
7153 u32 val;
7154
7155 msg = nlmsg_alloc();
7156 if (!msg)
7157 return -ENOMEM;
7158
7159 if (frag >= 2346)
7160 val = (u32) -1;
7161 else
7162 val = frag;
7163
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007164 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007165 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
7166 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
7167
7168 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007169 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007170 if (!ret)
7171 return 0;
7172nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007173 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007174 wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
7175 "%d: %d (%s)", frag, ret, strerror(-ret));
7176 return ret;
7177}
7178
7179
7180static int i802_flush(void *priv)
7181{
7182 struct i802_bss *bss = priv;
7183 struct wpa_driver_nl80211_data *drv = bss->drv;
7184 struct nl_msg *msg;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007185 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007186
7187 msg = nlmsg_alloc();
7188 if (!msg)
7189 return -1;
7190
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007191 nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007192
7193 /*
7194 * XXX: FIX! this needs to flush all VLANs too
7195 */
7196 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7197 if_nametoindex(bss->ifname));
7198
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007199 res = send_and_recv_msgs(drv, msg, NULL, NULL);
7200 if (res) {
7201 wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
7202 "(%s)", res, strerror(-res));
7203 }
7204 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007205 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007206 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007207 return -ENOBUFS;
7208}
7209
7210
7211static int get_sta_handler(struct nl_msg *msg, void *arg)
7212{
7213 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7214 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7215 struct hostap_sta_driver_data *data = arg;
7216 struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
7217 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
7218 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
7219 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
7220 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
7221 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
7222 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
7223 };
7224
7225 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7226 genlmsg_attrlen(gnlh, 0), NULL);
7227
7228 /*
7229 * TODO: validate the interface and mac address!
7230 * Otherwise, there's a race condition as soon as
7231 * the kernel starts sending station notifications.
7232 */
7233
7234 if (!tb[NL80211_ATTR_STA_INFO]) {
7235 wpa_printf(MSG_DEBUG, "sta stats missing!");
7236 return NL_SKIP;
7237 }
7238 if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
7239 tb[NL80211_ATTR_STA_INFO],
7240 stats_policy)) {
7241 wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
7242 return NL_SKIP;
7243 }
7244
7245 if (stats[NL80211_STA_INFO_INACTIVE_TIME])
7246 data->inactive_msec =
7247 nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
7248 if (stats[NL80211_STA_INFO_RX_BYTES])
7249 data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
7250 if (stats[NL80211_STA_INFO_TX_BYTES])
7251 data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
7252 if (stats[NL80211_STA_INFO_RX_PACKETS])
7253 data->rx_packets =
7254 nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
7255 if (stats[NL80211_STA_INFO_TX_PACKETS])
7256 data->tx_packets =
7257 nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
7258
7259 return NL_SKIP;
7260}
7261
7262static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
7263 const u8 *addr)
7264{
7265 struct i802_bss *bss = priv;
7266 struct wpa_driver_nl80211_data *drv = bss->drv;
7267 struct nl_msg *msg;
7268
7269 os_memset(data, 0, sizeof(*data));
7270 msg = nlmsg_alloc();
7271 if (!msg)
7272 return -ENOMEM;
7273
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007274 nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007275
7276 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7277 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
7278
7279 return send_and_recv_msgs(drv, msg, get_sta_handler, data);
7280 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007281 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007282 return -ENOBUFS;
7283}
7284
7285
7286static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
7287 int cw_min, int cw_max, int burst_time)
7288{
7289 struct i802_bss *bss = priv;
7290 struct wpa_driver_nl80211_data *drv = bss->drv;
7291 struct nl_msg *msg;
7292 struct nlattr *txq, *params;
7293
7294 msg = nlmsg_alloc();
7295 if (!msg)
7296 return -1;
7297
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007298 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007299
7300 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
7301
7302 txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
7303 if (!txq)
7304 goto nla_put_failure;
7305
7306 /* We are only sending parameters for a single TXQ at a time */
7307 params = nla_nest_start(msg, 1);
7308 if (!params)
7309 goto nla_put_failure;
7310
7311 switch (queue) {
7312 case 0:
7313 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
7314 break;
7315 case 1:
7316 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
7317 break;
7318 case 2:
7319 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
7320 break;
7321 case 3:
7322 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
7323 break;
7324 }
7325 /* Burst time is configured in units of 0.1 msec and TXOP parameter in
7326 * 32 usec, so need to convert the value here. */
7327 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
7328 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
7329 NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
7330 NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
7331
7332 nla_nest_end(msg, params);
7333
7334 nla_nest_end(msg, txq);
7335
7336 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
7337 return 0;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007338 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007339 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007340 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007341 return -1;
7342}
7343
7344
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007345static int i802_set_sta_vlan(void *priv, const u8 *addr,
7346 const char *ifname, int vlan_id)
7347{
7348 struct i802_bss *bss = priv;
7349 struct wpa_driver_nl80211_data *drv = bss->drv;
7350 struct nl_msg *msg;
7351 int ret = -ENOBUFS;
7352
7353 msg = nlmsg_alloc();
7354 if (!msg)
7355 return -ENOMEM;
7356
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007357 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007358
7359 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
7360 if_nametoindex(bss->ifname));
7361 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7362 NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
7363 if_nametoindex(ifname));
7364
7365 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007366 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007367 if (ret < 0) {
7368 wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
7369 MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
7370 MAC2STR(addr), ifname, vlan_id, ret,
7371 strerror(-ret));
7372 }
7373 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007374 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007375 return ret;
7376}
7377
7378
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007379static int i802_get_inact_sec(void *priv, const u8 *addr)
7380{
7381 struct hostap_sta_driver_data data;
7382 int ret;
7383
7384 data.inactive_msec = (unsigned long) -1;
7385 ret = i802_read_sta_data(priv, &data, addr);
7386 if (ret || data.inactive_msec == (unsigned long) -1)
7387 return -1;
7388 return data.inactive_msec / 1000;
7389}
7390
7391
7392static int i802_sta_clear_stats(void *priv, const u8 *addr)
7393{
7394#if 0
7395 /* TODO */
7396#endif
7397 return 0;
7398}
7399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007400
7401static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
7402 int reason)
7403{
7404 struct i802_bss *bss = priv;
7405 struct ieee80211_mgmt mgmt;
7406
7407 memset(&mgmt, 0, sizeof(mgmt));
7408 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7409 WLAN_FC_STYPE_DEAUTH);
7410 memcpy(mgmt.da, addr, ETH_ALEN);
7411 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7412 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7413 mgmt.u.deauth.reason_code = host_to_le16(reason);
7414 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7415 IEEE80211_HDRLEN +
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007416 sizeof(mgmt.u.deauth), 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007417}
7418
7419
7420static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
7421 int reason)
7422{
7423 struct i802_bss *bss = priv;
7424 struct ieee80211_mgmt mgmt;
7425
7426 memset(&mgmt, 0, sizeof(mgmt));
7427 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
7428 WLAN_FC_STYPE_DISASSOC);
7429 memcpy(mgmt.da, addr, ETH_ALEN);
7430 memcpy(mgmt.sa, own_addr, ETH_ALEN);
7431 memcpy(mgmt.bssid, own_addr, ETH_ALEN);
7432 mgmt.u.disassoc.reason_code = host_to_le16(reason);
7433 return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
7434 IEEE80211_HDRLEN +
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007435 sizeof(mgmt.u.disassoc), 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007436}
7437
7438#endif /* HOSTAPD || CONFIG_AP */
7439
7440#ifdef HOSTAPD
7441
Jouni Malinen75ecf522011-06-27 15:19:46 -07007442static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7443{
7444 int i;
7445 int *old;
7446
7447 wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
7448 ifidx);
7449 for (i = 0; i < drv->num_if_indices; i++) {
7450 if (drv->if_indices[i] == 0) {
7451 drv->if_indices[i] = ifidx;
7452 return;
7453 }
7454 }
7455
7456 if (drv->if_indices != drv->default_if_indices)
7457 old = drv->if_indices;
7458 else
7459 old = NULL;
7460
7461 drv->if_indices = os_realloc(old,
7462 sizeof(int) * (drv->num_if_indices + 1));
7463 if (!drv->if_indices) {
7464 if (!old)
7465 drv->if_indices = drv->default_if_indices;
7466 else
7467 drv->if_indices = old;
7468 wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
7469 "interfaces");
7470 wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
7471 return;
7472 } else if (!old)
7473 os_memcpy(drv->if_indices, drv->default_if_indices,
7474 sizeof(drv->default_if_indices));
7475 drv->if_indices[drv->num_if_indices] = ifidx;
7476 drv->num_if_indices++;
7477}
7478
7479
7480static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7481{
7482 int i;
7483
7484 for (i = 0; i < drv->num_if_indices; i++) {
7485 if (drv->if_indices[i] == ifidx) {
7486 drv->if_indices[i] = 0;
7487 break;
7488 }
7489 }
7490}
7491
7492
7493static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
7494{
7495 int i;
7496
7497 for (i = 0; i < drv->num_if_indices; i++)
7498 if (drv->if_indices[i] == ifidx)
7499 return 1;
7500
7501 return 0;
7502}
7503
7504
7505static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
7506 const char *bridge_ifname)
7507{
7508 struct i802_bss *bss = priv;
7509 struct wpa_driver_nl80211_data *drv = bss->drv;
7510 char name[IFNAMSIZ + 1];
7511
7512 os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
7513 wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
7514 " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
7515 if (val) {
7516 if (!if_nametoindex(name)) {
7517 if (nl80211_create_iface(drv, name,
7518 NL80211_IFTYPE_AP_VLAN,
7519 NULL, 1) < 0)
7520 return -1;
7521 if (bridge_ifname &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007522 linux_br_add_if(drv->global->ioctl_sock,
7523 bridge_ifname, name) < 0)
Jouni Malinen75ecf522011-06-27 15:19:46 -07007524 return -1;
7525 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007526 linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
Jouni Malinen75ecf522011-06-27 15:19:46 -07007527 return i802_set_sta_vlan(priv, addr, name, 0);
7528 } else {
7529 i802_set_sta_vlan(priv, addr, bss->ifname, 0);
7530 return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
7531 name);
7532 }
7533}
7534
7535
7536static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
7537{
7538 struct wpa_driver_nl80211_data *drv = eloop_ctx;
7539 struct sockaddr_ll lladdr;
7540 unsigned char buf[3000];
7541 int len;
7542 socklen_t fromlen = sizeof(lladdr);
7543
7544 len = recvfrom(sock, buf, sizeof(buf), 0,
7545 (struct sockaddr *)&lladdr, &fromlen);
7546 if (len < 0) {
7547 perror("recv");
7548 return;
7549 }
7550
7551 if (have_ifidx(drv, lladdr.sll_ifindex))
7552 drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
7553}
7554
7555
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007556static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
7557 struct i802_bss *bss,
7558 const char *brname, const char *ifname)
7559{
7560 int ifindex;
7561 char in_br[IFNAMSIZ];
7562
7563 os_strlcpy(bss->brname, brname, IFNAMSIZ);
7564 ifindex = if_nametoindex(brname);
7565 if (ifindex == 0) {
7566 /*
7567 * Bridge was configured, but the bridge device does
7568 * not exist. Try to add it now.
7569 */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007570 if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007571 wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
7572 "bridge interface %s: %s",
7573 brname, strerror(errno));
7574 return -1;
7575 }
7576 bss->added_bridge = 1;
7577 add_ifidx(drv, if_nametoindex(brname));
7578 }
7579
7580 if (linux_br_get(in_br, ifname) == 0) {
7581 if (os_strcmp(in_br, brname) == 0)
7582 return 0; /* already in the bridge */
7583
7584 wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
7585 "bridge %s", ifname, in_br);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007586 if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
7587 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007588 wpa_printf(MSG_ERROR, "nl80211: Failed to "
7589 "remove interface %s from bridge "
7590 "%s: %s",
7591 ifname, brname, strerror(errno));
7592 return -1;
7593 }
7594 }
7595
7596 wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
7597 ifname, brname);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007598 if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007599 wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
7600 "into bridge %s: %s",
7601 ifname, brname, strerror(errno));
7602 return -1;
7603 }
7604 bss->added_if_into_bridge = 1;
7605
7606 return 0;
7607}
7608
7609
7610static void *i802_init(struct hostapd_data *hapd,
7611 struct wpa_init_params *params)
7612{
7613 struct wpa_driver_nl80211_data *drv;
7614 struct i802_bss *bss;
7615 size_t i;
7616 char brname[IFNAMSIZ];
7617 int ifindex, br_ifindex;
7618 int br_added = 0;
7619
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007620 bss = wpa_driver_nl80211_init(hapd, params->ifname,
7621 params->global_priv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007622 if (bss == NULL)
7623 return NULL;
7624
7625 drv = bss->drv;
7626 drv->nlmode = NL80211_IFTYPE_AP;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007627 drv->eapol_sock = -1;
7628
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007629 if (linux_br_get(brname, params->ifname) == 0) {
7630 wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
7631 params->ifname, brname);
7632 br_ifindex = if_nametoindex(brname);
7633 } else {
7634 brname[0] = '\0';
7635 br_ifindex = 0;
7636 }
7637
7638 drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
7639 drv->if_indices = drv->default_if_indices;
7640 for (i = 0; i < params->num_bridge; i++) {
7641 if (params->bridge[i]) {
7642 ifindex = if_nametoindex(params->bridge[i]);
7643 if (ifindex)
7644 add_ifidx(drv, ifindex);
7645 if (ifindex == br_ifindex)
7646 br_added = 1;
7647 }
7648 }
7649 if (!br_added && br_ifindex &&
7650 (params->num_bridge == 0 || !params->bridge[0]))
7651 add_ifidx(drv, br_ifindex);
7652
7653 /* start listening for EAPOL on the default AP interface */
7654 add_ifidx(drv, drv->ifindex);
7655
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007656 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007657 goto failed;
7658
7659 if (params->bssid) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007660 if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007661 params->bssid))
7662 goto failed;
7663 }
7664
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007665 if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007666 wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
7667 "into AP mode", bss->ifname);
7668 goto failed;
7669 }
7670
7671 if (params->num_bridge && params->bridge[0] &&
7672 i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
7673 goto failed;
7674
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007675 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007676 goto failed;
7677
7678 drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
7679 if (drv->eapol_sock < 0) {
7680 perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
7681 goto failed;
7682 }
7683
7684 if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
7685 {
7686 printf("Could not register read socket for eapol\n");
7687 goto failed;
7688 }
7689
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007690 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
7691 params->own_addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007692 goto failed;
7693
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007694 memcpy(bss->addr, params->own_addr, ETH_ALEN);
7695
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007696 return bss;
7697
7698failed:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007699 wpa_driver_nl80211_deinit(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007700 return NULL;
7701}
7702
7703
7704static void i802_deinit(void *priv)
7705{
7706 wpa_driver_nl80211_deinit(priv);
7707}
7708
7709#endif /* HOSTAPD */
7710
7711
7712static enum nl80211_iftype wpa_driver_nl80211_if_type(
7713 enum wpa_driver_if_type type)
7714{
7715 switch (type) {
7716 case WPA_IF_STATION:
7717 return NL80211_IFTYPE_STATION;
7718 case WPA_IF_P2P_CLIENT:
7719 case WPA_IF_P2P_GROUP:
7720 return NL80211_IFTYPE_P2P_CLIENT;
7721 case WPA_IF_AP_VLAN:
7722 return NL80211_IFTYPE_AP_VLAN;
7723 case WPA_IF_AP_BSS:
7724 return NL80211_IFTYPE_AP;
7725 case WPA_IF_P2P_GO:
7726 return NL80211_IFTYPE_P2P_GO;
7727 }
7728 return -1;
7729}
7730
7731
7732#ifdef CONFIG_P2P
7733
7734static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
7735{
7736 struct wpa_driver_nl80211_data *drv;
7737 dl_list_for_each(drv, &global->interfaces,
7738 struct wpa_driver_nl80211_data, list) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007739 if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007740 return 1;
7741 }
7742 return 0;
7743}
7744
7745
7746static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
7747 u8 *new_addr)
7748{
7749 unsigned int idx;
7750
7751 if (!drv->global)
7752 return -1;
7753
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007754 os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007755 for (idx = 0; idx < 64; idx++) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007756 new_addr[0] = drv->first_bss.addr[0] | 0x02;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007757 new_addr[0] ^= idx << 2;
7758 if (!nl80211_addr_in_use(drv->global, new_addr))
7759 break;
7760 }
7761 if (idx == 64)
7762 return -1;
7763
7764 wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
7765 MACSTR, MAC2STR(new_addr));
7766
7767 return 0;
7768}
7769
7770#endif /* CONFIG_P2P */
7771
7772
7773static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
7774 const char *ifname, const u8 *addr,
7775 void *bss_ctx, void **drv_priv,
7776 char *force_ifname, u8 *if_addr,
7777 const char *bridge)
7778{
7779 struct i802_bss *bss = priv;
7780 struct wpa_driver_nl80211_data *drv = bss->drv;
7781 int ifidx;
7782#ifdef HOSTAPD
7783 struct i802_bss *new_bss = NULL;
7784
7785 if (type == WPA_IF_AP_BSS) {
7786 new_bss = os_zalloc(sizeof(*new_bss));
7787 if (new_bss == NULL)
7788 return -1;
7789 }
7790#endif /* HOSTAPD */
7791
7792 if (addr)
7793 os_memcpy(if_addr, addr, ETH_ALEN);
7794 ifidx = nl80211_create_iface(drv, ifname,
7795 wpa_driver_nl80211_if_type(type), addr,
7796 0);
7797 if (ifidx < 0) {
7798#ifdef HOSTAPD
7799 os_free(new_bss);
7800#endif /* HOSTAPD */
7801 return -1;
7802 }
7803
7804 if (!addr &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007805 linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
7806 if_addr) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007807 nl80211_remove_iface(drv, ifidx);
7808 return -1;
7809 }
7810
7811#ifdef CONFIG_P2P
7812 if (!addr &&
7813 (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
7814 type == WPA_IF_P2P_GO)) {
7815 /* Enforce unique P2P Interface Address */
7816 u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
7817
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007818 if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
7819 own_addr) < 0 ||
7820 linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
7821 new_addr) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007822 nl80211_remove_iface(drv, ifidx);
7823 return -1;
7824 }
7825 if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
7826 wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
7827 "for P2P group interface");
7828 if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
7829 nl80211_remove_iface(drv, ifidx);
7830 return -1;
7831 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007832 if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007833 new_addr) < 0) {
7834 nl80211_remove_iface(drv, ifidx);
7835 return -1;
7836 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007837 }
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07007838 os_memcpy(if_addr, new_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007839 }
7840#endif /* CONFIG_P2P */
7841
7842#ifdef HOSTAPD
7843 if (bridge &&
7844 i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
7845 wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
7846 "interface %s to a bridge %s", ifname, bridge);
7847 nl80211_remove_iface(drv, ifidx);
7848 os_free(new_bss);
7849 return -1;
7850 }
7851
7852 if (type == WPA_IF_AP_BSS) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007853 if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
7854 {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007855 nl80211_remove_iface(drv, ifidx);
7856 os_free(new_bss);
7857 return -1;
7858 }
7859 os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007860 os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007861 new_bss->ifindex = ifidx;
7862 new_bss->drv = drv;
7863 new_bss->next = drv->first_bss.next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007864 new_bss->freq = drv->first_bss.freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007865 drv->first_bss.next = new_bss;
7866 if (drv_priv)
7867 *drv_priv = new_bss;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007868 nl80211_init_bss(new_bss);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007869
7870 /* Subscribe management frames for this WPA_IF_AP_BSS */
7871 if (nl80211_setup_ap(new_bss))
7872 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007873 }
7874#endif /* HOSTAPD */
7875
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007876 if (drv->global)
7877 drv->global->if_add_ifindex = ifidx;
7878
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007879 return 0;
7880}
7881
7882
7883static int wpa_driver_nl80211_if_remove(void *priv,
7884 enum wpa_driver_if_type type,
7885 const char *ifname)
7886{
7887 struct i802_bss *bss = priv;
7888 struct wpa_driver_nl80211_data *drv = bss->drv;
7889 int ifindex = if_nametoindex(ifname);
7890
7891 wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
7892 __func__, type, ifname, ifindex);
7893 if (ifindex <= 0)
7894 return -1;
7895
7896#ifdef HOSTAPD
7897 if (bss->added_if_into_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007898 if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
7899 bss->ifname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007900 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
7901 "interface %s from bridge %s: %s",
7902 bss->ifname, bss->brname, strerror(errno));
7903 }
7904 if (bss->added_bridge) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007905 if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007906 wpa_printf(MSG_INFO, "nl80211: Failed to remove "
7907 "bridge %s: %s",
7908 bss->brname, strerror(errno));
7909 }
7910#endif /* HOSTAPD */
7911
7912 nl80211_remove_iface(drv, ifindex);
7913
7914#ifdef HOSTAPD
7915 if (type != WPA_IF_AP_BSS)
7916 return 0;
7917
7918 if (bss != &drv->first_bss) {
7919 struct i802_bss *tbss;
7920
7921 for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
7922 if (tbss->next == bss) {
7923 tbss->next = bss->next;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007924 /* Unsubscribe management frames */
7925 nl80211_teardown_ap(bss);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007926 nl80211_destroy_bss(bss);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007927 os_free(bss);
7928 bss = NULL;
7929 break;
7930 }
7931 }
7932 if (bss)
7933 wpa_printf(MSG_INFO, "nl80211: %s - could not find "
7934 "BSS %p in the list", __func__, bss);
7935 }
7936#endif /* HOSTAPD */
7937
7938 return 0;
7939}
7940
7941
7942static int cookie_handler(struct nl_msg *msg, void *arg)
7943{
7944 struct nlattr *tb[NL80211_ATTR_MAX + 1];
7945 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7946 u64 *cookie = arg;
7947 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7948 genlmsg_attrlen(gnlh, 0), NULL);
7949 if (tb[NL80211_ATTR_COOKIE])
7950 *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
7951 return NL_SKIP;
7952}
7953
7954
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007955static int nl80211_send_frame_cmd(struct i802_bss *bss,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007956 unsigned int freq, unsigned int wait,
7957 const u8 *buf, size_t buf_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007958 u64 *cookie_out, int no_cck, int no_ack,
7959 int offchanok)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007960{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007961 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007962 struct nl_msg *msg;
7963 u64 cookie;
7964 int ret = -1;
7965
7966 msg = nlmsg_alloc();
7967 if (!msg)
7968 return -1;
7969
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007970 nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007971
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007972 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007973 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007974#ifndef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07007975 if (wait)
7976 NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
7977#endif
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08007978 if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007979 NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
7980 if (no_cck)
7981 NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
7982 if (no_ack)
7983 NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
7984
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007985 NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
7986
7987 cookie = 0;
7988 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
7989 msg = NULL;
7990 if (ret) {
7991 wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07007992 "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
7993 freq, wait);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007994 goto nla_put_failure;
7995 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08007996 wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
7997 "cookie 0x%llx", no_ack ? " (no ACK)" : "",
7998 (long long unsigned int) cookie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007999
8000 if (cookie_out)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008001 *cookie_out = no_ack ? (u64) -1 : cookie;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008002
8003nla_put_failure:
8004 nlmsg_free(msg);
8005 return ret;
8006}
8007
8008
8009static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
8010 unsigned int wait_time,
8011 const u8 *dst, const u8 *src,
8012 const u8 *bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008013 const u8 *data, size_t data_len,
8014 int no_cck)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008015{
8016 struct i802_bss *bss = priv;
8017 struct wpa_driver_nl80211_data *drv = bss->drv;
8018 int ret = -1;
8019 u8 *buf;
8020 struct ieee80211_hdr *hdr;
8021
8022 wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008023 "freq=%u MHz wait=%d ms no_cck=%d)",
8024 drv->ifindex, freq, wait_time, no_cck);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008025
8026 buf = os_zalloc(24 + data_len);
8027 if (buf == NULL)
8028 return ret;
8029 os_memcpy(buf + 24, data, data_len);
8030 hdr = (struct ieee80211_hdr *) buf;
8031 hdr->frame_control =
8032 IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
8033 os_memcpy(hdr->addr1, dst, ETH_ALEN);
8034 os_memcpy(hdr->addr2, src, ETH_ALEN);
8035 os_memcpy(hdr->addr3, bssid, ETH_ALEN);
8036
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008037 if (is_ap_interface(drv->nlmode))
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008038 ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
8039 24 + data_len,
8040 0, freq, no_cck, 1,
8041 wait_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008042 else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008043 ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008044 24 + data_len,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008045 &drv->send_action_cookie,
8046 no_cck, 0, 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008047
8048 os_free(buf);
8049 return ret;
8050}
8051
8052
8053static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
8054{
8055 struct i802_bss *bss = priv;
8056 struct wpa_driver_nl80211_data *drv = bss->drv;
8057 struct nl_msg *msg;
8058 int ret;
8059
8060 msg = nlmsg_alloc();
8061 if (!msg)
8062 return;
8063
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008064 nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008065
8066 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8067 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
8068
8069 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8070 msg = NULL;
8071 if (ret)
8072 wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
8073 "(%s)", ret, strerror(-ret));
8074
8075 nla_put_failure:
8076 nlmsg_free(msg);
8077}
8078
8079
8080static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
8081 unsigned int duration)
8082{
8083 struct i802_bss *bss = priv;
8084 struct wpa_driver_nl80211_data *drv = bss->drv;
8085 struct nl_msg *msg;
8086 int ret;
8087 u64 cookie;
8088
8089 msg = nlmsg_alloc();
8090 if (!msg)
8091 return -1;
8092
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008093 nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008094
8095 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8096 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
8097 NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
8098
8099 cookie = 0;
8100 ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008101 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008102 if (ret == 0) {
8103 wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
8104 "0x%llx for freq=%u MHz duration=%u",
8105 (long long unsigned int) cookie, freq, duration);
8106 drv->remain_on_chan_cookie = cookie;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008107 drv->pending_remain_on_chan = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008108 return 0;
8109 }
8110 wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
8111 "(freq=%d duration=%u): %d (%s)",
8112 freq, duration, ret, strerror(-ret));
8113nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008114 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008115 return -1;
8116}
8117
8118
8119static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
8120{
8121 struct i802_bss *bss = priv;
8122 struct wpa_driver_nl80211_data *drv = bss->drv;
8123 struct nl_msg *msg;
8124 int ret;
8125
8126 if (!drv->pending_remain_on_chan) {
8127 wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
8128 "to cancel");
8129 return -1;
8130 }
8131
8132 wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
8133 "0x%llx",
8134 (long long unsigned int) drv->remain_on_chan_cookie);
8135
8136 msg = nlmsg_alloc();
8137 if (!msg)
8138 return -1;
8139
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008140 nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008141
8142 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8143 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
8144
8145 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008146 msg = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008147 if (ret == 0)
8148 return 0;
8149 wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
8150 "%d (%s)", ret, strerror(-ret));
8151nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008152 nlmsg_free(msg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008153 return -1;
8154}
8155
8156
8157static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
8158{
8159 struct i802_bss *bss = priv;
8160 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07008161
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008162 if (!report) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008163 if (bss->nl_preq && drv->device_ap_sme &&
8164 is_ap_interface(drv->nlmode)) {
8165 /*
8166 * Do not disable Probe Request reporting that was
8167 * enabled in nl80211_setup_ap().
8168 */
8169 wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
8170 "Probe Request reporting nl_preq=%p while "
8171 "in AP mode", bss->nl_preq);
8172 } else if (bss->nl_preq) {
8173 wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
8174 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008175 eloop_unregister_read_sock(
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008176 nl_socket_get_fd(bss->nl_preq));
8177 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008178 }
8179 return 0;
8180 }
8181
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008182 if (bss->nl_preq) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008183 wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008184 "already on! nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008185 return 0;
8186 }
8187
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008188 bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
8189 if (bss->nl_preq == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008190 return -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008191 wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
8192 "reporting nl_preq=%p", bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008193
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008194 if (nl80211_register_frame(bss, bss->nl_preq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008195 (WLAN_FC_TYPE_MGMT << 2) |
8196 (WLAN_FC_STYPE_PROBE_REQ << 4),
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008197 NULL, 0) < 0)
8198 goto out_err;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07008199
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008200 eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
8201 wpa_driver_nl80211_event_receive, bss->nl_cb,
8202 bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008203
8204 return 0;
8205
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008206 out_err:
8207 nl_destroy_handles(&bss->nl_preq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008208 return -1;
8209}
8210
8211
8212static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
8213 int ifindex, int disabled)
8214{
8215 struct nl_msg *msg;
8216 struct nlattr *bands, *band;
8217 int ret;
8218
8219 msg = nlmsg_alloc();
8220 if (!msg)
8221 return -1;
8222
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008223 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008224 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
8225
8226 bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
8227 if (!bands)
8228 goto nla_put_failure;
8229
8230 /*
8231 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
8232 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
8233 * rates. All 5 GHz rates are left enabled.
8234 */
8235 band = nla_nest_start(msg, NL80211_BAND_2GHZ);
8236 if (!band)
8237 goto nla_put_failure;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008238 if (disabled) {
8239 NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
8240 "\x0c\x12\x18\x24\x30\x48\x60\x6c");
8241 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008242 nla_nest_end(msg, band);
8243
8244 nla_nest_end(msg, bands);
8245
8246 ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8247 msg = NULL;
8248 if (ret) {
8249 wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
8250 "(%s)", ret, strerror(-ret));
8251 }
8252
8253 return ret;
8254
8255nla_put_failure:
8256 nlmsg_free(msg);
8257 return -1;
8258}
8259
8260
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008261static int wpa_driver_nl80211_deinit_ap(void *priv)
8262{
8263 struct i802_bss *bss = priv;
8264 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008265 if (!is_ap_interface(drv->nlmode))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008266 return -1;
8267 wpa_driver_nl80211_del_beacon(drv);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008268 return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008269}
8270
8271
8272static void wpa_driver_nl80211_resume(void *priv)
8273{
8274 struct i802_bss *bss = priv;
8275 struct wpa_driver_nl80211_data *drv = bss->drv;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008276 if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008277 wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
8278 "resume event");
8279 }
8280}
8281
8282
8283static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
8284 const u8 *ies, size_t ies_len)
8285{
8286 struct i802_bss *bss = priv;
8287 struct wpa_driver_nl80211_data *drv = bss->drv;
8288 int ret;
8289 u8 *data, *pos;
8290 size_t data_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008291 const u8 *own_addr = bss->addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008292
8293 if (action != 1) {
8294 wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
8295 "action %d", action);
8296 return -1;
8297 }
8298
8299 /*
8300 * Action frame payload:
8301 * Category[1] = 6 (Fast BSS Transition)
8302 * Action[1] = 1 (Fast BSS Transition Request)
8303 * STA Address
8304 * Target AP Address
8305 * FT IEs
8306 */
8307
8308 data_len = 2 + 2 * ETH_ALEN + ies_len;
8309 data = os_malloc(data_len);
8310 if (data == NULL)
8311 return -1;
8312 pos = data;
8313 *pos++ = 0x06; /* FT Action category */
8314 *pos++ = action;
8315 os_memcpy(pos, own_addr, ETH_ALEN);
8316 pos += ETH_ALEN;
8317 os_memcpy(pos, target_ap, ETH_ALEN);
8318 pos += ETH_ALEN;
8319 os_memcpy(pos, ies, ies_len);
8320
8321 ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
8322 drv->bssid, own_addr, drv->bssid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008323 data, data_len, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008324 os_free(data);
8325
8326 return ret;
8327}
8328
8329
8330static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
8331{
8332 struct i802_bss *bss = priv;
8333 struct wpa_driver_nl80211_data *drv = bss->drv;
8334 struct nl_msg *msg, *cqm = NULL;
8335
8336 wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
8337 "hysteresis=%d", threshold, hysteresis);
8338
8339 msg = nlmsg_alloc();
8340 if (!msg)
8341 return -1;
8342
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008343 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008344
8345 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8346
8347 cqm = nlmsg_alloc();
8348 if (cqm == NULL)
8349 return -1;
8350
8351 NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
8352 NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
8353 nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
8354
8355 if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
8356 return 0;
8357 msg = NULL;
8358
8359nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008360 nlmsg_free(cqm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008361 nlmsg_free(msg);
8362 return -1;
8363}
8364
8365
8366static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
8367{
8368 struct i802_bss *bss = priv;
8369 struct wpa_driver_nl80211_data *drv = bss->drv;
8370 int res;
8371
8372 os_memset(si, 0, sizeof(*si));
8373 res = nl80211_get_link_signal(drv, si);
8374 if (res != 0)
8375 return res;
8376
8377 return nl80211_get_link_noise(drv, si);
8378}
8379
8380
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008381static int wpa_driver_nl80211_shared_freq(void *priv)
8382{
8383 struct i802_bss *bss = priv;
8384 struct wpa_driver_nl80211_data *drv = bss->drv;
8385 struct wpa_driver_nl80211_data *driver;
8386 int freq = 0;
8387
8388 /*
8389 * If the same PHY is in connected state with some other interface,
8390 * then retrieve the assoc freq.
8391 */
8392 wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
8393 drv->phyname);
8394
8395 dl_list_for_each(driver, &drv->global->interfaces,
8396 struct wpa_driver_nl80211_data, list) {
8397 if (drv == driver ||
8398 os_strcmp(drv->phyname, driver->phyname) != 0 ||
8399#ifdef ANDROID_P2P
8400 (!driver->associated && !is_ap_interface(driver->nlmode)))
8401#else
8402 !driver->associated)
8403#endif
8404 continue;
8405
8406 wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
8407 MACSTR,
8408 driver->phyname, driver->first_bss.ifname,
8409 MAC2STR(driver->first_bss.addr));
8410#ifdef ANDROID_P2P
8411 if(is_ap_interface(driver->nlmode))
8412 freq = driver->first_bss.freq;
8413 else
8414#endif
8415 freq = nl80211_get_assoc_freq(driver);
8416 wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
8417 drv->phyname, freq);
8418 }
8419
8420 if (!freq)
8421 wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
8422 "PHY (%s) in associated state", drv->phyname);
8423
8424 return freq;
8425}
8426
8427
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008428static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
8429 int encrypt)
8430{
8431 struct i802_bss *bss = priv;
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008432 return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
8433 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008434}
8435
8436
8437static int nl80211_set_param(void *priv, const char *param)
8438{
8439 wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
8440 if (param == NULL)
8441 return 0;
8442
8443#ifdef CONFIG_P2P
8444 if (os_strstr(param, "use_p2p_group_interface=1")) {
8445 struct i802_bss *bss = priv;
8446 struct wpa_driver_nl80211_data *drv = bss->drv;
8447
8448 wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
8449 "interface");
8450 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
8451 drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
8452 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008453#ifdef ANDROID_P2P
8454 if(os_strstr(param, "use_multi_chan_concurrent=1")) {
8455 struct i802_bss *bss = priv;
8456 struct wpa_driver_nl80211_data *drv = bss->drv;
8457 wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
8458 "concurrency");
8459 drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
8460 }
8461#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008462#endif /* CONFIG_P2P */
8463
8464 return 0;
8465}
8466
8467
8468static void * nl80211_global_init(void)
8469{
8470 struct nl80211_global *global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008471 struct netlink_config *cfg;
8472
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008473 global = os_zalloc(sizeof(*global));
8474 if (global == NULL)
8475 return NULL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008476 global->ioctl_sock = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008477 dl_list_init(&global->interfaces);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008478 global->if_add_ifindex = -1;
8479
8480 cfg = os_zalloc(sizeof(*cfg));
8481 if (cfg == NULL)
8482 goto err;
8483
8484 cfg->ctx = global;
8485 cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
8486 cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
8487 global->netlink = netlink_init(cfg);
8488 if (global->netlink == NULL) {
8489 os_free(cfg);
8490 goto err;
8491 }
8492
8493 if (wpa_driver_nl80211_init_nl_global(global) < 0)
8494 goto err;
8495
8496 global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
8497 if (global->ioctl_sock < 0) {
8498 perror("socket(PF_INET,SOCK_DGRAM)");
8499 goto err;
8500 }
8501
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008502 return global;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008503
8504err:
8505 nl80211_global_deinit(global);
8506 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008507}
8508
8509
8510static void nl80211_global_deinit(void *priv)
8511{
8512 struct nl80211_global *global = priv;
8513 if (global == NULL)
8514 return;
8515 if (!dl_list_empty(&global->interfaces)) {
8516 wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
8517 "nl80211_global_deinit",
8518 dl_list_len(&global->interfaces));
8519 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008520
8521 if (global->netlink)
8522 netlink_deinit(global->netlink);
8523
8524 nl_destroy_handles(&global->nl);
8525
8526 if (global->nl_event) {
8527 eloop_unregister_read_sock(
8528 nl_socket_get_fd(global->nl_event));
8529 nl_destroy_handles(&global->nl_event);
8530 }
8531
8532 nl_cb_put(global->nl_cb);
8533
8534 if (global->ioctl_sock >= 0)
8535 close(global->ioctl_sock);
8536
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008537 os_free(global);
8538}
8539
8540
8541static const char * nl80211_get_radio_name(void *priv)
8542{
8543 struct i802_bss *bss = priv;
8544 struct wpa_driver_nl80211_data *drv = bss->drv;
8545 return drv->phyname;
8546}
8547
8548
Jouni Malinen75ecf522011-06-27 15:19:46 -07008549static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
8550 const u8 *pmkid)
8551{
8552 struct nl_msg *msg;
8553
8554 msg = nlmsg_alloc();
8555 if (!msg)
8556 return -ENOMEM;
8557
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008558 nl80211_cmd(bss->drv, msg, 0, cmd);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008559
8560 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
8561 if (pmkid)
8562 NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
8563 if (bssid)
8564 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
8565
8566 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
8567 nla_put_failure:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008568 nlmsg_free(msg);
Jouni Malinen75ecf522011-06-27 15:19:46 -07008569 return -ENOBUFS;
8570}
8571
8572
8573static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
8574{
8575 struct i802_bss *bss = priv;
8576 wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
8577 return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
8578}
8579
8580
8581static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
8582{
8583 struct i802_bss *bss = priv;
8584 wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
8585 MAC2STR(bssid));
8586 return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
8587}
8588
8589
8590static int nl80211_flush_pmkid(void *priv)
8591{
8592 struct i802_bss *bss = priv;
8593 wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
8594 return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
8595}
8596
8597
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008598static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
8599 const u8 *replay_ctr)
8600{
8601 struct i802_bss *bss = priv;
8602 struct wpa_driver_nl80211_data *drv = bss->drv;
8603 struct nlattr *replay_nested;
8604 struct nl_msg *msg;
8605
8606 msg = nlmsg_alloc();
8607 if (!msg)
8608 return;
8609
8610 nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
8611
8612 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8613
8614 replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
8615 if (!replay_nested)
8616 goto nla_put_failure;
8617
8618 NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
8619 NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
8620 NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
8621 replay_ctr);
8622
8623 nla_nest_end(msg, replay_nested);
8624
8625 send_and_recv_msgs(drv, msg, NULL, NULL);
8626 return;
8627 nla_put_failure:
8628 nlmsg_free(msg);
8629}
8630
8631
8632static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
8633 const u8 *addr, int qos)
8634{
8635 /* send data frame to poll STA and check whether
8636 * this frame is ACKed */
8637 struct {
8638 struct ieee80211_hdr hdr;
8639 u16 qos_ctl;
8640 } STRUCT_PACKED nulldata;
8641 size_t size;
8642
8643 /* Send data frame to poll STA and check whether this frame is ACKed */
8644
8645 os_memset(&nulldata, 0, sizeof(nulldata));
8646
8647 if (qos) {
8648 nulldata.hdr.frame_control =
8649 IEEE80211_FC(WLAN_FC_TYPE_DATA,
8650 WLAN_FC_STYPE_QOS_NULL);
8651 size = sizeof(nulldata);
8652 } else {
8653 nulldata.hdr.frame_control =
8654 IEEE80211_FC(WLAN_FC_TYPE_DATA,
8655 WLAN_FC_STYPE_NULLFUNC);
8656 size = sizeof(struct ieee80211_hdr);
8657 }
8658
8659 nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
8660 os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
8661 os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
8662 os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
8663
8664 if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
8665 wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
8666 "send poll frame");
8667}
8668
8669static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
8670 int qos)
8671{
8672 struct i802_bss *bss = priv;
8673 struct wpa_driver_nl80211_data *drv = bss->drv;
8674 struct nl_msg *msg;
8675
8676 if (!drv->poll_command_supported) {
8677 nl80211_send_null_frame(bss, own_addr, addr, qos);
8678 return;
8679 }
8680
8681 msg = nlmsg_alloc();
8682 if (!msg)
8683 return;
8684
8685 nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
8686
8687 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8688 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
8689
8690 send_and_recv_msgs(drv, msg, NULL, NULL);
8691 return;
8692 nla_put_failure:
8693 nlmsg_free(msg);
8694}
8695
8696
8697static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
8698{
8699 struct nl_msg *msg;
8700
8701 msg = nlmsg_alloc();
8702 if (!msg)
8703 return -ENOMEM;
8704
8705 nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
8706 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
8707 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
8708 enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
8709 return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
8710nla_put_failure:
8711 nlmsg_free(msg);
8712 return -ENOBUFS;
8713}
8714
8715
8716static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
8717 int ctwindow)
8718{
8719 struct i802_bss *bss = priv;
8720
8721 wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
8722 "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
8723
8724 if (opp_ps != -1 || ctwindow != -1)
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008725#ifdef ANDROID_P2P
8726 wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
8727#else
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008728 return -1; /* Not yet supported */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08008729#endif
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008730
8731 if (legacy_ps == -1)
8732 return 0;
8733 if (legacy_ps != 0 && legacy_ps != 1)
8734 return -1; /* Not yet supported */
8735
8736 return nl80211_set_power_save(bss, legacy_ps);
8737}
8738
8739
8740#ifdef CONFIG_TDLS
8741
8742static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
8743 u8 dialog_token, u16 status_code,
8744 const u8 *buf, size_t len)
8745{
8746 struct i802_bss *bss = priv;
8747 struct wpa_driver_nl80211_data *drv = bss->drv;
8748 struct nl_msg *msg;
8749
8750 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
8751 return -EOPNOTSUPP;
8752
8753 if (!dst)
8754 return -EINVAL;
8755
8756 msg = nlmsg_alloc();
8757 if (!msg)
8758 return -ENOMEM;
8759
8760 nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
8761 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8762 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
8763 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
8764 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
8765 NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
8766 NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
8767
8768 return send_and_recv_msgs(drv, msg, NULL, NULL);
8769
8770nla_put_failure:
8771 nlmsg_free(msg);
8772 return -ENOBUFS;
8773}
8774
8775
8776static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
8777{
8778 struct i802_bss *bss = priv;
8779 struct wpa_driver_nl80211_data *drv = bss->drv;
8780 struct nl_msg *msg;
8781 enum nl80211_tdls_operation nl80211_oper;
8782
8783 if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
8784 return -EOPNOTSUPP;
8785
8786 switch (oper) {
8787 case TDLS_DISCOVERY_REQ:
8788 nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
8789 break;
8790 case TDLS_SETUP:
8791 nl80211_oper = NL80211_TDLS_SETUP;
8792 break;
8793 case TDLS_TEARDOWN:
8794 nl80211_oper = NL80211_TDLS_TEARDOWN;
8795 break;
8796 case TDLS_ENABLE_LINK:
8797 nl80211_oper = NL80211_TDLS_ENABLE_LINK;
8798 break;
8799 case TDLS_DISABLE_LINK:
8800 nl80211_oper = NL80211_TDLS_DISABLE_LINK;
8801 break;
8802 case TDLS_ENABLE:
8803 return 0;
8804 case TDLS_DISABLE:
8805 return 0;
8806 default:
8807 return -EINVAL;
8808 }
8809
8810 msg = nlmsg_alloc();
8811 if (!msg)
8812 return -ENOMEM;
8813
8814 nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
8815 NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
8816 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
8817 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
8818
8819 return send_and_recv_msgs(drv, msg, NULL, NULL);
8820
8821nla_put_failure:
8822 nlmsg_free(msg);
8823 return -ENOBUFS;
8824}
8825
8826#endif /* CONFIG TDLS */
8827
8828
8829#ifdef ANDROID
8830
8831typedef struct android_wifi_priv_cmd {
8832 char *buf;
8833 int used_len;
8834 int total_len;
8835} android_wifi_priv_cmd;
8836
8837static int drv_errors = 0;
8838
8839static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
8840{
8841 drv_errors++;
8842 if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
8843 drv_errors = 0;
8844 wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
8845 }
8846}
8847
8848
8849static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
8850{
8851 struct wpa_driver_nl80211_data *drv = bss->drv;
8852 struct ifreq ifr;
8853 android_wifi_priv_cmd priv_cmd;
8854 char buf[MAX_DRV_CMD_SIZE];
8855 int ret;
8856
8857 os_memset(&ifr, 0, sizeof(ifr));
8858 os_memset(&priv_cmd, 0, sizeof(priv_cmd));
8859 os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
8860
8861 os_memset(buf, 0, sizeof(buf));
8862 os_strlcpy(buf, cmd, sizeof(buf));
8863
8864 priv_cmd.buf = buf;
8865 priv_cmd.used_len = sizeof(buf);
8866 priv_cmd.total_len = sizeof(buf);
8867 ifr.ifr_data = &priv_cmd;
8868
8869 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
8870 if (ret < 0) {
8871 wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
8872 __func__);
8873 wpa_driver_send_hang_msg(drv);
8874 return ret;
8875 }
8876
8877 drv_errors = 0;
8878 return 0;
8879}
8880
8881
8882static int android_pno_start(struct i802_bss *bss,
8883 struct wpa_driver_scan_params *params)
8884{
8885 struct wpa_driver_nl80211_data *drv = bss->drv;
8886 struct ifreq ifr;
8887 android_wifi_priv_cmd priv_cmd;
8888 int ret = 0, i = 0, bp;
8889 char buf[WEXT_PNO_MAX_COMMAND_SIZE];
8890
8891 bp = WEXT_PNOSETUP_HEADER_SIZE;
8892 os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
8893 buf[bp++] = WEXT_PNO_TLV_PREFIX;
8894 buf[bp++] = WEXT_PNO_TLV_VERSION;
8895 buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
8896 buf[bp++] = WEXT_PNO_TLV_RESERVED;
8897
8898 while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
8899 /* Check that there is enough space needed for 1 more SSID, the
8900 * other sections and null termination */
8901 if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
8902 WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
8903 break;
8904 wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
8905 params->ssids[i].ssid,
8906 params->ssids[i].ssid_len);
8907 buf[bp++] = WEXT_PNO_SSID_SECTION;
8908 buf[bp++] = params->ssids[i].ssid_len;
8909 os_memcpy(&buf[bp], params->ssids[i].ssid,
8910 params->ssids[i].ssid_len);
8911 bp += params->ssids[i].ssid_len;
8912 i++;
8913 }
8914
8915 buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
8916 os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
8917 WEXT_PNO_SCAN_INTERVAL);
8918 bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
8919
8920 buf[bp++] = WEXT_PNO_REPEAT_SECTION;
8921 os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
8922 WEXT_PNO_REPEAT);
8923 bp += WEXT_PNO_REPEAT_LENGTH;
8924
8925 buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
8926 os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
8927 WEXT_PNO_MAX_REPEAT);
8928 bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
8929
8930 memset(&ifr, 0, sizeof(ifr));
8931 memset(&priv_cmd, 0, sizeof(priv_cmd));
8932 os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
8933
8934 priv_cmd.buf = buf;
8935 priv_cmd.used_len = bp;
8936 priv_cmd.total_len = bp;
8937 ifr.ifr_data = &priv_cmd;
8938
8939 ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
8940
8941 if (ret < 0) {
8942 wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
8943 ret);
8944 wpa_driver_send_hang_msg(drv);
8945 return ret;
8946 }
8947
8948 drv_errors = 0;
8949
8950 return android_priv_cmd(bss, "PNOFORCE 1");
8951}
8952
8953
8954static int android_pno_stop(struct i802_bss *bss)
8955{
8956 return android_priv_cmd(bss, "PNOFORCE 0");
8957}
8958
8959#endif /* ANDROID */
8960
8961
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008962const struct wpa_driver_ops wpa_driver_nl80211_ops = {
8963 .name = "nl80211",
8964 .desc = "Linux nl80211/cfg80211",
8965 .get_bssid = wpa_driver_nl80211_get_bssid,
8966 .get_ssid = wpa_driver_nl80211_get_ssid,
8967 .set_key = wpa_driver_nl80211_set_key,
8968 .scan2 = wpa_driver_nl80211_scan,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008969 .sched_scan = wpa_driver_nl80211_sched_scan,
8970 .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008971 .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
8972 .deauthenticate = wpa_driver_nl80211_deauthenticate,
8973 .disassociate = wpa_driver_nl80211_disassociate,
8974 .authenticate = wpa_driver_nl80211_authenticate,
8975 .associate = wpa_driver_nl80211_associate,
8976 .global_init = nl80211_global_init,
8977 .global_deinit = nl80211_global_deinit,
8978 .init2 = wpa_driver_nl80211_init,
8979 .deinit = wpa_driver_nl80211_deinit,
8980 .get_capa = wpa_driver_nl80211_get_capa,
8981 .set_operstate = wpa_driver_nl80211_set_operstate,
8982 .set_supp_port = wpa_driver_nl80211_set_supp_port,
8983 .set_country = wpa_driver_nl80211_set_country,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08008984 .set_ap = wpa_driver_nl80211_set_ap,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008985 .if_add = wpa_driver_nl80211_if_add,
8986 .if_remove = wpa_driver_nl80211_if_remove,
8987 .send_mlme = wpa_driver_nl80211_send_mlme,
8988 .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
8989 .sta_add = wpa_driver_nl80211_sta_add,
8990 .sta_remove = wpa_driver_nl80211_sta_remove,
8991 .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
8992 .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
8993#ifdef HOSTAPD
8994 .hapd_init = i802_init,
8995 .hapd_deinit = i802_deinit,
Jouni Malinen75ecf522011-06-27 15:19:46 -07008996 .set_wds_sta = i802_set_wds_sta,
8997#endif /* HOSTAPD */
8998#if defined(HOSTAPD) || defined(CONFIG_AP)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07008999 .get_seqnum = i802_get_seqnum,
9000 .flush = i802_flush,
9001 .read_sta_data = i802_read_sta_data,
9002 .get_inact_sec = i802_get_inact_sec,
9003 .sta_clear_stats = i802_sta_clear_stats,
9004 .set_rts = i802_set_rts,
9005 .set_frag = i802_set_frag,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009006 .set_tx_queue_params = i802_set_tx_queue_params,
9007 .set_sta_vlan = i802_set_sta_vlan,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009008 .sta_deauth = i802_sta_deauth,
9009 .sta_disassoc = i802_sta_disassoc,
9010#endif /* HOSTAPD || CONFIG_AP */
9011 .set_freq = i802_set_freq,
9012 .send_action = wpa_driver_nl80211_send_action,
9013 .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
9014 .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
9015 .cancel_remain_on_channel =
9016 wpa_driver_nl80211_cancel_remain_on_channel,
9017 .probe_req_report = wpa_driver_nl80211_probe_req_report,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009018 .deinit_ap = wpa_driver_nl80211_deinit_ap,
9019 .resume = wpa_driver_nl80211_resume,
9020 .send_ft_action = nl80211_send_ft_action,
9021 .signal_monitor = nl80211_signal_monitor,
9022 .signal_poll = nl80211_signal_poll,
9023 .send_frame = nl80211_send_frame,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009024 .shared_freq = wpa_driver_nl80211_shared_freq,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009025 .set_param = nl80211_set_param,
9026 .get_radio_name = nl80211_get_radio_name,
Jouni Malinen75ecf522011-06-27 15:19:46 -07009027 .add_pmkid = nl80211_add_pmkid,
9028 .remove_pmkid = nl80211_remove_pmkid,
9029 .flush_pmkid = nl80211_flush_pmkid,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009030 .set_rekey_info = nl80211_set_rekey_info,
9031 .poll_client = nl80211_poll_client,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009032 .set_p2p_powersave = nl80211_set_p2p_powersave,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009033#ifdef CONFIG_TDLS
9034 .send_tdls_mgmt = nl80211_send_tdls_mgmt,
9035 .tdls_oper = nl80211_tdls_oper,
9036#endif /* CONFIG_TDLS */
9037#ifdef ANDROID_P2P
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009038 .set_noa = wpa_driver_set_p2p_noa,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08009039 .get_noa = wpa_driver_get_p2p_noa,
Dmitry Shmidt6e933c12011-09-27 12:29:26 -07009040 .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
9041#endif
Dmitry Shmidt738a26e2011-07-07 14:22:14 -07009042#ifdef ANDROID
9043 .driver_cmd = wpa_driver_nl80211_driver_cmd,
9044#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009045};