From: Luis R. Rodriguez Date: Fri, 9 Mar 2012 20:21:36 +0000 (-0800) Subject: compat: backport __pskb_copy() X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=17e8ea6f78b9d84f866c27e15ac726e60c44215d;p=openwrt%2Fstaging%2Fblogic.git compat: backport __pskb_copy() This was _not_ easy. The ckmake log: mcgrof@tux ~/compat (git::master)$ ckmake Trying kernel 3.3.0-030300rc2-generic [OK] Trying kernel 3.2.2-030202-generic [OK] Trying kernel 3.1.10-030110-generic [OK] Trying kernel 3.0.18-030018-generic [OK] Trying kernel 2.6.39-02063904-generic [OK] Trying kernel 2.6.38-13-generic [OK] Trying kernel 2.6.38-02063808-generic [OK] Trying kernel 2.6.37-02063706-generic [OK] Trying kernel 2.6.36-02063604-generic [OK] Trying kernel 2.6.35-02063512-generic [OK] Trying kernel 2.6.34-02063410-generic [OK] Trying kernel 2.6.33-02063305-generic [OK] Trying kernel 2.6.32-02063255-generic [OK] Trying kernel 2.6.31-22-generic [OK] Trying kernel 2.6.31-02063113-generic [OK] Trying kernel 2.6.30-02063010-generic [OK] Trying kernel 2.6.29-02062906-generic [OK] Trying kernel 2.6.28-02062810-generic [OK] Trying kernel 2.6.27-020627-generic [OK] Trying kernel 2.6.26-020626-generic [OK] Trying kernel 2.6.25-020625-generic [OK] Trying kernel 2.6.24-020624-generic [OK] Signed-off-by: Luis R. Rodriguez --- diff --git a/compat/Makefile b/compat/Makefile index 3c72ef9bf1e7..b49e8c0a3587 100644 --- a/compat/Makefile +++ b/compat/Makefile @@ -35,6 +35,7 @@ compat-$(CONFIG_COMPAT_KERNEL_2_6_39) += \ kstrtox.o compat-$(CONFIG_COMPAT_KERNEL_3_0) += compat-3.0.o compat-$(CONFIG_COMPAT_KERNEL_3_2) += compat-3.2.o +compat-$(CONFIG_COMPAT_KERNEL_3_3) += compat-3.3.o compat-$(CONFIG_COMPAT_CORDIC) += cordic.o compat-$(CONFIG_COMPAT_CRC8) += crc8.o diff --git a/compat/compat-3.3.c b/compat/compat-3.3.c new file mode 100644 index 000000000000..27c09e03b2d8 --- /dev/null +++ b/compat/compat-3.3.c @@ -0,0 +1,172 @@ +/* + * Copyright 2012 Luis R. Rodriguez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Compatibility file for Linux wireless for kernels 3.3. + */ + +#include +#include +#include +#include +#include + +static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) +{ + new->tstamp = old->tstamp; + new->dev = old->dev; + new->transport_header = old->transport_header; + new->network_header = old->network_header; + new->mac_header = old->mac_header; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) + skb_dst_copy(new, old); + new->rxhash = old->rxhash; +#else + skb_dst_set(new, dst_clone(skb_dst(old))); +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)) + new->ooo_okay = old->ooo_okay; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) + new->l4_rxhash = old->l4_rxhash; +#endif +#ifdef CONFIG_XFRM + new->sp = secpath_get(old->sp); +#endif + memcpy(new->cb, old->cb, sizeof(old->cb)); + new->csum = old->csum; + new->local_df = old->local_df; + new->pkt_type = old->pkt_type; + new->ip_summed = old->ip_summed; + skb_copy_queue_mapping(new, old); + new->priority = old->priority; +#if IS_ENABLED(CONFIG_IP_VS) + new->ipvs_property = old->ipvs_property; +#endif + new->protocol = old->protocol; + new->mark = old->mark; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) + new->skb_iif = old->skb_iif; +#endif + __nf_copy(new, old); +#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) + new->nf_trace = old->nf_trace; +#endif +#ifdef CONFIG_NET_SCHED + new->tc_index = old->tc_index; +#ifdef CONFIG_NET_CLS_ACT + new->tc_verd = old->tc_verd; +#endif +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) + new->vlan_tci = old->vlan_tci; +#endif + + skb_copy_secmark(new, old); +} + +static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) +{ +#ifndef NET_SKBUFF_DATA_USES_OFFSET + /* + * Shift between the two data areas in bytes + */ + unsigned long offset = new->data - old->data; +#endif + + __copy_skb_header(new, old); + +#ifndef NET_SKBUFF_DATA_USES_OFFSET + /* {transport,network,mac}_header are relative to skb->head */ + new->transport_header += offset; + new->network_header += offset; + if (skb_mac_header_was_set(new)) + new->mac_header += offset; +#endif + skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size; + skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; + skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type; +} + +static void skb_clone_fraglist(struct sk_buff *skb) +{ + struct sk_buff *list; + + skb_walk_frags(skb, list) + skb_get(list); +} + + +/** + * __pskb_copy - create copy of an sk_buff with private head. + * @skb: buffer to copy + * @headroom: headroom of new skb + * @gfp_mask: allocation priority + * + * Make a copy of both an &sk_buff and part of its data, located + * in header. Fragmented data remain shared. This is used when + * the caller wishes to modify only header of &sk_buff and needs + * private copy of the header to alter. Returns %NULL on failure + * or the pointer to the buffer on success. + * The returned buffer has a reference count of 1. + */ + +struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask) +{ + unsigned int size = skb_headlen(skb) + headroom; + struct sk_buff *n = alloc_skb(size, gfp_mask); + + if (!n) + goto out; + + /* Set the data pointer */ + skb_reserve(n, headroom); + /* Set the tail pointer and length */ + skb_put(n, skb_headlen(skb)); + /* Copy the bytes */ + skb_copy_from_linear_data(skb, n->data, n->len); + + n->truesize += skb->data_len; + n->data_len = skb->data_len; + n->len = skb->len; + + if (skb_shinfo(skb)->nr_frags) { + int i; + +/* + * SKBTX_DEV_ZEROCOPY was added on 3.1 as well but requires ubuf + * stuff added to the skb which we do not have + */ +#if 0 + if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { + if (skb_copy_ubufs(skb, gfp_mask)) { + kfree_skb(n); + n = NULL; + goto out; + } + } +#endif + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)) + skb_frag_ref(skb, i); +#else + get_page(skb_shinfo(skb)->frags[i].page); +#endif + } + skb_shinfo(n)->nr_frags = i; + } + + if (skb_has_frag_list(skb)) { + skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; + skb_clone_fraglist(n); + } + + copy_skb_header(n, skb); +out: + return n; +} +EXPORT_SYMBOL_GPL(__pskb_copy); diff --git a/include/linux/compat-3.1.h b/include/linux/compat-3.1.h index 5b00ac961805..845499b6c24c 100644 --- a/include/linux/compat-3.1.h +++ b/include/linux/compat-3.1.h @@ -7,6 +7,8 @@ #include +#define IS_ENABLED(option) defined(option) + #define genl_dump_check_consistent(cb, user_hdr, family) #define IFF_TX_SKB_SHARING 0x10000 /* The interface supports sharing diff --git a/include/linux/compat-3.3.h b/include/linux/compat-3.3.h index 4965f2346220..69bdcd0bbe4d 100644 --- a/include/linux/compat-3.3.h +++ b/include/linux/compat-3.3.h @@ -7,6 +7,10 @@ /* include to override NL80211_FEATURE_SK_TX_STATUS */ #include +#include + +extern struct sk_buff *__pskb_copy(struct sk_buff *skb, + int headroom, gfp_t gfp_mask); static inline void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) {