Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 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 | |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 11 | int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, |
| 12 | struct socket **sockp) |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 13 | { |
| 14 | int err = -EINVAL; |
| 15 | struct socket *sock = NULL; |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 16 | struct sockaddr_in udp_addr; |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 17 | |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 18 | err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); |
| 19 | if (err < 0) |
| 20 | goto error; |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 21 | |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 22 | sk_change_net(sock->sk, net); |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 23 | |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 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; |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 31 | |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 32 | if (cfg->peer_udp_port) { |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 33 | udp_addr.sin_family = AF_INET; |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 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); |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 38 | if (err < 0) |
| 39 | goto error; |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 40 | } |
| 41 | |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 42 | sock->sk->sk_no_check_tx = !cfg->use_udp_checksums; |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 43 | |
| 44 | *sockp = sock; |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 45 | return 0; |
| 46 | |
| 47 | error: |
| 48 | if (sock) { |
| 49 | kernel_sock_shutdown(sock, SHUT_RDWR); |
| 50 | sk_release_kernel(sock->sk); |
| 51 | } |
| 52 | *sockp = NULL; |
| 53 | return err; |
| 54 | } |
Andy Zhou | fd38441 | 2014-09-16 17:31:16 -0700 | [diff] [blame^] | 55 | EXPORT_SYMBOL(udp_sock_create4); |
Tom Herbert | 8024e02 | 2014-07-13 19:49:37 -0700 | [diff] [blame] | 56 | |
| 57 | MODULE_LICENSE("GPL"); |