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 11int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, 12 struct socket **sockp) 13{ 14 int err; 15 struct socket *sock = NULL; 16 struct sockaddr_in udp_addr; 17 18 err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); 19 if (err < 0) 20 goto error; 21 22 sk_change_net(sock->sk, net); 23 24 udp_addr.sin_family = AF_INET; 25 udp_addr.sin_addr = cfg->local_ip; 26 udp_addr.sin_port = cfg->local_udp_port; 27 err = kernel_bind(sock, (struct sockaddr *)&udp_addr, 28 sizeof(udp_addr)); 29 if (err < 0) 30 goto error; 31 32 if (cfg->peer_udp_port) { 33 udp_addr.sin_family = AF_INET; 34 udp_addr.sin_addr = cfg->peer_ip; 35 udp_addr.sin_port = cfg->peer_udp_port; 36 err = kernel_connect(sock, (struct sockaddr *)&udp_addr, 37 sizeof(udp_addr), 0); 38 if (err < 0) 39 goto error; 40 } 41 42 sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; 43 44 *sockp = sock; 45 return 0; 46 47error: 48 if (sock) { 49 kernel_sock_shutdown(sock, SHUT_RDWR); 50 sk_release_kernel(sock->sk); 51 } 52 *sockp = NULL; 53 return err; 54} 55EXPORT_SYMBOL(udp_sock_create4); 56 57void setup_udp_tunnel_sock(struct net *net, struct socket *sock, 58 struct udp_tunnel_sock_cfg *cfg) 59{ 60 struct sock *sk = sock->sk; 61 62 /* Disable multicast loopback */ 63 inet_sk(sk)->mc_loop = 0; 64 65 /* Enable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */ 66 inet_inc_convert_csum(sk); 67 68 rcu_assign_sk_user_data(sk, cfg->sk_user_data); 69 70 udp_sk(sk)->encap_type = cfg->encap_type; 71 udp_sk(sk)->encap_rcv = cfg->encap_rcv; 72 udp_sk(sk)->encap_destroy = cfg->encap_destroy; 73 74 udp_tunnel_encap_enable(sock); 75} 76EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); 77 78int udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, 79 __be32 src, __be32 dst, __u8 tos, __u8 ttl, 80 __be16 df, __be16 src_port, __be16 dst_port, 81 bool xnet, bool nocheck) 82{ 83 struct udphdr *uh; 84 85 __skb_push(skb, sizeof(*uh)); 86 skb_reset_transport_header(skb); 87 uh = udp_hdr(skb); 88 89 uh->dest = dst_port; 90 uh->source = src_port; 91 uh->len = htons(skb->len); 92 93 udp_set_csum(nocheck, skb, src, dst, skb->len); 94 95 return iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, 96 tos, ttl, df, xnet); 97} 98EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); 99 100void udp_tunnel_sock_release(struct socket *sock) 101{ 102 rcu_assign_sk_user_data(sock->sk, NULL); 103 kernel_sock_shutdown(sock, SHUT_RDWR); 104 sk_release_kernel(sock->sk); 105} 106EXPORT_SYMBOL_GPL(udp_tunnel_sock_release); 107 108MODULE_LICENSE("GPL"); 109