Track whether scan was started by us or an external program
[mech_eap.git] / src / drivers / driver_nl80211.c
index 4dffb3e..a782c11 100644 (file)
@@ -109,6 +109,17 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
 #endif /* CONFIG_LIBNL20 */
 
 
+#ifdef ANDROID
+/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
+static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+       return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+#undef nl_socket_set_nonblocking
+#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+#endif /* ANDROID */
+
+
 static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
 {
        struct nl_handle *handle;
@@ -286,6 +297,10 @@ struct wpa_driver_nl80211_data {
        unsigned int use_monitor:1;
        unsigned int ignore_next_local_disconnect:1;
        unsigned int allow_p2p_device:1;
+       unsigned int hostapd:1;
+       unsigned int start_mode_ap:1;
+       unsigned int start_iface_up:1;
+       unsigned int channel_switch_supported:1;
 
        u64 remain_on_chan_cookie;
        u64 send_action_cookie;
@@ -299,17 +314,12 @@ struct wpa_driver_nl80211_data {
 
        int eapol_tx_sock;
 
-#ifdef HOSTAPD
        int eapol_sock; /* socket for EAPOL frames */
 
        int default_if_indices[16];
        int *if_indices;
        int num_if_indices;
 
-       int last_freq;
-       int last_freq_ht;
-#endif /* HOSTAPD */
-
        /* From failed authentication command */
        int auth_freq;
        u8 auth_bssid_[ETH_ALEN];
@@ -332,7 +342,8 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
 static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                                       enum nl80211_iftype nlmode);
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+                                  const u8 *set_addr, int first);
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
                                   const u8 *addr, int cmd, u16 reason_code,
                                   int local_state_change);
@@ -351,29 +362,24 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
 static int android_pno_start(struct i802_bss *bss,
                             struct wpa_driver_scan_params *params);
 static int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+                                        size_t buf_len);
 #endif /* ANDROID */
+#ifdef ANDROID_P2P
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+                                const struct wpabuf *proberesp,
+                                const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
 
-#ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                                        enum wpa_driver_if_type type,
                                        const char *ifname);
-#else /* HOSTAPD */
-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;
-}
-#endif /* HOSTAPD */
 
 static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                                       struct hostapd_freq_params *freq);
@@ -498,6 +504,27 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
 }
 
 
+/* 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 is_ap_interface(enum nl80211_iftype nlmode)
 {
        return (nlmode == NL80211_IFTYPE_AP ||
@@ -794,7 +821,6 @@ nla_put_failure:
 }
 
 
-#ifndef HOSTAPD
 static int nl80211_get_macaddr(struct i802_bss *bss)
 {
        struct nl_msg *msg;
@@ -816,7 +842,6 @@ nla_put_failure:
        nlmsg_free(msg);
        return NL80211_IFTYPE_UNSPECIFIED;
 }
-#endif /* HOSTAPD */
 
 
 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
@@ -1101,7 +1126,7 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
        if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
                wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
                           "interface");
-               wpa_driver_nl80211_finish_drv_init(drv);
+               wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
                return 1;
        }
 
@@ -1480,34 +1505,60 @@ static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
 
 
 static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
-                                struct nlattr *freq, struct nlattr *type)
+                                struct nlattr *ifindex, struct nlattr *freq,
+                                struct nlattr *type, struct nlattr *bw,
+                                struct nlattr *cf1, struct nlattr *cf2)
 {
+       struct i802_bss *bss;
        union wpa_event_data data;
        int ht_enabled = 1;
        int chan_offset = 0;
+       int ifidx;
 
        wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
 
-       if (!freq || !type)
+       if (!freq)
                return;
 
-       switch (nla_get_u32(type)) {
-       case NL80211_CHAN_NO_HT:
-               ht_enabled = 0;
-               break;
-       case NL80211_CHAN_HT20:
-               break;
-       case NL80211_CHAN_HT40PLUS:
-               chan_offset = 1;
-               break;
-       case NL80211_CHAN_HT40MINUS:
-               chan_offset = -1;
-               break;
+       ifidx = nla_get_u32(ifindex);
+       for (bss = drv->first_bss; bss; bss = bss->next)
+               if (bss->ifindex == ifidx)
+                       break;
+
+       if (bss == NULL) {
+               wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+                          ifidx);
+               return;
        }
 
+       if (type) {
+               switch (nla_get_u32(type)) {
+               case NL80211_CHAN_NO_HT:
+                       ht_enabled = 0;
+                       break;
+               case NL80211_CHAN_HT20:
+                       break;
+               case NL80211_CHAN_HT40PLUS:
+                       chan_offset = 1;
+                       break;
+               case NL80211_CHAN_HT40MINUS:
+                       chan_offset = -1;
+                       break;
+               }
+       }
+
+       os_memset(&data, 0, sizeof(data));
        data.ch_switch.freq = nla_get_u32(freq);
        data.ch_switch.ht_enabled = ht_enabled;
        data.ch_switch.ch_offset = chan_offset;
+       if (bw)
+               data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+       if (cf1)
+               data.ch_switch.cf1 = nla_get_u32(cf1);
+       if (cf2)
+               data.ch_switch.cf2 = nla_get_u32(cf2);
+
+       bss->freq = data.ch_switch.freq;
 
        wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
 }
