Allow MLME frames to be sent without expecting an ACK (no retries)
[mech_eap.git] / src / drivers / driver_nl80211.c
index db8f5eb..4884d62 100644 (file)
@@ -88,23 +88,11 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
 
        nl_handle_destroy(handle);
 }
-
-static inline int __genl_ctrl_alloc_cache(struct nl_handle *h,
-                                         struct nl_cache **cache)
-{
-       struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
-       if (!tmp)
-               return -ENOMEM;
-       *cache = tmp;
-       return 0;
-}
-#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
 #endif /* CONFIG_LIBNL20 */
 
 
 struct nl80211_handles {
        struct nl_handle *handle;
-       struct nl_cache *cache;
 };
 
 
@@ -127,12 +115,6 @@ static int nl_create_handles(struct nl80211_handles *handles, struct nl_cb *cb,
                goto err;
        }
 
-       if (genl_ctrl_alloc_cache(handles->handle, &handles->cache) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-                          "netlink cache (%s)", dbg);
-               goto err;
-       }
-
        return 0;
 err:
        nl80211_handle_destroy(handles->handle);
@@ -144,7 +126,6 @@ static void nl_destroy_handles(struct nl80211_handles *handles)
 {
        if (handles->handle == NULL)
                return;
-       nl_cache_free(handles->cache);
        nl80211_handle_destroy(handles->handle);
        handles->handle = NULL;
 }
@@ -170,7 +151,8 @@ struct nl80211_global {
        struct netlink_data *netlink;
        struct nl_cb *nl_cb;
        struct nl80211_handles nl;
-       struct genl_family *nl80211;
+       int nl80211_id;
+       int ioctl_sock; /* socket for ioctl() use */
 };
 
 static void nl80211_global_deinit(void *priv);
@@ -193,7 +175,6 @@ struct wpa_driver_nl80211_data {
        u8 addr[ETH_ALEN];
        char phyname[32];
        void *ctx;
-       int ioctl_sock; /* socket for ioctl() use */
        int ifindex;
        int if_removed;
        int if_disabled;
@@ -219,11 +200,12 @@ struct wpa_driver_nl80211_data {
 
        int monitor_sock;
        int monitor_ifidx;
-       int no_monitor_iface_capab;
-       int disable_11b_rates;
 
+       unsigned int disabled_11b_rates:1;
        unsigned int pending_remain_on_chan:1;
        unsigned int in_interface_list:1;
+       unsigned int device_ap_sme:1;
+       unsigned int poll_command_supported:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -237,7 +219,7 @@ struct wpa_driver_nl80211_data {
        struct i802_bss first_bss;
 
 #ifdef CONFIG_AP
-       struct l2_packet_data *l2;
+       int eapol_tx_sock;
 #endif /* CONFIG_AP */
 
 #ifdef HOSTAPD
@@ -266,7 +248,8 @@ static void nl80211_remove_monitor_interface(
        struct wpa_driver_nl80211_data *drv);
 static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
                                  unsigned int freq, unsigned int wait,
-                                 const u8 *buf, size_t buf_len, u64 *cookie);
+                                 const u8 *buf, size_t buf_len, u64 *cookie,
+                                 int no_cck);
 static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
 
 #ifdef HOSTAPD
@@ -277,7 +260,15 @@ static int wpa_driver_nl80211_if_remove(void *priv,
                                        enum wpa_driver_if_type type,
                                        const char *ifname);
 #else /* HOSTAPD */
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
        return 0;
 }
@@ -304,6 +295,13 @@ static int is_sta_interface(enum nl80211_iftype nlmode)
 }
 
 
+static int is_p2p_interface(enum nl80211_iftype nlmode)
+{
+       return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+               nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
 struct nl80211_bss_info_arg {
        struct wpa_driver_nl80211_data *drv;
        struct wpa_scan_results *res;
@@ -455,7 +453,7 @@ nla_put_failure:
 static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
                          struct nl_msg *msg, int flags, uint8_t cmd)
 {
-       return genlmsg_put(msg, 0, 0, genl_family_get_id(drv->global->nl80211),
+       return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
                           0, flags, cmd, 0);
 }
 
@@ -593,6 +591,14 @@ 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)) {
+               char namebuf[IFNAMSIZ];
+               if (if_indextoname(ifi->ifi_index, namebuf) &&
+                   linux_iface_up(drv->global->ioctl_sock,
+                                  drv->first_bss.ifname) > 0) {
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+                                  "event since interface %s is up", namebuf);
+                       return;
+               }
                wpa_printf(MSG_DEBUG, "nl80211: Interface down");
                if (drv->ignore_if_down_event) {
                        wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
@@ -637,7 +643,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                attr = RTA_NEXT(attr, attrlen);
        }
 
