nl80211: Add support for P2P Device in add interface
[mech_eap.git] / src / drivers / driver_nl80211.c
index 0433ca6..a9a9c4a 100644 (file)
 
 #ifdef ANDROID
 #include "android_drv.h"
-
-/* system/core/libnl_2 in AOSP does not include nla_put_u32() */
-int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
-{
-       return nla_put(msg, attrtype, sizeof(uint32_t), &value);
-}
 #endif /* ANDROID */
 #ifdef CONFIG_LIBNL20
 /* libnl 2.0 compatibility code */
@@ -189,12 +183,14 @@ struct i802_bss {
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *next;
        int ifindex;
+       u64 wdev_id;
        char ifname[IFNAMSIZ + 1];
        char brname[IFNAMSIZ];
        unsigned int beacon_set:1;
        unsigned int added_if_into_bridge:1;
        unsigned int added_bridge:1;
        unsigned int in_deinit:1;
+       unsigned int wdev_id_set:1;
 
        u8 addr[ETH_ALEN];
 
@@ -231,7 +227,9 @@ struct wpa_driver_nl80211_data {
        struct nl_cb *nl_cb;
 
        u8 auth_bssid[ETH_ALEN];
+       u8 auth_attempt_bssid[ETH_ALEN];
        u8 bssid[ETH_ALEN];
+       u8 prev_bssid[ETH_ALEN];
        int associated;
        u8 ssid[32];
        size_t ssid_len;
@@ -349,6 +347,117 @@ static int wpa_driver_nl80211_authenticate_retry(
        struct wpa_driver_nl80211_data *drv);
 
 
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+       switch (cmd) {
+       C2S(NL80211_CMD_UNSPEC)
+       C2S(NL80211_CMD_GET_WIPHY)
+       C2S(NL80211_CMD_SET_WIPHY)
+       C2S(NL80211_CMD_NEW_WIPHY)
+       C2S(NL80211_CMD_DEL_WIPHY)
+       C2S(NL80211_CMD_GET_INTERFACE)
+       C2S(NL80211_CMD_SET_INTERFACE)
+       C2S(NL80211_CMD_NEW_INTERFACE)
+       C2S(NL80211_CMD_DEL_INTERFACE)
+       C2S(NL80211_CMD_GET_KEY)
+       C2S(NL80211_CMD_SET_KEY)
+       C2S(NL80211_CMD_NEW_KEY)
+       C2S(NL80211_CMD_DEL_KEY)
+       C2S(NL80211_CMD_GET_BEACON)
+       C2S(NL80211_CMD_SET_BEACON)
+       C2S(NL80211_CMD_START_AP)
+       C2S(NL80211_CMD_STOP_AP)
+       C2S(NL80211_CMD_GET_STATION)
+       C2S(NL80211_CMD_SET_STATION)
+       C2S(NL80211_CMD_NEW_STATION)
+       C2S(NL80211_CMD_DEL_STATION)
+       C2S(NL80211_CMD_GET_MPATH)
+       C2S(NL80211_CMD_SET_MPATH)
+       C2S(NL80211_CMD_NEW_MPATH)
+       C2S(NL80211_CMD_DEL_MPATH)
+       C2S(NL80211_CMD_SET_BSS)
+       C2S(NL80211_CMD_SET_REG)
+       C2S(NL80211_CMD_REQ_SET_REG)
+       C2S(NL80211_CMD_GET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+       C2S(NL80211_CMD_GET_REG)
+       C2S(NL80211_CMD_GET_SCAN)
+       C2S(NL80211_CMD_TRIGGER_SCAN)
+       C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCAN_ABORTED)
+       C2S(NL80211_CMD_REG_CHANGE)
+       C2S(NL80211_CMD_AUTHENTICATE)
+       C2S(NL80211_CMD_ASSOCIATE)
+       C2S(NL80211_CMD_DEAUTHENTICATE)
+       C2S(NL80211_CMD_DISASSOCIATE)
+       C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+       C2S(NL80211_CMD_REG_BEACON_HINT)
+       C2S(NL80211_CMD_JOIN_IBSS)
+       C2S(NL80211_CMD_LEAVE_IBSS)
+       C2S(NL80211_CMD_TESTMODE)
+       C2S(NL80211_CMD_CONNECT)
+       C2S(NL80211_CMD_ROAM)
+       C2S(NL80211_CMD_DISCONNECT)
+       C2S(NL80211_CMD_SET_WIPHY_NETNS)
+       C2S(NL80211_CMD_GET_SURVEY)
+       C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+       C2S(NL80211_CMD_SET_PMKSA)
+       C2S(NL80211_CMD_DEL_PMKSA)
+       C2S(NL80211_CMD_FLUSH_PMKSA)
+       C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+       C2S(NL80211_CMD_REGISTER_FRAME)
+       C2S(NL80211_CMD_FRAME)
+       C2S(NL80211_CMD_FRAME_TX_STATUS)
+       C2S(NL80211_CMD_SET_POWER_SAVE)
+       C2S(NL80211_CMD_GET_POWER_SAVE)
+       C2S(NL80211_CMD_SET_CQM)
+       C2S(NL80211_CMD_NOTIFY_CQM)
+       C2S(NL80211_CMD_SET_CHANNEL)
+       C2S(NL80211_CMD_SET_WDS_PEER)
+       C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+       C2S(NL80211_CMD_JOIN_MESH)
+       C2S(NL80211_CMD_LEAVE_MESH)
+       C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+       C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+       C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+       C2S(NL80211_CMD_GET_WOWLAN)
+       C2S(NL80211_CMD_SET_WOWLAN)
+       C2S(NL80211_CMD_START_SCHED_SCAN)
+       C2S(NL80211_CMD_STOP_SCHED_SCAN)
+       C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+       C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+       C2S(NL80211_CMD_PMKSA_CANDIDATE)
+       C2S(NL80211_CMD_TDLS_OPER)
+       C2S(NL80211_CMD_TDLS_MGMT)
+       C2S(NL80211_CMD_UNEXPECTED_FRAME)
+       C2S(NL80211_CMD_PROBE_CLIENT)
+       C2S(NL80211_CMD_REGISTER_BEACONS)
+       C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+       C2S(NL80211_CMD_SET_NOACK_MAP)
+       C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+       C2S(NL80211_CMD_START_P2P_DEVICE)
+       C2S(NL80211_CMD_STOP_P2P_DEVICE)
+       C2S(NL80211_CMD_CONN_FAILED)
+       C2S(NL80211_CMD_SET_MCAST_RATE)
+       C2S(NL80211_CMD_SET_MAC_ACL)
+       C2S(NL80211_CMD_RADAR_DETECT)
+       C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+       C2S(NL80211_CMD_UPDATE_FT_IES)
+       C2S(NL80211_CMD_FT_EVENT)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+       default:
+               return "NL80211_CMD_UNKNOWN";
+       }
+#undef C2S
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_AP ||
@@ -363,13 +472,22 @@ static int is_sta_interface(enum nl80211_iftype nlmode)
 }
 
 
-static int is_p2p_interface(enum nl80211_iftype nlmode)
+static int is_p2p_net_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
                nlmode == NL80211_IFTYPE_P2P_GO);
 }
 
 
