P2P: Fix crash when failed to create GO interface
[mech_eap.git] / wpa_supplicant / ap.c
index d18e3f1..fdbe248 100644 (file)
@@ -14,6 +14,7 @@
 #include "utils/uuid.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
+#include "eapol_supp/eapol_supp_sm.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #include "ap/ap_drv_ops.h"
@@ -46,24 +47,14 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                                  struct hostapd_config *conf)
 {
        struct hostapd_bss_config *bss = &conf->bss[0];
-       int pairwise;
 
        conf->driver = wpa_s->driver;
 
        os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
 
-       if (ssid->frequency == 0) {
-               /* default channel 11 */
-               conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-               conf->channel = 11;
-       } else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
-               conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-               conf->channel = (ssid->frequency - 2407) / 5;
-       } else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
-                  (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
-               conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
-               conf->channel = (ssid->frequency - 5000) / 5;
-       } else {
+       conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+                                              &conf->channel);
+       if (conf->hw_mode == NUM_HOSTAPD_MODES) {
                wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
                           ssid->frequency);
                return -1;
@@ -81,15 +72,36 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
         */
        if (wpa_s->hw.modes) {
                struct hostapd_hw_modes *mode = NULL;
-               int i;
+               int i, no_ht = 0;
                for (i = 0; i < wpa_s->hw.num_modes; i++) {
                        if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
                                mode = &wpa_s->hw.modes[i];
                                break;
                        }
                }
-               if (mode && mode->ht_capab) {
+
+#ifdef CONFIG_HT_OVERRIDES
+               if (ssid->disable_ht) {
+                       conf->ieee80211n = 0;
+                       conf->ht_capab = 0;
+                       no_ht = 1;
+               }
+#endif /* CONFIG_HT_OVERRIDES */
+
+               if (!no_ht && mode && mode->ht_capab) {
                        conf->ieee80211n = 1;
+#ifdef CONFIG_P2P
+                       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
+                           (mode->ht_capab &
+                            HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+                           ssid->ht40)
+                               conf->secondary_channel =
+                                       wpas_p2p_get_ht40_mode(wpa_s, mode,
+                                                              conf->channel);
+                       if (conf->secondary_channel)
+                               conf->ht_capab |=
+                                       HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+#endif /* CONFIG_P2P */
 
                        /*
                         * white-list capabilities that won't cause issues
@@ -107,7 +119,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_P2P
-       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
+           (ssid->mode == WPAS_MODE_P2P_GO ||
+            ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)) {
                /* Remove 802.11b rates from supported and basic rate sets */
                int *list = os_malloc(4 * sizeof(int));
                if (list) {
@@ -134,6 +148,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        }
 
        bss->isolate = !wpa_s->conf->p2p_intra_bss;
+       bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
 #endif /* CONFIG_P2P */
 
        if (ssid->ssid_len == 0) {
@@ -141,7 +156,6 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                return -1;
        }
        os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
-       bss->ssid.ssid[ssid->ssid_len] = '\0';
        bss->ssid.ssid_len = ssid->ssid_len;
        bss->ssid.ssid_set = 1;
 
@@ -154,15 +168,15 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                bss->wpa = ssid->proto;
        bss->wpa_key_mgmt = ssid->key_mgmt;
        bss->wpa_pairwise = ssid->pairwise_cipher;
-       if (ssid->passphrase) {
-               bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
-       } else if (ssid->psk_set) {
+       if (ssid->psk_set) {
                os_free(bss->ssid.wpa_psk);
                bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
                if (bss->ssid.wpa_psk == NULL)
                        return -1;
                os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
                bss->ssid.wpa_psk->group = 1;
+       } else if (ssid->passphrase) {
+               bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
        } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
                   ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
                struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -184,19 +198,20 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        if (ssid->ap_max_inactivity)
                bss->ap_max_inactivity = ssid->ap_max_inactivity;
 
-       /* Select group cipher based on the enabled pairwise cipher suites */
-       pairwise = 0;
-       if (bss->wpa & 1)
-               pairwise |= bss->wpa_pairwise;
-       if (bss->wpa & 2) {
-               if (bss->rsn_pairwise == 0)
-                       bss->rsn_pairwise = bss->wpa_pairwise;
-               pairwise |= bss->rsn_pairwise;
-       }
-       if (pairwise & WPA_CIPHER_TKIP)
-               bss->wpa_group = WPA_CIPHER_TKIP;
-       else
-               bss->wpa_group = WPA_CIPHER_CCMP;
+       if (ssid->dtim_period)
+               bss->dtim_period = ssid->dtim_period;
+       else if (wpa_s->conf->dtim_period)
+               bss->dtim_period = wpa_s->conf->dtim_period;
+
+       if (ssid->beacon_int)
+               conf->beacon_int = ssid->beacon_int;
+       else if (wpa_s->conf->beacon_int)
+               conf->beacon_int = wpa_s->conf->beacon_int;
+
+       if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+               bss->rsn_pairwise = bss->wpa_pairwise;
+       bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+                                                   bss->rsn_pairwise);
 
        if (bss->wpa && bss->ieee802_1x)
                bss->ssid.security_policy = SECURITY_WPA;
@@ -227,6 +242,16 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                bss->rsn_pairwise = WPA_CIPHER_NONE;
        }
 
+       if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) &&
+           (bss->wpa_group == WPA_CIPHER_CCMP ||
+            bss->wpa_group == WPA_CIPHER_GCMP)) {
+               /*
+                * Strong ciphers do not need frequent rekeying, so increase
+                * the default GTK rekeying period to 24 hours.
+                */
+               bss->wpa_group_rekey = 86400;
+       }
+
 #ifdef CONFIG_WPS
        /*
         * Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -238,7 +263,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                goto no_wps;
 #ifdef CONFIG_WPS2
        if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
-           (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+           (!(bss->rsn_pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
                goto no_wps; /* WPS2 does not allow WPA/TKIP-only
                              * configuration */
 #endif /* CONFIG_WPS2 */