@@ -1986,21 +2037,36 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
                                &info->ssids[info->num_ssids];
                        s->ssid = nla_data(nl);
                        s->ssid_len = nla_len(nl);
+                       wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+                                  wpa_ssid_txt(s->ssid, s->ssid_len));
                        info->num_ssids++;
                        if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
                                break;
                }
        }
        if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+               char msg[200], *pos, *end;
+               int res;
+
+               pos = msg;
+               end = pos + sizeof(msg);
+               *pos = '\0';
+
                nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
                {
                        freqs[num_freqs] = nla_get_u32(nl);
+                       res = os_snprintf(pos, end - pos, " %d",
+                                         freqs[num_freqs]);
+                       if (res > 0 && end - pos > res)
+                               pos += res;
                        num_freqs++;
                        if (num_freqs == MAX_REPORT_FREQS - 1)
                                break;
                }
                info->freqs = freqs;
                info->num_freqs = num_freqs;
+               wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+                          msg);
        }
        wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
 }
@@ -2528,8 +2594,6 @@ static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static enum chan_width convert2width(int width);
-
 static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
                                struct nlattr **tb)
 {
@@ -2621,6 +2685,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                                 struct nlattr **tb)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
+       union wpa_event_data data;
 
        wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
                   cmd, nl80211_command_to_string(cmd), bss->ifname);
@@ -2637,6 +2702,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
        case NL80211_CMD_TRIGGER_SCAN:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
                drv->scan_state = SCAN_STARTED;
+               wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
                break;
        case NL80211_CMD_START_SCHED_SCAN:
                wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
@@ -2695,8 +2761,13 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                                   tb[NL80211_ATTR_RESP_IE]);
                break;
        case NL80211_CMD_CH_SWITCH_NOTIFY:
-               mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
-                                    tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+               mlme_event_ch_switch(drv,
+                                    tb[NL80211_ATTR_IFINDEX],
+                                    tb[NL80211_ATTR_WIPHY_FREQ],
+                                    tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+                                    tb[NL80211_ATTR_CHANNEL_WIDTH],
+                                    tb[NL80211_ATTR_CENTER_FREQ1],
+                                    tb[NL80211_ATTR_CENTER_FREQ2]);
                break;
        case NL80211_CMD_DISCONNECT:
                mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -2720,8 +2791,33 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
                break;
        case NL80211_CMD_REG_CHANGE:
                wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+               if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+                       break;
+               os_memset(&data, 0, sizeof(data));
+               switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
+               case NL80211_REGDOM_SET_BY_CORE:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_CORE;
+                       break;
+               case NL80211_REGDOM_SET_BY_USER:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_USER;
+                       break;
+               case NL80211_REGDOM_SET_BY_DRIVER:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_DRIVER;
+                       break;
+               case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+                       data.channel_list_changed.initiator =
+                               REGDOM_SET_BY_COUNTRY_IE;
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
+                                  nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
+                       break;
+               }
                wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
-                                    NULL);
+                                    &data);
                break;
        case NL80211_CMD_REG_BEACON_HINT:
                wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
@@ -3024,6 +3120,8 @@ struct wiphy_info_data {
        unsigned int p2p_go_supported:1;
        unsigned int p2p_client_supported:1;
        unsigned int p2p_concurrent:1;
+       unsigned int channel_switch_supported:1;
+       unsigned int set_qos_map_supported:1;
 };
 
 
