hostapd: Use channel switch fallback on error
authorMichal Kazior <michal.kazior@tieto.com>
Fri, 27 Jun 2014 12:19:30 +0000 (14:19 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 28 Jun 2014 08:13:11 +0000 (11:13 +0300)
It's worth giving a try to fallback to re-starting BSSes at least once
hoping it works out instead of just leaving BSSes disabled.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
src/ap/drv_callbacks.c
src/ap/hostapd.c
src/ap/hostapd.h
src/drivers/driver.h

index ac5732c..93804de 100644 (file)
@@ -885,6 +885,20 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
 
 #ifdef NEED_AP_MLME
 
+static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
+{
+       wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
+                  hapd->conf->iface);
+
+       if (hapd->csa_in_progress) {
+               wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
+                          hapd->conf->iface);
+               hostapd_switch_channel_fallback(hapd->iface,
+                                               &hapd->cs_freq_params);
+       }
+}
+
+
 static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
                                             struct dfs_event *radar)
 {
@@ -1072,6 +1086,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                hostapd_event_get_survey(hapd, &data->survey_results);
                break;
 #ifdef NEED_AP_MLME
+       case EVENT_INTERFACE_UNAVAILABLE:
+               hostapd_event_iface_unavailable(hapd);
+               break;
        case EVENT_DFS_RADAR_DETECTED:
                if (!data)
                        break;
index 4c648b1..55b7ced 100644 (file)
@@ -2280,13 +2280,13 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
 
        if (!params->channel) {
                /* check if the new channel is supported by hw */
-               channel = hostapd_hw_get_channel(hapd, params->freq);
-               if (!channel)
-                       return -1;
-       } else {
-               channel = params->channel;
+               params->channel = hostapd_hw_get_channel(hapd, params->freq);
        }
 
+       channel = params->channel;
+       if (!channel)
+               return -1;
+
        /* if a pointer to old_params is provided we save previous state */
        if (old_params) {
                old_params->channel = conf->channel;
@@ -2381,4 +2381,60 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
        return 0;
 }
 
+
+void
+hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+                               const struct hostapd_freq_params *freq_params)
+{
+       int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
+       unsigned int i;
+
+       wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
+
+       if (freq_params->center_freq1)
+               vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
+       if (freq_params->center_freq2)
+               vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
+
+       switch (freq_params->bandwidth) {
+       case 0:
+       case 20:
+       case 40:
+               vht_bw = VHT_CHANWIDTH_USE_HT;
+               break;
+       case 80:
+               if (freq_params->center_freq2)
+                       vht_bw = VHT_CHANWIDTH_80P80MHZ;
+               else
+                       vht_bw = VHT_CHANWIDTH_80MHZ;
+               break;
+       case 160:
+               vht_bw = VHT_CHANWIDTH_160MHZ;
+               break;
+       default:
+               wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
+                          freq_params->bandwidth);
+               break;
+       }
+
+       iface->freq = freq_params->freq;
+       iface->conf->channel = freq_params->channel;
+       iface->conf->secondary_channel = freq_params->sec_channel_offset;
+       iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
+       iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
+       iface->conf->vht_oper_chwidth = vht_bw;
+       iface->conf->ieee80211n = freq_params->ht_enabled;
+       iface->conf->ieee80211ac = freq_params->vht_enabled;
+
+       /*
+        * cs_params must not be cleared earlier because the freq_params
+        * argument may actually point to one of these.
+        */
+       for (i = 0; i < iface->num_bss; i++)
+               hostapd_cleanup_cs_params(iface->bss[i]);
+
+       hostapd_disable_iface(iface);
+       hostapd_enable_iface(iface);
+}
+
 #endif /* NEED_AP_MLME */
index d413f7e..3c8727b 100644 (file)
@@ -397,6 +397,9 @@ void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
 const char * hostapd_state_text(enum hostapd_iface_state s);
 int hostapd_switch_channel(struct hostapd_data *hapd,
                           struct csa_settings *settings);
+void
+hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+                               const struct hostapd_freq_params *freq_params);
 void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
 
 /* utils.c */
index 33f53af..352c163 100644 (file)
@@ -3316,7 +3316,8 @@ enum wpa_event_type {
         * the driver does not support radar detection and another virtual
         * interfaces caused the operating channel to change. Other similar
         * resource conflicts could also trigger this for station mode
-        * interfaces.
+        * interfaces. This event can be propagated when channel switching
+        * fails.
         */
        EVENT_INTERFACE_UNAVAILABLE,