1 2 // SPDX-License-Identifier: GPL-2.0-only 3 #include <linux/module.h> 4 #include <linux/errno.h> 5 #include <linux/socket.h> 6 #include <linux/udp.h> 7 #include <linux/types.h> 8 #include <linux/kernel.h> 9 #include <linux/in6.h> 10 #include <net/udp.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> 16 17 int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, 18 struct socket **sockp) 19 { 20 struct sockaddr_in6 udp6_addr = {}; 21 int err; 22 struct socket *sock = NULL; 23 24 err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock); 25 if (err < 0) 26 goto error; 27 28 if (cfg->ipv6_v6only) { 29 err = ip6_sock_set_v6only(sock->sk); 30 if (err < 0) 31 goto error; 32 } 33 if (cfg->bind_ifindex) { 34 err = sock_bindtoindex(sock->sk, cfg->bind_ifindex, true); 35 if (err < 0) 36 goto error; 37 } 38 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, 44 sizeof(udp6_addr)); 45 if (err < 0) 46 goto error; 47 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); 57 } 58 if (err < 0) 59 goto error; 60 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); 63 64 *sockp = sock; 65 return 0; 66 67 error: 68 if (sock) { 69 kernel_sock_shutdown(sock, SHUT_RDWR); 70 sock_release(sock); 71 } 72 *sockp = NULL; 73 return err; 74 } 75 EXPORT_SYMBOL_GPL(udp_sock_create6); 76 77 int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, 78 struct sk_buff *skb, 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) 84 { 85 struct udphdr *uh; 86 struct ipv6hdr *ip6h; 87 88 __skb_push(skb, sizeof(*uh)); 89 skb_reset_transport_header(skb); 90 uh = udp_hdr(skb); 91 92 uh->dest = dst_port; 93 uh->source = src_port; 94 95 uh->len = htons(skb->len); 96 97 skb_dst_set(skb, dst); 98 99 udp6_set_csum(nocheck, skb, saddr, daddr, skb->len); 100 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; 110 111 ip6tunnel_xmit(sk, skb, dev); 112 return 0; 113 } 114 EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); 115 116 /** 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 130 * 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. 133 */ 134 135 struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, 136 struct net_device *dev, 137 struct net *net, 138 struct socket *sock, 139 int oif, 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) 144 { 145 struct dst_entry *dst = NULL; 146 struct flowi6 fl6; 147 148 #ifdef CONFIG_DST_CACHE 149 if (dst_cache) { 150 dst = dst_cache_get_ip6(dst_cache, saddr); 151 if (dst) 152 return dst; 153 } 154 #endif 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); 164 165 dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, 166 NULL); 167 if (IS_ERR(dst)) { 168 netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); 169 return ERR_PTR(-ENETUNREACH); 170 } 171 if (dst->dev == dev) { /* is this necessary? */ 172 netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); 173 dst_release(dst); 174 return ERR_PTR(-ELOOP); 175 } 176 #ifdef CONFIG_DST_CACHE 177 if (dst_cache) 178 dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); 179 #endif 180 *saddr = fl6.saddr; 181 return dst; 182 } 183 EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup); 184 185 MODULE_DESCRIPTION("IPv6 Foo over UDP tunnel driver"); 186 MODULE_LICENSE("GPL"); 187
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.