aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/util.c
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2009-11-30 21:18:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-22 13:31:15 -0500
commiteaf85ca7fecb218fc41ff57c1642ca73b097aabb (patch)
treead7965715f0cd67fe8946980ae2d1e9f3ea231a1 /net/wireless/util.c
parentca99861d5421c91f5a8fd3a77acb4b7be14f119d (diff)
wireless: add ieee80211_amsdu_to_8023s
Move the A-MSDU handling code from mac80211 to cfg80211 so that more drivers can use it. The new created function ieee80211_amsdu_to_8023s converts an A-MSDU frame to a list of 802.3 frames. Cc: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r--net/wireless/util.c99
1 files changed, 97 insertions, 2 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c
index a3c841a255db..23557c1d0a9c 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -285,7 +285,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
285 } 285 }
286} 286}
287 287
288int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, 288int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
289 enum nl80211_iftype iftype) 289 enum nl80211_iftype iftype)
290{ 290{
291 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 291 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -383,7 +383,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
383} 383}
384EXPORT_SYMBOL(ieee80211_data_to_8023); 384EXPORT_SYMBOL(ieee80211_data_to_8023);
385 385
386int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, 386int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
387 enum nl80211_iftype iftype, u8 *bssid, bool qos) 387 enum nl80211_iftype iftype, u8 *bssid, bool qos)
388{ 388{
389 struct ieee80211_hdr hdr; 389 struct ieee80211_hdr hdr;
@@ -497,6 +497,101 @@ int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
497} 497}
498EXPORT_SYMBOL(ieee80211_data_from_8023); 498EXPORT_SYMBOL(ieee80211_data_from_8023);
499 499
500
501void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
502 const u8 *addr, enum nl80211_iftype iftype,
503 const unsigned int extra_headroom)
504{
505 struct sk_buff *frame = NULL;
506 u16 ethertype;
507 u8 *payload;
508 const struct ethhdr *eth;
509 int remaining, err;
510 u8 dst[ETH_ALEN], src[ETH_ALEN];
511
512 err = ieee80211_data_to_8023(skb, addr, iftype);
513 if (err)
514 goto out;
515
516 /* skip the wrapping header */
517 eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
518 if (!eth)
519 goto out;
520
521 while (skb != frame) {
522 u8 padding;
523 __be16 len = eth->h_proto;
524 unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
525
526 remaining = skb->len;
527 memcpy(dst, eth->h_dest, ETH_ALEN);
528 memcpy(src, eth->h_source, ETH_ALEN);
529
530 padding = (4 - subframe_len) & 0x3;
531 /* the last MSDU has no padding */
532 if (subframe_len > remaining)
533 goto purge;
534
535 skb_pull(skb, sizeof(struct ethhdr));
536 /* reuse skb for the last subframe */
537 if (remaining <= subframe_len + padding)
538 frame = skb;
539 else {
540 unsigned int hlen = ALIGN(extra_headroom, 4);
541 /*
542 * Allocate and reserve two bytes more for payload
543 * alignment since sizeof(struct ethhdr) is 14.
544 */
545 frame = dev_alloc_skb(hlen + subframe_len + 2);
546 if (!frame)
547 goto purge;
548
549 skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
550 memcpy(skb_put(frame, ntohs(len)), skb->data,
551 ntohs(len));
552
553 eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
554 padding);
555 if (!eth) {
556 dev_kfree_skb(frame);
557 goto purge;
558 }
559 }
560
561 skb_reset_network_header(frame);
562 frame->dev = skb->dev;
563 frame->priority = skb->priority;
564
565 payload = frame->data;
566 ethertype = (payload[6] << 8) | payload[7];
567
568 if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
569 ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
570 compare_ether_addr(payload,
571 bridge_tunnel_header) == 0)) {
572 /* remove RFC1042 or Bridge-Tunnel
573 * encapsulation and replace EtherType */
574 skb_pull(frame, 6);
575 memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
576 memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
577 } else {
578 memcpy(skb_push(frame, sizeof(__be16)), &len,
579 sizeof(__be16));
580 memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
581 memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
582 }
583 __skb_queue_tail(list, frame);
584 }
585
586 return;
587
588 purge:
589 __skb_queue_purge(list);
590 out:
591 dev_kfree_skb(skb);
592}
593EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
594
500/* Given a data frame determine the 802.1p/1d tag to use. */ 595/* Given a data frame determine the 802.1p/1d tag to use. */
501unsigned int cfg80211_classify8021d(struct sk_buff *skb) 596unsigned int cfg80211_classify8021d(struct sk_buff *skb)
502{ 597{