mwifiex: channel switch handling for station
authorAmitkumar Karwar <akarwar@marvell.com>
Tue, 18 Jun 2013 23:36:58 +0000 (16:36 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 19 Jun 2013 19:28:43 +0000 (15:28 -0400)
After receiving channel switch announcement from AP, scan and
association on that channel is blocked for DFS_CHAN_MOVE_TIME
(10 seconds). Hence station will be able to connect to the AP,
once it is moved to new channel.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Paul Stewart <pstew@chromium.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/sta_ioctl.c

index b6fbbf64cf969365de05af124089938f12c0c7ba..1b45aa5333008c9475595f91123c1bcb2f81e018 100644 (file)
@@ -245,6 +245,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HT_BW_20    0
 #define HT_BW_40    1
 
+#define DFS_CHAN_MOVE_TIME      10000
+
 #define HostCmd_CMD_GET_HW_SPEC                       0x0003
 #define HostCmd_CMD_802_11_SCAN                       0x0006
 #define HostCmd_CMD_802_11_GET_LOG                    0x000b
index 2fe31dcaa6ef2e9deac6afbb6082410774047678..caaf4bd56b3062ea4c9a11028233c1517f69296c 100644 (file)
@@ -133,6 +133,9 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
 
        priv->scan_block = false;
 
+       priv->csa_chan = 0;
+       priv->csa_expire_time = 0;
+
        return mwifiex_add_bss_prio_tbl(priv);
 }
 
index 95a6f5269c6cdb9e15f7f9974c2fd848ebd1bd4d..3da73d36acdf5e9a5ebe30ce75333704d98a00c0 100644 (file)
@@ -513,6 +513,8 @@ struct mwifiex_private {
        u32 mgmt_frame_mask;
        struct mwifiex_roc_cfg roc_cfg;
        bool scan_aborting;
+       u8 csa_chan;
+       unsigned long csa_expire_time;
 };
 
 enum mwifiex_ba_status {
@@ -1021,6 +1023,24 @@ static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb)
        return (*(u32 *)skb->data == PKT_TYPE_MGMT);
 }
 
+/* This function retrieves channel closed for operation by Channel
+ * Switch Announcement.
+ */
+static inline u8
+mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv)
+{
+       if (!priv->csa_chan)
+               return 0;
+
+       /* Clear csa channel, if DFS channel move time has passed */
+       if (jiffies > priv->csa_expire_time) {
+               priv->csa_chan = 0;
+               priv->csa_expire_time = 0;
+       }
+
+       return priv->csa_chan;
+}
+
 int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
                             u32 func_init_shutdown);
 int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
index 284d68bf6acca2cd37639b0f0a47021e214f3370..c447d9bd1aa93746f5ad68b7c9205e1e85e20810 100644 (file)
@@ -575,6 +575,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                return -1;
        }
 
+       /* Check csa channel expiry before preparing scan list */
+       mwifiex_11h_get_csa_closed_channel(priv);
+
        chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
 
        /* Set the temp channel struct pointer to the start of the desired
@@ -604,6 +607,11 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                while (tlv_idx < max_chan_per_scan &&
                       tmp_chan_list->chan_number && !done_early) {
 
+                       if (tmp_chan_list->chan_number == priv->csa_chan) {
+                               tmp_chan_list++;
+                               continue;
+                       }
+
                        dev_dbg(priv->adapter->dev,
                                "info: Scan: Chan(%3d), Radio(%d),"
                                " Mode(%d, %d), Dur(%d)\n",
@@ -1594,6 +1602,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                goto check_next_scan;
        }
 
+       /* Check csa channel expiry before parsing scan response */
+       mwifiex_11h_get_csa_closed_channel(priv);
+
        bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
        dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
                bytes_left);
@@ -1746,6 +1757,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                        struct ieee80211_channel *chan;
                        u8 band;
 
+                       /* Skip entry if on csa closed channel */
+                       if (channel == priv->csa_chan) {
+                               dev_dbg(adapter->dev,
+                                       "Dropping entry on csa closed channel\n");
+                               continue;
+                       }
+
                        band = BAND_G;
                        if (chan_band_tlv) {
                                chan_band =
index d28c92005cceccd099943af65eefb49375b8b989..ea265ec0e522333837a13ab43a16d74ccaae7550 100644 (file)
@@ -429,6 +429,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_CHANNEL_SWITCH_ANN:
                dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+               priv->csa_expire_time =
+                               jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
+               priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
                ret = mwifiex_send_cmd_async(priv,
                        HostCmd_CMD_802_11_DEAUTHENTICATE,
                        HostCmd_ACT_GEN_SET, 0,
index 498add76a46d0b1a29af99dc60fb5b2fc96b91fb..206c3e03807235425ee3c0ad12676cc7c187cad7 100644 (file)
@@ -281,6 +281,14 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                if (ret)
                        goto done;
 
+               if (mwifiex_11h_get_csa_closed_channel(priv) ==
+                                                       (u8)bss_desc->channel) {
+                       dev_err(adapter->dev,
+                               "Attempt to reconnect on csa closed chan(%d)\n",
+                               bss_desc->channel);
+                       goto done;
+               }
+
                dev_dbg(adapter->dev, "info: SSID found in scan list ... "
                                      "associating...\n");