linux/net/ipv4/udp_tunnel.c
<<
>>
Prefs
   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