+static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+{
+       if (drv->associated)
+               os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+       drv->associated = 0;
+       os_memset(drv->bssid, 0, ETH_ALEN);
+}
+
+
 struct nl80211_bss_info_arg {
        struct wpa_driver_nl80211_data *drv;
        struct wpa_scan_results *res;
@@ -471,6 +589,19 @@ struct family_data {
 };
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+       if (bss->wdev_id_set)
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+       else
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
+
 static int family_handler(struct nl_msg *msg, void *arg)
 {
        struct family_data *res = arg;
@@ -1044,6 +1175,7 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
        }
 
        os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+       os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
        os_memset(&event, 0, sizeof(event));
        os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
        event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
@@ -1123,6 +1255,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
 
        drv->associated = 1;
        os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+       os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
 
        os_memset(&event, 0, sizeof(event));
        if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
@@ -1174,8 +1307,10 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
        }
 
        drv->associated = 1;
-       if (addr)
+       if (addr) {
                os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+               os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+       }
 
        if (req_ie) {
                event.assoc_info.req_ies = nla_data(req_ie);
@@ -1222,7 +1357,7 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
        }
 
        wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(&data, 0, sizeof(data));
        if (reason)
                data.deauth_info.reason_code = nla_get_u16(reason);
@@ -1391,6 +1526,22 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
        if (len >= 24) {
                bssid = mgmt->bssid;
 
+               if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+                   !drv->associated &&
+                   os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+                   os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+                   os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+                       /*
+                        * Avoid issues with some roaming cases where
+                        * disconnection event for the old AP may show up after
+                        * we have started connection with the new AP.
+                        */
+                       wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+                                  MAC2STR(bssid),
+                                  MAC2STR(drv->auth_attempt_bssid));
+                       return;
+               }
+
                if (drv->associated != 0 &&
                    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
                    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
@@ -1406,7 +1557,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
                }
        }
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(&event, 0, sizeof(event));
 
        /* Note: Same offset for Reason Code in both frame subtypes */
