Commit c13ed534 authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'mac80211-next-for-davem-2016-09-16' of...

Merge tag 'mac80211-next-for-davem-2016-09-16' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next



Johannes Berg says:

====================
This time we have various things - all across the board:
 * MU-MIMO sniffer support in mac80211
 * a create_singlethread_workqueue() cleanup
 * interface dump filtering that was documented but not implemented
 * support for the new radiotap timestamp field
 * send delBA in two unexpected conditions (as required by the spec)
 * connect keys cleanups - allow only WEP with index 0-3
 * per-station aggregation limit to work around broken APs
 * debugfs improvement for the integrated codel algorithm
and various other small improvements and cleanups.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 22da7349 fbd05e4a
......@@ -487,7 +487,7 @@ static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
};
static spinlock_t hwsim_radio_lock;
static struct list_head hwsim_radios;
static LIST_HEAD(hwsim_radios);
static int hwsim_radio_idx;
static struct platform_driver mac80211_hwsim_driver = {
......@@ -3376,7 +3376,6 @@ static int __init init_mac80211_hwsim(void)
mac80211_hwsim_unassign_vif_chanctx;
spin_lock_init(&hwsim_radio_lock);
INIT_LIST_HEAD(&hwsim_radios);
err = register_pernet_device(&hwsim_net_ops);
if (err)
......
......@@ -2432,7 +2432,8 @@ struct cfg80211_qos_map {
* cases, the result of roaming is indicated with a call to
* cfg80211_roamed() or cfg80211_roamed_bss().
* (invoked with the wireless_dev mutex held)
* @disconnect: Disconnect from the BSS/ESS.
* @disconnect: Disconnect from the BSS/ESS. Once done, call
* cfg80211_disconnected().
* (invoked with the wireless_dev mutex held)
*
* @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
......@@ -3954,6 +3955,34 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
unsigned int cfg80211_classify8021d(struct sk_buff *skb,
struct cfg80211_qos_map *qos_map);
/**
* cfg80211_find_ie_match - match information element and byte array in data
*
* @eid: element ID
* @ies: data consisting of IEs
* @len: length of data
* @match: byte array to match
* @match_len: number of bytes in the match array
* @match_offset: offset in the IE where the byte array should match.
* If match_len is zero, this must also be set to zero.
* Otherwise this must be set to 2 or more, because the first
* byte is the element id, which is already compared to eid, and
* the second byte is the IE length.
*
* Return: %NULL if the element ID could not be found or if
* the element is invalid (claims to be longer than the given
* data) or if the byte array doesn't match, or a pointer to the first
* byte of the requested element, that is the byte containing the
* element ID.
*
* Note: There are no checks on the element length other than
* having to fit into the given data and being large enough for the
* byte array to match.
*/
const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
const u8 *match, int match_len,
int match_offset);
/**
* cfg80211_find_ie - find information element in data
*
......@@ -3969,7 +3998,10 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
* Note: There are no checks on the element length other than
* having to fit into the given data.
*/
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
static inline const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
{
return cfg80211_find_ie_match(eid, ies, len, NULL, 0, 0);
}
/**
* cfg80211_find_vendor_ie - find vendor specific information element in data
......
......@@ -190,6 +190,10 @@ struct ieee80211_radiotap_header {
* IEEE80211_RADIOTAP_VHT u16, u8, u8, u8[4], u8, u8, u16
*
* Contains VHT information about this frame.
*
* IEEE80211_RADIOTAP_TIMESTAMP u64, u16, u8, u8 variable
*
* Contains timestamp information for this frame.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
......@@ -214,6 +218,7 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_MCS = 19,
IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
IEEE80211_RADIOTAP_VHT = 21,
IEEE80211_RADIOTAP_TIMESTAMP = 22,
/* valid in every it_present bitmap, even vendor namespaces */
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
......@@ -321,6 +326,22 @@ enum ieee80211_radiotap_type {
#define IEEE80211_RADIOTAP_CODING_LDPC_USER2 0x04
#define IEEE80211_RADIOTAP_CODING_LDPC_USER3 0x08
/* For IEEE80211_RADIOTAP_TIMESTAMP */
#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK 0x000F
#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS 0x0000
#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US 0x0001
#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS 0x0003
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK 0x00F0
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU 0x0000
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU 0x0010
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU 0x0020
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ 0x0030
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN 0x00F0
#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT 0x00
#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT 0x01
#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY 0x02
/* helpers */
static inline int ieee80211_get_radiotap_len(unsigned char *data)
{
......
......@@ -1735,6 +1735,9 @@ struct ieee80211_sta_rates {
* @supp_rates: Bitmap of supported rates (per band)
* @ht_cap: HT capabilities of this STA; restricted to our own capabilities
* @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
* @max_rx_aggregation_subframes: maximal amount of frames in a single AMPDU
* that this station is allowed to transmit to us.
* Can be modified by driver.
* @wme: indicates whether the STA supports QoS/WME (if local devices does,
* otherwise always false)
* @drv_priv: data area for driver use, will always be aligned to
......@@ -1775,6 +1778,7 @@ struct ieee80211_sta {
u16 aid;
struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap;
u8 max_rx_aggregation_subframes;
bool wme;
u8 uapsd_queues;
u8 max_sp;
......@@ -2014,6 +2018,11 @@ struct ieee80211_txq {
* @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list
* skbs, needed for zero-copy software A-MSDU.
*
* @IEEE80211_HW_REPORTS_LOW_ACK: The driver (or firmware) reports low ack event
* by ieee80211_report_low_ack() based on its own algorithm. For such
* drivers, mac80211 packet loss mechanism will not be triggered and driver
* is completely depending on firmware event for station kickout.
*
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
......@@ -2054,6 +2063,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_USES_RSS,
IEEE80211_HW_TX_AMSDU,
IEEE80211_HW_TX_FRAG_LIST,
IEEE80211_HW_REPORTS_LOW_ACK,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
......@@ -2141,6 +2151,14 @@ enum ieee80211_hw_flags {
* the default is _GI | _BANDWIDTH.
* Use the %IEEE80211_RADIOTAP_VHT_KNOWN_* values.
*
* @radiotap_timestamp: Information for the radiotap timestamp field; if the
* 'units_pos' member is set to a non-negative value it must be set to
* a combination of a IEEE80211_RADIOTAP_TIMESTAMP_UNIT_* and a
* IEEE80211_RADIOTAP_TIMESTAMP_SPOS_* value, and then the timestamp
* field will be added and populated from the &struct ieee80211_rx_status
* device_timestamp. If the 'accuracy' member is non-negative, it's put
* into the accuracy radiotap field and the accuracy known flag is set.
*
* @netdev_features: netdev features to be set in each netdev created
* from this HW. Note that not all features are usable with mac80211,
* other features will be rejected during HW registration.
......@@ -2184,6 +2202,10 @@ struct ieee80211_hw {
u8 offchannel_tx_hw_queue;
u8 radiotap_mcs_details;
u16 radiotap_vht_details;
struct {
int units_pos;
s16 accuracy;
} radiotap_timestamp;
netdev_features_t netdev_features;
u8 uapsd_queues;
u8 uapsd_max_sp_len;
......@@ -3085,11 +3107,8 @@ enum ieee80211_reconfig_type {
*
* @sta_add_debugfs: Drivers can use this callback to add debugfs files
* when a station is added to mac80211's station list. This callback
* and @sta_remove_debugfs should be within a CONFIG_MAC80211_DEBUGFS
* conditional. This callback can sleep.
*
* @sta_remove_debugfs: Remove the debugfs files which were added using
* @sta_add_debugfs. This callback can sleep.
* should be within a CONFIG_MAC80211_DEBUGFS conditional. This
* callback can sleep.
*
* @sta_notify: Notifies low level driver about power state transition of an
* associated station, AP, IBSS/WDS/mesh peer etc. For a VIF operating
......@@ -3485,10 +3504,6 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
void (*sta_remove_debugfs)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
#endif
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd, struct ieee80211_sta *sta);
......
......@@ -298,10 +298,13 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
buf_size = IEEE80211_MAX_AMPDU_BUF;
/* make sure the size doesn't exceed the maximum supported by the hw */
if (buf_size > local->hw.max_rx_aggregation_subframes)
buf_size = local->hw.max_rx_aggregation_subframes;
if (buf_size > sta->sta.max_rx_aggregation_subframes)
buf_size = sta->sta.max_rx_aggregation_subframes;
params.buf_size = buf_size;
ht_dbg(sta->sdata, "AddBA Req buf_size=%d for %pM\n",
buf_size, sta->sta.addr);
/* examine state machine */
mutex_lock(&sta->ampdu_mlme.mtx);
......@@ -406,8 +409,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
}
end:
if (status == WLAN_STATUS_SUCCESS)
if (status == WLAN_STATUS_SUCCESS) {
__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
}
mutex_unlock(&sta->ampdu_mlme.mtx);
end_no_lock:
......
......@@ -39,7 +39,7 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
if (type == NL80211_IFTYPE_MONITOR && flags) {
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
sdata->u.mntr_flags = *flags;
sdata->u.mntr.flags = *flags;
}
return wdev;
......@@ -73,8 +73,29 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
sdata->u.mgd.use_4addr = params->use_4addr;
}
if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *monitor_sdata;
u32 mu_mntr_cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
monitor_sdata = rtnl_dereference(local->monitor_sdata);
if (monitor_sdata &&
wiphy_ext_feature_isset(wiphy, mu_mntr_cap_flag)) {
memcpy(monitor_sdata->vif.bss_conf.mu_group.membership,
params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN);
memcpy(monitor_sdata->vif.bss_conf.mu_group.position,
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
WLAN_USER_POSITION_LEN);
monitor_sdata->vif.mu_mimo_owner = true;
ieee80211_bss_info_change_notify(monitor_sdata,
BSS_CHANGED_MU_GROUPS);
ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr,
params->macaddr);
}
if (!flags)
return 0;
if (ieee80211_sdata_running(sdata)) {
u32 mask = MONITOR_FLAG_COOK_FRAMES |
......@@ -89,11 +110,11 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
* cooked_mntrs, monitor and all fif_* counters
* reconfigure hardware
*/
if ((*flags & mask) != (sdata->u.mntr_flags & mask))
if ((*flags & mask) != (sdata->u.mntr.flags & mask))
return -EBUSY;
ieee80211_adjust_monitor_flags(sdata, -1);
sdata->u.mntr_flags = *flags;
sdata->u.mntr.flags = *flags;
ieee80211_adjust_monitor_flags(sdata, 1);
ieee80211_configure_filter(local);
......@@ -103,7 +124,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
* and ieee80211_do_open take care of "everything"
* mentioned in the comment above.
*/
sdata->u.mntr_flags = *flags;
sdata->u.mntr.flags = *flags;
}
}
......@@ -2940,10 +2961,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
}
chanctx = container_of(conf, struct ieee80211_chanctx, conf);
if (!chanctx) {
err = -EBUSY;
goto out;
}
ch_switch.timestamp = 0;
ch_switch.device_timestamp = 0;
......
......@@ -71,138 +71,39 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
struct aqm_info {
struct ieee80211_local *local;
size_t size;
size_t len;
unsigned char buf[0];
};
#define AQM_HDR_LEN 200
#define AQM_HW_ENTRY_LEN 40
#define AQM_TXQ_ENTRY_LEN 110
static int aqm_open(struct inode *inode, struct file *file)
static ssize_t aqm_read(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct ieee80211_local *local = inode->i_private;
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct txq_info *txqi;
struct ieee80211_local *local = file->private_data;
struct fq *fq = &local->fq;
struct aqm_info *info = NULL;
char buf[200];
int len = 0;
int i;
if (!local->ops->wake_tx_queue)
return -EOPNOTSUPP;
len += AQM_HDR_LEN;
len += 6 * AQM_HW_ENTRY_LEN;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
len += AQM_TXQ_ENTRY_LEN;
list_for_each_entry_rcu(sta, &local->sta_list, list)
len += AQM_TXQ_ENTRY_LEN * ARRAY_SIZE(sta->sta.txq);
rcu_read_unlock();
info = vmalloc(len);
if (!info)
return -ENOMEM;
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
file->private_data = info;
info->local = local;
info->size = len;
len = 0;
len += scnprintf(info->buf + len, info->size - len,
"* hw\n"
"access name value\n"
"R fq_flows_cnt %u\n"
"R fq_backlog %u\n"
"R fq_overlimit %u\n"
"R fq_collisions %u\n"
"RW fq_limit %u\n"
"RW fq_quantum %u\n",
fq->flows_cnt,
fq->backlog,
fq->overlimit,
fq->collisions,
fq->limit,
fq->quantum);
len += scnprintf(info->buf + len,
info->size - len,
"* vif\n"
"ifname addr ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
txqi = to_txq_info(sdata->vif.txq);
len += scnprintf(info->buf + len, info->size - len,
"%s %pM %u %u %u %u %u %u %u %u\n",
sdata->name,
sdata->vif.addr,
txqi->txq.ac,
txqi->tin.backlog_bytes,
txqi->tin.backlog_packets,
txqi->tin.flows,
txqi->tin.overlimit,
txqi->tin.collisions,
txqi->tin.tx_bytes,
txqi->tin.tx_packets);
}
len += scnprintf(info->buf + len,
info->size - len,
"* sta\n"
"ifname addr tid ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
list_for_each_entry_rcu(sta, &local->sta_list, list) {
sdata = sta->sdata;
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
txqi = to_txq_info(sta->sta.txq[i]);
len += scnprintf(info->buf + len, info->size - len,
"%s %pM %d %d %u %u %u %u %u %u %u\n",
sdata->name,
sta->sta.addr,
txqi->txq.tid,
txqi->txq.ac,
txqi->tin.backlog_bytes,
txqi->tin.backlog_packets,
txqi->tin.flows,
txqi->tin.overlimit,
txqi->tin.collisions,
txqi->tin.tx_bytes,
txqi->tin.tx_packets);
}
}
info->len = len;
len = scnprintf(buf, sizeof(buf),
"access name value\n"
"R fq_flows_cnt %u\n"
"R fq_backlog %u\n"
"R fq_overlimit %u\n"
"R fq_collisions %u\n"
"RW fq_limit %u\n"
"RW fq_quantum %u\n",
fq->flows_cnt,
fq->backlog,
fq->overlimit,
fq->collisions,
fq->limit,
fq->quantum);
rcu_read_unlock();
spin_unlock_bh(&local->fq.lock);
return 0;
}
static int aqm_release(struct inode *inode, struct file *file)
{
vfree(file->private_data);
return 0;
}
static ssize_t aqm_read(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct aqm_info *info = file->private_data;
return simple_read_from_buffer(user_buf, count, ppos,
info->buf, info->len);
buf, len);
}
static ssize_t aqm_write(struct file *file,
......@@ -210,8 +111,7 @@ static ssize_t aqm_write(struct file *file,
size_t count,
loff_t *ppos)
{
struct aqm_info *info = file->private_data;
struct ieee80211_local *local = info->local;
struct ieee80211_local *local = file->private_data;
char buf[100];
size_t len;
......@@ -237,8 +137,7 @@ static ssize_t aqm_write(struct file *file,
static const struct file_operations aqm_ops = {
.write = aqm_write,
.read = aqm_read,
.open = aqm_open,
.release = aqm_release,
.open = simple_open,
.llseek = default_llseek,
};
......@@ -302,6 +201,7 @@ static const char *hw_flag_names[] = {
FLAG(USES_RSS),
FLAG(TX_AMSDU),
FLAG(TX_FRAG_LIST),
FLAG(REPORTS_LOW_ACK),
#undef FLAG
};
......@@ -428,7 +328,9 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power);
DEBUGFS_ADD_MODE(aqm, 0600);
if (local->ops->wake_tx_queue)
DEBUGFS_ADD_MODE(aqm, 0600);
statsd = debugfs_create_dir("statistics", phyd);
......
......@@ -30,7 +30,7 @@ static ssize_t ieee80211_if_read(
size_t count, loff_t *ppos,
ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
{
char buf[70];
char buf[200];
ssize_t ret = -EINVAL;
read_lock(&dev_base_lock);
......@@ -486,6 +486,38 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
}
IEEE80211_IF_FILE_R(num_buffered_multicast);
static ssize_t ieee80211_if_fmt_aqm(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
struct ieee80211_local *local = sdata->local;
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
int len;
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
len = scnprintf(buf,
buflen,
"ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"
"%u %u %u %u %u %u %u %u %u %u\n",
txqi->txq.ac,
txqi->tin.backlog_bytes,
txqi->tin.backlog_packets,
txqi->tin.flows,
txqi->cstats.drop_count,
txqi->cstats.ecn_mark,
txqi->tin.overlimit,
txqi->tin.collisions,
txqi->tin.tx_bytes,
txqi->tin.tx_packets);
rcu_read_unlock();
spin_unlock_bh(&local->fq.lock);
return len;
}
IEEE80211_IF_FILE_R(aqm);
/* IBSS attributes */
static ssize_t ieee80211_if_fmt_tsf(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
......@@ -618,6 +650,9 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
DEBUGFS_ADD(hw_queues);
if (sdata->local->ops->wake_tx_queue)
DEBUGFS_ADD(aqm);
}
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
......
......@@ -133,6 +133,55 @@ static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
}
STA_OPS(last_seq_ctrl);
#define AQM_TXQ_ENTRY_LEN 130
static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct sta_info *sta = file->private_data;
struct ieee80211_local *local = sta->local;
size_t bufsz = AQM_TXQ_ENTRY_LEN*(IEEE80211_NUM_TIDS+1);
char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
struct txq_info *txqi;
ssize_t rv;
int i;
if (!buf)
return -ENOMEM;
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
p += scnprintf(p,
bufsz+buf-p,
"tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n");
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
txqi = to_txq_info(sta->sta.txq[i]);
p += scnprintf(p, bufsz+buf-p,
"%d %d %u %u %u %u %u %u %u %u %u\n",
txqi->txq.tid,
txqi->txq.ac,
txqi->tin.backlog_bytes,
txqi->tin.backlog_packets,
txqi->tin.flows,
txqi->cstats.drop_count,
txqi->cstats.ecn_mark,
txqi->tin.overlimit,
txqi->tin.collisions,
txqi->tin.tx_bytes,
txqi->tin.tx_packets);
}
rcu_read_unlock();
spin_unlock_bh(&local->fq.lock);
rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
kfree(buf);
return rv;
}
STA_OPS(aqm);
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
......@@ -478,6 +527,9 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered);
if (local->ops->wake_tx_queue)
DEBUGFS_ADD(aqm);
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
debugfs_create_x32("driver_buffered_tids", 0400,
sta->debugfs_dir,
......@@ -492,10 +544,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)