| @@ -529,121 +529,6 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, · 528 unmodified lines |
| 529 | } | 529 | } |
| 530 | EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr); | 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 | static void | 532 | static void |
| 648 | __frame_add_frag(struct sk_buff *skb, struct page *page, | 533 | __frame_add_frag(struct sk_buff *skb, struct page *page, |
| 649 | void *ptr, int len, int size) | 534 | void *ptr, int len, int size) |