Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / net / mac80211 / rate.c
index 0388c09..6d0bd19 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/rtnetlink.h>
+#include <linux/slab.h>
 #include "rate.h"
 #include "ieee80211_i.h"
+#include "debugfs.h"
 
 struct rate_control_alg {
        struct list_head list;
@@ -127,19 +129,45 @@ static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
        module_put(ops->module);
 }
 
-struct rate_control_ref *rate_control_alloc(const char *name,
+#ifdef CONFIG_MAC80211_DEBUGFS
+static ssize_t rcname_read(struct file *file, char __user *userbuf,
+                          size_t count, loff_t *ppos)
+{
+       struct rate_control_ref *ref = file->private_data;
+       int len = strlen(ref->ops->name);
+
+       return simple_read_from_buffer(userbuf, count, ppos,
+                                      ref->ops->name, len);
+}
+
+static const struct file_operations rcname_ops = {
+       .read = rcname_read,
+       .open = mac80211_open_file_generic,
+};
+#endif
+
+static struct rate_control_ref *rate_control_alloc(const char *name,
                                            struct ieee80211_local *local)
 {
+       struct dentry *debugfsdir = NULL;
        struct rate_control_ref *ref;
 
        ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
        if (!ref)
                goto fail_ref;
        kref_init(&ref->kref);
+       ref->local = local;
        ref->ops = ieee80211_rate_control_ops_get(name);
        if (!ref->ops)
                goto fail_ops;
-       ref->priv = ref->ops->alloc(local);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
+       local->debugfs.rcdir = debugfsdir;
+       debugfs_create_file("name", 0400, debugfsdir, ref, &rcname_ops);
+#endif
+
+       ref->priv = ref->ops->alloc(&local->hw, debugfsdir);
        if (!ref->priv)
                goto fail_priv;
        return ref;
@@ -158,46 +186,155 @@ static void rate_control_release(struct kref *kref)
 
        ctrl_ref = container_of(kref, struct rate_control_ref, kref);
        ctrl_ref->ops->free(ctrl_ref->priv);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir);
+       ctrl_ref->local->debugfs.rcdir = NULL;
+#endif
+
        ieee80211_rate_control_ops_put(ctrl_ref->ops);
        kfree(ctrl_ref);
 }
 
-void rate_control_get_rate(struct net_device *dev,
-                          struct ieee80211_supported_band *sband,
-                          struct sk_buff *skb,
-                          struct rate_selection *sel)
+static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct rate_control_ref *ref = local->rate_ctrl;
+       struct sk_buff *skb = txrc->skb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct sta_info *sta;
-       int i;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       __le16 fc;
 
-       rcu_read_lock();
-       sta = sta_info_get(local, hdr->addr1);
+       fc = hdr->frame_control;
 
-       sel->rate_idx = -1;
-       sel->nonerp_idx = -1;
-       sel->probe_idx = -1;
+       return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
+}
 
-       ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
+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;
+               }
+       }
 
-       BUG_ON(sel->rate_idx < 0);
+       /* could not find a basic rate; use original selection */
+}
 
-       /* Select a non-ERP backup rate. */
-       if (sel->nonerp_idx < 0) {
-               for (i = 0; i < sband->n_bitrates; i++) {
-                       struct ieee80211_rate *rate = &sband->bitrates[i];
-                       if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
-                               break;
+bool rate_control_send_low(struct ieee80211_sta *sta,
+                          void *priv_sta,
+                          struct ieee80211_tx_rate_control *txrc)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+
+       if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
+               info->control.rates[0].idx = rate_lowest_index(txrc->sband, 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)
+{
+       struct rate_control_ref *ref = sdata->local->rate_ctrl;
+       void *priv_sta = NULL;
+       struct ieee80211_sta *ista = NULL;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+       int i;
+       u32 mask;
+
+       if (sta) {
+               ista = &sta->sta;
+               priv_sta = sta->rate_ctrl_priv;
+       }
+
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               info->control.rates[i].idx = -1;
+               info->control.rates[i].flags = 0;
+               info->control.rates[i].count = 1;
+       }
 
-                       if (rate_supported(sta, sband->band, i) &&
-                           !(rate->flags & IEEE80211_RATE_ERP_G))
-                               sel->nonerp_idx = i;
+       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 rateidx mask the user wanted. skip this if the
+        * default mask (allow all rates) is used to save some processing for
+        * the common case.
+        */
+       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;
+                       rate_idx_match_mask(&info->control.rates[i],
+                                           txrc->sband->n_bitrates, mask);
                }
        }
 
-       rcu_read_unlock();
+       BUG_ON(info->control.rates[0].idx < 0);
 }
 
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
@@ -217,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 || netif_running(local->mdev))
+
+       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 "
@@ -238,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;
 }
 
@@ -247,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);
 }