mac80211: fix support for iftype wds
[openwrt/svn-archive/archive.git] / package / mac80211 / patches / 551-mac80211_fix_iftype_wds.patch
1 --- a/net/mac80211/rx.c
2 +++ b/net/mac80211/rx.c
3 @@ -2330,13 +2330,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
4
5 if (!ieee80211_vif_is_mesh(&sdata->vif) &&
6 sdata->vif.type != NL80211_IFTYPE_ADHOC &&
7 - sdata->vif.type != NL80211_IFTYPE_STATION)
8 + sdata->vif.type != NL80211_IFTYPE_STATION &&
9 + sdata->vif.type != NL80211_IFTYPE_WDS)
10 return RX_DROP_MONITOR;
11
12 switch (stype) {
13 case cpu_to_le16(IEEE80211_STYPE_BEACON):
14 case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
15 - /* process for all: mesh, mlme, ibss */
16 + /* process for all: mesh, mlme, ibss, wds */
17 break;
18 case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
19 case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
20 @@ -2716,7 +2717,10 @@ static int prepare_for_handlers(struct i
21 }
22 break;
23 case NL80211_IFTYPE_WDS:
24 - if (bssid || !ieee80211_is_data(hdr->frame_control))
25 + if (bssid) {
26 + if (!ieee80211_is_beacon(hdr->frame_control))
27 + return 0;
28 + } else if (!ieee80211_is_data(hdr->frame_control))
29 return 0;
30 if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
31 return 0;
32 --- a/net/mac80211/iface.c
33 +++ b/net/mac80211/iface.c
34 @@ -178,7 +178,6 @@ static int ieee80211_do_open(struct net_
35 {
36 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
37 struct ieee80211_local *local = sdata->local;
38 - struct sta_info *sta;
39 u32 changed = 0;
40 int res;
41 u32 hw_reconf_flags = 0;
42 @@ -290,27 +289,6 @@ static int ieee80211_do_open(struct net_
43
44 set_bit(SDATA_STATE_RUNNING, &sdata->state);
45
46 - if (sdata->vif.type == NL80211_IFTYPE_WDS) {
47 - /* Create STA entry for the WDS peer */
48 - sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
49 - GFP_KERNEL);
50 - if (!sta) {
51 - res = -ENOMEM;
52 - goto err_del_interface;
53 - }
54 -
55 - /* no locking required since STA is not live yet */
56 - sta->flags |= WLAN_STA_AUTHORIZED;
57 -
58 - res = sta_info_insert(sta);
59 - if (res) {
60 - /* STA has been freed */
61 - goto err_del_interface;
62 - }
63 -
64 - rate_control_rate_init(sta);
65 - }
66 -
67 /*
68 * set_multicast_list will be invoked by the networking core
69 * which will check whether any increments here were done in
70 @@ -344,8 +322,7 @@ static int ieee80211_do_open(struct net_
71 netif_tx_start_all_queues(dev);
72
73 return 0;
74 - err_del_interface:
75 - drv_remove_interface(local, &sdata->vif);
76 +
77 err_stop:
78 if (!local->open_count)
79 drv_stop(local);
80 @@ -717,6 +694,70 @@ static void ieee80211_if_setup(struct ne
81 dev->destructor = free_netdev;
82 }
83
84 +static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
85 + struct sk_buff *skb)
86 +{
87 + struct ieee80211_local *local = sdata->local;
88 + struct ieee80211_rx_status *rx_status;
89 + struct ieee802_11_elems elems;
90 + struct ieee80211_mgmt *mgmt;
91 + struct sta_info *sta;
92 + size_t baselen;
93 + u32 rates = 0;
94 + u16 stype;
95 + bool new = false;
96 + enum ieee80211_band band = local->hw.conf.channel->band;
97 + struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
98 +
99 + rx_status = IEEE80211_SKB_RXCB(skb);
100 + mgmt = (struct ieee80211_mgmt *) skb->data;
101 + stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
102 +
103 + if (stype != IEEE80211_STYPE_BEACON)
104 + return;
105 +
106 + baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
107 + if (baselen > skb->len)
108 + return;
109 +
110 + ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
111 + skb->len - baselen, &elems);
112 +
113 + rates = ieee80211_sta_get_rates(local, &elems, band);
114 +
115 + rcu_read_lock();
116 +
117 + sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
118 +
119 + if (!sta) {
120 + rcu_read_unlock();
121 + sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
122 + GFP_KERNEL);
123 + if (!sta)
124 + return;
125 +
126 + new = true;
127 + }
128 +
129 + sta->last_rx = jiffies;
130 + sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
131 +
132 + if (elems.ht_cap_elem)
133 + ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
134 + elems.ht_cap_elem, &sta->sta.ht_cap);
135 +
136 + if (elems.wmm_param)
137 + set_sta_flags(sta, WLAN_STA_WME);
138 +
139 + if (new) {
140 + sta->flags = WLAN_STA_AUTHORIZED;
141 + rate_control_rate_init(sta);
142 + sta_info_insert_rcu(sta);
143 + }
144 +
145 + rcu_read_unlock();
146 +}
147 +
148 static void ieee80211_iface_work(struct work_struct *work)
149 {
150 struct ieee80211_sub_if_data *sdata =
151 @@ -821,6 +862,9 @@ static void ieee80211_iface_work(struct
152 break;
153 ieee80211_mesh_rx_queued_mgmt(sdata, skb);
154 break;
155 + case NL80211_IFTYPE_WDS:
156 + ieee80211_wds_rx_queued_mgmt(sdata, skb);
157 + break;
158 default:
159 WARN(1, "frame for unexpected interface type");
160 break;