compat: backport __pskb_copy()
authorLuis R. Rodriguez <mcgrof@frijolero.org>
Fri, 9 Mar 2012 20:21:36 +0000 (12:21 -0800)
committerLuis R. Rodriguez <mcgrof@frijolero.org>
Fri, 9 Mar 2012 20:22:55 +0000 (12:22 -0800)
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 <mcgrof@frijolero.org>
compat/Makefile
compat/compat-3.3.c [new file with mode: 0644]
include/linux/compat-3.1.h
include/linux/compat-3.3.h

index 3c72ef9..b49e8c0 100644 (file)
@@ -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 (file)
index 0000000..27c09e0
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2012  Luis R. Rodriguez <mcgrof@frijolero.org>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
+
+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);
index 5b00ac9..845499b 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <linux/security.h>
 
+#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
index 4965f23..69bdcd0 100644 (file)
@@ -7,6 +7,10 @@
 
 /* include to override NL80211_FEATURE_SK_TX_STATUS */
 #include <linux/nl80211.h>
+#include <linux/skbuff.h>
+
+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)
 {