-#ifdef HOSTAPD
        if (ifi->ifi_family == AF_BRIDGE && brid) {
                /* device has been added to bridge */
                char namebuf[IFNAMSIZ];
@@ -646,7 +651,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                           brid, namebuf);
                add_ifidx(drv, brid);
        }
-#endif /* HOSTAPD */
 }
 
 
@@ -682,7 +686,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                attr = RTA_NEXT(attr, attrlen);
        }
 
-#ifdef HOSTAPD
        if (ifi->ifi_family == AF_BRIDGE && brid) {
                /* device has been removed from bridge */
                char namebuf[IFNAMSIZ];
@@ -691,7 +694,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                           "%s", brid, namebuf);
                del_ifidx(drv, brid);
        }
-#endif /* HOSTAPD */
 }
 
 
@@ -1393,6 +1395,80 @@ static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+       static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+               [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+               [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+       };
+       struct wpa_scan_results *scan_results = arg;
+       struct wpa_scan_res *scan_res;
+       size_t i;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+               wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+               return NL_SKIP;
+       }
+
+       if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+                            tb[NL80211_ATTR_SURVEY_INFO],
+                            survey_policy)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+                          "attributes");
+               return NL_SKIP;
+       }
+
+       if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+               return NL_SKIP;
+
+       if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+               return NL_SKIP;
+
+       for (i = 0; i < scan_results->num; ++i) {
+               scan_res = scan_results->res[i];
+               if (!scan_res)
+                       continue;
+               if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+                   scan_res->freq)
+                       continue;
+               if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+                       continue;
+               scan_res->noise = (s8)
+                       nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+               scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+       struct wpa_driver_nl80211_data *drv,
+       struct wpa_scan_results *scan_res)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+                                 scan_res);
+ nla_put_failure:
+       return -ENOBUFS;
+}
+
+
 static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
                              struct nlattr *tb[])
 {
@@ -1471,7 +1547,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
        addr = nla_data(tb[NL80211_ATTR_MAC]);
        wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
 
-       if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) {
+       if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
                u8 *ies = NULL;
                size_t ies_len = 0;
                if (tb[NL80211_ATTR_IE]) {
@@ -1504,7 +1580,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
        wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
                   MAC2STR(addr));
 
-       if (is_ap_interface(drv->nlmode) && drv->no_monitor_iface_capab) {
+       if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
                drv_event_disassoc(drv->ctx, addr);
                return;
        }
@@ -1594,6 +1670,22 @@ static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+                                      struct nlattr **tb)
+{
+       union wpa_event_data data;
+
+       if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       os_memcpy(data.client_poll.addr,
+                 nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+       wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
 static int process_event(struct nl_msg *msg, void *arg)
 {
        struct wpa_driver_nl80211_data *drv = arg;
@@ -1716,6 +1808,9 @@ static int process_event(struct nl_msg *msg, void *arg)
        case NL80211_CMD_PMKSA_CANDIDATE:
                nl80211_pmksa_candidate_event(drv, tb);
                break;
+       case NL80211_CMD_PROBE_CLIENT:
+               nl80211_client_probe_event(drv, tb);
+               break;
        default:
                wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
                           "(cmd=%d)", gnlh->cmd);
@@ -1783,6 +1878,8 @@ struct wiphy_info_data {
        struct wpa_driver_capa *capa;
 
        unsigned int error:1;
+       unsigned int device_ap_sme:1;
+       unsigned int poll_command_supported:1;
 };
 
 
@@ -1914,6 +2011,9 @@ broken_combination:
                        case NL80211_CMD_START_SCHED_SCAN:
                                capa->sched_scan_supported = 1;
                                break;
+                       case NL80211_CMD_PROBE_CLIENT:
+                               info->poll_command_supported = 1;
+                               break;
                        }
                }
        }
@@ -1953,6 +2053,20 @@ broken_combination:
                capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
        }
 
+       if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
+               wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+               capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+               if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
+                       wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+                       capa->flags |=
+                               WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+               }
+       }
+
+       if (tb[NL80211_ATTR_DEVICE_AP_SME])
+               info->device_ap_sme = 1;
+
        return NL_SKIP;
 }
 