@@ -3181,6 +3279,68 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
                case NL80211_CMD_PROBE_CLIENT:
                        info->poll_command_supported = 1;
                        break;
+               case NL80211_CMD_CHANNEL_SWITCH:
+                       info->channel_switch_supported = 1;
+                       break;
+               case NL80211_CMD_SET_QOS_MAP:
+                       info->set_qos_map_supported = 1;
+                       break;
+               }
+       }
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+                                    struct nlattr *tb)
+{
+       int i, num;
+       u32 *ciphers;
+
+       if (tb == NULL)
+               return;
+
+       num = nla_len(tb) / sizeof(u32);
+       ciphers = nla_data(tb);
+       for (i = 0; i < num; i++) {
+               u32 c = ciphers[i];
+
+               wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+                          c >> 24, (c >> 16) & 0xff,
+                          (c >> 8) & 0xff, c & 0xff);
+               switch (c) {
+               case WLAN_CIPHER_SUITE_CCMP_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+                       break;
+               case WLAN_CIPHER_SUITE_GCMP_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+                       break;
+               case WLAN_CIPHER_SUITE_CCMP:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+                       break;
+               case WLAN_CIPHER_SUITE_GCMP:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+                       break;
+               case WLAN_CIPHER_SUITE_TKIP:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+                       break;
+               case WLAN_CIPHER_SUITE_WEP104:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+                       break;
+               case WLAN_CIPHER_SUITE_WEP40:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+                       break;
+               case WLAN_CIPHER_SUITE_AES_CMAC:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+                       break;
+               case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+                       break;
+               case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+                       break;
+               case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+                       info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+                       break;
                }
        }
 }
@@ -3285,6 +3445,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        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]);
+       wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
 
        if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
                wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
@@ -3412,15 +3573,10 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
                return -1;
 
        drv->has_capability = 1;
-       /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
        drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
                WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
                WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
                WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-       drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
-               WPA_DRIVER_CAPA_ENC_WEP104 |
-               WPA_DRIVER_CAPA_ENC_TKIP |
-               WPA_DRIVER_CAPA_ENC_CCMP;
        drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
                WPA_DRIVER_AUTH_SHARED |
                WPA_DRIVER_AUTH_LEAP;
@@ -3442,6 +3598,9 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
        drv->device_ap_sme = info.device_ap_sme;
        drv->poll_command_supported = info.poll_command_supported;
        drv->data_tx_status = info.data_tx_status;
+       drv->channel_switch_supported = info.channel_switch_supported;
+       if (info.set_qos_map_supported)
+               drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
 
        /*
         * If poll command and tx status are supported, mac80211 is new enough
@@ -3708,16 +3867,9 @@ static void nl80211_destroy_bss(struct i802_bss *bss)
 }
 
 
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * @global_priv: private driver global data from global_init()
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
-                                     void *global_priv)
+static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
+                                         void *global_priv, int hostapd,
+                                         const u8 *set_addr)
 {
        struct wpa_driver_nl80211_data *drv;
        struct rfkill_config *rcfg;
@@ -3730,6 +3882,10 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                return NULL;
        drv->global = global_priv;
        drv->ctx = ctx;
+       drv->hostapd = !!hostapd;
+       drv->eapol_sock = -1;
+       drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+       drv->if_indices = drv->default_if_indices;
 
        drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
        if (!drv->first_bss) {
@@ -3767,7 +3923,10 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                os_free(rcfg);
        }
 
-       if (wpa_driver_nl80211_finish_drv_init(drv))
+       if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
+               drv->start_iface_up = 1;
+
+       if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
                goto failed;
 
        drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
@@ -3805,6 +3964,21 @@ failed:
 }
 
 
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+                                     void *global_priv)
+{
+       return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+}
+
+
 static int nl80211_register_frame(struct i802_bss *bss,
                                  struct nl_handle *nl_handle,
                                  u16 type, const u8 *match, size_t match_len)
@@ -4152,13 +4326,12 @@ static int i802_set_iface_flags(struct i802_bss *bss, int up)
 
 
 static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
+                                  const u8 *set_addr, int first)
 {
-#ifndef HOSTAPD
-       enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
-#endif /* HOSTAPD */
        struct i802_bss *bss = drv->first_bss;
        int send_rfkill_event = 0;
