aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2016-02-02 08:39:09 -0500
committerJohannes Berg <johannes.berg@intel.com>2016-02-24 03:04:33 -0500
commit2d1c304cb2d5cf28d8362496bd9ea6aadf4f01d2 (patch)
treec8634cadd97bcc9e6de2cbdf48fcc09918c841fc /net/wireless
parent88665f5a797a832ff7926ad2287ee41738bc09b9 (diff)
cfg80211: add function for 802.3 conversion with separate output buffer
Use skb_copy_bits in preparation for allowing fragmented skbs Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/util.c106
1 files changed, 53 insertions, 53 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6a407699a900..f75f6010eb08 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
393} 393}
394EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); 394EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
395 395
396unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) 396static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags)
397{ 397{
398 int ae = meshhdr->flags & MESH_FLAGS_AE; 398 int ae = flags & MESH_FLAGS_AE;
399 /* 802.11-2012, 8.2.4.7.3 */ 399 /* 802.11-2012, 8.2.4.7.3 */
400 switch (ae) { 400 switch (ae) {
401 default: 401 default:
@@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
407 return 18; 407 return 18;
408 } 408 }
409} 409}
410
411unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
412{
413 return __ieee80211_get_mesh_hdrlen(meshhdr->flags);
414}
410EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); 415EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
411 416
412int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, 417static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
413 enum nl80211_iftype iftype) 418 const u8 *addr, enum nl80211_iftype iftype)
414{ 419{
415 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 420 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
416 u16 hdrlen, ethertype; 421 struct {
417 u8 *payload; 422 u8 hdr[ETH_ALEN] __aligned(2);
418 u8 dst[ETH_ALEN]; 423 __be16 proto;
419 u8 src[ETH_ALEN] __aligned(2); 424 } payload;
425 struct ethhdr tmp;
426 u16 hdrlen;
427 u8 mesh_flags = 0;
420 428
421 if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) 429 if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
422 return -1; 430 return -1;
423 431
424 hdrlen = ieee80211_hdrlen(hdr->frame_control); 432 hdrlen = ieee80211_hdrlen(hdr->frame_control);
433 if (skb->len < hdrlen + 8)
434 return -1;
425 435
426 /* convert IEEE 802.11 header + possible LLC headers into Ethernet 436 /* convert IEEE 802.11 header + possible LLC headers into Ethernet
427 * header 437 * header
@@ -432,8 +442,11 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
432 * 1 0 BSSID SA DA n/a 442 * 1 0 BSSID SA DA n/a
433 * 1 1 RA TA DA SA 443 * 1 1 RA TA DA SA
434 */ 444 */
435 memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); 445 memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
436 memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); 446 memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
447
448 if (iftype == NL80211_IFTYPE_MESH_POINT)
449 skb_copy_bits(skb, hdrlen, &mesh_flags, 1);
437 450
438 switch (hdr->frame_control & 451 switch (hdr->frame_control &
439 cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { 452 cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
@@ -450,44 +463,31 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
450 iftype != NL80211_IFTYPE_STATION)) 463 iftype != NL80211_IFTYPE_STATION))
451 return -1; 464 return -1;
452 if (iftype == NL80211_IFTYPE_MESH_POINT) { 465 if (iftype == NL80211_IFTYPE_MESH_POINT) {
453 struct ieee80211s_hdr *meshdr = 466 if (mesh_flags & MESH_FLAGS_AE_A4)
454 (struct ieee80211s_hdr *) (skb->data + hdrlen);
455 /* make sure meshdr->flags is on the linear part */
456 if (!pskb_may_pull(skb, hdrlen + 1))
457 return -1;
458 if (meshdr->flags & MESH_FLAGS_AE_A4)
459 return -1; 467 return -1;
460 if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { 468 if (mesh_flags & MESH_FLAGS_AE_A5_A6) {
461 skb_copy_bits(skb, hdrlen + 469 skb_copy_bits(skb, hdrlen +
462 offsetof(struct ieee80211s_hdr, eaddr1), 470 offsetof(struct ieee80211s_hdr, eaddr1),
463 dst, ETH_ALEN); 471 tmp.h_dest, 2 * ETH_ALEN);
464 skb_copy_bits(skb, hdrlen +
465 offsetof(struct ieee80211s_hdr, eaddr2),
466 src, ETH_ALEN);
467 } 472 }
468 hdrlen += ieee80211_get_mesh_hdrlen(meshdr); 473 hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
469 } 474 }
470 break; 475 break;
471 case cpu_to_le16(IEEE80211_FCTL_FROMDS): 476 case cpu_to_le16(IEEE80211_FCTL_FROMDS):
472 if ((iftype != NL80211_IFTYPE_STATION && 477 if ((iftype != NL80211_IFTYPE_STATION &&
473 iftype != NL80211_IFTYPE_P2P_CLIENT && 478 iftype != NL80211_IFTYPE_P2P_CLIENT &&
474 iftype != NL80211_IFTYPE_MESH_POINT) || 479 iftype != NL80211_IFTYPE_MESH_POINT) ||
475 (is_multicast_ether_addr(dst) && 480 (is_multicast_ether_addr(tmp.h_dest) &&
476 ether_addr_equal(src, addr))) 481 ether_addr_equal(tmp.h_source, addr)))
477 return -1; 482 return -1;
478 if (iftype == NL80211_IFTYPE_MESH_POINT) { 483 if (iftype == NL80211_IFTYPE_MESH_POINT) {
479 struct ieee80211s_hdr *meshdr = 484 if (mesh_flags & MESH_FLAGS_AE_A5_A6)
480 (struct ieee80211s_hdr *) (skb->data + hdrlen);
481 /* make sure meshdr->flags is on the linear part */
482 if (!pskb_may_pull(skb, hdrlen + 1))
483 return -1; 485 return -1;
484 if (meshdr->flags & MESH_FLAGS_AE_A5_A6) 486 if (mesh_flags & MESH_FLAGS_AE_A4)
485 return -1;
486 if (meshdr->flags & MESH_FLAGS_AE_A4)
487 skb_copy_bits(skb, hdrlen + 487 skb_copy_bits(skb, hdrlen +
488 offsetof(struct ieee80211s_hdr, eaddr1), 488 offsetof(struct ieee80211s_hdr, eaddr1),
489 src, ETH_ALEN); 489 tmp.h_source, ETH_ALEN);
490 hdrlen += ieee80211_get_mesh_hdrlen(meshdr); 490 hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
491 } 491 }
492 break; 492 break;
493 case cpu_to_le16(0): 493 case cpu_to_le16(0):
@@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
498 break; 498 break;
499 } 499 }
500 500
501 if (!pskb_may_pull(skb, hdrlen + 8)) 501 skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
502 return -1; 502 tmp.h_proto = payload.proto;
503
504 payload = skb->data + hdrlen;
505 ethertype = (payload[6] << 8) | payload[7];
506 503
507 if (likely((ether_addr_equal(payload, rfc1042_header) && 504 if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
508 ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || 505 tmp.h_proto != htons(ETH_P_AARP) &&
509 ether_addr_equal(payload, bridge_tunnel_header))) { 506 tmp.h_proto != htons(ETH_P_IPX)) ||
507 ether_addr_equal(payload.hdr, bridge_tunnel_header)))
510 /* remove RFC1042 or Bridge-Tunnel encapsulation and 508 /* remove RFC1042 or Bridge-Tunnel encapsulation and
511 * replace EtherType */ 509 * replace EtherType */
512 skb_pull(skb, hdrlen + 6); 510 hdrlen += ETH_ALEN + 2;
513 memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); 511 else
514 memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); 512 tmp.h_proto = htons(skb->len);
515 } else { 513
516 struct ethhdr *ehdr; 514 pskb_pull(skb, hdrlen);
517 __be16 len;
518 515
519 skb_pull(skb, hdrlen); 516 if (!ehdr)
520 len = htons(skb->len);
521 ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); 517 ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
522 memcpy(ehdr->h_dest, dst, ETH_ALEN); 518 memcpy(ehdr, &tmp, sizeof(tmp));
523 memcpy(ehdr->h_source, src, ETH_ALEN); 519
524 ehdr->h_proto = len;
525 }
526 return 0; 520 return 0;
527} 521}
522
523int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
524 enum nl80211_iftype iftype)
525{
526 return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
527}
528EXPORT_SYMBOL(ieee80211_data_to_8023); 528EXPORT_SYMBOL(ieee80211_data_to_8023);
529 529
530int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, 530int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,