diff options
author | Zhu Yi <yi.zhu@intel.com> | 2009-11-30 21:18:37 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-12-22 13:31:15 -0500 |
commit | eaf85ca7fecb218fc41ff57c1642ca73b097aabb (patch) | |
tree | ad7965715f0cd67fe8946980ae2d1e9f3ea231a1 /net/mac80211/rx.c | |
parent | ca99861d5421c91f5a8fd3a77acb4b7be14f119d (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/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 106 |
1 files changed, 20 insertions, 86 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dbfd684e3e2e..a182e423109b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1541,16 +1541,10 @@ static ieee80211_rx_result debug_noinline | |||
1541 | ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | 1541 | ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) |
1542 | { | 1542 | { |
1543 | struct net_device *dev = rx->sdata->dev; | 1543 | struct net_device *dev = rx->sdata->dev; |
1544 | struct ieee80211_local *local = rx->local; | 1544 | struct sk_buff *skb = rx->skb; |
1545 | u16 ethertype; | ||
1546 | u8 *payload; | ||
1547 | struct sk_buff *skb = rx->skb, *frame = NULL; | ||
1548 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1545 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1549 | __le16 fc = hdr->frame_control; | 1546 | __le16 fc = hdr->frame_control; |
1550 | const struct ethhdr *eth; | 1547 | struct sk_buff_head frame_list; |
1551 | int remaining, err; | ||
1552 | u8 dst[ETH_ALEN]; | ||
1553 | u8 src[ETH_ALEN]; | ||
1554 | 1548 | ||
1555 | if (unlikely(!ieee80211_is_data(fc))) | 1549 | if (unlikely(!ieee80211_is_data(fc))) |
1556 | return RX_CONTINUE; | 1550 | return RX_CONTINUE; |
@@ -1561,94 +1555,34 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1561 | if (!(rx->flags & IEEE80211_RX_AMSDU)) | 1555 | if (!(rx->flags & IEEE80211_RX_AMSDU)) |
1562 | return RX_CONTINUE; | 1556 | return RX_CONTINUE; |
1563 | 1557 | ||
1564 | err = __ieee80211_data_to_8023(rx); | 1558 | if (ieee80211_has_a4(hdr->frame_control) && |
1565 | if (unlikely(err)) | 1559 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
1560 | !rx->sdata->u.vlan.sta) | ||
1566 | return RX_DROP_UNUSABLE; | 1561 | return RX_DROP_UNUSABLE; |
1567 | 1562 | ||
1568 | skb->dev = dev; | 1563 | if (is_multicast_ether_addr(hdr->addr1) && |
1569 | 1564 | ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | |
1570 | dev->stats.rx_packets++; | 1565 | rx->sdata->u.vlan.sta) || |
1571 | dev->stats.rx_bytes += skb->len; | 1566 | (rx->sdata->vif.type == NL80211_IFTYPE_STATION && |
1572 | 1567 | rx->sdata->u.mgd.use_4addr))) | |
1573 | /* skip the wrapping header */ | ||
1574 | eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); | ||
1575 | if (!eth) | ||
1576 | return RX_DROP_UNUSABLE; | 1568 | return RX_DROP_UNUSABLE; |
1577 | 1569 | ||
1578 | while (skb != frame) { | 1570 | skb->dev = dev; |
1579 | u8 padding; | 1571 | __skb_queue_head_init(&frame_list); |
1580 | __be16 len = eth->h_proto; | ||
1581 | unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); | ||
1582 | |||
1583 | remaining = skb->len; | ||
1584 | memcpy(dst, eth->h_dest, ETH_ALEN); | ||
1585 | memcpy(src, eth->h_source, ETH_ALEN); | ||
1586 | 1572 | ||
1587 | padding = ((4 - subframe_len) & 0x3); | 1573 | ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, |
1588 | /* the last MSDU has no padding */ | 1574 | rx->sdata->vif.type, |
1589 | if (subframe_len > remaining) | 1575 | rx->local->hw.extra_tx_headroom); |
1590 | return RX_DROP_UNUSABLE; | ||
1591 | 1576 | ||
1592 | skb_pull(skb, sizeof(struct ethhdr)); | 1577 | while (!skb_queue_empty(&frame_list)) { |
1593 | /* if last subframe reuse skb */ | 1578 | rx->skb = __skb_dequeue(&frame_list); |
1594 | if (remaining <= subframe_len + padding) | ||
1595 | frame = skb; | ||
1596 | else { | ||
1597 | /* | ||
1598 | * Allocate and reserve two bytes more for payload | ||
1599 | * alignment since sizeof(struct ethhdr) is 14. | ||
1600 | */ | ||
1601 | frame = dev_alloc_skb( | ||
1602 | ALIGN(local->hw.extra_tx_headroom, 4) + | ||
1603 | subframe_len + 2); | ||
1604 | |||
1605 | if (frame == NULL) | ||
1606 | return RX_DROP_UNUSABLE; | ||
1607 | |||
1608 | skb_reserve(frame, | ||
1609 | ALIGN(local->hw.extra_tx_headroom, 4) + | ||
1610 | sizeof(struct ethhdr) + 2); | ||
1611 | memcpy(skb_put(frame, ntohs(len)), skb->data, | ||
1612 | ntohs(len)); | ||
1613 | |||
1614 | eth = (struct ethhdr *) skb_pull(skb, ntohs(len) + | ||
1615 | padding); | ||
1616 | if (!eth) { | ||
1617 | dev_kfree_skb(frame); | ||
1618 | return RX_DROP_UNUSABLE; | ||
1619 | } | ||
1620 | } | ||
1621 | |||
1622 | skb_reset_network_header(frame); | ||
1623 | frame->dev = dev; | ||
1624 | frame->priority = skb->priority; | ||
1625 | rx->skb = frame; | ||
1626 | |||
1627 | payload = frame->data; | ||
1628 | ethertype = (payload[6] << 8) | payload[7]; | ||
1629 | |||
1630 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && | ||
1631 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
1632 | compare_ether_addr(payload, | ||
1633 | bridge_tunnel_header) == 0)) { | ||
1634 | /* remove RFC1042 or Bridge-Tunnel | ||
1635 | * encapsulation and replace EtherType */ | ||
1636 | skb_pull(frame, 6); | ||
1637 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||
1638 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||
1639 | } else { | ||
1640 | memcpy(skb_push(frame, sizeof(__be16)), | ||
1641 | &len, sizeof(__be16)); | ||
1642 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||
1643 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||
1644 | } | ||
1645 | 1579 | ||
1646 | if (!ieee80211_frame_allowed(rx, fc)) { | 1580 | if (!ieee80211_frame_allowed(rx, fc)) { |
1647 | if (skb == frame) /* last frame */ | 1581 | dev_kfree_skb(rx->skb); |
1648 | return RX_DROP_UNUSABLE; | ||
1649 | dev_kfree_skb(frame); | ||
1650 | continue; | 1582 | continue; |
1651 | } | 1583 | } |
1584 | dev->stats.rx_packets++; | ||
1585 | dev->stats.rx_bytes += rx->skb->len; | ||
1652 | 1586 | ||
1653 | ieee80211_deliver_skb(rx); | 1587 | ieee80211_deliver_skb(rx); |
1654 | } | 1588 | } |