mwl8k: honor peer rate set
authorLennert Buytenhek <buytenh@wantstofly.org>
Mon, 4 Jan 2010 20:55:52 +0000 (21:55 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 5 Jan 2010 22:13:28 +0000 (17:13 -0500)
When calling SET_RATE, SET_AID, or when creating a station database
entry for our AP, pass in the AP's rate set instead of just blindly
enabling all legacy rates, so as to end up doing the right thing when
talking to 11b-only APs.

Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwl8k.c

index 5b5cf9357dbf3a3b6d19fcf831cb6ad11f78693f..d8eff68978f1e0414cbdb4c931148a096635ffdd 100644 (file)
@@ -256,10 +256,6 @@ static const struct ieee80211_rate mwl8k_rates[] = {
        { .bitrate = 720, .hw_value = 144, },
 };
 
-static const u8 mwl8k_rateids[12] = {
-       2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108,
-};
-
 /* Set or get info from Firmware */
 #define MWL8K_CMD_SET                  0x0001
 #define MWL8K_CMD_GET                  0x0000
@@ -2076,8 +2072,25 @@ struct mwl8k_cmd_update_set_aid {
        __u8    supp_rates[14];
 } __attribute__((packed));
 
+static void legacy_rate_mask_to_array(u8 *rates, u32 mask)
+{
+       int i;
+       int j;
+
+       /*
+        * Clear nonstandard rates 4 and 13.
+        */
+       mask &= 0x1fef;
+
+       for (i = 0, j = 0; i < 14; i++) {
+               if (mask & (1 << i))
+                       rates[j++] = mwl8k_rates[i].hw_value;
+       }
+}
+
 static int
-mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
+                 struct ieee80211_vif *vif, u32 legacy_rate_mask)
 {
        struct mwl8k_cmd_update_set_aid *cmd;
        u16 prot_mode;
@@ -2090,7 +2103,6 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
        cmd->aid = cpu_to_le16(vif->bss_conf.aid);
-
        memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
 
        if (vif->bss_conf.use_cts_prot) {
@@ -2111,7 +2123,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        }
        cmd->protection_mode = cpu_to_le16(prot_mode);
 
-       memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+       legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2132,7 +2144,8 @@ struct mwl8k_cmd_set_rate {
 } __attribute__((packed));
 
 static int
-mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                  u32 legacy_rate_mask)
 {
        struct mwl8k_cmd_set_rate *cmd;
        int rc;
@@ -2143,7 +2156,7 @@ mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
        cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+       legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2644,7 +2657,8 @@ struct mwl8k_cmd_update_stadb {
 #define MWL8K_PEER_TYPE_ACCESSPOINT    2
 
 static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
-                                     struct ieee80211_vif *vif, u8 *addr)
+                                     struct ieee80211_vif *vif,
+                                     u8 *addr, u32 legacy_rate_mask)
 {
        struct mwl8k_cmd_update_stadb *cmd;
        struct peer_capability_info *p;
@@ -2662,7 +2676,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
        p = &cmd->peer_info;
        p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
        p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability);
-       memcpy(p->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+       legacy_rate_mask_to_array(p->legacy_rates, legacy_rate_mask);
        p->interop = 1;
        p->amsdu_enabled = 0;
 
@@ -2956,8 +2970,20 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
                return;
 
        if (vif->bss_conf.assoc) {
+               struct ieee80211_sta *ap;
+               u32 legacy_rate_mask;
+
+               rcu_read_lock();
+               ap = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+               if (ap != NULL)
+                       legacy_rate_mask = ap->supp_rates[IEEE80211_BAND_2GHZ];
+               rcu_read_unlock();
+
+               if (ap == NULL)
+                       goto out;
+
                /* Install rates */
-               rc = mwl8k_cmd_set_rate(hw, vif);
+               rc = mwl8k_cmd_set_rate(hw, vif, legacy_rate_mask);
                if (rc)
                        goto out;
 
@@ -2979,7 +3005,7 @@ static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
                        goto out;
 
                /* Set AID */
-               rc = mwl8k_cmd_set_aid(hw, vif);
+               rc = mwl8k_cmd_set_aid(hw, vif, legacy_rate_mask);
                if (rc)
                        goto out;
 
@@ -3139,6 +3165,7 @@ struct mwl8k_sta_notify_item
        struct ieee80211_vif *vif;
        enum sta_notify_cmd cmd;
        u8 addr[ETH_ALEN];
+       u32 legacy_rate_mask;
 };
 
 static void mwl8k_sta_notify_worker(struct work_struct *work)
@@ -3160,7 +3187,8 @@ static void mwl8k_sta_notify_worker(struct work_struct *work)
                if (s->cmd == STA_NOTIFY_ADD) {
                        int rc;
 
-                       rc = mwl8k_cmd_update_stadb_add(hw, s->vif, s->addr);
+                       rc = mwl8k_cmd_update_stadb_add(hw, s->vif,
+                                               s->addr, s->legacy_rate_mask);
                        if (rc >= 0) {
                                struct ieee80211_sta *sta;
 
@@ -3196,6 +3224,7 @@ mwl8k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                s->vif = vif;
                s->cmd = cmd;
                memcpy(s->addr, sta->addr, ETH_ALEN);
+               s->legacy_rate_mask = sta->supp_rates[IEEE80211_BAND_2GHZ];
 
                spin_lock(&priv->sta_notify_list_lock);
                list_add_tail(&s->list, &priv->sta_notify_list);