@@ -269,6 +294,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        else
                os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
        os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
+       bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
 no_wps:
 #endif /* CONFIG_WPS */
 
@@ -280,6 +306,11 @@ no_wps:
 
        bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
 
+       if (wpa_s->conf->ap_vendor_elements) {
+               bss->vendor_elements =
+                       wpabuf_dup(wpa_s->conf->ap_vendor_elements);
+       }
+
        return 0;
 }
 
@@ -336,6 +367,19 @@ static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
 }
 
 
+#ifdef CONFIG_P2P
+static void ap_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr,
+                         const u8 *psk, size_t psk_len)
+{
+
+       struct wpa_supplicant *wpa_s = ctx;
+       if (wpa_s->ap_iface == NULL || wpa_s->current_ssid == NULL)
+               return;
+       wpas_p2p_new_psk_cb(wpa_s, mac_addr, p2p_dev_addr, psk, psk_len);
+}
+#endif /* CONFIG_P2P */
+
+
 static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
 {
 #ifdef CONFIG_P2P
@@ -357,11 +401,13 @@ static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
 
 
 static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
-                          const u8 *bssid, const u8 *ie, size_t ie_len)
+                          const u8 *bssid, const u8 *ie, size_t ie_len,
+                          int ssi_signal)
 {
 #ifdef CONFIG_P2P
        struct wpa_supplicant *wpa_s = ctx;
-       return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len);
+       return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
+                                    ssi_signal);
 #else /* CONFIG_P2P */
        return 0;
 #endif /* CONFIG_P2P */
@@ -424,6 +470,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                params.mode = IEEE80211_MODE_AP;
                break;
        }
+       if (ssid->frequency == 0)
+               ssid->frequency = 2462; /* default channel 11 */
        params.freq = ssid->frequency;
 
        params.wpa_proto = ssid->proto;
@@ -433,18 +481,15 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
        params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
 
-       if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
-               wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
-       else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
-               wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
-       else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
-               wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
-       else {
+       wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher,
+                                                         1);
+       if (wpa_s->pairwise_cipher < 0) {
                wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
                           "cipher.");
                return -1;
        }
-       params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+       params.pairwise_suite =
+               wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
        params.group_suite = params.pairwise_suite;
 
 #ifdef CONFIG_P2P
@@ -469,6 +514,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        hapd_iface->owner = wpa_s;
        hapd_iface->drv_flags = wpa_s->drv_flags;
        hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
