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