@@ -2010,6 +2124,9 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
        drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
 
+       drv->device_ap_sme = info.device_ap_sme;
+       drv->poll_command_supported = info.poll_command_supported;
+
        return 0;
 }
 
@@ -2026,9 +2143,8 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
        if (nl_create_handles(&global->nl, global->nl_cb, "nl"))
                return -1;
 
-       global->nl80211 = genl_ctrl_search_by_name(global->nl.cache,
-                                                  "nl80211");
-       if (global->nl80211 == NULL) {
+       global->nl80211_id = genl_ctrl_resolve(global->nl.handle, "nl80211");
+       if (global->nl80211_id < 0) {
                wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
                           "found");
                return -1;
@@ -2105,7 +2221,8 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
 {
        struct wpa_driver_nl80211_data *drv = ctx;
        wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
-       if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) {
+       if (linux_set_iface_flags(drv->global->ioctl_sock,
+                                 drv->first_bss.ifname, 1)) {
                wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
                           "after rfkill unblock");
                return;
@@ -2147,16 +2264,6 @@ static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
 }
 
 
-#ifdef CONFIG_AP
-static void nl80211_l2_read(void *ctx, const u8 *src_addr, const u8 *buf,
-                           size_t len)
-{
-       wpa_printf(MSG_DEBUG, "nl80211: l2_packet read %u",
-                  (unsigned int) len);
-}
-#endif /* CONFIG_AP */
-
-
 /**
  * wpa_driver_nl80211_init - Initialize nl80211 driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -2172,6 +2279,8 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        struct rfkill_config *rcfg;
        struct i802_bss *bss;
 
+       if (global_priv == NULL)
+               return NULL;
        drv = os_zalloc(sizeof(*drv));
        if (drv == NULL)
                return NULL;
@@ -2182,7 +2291,9 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
        os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
        drv->monitor_ifidx = -1;
        drv->monitor_sock = -1;
-       drv->ioctl_sock = -1;
+#ifdef CONFIG_AP
+       drv->eapol_tx_sock = -1;
+#endif /* CONFIG_AP */
        drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
        if (wpa_driver_nl80211_init_nl(drv)) {
@@ -2192,12 +2303,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
 
        nl80211_get_phy_name(drv);
 
-       drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-       if (drv->ioctl_sock < 0) {
-               perror("socket(PF_INET,SOCK_DGRAM)");
-               goto failed;
-       }
-
        rcfg = os_zalloc(sizeof(*rcfg));
        if (rcfg == NULL)
                goto failed;
@@ -2215,8 +2320,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                goto failed;
 
 #ifdef CONFIG_AP
-       drv->l2 = l2_packet_init(ifname, NULL, ETH_P_EAPOL,
-                                nl80211_l2_read, drv, 0);
+       drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
 #endif /* CONFIG_AP */
 
        if (drv->global) {
@@ -2308,6 +2412,14 @@ static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
        if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0)
                return -1;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_TDLS
+       if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
+               /* TDLS Discovery Response */
+               if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0e", 2) <
+                   0)
+                       return -1;
+       }
+#endif /* CONFIG_TDLS */
 
        /* FT Action frames */
        if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
@@ -2345,15 +2457,14 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
         * dynamically added interface (e.g., P2P) that was already configured
         * with proper iftype.
         */
-       if ((drv->global == NULL ||
-            drv->ifindex != drv->global->if_add_ifindex) &&
+       if (drv->ifindex != drv->global->if_add_ifindex &&
            wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
                wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
                           "use managed mode");
                return -1;
        }
 
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
                if (rfkill_is_blocked(drv->rfkill)) {
                        wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
                                   "interface '%s' due to rfkill",
@@ -2374,7 +2485,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
        if (wpa_driver_nl80211_capa(drv))
                return -1;
 
-       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr))
+       if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                              drv->addr))
                return -1;
 
        if (nl80211_register_action_frames(drv) < 0) {
@@ -2426,21 +2538,21 @@ static void wpa_driver_nl80211_deinit(void *priv)
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
 #ifdef CONFIG_AP
-       if (drv->l2)
-               l2_packet_deinit(drv->l2);
+       if (drv->eapol_tx_sock >= 0)
+               close(drv->eapol_tx_sock);
 #endif /* CONFIG_AP */
 
        if (drv->nl_preq.handle)
                wpa_driver_nl80211_probe_req_report(bss, 0);
        if (bss->added_if_into_bridge) {
-               if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
-                   < 0)
+               if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+                                   bss->ifname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "interface %s from bridge %s: %s",
                                   bss->ifname, bss->brname, strerror(errno));
        }
        if (bss->added_bridge) {
-               if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+               if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "bridge %s: %s",
                                   bss->brname, strerror(errno));
