QCA vendor command support to set band to driver
[mech_eap.git] / src / drivers / driver_nl80211.c
index a7a536d..a6441e3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
  * Copyright (c) 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
@@ -87,7 +87,6 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
 #undef nl_socket_set_nonblocking
 #define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
 
-#define genl_ctrl_resolve android_genl_ctrl_resolve
 #endif /* ANDROID */
 
 
@@ -132,6 +131,22 @@ static void nl80211_register_eloop_read(struct nl_handle **handle,
                                        eloop_sock_handler handler,
                                        void *eloop_data)
 {
+#ifdef CONFIG_LIBNL20
+       /*
+        * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
+        * by default. It is possible to hit that limit in some cases where
+        * operations are blocked, e.g., with a burst of Deauthentication frames
+        * to hostapd and STA entry deletion. Try to increase the buffer to make
+        * this less likely to occur.
+        */
+       if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Could not set nl_socket RX buffer size: %s",
+                          strerror(errno));
+               /* continue anyway with the default (smaller) buffer */
+       }
+#endif /* CONFIG_LIBNL20 */
+
        nl_socket_set_nonblocking(*handle);
        eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
                                 eloop_data, *handle);
@@ -148,6 +163,7 @@ static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
 
 
 static void nl80211_global_deinit(void *priv);
+static void nl80211_check_global(struct nl80211_global *global);
 
 static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
 static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
@@ -161,27 +177,21 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                                  unsigned int freq, unsigned int wait,
                                  const u8 *buf, size_t buf_len, u64 *cookie,
                                  int no_cck, int no_ack, int offchanok);
-static int nl80211_register_frame(struct i802_bss *bss,
-                                 struct nl_handle *hl_handle,
-                                 u16 type, const u8 *match, size_t match_len);
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
                                               int report);
 
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
-                                       enum wpa_driver_if_type type,
-                                       const char *ifname);
 
 static int nl80211_set_channel(struct i802_bss *bss,
                               struct hostapd_freq_params *freq, int set_chan);
 static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
                                     int ifindex, int disabled);
 
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+                             int reset_mode);
 
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
 static int i802_set_iface_flags(struct i802_bss *bss, int up);
 static int nl80211_set_param(void *priv, const char *param);
 
@@ -287,6 +297,28 @@ static int no_seq_check(struct nl_msg *msg, void *arg)
 }
 
 
+static void nl80211_nlmsg_clear(struct nl_msg *msg)
+{
+       /*
+        * Clear nlmsg data, e.g., to make sure key material is not left in
+        * heap memory for unnecessarily long time.
+        */
+       if (msg) {
+               struct nlmsghdr *hdr = nlmsg_hdr(msg);
+               void *data = nlmsg_data(hdr);
+               /*
+                * This would use nlmsg_datalen() or the older nlmsg_len() if
+                * only libnl were to maintain a stable API.. Neither will work
+                * with all released versions, so just calculate the length
+                * here.
+                */
+               int len = hdr->nlmsg_len - NLMSG_HDRLEN;
+
+               os_memset(data, 0, len);
+       }
+}
+
+
 static int send_and_recv(struct nl80211_global *global,
                         struct nl_handle *nl_handle, struct nl_msg *msg,
                         int (*valid_handler)(struct nl_msg *, void *),
@@ -326,21 +358,13 @@ static int send_and_recv(struct nl80211_global *global,
        }
  out:
        nl_cb_put(cb);
+       if (!valid_handler && valid_data == (void *) -1)
+               nl80211_nlmsg_clear(msg);
        nlmsg_free(msg);
        return err;
 }
 
 
-static int send_and_recv_msgs_global(struct nl80211_global *global,
-                                    struct nl_msg *msg,
-                                    int (*valid_handler)(struct nl_msg *, void *),
-                                    void *valid_data)
-{
-       return send_and_recv(global, global->nl, msg, valid_handler,
-                            valid_data);
-}
-
-
 int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
                       struct nl_msg *msg,
                       int (*valid_handler)(struct nl_msg *, void *),
@@ -405,7 +429,7 @@ static int nl_get_multicast_id(struct nl80211_global *global,
                return -1;
        }
 
-       ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
+       ret = send_and_recv(global, global->nl, msg, family_handler, &res);
        if (ret == 0)
                ret = res.id;
        return ret;
@@ -756,7 +780,7 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
 
 
 static void wpa_driver_nl80211_event_newlink(
-       struct wpa_driver_nl80211_data *drv, char *ifname)
+       struct wpa_driver_nl80211_data *drv, const char *ifname)
 {
        union wpa_event_data event;
 
@@ -782,7 +806,7 @@ static void wpa_driver_nl80211_event_newlink(
 
 
 static void wpa_driver_nl80211_event_dellink(
-       struct wpa_driver_nl80211_data *drv, char *ifname)
+       struct wpa_driver_nl80211_data *drv, const char *ifname)
 {
        union wpa_event_data event;
 
@@ -840,6 +864,7 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
                return 1;
 
        if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
+               nl80211_check_global(drv->global);
                wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
                           "interface");
                wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
@@ -928,16 +953,21 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
        if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+               namebuf[0] = '\0';
                if (if_indextoname(ifi->ifi_index, namebuf) &&
-                   linux_iface_up(drv->global->ioctl_sock,
-                                  drv->first_bss->ifname) > 0) {
+                   linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
                                   "event since interface %s is up", namebuf);
                        drv->ignore_if_down_event = 0;
                        return;
                }
