aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorSujith <Sujith.Manoharan@atheros.com>2010-05-06 05:15:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-05-07 14:55:52 -0400
commit9c6dda4e2dfea970a7105e3805f0195bc3079f2f (patch)
tree3b255fefdca205e5f38032236faeb1d7e433a2a8 /drivers/net/wireless
parent0aaffa9b9699894aab3266195a529baf9f96ac29 (diff)
ath9k_htc: Fix beaconing in IBSS mode
The current way of managing beaconing in ad-hoc mode has a subtle race - the beacon obtained from mac80211 is freed in the SWBA handler rather than the TX completion routine. But transmission of beacons goes through the normal SKB queue maintained in hif_usb, leading to a situation where __skb_dequeue() in the TX completion handler goes kaput. Fix this by simply getting a beacon from mac80211 for every SWBA and free it in its completion routine. Signed-off-by: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c39
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c12
4 files changed, 13 insertions, 45 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 1ae18bbc4d9e..ad556aa8da39 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -356,7 +356,6 @@ struct ath9k_htc_priv {
356 u16 seq_no; 356 u16 seq_no;
357 u32 bmiss_cnt; 357 u32 bmiss_cnt;
358 358
359 struct sk_buff *beacon;
360 spinlock_t beacon_lock; 359 spinlock_t beacon_lock;
361 360
362 bool tx_queues_stop; 361 bool tx_queues_stop;
@@ -408,13 +407,13 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
408void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, 407void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
409 struct ieee80211_vif *vif); 408 struct ieee80211_vif *vif);
410void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); 409void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
411void ath9k_htc_beacon_update(struct ath9k_htc_priv *priv,
412 struct ieee80211_vif *vif);
413 410
414void ath9k_htc_rxep(void *priv, struct sk_buff *skb, 411void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
415 enum htc_endpoint_id ep_id); 412 enum htc_endpoint_id ep_id);
416void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, 413void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id,
417 bool txok); 414 bool txok);
415void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
416 enum htc_endpoint_id ep_id, bool txok);
418 417
419void ath9k_htc_station_work(struct work_struct *work); 418void ath9k_htc_station_work(struct work_struct *work);
420void ath9k_htc_aggr_work(struct work_struct *work); 419void ath9k_htc_aggr_work(struct work_struct *work);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 7cb55f5b071c..c10c7d002eb7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -165,22 +165,10 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
165 WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); 165 WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
166} 166}
167 167
168void ath9k_htc_beacon_update(struct ath9k_htc_priv *priv, 168void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
169 struct ieee80211_vif *vif) 169 enum htc_endpoint_id ep_id, bool txok)
170{ 170{
171 struct ath_common *common = ath9k_hw_common(priv->ah); 171 dev_kfree_skb_any(skb);
172
173 spin_lock_bh(&priv->beacon_lock);
174
175 if (priv->beacon)
176 dev_kfree_skb_any(priv->beacon);
177
178 priv->beacon = ieee80211_beacon_get(priv->hw, vif);
179 if (!priv->beacon)
180 ath_print(common, ATH_DBG_BEACON,
181 "Unable to allocate beacon\n");
182
183 spin_unlock_bh(&priv->beacon_lock);
184} 172}
185 173
186void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) 174void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
@@ -189,6 +177,7 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
189 struct tx_beacon_header beacon_hdr; 177 struct tx_beacon_header beacon_hdr;
190 struct ath9k_htc_tx_ctl tx_ctl; 178 struct ath9k_htc_tx_ctl tx_ctl;
191 struct ieee80211_tx_info *info; 179 struct ieee80211_tx_info *info;
180 struct sk_buff *beacon;
192 u8 *tx_fhdr; 181 u8 *tx_fhdr;
193 182
194 memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); 183 memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
@@ -207,25 +196,17 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
207 return; 196 return;
208 } 197 }
209 198
210 if (unlikely(priv->beacon == NULL)) {
211 spin_unlock_bh(&priv->beacon_lock);
212 return;
213 }
214
215 /* Free the old SKB first */
216 dev_kfree_skb_any(priv->beacon);
217
218 /* Get a new beacon */ 199 /* Get a new beacon */
219 priv->beacon = ieee80211_beacon_get(priv->hw, priv->vif); 200 beacon = ieee80211_beacon_get(priv->hw, priv->vif);
220 if (!priv->beacon) { 201 if (!beacon) {
221 spin_unlock_bh(&priv->beacon_lock); 202 spin_unlock_bh(&priv->beacon_lock);
222 return; 203 return;
223 } 204 }
224 205
225 info = IEEE80211_SKB_CB(priv->beacon); 206 info = IEEE80211_SKB_CB(beacon);
226 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { 207 if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
227 struct ieee80211_hdr *hdr = 208 struct ieee80211_hdr *hdr =
228 (struct ieee80211_hdr *) priv->beacon->data; 209 (struct ieee80211_hdr *) beacon->data;
229 priv->seq_no += 0x10; 210 priv->seq_no += 0x10;
230 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); 211 hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
231 hdr->seq_ctrl |= cpu_to_le16(priv->seq_no); 212 hdr->seq_ctrl |= cpu_to_le16(priv->seq_no);
@@ -233,10 +214,10 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
233 214
234 tx_ctl.type = ATH9K_HTC_NORMAL; 215 tx_ctl.type = ATH9K_HTC_NORMAL;
235 beacon_hdr.vif_index = avp->index; 216 beacon_hdr.vif_index = avp->index;
236 tx_fhdr = skb_push(priv->beacon, sizeof(beacon_hdr)); 217 tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
237 memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); 218 memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
238 219
239 htc_send(priv->htc, priv->beacon, priv->beacon_ep, &tx_ctl); 220 htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
240 221
241 spin_unlock_bh(&priv->beacon_lock); 222 spin_unlock_bh(&priv->beacon_lock);
242} 223}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 701f2ef5a440..17111fc1d2cc 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -144,7 +144,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
144 goto err; 144 goto err;
145 145
146 /* Beacon */ 146 /* Beacon */
147 ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, NULL, 147 ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep,
148 &priv->beacon_ep); 148 &priv->beacon_ep);
149 if (ret) 149 if (ret)
150 goto err; 150 goto err;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index ca7f3a78eb11..7c9e33ba95ab 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1313,15 +1313,6 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1313 priv->nvifs--; 1313 priv->nvifs--;
1314 1314
1315 ath9k_htc_remove_station(priv, vif, NULL); 1315 ath9k_htc_remove_station(priv, vif, NULL);
1316
1317 if (vif->type == NL80211_IFTYPE_ADHOC) {
1318 spin_lock_bh(&priv->beacon_lock);
1319 if (priv->beacon)
1320 dev_kfree_skb_any(priv->beacon);
1321 priv->beacon = NULL;
1322 spin_unlock_bh(&priv->beacon_lock);
1323 }
1324
1325 priv->vif = NULL; 1316 priv->vif = NULL;
1326 1317
1327 mutex_unlock(&priv->mutex); 1318 mutex_unlock(&priv->mutex);
@@ -1590,9 +1581,6 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1590 ath9k_htc_beacon_config(priv, vif); 1581 ath9k_htc_beacon_config(priv, vif);
1591 } 1582 }
1592 1583
1593 if (changed & BSS_CHANGED_BEACON)
1594 ath9k_htc_beacon_update(priv, vif);
1595
1596 if ((changed & BSS_CHANGED_BEACON_ENABLED) && 1584 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1597 !bss_conf->enable_beacon) { 1585 !bss_conf->enable_beacon) {
1598 priv->op_flags &= ~OP_ENABLE_BEACON; 1586 priv->op_flags &= ~OP_ENABLE_BEACON;