blob: 59b799b6b1704e9e8ca4c4c097aef9e0630c6f66 [file] [log] [blame]
developerff00d542023-06-08 11:36:33 +08001From 986e43b19ae9176093da35e0a844e65c8bf9ede7 Mon Sep 17 00:00:00 2001
developerdd6c8922023-02-15 16:38:49 +08002From: Felix Fietkau <nbd@nbd.name>
developerff00d542023-06-08 11:36:33 +08003Date: Mon, 13 Feb 2023 11:08:54 +0100
developerdd6c8922023-02-15 16:38:49 +08004Subject: [PATCH] wifi: mac80211: fix receiving A-MSDU frames on mesh
5 interfaces
6
7The current mac80211 mesh A-MSDU receive path fails to parse A-MSDU packets
8on mesh interfaces, because it assumes that the Mesh Control field is always
9directly after the 802.11 header.
10802.11-2020 9.3.2.2.2 Figure 9-70 shows that the Mesh Control field is
11actually part of the A-MSDU subframe header.
12This makes more sense, since it allows packets for multiple different
13destinations to be included in the same A-MSDU, as long as RA and TID are
14still the same.
15Another issue is the fact that the A-MSDU subframe length field was apparently
16accidentally defined as little-endian in the standard.
17
18In order to fix this, the mesh forwarding path needs happen at a different
19point in the receive path.
20
21ieee80211_data_to_8023_exthdr is changed to ignore the mesh control field
22and leave it in after the ethernet header. This also affects the source/dest
23MAC address fields, which now in the case of mesh point to the mesh SA/DA.
24
25ieee80211_amsdu_to_8023s is changed to deal with the endian difference and
26to add the Mesh Control length to the subframe length, since it's not covered
27by the MSDU length field.
28
29With these changes, the mac80211 will get the same packet structure for
30converted regular data packets and unpacked A-MSDU subframes.
31
32The mesh forwarding checks are now only performed after the A-MSDU decap.
33For locally received packets, the Mesh Control header is stripped away.
34For forwarded packets, a new 802.11 header gets added.
35
36Signed-off-by: Felix Fietkau <nbd@nbd.name>
developerff00d542023-06-08 11:36:33 +080037Link: https://lore.kernel.org/r/20230213100855.34315-4-nbd@nbd.name
38[fix fortify build error]
39Signed-off-by: Johannes Berg <johannes.berg@intel.com>
developerdd6c8922023-02-15 16:38:49 +080040---
developerff00d542023-06-08 11:36:33 +080041 .../wireless/marvell/mwifiex/11n_rxreorder.c | 2 +-
42 include/net/cfg80211.h | 27 +-
43 net/mac80211/rx.c | 350 ++++++++++--------
44 net/wireless/util.c | 120 +++---
45 4 files changed, 297 insertions(+), 202 deletions(-)
developerdd6c8922023-02-15 16:38:49 +080046
47--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
48+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
49@@ -33,7 +33,7 @@ static int mwifiex_11n_dispatch_amsdu_pk
50 skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
51
52 ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
53- priv->wdev.iftype, 0, NULL, NULL);
54+ priv->wdev.iftype, 0, NULL, NULL, false);
55
56 while (!skb_queue_empty(&list)) {
57 struct rx_packet_hdr *rx_hdr;
58--- a/include/net/cfg80211.h
59+++ b/include/net/cfg80211.h
60@@ -6208,11 +6208,36 @@ static inline int ieee80211_data_to_8023
61 * @extra_headroom: The hardware extra headroom for SKBs in the @list.
62 * @check_da: DA to check in the inner ethernet header, or NULL
63 * @check_sa: SA to check in the inner ethernet header, or NULL
64+ * @mesh_control: A-MSDU subframe header includes the mesh control field
65 */
66 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
67 const u8 *addr, enum nl80211_iftype iftype,
68 const unsigned int extra_headroom,
69- const u8 *check_da, const u8 *check_sa);
70+ const u8 *check_da, const u8 *check_sa,
71+ bool mesh_control);
72+
73+/**
74+ * ieee80211_get_8023_tunnel_proto - get RFC1042 or bridge tunnel encap protocol
75+ *
76+ * Check for RFC1042 or bridge tunnel header and fetch the encapsulated
77+ * protocol.
78+ *
79+ * @hdr: pointer to the MSDU payload
80+ * @proto: destination pointer to store the protocol
81+ * Return: true if encapsulation was found
82+ */
83+bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto);
84+
85+/**
86+ * ieee80211_strip_8023_mesh_hdr - strip mesh header from converted 802.3 frames
87+ *
88+ * Strip the mesh header, which was left in by ieee80211_data_to_8023 as part
89+ * of the MSDU data. Also move any source/destination addresses from the mesh
90+ * header to the ethernet header (if present).
91+ *
92+ * @skb: The 802.3 frame with embedded mesh header
93+ */
94+int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb);
95
96 /**
97 * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
98--- a/net/mac80211/rx.c
99+++ b/net/mac80211/rx.c
100@@ -2720,6 +2720,174 @@ ieee80211_deliver_skb(struct ieee80211_r
101 }
102 }
103
104+static ieee80211_rx_result
105+ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta,
106+ struct sk_buff *skb)
107+{
108+#ifdef CPTCFG_MAC80211_MESH
109+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
110+ struct ieee80211_local *local = sdata->local;
111+ uint16_t fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
112+ struct ieee80211_hdr hdr = {
113+ .frame_control = cpu_to_le16(fc)
114+ };
115+ struct ieee80211_hdr *fwd_hdr;
116+ struct ieee80211s_hdr *mesh_hdr;
117+ struct ieee80211_tx_info *info;
118+ struct sk_buff *fwd_skb;
119+ struct ethhdr *eth;
120+ bool multicast;
121+ int tailroom = 0;
122+ int hdrlen, mesh_hdrlen;
123+ u8 *qos;
124+
125+ if (!ieee80211_vif_is_mesh(&sdata->vif))
126+ return RX_CONTINUE;
127+
128+ if (!pskb_may_pull(skb, sizeof(*eth) + 6))
129+ return RX_DROP_MONITOR;
130+
131+ mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
132+ mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
133+
134+ if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
135+ return RX_DROP_MONITOR;
136+
137+ eth = (struct ethhdr *)skb->data;
138+ multicast = is_multicast_ether_addr(eth->h_dest);
139+
140+ mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
141+ if (!mesh_hdr->ttl)
142+ return RX_DROP_MONITOR;
143+
144+ /* frame is in RMC, don't forward */
145+ if (is_multicast_ether_addr(eth->h_dest) &&
146+ mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
147+ return RX_DROP_MONITOR;
148+
149+ /* Frame has reached destination. Don't forward */
150+ if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
151+ goto rx_accept;
152+
153+ if (!ifmsh->mshcfg.dot11MeshForwarding) {
154+ if (is_multicast_ether_addr(eth->h_dest))
155+ goto rx_accept;
156+
157+ return RX_DROP_MONITOR;
158+ }
159+
160+ /* forward packet */
161+ if (sdata->crypto_tx_tailroom_needed_cnt)
162+ tailroom = IEEE80211_ENCRYPT_TAILROOM;
163+
164+ if (!--mesh_hdr->ttl) {
165+ if (multicast)
166+ goto rx_accept;
167+
168+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
169+ return RX_DROP_MONITOR;
170+ }
171+
172+ if (mesh_hdr->flags & MESH_FLAGS_AE) {
173+ struct mesh_path *mppath;
174+ char *proxied_addr;
175+
176+ if (multicast)
177+ proxied_addr = mesh_hdr->eaddr1;
178+ else if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
179+ /* has_a4 already checked in ieee80211_rx_mesh_check */
180+ proxied_addr = mesh_hdr->eaddr2;
181+ else
182+ return RX_DROP_MONITOR;
183+
184+ rcu_read_lock();
185+ mppath = mpp_path_lookup(sdata, proxied_addr);
186+ if (!mppath) {
187+ mpp_path_add(sdata, proxied_addr, eth->h_source);
188+ } else {
189+ spin_lock_bh(&mppath->state_lock);
190+ if (!ether_addr_equal(mppath->mpp, eth->h_source))
191+ memcpy(mppath->mpp, eth->h_source, ETH_ALEN);
192+ mppath->exp_time = jiffies;
193+ spin_unlock_bh(&mppath->state_lock);
194+ }
195+ rcu_read_unlock();
196+ }
197+
198+ skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
199+
200+ ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
201+ eth->h_dest, eth->h_source);
202+ hdrlen = ieee80211_hdrlen(hdr.frame_control);
203+ if (multicast) {
204+ int extra_head = sizeof(struct ieee80211_hdr) - sizeof(*eth);
205+
206+ fwd_skb = skb_copy_expand(skb, local->tx_headroom + extra_head +
207+ IEEE80211_ENCRYPT_HEADROOM,
208+ tailroom, GFP_ATOMIC);
209+ if (!fwd_skb)
210+ goto rx_accept;
211+ } else {
212+ fwd_skb = skb;
213+ skb = NULL;
214+
215+ if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
216+ return RX_DROP_UNUSABLE;
217+ }
218+
219+ fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
220+ memcpy(fwd_hdr, &hdr, hdrlen - 2);
221+ qos = ieee80211_get_qos_ctl(fwd_hdr);
222+ qos[0] = qos[1] = 0;
223+
224+ skb_reset_mac_header(fwd_skb);
225+ hdrlen += mesh_hdrlen;
226+ if (ieee80211_get_8023_tunnel_proto(fwd_skb->data + hdrlen,
227+ &fwd_skb->protocol))
228+ hdrlen += ETH_ALEN;
229+ else
230+ fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
231+ skb_set_network_header(fwd_skb, hdrlen);
232+
233+ info = IEEE80211_SKB_CB(fwd_skb);
234+ memset(info, 0, sizeof(*info));
235+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
236+ info->control.vif = &sdata->vif;
237+ info->control.jiffies = jiffies;
238+ if (multicast) {
239+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
240+ memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
241+ /* update power mode indication when forwarding */
242+ ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
243+ } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
244+ /* mesh power mode flags updated in mesh_nexthop_lookup */
245+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
246+ } else {
247+ /* unable to resolve next hop */
248+ if (sta)
249+ mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
250+ hdr.addr3, 0,
251+ WLAN_REASON_MESH_PATH_NOFORWARD,
252+ sta->sta.addr);
253+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
254+ kfree_skb(fwd_skb);
255+ goto rx_accept;
256+ }
257+
258+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
259+ fwd_skb->dev = sdata->dev;
260+ ieee80211_add_pending_skb(local, fwd_skb);
261+
262+rx_accept:
263+ if (!skb)
264+ return RX_QUEUED;
265+
266+ ieee80211_strip_8023_mesh_hdr(skb);
267+#endif
268+
269+ return RX_CONTINUE;
270+}
271+
272 static ieee80211_rx_result debug_noinline
273 __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
274 {
275@@ -2728,8 +2896,10 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
276 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
277 __le16 fc = hdr->frame_control;
278 struct sk_buff_head frame_list;
279+ static ieee80211_rx_result res;
280 struct ethhdr ethhdr;
281 const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
282+ bool mesh = false;
283
284 if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
285 check_da = NULL;
286@@ -2746,6 +2916,8 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
287 break;
288 case NL80211_IFTYPE_MESH_POINT:
289 check_sa = NULL;
290+ check_da = NULL;
291+ mesh = true;
292 break;
293 default:
294 break;
295@@ -2763,17 +2935,29 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
296 ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
297 rx->sdata->vif.type,
298 rx->local->hw.extra_tx_headroom,
299- check_da, check_sa);
300+ check_da, check_sa, mesh);
301
302 while (!skb_queue_empty(&frame_list)) {
303 rx->skb = __skb_dequeue(&frame_list);
304
305- if (!ieee80211_frame_allowed(rx, fc)) {
306- dev_kfree_skb(rx->skb);
307+ res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
308+ switch (res) {
309+ case RX_QUEUED:
310 continue;
311+ case RX_CONTINUE:
312+ break;
313+ default:
314+ goto free;
315 }
316
317+ if (!ieee80211_frame_allowed(rx, fc))
318+ goto free;
319+
320 ieee80211_deliver_skb(rx);
321+ continue;
322+
323+free:
324+ dev_kfree_skb(rx->skb);
325 }
326
327 return RX_QUEUED;
328@@ -2806,6 +2990,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
329 if (!rx->sdata->u.mgd.use_4addr)
330 return RX_DROP_UNUSABLE;
331 break;
332+ case NL80211_IFTYPE_MESH_POINT:
333+ break;
334 default:
335 return RX_DROP_UNUSABLE;
336 }
337@@ -2834,155 +3020,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
338 return __ieee80211_rx_h_amsdu(rx, 0);
339 }
340
341-#ifdef CPTCFG_MAC80211_MESH
342-static ieee80211_rx_result
343-ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
344-{
345- struct ieee80211_hdr *fwd_hdr, *hdr;
346- struct ieee80211_tx_info *info;
347- struct ieee80211s_hdr *mesh_hdr;
348- struct sk_buff *skb = rx->skb, *fwd_skb;
349- struct ieee80211_local *local = rx->local;
350- struct ieee80211_sub_if_data *sdata = rx->sdata;
351- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
352- u16 ac, q, hdrlen;
353- int tailroom = 0;
354-
355- hdr = (struct ieee80211_hdr *) skb->data;
356- hdrlen = ieee80211_hdrlen(hdr->frame_control);
357-
358- /* make sure fixed part of mesh header is there, also checks skb len */
359- if (!pskb_may_pull(rx->skb, hdrlen + 6))
360- return RX_DROP_MONITOR;
361-
362- mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
363-
364- /* make sure full mesh header is there, also checks skb len */
365- if (!pskb_may_pull(rx->skb,
366- hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
367- return RX_DROP_MONITOR;
368-
369- /* reload pointers */
370- hdr = (struct ieee80211_hdr *) skb->data;
371- mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
372-
373- if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) {
374- int offset = hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr) +
375- sizeof(rfc1042_header);
376- __be16 ethertype;
377-
378- if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr) ||
379- skb_copy_bits(rx->skb, offset, &ethertype, 2) != 0 ||
380- ethertype != rx->sdata->control_port_protocol)
381- return RX_DROP_MONITOR;
382- }
383-
384- /* frame is in RMC, don't forward */
385- if (ieee80211_is_data(hdr->frame_control) &&
386- is_multicast_ether_addr(hdr->addr1) &&
387- mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
388- return RX_DROP_MONITOR;
389-
390- if (!ieee80211_is_data(hdr->frame_control))
391- return RX_CONTINUE;
392-
393- if (!mesh_hdr->ttl)
394- return RX_DROP_MONITOR;
395-
396- if (mesh_hdr->flags & MESH_FLAGS_AE) {
397- struct mesh_path *mppath;
398- char *proxied_addr;
399- char *mpp_addr;
400-
401- if (is_multicast_ether_addr(hdr->addr1)) {
402- mpp_addr = hdr->addr3;
403- proxied_addr = mesh_hdr->eaddr1;
404- } else if ((mesh_hdr->flags & MESH_FLAGS_AE) ==
405- MESH_FLAGS_AE_A5_A6) {
406- /* has_a4 already checked in ieee80211_rx_mesh_check */
407- mpp_addr = hdr->addr4;
408- proxied_addr = mesh_hdr->eaddr2;
409- } else {
410- return RX_DROP_MONITOR;
411- }
412-
413- rcu_read_lock();
414- mppath = mpp_path_lookup(sdata, proxied_addr);
415- if (!mppath) {
416- mpp_path_add(sdata, proxied_addr, mpp_addr);
417- } else {
418- spin_lock_bh(&mppath->state_lock);
419- if (!ether_addr_equal(mppath->mpp, mpp_addr))
420- memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
421- mppath->exp_time = jiffies;
422- spin_unlock_bh(&mppath->state_lock);
423- }
424- rcu_read_unlock();
425- }
426-
427- /* Frame has reached destination. Don't forward */
428- if (!is_multicast_ether_addr(hdr->addr1) &&
429- ether_addr_equal(sdata->vif.addr, hdr->addr3))
430- return RX_CONTINUE;
431-
432- ac = ieee802_1d_to_ac[skb->priority];
433- skb_set_queue_mapping(skb, ac);
434-
435- if (!--mesh_hdr->ttl) {
436- if (!is_multicast_ether_addr(hdr->addr1))
437- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh,
438- dropped_frames_ttl);
439- goto out;
440- }
441-
442- if (!ifmsh->mshcfg.dot11MeshForwarding)
443- goto out;
444-
445- if (sdata->crypto_tx_tailroom_needed_cnt)
446- tailroom = IEEE80211_ENCRYPT_TAILROOM;
447-
448- fwd_skb = skb_copy_expand(skb, local->tx_headroom +
449- IEEE80211_ENCRYPT_HEADROOM,
450- tailroom, GFP_ATOMIC);
451- if (!fwd_skb)
452- goto out;
453-
454- fwd_skb->dev = sdata->dev;
455- fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
456- fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
457- info = IEEE80211_SKB_CB(fwd_skb);
458- memset(info, 0, sizeof(*info));
459- info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
460- info->control.vif = &rx->sdata->vif;
461- info->control.jiffies = jiffies;
462- if (is_multicast_ether_addr(fwd_hdr->addr1)) {
463- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
464- memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
465- /* update power mode indication when forwarding */
466- ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
467- } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
468- /* mesh power mode flags updated in mesh_nexthop_lookup */
469- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
470- } else {
471- /* unable to resolve next hop */
472- mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
473- fwd_hdr->addr3, 0,
474- WLAN_REASON_MESH_PATH_NOFORWARD,
475- fwd_hdr->addr2);
476- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
477- kfree_skb(fwd_skb);
478- return RX_DROP_MONITOR;
479- }
480-
481- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
482- ieee80211_add_pending_skb(local, fwd_skb);
483- out:
484- if (is_multicast_ether_addr(hdr->addr1))
485- return RX_CONTINUE;
486- return RX_DROP_MONITOR;
487-}
488-#endif
489-
490 static ieee80211_rx_result debug_noinline
491 ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
492 {
493@@ -2991,6 +3028,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
494 struct net_device *dev = sdata->dev;
495 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
496 __le16 fc = hdr->frame_control;
497+ static ieee80211_rx_result res;
498 bool port_control;
499 int err;
500
501@@ -3017,6 +3055,10 @@ ieee80211_rx_h_data(struct ieee80211_rx_
502 if (unlikely(err))
503 return RX_DROP_UNUSABLE;
504
505+ res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
506+ if (res != RX_CONTINUE)
507+ return res;
508+
509 if (!ieee80211_frame_allowed(rx, fc))
510 return RX_DROP_MONITOR;
511
512@@ -3987,10 +4029,6 @@ static void ieee80211_rx_handlers(struct
513 CALL_RXH(ieee80211_rx_h_defragment);
514 CALL_RXH(ieee80211_rx_h_michael_mic_verify);
515 /* must be after MMIC verify so header is counted in MPDU mic */
516-#ifdef CPTCFG_MAC80211_MESH
517- if (ieee80211_vif_is_mesh(&rx->sdata->vif))
518- CALL_RXH(ieee80211_rx_h_mesh_fwding);
519-#endif
520 CALL_RXH(ieee80211_rx_h_amsdu);
521 CALL_RXH(ieee80211_rx_h_data);
522
523--- a/net/wireless/util.c
524+++ b/net/wireless/util.c
525@@ -542,7 +542,7 @@ unsigned int ieee80211_get_mesh_hdrlen(s
526 }
527 EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
528
529-static bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
530+bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
531 {
532 const __be16 *hdr_proto = hdr + ETH_ALEN;
533
534@@ -556,6 +556,49 @@ static bool ieee80211_get_8023_tunnel_pr
535
536 return true;
537 }
538+EXPORT_SYMBOL(ieee80211_get_8023_tunnel_proto);
539+
540+int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb)
541+{
542+ const void *mesh_addr;
543+ struct {
544+ struct ethhdr eth;
545+ u8 flags;
546+ } payload;
547+ int hdrlen;
548+ int ret;
549+
550+ ret = skb_copy_bits(skb, 0, &payload, sizeof(payload));
551+ if (ret)
552+ return ret;
553+
554+ hdrlen = sizeof(payload.eth) + __ieee80211_get_mesh_hdrlen(payload.flags);
555+
556+ if (likely(pskb_may_pull(skb, hdrlen + 8) &&
557+ ieee80211_get_8023_tunnel_proto(skb->data + hdrlen,
558+ &payload.eth.h_proto)))
559+ hdrlen += ETH_ALEN + 2;
560+ else if (!pskb_may_pull(skb, hdrlen))
561+ return -EINVAL;
562+
563+ mesh_addr = skb->data + sizeof(payload.eth) + ETH_ALEN;
564+ switch (payload.flags & MESH_FLAGS_AE) {
565+ case MESH_FLAGS_AE_A4:
566+ memcpy(&payload.eth.h_source, mesh_addr, ETH_ALEN);
567+ break;
568+ case MESH_FLAGS_AE_A5_A6:
developerff00d542023-06-08 11:36:33 +0800569+ memcpy(&payload.eth, mesh_addr, 2 * ETH_ALEN);
developerdd6c8922023-02-15 16:38:49 +0800570+ break;
571+ default:
572+ break;
573+ }
574+
575+ pskb_pull(skb, hdrlen - sizeof(payload.eth));
576+ memcpy(skb->data, &payload.eth, sizeof(payload.eth));
577+
578+ return 0;
579+}
580+EXPORT_SYMBOL(ieee80211_strip_8023_mesh_hdr);
581
582 int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
583 const u8 *addr, enum nl80211_iftype iftype,
584@@ -568,7 +611,6 @@ int ieee80211_data_to_8023_exthdr(struct
585 } payload;
586 struct ethhdr tmp;
587 u16 hdrlen;
588- u8 mesh_flags = 0;
589
590 if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
591 return -1;
592@@ -589,12 +631,6 @@ int ieee80211_data_to_8023_exthdr(struct
593 memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
594 memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
595
596- if (iftype == NL80211_IFTYPE_MESH_POINT &&
597- skb_copy_bits(skb, hdrlen, &mesh_flags, 1) < 0)
598- return -1;
599-
600- mesh_flags &= MESH_FLAGS_AE;
601-
602 switch (hdr->frame_control &
603 cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
604 case cpu_to_le16(IEEE80211_FCTL_TODS):
605@@ -608,17 +644,6 @@ int ieee80211_data_to_8023_exthdr(struct
606 iftype != NL80211_IFTYPE_AP_VLAN &&
607 iftype != NL80211_IFTYPE_STATION))
608 return -1;
609- if (iftype == NL80211_IFTYPE_MESH_POINT) {
610- if (mesh_flags == MESH_FLAGS_AE_A4)
611- return -1;
612- if (mesh_flags == MESH_FLAGS_AE_A5_A6 &&
613- skb_copy_bits(skb, hdrlen +
614- offsetof(struct ieee80211s_hdr, eaddr1),
615- tmp.h_dest, 2 * ETH_ALEN) < 0)
616- return -1;
617-
618- hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
619- }
620 break;
621 case cpu_to_le16(IEEE80211_FCTL_FROMDS):
622 if ((iftype != NL80211_IFTYPE_STATION &&
623@@ -627,16 +652,6 @@ int ieee80211_data_to_8023_exthdr(struct
624 (is_multicast_ether_addr(tmp.h_dest) &&
625 ether_addr_equal(tmp.h_source, addr)))
626 return -1;
627- if (iftype == NL80211_IFTYPE_MESH_POINT) {
628- if (mesh_flags == MESH_FLAGS_AE_A5_A6)
629- return -1;
630- if (mesh_flags == MESH_FLAGS_AE_A4 &&
631- skb_copy_bits(skb, hdrlen +
632- offsetof(struct ieee80211s_hdr, eaddr1),
633- tmp.h_source, ETH_ALEN) < 0)
634- return -1;
635- hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
636- }
637 break;
638 case cpu_to_le16(0):
639 if (iftype != NL80211_IFTYPE_ADHOC &&
640@@ -646,7 +661,7 @@ int ieee80211_data_to_8023_exthdr(struct
641 break;
642 }
643
644- if (likely(!is_amsdu &&
645+ if (likely(!is_amsdu && iftype != NL80211_IFTYPE_MESH_POINT &&
646 skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
647 ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) {
648 /* remove RFC1042 or Bridge-Tunnel encapsulation */
649@@ -722,7 +737,8 @@ __ieee80211_amsdu_copy_frag(struct sk_bu
650
651 static struct sk_buff *
652 __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
653- int offset, int len, bool reuse_frag)
654+ int offset, int len, bool reuse_frag,
655+ int min_len)
656 {
657 struct sk_buff *frame;
658 int cur_len = len;
659@@ -736,7 +752,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
660 * in the stack later.
661 */
662 if (reuse_frag)
663- cur_len = min_t(int, len, 32);
664+ cur_len = min_t(int, len, min_len);
665
666 /*
667 * Allocate and reserve two bytes more for payload
668@@ -746,6 +762,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
669 if (!frame)
670 return NULL;
671
672+ frame->priority = skb->priority;
673 skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
674 skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
675
676@@ -762,23 +779,37 @@ __ieee80211_amsdu_copy(struct sk_buff *s
677 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
678 const u8 *addr, enum nl80211_iftype iftype,
679 const unsigned int extra_headroom,
680- const u8 *check_da, const u8 *check_sa)
681+ const u8 *check_da, const u8 *check_sa,
682+ bool mesh_control)
683 {
684 unsigned int hlen = ALIGN(extra_headroom, 4);
685 struct sk_buff *frame = NULL;
686 int offset = 0, remaining;
687- struct ethhdr eth;
688+ struct {
689+ struct ethhdr eth;
690+ uint8_t flags;
691+ } hdr;
692 bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
693 bool reuse_skb = false;
694 bool last = false;
695+ int copy_len = sizeof(hdr.eth);
696+
697+ if (iftype == NL80211_IFTYPE_MESH_POINT)
698+ copy_len = sizeof(hdr);
699
700 while (!last) {
701 unsigned int subframe_len;
702- int len;
703+ int len, mesh_len = 0;
704 u8 padding;
705
706- skb_copy_bits(skb, offset, &eth, sizeof(eth));
707- len = ntohs(eth.h_proto);
708+ skb_copy_bits(skb, offset, &hdr, copy_len);
709+ if (iftype == NL80211_IFTYPE_MESH_POINT)
710+ mesh_len = __ieee80211_get_mesh_hdrlen(hdr.flags);
711+ if (mesh_control)
712+ len = le16_to_cpu(*(__le16 *)&hdr.eth.h_proto) + mesh_len;
713+ else
714+ len = ntohs(hdr.eth.h_proto);
715+
716 subframe_len = sizeof(struct ethhdr) + len;
717 padding = (4 - subframe_len) & 0x3;
718
719@@ -787,16 +818,16 @@ void ieee80211_amsdu_to_8023s(struct sk_
720 if (subframe_len > remaining)
721 goto purge;
722 /* mitigate A-MSDU aggregation injection attacks */
723- if (ether_addr_equal(eth.h_dest, rfc1042_header))
724+ if (ether_addr_equal(hdr.eth.h_dest, rfc1042_header))
725 goto purge;
726
727 offset += sizeof(struct ethhdr);
728 last = remaining <= subframe_len + padding;
729
730 /* FIXME: should we really accept multicast DA? */
731- if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
732- !ether_addr_equal(check_da, eth.h_dest)) ||
733- (check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
734+ if ((check_da && !is_multicast_ether_addr(hdr.eth.h_dest) &&
735+ !ether_addr_equal(check_da, hdr.eth.h_dest)) ||
736+ (check_sa && !ether_addr_equal(check_sa, hdr.eth.h_source))) {
737 offset += len + padding;
738 continue;
739 }
740@@ -808,7 +839,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
741 reuse_skb = true;
742 } else {
743 frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
744- reuse_frag);
745+ reuse_frag, 32 + mesh_len);
746 if (!frame)
747 goto purge;
748
749@@ -819,10 +850,11 @@ void ieee80211_amsdu_to_8023s(struct sk_
750 frame->dev = skb->dev;
751 frame->priority = skb->priority;
752
753- if (likely(ieee80211_get_8023_tunnel_proto(frame->data, &eth.h_proto)))
754+ if (likely(iftype != NL80211_IFTYPE_MESH_POINT &&
755+ ieee80211_get_8023_tunnel_proto(frame->data, &hdr.eth.h_proto)))
756 skb_pull(frame, ETH_ALEN + 2);
757
758- memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
759+ memcpy(skb_push(frame, sizeof(hdr.eth)), &hdr.eth, sizeof(hdr.eth));
760 __skb_queue_tail(list, frame);
761 }
762