@@ -2469,7 +2581,7 @@ static void wpa_driver_nl80211_deinit(void *priv)
                os_free(drv->if_indices);
 #endif /* HOSTAPD */
 
-       if (drv->disable_11b_rates)
+       if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
        netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
@@ -2478,12 +2590,9 @@ static void wpa_driver_nl80211_deinit(void *priv)
 
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-       (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
+       (void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
        wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
 
-       if (drv->ioctl_sock >= 0)
-               close(drv->ioctl_sock);
-
        eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_event.handle));
        nl_destroy_handles(&drv->nl_event);
 
@@ -2589,6 +2698,8 @@ static int wpa_driver_nl80211_scan(void *priv,
                NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
                        "\x0c\x12\x18\x24\x30\x48\x60\x6c");
                nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+
+               NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -2932,7 +3043,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg)
                r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
        } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
                r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
-               r->flags |= WPA_SCAN_LEVEL_INVALID;
+               r->flags |= WPA_SCAN_QUAL_INVALID;
        } else
                r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
        if (bss[NL80211_BSS_TSF])
@@ -3073,20 +3184,6 @@ static void wpa_driver_nl80211_check_bss_status(
 }
 
 
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-       size_t i;
-
-       if (res == NULL)
-               return;
-
-       for (i = 0; i < res->num; i++)
-               os_free(res->res[i]);
-       os_free(res->res);
-       os_free(res);
-}
-
-
 static struct wpa_scan_results *
 nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
 {
@@ -3110,8 +3207,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
        ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
        msg = NULL;
        if (ret == 0) {
-               wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
-                          (unsigned long) res->num);
+               wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+                          "BSSes)", (unsigned long) res->num);
+               nl80211_get_noise_for_scan_results(drv, res);
                return res;
        }
        wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -3182,6 +3280,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
                   "set_tx=%d seq_len=%lu key_len=%lu",
                   __func__, ifindex, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
+#ifdef CONFIG_TDLS
+       if (key_idx == -1)
+               key_idx = 0;
+#endif /* CONFIG_TDLS */
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -3453,8 +3555,9 @@ static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed: reason=%u ret=%d (%s)",
+                       reason_code, ret, strerror(-ret));
                goto nla_put_failure;
        }
        ret = 0;
@@ -3593,8 +3696,9 @@ retry:
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed (auth): ret=%d (%s)",
+                       ret, strerror(-ret));
                count++;
                if (ret == -EALREADY && count == 1 && params->bssid &&
                    !params->local_state_change) {
@@ -3675,6 +3779,7 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
 
                mode = &phy_info->modes[*(phy_info->num_modes)];
                memset(mode, 0, sizeof(*mode));
+               mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
                *(phy_info->num_modes) += 1;
 
                nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
@@ -4104,7 +4209,7 @@ static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
 
 
 static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-                                       size_t data_len)
+                                       size_t data_len, int noack)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -4124,12 +4229,12 @@ static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
                 * of wpa_supplicant.
                 */
                return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
-                                             data, data_len, NULL);
+                                             data, data_len, NULL, 1);
        }
 
-       if (drv->no_monitor_iface_capab && is_ap_interface(drv->nlmode)) {
+       if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
                return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
-                                             data, data_len, NULL);
+                                             data, data_len, NULL, 0);
        }
 
        if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -4403,6 +4508,8 @@ static u32 sta_flags_nl80211(int flags)
                f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
        if (flags & WPA_STA_MFP)
                f |= BIT(NL80211_STA_FLAG_MFP);
+       if (flags & WPA_STA_TDLS_PEER)
+               f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
 
        return f;
 }
@@ -4417,19 +4524,26 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        struct nl80211_sta_flag_update upd;
        int ret = -ENOBUFS;
 
+       if ((params->flags & WPA_STA_TDLS_PEER) &&
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+               return -EOPNOTSUPP;
+
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_STATION);
+       nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
+                   NL80211_CMD_NEW_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
-       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
        NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
                params->supp_rates);