@@ -1492,24 +1643,29 @@ static void mlme_event(struct i802_bss *bss,
        }
 
        if (frame == NULL) {
-               wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
-                          "data", cmd);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: MLME event %d (%s) without frame data",
+                          cmd, nl80211_command_to_string(cmd));
                return;
        }
 
        data = nla_data(frame);
        len = nla_len(frame);
-       if (len < 4 + ETH_ALEN) {
-               wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d on %s(" MACSTR
-                          ") - too short",
-                          cmd, bss->ifname, MAC2STR(bss->addr));
+       if (len < 4 + 2 * ETH_ALEN) {
+               wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+                          MACSTR ") - too short",
+                          cmd, nl80211_command_to_string(cmd), bss->ifname,
+                          MAC2STR(bss->addr));
                return;
        }
-       wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d on %s(" MACSTR ") A1="
-                  MACSTR, cmd, bss->ifname, MAC2STR(bss->addr),
-                  MAC2STR(data + 4));
+       wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+                  ") A1=" MACSTR " A2=" MACSTR, cmd,
+                  nl80211_command_to_string(cmd), bss->ifname,
+                  MAC2STR(bss->addr), MAC2STR(data + 4),
+                  MAC2STR(data + 4 + ETH_ALEN));
        if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
-           os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0) {
+           os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+           os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
                wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
                           "for foreign address", bss->ifname);
                return;
@@ -1739,6 +1895,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
        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 },
        };
        struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
        static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1761,6 +1918,12 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
        sig_change->current_signal =
                (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
 
+       if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
+               sig_change->avg_signal =
+                       (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
+       else
+               sig_change->avg_signal = 0;
+
        if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
                if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
                                     sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -2240,6 +2403,43 @@ static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+                               struct nlattr **tb)
+{
+       union wpa_event_data data;
+       enum nl80211_radar_event event_type;
+
+       if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+               return;
+
+       os_memset(&data, 0, sizeof(data));
+       data.dfs_event.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
+       event_type = nla_get_u8(tb[NL80211_ATTR_RADAR_EVENT]);
+
+       wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+                  data.dfs_event.freq);
+
+       switch (event_type) {
+       case NL80211_RADAR_DETECTED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+               break;
+       case NL80211_RADAR_CAC_FINISHED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+               break;
+       case NL80211_RADAR_CAC_ABORTED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+               break;
+       case NL80211_RADAR_NOP_FINISHED:
+               wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+                          "received", event_type);
+               break;
+       }
+}
+
+
 static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
                                   int wds)
 {
@@ -2263,6 +2463,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+                  cmd, nl80211_command_to_string(cmd), bss->ifname);
+
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
            (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
             cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2384,6 +2587,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        case NL80211_CMD_FT_EVENT:
                mlme_event_ft_event(drv, tb);
                break;
+       case NL80211_CMD_RADAR_DETECT:
+               nl80211_radar_event(drv, tb);
+               break;
        default:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
                        "(cmd=%d)", cmd);
