diff options
Diffstat (limited to 'package/kernel/mac80211/patches/315-mac80211-avoid-duplicate-TX-path-station-lookup.patch')
-rw-r--r-- | package/kernel/mac80211/patches/315-mac80211-avoid-duplicate-TX-path-station-lookup.patch | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/315-mac80211-avoid-duplicate-TX-path-station-lookup.patch b/package/kernel/mac80211/patches/315-mac80211-avoid-duplicate-TX-path-station-lookup.patch new file mode 100644 index 0000000000..31ed830c2a --- /dev/null +++ b/package/kernel/mac80211/patches/315-mac80211-avoid-duplicate-TX-path-station-lookup.patch @@ -0,0 +1,267 @@ +From: Johannes Berg <johannes.berg@intel.com> +Date: Fri, 20 Mar 2015 14:18:27 +0100 +Subject: [PATCH] mac80211: avoid duplicate TX path station lookup + +Instead of looking up the destination station twice in the TX path +(first to build the header, and then for control processing), save +it when building the header and use it later in the TX path. + +To avoid having to look up the station in the many callers, allow +those to pass %NULL which keeps the existing lookup. + +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3565,7 +3565,7 @@ static int ieee80211_probe_client(struct + nullfunc->qos_ctrl = cpu_to_le16(7); + + local_bh_disable(); +- ieee80211_xmit(sdata, skb); ++ ieee80211_xmit(sdata, sta, skb); + local_bh_enable(); + rcu_read_unlock(); + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1775,7 +1775,8 @@ void mac80211_ev_michael_mic_failure(str + gfp_t gfp); + void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, + bool bss_notify); +-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); ++void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta, struct sk_buff *skb); + + void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid, +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -1279,7 +1279,7 @@ static void ieee80211_send_null_response + } + + info->band = chanctx_conf->def.chan->band; +- ieee80211_xmit(sdata, skb); ++ ieee80211_xmit(sdata, sta, skb); + rcu_read_unlock(); + } + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1111,11 +1111,13 @@ static bool ieee80211_tx_prep_agg(struct + + /* + * initialises @tx ++ * pass %NULL for the station if unknown, a valid pointer if known ++ * or an ERR_PTR() if the station is known not to exist + */ + static ieee80211_tx_result + ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, + struct ieee80211_tx_data *tx, +- struct sk_buff *skb) ++ struct sta_info *sta, struct sk_buff *skb) + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_hdr *hdr; +@@ -1138,17 +1140,22 @@ ieee80211_tx_prepare(struct ieee80211_su + + hdr = (struct ieee80211_hdr *) skb->data; + +- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { +- tx->sta = rcu_dereference(sdata->u.vlan.sta); +- if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) +- return TX_DROP; +- } else if (info->flags & (IEEE80211_TX_CTL_INJECTED | +- IEEE80211_TX_INTFL_NL80211_FRAME_TX) || +- tx->sdata->control_port_protocol == tx->skb->protocol) { +- tx->sta = sta_info_get_bss(sdata, hdr->addr1); ++ if (likely(sta)) { ++ if (!IS_ERR(sta)) ++ tx->sta = sta; ++ } else { ++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { ++ tx->sta = rcu_dereference(sdata->u.vlan.sta); ++ if (!tx->sta && sdata->wdev.use_4addr) ++ return TX_DROP; ++ } else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX | ++ IEEE80211_TX_CTL_INJECTED) || ++ tx->sdata->control_port_protocol == tx->skb->protocol) { ++ tx->sta = sta_info_get_bss(sdata, hdr->addr1); ++ } ++ if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) ++ tx->sta = sta_info_get(sdata, hdr->addr1); + } +- if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) +- tx->sta = sta_info_get(sdata, hdr->addr1); + + if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && + !ieee80211_is_qos_nullfunc(hdr->frame_control) && +@@ -1486,7 +1493,7 @@ bool ieee80211_tx_prepare_skb(struct iee + struct ieee80211_tx_data tx; + struct sk_buff *skb2; + +- if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP) ++ if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP) + return false; + + info->band = band; +@@ -1519,7 +1526,8 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb); + * Returns false if the frame couldn't be transmitted but was queued instead. + */ + static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, +- struct sk_buff *skb, bool txpending) ++ struct sta_info *sta, struct sk_buff *skb, ++ bool txpending) + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_tx_data tx; +@@ -1535,7 +1543,7 @@ static bool ieee80211_tx(struct ieee8021 + + /* initialises tx */ + led_len = skb->len; +- res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); ++ res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb); + + if (unlikely(res_prepare == TX_DROP)) { + ieee80211_free_txskb(&local->hw, skb); +@@ -1591,7 +1599,8 @@ static int ieee80211_skb_resize(struct i + return 0; + } + +-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) ++void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta, struct sk_buff *skb) + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +@@ -1626,7 +1635,7 @@ void ieee80211_xmit(struct ieee80211_sub + } + + ieee80211_set_qos_hdr(sdata, skb); +- ieee80211_tx(sdata, skb, false); ++ ieee80211_tx(sdata, sta, skb, false); + } + + static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) +@@ -1847,7 +1856,7 @@ netdev_tx_t ieee80211_monitor_start_xmit + goto fail_rcu; + + info->band = chandef->chan->band; +- ieee80211_xmit(sdata, skb); ++ ieee80211_xmit(sdata, NULL, skb); + rcu_read_unlock(); + + return NETDEV_TX_OK; +@@ -1878,7 +1887,8 @@ fail: + * Returns: the (possibly reallocated) skb or an ERR_PTR() code + */ + static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, +- struct sk_buff *skb, u32 info_flags) ++ struct sk_buff *skb, u32 info_flags, ++ struct sta_info **sta_out) + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_tx_info *info; +@@ -1921,6 +1931,7 @@ static struct sk_buff *ieee80211_build_h + authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); + wme_sta = sta->sta.wme; + have_station = true; ++ *sta_out = sta; + } else if (sdata->wdev.use_4addr) { + ret = -ENOLINK; + goto free; +@@ -2074,6 +2085,7 @@ static struct sk_buff *ieee80211_build_h + have_station = true; + authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); + wme_sta = sta->sta.wme; ++ *sta_out = sta; + } else if (sdata->u.mgd.use_4addr && + cpu_to_be16(ethertype) != sdata->control_port_protocol) { + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | +@@ -2137,13 +2149,18 @@ static struct sk_buff *ieee80211_build_h + * and mesh mode checks authorization later. + */ + multicast = is_multicast_ether_addr(hdr.addr1); +- if (!multicast && !have_station && +- !ieee80211_vif_is_mesh(&sdata->vif)) { +- sta = sta_info_get(sdata, hdr.addr1); ++ if (multicast) { ++ *sta_out = ERR_PTR(-ENOENT); ++ } else if (!have_station && !ieee80211_vif_is_mesh(&sdata->vif)) { ++ if (sdata->control_port_protocol == skb->protocol) ++ sta = sta_info_get_bss(sdata, hdr.addr1); ++ else ++ sta = sta_info_get(sdata, hdr.addr1); + if (sta) { + authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); + wme_sta = sta->sta.wme; + } ++ *sta_out = sta ?: ERR_PTR(-ENOENT); + } + + /* For mesh, the use of the QoS header is mandatory */ +@@ -2321,6 +2338,7 @@ void __ieee80211_subif_start_xmit(struct + u32 info_flags) + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ struct sta_info *sta = NULL; + + if (unlikely(skb->len < ETH_HLEN)) { + kfree_skb(skb); +@@ -2329,7 +2347,7 @@ void __ieee80211_subif_start_xmit(struct + + rcu_read_lock(); + +- skb = ieee80211_build_hdr(sdata, skb, info_flags); ++ skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta); + if (IS_ERR(skb)) + goto out; + +@@ -2337,7 +2355,7 @@ void __ieee80211_subif_start_xmit(struct + dev->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; + +- ieee80211_xmit(sdata, skb); ++ ieee80211_xmit(sdata, sta, skb); + out: + rcu_read_unlock(); + } +@@ -2365,10 +2383,11 @@ ieee80211_build_data_template(struct iee + .local = sdata->local, + .sdata = sdata, + }; ++ struct sta_info *sta_ignore; + + rcu_read_lock(); + +- skb = ieee80211_build_hdr(sdata, skb, info_flags); ++ skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta_ignore); + if (IS_ERR(skb)) + goto out; + +@@ -2426,7 +2445,7 @@ static bool ieee80211_tx_pending_skb(str + return true; + } + info->band = chanctx_conf->def.chan->band; +- result = ieee80211_tx(sdata, skb, true); ++ result = ieee80211_tx(sdata, NULL, skb, true); + } else { + struct sk_buff_head skbs; + +@@ -3164,7 +3183,7 @@ ieee80211_get_buffered_bc(struct ieee802 + + if (sdata->vif.type == NL80211_IFTYPE_AP) + sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); +- if (!ieee80211_tx_prepare(sdata, &tx, skb)) ++ if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb)) + break; + dev_kfree_skb_any(skb); + } +@@ -3296,6 +3315,6 @@ void __ieee80211_tx_skb_tid_band(struct + */ + local_bh_disable(); + IEEE80211_SKB_CB(skb)->band = band; +- ieee80211_xmit(sdata, skb); ++ ieee80211_xmit(sdata, NULL, skb); + local_bh_enable(); + } |