diff options
author | Tom Herbert <therbert@google.com> | 2014-07-13 22:49:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-14 19:12:15 -0400 |
commit | 8024e02879ddd5042be02c70557f74cdc70b44b4 (patch) | |
tree | bd11e8dae8b5d397c4d9e43e0af3c9330de24658 /net | |
parent | 39b1c29b7bb932d7c2bd5680a927f269944bdfda (diff) |
udp: Add udp_sock_create for UDP tunnels to open listener socket
Added udp_tunnel.c which can contain some common functions for UDP
tunnels. The first function in this is udp_sock_create which is used
to open the listener port for a UDP tunnel.
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/Kconfig | 4 | ||||
-rw-r--r-- | net/ipv4/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/udp_tunnel.c | 100 |
3 files changed, 105 insertions, 0 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 05c57f0fcabe..dbc10d84161f 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -307,6 +307,10 @@ config NET_IPVTI | |||
307 | the notion of a secure tunnel for IPSEC and then use routing protocol | 307 | the notion of a secure tunnel for IPSEC and then use routing protocol |
308 | on top. | 308 | on top. |
309 | 309 | ||
310 | config NET_UDP_TUNNEL | ||
311 | tristate | ||
312 | default n | ||
313 | |||
310 | config INET_AH | 314 | config INET_AH |
311 | tristate "IP: AH transformation" | 315 | tristate "IP: AH transformation" |
312 | select XFRM_ALGO | 316 | select XFRM_ALGO |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index f032688d20d3..8ee1cd4053ee 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_NET_IPIP) += ipip.o | |||
22 | gre-y := gre_demux.o | 22 | gre-y := gre_demux.o |
23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o | 23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o |
24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o | 24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o |
25 | obj-$(CONFIG_NET_UDP_TUNNEL) += udp_tunnel.o | ||
25 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o | 26 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o |
26 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o | 27 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o |
27 | obj-$(CONFIG_INET_AH) += ah4.o | 28 | obj-$(CONFIG_INET_AH) += ah4.o |
diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c new file mode 100644 index 000000000000..61ec1a65207e --- /dev/null +++ b/net/ipv4/udp_tunnel.c | |||
@@ -0,0 +1,100 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <linux/socket.h> | ||
4 | #include <linux/udp.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <linux/kernel.h> | ||
7 | #include <net/udp.h> | ||
8 | #include <net/udp_tunnel.h> | ||
9 | #include <net/net_namespace.h> | ||
10 | |||
11 | int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, | ||
12 | struct socket **sockp) | ||
13 | { | ||
14 | int err = -EINVAL; | ||
15 | struct socket *sock = NULL; | ||
16 | |||
17 | #if IS_ENABLED(CONFIG_IPV6) | ||
18 | if (cfg->family == AF_INET6) { | ||
19 | struct sockaddr_in6 udp6_addr; | ||
20 | |||
21 | err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); | ||
22 | if (err < 0) | ||
23 | goto error; | ||
24 | |||
25 | sk_change_net(sock->sk, net); | ||
26 | |||
27 | udp6_addr.sin6_family = AF_INET6; | ||
28 | memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, | ||
29 | sizeof(udp6_addr.sin6_addr)); | ||
30 | udp6_addr.sin6_port = cfg->local_udp_port; | ||
31 | err = kernel_bind(sock, (struct sockaddr *)&udp6_addr, | ||
32 | sizeof(udp6_addr)); | ||
33 | if (err < 0) | ||
34 | goto error; | ||
35 | |||
36 | if (cfg->peer_udp_port) { | ||
37 | udp6_addr.sin6_family = AF_INET6; | ||
38 | memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6, | ||
39 | sizeof(udp6_addr.sin6_addr)); | ||
40 | udp6_addr.sin6_port = cfg->peer_udp_port; | ||
41 | err = kernel_connect(sock, | ||
42 | (struct sockaddr *)&udp6_addr, | ||
43 | sizeof(udp6_addr), 0); | ||
44 | } | ||
45 | if (err < 0) | ||
46 | goto error; | ||
47 | |||
48 | udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums); | ||
49 | udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums); | ||
50 | } else | ||
51 | #endif | ||
52 | if (cfg->family == AF_INET) { | ||
53 | struct sockaddr_in udp_addr; | ||
54 | |||
55 | err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); | ||
56 | if (err < 0) | ||
57 | goto error; | ||
58 | |||
59 | sk_change_net(sock->sk, net); | ||
60 | |||
61 | udp_addr.sin_family = AF_INET; | ||
62 | udp_addr.sin_addr = cfg->local_ip; | ||
63 | udp_addr.sin_port = cfg->local_udp_port; | ||
64 | err = kernel_bind(sock, (struct sockaddr *)&udp_addr, | ||
65 | sizeof(udp_addr)); | ||
66 | if (err < 0) | ||
67 | goto error; | ||
68 | |||
69 | if (cfg->peer_udp_port) { | ||
70 | udp_addr.sin_family = AF_INET; | ||
71 | udp_addr.sin_addr = cfg->peer_ip; | ||
72 | udp_addr.sin_port = cfg->peer_udp_port; | ||
73 | err = kernel_connect(sock, | ||
74 | (struct sockaddr *)&udp_addr, | ||
75 | sizeof(udp_addr), 0); | ||
76 | if (err < 0) | ||
77 | goto error; | ||
78 | } | ||
79 | |||
80 | sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; | ||
81 | } else { | ||
82 | return -EPFNOSUPPORT; | ||
83 | } | ||
84 | |||
85 | |||
86 | *sockp = sock; | ||
87 | |||
88 | return 0; | ||
89 | |||
90 | error: | ||
91 | if (sock) { | ||
92 | kernel_sock_shutdown(sock, SHUT_RDWR); | ||
93 | sk_release_kernel(sock->sk); | ||
94 | } | ||
95 | *sockp = NULL; | ||
96 | return err; | ||
97 | } | ||
98 | EXPORT_SYMBOL(udp_sock_create); | ||
99 | |||
100 | MODULE_LICENSE("GPL"); | ||