@@ -2403,19 +2609,31 @@ static int process_drv_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
-       if (tb[NL80211_ATTR_IFINDEX])
+       if (tb[NL80211_ATTR_IFINDEX]) {
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-       for (bss = &drv->first_bss; bss; bss = bss->next) {
-               if (ifidx == -1 || ifidx == bss->ifindex) {
-                       do_process_drv_event(bss, gnlh->cmd, tb);
-                       return NL_SKIP;
+               for (bss = &drv->first_bss; bss; bss = bss->next)
+                       if (ifidx == -1 || ifidx == bss->ifindex) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
+                          gnlh->cmd, ifidx);
+       } else if (tb[NL80211_ATTR_WDEV]) {
+               u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
+               for (bss = &drv->first_bss; bss; bss = bss->next) {
+                       if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
+                               do_process_drv_event(bss, gnlh->cmd, tb);
+                               return NL_SKIP;
+                       }
                }
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
+                          gnlh->cmd, (long long unsigned int) wdev_id);
        }
 
-       wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
-                  "interface (ifindex %d)", gnlh->cmd, ifidx);
-
        return NL_SKIP;
 }
 
@@ -2428,17 +2646,26 @@ static int process_global_event(struct nl_msg *msg, void *arg)
        struct wpa_driver_nl80211_data *drv, *tmp;
        int ifidx = -1;
        struct i802_bss *bss;
