Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/module.h>
0003 #include <linux/errno.h>
0004 #include <linux/socket.h>
0005 #include <linux/udp.h>
0006 #include <linux/types.h>
0007 #include <linux/kernel.h>
0008 #include <linux/in6.h>
0009 #include <net/udp.h>
0010 #include <net/udp_tunnel.h>
0011 #include <net/net_namespace.h>
0012 #include <net/netns/generic.h>
0013 #include <net/ip6_tunnel.h>
0014 #include <net/ip6_checksum.h>
0015 
0016 int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
0017              struct socket **sockp)
0018 {
0019     struct sockaddr_in6 udp6_addr = {};
0020     int err;
0021     struct socket *sock = NULL;
0022 
0023     err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock);
0024     if (err < 0)
0025         goto error;
0026 
0027     if (cfg->ipv6_v6only) {
0028         err = ip6_sock_set_v6only(sock->sk);
0029         if (err < 0)
0030             goto error;
0031     }
0032     if (cfg->bind_ifindex) {
0033         err = sock_bindtoindex(sock->sk, cfg->bind_ifindex, true);
0034         if (err < 0)
0035             goto error;
0036     }
0037 
0038     udp6_addr.sin6_family = AF_INET6;
0039     memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6,
0040            sizeof(udp6_addr.sin6_addr));
0041     udp6_addr.sin6_port = cfg->local_udp_port;
0042     err = kernel_bind(sock, (struct sockaddr *)&udp6_addr,
0043               sizeof(udp6_addr));
0044     if (err < 0)
0045         goto error;
0046 
0047     if (cfg->peer_udp_port) {
0048         memset(&udp6_addr, 0, sizeof(udp6_addr));
0049         udp6_addr.sin6_family = AF_INET6;
0050         memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6,
0051                sizeof(udp6_addr.sin6_addr));
0052         udp6_addr.sin6_port = cfg->peer_udp_port;
0053         err = kernel_connect(sock,
0054                      (struct sockaddr *)&udp6_addr,
0055                      sizeof(udp6_addr), 0);
0056     }
0057     if (err < 0)
0058         goto error;
0059 
0060     udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums);
0061     udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums);
0062 
0063     *sockp = sock;
0064     return 0;
0065 
0066 error:
0067     if (sock) {
0068         kernel_sock_shutdown(sock, SHUT_RDWR);
0069         sock_release(sock);
0070     }
0071     *sockp = NULL;
0072     return err;
0073 }
0074 EXPORT_SYMBOL_GPL(udp_sock_create6);
0075 
0076 int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
0077              struct sk_buff *skb,
0078              struct net_device *dev, struct in6_addr *saddr,
0079              struct in6_addr *daddr,
0080              __u8 prio, __u8 ttl, __be32 label,
0081              __be16 src_port, __be16 dst_port, bool nocheck)
0082 {
0083     struct udphdr *uh;
0084     struct ipv6hdr *ip6h;
0085 
0086     __skb_push(skb, sizeof(*uh));
0087     skb_reset_transport_header(skb);
0088     uh = udp_hdr(skb);
0089 
0090     uh->dest = dst_port;
0091     uh->source = src_port;
0092 
0093     uh->len = htons(skb->len);
0094 
0095     skb_dst_set(skb, dst);
0096 
0097     udp6_set_csum(nocheck, skb, saddr, daddr, skb->len);
0098 
0099     __skb_push(skb, sizeof(*ip6h));
0100     skb_reset_network_header(skb);
0101     ip6h          = ipv6_hdr(skb);
0102     ip6_flow_hdr(ip6h, prio, label);
0103     ip6h->payload_len = htons(skb->len);
0104     ip6h->nexthdr     = IPPROTO_UDP;
0105     ip6h->hop_limit   = ttl;
0106     ip6h->daddr   = *daddr;
0107     ip6h->saddr   = *saddr;
0108 
0109     ip6tunnel_xmit(sk, skb, dev);
0110     return 0;
0111 }
0112 EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb);
0113 
0114 MODULE_LICENSE("GPL");