-               wpa_printf(MSG_DEBUG, "nl80211: Interface down");
-               if (drv->ignore_if_down_event) {
+               wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
+                          namebuf, ifname);
+               if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Not the main interface (%s) - do not indicate interface down",
+                                  drv->first_bss->ifname);
+               } else if (drv->ignore_if_down_event) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
                                   "event generated by mode change");
                        drv->ignore_if_down_event = 0;
@@ -960,8 +990,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 
        if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
                if (if_indextoname(ifi->ifi_index, namebuf) &&
-                   linux_iface_up(drv->global->ioctl_sock,
-                                  drv->first_bss->ifname) == 0) {
+                   linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
                                   "event since interface %s is down",
                                   namebuf);
@@ -1024,7 +1053,12 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                struct i802_bss *bss;
 
                /* device has been added to bridge */
-               if_indextoname(brid, namebuf);
+               if (!if_indextoname(brid, namebuf)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Could not find bridge ifname for ifindex %u",
+                                  brid);
+                       return;
+               }
                wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
                           brid, namebuf);
                add_ifidx(drv, brid);
@@ -1104,9 +1138,16 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
        if (ifi->ifi_family == AF_BRIDGE && brid) {
                /* device has been removed from bridge */
                char namebuf[IFNAMSIZ];
-               if_indextoname(brid, namebuf);
-               wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
-                          "%s", brid, namebuf);
+
+               if (!if_indextoname(brid, namebuf)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Could not find bridge ifname for ifindex %u",
+                                  brid);
+               } else {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Remove ifindex %u for bridge %s",
+                                  brid, namebuf);
+               }
                del_ifidx(drv, brid);
        }
 }
@@ -1145,6 +1186,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
                [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
                [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
+               [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
        };
        struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
        static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1173,6 +1215,13 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        else
                sig_change->avg_signal = 0;
 
+       if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
+               sig_change->avg_beacon_signal =
+                       (s8)
+                       nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
+       else
+               sig_change->avg_beacon_signal = 0;
+
        if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
                                     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -1441,20 +1490,30 @@ err:
 }
 
 
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+static void nl80211_check_global(struct nl80211_global *global)
 {
-       drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
-       if (!drv->nl_cb) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
-               return -1;
-       }
-
-       nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
-                 no_seq_check, NULL);
-       nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
-                 process_drv_event, drv);
+       struct nl_handle *handle;
+       const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
+       int ret;
+       unsigned int i;
 
-       return 0;
+       /*
+        * Try to re-add memberships to handle case of cfg80211 getting reloaded
+        * and all registration having been cleared.
+        */
+       handle = (void *) (((intptr_t) global->nl_event) ^
+                          ELOOP_SOCKET_INVALID);
+
+       for (i = 0; groups[i]; i++) {
+               ret = nl_get_multicast_id(global, "nl80211", groups[i]);
+               if (ret >= 0)
+                       ret = nl_socket_add_membership(handle, ret);
+               if (ret < 0) {
+                       wpa_printf(MSG_INFO,
+                                  "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
+                                  groups[i], ret, strerror(-ret));
+               }
+       }
 }
 
 
@@ -1580,6 +1639,14 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
        drv->ctx = ctx;
        drv->hostapd = !!hostapd;
        drv->eapol_sock = -1;
+
+       /*
+        * There is no driver capability flag for this, so assume it is
+        * supported and disable this on first attempt to use if the driver
+        * rejects the command due to missing support.
+        */
+       drv->set_rekey_offload = 1;
+
        drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
        drv->if_indices = drv->default_if_indices;
 
@@ -1598,11 +1665,6 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
        drv->eapol_tx_sock = -1;
        drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
-       if (wpa_driver_nl80211_init_nl(drv)) {
-               os_free(drv);
-               return NULL;
-       }
-
        if (nl80211_init_bss(bss))
                goto failed;
 
@@ -1648,6 +1710,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
        }
 
        if (drv->global) {
+               nl80211_check_global(drv->global);
                dl_list_add(&drv->global->interfaces, &drv->list);
                drv->in_interface_list = 1;
        }
@@ -1711,15 +1774,13 @@ static int nl80211_register_frame(struct i802_bss *bss,
 
 static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
 {
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-
        if (bss->nl_mgmt) {
                wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
                           "already on! (nl_mgmt=%p)", bss->nl_mgmt);
                return -1;
        }
 
-       bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+       bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
        if (bss->nl_mgmt == NULL)
                return -1;
 
@@ -1817,6 +1878,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
                        ret = -1;
        }
 #endif /* CONFIG_TDLS */
+#ifdef CONFIG_FST
+       /* FST Action frames */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
+               ret = -1;
+#endif /* CONFIG_FST */
 
        /* FT Action frames */
        if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
@@ -1840,11 +1906,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 
        /* WMM-AC ADDTS Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
-               return -1;
+               ret = -1;
 
        /* WMM-AC DELTS */
        if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
-               return -1;
+               ret = -1;
 
        /* Radio Measurement - Neighbor Report Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
@@ -2045,6 +2111,60 @@ static int i802_set_iface_flags(struct i802_bss *bss, int up)
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
+{
+       /* struct wpa_driver_nl80211_data *drv = arg; */
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: QCA vendor test command response received");
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+       if (!tb[NL80211_ATTR_VENDOR_DATA]) {
+               wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
+               return NL_SKIP;
+       }
+
+       wpa_hexdump(MSG_DEBUG,
+                   "nl80211: Received QCA vendor test command response",
+                   nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
+                   nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
+
+       return NL_SKIP;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+       struct nl_msg *msg;
+       struct nlattr *params;
+       int ret;
+
+       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                       QCA_NL80211_VENDOR_SUBCMD_TEST) ||
+           !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
+               nlmsg_free(msg);
+               return;
+       }
+       nla_nest_end(msg, params);
+
+       ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv);
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: QCA vendor test command returned %d (%s)",
+                  ret, strerror(-ret));
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
                                   const u8 *set_addr, int first,
