[v2] DFS: restart CAC in case of CAC is aborted

Message ID 20180219154930.7011-1-dlebed@quantenna.com
State New
Headers show
Series
  • [v2] DFS: restart CAC in case of CAC is aborted
Related show

Commit Message

Dmitrii Lebed Feb. 19, 2018, 3:49 p.m.
From: Dmitry Lebed <dlebed@quantenna.com>

If CAC is aborted, hostapd will continue wait for
CAC completion and will stuck in this state forever.
Adding CAC restart action on CAC aborted event,
considering "CAC aborted" state as recoverable.
CAC aborted can be generated in some complex configs,
e.g. in repeater config, when wpa_supplicant is
doing something on another virtual interface that
can lead to generation of "CAC aborted" event.

Signed-off-by: Dmitrii Lebed <dlebed@quantenna.com>
---
V1->V2 changes:
1. Move CAC restart to eloop with 1 sec delay
2. Added CAC start error handling in CAC restart handler
3. Added DFS offload handling for CAC abort

 src/ap/dfs.c           | 97 ++++++++++++++++++++++++++++++++++++--------------
 src/ap/dfs.h           |  2 +-
 src/ap/drv_callbacks.c |  6 ++--
 3 files changed, 74 insertions(+), 31 deletions(-)

--
2.16.1



This email, including its contents and any attachment(s), may contain confidential information of Quantenna Communications, Inc. and is solely for the intended recipient(s). If you may have received this in error, please contact the sender and permanently delete this email, its contents and any attachment(s).

Patch

diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 5a0d7814b..f1476eee0 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -10,6 +10,7 @@ 
 #include "utils/includes.h"

 #include "utils/common.h"
+#include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/hw_features_common.h"
 #include "common/wpa_ctrl.h"
@@ -636,6 +637,34 @@  static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
        return cac_time_ms;
 }

+static int dfs_start_cac(struct hostapd_iface *iface)
+{
+       int res;
+
+       wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+               "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
+               iface->freq,
+               iface->conf->channel, iface->conf->secondary_channel,
+               iface->conf->vht_oper_chwidth,
+               iface->conf->vht_oper_centr_freq_seg0_idx,
+               iface->conf->vht_oper_centr_freq_seg1_idx,
+               iface->dfs_cac_ms / 1000);
+
+       res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+                                   iface->freq,
+                                   iface->conf->channel,
+                                   iface->conf->ieee80211n,
+                                   iface->conf->ieee80211ac,
+                                   iface->conf->secondary_channel,
+                                   iface->conf->vht_oper_chwidth,
+                                   iface->conf->vht_oper_centr_freq_seg0_idx,
+                                   iface->conf->vht_oper_centr_freq_seg1_idx);
+
+       if (res)
+               wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
+
+       return res;
+}

 /*
  * Main DFS handler
@@ -719,31 +748,8 @@  int hostapd_handle_dfs(struct hostapd_iface *iface)
        /* Finally start CAC */
        hostapd_set_state(iface, HAPD_IFACE_DFS);
        wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
-       wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
-               "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
-               iface->freq,
-               iface->conf->channel, iface->conf->secondary_channel,
-               iface->conf->vht_oper_chwidth,
-               iface->conf->vht_oper_centr_freq_seg0_idx,
-               iface->conf->vht_oper_centr_freq_seg1_idx,
-               iface->dfs_cac_ms / 1000);

-       res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
-                                   iface->freq,
-                                   iface->conf->channel,
-                                   iface->conf->ieee80211n,
-                                   iface->conf->ieee80211ac,
-                                   iface->conf->secondary_channel,
-                                   iface->conf->vht_oper_chwidth,
-                                   iface->conf->vht_oper_centr_freq_seg0_idx,
-                                   iface->conf->vht_oper_centr_freq_seg1_idx);
-
-       if (res) {
-               wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
-               return -1;
-       }
-
-       return 0;
+       return dfs_start_cac(iface);
 }


@@ -763,18 +769,43 @@  static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
        return dfs_check_chans_available(iface, start_chan_idx, n_chans);
 }

+static void hostapd_dfs_cac_restart(void *eloop_data, void *user_ctx)
+{
+       struct hostapd_iface *iface = eloop_data;
+       int res;
+
+       if (iface->state != HAPD_IFACE_DFS || !iface->cac_started) {
+               wpa_printf(MSG_WARNING, "CAC restart in wrong state=%d; started=%d",
+                          iface->state, iface->cac_started);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "DFS restart CAC on %d MHz", iface->freq);
+       res = dfs_start_cac(iface);
+
+       if (res)
+               hostapd_setup_interface_complete(iface, res);
+}

 int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
                             int ht_enabled, int chan_offset, int chan_width,
                             int cf1, int cf2)
 {
+       int res = 0;
+       int dfs_offload = !!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD);
+
        wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
                "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
                success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);

+       if (!iface->cac_started) {
+               wpa_printf(MSG_ERROR, "CAC complete received in wrong state");
+               return 1;
+       }
+
        if (success) {
                /* Complete iface/ap configuration */
-               if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+               if (dfs_offload) {
                        /* Complete AP configuration for the first bring up. */
                        if (iface->state != HAPD_IFACE_ENABLED)
                                hostapd_setup_interface_complete(iface, 0);
@@ -800,9 +831,21 @@  int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
                                iface->cac_started = 0;
                        }
                }
+       } else {
+               if (dfs_offload) {
+                       if (iface->state == HAPD_IFACE_ENABLED)
+                               iface->cac_started = 0;
+               } else if (iface->state == HAPD_IFACE_DFS) {
+                       /* Schedule CAC restart in 1 second */
+                       eloop_register_timeout(1, 0, hostapd_dfs_cac_restart,
+                                              iface, NULL);
+               } else {
+                       wpa_printf(MSG_ERROR, "CAC aborted received in wrong state=%d offload=%d",
+                                  iface->state, dfs_offload);
+               }
        }

-       return 0;
+       return res;
 }


@@ -1074,7 +1117,7 @@  int hostapd_is_dfs_required(struct hostapd_iface *iface)
 }


-int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+int hostapd_dfs_cac_started(struct hostapd_iface *iface, int freq,
                          int ht_enabled, int chan_offset, int chan_width,
                          int cf1, int cf2)
 {
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index f0fa6f688..2d1532815 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -25,7 +25,7 @@  int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
                             int ht_enabled,
                             int chan_offset, int chan_width, int cf1, int cf2);
 int hostapd_is_dfs_required(struct hostapd_iface *iface);
-int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+int hostapd_dfs_cac_started(struct hostapd_iface *iface, int freq,
                          int ht_enabled, int chan_offset, int chan_width,
                          int cf1, int cf2);
 int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index e4a458107..58e967704 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1398,9 +1398,9 @@  static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
                                          struct dfs_event *radar)
 {
        wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
-       hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
-                             radar->chan_offset, radar->chan_width,
-                             radar->cf1, radar->cf2);
+       hostapd_dfs_cac_started(hapd->iface, radar->freq, radar->ht_enabled,
+                               radar->chan_offset, radar->chan_width,
+                               radar->cf1, radar->cf2);
 }

 #endif /* NEED_AP_MLME */