Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / net / mac80211 / rate.c
index b33efc4..6d0bd19 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/kernel.h>
 #include <linux/rtnetlink.h>
+#include <linux/slab.h>
 #include "rate.h"
 #include "ieee80211_i.h"
 #include "debugfs.h"
@@ -145,7 +146,7 @@ static const struct file_operations rcname_ops = {
 };
 #endif
 
-struct rate_control_ref *rate_control_alloc(const char *name,
+static struct rate_control_ref *rate_control_alloc(const char *name,
                                            struct ieee80211_local *local)
 {
        struct dentry *debugfsdir = NULL;
@@ -163,8 +164,7 @@ struct rate_control_ref *rate_control_alloc(const char *name,
 #ifdef CONFIG_MAC80211_DEBUGFS
        debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
        local->debugfs.rcdir = debugfsdir;
-       local->debugfs.rcname = debugfs_create_file("name", 0400, debugfsdir,
-                                                   ref, &rcname_ops);
+       debugfs_create_file("name", 0400, debugfsdir, ref, &rcname_ops);
 #endif
 
        ref->priv = ref->ops->alloc(&local->hw, debugfsdir);
@@ -188,9 +188,7 @@ static void rate_control_release(struct kref *kref)
        ctrl_ref->ops->free(ctrl_ref->priv);
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-       debugfs_remove(ctrl_ref->local->debugfs.rcname);
-       ctrl_ref->local->debugfs.rcname = NULL;
-       debugfs_remove(ctrl_ref->local->debugfs.rcdir);
+       debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir);
        ctrl_ref->local->debugfs.rcdir = NULL;
 #endif
 
@@ -210,6 +208,27 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
        return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
 }
 
+static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx)
+{
+       u8 i;
+
+       if (basic_rates == 0)
+               return; /* assume basic rates unknown and accept rate */
+       if (*idx < 0)
+               return;
+       if (basic_rates & (1 << *idx))
+               return; /* selected rate is a basic rate */
+
+       for (i = *idx + 1; i <= max_rate_idx; i++) {
+               if (basic_rates & (1 << i)) {
+                       *idx = i;
+                       return;
+               }
+       }
+
+       /* could not find a basic rate; use original selection */
+}
+
 bool rate_control_send_low(struct ieee80211_sta *sta,
                           void *priv_sta,
                           struct ieee80211_tx_rate_control *txrc)
@@ -221,12 +240,48 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
                info->control.rates[0].count =
                        (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
                        1 : txrc->hw->max_rate_tries;
+               if (!sta && txrc->ap)
+                       rc_send_low_broadcast(&info->control.rates[0].idx,
+                                             txrc->bss_conf->basic_rates,
+                                             txrc->sband->n_bitrates);
                return true;
        }
        return false;
 }
 EXPORT_SYMBOL(rate_control_send_low);
 
+static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
+                               int n_bitrates, u32 mask)
+{
+       int j;
+
+       /* See whether the selected rate or anything below it is allowed. */
+       for (j = rate->idx; j >= 0; j--) {
+               if (mask & (1 << j)) {
+                       /* Okay, found a suitable rate. Use it. */
+                       rate->idx = j;
+                       return;
+               }
+       }
+
+       /* Try to find a higher rate that would be allowed */
+       for (j = rate->idx + 1; j < n_bitrates; j++) {
+               if (mask & (1 << j)) {
+                       /* Okay, found a suitable rate. Use it. */
+                       rate->idx = j;
+                       return;
+               }
+       }
+
+       /*
+        * Uh.. No suitable rate exists. This should not really happen with
+        * sane TX rate mask configurations. However, should someone manage to
+        * configure supported rates and TX rate mask in incompatible way,
+        * allow the frame to be transmitted with whatever the rate control
+        * selected.
+        */
+}
+
 void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
                           struct sta_info *sta,
                           struct ieee80211_tx_rate_control *txrc)
@@ -236,6 +291,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_sta *ista = NULL;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
        int i;
+       u32 mask;
 
        if (sta) {
                ista = &sta->sta;
@@ -248,23 +304,34 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
                info->control.rates[i].count = 1;
        }
 
-       if (sta && sdata->force_unicast_rateidx > -1) {
-               info->control.rates[0].idx = sdata->force_unicast_rateidx;
-       } else {
-               ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
-               info->flags |= IEEE80211_TX_INTFL_RCALGO;
-       }
+       if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return;
+
+       ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
 
        /*
-        * try to enforce the maximum rate the user wanted
+        * Try to enforce the rateidx mask the user wanted. skip this if the
+        * default mask (allow all rates) is used to save some processing for
+        * the common case.
         */
-       if (sdata->max_ratectrl_rateidx > -1)
+       mask = sdata->rc_rateidx_mask[info->band];
+       if (mask != (1 << txrc->sband->n_bitrates) - 1) {
+               if (sta) {
+                       /* Filter out rates that the STA does not support */
+                       mask &= sta->sta.supp_rates[info->band];
+               }
+               /*
+                * Make sure the rate index selected for each TX rate is
+                * included in the configured mask and change the rate indexes
+                * if needed.
+                */
                for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+                       /* Rate masking supports only legacy rates for now */
                        if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
                                continue;
-                       info->control.rates[i].idx =
-                               min_t(s8, info->control.rates[i].idx,
-                                     sdata->max_ratectrl_rateidx);
+                       rate_idx_match_mask(&info->control.rates[i],
+                                           txrc->sband->n_bitrates, mask);
+               }
        }
 
        BUG_ON(info->control.rates[0].idx < 0);
@@ -287,9 +354,16 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
        struct rate_control_ref *ref, *old;
 
        ASSERT_RTNL();
+
        if (local->open_count)
                return -EBUSY;
 
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
+               if (WARN_ON(!local->ops->set_rts_threshold))
+                       return -EINVAL;
+               return 0;
+       }
+
        ref = rate_control_alloc(name, local);
        if (!ref) {
                printk(KERN_WARNING "%s: Failed to select rate control "
@@ -308,7 +382,6 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
               "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
               ref->ops->name);
 
-
        return 0;
 }
 
@@ -317,6 +390,10 @@ void rate_control_deinitialize(struct ieee80211_local *local)
        struct rate_control_ref *ref;
 
        ref = local->rate_ctrl;
+
+       if (!ref)
+               return;
+
        local->rate_ctrl = NULL;
        rate_control_put(ref);
 }