diff options
Diffstat (limited to 'net')
34 files changed, 3201 insertions, 1946 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 54f46bc80cf..9d7a19581a2 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -19,7 +19,6 @@ mac80211-y := \ ieee80211_iface.o \ ieee80211_rate.o \ michael.o \ - regdomain.o \ tkip.o \ aes_ccm.o \ cfg.o \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 22c9619ba77..e7535ffc8e1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -34,10 +34,13 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type) } static int ieee80211_add_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type) + enum nl80211_iftype type, u32 *flags) { struct ieee80211_local *local = wiphy_priv(wiphy); enum ieee80211_if_types itype; + struct net_device *dev; + struct ieee80211_sub_if_data *sdata; + int err; if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) return -ENODEV; @@ -46,7 +49,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; - return ieee80211_if_add(local->mdev, name, NULL, itype); + err = ieee80211_if_add(local->mdev, name, &dev, itype); + if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) + return err; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata->u.mntr_flags = *flags; + return 0; } static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) @@ -69,7 +78,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) } static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, - enum nl80211_iftype type) + enum nl80211_iftype type, u32 *flags) { struct ieee80211_local *local = wiphy_priv(wiphy); struct net_device *dev; @@ -99,6 +108,10 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, ieee80211_if_reinit(dev); ieee80211_if_set_type(dev, itype); + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) + return 0; + + sdata->u.mntr_flags = *flags; return 0; } @@ -110,6 +123,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta = NULL; enum ieee80211_key_alg alg; int ret; + struct ieee80211_key *key; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -128,16 +142,21 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } + key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); + if (!key) + return -ENOMEM; + if (mac_addr) { sta = sta_info_get(sdata->local, mac_addr); - if (!sta) + if (!sta) { + ieee80211_key_free(key); return -ENOENT; + } } + ieee80211_key_link(key, sdata, sta); + ret = 0; - if (!ieee80211_key_alloc(sdata, sta, alg, key_idx, - params->key_len, params->key)) - ret = -ENOMEM; if (sta) sta_info_put(sta); @@ -151,6 +170,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_sub_if_data *sdata; struct sta_info *sta; int ret; + struct ieee80211_key *key; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -160,9 +180,11 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, return -ENOENT; ret = 0; - if (sta->key) - ieee80211_key_free(sta->key); - else + if (sta->key) { + key = sta->key; + ieee80211_key_free(key); + WARN_ON(sta->key); + } else ret = -ENOENT; sta_info_put(sta); @@ -172,7 +194,9 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (!sdata->keys[key_idx]) return -ENOENT; - ieee80211_key_free(sdata->keys[key_idx]); + key = sdata->keys[key_idx]; + ieee80211_key_free(key); + WARN_ON(sdata->keys[key_idx]); return 0; } @@ -498,7 +522,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, { u32 rates; int i, j; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; if (params->station_flags & STATION_FLAG_CHANGED) { sta->flags &= ~WLAN_STA_AUTHORIZED; @@ -525,15 +549,16 @@ static void sta_apply_parameters(struct ieee80211_local *local, if (params->supported_rates) { rates = 0; - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->oper_channel->band]; + for (i = 0; i < params->supported_rates_len; i++) { int rate = (params->supported_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) { - if (mode->rates[j].rate == rate) + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); } } - sta->supp_rates = rates; + sta->supp_rates[local->oper_channel->band] = rates; } } @@ -548,13 +573,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, if (!netif_running(dev)) return -ENETDOWN; - /* XXX: get sta belonging to dev */ - sta = sta_info_get(local, mac); - if (sta) { - sta_info_put(sta); - return -EEXIST; - } - if (params->vlan) { sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); @@ -565,8 +583,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); sta = sta_info_add(local, dev, mac, GFP_KERNEL); - if (!sta) - return -ENOMEM; + if (IS_ERR(sta)) + return PTR_ERR(sta); sta->dev = sdata->dev; if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 60514b2c97b..4736c64937b 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -19,41 +19,6 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file) return 0; } -static const char *ieee80211_mode_str(int mode) -{ - switch (mode) { - case MODE_IEEE80211A: - return "IEEE 802.11a"; - case MODE_IEEE80211B: - return "IEEE 802.11b"; - case MODE_IEEE80211G: - return "IEEE 802.11g"; - default: - return "UNKNOWN"; - } -} - -static ssize_t modes_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - struct ieee80211_hw_mode *mode; - char buf[150], *p = buf; - - /* FIXME: locking! */ - list_for_each_entry(mode, &local->modes_list, list) { - p += scnprintf(p, sizeof(buf)+buf-p, - "%s\n", ieee80211_mode_str(mode->mode)); - } - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations modes_ops = { - .read = modes_read, - .open = mac80211_open_file_generic, -}; - #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ @@ -80,10 +45,8 @@ static const struct file_operations name## _ops = { \ local->debugfs.name = NULL; -DEBUGFS_READONLY_FILE(channel, 20, "%d", - local->hw.conf.channel); DEBUGFS_READONLY_FILE(frequency, 20, "%d", - local->hw.conf.freq); + local->hw.conf.channel->center_freq); DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", local->hw.conf.antenna_sel_tx); DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", @@ -100,8 +63,6 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", local->long_retry_limit); DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", local->total_ps_buffered); -DEBUGFS_READONLY_FILE(mode, 20, "%s", - ieee80211_mode_str(local->hw.conf.phymode)); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", local->wep_iv & 0xffffff); DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", @@ -294,7 +255,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.stations = debugfs_create_dir("stations", phyd); local->debugfs.keys = debugfs_create_dir("keys", phyd); - DEBUGFS_ADD(channel); DEBUGFS_ADD(frequency); DEBUGFS_ADD(antenna_sel_tx); DEBUGFS_ADD(antenna_sel_rx); @@ -304,9 +264,7 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(short_retry_limit); DEBUGFS_ADD(long_retry_limit); DEBUGFS_ADD(total_ps_buffered); - DEBUGFS_ADD(mode); DEBUGFS_ADD(wep_iv); - DEBUGFS_ADD(modes); statsd = debugfs_create_dir("statistics", phyd); local->debugfs.statistics = statsd; @@ -356,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local) void debugfs_hw_del(struct ieee80211_local *local) { - DEBUGFS_DEL(channel); DEBUGFS_DEL(frequency); DEBUGFS_DEL(antenna_sel_tx); DEBUGFS_DEL(antenna_sel_rx); @@ -366,9 +323,7 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_DEL(short_retry_limit); DEBUGFS_DEL(long_retry_limit); DEBUGFS_DEL(total_ps_buffered); - DEBUGFS_DEL(mode); DEBUGFS_DEL(wep_iv); - DEBUGFS_DEL(modes); DEBUGFS_STATS_DEL(transmitted_fragment_count); DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 829872a3ae8..29f7b98ba1f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -91,7 +91,6 @@ static const struct file_operations name##_ops = { \ /* common attributes */ IEEE80211_IF_FILE(channel_use, channel_use, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); -IEEE80211_IF_FILE(ieee802_1x_pac, ieee802_1x_pac, DEC); /* STA/IBSS attributes */ IEEE80211_IF_FILE(state, u.sta.state, DEC); @@ -148,7 +147,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, sta); DEBUGFS_ADD(drop_unencrypted, sta); - DEBUGFS_ADD(ieee802_1x_pac, sta); DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(prev_bssid, sta); @@ -169,7 +167,6 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, ap); DEBUGFS_ADD(drop_unencrypted, ap); - DEBUGFS_ADD(ieee802_1x_pac, ap); DEBUGFS_ADD(num_sta_ps, ap); DEBUGFS_ADD(dtim_count, ap); DEBUGFS_ADD(num_beacons, ap); @@ -182,7 +179,6 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, wds); DEBUGFS_ADD(drop_unencrypted, wds); - DEBUGFS_ADD(ieee802_1x_pac, wds); DEBUGFS_ADD(peer, wds); } @@ -190,7 +186,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, vlan); DEBUGFS_ADD(drop_unencrypted, vlan); - DEBUGFS_ADD(ieee802_1x_pac, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -234,7 +229,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, sta); DEBUGFS_DEL(drop_unencrypted, sta); - DEBUGFS_DEL(ieee802_1x_pac, sta); DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); DEBUGFS_DEL(prev_bssid, sta); @@ -255,7 +249,6 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, ap); DEBUGFS_DEL(drop_unencrypted, ap); - DEBUGFS_DEL(ieee802_1x_pac, ap); DEBUGFS_DEL(num_sta_ps, ap); DEBUGFS_DEL(dtim_count, ap); DEBUGFS_DEL(num_beacons, ap); @@ -268,7 +261,6 @@ static void del_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, wds); DEBUGFS_DEL(drop_unencrypted, wds); - DEBUGFS_DEL(ieee802_1x_pac, wds); DEBUGFS_DEL(peer, wds); } @@ -276,7 +268,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, vlan); DEBUGFS_DEL(drop_unencrypted, vlan); - DEBUGFS_DEL(ieee802_1x_pac, vlan); } static void del_monitor_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 8f5944c53d4..ed7c9f3b460 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -33,25 +33,16 @@ static ssize_t sta_ ##name## _read(struct file *file, \ #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n") #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n") -#define STA_READ_RATE(name, field) \ -static ssize_t sta_##name##_read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct sta_info *sta = file->private_data; \ - struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\ - struct ieee80211_hw_mode *mode = local->oper_hw_mode; \ - char buf[20]; \ - int res = scnprintf(buf, sizeof(buf), "%d\n", \ - (sta->field >= 0 && \ - sta->field < mode->num_rates) ? \ - mode->rates[sta->field].rate : -1); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ +#define STA_OPS(name) \ +static const struct file_operations sta_ ##name## _ops = { \ + .read = sta_##name##_read, \ + .open = mac80211_open_file_generic, \ } -#define STA_OPS(name) \ +#define STA_OPS_WR(name) \ static const struct file_operations sta_ ##name## _ops = { \ .read = sta_##name##_read, \ + .write = sta_##name##_write, \ .open = mac80211_open_file_generic, \ } @@ -70,8 +61,6 @@ STA_FILE(rx_fragments, rx_fragments, LU); STA_FILE(rx_dropped, rx_dropped, LU); STA_FILE(tx_fragments, tx_fragments, LU); STA_FILE(tx_filtered, tx_filtered_count, LU); -STA_FILE(txrate, txrate, RATE); -STA_FILE(last_txrate, last_txrate, RATE); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); STA_FILE(last_rssi, last_rssi, D); @@ -85,12 +74,10 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, { char buf[100]; struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", + int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", sta->flags & WLAN_STA_PS ? "PS\n" : "", - sta->flags & WLAN_STA_TIM ? "TIM\n" : "", - sta->flags & WLAN_STA_PERM ? "PERM\n" : "", sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", sta->flags & WLAN_STA_WME ? "WME\n" : "", @@ -111,31 +98,6 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file, } STA_OPS(num_ps_buf_frames); -static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[100]; - struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%d %d %d\n", - sta->last_ack_rssi[0], - sta->last_ack_rssi[1], - sta->last_ack_rssi[2]); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} -STA_OPS(last_ack_rssi); - -static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[20]; - struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%d\n", - sta->last_ack ? - jiffies_to_msecs(jiffies - sta->last_ack) : -1); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} -STA_OPS(last_ack_ms); - static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -191,6 +153,113 @@ static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, STA_OPS(wme_tx_queue); #endif +static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[768], *p = buf; + int i; + struct sta_info *sta = file->private_data; + p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n"); + p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n " + "TIDs info is: \n TID :", + (sta->ampdu_mlme.dialog_token_allocator + 1)); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_rx[i].state); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_rx[i].dialog_token); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].state); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].dialog_token); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].ssn); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + + return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); +} + +static ssize_t sta_agg_status_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct net_device *dev = sta->dev; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + u8 *da = sta->addr; + static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1}; + char *endp; + char buf[32]; + int buf_size, rs; + unsigned int tid_num; + char state[4]; + + memset(buf, 0x00, sizeof(buf)); + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + tid_num = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + + if ((tid_num >= 100) && (tid_num <= 115)) { + /* toggle Rx aggregation command */ + tid_num = tid_num - 100; + if (tid_static_rx[tid_num] == 1) { + strcpy(state, "off "); + ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0, + WLAN_REASON_QSTA_REQUIRE_SETUP); + sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0xFF; + tid_static_rx[tid_num] = 0; + } else { + strcpy(state, "on "); + sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0x00; + tid_static_rx[tid_num] = 1; + } + printk(KERN_DEBUG "debugfs - try switching tid %u %s\n", + tid_num, state); + } else if ((tid_num >= 0) && (tid_num <= 15)) { + /* toggle Tx aggregation command */ + if (tid_static_tx[tid_num] == 0) { + strcpy(state, "on "); + rs = ieee80211_start_tx_ba_session(hw, da, tid_num); + if (rs == 0) + tid_static_tx[tid_num] = 1; + } else { + strcpy(state, "off"); + rs = ieee80211_stop_tx_ba_session(hw, da, tid_num, 1); + if (rs == 0) + tid_static_tx[tid_num] = 0; + } + printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n", + tid_num, state, rs); + } + + return count; +} +STA_OPS_WR(agg_status); + #define DEBUGFS_ADD(name) \ sta->debugfs.name = debugfs_create_file(#name, 0444, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); @@ -203,12 +272,13 @@ STA_OPS(wme_tx_queue); void ieee80211_sta_debugfs_add(struct sta_info *sta) { struct dentry *stations_dir = sta->local->debugfs.stations; - DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mbuf); + u8 *mac; if (!stations_dir) return; - print_mac(mac, sta->addr); + mac = print_mac(mbuf, sta->addr); sta->debugfs.dir = debugfs_create_dir(mac, stations_dir); if (!sta->debugfs.dir) @@ -216,28 +286,26 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(flags); DEBUGFS_ADD(num_ps_buf_frames); - DEBUGFS_ADD(last_ack_rssi); - DEBUGFS_ADD(last_ack_ms); DEBUGFS_ADD(inactive_ms); DEBUGFS_ADD(last_seq_ctrl); #ifdef CONFIG_MAC80211_DEBUG_COUNTERS DEBUGFS_ADD(wme_rx_queue); DEBUGFS_ADD(wme_tx_queue); #endif + DEBUGFS_ADD(agg_status); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) { DEBUGFS_DEL(flags); DEBUGFS_DEL(num_ps_buf_frames); - DEBUGFS_DEL(last_ack_rssi); - DEBUGFS_DEL(last_ack_ms); DEBUGFS_DEL(inactive_ms); DEBUGFS_DEL(last_seq_ctrl); #ifdef CONFIG_MAC80211_DEBUG_COUNTERS DEBUGFS_DEL(wme_rx_queue); DEBUGFS_DEL(wme_tx_queue); #endif + DEBUGFS_DEL(agg_status); debugfs_remove(sta->debugfs.dir); sta->debugfs.dir = NULL; diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 28bcdf9fc3d..2133c9fd27a 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -67,9 +67,19 @@ static void ieee80211_configure_filter(struct ieee80211_local *local) new_flags |= FIF_ALLMULTI; if (local->monitors) - new_flags |= FIF_CONTROL | - FIF_OTHER_BSS | - FIF_BCN_PRBRESP_PROMISC; + new_flags |= FIF_BCN_PRBRESP_PROMISC; + + if (local->fif_fcsfail) + new_flags |= FIF_FCSFAIL; + + if (local->fif_plcpfail) + new_flags |= FIF_PLCPFAIL; + + if (local->fif_control) + new_flags |= FIF_CONTROL; + + if (local->fif_other_bss) + new_flags |= FIF_OTHER_BSS; changed_flags = local->filter_flags ^ new_flags; @@ -173,8 +183,52 @@ static int ieee80211_open(struct net_device *dev) list_for_each_entry(nsdata, &local->interfaces, list) { struct net_device *ndev = nsdata->dev; - if (ndev != dev && ndev != local->mdev && netif_running(ndev) && - compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) { + if (ndev != dev && ndev != local->mdev && netif_running(ndev)) { + /* + * Allow only a single IBSS interface to be up at any + * time. This is restricted because beacon distribution + * cannot work properly if both are in the same IBSS. + * + * To remove this restriction we'd have to disallow them + * from setting the same SSID on different IBSS interfaces + * belonging to the same hardware. Then, however, we're + * faced with having to adopt two different TSF timers... + */ + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && + nsdata->vif.type == IEEE80211_IF_TYPE_IBSS) + return -EBUSY; + + /* + * Disallow multiple IBSS/STA mode interfaces. + * + * This is a technical restriction, it is possible although + * most likely not IEEE 802.11 compliant to have multiple + * STAs with just a single hardware (the TSF timer will not + * be adjusted properly.) + * + * However, because mac80211 uses the master device's BSS + * information for each STA/IBSS interface, doing this will + * currently corrupt that BSS information completely, unless, + * a not very useful case, both STAs are associated to the + * same BSS. + * + * To remove this restriction, the BSS information needs to + * be embedded in the STA/IBSS mode sdata instead of using + * the master device's BSS structure. + */ + if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && + (nsdata->vif.type == IEEE80211_IF_TYPE_STA || + nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)) + return -EBUSY; + + /* + * The remaining checks are only performed for interfaces + * with the same MAC address. + */ + if (compare_ether_addr(dev->dev_addr, ndev->dev_addr)) + continue; + /* * check whether it may have the same address */ @@ -186,8 +240,7 @@ static int ieee80211_open(struct net_device *dev) * can only add VLANs to enabled APs */ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN && - nsdata->vif.type == IEEE80211_IF_TYPE_AP && - netif_running(nsdata->dev)) + nsdata->vif.type == IEEE80211_IF_TYPE_AP) sdata->u.vlan.ap = nsdata; } } @@ -229,15 +282,28 @@ static int ieee80211_open(struct net_device *dev) /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs++; + break; + } + /* must be before the call to ieee80211_configure_filter */ local->monitors++; - if (local->monitors == 1) { - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); - + if (local->monitors == 1) local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control++; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss++; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: @@ -352,14 +418,27 @@ static int ieee80211_stop(struct net_device *dev) /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: - local->monitors--; - if (local->monitors == 0) { - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs--; + break; + } + local->monitors--; + if (local->monitors == 0) local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - } + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control--; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss--; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: @@ -414,6 +493,329 @@ static int ieee80211_stop(struct net_device *dev) return 0; } +int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata; + u16 start_seq_num = 0; + u8 *state; + int ret; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find the station\n"); + return -ENOENT; + } + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + /* we have tried too many times, receiver does not want A-MPDU */ + if (sta->ampdu_mlme.tid_tx[tid].addba_req_num > HT_AGG_MAX_RETRIES) { + ret = -EBUSY; + goto start_ba_exit; + } + + state = &sta->ampdu_mlme.tid_tx[tid].state; + /* check if the TID is not in aggregation flow already */ + if (*state != HT_AGG_STATE_IDLE) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - session is not " + "idle on tid %u\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -EAGAIN; + goto start_ba_exit; + } + + /* ensure that TX flow won't interrupt us + * until the end of the call to requeue function */ + spin_lock_bh(&local->mdev->queue_lock); + + /* create a new queue for this aggregation */ + ret = ieee80211_ht_agg_queue_add(local, sta, tid); + + /* case no queue is available to aggregation + * don't switch to aggregation */ + if (ret) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - no queue available for" + " tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + spin_unlock_bh(&local->mdev->queue_lock); + goto start_ba_exit; + } + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the + * call back right away, it must see that the flow has begun */ + *state |= HT_ADDBA_REQUESTED_MSK; + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, + ra, tid, &start_seq_num); + + if (ret) { + /* No need to requeue the packets in the agg queue, since we + * held the tx lock: no packet could be enqueued to the newly + * allocated queue */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 0); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - HW or queue unavailable" + " for tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + spin_unlock_bh(&local->mdev->queue_lock); + *state = HT_AGG_STATE_IDLE; + goto start_ba_exit; + } + + /* Will put all the packets in the new SW queue */ + ieee80211_requeue(local, ieee802_1d_to_ac[tid]); + spin_unlock_bh(&local->mdev->queue_lock); + + /* We have most probably almost emptied the legacy queue */ + /* ieee80211_wake_queue(local_to_hw(local), ieee802_1d_to_ac[tid]); */ + + /* send an addBA request */ + sta->ampdu_mlme.dialog_token_allocator++; + sta->ampdu_mlme.tid_tx[tid].dialog_token = + sta->ampdu_mlme.dialog_token_allocator; + sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; + + ieee80211_send_addba_request(sta->dev, ra, tid, + sta->ampdu_mlme.tid_tx[tid].dialog_token, + sta->ampdu_mlme.tid_tx[tid].ssn, + 0x40, 5000); + + /* activate the timer for the recipient's addBA response */ + sta->ampdu_mlme.tid_tx[tid].addba_resp_timer.expires = + jiffies + ADDBA_RESP_INTERVAL; + add_timer(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); + printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); + +start_ba_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return ret; +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_session); + +int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, + u8 *ra, u16 tid, + enum ieee80211_back_parties initiator) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int ret = 0; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + sta = sta_info_get(local, ra); + if (!sta) + return -ENOENT; + + /* check if the TID is in aggregation */ + state = &sta->ampdu_mlme.tid_tx[tid].state; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (*state != HT_AGG_STATE_OPERATIONAL) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Try to stop Tx aggregation on" + " non active TID\n"); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -ENOENT; + goto stop_BA_exit; + } + + ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); + + *state = HT_AGG_STATE_REQ_STOP_BA_MSK | + (initiator << HT_AGG_STATE_INITIATOR_SHIFT); + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, + ra, tid, NULL); + + /* case HW denied going back to legacy */ + if (ret) { + WARN_ON(ret != -EBUSY); + *state = HT_AGG_STATE_OPERATIONAL; + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + goto stop_BA_exit; + } + +stop_BA_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return ret; +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); + +void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + return; + } + + state = &sta->ampdu_mlme.tid_tx[tid].state; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", + *state); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return; + } + + WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); + + *state |= HT_ADDBA_DRV_READY_MSK; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); + +void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int agg_queue; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + + printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", + print_mac(mac, ra), tid); + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + return; + } + state = &sta->ampdu_mlme.tid_tx[tid].state; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { + printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); + sta_info_put(sta); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + return; + } + + if (*state & HT_AGG_STATE_INITIATOR_MSK) + ieee80211_send_delba(sta->dev, ra, tid, + WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); + + agg_queue = sta->tid_to_tx_q[tid]; + + /* avoid ordering issues: we are the only one that can modify + * the content of the qdiscs */ + spin_lock_bh(&local->mdev->queue_lock); + /* remove the queue for this aggregation */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 1); + spin_unlock_bh(&local->mdev->queue_lock); + + /* we just requeued the all the frames that were in the removed + * queue, and since we might miss a softirq we do netif_schedule. + * ieee80211_wake_queue is not used here as this queue is not + * necessarily stopped */ + netif_schedule(local->mdev); + *state = HT_AGG_STATE_IDLE; + sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + + sta_info_put(sta); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); + +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping start BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_ADDBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); + +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping stop BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_DELBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); + static void ieee80211_set_multicast_list(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -479,8 +881,11 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) /* Create STA entry for the new peer */ sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); - if (!sta) - return -ENOMEM; + if (IS_ERR(sta)) + return PTR_ERR(sta); + + sta->flags |= WLAN_STA_AUTHORIZED; + sta_info_put(sta); /* Remove STA entry for the old peer */ @@ -553,37 +958,28 @@ int ieee80211_if_config_beacon(struct net_device *dev) int ieee80211_hw_config(struct ieee80211_local *local) { - struct ieee80211_hw_mode *mode; struct ieee80211_channel *chan; int ret = 0; - if (local->sta_sw_scanning) { + if (local->sta_sw_scanning) chan = local->scan_channel; - mode = local->scan_hw_mode; - } else { + else chan = local->oper_channel; - mode = local->oper_hw_mode; - } - local->hw.conf.channel = chan->chan; - local->hw.conf.channel_val = chan->val; - if (!local->hw.conf.power_level) { - local->hw.conf.power_level = chan->power_level; - } else { - local->hw.conf.power_level = min(chan->power_level, - local->hw.conf.power_level); - } - local->hw.conf.freq = chan->freq; - local->hw.conf.phymode = mode->mode; - local->hw.conf.antenna_max = chan->antenna_max; - local->hw.conf.chan = chan; - local->hw.conf.mode = mode; + local->hw.conf.channel = chan; + + if (!local->hw.conf.power_level) + local->hw.conf.power_level = chan->max_power; + else + local->hw.conf.power_level = min(chan->max_power, + local->hw.conf.power_level); + + local->hw.conf.max_antenna_gain = chan->max_antenna_gain; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d " - "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq, - local->hw.conf.phymode); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n", + wiphy_name(local->hw.wiphy), chan->center_freq); +#endif if (local->open_count) ret = local->ops->config(local_to_hw(local), &local->hw.conf); @@ -601,11 +997,13 @@ int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_bss_info *req_bss_cap) { struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_hw_mode *mode = conf->mode; + struct ieee80211_supported_band *sband; int i; + sband = local->hw.wiphy->bands[conf->channel->band]; + /* HT is not supported */ - if (!mode->ht_info.ht_supported) { + if (!sband->ht_info.ht_supported) { conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; return -EOPNOTSUPP; } @@ -615,17 +1013,17 @@ int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; } else { conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - conf->ht_conf.cap = req_ht_cap->cap & mode->ht_info.cap; + conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); conf->ht_conf.cap |= - mode->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; conf->ht_bss_conf.primary_channel = req_bss_cap->primary_channel; conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap; conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; for (i = 0; i < SUPP_MCS_SET_LEN; i++) conf->ht_conf.supp_mcs_set[i] = - mode->ht_info.supp_mcs_set[i] & + sband->ht_info.supp_mcs_set[i] & req_ht_cap->supp_mcs_set[i]; /* In STA mode, this gives us indication @@ -713,6 +1111,7 @@ static void ieee80211_tasklet_handler(unsigned long data) struct sk_buff *skb; struct ieee80211_rx_status rx_status; struct ieee80211_tx_status *tx_status; + struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || (skb = skb_dequeue(&local->skb_queue_unreliable))) { @@ -733,6 +1132,18 @@ static void ieee80211_tasklet_handler(unsigned long data) skb, tx_status); kfree(tx_status); break; + case IEEE80211_DELBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_stop_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break; + case IEEE80211_ADDBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_start_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break ; default: /* should never get here! */ printk(KERN_ERR "%s: Unknown message type (%d)\n", wiphy_name(local->hw.wiphy), skb->pkt_type); @@ -810,6 +1221,77 @@ no_key: } } +static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, + struct sta_info *sta, + struct sk_buff *skb, + struct ieee80211_tx_status *status) +{ + sta->tx_filtered_count++; + + /* + * Clear the TX filter mask for this STA when sending the next + * packet. If the STA went to power save mode, this will happen + * happen when it wakes up for the next time. + */ + sta->flags |= WLAN_STA_CLEAR_PS_FILT; + + /* + * This code races in the following way: + * + * (1) STA sends frame indicating it will go to sleep and does so + * (2) hardware/firmware adds STA to filter list, passes frame up + * (3) hardware/firmware processes TX fifo and suppresses a frame + * (4) we get TX status before having processed the frame and + * knowing that the STA has gone to sleep. + * + * This is actually quite unlikely even when both those events are + * processed from interrupts coming in quickly after one another or + * even at the same time because we queue both TX status events and + * RX frames to be processed by a tasklet and process them in the + * same order that they were received or TX status last. Hence, there + * is no race as long as the frame RX is processed before the next TX + * status, which drivers can ensure, see below. + * + * Note that this can only happen if the hardware or firmware can + * actually add STAs to the filter list, if this is done by the + * driver in response to set_tim() (which will only reduce the race + * this whole filtering tries to solve, not completely solve it) + * this situation cannot happen. + * + * To completely solve this race drivers need to make sure that they + * (a) don't mix the irq-safe/not irq-safe TX status/RX processing + * functions and + * (b) always process RX events before TX status events if ordering + * can be unknown, for example with different interrupt status + * bits. + */ + if (sta->flags & WLAN_STA_PS && + skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { + ieee80211_remove_tx_extra(local, sta->key, skb, + &status->control); + skb_queue_tail(&sta->tx_filtered, skb); + return; + } + + if (!(sta->flags & WLAN_STA_PS) && + !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { + /* Software retry the packet once */ + status->control.flags |= IEEE80211_TXCTL_REQUEUE; + ieee80211_remove_tx_extra(local, sta->key, skb, + &status->control); + dev_queue_xmit(skb); + return; + } + + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped TX filtered frame, " + "queue_len=%d PS=%d @%lu\n", + wiphy_name(local->hw.wiphy), + skb_queue_len(&sta->tx_filtered), + !!(sta->flags & WLAN_STA_PS), jiffies); + dev_kfree_skb(skb); +} + void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) { @@ -819,7 +1301,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, u16 frag, type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; - int monitors; + struct net_device *prev_dev = NULL; if (!status) { printk(KERN_ERR @@ -834,11 +1316,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, sta = sta_info_get(local, hdr->addr1); if (sta) { if (sta->flags & WLAN_STA_PS) { - /* The STA is in power save mode, so assume + /* + * The STA is in power save mode, so assume * that this TX packet failed because of that. */ status->excessive_retries = 0; status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; + ieee80211_handle_filtered_frame(local, sta, + skb, status); + sta_info_put(sta); + return; } sta_info_put(sta); } @@ -848,47 +1335,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { - sta->tx_filtered_count++; - - /* Clear the TX filter mask for this STA when sending - * the next packet. If the STA went to power save mode, - * this will happen when it is waking up for the next - * time. */ - sta->clear_dst_mask = 1; - - /* TODO: Is the WLAN_STA_PS flag always set here or is - * the race between RX and TX status causing some - * packets to be filtered out before 80211.o gets an - * update for PS status? This seems to be the case, so - * no changes are likely to be needed. */ - if (sta->flags & WLAN_STA_PS && - skb_queue_len(&sta->tx_filtered) < - STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, - skb, - &status->control); - skb_queue_tail(&sta->tx_filtered, skb); - } else if (!(sta->flags & WLAN_STA_PS) && - !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { - /* Software retry the packet once */ - status->control.flags |= IEEE80211_TXCTL_REQUEUE; - ieee80211_remove_tx_extra(local, sta->key, - skb, - &status->control); - dev_queue_xmit(skb); - } else { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped TX " - "filtered frame queue_len=%d " - "PS=%d @%lu\n", - wiphy_name(local->hw.wiphy), - skb_queue_len( - &sta->tx_filtered), - !!(sta->flags & WLAN_STA_PS), - jiffies); - } - dev_kfree_skb(skb); - } + ieee80211_handle_filtered_frame(local, sta, skb, + status); sta_info_put(sta); return; } @@ -932,7 +1380,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); - if (!local->monitors) { + /* + * This is a bit racy but we can avoid a lot of work + * with this test... + */ + if (!local->monitors && !local->cooked_mntrs) { dev_kfree_skb(skb); return; } @@ -966,51 +1418,44 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, rthdr->data_retries = status->retry_count; + /* XXX: is this sufficient for BPF? */ + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + rcu_read_lock(); - monitors = local->monitors; list_for_each_entry_rcu(sdata, &local->interfaces, list) { - /* - * Using the monitors counter is possibly racy, but - * if the value is wrong we simply either clone the skb - * once too much or forget sending it to one monitor iface - * The latter case isn't nice but fixing the race is much - * more complicated. - */ - if (!monitors || !skb) - goto out; - if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) { if (!netif_running(sdata->dev)) continue; - monitors--; - if (monitors) + + if (prev_dev) { skb2 = skb_clone(skb, GFP_ATOMIC); - else - skb2 = NULL; - skb->dev = sdata->dev; - /* XXX: is this sufficient for BPF? */ - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - skb = skb2; + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; } } - out: + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } rcu_read_unlock(); - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_tx_status); struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { - struct net_device *mdev; struct ieee80211_local *local; - struct ieee80211_sub_if_data *sdata; int priv_size; struct wiphy *wiphy; @@ -1056,25 +1501,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, BUG_ON(!ops->configure_filter); local->ops = ops; - /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); - if (!mdev) { - wiphy_free(wiphy); - return NULL; - } - - sdata = IEEE80211_DEV_TO_SUB_IF(mdev); - mdev->ieee80211_ptr = &sdata->wdev; - sdata->wdev.wiphy = wiphy; - local->hw.queues = 1; /* default */ - local->mdev = mdev; - local->rx_pre_handlers = ieee80211_rx_pre_handlers; - local->rx_handlers = ieee80211_rx_handlers; - local->tx_handlers = ieee80211_tx_handlers; - local->bridge_packets = 1; local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; @@ -1083,33 +1511,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->long_retry_limit = 4; local->hw.conf.radio_enabled = 1; - local->enabled_modes = ~0; - - INIT_LIST_HEAD(&local->modes_list); - INIT_LIST_HEAD(&local->interfaces); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); - ieee80211_rx_bss_list_init(mdev); sta_info_init(local); - mdev->hard_start_xmit = ieee80211_master_start_xmit; - mdev->open = ieee80211_master_open; - mdev->stop = ieee80211_master_stop; - mdev->type = ARPHRD_IEEE80211; - mdev->header_ops = &ieee80211_header_ops; - mdev->set_multicast_list = ieee80211_master_set_multicast_list; - - sdata->vif.type = IEEE80211_IF_TYPE_AP; - sdata->dev = mdev; - sdata->local = local; - sdata->u.ap.force_unicast_rateidx = -1; - sdata->u.ap.max_ratectrl_rateidx = -1; - ieee80211_if_sdata_init(sdata); - /* no RCU needed since we're still during init phase */ - list_add_tail(&sdata->list, &local->interfaces); - tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); tasklet_disable(&local->tx_pending_tasklet); @@ -1131,11 +1538,63 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) struct ieee80211_local *local = hw_to_local(hw); const char *name; int result; + enum ieee80211_band band; + struct net_device *mdev; + struct ieee80211_sub_if_data *sdata; + + /* + * generic code guarantees at least one band, + * set this very early because much code assumes + * that hw.conf.channel is assigned + */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + if (sband) { + /* init channel we're on */ + local->hw.conf.channel = + local->oper_channel = + local->scan_channel = &sband->channels[0]; + break; + } + } result = wiphy_register(local->hw.wiphy); if (result < 0) return result; + /* for now, mdev needs sub_if_data :/ */ + mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup); + if (!mdev) + goto fail_mdev_alloc; + + sdata = IEEE80211_DEV_TO_SUB_IF(mdev); + mdev->ieee80211_ptr = &sdata->wdev; + sdata->wdev.wiphy = local->hw.wiphy; + + local->mdev = mdev; + + ieee80211_rx_bss_list_init(mdev); + + mdev->hard_start_xmit = ieee80211_master_start_xmit; + mdev->open = ieee80211_master_open; + mdev->stop = ieee80211_master_stop; + mdev->type = ARPHRD_IEEE80211; + mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; + + sdata->vif.type = IEEE80211_IF_TYPE_AP; + sdata->dev = mdev; + sdata->local = local; + sdata->u.ap.force_unicast_rateidx = -1; + sdata->u.ap.max_ratectrl_rateidx = -1; + ieee80211_if_sdata_init(sdata); + + /* no RCU needed since we're still during init phase */ + list_add_tail(&sdata->list, &local->interfaces); + name = wiphy_dev(local->hw.wiphy)->driver->name; local->hw.workqueue = create_singlethread_workqueue(name); if (!local->hw.workqueue) { @@ -1227,49 +1686,18 @@ fail_sta_info: debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); fail_workqueue: + ieee80211_if_free(local->mdev); + local->mdev = NULL; +fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); return result; } EXPORT_SYMBOL(ieee80211_register_hw); -int ieee80211_register_hwmode(struct ieee80211_hw *hw, - struct ieee80211_hw_mode *mode) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int i; - - INIT_LIST_HEAD(&mode->list); - list_add_tail(&mode->list, &local->modes_list); - - local->hw_modes |= (1 << mode->mode); - for (i = 0; i < mode->num_rates; i++) { - rate = &(mode->rates[i]); - rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate; - } - ieee80211_prepare_rates(local, mode); - - if (!local->oper_hw_mode) { - /* Default to this mode */ - local->hw.conf.phymode = mode->mode; - local->oper_hw_mode = local->scan_hw_mode = mode; - local->oper_channel = local->scan_channel = &mode->channels[0]; - local->hw.conf.mode = local->oper_hw_mode; - local->hw.conf.chan = local->oper_channel; - } - - if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED)) - ieee80211_set_default_regdomain(mode); - - return 0; -} -EXPORT_SYMBOL(ieee80211_register_hwmode); - void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; - int i; tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); @@ -1310,11 +1738,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rate_control_deinitialize(local); debugfs_hw_del(local); - for (i = 0; i < NUM_IEEE80211_MODES; i++) { - kfree(local->supp_rates[i]); - kfree(local->basic_rates[i]); - } - if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) printk(KERN_WARNING "%s: skb_queue not empty\n", @@ -1326,6 +1749,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); + ieee80211_if_free(local->mdev); + local->mdev = NULL; } EXPORT_SYMBOL(ieee80211_unregister_hw); @@ -1333,7 +1758,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); - ieee80211_if_free(local->mdev); wiphy_free(local->hw.wiphy); } EXPORT_SYMBOL(ieee80211_free_hw); @@ -1361,7 +1785,6 @@ static int __init ieee80211_init(void) } ieee80211_debugfs_netdev_init(); - ieee80211_regdomain_init(); return 0; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 72ecbf7bf96..b07b3cbfd03 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -79,8 +79,7 @@ struct ieee80211_sta_bss { u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; u16 capability; /* host byte order */ - int hw_mode; - int channel; + enum ieee80211_band band; int freq; int rssi, signal, noise; u8 *wpa_ie; @@ -109,9 +108,17 @@ struct ieee80211_sta_bss { }; -typedef enum { - TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED -} ieee80211_txrx_result; +typedef unsigned __bitwise__ ieee80211_tx_result; +#define TX_CONTINUE ((__force ieee80211_tx_result) 0u) +#define TX_DROP ((__force ieee80211_tx_result) 1u) +#define TX_QUEUED ((__force ieee80211_tx_result) 2u) + +typedef unsigned __bitwise__ ieee80211_rx_result; +#define RX_CONTINUE ((__force ieee80211_rx_result) 0u) +#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) +#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) +#define RX_QUEUED ((__force ieee80211_rx_result) 3u) + /* flags used in struct ieee80211_txrx_data.flags */ /* whether the MSDU was fragmented */ @@ -124,6 +131,7 @@ typedef enum { #define IEEE80211_TXRXD_RXRA_MATCH BIT(5) #define IEEE80211_TXRXD_TX_INJECTED BIT(6) #define IEEE80211_TXRXD_RX_AMSDU BIT(7) +#define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8) struct ieee80211_txrx_data { struct sk_buff *skb; struct net_device *dev; @@ -136,13 +144,12 @@ struct ieee80211_txrx_data { union { struct { struct ieee80211_tx_control *control; - struct ieee80211_hw_mode *mode; + struct ieee80211_channel *channel; struct ieee80211_rate *rate; /* use this rate (if set) for last fragment; rate can * be set to lower rate for the first fragments, e.g., * when using CTS protection with IEEE 802.11g. */ struct ieee80211_rate *last_frag_rate; - int last_frag_hwrate; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -151,6 +158,7 @@ struct ieee80211_txrx_data { } tx; struct { struct ieee80211_rx_status *status; + struct ieee80211_rate *rate; int sent_ps_buffered; int queue; int load; @@ -165,6 +173,7 @@ struct ieee80211_txrx_data { #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) #define IEEE80211_TXPD_REQUEUE BIT(2) #define IEEE80211_TXPD_EAPOL_FRAME BIT(3) +#define IEEE80211_TXPD_AMPDU BIT(4) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { int ifindex; @@ -178,18 +187,10 @@ struct ieee80211_tx_stored_packet { struct sk_buff *skb; int num_extra_frag; struct sk_buff **extra_frag; - int last_frag_rateidx; - int last_frag_hwrate; struct ieee80211_rate *last_frag_rate; unsigned int last_frag_rate_ctrl_probe; }; -typedef ieee80211_txrx_result (*ieee80211_tx_handler) -(struct ieee80211_txrx_data *tx); - -typedef ieee80211_txrx_result (*ieee80211_rx_handler) -(struct ieee80211_txrx_data *rx); - struct beacon_data { u8 *head, *tail; int head_len, tail_len; @@ -206,7 +207,7 @@ struct ieee80211_if_ap { /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) - * NB: don't ever use set_bit, use bss_tim_set/bss_tim_clear! */ + * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; atomic_t num_sta_ps; /* number of stations in PS mode */ struct sk_buff_head ps_bc_buf; @@ -282,7 +283,7 @@ struct ieee80211_if_sta { unsigned long ibss_join_req; struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ - u32 supp_rates_bits; + u32 supp_rates_bits[IEEE80211_NUM_BANDS]; int wmm_last_param_set; }; @@ -292,6 +293,7 @@ struct ieee80211_if_sta { #define IEEE80211_SDATA_ALLMULTI BIT(0) #define IEEE80211_SDATA_PROMISC BIT(1) #define IEEE80211_SDATA_USERSPACE_MLME BIT(2) +#define IEEE80211_SDATA_OPERATING_GMODE BIT(3) struct ieee80211_sub_if_data { struct list_head list; @@ -306,11 +308,11 @@ struct ieee80211_sub_if_data { unsigned int flags; int drop_unencrypted; + /* - * IEEE 802.1X Port access control in effect, - * drop packets to/from unauthorized port + * basic rates of this AP or the AP we're associated to */ - int ieee802_1x_pac; + u64 basic_rates; u16 sequence; @@ -338,6 +340,7 @@ struct ieee80211_sub_if_data { struct ieee80211_if_wds wds; struct ieee80211_if_vlan vlan; struct ieee80211_if_sta sta; + u32 mntr_flags; } u; int channel_use; int channel_use_raw; @@ -348,7 +351,6 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; struct dentry *state; struct dentry *bssid; struct dentry *prev_bssid; @@ -367,7 +369,6 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; struct dentry *num_sta_ps; struct dentry *dtim_count; struct dentry *num_beacons; @@ -378,13 +379,11 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; struct dentry *peer; } wds; struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; } vlan; struct { struct dentry *mode; @@ -407,6 +406,8 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) enum { IEEE80211_RX_MSG = 1, IEEE80211_TX_STATUS_MSG = 2, + IEEE80211_DELBA_MSG = 3, + IEEE80211_ADDBA_MSG = 4, }; struct ieee80211_local { @@ -417,12 +418,11 @@ struct ieee80211_local { const struct ieee80211_ops *ops; - /* List of registered struct ieee80211_hw_mode */ - struct list_head modes_list; - struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; - int monitors; + int monitors, cooked_mntrs; + /* number of interfaces with corresponding FIF_ flags */ + int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; @@ -450,8 +450,8 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[NUM_TX_DATA_QUEUES]; - struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES]; + unsigned long state[NUM_TX_DATA_QUEUES_AMPDU]; + struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU]; struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ @@ -459,11 +459,6 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - /* Supported and basic rate filters for different modes. These are - * pointers to -1 terminated lists and rates in 100 kbps units. */ - int *supp_rates[NUM_IEEE80211_MODES]; - int *basic_rates[NUM_IEEE80211_MODES]; - int rts_threshold; int fragmentation_threshold; int short_retry_limit; /* dot11ShortRetryLimit */ @@ -477,21 +472,18 @@ struct ieee80211_local { * deliver multicast frames both back to wireless * media and to the local net stack */ - ieee80211_rx_handler *rx_pre_handlers; - ieee80211_rx_handler *rx_handlers; - ieee80211_tx_handler *tx_handlers; - struct list_head interfaces; bool sta_sw_scanning; bool sta_hw_scanning; int scan_channel_idx; + enum ieee80211_band scan_band; + enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; unsigned long last_scan_completed; struct delayed_work scan_work; struct net_device *scan_dev; struct ieee80211_channel *oper_channel, *scan_channel; - struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode; u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; size_t scan_ssid_len; struct list_head sta_bss_list; @@ -560,14 +552,8 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - unsigned int enabled_modes; /* bitfield of allowed modes; - * (1 << MODE_*) */ - unsigned int hw_modes; /* bitfield of supported hardware modes; - * (1 << MODE_*) */ - #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { - struct dentry *channel; struct dentry *frequency; struct dentry *antenna_sel_tx; struct dentry *antenna_sel_rx; @@ -577,9 +563,7 @@ struct ieee80211_local { struct dentry *short_retry_limit; struct dentry *long_retry_limit; struct dentry *total_ps_buffered; - struct dentry *mode; struct dentry *wep_iv; - struct dentry *modes; struct dentry *statistics; struct local_debugfsdentries_statsdentries { struct dentry *transmitted_fragment_count; @@ -627,6 +611,12 @@ struct ieee80211_local { #endif }; +/* this struct represents 802.11n's RA/TID combination */ +struct ieee80211_ra_tid { + u8 ra[ETH_ALEN]; + u16 tid; +}; + static inline struct ieee80211_local *hw_to_local( struct ieee80211_hw *hw) { @@ -650,57 +640,6 @@ struct sta_attribute { ssize_t (*store)(struct sta_info *, const char *buf, size_t count); }; -static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) -{ - /* - * This format has been mandated by the IEEE specifications, - * so this line may not be changed to use the __set_bit() format. - */ - bss->tim[aid / 8] |= (1 << (aid % 8)); -} - -static inline void bss_tim_set(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, u16 aid) -{ - read_lock_bh(&local->sta_lock); - __bss_tim_set(bss, aid); - read_unlock_bh(&local->sta_lock); -} - -static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) -{ - /* - * This format has been mandated by the IEEE specifications, - * so this line may not be changed to use the __clear_bit() format. - */ - bss->tim[aid / 8] &= ~(1 << (aid % 8)); -} - -static inline void bss_tim_clear(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, u16 aid) -{ - read_lock_bh(&local->sta_lock); - __bss_tim_clear(bss, aid); - read_unlock_bh(&local->sta_lock); -} - -/** - * ieee80211_is_erp_rate - Check if a rate is an ERP rate - * @phymode: The PHY-mode for this rate (MODE_IEEE80211...) - * @rate: Transmission rate to check, in 100 kbps - * - * Check if a given rate is an Extended Rate PHY (ERP) rate. - */ -static inline int ieee80211_is_erp_rate(int phymode, int rate) -{ - if (phymode == MODE_IEEE80211G) { - if (rate != 10 && rate != 20 && - rate != 55 && rate != 110) - return 1; - } - return 0; -} - static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) { return compare_ether_addr(raddr, addr) == 0 || @@ -712,13 +651,9 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); -struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, - int phymode, int hwrate); int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_info *req_ht_cap, struct ieee80211_ht_bss_info *req_bss_cap); @@ -749,7 +684,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* ieee80211_ioctl.c */ int ieee80211_set_compression(struct ieee80211_local *local, struct net_device *dev, struct sta_info *sta); -int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq); +int ieee80211_set_freq(struct ieee80211_local *local, int freq); /* ieee80211_sta.c */ void ieee80211_sta_timer(unsigned long data); void ieee80211_sta_work(struct work_struct *work); @@ -763,9 +698,9 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); void ieee80211_sta_req_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta); int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len); -ieee80211_txrx_result ieee80211_sta_rx_scan(struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_rx_result ieee80211_sta_rx_scan( + struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status); void ieee80211_rx_bss_list_init(struct net_device *dev); void ieee80211_rx_bss_list_deinit(struct net_device *dev); int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len); @@ -782,9 +717,15 @@ int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, int ieee80211_ht_addt_info_ie_to_ht_bss_info( struct ieee80211_ht_addt_info *ht_add_info_ie, struct ieee80211_ht_bss_info *bss_info); +void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, + u16 tid, u8 dialog_token, u16 start_seq_num, + 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); /* ieee80211_iface.c */ int ieee80211_if_add(struct net_device *dev, const char *name, struct net_device **new_dev, int type); @@ -796,16 +737,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id); void ieee80211_if_free(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); -/* regdomain.c */ -void ieee80211_regdomain_init(void); -void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); - -/* rx handling */ -extern ieee80211_rx_handler ieee80211_rx_pre_handlers[]; -extern ieee80211_rx_handler ieee80211_rx_handlers[]; - /* tx handling */ -extern ieee80211_tx_handler ieee80211_tx_handlers[]; void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 92f1eb2da31..0d6824bca92 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -118,6 +118,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) sdata->bss = NULL; sdata->vif.type = type; + sdata->basic_rates = 0; + switch (type) { case IEEE80211_IF_TYPE_WDS: /* nothing special */ @@ -158,6 +160,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) case IEEE80211_IF_TYPE_MNTR: dev->type = ARPHRD_IEEE80211_RADIOTAP; dev->hard_start_xmit = ieee80211_monitor_start_xmit; + sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | + MONITOR_FLAG_OTHER_BSS; break; default: printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", @@ -189,6 +193,7 @@ void ieee80211_if_reinit(struct net_device *dev) /* Remove all virtual interfaces that use this BSS * as their sdata->bss */ struct ieee80211_sub_if_data *tsdata, *n; + struct beacon_data *beacon; list_for_each_entry_safe(tsdata, n, &local->interfaces, list) { if (tsdata != sdata && tsdata->bss == &sdata->u.ap) { @@ -206,7 +211,10 @@ void ieee80211_if_reinit(struct net_device *dev) } } - kfree(sdata->u.ap.beacon); + beacon = sdata->u.ap.beacon; + rcu_assign_pointer(sdata->u.ap.beacon, NULL); + synchronize_rcu(); + kfree(beacon); while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { local->total_ps_buffered--; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 5024d373383..7551db3f3ab 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -33,8 +33,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, size_t key_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int ret = 0; - struct sta_info *sta; + int ret; + struct sta_info *sta = NULL; struct ieee80211_key *key; struct ieee80211_sub_if_data *sdata; @@ -46,58 +46,64 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, return -EINVAL; } - if (is_broadcast_ether_addr(sta_addr)) { - sta = NULL; - key = sdata->keys[idx]; - } else { - set_tx_key = 0; - /* - * According to the standard, the key index of a pairwise - * key must be zero. However, some AP are broken when it - * comes to WEP key indices, so we work around this. - */ - if (idx != 0 && alg != ALG_WEP) { - printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for " - "individual key\n", dev->name); - return -EINVAL; + if (remove) { + if (is_broadcast_ether_addr(sta_addr)) { + key = sdata->keys[idx]; + } else { + sta = sta_info_get(local, sta_addr); + if (!sta) { + ret = -ENOENT; + key = NULL; + goto err_out; + } + + key = sta->key; } - sta = sta_info_get(local, sta_addr); - if (!sta) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: set_encrypt - unknown addr " - "%s\n", - dev->name, print_mac(mac, sta_addr)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + if (!key) + ret = -ENOENT; + else + ret = 0; + } else { + key = ieee80211_key_alloc(alg, idx, key_len, _key); + if (!key) + return -ENOMEM; - return -ENOENT; + if (!is_broadcast_ether_addr(sta_addr)) { + set_tx_key = 0; + /* + * According to the standard, the key index of a + * pairwise key must be zero. However, some AP are + * broken when it comes to WEP key indices, so we + * work around this. + */ + if (idx != 0 && alg != ALG_WEP) { + ret = -EINVAL; + goto err_out; + } + + sta = sta_info_get(local, sta_addr); + if (!sta) { + ret = -ENOENT; + goto err_out; + } } - key = sta->key; - } + ieee80211_key_link(key, sdata, sta); - if (remove) { - ieee80211_key_free(key); + if (set_tx_key || (!sta && !sdata->default_key && key)) + ieee80211_set_default_key(sdata, idx); + + /* don't free key later */ key = NULL; - } else { - /* - * Automatically frees any old key if present. - */ - key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); - if (!key) { - ret = -ENOMEM; - goto err_out; - } - } - if (set_tx_key || (!sta && !sdata->default_key && key)) - ieee80211_set_default_key(sdata, idx); + ret = 0; + } - ret = 0; err_out: if (sta) sta_info_put(sta); + ieee80211_key_free(key); return ret; } @@ -129,22 +135,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - switch (local->hw.conf.phymode) { - case MODE_IEEE80211A: - strcpy(name, "IEEE 802.11a"); - break; - case MODE_IEEE80211B: - strcpy(name, "IEEE 802.11b"); - break; - case MODE_IEEE80211G: - strcpy(name, "IEEE 802.11g"); - break; - default: - strcpy(name, "IEEE 802.11"); - break; - } + strcpy(name, "IEEE 802.11"); return 0; } @@ -156,7 +147,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iw_range *range = (struct iw_range *) extra; - struct ieee80211_hw_mode *mode = NULL; + enum ieee80211_band band; int c = 0; data->length = sizeof(struct iw_range); @@ -191,24 +182,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - list_for_each_entry(mode, &local->modes_list, list) { - int i = 0; - if (!(local->enabled_modes & (1 << mode->mode)) || - (local->hw_modes & local->enabled_modes & - (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) + for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { + int i; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + + if (!sband) continue; - while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) { - struct ieee80211_channel *chan = &mode->channels[i]; + for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; - if (chan->flag & IEEE80211_CHAN_W_SCAN) { - range->freq[c].i = chan->chan; - range->freq[c].m = chan->freq * 100000; - range->freq[c].e = 1; + if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { + range->freq[c].i = + ieee80211_frequency_to_channel( + chan->center_freq); + range->freq[c].m = chan->center_freq; + range->freq[c].e = 6; c++; } - i++; } } range->num_channels = c; @@ -294,22 +288,29 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, return 0; } -int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) +int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) { - struct ieee80211_hw_mode *mode; - int c, set = 0; + 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]; - list_for_each_entry(mode, &local->modes_list, list) { - if (!(local->enabled_modes & (1 << mode->mode))) + if (!sband) continue; - for (c = 0; c < mode->num_channels; c++) { - struct ieee80211_channel *chan = &mode->channels[c]; - if (chan->flag & IEEE80211_CHAN_W_SCAN && - ((chan->chan == channel) || (chan->freq == freq))) { - local->oper_channel = chan; - local->oper_hw_mode = mode; + + 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; } } @@ -347,13 +348,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else - return ieee80211_set_channel(local, freq->m, -1); + return ieee80211_set_freq(local, + ieee80211_channel_to_frequency(freq->m)); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; if (div > 0) - return ieee80211_set_channel(local, -1, freq->m / div); + return ieee80211_set_freq(local, freq->m / div); else return -EINVAL; } @@ -366,10 +368,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level - * driver for the current channel with firmware-based management */ - - freq->m = local->hw.conf.freq; + freq->m = local->hw.conf.channel->center_freq; freq->e = 6; return 0; @@ -566,15 +565,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, struct iw_param *rate, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; - int i; + int i, err = -EINVAL; u32 target_rate = rate->value / 100000; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!sdata->bss) return -ENODEV; - mode = local->oper_hw_mode; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates * target_rate = X, rate->fixed = 1 means only rate X * target_rate = X, rate->fixed = 0 means all rates <= X */ @@ -582,18 +583,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, sdata->bss->force_unicast_rateidx = -1; if (rate->value < 0) return 0; - for (i=0; i < mode->num_rates; i++) { - struct ieee80211_rate *rates = &mode->rates[i]; - int this_rate = rates->rate; + + for (i=0; i< sband->n_bitrates; i++) { + struct ieee80211_rate *brate = &sband->bitrates[i]; + int this_rate = brate->bitrate; if (target_rate == this_rate) { sdata->bss->max_ratectrl_rateidx = i; if (rate->fixed) sdata->bss->force_unicast_rateidx = i; - return 0; + err = 0; + break; } } - return -EINVAL; + return err; } static int ieee80211_ioctl_giwrate(struct net_device *dev, @@ -603,18 +606,24 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sta = sta_info_get(local, sdata->u.sta.bssid); else return -EOPNOTSUPP; if (!sta) return -ENODEV; - if (sta->txrate < local->oper_hw_mode->num_rates) - rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + if (sta->txrate_idx < sband->n_bitrates) + rate->value = sband->bitrates[sta->txrate_idx].bitrate; else rate->value = 0; + rate->value *= 100000; sta_info_put(sta); return 0; } @@ -625,7 +634,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); bool need_reconfig = 0; - u8 new_power_level; + int new_power_level; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; @@ -635,13 +644,15 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, if (data->txpower.fixed) { new_power_level = data->txpower.value; } else { - /* Automatic power level. Get the px power from the current - * channel. */ - struct ieee80211_channel* chan = local->oper_channel; + /* + * Automatic power level. Use maximum power for the current + * channel. Should be part of rate control. + */ + struct ieee80211_channel* chan = local->hw.conf.channel; if (!chan) return -EINVAL; - new_power_level = chan->power_level; + new_power_level = chan->max_power; } if (local->hw.conf.power_level != new_power_level) { diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index fc770e98d47..d670e6dbfa3 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -13,6 +13,7 @@ #include <linux/types.h> #include <linux/list.h> #include <linux/crypto.h> +#include <linux/rcupdate.h> #include <net/mac80211.h> /* ALG_TKIP @@ -45,7 +46,19 @@ struct ieee80211_local; struct ieee80211_sub_if_data; struct sta_info; -#define KEY_FLAG_UPLOADED_TO_HARDWARE (1<<0) +/** + * enum ieee80211_internal_key_flags - internal key flags + * + * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present + * in the hardware for TX crypto hardware acceleration. + * @KEY_FLAG_REMOVE_FROM_HARDWARE: Indicates to the key code that this + * key is present in the hardware (but it cannot be used for + * hardware acceleration any more!) + */ +enum ieee80211_internal_key_flags { + KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), + KEY_FLAG_REMOVE_FROM_HARDWARE = BIT(1), +}; struct ieee80211_key { struct ieee80211_local *local; @@ -112,12 +125,17 @@ struct ieee80211_key { struct ieee80211_key_conf conf; }; -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, - enum ieee80211_key_alg alg, +struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data); +/* + * Insert a key into data structures (sdata, sta if necessary) + * to make it used, free old key. + */ +void ieee80211_key_link(struct ieee80211_key *key, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta); void ieee80211_key_free(struct ieee80211_key *key); void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index b957e67c5fb..ebe29b716b2 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -163,7 +163,8 @@ static void rate_control_release(struct kref *kref) } void rate_control_get_rate(struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, struct rate_selection *sel) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -174,17 +175,17 @@ void rate_control_get_rate(struct net_device *dev, memset(sel, 0, sizeof(struct rate_selection)); - ref->ops->get_rate(ref->priv, dev, mode, skb, sel); + ref->ops->get_rate(ref->priv, dev, sband, skb, sel); /* Select a non-ERP backup rate. */ if (!sel->nonerp) { - for (i = 0; i < mode->num_rates - 1; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - if (sel->rate->rate < rate->rate) + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + if (sel->rate->bitrate < rate->bitrate) break; - if (rate_supported(sta, mode, i) && - !(rate->flags & IEEE80211_RATE_ERP)) + if (rate_supported(sta, sband->band, i) && + !(rate->flags & IEEE80211_RATE_ERP_G)) sel->nonerp = rate; } } diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index 73f19e8aa51..5f9a2ca49a5 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -18,6 +18,7 @@ #include "ieee80211_i.h" #include "sta_info.h" +/* TODO: kdoc */ struct rate_selection { /* Selected transmission rate */ struct ieee80211_rate *rate; @@ -34,7 +35,8 @@ struct rate_control_ops { struct sk_buff *skb, struct ieee80211_tx_status *status); void (*get_rate)(void *priv, struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *band, + struct sk_buff *skb, struct rate_selection *sel); void (*rate_init)(void *priv, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta); @@ -66,7 +68,8 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops); struct rate_control_ref *rate_control_alloc(const char *name, struct ieee80211_local *local); void rate_control_get_rate(struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, struct rate_selection *sel); struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); @@ -127,23 +130,23 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) #endif } -static inline int -rate_supported(struct sta_info *sta, struct ieee80211_hw_mode *mode, int index) +static inline int rate_supported(struct sta_info *sta, + enum ieee80211_band band, + int index) { - return (sta == NULL || sta->supp_rates & BIT(index)) && - (mode->rates[index].flags & IEEE80211_RATE_SUPPORTED); + return (sta == NULL || sta->supp_rates[band] & BIT(index)); } static inline int -rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode, +rate_lowest_index(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, struct sta_info *sta) { int i; - for (i = 0; i < mode->num_rates; i++) { - if (rate_supported(sta, mode, i)) + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) return i; - } /* warn when we cannot find a rate. */ WARN_ON(1); @@ -152,10 +155,11 @@ rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode, } static inline struct ieee80211_rate * -rate_lowest(struct ieee80211_local *local, struct ieee80211_hw_mode *mode, +rate_lowest(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, struct sta_info *sta) { - return &mode->rates[rate_lowest_index(local, mode, sta)]; + return &sband->bitrates[rate_lowest_index(local, sband, sta)]; } diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9aeed532022..ddb5832f37c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -74,7 +74,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, u8 *ssid, size_t ssid_len); static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len); static void ieee80211_rx_bss_put(struct net_device *dev, struct ieee80211_sta_bss *bss); @@ -227,12 +227,7 @@ static void ieee802_11_parse_elems(u8 *start, size_t len, static int ecw2cw(int ecw) { - int cw = 1; - while (ecw > 0) { - cw <<= 1; - ecw--; - } - return cw - 1; + return (1 << ecw) - 1; } static void ieee80211_sta_wmm_params(struct net_device *dev, @@ -297,12 +292,13 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, params.aifs = pos[0] & 0x0f; params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); params.cw_min = ecw2cw(pos[1] & 0x0f); - /* TXOP is in units of 32 usec; burst_time in 0.1 ms */ - params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100; + params.txop = pos[2] | (pos[3] << 8); +#ifdef CONFIG_MAC80211_DEBUG printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d burst=%d\n", + "cWmin=%d cWmax=%d txop=%d\n", dev->name, queue, aci, acm, params.aifs, params.cw_min, - params.cw_max, params.burst_time); + params.cw_max, params.txop); +#endif /* TODO: handle ACM (block TX, fallback to next lowest allowed * AC for now) */ if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { @@ -466,7 +462,7 @@ static void ieee80211_set_associated(struct net_device *dev, return; bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->has_erp_value) @@ -492,6 +488,7 @@ static void ieee80211_set_associated(struct net_device *dev, ifsta->last_probe = jiffies; ieee80211_led_assoc(local, assoc); + sdata->bss_conf.assoc = assoc; ieee80211_bss_info_change_notify(sdata, changed); } @@ -592,7 +589,6 @@ static void ieee80211_send_assoc(struct net_device *dev, struct ieee80211_if_sta *ifsta) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, *ies; @@ -600,6 +596,7 @@ static void ieee80211_send_assoc(struct net_device *dev, u16 capab; struct ieee80211_sta_bss *bss; int wmm = 0; + struct ieee80211_supported_band *sband; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + ifsta->extra_ie_len + @@ -611,13 +608,19 @@ static void ieee80211_send_assoc(struct net_device *dev, } skb_reserve(skb, local->hw.extra_tx_headroom); - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + capab = ifsta->capab; - if (mode->mode == MODE_IEEE80211G) { - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | - WLAN_CAPABILITY_SHORT_PREAMBLE; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; } - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, + + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->capability & WLAN_CAPABILITY_PRIVACY) @@ -656,23 +659,23 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = ifsta->ssid_len; memcpy(pos, ifsta->ssid, ifsta->ssid_len); - len = mode->num_rates; + len = sband->n_bitrates; if (len > 8) len = 8; pos = skb_put(skb, len + 2); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = len; for (i = 0; i < len; i++) { - int rate = mode->rates[i].rate; + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } - if (mode->num_rates > len) { - pos = skb_put(skb, mode->num_rates - len + 2); + if (sband->n_bitrates > len) { + pos = skb_put(skb, sband->n_bitrates - len + 2); *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = mode->num_rates - len; - for (i = len; i < mode->num_rates; i++) { - int rate = mode->rates[i].rate; + *pos++ = sband->n_bitrates - len; + for (i = len; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } } @@ -695,17 +698,18 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = 0; } /* wmm support is a must to HT */ - if (wmm && mode->ht_info.ht_supported) { - __le16 tmp = cpu_to_le16(mode->ht_info.cap); + if (wmm && sband->ht_info.ht_supported) { + __le16 tmp = cpu_to_le16(sband->ht_info.cap); pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); memset(pos, 0, sizeof(struct ieee80211_ht_cap)); memcpy(pos, &tmp, sizeof(u16)); pos += sizeof(u16); - *pos++ = (mode->ht_info.ampdu_factor | - (mode->ht_info.ampdu_density << 2)); - memcpy(pos, mode->ht_info.supp_mcs_set, 16); + /* TODO: needs a define here for << 2 */ + *pos++ = sband->ht_info.ampdu_factor | + (sband->ht_info.ampdu_density << 2); + memcpy(pos, sband->ht_info.supp_mcs_set, 16); } kfree(ifsta->assocreq_ies); @@ -788,7 +792,8 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) return 0; - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (!bss) return 0; @@ -898,7 +903,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, u8 *ssid, size_t ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, *supp_rates, *esupp_rates = NULL; @@ -932,11 +937,10 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, supp_rates = skb_put(skb, 2); supp_rates[0] = WLAN_EID_SUPP_RATES; supp_rates[1] = 0; - mode = local->oper_hw_mode; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - if (!(rate->flags & IEEE80211_RATE_SUPPORTED)) - continue; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; if (esupp_rates) { pos = skb_put(skb, 1); esupp_rates[1]++; @@ -949,7 +953,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, pos = skb_put(skb, 1); supp_rates[1]++; } - *pos = rate->rate / 5; + *pos = rate->bitrate / 5; } ieee80211_sta_tx(dev, skb, 0); @@ -1044,6 +1048,58 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid, return; } +void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, + u16 tid, u8 dialog_token, u16 start_seq_num, + u16 agg_size, u16 timeout) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 capab; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.addba_req)); + + + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer " + "for addba request frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); + + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; + + mgmt->u.action.u.addba_req.dialog_token = dialog_token; + capab = (u16)(1 << 1); /* bit 1 aggregation policy */ + capab |= (u16)(tid << 2); /* bit 5:2 TID number */ + capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ + + mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); + + mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); + mgmt->u.action.u.addba_req.start_seq_num = + cpu_to_le16(start_seq_num << 4); + + ieee80211_sta_tx(dev, skb, 0); +} + static void ieee80211_sta_process_addba_request(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len) @@ -1093,9 +1149,11 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, } /* determine default buffer size */ if (buf_size == 0) { - struct ieee80211_hw_mode *mode = conf->mode; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[conf->channel->band]; buf_size = IEEE80211_MIN_AMPDU_BUF; - buf_size = buf_size << mode->ht_info.ampdu_factor; + buf_size = buf_size << sband->ht_info.ampdu_factor; } tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid]; @@ -1127,7 +1185,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, if (local->ops->ampdu_action) ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, - sta->addr, tid, start_seq_num); + sta->addr, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1155,8 +1213,80 @@ end_no_lock: sta_info_put(sta); } -static void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, - u16 initiator, u16 reason_code) +static void ieee80211_sta_process_addba_resp(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u16 capab; + u16 tid; + u8 *state; + + sta = sta_info_get(local, mgmt->sa); + if (!sta) + return; + + capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + + state = &sta->ampdu_mlme.tid_tx[tid].state; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (mgmt->u.action.u.addba_resp.dialog_token != + sta->ampdu_mlme.tid_tx[tid].dialog_token) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + sta_info_put(sta); + return; + } + + del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) + == WLAN_STATUS_SUCCESS) { + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" + "%d\n", *state); + sta_info_put(sta); + return; + } + + if (*state & HT_ADDBA_RECEIVED_MSK) + printk(KERN_DEBUG "double addBA response\n"); + + *state |= HT_ADDBA_RECEIVED_MSK; + sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); + } else { + printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); + + sta->ampdu_mlme.tid_tx[tid].addba_req_num++; + /* this will allow the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, sta->addr, tid, + WLAN_BACK_INITIATOR); + } + sta_info_put(sta); +} + +void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, + u16 initiator, u16 reason_code) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1229,7 +1359,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, BUG_ON(!local->ops->ampdu_action); ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, - ra, tid, EINVAL); + ra, tid, NULL); if (ret) printk(KERN_DEBUG "HW problem - can not stop rx " "aggergation for tid %d\n", tid); @@ -1258,6 +1388,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, sta_info_put(sta); } + static void ieee80211_sta_process_delba(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len) { @@ -1277,14 +1408,70 @@ static void ieee80211_sta_process_delba(struct net_device *dev, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "delba from %s on tid %d reason code %d\n", - print_mac(mac, mgmt->sa), tid, + printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", + print_mac(mac, mgmt->sa), + initiator ? "recipient" : "initiator", tid, mgmt->u.action.u.delba.reason_code); #endif /* CONFIG_MAC80211_HT_DEBUG */ if (initiator == WLAN_BACK_INITIATOR) ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, WLAN_BACK_INITIATOR, 0); + else { /* WLAN_BACK_RECIPIENT */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + sta->ampdu_mlme.tid_tx[tid].state = + HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, + WLAN_BACK_RECIPIENT); + } + sta_info_put(sta); +} + +/* + * After sending add Block Ack request we activated a timer until + * add Block Ack response will arrive from the recipient. + * If this timer expires sta_addba_resp_timer_expired will be executed. + */ +void sta_addba_resp_timer_expired(unsigned long data) +{ + /* not an elegant detour, but there is no choice as the timer passes + * only one argument, and both sta_info and TID are needed, so init + * flow in sta_info_add gives the TID as data, while the timer_to_id + * array gives the sta through container_of */ + u16 tid = *(int *)data; + struct sta_info *temp_sta = container_of((void *)data, + struct sta_info, timer_to_tid[tid]); + + struct ieee80211_local *local = temp_sta->local; + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u8 *state; + + sta = sta_info_get(local, temp_sta->addr); + if (!sta) + return; + + state = &sta->ampdu_mlme.tid_tx[tid].state; + /* check if the TID waits for addBA response */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + *state = HT_AGG_STATE_IDLE; + printk(KERN_DEBUG "timer expired on tid %d but we are not " + "expecting addBA response there", tid); + goto timer_expired_exit; + } + + printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); + + /* go through the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, + WLAN_BACK_INITIATOR); + +timer_expired_exit: sta_info_put(sta); } @@ -1536,15 +1723,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct net_device *dev = sdata->dev; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct sta_info *sta; - u32 rates; + u64 rates, basic_rates; u16 capab_info, status_code, aid; struct ieee802_11_elems elems; struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; u8 *pos; int i, j; DECLARE_MAC_BUF(mac); + bool have_higher_than_11mbit = false; /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ @@ -1614,22 +1802,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (ifsta->assocresp_ies) memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); - /* set AID, ieee80211_set_associated() will tell the driver */ - bss_conf->aid = aid; - ieee80211_set_associated(dev, ifsta, 1); - /* Add STA entry for the AP */ sta = sta_info_get(local, ifsta->bssid); if (!sta) { struct ieee80211_sta_bss *bss; sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); - if (!sta) { + if (IS_ERR(sta)) { printk(KERN_DEBUG "%s: failed to add STA entry for the" - " AP\n", dev->name); + " AP (error %ld)\n", dev->name, PTR_ERR(sta)); return; } bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { sta->last_rssi = bss->rssi; @@ -1640,23 +1824,50 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } sta->dev = dev; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | + WLAN_STA_AUTHORIZED; rates = 0; - mode = local->oper_hw_mode; + basic_rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == rate) + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); + if (elems.supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } } + for (i = 0; i < elems.ext_supp_rates_len; i++) { int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == rate) + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); + if (elems.ext_supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } } - sta->supp_rates = rates; + + sta->supp_rates[local->hw.conf.channel->band] = rates; + sdata->basic_rates = basic_rates; + + /* cf. IEEE 802.11 9.2.12 */ + 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 (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && local->ops->conf_ht) { @@ -1679,6 +1890,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, elems.wmm_param_len); } + /* set AID, ieee80211_set_associated() will tell the driver */ + bss_conf->aid = aid; + ieee80211_set_associated(dev, ifsta, 1); sta_info_put(sta); @@ -1719,7 +1933,7 @@ static void __ieee80211_rx_bss_hash_del(struct net_device *dev, static struct ieee80211_sta_bss * -ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, +ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -1731,7 +1945,7 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, atomic_inc(&bss->users); atomic_inc(&bss->users); memcpy(bss->bssid, bssid, ETH_ALEN); - bss->channel = channel; + bss->freq = freq; if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { memcpy(bss->ssid, ssid, ssid_len); bss->ssid_len = ssid_len; @@ -1747,7 +1961,7 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -1757,7 +1971,7 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, bss = local->sta_bss_hash[STA_HASH(bssid)]; while (bss) { if (!memcmp(bss->bssid, bssid, ETH_ALEN) && - bss->channel == channel && + bss->freq == freq && bss->ssid_len == ssid_len && (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { atomic_inc(&bss->users); @@ -1813,6 +2027,165 @@ void ieee80211_rx_bss_list_deinit(struct net_device *dev) } +static int ieee80211_sta_join_ibss(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_sta_bss *bss) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int res, rates, i, j; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + struct ieee80211_tx_control control; + struct rate_selection ratesel; + u8 *pos; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + /* Remove possible STA entries from other IBSS networks. */ + sta_info_flush(local, NULL); + + if (local->ops->reset_tsf) { + /* Reset own TSF to allow time synchronization work. */ + local->ops->reset_tsf(local_to_hw(local)); + } + memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); + res = ieee80211_if_config(dev); + if (res) + return res; + + local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata->drop_unencrypted = bss->capability & + WLAN_CAPABILITY_PRIVACY ? 1 : 0; + + res = ieee80211_set_freq(local, bss->freq); + + if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { + printk(KERN_DEBUG "%s: IBSS not allowed on frequency " + "%d MHz\n", dev->name, local->oper_channel->center_freq); + return -1; + } + + /* Set beacon template */ + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + do { + if (!skb) + break; + + skb_reserve(skb, local->hw.extra_tx_headroom); + + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_BEACON); + memset(mgmt->da, 0xff, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->u.beacon.beacon_int = + cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); + + pos = skb_put(skb, 2 + ifsta->ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ifsta->ssid_len; + memcpy(pos, ifsta->ssid, ifsta->ssid_len); + + rates = bss->supp_rates_len; + if (rates > 8) + rates = 8; + pos = skb_put(skb, 2 + rates); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = rates; + memcpy(pos, bss->supp_rates, rates); + + if (bss->band == IEEE80211_BAND_2GHZ) { + pos = skb_put(skb, 2 + 1); + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = ieee80211_frequency_to_channel(bss->freq); + } + + pos = skb_put(skb, 2 + 2); + *pos++ = WLAN_EID_IBSS_PARAMS; + *pos++ = 2; + /* FIX: set ATIM window based on scan results */ + *pos++ = 0; + *pos++ = 0; + + if (bss->supp_rates_len > 8) { + rates = bss->supp_rates_len - 8; + pos = skb_put(skb, 2 + rates); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = rates; + memcpy(pos, &bss->supp_rates[8], rates); + } + + memset(&control, 0, sizeof(control)); + rate_control_get_rate(dev, sband, skb, &ratesel); + if (!ratesel.rate) { + printk(KERN_DEBUG "%s: Failed to determine TX rate " + "for IBSS beacon\n", dev->name); + break; + } + control.vif = &sdata->vif; + control.tx_rate = ratesel.rate; + if (sdata->bss_conf.use_short_preamble && + ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; + control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; + control.flags |= IEEE80211_TXCTL_NO_ACK; + control.retry_limit = 1; + + ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); + if (ifsta->probe_resp) { + mgmt = (struct ieee80211_mgmt *) + ifsta->probe_resp->data; + mgmt->frame_control = + IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_PROBE_RESP); + } else { + printk(KERN_DEBUG "%s: Could not allocate ProbeResp " + "template for IBSS\n", dev->name); + } + + if (local->ops->beacon_update && + local->ops->beacon_update(local_to_hw(local), + skb, &control) == 0) { + printk(KERN_DEBUG "%s: Configured IBSS beacon " + "template\n", dev->name); + skb = NULL; + } + + rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < bss->supp_rates_len; i++) { + int bitrate = (bss->supp_rates[i] & 0x7f) * 5; + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == bitrate) + rates |= BIT(j); + } + ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + } while (0); + + if (skb) { + printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " + "template\n", dev->name); + dev_kfree_skb(skb); + } + + ifsta->state = IEEE80211_IBSS_JOINED; + mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + + ieee80211_rx_bss_put(dev, bss); + + return res; +} + + static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len, @@ -1822,11 +2195,11 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee802_11_elems elems; size_t baselen; - int channel, clen; + int freq, clen; struct ieee80211_sta_bss *bss; struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - u64 timestamp; + u64 beacon_timestamp, rx_timestamp; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); @@ -1843,56 +2216,28 @@ static void ieee80211_rx_bss_info(struct net_device *dev, if (baselen > len) return; - timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); - - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && - memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG - static unsigned long last_tsf_debug = 0; - u64 tsf; - if (local->ops->get_tsf) - tsf = local->ops->get_tsf(local_to_hw(local)); - else - tsf = -1LLU; - if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { - printk(KERN_DEBUG "RX beacon SA=%s BSSID=" - "%s TSF=0x%llx BCN=0x%llx diff=%lld " - "@%lu\n", - print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid), - (unsigned long long)tsf, - (unsigned long long)timestamp, - (unsigned long long)(tsf - timestamp), - jiffies); - last_tsf_debug = jiffies; - } -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - } - + beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rates; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *bitrates; size_t num_rates; - u32 supp_rates, prev_rates; + u64 supp_rates, prev_rates; int i, j; - mode = local->sta_sw_scanning ? - local->scan_hw_mode : local->oper_hw_mode; + sband = local->hw.wiphy->bands[rx_status->band]; - if (local->sta_hw_scanning) { - /* search for the correct mode matches the beacon */ - list_for_each_entry(mode, &local->modes_list, list) - if (mode->mode == rx_status->phymode) - break; - - if (mode == NULL) - mode = local->oper_hw_mode; + if (!sband) { + WARN_ON(1); + sband = local->hw.wiphy->bands[ + local->hw.conf.channel->band]; } - rates = mode->rates; - num_rates = mode->num_rates; + + bitrates = sband->bitrates; + num_rates = sband->n_bitrates; supp_rates = 0; for (i = 0; i < elems.supp_rates_len + @@ -1906,24 +2251,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev, [i - elems.supp_rates_len]; own_rate = 5 * (rate & 0x7f); for (j = 0; j < num_rates; j++) - if (rates[j].rate == own_rate) + if (bitrates[j].bitrate == own_rate) supp_rates |= BIT(j); } - prev_rates = sta->supp_rates; - sta->supp_rates &= supp_rates; - if (sta->supp_rates == 0) { + prev_rates = sta->supp_rates[rx_status->band]; + sta->supp_rates[rx_status->band] &= supp_rates; + if (sta->supp_rates[rx_status->band] == 0) { /* No matching rates - this should not really happen. * Make sure that at least one rate is marked * supported to avoid issues with TX rate ctrl. */ - sta->supp_rates = sdata->u.sta.supp_rates_bits; + sta->supp_rates[rx_status->band] = + sdata->u.sta.supp_rates_bits[rx_status->band]; } - if (sta->supp_rates != prev_rates) { + if (sta->supp_rates[rx_status->band] != prev_rates) { printk(KERN_DEBUG "%s: updated supp_rates set for " - "%s based on beacon info (0x%x & 0x%x -> " - "0x%x)\n", - dev->name, print_mac(mac, sta->addr), prev_rates, - supp_rates, sta->supp_rates); + "%s based on beacon info (0x%llx & 0x%llx -> " + "0x%llx)\n", + dev->name, print_mac(mac, sta->addr), + (unsigned long long) prev_rates, + (unsigned long long) supp_rates, + (unsigned long long) sta->supp_rates[rx_status->band]); } sta_info_put(sta); } @@ -1932,14 +2280,14 @@ static void ieee80211_rx_bss_info(struct net_device *dev, return; if (elems.ds_params && elems.ds_params_len == 1) - channel = elems.ds_params[0]; + freq = ieee80211_channel_to_frequency(elems.ds_params[0]); else - channel = rx_status->channel; + freq = rx_status->freq; - bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel, + bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, elems.ssid, elems.ssid_len); if (!bss) { - bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel, + bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, elems.ssid, elems.ssid_len); if (!bss) return; @@ -1952,8 +2300,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif } - if (bss->probe_resp && beacon) { - /* Do not allow beacon to override data from Probe Response. */ + bss->band = rx_status->band; + + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + bss->probe_resp && beacon) { + /* STA mode: + * Do not allow beacon to override data from Probe Response. */ ieee80211_rx_bss_put(dev, bss); return; } @@ -2050,27 +2402,69 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->ht_ie_len = 0; } - bss->hw_mode = rx_status->phymode; - bss->freq = rx_status->freq; - if (channel != rx_status->channel && - (bss->hw_mode == MODE_IEEE80211G || - bss->hw_mode == MODE_IEEE80211B) && - channel >= 1 && channel <= 14) { - static const int freq_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 - }; - /* IEEE 802.11g/b mode can receive packets from neighboring - * channels, so map the channel into frequency. */ - bss->freq = freq_list[channel - 1]; - } - bss->timestamp = timestamp; + bss->timestamp = beacon_timestamp; bss->last_update = jiffies; bss->rssi = rx_status->ssi; bss->signal = rx_status->signal; bss->noise = rx_status->noise; if (!beacon) bss->probe_resp++; + + /* check if we need to merge IBSS */ + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && + !local->sta_sw_scanning && !local->sta_hw_scanning && + bss->capability & WLAN_CAPABILITY_IBSS && + bss->freq == local->oper_channel->center_freq && + elems.ssid_len == sdata->u.sta.ssid_len && + memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) { + if (rx_status->flag & RX_FLAG_TSFT) { + /* in order for correct IBSS merging we need mactime + * + * since mactime is defined as the time the first data + * symbol of the frame hits the PHY, and the timestamp + * of the beacon is defined as "the time that the data + * symbol containing the first bit of the timestamp is + * transmitted to the PHY plus the transmitting STA’s + * delays through its local PHY from the MAC-PHY + * interface to its interface with the WM" + * (802.11 11.1.2) - equals the time this bit arrives at + * the receiver - we have to take into account the + * offset between the two. + * e.g: at 1 MBit that means mactime is 192 usec earlier + * (=24 bytes * 8 usecs/byte) than the beacon timestamp. + */ + int rate = local->hw.wiphy->bands[rx_status->band]-> + bitrates[rx_status->rate_idx].bitrate; + rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); + } else if (local && local->ops && local->ops->get_tsf) + /* second best option: get current TSF */ + rx_timestamp = local->ops->get_tsf(local_to_hw(local)); + else + /* can't merge without knowing the TSF */ + rx_timestamp = -1LLU; +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "RX beacon SA=%s BSSID=" + "%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", + print_mac(mac, mgmt->sa), + print_mac(mac2, mgmt->bssid), + (unsigned long long)rx_timestamp, + (unsigned long long)beacon_timestamp, + (unsigned long long)(rx_timestamp - beacon_timestamp), + jiffies); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + if (beacon_timestamp > rx_timestamp) { +#ifndef CONFIG_MAC80211_IBSS_DEBUG + if (net_ratelimit()) +#endif + printk(KERN_DEBUG "%s: beacon TSF higher than " + "local TSF - IBSS merge with BSSID %s\n", + dev->name, print_mac(mac, mgmt->bssid)); + ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); + ieee80211_ibss_add_sta(dev, NULL, + mgmt->bssid, mgmt->sa); + } + } + ieee80211_rx_bss_put(dev, bss); } @@ -2235,6 +2629,12 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, break; ieee80211_sta_process_addba_request(dev, mgmt, len); break; + case WLAN_ACTION_ADDBA_RESP: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_resp))) + break; + ieee80211_sta_process_addba_resp(dev, mgmt, len); + break; case WLAN_ACTION_DELBA: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.delba))) @@ -2348,7 +2748,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status) { @@ -2356,31 +2756,31 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, u16 fc; if (skb->len < 2) - return TXRX_DROP; + return RX_DROP_UNUSABLE; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) - return TXRX_CONTINUE; + return RX_CONTINUE; if (skb->len < 24) - return TXRX_DROP; + return RX_DROP_MONITOR; if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); dev_kfree_skb(skb); - return TXRX_QUEUED; + return RX_QUEUED; } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); dev_kfree_skb(skb); - return TXRX_QUEUED; + return RX_QUEUED; } } - return TXRX_CONTINUE; + return RX_CONTINUE; } @@ -2629,7 +3029,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, } spin_lock_bh(&local->sta_bss_lock); - freq = local->oper_channel->freq; + freq = local->oper_channel->center_freq; list_for_each_entry(bss, &local->sta_bss_list, list) { if (!(bss->capability & WLAN_CAPABILITY_ESS)) continue; @@ -2660,7 +3060,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); if (selected) { - ieee80211_set_channel(local, -1, selected->freq); + ieee80211_set_freq(local, selected->freq); if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); @@ -2684,162 +3084,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev, return -1; } -static int ieee80211_sta_join_ibss(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_sta_bss *bss) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int res, rates, i, j; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - struct ieee80211_tx_control control; - struct ieee80211_hw_mode *mode; - struct rate_selection ratesel; - u8 *pos; - struct ieee80211_sub_if_data *sdata; - - /* Remove possible STA entries from other IBSS networks. */ - sta_info_flush(local, NULL); - - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } - memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); - res = ieee80211_if_config(dev); - if (res) - return res; - - local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sdata->drop_unencrypted = bss->capability & - WLAN_CAPABILITY_PRIVACY ? 1 : 0; - - res = ieee80211_set_channel(local, -1, bss->freq); - - if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) { - printk(KERN_DEBUG "%s: IBSS not allowed on channel %d " - "(%d MHz)\n", dev->name, local->hw.conf.channel, - local->hw.conf.freq); - return -1; - } - - /* Set beacon template based on scan results */ - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - do { - if (!skb) - break; - - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) - skb_put(skb, 24 + sizeof(mgmt->u.beacon)); - memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_BEACON); - memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); - mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); - - pos = skb_put(skb, 2 + ifsta->ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = ifsta->ssid_len; - memcpy(pos, ifsta->ssid, ifsta->ssid_len); - - rates = bss->supp_rates_len; - if (rates > 8) - rates = 8; - pos = skb_put(skb, 2 + rates); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = rates; - memcpy(pos, bss->supp_rates, rates); - - pos = skb_put(skb, 2 + 1); - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = bss->channel; - - pos = skb_put(skb, 2 + 2); - *pos++ = WLAN_EID_IBSS_PARAMS; - *pos++ = 2; - /* FIX: set ATIM window based on scan results */ - *pos++ = 0; - *pos++ = 0; - - if (bss->supp_rates_len > 8) { - rates = bss->supp_rates_len - 8; - pos = skb_put(skb, 2 + rates); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates; - memcpy(pos, &bss->supp_rates[8], rates); - } - - memset(&control, 0, sizeof(control)); - rate_control_get_rate(dev, local->oper_hw_mode, skb, &ratesel); - if (!ratesel.rate) { - printk(KERN_DEBUG "%s: Failed to determine TX rate " - "for IBSS beacon\n", dev->name); - break; - } - control.vif = &sdata->vif; - control.tx_rate = - (sdata->bss_conf.use_short_preamble && - (ratesel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - ratesel.rate->val2 : ratesel.rate->val; - control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.power_level = local->hw.conf.power_level; - control.flags |= IEEE80211_TXCTL_NO_ACK; - control.retry_limit = 1; - - ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); - if (ifsta->probe_resp) { - mgmt = (struct ieee80211_mgmt *) - ifsta->probe_resp->data; - mgmt->frame_control = - IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_PROBE_RESP); - } else { - printk(KERN_DEBUG "%s: Could not allocate ProbeResp " - "template for IBSS\n", dev->name); - } - - if (local->ops->beacon_update && - local->ops->beacon_update(local_to_hw(local), - skb, &control) == 0) { - printk(KERN_DEBUG "%s: Configured IBSS beacon " - "template based on scan results\n", dev->name); - skb = NULL; - } - - rates = 0; - mode = local->oper_hw_mode; - for (i = 0; i < bss->supp_rates_len; i++) { - int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == bitrate) - rates |= BIT(j); - } - ifsta->supp_rates_bits = rates; - } while (0); - - if (skb) { - printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " - "template\n", dev->name); - dev_kfree_skb(skb); - } - - ifsta->state = IEEE80211_IBSS_JOINED; - mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); - - ieee80211_rx_bss_put(dev, bss); - - return res; -} - static int ieee80211_sta_create_ibss(struct net_device *dev, struct ieee80211_if_sta *ifsta) @@ -2847,7 +3091,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; u8 bssid[ETH_ALEN], *pos; int i; DECLARE_MAC_BUF(mac); @@ -2869,28 +3113,28 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", dev->name, print_mac(mac, bssid)); - bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel, + bss = ieee80211_rx_bss_add(dev, bssid, + local->hw.conf.channel->center_freq, sdata->u.sta.ssid, sdata->u.sta.ssid_len); if (!bss) return -ENOMEM; - mode = local->oper_hw_mode; + bss->band = local->hw.conf.channel->band; + sband = local->hw.wiphy->bands[bss->band]; if (local->hw.conf.beacon_int == 0) local->hw.conf.beacon_int = 100; bss->beacon_int = local->hw.conf.beacon_int; - bss->hw_mode = local->hw.conf.phymode; - bss->freq = local->hw.conf.freq; bss->last_update = jiffies; bss->capability = WLAN_CAPABILITY_IBSS; if (sdata->default_key) { bss->capability |= WLAN_CAPABILITY_PRIVACY; } else sdata->drop_unencrypted = 0; - bss->supp_rates_len = mode->num_rates; + bss->supp_rates_len = sband->n_bitrates; pos = bss->supp_rates; - for (i = 0; i < mode->num_rates; i++) { - int rate = mode->rates[i].rate; + for (i = 0; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } @@ -2939,7 +3183,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && - (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel, + (bss = ieee80211_rx_bss_get(dev, bssid, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len))) { printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", @@ -2967,13 +3212,13 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, if (time_after(jiffies, ifsta->ibss_join_req + IEEE80211_IBSS_JOIN_TIMEOUT)) { if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && - local->oper_channel->flag & IEEE80211_CHAN_W_IBSS) + (!(local->oper_channel->flags & + IEEE80211_CHAN_NO_IBSS))) return ieee80211_sta_create_ibss(dev, ifsta); if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on the" - " configured channel %d (%d MHz)\n", - dev->name, local->hw.conf.channel, - local->hw.conf.freq); + printk(KERN_DEBUG "%s: IBSS not allowed on" + " %d MHz\n", dev->name, + local->hw.conf.channel->center_freq); } /* No IBSS found - decrease scan interval and continue @@ -2992,7 +3237,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) { - struct ieee80211_sub_if_data *sdata; + 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); @@ -3006,18 +3251,23 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) int i; memset(&qparam, 0, sizeof(qparam)); - /* TODO: are these ok defaults for all hw_modes? */ + qparam.aifs = 2; - qparam.cw_min = - local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15; + + 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.burst_time = 0; + 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; @@ -3026,7 +3276,6 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) IEEE80211_TX_QUEUE_BEACON, &qparam); } - sdata = IEEE80211_DEV_TO_SUB_IF(dev); ifsta = &sdata->u.sta; if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) @@ -3185,7 +3434,7 @@ void ieee80211_sta_scan_work(struct work_struct *work) container_of(work, struct ieee80211_local, scan_work.work); struct net_device *dev = local->scan_dev; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; int skip; unsigned long next_delay = 0; @@ -3195,44 +3444,59 @@ void ieee80211_sta_scan_work(struct work_struct *work) switch (local->scan_state) { case SCAN_SET_CHANNEL: - mode = local->scan_hw_mode; - if (local->scan_hw_mode->list.next == &local->modes_list && - local->scan_channel_idx >= mode->num_channels) { + /* + * Get current scan band. scan_band may be IEEE80211_NUM_BANDS + * after we successfully scanned the last channel of the last + * band (and the last band is supported by the hw) + */ + if (local->scan_band < IEEE80211_NUM_BANDS) + sband = local->hw.wiphy->bands[local->scan_band]; + else + sband = NULL; + + /* + * If we are at an unsupported band and have more bands + * left to scan, advance to the next supported one. + */ + while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { + local->scan_band++; + sband = local->hw.wiphy->bands[local->scan_band]; + local->scan_channel_idx = 0; + } + + /* if no more bands/channels left, complete scan */ + if (!sband || local->scan_channel_idx >= sband->n_channels) { ieee80211_scan_completed(local_to_hw(local)); return; } - skip = !(local->enabled_modes & (1 << mode->mode)); - chan = &mode->channels[local->scan_channel_idx]; - if (!(chan->flag & IEEE80211_CHAN_W_SCAN) || + skip = 0; + chan = &sband->channels[local->scan_channel_idx]; + + if (chan->flags & IEEE80211_CHAN_DISABLED || (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && - !(chan->flag & IEEE80211_CHAN_W_IBSS)) || - (local->hw_modes & local->enabled_modes & - (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) + chan->flags & IEEE80211_CHAN_NO_IBSS)) skip = 1; if (!skip) { -#if 0 - printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n", - dev->name, chan->chan, chan->freq); -#endif - local->scan_channel = chan; if (ieee80211_hw_config(local)) { - printk(KERN_DEBUG "%s: failed to set channel " - "%d (%d MHz) for scan\n", dev->name, - chan->chan, chan->freq); + printk(KERN_DEBUG "%s: failed to set freq to " + "%d MHz for scan\n", dev->name, + chan->center_freq); skip = 1; } } + /* advance state machine to next channel/band */ local->scan_channel_idx++; - if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) { - if (local->scan_hw_mode->list.next != &local->modes_list) { - local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next, - struct ieee80211_hw_mode, - list); - local->scan_channel_idx = 0; - } + if (local->scan_channel_idx >= sband->n_channels) { + /* + * scan_band may end up == IEEE80211_NUM_BANDS, but + * we'll catch that case above and complete the scan + * if that is the case. + */ + local->scan_band++; + local->scan_channel_idx = 0; } if (skip) @@ -3243,13 +3507,14 @@ void ieee80211_sta_scan_work(struct work_struct *work) local->scan_state = SCAN_SEND_PROBE; break; case SCAN_SEND_PROBE: - if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) { - ieee80211_send_probe_req(dev, NULL, local->scan_ssid, - local->scan_ssid_len); - next_delay = IEEE80211_CHANNEL_TIME; - } else - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; local->scan_state = SCAN_SET_CHANNEL; + + if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) + break; + ieee80211_send_probe_req(dev, NULL, local->scan_ssid, + local->scan_ssid_len); + next_delay = IEEE80211_CHANNEL_TIME; break; } @@ -3324,10 +3589,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev, } else local->scan_ssid_len = 0; local->scan_state = SCAN_SET_CHANNEL; - local->scan_hw_mode = list_entry(local->modes_list.next, - struct ieee80211_hw_mode, - list); local->scan_channel_idx = 0; + local->scan_band = IEEE80211_BAND_2GHZ; local->scan_dev = dev; netif_tx_lock_bh(local->mdev); @@ -3382,9 +3645,6 @@ ieee80211_sta_scan_result(struct net_device *dev, bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) return current_ev; - if (!(local->enabled_modes & (1 << bss->hw_mode))) - return current_ev; - memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; @@ -3412,12 +3672,15 @@ ieee80211_sta_scan_result(struct net_device *dev, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = bss->channel; - iwe.u.freq.e = 0; + iwe.u.freq.m = bss->freq; + iwe.u.freq.e = 6; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); - iwe.u.freq.m = bss->freq * 100000; - iwe.u.freq.e = 1; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); + iwe.u.freq.e = 0; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); @@ -3557,10 +3820,13 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); sta = sta_info_add(local, dev, addr, GFP_ATOMIC); - if (!sta) + if (IS_ERR(sta)) return NULL; - sta->supp_rates = sdata->u.sta.supp_rates_bits; + sta->flags |= WLAN_STA_AUTHORIZED; + + sta->supp_rates[local->hw.conf.channel->band] = + sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; rate_control_rate_init(sta, local); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ed57fb8e82f..eac9c59dbc4 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -13,6 +13,7 @@ #include <linux/etherdevice.h> #include <linux/list.h> #include <linux/rcupdate.h> +#include <linux/rtnetlink.h> #include <net/mac80211.h> #include "ieee80211_i.h" #include "debugfs_key.h" @@ -34,6 +35,10 @@ * * All operations here are called under RTNL so no extra locking is * required. + * + * NOTE: This code requires that sta info *destruction* is done under + * RTNL, otherwise it can try to access already freed STA structs + * when a STA key is being freed. */ static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -84,16 +89,25 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, print_mac(mac, addr), ret); } +static void ieee80211_key_mark_hw_accel_off(struct ieee80211_key *key) +{ + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + key->flags |= KEY_FLAG_REMOVE_FROM_HARDWARE; + } +} + static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; DECLARE_MAC_BUF(mac); - if (!key->local->ops->set_key) + if (!key || !key->local->ops->set_key) return; - if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(key->flags & KEY_FLAG_REMOVE_FROM_HARDWARE)) return; addr = get_mac_for_key(key); @@ -108,12 +122,11 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) wiphy_name(key->local->hw.wiphy), key->conf.keyidx, print_mac(mac, addr), ret); - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + key->flags &= ~(KEY_FLAG_UPLOADED_TO_HARDWARE | + KEY_FLAG_REMOVE_FROM_HARDWARE); } -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, - enum ieee80211_key_alg alg, +struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data) @@ -137,10 +150,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, key->conf.keyidx = idx; key->conf.keylen = key_len; memcpy(key->conf.key, key_data, key_len); - - key->local = sdata->local; - key->sdata = sdata; - key->sta = sta; + INIT_LIST_HEAD(&key->list); if (alg == ALG_CCMP) { /* @@ -154,13 +164,68 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, } } - ieee80211_debugfs_key_add(key->local, key); + return key; +} - /* remove key first */ - if (sta) - ieee80211_key_free(sta->key); - else - ieee80211_key_free(sdata->keys[idx]); +static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + struct ieee80211_key *key, + struct ieee80211_key *new) +{ + int idx, defkey; + + if (sta) { + rcu_assign_pointer(sta->key, new); + } else { + WARN_ON(new && key && new->conf.keyidx != key->conf.keyidx); + + if (key) + idx = key->conf.keyidx; + else + idx = new->conf.keyidx; + + defkey = key && sdata->default_key == key; + + if (defkey && !new) + ieee80211_set_default_key(sdata, -1); + + rcu_assign_pointer(sdata->keys[idx], new); + if (new) + list_add(&new->list, &sdata->key_list); + + if (defkey && new) + ieee80211_set_default_key(sdata, new->conf.keyidx); + } + + if (key) { + ieee80211_key_mark_hw_accel_off(key); + /* + * We'll use an empty list to indicate that the key + * has already been removed. + */ + list_del_init(&key->list); + } +} + +void ieee80211_key_link(struct ieee80211_key *key, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) +{ + struct ieee80211_key *old_key; + int idx; + + ASSERT_RTNL(); + might_sleep(); + + BUG_ON(!sdata); + BUG_ON(!key); + + idx = key->conf.keyidx; + key->local = sdata->local; + key->sdata = sdata; + key->sta = sta; + + ieee80211_debugfs_key_add(key->local, key); if (sta) { ieee80211_debugfs_key_sta_link(key, sta); @@ -186,50 +251,59 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, } } - /* enable hwaccel if appropriate */ - if (netif_running(key->sdata->dev)) - ieee80211_key_enable_hw_accel(key); - if (sta) - rcu_assign_pointer(sta->key, key); + old_key = sta->key; else - rcu_assign_pointer(sdata->keys[idx], key); + old_key = sdata->keys[idx]; - list_add(&key->list, &sdata->key_list); + __ieee80211_key_replace(sdata, sta, old_key, key); - return key; + if (old_key) { + synchronize_rcu(); + ieee80211_key_free(old_key); + } + + if (netif_running(sdata->dev)) + ieee80211_key_enable_hw_accel(key); } void ieee80211_key_free(struct ieee80211_key *key) { + ASSERT_RTNL(); + might_sleep(); + if (!key) return; - if (key->sta) { - rcu_assign_pointer(key->sta->key, NULL); - } else { - if (key->sdata->default_key == key) - ieee80211_set_default_key(key->sdata, -1); - if (key->conf.keyidx >= 0 && - key->conf.keyidx < NUM_DEFAULT_KEYS) - rcu_assign_pointer(key->sdata->keys[key->conf.keyidx], - NULL); - else - WARN_ON(1); - } + if (key->sdata) { + /* + * Replace key with nothingness. + * + * Because other code may have key reference (RCU protected) + * right now, we then wait for a grace period before freeing + * it. + * An empty list indicates it was never added to the key list + * or has been removed already. It may, however, still be in + * hardware for acceleration. + */ + if (!list_empty(&key->list)) + __ieee80211_key_replace(key->sdata, key->sta, + key, NULL); - /* wait for all key users to complete */ - synchronize_rcu(); + synchronize_rcu(); - /* remove from hwaccel if appropriate */ - ieee80211_key_disable_hw_accel(key); + /* + * Remove from hwaccel if appropriate, this will + * only happen when the key is actually unlinked, + * it will already be done when the key was replaced. + */ + ieee80211_key_disable_hw_accel(key); + } if (key->conf.alg == ALG_CCMP) ieee80211_aes_key_free(key->u.ccmp.tfm); ieee80211_debugfs_key_remove(key); - list_del(&key->list); - kfree(key); } @@ -253,6 +327,10 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key, *tmp; + LIST_HEAD(tmp_list); + + ASSERT_RTNL(); + might_sleep(); list_for_each_entry_safe(key, tmp, &sdata->key_list, list) ieee80211_key_free(key); @@ -262,8 +340,10 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key; - WARN_ON(!netif_running(sdata->dev)); - if (!netif_running(sdata->dev)) + ASSERT_RTNL(); + might_sleep(); + + if (WARN_ON(!netif_running(sdata->dev))) return; list_for_each_entry(key, &sdata->key_list, list) @@ -274,6 +354,9 @@ void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key; + ASSERT_RTNL(); + might_sleep(); + list_for_each_entry(key, &sdata->key_list, list) ieee80211_key_disable_hw_accel(key); } diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index c339571632b..9762803e487 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de> - * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it> + * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -64,71 +64,66 @@ */ -/* Shift the adjustment so that we won't switch to a lower rate if it exhibited - * a worse failed frames behaviour and we'll choose the highest rate whose - * failed frames behaviour is not worse than the one of the original rate - * target. While at it, check that the adjustment is within the ranges. Then, - * provide the new rate index. */ -static int rate_control_pid_shift_adjust(struct rc_pid_rateinfo *r, - int adj, int cur, int l) -{ - int i, j, k, tmp; - - j = r[cur].rev_index; - i = j + adj; - - if (i < 0) - return r[0].index; - if (i >= l - 1) - return r[l - 1].index; - - tmp = i; - - if (adj < 0) { - for (k = j; k >= i; k--) - if (r[k].diff <= r[j].diff) - tmp = k; - } else { - for (k = i + 1; k + i < l; k++) - if (r[k].diff <= r[i].diff) - tmp = k; - } - - return r[tmp].index; -} - +/* Adjust the rate while ensuring that we won't switch to a lower rate if it + * exhibited a worse failed frames behaviour and we'll choose the highest rate + * whose failed frames behaviour is not worse than the one of the original rate + * target. While at it, check that the new rate is valid. */ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, struct sta_info *sta, int adj, struct rc_pid_rateinfo *rinfo) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; - int newidx; - int maxrate; - int back = (adj > 0) ? 1 : -1; + struct ieee80211_supported_band *sband; + int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; + int cur = sta->txrate_idx; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + band = sband->band; + n_bitrates = sband->n_bitrates; - mode = local->oper_hw_mode; - maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; + /* Map passed arguments to sorted values. */ + cur_sorted = rinfo[cur].rev_index; + new_sorted = cur_sorted + adj; - newidx = rate_control_pid_shift_adjust(rinfo, adj, sta->txrate, - mode->num_rates); + /* Check limits. */ + if (new_sorted < 0) + new_sorted = rinfo[0].rev_index; + else if (new_sorted >= n_bitrates) + new_sorted = rinfo[n_bitrates - 1].rev_index; - while (newidx != sta->txrate) { - if (rate_supported(sta, mode, newidx) && - (maxrate < 0 || newidx <= maxrate)) { - sta->txrate = newidx; - break; - } + tmp = new_sorted; - newidx += back; + if (adj < 0) { + /* Ensure that the rate decrease isn't disadvantageous. */ + for (probe = cur_sorted; probe >= new_sorted; probe--) + if (rinfo[probe].diff <= rinfo[cur_sorted].diff && + rate_supported(sta, band, rinfo[probe].index)) + tmp = probe; + } else { + /* Look for rate increase with zero (or below) cost. */ + for (probe = new_sorted + 1; probe < n_bitrates; probe++) + if (rinfo[probe].diff <= rinfo[new_sorted].diff && + rate_supported(sta, band, rinfo[probe].index)) + tmp = probe; } + /* Fit the rate found to the nearest supported rate. */ + do { + if (rate_supported(sta, band, rinfo[tmp].index)) { + sta->txrate_idx = rinfo[tmp].index; + break; + } + if (adj < 0) + tmp--; + else + tmp++; + } while (tmp < n_bitrates && tmp >= 0); + #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_rate_change( &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events, - newidx, mode->rates[newidx].rate); + sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate); #endif } @@ -155,7 +150,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, { struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; struct rc_pid_rateinfo *rinfo = pinfo->rinfo; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; u32 pf; s32 err_avg; u32 err_prop; @@ -164,7 +159,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, int adj, i, j, tmp; unsigned long period; - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; spinfo = sta->rate_ctrl_priv; /* In case nothing happened during the previous control interval, turn @@ -190,18 +185,18 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, spinfo->tx_num_failed = 0; /* If we just switched rate, update the rate behaviour info. */ - if (pinfo->oldrate != sta->txrate) { + if (pinfo->oldrate != sta->txrate_idx) { i = rinfo[pinfo->oldrate].rev_index; - j = rinfo[sta->txrate].rev_index; + j = rinfo[sta->txrate_idx].rev_index; tmp = (pf - spinfo->last_pf); tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT); rinfo[j].diff = rinfo[i].diff + tmp; - pinfo->oldrate = sta->txrate; + pinfo->oldrate = sta->txrate_idx; } - rate_control_pid_normalize(pinfo, mode->num_rates); + rate_control_pid_normalize(pinfo, sband->n_bitrates); /* Compute the proportional, integral and derivative errors. */ err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf; @@ -242,8 +237,10 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, struct sta_info *sta; struct rc_pid_sta_info *spinfo; unsigned long period; + struct ieee80211_supported_band *sband; sta = sta_info_get(local, hdr->addr1); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; if (!sta) return; @@ -251,13 +248,13 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, /* Don't update the state if we're not controlling the rate. */ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { - sta->txrate = sdata->bss->max_ratectrl_rateidx; + sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; return; } /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.rate != &local->oper_hw_mode->rates[sta->txrate]) + if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) goto ignore; spinfo = sta->rate_ctrl_priv; @@ -283,9 +280,6 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; } else { - sta->last_ack_rssi[0] = sta->last_ack_rssi[1]; - sta->last_ack_rssi[1] = sta->last_ack_rssi[2]; - sta->last_ack_rssi[2] = status->ack_signal; sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } @@ -304,7 +298,7 @@ ignore: } static void rate_control_pid_get_rate(void *priv, struct net_device *dev, - struct ieee80211_hw_mode *mode, + struct ieee80211_supported_band *sband, struct sk_buff *skb, struct rate_selection *sel) { @@ -322,7 +316,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, mode, sta); + sel->rate = rate_lowest(local, sband, sta); if (sta) sta_info_put(sta); return; @@ -331,23 +325,23 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, /* If a forced rate is in effect, select it. */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) - sta->txrate = sdata->bss->force_unicast_rateidx; + sta->txrate_idx = sdata->bss->force_unicast_rateidx; - rateidx = sta->txrate; + rateidx = sta->txrate_idx; - if (rateidx >= mode->num_rates) - rateidx = mode->num_rates - 1; + if (rateidx >= sband->n_bitrates) + rateidx = sband->n_bitrates - 1; - sta->last_txrate = rateidx; + sta->last_txrate_idx = rateidx; sta_info_put(sta); - sel->rate = &mode->rates[rateidx]; + sel->rate = &sband->bitrates[rateidx]; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate( &((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events, - rateidx, mode->rates[rateidx].rate); + rateidx, sband->bitrates[rateidx].bitrate); #endif } @@ -359,28 +353,32 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta, * as we need to have IEEE 802.1X auth succeed immediately after assoc.. * Until that method is implemented, we will use the lowest supported * rate as a workaround. */ - sta->txrate = rate_lowest_index(local, local->oper_hw_mode, sta); + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sta->txrate_idx = rate_lowest_index(local, sband, sta); } static void *rate_control_pid_alloc(struct ieee80211_local *local) { struct rc_pid_info *pinfo; struct rc_pid_rateinfo *rinfo; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; int i, j, tmp; bool s; #ifdef CONFIG_MAC80211_DEBUGFS struct rc_pid_debugfs_entries *de; #endif + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC); if (!pinfo) return NULL; - /* We can safely assume that oper_hw_mode won't change unless we get + /* We can safely assume that sband won't change unless we get * reinitialized. */ - mode = local->oper_hw_mode; - rinfo = kmalloc(sizeof(*rinfo) * mode->num_rates, GFP_ATOMIC); + rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC); if (!rinfo) { kfree(pinfo); return NULL; @@ -389,7 +387,7 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local) /* Sort the rates. This is optimized for the most common case (i.e. * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed * mapping too. */ - for (i = 0; i < mode->num_rates; i++) { + for (i = 0; i < sband->n_bitrates; i++) { rinfo[i].index = i; rinfo[i].rev_index = i; if (pinfo->fast_start) @@ -397,11 +395,11 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local) else rinfo[i].diff = i * pinfo->norm_offset; } - for (i = 1; i < mode->num_rates; i++) { + for (i = 1; i < sband->n_bitrates; i++) { s = 0; - for (j = 0; j < mode->num_rates - i; j++) - if (unlikely(mode->rates[rinfo[j].index].rate > - mode->rates[rinfo[j + 1].index].rate)) { + for (j = 0; j < sband->n_bitrates - i; j++) + if (unlikely(sband->bitrates[rinfo[j].index].bitrate > + sband->bitrates[rinfo[j + 1].index].bitrate)) { tmp = rinfo[j].index; rinfo[j].index = rinfo[j + 1].index; rinfo[j + 1].index = tmp; diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index 9a78b116acf..bcc541d4b95 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include <linux/jiffies.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/types.h> @@ -35,8 +36,8 @@ static void rate_control_rate_inc(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; - int i = sta->txrate; + struct ieee80211_supported_band *sband; + int i = sta->txrate_idx; int maxrate; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); @@ -45,18 +46,17 @@ static void rate_control_rate_inc(struct ieee80211_local *local, return; } - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; - if (i > mode->num_rates) - i = mode->num_rates - 2; + if (i > sband->n_bitrates) + i = sband->n_bitrates - 2; - while (i + 1 < mode->num_rates) { + while (i + 1 < sband->n_bitrates) { i++; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED && + if (rate_supported(sta, sband->band, i) && (maxrate < 0 || i <= maxrate)) { - sta->txrate = i; + sta->txrate_idx = i; break; } } @@ -67,8 +67,8 @@ static void rate_control_rate_dec(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; - int i = sta->txrate; + struct ieee80211_supported_band *sband; + int i = sta->txrate_idx; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { @@ -76,15 +76,14 @@ static void rate_control_rate_dec(struct ieee80211_local *local, return; } - mode = local->oper_hw_mode; - if (i > mode->num_rates) - i = mode->num_rates; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + if (i > sband->n_bitrates) + i = sband->n_bitrates; while (i > 0) { i--; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) { - sta->txrate = i; + if (rate_supported(sta, sband->band, i)) { + sta->txrate_idx = i; break; } } @@ -132,9 +131,6 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; } else { - sta->last_ack_rssi[0] = sta->last_ack_rssi[1]; - sta->last_ack_rssi[1] = sta->last_ack_rssi[2]; - sta->last_ack_rssi[2] = status->ack_signal; sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } @@ -168,7 +164,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, } else if (per_failed < RATE_CONTROL_NUM_UP) { rate_control_rate_inc(local, sta); } - srctrl->tx_avg_rate_sum += status->control.rate->rate; + srctrl->tx_avg_rate_sum += status->control.tx_rate->bitrate; srctrl->tx_avg_rate_num++; srctrl->tx_num_failures = 0; srctrl->tx_num_xmit = 0; @@ -177,7 +173,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, rate_control_rate_dec(local, sta); } - if (srctrl->avg_rate_update + 60 * HZ < jiffies) { + if (time_after(jiffies, srctrl->avg_rate_update + 60 * HZ)) { srctrl->avg_rate_update = jiffies; if (srctrl->tx_avg_rate_num > 0) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -201,7 +197,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, static void rate_control_simple_get_rate(void *priv, struct net_device *dev, - struct ieee80211_hw_mode *mode, + struct ieee80211_supported_band *sband, struct sk_buff *skb, struct rate_selection *sel) { @@ -219,7 +215,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, mode, sta); + sel->rate = rate_lowest(local, sband, sta); if (sta) sta_info_put(sta); return; @@ -228,18 +224,18 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, /* If a forced rate is in effect, select it. */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) - sta->txrate = sdata->bss->force_unicast_rateidx; + sta->txrate_idx = sdata->bss->force_unicast_rateidx; - rateidx = sta->txrate; + rateidx = sta->txrate_idx; - if (rateidx >= mode->num_rates) - rateidx = mode->num_rates - 1; + if (rateidx >= sband->n_bitrates) + rateidx = sband->n_bitrates - 1; - sta->last_txrate = rateidx; + sta->last_txrate_idx = rateidx; sta_info_put(sta); - sel->rate = &mode->rates[rateidx]; + sel->rate = &sband->bitrates[rateidx]; } @@ -247,21 +243,15 @@ static void rate_control_simple_rate_init(void *priv, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta) { - struct ieee80211_hw_mode *mode; - int i; - sta->txrate = 0; - mode = local->oper_hw_mode; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + /* TODO: This routine should consider using RSSI from previous packets * as we need to have IEEE 802.1X auth succeed immediately after assoc.. * Until that method is implemented, we will use the lowest supported rate * as a workaround, */ - for (i = 0; i < mode->num_rates; i++) { - if ((sta->supp_rates & BIT(i)) && - (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) { - sta->txrate = i; - break; - } - } + sta->txrate_idx = rate_lowest_index(local, sband, sta); } diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c deleted file mode 100644 index f42678fa62d..00000000000 --- a/net/mac80211/regdomain.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * This regulatory domain control implementation is known to be incomplete - * and confusing. mac80211 regulatory domain control will be significantly - * reworked in the not-too-distant future. - * - * For now, drivers wishing to control which channels are and aren't available - * are advised as follows: - * - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag - * - continue to include *ALL* possible channels in the modes registered - * through ieee80211_register_hwmode() - * - for each allowable ieee80211_channel structure registered in the above - * call, set the flag member to some meaningful value such as - * IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | - * IEEE80211_CHAN_W_IBSS. - * - leave flag as 0 for non-allowable channels - * - * The usual implementation is for a driver to read a device EEPROM to - * determine which regulatory domain it should be operating under, then - * looking up the allowable channels in a driver-local table, then performing - * the above. - */ - -#include <linux/module.h> -#include <linux/netdevice.h> -#include <net/mac80211.h> -#include "ieee80211_i.h" - -static int ieee80211_regdom = 0x10; /* FCC */ -module_param(ieee80211_regdom, int, 0444); -MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK"); - -/* - * If firmware is upgraded by the vendor, additional channels can be used based - * on the new Japanese regulatory rules. This is indicated by setting - * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel - * module. - */ -static int ieee80211_japan_5ghz /* = 0 */; -module_param(ieee80211_japan_5ghz, int, 0444); -MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz"); - - -struct ieee80211_channel_range { - short start_freq; - short end_freq; - unsigned char power_level; - unsigned char antenna_max; -}; - -static const struct ieee80211_channel_range ieee80211_fcc_channels[] = { - { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */, - { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */, - { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */, - { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */, - { 0 } -}; - -static const struct ieee80211_channel_range ieee80211_mkk_channels[] = { - { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */, - { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */, - { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */, - { 0 } -}; - - -static const struct ieee80211_channel_range *channel_range = - ieee80211_fcc_channels; - - -static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan) -{ - int i; - - chan->flag = 0; - - for (i = 0; channel_range[i].start_freq; i++) { - const struct ieee80211_channel_range *r = &channel_range[i]; - if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { - if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz && - chan->freq >= 5260 && chan->freq <= 5320) { - /* - * Skip new channels in Japan since the - * firmware was not marked having been upgraded - * by the vendor. - */ - continue; - } - - if (ieee80211_regdom == 0x10 && - (chan->freq == 5190 || chan->freq == 5210 || - chan->freq == 5230)) { - /* Skip MKK channels when in FCC domain. */ - continue; - } - - chan->flag |= IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; - chan->power_level = r->power_level; - chan->antenna_max = r->antenna_max; - - if (ieee80211_regdom == 64 && - (chan->freq == 5170 || chan->freq == 5190 || - chan->freq == 5210 || chan->freq == 5230)) { - /* - * New regulatory rules in Japan have backwards - * compatibility with old channels in 5.15-5.25 - * GHz band, but the station is not allowed to - * use active scan on these old channels. - */ - chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN; - } - - if (ieee80211_regdom == 64 && - (chan->freq == 5260 || chan->freq == 5280 || - chan->freq == 5300 || chan->freq == 5320)) { - /* - * IBSS is not allowed on 5.25-5.35 GHz band - * due to radar detection requirements. - */ - chan->flag &= ~IEEE80211_CHAN_W_IBSS; - } - - break; - } - } -} - - -void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode) -{ - int c; - for (c = 0; c < mode->num_channels; c++) - ieee80211_unmask_channel(mode->mode, &mode->channels[c]); -} - - -void ieee80211_regdomain_init(void) -{ - if (ieee80211_regdom == 0x40) - channel_range = ieee80211_mkk_channels; -} - diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 535407d07fa..48574f6c0e7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/netdevice.h> @@ -82,10 +83,10 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, */ static struct sk_buff * ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, - struct ieee80211_rx_status *status) + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_rate *rate; int needed_headroom = 0; struct ieee80211_radiotap_header *rthdr; __le64 *rttsft = NULL; @@ -194,14 +195,11 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, rtfixed->rx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); - rate = ieee80211_get_rate(local, status->phymode, - status->rate); - if (rate) - rtfixed->rate = rate->rate / 5; + rtfixed->rate = rate->bitrate / 5; rtfixed->chan_freq = cpu_to_le16(status->freq); - if (status->phymode == MODE_IEEE80211A) + if (status->band == IEEE80211_BAND_5GHZ) rtfixed->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ); @@ -226,6 +224,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR) continue; + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) + continue; + if (prev_dev) { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { @@ -249,15 +250,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, } -/* pre-rx handlers - * - * these don't have dev/sdata fields in the rx data - * The sta value should also not be used because it may - * be NULL even though a STA (in IBSS mode) will be added. - */ - -static ieee80211_txrx_result -ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) +static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) { u8 *data = rx->skb->data; int tid; @@ -290,64 +283,15 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ rx->skb->priority = (tid > 7) ? 0 : tid; - - return TXRX_CONTINUE; } - -static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_rx_status *status) +static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - struct ieee80211_rate *rate; - struct ieee80211_hw_mode *mode = local->hw.conf.mode; - int i; - - /* Estimate total channel use caused by this frame */ - - if (unlikely(mode->num_rates < 0)) - return TXRX_CONTINUE; - - rate = &mode->rates[0]; - for (i = 0; i < mode->num_rates; i++) { - if (mode->rates[i].val == status->rate) { - rate = &mode->rates[i]; - break; - } - } - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (mode->mode == MODE_IEEE80211A || - (mode->mode == MODE_IEEE80211G && - rate->flags & IEEE80211_RATE_ERP)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - load += skb->len * rate->rate_inv; - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - - return load; -} - #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT -static ieee80211_txrx_result -ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx) -{ int hdrlen; if (!WLAN_FC_DATA_PRESENT(rx->fc)) - return TXRX_CONTINUE; + return; /* * Drivers are required to align the payload data in a way that @@ -372,32 +316,55 @@ ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx) if (rx->flags & IEEE80211_TXRXD_RX_AMSDU) hdrlen += ETH_HLEN; WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); - - return TXRX_CONTINUE; -} #endif +} -ieee80211_rx_handler ieee80211_rx_pre_handlers[] = + +static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate) { - ieee80211_rx_h_parse_qos, -#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT - ieee80211_rx_h_verify_ip_alignment, -#endif - NULL -}; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u32 load = 0, hdrtime; + + /* Estimate total channel use caused by this frame */ + + /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, + * 1 usec = 1/8 * (1080 / 10) = 13.5 */ + + if (status->band == IEEE80211_BAND_5GHZ || + (status->band == IEEE80211_BAND_5GHZ && + rate->flags & IEEE80211_RATE_ERP_G)) + hdrtime = CHAN_UTIL_HDR_SHORT; + else + hdrtime = CHAN_UTIL_HDR_LONG; + + load = hdrtime; + if (!is_multicast_ether_addr(hdr->addr1)) + load += hdrtime; + + /* TODO: optimise again */ + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; + + /* Divide channel_use by 8 to avoid wrapping around the counter */ + load >>= CHAN_UTIL_SHIFT; + + return load; +} /* rx handlers */ -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) { if (rx->sta) rx->sta->channel_use_raw += rx->u.rx.load; rx->sdata->channel_use_raw += rx->u.rx.load; - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) { struct ieee80211_local *local = rx->local; @@ -409,21 +376,21 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) if (unlikely(local->sta_sw_scanning)) { /* drop all the other packets during a software scan anyway */ if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status) - != TXRX_QUEUED) + != RX_QUEUED) dev_kfree_skb(skb); - return TXRX_QUEUED; + return RX_QUEUED; } if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { /* scanning finished during invoking of handlers */ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; @@ -438,14 +405,14 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) rx->local->dot11FrameDuplicateCount++; rx->sta->num_duplicates++; } - return TXRX_DROP; + return RX_DROP_MONITOR; } else rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; } if (unlikely(rx->skb->len < 16)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return TXRX_DROP; + return RX_DROP_MONITOR; } /* Drop disallowed frame classes based on STA auth/assoc state; @@ -467,23 +434,23 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ - return TXRX_DROP; + return RX_DROP_MONITOR; } - return TXRX_DROP; + return RX_DROP_MONITOR; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; int hdrlen; - ieee80211_txrx_result result = TXRX_DROP; + ieee80211_rx_result result = RX_DROP_UNUSABLE; struct ieee80211_key *stakey = NULL; /* @@ -513,14 +480,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) */ if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) - return TXRX_CONTINUE; + return RX_CONTINUE; /* * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. */ if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (rx->sta) stakey = rcu_dereference(rx->sta->key); @@ -539,12 +506,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) */ if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) - return TXRX_CONTINUE; + return RX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); if (rx->skb->len < 8 + hdrlen) - return TXRX_DROP; /* TODO: count this? */ + return RX_DROP_UNUSABLE; /* TODO: count this? */ /* * no need to call ieee80211_wep_get_keyidx, @@ -573,7 +540,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: RX protected frame," " but have no key\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP_MONITOR; } /* Check for weak IVs if possible */ @@ -612,7 +579,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) if (sdata->bss) atomic_inc(&sdata->bss->num_sta_ps); sta->flags |= WLAN_STA_PS; - sta->pspoll = 0; + sta->flags &= ~WLAN_STA_PSPOLL; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", dev->name, print_mac(mac, sta->addr), sta->aid); @@ -629,20 +596,20 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) DECLARE_MAC_BUF(mac); sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM); - sta->pspoll = 0; - if (!skb_queue_empty(&sta->ps_tx_buf)) { - if (local->ops->set_tim) - local->ops->set_tim(local_to_hw(local), sta->aid, 0); - if (sdata->bss) - bss_tim_clear(local, sdata->bss, sta->aid); - } + + sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); + + if (!skb_queue_empty(&sta->ps_tx_buf)) + sta_info_clear_tim_bit(sta); + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; @@ -666,7 +633,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) return sent; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) { struct sta_info *sta = rx->sta; @@ -674,7 +641,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; if (!sta) - return TXRX_CONTINUE; + return RX_CONTINUE; /* Update last_rx only for IBSS packets which are for the current * BSSID to avoid keeping the current IBSS network alive in cases where @@ -695,7 +662,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) } if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + return RX_CONTINUE; sta->rx_fragments++; sta->rx_bytes += rx->skb->len; @@ -722,10 +689,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) * as a dropped packed. */ sta->rx_packets++; dev_kfree_skb(rx->skb); - return TXRX_QUEUED; + return RX_QUEUED; } - return TXRX_CONTINUE; + return RX_CONTINUE; } /* ieee80211_rx_h_sta_process */ static inline struct ieee80211_fragment_entry * @@ -801,7 +768,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0) continue; - if (entry->first_frag_time + 2 * HZ < jiffies) { + if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) { __skb_queue_purge(&entry->skb_list); continue; } @@ -811,7 +778,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, return NULL; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; @@ -848,7 +815,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN); } - return TXRX_QUEUED; + return RX_QUEUED; } /* This is a fragment for a frame that should already be pending in @@ -858,7 +825,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->u.rx.queue, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return TXRX_DROP; + return RX_DROP_MONITOR; } /* Verify that MPDUs within one MSDU have sequential PN values. @@ -867,7 +834,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) int i; u8 pn[CCMP_PN_LEN], *rpn; if (!rx->key || rx->key->conf.alg != ALG_CCMP) - return TXRX_DROP; + return RX_DROP_UNUSABLE; memcpy(pn, entry->last_pn, CCMP_PN_LEN); for (i = CCMP_PN_LEN - 1; i >= 0; i--) { pn[i]++; @@ -885,7 +852,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } memcpy(entry->last_pn, pn, CCMP_PN_LEN); } @@ -896,7 +863,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) entry->extra_len += rx->skb->len; if (rx->fc & IEEE80211_FCTL_MOREFRAGS) { rx->skb = NULL; - return TXRX_QUEUED; + return RX_QUEUED; } rx->skb = __skb_dequeue(&entry->skb_list); @@ -906,7 +873,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) GFP_ATOMIC))) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); __skb_queue_purge(&entry->skb_list); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } } while ((skb = __skb_dequeue(&entry->skb_list))) { @@ -924,10 +891,10 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->local->dot11MulticastReceivedFrameCount++; else ieee80211_led_rx(rx->local); - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); @@ -939,11 +906,11 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) - return TXRX_CONTINUE; + return RX_CONTINUE; if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && (sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; skb = skb_dequeue(&rx->sta->tx_filtered); if (!skb) { @@ -958,9 +925,11 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - /* tell TX path to send one frame even though the STA may - * still remain is PS mode after this frame exchange */ - rx->sta->pspoll = 1; + /* + * Tell TX path to send one frame even though the STA may + * still remain is PS mode after this frame exchange. + */ + rx->sta->flags |= WLAN_STA_PSPOLL; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", @@ -970,38 +939,37 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) /* Use MoreData flag to indicate whether there are more * buffered frames for this STA */ - if (no_pending_pkts) { + if (no_pending_pkts) hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); - rx->sta->flags &= ~WLAN_STA_TIM; - } else + else hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); dev_queue_xmit(skb); - if (no_pending_pkts) { - if (rx->local->ops->set_tim) - rx->local->ops->set_tim(local_to_hw(rx->local), - rx->sta->aid, 0); - if (rx->sdata->bss) - bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); - } + if (no_pending_pkts) + sta_info_clear_tim_bit(rx->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG } else if (!rx->u.rx.sent_ps_buffered) { + /* + * FIXME: This can be the result of a race condition between + * us expiring a frame and the station polling for it. + * Should we send it a null-func frame indicating we + * have nothing buffered for it? + */ printk(KERN_DEBUG "%s: STA %s sent PS Poll even " "though there is no buffered frames for it\n", rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - } - /* Free PS Poll skb here instead of returning TXRX_DROP that would + /* Free PS Poll skb here instead of returning RX_DROP that would * count as an dropped frame. */ dev_kfree_skb(rx->skb); - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) { u16 fc = rx->fc; @@ -1009,7 +977,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; if (!WLAN_FC_IS_QOS_DATA(fc)) - return TXRX_CONTINUE; + return RX_CONTINUE; /* remove the qos control field, update frame type and meta-data */ memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); @@ -1018,17 +986,17 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; hdr->frame_control = cpu_to_le16(fc); - return TXRX_CONTINUE; + return RX_CONTINUE; } static int ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) { - if (unlikely(rx->sdata->ieee802_1x_pac && - (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)))) { + if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_DEBUG - printk(KERN_DEBUG "%s: dropped frame " - "(unauthorized port)\n", rx->dev->name); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped frame " + "(unauthorized port)\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ return -EACCES; } @@ -1275,7 +1243,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) } } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) { struct net_device *dev = rx->dev; @@ -1291,17 +1259,17 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) fc = rx->fc; if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; + return RX_DROP_MONITOR; if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) - return TXRX_CONTINUE; + return RX_CONTINUE; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; skb->dev = dev; @@ -1311,7 +1279,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) /* skip the wrapping header */ eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); if (!eth) - return TXRX_DROP; + return RX_DROP_UNUSABLE; while (skb != frame) { u8 padding; @@ -1326,7 +1294,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) /* the last MSDU has no padding */ if (subframe_len > remaining) { printk(KERN_DEBUG "%s: wrong buffer size", dev->name); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } skb_pull(skb, sizeof(struct ethhdr)); @@ -1338,7 +1306,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) subframe_len); if (frame == NULL) - return TXRX_DROP; + return RX_DROP_UNUSABLE; skb_reserve(frame, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); @@ -1351,7 +1319,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: wrong buffer size ", dev->name); dev_kfree_skb(frame); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } } @@ -1381,7 +1349,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) if (!ieee80211_frame_allowed(rx)) { if (skb == frame) /* last frame */ - return TXRX_DROP; + return RX_DROP_UNUSABLE; dev_kfree_skb(frame); continue; } @@ -1389,10 +1357,10 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) ieee80211_deliver_skb(rx); } - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) { struct net_device *dev = rx->dev; @@ -1401,17 +1369,17 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) fc = rx->fc; if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; + return RX_DROP_MONITOR; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; if (!ieee80211_frame_allowed(rx)) - return TXRX_DROP; + return RX_DROP_MONITOR; rx->skb->dev = dev; @@ -1420,10 +1388,10 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) ieee80211_deliver_skb(rx); - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) { struct ieee80211_local *local = rx->local; @@ -1435,15 +1403,15 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) u16 tid; if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL)) - return TXRX_CONTINUE; + return RX_CONTINUE; if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) { if (!rx->sta) - return TXRX_CONTINUE; + return RX_CONTINUE; tid = le16_to_cpu(bar->control) >> 12; tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]); if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL) - return TXRX_CONTINUE; + return RX_CONTINUE; start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; @@ -1460,19 +1428,19 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, start_seq_num, 1); rcu_read_unlock(); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) { struct ieee80211_sub_if_data *sdata; if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_DROP; + return RX_DROP_MONITOR; sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || @@ -1480,56 +1448,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); else - return TXRX_DROP; + return RX_DROP_MONITOR; - return TXRX_QUEUED; -} - -static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( - struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - ieee80211_rx_handler *handler; - ieee80211_txrx_result res = TXRX_DROP; - - for (handler = handlers; *handler != NULL; handler++) { - res = (*handler)(rx); - - switch (res) { - case TXRX_CONTINUE: - continue; - case TXRX_DROP: - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; - break; - case TXRX_QUEUED: - I802_DEBUG_INC(local->rx_handlers_queued); - break; - } - break; - } - - if (res == TXRX_DROP) - dev_kfree_skb(rx->skb); - return res; -} - -static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == - TXRX_CONTINUE) - dev_kfree_skb(rx->skb); + return RX_QUEUED; } static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta, struct ieee80211_txrx_data *rx) { int keyidx, hdrlen; @@ -1548,7 +1473,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, dev->name, print_mac(mac, hdr->addr2), print_mac(mac2, hdr->addr1), keyidx); - if (!sta) { + if (!rx->sta) { /* * Some hardware seem to generate incorrect Michael MIC * reports; ignore them to avoid triggering countermeasures. @@ -1600,7 +1525,88 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, rx->skb = NULL; } -ieee80211_rx_handler ieee80211_rx_handlers[] = +static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local = rx->local; + struct ieee80211_rtap_hdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + __le16 chan_freq; + __le16 chan_flags; + } __attribute__ ((packed)) *rthdr; + struct sk_buff *skb = rx->skb, *skb2; + struct net_device *prev_dev = NULL; + struct ieee80211_rx_status *status = rx->u.rx.status; + + if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED) + goto out_free_skb; + + if (skb_headroom(skb) < sizeof(*rthdr) && + pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) + goto out_free_skb; + + rthdr = (void *)skb_push(skb, sizeof(*rthdr)); + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL)); + + rthdr->rate = rx->u.rx.rate->bitrate / 5; + rthdr->chan_freq = cpu_to_le16(status->freq); + + if (status->band == IEEE80211_BAND_5GHZ) + rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else + rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN | + IEEE80211_CHAN_2GHZ); + + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || + !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) + continue; + + if (prev_dev) { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; + sdata->dev->stats.rx_packets++; + sdata->dev->stats.rx_bytes += skb->len; + } + + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } else + goto out_free_skb; + + rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED; + return; + + out_free_skb: + dev_kfree_skb(skb); +} + +typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); +static ieee80211_rx_handler ieee80211_rx_handlers[] = { ieee80211_rx_h_if_stats, ieee80211_rx_h_passive_scan, @@ -1622,6 +1628,47 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = NULL }; +static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, + struct ieee80211_txrx_data *rx, + struct sk_buff *skb) +{ + ieee80211_rx_handler *handler; + ieee80211_rx_result res = RX_DROP_MONITOR; + + rx->skb = skb; + rx->sdata = sdata; + rx->dev = sdata->dev; + + for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) { + res = (*handler)(rx); + + switch (res) { + case RX_CONTINUE: + continue; + case RX_DROP_UNUSABLE: + case RX_DROP_MONITOR: + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; + break; + case RX_QUEUED: + I802_DEBUG_INC(sdata->local->rx_handlers_queued); + break; + } + break; + } + + switch (res) { + case RX_CONTINUE: + case RX_DROP_MONITOR: + ieee80211_rx_cooked_monitor(rx); + break; + case RX_DROP_UNUSABLE: + dev_kfree_skb(rx->skb); + break; + } +} + /* main receive path */ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, @@ -1649,7 +1696,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case IEEE80211_IF_TYPE_IBSS: if (!bssid) return 0; - if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + return 1; + else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; @@ -1707,11 +1757,11 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status *status, - u32 load) + u32 load, + struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; struct ieee80211_hdr *hdr; struct ieee80211_txrx_data rx; u16 type; @@ -1727,40 +1777,31 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.u.rx.status = status; rx.u.rx.load = load; + rx.u.rx.rate = rate; rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) local->dot11ReceivedFragmentCount++; - sta = rx.sta = sta_info_get(local, hdr->addr2); - if (sta) { + rx.sta = sta_info_get(local, hdr->addr2); + if (rx.sta) { rx.dev = rx.sta->dev; rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); } if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); + ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); goto end; } if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; - if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, - sta) != TXRX_CONTINUE) - goto end; - skb = rx.skb; + ieee80211_parse_qos(&rx); + ieee80211_verify_ip_alignment(&rx); - if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && - !atomic_read(&local->iff_promiscs) && - !is_multicast_ether_addr(hdr->addr1)) { - rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, - rx.sta); - sta_info_put(sta); - return; - } + skb = rx.skb; list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!netif_running(sdata->dev)) @@ -1772,8 +1813,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); - /* prepare_for_handlers can change sta */ - sta = rx.sta; if (!prepares) continue; @@ -1804,26 +1843,18 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; } rx.fc = le16_to_cpu(hdr->frame_control); - rx.skb = skb_new; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); + ieee80211_invoke_rx_handlers(prev, &rx, skb_new); prev = sdata; } if (prev) { rx.fc = le16_to_cpu(hdr->frame_control); - rx.skb = skb; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); + ieee80211_invoke_rx_handlers(prev, &rx, skb); } else dev_kfree_skb(skb); end: - if (sta) - sta_info_put(sta); + if (rx.sta) + sta_info_put(rx.sta); } #define SEQ_MODULO 0x1000 @@ -1859,6 +1890,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, u16 head_seq_num, buf_size; int index; u32 pkt_load; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; buf_size = tid_agg_rx->buf_size; head_seq_num = tid_agg_rx->head_seq_num; @@ -1889,12 +1922,14 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); + sband = local->hw.wiphy->bands[status.band]; + rate = &sband->bitrates[status.rate_idx]; pkt_load = ieee80211_rx_load_stats(local, tid_agg_rx->reorder_buf[index], - &status); + &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load); + &status, pkt_load, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; } @@ -1934,11 +1969,13 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* release the reordered frame back to stack */ memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); + sband = local->hw.wiphy->bands[status.band]; + rate = &sband->bitrates[status.rate_idx]; pkt_load = ieee80211_rx_load_stats(local, tid_agg_rx->reorder_buf[index], - &status); + &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load); + &status, pkt_load, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); @@ -2019,6 +2056,25 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, { struct ieee80211_local *local = hw_to_local(hw); u32 pkt_load; + struct ieee80211_rate *rate = NULL; + struct ieee80211_supported_band *sband; + + if (status->band < 0 || + status->band > IEEE80211_NUM_BANDS) { + WARN_ON(1); + return; + } + + sband = local->hw.wiphy->bands[status->band]; + + if (!sband || + status->rate_idx < 0 || + status->rate_idx >= sband->n_bitrates) { + WARN_ON(1); + return; + } + + rate = &sband->bitrates[status->rate_idx]; /* * key references and virtual interfaces are protected using RCU @@ -2033,17 +2089,17 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * if it was previously present. * Also, frames with less than 16 bytes are dropped. */ - skb = ieee80211_rx_monitor(local, skb, status); + skb = ieee80211_rx_monitor(local, skb, status, rate); if (!skb) { rcu_read_unlock(); return; } - pkt_load = ieee80211_rx_load_stats(local, skb, status); + pkt_load = ieee80211_rx_load_stats(local, skb, status, rate); local->channel_use_raw += pkt_load; if (!ieee80211_rx_reorder_ampdu(local, skb)) - __ieee80211_rx_handle_packet(hw, skb, status, pkt_load); + __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate); rcu_read_unlock(); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1f74bd29635..e384e6632d9 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -55,48 +55,34 @@ static int sta_info_hash_del(struct ieee80211_local *local, return -ENOENT; } -struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) +/* must hold local->sta_lock */ +static struct sta_info *__sta_info_find(struct ieee80211_local *local, + u8 *addr) { struct sta_info *sta; - read_lock_bh(&local->sta_lock); sta = local->sta_hash[STA_HASH(addr)]; while (sta) { - if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { - __sta_info_get(sta); + if (compare_ether_addr(sta->addr, addr) == 0) break; - } sta = sta->hnext; } - read_unlock_bh(&local->sta_lock); - return sta; } -EXPORT_SYMBOL(sta_info_get); -int sta_info_min_txrate_get(struct ieee80211_local *local) +struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) { struct sta_info *sta; - struct ieee80211_hw_mode *mode; - int min_txrate = 9999999; - int i; read_lock_bh(&local->sta_lock); - mode = local->oper_hw_mode; - for (i = 0; i < STA_HASH_SIZE; i++) { - sta = local->sta_hash[i]; - while (sta) { - if (sta->txrate < min_txrate) - min_txrate = sta->txrate; - sta = sta->hnext; - } - } + sta = __sta_info_find(local, addr); + if (sta) + __sta_info_get(sta); read_unlock_bh(&local->sta_lock); - if (min_txrate == 9999999) - min_txrate = 0; - return mode->rates[min_txrate].rate; + return sta; } +EXPORT_SYMBOL(sta_info_get); static void sta_info_release(struct kref *kref) @@ -117,8 +103,10 @@ static void sta_info_release(struct kref *kref) while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { dev_kfree_skb_any(skb); } - for (i = 0; i < STA_TID_NUM; i++) + for (i = 0; i < STA_TID_NUM; i++) { del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); + del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); + } rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); kfree(sta); @@ -132,8 +120,8 @@ void sta_info_put(struct sta_info *sta) EXPORT_SYMBOL(sta_info_put); -struct sta_info * sta_info_add(struct ieee80211_local *local, - struct net_device *dev, u8 *addr, gfp_t gfp) +struct sta_info *sta_info_add(struct ieee80211_local *local, + struct net_device *dev, u8 *addr, gfp_t gfp) { struct sta_info *sta; int i; @@ -141,7 +129,7 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, sta = kzalloc(sizeof(*sta), gfp); if (!sta) - return NULL; + return ERR_PTR(-ENOMEM); kref_init(&sta->kref); @@ -150,30 +138,45 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, if (!sta->rate_ctrl_priv) { rate_control_put(sta->rate_ctrl); kfree(sta); - return NULL; + return ERR_PTR(-ENOMEM); } memcpy(sta->addr, addr, ETH_ALEN); sta->local = local; sta->dev = dev; spin_lock_init(&sta->ampdu_mlme.ampdu_rx); + spin_lock_init(&sta->ampdu_mlme.ampdu_tx); for (i = 0; i < STA_TID_NUM; i++) { /* timer_to_tid must be initialized with identity mapping to * enable session_timer's data differentiation. refer to * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; + /* tid to tx queue: initialize according to HW (0 is valid) */ + sta->tid_to_tx_q[i] = local->hw.queues; /* rx timers */ sta->ampdu_mlme.tid_rx[i].session_timer.function = sta_rx_agg_session_timer_expired; sta->ampdu_mlme.tid_rx[i].session_timer.data = (unsigned long)&sta->timer_to_tid[i]; init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer); + /* tx timers */ + sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function = + sta_addba_resp_timer_expired; + sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data = + (unsigned long)&sta->timer_to_tid[i]; + init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); } skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); - __sta_info_get(sta); /* sta used by caller, decremented by - * sta_info_put() */ write_lock_bh(&local->sta_lock); + /* mark sta as used (by caller) */ + __sta_info_get(sta); + /* check if STA exists already */ + if (__sta_info_find(local, addr)) { + write_unlock_bh(&local->sta_lock); + sta_info_put(sta); + return ERR_PTR(-EEXIST); + } list_add(&sta->list, &local->sta_list); local->num_sta++; sta_info_hash_add(local, sta); @@ -204,6 +207,64 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, return sta; } +static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) +{ + /* + * This format has been mandated by the IEEE specifications, + * so this line may not be changed to use the __set_bit() format. + */ + bss->tim[aid / 8] |= (1 << (aid % 8)); +} + +static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) +{ + /* + * This format has been mandated by the IEEE specifications, + * so this line may not be changed to use the __clear_bit() format. + */ + bss->tim[aid / 8] &= ~(1 << (aid % 8)); +} + +static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, + struct sta_info *sta) +{ + if (bss) + __bss_tim_set(bss, sta->aid); + if (sta->local->ops->set_tim) + sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); +} + +void sta_info_set_tim_bit(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + read_lock_bh(&sta->local->sta_lock); + __sta_info_set_tim_bit(sdata->bss, sta); + read_unlock_bh(&sta->local->sta_lock); +} + +static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, + struct sta_info *sta) +{ + if (bss) + __bss_tim_clear(bss, sta->aid); + if (sta->local->ops->set_tim) + sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); +} + +void sta_info_clear_tim_bit(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + read_lock_bh(&sta->local->sta_lock); + __sta_info_clear_tim_bit(sdata->bss, sta); + read_unlock_bh(&sta->local->sta_lock); +} + /* Caller must hold local->sta_lock */ void sta_info_remove(struct sta_info *sta) { @@ -220,10 +281,9 @@ void sta_info_remove(struct sta_info *sta) sta->flags &= ~WLAN_STA_PS; if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); + __sta_info_clear_tim_bit(sdata->bss, sta); } local->num_sta--; - sta_info_remove_aid_ptr(sta); - } void sta_info_free(struct sta_info *sta) @@ -252,7 +312,7 @@ void sta_info_free(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ ieee80211_key_free(sta->key); - sta->key = NULL; + WARN_ON(sta->key); if (local->ops->sta_notify) { struct ieee80211_sub_if_data *sdata; @@ -299,6 +359,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; + struct ieee80211_sub_if_data *sdata; DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->ps_tx_buf)) @@ -307,21 +368,23 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, for (;;) { spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); skb = skb_peek(&sta->ps_tx_buf); - if (sta_info_buffer_expired(local, sta, skb)) { + if (sta_info_buffer_expired(local, sta, skb)) skb = __skb_dequeue(&sta->ps_tx_buf); - if (skb_queue_empty(&sta->ps_tx_buf)) - sta->flags &= ~WLAN_STA_TIM; - } else + else skb = NULL; spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags); - if (skb) { - local->total_ps_buffered--; - printk(KERN_DEBUG "Buffered frame expired (STA " - "%s)\n", print_mac(mac, sta->addr)); - dev_kfree_skb(skb); - } else + if (!skb) break; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + local->total_ps_buffered--; + printk(KERN_DEBUG "Buffered frame expired (STA " + "%s)\n", print_mac(mac, sta->addr)); + dev_kfree_skb(skb); + + if (skb_queue_empty(&sta->ps_tx_buf)) + sta_info_clear_tim_bit(sta); } } @@ -400,23 +463,6 @@ void sta_info_stop(struct ieee80211_local *local) sta_info_flush(local, NULL); } -void sta_info_remove_aid_ptr(struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata; - - if (sta->aid <= 0) - return; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - - if (sdata->local->ops->set_tim) - sdata->local->ops->set_tim(local_to_hw(sdata->local), - sta->aid, 0); - if (sdata->bss) - __bss_tim_clear(sdata->bss, sta->aid); -} - - /** * sta_info_flush - flush matching STA entries from the STA table * @local: local interface data diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 96fe3ed9503..86eed40ada7 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -15,31 +15,72 @@ #include <linux/kref.h> #include "ieee80211_key.h" -/* Stations flags (struct sta_info::flags) */ -#define WLAN_STA_AUTH BIT(0) -#define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ -#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ -#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is - * controlling whether STA is authorized to - * send and receive non-IEEE 802.1X frames - */ -#define WLAN_STA_SHORT_PREAMBLE BIT(7) -/* whether this is an AP that we are associated with as a client */ -#define WLAN_STA_ASSOC_AP BIT(8) -#define WLAN_STA_WME BIT(9) -#define WLAN_STA_WDS BIT(27) +/** + * enum ieee80211_sta_info_flags - Stations flags + * + * These flags are used with &struct sta_info's @flags member. + * + * @WLAN_STA_AUTH: Station is authenticated. + * @WLAN_STA_ASSOC: Station is associated. + * @WLAN_STA_PS: Station is in power-save mode + * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic. + * This bit is always checked so needs to be enabled for all stations + * when virtual port control is not in use. + * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble + * frames. + * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. + * @WLAN_STA_WME: Station is a QoS-STA. + * @WLAN_STA_WDS: Station is one of our WDS peers. + * @WLAN_STA_PSPOLL: Station has just PS-polled us. + * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the + * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next + * frame to this station is transmitted. + */ +enum ieee80211_sta_info_flags { + WLAN_STA_AUTH = 1<<0, + WLAN_STA_ASSOC = 1<<1, + WLAN_STA_PS = 1<<2, + WLAN_STA_AUTHORIZED = 1<<3, + WLAN_STA_SHORT_PREAMBLE = 1<<4, + WLAN_STA_ASSOC_AP = 1<<5, + WLAN_STA_WME = 1<<6, + WLAN_STA_WDS = 1<<7, + WLAN_STA_PSPOLL = 1<<8, + WLAN_STA_CLEAR_PS_FILT = 1<<9, +}; #define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ +#define HT_AGG_MAX_RETRIES (0x3) #define HT_AGG_STATE_INITIATOR_SHIFT (4) +#define HT_ADDBA_REQUESTED_MSK BIT(0) +#define HT_ADDBA_DRV_READY_MSK BIT(1) +#define HT_ADDBA_RECEIVED_MSK BIT(2) #define HT_AGG_STATE_REQ_STOP_BA_MSK BIT(3) - +#define HT_AGG_STATE_INITIATOR_MSK BIT(HT_AGG_STATE_INITIATOR_SHIFT) #define HT_AGG_STATE_IDLE (0x0) -#define HT_AGG_STATE_OPERATIONAL (0x7) +#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \ + HT_ADDBA_DRV_READY_MSK | \ + HT_ADDBA_RECEIVED_MSK) + +/** + * struct tid_ampdu_tx - TID aggregation information (Tx). + * + * @state: TID's state in session state machine. + * @dialog_token: dialog token for aggregation session + * @ssn: Starting Sequence Number expected to be aggregated. + * @addba_resp_timer: timer for peer's response to addba request + * @addba_req_num: number of times addBA request has been sent. + */ +struct tid_ampdu_tx { + u8 state; + u8 dialog_token; + u16 ssn; + struct timer_list addba_resp_timer; + u8 addba_req_num; +}; /** * struct tid_ampdu_rx - TID aggregation information (Rx). @@ -69,12 +110,18 @@ struct tid_ampdu_rx { /** * struct sta_ampdu_mlme - STA aggregation information. * - * @tid_agg_info_rx: aggregation info for Rx per TID + * @tid_rx: aggregation info for Rx per TID + * @tid_tx: aggregation info for Tx per TID * @ampdu_rx: for locking sections in aggregation Rx flow + * @ampdu_tx: for locking sectionsi in aggregation Tx flow + * @dialog_token_allocator: dialog token enumerator for each new session; */ struct sta_ampdu_mlme { struct tid_ampdu_rx tid_rx[STA_TID_NUM]; + struct tid_ampdu_tx tid_tx[STA_TID_NUM]; spinlock_t ampdu_rx; + spinlock_t ampdu_tx; + u8 dialog_token_allocator; }; struct sta_info { @@ -90,12 +137,9 @@ struct sta_info { struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in * power saving state */ - int pspoll; /* whether STA has send a PS Poll frame */ struct sk_buff_head tx_filtered; /* buffer of TX frames that were * already given to low-level driver, * but were filtered */ - int clear_dst_mask; - unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */ unsigned long rx_bytes, tx_bytes; unsigned long tx_retry_failed, tx_retry_count; @@ -104,10 +148,11 @@ struct sta_info { unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ unsigned long last_rx; - u32 supp_rates; /* bitmap of supported rates in local->curr_rates */ - int txrate; /* index in local->curr_rates */ - int last_txrate; /* last rate used to send a frame to this STA */ - int last_nonerp_idx; + /* bitmap of supported rates per band */ + u64 supp_rates[IEEE80211_NUM_BANDS]; + int txrate_idx; + /* last rates used to send a frame to this STA */ + int last_txrate_idx, last_nonerp_txrate_idx; struct net_device *dev; /* which net device is this station associated * to */ @@ -132,8 +177,6 @@ struct sta_info { int last_rssi; /* RSSI of last received frame from this STA */ int last_signal; /* signal of last received frame from this STA */ int last_noise; /* noise of last received frame from this STA */ - int last_ack_rssi[3]; /* RSSI of last received ACKs from this STA */ - unsigned long last_ack; int channel_use; int channel_use_raw; @@ -148,20 +191,20 @@ struct sta_info { of this STA */ struct sta_ampdu_mlme ampdu_mlme; u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ + u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ #ifdef CONFIG_MAC80211_DEBUGFS struct sta_info_debugfsdentries { struct dentry *dir; struct dentry *flags; struct dentry *num_ps_buf_frames; - struct dentry *last_ack_rssi; - struct dentry *last_ack_ms; struct dentry *inactive_ms; struct dentry *last_seq_ctrl; #ifdef CONFIG_MAC80211_DEBUG_COUNTERS struct dentry *wme_rx_queue; struct dentry *wme_tx_queue; #endif + struct dentry *agg_status; } debugfs; #endif }; @@ -191,16 +234,17 @@ static inline void __sta_info_get(struct sta_info *sta) } struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); -int sta_info_min_txrate_get(struct ieee80211_local *local); void sta_info_put(struct sta_info *sta); -struct sta_info * sta_info_add(struct ieee80211_local *local, - struct net_device *dev, u8 *addr, gfp_t gfp); +struct sta_info *sta_info_add(struct ieee80211_local *local, + struct net_device *dev, u8 *addr, gfp_t gfp); void sta_info_remove(struct sta_info *sta); void sta_info_free(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); -void sta_info_remove_aid_ptr(struct sta_info *sta); void sta_info_flush(struct ieee80211_local *local, struct net_device *dev); +void sta_info_set_tim_bit(struct sta_info *sta); +void sta_info_clear_tim_bit(struct sta_info *sta); + #endif /* STA_INFO_H */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 67b509edd43..1cd58e01f1e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -92,9 +92,13 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, int rate, mrate, erp, dur, i; struct ieee80211_rate *txrate = tx->u.tx.rate; struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; + struct ieee80211_supported_band *sband; - erp = txrate->flags & IEEE80211_RATE_ERP; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + erp = 0; + if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = txrate->flags & IEEE80211_RATE_ERP_G; /* * data and mgmt (except PS Poll): @@ -150,20 +154,36 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps */ rate = -1; - mrate = 10; /* use 1 Mbps if everything fails */ - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; - if (r->rate > txrate->rate) - break; + /* use lowest available if everything fails */ + mrate = sband->bitrates[0].bitrate; + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *r = &sband->bitrates[i]; - if (IEEE80211_RATE_MODULATION(txrate->flags) != - IEEE80211_RATE_MODULATION(r->flags)) - continue; + if (r->bitrate > txrate->bitrate) + break; - if (r->flags & IEEE80211_RATE_BASIC) - rate = r->rate; - else if (r->flags & IEEE80211_RATE_MANDATORY) - mrate = r->rate; + if (tx->sdata->basic_rates & BIT(i)) + rate = r->bitrate; + + switch (sband->band) { + case IEEE80211_BAND_2GHZ: { + u32 flag; + if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + flag = IEEE80211_RATE_MANDATORY_G; + else + flag = IEEE80211_RATE_MANDATORY_B; + if (r->flags & flag) + mrate = r->bitrate; + break; + } + case IEEE80211_BAND_5GHZ: + if (r->flags & IEEE80211_RATE_MANDATORY_A) + mrate = r->bitrate; + break; + case IEEE80211_NUM_BANDS: + WARN_ON(1); + break; + } } if (rate == -1) { /* No matching basic rate found; use highest suitable mandatory @@ -184,7 +204,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, dur *= 2; /* ACK + SIFS */ /* next fragment */ dur += ieee80211_frame_duration(local, next_frag_len, - txrate->rate, erp, + txrate->bitrate, erp, tx->sdata->bss_conf.use_short_preamble); } @@ -212,7 +232,7 @@ static int inline is_ieee80211_device(struct net_device *dev, /* tx handlers */ -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -222,15 +242,15 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) u32 sta_flags; if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) - return TXRX_DROP; + return TX_DROP; if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) - return TXRX_CONTINUE; + return TX_CONTINUE; sta_flags = tx->sta ? tx->sta->flags : 0; @@ -245,7 +265,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) tx->dev->name, print_mac(mac, hdr->addr1)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); - return TXRX_DROP; + return TX_DROP; } } else { if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && @@ -255,15 +275,15 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) * No associated STAs - no need to send multicast * frames. */ - return TXRX_DROP; + return TX_DROP; } - return TXRX_CONTINUE; + return TX_CONTINUE; } - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -271,7 +291,7 @@ ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) ieee80211_include_sequence(tx->sdata, hdr); - return TXRX_CONTINUE; + return TX_CONTINUE; } /* This function is called whenever the AP is about to exceed the maximum limit @@ -321,7 +341,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) wiphy_name(local->hw.wiphy), purged); } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) { /* @@ -334,11 +354,11 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) /* not AP/IBSS or ordered frame */ if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER)) - return TXRX_CONTINUE; + return TX_CONTINUE; /* no stations in PS mode */ if (!atomic_read(&tx->sdata->bss->num_sta_ps)) - return TXRX_CONTINUE; + return TX_CONTINUE; /* buffered in mac80211 */ if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { @@ -355,16 +375,16 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) } else tx->local->total_ps_buffered++; skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TXRX_QUEUED; + return TX_QUEUED; } /* buffered in hardware */ tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) { struct sta_info *sta = tx->sta; @@ -373,9 +393,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) if (unlikely(!sta || ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) - return TXRX_CONTINUE; + return TX_CONTINUE; - if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { + if (unlikely((sta->flags & WLAN_STA_PS) && + !(sta->flags & WLAN_STA_PSPOLL))) { struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " @@ -383,7 +404,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) print_mac(mac, sta->addr), sta->aid, skb_queue_len(&sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->flags |= WLAN_STA_TIM; if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { @@ -396,18 +416,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) dev_kfree_skb(old); } else tx->local->total_ps_buffered++; + /* Queue frame to be sent after STA sends an PS Poll frame */ - if (skb_queue_empty(&sta->ps_tx_buf)) { - if (tx->local->ops->set_tim) - tx->local->ops->set_tim(local_to_hw(tx->local), - sta->aid, 1); - if (tx->sdata->bss) - bss_tim_set(tx->local, tx->sdata->bss, sta->aid); - } + if (skb_queue_empty(&sta->ps_tx_buf)) + sta_info_set_tim_bit(sta); + pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; pkt_data->jiffies = jiffies; skb_queue_tail(&sta->ps_tx_buf, tx->skb); - return TXRX_QUEUED; + return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(sta->flags & WLAN_STA_PS)) { @@ -416,16 +433,16 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->pspoll = 0; + sta->flags &= ~WLAN_STA_PSPOLL; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) { if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (tx->flags & IEEE80211_TXRXD_TXUNICAST) return ieee80211_tx_h_unicast_ps_buf(tx); @@ -433,7 +450,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) return ieee80211_tx_h_multicast_ps_buf(tx); } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) { struct ieee80211_key *key; @@ -449,7 +466,7 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); - return TXRX_DROP; + return TX_DROP; } else tx->key = NULL; @@ -478,10 +495,10 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; @@ -493,7 +510,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) int frag_threshold = tx->local->fragmentation_threshold; if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) - return TXRX_CONTINUE; + return TX_CONTINUE; first = tx->skb; @@ -547,7 +564,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) tx->u.tx.num_extra_frag = num_fragm - 1; tx->u.tx.extra_frag = frags; - return TXRX_CONTINUE; + return TX_CONTINUE; fail: printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); @@ -558,14 +575,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) kfree(frags); } I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TXRX_DROP; + return TX_DROP; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) { if (!tx->key) - return TXRX_CONTINUE; + return TX_CONTINUE; switch (tx->key->conf.alg) { case ALG_WEP: @@ -578,33 +595,35 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) /* not reached */ WARN_ON(1); - return TXRX_DROP; + return TX_DROP; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) { struct rate_selection rsel; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; if (likely(!tx->u.tx.rate)) { - rate_control_get_rate(tx->dev, tx->u.tx.mode, tx->skb, &rsel); + rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); tx->u.tx.rate = rsel.rate; - if (unlikely(rsel.probe != NULL)) { + if (unlikely(rsel.probe)) { tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; - tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; + tx->u.tx.control->alt_retry_rate = tx->u.tx.rate; tx->u.tx.rate = rsel.probe; } else - tx->u.tx.control->alt_retry_rate = -1; + tx->u.tx.control->alt_retry_rate = NULL; if (!tx->u.tx.rate) - return TXRX_DROP; + return TX_DROP; } else - tx->u.tx.control->alt_retry_rate = -1; + tx->u.tx.control->alt_retry_rate = NULL; - if (tx->u.tx.mode->mode == MODE_IEEE80211G && - tx->sdata->bss_conf.use_cts_prot && + if (tx->sdata->bss_conf.use_cts_prot && (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) { tx->u.tx.last_frag_rate = tx->u.tx.rate; if (rsel.probe) @@ -612,25 +631,24 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) else tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; tx->u.tx.rate = rsel.nonerp; - tx->u.tx.control->rate = rsel.nonerp; + tx->u.tx.control->tx_rate = rsel.nonerp; tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.control->rate = tx->u.tx.rate; + tx->u.tx.control->tx_rate = tx->u.tx.rate; } - tx->u.tx.control->tx_rate = tx->u.tx.rate->val; + tx->u.tx.control->tx_rate = tx->u.tx.rate; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->u.tx.control; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -657,14 +675,14 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate = -1; + control->alt_retry_rate = NULL; } /* Use CTS protection for unicast frames sent using extended rates if * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ - if (mode->mode == MODE_IEEE80211G && - (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && + if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && + (tx->u.tx.rate->flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TXRXD_TXUNICAST) && tx->sdata->bss_conf.use_cts_prot && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) @@ -674,10 +692,10 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && + (tx->u.tx.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; + tx->u.tx.control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; } /* Setup duration field for the first fragment of the frame. Duration @@ -690,19 +708,33 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { - struct ieee80211_rate *rate; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate, *baserate; + int idx; + + sband = tx->local->hw.wiphy->bands[ + tx->local->hw.conf.channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = -1; + control->alt_retry_rate = NULL; /* Use min(data rate, max base rate) as CTS/RTS rate */ rate = tx->u.tx.rate; - while (rate > mode->rates && - !(rate->flags & IEEE80211_RATE_BASIC)) - rate--; + baserate = NULL; - control->rts_cts_rate = rate->val; - control->rts_rate = rate; + for (idx = 0; idx < sband->n_bitrates; idx++) { + if (sband->bitrates[idx].bitrate > rate->bitrate) + continue; + if (tx->sdata->basic_rates & BIT(idx) && + (!baserate || + (baserate->bitrate < sband->bitrates[idx].bitrate))) + baserate = &sband->bitrates[idx]; + } + + if (baserate) + control->rts_cts_rate = baserate; + else + control->rts_cts_rate = &sband->bitrates[0]; } if (tx->sta) { @@ -719,17 +751,17 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) { struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; + struct ieee80211_rate *rate = tx->u.tx.rate; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored @@ -740,9 +772,9 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - if (mode->mode == MODE_IEEE80211A || - (mode->mode == MODE_IEEE80211G && - tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) + if (tx->u.tx.channel->band == IEEE80211_BAND_5GHZ || + (tx->u.tx.channel->band == IEEE80211_BAND_2GHZ && + rate->flags & IEEE80211_RATE_ERP_G)) hdrtime = CHAN_UTIL_HDR_SHORT; else hdrtime = CHAN_UTIL_HDR_LONG; @@ -756,14 +788,15 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) load += hdrtime; - load += skb->len * tx->u.tx.rate->rate_inv; + /* TODO: optimise again */ + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { load += 2 * hdrtime; load += tx->u.tx.extra_frag[i]->len * - tx->u.tx.rate->rate; + tx->u.tx.rate->bitrate; } } @@ -774,13 +807,12 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) tx->sta->channel_use_raw += load; tx->sdata->channel_use_raw += load; - return TXRX_CONTINUE; + return TX_CONTINUE; } -/* TODO: implement register/unregister functions for adding TX/RX handlers - * into ordered list */ -ieee80211_tx_handler ieee80211_tx_handlers[] = +typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_txrx_data *); +static ieee80211_tx_handler ieee80211_tx_handlers[] = { ieee80211_tx_h_check_assoc, ieee80211_tx_h_sequence, @@ -801,7 +833,7 @@ ieee80211_tx_handler ieee80211_tx_handlers[] = * deal with packet injection down monitor interface * with Radiotap Header -- only called for monitor mode interface */ -static ieee80211_txrx_result +static ieee80211_tx_result __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, struct sk_buff *skb) { @@ -816,10 +848,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, struct ieee80211_radiotap_iterator iterator; struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; + struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); struct ieee80211_tx_control *control = tx->u.tx.control; + sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; tx->flags |= IEEE80211_TXRXD_TX_INJECTED; tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; @@ -852,10 +886,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps */ target_rate = (*iterator.this_arg) * 5; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *r; + + r = &sband->bitrates[i]; - if (r->rate == target_rate) { + if (r->bitrate == target_rate) { tx->u.tx.rate = r; break; } @@ -870,9 +906,11 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, control->antenna_sel_tx = (*iterator.this_arg) + 1; break; +#if 0 case IEEE80211_RADIOTAP_DBM_TX_POWER: control->power_level = *iterator.this_arg; break; +#endif case IEEE80211_RADIOTAP_FLAGS: if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { @@ -884,7 +922,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, * on transmission */ if (skb->len < (iterator.max_length + FCS_LEN)) - return TXRX_DROP; + return TX_DROP; skb_trim(skb, skb->len - FCS_LEN); } @@ -907,7 +945,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, } if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TXRX_DROP; + return TX_DROP; /* * remove the radiotap header @@ -916,13 +954,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, */ skb_pull(skb, iterator.max_length); - return TXRX_CONTINUE; + return TX_CONTINUE; } /* * initialises @tx */ -static ieee80211_txrx_result +static ieee80211_tx_result __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct sk_buff *skb, struct net_device *dev, @@ -949,8 +987,8 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) { - if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP) - return TXRX_DROP; + if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) + return TX_DROP; /* * __ieee80211_parse_tx_radiotap has now removed @@ -982,10 +1020,10 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } if (!tx->sta) - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - else if (tx->sta->clear_dst_mask) { - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - tx->sta->clear_dst_mask = 0; + control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) { + control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT; } hdrlen = ieee80211_get_hdrlen(tx->fc); @@ -995,7 +1033,7 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; - return TXRX_CONTINUE; + return TX_CONTINUE; } /* @@ -1046,7 +1084,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (tx->u.tx.extra_frag) { control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_DST_MASK | + IEEE80211_TXCTL_CLEAR_PS_FILT | IEEE80211_TXCTL_FIRST_FRAGMENT); for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (!tx->u.tx.extra_frag[i]) @@ -1054,8 +1092,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->u.tx.num_extra_frag) { - control->tx_rate = tx->u.tx.last_frag_hwrate; - control->rate = tx->u.tx.last_frag_rate; + control->tx_rate = tx->u.tx.last_frag_rate; + if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; @@ -1089,7 +1127,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP, res_prepare; + ieee80211_tx_result res = TX_DROP, res_prepare; int ret, i; WARN_ON(__ieee80211_queue_pending(local, control->queue)); @@ -1102,7 +1140,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, /* initialises tx */ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); - if (res_prepare == TXRX_DROP) { + if (res_prepare == TX_DROP) { dev_kfree_skb(skb); return 0; } @@ -1114,12 +1152,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); sta = tx.sta; - tx.u.tx.mode = local->hw.conf.mode; + tx.u.tx.channel = local->hw.conf.channel; - for (handler = local->tx_handlers; *handler != NULL; + for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); - if (res != TXRX_CONTINUE) + if (res != TX_CONTINUE) break; } @@ -1128,12 +1166,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, if (sta) sta_info_put(sta); - if (unlikely(res == TXRX_DROP)) { + if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(local->tx_handlers_drop); goto drop; } - if (unlikely(res == TXRX_QUEUED)) { + if (unlikely(res == TX_QUEUED)) { I802_DEBUG_INC(local->tx_handlers_queued); rcu_read_unlock(); return 0; @@ -1151,7 +1189,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, } else { next_len = 0; tx.u.tx.rate = tx.u.tx.last_frag_rate; - tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1188,7 +1225,6 @@ retry: store->skb = skb; store->extra_frag = tx.u.tx.extra_frag; store->num_extra_frag = tx.u.tx.num_extra_frag; - store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; store->last_frag_rate = tx.u.tx.last_frag_rate; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); @@ -1260,6 +1296,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, control.flags |= IEEE80211_TXCTL_REQUEUE; if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME) control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; + if (pkt_data->flags & IEEE80211_TXPD_AMPDU) + control.flags |= IEEE80211_TXCTL_AMPDU; control.queue = pkt_data->queue; ret = ieee80211_tx(odev, skb, &control); @@ -1409,10 +1447,17 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } - sta = sta_info_get(local, hdr.addr1); - if (sta) { - sta_flags = sta->flags; - sta_info_put(sta); + /* + * There's no need to try to look up the destination + * if it is a multicast address (which can only happen + * in AP mode) + */ + if (!is_multicast_ether_addr(hdr.addr1)) { + sta = sta_info_get(local, hdr.addr1); + if (sta) { + sta_flags = sta->flags; + sta_info_put(sta); + } } /* receiver is QoS enabled, use a QoS type frame */ @@ -1422,10 +1467,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, } /* - * If port access control is enabled, drop frames to unauthorised - * stations unless they are EAPOL frames from the local station. + * Drop unicast frames to unauthorised stations unless they are + * EAPOL frames from the local station. */ - if (unlikely(sdata->ieee802_1x_pac && + if (unlikely(!is_multicast_ether_addr(hdr.addr1) && !(sta_flags & WLAN_STA_AUTHORIZED) && !(ethertype == ETH_P_PAE && compare_ether_addr(dev->dev_addr, @@ -1598,7 +1643,6 @@ void ieee80211_tx_pending(unsigned long data) tx.u.tx.control = &store->control; tx.u.tx.extra_frag = store->extra_frag; tx.u.tx.num_extra_frag = store->num_extra_frag; - tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; tx.u.tx.last_frag_rate = store->last_frag_rate; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) @@ -1701,6 +1745,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_if_ap *ap = NULL; struct rate_selection rsel; struct beacon_data *beacon; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; rcu_read_lock(); @@ -1739,8 +1786,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, beacon->tail_len); if (control) { - rate_control_get_rate(local->mdev, local->oper_hw_mode, skb, - &rsel); + rate_control_get_rate(local->mdev, sband, skb, &rsel); if (!rsel.rate) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: ieee80211_beacon_get: " @@ -1753,15 +1799,14 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } control->vif = vif; - control->tx_rate = - (sdata->bss_conf.use_short_preamble && - (rsel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - rsel.rate->val2 : rsel.rate->val; + control->tx_rate = rsel.rate; + if (sdata->bss_conf.use_short_preamble && + rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->power_level = local->hw.conf.power_level; control->flags |= IEEE80211_TXCTL_NO_ACK; control->retry_limit = 1; - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; } ap->num_beacons++; @@ -1815,7 +1860,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP; + ieee80211_tx_result res = TX_DROP; struct net_device *bdev; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; @@ -1863,20 +1908,20 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, } sta = tx.sta; tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; - tx.u.tx.mode = local->hw.conf.mode; + tx.u.tx.channel = local->hw.conf.channel; - for (handler = local->tx_handlers; *handler != NULL; handler++) { + for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); - if (res == TXRX_DROP || res == TXRX_QUEUED) + if (res == TX_DROP || res == TX_QUEUED) break; } skb = tx.skb; /* handlers are allowed to change skb */ - if (res == TXRX_DROP) { + if (res == TX_DROP) { I802_DEBUG_INC(local->tx_handlers_drop); dev_kfree_skb(skb); skb = NULL; - } else if (res == TXRX_QUEUED) { + } else if (res == TX_QUEUED) { I802_DEBUG_INC(local->tx_handlers_queued); skb = NULL; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5e631ce98d7..f64804fed0a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -41,92 +41,6 @@ const unsigned char bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -static int rate_list_match(const int *rate_list, int rate) -{ - int i; - - if (!rate_list) - return 0; - - for (i = 0; rate_list[i] >= 0; i++) - if (rate_list[i] == rate) - return 1; - - return 0; -} - -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode) -{ - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - rate->flags &= ~(IEEE80211_RATE_SUPPORTED | - IEEE80211_RATE_BASIC); - - if (local->supp_rates[mode->mode]) { - if (!rate_list_match(local->supp_rates[mode->mode], - rate->rate)) - continue; - } - - rate->flags |= IEEE80211_RATE_SUPPORTED; - - /* Use configured basic rate set if it is available. If not, - * use defaults that are sane for most cases. */ - if (local->basic_rates[mode->mode]) { - if (rate_list_match(local->basic_rates[mode->mode], - rate->rate)) - rate->flags |= IEEE80211_RATE_BASIC; - } else switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211B: - if (rate->rate == 10 || rate->rate == 20) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case NUM_IEEE80211_MODES: - /* not useful */ - break; - } - - /* Set ERP and MANDATORY flags based on phymode */ - switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211B: - if (rate->rate == 10) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110 || - rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case NUM_IEEE80211_MODES: - /* not useful */ - break; - } - if (ieee80211_is_erp_rate(mode->mode, rate->rate)) - rate->flags |= IEEE80211_RATE_ERP; - } -} - u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum ieee80211_if_types type) { @@ -262,7 +176,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, * DIV_ROUND_UP() operations. */ - if (local->hw.conf.phymode == MODE_IEEE80211A || erp) { + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { /* * OFDM: * @@ -304,15 +218,19 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, /* Exported duration function for driver use */ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - size_t frame_len, int rate) + size_t frame_len, + struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); u16 dur; int erp; - erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); - dur = ieee80211_frame_duration(local, frame_len, rate, erp, + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; + + dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, sdata->bss_conf.use_short_preamble); return cpu_to_le16(dur); @@ -332,17 +250,20 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); + rate = frame_txctl->rts_cts_rate; + + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; /* CTS duration */ - dur = ieee80211_frame_duration(local, 10, rate->rate, + dur = ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); /* Data frame duration */ - dur += ieee80211_frame_duration(local, frame_len, rate->rate, + dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, + dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); return cpu_to_le16(dur); @@ -363,15 +284,17 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); + rate = frame_txctl->rts_cts_rate; + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; /* Data frame duration */ - dur = ieee80211_frame_duration(local, frame_len, rate->rate, + dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, + dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); } @@ -379,27 +302,6 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_ctstoself_duration); -struct ieee80211_rate * -ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) -{ - struct ieee80211_hw_mode *mode; - int r; - - list_for_each_entry(mode, &local->modes_list, list) { - if (mode->mode != phymode) - continue; - for (r = 0; r < mode->num_rates; r++) { - struct ieee80211_rate *rate = &mode->rates[r]; - if (rate->val == hw_rate || - (rate->flags & IEEE80211_RATE_PREAMBLE2 && - rate->val2 == hw_rate)) - return rate; - } - } - - return NULL; -} - void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index a0cff72a580..a33ef5cfa9a 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -305,13 +305,13 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) return NULL; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) { if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { @@ -320,7 +320,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP_UNUSABLE; } } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); @@ -328,7 +328,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) skb_trim(rx->skb, rx->skb->len - 4); } - return TXRX_CONTINUE; + return RX_CONTINUE; } static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) @@ -346,7 +346,7 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) return 0; } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) { tx->u.tx.control->iv_len = WEP_IV_LEN; @@ -355,7 +355,7 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) if (wep_encrypt_skb(tx, tx->skb) < 0) { I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); - return TXRX_DROP; + return TX_DROP; } if (tx->u.tx.extra_frag) { @@ -364,10 +364,10 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { I802_DEBUG_INC(tx->local-> tx_handlers_drop_wep); - return TXRX_DROP; + return TX_DROP; } } } - return TXRX_CONTINUE; + return TX_CONTINUE; } diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 785fbb4e0dd..43aef50cd0d 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -28,9 +28,9 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); #endif /* WEP_H */ diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 4e236599dd3..8cc036decc8 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -19,10 +19,13 @@ #include "wme.h" /* maximum number of hardware queues we support. */ -#define TC_80211_MAX_QUEUES 8 +#define TC_80211_MAX_QUEUES 16 + +const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; struct ieee80211_sched_data { + unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)]; struct tcf_proto *filter_list; struct Qdisc *queues[TC_80211_MAX_QUEUES]; struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; @@ -98,7 +101,6 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); int qos; - const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; /* see if frame is data or non data frame */ if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) { @@ -146,9 +148,25 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) unsigned short fc = le16_to_cpu(hdr->frame_control); struct Qdisc *qdisc; int err, queue; + struct sta_info *sta; + u8 tid; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - skb_queue_tail(&q->requeued[pkt_data->queue], skb); + queue = pkt_data->queue; + sta = sta_info_get(local, hdr->addr1); + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; + if (sta) { + int ampdu_queue = sta->tid_to_tx_q[tid]; + if ((ampdu_queue < local->hw.queues) && + test_bit(ampdu_queue, q->qdisc_pool)) { + queue = ampdu_queue; + pkt_data->flags |= IEEE80211_TXPD_AMPDU; + } else { + pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + } + sta_info_put(sta); + } + skb_queue_tail(&q->requeued[queue], skb); qd->q.qlen++; return 0; } @@ -159,14 +177,28 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) */ if (WLAN_FC_IS_QOS_DATA(fc)) { u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2; - u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK; + u8 ack_policy = 0; + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; if (local->wifi_wme_noack_test) - qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK << + ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << QOS_CONTROL_ACK_POLICY_SHIFT; /* qos header is 2 bytes, second reserved */ - *p = qos_hdr; + *p = ack_policy | tid; p++; *p = 0; + + sta = sta_info_get(local, hdr->addr1); + if (sta) { + int ampdu_queue = sta->tid_to_tx_q[tid]; + if ((ampdu_queue < local->hw.queues) && + test_bit(ampdu_queue, q->qdisc_pool)) { + queue = ampdu_queue; + pkt_data->flags |= IEEE80211_TXPD_AMPDU; + } else { + pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + } + sta_info_put(sta); + } } if (unlikely(queue >= local->hw.queues)) { @@ -184,6 +216,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) kfree_skb(skb); err = NET_XMIT_DROP; } else { + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; pkt_data->queue = (unsigned int) queue; qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); @@ -235,10 +268,11 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < hw->queues; queue++) { /* see if there is room in this hardware queue */ - if (test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue]) || - test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) + if ((test_bit(IEEE80211_LINK_STATE_XOFF, + &local->state[queue])) || + (test_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[queue])) || + (!test_bit(queue, q->qdisc_pool))) continue; /* there is space - try and get a frame */ @@ -360,6 +394,10 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) } } + /* reserve all legacy QoS queues */ + for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++) + set_bit(i, q->qdisc_pool); + return err; } @@ -605,3 +643,80 @@ void ieee80211_wme_unregister(void) { unregister_qdisc(&wme_qdisc_ops); } + +int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid) +{ + int i; + struct ieee80211_sched_data *q = + qdisc_priv(local->mdev->qdisc_sleeping); + DECLARE_MAC_BUF(mac); + + /* prepare the filter and save it for the SW queue + * matching the recieved HW queue */ + + /* try to get a Qdisc from the pool */ + for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++) + if (!test_and_set_bit(i, q->qdisc_pool)) { + ieee80211_stop_queue(local_to_hw(local), i); + sta->tid_to_tx_q[tid] = i; + + /* IF there are already pending packets + * on this tid first we need to drain them + * on the previous queue + * since HT is strict in order */ +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "allocated aggregation queue" + " %d tid %d addr %s pool=0x%lX", + i, tid, print_mac(mac, sta->addr), + q->qdisc_pool[0]); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + return 0; + } + + return -EAGAIN; +} + +/** + * the caller needs to hold local->mdev->queue_lock + */ +void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue) +{ + struct ieee80211_sched_data *q = + qdisc_priv(local->mdev->qdisc_sleeping); + int agg_queue = sta->tid_to_tx_q[tid]; + + /* return the qdisc to the pool */ + clear_bit(agg_queue, q->qdisc_pool); + sta->tid_to_tx_q[tid] = local->hw.queues; + + if (requeue) + ieee80211_requeue(local, agg_queue); + else + q->queues[agg_queue]->ops->reset(q->queues[agg_queue]); +} + +void ieee80211_requeue(struct ieee80211_local *local, int queue) +{ + struct Qdisc *root_qd = local->mdev->qdisc_sleeping; + struct ieee80211_sched_data *q = qdisc_priv(root_qd); + struct Qdisc *qdisc = q->queues[queue]; + struct sk_buff *skb = NULL; + u32 len = qdisc->q.qlen; + + if (!qdisc || !qdisc->dequeue) + return; + + printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen); + for (len = qdisc->q.qlen; len > 0; len--) { + skb = qdisc->dequeue(qdisc); + root_qd->q.qlen--; + /* packet will be classified again and */ + /* skb->packet_data->queue will be overridden if needed */ + if (skb) + wme_qdiscop_enqueue(skb, root_qd); + } +} diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 76c713a6450..fcc6b05508c 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -24,6 +24,8 @@ #define QOS_CONTROL_TAG1D_MASK 0x07 +extern const int ieee802_1d_to_ac[8]; + static inline int WLAN_FC_IS_QOS_DATA(u16 fc) { return (fc & 0x8C) == 0x88; @@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc) #ifdef CONFIG_NET_SCHED void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); - +int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid); +void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue); +void ieee80211_requeue(struct ieee80211_local *local, int queue); int ieee80211_wme_register(void); void ieee80211_wme_unregister(void); #else @@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev) { return 0; } - +static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid) +{ + return -EAGAIN; +} +static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue) +{ +} +static inline void ieee80211_requeue(struct ieee80211_local *local, int queue) +{ +} static inline int ieee80211_wme_register(void) { return 0; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 6f04311cf0a..b35e51c6ce0 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -70,7 +70,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) { u8 *data, *sa, *da, *key, *mic, qos_tid; @@ -84,10 +84,10 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 || !WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)) - return TXRX_DROP; + return TX_DROP; if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && @@ -95,7 +95,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC */ - return TXRX_CONTINUE; + return TX_CONTINUE; } if (skb_tailroom(skb) < MICHAEL_MIC_LEN) { @@ -105,7 +105,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) GFP_ATOMIC))) { printk(KERN_DEBUG "%s: failed to allocate more memory " "for Michael MIC\n", tx->dev->name); - return TXRX_DROP; + return TX_DROP; } } @@ -119,11 +119,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) mic = skb_put(skb, MICHAEL_MIC_LEN); michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) { u8 *data, *sa, *da, *key = NULL, qos_tid; @@ -140,15 +140,15 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) * No way to verify the MIC if the hardware stripped it */ if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) - return TXRX_DROP; + return RX_DROP_UNUSABLE; data_len -= MICHAEL_MIC_LEN; @@ -162,14 +162,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " "%s\n", rx->dev->name, print_mac(mac, sa)); mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); - return TXRX_DROP; + return RX_DROP_UNUSABLE; } /* remove Michael MIC from payload */ @@ -179,7 +179,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32; rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16; - return TXRX_CONTINUE; + return RX_CONTINUE; } @@ -242,7 +242,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) { struct sk_buff *skb = tx->skb; @@ -257,26 +257,26 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - return TXRX_CONTINUE; + return TX_CONTINUE; } if (tkip_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + return TX_DROP; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) - return TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -290,10 +290,10 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!rx->sta || skb->len - hdrlen < 12) - return TXRX_DROP; + return RX_DROP_UNUSABLE; if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { @@ -302,7 +302,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) * replay protection, and stripped the ICV/IV so * we cannot do any checks here. */ - return TXRX_CONTINUE; + return RX_CONTINUE; } /* let TKIP code verify IV, but skip decryption */ @@ -322,7 +322,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) "frame from %s (res=%d)\n", rx->dev->name, print_mac(mac, rx->sta->addr), res); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP_UNUSABLE; } /* Trim ICV */ @@ -332,7 +332,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen); skb_pull(skb, TKIP_IV_LEN); - return TXRX_CONTINUE; + return RX_CONTINUE; } @@ -491,7 +491,7 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) { struct sk_buff *skb = tx->skb; @@ -506,26 +506,26 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - return TXRX_CONTINUE; + return TX_CONTINUE; } if (ccmp_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + return TX_DROP; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) - return TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -541,15 +541,15 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - return TXRX_CONTINUE; + return RX_CONTINUE; data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; if (!rx->sta || data_len < 0) - return TXRX_DROP; + return RX_DROP_UNUSABLE; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) - return TXRX_CONTINUE; + return RX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); @@ -565,7 +565,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); #endif /* CONFIG_MAC80211_DEBUG */ key->u.ccmp.replays++; - return TXRX_DROP; + return RX_DROP_UNUSABLE; } if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { @@ -589,7 +589,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) "for RX frame from %s\n", rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP_UNUSABLE; } } @@ -600,5 +600,5 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen); skb_pull(skb, CCMP_HDR_LEN); - return TXRX_CONTINUE; + return RX_CONTINUE; } diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 49d80cf0cd7..16e4dba4aa7 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -13,19 +13,19 @@ #include <linux/types.h> #include "ieee80211_i.h" -ieee80211_txrx_result +ieee80211_tx_result ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); #endif /* WPA_H */ diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 65710a42e5a..b9f943c45f3 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_WIRELESS_EXT) += wext.o obj-$(CONFIG_CFG80211) += cfg80211.o -cfg80211-y += core.o sysfs.o radiotap.o +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o cfg80211-$(CONFIG_NL80211) += nl80211.o diff --git a/net/wireless/core.c b/net/wireless/core.c index cfc5fc5f9e7..80afacdae46 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -232,6 +232,47 @@ int wiphy_register(struct wiphy *wiphy) { struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); int res; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + bool have_band = false; + int i; + + /* sanity check supported bands/channels */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + + sband->band = band; + + if (!sband->n_channels || !sband->n_bitrates) { + WARN_ON(1); + return -EINVAL; + } + + for (i = 0; i < sband->n_channels; i++) { + sband->channels[i].orig_flags = + sband->channels[i].flags; + sband->channels[i].orig_mag = + sband->channels[i].max_antenna_gain; + sband->channels[i].orig_mpwr = + sband->channels[i].max_power; + sband->channels[i].band = band; + } + + have_band = true; + } + + if (!have_band) { + WARN_ON(1); + return -EINVAL; + } + + /* check and set up bitrates */ + ieee80211_set_bitrate_flags(wiphy); + + /* set up regulatory info */ + wiphy_update_regulatory(wiphy); mutex_lock(&cfg80211_drv_mutex); diff --git a/net/wireless/core.h b/net/wireless/core.h index eb0f846b40d..7a02c356d63 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -78,4 +78,7 @@ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv, char *newname); +void ieee80211_set_bitrate_flags(struct wiphy *wiphy); +void wiphy_update_regulatory(struct wiphy *wiphy); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e3a214f63f9..5b3474798b8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -82,6 +82,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, + [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, }; /* message building helper */ @@ -98,6 +99,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *dev) { void *hdr; + struct nlattr *nl_bands, *nl_band; + struct nlattr *nl_freqs, *nl_freq; + struct nlattr *nl_rates, *nl_rate; + enum ieee80211_band band; + struct ieee80211_channel *chan; + struct ieee80211_rate *rate; + int i; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); if (!hdr) @@ -105,6 +113,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + + nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); + if (!nl_bands) + goto nla_put_failure; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!dev->wiphy.bands[band]) + continue; + + nl_band = nla_nest_start(msg, band); + if (!nl_band) + goto nla_put_failure; + + /* add frequencies */ + nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); + if (!nl_freqs) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { + nl_freq = nla_nest_start(msg, i); + if (!nl_freq) + goto nla_put_failure; + + chan = &dev->wiphy.bands[band]->channels[i]; + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, + chan->center_freq); + + if (chan->flags & IEEE80211_CHAN_DISABLED) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); + if (chan->flags & IEEE80211_CHAN_RADAR) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + + nla_nest_end(msg, nl_freq); + } + + nla_nest_end(msg, nl_freqs); + + /* add bitrates */ + nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); + if (!nl_rates) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { + nl_rate = nla_nest_start(msg, i); + if (!nl_rate) + goto nla_put_failure; + + rate = &dev->wiphy.bands[band]->bitrates[i]; + NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, + rate->bitrate); + if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); + + nla_nest_end(msg, nl_rate); + } + + nla_nest_end(msg, nl_rates); + + nla_nest_end(msg, nl_band); + } + nla_nest_end(msg, nl_bands); + return genlmsg_end(msg, hdr); nla_put_failure: @@ -262,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) return -ENOBUFS; } +static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { + [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, +}; + +static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) +{ + struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; + int flag; + + *mntrflags = 0; + + if (!nla) + return -EINVAL; + + if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, + nla, mntr_flags_policy)) + return -EINVAL; + + for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) + if (flags[flag]) + *mntrflags |= (1<<flag); + + return 0; +} + static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; int err, ifindex; enum nl80211_iftype type; struct net_device *dev; + u32 flags; if (info->attrs[NL80211_ATTR_IFTYPE]) { type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); @@ -288,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); - err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); + err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, + type, err ? NULL : &flags); rtnl_unlock(); unlock: @@ -301,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *drv; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; + u32 flags; if (!info->attrs[NL80211_ATTR_IFNAME]) return -EINVAL; @@ -321,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); err = drv->ops->add_virtual_intf(&drv->wiphy, - nla_data(info->attrs[NL80211_ATTR_IFNAME]), type); + nla_data(info->attrs[NL80211_ATTR_IFNAME]), + type, err ? NULL : &flags); rtnl_unlock(); unlock: diff --git a/net/wireless/reg.c b/net/wireless/reg.c new file mode 100644 index 00000000000..8cc6037eb2a --- /dev/null +++ b/net/wireless/reg.c @@ -0,0 +1,159 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This regulatory domain control implementation is highly incomplete, it + * only exists for the purpose of not regressing mac80211. + * + * For now, drivers can restrict the set of allowed channels by either + * not registering those channels or setting the IEEE80211_CHAN_DISABLED + * flag; that flag will only be *set* by this code, never *cleared. + * + * The usual implementation is for a driver to read a device EEPROM to + * determine which regulatory domain it should be operating under, then + * looking up the allowable channels in a driver-local table and finally + * registering those channels in the wiphy structure. + * + * Alternatively, drivers that trust the regulatory domain control here + * will register a complete set of capabilities and the control code + * will restrict the set by setting the IEEE80211_CHAN_* flags. + */ +#include <linux/kernel.h> +#include <net/wireless.h> +#include "core.h" + +static char *ieee80211_regdom = "US"; +module_param(ieee80211_regdom, charp, 0444); +MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); + +struct ieee80211_channel_range { + short start_freq; + short end_freq; + int max_power; + int max_antenna_gain; + u32 flags; +}; + +struct ieee80211_regdomain { + const char *code; + const struct ieee80211_channel_range *ranges; + int n_ranges; +}; + +#define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \ + { _start, _end, _pwr, _ag, _flags } + + +/* + * Ideally, in the future, these definitions will be loaded from a + * userspace table via some daemon. + */ +static const struct ieee80211_channel_range ieee80211_US_channels[] = { + /* IEEE 802.11b/g, channels 1..11 */ + RANGE_PWR(2412, 2462, 27, 6, 0), + /* IEEE 802.11a, channel 36*/ + RANGE_PWR(5180, 5180, 23, 6, 0), + /* IEEE 802.11a, channel 40*/ + RANGE_PWR(5200, 5200, 23, 6, 0), + /* IEEE 802.11a, channel 44*/ + RANGE_PWR(5220, 5220, 23, 6, 0), + /* IEEE 802.11a, channels 48..64 */ + RANGE_PWR(5240, 5320, 23, 6, 0), + /* IEEE 802.11a, channels 149..165, outdoor */ + RANGE_PWR(5745, 5825, 30, 6, 0), +}; + +static const struct ieee80211_channel_range ieee80211_JP_channels[] = { + /* IEEE 802.11b/g, channels 1..14 */ + RANGE_PWR(2412, 2484, 20, 6, 0), + /* IEEE 802.11a, channels 34..48 */ + RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN), + /* IEEE 802.11a, channels 52..64 */ + RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR), +}; + +#define REGDOM(_code) \ + { \ + .code = __stringify(_code), \ + .ranges = ieee80211_ ##_code## _channels, \ + .n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \ + } + +static const struct ieee80211_regdomain ieee80211_regdoms[] = { + REGDOM(US), + REGDOM(JP), +}; + + +static const struct ieee80211_regdomain *get_regdom(void) +{ + static const struct ieee80211_channel_range + ieee80211_world_channels[] = { + /* IEEE 802.11b/g, channels 1..11 */ + RANGE_PWR(2412, 2462, 27, 6, 0), + }; + static const struct ieee80211_regdomain regdom_world = REGDOM(world); + int i; + + for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++) + if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0) + return &ieee80211_regdoms[i]; + + return ®dom_world; +} + + +static void handle_channel(struct ieee80211_channel *chan, + const struct ieee80211_regdomain *rd) +{ + int i; + u32 flags = chan->orig_flags; + const struct ieee80211_channel_range *rg = NULL; + + for (i = 0; i < rd->n_ranges; i++) { + if (rd->ranges[i].start_freq <= chan->center_freq && + chan->center_freq <= rd->ranges[i].end_freq) { + rg = &rd->ranges[i]; + break; + } + } + + if (!rg) { + /* not found */ + flags |= IEEE80211_CHAN_DISABLED; + chan->flags = flags; + return; + } + + chan->flags = flags; + chan->max_antenna_gain = min(chan->orig_mag, + rg->max_antenna_gain); + chan->max_power = min(chan->orig_mpwr, rg->max_power); +} + +static void handle_band(struct ieee80211_supported_band *sband, + const struct ieee80211_regdomain *rd) +{ + int i; + + for (i = 0; i < sband->n_channels; i++) + handle_channel(&sband->channels[i], rd); +} + +void wiphy_update_regulatory(struct wiphy *wiphy) +{ + enum ieee80211_band band; + const struct ieee80211_regdomain *rd = get_regdom(); + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + handle_band(wiphy->bands[band], rd); +} diff --git a/net/wireless/util.c b/net/wireless/util.c new file mode 100644 index 00000000000..77336c22fcf --- /dev/null +++ b/net/wireless/util.c @@ -0,0 +1,98 @@ +/* + * Wireless utility functions + * + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + */ +#include <net/wireless.h> +#include <asm/bitops.h> +#include "core.h" + +int ieee80211_channel_to_frequency(int chan) +{ + if (chan < 14) + return 2407 + chan * 5; + + if (chan == 14) + return 2484; + + /* FIXME: 802.11j 17.3.8.3.2 */ + return (chan + 1000) * 5; +} +EXPORT_SYMBOL(ieee80211_channel_to_frequency); + +int ieee80211_frequency_to_channel(int freq) +{ + if (freq == 2484) + return 14; + + if (freq < 2484) + return (freq - 2407) / 5; + + /* FIXME: 802.11j 17.3.8.3.2 */ + return freq/5 - 1000; +} +EXPORT_SYMBOL(ieee80211_frequency_to_channel); + +static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, + enum ieee80211_band band) +{ + int i, want; + + switch (band) { + case IEEE80211_BAND_5GHZ: + want = 3; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_A; + want--; + } + } + WARN_ON(want); + break; + case IEEE80211_BAND_2GHZ: + want = 7; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 10) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_B | + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate == 20 || + sband->bitrates[i].bitrate == 55 || + sband->bitrates[i].bitrate == 110 || + sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate != 10 && + sband->bitrates[i].bitrate != 20 && + sband->bitrates[i].bitrate != 55 && + sband->bitrates[i].bitrate != 110) + sband->bitrates[i].flags |= + IEEE80211_RATE_ERP_G; + } + WARN_ON(want != 0 && want != 3 && want != 6); + break; + case IEEE80211_NUM_BANDS: + WARN_ON(1); + break; + } +} + +void ieee80211_set_bitrate_flags(struct wiphy *wiphy) +{ + enum ieee80211_band band; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + set_mandatory_flags_band(wiphy->bands[band], band); +} |