1 #include <linux/module.h>
2 #include <linux/errno.h>
3 #include <linux/socket.h>
5 #include <linux/types.h>
6 #include <linux/kernel.h>
8 #include <net/udp_tunnel.h>
9 #include <net/net_namespace.h>
11 int udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
12 struct socket **sockp)
15 struct socket *sock = NULL;
17 #if IS_ENABLED(CONFIG_IPV6)
18 if (cfg->family == AF_INET6) {
19 struct sockaddr_in6 udp6_addr;
21 err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock);
25 sk_change_net(sock->sk, net);
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,
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);
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);
52 if (cfg->family == AF_INET) {
53 struct sockaddr_in udp_addr;
55 err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock);
59 sk_change_net(sock->sk, net);
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,
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,
80 sock->sk->sk_no_check_tx = !cfg->use_udp_checksums;
92 kernel_sock_shutdown(sock, SHUT_RDWR);
93 sk_release_kernel(sock->sk);
98 EXPORT_SYMBOL(udp_sock_create);
100 MODULE_LICENSE("GPL");