diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 7 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 73 | ||||
-rw-r--r-- | net/mac80211/debugfs.h | 2 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 44 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 174 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 38 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 4 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 123 | ||||
-rw-r--r-- | net/mac80211/iface.c | 22 | ||||
-rw-r--r-- | net/mac80211/key.h | 12 | ||||
-rw-r--r-- | net/mac80211/main.c | 11 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 4 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 22 | ||||
-rw-r--r-- | net/mac80211/rate.c | 7 | ||||
-rw-r--r-- | net/mac80211/rx.c | 194 | ||||
-rw-r--r-- | net/mac80211/scan.c | 129 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 136 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 47 | ||||
-rw-r--r-- | net/mac80211/tx.c | 99 | ||||
-rw-r--r-- | net/mac80211/util.c | 8 |
20 files changed, 470 insertions, 686 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7b5131b..56319b5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -738,13 +738,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, err = sta_info_insert(sta); if (err) { - /* STA has been freed */ - if (err == -EEXIST && layer2_update) { - /* Need to update layer 2 devices on reassociation */ - sta = sta_info_get(local, mac); - if (sta) - ieee80211_send_layer2_update(sta); - } rcu_read_unlock(); return err; } diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 96991b6..82c8077 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -1,3 +1,4 @@ + /* * mac80211 debugfs for wireless PHYs * @@ -38,16 +39,10 @@ static const struct file_operations name## _ops = { \ }; #define DEBUGFS_ADD(name) \ - local->debugfs.name = debugfs_create_file(#name, 0400, phyd, \ - local, &name## _ops); + debugfs_create_file(#name, 0400, phyd, local, &name## _ops); #define DEBUGFS_ADD_MODE(name, mode) \ - local->debugfs.name = debugfs_create_file(#name, mode, phyd, \ - local, &name## _ops); - -#define DEBUGFS_DEL(name) \ - debugfs_remove(local->debugfs.name); \ - local->debugfs.name = NULL; + debugfs_create_file(#name, mode, phyd, local, &name## _ops); DEBUGFS_READONLY_FILE(frequency, 20, "%d", @@ -233,12 +228,7 @@ static const struct file_operations stats_ ##name## _ops = { \ }; #define DEBUGFS_STATS_ADD(name) \ - local->debugfs.stats.name = debugfs_create_file(#name, 0400, statsd,\ - local, &stats_ ##name## _ops); - -#define DEBUGFS_STATS_DEL(name) \ - debugfs_remove(local->debugfs.stats.name); \ - local->debugfs.stats.name = NULL; + debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops); DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u", local->dot11TransmittedFragmentCount); @@ -326,7 +316,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(noack); statsd = debugfs_create_dir("statistics", phyd); - local->debugfs.statistics = statsd; /* if the dir failed, don't put all the other things into the root! */ if (!statsd) @@ -367,57 +356,3 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_STATS_ADD(dot11FCSErrorCount); DEBUGFS_STATS_ADD(dot11RTSSuccessCount); } - -void debugfs_hw_del(struct ieee80211_local *local) -{ - DEBUGFS_DEL(frequency); - DEBUGFS_DEL(total_ps_buffered); - DEBUGFS_DEL(wep_iv); - DEBUGFS_DEL(tsf); - DEBUGFS_DEL(queues); - DEBUGFS_DEL(reset); - DEBUGFS_DEL(noack); - - DEBUGFS_STATS_DEL(transmitted_fragment_count); - DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); - DEBUGFS_STATS_DEL(failed_count); - DEBUGFS_STATS_DEL(retry_count); - DEBUGFS_STATS_DEL(multiple_retry_count); - DEBUGFS_STATS_DEL(frame_duplicate_count); - DEBUGFS_STATS_DEL(received_fragment_count); - DEBUGFS_STATS_DEL(multicast_received_frame_count); - DEBUGFS_STATS_DEL(transmitted_frame_count); - DEBUGFS_STATS_DEL(num_scans); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_STATS_DEL(tx_handlers_drop); - DEBUGFS_STATS_DEL(tx_handlers_queued); - DEBUGFS_STATS_DEL(tx_handlers_drop_unencrypted); - DEBUGFS_STATS_DEL(tx_handlers_drop_fragment); - DEBUGFS_STATS_DEL(tx_handlers_drop_wep); - DEBUGFS_STATS_DEL(tx_handlers_drop_not_assoc); - DEBUGFS_STATS_DEL(tx_handlers_drop_unauth_port); - DEBUGFS_STATS_DEL(rx_handlers_drop); - DEBUGFS_STATS_DEL(rx_handlers_queued); - DEBUGFS_STATS_DEL(rx_handlers_drop_nullfunc); - DEBUGFS_STATS_DEL(rx_handlers_drop_defrag); - DEBUGFS_STATS_DEL(rx_handlers_drop_short); - DEBUGFS_STATS_DEL(rx_handlers_drop_passive_scan); - DEBUGFS_STATS_DEL(tx_expand_skb_head); - DEBUGFS_STATS_DEL(tx_expand_skb_head_cloned); - DEBUGFS_STATS_DEL(rx_expand_skb_head); - DEBUGFS_STATS_DEL(rx_expand_skb_head2); - DEBUGFS_STATS_DEL(rx_handlers_fragments); - DEBUGFS_STATS_DEL(tx_status_drop); -#endif - DEBUGFS_STATS_DEL(dot11ACKFailureCount); - DEBUGFS_STATS_DEL(dot11RTSFailureCount); - DEBUGFS_STATS_DEL(dot11FCSErrorCount); - DEBUGFS_STATS_DEL(dot11RTSSuccessCount); - - debugfs_remove(local->debugfs.statistics); - local->debugfs.statistics = NULL; - debugfs_remove(local->debugfs.stations); - local->debugfs.stations = NULL; - debugfs_remove(local->debugfs.keys); - local->debugfs.keys = NULL; -} diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index dd25419..68e6a20 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h @@ -3,14 +3,12 @@ #ifdef CONFIG_MAC80211_DEBUGFS extern void debugfs_hw_add(struct ieee80211_local *local); -extern void debugfs_hw_del(struct ieee80211_local *local); extern int mac80211_open_file_generic(struct inode *inode, struct file *file); #else static inline void debugfs_hw_add(struct ieee80211_local *local) { return; } -static inline void debugfs_hw_del(struct ieee80211_local *local) {} #endif #endif /* __MAC80211_DEBUGFS_H */ diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 99c7525..e0f5224 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -225,8 +225,8 @@ static ssize_t key_key_read(struct file *file, char __user *userbuf, KEY_OPS(key); #define DEBUGFS_ADD(name) \ - key->debugfs.name = debugfs_create_file(#name, 0400,\ - key->debugfs.dir, key, &key_##name##_ops); + debugfs_create_file(#name, 0400, key->debugfs.dir, \ + key, &key_##name##_ops); void ieee80211_debugfs_key_add(struct ieee80211_key *key) { @@ -271,30 +271,12 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) DEBUGFS_ADD(ifindex); }; -#define DEBUGFS_DEL(name) \ - debugfs_remove(key->debugfs.name); key->debugfs.name = NULL; - void ieee80211_debugfs_key_remove(struct ieee80211_key *key) { if (!key) return; - DEBUGFS_DEL(keylen); - DEBUGFS_DEL(flags); - DEBUGFS_DEL(keyidx); - DEBUGFS_DEL(hw_key_idx); - DEBUGFS_DEL(tx_rx_count); - DEBUGFS_DEL(algorithm); - DEBUGFS_DEL(tx_spec); - DEBUGFS_DEL(rx_spec); - DEBUGFS_DEL(replays); - DEBUGFS_DEL(icverrors); - DEBUGFS_DEL(key); - DEBUGFS_DEL(ifindex); - - debugfs_remove(key->debugfs.stalink); - key->debugfs.stalink = NULL; - debugfs_remove(key->debugfs.dir); + debugfs_remove_recursive(key->debugfs.dir); key->debugfs.dir = NULL; } void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) @@ -302,7 +284,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) char buf[50]; struct ieee80211_key *key; - if (!sdata->debugfsdir) + if (!sdata->debugfs.dir) return; /* this is running under the key lock */ @@ -310,9 +292,9 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) key = sdata->default_key; if (key) { sprintf(buf, "../keys/%d", key->debugfs.cnt); - sdata->common_debugfs.default_key = + sdata->debugfs.default_key = debugfs_create_symlink("default_key", - sdata->debugfsdir, buf); + sdata->debugfs.dir, buf); } else ieee80211_debugfs_key_remove_default(sdata); } @@ -322,8 +304,8 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) if (!sdata) return; - debugfs_remove(sdata->common_debugfs.default_key); - sdata->common_debugfs.default_key = NULL; + debugfs_remove(sdata->debugfs.default_key); + sdata->debugfs.default_key = NULL; } void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) @@ -331,7 +313,7 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) char buf[50]; struct ieee80211_key *key; - if (!sdata->debugfsdir) + if (!sdata->debugfs.dir) return; /* this is running under the key lock */ @@ -339,9 +321,9 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) key = sdata->default_mgmt_key; if (key) { sprintf(buf, "../keys/%d", key->debugfs.cnt); - sdata->common_debugfs.default_mgmt_key = + sdata->debugfs.default_mgmt_key = debugfs_create_symlink("default_mgmt_key", - sdata->debugfsdir, buf); + sdata->debugfs.dir, buf); } else ieee80211_debugfs_key_remove_mgmt_default(sdata); } @@ -351,8 +333,8 @@ void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sda if (!sdata) return; - debugfs_remove(sdata->common_debugfs.default_mgmt_key); - sdata->common_debugfs.default_mgmt_key = NULL; + debugfs_remove(sdata->debugfs.default_mgmt_key); + sdata->debugfs.default_mgmt_key = NULL; } void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 61234e7..8782264 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -152,9 +152,9 @@ IEEE80211_IF_FILE(min_discovery_timeout, #endif -#define DEBUGFS_ADD(name, type)\ - sdata->debugfs.type.name = debugfs_create_file(#name, 0400,\ - sdata->debugfsdir, sdata, &name##_ops); +#define DEBUGFS_ADD(name, type) \ + debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ + sdata, &name##_ops); static void add_sta_files(struct ieee80211_sub_if_data *sdata) { @@ -199,30 +199,32 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata) } #ifdef CONFIG_MAC80211_MESH -#define MESHSTATS_ADD(name)\ - sdata->mesh_stats.name = debugfs_create_file(#name, 0400,\ - sdata->mesh_stats_dir, sdata, &name##_ops); static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) { - sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", - sdata->debugfsdir); + struct dentry *dir = debugfs_create_dir("mesh_stats", + sdata->debugfs.dir); + +#define MESHSTATS_ADD(name)\ + debugfs_create_file(#name, 0400, dir, sdata, &name##_ops); + MESHSTATS_ADD(fwded_mcast); MESHSTATS_ADD(fwded_unicast); MESHSTATS_ADD(fwded_frames); MESHSTATS_ADD(dropped_frames_ttl); MESHSTATS_ADD(dropped_frames_no_route); MESHSTATS_ADD(estab_plinks); +#undef MESHSTATS_ADD } -#define MESHPARAMS_ADD(name)\ - sdata->mesh_config.name = debugfs_create_file(#name, 0600,\ - sdata->mesh_config_dir, sdata, &name##_ops); - static void add_mesh_config(struct ieee80211_sub_if_data *sdata) { - sdata->mesh_config_dir = debugfs_create_dir("mesh_config", - sdata->debugfsdir); + struct dentry *dir = debugfs_create_dir("mesh_config", + sdata->debugfs.dir); + +#define MESHPARAMS_ADD(name) \ + debugfs_create_file(#name, 0600, dir, sdata, &name##_ops); + MESHPARAMS_ADD(dot11MeshMaxRetries); MESHPARAMS_ADD(dot11MeshRetryTimeout); MESHPARAMS_ADD(dot11MeshConfirmTimeout); @@ -236,12 +238,14 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries); MESHPARAMS_ADD(path_refresh_time); MESHPARAMS_ADD(min_discovery_timeout); + +#undef MESHPARAMS_ADD } #endif static void add_files(struct ieee80211_sub_if_data *sdata) { - if (!sdata->debugfsdir) + if (!sdata->debugfs.dir) return; switch (sdata->vif.type) { @@ -274,134 +278,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata) } } -#define DEBUGFS_DEL(name, type) \ - do { \ - debugfs_remove(sdata->debugfs.type.name); \ - sdata->debugfs.type.name = NULL; \ - } while (0) - -static void del_sta_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, sta); - DEBUGFS_DEL(force_unicast_rateidx, sta); - DEBUGFS_DEL(max_ratectrl_rateidx, sta); - - DEBUGFS_DEL(bssid, sta); - DEBUGFS_DEL(aid, sta); - DEBUGFS_DEL(capab, sta); -} - -static void del_ap_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, ap); - DEBUGFS_DEL(force_unicast_rateidx, ap); - DEBUGFS_DEL(max_ratectrl_rateidx, ap); - - DEBUGFS_DEL(num_sta_ps, ap); - DEBUGFS_DEL(dtim_count, ap); - DEBUGFS_DEL(num_buffered_multicast, ap); -} - -static void del_wds_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, wds); - DEBUGFS_DEL(force_unicast_rateidx, wds); - DEBUGFS_DEL(max_ratectrl_rateidx, wds); - - DEBUGFS_DEL(peer, wds); -} - -static void del_vlan_files(struct ieee80211_sub_if_data *sdata) -{ - DEBUGFS_DEL(drop_unencrypted, vlan); - DEBUGFS_DEL(force_unicast_rateidx, vlan); - DEBUGFS_DEL(max_ratectrl_rateidx, vlan); -} - -static void del_monitor_files(struct ieee80211_sub_if_data *sdata) -{ -} - -#ifdef CONFIG_MAC80211_MESH -#define MESHSTATS_DEL(name) \ - do { \ - debugfs_remove(sdata->mesh_stats.name); \ - sdata->mesh_stats.name = NULL; \ - } while (0) - -static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) -{ - MESHSTATS_DEL(fwded_mcast); - MESHSTATS_DEL(fwded_unicast); - MESHSTATS_DEL(fwded_frames); - MESHSTATS_DEL(dropped_frames_ttl); - MESHSTATS_DEL(dropped_frames_no_route); - MESHSTATS_DEL(estab_plinks); - debugfs_remove(sdata->mesh_stats_dir); - sdata->mesh_stats_dir = NULL; -} - -#define MESHPARAMS_DEL(name) \ - do { \ - debugfs_remove(sdata->mesh_config.name); \ - sdata->mesh_config.name = NULL; \ - } while (0) - -static void del_mesh_config(struct ieee80211_sub_if_data *sdata) -{ - MESHPARAMS_DEL(dot11MeshMaxRetries); - MESHPARAMS_DEL(dot11MeshRetryTimeout); - MESHPARAMS_DEL(dot11MeshConfirmTimeout); - MESHPARAMS_DEL(dot11MeshHoldingTimeout); - MESHPARAMS_DEL(dot11MeshTTL); - MESHPARAMS_DEL(auto_open_plinks); - MESHPARAMS_DEL(dot11MeshMaxPeerLinks); - MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout); - MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval); - MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime); - MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries); - MESHPARAMS_DEL(path_refresh_time); - MESHPARAMS_DEL(min_discovery_timeout); - debugfs_remove(sdata->mesh_config_dir); - sdata->mesh_config_dir = NULL; -} -#endif - -static void del_files(struct ieee80211_sub_if_data *sdata) -{ - if (!sdata->debugfsdir) - return; - - switch (sdata->vif.type) { - case NL80211_IFTYPE_MESH_POINT: -#ifdef CONFIG_MAC80211_MESH - del_mesh_stats(sdata); - del_mesh_config(sdata); -#endif - break; - case NL80211_IFTYPE_STATION: - del_sta_files(sdata); - break; - case NL80211_IFTYPE_ADHOC: - /* XXX */ - break; - case NL80211_IFTYPE_AP: - del_ap_files(sdata); - break; - case NL80211_IFTYPE_WDS: - del_wds_files(sdata); - break; - case NL80211_IFTYPE_MONITOR: - del_monitor_files(sdata); - break; - case NL80211_IFTYPE_AP_VLAN: - del_vlan_files(sdata); - break; - default: - break; - } -} - static int notif_registered; void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) @@ -412,16 +288,18 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata) return; sprintf(buf, "netdev:%s", sdata->dev->name); - sdata->debugfsdir = debugfs_create_dir(buf, + sdata->debugfs.dir = debugfs_create_dir(buf, sdata->local->hw.wiphy->debugfsdir); add_files(sdata); } void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata) { - del_files(sdata); - debugfs_remove(sdata->debugfsdir); - sdata->debugfsdir = NULL; + if (!sdata->debugfs.dir) + return; + + debugfs_remove_recursive(sdata->debugfs.dir); + sdata->debugfs.dir = NULL; } static int netdev_notify(struct notifier_block *nb, @@ -444,7 +322,7 @@ static int netdev_notify(struct notifier_block *nb, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - dir = sdata->debugfsdir; + dir = sdata->debugfs.dir; if (!dir) return 0; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 33a2e89..f043c29 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -57,7 +57,6 @@ STA_FILE(tx_filtered, tx_filtered_count, LU); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); STA_FILE(last_signal, last_signal, D); -STA_FILE(last_qual, last_qual, D); STA_FILE(last_noise, last_noise, D); STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); @@ -67,10 +66,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, char buf[100]; struct sta_info *sta = file->private_data; u32 staflags = get_sta_flags(sta); - int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", + int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", staflags & WLAN_STA_AUTH ? "AUTH\n" : "", staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "", - staflags & WLAN_STA_PS ? "PS\n" : "", + staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "", + staflags & WLAN_STA_PS_DRIVER ? "PS (driver)\n" : "", staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", staflags & WLAN_STA_WME ? "WME\n" : "", @@ -158,13 +158,9 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, STA_OPS(agg_status); #define DEBUGFS_ADD(name) \ - sta->debugfs.name = debugfs_create_file(#name, 0400, \ + debugfs_create_file(#name, 0400, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); -#define DEBUGFS_DEL(name) \ - debugfs_remove(sta->debugfs.name);\ - sta->debugfs.name = NULL; - void ieee80211_sta_debugfs_add(struct sta_info *sta) { @@ -209,36 +205,12 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(tx_retry_failed); DEBUGFS_ADD(tx_retry_count); DEBUGFS_ADD(last_signal); - DEBUGFS_ADD(last_qual); DEBUGFS_ADD(last_noise); DEBUGFS_ADD(wep_weak_iv_count); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) { - DEBUGFS_DEL(flags); - DEBUGFS_DEL(num_ps_buf_frames); - DEBUGFS_DEL(inactive_ms); - DEBUGFS_DEL(last_seq_ctrl); - DEBUGFS_DEL(agg_status); - DEBUGFS_DEL(aid); - DEBUGFS_DEL(dev); - DEBUGFS_DEL(rx_packets); - DEBUGFS_DEL(tx_packets); - DEBUGFS_DEL(rx_bytes); - DEBUGFS_DEL(tx_bytes); - DEBUGFS_DEL(rx_duplicates); - DEBUGFS_DEL(rx_fragments); - DEBUGFS_DEL(rx_dropped); - DEBUGFS_DEL(tx_fragments); - DEBUGFS_DEL(tx_filtered); - DEBUGFS_DEL(tx_retry_failed); - DEBUGFS_DEL(tx_retry_count); - DEBUGFS_DEL(last_signal); - DEBUGFS_DEL(last_qual); - DEBUGFS_DEL(last_noise); - DEBUGFS_DEL(wep_weak_iv_count); - - debugfs_remove(sta->debugfs.dir); + debugfs_remove_recursive(sta->debugfs.dir); sta->debugfs.dir = NULL; } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f1362f3..fbffce9 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -455,6 +455,10 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); + if (time_before(jiffies, ifibss->last_scan_completed + + IEEE80211_IBSS_MERGE_INTERVAL)) + return; + if (ieee80211_sta_active_ibss(sdata)) return; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 588005c..1ef7673 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -176,7 +176,6 @@ struct ieee80211_rx_data { struct ieee80211_rate *rate; unsigned int flags; - int sent_ps_buffered; int queue; u32 tkip_iv32; u16 tkip_iv16; @@ -471,74 +470,11 @@ struct ieee80211_sub_if_data { } u; #ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *debugfsdir; - union { - struct { - struct dentry *drop_unencrypted; - struct dentry *bssid; - struct dentry *aid; - struct dentry *capab; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - } sta; - struct { - struct dentry *drop_unencrypted; - struct dentry *num_sta_ps; - struct dentry *dtim_count; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - struct dentry *num_buffered_multicast; - } ap; - struct { - struct dentry *drop_unencrypted; - struct dentry *peer; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - } wds; - struct { - struct dentry *drop_unencrypted; - struct dentry *force_unicast_rateidx; - struct dentry *max_ratectrl_rateidx; - } vlan; - struct { - struct dentry *mode; - } monitor; - } debugfs; struct { + struct dentry *dir; struct dentry *default_key; struct dentry *default_mgmt_key; - } common_debugfs; - -#ifdef CONFIG_MAC80211_MESH - struct dentry *mesh_stats_dir; - struct { - struct dentry *fwded_mcast; - struct dentry *fwded_unicast; - struct dentry *fwded_frames; - struct dentry *dropped_frames_ttl; - struct dentry *dropped_frames_no_route; - struct dentry *estab_plinks; - struct timer_list mesh_path_timer; - } mesh_stats; - - struct dentry *mesh_config_dir; - struct { - struct dentry *dot11MeshRetryTimeout; - struct dentry *dot11MeshConfirmTimeout; - struct dentry *dot11MeshHoldingTimeout; - struct dentry *dot11MeshMaxRetries; - struct dentry *dot11MeshTTL; - struct dentry *auto_open_plinks; - struct dentry *dot11MeshMaxPeerLinks; - struct dentry *dot11MeshHWMPactivePathTimeout; - struct dentry *dot11MeshHWMPpreqMinInterval; - struct dentry *dot11MeshHWMPnetDiameterTraversalTime; - struct dentry *dot11MeshHWMPmaxPREQretries; - struct dentry *path_refresh_time; - struct dentry *min_discovery_timeout; - } mesh_config; -#endif - + } debugfs; #endif /* must be last, dynamically sized area in this! */ struct ieee80211_vif vif; @@ -730,10 +666,9 @@ struct ieee80211_local { unsigned long scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request *int_scan_req; - struct cfg80211_scan_request *scan_req; + struct cfg80211_scan_request *scan_req, *hw_scan_req; struct ieee80211_channel *scan_channel; - const u8 *orig_ies; - int orig_ies_len; + enum ieee80211_band hw_scan_band; int scan_channel_idx; int scan_ies_len; @@ -818,53 +753,6 @@ struct ieee80211_local { #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *rcdir; - struct dentry *rcname; - struct dentry *frequency; - struct dentry *total_ps_buffered; - struct dentry *wep_iv; - struct dentry *tsf; - struct dentry *queues; - struct dentry *reset; - struct dentry *noack; - struct dentry *statistics; - struct local_debugfsdentries_statsdentries { - struct dentry *transmitted_fragment_count; - struct dentry *multicast_transmitted_frame_count; - struct dentry *failed_count; - struct dentry *retry_count; - struct dentry *multiple_retry_count; - struct dentry *frame_duplicate_count; - struct dentry *received_fragment_count; - struct dentry *multicast_received_frame_count; - struct dentry *transmitted_frame_count; - struct dentry *wep_undecryptable_count; - struct dentry *num_scans; -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - struct dentry *tx_handlers_drop; - struct dentry *tx_handlers_queued; - struct dentry *tx_handlers_drop_unencrypted; - struct dentry *tx_handlers_drop_fragment; - struct dentry *tx_handlers_drop_wep; - struct dentry *tx_handlers_drop_not_assoc; - struct dentry *tx_handlers_drop_unauth_port; - struct dentry *rx_handlers_drop; - struct dentry *rx_handlers_queued; - struct dentry *rx_handlers_drop_nullfunc; - struct dentry *rx_handlers_drop_defrag; - struct dentry *rx_handlers_drop_short; - struct dentry *rx_handlers_drop_passive_scan; - struct dentry *tx_expand_skb_head; - struct dentry *tx_expand_skb_head_cloned; - struct dentry *rx_expand_skb_head; - struct dentry *rx_expand_skb_head2; - struct dentry *rx_handlers_fragments; - struct dentry *tx_status_drop; -#endif - struct dentry *dot11ACKFailureCount; - struct dentry *dot11RTSFailureCount; - struct dentry *dot11FCSErrorCount; - struct dentry *dot11RTSSuccessCount; - } stats; struct dentry *stations; struct dentry *keys; } debugfs; @@ -1160,7 +1048,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u8 *extra, size_t extra_len, const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - const u8 *ie, size_t ie_len); + const u8 *ie, size_t ie_len, + enum ieee80211_band band); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, const u8 *ssid, size_t ssid_len, const u8 *ie, size_t ie_len); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b8295cb..8495161 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -184,10 +184,12 @@ static int ieee80211_open(struct net_device *dev) * No need to check netif_running since we do not allow * it to start up with this invalid address. */ - if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) + if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); + memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); + } } /* @@ -212,8 +214,8 @@ static int ieee80211_open(struct net_device *dev) /* must be before the call to ieee80211_configure_filter */ local->monitors++; if (local->monitors == 1) { - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + local->hw.conf.flags |= IEEE80211_CONF_MONITOR; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) @@ -312,7 +314,7 @@ static int ieee80211_open(struct net_device *dev) if (sdata->vif.type == NL80211_IFTYPE_STATION) ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); - netif_tx_start_all_queues(dev); + netif_start_queue(dev); return 0; err_del_interface: @@ -341,7 +343,7 @@ static int ieee80211_stop(struct net_device *dev) /* * Stop TX on this interface first. */ - netif_tx_stop_all_queues(dev); + netif_stop_queue(dev); /* * Now delete all active aggregation sessions. @@ -433,8 +435,8 @@ static int ieee80211_stop(struct net_device *dev) local->monitors--; if (local->monitors == 0) { - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) @@ -754,10 +756,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, return 0; } -static struct device_type wiphy_type = { - .name = "wlan", -}; - int ieee80211_if_add(struct ieee80211_local *local, const char *name, struct net_device **new_dev, enum nl80211_iftype type, struct vif_params *params) @@ -788,8 +786,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, goto fail; memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); + memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - SET_NETDEV_DEVTYPE(ndev, &wiphy_type); /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 9572e00..a49f93b 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -118,18 +118,6 @@ struct ieee80211_key { struct { struct dentry *stalink; struct dentry *dir; - struct dentry *keylen; - struct dentry *flags; - struct dentry *keyidx; - struct dentry *hw_key_idx; - struct dentry *tx_rx_count; - struct dentry *algorithm; - struct dentry *tx_spec; - struct dentry *rx_spec; - struct dentry *replays; - struct dentry *icverrors; - struct dentry *key; - struct dentry *ifindex; int cnt; } debugfs; #endif diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 797f539..beb8718 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -385,13 +385,13 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, * can be unknown, for example with different interrupt status * bits. */ - if (test_sta_flags(sta, WLAN_STA_PS) && + if (test_sta_flags(sta, WLAN_STA_PS_STA) && skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { skb_queue_tail(&sta->tx_filtered, skb); return; } - if (!test_sta_flags(sta, WLAN_STA_PS) && + if (!test_sta_flags(sta, WLAN_STA_PS_STA) && !(info->flags & IEEE80211_TX_INTFL_RETRIED)) { /* Software retry the packet once */ info->flags |= IEEE80211_TX_INTFL_RETRIED; @@ -406,7 +406,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, "queue_len=%d PS=%d @%lu\n", wiphy_name(local->hw.wiphy), skb_queue_len(&sta->tx_filtered), - !!test_sta_flags(sta, WLAN_STA_PS), jiffies); + !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); #endif dev_kfree_skb(skb); } @@ -446,7 +446,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (sta) { if (!(info->flags & IEEE80211_TX_STAT_ACK) && - test_sta_flags(sta, WLAN_STA_PS)) { + test_sta_flags(sta, WLAN_STA_PS_STA)) { /* * The STA is in power save mode, so assume * that this TX packet failed because of that. @@ -901,6 +901,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) i++; } } + local->int_scan_req->n_channels = i; local->network_latency_notifier.notifier_call = ieee80211_max_network_latency; @@ -923,7 +924,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_wep: sta_info_stop(local); fail_sta_info: - debugfs_hw_del(local); destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); @@ -959,7 +959,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); - debugfs_hw_del(local); if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f7364e5..9a73389 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -50,7 +50,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; + set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); if (local->quiescing) { set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); @@ -480,7 +480,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; - ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; + set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); ieee80211_queue_work(&local->hw, &ifmsh->work); sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dc5049d..dcc14e9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -458,9 +458,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie); + if (cookie) + __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + else + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); else - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie); + if (cookie) + __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); + else + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -923,7 +929,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_ps(local, -1); mutex_unlock(&local->iflist_mtx); - netif_tx_start_all_queues(sdata->dev); + netif_start_queue(sdata->dev); netif_carrier_on(sdata->dev); } @@ -1055,7 +1061,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, * time -- we don't want the scan code to enable queues. */ - netif_tx_stop_all_queues(sdata->dev); + netif_stop_queue(sdata->dev); netif_carrier_off(sdata->dev); rcu_read_lock(); @@ -1958,12 +1964,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, - NULL); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); break; case RX_MGMT_CFG80211_DISASSOC: - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, - NULL); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); @@ -2018,7 +2022,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b33efc4..ccda745 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -163,8 +163,7 @@ struct rate_control_ref *rate_control_alloc(const char *name, #ifdef CONFIG_MAC80211_DEBUGFS debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir); local->debugfs.rcdir = debugfsdir; - local->debugfs.rcname = debugfs_create_file("name", 0400, debugfsdir, - ref, &rcname_ops); + debugfs_create_file("name", 0400, debugfsdir, ref, &rcname_ops); #endif ref->priv = ref->ops->alloc(&local->hw, debugfsdir); @@ -188,9 +187,7 @@ static void rate_control_release(struct kref *kref) ctrl_ref->ops->free(ctrl_ref->priv); #ifdef CONFIG_MAC80211_DEBUGFS - debugfs_remove(ctrl_ref->local->debugfs.rcname); - ctrl_ref->local->debugfs.rcname = NULL; - debugfs_remove(ctrl_ref->local->debugfs.rcdir); + debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir); ctrl_ref->local->debugfs.rcdir = NULL; #endif diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7170bf4..28316b2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -39,11 +39,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, * only useful for monitoring. */ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, - struct sk_buff *skb, - int rtap_len) + struct sk_buff *skb) { - skb_pull(skb, rtap_len); - if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { if (likely(skb->len > FCS_LEN)) skb_trim(skb, skb->len - FCS_LEN); @@ -59,15 +56,14 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, } static inline int should_drop_frame(struct sk_buff *skb, - int present_fcs_len, - int radiotap_len) + int present_fcs_len) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) return 1; - if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) + if (unlikely(skb->len < 16 + present_fcs_len)) return 1; if (ieee80211_is_ctl(hdr->frame_control) && !ieee80211_is_pspoll(hdr->frame_control) && @@ -95,10 +91,6 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, if (len & 1) /* padding for RX_FLAGS if necessary */ len++; - /* make sure radiotap starts at a naturally aligned address */ - if (len % 8) - len = roundup(len, 8); - return len; } @@ -116,6 +108,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_header *rthdr; unsigned char *pos; + u16 rx_flags = 0; rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); memset(rthdr, 0, rtap_len); @@ -134,7 +127,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* IEEE80211_RADIOTAP_TSFT */ if (status->flag & RX_FLAG_TSFT) { - *(__le64 *)pos = cpu_to_le64(status->mactime); + put_unaligned_le64(status->mactime, pos); rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); pos += 8; @@ -166,17 +159,17 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos++; /* IEEE80211_RADIOTAP_CHANNEL */ - *(__le16 *)pos = cpu_to_le16(status->freq); + put_unaligned_le16(status->freq, pos); pos += 2; if (status->band == IEEE80211_BAND_5GHZ) - *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ); + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, + pos); else if (rate->flags & IEEE80211_RATE_ERP_G) - *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ); + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, + pos); else - *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ); + put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, + pos); pos += 2; /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ @@ -205,10 +198,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* IEEE80211_RADIOTAP_RX_FLAGS */ /* ensure 2 byte alignment for the 2 byte field as required */ - if ((pos - (unsigned char *)rthdr) & 1) + if ((pos - (u8 *)rthdr) & 1) pos++; if (status->flag & RX_FLAG_FAILED_PLCP_CRC) - *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADPLCP); + rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; + put_unaligned_le16(rx_flags, pos); pos += 2; } @@ -227,7 +221,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, struct sk_buff *skb, *skb2; struct net_device *prev_dev = NULL; int present_fcs_len = 0; - int rtap_len = 0; /* * First, we may need to make a copy of the skb because @@ -237,25 +230,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, * We don't need to, of course, if we aren't going to return * the SKB because it has a bad FCS/PLCP checksum. */ - if (status->flag & RX_FLAG_RADIOTAP) - rtap_len = ieee80211_get_radiotap_len(origskb->data); - else - /* room for the radiotap header based on driver features */ - needed_headroom = ieee80211_rx_radiotap_len(local, status); + + /* room for the radiotap header based on driver features */ + needed_headroom = ieee80211_rx_radiotap_len(local, status); if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; if (!local->monitors) { - if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len)) { dev_kfree_skb(origskb); return NULL; } - return remove_monitor_info(local, origskb, rtap_len); + return remove_monitor_info(local, origskb); } - if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len)) { /* only need to expand headroom if necessary */ skb = origskb; origskb = NULL; @@ -279,16 +270,14 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, */ skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); - origskb = remove_monitor_info(local, origskb, rtap_len); + origskb = remove_monitor_info(local, origskb); if (!skb) return origskb; } - /* if necessary, prepend radiotap information */ - if (!(status->flag & RX_FLAG_RADIOTAP)) - ieee80211_add_rx_radiotap_header(local, skb, rate, - needed_headroom); + /* prepend radiotap information */ + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -792,7 +781,7 @@ static void ap_sta_ps_start(struct sta_info *sta) struct ieee80211_local *local = sdata->local; atomic_inc(&sdata->bss->num_sta_ps); - set_sta_flags(sta, WLAN_STA_PS); + set_sta_flags(sta, WLAN_STA_PS_STA); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", @@ -800,38 +789,28 @@ static void ap_sta_ps_start(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } -static int ap_sta_ps_end(struct sta_info *sta) +static void ap_sta_ps_end(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - struct ieee80211_local *local = sdata->local; - int sent, buffered; atomic_dec(&sdata->bss->num_sta_ps); - clear_sta_flags(sta, WLAN_STA_PS); - drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); - - if (!skb_queue_empty(&sta->ps_tx_buf)) - sta_info_clear_tim_bit(sta); + clear_sta_flags(sta, WLAN_STA_PS_STA); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - /* Send all buffered frames to the station */ - sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); - buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); - sent += buffered; - local->total_ps_buffered -= buffered; - + if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " - "since STA not sleeping anymore\n", sdata->dev->name, - sta->sta.addr, sta->sta.aid, sent - buffered, buffered); + printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n", + sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + return; + } - return sent; + ieee80211_sta_ps_deliver_wakeup(sta); } static ieee80211_rx_result debug_noinline @@ -870,7 +849,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; sta->last_signal = rx->status->signal; - sta->last_qual = rx->status->qual; sta->last_noise = rx->status->noise; /* @@ -880,7 +858,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!ieee80211_has_morefrags(hdr->frame_control) && (rx->sdata->vif.type == NL80211_IFTYPE_AP || rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { - if (test_sta_flags(sta, WLAN_STA_PS)) { + if (test_sta_flags(sta, WLAN_STA_PS_STA)) { /* * Ignore doze->wake transitions that are * indicated by non-data frames, the standard @@ -891,19 +869,24 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) */ if (ieee80211_is_data(hdr->frame_control) && !ieee80211_has_pm(hdr->frame_control)) - rx->sent_ps_buffered += ap_sta_ps_end(sta); + ap_sta_ps_end(sta); } else { if (ieee80211_has_pm(hdr->frame_control)) ap_sta_ps_start(sta); } } - /* Drop data::nullfunc frames silently, since they are used only to - * control station power saving mode. */ - if (ieee80211_is_nullfunc(hdr->frame_control)) { + /* + * Drop (qos-)data::nullfunc frames silently, since they + * are used only to control station power saving mode. + */ + if (ieee80211_is_nullfunc(hdr->frame_control) || + ieee80211_is_qos_nullfunc(hdr->frame_control)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); - /* Update counter and free packet here to avoid counting this - * as a dropped packed. */ + /* + * Update counter and free packet here to avoid + * counting this as a dropped packed. + */ sta->rx_packets++; dev_kfree_skb(rx->skb); return RX_QUEUED; @@ -1103,9 +1086,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); - struct sk_buff *skb; - int no_pending_pkts; + struct ieee80211_sub_if_data *sdata = rx->sdata; __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || @@ -1116,56 +1097,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) return RX_DROP_UNUSABLE; - skb = skb_dequeue(&rx->sta->tx_filtered); - if (!skb) { - skb = skb_dequeue(&rx->sta->ps_tx_buf); - if (skb) - rx->local->total_ps_buffered--; - } - no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) && - skb_queue_empty(&rx->sta->ps_tx_buf); - - if (skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) skb->data; - - /* - * Tell TX path to send this frame even though the STA may - * still remain is PS mode after this frame exchange. - */ - info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; - -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", - rx->sta->sta.addr, rx->sta->sta.aid, - skb_queue_len(&rx->sta->ps_tx_buf)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - - /* Use MoreData flag to indicate whether there are more - * buffered frames for this STA */ - if (no_pending_pkts) - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); - else - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - - ieee80211_add_pending_skb(rx->local, skb); - - if (no_pending_pkts) - sta_info_clear_tim_bit(rx->sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - } else if (!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 %pM sent PS Poll even " - "though there are no buffered frames for it\n", - rx->dev->name, rx->sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - } + if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER)) + ieee80211_sta_ps_deliver_poll_response(rx->sta); + else + set_sta_flags(rx->sta, WLAN_STA_PSPOLL); /* Free PS Poll skb here instead of returning RX_DROP that would * count as an dropped frame. */ @@ -1337,10 +1272,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) skb = NULL; } else { u8 *data = skb->data; - size_t len = skb->len; - u8 *new = __skb_push(skb, align); - memmove(new, data, len); - __skb_trim(skb, len); + size_t len = skb_headlen(skb); + skb->data -= align; + memmove(skb->data, data, len); + skb_set_tail_pointer(skb, len); } } #endif @@ -1504,19 +1439,28 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* illegal frame */ return RX_DROP_MONITOR; - if (!is_multicast_ether_addr(hdr->addr1) && - (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) { + if (mesh_hdr->flags & MESH_FLAGS_AE) { struct mesh_path *mppath; + char *proxied_addr; + char *mpp_addr; + + if (is_multicast_ether_addr(hdr->addr1)) { + mpp_addr = hdr->addr3; + proxied_addr = mesh_hdr->eaddr1; + } else { + mpp_addr = hdr->addr4; + proxied_addr = mesh_hdr->eaddr2; + } rcu_read_lock(); - mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata); + mppath = mpp_path_lookup(proxied_addr, sdata); if (!mppath) { - mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata); + mpp_path_add(proxied_addr, mpp_addr, sdata); } else { spin_lock_bh(&mppath->state_lock); mppath->exp_time = jiffies; - if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0) - memcpy(mppath->mpp, hdr->addr4, ETH_ALEN); + if (compare_ether_addr(mppath->mpp, mpp_addr) != 0) + memcpy(mppath->mpp, mpp_addr, ETH_ALEN); spin_unlock_bh(&mppath->state_lock); } rcu_read_unlock(); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 71e10ca..4cf387c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -12,8 +12,6 @@ * published by the Free Software Foundation. */ -/* TODO: figure out how to avoid that the "current BSS" expires */ - #include <linux/wireless.h> #include <linux/if_arp.h> #include <linux/rtnetlink.h> @@ -189,6 +187,39 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) return RX_QUEUED; } +/* return false if no more work */ +static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) +{ + struct cfg80211_scan_request *req = local->scan_req; + enum ieee80211_band band; + int i, ielen, n_chans; + + do { + if (local->hw_scan_band == IEEE80211_NUM_BANDS) + return false; + + band = local->hw_scan_band; + n_chans = 0; + for (i = 0; i < req->n_channels; i++) { + if (req->channels[i]->band == band) { + local->hw_scan_req->channels[n_chans] = + req->channels[i]; + n_chans++; + } + } + + local->hw_scan_band++; + } while (!n_chans); + + local->hw_scan_req->n_channels = n_chans; + + ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, + req->ie, req->ie_len, band); + local->hw_scan_req->ie_len = ielen; + + return true; +} + /* * inform AP that we will go to sleep so that it will buffer the frames * while we scan @@ -249,13 +280,6 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) } } -static void ieee80211_restore_scan_ies(struct ieee80211_local *local) -{ - kfree(local->scan_req->ie); - local->scan_req->ie = local->orig_ies; - local->scan_req->ie_len = local->orig_ies_len; -} - void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) { struct ieee80211_local *local = hw_to_local(hw); @@ -264,25 +288,36 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) mutex_lock(&local->scan_mtx); - if (WARN_ON(!local->scanning)) { + /* + * It's ok to abort a not-yet-running scan (that + * we have one at all will be verified by checking + * local->scan_req next), but not to complete it + * successfully. + */ + if (WARN_ON(!local->scanning && !aborted)) + aborted = true; + + if (WARN_ON(!local->scan_req)) { mutex_unlock(&local->scan_mtx); return; } - if (WARN_ON(!local->scan_req)) { + was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); + if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, 0); mutex_unlock(&local->scan_mtx); return; } - if (test_bit(SCAN_HW_SCANNING, &local->scanning)) - ieee80211_restore_scan_ies(local); + kfree(local->hw_scan_req); + local->hw_scan_req = NULL; if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; local->scan_sdata = NULL; - was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); local->scanning = 0; local->scan_channel = NULL; @@ -306,10 +341,10 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.associated) { ieee80211_scan_ps_disable(sdata); - netif_tx_wake_all_queues(sdata->dev); + netif_wake_queue(sdata->dev); } } else - netif_tx_wake_all_queues(sdata->dev); + netif_wake_queue(sdata->dev); /* re-enable beaconing */ if (sdata->vif.type == NL80211_IFTYPE_AP || @@ -364,7 +399,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) * are handled in the scan state machine */ if (sdata->vif.type != NL80211_IFTYPE_STATION) - netif_tx_stop_all_queues(sdata->dev); + netif_stop_queue(sdata->dev); } mutex_unlock(&local->iflist_mtx); @@ -394,19 +429,23 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (local->ops->hw_scan) { u8 *ies; - int ielen; - ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + - local->scan_ies_len + req->ie_len, GFP_KERNEL); - if (!ies) + local->hw_scan_req = kmalloc( + sizeof(*local->hw_scan_req) + + req->n_channels * sizeof(req->channels[0]) + + 2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + + req->ie_len, GFP_KERNEL); + if (!local->hw_scan_req) return -ENOMEM; - ielen = ieee80211_build_preq_ies(local, ies, - req->ie, req->ie_len); - local->orig_ies = req->ie; - local->orig_ies_len = req->ie_len; - req->ie = ies; - req->ie_len = ielen; + local->hw_scan_req->ssids = req->ssids; + local->hw_scan_req->n_ssids = req->n_ssids; + ies = (u8 *)local->hw_scan_req + + sizeof(*local->hw_scan_req) + + req->n_channels * sizeof(req->channels[0]); + local->hw_scan_req->ie = ies; + + local->hw_scan_band = 0; } local->scan_req = req; @@ -438,16 +477,17 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(local); mutex_unlock(&local->scan_mtx); - if (local->ops->hw_scan) - rc = drv_hw_scan(local, local->scan_req); - else + if (local->ops->hw_scan) { + WARN_ON(!ieee80211_prep_hw_scan(local)); + rc = drv_hw_scan(local, local->hw_scan_req); + } else rc = ieee80211_start_sw_scan(local); mutex_lock(&local->scan_mtx); if (rc) { - if (local->ops->hw_scan) - ieee80211_restore_scan_ies(local); + kfree(local->hw_scan_req); + local->hw_scan_req = NULL; local->scanning = 0; ieee80211_recalc_idle(local); @@ -523,7 +563,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca continue; if (sdata->vif.type == NL80211_IFTYPE_STATION) { - netif_tx_stop_all_queues(sdata->dev); + netif_stop_queue(sdata->dev); if (sdata->u.mgd.associated) ieee80211_scan_ps_enable(sdata); } @@ -558,7 +598,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca if (sdata->vif.type == NL80211_IFTYPE_STATION) { if (sdata->u.mgd.associated) ieee80211_scan_ps_disable(sdata); - netif_tx_wake_all_queues(sdata->dev); + netif_wake_queue(sdata->dev); } } mutex_unlock(&local->iflist_mtx); @@ -574,23 +614,14 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, { int skip; struct ieee80211_channel *chan; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; skip = 0; chan = local->scan_req->channels[local->scan_channel_idx]; - if (chan->flags & IEEE80211_CHAN_DISABLED || - (sdata->vif.type == NL80211_IFTYPE_ADHOC && - chan->flags & IEEE80211_CHAN_NO_IBSS)) + local->scan_channel = chan; + if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) skip = 1; - if (!skip) { - local->scan_channel = chan; - if (ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_CHANNEL)) - skip = 1; - } - /* advance state machine to next channel/band */ local->scan_channel_idx++; @@ -656,6 +687,14 @@ void ieee80211_scan_work(struct work_struct *work) return; } + if (local->hw_scan_req) { + int rc = drv_hw_scan(local, local->hw_scan_req); + mutex_unlock(&local->scan_mtx); + if (rc) + ieee80211_scan_completed(&local->hw, true); + return; + } + if (local->scan_req && !local->scanning) { struct cfg80211_scan_request *req = local->scan_req; int rc; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 594f231..be59456e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -171,6 +171,8 @@ void sta_info_destroy(struct sta_info *sta) local = sta->local; + cancel_work_sync(&sta->drv_unblock_wk); + rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); @@ -259,6 +261,21 @@ static void sta_info_hash_add(struct ieee80211_local *local, rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); } +static void sta_unblock(struct work_struct *wk) +{ + struct sta_info *sta; + + sta = container_of(wk, struct sta_info, drv_unblock_wk); + + if (sta->dead) + return; + + if (!test_sta_flags(sta, WLAN_STA_PS_STA)) + ieee80211_sta_ps_deliver_wakeup(sta); + else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) + ieee80211_sta_ps_deliver_poll_response(sta); +} + struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, gfp_t gfp) { @@ -272,6 +289,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, spin_lock_init(&sta->lock); spin_lock_init(&sta->flaglock); + INIT_WORK(&sta->drv_unblock_wk, sta_unblock); memcpy(sta->sta.addr, addr, ETH_ALEN); sta->local = local; @@ -478,8 +496,10 @@ static void __sta_info_unlink(struct sta_info **sta) } list_del(&(*sta)->list); + (*sta)->dead = true; - if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { + if (test_and_clear_sta_flags(*sta, + WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { BUG_ON(!sdata->bss); atomic_dec(&sdata->bss->num_sta_ps); @@ -801,8 +821,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, - const u8 *addr) +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr) { struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); @@ -810,4 +830,114 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, return NULL; return &sta->sta; } +EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); + +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, + const u8 *addr) +{ + struct ieee80211_sub_if_data *sdata; + + if (!vif) + return NULL; + + sdata = vif_to_sdata(vif); + + return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); +} EXPORT_SYMBOL(ieee80211_find_sta); + +/* powersave support code */ +void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + int sent, buffered; + + drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); + + if (!skb_queue_empty(&sta->ps_tx_buf)) + sta_info_clear_tim_bit(sta); + + /* Send all buffered frames to the station */ + sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); + buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); + sent += buffered; + local->total_ps_buffered -= buffered; + +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " + "since STA not sleeping anymore\n", sdata->dev->name, + sta->sta.addr, sta->sta.aid, sent - buffered, buffered); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ +} + +void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; + struct sk_buff *skb; + int no_pending_pkts; + + skb = skb_dequeue(&sta->tx_filtered); + if (!skb) { + skb = skb_dequeue(&sta->ps_tx_buf); + if (skb) + local->total_ps_buffered--; + } + no_pending_pkts = skb_queue_empty(&sta->tx_filtered) && + skb_queue_empty(&sta->ps_tx_buf); + + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) skb->data; + + /* + * Tell TX path to send this frame even though the STA may + * still remain is PS mode after this frame exchange. + */ + info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; + +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", + sta->sta.addr, sta->sta.aid, + skb_queue_len(&sta->ps_tx_buf)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + + /* Use MoreData flag to indicate whether there are more + * buffered frames for this STA */ + if (no_pending_pkts) + hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); + else + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + + ieee80211_add_pending_skb(local, skb); + + if (no_pending_pkts) + sta_info_clear_tim_bit(sta); +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + } else { + /* + * 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 %pM sent PS Poll even " + "though there are no buffered frames for it\n", + sdata->dev->name, sta->sta.addr); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + } +} + +void ieee80211_sta_block_awake(struct ieee80211_hw *hw, + struct ieee80211_sta *pubsta, bool block) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + + if (block) + set_sta_flags(sta, WLAN_STA_PS_DRIVER); + else + ieee80211_queue_work(hw, &sta->drv_unblock_wk); +} +EXPORT_SYMBOL(ieee80211_sta_block_awake); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ccc3adf..4673454 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -12,6 +12,7 @@ #include <linux/list.h> #include <linux/types.h> #include <linux/if_ether.h> +#include <linux/workqueue.h> #include "key.h" /** @@ -21,7 +22,7 @@ * * @WLAN_STA_AUTH: Station is authenticated. * @WLAN_STA_ASSOC: Station is associated. - * @WLAN_STA_PS: Station is in power-save mode + * @WLAN_STA_PS_STA: 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. @@ -36,11 +37,16 @@ * @WLAN_STA_MFP: Management frame protection is used with this STA. * @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle. * Used to deny ADDBA requests (both TX and RX). + * @WLAN_STA_PS_DRIVER: driver requires keeping this station in + * power-save mode logically to flush frames that might still + * be in the queues + * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping + * station in power-save mode, reply when the driver unblocks. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, WLAN_STA_ASSOC = 1<<1, - WLAN_STA_PS = 1<<2, + WLAN_STA_PS_STA = 1<<2, WLAN_STA_AUTHORIZED = 1<<3, WLAN_STA_SHORT_PREAMBLE = 1<<4, WLAN_STA_ASSOC_AP = 1<<5, @@ -48,7 +54,9 @@ enum ieee80211_sta_info_flags { WLAN_STA_WDS = 1<<7, WLAN_STA_CLEAR_PS_FILT = 1<<9, WLAN_STA_MFP = 1<<10, - WLAN_STA_SUSPEND = 1<<11 + WLAN_STA_SUSPEND = 1<<11, + WLAN_STA_PS_DRIVER = 1<<12, + WLAN_STA_PSPOLL = 1<<13, }; #define STA_TID_NUM 16 @@ -193,7 +201,6 @@ struct sta_ampdu_mlme { * @rx_fragments: number of received MPDUs * @rx_dropped: number of dropped MPDUs from this STA * @last_signal: signal of last received frame from this STA - * @last_qual: qual of last received frame from this STA * @last_noise: noise of last received frame from this STA * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) * @tx_filtered_count: number of frames the hardware filtered for this STA @@ -217,6 +224,8 @@ struct sta_ampdu_mlme { * @plink_timer_was_running: used by suspend/resume to restore timers * @debugfs: debug filesystem info * @sta: station information we share with the driver + * @dead: set to true when sta is unlinked + * @drv_unblock_wk used for driver PS unblocking */ struct sta_info { /* General information, mostly static */ @@ -230,8 +239,12 @@ struct sta_info { spinlock_t lock; spinlock_t flaglock; + struct work_struct drv_unblock_wk; + u16 listen_interval; + bool dead; + /* * for use by the internal lifetime management, * see __sta_info_unlink @@ -259,7 +272,6 @@ struct sta_info { unsigned long rx_fragments; unsigned long rx_dropped; int last_signal; - int last_qual; int last_noise; __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; @@ -301,28 +313,6 @@ struct sta_info { #ifdef CONFIG_MAC80211_DEBUGFS struct sta_info_debugfsdentries { struct dentry *dir; - struct dentry *flags; - struct dentry *num_ps_buf_frames; - struct dentry *inactive_ms; - struct dentry *last_seq_ctrl; - struct dentry *agg_status; - struct dentry *aid; - struct dentry *dev; - struct dentry *rx_packets; - struct dentry *tx_packets; - struct dentry *rx_bytes; - struct dentry *tx_bytes; - struct dentry *rx_duplicates; - struct dentry *rx_fragments; - struct dentry *rx_dropped; - struct dentry *tx_fragments; - struct dentry *tx_filtered; - struct dentry *tx_retry_failed; - struct dentry *tx_retry_count; - struct dentry *last_signal; - struct dentry *last_qual; - struct dentry *last_noise; - struct dentry *wep_weak_iv_count; bool add_has_run; } debugfs; #endif @@ -454,4 +444,7 @@ int sta_info_flush(struct ieee80211_local *local, void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); +void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); +void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); + #endif /* STA_INFO_H */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index eaa4118..bfaa43e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -317,12 +317,11 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) if (!atomic_read(&tx->sdata->bss->num_sta_ps)) return TX_CONTINUE; - /* buffered in hardware */ - if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) { - info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + /* device releases frame after DTIM beacon */ + if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) return TX_CONTINUE; - } /* buffered in mac80211 */ if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) @@ -375,7 +374,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) staflags = get_sta_flags(sta); - if (unlikely((staflags & WLAN_STA_PS) && + if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) && !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " @@ -398,8 +397,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) } 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)) + /* + * Queue frame to be sent after STA wakes up/polls, + * but don't set the TIM bit if the driver is blocking + * wakeup or poll response transmissions anyway. + */ + if (skb_queue_empty(&sta->ps_tx_buf) && + !(staflags & WLAN_STA_PS_DRIVER)) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; @@ -409,7 +413,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { + else if (unlikely(staflags & WLAN_STA_PS_STA)) { printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, sta->sta.addr); @@ -1201,23 +1205,25 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) struct sk_buff *skb = tx->skb; ieee80211_tx_result res = TX_DROP; -#define CALL_TXH(txh) \ - res = txh(tx); \ - if (res != TX_CONTINUE) \ - goto txh_done; - - CALL_TXH(ieee80211_tx_h_check_assoc) - CALL_TXH(ieee80211_tx_h_ps_buf) - CALL_TXH(ieee80211_tx_h_select_key) - CALL_TXH(ieee80211_tx_h_michael_mic_add) - CALL_TXH(ieee80211_tx_h_rate_ctrl) - CALL_TXH(ieee80211_tx_h_misc) - CALL_TXH(ieee80211_tx_h_sequence) - CALL_TXH(ieee80211_tx_h_fragment) +#define CALL_TXH(txh) \ + do { \ + res = txh(tx); \ + if (res != TX_CONTINUE) \ + goto txh_done; \ + } while (0) + + CALL_TXH(ieee80211_tx_h_check_assoc); + CALL_TXH(ieee80211_tx_h_ps_buf); + CALL_TXH(ieee80211_tx_h_select_key); + CALL_TXH(ieee80211_tx_h_michael_mic_add); + CALL_TXH(ieee80211_tx_h_rate_ctrl); + CALL_TXH(ieee80211_tx_h_misc); + CALL_TXH(ieee80211_tx_h_sequence); + CALL_TXH(ieee80211_tx_h_fragment); /* handlers after fragment must be aware of tx info fragmentation! */ - CALL_TXH(ieee80211_tx_h_stats) - CALL_TXH(ieee80211_tx_h_encrypt) - CALL_TXH(ieee80211_tx_h_calculate_duration) + CALL_TXH(ieee80211_tx_h_stats); + CALL_TXH(ieee80211_tx_h_encrypt); + CALL_TXH(ieee80211_tx_h_calculate_duration); #undef CALL_TXH txh_done: @@ -1387,6 +1393,30 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, return 0; } +static bool need_dynamic_ps(struct ieee80211_local *local) +{ + /* driver doesn't support power save */ + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) + return false; + + /* hardware does dynamic power save */ + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) + return false; + + /* dynamic power save disabled */ + if (local->hw.conf.dynamic_ps_timeout <= 0) + return false; + + /* we are scanning, don't enable power save */ + if (local->scanning) + return false; + + if (!local->ps_sdata) + return false; + + return true; +} + static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -1399,9 +1429,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_hold(sdata->dev); - if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && - local->hw.conf.dynamic_ps_timeout > 0 && - !(local->scanning) && local->ps_sdata) { + if (need_dynamic_ps(local)) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); @@ -1990,8 +2018,9 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, } } -struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 *tim_offset, u16 *tim_length) { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb = NULL; @@ -2008,6 +2037,11 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); + if (tim_offset) + *tim_offset = 0; + if (tim_length) + *tim_length = 0; + if (sdata->vif.type == NL80211_IFTYPE_AP) { ap = &sdata->u.ap; beacon = rcu_dereference(ap->beacon); @@ -2043,6 +2077,11 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, spin_unlock_irqrestore(&local->sta_lock, flags); } + if (tim_offset) + *tim_offset = beacon->head_len; + if (tim_length) + *tim_length = skb->len - beacon->head_len; + if (beacon->tail) memcpy(skb_put(skb, beacon->tail_len), beacon->tail, beacon->tail_len); @@ -2119,7 +2158,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, rcu_read_unlock(); return skb; } -EXPORT_SYMBOL(ieee80211_beacon_get); +EXPORT_SYMBOL(ieee80211_beacon_get_tim); void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aeb65b3..aedbaaa 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -872,13 +872,14 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, } int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, + enum ieee80211_band band) { struct ieee80211_supported_band *sband; u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; int i; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; pos = buffer; @@ -966,7 +967,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, memcpy(pos, ssid, ssid_len); pos += ssid_len; - skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len)); + skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, + local->hw.conf.channel->band)); ieee80211_tx_skb(sdata, skb, 0); } |