Loading include/net/mac80211.h +2 −3 Original line number Diff line number Diff line Loading @@ -518,7 +518,7 @@ struct ieee80211_tx_rate { * @flags: transmit info flags, defined above * @band: the band to transmit on (use for checking for races) * @antenna_sel_tx: antenna to use, 0 for automatic diversity * @pad: padding, ignore * @ack_frame_id: internal frame ID for TX status, used internally * @control: union for control data * @status: union for status data * @driver_data: array of driver_data pointers Loading @@ -535,8 +535,7 @@ struct ieee80211_tx_info { u8 antenna_sel_tx; /* 2 byte hole */ u8 pad[2]; u16 ack_frame_id; union { struct { Loading net/mac80211/ieee80211_i.h +4 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/etherdevice.h> #include <linux/leds.h> #include <linux/idr.h> #include <net/ieee80211_radiotap.h> #include <net/cfg80211.h> #include <net/mac80211.h> Loading Loading @@ -1017,6 +1018,9 @@ struct ieee80211_local { u32 hw_roc_cookie; bool hw_roc_for_tx; struct idr ack_status_frames; spinlock_t ack_status_lock; /* dummy netdev for use w/ NAPI */ struct net_device napi_dev; Loading net/mac80211/main.c +18 −0 Original line number Diff line number Diff line Loading @@ -596,6 +596,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, WIPHY_FLAG_4ADDR_STATION | WIPHY_FLAG_REPORTS_OBSS; wiphy->features = NL80211_FEATURE_SK_TX_STATUS; if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; Loading Loading @@ -669,6 +671,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_WORK(&local->sched_scan_stopped_work, ieee80211_sched_scan_stopped_work); spin_lock_init(&local->ack_status_lock); idr_init(&local->ack_status_frames); /* preallocate at least one entry */ idr_pre_get(&local->ack_status_frames, GFP_KERNEL); sta_info_init(local); for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { Loading Loading @@ -1044,6 +1051,13 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_unregister_hw); static int ieee80211_free_ack_frame(int id, void *p, void *data) { WARN_ONCE(1, "Have pending ack frames!\n"); kfree_skb(p); return 0; } void ieee80211_free_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); Loading @@ -1054,6 +1068,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) if (local->wiphy_ciphers_allocated) kfree(local->hw.wiphy->cipher_suites); idr_for_each(&local->ack_status_frames, ieee80211_free_ack_frame, NULL); idr_destroy(&local->ack_status_frames); wiphy_free(local->hw.wiphy); } EXPORT_SYMBOL(ieee80211_free_hw); Loading net/mac80211/status.c +38 −0 Original line number Diff line number Diff line Loading @@ -548,6 +548,24 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } } if (unlikely(info->ack_frame_id)) { struct sk_buff *ack_skb; unsigned long flags; spin_lock_irqsave(&local->ack_status_lock, flags); ack_skb = idr_find(&local->ack_status_frames, info->ack_frame_id); if (ack_skb) idr_remove(&local->ack_status_frames, info->ack_frame_id); spin_unlock_irqrestore(&local->ack_status_lock, flags); /* consumes ack_skb */ if (ack_skb) skb_complete_wifi_ack(ack_skb, info->flags & IEEE80211_TX_STAT_ACK); } /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); Loading Loading @@ -621,6 +639,26 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (unlikely(info->ack_frame_id)) { struct sk_buff *ack_skb; unsigned long flags; spin_lock_irqsave(&local->ack_status_lock, flags); ack_skb = idr_find(&local->ack_status_frames, info->ack_frame_id); if (ack_skb) idr_remove(&local->ack_status_frames, info->ack_frame_id); spin_unlock_irqrestore(&local->ack_status_lock, flags); /* consumes ack_skb */ if (ack_skb) dev_kfree_skb_any(ack_skb); } dev_kfree_skb_any(skb); } EXPORT_SYMBOL(ieee80211_free_txskb); net/mac80211/tx.c +53 −3 Original line number Diff line number Diff line Loading @@ -1684,8 +1684,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, int nh_pos, h_pos; struct sta_info *sta = NULL; bool wme_sta = false, authorized = false, tdls_auth = false; struct sk_buff *tmp_skb; bool tdls_direct = false; bool multicast; u32 info_flags = 0; u16 info_id = 0; if (unlikely(skb->len < ETH_HLEN)) { ret = NETDEV_TX_OK; Loading Loading @@ -1872,7 +1874,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, * if it is a multicast address (which can only happen * in AP mode) */ if (!is_multicast_ether_addr(hdr.addr1)) { multicast = is_multicast_ether_addr(hdr.addr1); if (!multicast) { rcu_read_lock(); sta = sta_info_get(sdata, hdr.addr1); if (sta) { Loading Loading @@ -1913,11 +1916,54 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } if (unlikely(!multicast && skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) { struct sk_buff *orig_skb = skb; skb = skb_clone(skb, GFP_ATOMIC); if (skb) { unsigned long flags; int id, r; spin_lock_irqsave(&local->ack_status_lock, flags); r = idr_get_new_above(&local->ack_status_frames, orig_skb, 1, &id); if (r == -EAGAIN) { idr_pre_get(&local->ack_status_frames, GFP_ATOMIC); r = idr_get_new_above(&local->ack_status_frames, orig_skb, 1, &id); } if (WARN_ON(!id) || id > 0xffff) { idr_remove(&local->ack_status_frames, id); r = -ERANGE; } spin_unlock_irqrestore(&local->ack_status_lock, flags); if (!r) { info_id = id; info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; } else if (skb_shared(skb)) { kfree_skb(orig_skb); } else { kfree_skb(skb); skb = orig_skb; } } else { /* couldn't clone -- lose tx status ... */ skb = orig_skb; } } /* * If the skb is shared we need to obtain our own copy. */ if (skb_shared(skb)) { tmp_skb = skb; struct sk_buff *tmp_skb = skb; /* can't happen -- skb is a clone if info_id != 0 */ WARN_ON(info_id); skb = skb_clone(skb, GFP_ATOMIC); kfree_skb(tmp_skb); Loading Loading @@ -2018,6 +2064,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, memset(info, 0, sizeof(*info)); dev->trans_start = jiffies; info->flags = info_flags; info->ack_frame_id = info_id; ieee80211_xmit(sdata, skb); return NETDEV_TX_OK; Loading Loading
include/net/mac80211.h +2 −3 Original line number Diff line number Diff line Loading @@ -518,7 +518,7 @@ struct ieee80211_tx_rate { * @flags: transmit info flags, defined above * @band: the band to transmit on (use for checking for races) * @antenna_sel_tx: antenna to use, 0 for automatic diversity * @pad: padding, ignore * @ack_frame_id: internal frame ID for TX status, used internally * @control: union for control data * @status: union for status data * @driver_data: array of driver_data pointers Loading @@ -535,8 +535,7 @@ struct ieee80211_tx_info { u8 antenna_sel_tx; /* 2 byte hole */ u8 pad[2]; u16 ack_frame_id; union { struct { Loading
net/mac80211/ieee80211_i.h +4 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/etherdevice.h> #include <linux/leds.h> #include <linux/idr.h> #include <net/ieee80211_radiotap.h> #include <net/cfg80211.h> #include <net/mac80211.h> Loading Loading @@ -1017,6 +1018,9 @@ struct ieee80211_local { u32 hw_roc_cookie; bool hw_roc_for_tx; struct idr ack_status_frames; spinlock_t ack_status_lock; /* dummy netdev for use w/ NAPI */ struct net_device napi_dev; Loading
net/mac80211/main.c +18 −0 Original line number Diff line number Diff line Loading @@ -596,6 +596,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, WIPHY_FLAG_4ADDR_STATION | WIPHY_FLAG_REPORTS_OBSS; wiphy->features = NL80211_FEATURE_SK_TX_STATUS; if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; Loading Loading @@ -669,6 +671,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_WORK(&local->sched_scan_stopped_work, ieee80211_sched_scan_stopped_work); spin_lock_init(&local->ack_status_lock); idr_init(&local->ack_status_frames); /* preallocate at least one entry */ idr_pre_get(&local->ack_status_frames, GFP_KERNEL); sta_info_init(local); for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { Loading Loading @@ -1044,6 +1051,13 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_unregister_hw); static int ieee80211_free_ack_frame(int id, void *p, void *data) { WARN_ONCE(1, "Have pending ack frames!\n"); kfree_skb(p); return 0; } void ieee80211_free_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); Loading @@ -1054,6 +1068,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) if (local->wiphy_ciphers_allocated) kfree(local->hw.wiphy->cipher_suites); idr_for_each(&local->ack_status_frames, ieee80211_free_ack_frame, NULL); idr_destroy(&local->ack_status_frames); wiphy_free(local->hw.wiphy); } EXPORT_SYMBOL(ieee80211_free_hw); Loading
net/mac80211/status.c +38 −0 Original line number Diff line number Diff line Loading @@ -548,6 +548,24 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } } if (unlikely(info->ack_frame_id)) { struct sk_buff *ack_skb; unsigned long flags; spin_lock_irqsave(&local->ack_status_lock, flags); ack_skb = idr_find(&local->ack_status_frames, info->ack_frame_id); if (ack_skb) idr_remove(&local->ack_status_frames, info->ack_frame_id); spin_unlock_irqrestore(&local->ack_status_lock, flags); /* consumes ack_skb */ if (ack_skb) skb_complete_wifi_ack(ack_skb, info->flags & IEEE80211_TX_STAT_ACK); } /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); Loading Loading @@ -621,6 +639,26 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (unlikely(info->ack_frame_id)) { struct sk_buff *ack_skb; unsigned long flags; spin_lock_irqsave(&local->ack_status_lock, flags); ack_skb = idr_find(&local->ack_status_frames, info->ack_frame_id); if (ack_skb) idr_remove(&local->ack_status_frames, info->ack_frame_id); spin_unlock_irqrestore(&local->ack_status_lock, flags); /* consumes ack_skb */ if (ack_skb) dev_kfree_skb_any(ack_skb); } dev_kfree_skb_any(skb); } EXPORT_SYMBOL(ieee80211_free_txskb);
net/mac80211/tx.c +53 −3 Original line number Diff line number Diff line Loading @@ -1684,8 +1684,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, int nh_pos, h_pos; struct sta_info *sta = NULL; bool wme_sta = false, authorized = false, tdls_auth = false; struct sk_buff *tmp_skb; bool tdls_direct = false; bool multicast; u32 info_flags = 0; u16 info_id = 0; if (unlikely(skb->len < ETH_HLEN)) { ret = NETDEV_TX_OK; Loading Loading @@ -1872,7 +1874,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, * if it is a multicast address (which can only happen * in AP mode) */ if (!is_multicast_ether_addr(hdr.addr1)) { multicast = is_multicast_ether_addr(hdr.addr1); if (!multicast) { rcu_read_lock(); sta = sta_info_get(sdata, hdr.addr1); if (sta) { Loading Loading @@ -1913,11 +1916,54 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } if (unlikely(!multicast && skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) { struct sk_buff *orig_skb = skb; skb = skb_clone(skb, GFP_ATOMIC); if (skb) { unsigned long flags; int id, r; spin_lock_irqsave(&local->ack_status_lock, flags); r = idr_get_new_above(&local->ack_status_frames, orig_skb, 1, &id); if (r == -EAGAIN) { idr_pre_get(&local->ack_status_frames, GFP_ATOMIC); r = idr_get_new_above(&local->ack_status_frames, orig_skb, 1, &id); } if (WARN_ON(!id) || id > 0xffff) { idr_remove(&local->ack_status_frames, id); r = -ERANGE; } spin_unlock_irqrestore(&local->ack_status_lock, flags); if (!r) { info_id = id; info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; } else if (skb_shared(skb)) { kfree_skb(orig_skb); } else { kfree_skb(skb); skb = orig_skb; } } else { /* couldn't clone -- lose tx status ... */ skb = orig_skb; } } /* * If the skb is shared we need to obtain our own copy. */ if (skb_shared(skb)) { tmp_skb = skb; struct sk_buff *tmp_skb = skb; /* can't happen -- skb is a clone if info_id != 0 */ WARN_ON(info_id); skb = skb_clone(skb, GFP_ATOMIC); kfree_skb(tmp_skb); Loading Loading @@ -2018,6 +2064,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, memset(info, 0, sizeof(*info)); dev->trans_start = jiffies; info->flags = info_flags; info->ack_frame_id = info_id; ieee80211_xmit(sdata, skb); return NETDEV_TX_OK; Loading