a59f6cce49ad0d5de70df257a5f5189ff91f2c47
[openwrt.git] / target / linux / lantiq / patches / 300-udp_redirect.patch
1 --- /dev/null
2 +++ b/include/linux/udp_redirect.h
3 @@ -0,0 +1,57 @@
4 +#ifndef _UDP_REDIRECT_H
5 +#define _UDP_REDIRECT_H
6 +
7 +/******************************************************************************
8 +
9 +                               Copyright (c) 2006
10 +                            Infineon Technologies AG
11 +                     Am Campeon 1-12; 81726 Munich, Germany
12 +
13 +  THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
14 +  WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
15 +  SOFTWARE IS FREE OF CHARGE.
16 +
17 +  THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
18 +  ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
19 +  WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
20 +  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
21 +  OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
22 +  PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
23 +  PROPERTY INFRINGEMENT.
24 +
25 +  EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
26 +  FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
27 +  OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 +  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 +  DEALINGS IN THE SOFTWARE.
30 +
31 +******************************************************************************/
32 +
33 +/* ============================= */
34 +/* Includes                      */
35 +/* ============================= */
36 +#ifndef _LINUX_TYPES_H
37 +#include <linux/types.h>
38 +#endif
39 +
40 +
41 +/* ============================= */
42 +/* Definitions                   */
43 +/* ============================= */
44 +#define UDP_REDIRECT_MAGIC (void*)0x55445052L
45 +
46 +
47 +/* ============================= */
48 +/* Global variable declaration   */
49 +/* ============================= */
50 +extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb);
51 +extern int (*udpredirect_getfrag_fn)(void *p, char * to,
52 +                                     int offset, int fraglen, int odd,
53 +                                     struct sk_buff *skb);
54 +/* ============================= */
55 +/* Global function declaration   */
56 +/* ============================= */
57 +
58 +extern int udpredirect_getfrag(void *p, char * to, int offset,
59 +                               int fraglen, int odd, struct sk_buff *skb);
60 +#endif
61 --- /dev/null
62 +++ b/net/ipv4/udp_redirect_symb.c
63 @@ -0,0 +1,186 @@
64 +/******************************************************************************
65 +
66 +                               Copyright (c) 2006
67 +                            Infineon Technologies AG
68 +                     Am Campeon 1-12; 81726 Munich, Germany
69 +
70 +  THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
71 +  WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
72 +  SOFTWARE IS FREE OF CHARGE.
73 +
74 +  THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
75 +  ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
76 +  WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
77 +  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
78 +  OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
79 +  PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
80 +  PROPERTY INFRINGEMENT.
81 +
82 +  EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
83 +  FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
84 +  OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
85 +  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
86 +  DEALINGS IN THE SOFTWARE.
87 +
88 +******************************************************************************/
89 +#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
90 +/* ============================= */
91 +/* Includes                      */
92 +/* ============================= */
93 +#include <net/checksum.h>
94 +#include <net/udp.h>
95 +#include <linux/module.h>
96 +#include <linux/skbuff.h>
97 +#include <linux/udp_redirect.h>
98 +
99 +/* ============================= */
100 +/* Global variable definition    */
101 +/* ============================= */
102 +int (*udpredirect_getfrag_fn) (void *p, char * to, int offset,
103 +                               int fraglen, int odd, struct sk_buff *skb) = NULL;
104 +int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL;
105 +
106 +/* ============================= */
107 +/* Local type definitions        */
108 +/* ============================= */
109 +struct udpfakehdr
110 +{
111 +  struct udphdr uh;
112 +  u32 saddr;
113 +  u32 daddr;
114 +  struct iovec *iov;
115 +  u32 wcheck;
116 +};
117 +
118 +/* ============================= */
119 +/* Local function declaration    */
120 +/* ============================= */
121 +static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata,
122 +              struct iovec *iov, int offset, unsigned int len, __wsum *csump);
123 +
124 +static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
125 +                        int len);
126 +
127 +/* ============================= */
128 +/* Global function definition    */
129 +/* ============================= */
130 +
131 +/*
132 +   Copy of udp_getfrag() from udp.c
133 +   This function exists because no copy_from_user() is needed for udpredirect.
134 +*/
135 +
136 +int
137 +udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
138 +{
139 +   struct iovec *iov = from;
140 +
141 +        if (skb->ip_summed == CHECKSUM_PARTIAL) {
142 +                if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0)
143 +                        return -EFAULT;
144 +        } else {
145 +                __wsum csum = 0;
146 +                if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)
147 +                        return -EFAULT;
148 +                skb->csum = csum_block_add(skb->csum, csum, odd);
149 +        }
150 +        return 0;
151 +}
152 +
153 +static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
154 +                        int len)
155 +{
156 +        /* Skip over the finished iovecs */
157 +        while (offset >= iov->iov_len) {
158 +                offset -= iov->iov_len;
159 +                iov++;
160 +        }
161 +
162 +        while (len > 0) {
163 +                u8 __user *base = iov->iov_base + offset;
164 +                int copy = min_t(unsigned int, len, iov->iov_len - offset);
165 +
166 +                offset = 0;
167 +                memcpy(kdata, base, copy);
168 +                len -= copy;
169 +                kdata += copy;
170 +                iov++;
171 +        }
172 +
173 +        return 0;
174 +}
175 +
176 +/*
177 +   Copy of csum_partial_copy_fromiovecend() from iovec.c
178 +   This function exists because no copy_from_user() is needed for udpredirect.
179 +*/
180 +
181 +int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
182 +                                int offset, unsigned int len, __wsum *csump)
183 +{
184 +       __wsum csum = *csump;
185 +       int partial_cnt = 0, err = 0;
186 +
187 +       /* Skip over the finished iovecs */
188 +       while (offset >= iov->iov_len) {
189 +               offset -= iov->iov_len;
190 +               iov++;
191 +       }
192 +
193 +       while (len > 0) {
194 +               u8 __user *base = iov->iov_base + offset;
195 +               int copy = min_t(unsigned int, len, iov->iov_len - offset);
196 +
197 +               offset = 0;
198 +
199 +               /* There is a remnant from previous iov. */
200 +               if (partial_cnt) {
201 +                       int par_len = 4 - partial_cnt;
202 +
203 +                       /* iov component is too short ... */
204 +                       if (par_len > copy) {
205 +                               memcpy(kdata, base, copy);
206 +                               kdata += copy;
207 +                               base  += copy;
208 +                               partial_cnt += copy;
209 +                               len   -= copy;
210 +                               iov++;
211 +                               if (len)
212 +                                       continue;
213 +                               *csump = csum_partial(kdata - partial_cnt,
214 +                                                        partial_cnt, csum);
215 +                               goto out;
216 +                       }
217 +                       memcpy(kdata, base, par_len);
218 +                       csum = csum_partial(kdata - partial_cnt, 4, csum);
219 +                       kdata += par_len;
220 +                       base  += par_len;
221 +                       copy  -= par_len;
222 +                       len   -= par_len;
223 +                       partial_cnt = 0;
224 +               }
225 +
226 +               if (len > copy) {
227 +                       partial_cnt = copy % 4;
228 +                       if (partial_cnt) {
229 +                               copy -= partial_cnt;
230 +                               memcpy(kdata + copy, base + copy, partial_cnt);
231 +                       }
232 +               }
233 +
234 +               if (copy) {
235 +                       csum = csum_partial_copy_nocheck(base, kdata, copy, csum);
236 +               }
237 +               len   -= copy + partial_cnt;
238 +               kdata += copy + partial_cnt;
239 +               iov++;
240 +       }
241 +        *csump = csum;
242 +out:
243 +       return err;
244 +}
245 +
246 +EXPORT_SYMBOL(udpredirect_getfrag);
247 +EXPORT_SYMBOL(udp_do_redirect_fn);
248 +EXPORT_SYMBOL(udpredirect_getfrag_fn);
249 +#endif /* CONFIG_IFX_UDP_REDIRECT* */
250 --- a/net/ipv4/Makefile
251 +++ b/net/ipv4/Makefile
252 @@ -14,6 +14,9 @@
253              inet_fragment.o
254  
255  obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
256 +ifneq ($(CONFIG_IFX_UDP_REDIRECT),)
257 +obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o
258 +endif
259  obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
260  obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
261  obj-$(CONFIG_PROC_FS) += proc.o
262 --- a/net/ipv4/udp.c
263 +++ b/net/ipv4/udp.c
264 @@ -107,6 +107,10 @@
265  #include <net/xfrm.h>
266  #include "udp_impl.h"
267  
268 +#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
269 +#include <linux/udp_redirect.h>
270 +#endif
271 +
272  struct udp_table udp_table __read_mostly;
273  EXPORT_SYMBOL(udp_table);
274  
275 @@ -784,7 +788,7 @@
276         u8  tos;
277         int err, is_udplite = IS_UDPLITE(sk);
278         int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
279 -       int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
280 +       int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL;
281  
282         if (len > 0xFFFF)
283                 return -EMSGSIZE;
284 @@ -946,6 +950,12 @@
285  
286  do_append_data:
287         up->len += ulen;
288 +       /* UDPREDIRECT */
289 +#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
290 +       if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
291 +               getfrag = udpredirect_getfrag_fn;
292 +       else
293 +#endif /* IFX_UDP_REDIRECT */
294         getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
295         err = ip_append_data(sk, getfrag, msg->msg_iov, ulen,
296                         sizeof(struct udphdr), &ipc, &rt,
297 @@ -1573,6 +1583,7 @@
298         struct rtable *rt = skb_rtable(skb);
299         __be32 saddr, daddr;
300         struct net *net = dev_net(skb->dev);
301 +       int ret = 0;
302  
303         /*
304          *  Validate the packet.
305 @@ -1605,7 +1616,16 @@
306         sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
307  
308         if (sk != NULL) {
309 -               int ret = udp_queue_rcv_skb(sk, skb);
310 +       /* UDPREDIRECT */
311 +#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
312 +      if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
313 +      {
314 +         udp_do_redirect_fn(sk,skb);
315 +         kfree_skb(skb);
316 +         return(0);
317 +      }
318 +#endif
319 +               ret = udp_queue_rcv_skb(sk, skb);
320                 sock_put(sk);
321  
322                 /* a return value > 0 means to resubmit the input, but
323 @@ -1902,7 +1922,7 @@
324         .clear_sk          = sk_prot_clear_portaddr_nulls,
325  };
326  EXPORT_SYMBOL(udp_prot);
327 -
328 +EXPORT_SYMBOL(udp_rcv);
329  /* ------------------------------------------------------------------------ */
330  #ifdef CONFIG_PROC_FS
331  
332 --- a/net/Kconfig
333 +++ b/net/Kconfig
334 @@ -72,6 +72,12 @@
335  
336           Short answer: say Y.
337  
338 +config IFX_UDP_REDIRECT
339 +       bool "IFX Kernel Packet Interface for UDP redirection"
340 +       help
341 +         You can say Y here if you want to use hooks from kernel for
342 +         UDP redirection.
343 +
344  if INET
345  source "net/ipv4/Kconfig"
346  source "net/ipv6/Kconfig"