-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Tom Herbert
authored and
David S. Miller
committed
Jul 14, 2014
1 parent
39b1c29
commit 8024e02
Showing
4 changed files
with
137 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#ifndef __NET_UDP_TUNNEL_H | ||
#define __NET_UDP_TUNNEL_H | ||
|
||
struct udp_port_cfg { | ||
u8 family; | ||
|
||
/* Used only for kernel-created sockets */ | ||
union { | ||
struct in_addr local_ip; | ||
#if IS_ENABLED(CONFIG_IPV6) | ||
struct in6_addr local_ip6; | ||
#endif | ||
}; | ||
|
||
union { | ||
struct in_addr peer_ip; | ||
#if IS_ENABLED(CONFIG_IPV6) | ||
struct in6_addr peer_ip6; | ||
#endif | ||
}; | ||
|
||
__be16 local_udp_port; | ||
__be16 peer_udp_port; | ||
unsigned int use_udp_checksums:1, | ||
use_udp6_tx_checksums:1, | ||
use_udp6_rx_checksums:1; | ||
}; | ||
|
||
int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, | ||
struct socket **sockp); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#include <linux/module.h> | ||
#include <linux/errno.h> | ||
#include <linux/socket.h> | ||
#include <linux/udp.h> | ||
#include <linux/types.h> | ||
#include <linux/kernel.h> | ||
#include <net/udp.h> | ||
#include <net/udp_tunnel.h> | ||
#include <net/net_namespace.h> | ||
|
||
int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, | ||
struct socket **sockp) | ||
{ | ||
int err = -EINVAL; | ||
struct socket *sock = NULL; | ||
|
||
#if IS_ENABLED(CONFIG_IPV6) | ||
if (cfg->family == AF_INET6) { | ||
struct sockaddr_in6 udp6_addr; | ||
|
||
err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); | ||
if (err < 0) | ||
goto error; | ||
|
||
sk_change_net(sock->sk, net); | ||
|
||
udp6_addr.sin6_family = AF_INET6; | ||
memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, | ||
sizeof(udp6_addr.sin6_addr)); | ||
udp6_addr.sin6_port = cfg->local_udp_port; | ||
err = kernel_bind(sock, (struct sockaddr *)&udp6_addr, | ||
sizeof(udp6_addr)); | ||
if (err < 0) | ||
goto error; | ||
|
||
if (cfg->peer_udp_port) { | ||
udp6_addr.sin6_family = AF_INET6; | ||
memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6, | ||
sizeof(udp6_addr.sin6_addr)); | ||
udp6_addr.sin6_port = cfg->peer_udp_port; | ||
err = kernel_connect(sock, | ||
(struct sockaddr *)&udp6_addr, | ||
sizeof(udp6_addr), 0); | ||
} | ||
if (err < 0) | ||
goto error; | ||
|
||
udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums); | ||
udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums); | ||
} else | ||
#endif | ||
if (cfg->family == AF_INET) { | ||
struct sockaddr_in udp_addr; | ||
|
||
err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); | ||
if (err < 0) | ||
goto error; | ||
|
||
sk_change_net(sock->sk, net); | ||
|
||
udp_addr.sin_family = AF_INET; | ||
udp_addr.sin_addr = cfg->local_ip; | ||
udp_addr.sin_port = cfg->local_udp_port; | ||
err = kernel_bind(sock, (struct sockaddr *)&udp_addr, | ||
sizeof(udp_addr)); | ||
if (err < 0) | ||
goto error; | ||
|
||
if (cfg->peer_udp_port) { | ||
udp_addr.sin_family = AF_INET; | ||
udp_addr.sin_addr = cfg->peer_ip; | ||
udp_addr.sin_port = cfg->peer_udp_port; | ||
err = kernel_connect(sock, | ||
(struct sockaddr *)&udp_addr, | ||
sizeof(udp_addr), 0); | ||
if (err < 0) | ||
goto error; | ||
} | ||
|
||
sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; | ||
} else { | ||
return -EPFNOSUPPORT; | ||
} | ||
|
||
|
||
*sockp = sock; | ||
|
||
return 0; | ||
|
||
error: | ||
if (sock) { | ||
kernel_sock_shutdown(sock, SHUT_RDWR); | ||
sk_release_kernel(sock->sk); | ||
} | ||
*sockp = NULL; | ||
return err; | ||
} | ||
EXPORT_SYMBOL(udp_sock_create); | ||
|
||
MODULE_LICENSE("GPL"); |