2 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/module.h>
4 #include <linux/errno.h>
5 #include <linux/socket.h>
7 #include <linux/types.h>
8 #include <linux/kernel.h>
11 #include <net/udp_tunnel.h>
12 #include <net/net_namespace.h>
13 #include <net/netns/generic.h>
14 #include <net/ip6_tunnel.h>
15 #include <net/ip6_checksum.h>
17 int udp_sock_create6(struct net
*net
, struct udp_port_cfg
*cfg
,
18 struct socket
**sockp
)
20 struct sockaddr_in6 udp6_addr
= {};
22 struct socket
*sock
= NULL
;
24 err
= sock_create_kern(net
, AF_INET6
, SOCK_DGRAM
, 0, &sock
);
28 if (cfg
->ipv6_v6only
) {
29 err
= ip6_sock_set_v6only(sock
->sk
);
33 if (cfg
->bind_ifindex
) {
34 err
= sock_bindtoindex(sock
->sk
, cfg
->bind_ifindex
, true);
39 udp6_addr
.sin6_family
= AF_INET6
;
40 memcpy(&udp6_addr
.sin6_addr
, &cfg
->local_ip6
,
41 sizeof(udp6_addr
.sin6_addr
));
42 udp6_addr
.sin6_port
= cfg
->local_udp_port
;
43 err
= kernel_bind(sock
, (struct sockaddr
*)&udp6_addr
,
48 if (cfg
->peer_udp_port
) {
49 memset(&udp6_addr
, 0, sizeof(udp6_addr
));
50 udp6_addr
.sin6_family
= AF_INET6
;
51 memcpy(&udp6_addr
.sin6_addr
, &cfg
->peer_ip6
,
52 sizeof(udp6_addr
.sin6_addr
));
53 udp6_addr
.sin6_port
= cfg
->peer_udp_port
;
54 err
= kernel_connect(sock
,
55 (struct sockaddr
*)&udp6_addr
,
56 sizeof(udp6_addr
), 0);
61 udp_set_no_check6_tx(sock
->sk
, !cfg
->use_udp6_tx_checksums
);
62 udp_set_no_check6_rx(sock
->sk
, !cfg
->use_udp6_rx_checksums
);
69 kernel_sock_shutdown(sock
, SHUT_RDWR
);
75 EXPORT_SYMBOL_GPL(udp_sock_create6
);
77 int udp_tunnel6_xmit_skb(struct dst_entry
*dst
, struct sock
*sk
,
79 struct net_device
*dev
,
80 const struct in6_addr
*saddr
,
81 const struct in6_addr
*daddr
,
82 __u8 prio
, __u8 ttl
, __be32 label
,
83 __be16 src_port
, __be16 dst_port
, bool nocheck
)
88 __skb_push(skb
, sizeof(*uh
));
89 skb_reset_transport_header(skb
);
93 uh
->source
= src_port
;
95 uh
->len
= htons(skb
->len
);
97 skb_dst_set(skb
, dst
);
99 udp6_set_csum(nocheck
, skb
, saddr
, daddr
, skb
->len
);
101 __skb_push(skb
, sizeof(*ip6h
));
102 skb_reset_network_header(skb
);
103 ip6h
= ipv6_hdr(skb
);
104 ip6_flow_hdr(ip6h
, prio
, label
);
105 ip6h
->payload_len
= htons(skb
->len
);
106 ip6h
->nexthdr
= IPPROTO_UDP
;
107 ip6h
->hop_limit
= ttl
;
108 ip6h
->daddr
= *daddr
;
109 ip6h
->saddr
= *saddr
;
111 ip6tunnel_xmit(sk
, skb
, dev
);
114 EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb
);
117 * udp_tunnel6_dst_lookup - perform route lookup on UDP tunnel
118 * @skb: Packet for which lookup is done
119 * @dev: Tunnel device
120 * @net: Network namespace of tunnel device
121 * @sock: Socket which provides route info
122 * @oif: Index of the output interface
123 * @saddr: Memory to store the src ip address
124 * @key: Tunnel information
125 * @sport: UDP source port
126 * @dport: UDP destination port
127 * @dsfield: The traffic class field
128 * @dst_cache: The dst cache to use for lookup
129 * This function performs a route lookup on a UDP tunnel
131 * It returns a valid dst pointer and stores src address to be used in
132 * tunnel in param saddr on success, else a pointer encoded error code.
135 struct dst_entry
*udp_tunnel6_dst_lookup(struct sk_buff
*skb
,
136 struct net_device
*dev
,
140 struct in6_addr
*saddr
,
141 const struct ip_tunnel_key
*key
,
142 __be16 sport
, __be16 dport
, u8 dsfield
,
143 struct dst_cache
*dst_cache
)
145 struct dst_entry
*dst
= NULL
;
148 #ifdef CONFIG_DST_CACHE
150 dst
= dst_cache_get_ip6(dst_cache
, saddr
);
155 memset(&fl6
, 0, sizeof(fl6
));
156 fl6
.flowi6_mark
= skb
->mark
;
157 fl6
.flowi6_proto
= IPPROTO_UDP
;
158 fl6
.flowi6_oif
= oif
;
159 fl6
.daddr
= key
->u
.ipv6
.dst
;
160 fl6
.saddr
= key
->u
.ipv6
.src
;
161 fl6
.fl6_sport
= sport
;
162 fl6
.fl6_dport
= dport
;
163 fl6
.flowlabel
= ip6_make_flowinfo(dsfield
, key
->label
);
165 dst
= ipv6_stub
->ipv6_dst_lookup_flow(net
, sock
->sk
, &fl6
,
168 netdev_dbg(dev
, "no route to %pI6\n", &fl6
.daddr
);
169 return ERR_PTR(-ENETUNREACH
);
171 if (dst
->dev
== dev
) { /* is this necessary? */
172 netdev_dbg(dev
, "circular route to %pI6\n", &fl6
.daddr
);
174 return ERR_PTR(-ELOOP
);
176 #ifdef CONFIG_DST_CACHE
178 dst_cache_set_ip6(dst_cache
, dst
, &fl6
.saddr
);
183 EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup
);
185 MODULE_DESCRIPTION("IPv6 Foo over UDP tunnel driver");
186 MODULE_LICENSE("GPL");