|
|
@@ -0,0 +1,160 @@
|
|
|
+--- a/net/mac80211/rx.c
|
|
|
++++ b/net/mac80211/rx.c
|
|
|
+@@ -2330,13 +2330,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):
|
|
|
+@@ -2716,7 +2717,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);
|
|
|
+@@ -717,6 +694,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 =
|
|
|
+@@ -821,6 +862,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;
|