+       u64 wdev_id;
+       int wdev_id_set = 0;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
        if (tb[NL80211_ATTR_IFINDEX])
                ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+       else if (tb[NL80211_ATTR_WDEV]) {
+               wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+               wdev_id_set = 1;
+       }
 
        dl_list_for_each_safe(drv, tmp, &global->interfaces,
                              struct wpa_driver_nl80211_data, list) {
                for (bss = &drv->first_bss; bss; bss = bss->next) {
-                       if (ifidx == -1 || ifidx == bss->ifindex) {
+                       if ((ifidx == -1 && !wdev_id_set) ||
+                           ifidx == bss->ifindex ||
+                           (wdev_id_set && bss->wdev_id_set &&
+                            wdev_id == bss->wdev_id)) {
                                do_process_drv_event(bss, gnlh->cmd, tb);
                                return NL_SKIP;
                        }
@@ -2458,6 +2685,10 @@ static int process_bss_event(struct nl_msg *msg, void *arg)
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
 
+       wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+                  gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+                  bss->ifname);
+
        switch (gnlh->cmd) {
        case NL80211_CMD_FRAME:
        case NL80211_CMD_FRAME_TX_STATUS:
@@ -2618,6 +2849,10 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
                case NL80211_IFTYPE_ADHOC:
                        info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
                        break;
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       info->capa->flags |=
+                               WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+                       break;
                case NL80211_IFTYPE_P2P_GO:
                        info->p2p_go_supported = 1;
                        break;
@@ -2646,6 +2881,7 @@ static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
                [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
                [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
                [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+               [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
        },
        iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
                [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
@@ -2659,6 +2895,9 @@ static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
            !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
                return 0; /* broken combination */
 
+       if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+               info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
+
        nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
                            rem_limit) {
                err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
@@ -2823,6 +3062,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                capa->max_match_sets =
                        nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
 
+       if (tb[NL80211_ATTR_MAC_ACL_MAX])
+               capa->max_acl_mac_addrs =
+                       nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
        wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
        wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
        wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
@@ -3393,7 +3636,9 @@ static int nl80211_register_frame(struct i802_bss *bss,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
        NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
@@ -3813,7 +4058,7 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 
 static struct nl_msg *
 nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-                   struct wpa_driver_scan_params *params)
+                   struct wpa_driver_scan_params *params, u64 *wdev_id)
 {
        struct nl_msg *msg;
        size_t i;
@@ -3824,8 +4069,10 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
 
        nl80211_cmd(drv, msg, 0, cmd);
 
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
-               goto fail;
+       if (!wdev_id)
+               NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       else
+               NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
 
        if (params->num_ssids) {
                struct nlattr *ssids;
@@ -3874,6 +4121,7 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
        return msg;
 
 fail:
+nla_put_failure:
        nlmsg_free(msg);
        return NULL;
 }
@@ -3895,7 +4143,8 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
        wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
        drv->scan_for_auth = 0;
 
-       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+       msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
        if (!msg)
                return -1;
 
@@ -3998,7 +4247,8 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                return android_pno_start(bss, params);
 #endif /* ANDROID */
 
-       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+       msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
+                                 bss->wdev_id_set ? &bss->wdev_id : NULL);
        if (!msg)
                goto nla_put_failure;
 
@@ -4476,9 +4726,9 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        struct nl_msg *msg;
        int ret;
 
-       wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+       wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
                   "set_tx=%d seq_len=%lu key_len=%lu",
-                  __func__, ifindex, alg, addr, key_idx, set_tx,
+                  __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
                   (unsigned long) seq_len, (unsigned long) key_len);
 #ifdef CONFIG_TDLS
        if (key_idx == -1)
@@ -4778,7 +5028,7 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
                                         int reason_code)
 {
        wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        drv->ignore_next_local_disconnect = 0;
        /* Disconnect command doesn't need BSSID - it uses cached value */
        return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
@@ -4794,7 +5044,7 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
                return wpa_driver_nl80211_disconnect(drv, reason_code);
        wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
                   __func__, MAC2STR(addr), reason_code);
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        if (drv->nlmode == NL80211_IFTYPE_ADHOC)
                return nl80211_leave_ibss(drv);
        return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
@@ -4862,8 +5112,12 @@ static int wpa_driver_nl80211_authenticate(
        is_retry = drv->retry_auth;
        drv->retry_auth = 0;
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
        os_memset(drv->auth_bssid, 0, ETH_ALEN);
+       if (params->bssid)
+               os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
+       else
+               os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
        /* FIX: IBSS mode */
        nlmode = params->p2p ?
                NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
@@ -5124,6 +5378,22 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
            !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
                chan->max_tx_power = nla_get_u32(
                        tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+               enum nl80211_dfs_state state =
+                       nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+
+               switch (state) {
+               case NL80211_DFS_USABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+                       break;
+               case NL80211_DFS_AVAILABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+                       break;
+               case NL80211_DFS_UNAVAILABLE:
+                       chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+                       break;
+               }
+       }
 }
 
 
@@ -5137,6 +5407,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
                [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
                [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
                [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+               [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
        };
        int new_channels = 0;
        struct hostapd_channel_data *channel;
@@ -5757,6 +6028,60 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
 }
 
 
+static int wpa_driver_nl80211_set_acl(void *priv,
+                                     struct hostapd_acl_params *params)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *acl;
+       unsigned int i;
+       int ret = 0;
+
+       if (!(drv->capa.max_acl_mac_addrs))
+               return -ENOTSUP;
+
+       if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
+               return -ENOTSUP;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
+                  params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+                   NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+                   NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
+
+       acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
+       if (acl == NULL)
+               goto nla_put_failure;
+
+       for (i = 0; i < params->num_mac_acl; i++)
+               NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+
+       nla_nest_end(msg, acl);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
+                          ret, strerror(-ret));
+       }
+
+nla_put_failure:
+       nlmsg_free(msg);
+
+       return ret;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -6076,12 +6401,25 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        wpa_hexdump(MSG_DEBUG, "  * supported rates", params->supp_rates,
                    params->supp_rates_len);
        if (!params->set) {
-               wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
-               NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               if (params->aid) {
+                       wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
+                       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+               } else {
+                       /*
+                        * cfg80211 validates that AID is non-zero, so we have
+                        * to make this a non-zero value for the TDLS case where
+                        * a dummy STA entry is used for now.
+                        */
+                       wpa_printf(MSG_DEBUG, "  * aid=1 (TDLS workaround)");
+                       NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+               }
                wpa_printf(MSG_DEBUG, "  * listen_interval=%u",
                           params->listen_interval);
                NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
                            params->listen_interval);
+       } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
+               wpa_printf(MSG_DEBUG, "  * peer_aid=%u", params->aid);
+               NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
        }
        if (params->ht_capabilities) {
                wpa_hexdump(MSG_DEBUG, "  * ht_capabilities",
@@ -6208,12 +6546,20 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
                return "STATION";
        case NL80211_IFTYPE_AP:
                return "AP";
+       case NL80211_IFTYPE_AP_VLAN:
+               return "AP_VLAN";
+       case NL80211_IFTYPE_WDS:
+               return "WDS";
        case NL80211_IFTYPE_MONITOR:
                return "MONITOR";
+       case NL80211_IFTYPE_MESH_POINT:
+               return "MESH_POINT";
        case NL80211_IFTYPE_P2P_CLIENT:
                return "P2P_CLIENT";
        case NL80211_IFTYPE_P2P_GO:
                return "P2P_GO";
+       case NL80211_IFTYPE_P2P_DEVICE:
+               return "P2P_DEVICE";
        default:
                return "unknown";
        }
@@ -6223,7 +6569,9 @@ static const char * nl80211_iftype_str(enum nl80211_iftype mode)
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                                     const char *ifname,
                                     enum nl80211_iftype iftype,
-                                    const u8 *addr, int wds)
+                                    const u8 *addr, int wds,
+                                    int (*handler)(struct nl_msg *, void *),
+                                    void *arg)
 {
        struct nl_msg *msg;
        int ifidx;
@@ -6255,7 +6603,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
        }
 
-       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       ret = send_and_recv_msgs(drv, msg, handler, arg);
        msg = NULL;
        if (ret) {
  nla_put_failure:
@@ -6265,6 +6613,13 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                return ret;
        }
 
+       if (iftype == NL80211_IFTYPE_P2P_DEVICE) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: New P2P Device interface %s created",
+                          ifname);
+               return 0;
+       }
+
        ifidx = if_nametoindex(ifname);
        wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
                   ifname, ifidx);
