iwmc3200wifi: refuse to associate on unallowed channels
authorZhu Yi <yi.zhu@intel.com>
Thu, 25 Feb 2010 06:15:25 +0000 (14:15 +0800)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 10 Mar 2010 22:09:37 +0000 (17:09 -0500)
We need to make sure we don't associate with APs on unallowed
channels (according to regulatory setting). This could happen
when the channel is not specified (auto-select) within the
connection request. In this case we get the AP's channel until
the firmware indicates the association succeeded later. We need
to verify the associated channel. If the channel is disabled by
regulatory, we have to disassociate with the AP.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwmc3200wifi/commands.c
drivers/net/wireless/iwmc3200wifi/commands.h
drivers/net/wireless/iwmc3200wifi/rx.c

index 1e41ad0fcad5c8cd5989dcadf0fa1345e6634dc5..9ef4fd045041c59fd5995353f56f47fa1380c40d 100644 (file)
@@ -781,10 +781,9 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
        return 0;
 }
 
-int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
+int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 {
        struct iwm_umac_invalidate_profile invalid;
-       int ret;
 
        invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
        invalid.hdr.buf_size =
@@ -793,7 +792,14 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 
        invalid.reason = WLAN_REASON_UNSPECIFIED;
 
-       ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
+       return iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
+}
+
+int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
+{
+       int ret;
+
+       ret = __iwm_invalidate_mlme_profile(iwm);
        if (ret)
                return ret;
 
index 3dfd9f0e90035ba3043268cc1a53110454e20621..7e16bcf59978a99c6a78f38b4913484447072b0f 100644 (file)
@@ -488,6 +488,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
                            void *payload, u16 payload_size);
 int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags);
 int iwm_send_mlme_profile(struct iwm_priv *iwm);
+int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
 int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
 int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
 int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
index ad8f7eabb5aa283f9c8954860b1198b37af13ecc..36b1580329cc32b7dff67f4cb8656d6ae6087720 100644 (file)
@@ -518,6 +518,8 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                                   unsigned long buf_size,
                                   struct iwm_wifi_cmd *cmd)
 {
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
+       struct ieee80211_channel *chan;
        struct iwm_umac_notif_assoc_complete *complete =
                (struct iwm_umac_notif_assoc_complete *)buf;
 
@@ -526,6 +528,18 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 
        switch (le32_to_cpu(complete->status)) {
        case UMAC_ASSOC_COMPLETE_SUCCESS:
+               chan = ieee80211_get_channel(wiphy,
+                       ieee80211_channel_to_frequency(complete->channel));
+               if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+                       /* Associated to a unallowed channel, disassociate. */
+                       __iwm_invalidate_mlme_profile(iwm);
+                       IWM_WARN(iwm, "Couldn't associate with %pM due to "
+                                "channel %d is disabled. Check your local "
+                                "regulatory setting.\n",
+                                complete->bssid, complete->channel);
+                       goto failure;
+               }
+
                set_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
                memcpy(iwm->bssid, complete->bssid, ETH_ALEN);
                iwm->channel = complete->channel;
@@ -562,6 +576,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                                        GFP_KERNEL);
                break;
        case UMAC_ASSOC_COMPLETE_FAILURE:
+ failure:
                clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
                memset(iwm->bssid, 0, ETH_ALEN);
                iwm->channel = 0;