-       NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
-                   params->listen_interval);
+       if (!params->set) {
+               NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+                           params->listen_interval);
+       }
        if (params->ht_capabilities) {
                NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
                        sizeof(*params->ht_capabilities),
@@ -4443,8 +4557,9 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        if (ret)
-               wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
-                          "result: %d (%s)", ret, strerror(-ret));
+               wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+                          "result: %d (%s)", params->set ? "SET" : "NEW", ret,
+                          strerror(-ret));
        if (ret == -EEXIST)
                ret = 0;
  nla_put_failure:
@@ -4485,10 +4600,8 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
 
-#ifdef HOSTAPD
        /* stop listening for EAPOL on this interface */
        del_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -4580,13 +4693,11 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        if (ifidx <= 0)
                return -1;
 
-#ifdef HOSTAPD
        /* start listening for EAPOL on this interface */
        add_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
        if (addr && iftype != NL80211_IFTYPE_MONITOR &&
-           linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) {
+           linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
                nl80211_remove_iface(drv, ifidx);
                return -1;
        }
@@ -4615,7 +4726,7 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                                wds);
        }
 
-       if (ret >= 0 && drv->disable_11b_rates)
+       if (ret >= 0 && is_p2p_interface(iftype))
                nl80211_disable_11b_rates(drv, ret, 1);
 
        return ret;
@@ -4956,15 +5067,21 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
                                     0);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
+               /*
+                * This is backward compatibility for a few versions of
+                * the kernel only that didn't advertise the right
+                * attributes for the only driver that then supported
+                * AP mode w/o monitor -- ath6kl.
+                */
                wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
                           "monitor interface type - try to run without it");
-               drv->no_monitor_iface_capab = 1;
+               drv->device_ap_sme = 1;
        }
 
        if (drv->monitor_ifidx < 0)
                return -1;
 
-       if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
+       if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
                goto error;
 
        memset(&ll, 0, sizeof(ll));
@@ -5011,17 +5128,29 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 #ifdef CONFIG_AP
 static int nl80211_send_eapol_data(struct i802_bss *bss,
                                   const u8 *addr, const u8 *data,
-                                  size_t data_len, const u8 *own_addr)
+                                  size_t data_len)
 {
-       if (bss->drv->l2 == NULL) {
-               wpa_printf(MSG_DEBUG, "nl80211: No l2_packet to send EAPOL");
+       struct sockaddr_ll ll;
+       int ret;
+
+       if (bss->drv->eapol_tx_sock < 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
                return -1;
        }
 
-       if (l2_packet_send(bss->drv->l2, addr, ETH_P_EAPOL, data, data_len) <
-           0)
-               return -1;
-       return 0;
+       os_memset(&ll, 0, sizeof(ll));
+       ll.sll_family = AF_PACKET;
+       ll.sll_ifindex = bss->ifindex;
+       ll.sll_protocol = htons(ETH_P_PAE);
+       ll.sll_halen = ETH_ALEN;
+       os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+       ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+                    (struct sockaddr *) &ll, sizeof(ll));
+       if (ret < 0)
+               wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+                          strerror(errno));
+
+       return ret;
 }
 #endif /* CONFIG_AP */
 
@@ -5041,9 +5170,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
        int qos = flags & WPA_STA_WMM;
 
 #ifdef CONFIG_AP
-       if (drv->no_monitor_iface_capab)
-               return nl80211_send_eapol_data(bss, addr, data, data_len,
-                                              own_addr);
+       if (drv->device_ap_sme)
+               return nl80211_send_eapol_data(bss, addr, data, data_len);
 #endif /* CONFIG_AP */
 
        len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
@@ -5136,6 +5264,9 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
        if (total_flags & WPA_STA_MFP)
                NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
 
+       if (total_flags & WPA_STA_TDLS_PEER)
+               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+
        if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
                goto nla_put_failure;
 
@@ -5171,7 +5302,7 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
                return -1;
        }
 
