From f4bda337bbb6e245e2a07f344990adeb6a70ff35 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 13 Nov 2012 10:46:27 -0800 Subject: mac80211: support RX_FLAG_MACTIME_END Allow drivers to indicate their mactime is at RX completion and adjust for this in mac80211. Also rename the existing RX_FLAG_MACTIME_MPDU to RX_FLAG_MACTIME_START to clarify its intent. Based on similar code by Johannes Berg. Signed-off-by: Thomas Pedersen [fix docs, atheros drivers] Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 29 +++++--------------------- net/mac80211/ieee80211_i.h | 11 ++++++++++ net/mac80211/mesh_sync.c | 44 +++++++-------------------------------- net/mac80211/rx.c | 14 ++++++++++--- net/mac80211/util.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 64 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c7386b2b767e..cc11558d8c1a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -543,30 +543,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) goto put_bss; - if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { - /* - * 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; - - if (rx_status->flag & RX_FLAG_HT) - rate = 65; /* TODO: HT rates */ - else - rate = local->hw.wiphy->bands[band]-> - bitrates[rx_status->rate_idx].bitrate; - - rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); + if (ieee80211_have_rx_timestamp(rx_status)) { + /* time when timestamp field was received */ + rx_timestamp = + ieee80211_calculate_rx_timestamp(local, rx_status, + len + FCS_LEN, 24); } else { /* * second best option: get current TSF diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e1fb97cc9a41..bff82a8e62f3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1259,7 +1259,18 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) is_broadcast_ether_addr(raddr); } +static inline bool +ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) +{ + WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && + status->flag & RX_FLAG_MACTIME_END); + return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END); +} +u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, + struct ieee80211_rx_status *status, + unsigned int mpdu_len, + unsigned int mpdu_offset); int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 407c8705e10d..9c6ea9cfe1b3 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -116,43 +116,13 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, goto no_sync; } - if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) { - /* - * The 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) - * - * T_r, in 13.13.2.2.2, is just defined as "the frame reception - * time" but we unless we interpret that time to be the same - * time of the beacon timestamp, the offset calculation will be - * off. Below we adjust t_r to be "the time at which the first - * symbol of the timestamp element in the beacon is received". - * This correction depends on the rate. - * - * Based on similar code in ibss.c - */ - int rate; - - if (rx_status->flag & RX_FLAG_HT) { - /* TODO: - * In principle there could be HT-beacons (Dual Beacon - * HT Operation options), but for now ignore them and - * just use the primary (i.e. non-HT) beacons for - * synchronization. - * */ - goto no_sync; - } else - rate = local->hw.wiphy->bands[rx_status->band]-> - bitrates[rx_status->rate_idx].bitrate; - - /* 24 bytes of header * 8 bits/byte * - * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/ - t_r = rx_status->mactime + (24 * 8 * 10 / rate); - } + if (ieee80211_have_rx_timestamp(rx_status)) + /* time when timestamp field was received */ + t_r = ieee80211_calculate_rx_timestamp(local, rx_status, + 24 + 12 + + elems->total_len + + FCS_LEN, + 24); /* Timing offset calculation (see 13.13.2.2.2) */ t_t = le64_to_cpu(mgmt->u.beacon.timestamp); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6ad330341b71..e3daee8fdf7a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -81,7 +81,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, /* always present fields */ len = sizeof(struct ieee80211_radiotap_header) + 9; - if (status->flag & RX_FLAG_MACTIME_MPDU) + if (ieee80211_have_rx_timestamp(status)) len += 8; if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) len += 1; @@ -117,6 +117,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct ieee80211_radiotap_header *rthdr; unsigned char *pos; u16 rx_flags = 0; + int mpdulen; + + mpdulen = skb->len; + if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) + mpdulen += FCS_LEN; rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); memset(rthdr, 0, rtap_len); @@ -134,8 +139,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* the order of the following fields is important */ /* IEEE80211_RADIOTAP_TSFT */ - if (status->flag & RX_FLAG_MACTIME_MPDU) { - put_unaligned_le64(status->mactime, pos); + if (ieee80211_have_rx_timestamp(status)) { + put_unaligned_le64( + ieee80211_calculate_rx_timestamp(local, status, + mpdulen, 0), + pos); rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); pos += 8; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4e4f58513673..5bad758abfb3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2013,3 +2013,54 @@ u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs) return 2; return 1; } + +/** + * ieee80211_calculate_rx_timestamp - calculate timestamp in frame + * @local: mac80211 hw info struct + * @status: RX status + * @mpdu_len: total MPDU length (including FCS) + * @mpdu_offset: offset into MPDU to calculate timestamp at + * + * This function calculates the RX timestamp at the given MPDU offset, taking + * into account what the RX timestamp was. An offset of 0 will just normalize + * the timestamp to TSF at beginning of MPDU reception. + */ +u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, + struct ieee80211_rx_status *status, + unsigned int mpdu_len, + unsigned int mpdu_offset) +{ + u64 ts = status->mactime; + struct rate_info ri; + u16 rate; + + if (WARN_ON(!ieee80211_have_rx_timestamp(status))) + return 0; + + memset(&ri, 0, sizeof(ri)); + + /* Fill cfg80211 rate info */ + if (status->flag & RX_FLAG_HT) { + ri.mcs = status->rate_idx; + ri.flags |= RATE_INFO_FLAGS_MCS; + if (status->flag & RX_FLAG_40MHZ) + ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (status->flag & RX_FLAG_SHORT_GI) + ri.flags |= RATE_INFO_FLAGS_SHORT_GI; + } else { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[status->band]; + ri.legacy = sband->bitrates[status->rate_idx].bitrate; + } + + rate = cfg80211_calculate_bitrate(&ri); + + /* rewind from end of MPDU */ + if (status->flag & RX_FLAG_MACTIME_END) + ts -= mpdu_len * 8 * 10 / rate; + + ts += mpdu_offset * 8 * 10 / rate; + + return ts; +} -- cgit v1.2.1 From f0dea9c73a16caac6b46886eb08f51dd82894ca4 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Mon, 19 Nov 2012 12:01:05 +0100 Subject: mac80211: check add_chanctx callback before use in ieee80211_reconfig During testing our mac80211 driver a fatal error occurred which was signalled to mac80211. Upon performing the reconfiguration of the device a WARN_ON was triggered. This warning checked the return value of drv_add_chanctx(). However, this returns -EOPNOTSUPP when the driver does not provide the callback. As the callback is optional better check it is defined before calling drv_add_chanctx(). Signed-off-by: Arend van Spriel Signed-off-by: Johannes Berg --- net/mac80211/util.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5bad758abfb3..7fb55bf6561e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1417,10 +1417,12 @@ int ieee80211_reconfig(struct ieee80211_local *local) } /* add channel contexts */ - mutex_lock(&local->chanctx_mtx); - list_for_each_entry(ctx, &local->chanctx_list, list) - WARN_ON(drv_add_chanctx(local, ctx)); - mutex_unlock(&local->chanctx_mtx); + if (local->use_chanctx) { + mutex_lock(&local->chanctx_mtx); + list_for_each_entry(ctx, &local->chanctx_list, list) + WARN_ON(drv_add_chanctx(local, ctx)); + mutex_unlock(&local->chanctx_mtx); + } list_for_each_entry(sdata, &local->interfaces, list) { struct ieee80211_chanctx_conf *ctx_conf; -- cgit v1.2.1 From 0f92732344e88023807342fef4c566e0660c2fd9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Nov 2012 23:15:11 +0100 Subject: mac80211: use CMAC_PN_LEN Instead of hardcoding its value (6), use the constant. Signed-off-by: Johannes Berg --- net/mac80211/key.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d27e61aaa71b..0f18ef59392d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -372,8 +372,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, key->conf.iv_len = 0; key->conf.icv_len = sizeof(struct ieee80211_mmie); if (seq) - for (j = 0; j < 6; j++) - key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; + for (j = 0; j < CMAC_PN_LEN; j++) + key->u.aes_cmac.rx_pn[j] = + seq[CMAC_PN_LEN - j - 1]; /* * Initialize AES key state here as an optimization so that * it does not need to be initialized for every packet. -- cgit v1.2.1 From 5a306f5887d5fd840beb8ea872897fa89e8fcdef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Nov 2012 23:22:21 +0100 Subject: mac80211: introduce IEEE80211_NUM_TIDS and use it Introduce IEEE80211_NUM_TIDS in the generic 802.11 header file and use it in place of STA_TID_NUM and NUM_RX_DATA_QUEUES which are both really the number of TIDs. Signed-off-by: Johannes Berg --- net/mac80211/agg-rx.c | 2 +- net/mac80211/agg-tx.c | 12 ++++++------ net/mac80211/debugfs_key.c | 6 +++--- net/mac80211/debugfs_sta.c | 10 +++++----- net/mac80211/ht.c | 4 ++-- net/mac80211/key.c | 10 +++++----- net/mac80211/key.h | 8 +++----- net/mac80211/rx.c | 4 ++-- net/mac80211/sta_info.c | 10 +++++----- net/mac80211/sta_info.h | 19 +++++++++---------- 10 files changed, 41 insertions(+), 44 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 186d9919b043..808338a1bce5 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -118,7 +118,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, return; } - for (i = 0; i < STA_TID_NUM; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) if (ba_rx_bitmap & BIT(i)) set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 3195a6307f50..4152ed1034b8 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -448,7 +448,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; - if ((tid >= STA_TID_NUM) || + if ((tid >= IEEE80211_NUM_TIDS) || !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) || (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) return -EINVAL; @@ -605,9 +605,9 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) trace_api_start_tx_ba_cb(sdata, ra, tid); - if (tid >= STA_TID_NUM) { + if (tid >= IEEE80211_NUM_TIDS) { ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); + tid, IEEE80211_NUM_TIDS); return; } @@ -687,7 +687,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) if (!local->ops->ampdu_action) return -EINVAL; - if (tid >= STA_TID_NUM) + if (tid >= IEEE80211_NUM_TIDS) return -EINVAL; spin_lock_bh(&sta->lock); @@ -722,9 +722,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) trace_api_stop_tx_ba_cb(sdata, ra, tid); - if (tid >= STA_TID_NUM) { + if (tid >= IEEE80211_NUM_TIDS) { ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); + tid, IEEE80211_NUM_TIDS); return; } diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 090d08ff22c4..2d4235497f1b 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -116,7 +116,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct ieee80211_key *key = file->private_data; - char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf; + char buf[14*IEEE80211_NUM_TIDS+1], *p = buf; int i, len; const u8 *rpn; @@ -126,7 +126,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, len = scnprintf(buf, sizeof(buf), "\n"); break; case WLAN_CIPHER_SUITE_TKIP: - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%08x %04x\n", key->u.tkip.rx[i].iv32, @@ -134,7 +134,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, len = p - buf; break; case WLAN_CIPHER_SUITE_CCMP: - for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { rpn = key->u.ccmp.rx_pn[i]; p += scnprintf(p, sizeof(buf)+buf-p, "%02x%02x%02x%02x%02x%02x\n", diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 5ccec2c1e9f6..3d103929d41a 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -131,10 +131,10 @@ STA_OPS(connected_time); static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[15*NUM_RX_DATA_QUEUES], *p = buf; + char buf[15*IEEE80211_NUM_TIDS], *p = buf; int i; struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%x ", le16_to_cpu(sta->last_seq_ctrl[i])); p += scnprintf(p, sizeof(buf)+buf-p, "\n"); @@ -145,7 +145,7 @@ STA_OPS(last_seq_ctrl); static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[71 + STA_TID_NUM * 40], *p = buf; + char buf[71 + IEEE80211_NUM_TIDS * 40], *p = buf; int i; struct sta_info *sta = file->private_data; struct tid_ampdu_rx *tid_rx; @@ -158,7 +158,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf) + buf - p, "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); @@ -220,7 +220,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu tid = simple_strtoul(buf, NULL, 0); - if (tid >= STA_TID_NUM) + if (tid >= IEEE80211_NUM_TIDS) return -EINVAL; if (tx) { diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4b4538d63925..a71d891794a4 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -185,7 +185,7 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) cancel_work_sync(&sta->ampdu_mlme.work); - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, WLAN_REASON_QSTA_LEAVE_QBSS, tx); @@ -209,7 +209,7 @@ void ieee80211_ba_session_work(struct work_struct *work) return; mutex_lock(&sta->ampdu_mlme.mtx); - for (tid = 0; tid < STA_TID_NUM; tid++) { + for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) ___ieee80211_stop_rx_ba_session( sta, tid, WLAN_BACK_RECIPIENT, diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 0f18ef59392d..619c5d697999 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -339,7 +339,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, key->conf.iv_len = TKIP_IV_LEN; key->conf.icv_len = TKIP_ICV_LEN; if (seq) { - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { key->u.tkip.rx[i].iv32 = get_unaligned_le32(&seq[2]); key->u.tkip.rx[i].iv16 = @@ -352,7 +352,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, key->conf.iv_len = CCMP_HDR_LEN; key->conf.icv_len = CCMP_MIC_LEN; if (seq) { - for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) + for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) for (j = 0; j < CCMP_PN_LEN; j++) key->u.ccmp.rx_pn[i][j] = seq[CCMP_PN_LEN - j - 1]; @@ -655,16 +655,16 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, switch (key->conf.cipher) { case WLAN_CIPHER_SUITE_TKIP: - if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES)) + if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS)) return; seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; break; case WLAN_CIPHER_SUITE_CCMP: - if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES)) + if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) return; if (tid < 0) - pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES]; + pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS]; else pn = key->u.ccmp.rx_pn[tid]; memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 7d4e31f037d7..7cff0d3a519c 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -30,8 +30,6 @@ #define TKIP_ICV_LEN 4 #define CMAC_PN_LEN 6 -#define NUM_RX_DATA_QUEUES 16 - struct ieee80211_local; struct ieee80211_sub_if_data; struct sta_info; @@ -82,17 +80,17 @@ struct ieee80211_key { struct tkip_ctx tx; /* last received RSC */ - struct tkip_ctx rx[NUM_RX_DATA_QUEUES]; + struct tkip_ctx rx[IEEE80211_NUM_TIDS]; } tkip; struct { atomic64_t tx_pn; /* * Last received packet number. The first - * NUM_RX_DATA_QUEUES counters are used with Data + * IEEE80211_NUM_TIDS counters are used with Data * frames and the last counter is used with Robust * Management frames. */ - u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN]; + u8 rx_pn[IEEE80211_NUM_TIDS + 1][CCMP_PN_LEN]; struct crypto_cipher *tfm; u32 replays; /* dot11RSNAStatsCCMPReplays */ } ccmp; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e3daee8fdf7a..8480bbf1a707 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -408,10 +408,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) * * We also use that counter for non-QoS STAs. */ - seqno_idx = NUM_RX_DATA_QUEUES; + seqno_idx = IEEE80211_NUM_TIDS; security_idx = 0; if (ieee80211_is_mgmt(hdr->frame_control)) - security_idx = NUM_RX_DATA_QUEUES; + security_idx = IEEE80211_NUM_TIDS; tid = 0; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f7bb54f9ab72..a0836d7187c1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -142,7 +142,7 @@ static void free_sta_work(struct work_struct *wk) * drivers have to handle aggregation stop being requested, followed * directly by station destruction. */ - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); if (!tid_tx) continue; @@ -330,7 +330,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, return NULL; } - for (i = 0; i < STA_TID_NUM; i++) { + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { /* * timer_to_tid must be initialized with identity mapping * to enable session_timer's data differentiation. See @@ -343,7 +343,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, skb_queue_head_init(&sta->tx_filtered[i]); } - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) + for (i = 0; i < IEEE80211_NUM_TIDS; i++) sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); @@ -985,7 +985,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) clear_sta_flag(sta, WLAN_STA_SP); - BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1); + BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); sta->driver_buffered_tids = 0; if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) @@ -1369,7 +1369,7 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); - if (WARN_ON(tid >= STA_TID_NUM)) + if (WARN_ON(tid >= IEEE80211_NUM_TIDS)) return; if (buffered) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c88f161f8118..776f3d0b4a47 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -80,7 +80,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_TOFFSET_KNOWN, }; -#define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ #define HT_AGG_MAX_RETRIES 15 #define HT_AGG_BURST_RETRIES 3 @@ -197,15 +196,15 @@ struct tid_ampdu_rx { struct sta_ampdu_mlme { struct mutex mtx; /* rx */ - struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; - unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; - unsigned long tid_rx_stop_requested[BITS_TO_LONGS(STA_TID_NUM)]; + struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; + unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; + unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; /* tx */ struct work_struct work; - struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; - struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; - unsigned long last_addba_req_time[STA_TID_NUM]; - u8 addba_req_num[STA_TID_NUM]; + struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; + struct tid_ampdu_tx *tid_start_tx[IEEE80211_NUM_TIDS]; + unsigned long last_addba_req_time[IEEE80211_NUM_TIDS]; + u8 addba_req_num[IEEE80211_NUM_TIDS]; u8 dialog_token_allocator; }; @@ -330,7 +329,7 @@ struct sta_info { int last_signal; struct ewma avg_signal; /* Plus 1 for non-QoS frames */ - __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1]; + __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; /* Updated from TX status path only, no locking requirements */ unsigned long tx_filtered_count; @@ -351,7 +350,7 @@ struct sta_info { * Aggregation information, locked with lock. */ struct sta_ampdu_mlme ampdu_mlme; - u8 timer_to_tid[STA_TID_NUM]; + u8 timer_to_tid[IEEE80211_NUM_TIDS]; #ifdef CONFIG_MAC80211_MESH /* -- cgit v1.2.1 From 90b9e446fbb64630c72cab48c007d7081aec2533 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Nov 2012 10:09:08 +0100 Subject: mac80211: support radiotap vendor namespace RX data In some cases, in particular for experimentation, it can be useful to be able to add vendor namespace data to received frames in addition to the normal radiotap data. Allow doing this through mac80211 by adding fields to the RX status descriptor that describe the data while the data itself is prepended to the frame. Also add some example code to hwsim, but don't enable it because it doesn't use a proper OUI identifier. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 71 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 12 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8480bbf1a707..ec15a4929f7a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -40,6 +40,8 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, struct sk_buff *skb) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { if (likely(skb->len > FCS_LEN)) __pskb_trim(skb, skb->len - FCS_LEN); @@ -51,6 +53,9 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, } } + if (status->vendor_radiotap_len) + __pskb_pull(skb, status->vendor_radiotap_len); + return skb; } @@ -73,32 +78,48 @@ static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) } static int -ieee80211_rx_radiotap_len(struct ieee80211_local *local, - struct ieee80211_rx_status *status) +ieee80211_rx_radiotap_space(struct ieee80211_local *local, + struct ieee80211_rx_status *status) { int len; /* always present fields */ len = sizeof(struct ieee80211_radiotap_header) + 9; - if (ieee80211_have_rx_timestamp(status)) + /* allocate extra bitmap */ + if (status->vendor_radiotap_len) + len += 4; + + if (ieee80211_have_rx_timestamp(status)) { + len = ALIGN(len, 8); len += 8; + } if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) len += 1; - if (len & 1) /* padding for RX_FLAGS if necessary */ - len++; + /* padding for RX_FLAGS if necessary */ + len = ALIGN(len, 2); if (status->flag & RX_FLAG_HT) /* HT info */ len += 3; if (status->flag & RX_FLAG_AMPDU_DETAILS) { - /* padding */ - while (len & 3) - len++; + len = ALIGN(len, 4); len += 8; } + if (status->vendor_radiotap_len) { + if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) + status->vendor_radiotap_align = 1; + /* align standard part of vendor namespace */ + len = ALIGN(len, 2); + /* allocate standard part of vendor namespace */ + len += 6; + /* align vendor-defined part */ + len = ALIGN(len, status->vendor_radiotap_align); + /* vendor-defined part is already in skb */ + } + return len; } @@ -132,14 +153,25 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_ANTENNA) | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); - rthdr->it_len = cpu_to_le16(rtap_len); + rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); pos = (unsigned char *)(rthdr + 1); + if (status->vendor_radiotap_len) { + rthdr->it_present |= + cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | + cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); + put_unaligned_le32(status->vendor_radiotap_bitmap, pos); + pos += 4; + } + /* the order of the following fields is important */ /* IEEE80211_RADIOTAP_TSFT */ if (ieee80211_have_rx_timestamp(status)) { + /* padding */ + while ((pos - (u8 *)rthdr) & 7) + *pos++ = 0; put_unaligned_le64( ieee80211_calculate_rx_timestamp(local, status, mpdulen, 0), @@ -211,7 +243,7 @@ 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 - (u8 *)rthdr) & 1) - pos++; + *pos++ = 0; if (status->flag & RX_FLAG_FAILED_PLCP_CRC) rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; put_unaligned_le16(rx_flags, pos); @@ -261,6 +293,21 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, *pos++ = 0; *pos++ = 0; } + + if (status->vendor_radiotap_len) { + /* ensure 2 byte alignment for the vendor field as required */ + if ((pos - (u8 *)rthdr) & 1) + *pos++ = 0; + *pos++ = status->vendor_radiotap_oui[0]; + *pos++ = status->vendor_radiotap_oui[1]; + *pos++ = status->vendor_radiotap_oui[2]; + *pos++ = status->vendor_radiotap_subns; + put_unaligned_le16(status->vendor_radiotap_len, pos); + pos += 2; + /* align the actual payload as requested */ + while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1)) + *pos++ = 0; + } } /* @@ -289,7 +336,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, */ /* room for the radiotap header based on driver features */ - needed_headroom = ieee80211_rx_radiotap_len(local, status); + needed_headroom = ieee80211_rx_radiotap_space(local, status); if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; @@ -2593,7 +2640,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, goto out_free_skb; /* room for the radiotap header based on driver features */ - needed_headroom = ieee80211_rx_radiotap_len(local, status); + needed_headroom = ieee80211_rx_radiotap_space(local, status); if (skb_headroom(skb) < needed_headroom && pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) -- cgit v1.2.1 From 49884568628db47a1f8c1f596c6ab3b8db81b73c Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 19 Nov 2012 17:05:09 +0200 Subject: mac80211: make remain_on_channel() op pass vif param Drivers (e.g. wl12xx) might need to know the vif to roc on (mainly in order to configure the rx filters correctly). Add the vif to the op params, and update the current users (iwlwifi) to use the new api. Signed-off-by: Eliad Peller [fix hwsim] Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 6 ++++-- net/mac80211/driver-ops.h | 7 ++++--- net/mac80211/offchannel.c | 2 +- net/mac80211/trace.h | 13 +++++++++---- 4 files changed, 18 insertions(+), 10 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 80e0618b25ba..18926aea480c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2287,7 +2287,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, if (!duration) duration = 10; - ret = drv_remain_on_channel(local, channel, channel_type, duration); + ret = drv_remain_on_channel(local, sdata, channel, channel_type, + duration); if (ret) { kfree(roc); return ret; @@ -2298,7 +2299,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, out_check_combine: list_for_each_entry(tmp, &local->roc_list, list) { - if (tmp->chan != channel || tmp->chan_type != channel_type) + if (tmp->chan != channel || tmp->chan_type != channel_type || + tmp->sdata != sdata) continue; /* diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4dc2577886ff..284dd02385e4 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -704,6 +704,7 @@ static inline int drv_get_antenna(struct ieee80211_local *local, } static inline int drv_remain_on_channel(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *chan, enum nl80211_channel_type chantype, unsigned int duration) @@ -712,9 +713,9 @@ static inline int drv_remain_on_channel(struct ieee80211_local *local, might_sleep(); - trace_drv_remain_on_channel(local, chan, chantype, duration); - ret = local->ops->remain_on_channel(&local->hw, chan, chantype, - duration); + trace_drv_remain_on_channel(local, sdata, chan, chantype, duration); + ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, + chan, chantype, duration); trace_drv_return_int(local, ret); return ret; diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 0cd42d52880c..7f8a36510813 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -283,7 +283,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) if (!duration) duration = 10; - ret = drv_remain_on_channel(local, roc->chan, + ret = drv_remain_on_channel(local, roc->sdata, roc->chan, roc->chan_type, duration); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 758836c85a80..e9579b7a2cd0 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1019,13 +1019,16 @@ TRACE_EVENT(drv_get_antenna, ); TRACE_EVENT(drv_remain_on_channel, - TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel *chan, enum nl80211_channel_type chantype, unsigned int duration), - TP_ARGS(local, chan, chantype, duration), + TP_ARGS(local, sdata, chan, chantype, duration), TP_STRUCT__entry( LOCAL_ENTRY + VIF_ENTRY __field(int, center_freq) __field(int, channel_type) __field(unsigned int, duration) @@ -1033,14 +1036,16 @@ TRACE_EVENT(drv_remain_on_channel, TP_fast_assign( LOCAL_ASSIGN; + VIF_ASSIGN; __entry->center_freq = chan->center_freq; __entry->channel_type = chantype; __entry->duration = duration; ), TP_printk( - LOCAL_PR_FMT " freq:%dMHz duration:%dms", - LOCAL_PR_ARG, __entry->center_freq, __entry->duration + LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms", + LOCAL_PR_ARG, VIF_PR_ARG, + __entry->center_freq, __entry->duration ) ); -- cgit v1.2.1 From fe5f255930af02ef3c3e0d00545b674e7e9d0cfb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Nov 2012 22:19:08 +0100 Subject: mac80211: fix channel context suspend/reconfig handling Sujith reported warnings with suspend/resume due to channel contexts. When I looked into it, I realised that the code was completely broken as it unassigned the channel contexts when suspending, which actually means they are destroyed. Eliad Peller then pointed out that we also need to remove the channel contexts from the driver. When I looked into this, I also noticed that the code isn't handling the virtual monitor interface correctly (if it exists.) Fix this by calling just the driver methods (if they are implemented) instead of using the channel context management code. Also add reconfiguration for the virtual monitor interface. Reported-by: Sujith Manoharan Signed-off-by: Johannes Berg --- net/mac80211/pm.c | 44 +++++++++++++++++++++++++++++++++++++++++--- net/mac80211/util.c | 15 +++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 0f1c434638bc..79a48f37d409 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -33,6 +33,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct sta_info *sta; + struct ieee80211_chanctx *ctx; if (!local->open_count) goto suspend; @@ -139,14 +140,51 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) rcu_access_pointer(sdata->u.ap.beacon)) drv_stop_ap(local, sdata); - /* the interface is leaving the channel and is removed */ - ieee80211_vif_release_channel(sdata); + if (local->use_chanctx) { + struct ieee80211_chanctx_conf *conf; + + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected( + sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (conf) { + ctx = container_of(conf, + struct ieee80211_chanctx, + conf); + drv_unassign_vif_chanctx(local, sdata, ctx); + } + + mutex_unlock(&local->chanctx_mtx); + } drv_remove_interface(local, sdata); } sdata = rtnl_dereference(local->monitor_sdata); - if (sdata) + if (sdata) { + if (local->use_chanctx) { + struct ieee80211_chanctx_conf *conf; + + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected( + sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (conf) { + ctx = container_of(conf, + struct ieee80211_chanctx, + conf); + drv_unassign_vif_chanctx(local, sdata, ctx); + } + + mutex_unlock(&local->chanctx_mtx); + } + drv_remove_interface(local, sdata); + } + + mutex_lock(&local->chanctx_mtx); + list_for_each_entry(ctx, &local->chanctx_list, list) + drv_remove_chanctx(local, ctx); + mutex_unlock(&local->chanctx_mtx); /* stop hardware - this must stop RX */ if (local->open_count) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7fb55bf6561e..2f08a7e09b7e 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1441,6 +1441,21 @@ int ieee80211_reconfig(struct ieee80211_local *local) mutex_unlock(&local->chanctx_mtx); } + sdata = rtnl_dereference(local->monitor_sdata); + if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) { + struct ieee80211_chanctx_conf *ctx_conf; + + mutex_lock(&local->chanctx_mtx); + ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (ctx_conf) { + ctx = container_of(ctx_conf, struct ieee80211_chanctx, + conf); + drv_assign_vif_chanctx(local, sdata, ctx); + } + mutex_unlock(&local->chanctx_mtx); + } + /* add STAs back */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { -- cgit v1.2.1 From 77d2ece6fde80631193054edc9c9a3edad519565 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 20 Nov 2012 08:46:02 +0530 Subject: mac80211: Add debugfs callbacks for station addition/removal Provide drivers with hooks to create debugfs files when a new station is added. This would help drivers to take advantage of mac80211's station list infrastructure and not maintain tedious station management code internally. Signed-off-by: Sujith Manoharan [ifdef inline wrapper functions] Signed-off-by: Johannes Berg --- net/mac80211/debugfs_sta.c | 9 +++++++++ net/mac80211/driver-ops.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 3d103929d41a..89281d24b094 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -14,6 +14,7 @@ #include "debugfs.h" #include "debugfs_sta.h" #include "sta_info.h" +#include "driver-ops.h" /* sta attributtes */ @@ -334,6 +335,8 @@ STA_OPS(ht_capa); void ieee80211_sta_debugfs_add(struct sta_info *sta) { + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; u8 mac[3*ETH_ALEN]; @@ -379,10 +382,16 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); + + drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) { + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; + + drv_sta_remove_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); debugfs_remove_recursive(sta->debugfs.dir); sta->debugfs.dir = NULL; } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 284dd02385e4..68c27aaf5c93 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -490,6 +490,38 @@ static inline void drv_sta_remove(struct ieee80211_local *local, trace_drv_return_void(local); } +#ifdef CONFIG_MAC80211_DEBUGFS +static inline void drv_sta_add_debugfs(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + might_sleep(); + + sdata = get_bss_sdata(sdata); + check_sdata_in_driver(sdata); + + if (local->ops->sta_add_debugfs) + local->ops->sta_add_debugfs(&local->hw, &sdata->vif, + sta, dir); +} + +static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + might_sleep(); + + sdata = get_bss_sdata(sdata); + check_sdata_in_driver(sdata); + + if (local->ops->sta_remove_debugfs) + local->ops->sta_remove_debugfs(&local->hw, &sdata->vif, + sta, dir); +} +#endif + static inline __must_check int drv_sta_state(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, -- cgit v1.2.1