[PATCH] softmac: suggest per-frame-type TX rate

This patch is the first step towards rate control inside softmac.

The txrates substructure has been extended to provide
different fields for different types of packets (management/data,
unicast/multicast). These fields are updated on association to values
compatible with the access point we are associating to.

Drivers can then use the new ieee80211softmac_suggest_txrate() function
call when deciding which rate to transmit each frame at. This is
immensely useful for ZD1211, and bcm can use it too.

The user can still specify a rate through iwconfig, which is matched
for all transmissions (assuming the rate they have specified is in
the rate set required by the AP).

At a later date, we can incorporate automatic rate management into
the ieee80211softmac_recalc_txrates() function.

This patch also removes the mcast_fallback field. Sam Leffler pointed
out that this field is meaningless, because no driver will ever be
retransmitting mcast frames (they are not acked).

Signed-off-by: Daniel Drake <dsd@gentoo.org>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Daniel Drake 2006-05-01 22:45:50 +01:00 committed by John W. Linville
parent 461c078c9c
commit 8462fe3cd9
5 changed files with 141 additions and 40 deletions

View file

@ -86,6 +86,9 @@ struct ieee80211softmac_assoc_info {
/* BSSID we're trying to associate to */ /* BSSID we're trying to associate to */
char bssid[ETH_ALEN]; char bssid[ETH_ALEN];
/* Rates supported by the network */
struct ieee80211softmac_ratesinfo supported_rates;
/* some flags. /* some flags.
* static_essid is valid if the essid is constant, * static_essid is valid if the essid is constant,
@ -132,23 +135,26 @@ enum {
struct ieee80211softmac_txrates { struct ieee80211softmac_txrates {
/* The Bit-Rate to be used for multicast frames. */ /* The Bit-Rate to be used for multicast frames. */
u8 mcast_rate; u8 mcast_rate;
/* The Bit-Rate to be used for multicast fallback
* (If the device supports fallback and hardware-retry) /* The Bit-Rate to be used for multicast management frames. */
*/ u8 mgt_mcast_rate;
u8 mcast_fallback;
/* The Bit-Rate to be used for any other (normal) data packet. */ /* The Bit-Rate to be used for any other (normal) data packet. */
u8 default_rate; u8 default_rate;
/* The Bit-Rate to be used for default fallback /* The Bit-Rate to be used for default fallback
* (If the device supports fallback and hardware-retry) * (If the device supports fallback and hardware-retry)
*/ */
u8 default_fallback; u8 default_fallback;
/* This is the rate that the user asked for */
u8 user_rate;
}; };
/* Bits for txrates_change callback. */ /* Bits for txrates_change callback. */
#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT (1 << 0) /* default_rate */ #define IEEE80211SOFTMAC_TXRATECHG_DEFAULT (1 << 0) /* default_rate */
#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */ #define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */
#define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */ #define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */
#define IEEE80211SOFTMAC_TXRATECHG_MCAST_FBACK (1 << 3) /* mcast_fallback */ #define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */
struct ieee80211softmac_device { struct ieee80211softmac_device {
/* 802.11 structure for data stuff */ /* 802.11 structure for data stuff */
@ -250,6 +256,28 @@ extern void ieee80211softmac_fragment_lost(struct net_device *dev,
* Note that the rates need to be sorted. */ * Note that the rates need to be sorted. */
extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates); extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
/* Helper function which advises you the rate at which a frame should be
* transmitted at. */
static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
int is_multicast,
int is_mgt)
{
struct ieee80211softmac_txrates *txrates = &mac->txrates;
if (!mac->associated)
return txrates->mgt_mcast_rate;
/* We are associated, sending unicast frame */
if (!is_multicast)
return txrates->default_rate;
/* We are associated, sending multicast frame */
if (is_mgt)
return txrates->mgt_mcast_rate;
else
return txrates->mcast_rate;
}
/* Start the SoftMAC. Call this after you initialized the device /* Start the SoftMAC. Call this after you initialized the device
* and it is ready to run. * and it is ready to run.
*/ */

View file

@ -96,6 +96,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
mac->associated = 0; mac->associated = 0;
mac->associnfo.bssvalid = 0; mac->associnfo.bssvalid = 0;
mac->associnfo.associating = 0; mac->associnfo.associating = 0;
ieee80211softmac_init_txrates(mac);
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
spin_unlock_irqrestore(&mac->lock, flags); spin_unlock_irqrestore(&mac->lock, flags);
} }
@ -118,24 +119,15 @@ ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reas
static inline int static inline int
we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
{ {
int idx, search, found; int idx;
u8 rate, search_rate; u8 rate;
for (idx = 0; idx < (from_len); idx++) { for (idx = 0; idx < (from_len); idx++) {
rate = (from)[idx]; rate = (from)[idx];
if (!(rate & IEEE80211_BASIC_RATE_MASK)) if (!(rate & IEEE80211_BASIC_RATE_MASK))
continue; continue;
found = 0;
rate &= ~IEEE80211_BASIC_RATE_MASK; rate &= ~IEEE80211_BASIC_RATE_MASK;
for (search = 0; search < mac->ratesinfo.count; search++) { if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
search_rate = mac->ratesinfo.rates[search];
search_rate &= ~IEEE80211_BASIC_RATE_MASK;
if (rate == search_rate) {
found = 1;
break;
}
}
if (!found)
return 0; return 0;
} }
return 1; return 1;
@ -310,6 +302,9 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *net) struct ieee80211softmac_network *net)
{ {
mac->associnfo.associating = 0; mac->associnfo.associating = 0;
mac->associnfo.supported_rates = net->supported_rates;
ieee80211softmac_recalc_txrates(mac);
mac->associated = 1; mac->associated = 1;
if (mac->set_bssid_filter) if (mac->set_bssid_filter)
mac->set_bssid_filter(mac->dev, net->bssid); mac->set_bssid_filter(mac->dev, net->bssid);

View file

@ -26,6 +26,7 @@
#include "ieee80211softmac_priv.h" #include "ieee80211softmac_priv.h"
#include <linux/sort.h> #include <linux/sort.h>
#include <linux/etherdevice.h>
struct net_device *alloc_ieee80211softmac(int sizeof_priv) struct net_device *alloc_ieee80211softmac(int sizeof_priv)
{ {
@ -61,14 +62,6 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv)
softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
softmac->stop_scan = ieee80211softmac_stop_scan_implementation; softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
//TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
// It has to be set to the highest rate all stations in the current network can handle.
softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
/* This is reassigned in ieee80211softmac_start to sane values. */
softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
/* to start with, we can't send anything ... */ /* to start with, we can't send anything ... */
netif_carrier_off(dev); netif_carrier_off(dev);
@ -170,15 +163,82 @@ static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *m
} }
} }
void ieee80211softmac_start(struct net_device *dev) int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
{
int search;
u8 search_rate;
for (search = 0; search < ri->count; search++) {
search_rate = ri->rates[search];
search_rate &= ~IEEE80211_BASIC_RATE_MASK;
if (rate == search_rate)
return 1;
}
return 0;
}
/* Finds the highest rate which is:
* 1. Present in ri (optionally a basic rate)
* 2. Supported by the device
* 3. Less than or equal to the user-defined rate
*/
static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
struct ieee80211softmac_ratesinfo *ri, int basic_only)
{
u8 user_rate = mac->txrates.user_rate;
int i;
if (ri->count == 0) {
dprintk(KERN_ERR PFX "empty ratesinfo?\n");
return IEEE80211_CCK_RATE_1MB;
}
for (i = ri->count - 1; i >= 0; i--) {
u8 rate = ri->rates[i];
if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
continue;
rate &= ~IEEE80211_BASIC_RATE_MASK;
if (rate > user_rate)
continue;
if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
return rate;
}
/* If we haven't found a suitable rate by now, just trust the user */
return user_rate;
}
void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
{
struct ieee80211softmac_txrates *txrates = &mac->txrates;
struct ieee80211softmac_txrates oldrates;
u32 change = 0;
if (mac->txrates_change)
oldrates = mac->txrates;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
txrates->default_fallback = lower_rate(mac, txrates->default_rate);
change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
if (mac->txrates_change)
mac->txrates_change(mac->dev, change, &oldrates);
}
void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
{ {
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
struct ieee80211_device *ieee = mac->ieee; struct ieee80211_device *ieee = mac->ieee;
u32 change = 0; u32 change = 0;
struct ieee80211softmac_txrates *txrates = &mac->txrates;
struct ieee80211softmac_txrates oldrates; struct ieee80211softmac_txrates oldrates;
ieee80211softmac_start_check_rates(mac);
/* TODO: We need some kind of state machine to lower the default rates /* TODO: We need some kind of state machine to lower the default rates
* if we loose too many packets. * if we loose too many packets.
*/ */
@ -193,22 +253,37 @@ void ieee80211softmac_start(struct net_device *dev)
more reliable. Note similar logic in more reliable. Note similar logic in
ieee80211softmac_wx_set_rate() */ ieee80211softmac_wx_set_rate() */
if (ieee->modulation & IEEE80211_CCK_MODULATION) { if (ieee->modulation & IEEE80211_CCK_MODULATION) {
mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB; txrates->user_rate = IEEE80211_CCK_RATE_11MB;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
} else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
} else } else
assert(0); assert(0);
txrates->default_rate = IEEE80211_CCK_RATE_1MB;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
if (mac->txrates_change) if (mac->txrates_change)
mac->txrates_change(dev, change, &oldrates); mac->txrates_change(mac->dev, change, &oldrates);
mac->running = 1; mac->running = 1;
} }
void ieee80211softmac_start(struct net_device *dev)
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
ieee80211softmac_start_check_rates(mac);
ieee80211softmac_init_txrates(mac);
}
EXPORT_SYMBOL_GPL(ieee80211softmac_start); EXPORT_SYMBOL_GPL(ieee80211softmac_start);
void ieee80211softmac_stop(struct net_device *dev) void ieee80211softmac_stop(struct net_device *dev)

View file

@ -116,7 +116,10 @@ ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
struct ieee80211softmac_essid *essid); struct ieee80211softmac_essid *essid);
/* Rates related */ /* Rates related */
int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
return ieee80211softmac_lower_rate_delta(mac, rate, 1); return ieee80211softmac_lower_rate_delta(mac, rate, 1);
} }

View file

@ -211,8 +211,8 @@ ieee80211softmac_wx_set_rate(struct net_device *net_dev,
if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
goto out_unlock; goto out_unlock;
mac->txrates.default_rate = rate; mac->txrates.user_rate = rate;
mac->txrates.default_fallback = lower_rate(mac, rate); ieee80211softmac_recalc_txrates(mac);
err = 0; err = 0;
out_unlock: out_unlock: