mac80211: implement wds sta support (wds ap support work in progress, needs hostapd...
[openwrt/svn-archive/archive.git] / package / mac80211 / patches / 510-mac80211_4addr_vlan.patch
1 --- a/net/mac80211/ieee80211_i.h
2 +++ b/net/mac80211/ieee80211_i.h
3 @@ -208,6 +208,9 @@ struct ieee80211_if_wds {
4
5 struct ieee80211_if_vlan {
6 struct list_head list;
7 +
8 + /* used for all tx if the VLAN is configured to 4-addr mode */
9 + struct sta_info *sta;
10 };
11
12 struct mesh_stats {
13 @@ -457,6 +460,8 @@ struct ieee80211_sub_if_data {
14 int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
15 int max_ratectrl_rateidx; /* max TX rateidx for rate control */
16
17 + bool use_4addr; /* use 4-address frames */
18 +
19 union {
20 struct ieee80211_if_ap ap;
21 struct ieee80211_if_wds wds;
22 --- a/net/mac80211/cfg.c
23 +++ b/net/mac80211/cfg.c
24 @@ -36,6 +36,24 @@ static bool nl80211_type_check(enum nl80
25 }
26 }
27
28 +static bool nl80211_params_check(enum nl80211_iftype type,
29 + struct vif_params *params)
30 +{
31 + if (!nl80211_type_check(type))
32 + return false;
33 +
34 + if (params->use_4addr > 0) {
35 + switch(type) {
36 + case NL80211_IFTYPE_AP_VLAN:
37 + case NL80211_IFTYPE_STATION:
38 + break;
39 + default:
40 + return false;
41 + }
42 + }
43 + return true;
44 +}
45 +
46 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
47 enum nl80211_iftype type, u32 *flags,
48 struct vif_params *params)
49 @@ -45,7 +63,7 @@ static int ieee80211_add_iface(struct wi
50 struct ieee80211_sub_if_data *sdata;
51 int err;
52
53 - if (!nl80211_type_check(type))
54 + if (!nl80211_params_check(type, params))
55 return -EINVAL;
56
57 err = ieee80211_if_add(local, name, &dev, type, params);
58 @@ -75,7 +93,7 @@ static int ieee80211_change_iface(struct
59 if (netif_running(dev))
60 return -EBUSY;
61
62 - if (!nl80211_type_check(type))
63 + if (!nl80211_params_check(type, params))
64 return -EINVAL;
65
66 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
67 @@ -89,6 +107,9 @@ static int ieee80211_change_iface(struct
68 params->mesh_id_len,
69 params->mesh_id);
70
71 + if (params->use_4addr >= 0)
72 + sdata->use_4addr = !!params->use_4addr;
73 +
74 if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
75 return 0;
76
77 @@ -806,6 +827,13 @@ static int ieee80211_change_station(stru
78 return -EINVAL;
79 }
80
81 + if (vlansdata->use_4addr) {
82 + if (vlansdata->u.vlan.sta)
83 + return -EBUSY;
84 +
85 + rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
86 + }
87 +
88 sta->sdata = vlansdata;
89 ieee80211_send_layer2_update(sta);
90 }
91 --- a/net/mac80211/sta_info.c
92 +++ b/net/mac80211/sta_info.c
93 @@ -489,6 +489,9 @@ static void __sta_info_unlink(struct sta
94 local->num_sta--;
95 local->sta_generation++;
96
97 + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
98 + rcu_assign_pointer(sdata->u.vlan.sta, NULL);
99 +
100 if (local->ops->sta_notify) {
101 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
102 sdata = container_of(sdata->bss,
103 --- a/net/mac80211/tx.c
104 +++ b/net/mac80211/tx.c
105 @@ -1046,7 +1046,10 @@ ieee80211_tx_prepare(struct ieee80211_su
106
107 hdr = (struct ieee80211_hdr *) skb->data;
108
109 - tx->sta = sta_info_get(local, hdr->addr1);
110 + if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
111 + tx->sta = rcu_dereference(sdata->u.vlan.sta);
112 + if (!tx->sta)
113 + tx->sta = sta_info_get(local, hdr->addr1);
114
115 if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
116 (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
117 @@ -1608,7 +1611,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s
118 const u8 *encaps_data;
119 int encaps_len, skip_header_bytes;
120 int nh_pos, h_pos;
121 - struct sta_info *sta;
122 + struct sta_info *sta = NULL;
123 u32 sta_flags = 0;
124
125 if (unlikely(skb->len < ETH_HLEN)) {
126 @@ -1625,8 +1628,25 @@ netdev_tx_t ieee80211_subif_start_xmit(s
127 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
128
129 switch (sdata->vif.type) {
130 - case NL80211_IFTYPE_AP:
131 case NL80211_IFTYPE_AP_VLAN:
132 + rcu_read_lock();
133 + if (sdata->use_4addr)
134 + sta = rcu_dereference(sdata->u.vlan.sta);
135 + if (sta) {
136 + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
137 + /* RA TA DA SA */
138 + memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
139 + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
140 + memcpy(hdr.addr3, skb->data, ETH_ALEN);
141 + memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
142 + hdrlen = 30;
143 + sta_flags = get_sta_flags(sta);
144 + }
145 + rcu_read_unlock();
146 + if (sta)
147 + break;
148 + /* fall through */
149 + case NL80211_IFTYPE_AP:
150 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
151 /* DA BSSID SA */
152 memcpy(hdr.addr1, skb->data, ETH_ALEN);
153 @@ -1700,12 +1720,21 @@ netdev_tx_t ieee80211_subif_start_xmit(s
154 break;
155 #endif
156 case NL80211_IFTYPE_STATION:
157 - fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
158 - /* BSSID SA DA */
159 memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
160 - memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
161 - memcpy(hdr.addr3, skb->data, ETH_ALEN);
162 - hdrlen = 24;
163 + if (sdata->use_4addr && ethertype != ETH_P_PAE) {
164 + fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
165 + /* RA TA DA SA */
166 + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
167 + memcpy(hdr.addr3, skb->data, ETH_ALEN);
168 + memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
169 + hdrlen = 30;
170 + } else {
171 + fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
172 + /* BSSID SA DA */
173 + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
174 + memcpy(hdr.addr3, skb->data, ETH_ALEN);
175 + hdrlen = 24;
176 + }
177 break;
178 case NL80211_IFTYPE_ADHOC:
179 /* DA SA BSSID */
180 --- a/net/mac80211/iface.c
181 +++ b/net/mac80211/iface.c
182 @@ -772,6 +772,7 @@ int ieee80211_if_change_type(struct ieee
183 ieee80211_mandatory_rates(sdata->local,
184 sdata->local->hw.conf.channel->band);
185 sdata->drop_unencrypted = 0;
186 + sdata->use_4addr = 0;
187
188 return 0;
189 }
190 @@ -853,6 +854,9 @@ int ieee80211_if_add(struct ieee80211_lo
191 params->mesh_id_len,
192 params->mesh_id);
193
194 + if (params && params->use_4addr >= 0)
195 + sdata->use_4addr = !!params->use_4addr;
196 +
197 mutex_lock(&local->iflist_mtx);
198 list_add_tail_rcu(&sdata->list, &local->interfaces);
199 mutex_unlock(&local->iflist_mtx);
200 --- a/net/mac80211/rx.c
201 +++ b/net/mac80211/rx.c
202 @@ -1237,6 +1237,13 @@ __ieee80211_data_to_8023(struct ieee8021
203 {
204 struct net_device *dev = rx->dev;
205 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
206 + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
207 +
208 + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
209 + ieee80211_has_a4(hdr->frame_control))
210 + return -1;
211 + if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
212 + return -1;
213
214 return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
215 }
216 @@ -1590,6 +1597,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
217 {
218 struct net_device *dev = rx->dev;
219 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
220 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
221 __le16 fc = hdr->frame_control;
222 int err;
223
224 @@ -1599,6 +1607,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_
225 if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
226 return RX_DROP_MONITOR;
227
228 + /*
229 + * Allow the cooked monitor interface of an AP to see 4-addr frames so
230 + * that a 4-addr station can be detected and moved into a separate VLAN
231 + */
232 + if (ieee80211_has_a4(hdr->frame_control) &&
233 + sdata->vif.type == NL80211_IFTYPE_AP)
234 + return RX_DROP_MONITOR;
235 +
236 err = __ieee80211_data_to_8023(rx);
237 if (unlikely(err))
238 return RX_DROP_UNUSABLE;
239 @@ -2039,7 +2055,7 @@ static int prepare_for_handlers(struct i
240
241 switch (sdata->vif.type) {
242 case NL80211_IFTYPE_STATION:
243 - if (!bssid)
244 + if (!bssid && !sdata->use_4addr)
245 return 0;
246 if (!multicast &&
247 compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
248 --- a/net/wireless/util.c
249 +++ b/net/wireless/util.c
250 @@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buf
251 break;
252 case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
253 if (unlikely(iftype != NL80211_IFTYPE_WDS &&
254 - iftype != NL80211_IFTYPE_MESH_POINT))
255 + iftype != NL80211_IFTYPE_MESH_POINT &&
256 + iftype != NL80211_IFTYPE_AP_VLAN &&
257 + iftype != NL80211_IFTYPE_STATION))
258 return -1;
259 if (iftype == NL80211_IFTYPE_MESH_POINT) {
260 struct ieee80211s_hdr *meshdr =