]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/ap/drv_callbacks.c
hostapd: DFS for channel switch in repeater mode
[thirdparty/hostap.git] / src / ap / drv_callbacks.c
index 38506a09711dedad264bce205c7707de9b027d03..559bb87c213e726cddcb3ecd9432ab196292ba42 100644 (file)
@@ -109,7 +109,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                        const u8 *req_ies, size_t req_ies_len, int reassoc)
 {
        struct sta_info *sta;
-       int new_assoc, res;
+       int new_assoc;
+       enum wpa_validate_result res;
        struct ieee802_11_elems elems;
        const u8 *ie;
        size_t ielen;
@@ -220,7 +221,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
        }
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_IEEE80211N
 #ifdef NEED_AP_MLME
        if (elems.ht_capabilities &&
            (hapd->iface->conf->ht_capab &
@@ -234,7 +234,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                        ht40_intolerant_add(hapd->iface, sta);
        }
 #endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_INTERWORKING
        if (elems.ext_capab && elems.ext_capab_len > 4) {
@@ -325,33 +324,67 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                                          elems.rsnxe ? elems.rsnxe_len + 2 : 0,
                                          elems.mdie, elems.mdie_len,
                                          elems.owe_dh, elems.owe_dh_len);
-               if (res != WPA_IE_OK) {
+               reason = WLAN_REASON_INVALID_IE;
+               status = WLAN_STATUS_INVALID_IE;
+               switch (res) {
+               case WPA_IE_OK:
+                       reason = WLAN_REASON_UNSPECIFIED;
+                       status = WLAN_STATUS_SUCCESS;
+                       break;
+               case WPA_INVALID_IE:
+                       reason = WLAN_REASON_INVALID_IE;
+                       status = WLAN_STATUS_INVALID_IE;
+                       break;
+               case WPA_INVALID_GROUP:
+                       reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+                       status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+                       break;
+               case WPA_INVALID_PAIRWISE:
+                       reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+                       status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+                       break;
+               case WPA_INVALID_AKMP:
+                       reason = WLAN_REASON_AKMP_NOT_VALID;
+                       status = WLAN_STATUS_AKMP_NOT_VALID;
+                       break;
+               case WPA_NOT_ENABLED:
+                       reason = WLAN_REASON_INVALID_IE;
+                       status = WLAN_STATUS_INVALID_IE;
+                       break;
+               case WPA_ALLOC_FAIL:
+                       reason = WLAN_REASON_UNSPECIFIED;
+                       status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       break;
+               case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+                       reason = WLAN_REASON_INVALID_IE;
+                       status = WLAN_STATUS_INVALID_IE;
+                       break;
+               case WPA_INVALID_MGMT_GROUP_CIPHER:
+                       reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+                       status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+                       break;
+               case WPA_INVALID_MDIE:
+                       reason = WLAN_REASON_INVALID_MDE;
+                       status = WLAN_STATUS_INVALID_MDIE;
+                       break;
+               case WPA_INVALID_PROTO:
+                       reason = WLAN_REASON_INVALID_IE;
+                       status = WLAN_STATUS_INVALID_IE;
+                       break;
+               case WPA_INVALID_PMKID:
+                       reason = WLAN_REASON_INVALID_PMKID;
+                       status = WLAN_STATUS_INVALID_PMKID;
+                       break;
+               case WPA_DENIED_OTHER_REASON:
+                       reason = WLAN_REASON_UNSPECIFIED;
+                       status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+                       break;
+               }
+               if (status != WLAN_STATUS_SUCCESS) {
                        wpa_printf(MSG_DEBUG,
                                   "WPA/RSN information element rejected? (res %u)",
                                   res);
                        wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
-                       if (res == WPA_INVALID_GROUP) {
-                               reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
-                               status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
-                       } else if (res == WPA_INVALID_PAIRWISE) {
-                               reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
-                               status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
-                       } else if (res == WPA_INVALID_AKMP) {
-                               reason = WLAN_REASON_AKMP_NOT_VALID;
-                               status = WLAN_STATUS_AKMP_NOT_VALID;
-                       } else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
-                               reason = WLAN_REASON_INVALID_IE;
-                               status = WLAN_STATUS_INVALID_IE;
-                       } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
-                               reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
-                               status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-                       } else if (res == WPA_INVALID_PMKID) {
-                               reason = WLAN_REASON_INVALID_PMKID;
-                               status = WLAN_STATUS_INVALID_PMKID;
-                       } else {
-                               reason = WLAN_REASON_INVALID_IE;
-                               status = WLAN_STATUS_INVALID_IE;
-                       }
                        goto fail;
                }
 
@@ -469,6 +502,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                        return WLAN_STATUS_INVALID_IE;
 #endif /* CONFIG_HS20 */
        }
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
 
 #ifdef CONFIG_MBO
        if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
@@ -480,13 +516,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
        }
 #endif /* CONFIG_MBO */
 
-#ifdef CONFIG_WPS
-skip_wpa_check:
-#endif /* CONFIG_WPS */
-
 #ifdef CONFIG_IEEE80211R_AP
        p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
-                                       sta->auth_alg, req_ies, req_ies_len);
+                                       sta->auth_alg, req_ies, req_ies_len,
+                                       !elems.rsnxe);
        if (!p) {
                wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
                return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -625,6 +658,11 @@ skip_wpa_check:
        pfs_fail:
 #endif /* CONFIG_DPP2 */
 
+       if (elems.rrm_enabled &&
+           elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+           os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+                     sizeof(sta->rrm_enabled_capa));
+
 #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
        hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
 
@@ -709,6 +747,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
 
        ap_sta_set_authorized(hapd, sta, 0);
        sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+       hostapd_set_sta_flags(hapd, sta);
        wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
        sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
        ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -906,6 +945,12 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
        } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
                wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
                        "freq=%d dfs=%d", freq, is_dfs);
+       } else if (is_dfs &&
+                  hostapd_is_dfs_required(hapd->iface) &&
+                  !hostapd_is_dfs_chan_available(hapd->iface) &&
+                  !hapd->iface->cac_started) {
+               hostapd_disable_iface(hapd->iface);
+               hostapd_enable_iface(hapd->iface);
        }
 
        for (i = 0; i < hapd->iface->num_bss; i++)
@@ -1005,6 +1050,8 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
                goto out;
        }
 
+       hapd->iconf->edmg_channel = acs_res->edmg_channel;
+
        if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
                /* set defaults for backwards compatibility */
                hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
@@ -1427,15 +1474,33 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
 #endif /* HOSTAPD */
 
 
+static struct hostapd_channel_data *
+hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
+{
+       int i;
+       struct hostapd_channel_data *chan;
+
+       for (i = 0; i < mode->num_channels; i++) {
+               chan = &mode->channels[i];
+               if ((unsigned int) chan->freq == freq)
+                       return chan;
+       }
+
+       return NULL;
+}
+
+
 static struct hostapd_channel_data * hostapd_get_mode_channel(
        struct hostapd_iface *iface, unsigned int freq)
 {
        int i;
        struct hostapd_channel_data *chan;
 
-       for (i = 0; i < iface->current_mode->num_channels; i++) {
-               chan = &iface->current_mode->channels[i];
-               if ((unsigned int) chan->freq == freq)
+       for (i = 0; i < iface->num_hw_features; i++) {
+               if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
+                       continue;
+               chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
+               if (chan)
                        return chan;
        }