| @@ -529,121 +529,6 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, · 528 unmodified lines |
| 529 | 529 | } |
| 530 | 530 | EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr); |
| 531 | 531 | |
| 532 | | −int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, |
| 533 | | − enum nl80211_iftype iftype, |
| 534 | | − const u8 *bssid, bool qos) |
| 535 | | −{ |
| 536 | | − struct ieee80211_hdr hdr; |
| 537 | | − u16 hdrlen, ethertype; |
| 538 | | − __le16 fc; |
| 539 | | − const u8 *encaps_data; |
| 540 | | − int encaps_len, skip_header_bytes; |
| 541 | | − int nh_pos, h_pos; |
| 542 | | − int head_need; |
| 543 | | − |
| 544 | | − if (unlikely(skb->len < ETH_HLEN)) |
| 545 | | − return -EINVAL; |
| 546 | | − |
| 547 | | − nh_pos = skb_network_header(skb) - skb->data; |
| 548 | | − h_pos = skb_transport_header(skb) - skb->data; |
| 549 | | − |
| 550 | | − /* convert Ethernet header to proper 802.11 header (based on |
| 551 | | − * operation mode) */ |
| 552 | | − ethertype = (skb->data[12] << 8) | skb->data[13]; |
| 553 | | − fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
| 554 | | − |
| 555 | | − switch (iftype) { |
| 556 | | − case NL80211_IFTYPE_AP: |
| 557 | | − case NL80211_IFTYPE_AP_VLAN: |
| 558 | | − case NL80211_IFTYPE_P2P_GO: |
| 559 | | − fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
| 560 | | − /* DA BSSID SA */ |
| 561 | | − memcpy(hdr.addr1, skb->data, ETH_ALEN); |
| 562 | | − memcpy(hdr.addr2, addr, ETH_ALEN); |
| 563 | | − memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); |
| 564 | | − hdrlen = 24; |
| 565 | | − break; |
| 566 | | − case NL80211_IFTYPE_STATION: |
| 567 | | − case NL80211_IFTYPE_P2P_CLIENT: |
| 568 | | − fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
| 569 | | − /* BSSID SA DA */ |
| 570 | | − memcpy(hdr.addr1, bssid, ETH_ALEN); |
| 571 | | − memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
| 572 | | − memcpy(hdr.addr3, skb->data, ETH_ALEN); |
| 573 | | − hdrlen = 24; |
| 574 | | − break; |
| 575 | | − case NL80211_IFTYPE_OCB: |
| 576 | | − case NL80211_IFTYPE_ADHOC: |
| 577 | | − /* DA SA BSSID */ |
| 578 | | − memcpy(hdr.addr1, skb->data, ETH_ALEN); |
| 579 | | − memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
| 580 | | − memcpy(hdr.addr3, bssid, ETH_ALEN); |
| 581 | | − hdrlen = 24; |
| 582 | | − break; |
| 583 | | − default: |
| 584 | | − return -EOPNOTSUPP; |
| 585 | | − } |
| 586 | | − |
| 587 | | − if (qos) { |
| 588 | | − fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
| 589 | | − hdrlen += 2; |
| 590 | | − } |
| 591 | | − |
| 592 | | − hdr.frame_control = fc; |
| 593 | | − hdr.duration_id = 0; |
| 594 | | − hdr.seq_ctrl = 0; |
| 595 | | − |
| 596 | | − skip_header_bytes = ETH_HLEN; |
| 597 | | − if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { |
| 598 | | − encaps_data = bridge_tunnel_header; |
| 599 | | − encaps_len = sizeof(bridge_tunnel_header); |
| 600 | | − skip_header_bytes -= 2; |
| 601 | | − } else if (ethertype >= ETH_P_802_3_MIN) { |
| 602 | | − encaps_data = rfc1042_header; |
| 603 | | − encaps_len = sizeof(rfc1042_header); |
| 604 | | − skip_header_bytes -= 2; |
| 605 | | − } else { |
| 606 | | − encaps_data = NULL; |
| 607 | | − encaps_len = 0; |
| 608 | | − } |
| 609 | | − |
| 610 | | − skb_pull(skb, skip_header_bytes); |
| 611 | | − nh_pos -= skip_header_bytes; |
| 612 | | − h_pos -= skip_header_bytes; |
| 613 | | − |
| 614 | | − head_need = hdrlen + encaps_len - skb_headroom(skb); |
| 615 | | − |
| 616 | | − if (head_need > 0 || skb_cloned(skb)) { |
| 617 | | − head_need = max(head_need, 0); |
| 618 | | − if (head_need) |
| 619 | | − skb_orphan(skb); |
| 620 | | − |
| 621 | | − if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) |
| 622 | | − return -ENOMEM; |
| 623 | | − } |
| 624 | | − |
| 625 | | − if (encaps_data) { |
| 626 | | − memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); |
| 627 | | − nh_pos += encaps_len; |
| 628 | | − h_pos += encaps_len; |
| 629 | | − } |
| 630 | | − |
| 631 | | − memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); |
| 632 | | − |
| 633 | | − nh_pos += hdrlen; |
| 634 | | − h_pos += hdrlen; |
| 635 | | − |
| 636 | | − /* Update skb pointers to various headers since this modified frame |
| 637 | | − * is going to go through Linux networking code that may potentially |
| 638 | | − * need things like pointer to IP header. */ |
| 639 | | − skb_reset_mac_header(skb); |
| 640 | | − skb_set_network_header(skb, nh_pos); |
| 641 | | − skb_set_transport_header(skb, h_pos); |
| 642 | | − |
| 643 | | − return 0; |
| 644 | | −} |
| 645 | | −EXPORT_SYMBOL(ieee80211_data_from_8023); |
| 646 | | − |
| 647 | 532 | static void |
| 648 | 533 | __frame_add_frag(struct sk_buff *skb, struct page *page, |
| 649 | 534 | void *ptr, int len, int size) |