diff options
author | David S. Miller <davem@davemloft.net> | 2008-03-25 17:20:03 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-25 17:20:03 -0700 |
commit | f89e6e3834035c6e8203042f3527931aa7f52496 (patch) | |
tree | a82677254fe4511679d5690606ac75f4300fefe1 /net | |
parent | 7cbca67c073263c179f605bdbbdc565ab29d801d (diff) | |
parent | 3a643d244f09fa1fdd25d48a56a073c1a69583ee (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.26
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211.c | 7 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 31 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 125 | ||||
-rw-r--r-- | net/mac80211/tkip.c | 68 | ||||
-rw-r--r-- | net/mac80211/tkip.h | 2 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 2 | ||||
-rw-r--r-- | net/wireless/util.c | 23 |
8 files changed, 186 insertions, 74 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 55b63712e48c..616ce10d2a38 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -386,7 +386,6 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; - int i; /* * Stop TX on this interface first. @@ -400,11 +399,7 @@ static int ieee80211_stop(struct net_device *dev) list_for_each_entry_rcu(sta, &local->sta_list, list) { if (sta->sdata == sdata) - for (i = 0; i < STA_TID_NUM; i++) - ieee80211_sta_stop_rx_ba_session(sdata->dev, - sta->addr, i, - WLAN_BACK_RECIPIENT, - WLAN_REASON_QSTA_LEAVE_QBSS); + ieee80211_sta_tear_down_BA_sessions(dev, sta->addr); } rcu_read_unlock(); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7f10ff5d4a0b..a6485f01b3c8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -928,10 +928,12 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, u16 agg_size, u16 timeout); void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, u16 initiator, u16 reason_code); + void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, u16 tid, u16 initiator, u16 reason); void sta_rx_agg_session_timer_expired(unsigned long data); void sta_addba_resp_timer_expired(unsigned long data); +void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr); u64 ieee80211_sta_get_rates(struct ieee80211_local *local, struct ieee802_11_elems *elems, enum ieee80211_band band); diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 1d91575a0fe9..5af23d318726 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -279,36 +279,15 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) { - int set = 0; int ret = -EINVAL; - enum ieee80211_band band; - struct ieee80211_supported_band *sband; - int i; - - for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { - sband = local->hw.wiphy->bands[band]; + struct ieee80211_channel *chan; - if (!sband) - continue; + chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); - for (i = 0; i < sband->n_channels; i++) { - struct ieee80211_channel *chan = &sband->channels[i]; - - if (chan->flags & IEEE80211_CHAN_DISABLED) - continue; - - if (chan->center_freq == freqMHz) { - set = 1; - local->oper_channel = chan; - break; - } - } - if (set) - break; - } + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + local->oper_channel = chan; - if (set) { - if (local->sta_sw_scanning) + if (local->sta_sw_scanning || local->sta_hw_scanning) ret = 0; else ret = ieee80211_hw_config(local); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8b991ebcbb4e..cf51ca6804dd 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -220,6 +220,61 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } + +static void ieee80211_sta_def_wmm_params(struct net_device *dev, + struct ieee80211_sta_bss *bss, + int ibss) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + int i, have_higher_than_11mbit = 0; + + + /* cf. IEEE 802.11 9.2.12 */ + for (i = 0; i < bss->supp_rates_len; i++) + if ((bss->supp_rates[i] & 0x7f) * 5 > 110) + have_higher_than_11mbit = 1; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + have_higher_than_11mbit) + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + else + sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + + + if (local->ops->conf_tx) { + struct ieee80211_tx_queue_params qparam; + int i; + + memset(&qparam, 0, sizeof(qparam)); + + qparam.aifs = 2; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) + qparam.cw_min = 31; + else + qparam.cw_min = 15; + + qparam.cw_max = 1023; + qparam.txop = 0; + + for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) + local->ops->conf_tx(local_to_hw(local), + i + IEEE80211_TX_QUEUE_DATA0, + &qparam); + + if (ibss) { + /* IBSS uses different parameters for Beacon sending */ + qparam.cw_min++; + qparam.cw_min *= 2; + qparam.cw_min--; + local->ops->conf_tx(local_to_hw(local), + IEEE80211_TX_QUEUE_BEACON, &qparam); + } + } +} + static void ieee80211_sta_wmm_params(struct net_device *dev, struct ieee80211_if_sta *ifsta, u8 *wmm_param, size_t wmm_param_len) @@ -467,8 +522,8 @@ static void ieee80211_set_associated(struct net_device *dev, memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); ieee80211_sta_send_associnfo(dev, ifsta); } else { + ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid); ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; - netif_carrier_off(dev); ieee80211_reset_erp_info(dev); memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); @@ -1145,7 +1200,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, status = WLAN_STATUS_INVALID_QOS_PARAM; #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "Block Ack Req with bad params from " + printk(KERN_DEBUG "AddBA Req with bad params from " "%s on tid %u. policy %d, buffer size %d\n", print_mac(mac, mgmt->sa), tid, ba_policy, buf_size); @@ -1169,7 +1224,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, if (tid_agg_rx->state != HT_AGG_STATE_IDLE) { #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "unexpected Block Ack Req from " + printk(KERN_DEBUG "unexpected AddBA Req from " "%s on tid %u\n", print_mac(mac, mgmt->sa), tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1427,7 +1482,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", print_mac(mac, mgmt->sa), - initiator ? "recipient" : "initiator", tid, + initiator ? "initiator" : "recipient", tid, mgmt->u.action.u.delba.reason_code); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1497,8 +1552,8 @@ timer_expired_exit: } /* - * After receiving Block Ack Request (BAR) we activated a - * timer after each frame arrives from the originator. + * After accepting the AddBA Request we activated a timer, + * resetting it after each frame that arrives from the originator. * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. */ void sta_rx_agg_session_timer_expired(unsigned long data) @@ -1518,6 +1573,19 @@ void sta_rx_agg_session_timer_expired(unsigned long data) WLAN_REASON_QSTA_TIMEOUT); } +void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int i; + + for (i = 0; i < STA_TID_NUM; i++) { + ieee80211_stop_tx_ba_session(&local->hw, addr, i, + WLAN_BACK_INITIATOR); + ieee80211_sta_stop_rx_ba_session(dev, addr, i, + WLAN_BACK_RECIPIENT, + WLAN_REASON_QSTA_LEAVE_QBSS); + } +} static void ieee80211_rx_mgmt_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta, @@ -2289,6 +2357,8 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, rates |= BIT(j); } ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + + ieee80211_sta_def_wmm_params(dev, bss, 1); } while (0); if (skb) { @@ -2356,6 +2426,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u64 beacon_timestamp, rx_timestamp; + struct ieee80211_channel *channel; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); @@ -2420,6 +2491,11 @@ static void ieee80211_rx_bss_info(struct net_device *dev, else freq = rx_status->freq; + channel = ieee80211_get_channel(local->hw.wiphy, freq); + + if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) + return; + #ifdef CONFIG_MAC80211_MESH if (elems.mesh_config) bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, @@ -3274,6 +3350,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); ieee80211_sta_set_bssid(dev, selected->bssid); + ieee80211_sta_def_wmm_params(dev, selected, 0); ieee80211_rx_bss_put(dev, selected); ifsta->state = IEEE80211_AUTHENTICATE; ieee80211_sta_reset_auth(dev, ifsta); @@ -3448,43 +3525,10 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; - /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is - * not defined. */ - if (local->ops->conf_tx) { - struct ieee80211_tx_queue_params qparam; - int i; - - memset(&qparam, 0, sizeof(qparam)); - - qparam.aifs = 2; - - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && - !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) - qparam.cw_min = 31; - else - qparam.cw_min = 15; - - qparam.cw_max = 1023; - qparam.txop = 0; - - for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - local->ops->conf_tx(local_to_hw(local), - i + IEEE80211_TX_QUEUE_DATA0, - &qparam); - - /* IBSS uses different parameters for Beacon sending */ - qparam.cw_min++; - qparam.cw_min *= 2; - qparam.cw_min--; - local->ops->conf_tx(local_to_hw(local), - IEEE80211_TX_QUEUE_BEACON, &qparam); - } - ifsta = &sdata->u.sta; if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) @@ -3596,6 +3640,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) if (local->sta_hw_scanning) { local->sta_hw_scanning = 0; + if (ieee80211_hw_config(local)) + printk(KERN_DEBUG "%s: failed to restore operational " + "channel after scan\n", dev->name); /* Restart STA timer for HW scan case */ rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 3abe194e4d55..45d59f19c29f 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -214,6 +214,59 @@ void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, key->u.tkip.iv16, rc4key); } +void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, enum ieee80211_tkip_key_type type, + u8 *outkey) +{ + struct ieee80211_key *key = (struct ieee80211_key *) + container_of(keyconf, struct ieee80211_key, conf); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *data = (u8 *) hdr; + u16 fc = le16_to_cpu(hdr->frame_control); + int hdr_len = ieee80211_get_hdrlen(fc); + u8 *ta = hdr->addr2; + u16 iv16; + u32 iv32; + + iv16 = data[hdr_len] << 8; + iv16 += data[hdr_len + 2]; + iv32 = data[hdr_len + 4] + + (data[hdr_len + 5] >> 8) + + (data[hdr_len + 6] >> 16) + + (data[hdr_len + 7] >> 24); + +#ifdef CONFIG_TKIP_DEBUG + printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", + iv16, iv32); + + if (iv32 != key->u.tkip.iv32) { + printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n", + iv32, key->u.tkip.iv32); + printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " + "fragmented packet\n"); + } +#endif /* CONFIG_TKIP_DEBUG */ + + /* Update the p1k only when the iv16 in the packet wraps around, this + * might occur after the wrap around of iv16 in the key in case of + * fragmented packets. */ + if (iv16 == 0 || !key->u.tkip.tx_initialized) { + /* IV16 wrapped around - perform TKIP phase 1 */ + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], + iv32, key->u.tkip.p1k); + key->u.tkip.tx_initialized = 1; + } + + if (type == IEEE80211_TKIP_P1_KEY) { + memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5); + return; + } + + tkip_mixing_phase2(key->u.tkip.p1k, + &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey); +} +EXPORT_SYMBOL(ieee80211_get_tkip_key); + /* Encrypt packet payload with TKIP using @key. @pos is a pointer to the * beginning of the buffer containing payload. This payload must include * headroom of eight octets for IV and Ext. IV and taildroom of four octets @@ -238,7 +291,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue, + u8 *ra, int only_iv, int queue, u32 *out_iv32, u16 *out_iv16) { u32 iv32; @@ -315,6 +368,19 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, printk("\n"); } #endif /* CONFIG_TKIP_DEBUG */ + if (key->local->ops->update_tkip_key && + key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { + u8 bcast[ETH_ALEN] = + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 *sta_addr = key->sta->addr; + + if (is_multicast_ether_addr(ra)) + sta_addr = bcast; + + key->local->ops->update_tkip_key( + local_to_hw(key->local), &key->conf, + sta_addr, iv32, key->u.tkip.p1k_rx[queue]); + } } tkip_mixing_phase2(key->u.tkip.p1k_rx[queue], diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index 73d8ef2a93b0..ffaee3253e19 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -31,7 +31,7 @@ enum { int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue, + u8 *ra, int only_iv, int queue, u32 *out_iv32, u16 *out_iv16); #endif /* TKIP_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index df0b7341efc8..45709ada8fee 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -312,7 +312,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->addr, - hwaccel, rx->queue, + hdr->addr1, hwaccel, rx->queue, &rx->tkip_iv32, &rx->tkip_iv16); if (res != TKIP_DECRYPT_OK || wpa_test) { diff --git a/net/wireless/util.c b/net/wireless/util.c index 77336c22fcf2..f3e623df3515 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -33,6 +33,29 @@ int ieee80211_frequency_to_channel(int freq) } EXPORT_SYMBOL(ieee80211_frequency_to_channel); +struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, + int freq) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + int i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].center_freq == freq) + return &sband->channels[i]; + } + } + + return NULL; +} +EXPORT_SYMBOL(ieee80211_get_channel); + static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, enum ieee80211_band band) { |