-       if (drv->no_monitor_iface_capab) {
+       if (drv->device_ap_sme) {
                if (wpa_driver_nl80211_probe_req_report(&drv->first_bss, 1) < 0)
                {
                        wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
@@ -5629,8 +5760,9 @@ static int wpa_driver_nl80211_associate(
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-                          "(%s)", ret, strerror(-ret));
+               wpa_dbg(drv->ctx, MSG_DEBUG,
+                       "nl80211: MLME command failed (assoc): ret=%d (%s)",
+                       ret, strerror(-ret));
                nl80211_dump_scan(drv);
                goto nla_put_failure;
        }
@@ -5700,7 +5832,8 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                   "interface down");
        for (i = 0; i < 10; i++) {
                int res;
-               res = linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
+               res = linux_set_iface_flags(drv->global->ioctl_sock,
+                                           bss->ifname, 0);
                if (res == -EACCES || res == -ENODEV)
                        break;
                if (res == 0) {
@@ -5709,7 +5842,7 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                        ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
                        if (ret == -EACCES)
                                break;
-                       res = linux_set_iface_flags(drv->ioctl_sock,
+                       res = linux_set_iface_flags(drv->global->ioctl_sock,
                                                    bss->ifname, 1);
                        if (res && !ret)
                                ret = -1;
@@ -5731,18 +5864,26 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
 done:
        if (!ret && is_ap_interface(nlmode)) {
                /* Setup additional AP mode functionality if needed */
-               if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 &&
+               if (!drv->device_ap_sme && drv->monitor_ifidx < 0 &&
                    nl80211_create_monitor_interface(drv) &&
-                   !drv->no_monitor_iface_capab)
+                   !drv->device_ap_sme)
                        return -1;
        } else if (!ret && !is_ap_interface(nlmode)) {
                /* Remove additional AP mode functionality */
-               if (was_ap && drv->no_monitor_iface_capab)
+               if (was_ap && drv->device_ap_sme)
                        wpa_driver_nl80211_probe_req_report(bss, 0);
                nl80211_remove_monitor_interface(drv);
                bss->beacon_set = 0;
        }
 
+       if (!ret && is_p2p_interface(drv->nlmode)) {
+               nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+               drv->disabled_11b_rates = 1;
+       } else if (!ret && drv->disabled_11b_rates) {
+               nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+               drv->disabled_11b_rates = 0;
+       }
+
        if (ret)
                wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
                           "from %d failed", nlmode, drv->nlmode);
@@ -6187,7 +6328,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
        mgmt.u.deauth.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
-                                           sizeof(mgmt.u.deauth));
+                                           sizeof(mgmt.u.deauth), 0);
 }
 
 
@@ -6206,7 +6347,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
        mgmt.u.disassoc.reason_code = host_to_le16(reason);
        return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
                                            IEEE80211_HDRLEN +
-                                           sizeof(mgmt.u.disassoc));
+                                           sizeof(mgmt.u.disassoc), 0);
 }
 
 #endif /* HOSTAPD || CONFIG_AP */
@@ -6293,11 +6434,11 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                                                 NULL, 1) < 0)
                                return -1;
                        if (bridge_ifname &&
-                           linux_br_add_if(drv->ioctl_sock, bridge_ifname,
-                                           name) < 0)
+                           linux_br_add_if(drv->global->ioctl_sock,
+                                           bridge_ifname, name) < 0)
                                return -1;
                }
-               linux_set_iface_flags(drv->ioctl_sock, name, 1);
+               linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
                return i802_set_sta_vlan(priv, addr, name, 0);
        } else {
                i802_set_sta_vlan(priv, addr, bss->ifname, 0);
@@ -6341,7 +6482,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
                 * Bridge was configured, but the bridge device does
                 * not exist. Try to add it now.
                 */
-               if (linux_br_add(drv->ioctl_sock, brname) < 0) {
+               if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
                        wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
                                   "bridge interface %s: %s",
                                   brname, strerror(errno));
@@ -6357,7 +6498,8 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
 
                wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
                           "bridge %s", ifname, in_br);
-               if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) {
+               if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
+                   0) {
                        wpa_printf(MSG_ERROR, "nl80211: Failed to "
                                   "remove interface %s from bridge "
                                   "%s: %s",
@@ -6368,7 +6510,7 @@ static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
                   ifname, brname);
-       if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
+       if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
                wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
                           "into bridge %s: %s",
                           ifname, brname, strerror(errno));
@@ -6426,11 +6568,11 @@ static void *i802_init(struct hostapd_data *hapd,
        /* start listening for EAPOL on the default AP interface */
        add_ifidx(drv, drv->ifindex);
 
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
+       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
                goto failed;
 
        if (params->bssid) {
-               if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
+               if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
                                       params->bssid))
                        goto failed;
        }