@@ -2131,6 +2251,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
                                       drv, drv->ctx);
        }
 
+       if (drv->vendor_cmd_test_avail)
+               qca_vendor_test(drv);
+
        return 0;
 }
 
@@ -2178,6 +2301,11 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
                        nl80211_handle_destroy(drv->rtnl_sk);
        }
        if (bss->added_bridge) {
+               if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
+                                         0) < 0)
+                       wpa_printf(MSG_INFO,
+                                  "nl80211: Could not set bridge %s down",
+                                  bss->brname);
                if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "bridge %s: %s",
@@ -2232,7 +2360,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
                nl80211_mgmt_unsubscribe(bss, "deinit");
                nl80211_del_p2pdev(bss);
        }
-       nl_cb_put(drv->nl_cb);
 
        nl80211_destroy_bss(drv->first_bss);
 
@@ -2355,10 +2482,11 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
            nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
                        QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
            nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
+               nl80211_nlmsg_clear(msg);
                nlmsg_free(msg);
                return -1;
        }
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
        if (ret) {
                wpa_printf(MSG_DEBUG,
                           "nl80211: Key management set key failed: ret=%d (%s)",
@@ -2377,7 +2505,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifindex;
-       struct nl_msg *msg;
+       struct nl_msg *msg = NULL;
        int ret;
        int tdls = 0;
 
@@ -2410,11 +2538,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                if (!msg)
                        return -ENOBUFS;
        } else {
+               u32 suite;
+
+               suite = wpa_alg_to_cipher_suite(alg, key_len);
+               if (!suite)
+                       goto fail;
                msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
                if (!msg ||
                    nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
-                   nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
-                               wpa_alg_to_cipher_suite(alg, key_len)))
+                   nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
                        goto fail;
                wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
        }
@@ -2450,7 +2582,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
                goto fail;
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
        if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
                ret = 0;
        if (ret)
@@ -2470,7 +2602,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
        if (!msg ||
            nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
-           nla_put_flag(msg, alg == WPA_ALG_IGTK ?
+           nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
+                              alg == WPA_ALG_BIP_GMAC_128 ||
+                              alg == WPA_ALG_BIP_GMAC_256 ||
+                              alg == WPA_ALG_BIP_CMAC_256) ?
                         NL80211_ATTR_KEY_DEFAULT_MGMT :
                         NL80211_ATTR_KEY_DEFAULT))
                goto fail;
@@ -2501,6 +2636,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        return ret;
 
 fail:
+       nl80211_nlmsg_clear(msg);
        nlmsg_free(msg);
        return -ENOBUFS;
 }
@@ -2512,9 +2648,15 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
                      const u8 *key, size_t key_len)
 {
        struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
+       u32 suite;
+
        if (!key_attr)
                return -1;
 
+       suite = wpa_alg_to_cipher_suite(alg, key_len);
+       if (!suite)
+               return -1;
+
        if (defkey && alg == WPA_ALG_IGTK) {
                if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
                        return -1;
@@ -2524,8 +2666,7 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
        }
 
        if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
-           nla_put_u32(msg, NL80211_KEY_CIPHER,
-                       wpa_alg_to_cipher_suite(alg, key_len)) ||
+           nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
            (seq && seq_len &&
             nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
            nla_put(msg, NL80211_KEY_DATA, key_len, key))
@@ -2644,7 +2785,7 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
 
        if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
                nl80211_mark_disconnected(drv);
-               return nl80211_leave_ibss(drv);
+               return nl80211_leave_ibss(drv, 1);
        }
        if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
                return wpa_driver_nl80211_disconnect(drv, reason_code);
@@ -3068,9 +3209,25 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 }
 
 
+static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
+{
+       u8 rates[NL80211_MAX_SUPP_RATES];
+       u8 rates_len = 0;
+       int i;
+
+       if (!basic_rates)
+               return 0;
+
+       for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
+               rates[rates_len++] = basic_rates[i] / 5;
+
+       return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+}
+
+
 static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
                           int slot, int ht_opmode, int ap_isolate,
-                          int *basic_rates)
+                          const int *basic_rates)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
@@ -3085,27 +3242,13 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
            (ht_opmode >= 0 &&
             nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
            (ap_isolate >= 0 &&
-            nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)))
-               goto fail;
-
-       if (basic_rates) {
-               u8 rates[NL80211_MAX_SUPP_RATES];
-               u8 rates_len = 0;
-               int i;
-
-               for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
-                    i++)
-                       rates[rates_len++] = basic_rates[i] / 5;
-
-               if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
-                           rates))
-                       goto fail;
+            nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
+           nl80211_put_basic_rates(msg, basic_rates)) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
        }
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
-fail:
-       nlmsg_free(msg);
-       return -ENOBUFS;
 }
 
 
@@ -3156,6 +3299,18 @@ static int wpa_driver_nl80211_set_acl(void *priv,
 }
 
 
+static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
+{
+       if (beacon_int > 0) {
+               wpa_printf(MSG_DEBUG, "  * beacon_int=%d", beacon_int);
+               return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+                                  beacon_int);
+       }
+
+       return 0;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -3170,7 +3325,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        u32 suites[10], suite;
        u32 ver;
 