+       hapd_iface->extended_capa = wpa_s->extended_capa;
+       hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
+       hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
 
        wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
        if (conf == NULL) {
@@ -476,6 +524,10 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+       os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
+                 wpa_s->conf->wmm_ac_params,
+                 sizeof(wpa_s->conf->wmm_ac_params));
+
        if (params.uapsd > 0) {
                conf->bss->wmm_enabled = 1;
                conf->bss->wmm_uapsd = 1;
@@ -496,7 +548,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_P2P */
 
        hapd_iface->num_bss = conf->num_bss;
-       hapd_iface->bss = os_zalloc(conf->num_bss *
+       hapd_iface->bss = os_calloc(conf->num_bss,
                                    sizeof(struct hostapd_data *));
        if (hapd_iface->bss == NULL) {
                wpa_supplicant_ap_deinit(wpa_s);
@@ -527,10 +579,11 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
                hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
 #ifdef CONFIG_P2P
+               hapd_iface->bss[i]->new_psk_cb = ap_new_psk_cb;
+               hapd_iface->bss[i]->new_psk_cb_ctx = wpa_s;
                hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
-               hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(
-                       wpa_s, ssid->p2p_persistent_group,
-                       ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION);
+               hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
+                                                                   ssid);
 #endif /* CONFIG_P2P */
                hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
                hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
@@ -541,6 +594,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
 
        wpa_s->current_ssid = ssid;
+       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
        os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
        wpa_s->assoc_freq = ssid->frequency;
 
@@ -564,8 +618,8 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
                return;
 
        wpa_s->current_ssid = NULL;
+       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
        wpa_s->assoc_freq = 0;
-       wpa_s->reassociated_connection = 0;
 #ifdef CONFIG_P2P
        if (wpa_s->ap_iface->bss)
                wpa_s->ap_iface->bss[0]->p2p_group = NULL;
@@ -659,21 +713,6 @@ int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
-static int wpa_supplicant_ap_wps_sta_cancel(struct hostapd_data *hapd,
-                                           struct sta_info *sta, void *ctx)
-{
-       if (sta && (sta->flags & WLAN_STA_WPS)) {
-               ap_sta_deauthenticate(hapd, sta,
-                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
-               wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
-                          __func__, MAC2STR(sta->addr));
-               return 1;
-       }
-
-       return 0;
-}
-
-
 int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
 {
        struct wps_registrar *reg;
@@ -685,7 +724,7 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
        reg = wpa_s->ap_iface->bss[0]->wps->registrar;
        reg_sel = wps_registrar_wps_cancel(reg);
        wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
-                                 wpa_supplicant_ap_wps_sta_cancel, NULL);
+                                 ap_sta_wps_cancel, NULL);
 
        if (!reg_sel && !wps_sta) {
                wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
@@ -705,7 +744,8 @@ int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
 
 
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                             const char *pin, char *buf, size_t buflen)
+                             const char *pin, char *buf, size_t buflen,
+                             int timeout)
 {
        int ret, ret_len = 0;
 
@@ -720,7 +760,7 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                ret_len = os_snprintf(buf, buflen, "%s", pin);
 
        ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
-                                 0);
+                                 timeout);
        if (ret)
                return -1;
        return ret_len;
@@ -843,6 +883,34 @@ void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
        hapd->conf->ap_pin = NULL;
 }
 
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+                                            int ndef)
+{
+       struct hostapd_data *hapd;
+
+       if (wpa_s->ap_iface == NULL)
+               return NULL;
+       hapd = wpa_s->ap_iface->bss[0];
+       return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+                                            int ndef)
+{
+       struct hostapd_data *hapd;
+
+       if (wpa_s->ap_iface == NULL)
+               return NULL;
+       hapd = wpa_s->ap_iface->bss[0];
+       return hostapd_wps_nfc_hs_cr(hapd, ndef);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
 #endif /* CONFIG_WPS */
 
 
@@ -958,6 +1026,17 @@ int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
 }
 
 
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+                      int offset)
+{
+       if (!wpa_s->ap_iface)
+               return;
+
+       wpa_s->assoc_freq = freq;
+       hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+}
+
+
 int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
                                      const u8 *addr)
 {