@@ -6287,11 +6642,14 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 
 static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
                                const char *ifname, enum nl80211_iftype iftype,
-                               const u8 *addr, int wds)
+                               const u8 *addr, int wds,
+                               int (*handler)(struct nl_msg *, void *),
+                               void *arg)
 {
        int ret;
 
-       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
+                                       arg);
 
        /* if error occurred and interface exists already */
        if (ret == -ENFILE && if_nametoindex(ifname)) {
@@ -6302,10 +6660,10 @@ static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
 
                /* Try to create the interface again */
                ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-                                               wds);
+                                               wds, handler, arg);
        }
 
-       if (ret >= 0 && is_p2p_interface(iftype))
+       if (ret >= 0 && is_p2p_net_interface(iftype))
                nl80211_disable_11b_rates(drv, ret, 1);
 
        return ret;
@@ -6652,7 +7010,7 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
 
        drv->monitor_ifidx =
                nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-                                    0);
+                                    0, NULL, NULL);
 
        if (drv->monitor_ifidx == -EOPNOTSUPP) {
                /*
@@ -7335,7 +7693,7 @@ static int wpa_driver_nl80211_associate(
                return wpa_driver_nl80211_connect(drv, params);
        }
 
-       drv->associated = 0;
+       nl80211_mark_disconnected(drv);
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -7586,7 +7944,7 @@ done:
                return ret;
        }
 
-       if (is_p2p_interface(nlmode))
+       if (is_p2p_net_interface(nlmode))
                nl80211_disable_11b_rates(drv, drv->ifindex, 1);
        else if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -7649,6 +8007,9 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
        struct nl_msg *msg;
        struct nl80211_sta_flag_update upd;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
+                  MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
+
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
@@ -8160,7 +8521,7 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
                if (!if_nametoindex(name)) {
                        if (nl80211_create_iface(drv, name,
                                                 NL80211_IFTYPE_AP_VLAN,
-                                                bss->addr, 1) < 0)
+                                                bss->addr, 1, NULL, NULL) < 0)
                                return -1;
                        if (bridge_ifname &&
                            linux_br_add_if(drv->global->ioctl_sock,
@@ -8376,6 +8737,8 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
                return NL80211_IFTYPE_AP;
        case WPA_IF_P2P_GO:
                return NL80211_IFTYPE_P2P_GO;
+       case WPA_IF_P2P_DEVICE:
+               return NL80211_IFTYPE_P2P_DEVICE;
        }
        return -1;
 }
@@ -8445,7 +8808,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                os_memcpy(if_addr, addr, ETH_ALEN);
        ifidx = nl80211_create_iface(drv, ifname,
                                     wpa_driver_nl80211_if_type(type), addr,
-                                    0);
+                                    0, NULL, NULL);
        if (ifidx < 0) {
 #ifdef HOSTAPD
                os_free(new_bss);
@@ -8622,7 +8985,9 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
                   freq, wait, no_cck, no_ack, offchanok);
        nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        if (wait)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
@@ -8744,7 +9109,9 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
@@ -8791,7 +9158,9 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
 
        nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_set_iface_id(msg, bss))
+               goto nla_put_failure;
+
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8921,6 +9290,18 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
 }
 
 
+static int wpa_driver_nl80211_stop_ap(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       if (!is_ap_interface(drv->nlmode))
+               return -1;
+       wpa_driver_nl80211_del_beacon(drv);
+       bss->beacon_set = 0;
+       return 0;
+}
+
+
 static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
 {
        struct i802_bss *bss = priv;
@@ -9025,6 +9406,75 @@ nla_put_failure:
 }
 
 
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+       switch (width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               return CHAN_WIDTH_20_NOHT;
+       case NL80211_CHAN_WIDTH_20:
+               return CHAN_WIDTH_20;
+       case NL80211_CHAN_WIDTH_40:
+               return CHAN_WIDTH_40;
+       case NL80211_CHAN_WIDTH_80:
+               return CHAN_WIDTH_80;
+       case NL80211_CHAN_WIDTH_80P80:
+               return CHAN_WIDTH_80P80;
+       case NL80211_CHAN_WIDTH_160:
+               return CHAN_WIDTH_160;
+       }
+       return CHAN_WIDTH_UNKNOWN;
+}
+
+
+static int get_channel_width(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct wpa_signal_info *sig_change = arg;
+
+       nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       sig_change->center_frq1 = -1;
+       sig_change->center_frq2 = -1;
+       sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+       if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
+               sig_change->chanwidth = convert2width(
+                       nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+               if (tb[NL80211_ATTR_CENTER_FREQ1])
+                       sig_change->center_frq1 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+               if (tb[NL80211_ATTR_CENTER_FREQ2])
+                       sig_change->center_frq2 =
+                               nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+       }
+
+       return NL_SKIP;
+}
+
+
+static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
+                                    struct wpa_signal_info *sig)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+       return send_and_recv_msgs(drv, msg, get_channel_width, sig);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
 static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
 {
        struct i802_bss *bss = priv;
@@ -9036,6 +9486,10 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
        if (res != 0)
                return res;
 
+       res = nl80211_get_channel_width(drv, si);
+       if (res != 0)
+               return res;
+
        return nl80211_get_link_noise(drv, si);
 }
 
@@ -9381,6 +9835,40 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
 }
 
 
+static int nl80211_start_radar_detection(void *priv, int freq)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC)");
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
+               wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
+                          "detection");
+               return -1;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+       /* only HT20 is supported at this point */
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret == 0)
+               return 0;
+       wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
+                  "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+       return -1;
+}
+
 #ifdef CONFIG_TDLS
 
 static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
@@ -9764,6 +10252,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_supp_port = wpa_driver_nl80211_set_supp_port,
        .set_country = wpa_driver_nl80211_set_country,
        .set_ap = wpa_driver_nl80211_set_ap,
+       .set_acl = wpa_driver_nl80211_set_acl,
        .if_add = wpa_driver_nl80211_if_add,
        .if_remove = driver_nl80211_if_remove,
        .send_mlme = driver_nl80211_send_mlme,
@@ -9813,6 +10302,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_rekey_info = nl80211_set_rekey_info,
        .poll_client = nl80211_poll_client,
        .set_p2p_powersave = nl80211_set_p2p_powersave,
+       .start_dfs_cac = nl80211_start_radar_detection,
+       .stop_ap = wpa_driver_nl80211_stop_ap,
 #ifdef CONFIG_TDLS
        .send_tdls_mgmt = nl80211_send_tdls_mgmt,
        .tdls_oper = nl80211_tdls_oper,