+       enum nl80211_iftype nlmode;
 
        drv->ifindex = if_nametoindex(bss->ifname);
        bss->ifindex = drv->ifindex;
@@ -4175,20 +4348,26 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
        wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
                   bss->ifname, drv->phyname);
 
-#ifndef HOSTAPD
-       if (bss->if_dynamic)
+       if (set_addr &&
+           (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
+            linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+                               set_addr)))
+               return -1;
+
+       if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
+               drv->start_mode_ap = 1;
+
+       if (drv->hostapd)
+               nlmode = NL80211_IFTYPE_AP;
+       else if (bss->if_dynamic)
                nlmode = nl80211_get_ifmode(bss);
+       else
+               nlmode = NL80211_IFTYPE_STATION;
 
-       /*
-        * Make sure the interface starts up in station mode unless this is a
-        * dynamically added interface (e.g., P2P) that was already configured
-        * with proper iftype.
-        */
        if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
-               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
+               wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
                return -1;
        }
-       drv->nlmode = nlmode;
 
        if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
                int ret = nl80211_set_p2pdev(bss, 1);
@@ -4212,9 +4391,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
                }
        }
 
-       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
-                              1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
+       if (!drv->hostapd)
+               netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+                                      1, IF_OPER_DORMANT);
 
        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
                               bss->addr))
@@ -4287,15 +4466,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
        if (is_ap_interface(drv->nlmode))
                wpa_driver_nl80211_del_beacon(drv);
 
-#ifdef HOSTAPD
-       if (drv->last_freq_ht) {
-               /* Clear HT flags from the driver */
-               struct hostapd_freq_params freq;
-               os_memset(&freq, 0, sizeof(freq));
-               freq.freq = drv->last_freq;
-               wpa_driver_nl80211_set_freq(bss, &freq);
-       }
-
        if (drv->eapol_sock >= 0) {
                eloop_unregister_read_sock(drv->eapol_sock);
                close(drv->eapol_sock);
@@ -4303,7 +4473,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        if (drv->if_indices != drv->default_if_indices)
                os_free(drv->if_indices);
-#endif /* HOSTAPD */
 
        if (drv->disabled_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
@@ -4314,9 +4483,12 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-       (void) i802_set_iface_flags(bss, 0);
+       if (!drv->start_iface_up)
+               (void) i802_set_iface_flags(bss, 0);
        if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
-               wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+               if (!drv->hostapd || !drv->start_mode_ap)
+                       wpa_driver_nl80211_set_mode(bss,
+                                                   NL80211_IFTYPE_STATION);
                nl80211_mgmt_unsubscribe(bss, "deinit");
        } else {
                nl80211_mgmt_unsubscribe(bss, "deinit");
@@ -4480,8 +4652,7 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
                           "(%s)", ret, strerror(-ret));
-#ifdef HOSTAPD
-               if (is_ap_interface(drv->nlmode)) {
+               if (drv->hostapd && is_ap_interface(drv->nlmode)) {
                        /*
                         * mac80211 does not allow scan requests in AP mode, so
                         * try to do this in station mode.
@@ -4500,9 +4671,6 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
                        ret = 0;
                } else
                        goto nla_put_failure;
-#else /* HOSTAPD */
-               goto nla_put_failure;
-#endif /* HOSTAPD */
        }
 
        drv->scan_state = SCAN_REQUESTED;
@@ -5080,10 +5248,30 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_GCMP);
                        break;
+               case WPA_ALG_CCMP_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_CCMP_256);
+                       break;
+               case WPA_ALG_GCMP_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_GCMP_256);
+                       break;
                case WPA_ALG_IGTK:
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_AES_CMAC);
                        break;
+               case WPA_ALG_BIP_GMAC_128:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_BIP_GMAC_128);
+                       break;
+               case WPA_ALG_BIP_GMAC_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_BIP_GMAC_256);
+                       break;
+               case WPA_ALG_BIP_CMAC_256:
+                       NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+                                   WLAN_CIPHER_SUITE_BIP_CMAC_256);
+                       break;
                case WPA_ALG_SMS4:
                        NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
                                    WLAN_CIPHER_SUITE_SMS4);
@@ -5220,10 +5408,30 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
        case WPA_ALG_GCMP:
                NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
                break;
+       case WPA_ALG_CCMP_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_CCMP_256);
+               break;
+       case WPA_ALG_GCMP_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_GCMP_256);
+               break;
        case WPA_ALG_IGTK:
                NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
                            WLAN_CIPHER_SUITE_AES_CMAC);
                break;