@@ -6445,7 +6587,7 @@ static void *i802_init(struct hostapd_data *hapd,
            i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
                goto failed;
 
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
+       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
                goto failed;
 
        drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
@@ -6460,7 +6602,8 @@ static void *i802_init(struct hostapd_data *hapd,
                goto failed;
        }
 
-       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
+       if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                              params->own_addr))
                goto failed;
 
        return bss;
@@ -6572,7 +6715,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        }
 
        if (!addr &&
-           linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) {
+           linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                              if_addr) < 0) {
                nl80211_remove_iface(drv, ifidx);
                return -1;
        }
@@ -6584,10 +6728,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                /* Enforce unique P2P Interface Address */
                u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
 
-               if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr)
-                   < 0 ||
-                   linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0)
-               {
+               if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                                      own_addr) < 0 ||
+                   linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+                                      new_addr) < 0) {
                        nl80211_remove_iface(drv, ifidx);
                        return -1;
                }
@@ -6598,7 +6742,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                                nl80211_remove_iface(drv, ifidx);
                                return -1;
                        }
-                       if (linux_set_ifhwaddr(drv->ioctl_sock, ifname,
+                       if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
                                               new_addr) < 0) {
                                nl80211_remove_iface(drv, ifidx);
                                return -1;
@@ -6619,7 +6763,8 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        }
 
        if (type == WPA_IF_AP_BSS) {
-               if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
+               if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
+               {
                        nl80211_remove_iface(drv, ifidx);
                        os_free(new_bss);
                        return -1;
@@ -6656,14 +6801,14 @@ static int wpa_driver_nl80211_if_remove(void *priv,
 
 #ifdef HOSTAPD
        if (bss->added_if_into_bridge) {
-               if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
-                   < 0)
+               if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+                                   bss->ifname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "interface %s from bridge %s: %s",
                                   bss->ifname, bss->brname, strerror(errno));
        }
        if (bss->added_bridge) {
-               if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+               if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
                        wpa_printf(MSG_INFO, "nl80211: Failed to remove "
                                   "bridge %s: %s",
                                   bss->brname, strerror(errno));
@@ -6713,7 +6858,7 @@ static int cookie_handler(struct nl_msg *msg, void *arg)
 static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
                                  unsigned int freq, unsigned int wait,
                                  const u8 *buf, size_t buf_len,
-                                 u64 *cookie_out)
+                                 u64 *cookie_out, int no_cck)
 {
        struct nl_msg *msg;
        u64 cookie;
@@ -6730,6 +6875,9 @@ static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
        NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+       if (no_cck)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+
        NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
 
        cookie = 0;
@@ -6757,7 +6905,8 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
                                          unsigned int wait_time,
                                          const u8 *dst, const u8 *src,
                                          const u8 *bssid,
-                                         const u8 *data, size_t data_len)
+                                         const u8 *data, size_t data_len,
+                                         int no_cck)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6766,7 +6915,7 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
        struct ieee80211_hdr *hdr;
 
        wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
-                  "wait=%d ms)", drv->ifindex, wait_time);
+                  "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck);
 
        buf = os_zalloc(24 + data_len);
        if (buf == NULL)
@@ -6780,11 +6929,13 @@ static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
        os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
        if (is_ap_interface(drv->nlmode))
-               ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
+               ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len,
+                                                  0);
        else
                ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf,
                                             24 + data_len,
-                                            &drv->send_action_cookie);
+                                            &drv->send_action_cookie,
+                                            no_cck);
 
        os_free(buf);
        return ret;
@@ -6958,8 +7109,10 @@ static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
        band = nla_nest_start(msg, NL80211_BAND_2GHZ);
        if (!band)
                goto nla_put_failure;
-       NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
-               "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+       if (disabled) {
+               NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
+                       "\x0c\x12\x18\x24\x30\x48\x60\x6c");
+       }
        nla_nest_end(msg, band);
 
        nla_nest_end(msg, bands);
@@ -6979,15 +7132,6 @@ nla_put_failure:
 }
 
 
-static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
-{
-       struct i802_bss *bss = priv;
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       drv->disable_11b_rates = disabled;
-       return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
-}
-
-
 static int wpa_driver_nl80211_deinit_ap(void *priv)
 {
        struct i802_bss *bss = priv;
@@ -7003,7 +7147,7 @@ static void wpa_driver_nl80211_resume(void *priv)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+       if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
                wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
                           "resume event");
        }
@@ -7020,7 +7164,8 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
        size_t data_len;
        u8 own_addr[ETH_ALEN];
 
