--- linux/include/net/ieee80211softmac.h.orig 2006-04-16 23:37:32.000000000 +0100 +++ linux/include/net/ieee80211softmac.h 2006-04-17 18:40:04.000000000 +0100 @@ -86,6 +86,9 @@ struct ieee80211softmac_assoc_info { /* BSSID we're trying to associate to */ char bssid[ETH_ALEN]; + + /* Rates supported by the network */ + struct ieee80211softmac_ratesinfo supported_rates; /* some flags. * static_essid is valid if the essid is constant, @@ -133,12 +136,23 @@ struct ieee80211softmac_txrates { * (If the device supports fallback and hardware-retry) */ u8 mcast_fallback; + + /* The Bit-Rate to be used for multicast management frames. */ + u8 mgt_mcast_rate; + /* The Bit-Rate to be used for multicast management fallback + * (If the device supports fallback and hardware-retry) + */ + u8 mgt_mcast_fallback; + /* The Bit-Rate to be used for any other (normal) data packet. */ u8 default_rate; /* The Bit-Rate to be used for default fallback * (If the device supports fallback and hardware-retry) */ u8 default_fallback; + + /* This is the rate that the user asked for */ + u8 user_rate; }; /* Bits for txrates_change callback. */ @@ -146,6 +160,8 @@ struct ieee80211softmac_txrates { #define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */ #define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */ #define IEEE80211SOFTMAC_TXRATECHG_MCAST_FBACK (1 << 3) /* mcast_fallback */ +#define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 4) /* mgt_mcast_rate */ +#define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST_FBACK (1 << 5) /* mgt_mcast_fallback */ struct ieee80211softmac_device { /* 802.11 structure for data stuff */ @@ -246,6 +262,28 @@ extern void ieee80211softmac_fragment_lo * Note that the rates need to be sorted. */ 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 * and it is ready to run. */ --- linux/net/ieee80211/softmac/ieee80211softmac_module.c.orig 2006-04-17 01:04:42.000000000 +0100 +++ linux/net/ieee80211/softmac/ieee80211softmac_module.c 2006-04-17 18:30:04.000000000 +0100 @@ -26,6 +26,7 @@ #include "ieee80211softmac_priv.h" #include +#include struct net_device *alloc_ieee80211softmac(int sizeof_priv) { @@ -166,15 +167,85 @@ static void ieee80211softmac_start_check } } -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_ERROR 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); + + change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST_FBACK; + txrates->mcast_fallback = lower_rate(mac, txrates->mcast_rate); + + 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; u32 change = 0; + struct ieee80211softmac_txrates *txrates = &mac->txrates; struct ieee80211softmac_txrates oldrates; - ieee80211softmac_start_check_rates(mac); - /* TODO: We need some kind of state machine to lower the default rates * if we loose too many packets. */ @@ -189,19 +260,40 @@ void ieee80211softmac_start(struct net_d more reliable. Note similar logic in ieee80211softmac_wx_set_rate() */ if (ieee->modulation & IEEE80211_CCK_MODULATION) { - mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; + txrates->user_rate = IEEE80211_CCK_RATE_11MB; } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { - mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; + txrates->user_rate = IEEE80211_OFDM_RATE_54MB; } else 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->mcast_fallback = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_MCAST_FBACK; + + txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST; + + txrates->mgt_mcast_fallback = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST_FBACK; + if (mac->txrates_change) - mac->txrates_change(dev, change, &oldrates); + mac->txrates_change(mac->dev, change, &oldrates); +} + +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); --- linux/net/ieee80211/softmac/ieee80211softmac_assoc.c.orig 2006-04-16 23:55:23.000000000 +0100 +++ linux/net/ieee80211/softmac/ieee80211softmac_assoc.c 2006-04-17 17:17:59.000000000 +0100 @@ -101,30 +101,22 @@ ieee80211softmac_disassoc(struct ieee802 /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */ mac->associated = 0; mac->associnfo.associating = 0; + ieee80211softmac_init_txrates(mac); spin_unlock_irqrestore(&mac->lock, flags); } static inline int we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) { - int idx, search, found; - u8 rate, search_rate; + int idx; + u8 rate; for (idx = 0; idx < (from_len); idx++) { rate = (from)[idx]; if (!(rate & IEEE80211_BASIC_RATE_MASK)) continue; - found = 0; rate &= ~IEEE80211_BASIC_RATE_MASK; - for (search = 0; search < mac->ratesinfo.count; search++) { - search_rate = mac->ratesinfo.rates[search]; - search_rate &= ~IEEE80211_BASIC_RATE_MASK; - if (rate == search_rate) { - found = 1; - break; - } - } - if (!found) + if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) return 0; } return 1; @@ -283,6 +275,9 @@ ieee80211softmac_associated(struct ieee8 struct ieee80211softmac_network *net) { mac->associnfo.associating = 0; + mac->associnfo.supported_rates = net->supported_rates; + ieee80211softmac_recalc_txrates(mac); + mac->associated = 1; if (mac->set_bssid_filter) mac->set_bssid_filter(mac->dev, net->bssid); @@ -373,6 +368,7 @@ ieee80211softmac_handle_disassoc(struct spin_lock_irqsave(&mac->lock, flags); mac->associnfo.bssvalid = 0; mac->associated = 0; + ieee80211softmac_init_txrates(mac); schedule_work(&mac->associnfo.work); spin_unlock_irqrestore(&mac->lock, flags); --- linux/net/ieee80211/softmac/ieee80211softmac_wx.c.orig 2006-04-17 16:45:51.000000000 +0100 +++ linux/net/ieee80211/softmac/ieee80211softmac_wx.c 2006-04-17 17:27:47.000000000 +0100 @@ -201,8 +201,8 @@ ieee80211softmac_wx_set_rate(struct net_ if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) goto out_unlock; - mac->txrates.default_rate = rate; - mac->txrates.default_fallback = lower_rate(mac, rate); + mac->txrates.user_rate = rate; + ieee80211softmac_recalc_txrates(mac); err = 0; out_unlock: @@ -223,7 +223,7 @@ ieee80211softmac_wx_get_rate(struct net_ int err = -EINVAL; spin_lock_irqsave(&mac->lock, flags); - switch (mac->txrates.default_rate) { + switch (mac->txrates.user_rate) { case IEEE80211_CCK_RATE_1MB: data->bitrate.value = 1000000; break; --- linux/net/ieee80211/softmac/ieee80211softmac_priv.h.orig 2006-04-17 16:46:09.000000000 +0100 +++ linux/net/ieee80211/softmac/ieee80211softmac_priv.h 2006-04-17 17:09:08.000000000 +0100 @@ -116,7 +116,10 @@ ieee80211softmac_get_network_by_essid(st struct ieee80211softmac_essid *essid); /* 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); +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) { return ieee80211softmac_lower_rate_delta(mac, rate, 1); }