+       case WPA_ALG_BIP_GMAC_128:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_BIP_GMAC_128);
+               break;
+       case WPA_ALG_BIP_GMAC_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_BIP_GMAC_256);
+               break;
+       case WPA_ALG_BIP_CMAC_256:
+               NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+                           WLAN_CIPHER_SUITE_BIP_CMAC_256);
+               break;
        default:
                wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
                           "algorithm %d", __func__, alg);
@@ -5690,10 +5898,8 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
 
        if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
                chan->flag |= HOSTAPD_CHAN_DISABLED;
-       if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
-               chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN;
-       if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
-               chan->flag |= HOSTAPD_CHAN_NO_IBSS;
+       if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
+               chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS;
        if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
                chan->flag |= HOSTAPD_CHAN_RADAR;
 
@@ -5722,8 +5928,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
        static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
                [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
                [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
-               [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
-               [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+               [NL80211_FREQUENCY_ATTR_NO_IR] = { .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 },
@@ -6650,6 +6855,10 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
                   params->pairwise_ciphers);
        num_suites = 0;
+       if (params->pairwise_ciphers & WPA_CIPHER_CCMP_256)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256;
+       if (params->pairwise_ciphers & WPA_CIPHER_GCMP_256)
+               suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256;
        if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
                suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
        if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
@@ -6668,6 +6877,14 @@ static int wpa_driver_nl80211_set_ap(void *priv,
        wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
                   params->group_cipher);
        switch (params->group_cipher) {
+       case WPA_CIPHER_CCMP_256:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_CCMP_256);
+               break;
+       case WPA_CIPHER_GCMP_256:
+               NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+                           WLAN_CIPHER_SUITE_GCMP_256);
+               break;
        case WPA_CIPHER_CCMP:
                NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
                            WLAN_CIPHER_SUITE_CCMP);
@@ -6735,24 +6952,9 @@ static int wpa_driver_nl80211_set_ap(void *priv,
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
-                                      struct hostapd_freq_params *freq)
+static int nl80211_put_freq_params(struct nl_msg *msg,
+                                  struct hostapd_freq_params *freq)
 {
-       struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg;
-       int ret;
-
-       wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
-                  " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
-                  freq->freq, freq->ht_enabled, freq->vht_enabled,
-                  freq->bandwidth, freq->center_freq1, freq->center_freq2);
-       msg = nlmsg_alloc();
-       if (!msg)
-               return -1;
-
-       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-
-       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
        if (freq->vht_enabled) {
                switch (freq->bandwidth) {
@@ -6777,7 +6979,7 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                                    NL80211_CHAN_WIDTH_160);
                        break;
                default:
-                       return -1;
+                       return -EINVAL;
                }
                NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
                if (freq->center_freq2)
@@ -6799,6 +7001,33 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
                        break;
                }
        }