-       beacon_set = bss->beacon_set;
+       beacon_set = params->reenable ? 0 : bss->beacon_set;
 
        wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
                   beacon_set);
@@ -3191,8 +3346,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                    params->head) ||
            nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
                    params->tail) ||
-           nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-                       params->beacon_int) ||
+           nl80211_put_beacon_int(msg, params->beacon_int) ||
            nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
            nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
                goto fail;
@@ -3263,7 +3417,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                    suites))
                goto fail;
 
-       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
+       if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
            params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
            nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
                goto fail;
@@ -3336,6 +3490,21 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        goto fail;
        }
 
+#ifdef CONFIG_P2P
+       if (params->p2p_go_ctwindow > 0) {
+               if (drv->p2p_go_ctwindow_supported) {
+                       wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
+                                  params->p2p_go_ctwindow);
+                       if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
+                                      params->p2p_go_ctwindow))
+                               goto fail;
+               } else {
+                       wpa_printf(MSG_INFO,
+                                  "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
+               }
+       }
+#endif /* CONFIG_P2P */
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -3378,14 +3547,19 @@ fail:
 
 
 static int nl80211_put_freq_params(struct nl_msg *msg,
-                                  struct hostapd_freq_params *freq)
+                                  const struct hostapd_freq_params *freq)
 {
+       wpa_printf(MSG_DEBUG, "  * freq=%d", freq->freq);
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
                return -ENOBUFS;
 
+       wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", freq->vht_enabled);
+       wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", freq->ht_enabled);
+
        if (freq->vht_enabled) {
                enum nl80211_chan_width cw;
 
+               wpa_printf(MSG_DEBUG, "  * bandwidth=%d", freq->bandwidth);
                switch (freq->bandwidth) {
                case 20:
                        cw = NL80211_CHAN_WIDTH_20;
@@ -3406,6 +3580,11 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
                        return -EINVAL;
                }
 
+               wpa_printf(MSG_DEBUG, "  * channel_width=%d", cw);
+               wpa_printf(MSG_DEBUG, "  * center_freq1=%d",
+                          freq->center_freq1);
+               wpa_printf(MSG_DEBUG, "  * center_freq2=%d",
+                          freq->center_freq2);
                if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
                    nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
                                freq->center_freq1) ||
@@ -3416,6 +3595,8 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
        } else if (freq->ht_enabled) {
                enum nl80211_channel_type ct;
 
+               wpa_printf(MSG_DEBUG, "  * sec_channel_offset=%d",
+                          freq->sec_channel_offset);
                switch (freq->sec_channel_offset) {
                case -1:
                        ct = NL80211_CHAN_HT40MINUS;
@@ -3428,6 +3609,7 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
                        break;
                }
 
+               wpa_printf(MSG_DEBUG, "  * channel_type=%d", ct);
                if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
                        return -ENOBUFS;
        }
@@ -4072,8 +4254,9 @@ static int wpa_driver_nl80211_hapd_send_eapol(
 
 
 static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
-                                           int total_flags,
-                                           int flags_or, int flags_and)
+                                           unsigned int total_flags,
+                                           unsigned int flags_or,
+                                           unsigned int flags_and)
 {
        struct i802_bss *bss = priv;
        struct nl_msg *msg;
@@ -4140,7 +4323,8 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                return -1;
        }
 
-       if (nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
+       if (params->freq.freq &&
+           nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
                if (old_mode != nlmode)
                        wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
                nl80211_remove_monitor_interface(drv);
@@ -4151,7 +4335,8 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+                             int reset_mode)
 {
        struct nl_msg *msg;
        int ret;
@@ -4166,7 +4351,8 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
                           "nl80211: Leave IBSS request sent successfully");
        }
 
-       if (wpa_driver_nl80211_set_mode(drv->first_bss,
+       if (reset_mode &&
+           wpa_driver_nl80211_set_mode(drv->first_bss,
                                        NL80211_IFTYPE_STATION)) {
                wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
                           "station mode");
@@ -4176,6 +4362,48 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
 }
 
 
+static int nl80211_ht_vht_overrides(struct nl_msg *msg,
+                                   struct wpa_driver_associate_params *params)
+{
+       if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+               return -1;
+
+       if (params->htcaps && params->htcaps_mask) {
+               int sz = sizeof(struct ieee80211_ht_capabilities);
+               wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
+               wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
+                           params->htcaps_mask, sz);
+               if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+                           params->htcaps) ||
+                   nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+                           params->htcaps_mask))
+                       return -1;
+       }
+
+#ifdef CONFIG_VHT_OVERRIDES
+       if (params->disable_vht) {
+               wpa_printf(MSG_DEBUG, "  * VHT disabled");
+               if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+                       return -1;
+       }
+
+       if (params->vhtcaps && params->vhtcaps_mask) {
+               int sz = sizeof(struct ieee80211_vht_capabilities);
+               wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
+               wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
+                           params->vhtcaps_mask, sz);
+               if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+                           params->vhtcaps) ||
+                   nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+                           params->vhtcaps_mask))
+                       return -1;
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
+       return 0;
+}
+
+
 static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
                                   struct wpa_driver_associate_params *params)
 {
@@ -4203,24 +4431,10 @@ retry:
        os_memcpy(drv->ssid, params->ssid, params->ssid_len);
        drv->ssid_len = params->ssid_len;
 
-       wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq.freq);
-       wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", params->freq.ht_enabled);
-       wpa_printf(MSG_DEBUG, "  * sec_channel_offset=%d",
-                  params->freq.sec_channel_offset);
-       wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", params->freq.vht_enabled);
-       wpa_printf(MSG_DEBUG, "  * center_freq1=%d", params->freq.center_freq1);
-       wpa_printf(MSG_DEBUG, "  * center_freq2=%d", params->freq.center_freq2);
-       wpa_printf(MSG_DEBUG, "  * bandwidth=%d", params->freq.bandwidth);
-       if (nl80211_put_freq_params(msg, &params->freq) < 0)
+       if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
+           nl80211_put_beacon_int(msg, params->beacon_int))
                goto fail;
 
