diff options
Diffstat (limited to 'package/kernel/mac80211/patches/300-pending_work.patch')
-rw-r--r-- | package/kernel/mac80211/patches/300-pending_work.patch | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch new file mode 100644 index 0000000..bd21e53 --- /dev/null +++ b/package/kernel/mac80211/patches/300-pending_work.patch @@ -0,0 +1,313 @@ +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -204,6 +204,8 @@ static void ieee80211_send_addba_resp(st + memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); + else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) + memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN); ++ else if (sdata->vif.type == NL80211_IFTYPE_WDS) ++ memcpy(mgmt->bssid, da, ETH_ALEN); + + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); +--- a/net/mac80211/agg-tx.c ++++ b/net/mac80211/agg-tx.c +@@ -81,7 +81,8 @@ static void ieee80211_send_addba_request + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN || +- sdata->vif.type == NL80211_IFTYPE_MESH_POINT) ++ sdata->vif.type == NL80211_IFTYPE_MESH_POINT || ++ sdata->vif.type == NL80211_IFTYPE_WDS) + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); +@@ -527,6 +528,7 @@ int ieee80211_start_tx_ba_session(struct + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP && ++ sdata->vif.type != NL80211_IFTYPE_WDS && + sdata->vif.type != NL80211_IFTYPE_ADHOC) + return -EINVAL; + +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -66,11 +66,11 @@ static ssize_t sta_flags_read(struct fil + test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" + + int res = scnprintf(buf, sizeof(buf), +- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", ++ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + TEST(AUTH), TEST(ASSOC), TEST(PS_STA), + TEST(PS_DRIVER), TEST(AUTHORIZED), + TEST(SHORT_PREAMBLE), +- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), ++ TEST(WME), TEST(CLEAR_PS_FILT), + TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), + TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), + TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), +--- a/net/mac80211/ht.c ++++ b/net/mac80211/ht.c +@@ -281,13 +281,14 @@ void ieee80211_ba_session_work(struct wo + sta, tid, WLAN_BACK_RECIPIENT, + WLAN_REASON_UNSPECIFIED, true); + ++ spin_lock_bh(&sta->lock); ++ + tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; + if (tid_tx) { + /* + * Assign it over to the normal tid_tx array + * where it "goes live". + */ +- spin_lock_bh(&sta->lock); + + sta->ampdu_mlme.tid_start_tx[tid] = NULL; + /* could there be a race? */ +@@ -300,6 +301,7 @@ void ieee80211_ba_session_work(struct wo + ieee80211_tx_ba_session_handle_start(sta, tid); + continue; + } ++ spin_unlock_bh(&sta->lock); + + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); + if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -463,7 +463,6 @@ int ieee80211_do_open(struct wireless_de + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + struct net_device *dev = wdev->netdev; + struct ieee80211_local *local = sdata->local; +- struct sta_info *sta; + u32 changed = 0; + int res; + u32 hw_reconf_flags = 0; +@@ -629,30 +628,8 @@ int ieee80211_do_open(struct wireless_de + + set_bit(SDATA_STATE_RUNNING, &sdata->state); + +- if (sdata->vif.type == NL80211_IFTYPE_WDS) { +- /* Create STA entry for the WDS peer */ +- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, +- GFP_KERNEL); +- if (!sta) { +- res = -ENOMEM; +- goto err_del_interface; +- } +- +- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); +- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); +- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); +- +- res = sta_info_insert(sta); +- if (res) { +- /* STA has been freed */ +- goto err_del_interface; +- } +- +- rate_control_rate_init(sta); +- netif_carrier_on(dev); +- } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { ++ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) + rcu_assign_pointer(local->p2p_sdata, sdata); +- } + + /* + * set_multicast_list will be invoked by the networking core +@@ -1116,6 +1093,74 @@ static void ieee80211_if_setup(struct ne + dev->destructor = free_netdev; + } + ++static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_rx_status *rx_status; ++ struct ieee802_11_elems elems; ++ struct ieee80211_mgmt *mgmt; ++ struct sta_info *sta; ++ size_t baselen; ++ u32 rates = 0; ++ u16 stype; ++ bool new = false; ++ enum ieee80211_band band; ++ struct ieee80211_supported_band *sband; ++ ++ rx_status = IEEE80211_SKB_RXCB(skb); ++ band = rx_status->band; ++ sband = local->hw.wiphy->bands[band]; ++ mgmt = (struct ieee80211_mgmt *) skb->data; ++ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; ++ ++ if (stype != IEEE80211_STYPE_BEACON) ++ return; ++ ++ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; ++ if (baselen > skb->len) ++ return; ++ ++ ieee802_11_parse_elems(mgmt->u.probe_resp.variable, ++ skb->len - baselen, false, &elems); ++ ++ rates = ieee80211_sta_get_rates(local, &elems, band, NULL); ++ ++ rcu_read_lock(); ++ ++ sta = sta_info_get(sdata, sdata->u.wds.remote_addr); ++ ++ if (!sta) { ++ rcu_read_unlock(); ++ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, ++ GFP_KERNEL); ++ if (!sta) ++ return; ++ ++ new = true; ++ } ++ ++ sta->last_rx = jiffies; ++ sta->sta.supp_rates[band] = rates; ++ ++ if (elems.ht_cap_elem) ++ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, ++ elems.ht_cap_elem, sta); ++ ++ if (elems.wmm_param) ++ set_sta_flag(sta, WLAN_STA_WME); ++ ++ if (new) { ++ sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); ++ sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); ++ sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); ++ rate_control_rate_init(sta); ++ sta_info_insert_rcu(sta); ++ } ++ ++ rcu_read_unlock(); ++} ++ + static void ieee80211_iface_work(struct work_struct *work) + { + struct ieee80211_sub_if_data *sdata = +@@ -1220,6 +1265,9 @@ static void ieee80211_iface_work(struct + break; + ieee80211_mesh_rx_queued_mgmt(sdata, skb); + break; ++ case NL80211_IFTYPE_WDS: ++ ieee80211_wds_rx_queued_mgmt(sdata, skb); ++ break; + default: + WARN(1, "frame for unexpected interface type"); + break; +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2369,6 +2369,7 @@ ieee80211_rx_h_action(struct ieee80211_r + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP && ++ sdata->vif.type != NL80211_IFTYPE_WDS && + sdata->vif.type != NL80211_IFTYPE_ADHOC) + break; + +@@ -2720,14 +2721,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_ + + if (!ieee80211_vif_is_mesh(&sdata->vif) && + sdata->vif.type != NL80211_IFTYPE_ADHOC && +- sdata->vif.type != NL80211_IFTYPE_STATION) ++ sdata->vif.type != NL80211_IFTYPE_STATION && ++ sdata->vif.type != NL80211_IFTYPE_WDS) + return RX_DROP_MONITOR; + + switch (stype) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): + case cpu_to_le16(IEEE80211_STYPE_BEACON): + case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): +- /* process for all: mesh, mlme, ibss */ ++ /* process for all: mesh, mlme, ibss, wds */ + break; + case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): +@@ -3059,10 +3061,16 @@ static int prepare_for_handlers(struct i + } + break; + case NL80211_IFTYPE_WDS: +- if (bssid || !ieee80211_is_data(hdr->frame_control)) +- return 0; + if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2)) + return 0; ++ ++ if (ieee80211_is_data(hdr->frame_control) || ++ ieee80211_is_action(hdr->frame_control)) { ++ if (compare_ether_addr(sdata->vif.addr, hdr->addr1)) ++ return 0; ++ } else if (!ieee80211_is_beacon(hdr->frame_control)) ++ return 0; ++ + break; + case NL80211_IFTYPE_P2P_DEVICE: + if (!ieee80211_is_public_action(hdr, skb->len) && +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -149,6 +149,7 @@ static void cleanup_single_sta(struct st + * directly by station destruction. + */ + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { ++ kfree(sta->ampdu_mlme.tid_start_tx[i]); + tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); + if (!tid_tx) + continue; +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -32,7 +32,6 @@ + * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble + * frames. + * @WLAN_STA_WME: Station is a QoS-STA. +- * @WLAN_STA_WDS: Station is one of our WDS peers. + * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the + * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next + * frame to this station is transmitted. +@@ -66,7 +65,6 @@ enum ieee80211_sta_info_flags { + WLAN_STA_AUTHORIZED, + WLAN_STA_SHORT_PREAMBLE, + WLAN_STA_WME, +- WLAN_STA_WDS, + WLAN_STA_CLEAR_PS_FILT, + WLAN_STA_MFP, + WLAN_STA_BLOCK_BA, +@@ -203,6 +201,7 @@ struct tid_ampdu_rx { + * driver requested to close until the work for it runs + * @mtx: mutex to protect all TX data (except non-NULL assignments + * to tid_tx[idx], which are protected by the sta spinlock) ++ * tid_start_tx is also protected by sta->lock. + */ + struct sta_ampdu_mlme { + struct mutex mtx; +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -1778,9 +1778,13 @@ static void ath_tx_txqaddbuf(struct ath_ + } + + if (!internal) { +- txq->axq_depth++; +- if (bf_is_ampdu_not_probing(bf)) +- txq->axq_ampdu_depth++; ++ while (bf) { ++ txq->axq_depth++; ++ if (bf_is_ampdu_not_probing(bf)) ++ txq->axq_ampdu_depth++; ++ ++ bf = bf->bf_lastbf->bf_next; ++ } + } + } + +--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c +@@ -1183,7 +1183,7 @@ static int ath9k_htc_config(struct ieee8 + mutex_lock(&priv->htc_pm_lock); + + priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); +- if (priv->ps_idle) ++ if (!priv->ps_idle) + chip_reset = true; + + mutex_unlock(&priv->htc_pm_lock); |