1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/module.h>
3 #include <linux/errno.h>
4 #include <linux/socket.h>
6 #include <linux/types.h>
7 #include <linux/kernel.h>
10 #include <net/udp_tunnel.h>
11 #include <net/net_namespace.h>
12 #include <net/netns/generic.h>
13 #include <net/ip6_tunnel.h>
14 #include <net/ip6_checksum.h>
16 int udp_sock_create6(struct net
*net
, struct udp_port_cfg
*cfg
,
17 struct socket
**sockp
)
19 struct sockaddr_in6 udp6_addr
= {};
21 struct socket
*sock
= NULL
;
23 err
= sock_create_kern(net
, AF_INET6
, SOCK_DGRAM
, 0, &sock
);
27 if (cfg
->ipv6_v6only
) {
30 err
= kernel_setsockopt(sock
, IPPROTO_IPV6
, IPV6_V6ONLY
,
31 (char *) &val
, sizeof(val
));
35 if (cfg
->bind_ifindex
) {
36 err
= kernel_setsockopt(sock
, SOL_SOCKET
, SO_BINDTOIFINDEX
,
37 (void *)&cfg
->bind_ifindex
,
38 sizeof(cfg
->bind_ifindex
));
43 udp6_addr
.sin6_family
= AF_INET6
;
44 memcpy(&udp6_addr
.sin6_addr
, &cfg
->local_ip6
,
45 sizeof(udp6_addr
.sin6_addr
));
46 udp6_addr
.sin6_port
= cfg
->local_udp_port
;
47 err
= kernel_bind(sock
, (struct sockaddr
*)&udp6_addr
,
52 if (cfg
->peer_udp_port
) {
53 memset(&udp6_addr
, 0, sizeof(udp6_addr
));
54 udp6_addr
.sin6_family
= AF_INET6
;
55 memcpy(&udp6_addr
.sin6_addr
, &cfg
->peer_ip6
,
56 sizeof(udp6_addr
.sin6_addr
));
57 udp6_addr
.sin6_port
= cfg
->peer_udp_port
;
58 err
= kernel_connect(sock
,
59 (struct sockaddr
*)&udp6_addr
,
60 sizeof(udp6_addr
), 0);
65 udp_set_no_check6_tx(sock
->sk
, !cfg
->use_udp6_tx_checksums
);
66 udp_set_no_check6_rx(sock
->sk
, !cfg
->use_udp6_rx_checksums
);
73 kernel_sock_shutdown(sock
, SHUT_RDWR
);
79 EXPORT_SYMBOL_GPL(udp_sock_create6
);
81 int udp_tunnel6_xmit_skb(struct dst_entry
*dst
, struct sock
*sk
,
83 struct net_device
*dev
, struct in6_addr
*saddr
,
84 struct in6_addr
*daddr
,
85 __u8 prio
, __u8 ttl
, __be32 label
,
86 __be16 src_port
, __be16 dst_port
, bool nocheck
)
91 __skb_push(skb
, sizeof(*uh
));
92 skb_reset_transport_header(skb
);
96 uh
->source
= src_port
;
98 uh
->len
= htons(skb
->len
);
100 skb_dst_set(skb
, dst
);
102 udp6_set_csum(nocheck
, skb
, saddr
, daddr
, skb
->len
);
104 __skb_push(skb
, sizeof(*ip6h
));
105 skb_reset_network_header(skb
);
106 ip6h
= ipv6_hdr(skb
);
107 ip6_flow_hdr(ip6h
, prio
, label
);
108 ip6h
->payload_len
= htons(skb
->len
);
109 ip6h
->nexthdr
= IPPROTO_UDP
;
110 ip6h
->hop_limit
= ttl
;
111 ip6h
->daddr
= *daddr
;
112 ip6h
->saddr
= *saddr
;
114 ip6tunnel_xmit(sk
, skb
, dev
);
117 EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb
);
119 MODULE_LICENSE("GPL");