mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-08-22 11:43:21 +03:00
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@31335 3c298f89-4303-0410-b956-a3cf2f4a3e73
364 lines
12 KiB
Diff
364 lines
12 KiB
Diff
From 8bf74990542ad73bc633332f716a5edc76f858a2 Mon Sep 17 00:00:00 2001
|
|
From: John Crispin <blogic@openwrt.org>
|
|
Date: Thu, 29 Sep 2011 20:29:54 +0200
|
|
Subject: [PATCH 58/73] MIPS: lantiq: udp in-kernel redirect
|
|
|
|
---
|
|
include/linux/udp_redirect.h | 57 +++++++++++++
|
|
net/Kconfig | 6 ++
|
|
net/ipv4/Makefile | 3 +
|
|
net/ipv4/udp.c | 28 ++++++-
|
|
net/ipv4/udp_redirect_symb.c | 186 ++++++++++++++++++++++++++++++++++++++++++
|
|
5 files changed, 276 insertions(+), 4 deletions(-)
|
|
create mode 100644 include/linux/udp_redirect.h
|
|
create mode 100644 net/ipv4/udp_redirect_symb.c
|
|
|
|
--- /dev/null
|
|
+++ b/include/linux/udp_redirect.h
|
|
@@ -0,0 +1,57 @@
|
|
+#ifndef _UDP_REDIRECT_H
|
|
+#define _UDP_REDIRECT_H
|
|
+
|
|
+/******************************************************************************
|
|
+
|
|
+ Copyright (c) 2006
|
|
+ Infineon Technologies AG
|
|
+ Am Campeon 1-12; 81726 Munich, Germany
|
|
+
|
|
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
|
|
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
|
|
+ SOFTWARE IS FREE OF CHARGE.
|
|
+
|
|
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
|
|
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
|
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
|
|
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
|
|
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
|
|
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
|
|
+ PROPERTY INFRINGEMENT.
|
|
+
|
|
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
|
|
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
|
|
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
+ DEALINGS IN THE SOFTWARE.
|
|
+
|
|
+******************************************************************************/
|
|
+
|
|
+/* ============================= */
|
|
+/* Includes */
|
|
+/* ============================= */
|
|
+#ifndef _LINUX_TYPES_H
|
|
+#include <linux/types.h>
|
|
+#endif
|
|
+
|
|
+
|
|
+/* ============================= */
|
|
+/* Definitions */
|
|
+/* ============================= */
|
|
+#define UDP_REDIRECT_MAGIC (void*)0x55445052L
|
|
+
|
|
+
|
|
+/* ============================= */
|
|
+/* Global variable declaration */
|
|
+/* ============================= */
|
|
+extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb);
|
|
+extern int (*udpredirect_getfrag_fn)(void *p, char * to,
|
|
+ int offset, int fraglen, int odd,
|
|
+ struct sk_buff *skb);
|
|
+/* ============================= */
|
|
+/* Global function declaration */
|
|
+/* ============================= */
|
|
+
|
|
+extern int udpredirect_getfrag(void *p, char * to, int offset,
|
|
+ int fraglen, int odd, struct sk_buff *skb);
|
|
+#endif
|
|
--- a/net/Kconfig
|
|
+++ b/net/Kconfig
|
|
@@ -72,6 +72,12 @@ config INET
|
|
|
|
Short answer: say Y.
|
|
|
|
+config IFX_UDP_REDIRECT
|
|
+ bool "IFX Kernel Packet Interface for UDP redirection"
|
|
+ help
|
|
+ You can say Y here if you want to use hooks from kernel for
|
|
+ UDP redirection.
|
|
+
|
|
if INET
|
|
source "net/ipv4/Kconfig"
|
|
source "net/ipv6/Kconfig"
|
|
--- a/net/ipv4/Makefile
|
|
+++ b/net/ipv4/Makefile
|
|
@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol
|
|
inet_fragment.o ping.o
|
|
|
|
obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
|
|
+ifneq ($(CONFIG_IFX_UDP_REDIRECT),)
|
|
+obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o
|
|
+endif
|
|
obj-$(CONFIG_PROC_FS) += proc.o
|
|
obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
|
|
obj-$(CONFIG_IP_MROUTE) += ipmr.o
|
|
--- a/net/ipv4/udp.c
|
|
+++ b/net/ipv4/udp.c
|
|
@@ -108,6 +108,10 @@
|
|
#include <trace/events/udp.h>
|
|
#include "udp_impl.h"
|
|
|
|
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
|
+#include <linux/udp_redirect.h>
|
|
+#endif
|
|
+
|
|
struct udp_table udp_table __read_mostly;
|
|
EXPORT_SYMBOL(udp_table);
|
|
|
|
@@ -803,7 +807,7 @@ int udp_sendmsg(struct kiocb *iocb, stru
|
|
u8 tos;
|
|
int err, is_udplite = IS_UDPLITE(sk);
|
|
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
|
|
- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
|
|
+ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL;
|
|
struct sk_buff *skb;
|
|
struct ip_options_data opt_copy;
|
|
|
|
@@ -820,7 +824,13 @@ int udp_sendmsg(struct kiocb *iocb, stru
|
|
ipc.opt = NULL;
|
|
ipc.tx_flags = 0;
|
|
|
|
- getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
|
+/* UDPREDIRECT */
|
|
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
|
+ if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
|
|
+ getfrag = udpredirect_getfrag_fn;
|
|
+ else
|
|
+#endif /* IFX_UDP_REDIRECT */
|
|
+ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
|
|
|
fl4 = &inet->cork.fl.u.ip4;
|
|
if (up->pending) {
|
|
@@ -1623,6 +1633,7 @@ int __udp4_lib_rcv(struct sk_buff *skb,
|
|
struct rtable *rt = skb_rtable(skb);
|
|
__be32 saddr, daddr;
|
|
struct net *net = dev_net(skb->dev);
|
|
+ int ret = 0;
|
|
|
|
/*
|
|
* Validate the packet.
|
|
@@ -1655,7 +1666,16 @@ int __udp4_lib_rcv(struct sk_buff *skb,
|
|
sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
|
|
|
|
if (sk != NULL) {
|
|
- int ret = udp_queue_rcv_skb(sk, skb);
|
|
+ /* UDPREDIRECT */
|
|
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
|
+ if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
|
|
+ {
|
|
+ udp_do_redirect_fn(sk,skb);
|
|
+ kfree_skb(skb);
|
|
+ return(0);
|
|
+ }
|
|
+#endif
|
|
+ ret = udp_queue_rcv_skb(sk, skb);
|
|
sock_put(sk);
|
|
|
|
/* a return value > 0 means to resubmit the input, but
|
|
@@ -1952,7 +1972,7 @@ struct proto udp_prot = {
|
|
.clear_sk = sk_prot_clear_portaddr_nulls,
|
|
};
|
|
EXPORT_SYMBOL(udp_prot);
|
|
-
|
|
+EXPORT_SYMBOL(udp_rcv);
|
|
/* ------------------------------------------------------------------------ */
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
--- /dev/null
|
|
+++ b/net/ipv4/udp_redirect_symb.c
|
|
@@ -0,0 +1,186 @@
|
|
+/******************************************************************************
|
|
+
|
|
+ Copyright (c) 2006
|
|
+ Infineon Technologies AG
|
|
+ Am Campeon 1-12; 81726 Munich, Germany
|
|
+
|
|
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
|
|
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
|
|
+ SOFTWARE IS FREE OF CHARGE.
|
|
+
|
|
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
|
|
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
|
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
|
|
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
|
|
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
|
|
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
|
|
+ PROPERTY INFRINGEMENT.
|
|
+
|
|
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
|
|
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
|
|
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
+ DEALINGS IN THE SOFTWARE.
|
|
+
|
|
+******************************************************************************/
|
|
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
|
+/* ============================= */
|
|
+/* Includes */
|
|
+/* ============================= */
|
|
+#include <net/checksum.h>
|
|
+#include <net/udp.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/skbuff.h>
|
|
+#include <linux/udp_redirect.h>
|
|
+
|
|
+/* ============================= */
|
|
+/* Global variable definition */
|
|
+/* ============================= */
|
|
+int (*udpredirect_getfrag_fn) (void *p, char * to, int offset,
|
|
+ int fraglen, int odd, struct sk_buff *skb) = NULL;
|
|
+int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL;
|
|
+
|
|
+/* ============================= */
|
|
+/* Local type definitions */
|
|
+/* ============================= */
|
|
+struct udpfakehdr
|
|
+{
|
|
+ struct udphdr uh;
|
|
+ u32 saddr;
|
|
+ u32 daddr;
|
|
+ struct iovec *iov;
|
|
+ u32 wcheck;
|
|
+};
|
|
+
|
|
+/* ============================= */
|
|
+/* Local function declaration */
|
|
+/* ============================= */
|
|
+static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata,
|
|
+ struct iovec *iov, int offset, unsigned int len, __wsum *csump);
|
|
+
|
|
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
|
|
+ int len);
|
|
+
|
|
+/* ============================= */
|
|
+/* Global function definition */
|
|
+/* ============================= */
|
|
+
|
|
+/*
|
|
+ Copy of udp_getfrag() from udp.c
|
|
+ This function exists because no copy_from_user() is needed for udpredirect.
|
|
+*/
|
|
+
|
|
+int
|
|
+udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
|
|
+{
|
|
+ struct iovec *iov = from;
|
|
+
|
|
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
|
+ if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0)
|
|
+ return -EFAULT;
|
|
+ } else {
|
|
+ __wsum csum = 0;
|
|
+ if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)
|
|
+ return -EFAULT;
|
|
+ skb->csum = csum_block_add(skb->csum, csum, odd);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
|
|
+ int len)
|
|
+{
|
|
+ /* Skip over the finished iovecs */
|
|
+ while (offset >= iov->iov_len) {
|
|
+ offset -= iov->iov_len;
|
|
+ iov++;
|
|
+ }
|
|
+
|
|
+ while (len > 0) {
|
|
+ u8 __user *base = iov->iov_base + offset;
|
|
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
|
|
+
|
|
+ offset = 0;
|
|
+ memcpy(kdata, base, copy);
|
|
+ len -= copy;
|
|
+ kdata += copy;
|
|
+ iov++;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ Copy of csum_partial_copy_fromiovecend() from iovec.c
|
|
+ This function exists because no copy_from_user() is needed for udpredirect.
|
|
+*/
|
|
+
|
|
+int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
|
|
+ int offset, unsigned int len, __wsum *csump)
|
|
+{
|
|
+ __wsum csum = *csump;
|
|
+ int partial_cnt = 0, err = 0;
|
|
+
|
|
+ /* Skip over the finished iovecs */
|
|
+ while (offset >= iov->iov_len) {
|
|
+ offset -= iov->iov_len;
|
|
+ iov++;
|
|
+ }
|
|
+
|
|
+ while (len > 0) {
|
|
+ u8 __user *base = iov->iov_base + offset;
|
|
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
|
|
+
|
|
+ offset = 0;
|
|
+
|
|
+ /* There is a remnant from previous iov. */
|
|
+ if (partial_cnt) {
|
|
+ int par_len = 4 - partial_cnt;
|
|
+
|
|
+ /* iov component is too short ... */
|
|
+ if (par_len > copy) {
|
|
+ memcpy(kdata, base, copy);
|
|
+ kdata += copy;
|
|
+ base += copy;
|
|
+ partial_cnt += copy;
|
|
+ len -= copy;
|
|
+ iov++;
|
|
+ if (len)
|
|
+ continue;
|
|
+ *csump = csum_partial(kdata - partial_cnt,
|
|
+ partial_cnt, csum);
|
|
+ goto out;
|
|
+ }
|
|
+ memcpy(kdata, base, par_len);
|
|
+ csum = csum_partial(kdata - partial_cnt, 4, csum);
|
|
+ kdata += par_len;
|
|
+ base += par_len;
|
|
+ copy -= par_len;
|
|
+ len -= par_len;
|
|
+ partial_cnt = 0;
|
|
+ }
|
|
+
|
|
+ if (len > copy) {
|
|
+ partial_cnt = copy % 4;
|
|
+ if (partial_cnt) {
|
|
+ copy -= partial_cnt;
|
|
+ memcpy(kdata + copy, base + copy, partial_cnt);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (copy) {
|
|
+ csum = csum_partial_copy_nocheck(base, kdata, copy, csum);
|
|
+ }
|
|
+ len -= copy + partial_cnt;
|
|
+ kdata += copy + partial_cnt;
|
|
+ iov++;
|
|
+ }
|
|
+ *csump = csum;
|
|
+out:
|
|
+ return err;
|
|
+}
|
|
+
|
|
+EXPORT_SYMBOL(udpredirect_getfrag);
|
|
+EXPORT_SYMBOL(udp_do_redirect_fn);
|
|
+EXPORT_SYMBOL(udpredirect_getfrag_fn);
|
|
+#endif /* CONFIG_IFX_UDP_REDIRECT* */
|