-       if (params->beacon_int > 0) {
-               wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
-               if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-                               params->beacon_int))
-                       goto fail;
-       }
-
        ret = nl80211_set_conn_keys(params, msg);
        if (ret)
                goto fail;
@@ -4232,6 +4446,12 @@ retry:
                        goto fail;
        }
 
+       if (params->fixed_freq) {
+               wpa_printf(MSG_DEBUG, "  * fixed_freq");
+               if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
+                       goto fail;
+       }
+
        if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
            params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
            params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
@@ -4250,6 +4470,9 @@ retry:
                        goto fail;
        }
 
+       if (nl80211_ht_vht_overrides(msg, params) < 0)
+               return -1;
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
@@ -4259,7 +4482,7 @@ retry:
                if (ret == -EALREADY && count == 1) {
                        wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
                                   "forced leave");
-                       nl80211_leave_ibss(drv);
+                       nl80211_leave_ibss(drv, 0);
                        nlmsg_free(msg);
                        goto retry;
                }
@@ -4377,7 +4600,8 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
            params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
            params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
            params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
-           params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+           params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+           params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
                int mgmt = WLAN_AKM_SUITE_PSK;
 
                switch (params->key_mgmt_suite) {
@@ -4405,6 +4629,9 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
                        mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
                        break;
+               case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+                       mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
+                       break;
                case WPA_KEY_MGMT_PSK:
                default:
                        mgmt = WLAN_AKM_SUITE_PSK;
@@ -4431,41 +4658,9 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                        return -1;
        }
 
-       if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+       if (nl80211_ht_vht_overrides(msg, params) < 0)
                return -1;
 
-       if (params->htcaps && params->htcaps_mask) {
-               int sz = sizeof(struct ieee80211_ht_capabilities);
-               wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
-               wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
-                           params->htcaps_mask, sz);
-               if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
-                           params->htcaps) ||
-                   nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
-                           params->htcaps_mask))
-                       return -1;
-       }
-
-#ifdef CONFIG_VHT_OVERRIDES
-       if (params->disable_vht) {
-               wpa_printf(MSG_DEBUG, "  * VHT disabled");
-               if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
-                       return -1;
-       }
-
-       if (params->vhtcaps && params->vhtcaps_mask) {
-               int sz = sizeof(struct ieee80211_vht_capabilities);
-               wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
-               wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
-                           params->vhtcaps_mask, sz);
-               if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
-                           params->vhtcaps) ||
-                   nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
-                           params->vhtcaps_mask))
-                       return -1;
-       }
-#endif /* CONFIG_VHT_OVERRIDES */
-
        if (params->p2p)
                wpa_printf(MSG_DEBUG, "  * P2P group");
 