+       return 0;
+
+nla_put_failure:
+       return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+                                      struct hostapd_freq_params *freq)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+                  freq->freq, freq->ht_enabled, freq->vht_enabled,
+                  freq->bandwidth, freq->center_freq1, freq->center_freq2);
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -1;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       if (nl80211_put_freq_params(msg, freq) < 0)
+               goto nla_put_failure;
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
@@ -8020,6 +8249,12 @@ skip_auth_type:
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -8047,6 +8282,12 @@ skip_auth_type:
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -8238,6 +8479,12 @@ static int wpa_driver_nl80211_associate(
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -8263,6 +8510,12 @@ static int wpa_driver_nl80211_associate(
                case CIPHER_GCMP:
                        cipher = WLAN_CIPHER_SUITE_GCMP;
                        break;
+               case CIPHER_CCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_CCMP_256;
+                       break;
+               case CIPHER_GCMP_256:
+                       cipher = WLAN_CIPHER_SUITE_GCMP_256;
+                       break;
                case CIPHER_TKIP:
                default:
                        cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -8536,8 +8789,6 @@ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
 static inline int min_int(int a, int b)
 {
        if (a < b)
@@ -8692,8 +8943,6 @@ static int i802_flush(void *priv)
        return -ENOBUFS;
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
 
 static int get_sta_handler(struct nl_msg *msg, void *arg)
 {
@@ -8774,8 +9023,6 @@ static int i802_read_sta_data(struct i802_bss *bss,
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
-
 static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
                                    int cw_min, int cw_max, int burst_time)
 {
@@ -8941,9 +9188,6 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
                                            0);
 }
 
-#endif /* HOSTAPD || CONFIG_AP */
-
-#ifdef HOSTAPD
 
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
@@ -9135,14 +9379,13 @@ static void *i802_init(struct hostapd_data *hapd,
        int ifindex, br_ifindex;
        int br_added = 0;
 
-       bss = wpa_driver_nl80211_init(hapd, params->ifname,
-                                     params->global_priv);
+       bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
+                                         params->global_priv, 1,
+                                         params->bssid);
        if (bss == NULL)
                return NULL;
 
        drv = bss->drv;
-       drv->nlmode = NL80211_IFTYPE_AP;
-       drv->eapol_sock = -1;
 
        if (linux_br_get(brname, params->ifname) == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
@@ -9153,8 +9396,6 @@ static void *i802_init(struct hostapd_data *hapd,
                br_ifindex = 0;
        }
 
-       drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
-       drv->if_indices = drv->default_if_indices;
        for (i = 0; i < params->num_bridge; i++) {
                if (params->bridge[i]) {
                        ifindex = if_nametoindex(params->bridge[i]);
@@ -9171,28 +9412,10 @@ 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->global->ioctl_sock, bss->ifname, 0))
-               goto failed;
-
-       if (params->bssid) {
-               if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
-                                      params->bssid))
-                       goto failed;
-       }
-
-       if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
-               wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
-                          "into AP mode", bss->ifname);
-               goto failed;
-       }
-
        if (params->num_bridge && params->bridge[0] &&
            i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
                goto failed;
 
-       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));
        if (drv->eapol_sock < 0) {
                wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
@@ -9226,8 +9449,6 @@ static void i802_deinit(void *priv)
        wpa_driver_nl80211_deinit(bss);
 }
 
-#endif /* HOSTAPD */
-
 
 static enum nl80211_iftype wpa_driver_nl80211_if_type(
        enum wpa_driver_if_type type)
@@ -9405,7 +9626,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        }
 #endif /* CONFIG_P2P */
 
-#ifdef HOSTAPD
        if (type == WPA_IF_AP_BSS) {
                struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
                if (new_bss == NULL) {
@@ -9448,7 +9668,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                if (nl80211_setup_ap(new_bss))
                        return -1;
        }
-#endif /* HOSTAPD */
 
        if (drv->global)
                drv->global->if_add_ifindex = ifidx;
@@ -9466,10 +9685,9 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
 
        wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
                   __func__, type, ifname, ifindex, bss->added_if);
-       if (ifindex > 0 && bss->added_if)
+       if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
                nl80211_remove_iface(drv, ifindex);
 
-#ifdef HOSTAPD
        if (type != WPA_IF_AP_BSS)
                return 0;
 
@@ -9521,7 +9739,6 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
                        wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
                }
        }
-#endif /* HOSTAPD */
 
        return 0;
 }
@@ -9998,27 +10215,6 @@ 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];
@@ -10598,8 +10794,13 @@ static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
        wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
                   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
 
-       if (opp_ps != -1 || ctwindow != -1)
+       if (opp_ps != -1 || ctwindow != -1) {
+#ifdef ANDROID_P2P
+               wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
+#else /* ANDROID_P2P */
                return -1; /* Not yet supported */
+#endif /* ANDROID_P2P */
+       }
 
        if (legacy_ps == -1)
                return 0;
@@ -10980,14 +11181,12 @@ static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
 }
 
 
-#if defined(HOSTAPD) || defined(CONFIG_AP)
 static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
                                       const char *ifname, int vlan_id)
 {
        struct i802_bss *bss = priv;
        return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
 }
-#endif /* HOSTAPD || CONFIG_AP */
 
 
 static int driver_nl80211_read_sta_data(void *priv,
@@ -11221,6 +11420,161 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
 }
 
 