-       if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
+       if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                              own_addr) < 0)
                return -1;
 
        if (action != 1) {
@@ -7053,7 +7198,7 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
 
        ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
                                             drv->bssid, own_addr, drv->bssid,
-                                            data, data_len);
+                                            data, data_len, 0);
        os_free(data);
 
        return ret;
@@ -7112,6 +7257,44 @@ 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->addr));
+               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)
 {
@@ -7151,6 +7334,7 @@ static void * nl80211_global_init(void)
        global = os_zalloc(sizeof(*global));
        if (global == NULL)
                return NULL;
+       global->ioctl_sock = -1;
        dl_list_init(&global->interfaces);
        global->if_add_ifindex = -1;
 
@@ -7170,6 +7354,12 @@ static void * nl80211_global_init(void)
        if (wpa_driver_nl80211_init_nl_global(global) < 0)
                goto err;
 
+       global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+       if (global->ioctl_sock < 0) {
+               perror("socket(PF_INET,SOCK_DGRAM)");
+               goto err;
+       }
+
        return global;
 
 err:
@@ -7192,13 +7382,14 @@ static void nl80211_global_deinit(void *priv)
        if (global->netlink)
                netlink_deinit(global->netlink);
 
-       if (global->nl80211)
-               genl_family_put(global->nl80211);
        nl_destroy_handles(&global->nl);
 
        if (global->nl_cb)
                nl_cb_put(global->nl_cb);
 
+       if (global->ioctl_sock >= 0)
+               close(global->ioctl_sock);
+
        os_free(global);
 }
 
@@ -7293,10 +7484,11 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
 }
 
 
-static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
-                               int qos)
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+                                   const u8 *addr, int qos)
 {
-       struct i802_bss *bss = priv;
+       /* send data frame to poll STA and check whether
+        * this frame is ACKed */
        struct {
                struct ieee80211_hdr hdr;
                u16 qos_ctl;
@@ -7324,11 +7516,127 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
        os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
        os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
-       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size) < 0)
+       if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
                wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
                           "send poll frame");
 }
 
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+                               int qos)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       if (!drv->poll_command_supported) {
+               nl80211_send_null_frame(bss, own_addr, addr, qos);
+               return;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+       send_and_recv_msgs(drv, msg, NULL, NULL);
+       return;
+ nla_put_failure:
+       nlmsg_free(msg);
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
+                                 u8 dialog_token, u16 status_code,
+                                 const u8 *buf, size_t len)
+{
+       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))
+               return -EOPNOTSUPP;
+
+       if (!dst)
+               return -EINVAL;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+       NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
+       NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
+       NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+       NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
+static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       enum nl80211_tdls_operation nl80211_oper;
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+               return -EOPNOTSUPP;
+
+       switch (oper) {
+       case TDLS_DISCOVERY_REQ:
+               nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
+               break;
+       case TDLS_SETUP:
+               nl80211_oper = NL80211_TDLS_SETUP;
+               break;
+       case TDLS_TEARDOWN:
+               nl80211_oper = NL80211_TDLS_TEARDOWN;
+               break;
+       case TDLS_ENABLE_LINK:
+               nl80211_oper = NL80211_TDLS_ENABLE_LINK;
+               break;
+       case TDLS_DISABLE_LINK:
+               nl80211_oper = NL80211_TDLS_DISABLE_LINK;
+               break;
+       case TDLS_ENABLE:
+               return 0;
+       case TDLS_DISABLE:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
+       NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+#endif /* CONFIG TDLS */
+
 
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
@@ -7387,13 +7695,13 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .cancel_remain_on_channel =
        wpa_driver_nl80211_cancel_remain_on_channel,
        .probe_req_report = wpa_driver_nl80211_probe_req_report,
-       .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
        .deinit_ap = wpa_driver_nl80211_deinit_ap,
        .resume = wpa_driver_nl80211_resume,
        .send_ft_action = nl80211_send_ft_action,
        .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,
@@ -7401,4 +7709,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .flush_pmkid = nl80211_flush_pmkid,
        .set_rekey_info = nl80211_set_rekey_info,
        .poll_client = nl80211_poll_client,
+#ifdef CONFIG_TDLS
+       .send_tdls_mgmt = nl80211_send_tdls_mgmt,
+       .tdls_oper = nl80211_tdls_oper,
+#endif /* CONFIG_TDLS */
 };