162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * UDP over IPv6 462306a36Sopenharmony_ci * Linux INET6 implementation 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: 762306a36Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on linux/ipv4/udp.c 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Fixes: 1262306a36Sopenharmony_ci * Hideaki YOSHIFUJI : sin6_scope_id support 1362306a36Sopenharmony_ci * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which 1462306a36Sopenharmony_ci * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind 1562306a36Sopenharmony_ci * a single port at the same time. 1662306a36Sopenharmony_ci * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data 1762306a36Sopenharmony_ci * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/bpf-cgroup.h> 2162306a36Sopenharmony_ci#include <linux/errno.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/socket.h> 2462306a36Sopenharmony_ci#include <linux/sockios.h> 2562306a36Sopenharmony_ci#include <linux/net.h> 2662306a36Sopenharmony_ci#include <linux/in6.h> 2762306a36Sopenharmony_ci#include <linux/netdevice.h> 2862306a36Sopenharmony_ci#include <linux/if_arp.h> 2962306a36Sopenharmony_ci#include <linux/ipv6.h> 3062306a36Sopenharmony_ci#include <linux/icmpv6.h> 3162306a36Sopenharmony_ci#include <linux/init.h> 3262306a36Sopenharmony_ci#include <linux/module.h> 3362306a36Sopenharmony_ci#include <linux/skbuff.h> 3462306a36Sopenharmony_ci#include <linux/slab.h> 3562306a36Sopenharmony_ci#include <linux/uaccess.h> 3662306a36Sopenharmony_ci#include <linux/indirect_call_wrapper.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <net/addrconf.h> 3962306a36Sopenharmony_ci#include <net/ndisc.h> 4062306a36Sopenharmony_ci#include <net/protocol.h> 4162306a36Sopenharmony_ci#include <net/transp_v6.h> 4262306a36Sopenharmony_ci#include <net/ip6_route.h> 4362306a36Sopenharmony_ci#include <net/raw.h> 4462306a36Sopenharmony_ci#include <net/seg6.h> 4562306a36Sopenharmony_ci#include <net/tcp_states.h> 4662306a36Sopenharmony_ci#include <net/ip6_checksum.h> 4762306a36Sopenharmony_ci#include <net/ip6_tunnel.h> 4862306a36Sopenharmony_ci#include <trace/events/udp.h> 4962306a36Sopenharmony_ci#include <net/xfrm.h> 5062306a36Sopenharmony_ci#include <net/inet_hashtables.h> 5162306a36Sopenharmony_ci#include <net/inet6_hashtables.h> 5262306a36Sopenharmony_ci#include <net/busy_poll.h> 5362306a36Sopenharmony_ci#include <net/sock_reuseport.h> 5462306a36Sopenharmony_ci#include <net/gro.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include <linux/proc_fs.h> 5762306a36Sopenharmony_ci#include <linux/seq_file.h> 5862306a36Sopenharmony_ci#include <trace/events/skb.h> 5962306a36Sopenharmony_ci#include "udp_impl.h" 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void udpv6_destruct_sock(struct sock *sk) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci udp_destruct_common(sk); 6462306a36Sopenharmony_ci inet6_sock_destruct(sk); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciint udpv6_init_sock(struct sock *sk) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci udp_lib_init_sock(sk); 7062306a36Sopenharmony_ci sk->sk_destruct = udpv6_destruct_sock; 7162306a36Sopenharmony_ci set_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags); 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciINDIRECT_CALLABLE_SCOPE 7662306a36Sopenharmony_ciu32 udp6_ehashfn(const struct net *net, 7762306a36Sopenharmony_ci const struct in6_addr *laddr, 7862306a36Sopenharmony_ci const u16 lport, 7962306a36Sopenharmony_ci const struct in6_addr *faddr, 8062306a36Sopenharmony_ci const __be16 fport) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci static u32 udp6_ehash_secret __read_mostly; 8362306a36Sopenharmony_ci static u32 udp_ipv6_hash_secret __read_mostly; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci u32 lhash, fhash; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci net_get_random_once(&udp6_ehash_secret, 8862306a36Sopenharmony_ci sizeof(udp6_ehash_secret)); 8962306a36Sopenharmony_ci net_get_random_once(&udp_ipv6_hash_secret, 9062306a36Sopenharmony_ci sizeof(udp_ipv6_hash_secret)); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci lhash = (__force u32)laddr->s6_addr32[3]; 9362306a36Sopenharmony_ci fhash = __ipv6_addr_jhash(faddr, udp_ipv6_hash_secret); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return __inet6_ehashfn(lhash, lport, fhash, fport, 9662306a36Sopenharmony_ci udp6_ehash_secret + net_hash_mix(net)); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciint udp_v6_get_port(struct sock *sk, unsigned short snum) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci unsigned int hash2_nulladdr = 10262306a36Sopenharmony_ci ipv6_portaddr_hash(sock_net(sk), &in6addr_any, snum); 10362306a36Sopenharmony_ci unsigned int hash2_partial = 10462306a36Sopenharmony_ci ipv6_portaddr_hash(sock_net(sk), &sk->sk_v6_rcv_saddr, 0); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* precompute partial secondary hash */ 10762306a36Sopenharmony_ci udp_sk(sk)->udp_portaddr_hash = hash2_partial; 10862306a36Sopenharmony_ci return udp_lib_get_port(sk, snum, hash2_nulladdr); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_civoid udp_v6_rehash(struct sock *sk) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci u16 new_hash = ipv6_portaddr_hash(sock_net(sk), 11462306a36Sopenharmony_ci &sk->sk_v6_rcv_saddr, 11562306a36Sopenharmony_ci inet_sk(sk)->inet_num); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci udp_lib_rehash(sk, new_hash); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int compute_score(struct sock *sk, struct net *net, 12162306a36Sopenharmony_ci const struct in6_addr *saddr, __be16 sport, 12262306a36Sopenharmony_ci const struct in6_addr *daddr, unsigned short hnum, 12362306a36Sopenharmony_ci int dif, int sdif) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci int bound_dev_if, score; 12662306a36Sopenharmony_ci struct inet_sock *inet; 12762306a36Sopenharmony_ci bool dev_match; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (!net_eq(sock_net(sk), net) || 13062306a36Sopenharmony_ci udp_sk(sk)->udp_port_hash != hnum || 13162306a36Sopenharmony_ci sk->sk_family != PF_INET6) 13262306a36Sopenharmony_ci return -1; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) 13562306a36Sopenharmony_ci return -1; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci score = 0; 13862306a36Sopenharmony_ci inet = inet_sk(sk); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (inet->inet_dport) { 14162306a36Sopenharmony_ci if (inet->inet_dport != sport) 14262306a36Sopenharmony_ci return -1; 14362306a36Sopenharmony_ci score++; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!ipv6_addr_any(&sk->sk_v6_daddr)) { 14762306a36Sopenharmony_ci if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr)) 14862306a36Sopenharmony_ci return -1; 14962306a36Sopenharmony_ci score++; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); 15362306a36Sopenharmony_ci dev_match = udp_sk_bound_dev_eq(net, bound_dev_if, dif, sdif); 15462306a36Sopenharmony_ci if (!dev_match) 15562306a36Sopenharmony_ci return -1; 15662306a36Sopenharmony_ci if (bound_dev_if) 15762306a36Sopenharmony_ci score++; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) 16062306a36Sopenharmony_ci score++; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return score; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* called with rcu_read_lock() */ 16662306a36Sopenharmony_cistatic struct sock *udp6_lib_lookup2(struct net *net, 16762306a36Sopenharmony_ci const struct in6_addr *saddr, __be16 sport, 16862306a36Sopenharmony_ci const struct in6_addr *daddr, unsigned int hnum, 16962306a36Sopenharmony_ci int dif, int sdif, struct udp_hslot *hslot2, 17062306a36Sopenharmony_ci struct sk_buff *skb) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct sock *sk, *result; 17362306a36Sopenharmony_ci int score, badness; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci result = NULL; 17662306a36Sopenharmony_ci badness = -1; 17762306a36Sopenharmony_ci udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { 17862306a36Sopenharmony_ci score = compute_score(sk, net, saddr, sport, 17962306a36Sopenharmony_ci daddr, hnum, dif, sdif); 18062306a36Sopenharmony_ci if (score > badness) { 18162306a36Sopenharmony_ci badness = score; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (sk->sk_state == TCP_ESTABLISHED) { 18462306a36Sopenharmony_ci result = sk; 18562306a36Sopenharmony_ci continue; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci result = inet6_lookup_reuseport(net, sk, skb, sizeof(struct udphdr), 18962306a36Sopenharmony_ci saddr, sport, daddr, hnum, udp6_ehashfn); 19062306a36Sopenharmony_ci if (!result) { 19162306a36Sopenharmony_ci result = sk; 19262306a36Sopenharmony_ci continue; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Fall back to scoring if group has connections */ 19662306a36Sopenharmony_ci if (!reuseport_has_conns(sk)) 19762306a36Sopenharmony_ci return result; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Reuseport logic returned an error, keep original score. */ 20062306a36Sopenharmony_ci if (IS_ERR(result)) 20162306a36Sopenharmony_ci continue; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci badness = compute_score(sk, net, saddr, sport, 20462306a36Sopenharmony_ci daddr, hnum, dif, sdif); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci return result; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* rcu_read_lock() must be held */ 21162306a36Sopenharmony_cistruct sock *__udp6_lib_lookup(struct net *net, 21262306a36Sopenharmony_ci const struct in6_addr *saddr, __be16 sport, 21362306a36Sopenharmony_ci const struct in6_addr *daddr, __be16 dport, 21462306a36Sopenharmony_ci int dif, int sdif, struct udp_table *udptable, 21562306a36Sopenharmony_ci struct sk_buff *skb) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci unsigned short hnum = ntohs(dport); 21862306a36Sopenharmony_ci unsigned int hash2, slot2; 21962306a36Sopenharmony_ci struct udp_hslot *hslot2; 22062306a36Sopenharmony_ci struct sock *result, *sk; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci hash2 = ipv6_portaddr_hash(net, daddr, hnum); 22362306a36Sopenharmony_ci slot2 = hash2 & udptable->mask; 22462306a36Sopenharmony_ci hslot2 = &udptable->hash2[slot2]; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Lookup connected or non-wildcard sockets */ 22762306a36Sopenharmony_ci result = udp6_lib_lookup2(net, saddr, sport, 22862306a36Sopenharmony_ci daddr, hnum, dif, sdif, 22962306a36Sopenharmony_ci hslot2, skb); 23062306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(result) && result->sk_state == TCP_ESTABLISHED) 23162306a36Sopenharmony_ci goto done; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Lookup redirect from BPF */ 23462306a36Sopenharmony_ci if (static_branch_unlikely(&bpf_sk_lookup_enabled) && 23562306a36Sopenharmony_ci udptable == net->ipv4.udp_table) { 23662306a36Sopenharmony_ci sk = inet6_lookup_run_sk_lookup(net, IPPROTO_UDP, skb, sizeof(struct udphdr), 23762306a36Sopenharmony_ci saddr, sport, daddr, hnum, dif, 23862306a36Sopenharmony_ci udp6_ehashfn); 23962306a36Sopenharmony_ci if (sk) { 24062306a36Sopenharmony_ci result = sk; 24162306a36Sopenharmony_ci goto done; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* Got non-wildcard socket or error on first lookup */ 24662306a36Sopenharmony_ci if (result) 24762306a36Sopenharmony_ci goto done; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Lookup wildcard sockets */ 25062306a36Sopenharmony_ci hash2 = ipv6_portaddr_hash(net, &in6addr_any, hnum); 25162306a36Sopenharmony_ci slot2 = hash2 & udptable->mask; 25262306a36Sopenharmony_ci hslot2 = &udptable->hash2[slot2]; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci result = udp6_lib_lookup2(net, saddr, sport, 25562306a36Sopenharmony_ci &in6addr_any, hnum, dif, sdif, 25662306a36Sopenharmony_ci hslot2, skb); 25762306a36Sopenharmony_cidone: 25862306a36Sopenharmony_ci if (IS_ERR(result)) 25962306a36Sopenharmony_ci return NULL; 26062306a36Sopenharmony_ci return result; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__udp6_lib_lookup); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, 26562306a36Sopenharmony_ci __be16 sport, __be16 dport, 26662306a36Sopenharmony_ci struct udp_table *udptable) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci const struct ipv6hdr *iph = ipv6_hdr(skb); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport, 27162306a36Sopenharmony_ci &iph->daddr, dport, inet6_iif(skb), 27262306a36Sopenharmony_ci inet6_sdif(skb), udptable, skb); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistruct sock *udp6_lib_lookup_skb(const struct sk_buff *skb, 27662306a36Sopenharmony_ci __be16 sport, __be16 dport) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci const struct ipv6hdr *iph = ipv6_hdr(skb); 27962306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 28062306a36Sopenharmony_ci int iif, sdif; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci inet6_get_iif_sdif(skb, &iif, &sdif); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return __udp6_lib_lookup(net, &iph->saddr, sport, 28562306a36Sopenharmony_ci &iph->daddr, dport, iif, 28662306a36Sopenharmony_ci sdif, net->ipv4.udp_table, NULL); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* Must be called under rcu_read_lock(). 29062306a36Sopenharmony_ci * Does increment socket refcount. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NF_TPROXY_IPV6) || IS_ENABLED(CONFIG_NF_SOCKET_IPV6) 29362306a36Sopenharmony_cistruct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport, 29462306a36Sopenharmony_ci const struct in6_addr *daddr, __be16 dport, int dif) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct sock *sk; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci sk = __udp6_lib_lookup(net, saddr, sport, daddr, dport, 29962306a36Sopenharmony_ci dif, 0, net->ipv4.udp_table, NULL); 30062306a36Sopenharmony_ci if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) 30162306a36Sopenharmony_ci sk = NULL; 30262306a36Sopenharmony_ci return sk; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(udp6_lib_lookup); 30562306a36Sopenharmony_ci#endif 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/* do not use the scratch area len for jumbogram: their length execeeds the 30862306a36Sopenharmony_ci * scratch area space; note that the IP6CB flags is still in the first 30962306a36Sopenharmony_ci * cacheline, so checking for jumbograms is cheap 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cistatic int udp6_skb_len(struct sk_buff *skb) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci return unlikely(inet6_is_jumbogram(skb)) ? skb->len : udp_skb_len(skb); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* 31762306a36Sopenharmony_ci * This should be easy, if there is something there we 31862306a36Sopenharmony_ci * return it, otherwise we block. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ciint udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 32262306a36Sopenharmony_ci int flags, int *addr_len) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct ipv6_pinfo *np = inet6_sk(sk); 32562306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 32662306a36Sopenharmony_ci struct sk_buff *skb; 32762306a36Sopenharmony_ci unsigned int ulen, copied; 32862306a36Sopenharmony_ci int off, err, peeking = flags & MSG_PEEK; 32962306a36Sopenharmony_ci int is_udplite = IS_UDPLITE(sk); 33062306a36Sopenharmony_ci struct udp_mib __percpu *mib; 33162306a36Sopenharmony_ci bool checksum_valid = false; 33262306a36Sopenharmony_ci int is_udp4; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (flags & MSG_ERRQUEUE) 33562306a36Sopenharmony_ci return ipv6_recv_error(sk, msg, len, addr_len); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (np->rxpmtu && np->rxopt.bits.rxpmtu) 33862306a36Sopenharmony_ci return ipv6_recv_rxpmtu(sk, msg, len, addr_len); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_citry_again: 34162306a36Sopenharmony_ci off = sk_peek_offset(sk, flags); 34262306a36Sopenharmony_ci skb = __skb_recv_udp(sk, flags, &off, &err); 34362306a36Sopenharmony_ci if (!skb) 34462306a36Sopenharmony_ci return err; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci ulen = udp6_skb_len(skb); 34762306a36Sopenharmony_ci copied = len; 34862306a36Sopenharmony_ci if (copied > ulen - off) 34962306a36Sopenharmony_ci copied = ulen - off; 35062306a36Sopenharmony_ci else if (copied < ulen) 35162306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci is_udp4 = (skb->protocol == htons(ETH_P_IP)); 35462306a36Sopenharmony_ci mib = __UDPX_MIB(sk, is_udp4); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* 35762306a36Sopenharmony_ci * If checksum is needed at all, try to do it while copying the 35862306a36Sopenharmony_ci * data. If the data is truncated, or if we only want a partial 35962306a36Sopenharmony_ci * coverage checksum (UDP-Lite), do it before the copy. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (copied < ulen || peeking || 36362306a36Sopenharmony_ci (is_udplite && UDP_SKB_CB(skb)->partial_cov)) { 36462306a36Sopenharmony_ci checksum_valid = udp_skb_csum_unnecessary(skb) || 36562306a36Sopenharmony_ci !__udp_lib_checksum_complete(skb); 36662306a36Sopenharmony_ci if (!checksum_valid) 36762306a36Sopenharmony_ci goto csum_copy_err; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (checksum_valid || udp_skb_csum_unnecessary(skb)) { 37162306a36Sopenharmony_ci if (udp_skb_is_linear(skb)) 37262306a36Sopenharmony_ci err = copy_linear_skb(skb, copied, off, &msg->msg_iter); 37362306a36Sopenharmony_ci else 37462306a36Sopenharmony_ci err = skb_copy_datagram_msg(skb, off, msg, copied); 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci err = skb_copy_and_csum_datagram_msg(skb, off, msg); 37762306a36Sopenharmony_ci if (err == -EINVAL) 37862306a36Sopenharmony_ci goto csum_copy_err; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci if (unlikely(err)) { 38162306a36Sopenharmony_ci if (!peeking) { 38262306a36Sopenharmony_ci atomic_inc(&sk->sk_drops); 38362306a36Sopenharmony_ci SNMP_INC_STATS(mib, UDP_MIB_INERRORS); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci kfree_skb(skb); 38662306a36Sopenharmony_ci return err; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci if (!peeking) 38962306a36Sopenharmony_ci SNMP_INC_STATS(mib, UDP_MIB_INDATAGRAMS); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Copy the address. */ 39462306a36Sopenharmony_ci if (msg->msg_name) { 39562306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); 39662306a36Sopenharmony_ci sin6->sin6_family = AF_INET6; 39762306a36Sopenharmony_ci sin6->sin6_port = udp_hdr(skb)->source; 39862306a36Sopenharmony_ci sin6->sin6_flowinfo = 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (is_udp4) { 40162306a36Sopenharmony_ci ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, 40262306a36Sopenharmony_ci &sin6->sin6_addr); 40362306a36Sopenharmony_ci sin6->sin6_scope_id = 0; 40462306a36Sopenharmony_ci } else { 40562306a36Sopenharmony_ci sin6->sin6_addr = ipv6_hdr(skb)->saddr; 40662306a36Sopenharmony_ci sin6->sin6_scope_id = 40762306a36Sopenharmony_ci ipv6_iface_scope_id(&sin6->sin6_addr, 40862306a36Sopenharmony_ci inet6_iif(skb)); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci *addr_len = sizeof(*sin6); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci BPF_CGROUP_RUN_PROG_UDP6_RECVMSG_LOCK(sk, 41362306a36Sopenharmony_ci (struct sockaddr *)sin6, 41462306a36Sopenharmony_ci addr_len); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (udp_test_bit(GRO_ENABLED, sk)) 41862306a36Sopenharmony_ci udp_cmsg_recv(msg, sk, skb); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (np->rxopt.all) 42162306a36Sopenharmony_ci ip6_datagram_recv_common_ctl(sk, msg, skb); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (is_udp4) { 42462306a36Sopenharmony_ci if (inet_cmsg_flags(inet)) 42562306a36Sopenharmony_ci ip_cmsg_recv_offset(msg, sk, skb, 42662306a36Sopenharmony_ci sizeof(struct udphdr), off); 42762306a36Sopenharmony_ci } else { 42862306a36Sopenharmony_ci if (np->rxopt.all) 42962306a36Sopenharmony_ci ip6_datagram_recv_specific_ctl(sk, msg, skb); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci err = copied; 43362306a36Sopenharmony_ci if (flags & MSG_TRUNC) 43462306a36Sopenharmony_ci err = ulen; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci skb_consume_udp(sk, skb, peeking ? -err : err); 43762306a36Sopenharmony_ci return err; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cicsum_copy_err: 44062306a36Sopenharmony_ci if (!__sk_queue_drop_skb(sk, &udp_sk(sk)->reader_queue, skb, flags, 44162306a36Sopenharmony_ci udp_skb_destructor)) { 44262306a36Sopenharmony_ci SNMP_INC_STATS(mib, UDP_MIB_CSUMERRORS); 44362306a36Sopenharmony_ci SNMP_INC_STATS(mib, UDP_MIB_INERRORS); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci kfree_skb(skb); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* starting over for a new packet, but check if we need to yield */ 44862306a36Sopenharmony_ci cond_resched(); 44962306a36Sopenharmony_ci msg->msg_flags &= ~MSG_TRUNC; 45062306a36Sopenharmony_ci goto try_again; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(udpv6_encap_needed_key); 45462306a36Sopenharmony_civoid udpv6_encap_enable(void) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci static_branch_inc(&udpv6_encap_needed_key); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ciEXPORT_SYMBOL(udpv6_encap_enable); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* Handler for tunnels with arbitrary destination ports: no socket lookup, go 46162306a36Sopenharmony_ci * through error handlers in encapsulations looking for a match. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_cistatic int __udp6_lib_err_encap_no_sk(struct sk_buff *skb, 46462306a36Sopenharmony_ci struct inet6_skb_parm *opt, 46562306a36Sopenharmony_ci u8 type, u8 code, int offset, __be32 info) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci int i; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci for (i = 0; i < MAX_IPTUN_ENCAP_OPS; i++) { 47062306a36Sopenharmony_ci int (*handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, 47162306a36Sopenharmony_ci u8 type, u8 code, int offset, __be32 info); 47262306a36Sopenharmony_ci const struct ip6_tnl_encap_ops *encap; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci encap = rcu_dereference(ip6tun_encaps[i]); 47562306a36Sopenharmony_ci if (!encap) 47662306a36Sopenharmony_ci continue; 47762306a36Sopenharmony_ci handler = encap->err_handler; 47862306a36Sopenharmony_ci if (handler && !handler(skb, opt, type, code, offset, info)) 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return -ENOENT; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/* Try to match ICMP errors to UDP tunnels by looking up a socket without 48662306a36Sopenharmony_ci * reversing source and destination port: this will match tunnels that force the 48762306a36Sopenharmony_ci * same destination port on both endpoints (e.g. VXLAN, GENEVE). Note that 48862306a36Sopenharmony_ci * lwtunnels might actually break this assumption by being configured with 48962306a36Sopenharmony_ci * different destination ports on endpoints, in this case we won't be able to 49062306a36Sopenharmony_ci * trace ICMP messages back to them. 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * If this doesn't match any socket, probe tunnels with arbitrary destination 49362306a36Sopenharmony_ci * ports (e.g. FoU, GUE): there, the receiving socket is useless, as the port 49462306a36Sopenharmony_ci * we've sent packets to won't necessarily match the local destination port. 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * Then ask the tunnel implementation to match the error against a valid 49762306a36Sopenharmony_ci * association. 49862306a36Sopenharmony_ci * 49962306a36Sopenharmony_ci * Return an error if we can't find a match, the socket if we need further 50062306a36Sopenharmony_ci * processing, zero otherwise. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_cistatic struct sock *__udp6_lib_err_encap(struct net *net, 50362306a36Sopenharmony_ci const struct ipv6hdr *hdr, int offset, 50462306a36Sopenharmony_ci struct udphdr *uh, 50562306a36Sopenharmony_ci struct udp_table *udptable, 50662306a36Sopenharmony_ci struct sock *sk, 50762306a36Sopenharmony_ci struct sk_buff *skb, 50862306a36Sopenharmony_ci struct inet6_skb_parm *opt, 50962306a36Sopenharmony_ci u8 type, u8 code, __be32 info) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci int (*lookup)(struct sock *sk, struct sk_buff *skb); 51262306a36Sopenharmony_ci int network_offset, transport_offset; 51362306a36Sopenharmony_ci struct udp_sock *up; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci network_offset = skb_network_offset(skb); 51662306a36Sopenharmony_ci transport_offset = skb_transport_offset(skb); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* Network header needs to point to the outer IPv6 header inside ICMP */ 51962306a36Sopenharmony_ci skb_reset_network_header(skb); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* Transport header needs to point to the UDP header */ 52262306a36Sopenharmony_ci skb_set_transport_header(skb, offset); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (sk) { 52562306a36Sopenharmony_ci up = udp_sk(sk); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci lookup = READ_ONCE(up->encap_err_lookup); 52862306a36Sopenharmony_ci if (lookup && lookup(sk, skb)) 52962306a36Sopenharmony_ci sk = NULL; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci goto out; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci sk = __udp6_lib_lookup(net, &hdr->daddr, uh->source, 53562306a36Sopenharmony_ci &hdr->saddr, uh->dest, 53662306a36Sopenharmony_ci inet6_iif(skb), 0, udptable, skb); 53762306a36Sopenharmony_ci if (sk) { 53862306a36Sopenharmony_ci up = udp_sk(sk); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci lookup = READ_ONCE(up->encap_err_lookup); 54162306a36Sopenharmony_ci if (!lookup || lookup(sk, skb)) 54262306a36Sopenharmony_ci sk = NULL; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ciout: 54662306a36Sopenharmony_ci if (!sk) { 54762306a36Sopenharmony_ci sk = ERR_PTR(__udp6_lib_err_encap_no_sk(skb, opt, type, code, 54862306a36Sopenharmony_ci offset, info)); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci skb_set_transport_header(skb, transport_offset); 55262306a36Sopenharmony_ci skb_set_network_header(skb, network_offset); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return sk; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ciint __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 55862306a36Sopenharmony_ci u8 type, u8 code, int offset, __be32 info, 55962306a36Sopenharmony_ci struct udp_table *udptable) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct ipv6_pinfo *np; 56262306a36Sopenharmony_ci const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; 56362306a36Sopenharmony_ci const struct in6_addr *saddr = &hdr->saddr; 56462306a36Sopenharmony_ci const struct in6_addr *daddr = seg6_get_daddr(skb, opt) ? : &hdr->daddr; 56562306a36Sopenharmony_ci struct udphdr *uh = (struct udphdr *)(skb->data+offset); 56662306a36Sopenharmony_ci bool tunnel = false; 56762306a36Sopenharmony_ci struct sock *sk; 56862306a36Sopenharmony_ci int harderr; 56962306a36Sopenharmony_ci int err; 57062306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source, 57362306a36Sopenharmony_ci inet6_iif(skb), inet6_sdif(skb), udptable, NULL); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (!sk || READ_ONCE(udp_sk(sk)->encap_type)) { 57662306a36Sopenharmony_ci /* No socket for error: try tunnels before discarding */ 57762306a36Sopenharmony_ci if (static_branch_unlikely(&udpv6_encap_needed_key)) { 57862306a36Sopenharmony_ci sk = __udp6_lib_err_encap(net, hdr, offset, uh, 57962306a36Sopenharmony_ci udptable, sk, skb, 58062306a36Sopenharmony_ci opt, type, code, info); 58162306a36Sopenharmony_ci if (!sk) 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci } else 58462306a36Sopenharmony_ci sk = ERR_PTR(-ENOENT); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (IS_ERR(sk)) { 58762306a36Sopenharmony_ci __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), 58862306a36Sopenharmony_ci ICMP6_MIB_INERRORS); 58962306a36Sopenharmony_ci return PTR_ERR(sk); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci tunnel = true; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci harderr = icmpv6_err_convert(type, code, &err); 59662306a36Sopenharmony_ci np = inet6_sk(sk); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (type == ICMPV6_PKT_TOOBIG) { 59962306a36Sopenharmony_ci if (!ip6_sk_accept_pmtu(sk)) 60062306a36Sopenharmony_ci goto out; 60162306a36Sopenharmony_ci ip6_sk_update_pmtu(skb, sk, info); 60262306a36Sopenharmony_ci if (np->pmtudisc != IPV6_PMTUDISC_DONT) 60362306a36Sopenharmony_ci harderr = 1; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci if (type == NDISC_REDIRECT) { 60662306a36Sopenharmony_ci if (tunnel) { 60762306a36Sopenharmony_ci ip6_redirect(skb, sock_net(sk), inet6_iif(skb), 60862306a36Sopenharmony_ci READ_ONCE(sk->sk_mark), sk->sk_uid); 60962306a36Sopenharmony_ci } else { 61062306a36Sopenharmony_ci ip6_sk_redirect(skb, sk); 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci goto out; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* Tunnels don't have an application socket: don't pass errors back */ 61662306a36Sopenharmony_ci if (tunnel) { 61762306a36Sopenharmony_ci if (udp_sk(sk)->encap_err_rcv) 61862306a36Sopenharmony_ci udp_sk(sk)->encap_err_rcv(sk, skb, err, uh->dest, 61962306a36Sopenharmony_ci ntohl(info), (u8 *)(uh+1)); 62062306a36Sopenharmony_ci goto out; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!np->recverr) { 62462306a36Sopenharmony_ci if (!harderr || sk->sk_state != TCP_ESTABLISHED) 62562306a36Sopenharmony_ci goto out; 62662306a36Sopenharmony_ci } else { 62762306a36Sopenharmony_ci ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci sk->sk_err = err; 63162306a36Sopenharmony_ci sk_error_report(sk); 63262306a36Sopenharmony_ciout: 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci int rc; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (!ipv6_addr_any(&sk->sk_v6_daddr)) { 64162306a36Sopenharmony_ci sock_rps_save_rxhash(sk, skb); 64262306a36Sopenharmony_ci sk_mark_napi_id(sk, skb); 64362306a36Sopenharmony_ci sk_incoming_cpu_update(sk); 64462306a36Sopenharmony_ci } else { 64562306a36Sopenharmony_ci sk_mark_napi_id_once(sk, skb); 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci rc = __udp_enqueue_schedule_skb(sk, skb); 64962306a36Sopenharmony_ci if (rc < 0) { 65062306a36Sopenharmony_ci int is_udplite = IS_UDPLITE(sk); 65162306a36Sopenharmony_ci enum skb_drop_reason drop_reason; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* Note that an ENOMEM error is charged twice */ 65462306a36Sopenharmony_ci if (rc == -ENOMEM) { 65562306a36Sopenharmony_ci UDP6_INC_STATS(sock_net(sk), 65662306a36Sopenharmony_ci UDP_MIB_RCVBUFERRORS, is_udplite); 65762306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_SOCKET_RCVBUFF; 65862306a36Sopenharmony_ci } else { 65962306a36Sopenharmony_ci UDP6_INC_STATS(sock_net(sk), 66062306a36Sopenharmony_ci UDP_MIB_MEMERRORS, is_udplite); 66162306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_PROTO_MEM; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 66462306a36Sopenharmony_ci kfree_skb_reason(skb, drop_reason); 66562306a36Sopenharmony_ci trace_udp_fail_queue_rcv_skb(rc, sk); 66662306a36Sopenharmony_ci return -1; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return 0; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic __inline__ int udpv6_err(struct sk_buff *skb, 67362306a36Sopenharmony_ci struct inet6_skb_parm *opt, u8 type, 67462306a36Sopenharmony_ci u8 code, int offset, __be32 info) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci return __udp6_lib_err(skb, opt, type, code, offset, info, 67762306a36Sopenharmony_ci dev_net(skb->dev)->ipv4.udp_table); 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci enum skb_drop_reason drop_reason = SKB_DROP_REASON_NOT_SPECIFIED; 68362306a36Sopenharmony_ci struct udp_sock *up = udp_sk(sk); 68462306a36Sopenharmony_ci int is_udplite = IS_UDPLITE(sk); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { 68762306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_XFRM_POLICY; 68862306a36Sopenharmony_ci goto drop; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci nf_reset_ct(skb); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (static_branch_unlikely(&udpv6_encap_needed_key) && 69362306a36Sopenharmony_ci READ_ONCE(up->encap_type)) { 69462306a36Sopenharmony_ci int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* 69762306a36Sopenharmony_ci * This is an encapsulation socket so pass the skb to 69862306a36Sopenharmony_ci * the socket's udp_encap_rcv() hook. Otherwise, just 69962306a36Sopenharmony_ci * fall through and pass this up the UDP socket. 70062306a36Sopenharmony_ci * up->encap_rcv() returns the following value: 70162306a36Sopenharmony_ci * =0 if skb was successfully passed to the encap 70262306a36Sopenharmony_ci * handler or was discarded by it. 70362306a36Sopenharmony_ci * >0 if skb should be passed on to UDP. 70462306a36Sopenharmony_ci * <0 if skb should be resubmitted as proto -N 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* if we're overly short, let UDP handle it */ 70862306a36Sopenharmony_ci encap_rcv = READ_ONCE(up->encap_rcv); 70962306a36Sopenharmony_ci if (encap_rcv) { 71062306a36Sopenharmony_ci int ret; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* Verify checksum before giving to encap */ 71362306a36Sopenharmony_ci if (udp_lib_checksum_complete(skb)) 71462306a36Sopenharmony_ci goto csum_error; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci ret = encap_rcv(sk, skb); 71762306a36Sopenharmony_ci if (ret <= 0) { 71862306a36Sopenharmony_ci __UDP6_INC_STATS(sock_net(sk), 71962306a36Sopenharmony_ci UDP_MIB_INDATAGRAMS, 72062306a36Sopenharmony_ci is_udplite); 72162306a36Sopenharmony_ci return -ret; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* FALLTHROUGH -- it's a UDP Packet */ 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* 72962306a36Sopenharmony_ci * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci if (udp_test_bit(UDPLITE_RECV_CC, sk) && UDP_SKB_CB(skb)->partial_cov) { 73262306a36Sopenharmony_ci u16 pcrlen = READ_ONCE(up->pcrlen); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (pcrlen == 0) { /* full coverage was set */ 73562306a36Sopenharmony_ci net_dbg_ratelimited("UDPLITE6: partial coverage %d while full coverage %d requested\n", 73662306a36Sopenharmony_ci UDP_SKB_CB(skb)->cscov, skb->len); 73762306a36Sopenharmony_ci goto drop; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci if (UDP_SKB_CB(skb)->cscov < pcrlen) { 74062306a36Sopenharmony_ci net_dbg_ratelimited("UDPLITE6: coverage %d too small, need min %d\n", 74162306a36Sopenharmony_ci UDP_SKB_CB(skb)->cscov, pcrlen); 74262306a36Sopenharmony_ci goto drop; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci prefetch(&sk->sk_rmem_alloc); 74762306a36Sopenharmony_ci if (rcu_access_pointer(sk->sk_filter) && 74862306a36Sopenharmony_ci udp_lib_checksum_complete(skb)) 74962306a36Sopenharmony_ci goto csum_error; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr))) { 75262306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_SOCKET_FILTER; 75362306a36Sopenharmony_ci goto drop; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci udp_csum_pull_header(skb); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci skb_dst_drop(skb); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return __udpv6_queue_rcv_skb(sk, skb); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cicsum_error: 76362306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_UDP_CSUM; 76462306a36Sopenharmony_ci __UDP6_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); 76562306a36Sopenharmony_cidrop: 76662306a36Sopenharmony_ci __UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); 76762306a36Sopenharmony_ci atomic_inc(&sk->sk_drops); 76862306a36Sopenharmony_ci kfree_skb_reason(skb, drop_reason); 76962306a36Sopenharmony_ci return -1; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct sk_buff *next, *segs; 77562306a36Sopenharmony_ci int ret; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (likely(!udp_unexpected_gso(sk, skb))) 77862306a36Sopenharmony_ci return udpv6_queue_rcv_one_skb(sk, skb); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci __skb_push(skb, -skb_mac_offset(skb)); 78162306a36Sopenharmony_ci segs = udp_rcv_segment(sk, skb, false); 78262306a36Sopenharmony_ci skb_list_walk_safe(segs, skb, next) { 78362306a36Sopenharmony_ci __skb_pull(skb, skb_transport_offset(skb)); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci udp_post_segment_fix_csum(skb); 78662306a36Sopenharmony_ci ret = udpv6_queue_rcv_one_skb(sk, skb); 78762306a36Sopenharmony_ci if (ret > 0) 78862306a36Sopenharmony_ci ip6_protocol_deliver_rcu(dev_net(skb->dev), skb, ret, 78962306a36Sopenharmony_ci true); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic bool __udp_v6_is_mcast_sock(struct net *net, const struct sock *sk, 79562306a36Sopenharmony_ci __be16 loc_port, const struct in6_addr *loc_addr, 79662306a36Sopenharmony_ci __be16 rmt_port, const struct in6_addr *rmt_addr, 79762306a36Sopenharmony_ci int dif, int sdif, unsigned short hnum) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci const struct inet_sock *inet = inet_sk(sk); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (!net_eq(sock_net(sk), net)) 80262306a36Sopenharmony_ci return false; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (udp_sk(sk)->udp_port_hash != hnum || 80562306a36Sopenharmony_ci sk->sk_family != PF_INET6 || 80662306a36Sopenharmony_ci (inet->inet_dport && inet->inet_dport != rmt_port) || 80762306a36Sopenharmony_ci (!ipv6_addr_any(&sk->sk_v6_daddr) && 80862306a36Sopenharmony_ci !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) || 80962306a36Sopenharmony_ci !udp_sk_bound_dev_eq(net, READ_ONCE(sk->sk_bound_dev_if), dif, sdif) || 81062306a36Sopenharmony_ci (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) && 81162306a36Sopenharmony_ci !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr))) 81262306a36Sopenharmony_ci return false; 81362306a36Sopenharmony_ci if (!inet6_mc_check(sk, loc_addr, rmt_addr)) 81462306a36Sopenharmony_ci return false; 81562306a36Sopenharmony_ci return true; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic void udp6_csum_zero_error(struct sk_buff *skb) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci /* RFC 2460 section 8.1 says that we SHOULD log 82162306a36Sopenharmony_ci * this error. Well, it is reasonable. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci net_dbg_ratelimited("IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", 82462306a36Sopenharmony_ci &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source), 82562306a36Sopenharmony_ci &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest)); 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci/* 82962306a36Sopenharmony_ci * Note: called only from the BH handler context, 83062306a36Sopenharmony_ci * so we don't need to lock the hashes. 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_cistatic int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, 83362306a36Sopenharmony_ci const struct in6_addr *saddr, const struct in6_addr *daddr, 83462306a36Sopenharmony_ci struct udp_table *udptable, int proto) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci struct sock *sk, *first = NULL; 83762306a36Sopenharmony_ci const struct udphdr *uh = udp_hdr(skb); 83862306a36Sopenharmony_ci unsigned short hnum = ntohs(uh->dest); 83962306a36Sopenharmony_ci struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); 84062306a36Sopenharmony_ci unsigned int offset = offsetof(typeof(*sk), sk_node); 84162306a36Sopenharmony_ci unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); 84262306a36Sopenharmony_ci int dif = inet6_iif(skb); 84362306a36Sopenharmony_ci int sdif = inet6_sdif(skb); 84462306a36Sopenharmony_ci struct hlist_node *node; 84562306a36Sopenharmony_ci struct sk_buff *nskb; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (use_hash2) { 84862306a36Sopenharmony_ci hash2_any = ipv6_portaddr_hash(net, &in6addr_any, hnum) & 84962306a36Sopenharmony_ci udptable->mask; 85062306a36Sopenharmony_ci hash2 = ipv6_portaddr_hash(net, daddr, hnum) & udptable->mask; 85162306a36Sopenharmony_cistart_lookup: 85262306a36Sopenharmony_ci hslot = &udptable->hash2[hash2]; 85362306a36Sopenharmony_ci offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) { 85762306a36Sopenharmony_ci if (!__udp_v6_is_mcast_sock(net, sk, uh->dest, daddr, 85862306a36Sopenharmony_ci uh->source, saddr, dif, sdif, 85962306a36Sopenharmony_ci hnum)) 86062306a36Sopenharmony_ci continue; 86162306a36Sopenharmony_ci /* If zero checksum and no_check is not on for 86262306a36Sopenharmony_ci * the socket then skip it. 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_ci if (!uh->check && !udp_get_no_check6_rx(sk)) 86562306a36Sopenharmony_ci continue; 86662306a36Sopenharmony_ci if (!first) { 86762306a36Sopenharmony_ci first = sk; 86862306a36Sopenharmony_ci continue; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci nskb = skb_clone(skb, GFP_ATOMIC); 87162306a36Sopenharmony_ci if (unlikely(!nskb)) { 87262306a36Sopenharmony_ci atomic_inc(&sk->sk_drops); 87362306a36Sopenharmony_ci __UDP6_INC_STATS(net, UDP_MIB_RCVBUFERRORS, 87462306a36Sopenharmony_ci IS_UDPLITE(sk)); 87562306a36Sopenharmony_ci __UDP6_INC_STATS(net, UDP_MIB_INERRORS, 87662306a36Sopenharmony_ci IS_UDPLITE(sk)); 87762306a36Sopenharmony_ci continue; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (udpv6_queue_rcv_skb(sk, nskb) > 0) 88162306a36Sopenharmony_ci consume_skb(nskb); 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* Also lookup *:port if we are using hash2 and haven't done so yet. */ 88562306a36Sopenharmony_ci if (use_hash2 && hash2 != hash2_any) { 88662306a36Sopenharmony_ci hash2 = hash2_any; 88762306a36Sopenharmony_ci goto start_lookup; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (first) { 89162306a36Sopenharmony_ci if (udpv6_queue_rcv_skb(first, skb) > 0) 89262306a36Sopenharmony_ci consume_skb(skb); 89362306a36Sopenharmony_ci } else { 89462306a36Sopenharmony_ci kfree_skb(skb); 89562306a36Sopenharmony_ci __UDP6_INC_STATS(net, UDP_MIB_IGNOREDMULTI, 89662306a36Sopenharmony_ci proto == IPPROTO_UDPLITE); 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic void udp6_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci if (udp_sk_rx_dst_set(sk, dst)) { 90462306a36Sopenharmony_ci const struct rt6_info *rt = (const struct rt6_info *)dst; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci sk->sk_rx_dst_cookie = rt6_get_cookie(rt); 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci/* wrapper for udp_queue_rcv_skb tacking care of csum conversion and 91162306a36Sopenharmony_ci * return code conversion for ip layer consumption 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_cistatic int udp6_unicast_rcv_skb(struct sock *sk, struct sk_buff *skb, 91462306a36Sopenharmony_ci struct udphdr *uh) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci int ret; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk)) 91962306a36Sopenharmony_ci skb_checksum_try_convert(skb, IPPROTO_UDP, ip6_compute_pseudo); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci ret = udpv6_queue_rcv_skb(sk, skb); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* a return value > 0 means to resubmit the input */ 92462306a36Sopenharmony_ci if (ret > 0) 92562306a36Sopenharmony_ci return ret; 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ciint __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, 93062306a36Sopenharmony_ci int proto) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 93362306a36Sopenharmony_ci const struct in6_addr *saddr, *daddr; 93462306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 93562306a36Sopenharmony_ci struct udphdr *uh; 93662306a36Sopenharmony_ci struct sock *sk; 93762306a36Sopenharmony_ci bool refcounted; 93862306a36Sopenharmony_ci u32 ulen = 0; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct udphdr))) 94162306a36Sopenharmony_ci goto discard; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci saddr = &ipv6_hdr(skb)->saddr; 94462306a36Sopenharmony_ci daddr = &ipv6_hdr(skb)->daddr; 94562306a36Sopenharmony_ci uh = udp_hdr(skb); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci ulen = ntohs(uh->len); 94862306a36Sopenharmony_ci if (ulen > skb->len) 94962306a36Sopenharmony_ci goto short_packet; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (proto == IPPROTO_UDP) { 95262306a36Sopenharmony_ci /* UDP validates ulen. */ 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* Check for jumbo payload */ 95562306a36Sopenharmony_ci if (ulen == 0) 95662306a36Sopenharmony_ci ulen = skb->len; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (ulen < sizeof(*uh)) 95962306a36Sopenharmony_ci goto short_packet; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (ulen < skb->len) { 96262306a36Sopenharmony_ci if (pskb_trim_rcsum(skb, ulen)) 96362306a36Sopenharmony_ci goto short_packet; 96462306a36Sopenharmony_ci saddr = &ipv6_hdr(skb)->saddr; 96562306a36Sopenharmony_ci daddr = &ipv6_hdr(skb)->daddr; 96662306a36Sopenharmony_ci uh = udp_hdr(skb); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (udp6_csum_init(skb, uh, proto)) 97162306a36Sopenharmony_ci goto csum_error; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* Check if the socket is already available, e.g. due to early demux */ 97462306a36Sopenharmony_ci sk = inet6_steal_sock(net, skb, sizeof(struct udphdr), saddr, uh->source, daddr, uh->dest, 97562306a36Sopenharmony_ci &refcounted, udp6_ehashfn); 97662306a36Sopenharmony_ci if (IS_ERR(sk)) 97762306a36Sopenharmony_ci goto no_sk; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (sk) { 98062306a36Sopenharmony_ci struct dst_entry *dst = skb_dst(skb); 98162306a36Sopenharmony_ci int ret; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (unlikely(rcu_dereference(sk->sk_rx_dst) != dst)) 98462306a36Sopenharmony_ci udp6_sk_rx_dst_set(sk, dst); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (!uh->check && !udp_get_no_check6_rx(sk)) { 98762306a36Sopenharmony_ci if (refcounted) 98862306a36Sopenharmony_ci sock_put(sk); 98962306a36Sopenharmony_ci goto report_csum_error; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci ret = udp6_unicast_rcv_skb(sk, skb, uh); 99362306a36Sopenharmony_ci if (refcounted) 99462306a36Sopenharmony_ci sock_put(sk); 99562306a36Sopenharmony_ci return ret; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* 99962306a36Sopenharmony_ci * Multicast receive code 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci if (ipv6_addr_is_multicast(daddr)) 100262306a36Sopenharmony_ci return __udp6_lib_mcast_deliver(net, skb, 100362306a36Sopenharmony_ci saddr, daddr, udptable, proto); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Unicast */ 100662306a36Sopenharmony_ci sk = __udp6_lib_lookup_skb(skb, uh->source, uh->dest, udptable); 100762306a36Sopenharmony_ci if (sk) { 100862306a36Sopenharmony_ci if (!uh->check && !udp_get_no_check6_rx(sk)) 100962306a36Sopenharmony_ci goto report_csum_error; 101062306a36Sopenharmony_ci return udp6_unicast_rcv_skb(sk, skb, uh); 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_cino_sk: 101362306a36Sopenharmony_ci reason = SKB_DROP_REASON_NO_SOCKET; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (!uh->check) 101662306a36Sopenharmony_ci goto report_csum_error; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 101962306a36Sopenharmony_ci goto discard; 102062306a36Sopenharmony_ci nf_reset_ct(skb); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (udp_lib_checksum_complete(skb)) 102362306a36Sopenharmony_ci goto csum_error; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci __UDP6_INC_STATS(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); 102662306a36Sopenharmony_ci icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 102962306a36Sopenharmony_ci return 0; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cishort_packet: 103262306a36Sopenharmony_ci if (reason == SKB_DROP_REASON_NOT_SPECIFIED) 103362306a36Sopenharmony_ci reason = SKB_DROP_REASON_PKT_TOO_SMALL; 103462306a36Sopenharmony_ci net_dbg_ratelimited("UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n", 103562306a36Sopenharmony_ci proto == IPPROTO_UDPLITE ? "-Lite" : "", 103662306a36Sopenharmony_ci saddr, ntohs(uh->source), 103762306a36Sopenharmony_ci ulen, skb->len, 103862306a36Sopenharmony_ci daddr, ntohs(uh->dest)); 103962306a36Sopenharmony_ci goto discard; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cireport_csum_error: 104262306a36Sopenharmony_ci udp6_csum_zero_error(skb); 104362306a36Sopenharmony_cicsum_error: 104462306a36Sopenharmony_ci if (reason == SKB_DROP_REASON_NOT_SPECIFIED) 104562306a36Sopenharmony_ci reason = SKB_DROP_REASON_UDP_CSUM; 104662306a36Sopenharmony_ci __UDP6_INC_STATS(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); 104762306a36Sopenharmony_cidiscard: 104862306a36Sopenharmony_ci __UDP6_INC_STATS(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); 104962306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 105062306a36Sopenharmony_ci return 0; 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic struct sock *__udp6_lib_demux_lookup(struct net *net, 105562306a36Sopenharmony_ci __be16 loc_port, const struct in6_addr *loc_addr, 105662306a36Sopenharmony_ci __be16 rmt_port, const struct in6_addr *rmt_addr, 105762306a36Sopenharmony_ci int dif, int sdif) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct udp_table *udptable = net->ipv4.udp_table; 106062306a36Sopenharmony_ci unsigned short hnum = ntohs(loc_port); 106162306a36Sopenharmony_ci unsigned int hash2, slot2; 106262306a36Sopenharmony_ci struct udp_hslot *hslot2; 106362306a36Sopenharmony_ci __portpair ports; 106462306a36Sopenharmony_ci struct sock *sk; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci hash2 = ipv6_portaddr_hash(net, loc_addr, hnum); 106762306a36Sopenharmony_ci slot2 = hash2 & udptable->mask; 106862306a36Sopenharmony_ci hslot2 = &udptable->hash2[slot2]; 106962306a36Sopenharmony_ci ports = INET_COMBINED_PORTS(rmt_port, hnum); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { 107262306a36Sopenharmony_ci if (sk->sk_state == TCP_ESTABLISHED && 107362306a36Sopenharmony_ci inet6_match(net, sk, rmt_addr, loc_addr, ports, dif, sdif)) 107462306a36Sopenharmony_ci return sk; 107562306a36Sopenharmony_ci /* Only check first socket in chain */ 107662306a36Sopenharmony_ci break; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci return NULL; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_civoid udp_v6_early_demux(struct sk_buff *skb) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 108462306a36Sopenharmony_ci const struct udphdr *uh; 108562306a36Sopenharmony_ci struct sock *sk; 108662306a36Sopenharmony_ci struct dst_entry *dst; 108762306a36Sopenharmony_ci int dif = skb->dev->ifindex; 108862306a36Sopenharmony_ci int sdif = inet6_sdif(skb); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (!pskb_may_pull(skb, skb_transport_offset(skb) + 109162306a36Sopenharmony_ci sizeof(struct udphdr))) 109262306a36Sopenharmony_ci return; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci uh = udp_hdr(skb); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (skb->pkt_type == PACKET_HOST) 109762306a36Sopenharmony_ci sk = __udp6_lib_demux_lookup(net, uh->dest, 109862306a36Sopenharmony_ci &ipv6_hdr(skb)->daddr, 109962306a36Sopenharmony_ci uh->source, &ipv6_hdr(skb)->saddr, 110062306a36Sopenharmony_ci dif, sdif); 110162306a36Sopenharmony_ci else 110262306a36Sopenharmony_ci return; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt)) 110562306a36Sopenharmony_ci return; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci skb->sk = sk; 110862306a36Sopenharmony_ci skb->destructor = sock_efree; 110962306a36Sopenharmony_ci dst = rcu_dereference(sk->sk_rx_dst); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (dst) 111262306a36Sopenharmony_ci dst = dst_check(dst, sk->sk_rx_dst_cookie); 111362306a36Sopenharmony_ci if (dst) { 111462306a36Sopenharmony_ci /* set noref for now. 111562306a36Sopenharmony_ci * any place which wants to hold dst has to call 111662306a36Sopenharmony_ci * dst_hold_safe() 111762306a36Sopenharmony_ci */ 111862306a36Sopenharmony_ci skb_dst_set_noref(skb, dst); 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ciINDIRECT_CALLABLE_SCOPE int udpv6_rcv(struct sk_buff *skb) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci return __udp6_lib_rcv(skb, dev_net(skb->dev)->ipv4.udp_table, IPPROTO_UDP); 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci/* 112862306a36Sopenharmony_ci * Throw away all pending data and cancel the corking. Socket is locked. 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_cistatic void udp_v6_flush_pending_frames(struct sock *sk) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci struct udp_sock *up = udp_sk(sk); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (up->pending == AF_INET) 113562306a36Sopenharmony_ci udp_flush_pending_frames(sk); 113662306a36Sopenharmony_ci else if (up->pending) { 113762306a36Sopenharmony_ci up->len = 0; 113862306a36Sopenharmony_ci WRITE_ONCE(up->pending, 0); 113962306a36Sopenharmony_ci ip6_flush_pending_frames(sk); 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic int udpv6_pre_connect(struct sock *sk, struct sockaddr *uaddr, 114462306a36Sopenharmony_ci int addr_len) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci if (addr_len < offsetofend(struct sockaddr, sa_family)) 114762306a36Sopenharmony_ci return -EINVAL; 114862306a36Sopenharmony_ci /* The following checks are replicated from __ip6_datagram_connect() 114962306a36Sopenharmony_ci * and intended to prevent BPF program called below from accessing 115062306a36Sopenharmony_ci * bytes that are out of the bound specified by user in addr_len. 115162306a36Sopenharmony_ci */ 115262306a36Sopenharmony_ci if (uaddr->sa_family == AF_INET) { 115362306a36Sopenharmony_ci if (ipv6_only_sock(sk)) 115462306a36Sopenharmony_ci return -EAFNOSUPPORT; 115562306a36Sopenharmony_ci return udp_pre_connect(sk, uaddr, addr_len); 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (addr_len < SIN6_LEN_RFC2133) 115962306a36Sopenharmony_ci return -EINVAL; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return BPF_CGROUP_RUN_PROG_INET6_CONNECT_LOCK(sk, uaddr, &addr_len); 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci/** 116562306a36Sopenharmony_ci * udp6_hwcsum_outgoing - handle outgoing HW checksumming 116662306a36Sopenharmony_ci * @sk: socket we are sending on 116762306a36Sopenharmony_ci * @skb: sk_buff containing the filled-in UDP header 116862306a36Sopenharmony_ci * (checksum field must be zeroed out) 116962306a36Sopenharmony_ci * @saddr: source address 117062306a36Sopenharmony_ci * @daddr: destination address 117162306a36Sopenharmony_ci * @len: length of packet 117262306a36Sopenharmony_ci */ 117362306a36Sopenharmony_cistatic void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, 117462306a36Sopenharmony_ci const struct in6_addr *saddr, 117562306a36Sopenharmony_ci const struct in6_addr *daddr, int len) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci unsigned int offset; 117862306a36Sopenharmony_ci struct udphdr *uh = udp_hdr(skb); 117962306a36Sopenharmony_ci struct sk_buff *frags = skb_shinfo(skb)->frag_list; 118062306a36Sopenharmony_ci __wsum csum = 0; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (!frags) { 118362306a36Sopenharmony_ci /* Only one fragment on the socket. */ 118462306a36Sopenharmony_ci skb->csum_start = skb_transport_header(skb) - skb->head; 118562306a36Sopenharmony_ci skb->csum_offset = offsetof(struct udphdr, check); 118662306a36Sopenharmony_ci uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0); 118762306a36Sopenharmony_ci } else { 118862306a36Sopenharmony_ci /* 118962306a36Sopenharmony_ci * HW-checksum won't work as there are two or more 119062306a36Sopenharmony_ci * fragments on the socket so that all csums of sk_buffs 119162306a36Sopenharmony_ci * should be together 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ci offset = skb_transport_offset(skb); 119462306a36Sopenharmony_ci skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); 119562306a36Sopenharmony_ci csum = skb->csum; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci do { 120062306a36Sopenharmony_ci csum = csum_add(csum, frags->csum); 120162306a36Sopenharmony_ci } while ((frags = frags->next)); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 120462306a36Sopenharmony_ci csum); 120562306a36Sopenharmony_ci if (uh->check == 0) 120662306a36Sopenharmony_ci uh->check = CSUM_MANGLED_0; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci/* 121162306a36Sopenharmony_ci * Sending 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, 121562306a36Sopenharmony_ci struct inet_cork *cork) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci struct sock *sk = skb->sk; 121862306a36Sopenharmony_ci struct udphdr *uh; 121962306a36Sopenharmony_ci int err = 0; 122062306a36Sopenharmony_ci int is_udplite = IS_UDPLITE(sk); 122162306a36Sopenharmony_ci __wsum csum = 0; 122262306a36Sopenharmony_ci int offset = skb_transport_offset(skb); 122362306a36Sopenharmony_ci int len = skb->len - offset; 122462306a36Sopenharmony_ci int datalen = len - sizeof(*uh); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * Create a UDP header 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_ci uh = udp_hdr(skb); 123062306a36Sopenharmony_ci uh->source = fl6->fl6_sport; 123162306a36Sopenharmony_ci uh->dest = fl6->fl6_dport; 123262306a36Sopenharmony_ci uh->len = htons(len); 123362306a36Sopenharmony_ci uh->check = 0; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (cork->gso_size) { 123662306a36Sopenharmony_ci const int hlen = skb_network_header_len(skb) + 123762306a36Sopenharmony_ci sizeof(struct udphdr); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (hlen + cork->gso_size > cork->fragsize) { 124062306a36Sopenharmony_ci kfree_skb(skb); 124162306a36Sopenharmony_ci return -EINVAL; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci if (datalen > cork->gso_size * UDP_MAX_SEGMENTS) { 124462306a36Sopenharmony_ci kfree_skb(skb); 124562306a36Sopenharmony_ci return -EINVAL; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci if (udp_get_no_check6_tx(sk)) { 124862306a36Sopenharmony_ci kfree_skb(skb); 124962306a36Sopenharmony_ci return -EINVAL; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || 125262306a36Sopenharmony_ci dst_xfrm(skb_dst(skb))) { 125362306a36Sopenharmony_ci kfree_skb(skb); 125462306a36Sopenharmony_ci return -EIO; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (datalen > cork->gso_size) { 125862306a36Sopenharmony_ci skb_shinfo(skb)->gso_size = cork->gso_size; 125962306a36Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; 126062306a36Sopenharmony_ci skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(datalen, 126162306a36Sopenharmony_ci cork->gso_size); 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci goto csum_partial; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (is_udplite) 126762306a36Sopenharmony_ci csum = udplite_csum(skb); 126862306a36Sopenharmony_ci else if (udp_get_no_check6_tx(sk)) { /* UDP csum disabled */ 126962306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 127062306a36Sopenharmony_ci goto send; 127162306a36Sopenharmony_ci } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ 127262306a36Sopenharmony_cicsum_partial: 127362306a36Sopenharmony_ci udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len); 127462306a36Sopenharmony_ci goto send; 127562306a36Sopenharmony_ci } else 127662306a36Sopenharmony_ci csum = udp_csum(skb); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci /* add protocol-dependent pseudo-header */ 127962306a36Sopenharmony_ci uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, 128062306a36Sopenharmony_ci len, fl6->flowi6_proto, csum); 128162306a36Sopenharmony_ci if (uh->check == 0) 128262306a36Sopenharmony_ci uh->check = CSUM_MANGLED_0; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cisend: 128562306a36Sopenharmony_ci err = ip6_send_skb(skb); 128662306a36Sopenharmony_ci if (err) { 128762306a36Sopenharmony_ci if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { 128862306a36Sopenharmony_ci UDP6_INC_STATS(sock_net(sk), 128962306a36Sopenharmony_ci UDP_MIB_SNDBUFERRORS, is_udplite); 129062306a36Sopenharmony_ci err = 0; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci } else { 129362306a36Sopenharmony_ci UDP6_INC_STATS(sock_net(sk), 129462306a36Sopenharmony_ci UDP_MIB_OUTDATAGRAMS, is_udplite); 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci return err; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int udp_v6_push_pending_frames(struct sock *sk) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct sk_buff *skb; 130262306a36Sopenharmony_ci struct udp_sock *up = udp_sk(sk); 130362306a36Sopenharmony_ci int err = 0; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (up->pending == AF_INET) 130662306a36Sopenharmony_ci return udp_push_pending_frames(sk); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci skb = ip6_finish_skb(sk); 130962306a36Sopenharmony_ci if (!skb) 131062306a36Sopenharmony_ci goto out; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci err = udp_v6_send_skb(skb, &inet_sk(sk)->cork.fl.u.ip6, 131362306a36Sopenharmony_ci &inet_sk(sk)->cork.base); 131462306a36Sopenharmony_ciout: 131562306a36Sopenharmony_ci up->len = 0; 131662306a36Sopenharmony_ci WRITE_ONCE(up->pending, 0); 131762306a36Sopenharmony_ci return err; 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ciint udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci struct ipv6_txoptions opt_space; 132362306a36Sopenharmony_ci struct udp_sock *up = udp_sk(sk); 132462306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 132562306a36Sopenharmony_ci struct ipv6_pinfo *np = inet6_sk(sk); 132662306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); 132762306a36Sopenharmony_ci struct in6_addr *daddr, *final_p, final; 132862306a36Sopenharmony_ci struct ipv6_txoptions *opt = NULL; 132962306a36Sopenharmony_ci struct ipv6_txoptions *opt_to_free = NULL; 133062306a36Sopenharmony_ci struct ip6_flowlabel *flowlabel = NULL; 133162306a36Sopenharmony_ci struct inet_cork_full cork; 133262306a36Sopenharmony_ci struct flowi6 *fl6 = &cork.fl.u.ip6; 133362306a36Sopenharmony_ci struct dst_entry *dst; 133462306a36Sopenharmony_ci struct ipcm6_cookie ipc6; 133562306a36Sopenharmony_ci int addr_len = msg->msg_namelen; 133662306a36Sopenharmony_ci bool connected = false; 133762306a36Sopenharmony_ci int ulen = len; 133862306a36Sopenharmony_ci int corkreq = udp_test_bit(CORK, sk) || msg->msg_flags & MSG_MORE; 133962306a36Sopenharmony_ci int err; 134062306a36Sopenharmony_ci int is_udplite = IS_UDPLITE(sk); 134162306a36Sopenharmony_ci int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci ipcm6_init(&ipc6); 134462306a36Sopenharmony_ci ipc6.gso_size = READ_ONCE(up->gso_size); 134562306a36Sopenharmony_ci ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags); 134662306a36Sopenharmony_ci ipc6.sockc.mark = READ_ONCE(sk->sk_mark); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* destination address check */ 134962306a36Sopenharmony_ci if (sin6) { 135062306a36Sopenharmony_ci if (addr_len < offsetof(struct sockaddr, sa_data)) 135162306a36Sopenharmony_ci return -EINVAL; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci switch (sin6->sin6_family) { 135462306a36Sopenharmony_ci case AF_INET6: 135562306a36Sopenharmony_ci if (addr_len < SIN6_LEN_RFC2133) 135662306a36Sopenharmony_ci return -EINVAL; 135762306a36Sopenharmony_ci daddr = &sin6->sin6_addr; 135862306a36Sopenharmony_ci if (ipv6_addr_any(daddr) && 135962306a36Sopenharmony_ci ipv6_addr_v4mapped(&np->saddr)) 136062306a36Sopenharmony_ci ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK), 136162306a36Sopenharmony_ci daddr); 136262306a36Sopenharmony_ci break; 136362306a36Sopenharmony_ci case AF_INET: 136462306a36Sopenharmony_ci goto do_udp_sendmsg; 136562306a36Sopenharmony_ci case AF_UNSPEC: 136662306a36Sopenharmony_ci msg->msg_name = sin6 = NULL; 136762306a36Sopenharmony_ci msg->msg_namelen = addr_len = 0; 136862306a36Sopenharmony_ci daddr = NULL; 136962306a36Sopenharmony_ci break; 137062306a36Sopenharmony_ci default: 137162306a36Sopenharmony_ci return -EINVAL; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci } else if (!READ_ONCE(up->pending)) { 137462306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 137562306a36Sopenharmony_ci return -EDESTADDRREQ; 137662306a36Sopenharmony_ci daddr = &sk->sk_v6_daddr; 137762306a36Sopenharmony_ci } else 137862306a36Sopenharmony_ci daddr = NULL; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci if (daddr) { 138162306a36Sopenharmony_ci if (ipv6_addr_v4mapped(daddr)) { 138262306a36Sopenharmony_ci struct sockaddr_in sin; 138362306a36Sopenharmony_ci sin.sin_family = AF_INET; 138462306a36Sopenharmony_ci sin.sin_port = sin6 ? sin6->sin6_port : inet->inet_dport; 138562306a36Sopenharmony_ci sin.sin_addr.s_addr = daddr->s6_addr32[3]; 138662306a36Sopenharmony_ci msg->msg_name = &sin; 138762306a36Sopenharmony_ci msg->msg_namelen = sizeof(sin); 138862306a36Sopenharmony_cido_udp_sendmsg: 138962306a36Sopenharmony_ci err = ipv6_only_sock(sk) ? 139062306a36Sopenharmony_ci -ENETUNREACH : udp_sendmsg(sk, msg, len); 139162306a36Sopenharmony_ci msg->msg_name = sin6; 139262306a36Sopenharmony_ci msg->msg_namelen = addr_len; 139362306a36Sopenharmony_ci return err; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* Rough check on arithmetic overflow, 139862306a36Sopenharmony_ci better check is made in ip6_append_data(). 139962306a36Sopenharmony_ci */ 140062306a36Sopenharmony_ci if (len > INT_MAX - sizeof(struct udphdr)) 140162306a36Sopenharmony_ci return -EMSGSIZE; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; 140462306a36Sopenharmony_ci if (READ_ONCE(up->pending)) { 140562306a36Sopenharmony_ci if (READ_ONCE(up->pending) == AF_INET) 140662306a36Sopenharmony_ci return udp_sendmsg(sk, msg, len); 140762306a36Sopenharmony_ci /* 140862306a36Sopenharmony_ci * There are pending frames. 140962306a36Sopenharmony_ci * The socket lock must be held while it's corked. 141062306a36Sopenharmony_ci */ 141162306a36Sopenharmony_ci lock_sock(sk); 141262306a36Sopenharmony_ci if (likely(up->pending)) { 141362306a36Sopenharmony_ci if (unlikely(up->pending != AF_INET6)) { 141462306a36Sopenharmony_ci release_sock(sk); 141562306a36Sopenharmony_ci return -EAFNOSUPPORT; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci dst = NULL; 141862306a36Sopenharmony_ci goto do_append_data; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci release_sock(sk); 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci ulen += sizeof(struct udphdr); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci memset(fl6, 0, sizeof(*fl6)); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (sin6) { 142762306a36Sopenharmony_ci if (sin6->sin6_port == 0) 142862306a36Sopenharmony_ci return -EINVAL; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci fl6->fl6_dport = sin6->sin6_port; 143162306a36Sopenharmony_ci daddr = &sin6->sin6_addr; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (np->sndflow) { 143462306a36Sopenharmony_ci fl6->flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; 143562306a36Sopenharmony_ci if (fl6->flowlabel & IPV6_FLOWLABEL_MASK) { 143662306a36Sopenharmony_ci flowlabel = fl6_sock_lookup(sk, fl6->flowlabel); 143762306a36Sopenharmony_ci if (IS_ERR(flowlabel)) 143862306a36Sopenharmony_ci return -EINVAL; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* 144362306a36Sopenharmony_ci * Otherwise it will be difficult to maintain 144462306a36Sopenharmony_ci * sk->sk_dst_cache. 144562306a36Sopenharmony_ci */ 144662306a36Sopenharmony_ci if (sk->sk_state == TCP_ESTABLISHED && 144762306a36Sopenharmony_ci ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) 144862306a36Sopenharmony_ci daddr = &sk->sk_v6_daddr; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (addr_len >= sizeof(struct sockaddr_in6) && 145162306a36Sopenharmony_ci sin6->sin6_scope_id && 145262306a36Sopenharmony_ci __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr))) 145362306a36Sopenharmony_ci fl6->flowi6_oif = sin6->sin6_scope_id; 145462306a36Sopenharmony_ci } else { 145562306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 145662306a36Sopenharmony_ci return -EDESTADDRREQ; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci fl6->fl6_dport = inet->inet_dport; 145962306a36Sopenharmony_ci daddr = &sk->sk_v6_daddr; 146062306a36Sopenharmony_ci fl6->flowlabel = np->flow_label; 146162306a36Sopenharmony_ci connected = true; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci if (!fl6->flowi6_oif) 146562306a36Sopenharmony_ci fl6->flowi6_oif = READ_ONCE(sk->sk_bound_dev_if); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if (!fl6->flowi6_oif) 146862306a36Sopenharmony_ci fl6->flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci fl6->flowi6_uid = sk->sk_uid; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (msg->msg_controllen) { 147362306a36Sopenharmony_ci opt = &opt_space; 147462306a36Sopenharmony_ci memset(opt, 0, sizeof(struct ipv6_txoptions)); 147562306a36Sopenharmony_ci opt->tot_len = sizeof(*opt); 147662306a36Sopenharmony_ci ipc6.opt = opt; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci err = udp_cmsg_send(sk, msg, &ipc6.gso_size); 147962306a36Sopenharmony_ci if (err > 0) 148062306a36Sopenharmony_ci err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, fl6, 148162306a36Sopenharmony_ci &ipc6); 148262306a36Sopenharmony_ci if (err < 0) { 148362306a36Sopenharmony_ci fl6_sock_release(flowlabel); 148462306a36Sopenharmony_ci return err; 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci if ((fl6->flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { 148762306a36Sopenharmony_ci flowlabel = fl6_sock_lookup(sk, fl6->flowlabel); 148862306a36Sopenharmony_ci if (IS_ERR(flowlabel)) 148962306a36Sopenharmony_ci return -EINVAL; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci if (!(opt->opt_nflen|opt->opt_flen)) 149262306a36Sopenharmony_ci opt = NULL; 149362306a36Sopenharmony_ci connected = false; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci if (!opt) { 149662306a36Sopenharmony_ci opt = txopt_get(np); 149762306a36Sopenharmony_ci opt_to_free = opt; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci if (flowlabel) 150062306a36Sopenharmony_ci opt = fl6_merge_options(&opt_space, flowlabel, opt); 150162306a36Sopenharmony_ci opt = ipv6_fixup_options(&opt_space, opt); 150262306a36Sopenharmony_ci ipc6.opt = opt; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci fl6->flowi6_proto = sk->sk_protocol; 150562306a36Sopenharmony_ci fl6->flowi6_mark = ipc6.sockc.mark; 150662306a36Sopenharmony_ci fl6->daddr = *daddr; 150762306a36Sopenharmony_ci if (ipv6_addr_any(&fl6->saddr) && !ipv6_addr_any(&np->saddr)) 150862306a36Sopenharmony_ci fl6->saddr = np->saddr; 150962306a36Sopenharmony_ci fl6->fl6_sport = inet->inet_sport; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if (cgroup_bpf_enabled(CGROUP_UDP6_SENDMSG) && !connected) { 151262306a36Sopenharmony_ci err = BPF_CGROUP_RUN_PROG_UDP6_SENDMSG_LOCK(sk, 151362306a36Sopenharmony_ci (struct sockaddr *)sin6, 151462306a36Sopenharmony_ci &addr_len, 151562306a36Sopenharmony_ci &fl6->saddr); 151662306a36Sopenharmony_ci if (err) 151762306a36Sopenharmony_ci goto out_no_dst; 151862306a36Sopenharmony_ci if (sin6) { 151962306a36Sopenharmony_ci if (ipv6_addr_v4mapped(&sin6->sin6_addr)) { 152062306a36Sopenharmony_ci /* BPF program rewrote IPv6-only by IPv4-mapped 152162306a36Sopenharmony_ci * IPv6. It's currently unsupported. 152262306a36Sopenharmony_ci */ 152362306a36Sopenharmony_ci err = -ENOTSUPP; 152462306a36Sopenharmony_ci goto out_no_dst; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci if (sin6->sin6_port == 0) { 152762306a36Sopenharmony_ci /* BPF program set invalid port. Reject it. */ 152862306a36Sopenharmony_ci err = -EINVAL; 152962306a36Sopenharmony_ci goto out_no_dst; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci fl6->fl6_dport = sin6->sin6_port; 153262306a36Sopenharmony_ci fl6->daddr = sin6->sin6_addr; 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (ipv6_addr_any(&fl6->daddr)) 153762306a36Sopenharmony_ci fl6->daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci final_p = fl6_update_dst(fl6, opt, &final); 154062306a36Sopenharmony_ci if (final_p) 154162306a36Sopenharmony_ci connected = false; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (!fl6->flowi6_oif && ipv6_addr_is_multicast(&fl6->daddr)) { 154462306a36Sopenharmony_ci fl6->flowi6_oif = np->mcast_oif; 154562306a36Sopenharmony_ci connected = false; 154662306a36Sopenharmony_ci } else if (!fl6->flowi6_oif) 154762306a36Sopenharmony_ci fl6->flowi6_oif = np->ucast_oif; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci security_sk_classify_flow(sk, flowi6_to_flowi_common(fl6)); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (ipc6.tclass < 0) 155262306a36Sopenharmony_ci ipc6.tclass = np->tclass; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci fl6->flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6->flowlabel); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci dst = ip6_sk_dst_lookup_flow(sk, fl6, final_p, connected); 155762306a36Sopenharmony_ci if (IS_ERR(dst)) { 155862306a36Sopenharmony_ci err = PTR_ERR(dst); 155962306a36Sopenharmony_ci dst = NULL; 156062306a36Sopenharmony_ci goto out; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci if (ipc6.hlimit < 0) 156462306a36Sopenharmony_ci ipc6.hlimit = ip6_sk_dst_hoplimit(np, fl6, dst); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (msg->msg_flags&MSG_CONFIRM) 156762306a36Sopenharmony_ci goto do_confirm; 156862306a36Sopenharmony_ciback_from_confirm: 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci /* Lockless fast path for the non-corking case */ 157162306a36Sopenharmony_ci if (!corkreq) { 157262306a36Sopenharmony_ci struct sk_buff *skb; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci skb = ip6_make_skb(sk, getfrag, msg, ulen, 157562306a36Sopenharmony_ci sizeof(struct udphdr), &ipc6, 157662306a36Sopenharmony_ci (struct rt6_info *)dst, 157762306a36Sopenharmony_ci msg->msg_flags, &cork); 157862306a36Sopenharmony_ci err = PTR_ERR(skb); 157962306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(skb)) 158062306a36Sopenharmony_ci err = udp_v6_send_skb(skb, fl6, &cork.base); 158162306a36Sopenharmony_ci /* ip6_make_skb steals dst reference */ 158262306a36Sopenharmony_ci goto out_no_dst; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci lock_sock(sk); 158662306a36Sopenharmony_ci if (unlikely(up->pending)) { 158762306a36Sopenharmony_ci /* The socket is already corked while preparing it. */ 158862306a36Sopenharmony_ci /* ... which is an evident application bug. --ANK */ 158962306a36Sopenharmony_ci release_sock(sk); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci net_dbg_ratelimited("udp cork app bug 2\n"); 159262306a36Sopenharmony_ci err = -EINVAL; 159362306a36Sopenharmony_ci goto out; 159462306a36Sopenharmony_ci } 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci WRITE_ONCE(up->pending, AF_INET6); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cido_append_data: 159962306a36Sopenharmony_ci if (ipc6.dontfrag < 0) 160062306a36Sopenharmony_ci ipc6.dontfrag = np->dontfrag; 160162306a36Sopenharmony_ci up->len += ulen; 160262306a36Sopenharmony_ci err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr), 160362306a36Sopenharmony_ci &ipc6, fl6, (struct rt6_info *)dst, 160462306a36Sopenharmony_ci corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); 160562306a36Sopenharmony_ci if (err) 160662306a36Sopenharmony_ci udp_v6_flush_pending_frames(sk); 160762306a36Sopenharmony_ci else if (!corkreq) 160862306a36Sopenharmony_ci err = udp_v6_push_pending_frames(sk); 160962306a36Sopenharmony_ci else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) 161062306a36Sopenharmony_ci WRITE_ONCE(up->pending, 0); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (err > 0) 161362306a36Sopenharmony_ci err = np->recverr ? net_xmit_errno(err) : 0; 161462306a36Sopenharmony_ci release_sock(sk); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ciout: 161762306a36Sopenharmony_ci dst_release(dst); 161862306a36Sopenharmony_ciout_no_dst: 161962306a36Sopenharmony_ci fl6_sock_release(flowlabel); 162062306a36Sopenharmony_ci txopt_put(opt_to_free); 162162306a36Sopenharmony_ci if (!err) 162262306a36Sopenharmony_ci return len; 162362306a36Sopenharmony_ci /* 162462306a36Sopenharmony_ci * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting 162562306a36Sopenharmony_ci * ENOBUFS might not be good (it's not tunable per se), but otherwise 162662306a36Sopenharmony_ci * we don't have a good statistic (IpOutDiscards but it can be too many 162762306a36Sopenharmony_ci * things). We could add another new stat but at least for now that 162862306a36Sopenharmony_ci * seems like overkill. 162962306a36Sopenharmony_ci */ 163062306a36Sopenharmony_ci if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { 163162306a36Sopenharmony_ci UDP6_INC_STATS(sock_net(sk), 163262306a36Sopenharmony_ci UDP_MIB_SNDBUFERRORS, is_udplite); 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci return err; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_cido_confirm: 163762306a36Sopenharmony_ci if (msg->msg_flags & MSG_PROBE) 163862306a36Sopenharmony_ci dst_confirm_neigh(dst, &fl6->daddr); 163962306a36Sopenharmony_ci if (!(msg->msg_flags&MSG_PROBE) || len) 164062306a36Sopenharmony_ci goto back_from_confirm; 164162306a36Sopenharmony_ci err = 0; 164262306a36Sopenharmony_ci goto out; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ciEXPORT_SYMBOL(udpv6_sendmsg); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_cistatic void udpv6_splice_eof(struct socket *sock) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci struct sock *sk = sock->sk; 164962306a36Sopenharmony_ci struct udp_sock *up = udp_sk(sk); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (!READ_ONCE(up->pending) || udp_test_bit(CORK, sk)) 165262306a36Sopenharmony_ci return; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci lock_sock(sk); 165562306a36Sopenharmony_ci if (up->pending && !udp_test_bit(CORK, sk)) 165662306a36Sopenharmony_ci udp_v6_push_pending_frames(sk); 165762306a36Sopenharmony_ci release_sock(sk); 165862306a36Sopenharmony_ci} 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_civoid udpv6_destroy_sock(struct sock *sk) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci struct udp_sock *up = udp_sk(sk); 166362306a36Sopenharmony_ci lock_sock(sk); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci /* protects from races with udp_abort() */ 166662306a36Sopenharmony_ci sock_set_flag(sk, SOCK_DEAD); 166762306a36Sopenharmony_ci udp_v6_flush_pending_frames(sk); 166862306a36Sopenharmony_ci release_sock(sk); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci if (static_branch_unlikely(&udpv6_encap_needed_key)) { 167162306a36Sopenharmony_ci if (up->encap_type) { 167262306a36Sopenharmony_ci void (*encap_destroy)(struct sock *sk); 167362306a36Sopenharmony_ci encap_destroy = READ_ONCE(up->encap_destroy); 167462306a36Sopenharmony_ci if (encap_destroy) 167562306a36Sopenharmony_ci encap_destroy(sk); 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci if (udp_test_bit(ENCAP_ENABLED, sk)) { 167862306a36Sopenharmony_ci static_branch_dec(&udpv6_encap_needed_key); 167962306a36Sopenharmony_ci udp_encap_disable(); 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci} 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci/* 168562306a36Sopenharmony_ci * Socket option code for UDP 168662306a36Sopenharmony_ci */ 168762306a36Sopenharmony_ciint udpv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, 168862306a36Sopenharmony_ci unsigned int optlen) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci if (level == SOL_UDP || level == SOL_UDPLITE || level == SOL_SOCKET) 169162306a36Sopenharmony_ci return udp_lib_setsockopt(sk, level, optname, 169262306a36Sopenharmony_ci optval, optlen, 169362306a36Sopenharmony_ci udp_v6_push_pending_frames); 169462306a36Sopenharmony_ci return ipv6_setsockopt(sk, level, optname, optval, optlen); 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ciint udpv6_getsockopt(struct sock *sk, int level, int optname, 169862306a36Sopenharmony_ci char __user *optval, int __user *optlen) 169962306a36Sopenharmony_ci{ 170062306a36Sopenharmony_ci if (level == SOL_UDP || level == SOL_UDPLITE) 170162306a36Sopenharmony_ci return udp_lib_getsockopt(sk, level, optname, optval, optlen); 170262306a36Sopenharmony_ci return ipv6_getsockopt(sk, level, optname, optval, optlen); 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic const struct inet6_protocol udpv6_protocol = { 170662306a36Sopenharmony_ci .handler = udpv6_rcv, 170762306a36Sopenharmony_ci .err_handler = udpv6_err, 170862306a36Sopenharmony_ci .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 170962306a36Sopenharmony_ci}; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci/* ------------------------------------------------------------------------ */ 171262306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 171362306a36Sopenharmony_ciint udp6_seq_show(struct seq_file *seq, void *v) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 171662306a36Sopenharmony_ci seq_puts(seq, IPV6_SEQ_DGRAM_HEADER); 171762306a36Sopenharmony_ci } else { 171862306a36Sopenharmony_ci int bucket = ((struct udp_iter_state *)seq->private)->bucket; 171962306a36Sopenharmony_ci const struct inet_sock *inet = inet_sk((const struct sock *)v); 172062306a36Sopenharmony_ci __u16 srcp = ntohs(inet->inet_sport); 172162306a36Sopenharmony_ci __u16 destp = ntohs(inet->inet_dport); 172262306a36Sopenharmony_ci __ip6_dgram_sock_seq_show(seq, v, srcp, destp, 172362306a36Sopenharmony_ci udp_rqueue_get(v), bucket); 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci return 0; 172662306a36Sopenharmony_ci} 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ciconst struct seq_operations udp6_seq_ops = { 172962306a36Sopenharmony_ci .start = udp_seq_start, 173062306a36Sopenharmony_ci .next = udp_seq_next, 173162306a36Sopenharmony_ci .stop = udp_seq_stop, 173262306a36Sopenharmony_ci .show = udp6_seq_show, 173362306a36Sopenharmony_ci}; 173462306a36Sopenharmony_ciEXPORT_SYMBOL(udp6_seq_ops); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cistatic struct udp_seq_afinfo udp6_seq_afinfo = { 173762306a36Sopenharmony_ci .family = AF_INET6, 173862306a36Sopenharmony_ci .udp_table = NULL, 173962306a36Sopenharmony_ci}; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ciint __net_init udp6_proc_init(struct net *net) 174262306a36Sopenharmony_ci{ 174362306a36Sopenharmony_ci if (!proc_create_net_data("udp6", 0444, net->proc_net, &udp6_seq_ops, 174462306a36Sopenharmony_ci sizeof(struct udp_iter_state), &udp6_seq_afinfo)) 174562306a36Sopenharmony_ci return -ENOMEM; 174662306a36Sopenharmony_ci return 0; 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_civoid udp6_proc_exit(struct net *net) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci remove_proc_entry("udp6", net->proc_net); 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci/* ------------------------------------------------------------------------ */ 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_cistruct proto udpv6_prot = { 175862306a36Sopenharmony_ci .name = "UDPv6", 175962306a36Sopenharmony_ci .owner = THIS_MODULE, 176062306a36Sopenharmony_ci .close = udp_lib_close, 176162306a36Sopenharmony_ci .pre_connect = udpv6_pre_connect, 176262306a36Sopenharmony_ci .connect = ip6_datagram_connect, 176362306a36Sopenharmony_ci .disconnect = udp_disconnect, 176462306a36Sopenharmony_ci .ioctl = udp_ioctl, 176562306a36Sopenharmony_ci .init = udpv6_init_sock, 176662306a36Sopenharmony_ci .destroy = udpv6_destroy_sock, 176762306a36Sopenharmony_ci .setsockopt = udpv6_setsockopt, 176862306a36Sopenharmony_ci .getsockopt = udpv6_getsockopt, 176962306a36Sopenharmony_ci .sendmsg = udpv6_sendmsg, 177062306a36Sopenharmony_ci .recvmsg = udpv6_recvmsg, 177162306a36Sopenharmony_ci .splice_eof = udpv6_splice_eof, 177262306a36Sopenharmony_ci .release_cb = ip6_datagram_release_cb, 177362306a36Sopenharmony_ci .hash = udp_lib_hash, 177462306a36Sopenharmony_ci .unhash = udp_lib_unhash, 177562306a36Sopenharmony_ci .rehash = udp_v6_rehash, 177662306a36Sopenharmony_ci .get_port = udp_v6_get_port, 177762306a36Sopenharmony_ci .put_port = udp_lib_unhash, 177862306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 177962306a36Sopenharmony_ci .psock_update_sk_prot = udp_bpf_update_proto, 178062306a36Sopenharmony_ci#endif 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci .memory_allocated = &udp_memory_allocated, 178362306a36Sopenharmony_ci .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci .sysctl_mem = sysctl_udp_mem, 178662306a36Sopenharmony_ci .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_udp_wmem_min), 178762306a36Sopenharmony_ci .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_udp_rmem_min), 178862306a36Sopenharmony_ci .obj_size = sizeof(struct udp6_sock), 178962306a36Sopenharmony_ci .ipv6_pinfo_offset = offsetof(struct udp6_sock, inet6), 179062306a36Sopenharmony_ci .h.udp_table = NULL, 179162306a36Sopenharmony_ci .diag_destroy = udp_abort, 179262306a36Sopenharmony_ci}; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_cistatic struct inet_protosw udpv6_protosw = { 179562306a36Sopenharmony_ci .type = SOCK_DGRAM, 179662306a36Sopenharmony_ci .protocol = IPPROTO_UDP, 179762306a36Sopenharmony_ci .prot = &udpv6_prot, 179862306a36Sopenharmony_ci .ops = &inet6_dgram_ops, 179962306a36Sopenharmony_ci .flags = INET_PROTOSW_PERMANENT, 180062306a36Sopenharmony_ci}; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ciint __init udpv6_init(void) 180362306a36Sopenharmony_ci{ 180462306a36Sopenharmony_ci int ret; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); 180762306a36Sopenharmony_ci if (ret) 180862306a36Sopenharmony_ci goto out; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci ret = inet6_register_protosw(&udpv6_protosw); 181162306a36Sopenharmony_ci if (ret) 181262306a36Sopenharmony_ci goto out_udpv6_protocol; 181362306a36Sopenharmony_ciout: 181462306a36Sopenharmony_ci return ret; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ciout_udpv6_protocol: 181762306a36Sopenharmony_ci inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); 181862306a36Sopenharmony_ci goto out; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_civoid udpv6_exit(void) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci inet6_unregister_protosw(&udpv6_protosw); 182462306a36Sopenharmony_ci inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); 182562306a36Sopenharmony_ci} 1826