From e64b379574d6c92c15b4239ee0a5173317176547 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Apr 2010 11:18:43 +0200 Subject: mac80211: fix station destruction problem When a station w/o a key is destroyed, or when a driver submits work for a station and thereby references it again, it seems like potentially we could reference the station structure while it is being destroyed. Wait for an RCU grace period to elapse before finishing destroying the station after we have removed the station from the driver and from the hash table etc., even in the case where no key is associated with the station. Also, there's no point in deleting the plink timer here since it'll be properly deleted just a bit later. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'net/mac80211/sta_info.c') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 211c475f73c6..bd11753c1525 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -632,9 +632,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) * may mean it is removed from hardware which requires that * the key->sta pointer is still valid, so flush the key todo * list here. - * - * ieee80211_key_todo() will synchronize_rcu() so after this - * nothing can reference this sta struct any more. */ ieee80211_key_todo(); @@ -666,11 +663,17 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) sdata = sta->sdata; } + /* + * At this point, after we wait for an RCU grace period, + * neither mac80211 nor the driver can reference this + * sta struct any more except by still existing timers + * associated with this station that we clean up below. + */ + synchronize_rcu(); + #ifdef CONFIG_MAC80211_MESH - if (ieee80211_vif_is_mesh(&sdata->vif)) { + if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_accept_plinks_update(sdata); - del_timer(&sta->plink_timer); - } #endif #ifdef CONFIG_MAC80211_VERBOSE_DEBUG -- cgit v1.2.3 From 098a607091426e79178b9a6c318d993fea131791 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Apr 2010 11:18:47 +0200 Subject: mac80211: clean up/fix aggregation code The aggregation code has a number of quirks, like inventing an unneeded WLAN_BACK_TIMER value and leaking memory under certain circumstances during station destruction. Fix these issues by using the regular aggregation session teardown code and blocking new aggregation sessions, all before the station is really destructed. As a side effect, this gets rid of the long code block to destroy aggregation safely. Additionally, rename tid_state_rx which can only have the values IDLE and OPERATIONAL to tid_active_rx to make it easier to understand that there is no bitwise stuff going on on the RX side -- the TX side remains because it needs to keep track of the driver and peer states. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 1 - net/mac80211/agg-rx.c | 48 +++++++++++++++++--------------------- net/mac80211/debugfs_sta.c | 10 ++++---- net/mac80211/rx.c | 5 ++-- net/mac80211/sta_info.c | 58 ++++++++-------------------------------------- net/mac80211/sta_info.h | 6 ++--- 6 files changed, 40 insertions(+), 88 deletions(-) (limited to 'net/mac80211/sta_info.c') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 19984958ab7b..e9e03b02cb08 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1324,7 +1324,6 @@ enum ieee80211_back_actioncode { enum ieee80211_back_parties { WLAN_BACK_RECIPIENT = 0, WLAN_BACK_INITIATOR = 1, - WLAN_BACK_TIMER = 2, }; /* SA Query action */ diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 7d87f446f030..53233ab50f65 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -22,19 +22,20 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, u16 initiator, u16 reason) { struct ieee80211_local *local = sta->local; + struct tid_ampdu_rx *tid_rx; int i; - /* check if TID is in operational state */ spin_lock_bh(&sta->lock); - if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) { + + /* check if TID is in operational state */ + if (!sta->ampdu_mlme.tid_active_rx[tid]) { spin_unlock_bh(&sta->lock); return; } - sta->ampdu_mlme.tid_state_rx[tid] = - HT_AGG_STATE_REQ_STOP_BA_MSK | - (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - spin_unlock_bh(&sta->lock); + sta->ampdu_mlme.tid_active_rx[tid] = false; + + tid_rx = sta->ampdu_mlme.tid_rx[tid]; #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", @@ -46,37 +47,30 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); - /* shutdown timer has not expired */ - if (initiator != WLAN_BACK_TIMER) - del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); - /* check if this is a self generated aggregation halt */ - if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) + if (initiator == WLAN_BACK_RECIPIENT) ieee80211_send_delba(sta->sdata, sta->sta.addr, tid, 0, reason); /* free the reordering buffer */ - for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { - if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { + for (i = 0; i < tid_rx->buf_size; i++) { + if (tid_rx->reorder_buf[i]) { /* release the reordered frames */ - dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); - sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; - sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; + dev_kfree_skb(tid_rx->reorder_buf[i]); + tid_rx->stored_mpdu_num--; + tid_rx->reorder_buf[i] = NULL; } } - spin_lock_bh(&sta->lock); /* free resources */ - kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); - kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time); - - if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) { - kfree(sta->ampdu_mlme.tid_rx[tid]); - sta->ampdu_mlme.tid_rx[tid] = NULL; - } + kfree(tid_rx->reorder_buf); + kfree(tid_rx->reorder_time); + sta->ampdu_mlme.tid_rx[tid] = NULL; - sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; spin_unlock_bh(&sta->lock); + + del_timer_sync(&tid_rx->session_timer); + kfree(tid_rx); } /* @@ -211,7 +205,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, /* examine state machine */ spin_lock_bh(&sta->lock); - if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { + if (sta->ampdu_mlme.tid_active_rx[tid]) { #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "unexpected AddBA Req from " @@ -273,7 +267,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, } /* change state and send addba resp */ - sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; + sta->ampdu_mlme.tid_active_rx[tid] = true; tid_agg_rx->dialog_token = dialog_token; tid_agg_rx->ssn = start_seq_num; tid_agg_rx->head_seq_num = start_seq_num; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 23e720034577..740ff6c5b92c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -119,7 +119,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[64 + STA_TID_NUM * 40], *p = buf; + char buf[71 + STA_TID_NUM * 40], *p = buf; int i; struct sta_info *sta = file->private_data; @@ -127,16 +127,16 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", sta->ampdu_mlme.dialog_token_allocator + 1); p += scnprintf(p, sizeof(buf) + buf - p, - "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); + "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); for (i = 0; i < STA_TID_NUM; i++) { p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", - sta->ampdu_mlme.tid_state_rx[i]); + sta->ampdu_mlme.tid_active_rx[i]); p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", - sta->ampdu_mlme.tid_state_rx[i] ? + sta->ampdu_mlme.tid_active_rx[i] ? sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", - sta->ampdu_mlme.tid_state_rx[i] ? + sta->ampdu_mlme.tid_active_rx[i] ? sta->ampdu_mlme.tid_rx[i]->ssn : 0); p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c02e43b50ac3..62053fa711f3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -720,7 +720,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; - if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) + if (!sta->ampdu_mlme.tid_active_rx[tid]) goto dont_reorder; tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; @@ -1805,8 +1805,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) if (!rx->sta) return RX_DROP_MONITOR; tid = le16_to_cpu(bar->control) >> 12; - if (rx->sta->ampdu_mlme.tid_state_rx[tid] - != HT_AGG_STATE_OPERATIONAL) + if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) return RX_DROP_MONITOR; tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index bd11753c1525..5bf044b92dca 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -238,9 +238,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, * enable session_timer's data differentiation. refer to * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; - /* rx */ - sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; - sta->ampdu_mlme.tid_rx[i] = NULL; /* tx */ sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; sta->ampdu_mlme.tid_tx[i] = NULL; @@ -606,7 +603,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) struct ieee80211_sub_if_data *sdata; struct sk_buff *skb; unsigned long flags; - int ret, i; + int ret; might_sleep(); @@ -616,6 +613,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) local = sta->local; sdata = sta->sdata; + /* + * Before removing the station from the driver and + * rate control, it might still start new aggregation + * sessions -- block that to make sure the tear-down + * will be sufficient. + */ + set_sta_flags(sta, WLAN_STA_BLOCK_BA); + ieee80211_sta_tear_down_BA_sessions(sta); + spin_lock_irqsave(&local->sta_lock, flags); ret = sta_info_hash_del(local, sta); /* this might still be the pending list ... which is fine */ @@ -700,50 +706,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) dev_kfree_skb_any(skb); - for (i = 0; i < STA_TID_NUM; i++) { - struct tid_ampdu_rx *tid_rx; - struct tid_ampdu_tx *tid_tx; - - spin_lock_bh(&sta->lock); - tid_rx = sta->ampdu_mlme.tid_rx[i]; - /* Make sure timer won't free the tid_rx struct, see below */ - if (tid_rx) - tid_rx->shutdown = true; - - spin_unlock_bh(&sta->lock); - - /* - * Outside spinlock - shutdown is true now so that the timer - * won't free tid_rx, we have to do that now. Can't let the - * timer do it because we have to sync the timer outside the - * lock that it takes itself. - */ - if (tid_rx) { - del_timer_sync(&tid_rx->session_timer); - kfree(tid_rx); - } - - /* - * No need to do such complications for TX agg sessions, the - * path leading to freeing the tid_tx struct goes via a call - * from the driver, and thus needs to look up the sta struct - * again, which cannot be found when we get here. Hence, we - * just need to delete the timer and free the aggregation - * info; we won't be telling the peer about it then but that - * doesn't matter if we're not talking to it again anyway. - */ - tid_tx = sta->ampdu_mlme.tid_tx[i]; - if (tid_tx) { - del_timer_sync(&tid_tx->addba_resp_timer); - /* - * STA removed while aggregation session being - * started? Bit odd, but purge frames anyway. - */ - skb_queue_purge(&tid_tx->pending); - kfree(tid_tx); - } - } - __sta_info_free(local, sta); return 0; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 57e81758d6f7..48a5e80957f0 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -36,7 +36,7 @@ * frame to this station is transmitted. * @WLAN_STA_MFP: Management frame protection is used with this STA. * @WLAN_STA_BLOCK_BA: Used to deny ADDBA requests (both TX and RX) - * during suspend/resume. + * during suspend/resume and station removal. * @WLAN_STA_PS_DRIVER: driver requires keeping this station in * power-save mode logically to flush frames that might still * be in the queues @@ -106,7 +106,6 @@ struct tid_ampdu_tx { * @buf_size: buffer size for incoming A-MPDUs * @timeout: reset timer value (in TUs). * @dialog_token: dialog token for aggregation session - * @shutdown: this session is being shut down due to STA removal */ struct tid_ampdu_rx { struct sk_buff **reorder_buf; @@ -118,7 +117,6 @@ struct tid_ampdu_rx { u16 buf_size; u16 timeout; u8 dialog_token; - bool shutdown; }; /** @@ -156,7 +154,7 @@ enum plink_state { */ struct sta_ampdu_mlme { /* rx */ - u8 tid_state_rx[STA_TID_NUM]; + bool tid_active_rx[STA_TID_NUM]; struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; /* tx */ u8 tid_state_tx[STA_TID_NUM]; -- cgit v1.2.3 From b5878a2dc5e7e7f031a52c3e15b571224cb6b540 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Apr 2010 16:48:40 +0200 Subject: mac80211: enhance tracing Enhance tracing by adding tracing for a variety of callbacks that the drivers call, and also for internal calls (currently limited to queue status). This can aid debugging what is going on in mac80211 in interaction with drivers, since we can now see what drivers call and not just what mac80211 calls in the driver. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 8 +- net/mac80211/agg-tx.c | 8 ++ net/mac80211/driver-trace.h | 275 ++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/main.c | 2 + net/mac80211/mlme.c | 6 + net/mac80211/scan.c | 2 + net/mac80211/sta_info.c | 2 + net/mac80211/util.c | 4 + 8 files changed, 303 insertions(+), 4 deletions(-) (limited to 'net/mac80211/sta_info.c') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 334c359da5e8..8a91f6c0bb18 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -221,8 +221,8 @@ config MAC80211_DRIVER_API_TRACER depends on EVENT_TRACING help Say Y here to make mac80211 register with the ftrace - framework for the driver API -- you can see which - driver methods it is calling then by looking at the - trace. + framework for the driver API -- you can then see which + driver methods it is calling and which API functions + drivers are calling by looking at the trace. - If unsure, say N. + If unsure, say Y. diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 32d2148b5b98..6bb4d0a1e5c5 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -214,6 +214,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) int ret = 0; u16 start_seq_num; + trace_api_start_tx_ba_session(pubsta, tid); + if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; @@ -440,6 +442,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) struct sta_info *sta; u8 *state; + trace_api_start_tx_ba_cb(sdata, ra, tid); + if (tid >= STA_TID_NUM) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", @@ -541,6 +545,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; + trace_api_stop_tx_ba_session(pubsta, tid, initiator); + if (!local->ops->ampdu_action) return -EINVAL; @@ -558,6 +564,8 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) struct sta_info *sta; u8 *state; + trace_api_stop_tx_ba_cb(sdata, ra, tid); + if (tid >= STA_TID_NUM) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 41baf730a5c7..e209cb82ff29 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -32,6 +32,10 @@ static inline void trace_ ## name(proto) {} #define VIF_PR_FMT " vif:%s(%d)" #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type +/* + * Tracing for driver callbacks. + */ + TRACE_EVENT(drv_start, TP_PROTO(struct ieee80211_local *local, int ret), @@ -766,6 +770,277 @@ TRACE_EVENT(drv_flush, LOCAL_PR_ARG, __entry->drop ) ); + +/* + * Tracing for API calls that drivers call. + */ + +TRACE_EVENT(api_start_tx_ba_session, + TP_PROTO(struct ieee80211_sta *sta, u16 tid), + + TP_ARGS(sta, tid), + + TP_STRUCT__entry( + STA_ENTRY + __field(u16, tid) + ), + + TP_fast_assign( + STA_ASSIGN; + __entry->tid = tid; + ), + + TP_printk( + STA_PR_FMT " tid:%d", + STA_PR_ARG, __entry->tid + ) +); + +TRACE_EVENT(api_start_tx_ba_cb, + TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid), + + TP_ARGS(sdata, ra, tid), + + TP_STRUCT__entry( + VIF_ENTRY + __array(u8, ra, ETH_ALEN) + __field(u16, tid) + ), + + TP_fast_assign( + VIF_ASSIGN; + memcpy(__entry->ra, ra, ETH_ALEN); + __entry->tid = tid; + ), + + TP_printk( + VIF_PR_FMT " ra:%pM tid:%d", + VIF_PR_ARG, __entry->ra, __entry->tid + ) +); + +TRACE_EVENT(api_stop_tx_ba_session, + TP_PROTO(struct ieee80211_sta *sta, u16 tid, u16 initiator), + + TP_ARGS(sta, tid, initiator), + + TP_STRUCT__entry( + STA_ENTRY + __field(u16, tid) + __field(u16, initiator) + ), + + TP_fast_assign( + STA_ASSIGN; + __entry->tid = tid; + __entry->initiator = initiator; + ), + + TP_printk( + STA_PR_FMT " tid:%d initiator:%d", + STA_PR_ARG, __entry->tid, __entry->initiator + ) +); + +TRACE_EVENT(api_stop_tx_ba_cb, + TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid), + + TP_ARGS(sdata, ra, tid), + + TP_STRUCT__entry( + VIF_ENTRY + __array(u8, ra, ETH_ALEN) + __field(u16, tid) + ), + + TP_fast_assign( + VIF_ASSIGN; + memcpy(__entry->ra, ra, ETH_ALEN); + __entry->tid = tid; + ), + + TP_printk( + VIF_PR_FMT " ra:%pM tid:%d", + VIF_PR_ARG, __entry->ra, __entry->tid + ) +); + +TRACE_EVENT(api_restart_hw, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, + LOCAL_PR_ARG + ) +); + +TRACE_EVENT(api_beacon_loss, + TP_PROTO(struct ieee80211_sub_if_data *sdata), + + TP_ARGS(sdata), + + TP_STRUCT__entry( + VIF_ENTRY + ), + + TP_fast_assign( + VIF_ASSIGN; + ), + + TP_printk( + VIF_PR_FMT, + VIF_PR_ARG + ) +); + +TRACE_EVENT(api_connection_loss, + TP_PROTO(struct ieee80211_sub_if_data *sdata), + + TP_ARGS(sdata), + + TP_STRUCT__entry( + VIF_ENTRY + ), + + TP_fast_assign( + VIF_ASSIGN; + ), + + TP_printk( + VIF_PR_FMT, + VIF_PR_ARG + ) +); + +TRACE_EVENT(api_cqm_rssi_notify, + TP_PROTO(struct ieee80211_sub_if_data *sdata, + enum nl80211_cqm_rssi_threshold_event rssi_event), + + TP_ARGS(sdata, rssi_event), + + TP_STRUCT__entry( + VIF_ENTRY + __field(u32, rssi_event) + ), + + TP_fast_assign( + VIF_ASSIGN; + __entry->rssi_event = rssi_event; + ), + + TP_printk( + VIF_PR_FMT " event:%d", + VIF_PR_ARG, __entry->rssi_event + ) +); + +TRACE_EVENT(api_scan_completed, + TP_PROTO(struct ieee80211_local *local, bool aborted), + + TP_ARGS(local, aborted), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(bool, aborted) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->aborted = aborted; + ), + + TP_printk( + LOCAL_PR_FMT " aborted:%d", + LOCAL_PR_ARG, __entry->aborted + ) +); + +TRACE_EVENT(api_sta_block_awake, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, bool block), + + TP_ARGS(local, sta, block), + + TP_STRUCT__entry( + LOCAL_ENTRY + STA_ENTRY + __field(bool, block) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->block = block; + ), + + TP_printk( + LOCAL_PR_FMT STA_PR_FMT " block:%d", + LOCAL_PR_ARG, STA_PR_FMT, __entry->block + ) +); + +/* + * Tracing for internal functions + * (which may also be called in response to driver calls) + */ + +TRACE_EVENT(wake_queue, + TP_PROTO(struct ieee80211_local *local, u16 queue, + enum queue_stop_reason reason), + + TP_ARGS(local, queue, reason), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u16, queue) + __field(u32, reason) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->queue = queue; + __entry->reason = reason; + ), + + TP_printk( + LOCAL_PR_FMT " queue:%d, reason:%d", + LOCAL_PR_ARG, __entry->queue, __entry->reason + ) +); + +TRACE_EVENT(stop_queue, + TP_PROTO(struct ieee80211_local *local, u16 queue, + enum queue_stop_reason reason), + + TP_ARGS(local, queue, reason), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u16, queue) + __field(u32, reason) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->queue = queue; + __entry->reason = reason; + ), + + TP_printk( + LOCAL_PR_FMT " queue:%d, reason:%d", + LOCAL_PR_ARG, __entry->queue, __entry->reason + ) +); #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b887e484ae04..4afe851cf8dc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -309,6 +309,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); + trace_api_restart_hw(local); + /* use this reason, __ieee80211_resume will unblock it */ ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 461167dfa42c..d11a54c289a2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1007,6 +1007,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_hw *hw = &sdata->local->hw; + trace_api_beacon_loss(sdata); + WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR); ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); } @@ -1017,6 +1019,8 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_hw *hw = &sdata->local->hw; + trace_api_connection_loss(sdata); + WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR)); ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); } @@ -2261,6 +2265,8 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + trace_api_cqm_rssi_notify(sdata, rssi_event); + cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp); } EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 75a85978c3b3..eb86a5f6e645 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -247,6 +247,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) struct ieee80211_local *local = hw_to_local(hw); bool was_hw_scan; + trace_api_scan_completed(local, aborted); + mutex_lock(&local->scan_mtx); /* diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4de987cbda1c..ff0eb948917b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -957,6 +957,8 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + trace_api_sta_block_awake(sta->local, pubsta, block); + if (block) set_sta_flags(sta, WLAN_STA_PS_DRIVER); else diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ad9009f717ed..2b75b4fb68f4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -270,6 +270,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + trace_wake_queue(local, queue, reason); + if (WARN_ON(queue >= hw->queues)) return; @@ -312,6 +314,8 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + trace_stop_queue(local, queue, reason); + if (WARN_ON(queue >= hw->queues)) return; -- cgit v1.2.3 From 3393a608c4979a94d1887efc05b792849d361a65 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 19 Apr 2010 10:12:52 +0300 Subject: mac80211: Prevent running sta_cleanup timer unnecessarily MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sta_cleanup timer is used to periodically expire buffered frames from the tx buf. The timer is executing periodically, regardless of the need for it. This is wasting resources. Fix this simply by not restarting the sta_cleanup timer if the tx buffer was empty. Restart the timer when there is some more tx-traffic. Cc: Janne Ylälehto Signed-off-by: Juuso Oikarinen Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 13 ++++++++++--- net/mac80211/tx.c | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'net/mac80211/sta_info.c') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ff0eb948917b..3de7a2260d65 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -575,7 +575,7 @@ static int sta_info_buffer_expired(struct sta_info *sta, } -static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, +static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, struct sta_info *sta) { unsigned long flags; @@ -583,7 +583,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata; if (skb_queue_empty(&sta->ps_tx_buf)) - return; + return false; for (;;) { spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); @@ -608,6 +608,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (skb_queue_empty(&sta->ps_tx_buf)) sta_info_clear_tim_bit(sta); } + + return true; } static int __must_check __sta_info_destroy(struct sta_info *sta) @@ -755,15 +757,20 @@ static void sta_info_cleanup(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; struct sta_info *sta; + bool timer_needed = false; rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) - sta_info_cleanup_expire_buffered(local, sta); + if (sta_info_cleanup_expire_buffered(local, sta)) + timer_needed = true; rcu_read_unlock(); if (local->quiescing) return; + if (!timer_needed) + return; + local->sta_cleanup.expires = round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); add_timer(&local->sta_cleanup); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2cb77267f733..e2aa972d584f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -429,6 +429,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct sta_info *sta = tx->sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + struct ieee80211_local *local = tx->local; u32 staflags; if (unlikely(!sta || @@ -476,6 +477,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) info->control.vif = &tx->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&sta->ps_tx_buf, tx->skb); + + if (!timer_pending(&local->sta_cleanup)) + mod_timer(&local->sta_cleanup, + round_jiffies(jiffies + + STA_INFO_CLEANUP_INTERVAL)); + return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -- cgit v1.2.3 From f7c65594f7148b778f41d591a701e94bb22428e4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 30 Apr 2010 13:48:36 +0200 Subject: mac80211: fix ieee80211_find_sta[_by_hw] Both of these functions can currently return a station pointer that, to the driver, is invalid (in IBSS mode only) because adding the station failed. Check for that, and also make ieee80211_find_sta() properly use the per interface station search. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'net/mac80211/sta_info.c') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 3de7a2260d65..730197591ab5 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -855,8 +855,12 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, struct sta_info *sta, *nxt; /* Just return a random station ... first in list ... */ - for_each_sta_info(hw_to_local(hw), addr, sta, nxt) + for_each_sta_info(hw_to_local(hw), addr, sta, nxt) { + if (!sta->uploaded) + return NULL; return &sta->sta; + } + return NULL; } EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); @@ -864,14 +868,19 @@ 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; + struct sta_info *sta; if (!vif) return NULL; - sdata = vif_to_sdata(vif); + sta = sta_info_get_bss(vif_to_sdata(vif), addr); + if (!sta) + return NULL; + + if (!sta->uploaded) + return NULL; - return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); + return &sta->sta; } EXPORT_SYMBOL(ieee80211_find_sta); -- cgit v1.2.3