27c09e03b2d83acbe82fde183f534e20cc6e48b7
[~tnikolova/compat/.git] / compat / compat-3.3.c
1 /*
2  * Copyright 2012  Luis R. Rodriguez <mcgrof@frijolero.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Compatibility file for Linux wireless for kernels 3.3.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/version.h>
13 #include <linux/skbuff.h>
14 #include <net/dst.h>
15 #include <net/xfrm.h>
16
17 static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
18 {
19         new->tstamp             = old->tstamp;
20         new->dev                = old->dev;
21         new->transport_header   = old->transport_header;
22         new->network_header     = old->network_header;
23         new->mac_header         = old->mac_header;
24 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
25         skb_dst_copy(new, old);
26         new->rxhash             = old->rxhash;
27 #else
28         skb_dst_set(new, dst_clone(skb_dst(old)));
29 #endif
30 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0))
31         new->ooo_okay           = old->ooo_okay;
32 #endif
33 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0))
34         new->l4_rxhash          = old->l4_rxhash;
35 #endif
36 #ifdef CONFIG_XFRM
37         new->sp                 = secpath_get(old->sp);
38 #endif
39         memcpy(new->cb, old->cb, sizeof(old->cb));
40         new->csum               = old->csum;
41         new->local_df           = old->local_df;
42         new->pkt_type           = old->pkt_type;
43         new->ip_summed          = old->ip_summed;
44         skb_copy_queue_mapping(new, old);
45         new->priority           = old->priority;
46 #if IS_ENABLED(CONFIG_IP_VS)
47         new->ipvs_property      = old->ipvs_property;
48 #endif
49         new->protocol           = old->protocol;
50         new->mark               = old->mark;
51 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
52         new->skb_iif            = old->skb_iif;
53 #endif
54         __nf_copy(new, old);
55 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
56         new->nf_trace           = old->nf_trace;
57 #endif
58 #ifdef CONFIG_NET_SCHED
59         new->tc_index           = old->tc_index;
60 #ifdef CONFIG_NET_CLS_ACT
61         new->tc_verd            = old->tc_verd;
62 #endif
63 #endif
64 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
65         new->vlan_tci           = old->vlan_tci;
66 #endif
67
68         skb_copy_secmark(new, old);
69 }
70
71 static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
72 {
73 #ifndef NET_SKBUFF_DATA_USES_OFFSET
74         /*
75          *      Shift between the two data areas in bytes
76          */
77         unsigned long offset = new->data - old->data;
78 #endif
79
80         __copy_skb_header(new, old);
81
82 #ifndef NET_SKBUFF_DATA_USES_OFFSET
83         /* {transport,network,mac}_header are relative to skb->head */
84         new->transport_header += offset;
85         new->network_header   += offset;
86         if (skb_mac_header_was_set(new))
87                 new->mac_header       += offset;
88 #endif
89         skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
90         skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
91         skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
92 }
93
94 static void skb_clone_fraglist(struct sk_buff *skb)
95 {
96         struct sk_buff *list;
97
98         skb_walk_frags(skb, list)
99                 skb_get(list);
100 }
101
102
103 /**
104  *      __pskb_copy     -       create copy of an sk_buff with private head.
105  *      @skb: buffer to copy
106  *      @headroom: headroom of new skb
107  *      @gfp_mask: allocation priority
108  *
109  *      Make a copy of both an &sk_buff and part of its data, located
110  *      in header. Fragmented data remain shared. This is used when
111  *      the caller wishes to modify only header of &sk_buff and needs
112  *      private copy of the header to alter. Returns %NULL on failure
113  *      or the pointer to the buffer on success.
114  *      The returned buffer has a reference count of 1.
115  */
116
117 struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask)
118 {
119         unsigned int size = skb_headlen(skb) + headroom;
120         struct sk_buff *n = alloc_skb(size, gfp_mask);
121
122         if (!n)
123                 goto out;
124
125         /* Set the data pointer */
126         skb_reserve(n, headroom);
127         /* Set the tail pointer and length */
128         skb_put(n, skb_headlen(skb));
129         /* Copy the bytes */
130         skb_copy_from_linear_data(skb, n->data, n->len);
131
132         n->truesize += skb->data_len;
133         n->data_len  = skb->data_len;
134         n->len       = skb->len;
135
136         if (skb_shinfo(skb)->nr_frags) {
137                 int i;
138
139 /*
140  * SKBTX_DEV_ZEROCOPY was added on 3.1 as well but requires ubuf
141  * stuff added to the skb which we do not have
142  */
143 #if 0
144                 if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
145                         if (skb_copy_ubufs(skb, gfp_mask)) {
146                                 kfree_skb(n);
147                                 n = NULL;
148                                 goto out;
149                         }
150                 }
151 #endif
152                 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
153                         skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
154 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0))
155                         skb_frag_ref(skb, i);
156 #else
157                         get_page(skb_shinfo(skb)->frags[i].page);
158 #endif
159                 }
160                 skb_shinfo(n)->nr_frags = i;
161         }
162
163         if (skb_has_frag_list(skb)) {
164                 skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
165                 skb_clone_fraglist(n);
166         }
167
168         copy_skb_header(n, skb);
169 out:
170         return n;
171 }
172 EXPORT_SYMBOL_GPL(__pskb_copy);