summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/531-mac80211_fix_iftype_wds.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/531-mac80211_fix_iftype_wds.patch')
-rw-r--r--package/mac80211/patches/531-mac80211_fix_iftype_wds.patch160
1 files changed, 160 insertions, 0 deletions
diff --git a/package/mac80211/patches/531-mac80211_fix_iftype_wds.patch b/package/mac80211/patches/531-mac80211_fix_iftype_wds.patch
new file mode 100644
index 000000000..98a899323
--- /dev/null
+++ b/package/mac80211/patches/531-mac80211_fix_iftype_wds.patch
@@ -0,0 +1,160 @@
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2335,13 +2335,14 @@ 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_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_DEAUTH):
+ case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+@@ -2680,7 +2681,10 @@ static int prepare_for_handlers(struct i
+ }
+ break;
+ case NL80211_IFTYPE_WDS:
+- if (bssid || !ieee80211_is_data(hdr->frame_control))
++ if (bssid) {
++ if (!ieee80211_is_beacon(hdr->frame_control))
++ return 0;
++ } else if (!ieee80211_is_data(hdr->frame_control))
+ return 0;
+ if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
+ return 0;
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -178,7 +178,6 @@ static int ieee80211_do_open(struct net_
+ {
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+- struct sta_info *sta;
+ u32 changed = 0;
+ int res;
+ u32 hw_reconf_flags = 0;
+@@ -290,27 +289,6 @@ static int ieee80211_do_open(struct net_
+
+ 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;
+- }
+-
+- /* no locking required since STA is not live yet */
+- sta->flags |= WLAN_STA_AUTHORIZED;
+-
+- res = sta_info_insert(sta);
+- if (res) {
+- /* STA has been freed */
+- goto err_del_interface;
+- }
+-
+- rate_control_rate_init(sta);
+- }
+-
+ /*
+ * set_multicast_list will be invoked by the networking core
+ * which will check whether any increments here were done in
+@@ -344,8 +322,7 @@ static int ieee80211_do_open(struct net_
+ netif_tx_start_all_queues(dev);
+
+ return 0;
+- err_del_interface:
+- drv_remove_interface(local, &sdata->vif);
++
+ err_stop:
+ if (!local->open_count)
+ drv_stop(local);
+@@ -718,6 +695,70 @@ 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 = local->hw.conf.channel->band;
++ struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
++
++ rx_status = IEEE80211_SKB_RXCB(skb);
++ 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, &elems);
++
++ rates = ieee80211_sta_get_rates(local, &elems, band);
++
++ 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[local->hw.conf.channel->band] = rates;
++
++ if (elems.ht_cap_elem)
++ ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
++ elems.ht_cap_elem, &sta->sta.ht_cap);
++
++ if (elems.wmm_param)
++ set_sta_flags(sta, WLAN_STA_WME);
++
++ if (new) {
++ sta->flags = WLAN_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 =
+@@ -822,6 +863,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;