@@ -4724,7 +4919,7 @@ static int wpa_driver_nl80211_set_mode_impl(
                 * on a frequency that the mode is disallowed in.
                 */
                if (desired_freq_params) {
-                       res = i802_set_freq(bss, desired_freq_params);
+                       res = nl80211_set_channel(bss, desired_freq_params, 0);
                        if (res) {
                                wpa_printf(MSG_DEBUG,
                                           "nl80211: Failed to set frequency on interface");
@@ -5195,6 +5390,8 @@ static int i802_get_inact_sec(void *priv, const u8 *addr)
 
        data.inactive_msec = (unsigned long) -1;
        ret = i802_read_sta_data(priv, &data, addr);
+       if (ret == -ENOENT)
+               return -ENOENT;
        if (ret || data.inactive_msec == (unsigned long) -1)
                return -1;
        return data.inactive_msec / 1000;
@@ -5483,8 +5680,8 @@ static void *i802_init(struct hostapd_data *hapd,
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *bss;
        size_t i;
-       char brname[IFNAMSIZ];
-       int ifindex, br_ifindex;
+       char master_ifname[IFNAMSIZ];
+       int ifindex, br_ifindex = 0;
        int br_added = 0;
 
        bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
@@ -5495,15 +5692,21 @@ static void *i802_init(struct hostapd_data *hapd,
 
        drv = bss->drv;
 
-       if (linux_br_get(brname, params->ifname) == 0) {
+       if (linux_br_get(master_ifname, params->ifname) == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
-                          params->ifname, brname);
-               br_ifindex = if_nametoindex(brname);
-               os_strlcpy(bss->brname, brname, IFNAMSIZ);
+                          params->ifname, master_ifname);
+               br_ifindex = if_nametoindex(master_ifname);
+               os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
+       } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
+                  linux_master_get(master_ifname, params->ifname) == 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
+                       params->ifname, master_ifname);
+               /* start listening for EAPOL on the master interface */
+               add_ifidx(drv, if_nametoindex(master_ifname));
        } else {
-               brname[0] = '\0';
-               br_ifindex = 0;
+               master_ifname[0] = '\0';
        }
+
        bss->br_ifindex = br_ifindex;
 
        for (i = 0; i < params->num_bridge; i++) {
@@ -5515,16 +5718,21 @@ static void *i802_init(struct hostapd_data *hapd,
                                br_added = 1;
                }
        }
-       if (!br_added && br_ifindex &&
-           (params->num_bridge == 0 || !params->bridge[0]))
-               add_ifidx(drv, br_ifindex);
 
        /* start listening for EAPOL on the default AP interface */
        add_ifidx(drv, drv->ifindex);
 
-       if (params->num_bridge && params->bridge[0] &&
-           i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
-               goto failed;
+       if (params->num_bridge && params->bridge[0]) {
+               if (i802_check_bridge(drv, bss, params->bridge[0],
+                                     params->ifname) < 0)
+                       goto failed;
+               if (os_strcmp(params->bridge[0], master_ifname) != 0)
+                       br_added = 1;
+       }
+
+       if (!br_added && br_ifindex &&
+           (params->num_bridge == 0 || !params->bridge[0]))
+               add_ifidx(drv, br_ifindex);
 
 #ifdef CONFIG_LIBNL3_ROUTE
        if (bss->added_if_into_bridge) {
@@ -5601,8 +5809,6 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
 }
 
 
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
-
 static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
 {
        struct wpa_driver_nl80211_data *drv;
@@ -5638,8 +5844,6 @@ static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
        return 0;
 }
 
-#endif /* CONFIG_P2P || CONFIG_MESH */
-
 
 struct wdev_info {
        u64 wdev_id;
@@ -5715,21 +5919,21 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        }
 
        if (!addr) {
-               if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+               if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
                        os_memcpy(if_addr, bss->addr, ETH_ALEN);
                else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
-                                           bss->ifname, if_addr) < 0) {
+                                           ifname, if_addr) < 0) {
                        if (added)
                                nl80211_remove_iface(drv, ifidx);
                        return -1;
                }
        }
 
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
        if (!addr &&
            (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
-            type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
-               /* Enforce unique P2P Interface Address */
+            type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
+            type == WPA_IF_STATION)) {
+               /* Enforce unique address */
                u8 new_addr[ETH_ALEN];
 
                if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
@@ -5740,8 +5944,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                }
                if (nl80211_addr_in_use(drv->global, new_addr)) {
                        wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
-                                  "for %s interface", type == WPA_IF_MESH ?
-                                  "mesh" : "P2P group");
+                                  "for interface %s type %d", ifname, type);
                        if (nl80211_vif_addr(drv, new_addr) < 0) {
                                if (added)
                                        nl80211_remove_iface(drv, ifidx);
@@ -5756,7 +5959,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                }
                os_memcpy(if_addr, new_addr, ETH_ALEN);
        }
-#endif /* CONFIG_P2P || CONFIG_MESH */
 
        if (type == WPA_IF_AP_BSS) {
                struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -6334,47 +6536,6 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 }
 
 
-static int wpa_driver_nl80211_shared_freq(void *priv)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct wpa_driver_nl80211_data *driver;
-       int freq = 0;
-
-       /*
-        * If the same PHY is in connected state with some other interface,
-        * then retrieve the assoc freq.
-        */
-       wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
-                  drv->phyname);
-
-       dl_list_for_each(driver, &drv->global->interfaces,
-                        struct wpa_driver_nl80211_data, list) {
-               if (drv == driver ||
-                   os_strcmp(drv->phyname, driver->phyname) != 0 ||
-                   !driver->associated)
-                       continue;
-
-               wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
-                          MACSTR,
-                          driver->phyname, driver->first_bss->ifname,
-                          MAC2STR(driver->first_bss->addr));
-               if (is_ap_interface(driver->nlmode))
-                       freq = driver->first_bss->freq;
-               else
-                       freq = nl80211_get_assoc_freq(driver);
-               wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
-                          drv->phyname, freq);
-       }
-
-       if (!freq)
-               wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
-                          "PHY (%s) in associated state", drv->phyname);
-
-       return freq;
-}
-
-
 static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
                              int encrypt)
 {
@@ -6720,27 +6881,39 @@ static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
 }
 
 
-static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
+                                  const u8 *kck, size_t kck_len,
                                   const u8 *replay_ctr)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nlattr *replay_nested;
        struct nl_msg *msg;
+       int ret;
 
+       if (!drv->set_rekey_offload)
+               return;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
        if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
            !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
-           nla_put(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek) ||
-           nla_put(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck) ||
+           nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
+           nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
            nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
                    replay_ctr)) {
+               nl80211_nlmsg_clear(msg);
                nlmsg_free(msg);
                return;
        }
 
        nla_nest_end(msg, replay_nested);
 
-       send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+       if (ret == -EOPNOTSUPP) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Driver does not support rekey offload");
+               drv->set_rekey_offload = 0;
+       }
 }
 
 
@@ -6788,6 +6961,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
+       int ret;
 
        if (!drv->poll_command_supported) {
                nl80211_send_null_frame(bss, own_addr, addr, qos);
@@ -6800,7 +6974,12 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
                return;
        }
 
-       send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
+                          MACSTR " failed: ret=%d (%s)",
+                          MAC2STR(addr), ret, strerror(-ret));
+       }
 }
 
 
@@ -6966,6 +7145,62 @@ static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
        return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
 
