aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
authorLiad Kaufman <liad.kaufman@intel.com>2014-11-09 11:50:08 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-11-19 12:44:29 -0500
commit1277b4a9f531e84e26f9e0210c1801b0c0bf81ca (patch)
treebabc1273db9300734cecbab2d692bd39db946028 /net/mac80211/status.c
parent24d342c514827d52d008736bf02c9f145651ca8e (diff)
mac80211: retransmit TDLS teardown packet through AP if not ACKed
Since the TDLS peer station might not receive the teardown packet (e.g., when in PS), this makes sure the packet is retransmitted - this time through the AP - if the TDLS peer didn't ACK the packet. Signed-off-by: Liad Kaufman <liad.kaufman@intel.com> Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c55
1 files changed, 53 insertions, 2 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 9612d89fad56..71de2d3866cc 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -390,6 +390,46 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local,
390 } 390 }
391} 391}
392 392
393/*
394 * Handles the tx for TDLS teardown frames.
395 * If the frame wasn't ACKed by the peer - it will be re-sent through the AP
396 */
397static void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local,
398 struct ieee80211_sub_if_data *sdata,
399 struct sk_buff *skb, u32 flags)
400{
401 struct sk_buff *teardown_skb;
402 struct sk_buff *orig_teardown_skb;
403 bool is_teardown = false;
404
405 /* Get the teardown data we need and free the lock */
406 spin_lock(&sdata->u.mgd.teardown_lock);
407 teardown_skb = sdata->u.mgd.teardown_skb;
408 orig_teardown_skb = sdata->u.mgd.orig_teardown_skb;
409 if ((skb == orig_teardown_skb) && teardown_skb) {
410 sdata->u.mgd.teardown_skb = NULL;
411 sdata->u.mgd.orig_teardown_skb = NULL;
412 is_teardown = true;
413 }
414 spin_unlock(&sdata->u.mgd.teardown_lock);
415
416 if (is_teardown) {
417 /* This mechanism relies on being able to get ACKs */
418 WARN_ON(!(local->hw.flags &
419 IEEE80211_HW_REPORTS_TX_ACK_STATUS));
420
421 /* Check if peer has ACKed */
422 if (flags & IEEE80211_TX_STAT_ACK) {
423 dev_kfree_skb_any(teardown_skb);
424 } else {
425 tdls_dbg(sdata,
426 "TDLS Resending teardown through AP\n");
427
428 ieee80211_subif_start_xmit(teardown_skb, skb->dev);
429 }
430 }
431}
432
393static void ieee80211_report_used_skb(struct ieee80211_local *local, 433static void ieee80211_report_used_skb(struct ieee80211_local *local,
394 struct sk_buff *skb, bool dropped) 434 struct sk_buff *skb, bool dropped)
395{ 435{
@@ -426,8 +466,19 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
426 if (!sdata) { 466 if (!sdata) {
427 skb->dev = NULL; 467 skb->dev = NULL;
428 } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { 468 } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
429 ieee80211_mgd_conn_tx_status(sdata, hdr->frame_control, 469 unsigned int hdr_size =
430 acked); 470 ieee80211_hdrlen(hdr->frame_control);
471
472 /* Check to see if packet is a TDLS teardown packet */
473 if (ieee80211_is_data(hdr->frame_control) &&
474 (ieee80211_get_tdls_action(skb, hdr_size) ==
475 WLAN_TDLS_TEARDOWN))
476 ieee80211_tdls_td_tx_handle(local, sdata, skb,
477 info->flags);
478 else
479 ieee80211_mgd_conn_tx_status(sdata,
480 hdr->frame_control,
481 acked);
431 } else if (ieee80211_is_nullfunc(hdr->frame_control) || 482 } else if (ieee80211_is_nullfunc(hdr->frame_control) ||
432 ieee80211_is_qos_nullfunc(hdr->frame_control)) { 483 ieee80211_is_qos_nullfunc(hdr->frame_control)) {
433 cfg80211_probe_status(sdata->dev, hdr->addr1, 484 cfg80211_probe_status(sdata->dev, hdr->addr1,