|
@@ -529,121 +529,6 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
|
|
|
}
|
|
|
EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
|
|
|
|
|
|
-int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
|
|
- enum nl80211_iftype iftype,
|
|
|
- const u8 *bssid, bool qos)
|
|
|
-{
|
|
|
- struct ieee80211_hdr hdr;
|
|
|
- u16 hdrlen, ethertype;
|
|
|
- __le16 fc;
|
|
|
- const u8 *encaps_data;
|
|
|
- int encaps_len, skip_header_bytes;
|
|
|
- int nh_pos, h_pos;
|
|
|
- int head_need;
|
|
|
-
|
|
|
- if (unlikely(skb->len < ETH_HLEN))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- nh_pos = skb_network_header(skb) - skb->data;
|
|
|
- h_pos = skb_transport_header(skb) - skb->data;
|
|
|
-
|
|
|
- /* convert Ethernet header to proper 802.11 header (based on
|
|
|
- * operation mode) */
|
|
|
- ethertype = (skb->data[12] << 8) | skb->data[13];
|
|
|
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
|
|
|
-
|
|
|
- switch (iftype) {
|
|
|
- case NL80211_IFTYPE_AP:
|
|
|
- case NL80211_IFTYPE_AP_VLAN:
|
|
|
- case NL80211_IFTYPE_P2P_GO:
|
|
|
- fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
|
|
- /* DA BSSID SA */
|
|
|
- memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
|
|
- memcpy(hdr.addr2, addr, ETH_ALEN);
|
|
|
- memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
- hdrlen = 24;
|
|
|
- break;
|
|
|
- case NL80211_IFTYPE_STATION:
|
|
|
- case NL80211_IFTYPE_P2P_CLIENT:
|
|
|
- fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
|
|
|
- /* BSSID SA DA */
|
|
|
- memcpy(hdr.addr1, bssid, ETH_ALEN);
|
|
|
- memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
- memcpy(hdr.addr3, skb->data, ETH_ALEN);
|
|
|
- hdrlen = 24;
|
|
|
- break;
|
|
|
- case NL80211_IFTYPE_OCB:
|
|
|
- case NL80211_IFTYPE_ADHOC:
|
|
|
- /* DA SA BSSID */
|
|
|
- memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
|
|
- memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
|
|
- memcpy(hdr.addr3, bssid, ETH_ALEN);
|
|
|
- hdrlen = 24;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return -EOPNOTSUPP;
|
|
|
- }
|
|
|
-
|
|
|
- if (qos) {
|
|
|
- fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
|
|
- hdrlen += 2;
|
|
|
- }
|
|
|
-
|
|
|
- hdr.frame_control = fc;
|
|
|
- hdr.duration_id = 0;
|
|
|
- hdr.seq_ctrl = 0;
|
|
|
-
|
|
|
- skip_header_bytes = ETH_HLEN;
|
|
|
- if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
|
|
|
- encaps_data = bridge_tunnel_header;
|
|
|
- encaps_len = sizeof(bridge_tunnel_header);
|
|
|
- skip_header_bytes -= 2;
|
|
|
- } else if (ethertype >= ETH_P_802_3_MIN) {
|
|
|
- encaps_data = rfc1042_header;
|
|
|
- encaps_len = sizeof(rfc1042_header);
|
|
|
- skip_header_bytes -= 2;
|
|
|
- } else {
|
|
|
- encaps_data = NULL;
|
|
|
- encaps_len = 0;
|
|
|
- }
|
|
|
-
|
|
|
- skb_pull(skb, skip_header_bytes);
|
|
|
- nh_pos -= skip_header_bytes;
|
|
|
- h_pos -= skip_header_bytes;
|
|
|
-
|
|
|
- head_need = hdrlen + encaps_len - skb_headroom(skb);
|
|
|
-
|
|
|
- if (head_need > 0 || skb_cloned(skb)) {
|
|
|
- head_need = max(head_need, 0);
|
|
|
- if (head_need)
|
|
|
- skb_orphan(skb);
|
|
|
-
|
|
|
- if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- if (encaps_data) {
|
|
|
- memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
|
|
|
- nh_pos += encaps_len;
|
|
|
- h_pos += encaps_len;
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
|
|
|
-
|
|
|
- nh_pos += hdrlen;
|
|
|
- h_pos += hdrlen;
|
|
|
-
|
|
|
- /* Update skb pointers to various headers since this modified frame
|
|
|
- * is going to go through Linux networking code that may potentially
|
|
|
- * need things like pointer to IP header. */
|
|
|
- skb_reset_mac_header(skb);
|
|
|
- skb_set_network_header(skb, nh_pos);
|
|
|
- skb_set_transport_header(skb, h_pos);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(ieee80211_data_from_8023);
|
|
|
-
|
|
|
static void
|
|
|
__frame_add_frag(struct sk_buff *skb, struct page *page,
|
|
|
void *ptr, int len, int size)
|