+
+static int
+nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
+                                  const struct hostapd_freq_params *params)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -ENOBUFS;
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+               return -EOPNOTSUPP;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
+                  " oper_class=%u freq=%u",
+                  MAC2STR(addr), oper_class, params->freq);
+       msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
+       if (!msg ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+           nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
+           (ret = nl80211_put_freq_params(msg, params))) {
+               nlmsg_free(msg);
+               wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
+               return ret;
+       }
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+static int
+nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+               return -EOPNOTSUPP;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
+                  MAC2STR(addr));
+       msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
+       if (!msg ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+               nlmsg_free(msg);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Could not build TDLS cancel chan switch");
+               return -ENOBUFS;
+       }
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
 #endif /* CONFIG TDLS */
 
 
@@ -7021,11 +7256,12 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
 
 
 static int driver_nl80211_send_mlme(void *priv, const u8 *data,
-                                   size_t data_len, int noack)
+                                   size_t data_len, int noack,
+                                   unsigned int freq)
 {
        struct i802_bss *bss = priv;
        return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
-                                           0, 0, 0, 0);
+                                           freq, 0, 0, 0);
 }
 
 
@@ -7250,7 +7486,9 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  "capa.max_stations=%u\n"
                                  "capa.probe_resp_offloads=0x%x\n"
                                  "capa.max_acl_mac_addrs=%u\n"
-                                 "capa.num_multichan_concurrent=%u\n",
+                                 "capa.num_multichan_concurrent=%u\n"
+                                 "capa.mac_addr_rand_sched_scan_supported=%d\n"
+                                 "capa.mac_addr_rand_scan_supported=%d\n",
                                  drv->capa.key_mgmt,
                                  drv->capa.enc,
                                  drv->capa.auth,
@@ -7264,7 +7502,9 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  drv->capa.max_stations,
                                  drv->capa.probe_resp_offloads,
                                  drv->capa.max_acl_mac_addrs,
-                                 drv->capa.num_multichan_concurrent);
+                                 drv->capa.num_multichan_concurrent,
+                                 drv->capa.mac_addr_rand_sched_scan_supported,
+                                 drv->capa.mac_addr_rand_scan_supported);
                if (os_snprintf_error(end - pos, res))
                        return pos - buf;
                pos += res;
@@ -7579,7 +7819,7 @@ static int nl80211_set_wowlan(void *priv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
 
-       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+       if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
            !(wowlan_triggers = nla_nest_start(msg,
                                               NL80211_ATTR_WOWLAN_TRIGGERS)) ||
            (triggers->any &&
@@ -7697,77 +7937,35 @@ static int wpa_driver_nl80211_init_mesh(void *priv)
 }
 
 
-static int
-wpa_driver_nl80211_join_mesh(void *priv,
+static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
+                              size_t mesh_id_len)
+{
+       if (mesh_id) {
+               wpa_hexdump_ascii(MSG_DEBUG, "  * Mesh ID (SSID)",
+                                 mesh_id, mesh_id_len);
+               return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
+       }
+
+       return 0;
+}
+
+
+static int nl80211_join_mesh(struct i802_bss *bss,
                             struct wpa_driver_mesh_join_params *params)
 {
-       struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct nlattr *container;
-       int ret = 0;
+       int ret = -1;
 
        wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
        msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
-       if (!msg)
+       if (!msg ||
+           nl80211_put_freq_params(msg, &params->freq) ||
+           nl80211_put_basic_rates(msg, params->basic_rates) ||
+           nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
+           nl80211_put_beacon_int(msg, params->beacon_int))
                goto fail;
-       if (params->freq) {
-               wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-               if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
-                       goto fail;
-       }
-
-       if (params->ht_mode) {
-               unsigned int ht_value;
-               char *ht_mode = "";
-
-               switch (params->ht_mode) {
-               default:
-               case CHAN_NO_HT:
-                       ht_value = NL80211_CHAN_NO_HT;
-                       ht_mode = "NOHT";
-                       break;
-               case CHAN_HT20:
-                       ht_value = NL80211_CHAN_HT20;
-                       ht_mode = "HT20";
-                       break;
-               case CHAN_HT40PLUS:
-                       ht_value = NL80211_CHAN_HT40PLUS;
-                       ht_mode = "HT40+";
-                       break;
-               case CHAN_HT40MINUS:
-                       ht_value = NL80211_CHAN_HT40MINUS;
-                       ht_mode = "HT40-";
-                       break;
-               }
-               wpa_printf(MSG_DEBUG, "  * ht_mode=%s", ht_mode);
-               if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value))
-                       goto fail;
-       }
-
-       if (params->basic_rates) {
-               u8 rates[NL80211_MAX_SUPP_RATES];
-               u8 rates_len = 0;
-               int i;
-
-               for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) {
-                       if (params->basic_rates[i] < 0)
-                               break;
-                       rates[rates_len++] = params->basic_rates[i] / 5;
-               }
-
-               if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
-                           rates))
-                       goto fail;
-       }
-
-       if (params->meshid) {
-               wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-                                 params->meshid, params->meshid_len);
-               if (nla_put(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
-                           params->meshid))
-                       goto fail;
-       }
 
        wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
 
@@ -7802,6 +8000,21 @@ wpa_driver_nl80211_join_mesh(void *priv,
        if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
            nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
                goto fail;
+       if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
+           nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+                       params->max_peer_links))
+               goto fail;
+
+       /*
+        * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+        * the timer could disconnect stations even in that case.
+        */
+       if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+                       params->conf.peer_link_timeout)) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+               goto fail;
+       }
+
        nla_nest_end(msg, container);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7812,7 +8025,7 @@ wpa_driver_nl80211_join_mesh(void *priv,
                goto fail;
        }
        ret = 0;