+static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
+{
+       if (settings->head)
+               NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
+                       settings->head_len, settings->head);
+
+       if (settings->tail)
+               NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
+                       settings->tail_len, settings->tail);
+
+       if (settings->beacon_ies)
+               NLA_PUT(msg, NL80211_ATTR_IE,
+                       settings->beacon_ies_len, settings->beacon_ies);
+
+       if (settings->proberesp_ies)
+               NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+                       settings->proberesp_ies_len, settings->proberesp_ies);
+
+       if (settings->assocresp_ies)
+               NLA_PUT(msg,
+                       NL80211_ATTR_IE_ASSOC_RESP,
+                       settings->assocresp_ies_len, settings->assocresp_ies);
+
+       if (settings->probe_resp)
+               NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
+                       settings->probe_resp_len, settings->probe_resp);
+
+       return 0;
+
+nla_put_failure:
+       return -ENOBUFS;
+}
+
+
+static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
+{
+       struct nl_msg *msg;
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nlattr *beacon_csa;
+       int ret = -ENOBUFS;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
+                  settings->cs_count, settings->block_tx,
+                  settings->freq_params.freq, settings->freq_params.bandwidth,
+                  settings->freq_params.center_freq1,
+                  settings->freq_params.center_freq2);
+
+       if (!drv->channel_switch_supported) {
+               wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
+               return -EOPNOTSUPP;
+       }
+
+       if ((drv->nlmode != NL80211_IFTYPE_AP) &&
+           (drv->nlmode != NL80211_IFTYPE_P2P_GO))
+               return -EOPNOTSUPP;
+
+       /* check settings validity */
+       if (!settings->beacon_csa.tail ||
+           ((settings->beacon_csa.tail_len <=
+             settings->counter_offset_beacon) ||
+            (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
+             settings->cs_count)))
+               return -EINVAL;
+
+       if (settings->beacon_csa.probe_resp &&
+           ((settings->beacon_csa.probe_resp_len <=
+             settings->counter_offset_presp) ||
+            (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
+             settings->cs_count)))
+               return -EINVAL;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
+       ret = nl80211_put_freq_params(msg, &settings->freq_params);
+       if (ret)
+               goto error;
+
+       if (settings->block_tx)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
+
+       /* beacon_after params */
+       ret = set_beacon_data(msg, &settings->beacon_after);
+       if (ret)
+               goto error;
+
+       /* beacon_csa params */
+       beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
+       if (!beacon_csa)
+               goto nla_put_failure;
+
+       ret = set_beacon_data(msg, &settings->beacon_csa);
+       if (ret)
+               goto error;
+
+       NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+                   settings->counter_offset_beacon);
+
+       if (settings->beacon_csa.probe_resp)
+               NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+                           settings->counter_offset_presp);
+
+       nla_nest_end(msg, beacon_csa);
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
+                          ret, strerror(-ret));
+       }
+       return ret;
+
+nla_put_failure:
+       ret = -ENOBUFS;
+error:
+       nlmsg_free(msg);
+       wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
+       return ret;
+}
+
+
+static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
+                              u8 qos_map_set_len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret;
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               return -ENOMEM;
+
+       wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
+                   qos_map_set, qos_map_set_len);
+
+       nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret)
+               wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
+
+       return ret;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -11253,12 +11607,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .sta_remove = driver_nl80211_sta_remove,
        .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
        .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
-#ifdef HOSTAPD
        .hapd_init = i802_init,
        .hapd_deinit = i802_deinit,
        .set_wds_sta = i802_set_wds_sta,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
        .get_seqnum = i802_get_seqnum,
        .flush = i802_flush,
        .get_inact_sec = i802_get_inact_sec,
@@ -11269,7 +11620,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_sta_vlan = driver_nl80211_set_sta_vlan,
        .sta_deauth = i802_sta_deauth,
        .sta_disassoc = i802_sta_disassoc,
-#endif /* HOSTAPD || CONFIG_AP */
        .read_sta_data = driver_nl80211_read_sta_data,
        .set_freq = i802_set_freq,
        .send_action = driver_nl80211_send_action,
@@ -11304,4 +11654,14 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .get_mac_addr = wpa_driver_nl80211_get_macaddr,
        .get_survey = wpa_driver_nl80211_get_survey,
        .status = wpa_driver_nl80211_status,
+       .switch_channel = nl80211_switch_channel,
+#ifdef ANDROID_P2P
+       .set_noa = wpa_driver_set_p2p_noa,
+       .get_noa = wpa_driver_get_p2p_noa,
+       .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
+#endif /* ANDROID_P2P */
+#ifdef ANDROID
+       .driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* ANDROID */
+       .set_qos_map = nl80211_set_qos_map,
 };