-       bss->freq = params->freq;
+       bss->freq = params->freq.freq;
        wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
 
 fail:
@@ -7821,6 +8034,37 @@ fail:
 }
 
 
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+                            struct wpa_driver_mesh_join_params *params)
+{
+       struct i802_bss *bss = priv;
+       int ret, timeout;
+
+       timeout = params->conf.peer_link_timeout;
+
+       /* Disable kernel inactivity timer */
+       if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
+               params->conf.peer_link_timeout = 0;
+
+       ret = nl80211_join_mesh(bss, params);
+       if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Mesh join retry for peer_link_timeout");
+               /*
+                * Old kernel does not support setting
+                * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
+                * into future from peer_link_timeout.
+                */
+               params->conf.peer_link_timeout = timeout + 60;
+               ret = nl80211_join_mesh(priv, params);
+       }
+
+       params->conf.peer_link_timeout = timeout;
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_leave_mesh(void *priv)
 {
        struct i802_bss *bss = priv;
@@ -8043,7 +8287,7 @@ static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
 {
        switch (attr) {
        case DRV_BR_PORT_ATTR_PROXYARP:
-               return "proxyarp";
+               return "proxyarp_wifi";
        case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
                return "hairpin_mode";
        }
@@ -8078,9 +8322,9 @@ static const char * drv_br_net_param_str(enum drv_br_net_param param)
        switch (param) {
        case DRV_BR_NET_PARAM_GARP_ACCEPT:
                return "arp_accept";
+       default:
+               return NULL;
        }
-
-       return NULL;
 }
 
 
@@ -8092,6 +8336,13 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
        const char *param_txt;
        int ip_version = 4;
 
+       if (param == DRV_BR_MULTICAST_SNOOPING) {
+               os_snprintf(path, sizeof(path),
+                           "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
+                           bss->brname);
+               goto set_val;
+       }
+
        param_txt = drv_br_net_param_str(param);
        if (param_txt == NULL)
                return -EINVAL;
@@ -8107,6 +8358,7 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
        os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
                    ip_version, bss->brname, param_txt);
 
+set_val:
        if (linux_write_system_file(path, val))
                return -1;
 
@@ -8125,6 +8377,8 @@ static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
                return QCA_ACS_MODE_IEEE80211A;
        case HOSTAPD_MODE_IEEE80211AD:
                return QCA_ACS_MODE_IEEE80211AD;
+       case HOSTAPD_MODE_IEEE80211ANY:
+               return QCA_ACS_MODE_IEEE80211ANY;
        default:
                return -1;
        }
@@ -8153,12 +8407,24 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
            (params->ht_enabled &&
             nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
            (params->ht40_enabled &&
-            nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+            nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
+           (params->vht_enabled &&
+            nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
+           nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+                       params->ch_width) ||
+           (params->ch_list_len &&
+            nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
+                    params->ch_list))) {
                nlmsg_free(msg);
                return -ENOBUFS;
        }
        nla_nest_end(msg, data);
 
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
+                  params->hw_mode, params->ht_enabled, params->ht40_enabled,
+                  params->vht_enabled, params->ch_width, params->ch_list_len);
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret) {
                wpa_printf(MSG_DEBUG,
@@ -8169,6 +8435,53 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
 }
 
 
+static int nl80211_set_band(void *priv, enum set_band band)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *data;
+       int ret;
+       enum qca_set_band qca_band;
+
+       if (!drv->setband_vendor_cmd_avail)
+               return -1;
+
+       switch (band) {
+       case WPA_SETBAND_AUTO:
+               qca_band = QCA_SETBAND_AUTO;
+               break;
+       case WPA_SETBAND_5G:
+               qca_band = QCA_SETBAND_5G;
+               break;
+       case WPA_SETBAND_2G:
+               qca_band = QCA_SETBAND_2G;
+               break;
+       default:
+               return -1;
+       }
+
+       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                       QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
+           !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+       nla_nest_end(msg, data);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Driver setband function failed: %s",
+                          strerror(errno));
+       }
+       return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -8228,7 +8541,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .signal_monitor = nl80211_signal_monitor,
        .signal_poll = nl80211_signal_poll,
        .send_frame = nl80211_send_frame,
-       .shared_freq = wpa_driver_nl80211_shared_freq,
        .set_param = nl80211_set_param,
        .get_radio_name = nl80211_get_radio_name,
        .add_pmkid = nl80211_add_pmkid,
@@ -8242,6 +8554,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 #ifdef CONFIG_TDLS
        .send_tdls_mgmt = nl80211_send_tdls_mgmt,
        .tdls_oper = nl80211_tdls_oper,
+       .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
+       .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
 #endif /* CONFIG_TDLS */
        .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
        .get_mac_addr = wpa_driver_nl80211_get_macaddr,
@@ -8254,7 +8568,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
 #endif /* ANDROID_P2P */
 #ifdef ANDROID
+#ifndef ANDROID_LIB_STUB
        .driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* !ANDROID_LIB_STUB */
 #endif /* ANDROID */
        .vendor_cmd = nl80211_vendor_cmd,
        .set_qos_map = nl80211_set_qos_map,
@@ -8273,4 +8589,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .add_tx_ts = nl80211_add_ts,
        .del_tx_ts = nl80211_del_ts,
        .do_acs = wpa_driver_do_acs,
+       .set_band = nl80211_set_band,
 };