162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TCP 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: 1062306a36Sopenharmony_ci * linux/net/ipv4/tcp.c 1162306a36Sopenharmony_ci * linux/net/ipv4/tcp_input.c 1262306a36Sopenharmony_ci * linux/net/ipv4/tcp_output.c 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Fixes: 1562306a36Sopenharmony_ci * Hideaki YOSHIFUJI : sin6_scope_id support 1662306a36Sopenharmony_ci * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which 1762306a36Sopenharmony_ci * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind 1862306a36Sopenharmony_ci * a single port at the same time. 1962306a36Sopenharmony_ci * YOSHIFUJI Hideaki @USAGI: convert /proc/net/tcp6 to seq_file. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/bottom_half.h> 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/errno.h> 2562306a36Sopenharmony_ci#include <linux/types.h> 2662306a36Sopenharmony_ci#include <linux/socket.h> 2762306a36Sopenharmony_ci#include <linux/sockios.h> 2862306a36Sopenharmony_ci#include <linux/net.h> 2962306a36Sopenharmony_ci#include <linux/jiffies.h> 3062306a36Sopenharmony_ci#include <linux/in.h> 3162306a36Sopenharmony_ci#include <linux/in6.h> 3262306a36Sopenharmony_ci#include <linux/netdevice.h> 3362306a36Sopenharmony_ci#include <linux/init.h> 3462306a36Sopenharmony_ci#include <linux/jhash.h> 3562306a36Sopenharmony_ci#include <linux/ipsec.h> 3662306a36Sopenharmony_ci#include <linux/times.h> 3762306a36Sopenharmony_ci#include <linux/slab.h> 3862306a36Sopenharmony_ci#include <linux/uaccess.h> 3962306a36Sopenharmony_ci#include <linux/ipv6.h> 4062306a36Sopenharmony_ci#include <linux/icmpv6.h> 4162306a36Sopenharmony_ci#include <linux/random.h> 4262306a36Sopenharmony_ci#include <linux/indirect_call_wrapper.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include <net/tcp.h> 4562306a36Sopenharmony_ci#include <net/ndisc.h> 4662306a36Sopenharmony_ci#include <net/inet6_hashtables.h> 4762306a36Sopenharmony_ci#include <net/inet6_connection_sock.h> 4862306a36Sopenharmony_ci#include <net/ipv6.h> 4962306a36Sopenharmony_ci#include <net/transp_v6.h> 5062306a36Sopenharmony_ci#include <net/addrconf.h> 5162306a36Sopenharmony_ci#include <net/ip6_route.h> 5262306a36Sopenharmony_ci#include <net/ip6_checksum.h> 5362306a36Sopenharmony_ci#include <net/inet_ecn.h> 5462306a36Sopenharmony_ci#include <net/protocol.h> 5562306a36Sopenharmony_ci#include <net/xfrm.h> 5662306a36Sopenharmony_ci#include <net/snmp.h> 5762306a36Sopenharmony_ci#include <net/dsfield.h> 5862306a36Sopenharmony_ci#include <net/timewait_sock.h> 5962306a36Sopenharmony_ci#include <net/inet_common.h> 6062306a36Sopenharmony_ci#include <net/secure_seq.h> 6162306a36Sopenharmony_ci#include <net/busy_poll.h> 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#include <linux/proc_fs.h> 6462306a36Sopenharmony_ci#include <linux/seq_file.h> 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#include <crypto/hash.h> 6762306a36Sopenharmony_ci#include <linux/scatterlist.h> 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#include <trace/events/tcp.h> 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); 7262306a36Sopenharmony_cistatic void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, 7362306a36Sopenharmony_ci struct request_sock *req); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciINDIRECT_CALLABLE_SCOPE int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct inet_connection_sock_af_ops ipv6_mapped; 7862306a36Sopenharmony_ciconst struct inet_connection_sock_af_ops ipv6_specific; 7962306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 8062306a36Sopenharmony_cistatic const struct tcp_sock_af_ops tcp_sock_ipv6_specific; 8162306a36Sopenharmony_cistatic const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; 8262306a36Sopenharmony_ci#else 8362306a36Sopenharmony_cistatic struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk, 8462306a36Sopenharmony_ci const struct in6_addr *addr, 8562306a36Sopenharmony_ci int l3index) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci return NULL; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci#endif 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Helper returning the inet6 address from a given tcp socket. 9262306a36Sopenharmony_ci * It can be used in TCP stack instead of inet6_sk(sk). 9362306a36Sopenharmony_ci * This avoids a dereference and allow compiler optimizations. 9462306a36Sopenharmony_ci * It is a specialized version of inet6_sk_generic(). 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci#define tcp_inet6_sk(sk) (&container_of_const(tcp_sk(sk), \ 9762306a36Sopenharmony_ci struct tcp6_sock, tcp)->inet6) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct dst_entry *dst = skb_dst(skb); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (dst && dst_hold_safe(dst)) { 10462306a36Sopenharmony_ci const struct rt6_info *rt = (const struct rt6_info *)dst; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci rcu_assign_pointer(sk->sk_rx_dst, dst); 10762306a36Sopenharmony_ci sk->sk_rx_dst_ifindex = skb->skb_iif; 10862306a36Sopenharmony_ci sk->sk_rx_dst_cookie = rt6_get_cookie(rt); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic u32 tcp_v6_init_seq(const struct sk_buff *skb) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci return secure_tcpv6_seq(ipv6_hdr(skb)->daddr.s6_addr32, 11562306a36Sopenharmony_ci ipv6_hdr(skb)->saddr.s6_addr32, 11662306a36Sopenharmony_ci tcp_hdr(skb)->dest, 11762306a36Sopenharmony_ci tcp_hdr(skb)->source); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic u32 tcp_v6_init_ts_off(const struct net *net, const struct sk_buff *skb) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return secure_tcpv6_ts_off(net, ipv6_hdr(skb)->daddr.s6_addr32, 12362306a36Sopenharmony_ci ipv6_hdr(skb)->saddr.s6_addr32); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int tcp_v6_pre_connect(struct sock *sk, struct sockaddr *uaddr, 12762306a36Sopenharmony_ci int addr_len) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci /* This check is replicated from tcp_v6_connect() and intended to 13062306a36Sopenharmony_ci * prevent BPF program called below from accessing bytes that are out 13162306a36Sopenharmony_ci * of the bound specified by user in addr_len. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci if (addr_len < SIN6_LEN_RFC2133) 13462306a36Sopenharmony_ci return -EINVAL; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci sock_owned_by_me(sk); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return BPF_CGROUP_RUN_PROG_INET6_CONNECT(sk, uaddr, &addr_len); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 14262306a36Sopenharmony_ci int addr_len) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; 14562306a36Sopenharmony_ci struct inet_connection_sock *icsk = inet_csk(sk); 14662306a36Sopenharmony_ci struct in6_addr *saddr = NULL, *final_p, final; 14762306a36Sopenharmony_ci struct inet_timewait_death_row *tcp_death_row; 14862306a36Sopenharmony_ci struct ipv6_pinfo *np = tcp_inet6_sk(sk); 14962306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 15062306a36Sopenharmony_ci struct tcp_sock *tp = tcp_sk(sk); 15162306a36Sopenharmony_ci struct net *net = sock_net(sk); 15262306a36Sopenharmony_ci struct ipv6_txoptions *opt; 15362306a36Sopenharmony_ci struct dst_entry *dst; 15462306a36Sopenharmony_ci struct flowi6 fl6; 15562306a36Sopenharmony_ci int addr_type; 15662306a36Sopenharmony_ci int err; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (addr_len < SIN6_LEN_RFC2133) 15962306a36Sopenharmony_ci return -EINVAL; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (usin->sin6_family != AF_INET6) 16262306a36Sopenharmony_ci return -EAFNOSUPPORT; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci memset(&fl6, 0, sizeof(fl6)); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (np->sndflow) { 16762306a36Sopenharmony_ci fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; 16862306a36Sopenharmony_ci IP6_ECN_flow_init(fl6.flowlabel); 16962306a36Sopenharmony_ci if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { 17062306a36Sopenharmony_ci struct ip6_flowlabel *flowlabel; 17162306a36Sopenharmony_ci flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); 17262306a36Sopenharmony_ci if (IS_ERR(flowlabel)) 17362306a36Sopenharmony_ci return -EINVAL; 17462306a36Sopenharmony_ci fl6_sock_release(flowlabel); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * connect() to INADDR_ANY means loopback (BSD'ism). 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (ipv6_addr_any(&usin->sin6_addr)) { 18362306a36Sopenharmony_ci if (ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)) 18462306a36Sopenharmony_ci ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK), 18562306a36Sopenharmony_ci &usin->sin6_addr); 18662306a36Sopenharmony_ci else 18762306a36Sopenharmony_ci usin->sin6_addr = in6addr_loopback; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci addr_type = ipv6_addr_type(&usin->sin6_addr); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (addr_type & IPV6_ADDR_MULTICAST) 19362306a36Sopenharmony_ci return -ENETUNREACH; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (addr_type&IPV6_ADDR_LINKLOCAL) { 19662306a36Sopenharmony_ci if (addr_len >= sizeof(struct sockaddr_in6) && 19762306a36Sopenharmony_ci usin->sin6_scope_id) { 19862306a36Sopenharmony_ci /* If interface is set while binding, indices 19962306a36Sopenharmony_ci * must coincide. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci if (!sk_dev_equal_l3scope(sk, usin->sin6_scope_id)) 20262306a36Sopenharmony_ci return -EINVAL; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci sk->sk_bound_dev_if = usin->sin6_scope_id; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Connect to link-local address requires an interface */ 20862306a36Sopenharmony_ci if (!sk->sk_bound_dev_if) 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (tp->rx_opt.ts_recent_stamp && 21362306a36Sopenharmony_ci !ipv6_addr_equal(&sk->sk_v6_daddr, &usin->sin6_addr)) { 21462306a36Sopenharmony_ci tp->rx_opt.ts_recent = 0; 21562306a36Sopenharmony_ci tp->rx_opt.ts_recent_stamp = 0; 21662306a36Sopenharmony_ci WRITE_ONCE(tp->write_seq, 0); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci sk->sk_v6_daddr = usin->sin6_addr; 22062306a36Sopenharmony_ci np->flow_label = fl6.flowlabel; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * TCP over IPv4 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (addr_type & IPV6_ADDR_MAPPED) { 22762306a36Sopenharmony_ci u32 exthdrlen = icsk->icsk_ext_hdr_len; 22862306a36Sopenharmony_ci struct sockaddr_in sin; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (ipv6_only_sock(sk)) 23162306a36Sopenharmony_ci return -ENETUNREACH; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci sin.sin_family = AF_INET; 23462306a36Sopenharmony_ci sin.sin_port = usin->sin6_port; 23562306a36Sopenharmony_ci sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ 23862306a36Sopenharmony_ci WRITE_ONCE(icsk->icsk_af_ops, &ipv6_mapped); 23962306a36Sopenharmony_ci if (sk_is_mptcp(sk)) 24062306a36Sopenharmony_ci mptcpv6_handle_mapped(sk, true); 24162306a36Sopenharmony_ci sk->sk_backlog_rcv = tcp_v4_do_rcv; 24262306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 24362306a36Sopenharmony_ci tp->af_specific = &tcp_sock_ipv6_mapped_specific; 24462306a36Sopenharmony_ci#endif 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (err) { 24962306a36Sopenharmony_ci icsk->icsk_ext_hdr_len = exthdrlen; 25062306a36Sopenharmony_ci /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ 25162306a36Sopenharmony_ci WRITE_ONCE(icsk->icsk_af_ops, &ipv6_specific); 25262306a36Sopenharmony_ci if (sk_is_mptcp(sk)) 25362306a36Sopenharmony_ci mptcpv6_handle_mapped(sk, false); 25462306a36Sopenharmony_ci sk->sk_backlog_rcv = tcp_v6_do_rcv; 25562306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 25662306a36Sopenharmony_ci tp->af_specific = &tcp_sock_ipv6_specific; 25762306a36Sopenharmony_ci#endif 25862306a36Sopenharmony_ci goto failure; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci np->saddr = sk->sk_v6_rcv_saddr; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return err; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) 26662306a36Sopenharmony_ci saddr = &sk->sk_v6_rcv_saddr; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci fl6.flowi6_proto = IPPROTO_TCP; 26962306a36Sopenharmony_ci fl6.daddr = sk->sk_v6_daddr; 27062306a36Sopenharmony_ci fl6.saddr = saddr ? *saddr : np->saddr; 27162306a36Sopenharmony_ci fl6.flowlabel = ip6_make_flowinfo(np->tclass, np->flow_label); 27262306a36Sopenharmony_ci fl6.flowi6_oif = sk->sk_bound_dev_if; 27362306a36Sopenharmony_ci fl6.flowi6_mark = sk->sk_mark; 27462306a36Sopenharmony_ci fl6.fl6_dport = usin->sin6_port; 27562306a36Sopenharmony_ci fl6.fl6_sport = inet->inet_sport; 27662306a36Sopenharmony_ci fl6.flowi6_uid = sk->sk_uid; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk)); 27962306a36Sopenharmony_ci final_p = fl6_update_dst(&fl6, opt, &final); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci dst = ip6_dst_lookup_flow(net, sk, &fl6, final_p); 28462306a36Sopenharmony_ci if (IS_ERR(dst)) { 28562306a36Sopenharmony_ci err = PTR_ERR(dst); 28662306a36Sopenharmony_ci goto failure; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (!saddr) { 29262306a36Sopenharmony_ci saddr = &fl6.saddr; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci err = inet_bhash2_update_saddr(sk, saddr, AF_INET6); 29562306a36Sopenharmony_ci if (err) 29662306a36Sopenharmony_ci goto failure; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* set the source address */ 30062306a36Sopenharmony_ci np->saddr = *saddr; 30162306a36Sopenharmony_ci inet->inet_rcv_saddr = LOOPBACK4_IPV6; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci sk->sk_gso_type = SKB_GSO_TCPV6; 30462306a36Sopenharmony_ci ip6_dst_store(sk, dst, NULL, NULL); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci icsk->icsk_ext_hdr_len = 0; 30762306a36Sopenharmony_ci if (opt) 30862306a36Sopenharmony_ci icsk->icsk_ext_hdr_len = opt->opt_flen + 30962306a36Sopenharmony_ci opt->opt_nflen; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci inet->inet_dport = usin->sin6_port; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci tcp_set_state(sk, TCP_SYN_SENT); 31662306a36Sopenharmony_ci err = inet6_hash_connect(tcp_death_row, sk); 31762306a36Sopenharmony_ci if (err) 31862306a36Sopenharmony_ci goto late_failure; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci sk_set_txhash(sk); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (likely(!tp->repair)) { 32362306a36Sopenharmony_ci if (!tp->write_seq) 32462306a36Sopenharmony_ci WRITE_ONCE(tp->write_seq, 32562306a36Sopenharmony_ci secure_tcpv6_seq(np->saddr.s6_addr32, 32662306a36Sopenharmony_ci sk->sk_v6_daddr.s6_addr32, 32762306a36Sopenharmony_ci inet->inet_sport, 32862306a36Sopenharmony_ci inet->inet_dport)); 32962306a36Sopenharmony_ci tp->tsoffset = secure_tcpv6_ts_off(net, np->saddr.s6_addr32, 33062306a36Sopenharmony_ci sk->sk_v6_daddr.s6_addr32); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (tcp_fastopen_defer_connect(sk, &err)) 33462306a36Sopenharmony_ci return err; 33562306a36Sopenharmony_ci if (err) 33662306a36Sopenharmony_ci goto late_failure; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci err = tcp_connect(sk); 33962306a36Sopenharmony_ci if (err) 34062306a36Sopenharmony_ci goto late_failure; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cilate_failure: 34562306a36Sopenharmony_ci tcp_set_state(sk, TCP_CLOSE); 34662306a36Sopenharmony_ci inet_bhash2_reset_saddr(sk); 34762306a36Sopenharmony_cifailure: 34862306a36Sopenharmony_ci inet->inet_dport = 0; 34962306a36Sopenharmony_ci sk->sk_route_caps = 0; 35062306a36Sopenharmony_ci return err; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void tcp_v6_mtu_reduced(struct sock *sk) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct dst_entry *dst; 35662306a36Sopenharmony_ci u32 mtu; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) 35962306a36Sopenharmony_ci return; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mtu = READ_ONCE(tcp_sk(sk)->mtu_info); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Drop requests trying to increase our current mss. 36462306a36Sopenharmony_ci * Check done in __ip6_rt_update_pmtu() is too late. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci if (tcp_mtu_to_mss(sk, mtu) >= tcp_sk(sk)->mss_cache) 36762306a36Sopenharmony_ci return; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci dst = inet6_csk_update_pmtu(sk, mtu); 37062306a36Sopenharmony_ci if (!dst) 37162306a36Sopenharmony_ci return; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { 37462306a36Sopenharmony_ci tcp_sync_mss(sk, dst_mtu(dst)); 37562306a36Sopenharmony_ci tcp_simple_retransmit(sk); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 38062306a36Sopenharmony_ci u8 type, u8 code, int offset, __be32 info) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; 38362306a36Sopenharmony_ci const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); 38462306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 38562306a36Sopenharmony_ci struct request_sock *fastopen; 38662306a36Sopenharmony_ci struct ipv6_pinfo *np; 38762306a36Sopenharmony_ci struct tcp_sock *tp; 38862306a36Sopenharmony_ci __u32 seq, snd_una; 38962306a36Sopenharmony_ci struct sock *sk; 39062306a36Sopenharmony_ci bool fatal; 39162306a36Sopenharmony_ci int err; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, 39462306a36Sopenharmony_ci &hdr->daddr, th->dest, 39562306a36Sopenharmony_ci &hdr->saddr, ntohs(th->source), 39662306a36Sopenharmony_ci skb->dev->ifindex, inet6_sdif(skb)); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (!sk) { 39962306a36Sopenharmony_ci __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), 40062306a36Sopenharmony_ci ICMP6_MIB_INERRORS); 40162306a36Sopenharmony_ci return -ENOENT; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (sk->sk_state == TCP_TIME_WAIT) { 40562306a36Sopenharmony_ci inet_twsk_put(inet_twsk(sk)); 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci seq = ntohl(th->seq); 40962306a36Sopenharmony_ci fatal = icmpv6_err_convert(type, code, &err); 41062306a36Sopenharmony_ci if (sk->sk_state == TCP_NEW_SYN_RECV) { 41162306a36Sopenharmony_ci tcp_req_err(sk, seq, fatal); 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci bh_lock_sock(sk); 41662306a36Sopenharmony_ci if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) 41762306a36Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (sk->sk_state == TCP_CLOSE) 42062306a36Sopenharmony_ci goto out; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (static_branch_unlikely(&ip6_min_hopcount)) { 42362306a36Sopenharmony_ci /* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */ 42462306a36Sopenharmony_ci if (ipv6_hdr(skb)->hop_limit < READ_ONCE(tcp_inet6_sk(sk)->min_hopcount)) { 42562306a36Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 42662306a36Sopenharmony_ci goto out; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci tp = tcp_sk(sk); 43162306a36Sopenharmony_ci /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ 43262306a36Sopenharmony_ci fastopen = rcu_dereference(tp->fastopen_rsk); 43362306a36Sopenharmony_ci snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; 43462306a36Sopenharmony_ci if (sk->sk_state != TCP_LISTEN && 43562306a36Sopenharmony_ci !between(seq, snd_una, tp->snd_nxt)) { 43662306a36Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS); 43762306a36Sopenharmony_ci goto out; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci np = tcp_inet6_sk(sk); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (type == NDISC_REDIRECT) { 44362306a36Sopenharmony_ci if (!sock_owned_by_user(sk)) { 44462306a36Sopenharmony_ci struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (dst) 44762306a36Sopenharmony_ci dst->ops->redirect(dst, sk, skb); 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci goto out; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (type == ICMPV6_PKT_TOOBIG) { 45362306a36Sopenharmony_ci u32 mtu = ntohl(info); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* We are not interested in TCP_LISTEN and open_requests 45662306a36Sopenharmony_ci * (SYN-ACKs send out by Linux are always <576bytes so 45762306a36Sopenharmony_ci * they should go through unfragmented). 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) 46062306a36Sopenharmony_ci goto out; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (!ip6_sk_accept_pmtu(sk)) 46362306a36Sopenharmony_ci goto out; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (mtu < IPV6_MIN_MTU) 46662306a36Sopenharmony_ci goto out; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci WRITE_ONCE(tp->mtu_info, mtu); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!sock_owned_by_user(sk)) 47162306a36Sopenharmony_ci tcp_v6_mtu_reduced(sk); 47262306a36Sopenharmony_ci else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, 47362306a36Sopenharmony_ci &sk->sk_tsq_flags)) 47462306a36Sopenharmony_ci sock_hold(sk); 47562306a36Sopenharmony_ci goto out; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Might be for an request_sock */ 48062306a36Sopenharmony_ci switch (sk->sk_state) { 48162306a36Sopenharmony_ci case TCP_SYN_SENT: 48262306a36Sopenharmony_ci case TCP_SYN_RECV: 48362306a36Sopenharmony_ci /* Only in fast or simultaneous open. If a fast open socket is 48462306a36Sopenharmony_ci * already accepted it is treated as a connected one below. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci if (fastopen && !fastopen->sk) 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci ipv6_icmp_error(sk, skb, err, th->dest, ntohl(info), (u8 *)th); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (!sock_owned_by_user(sk)) { 49262306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err, err); 49362306a36Sopenharmony_ci sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci tcp_done(sk); 49662306a36Sopenharmony_ci } else { 49762306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err_soft, err); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci goto out; 50062306a36Sopenharmony_ci case TCP_LISTEN: 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci default: 50362306a36Sopenharmony_ci /* check if this ICMP message allows revert of backoff. 50462306a36Sopenharmony_ci * (see RFC 6069) 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci if (!fastopen && type == ICMPV6_DEST_UNREACH && 50762306a36Sopenharmony_ci code == ICMPV6_NOROUTE) 50862306a36Sopenharmony_ci tcp_ld_RTO_revert(sk, seq); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!sock_owned_by_user(sk) && np->recverr) { 51262306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err, err); 51362306a36Sopenharmony_ci sk_error_report(sk); 51462306a36Sopenharmony_ci } else { 51562306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err_soft, err); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ciout: 51862306a36Sopenharmony_ci bh_unlock_sock(sk); 51962306a36Sopenharmony_ci sock_put(sk); 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, 52562306a36Sopenharmony_ci struct flowi *fl, 52662306a36Sopenharmony_ci struct request_sock *req, 52762306a36Sopenharmony_ci struct tcp_fastopen_cookie *foc, 52862306a36Sopenharmony_ci enum tcp_synack_type synack_type, 52962306a36Sopenharmony_ci struct sk_buff *syn_skb) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct inet_request_sock *ireq = inet_rsk(req); 53262306a36Sopenharmony_ci const struct ipv6_pinfo *np = tcp_inet6_sk(sk); 53362306a36Sopenharmony_ci struct ipv6_txoptions *opt; 53462306a36Sopenharmony_ci struct flowi6 *fl6 = &fl->u.ip6; 53562306a36Sopenharmony_ci struct sk_buff *skb; 53662306a36Sopenharmony_ci int err = -ENOMEM; 53762306a36Sopenharmony_ci u8 tclass; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* First, grab a route. */ 54062306a36Sopenharmony_ci if (!dst && (dst = inet6_csk_route_req(sk, fl6, req, 54162306a36Sopenharmony_ci IPPROTO_TCP)) == NULL) 54262306a36Sopenharmony_ci goto done; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci skb = tcp_make_synack(sk, dst, req, foc, synack_type, syn_skb); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (skb) { 54762306a36Sopenharmony_ci __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, 54862306a36Sopenharmony_ci &ireq->ir_v6_rmt_addr); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci fl6->daddr = ireq->ir_v6_rmt_addr; 55162306a36Sopenharmony_ci if (np->repflow && ireq->pktopts) 55262306a36Sopenharmony_ci fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci tclass = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos) ? 55562306a36Sopenharmony_ci (tcp_rsk(req)->syn_tos & ~INET_ECN_MASK) | 55662306a36Sopenharmony_ci (np->tclass & INET_ECN_MASK) : 55762306a36Sopenharmony_ci np->tclass; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (!INET_ECN_is_capable(tclass) && 56062306a36Sopenharmony_ci tcp_bpf_ca_needs_ecn((struct sock *)req)) 56162306a36Sopenharmony_ci tclass |= INET_ECN_ECT_0; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci rcu_read_lock(); 56462306a36Sopenharmony_ci opt = ireq->ipv6_opt; 56562306a36Sopenharmony_ci if (!opt) 56662306a36Sopenharmony_ci opt = rcu_dereference(np->opt); 56762306a36Sopenharmony_ci err = ip6_xmit(sk, skb, fl6, skb->mark ? : READ_ONCE(sk->sk_mark), 56862306a36Sopenharmony_ci opt, tclass, sk->sk_priority); 56962306a36Sopenharmony_ci rcu_read_unlock(); 57062306a36Sopenharmony_ci err = net_xmit_eval(err); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cidone: 57462306a36Sopenharmony_ci return err; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic void tcp_v6_reqsk_destructor(struct request_sock *req) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci kfree(inet_rsk(req)->ipv6_opt); 58162306a36Sopenharmony_ci consume_skb(inet_rsk(req)->pktopts); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 58562306a36Sopenharmony_cistatic struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk, 58662306a36Sopenharmony_ci const struct in6_addr *addr, 58762306a36Sopenharmony_ci int l3index) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci return tcp_md5_do_lookup(sk, l3index, 59062306a36Sopenharmony_ci (union tcp_md5_addr *)addr, AF_INET6); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic struct tcp_md5sig_key *tcp_v6_md5_lookup(const struct sock *sk, 59462306a36Sopenharmony_ci const struct sock *addr_sk) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci int l3index; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci l3index = l3mdev_master_ifindex_by_index(sock_net(sk), 59962306a36Sopenharmony_ci addr_sk->sk_bound_dev_if); 60062306a36Sopenharmony_ci return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr, 60162306a36Sopenharmony_ci l3index); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int tcp_v6_parse_md5_keys(struct sock *sk, int optname, 60562306a36Sopenharmony_ci sockptr_t optval, int optlen) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct tcp_md5sig cmd; 60862306a36Sopenharmony_ci struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; 60962306a36Sopenharmony_ci int l3index = 0; 61062306a36Sopenharmony_ci u8 prefixlen; 61162306a36Sopenharmony_ci u8 flags; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (optlen < sizeof(cmd)) 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (copy_from_sockptr(&cmd, optval, sizeof(cmd))) 61762306a36Sopenharmony_ci return -EFAULT; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (sin6->sin6_family != AF_INET6) 62062306a36Sopenharmony_ci return -EINVAL; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci flags = cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (optname == TCP_MD5SIG_EXT && 62562306a36Sopenharmony_ci cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) { 62662306a36Sopenharmony_ci prefixlen = cmd.tcpm_prefixlen; 62762306a36Sopenharmony_ci if (prefixlen > 128 || (ipv6_addr_v4mapped(&sin6->sin6_addr) && 62862306a36Sopenharmony_ci prefixlen > 32)) 62962306a36Sopenharmony_ci return -EINVAL; 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (optname == TCP_MD5SIG_EXT && cmd.tcpm_ifindex && 63562306a36Sopenharmony_ci cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX) { 63662306a36Sopenharmony_ci struct net_device *dev; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci rcu_read_lock(); 63962306a36Sopenharmony_ci dev = dev_get_by_index_rcu(sock_net(sk), cmd.tcpm_ifindex); 64062306a36Sopenharmony_ci if (dev && netif_is_l3_master(dev)) 64162306a36Sopenharmony_ci l3index = dev->ifindex; 64262306a36Sopenharmony_ci rcu_read_unlock(); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* ok to reference set/not set outside of rcu; 64562306a36Sopenharmony_ci * right now device MUST be an L3 master 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci if (!dev || !l3index) 64862306a36Sopenharmony_ci return -EINVAL; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (!cmd.tcpm_keylen) { 65262306a36Sopenharmony_ci if (ipv6_addr_v4mapped(&sin6->sin6_addr)) 65362306a36Sopenharmony_ci return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], 65462306a36Sopenharmony_ci AF_INET, prefixlen, 65562306a36Sopenharmony_ci l3index, flags); 65662306a36Sopenharmony_ci return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, 65762306a36Sopenharmony_ci AF_INET6, prefixlen, l3index, flags); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) 66162306a36Sopenharmony_ci return -EINVAL; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (ipv6_addr_v4mapped(&sin6->sin6_addr)) 66462306a36Sopenharmony_ci return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], 66562306a36Sopenharmony_ci AF_INET, prefixlen, l3index, flags, 66662306a36Sopenharmony_ci cmd.tcpm_key, cmd.tcpm_keylen); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr, 66962306a36Sopenharmony_ci AF_INET6, prefixlen, l3index, flags, 67062306a36Sopenharmony_ci cmd.tcpm_key, cmd.tcpm_keylen); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp, 67462306a36Sopenharmony_ci const struct in6_addr *daddr, 67562306a36Sopenharmony_ci const struct in6_addr *saddr, 67662306a36Sopenharmony_ci const struct tcphdr *th, int nbytes) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct tcp6_pseudohdr *bp; 67962306a36Sopenharmony_ci struct scatterlist sg; 68062306a36Sopenharmony_ci struct tcphdr *_th; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci bp = hp->scratch; 68362306a36Sopenharmony_ci /* 1. TCP pseudo-header (RFC2460) */ 68462306a36Sopenharmony_ci bp->saddr = *saddr; 68562306a36Sopenharmony_ci bp->daddr = *daddr; 68662306a36Sopenharmony_ci bp->protocol = cpu_to_be32(IPPROTO_TCP); 68762306a36Sopenharmony_ci bp->len = cpu_to_be32(nbytes); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci _th = (struct tcphdr *)(bp + 1); 69062306a36Sopenharmony_ci memcpy(_th, th, sizeof(*th)); 69162306a36Sopenharmony_ci _th->check = 0; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th)); 69462306a36Sopenharmony_ci ahash_request_set_crypt(hp->md5_req, &sg, NULL, 69562306a36Sopenharmony_ci sizeof(*bp) + sizeof(*th)); 69662306a36Sopenharmony_ci return crypto_ahash_update(hp->md5_req); 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, 70062306a36Sopenharmony_ci const struct in6_addr *daddr, struct in6_addr *saddr, 70162306a36Sopenharmony_ci const struct tcphdr *th) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct tcp_md5sig_pool *hp; 70462306a36Sopenharmony_ci struct ahash_request *req; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci hp = tcp_get_md5sig_pool(); 70762306a36Sopenharmony_ci if (!hp) 70862306a36Sopenharmony_ci goto clear_hash_noput; 70962306a36Sopenharmony_ci req = hp->md5_req; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (crypto_ahash_init(req)) 71262306a36Sopenharmony_ci goto clear_hash; 71362306a36Sopenharmony_ci if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2)) 71462306a36Sopenharmony_ci goto clear_hash; 71562306a36Sopenharmony_ci if (tcp_md5_hash_key(hp, key)) 71662306a36Sopenharmony_ci goto clear_hash; 71762306a36Sopenharmony_ci ahash_request_set_crypt(req, NULL, md5_hash, 0); 71862306a36Sopenharmony_ci if (crypto_ahash_final(req)) 71962306a36Sopenharmony_ci goto clear_hash; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci tcp_put_md5sig_pool(); 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ciclear_hash: 72562306a36Sopenharmony_ci tcp_put_md5sig_pool(); 72662306a36Sopenharmony_ciclear_hash_noput: 72762306a36Sopenharmony_ci memset(md5_hash, 0, 16); 72862306a36Sopenharmony_ci return 1; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int tcp_v6_md5_hash_skb(char *md5_hash, 73262306a36Sopenharmony_ci const struct tcp_md5sig_key *key, 73362306a36Sopenharmony_ci const struct sock *sk, 73462306a36Sopenharmony_ci const struct sk_buff *skb) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci const struct in6_addr *saddr, *daddr; 73762306a36Sopenharmony_ci struct tcp_md5sig_pool *hp; 73862306a36Sopenharmony_ci struct ahash_request *req; 73962306a36Sopenharmony_ci const struct tcphdr *th = tcp_hdr(skb); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (sk) { /* valid for establish/request sockets */ 74262306a36Sopenharmony_ci saddr = &sk->sk_v6_rcv_saddr; 74362306a36Sopenharmony_ci daddr = &sk->sk_v6_daddr; 74462306a36Sopenharmony_ci } else { 74562306a36Sopenharmony_ci const struct ipv6hdr *ip6h = ipv6_hdr(skb); 74662306a36Sopenharmony_ci saddr = &ip6h->saddr; 74762306a36Sopenharmony_ci daddr = &ip6h->daddr; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci hp = tcp_get_md5sig_pool(); 75162306a36Sopenharmony_ci if (!hp) 75262306a36Sopenharmony_ci goto clear_hash_noput; 75362306a36Sopenharmony_ci req = hp->md5_req; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (crypto_ahash_init(req)) 75662306a36Sopenharmony_ci goto clear_hash; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len)) 75962306a36Sopenharmony_ci goto clear_hash; 76062306a36Sopenharmony_ci if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) 76162306a36Sopenharmony_ci goto clear_hash; 76262306a36Sopenharmony_ci if (tcp_md5_hash_key(hp, key)) 76362306a36Sopenharmony_ci goto clear_hash; 76462306a36Sopenharmony_ci ahash_request_set_crypt(req, NULL, md5_hash, 0); 76562306a36Sopenharmony_ci if (crypto_ahash_final(req)) 76662306a36Sopenharmony_ci goto clear_hash; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci tcp_put_md5sig_pool(); 76962306a36Sopenharmony_ci return 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ciclear_hash: 77262306a36Sopenharmony_ci tcp_put_md5sig_pool(); 77362306a36Sopenharmony_ciclear_hash_noput: 77462306a36Sopenharmony_ci memset(md5_hash, 0, 16); 77562306a36Sopenharmony_ci return 1; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci#endif 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic void tcp_v6_init_req(struct request_sock *req, 78162306a36Sopenharmony_ci const struct sock *sk_listener, 78262306a36Sopenharmony_ci struct sk_buff *skb) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); 78562306a36Sopenharmony_ci struct inet_request_sock *ireq = inet_rsk(req); 78662306a36Sopenharmony_ci const struct ipv6_pinfo *np = tcp_inet6_sk(sk_listener); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; 78962306a36Sopenharmony_ci ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* So that link locals have meaning */ 79262306a36Sopenharmony_ci if ((!sk_listener->sk_bound_dev_if || l3_slave) && 79362306a36Sopenharmony_ci ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) 79462306a36Sopenharmony_ci ireq->ir_iif = tcp_v6_iif(skb); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (!TCP_SKB_CB(skb)->tcp_tw_isn && 79762306a36Sopenharmony_ci (ipv6_opt_accepted(sk_listener, skb, &TCP_SKB_CB(skb)->header.h6) || 79862306a36Sopenharmony_ci np->rxopt.bits.rxinfo || 79962306a36Sopenharmony_ci np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim || 80062306a36Sopenharmony_ci np->rxopt.bits.rxohlim || np->repflow)) { 80162306a36Sopenharmony_ci refcount_inc(&skb->users); 80262306a36Sopenharmony_ci ireq->pktopts = skb; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic struct dst_entry *tcp_v6_route_req(const struct sock *sk, 80762306a36Sopenharmony_ci struct sk_buff *skb, 80862306a36Sopenharmony_ci struct flowi *fl, 80962306a36Sopenharmony_ci struct request_sock *req) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci tcp_v6_init_req(req, sk, skb); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (security_inet_conn_request(sk, skb, req)) 81462306a36Sopenharmony_ci return NULL; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return inet6_csk_route_req(sk, &fl->u.ip6, req, IPPROTO_TCP); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistruct request_sock_ops tcp6_request_sock_ops __read_mostly = { 82062306a36Sopenharmony_ci .family = AF_INET6, 82162306a36Sopenharmony_ci .obj_size = sizeof(struct tcp6_request_sock), 82262306a36Sopenharmony_ci .rtx_syn_ack = tcp_rtx_synack, 82362306a36Sopenharmony_ci .send_ack = tcp_v6_reqsk_send_ack, 82462306a36Sopenharmony_ci .destructor = tcp_v6_reqsk_destructor, 82562306a36Sopenharmony_ci .send_reset = tcp_v6_send_reset, 82662306a36Sopenharmony_ci .syn_ack_timeout = tcp_syn_ack_timeout, 82762306a36Sopenharmony_ci}; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ciconst struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { 83062306a36Sopenharmony_ci .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - 83162306a36Sopenharmony_ci sizeof(struct ipv6hdr), 83262306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 83362306a36Sopenharmony_ci .req_md5_lookup = tcp_v6_md5_lookup, 83462306a36Sopenharmony_ci .calc_md5_hash = tcp_v6_md5_hash_skb, 83562306a36Sopenharmony_ci#endif 83662306a36Sopenharmony_ci#ifdef CONFIG_SYN_COOKIES 83762306a36Sopenharmony_ci .cookie_init_seq = cookie_v6_init_sequence, 83862306a36Sopenharmony_ci#endif 83962306a36Sopenharmony_ci .route_req = tcp_v6_route_req, 84062306a36Sopenharmony_ci .init_seq = tcp_v6_init_seq, 84162306a36Sopenharmony_ci .init_ts_off = tcp_v6_init_ts_off, 84262306a36Sopenharmony_ci .send_synack = tcp_v6_send_synack, 84362306a36Sopenharmony_ci}; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, 84662306a36Sopenharmony_ci u32 ack, u32 win, u32 tsval, u32 tsecr, 84762306a36Sopenharmony_ci int oif, struct tcp_md5sig_key *key, int rst, 84862306a36Sopenharmony_ci u8 tclass, __be32 label, u32 priority, u32 txhash) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci const struct tcphdr *th = tcp_hdr(skb); 85162306a36Sopenharmony_ci struct tcphdr *t1; 85262306a36Sopenharmony_ci struct sk_buff *buff; 85362306a36Sopenharmony_ci struct flowi6 fl6; 85462306a36Sopenharmony_ci struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); 85562306a36Sopenharmony_ci struct sock *ctl_sk = net->ipv6.tcp_sk; 85662306a36Sopenharmony_ci unsigned int tot_len = sizeof(struct tcphdr); 85762306a36Sopenharmony_ci __be32 mrst = 0, *topt; 85862306a36Sopenharmony_ci struct dst_entry *dst; 85962306a36Sopenharmony_ci __u32 mark = 0; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (tsecr) 86262306a36Sopenharmony_ci tot_len += TCPOLEN_TSTAMP_ALIGNED; 86362306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 86462306a36Sopenharmony_ci if (key) 86562306a36Sopenharmony_ci tot_len += TCPOLEN_MD5SIG_ALIGNED; 86662306a36Sopenharmony_ci#endif 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci#ifdef CONFIG_MPTCP 86962306a36Sopenharmony_ci if (rst && !key) { 87062306a36Sopenharmony_ci mrst = mptcp_reset_option(skb); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (mrst) 87362306a36Sopenharmony_ci tot_len += sizeof(__be32); 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci#endif 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci buff = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); 87862306a36Sopenharmony_ci if (!buff) 87962306a36Sopenharmony_ci return; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci skb_reserve(buff, MAX_TCP_HEADER); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci t1 = skb_push(buff, tot_len); 88462306a36Sopenharmony_ci skb_reset_transport_header(buff); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* Swap the send and the receive. */ 88762306a36Sopenharmony_ci memset(t1, 0, sizeof(*t1)); 88862306a36Sopenharmony_ci t1->dest = th->source; 88962306a36Sopenharmony_ci t1->source = th->dest; 89062306a36Sopenharmony_ci t1->doff = tot_len / 4; 89162306a36Sopenharmony_ci t1->seq = htonl(seq); 89262306a36Sopenharmony_ci t1->ack_seq = htonl(ack); 89362306a36Sopenharmony_ci t1->ack = !rst || !th->ack; 89462306a36Sopenharmony_ci t1->rst = rst; 89562306a36Sopenharmony_ci t1->window = htons(win); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci topt = (__be32 *)(t1 + 1); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if (tsecr) { 90062306a36Sopenharmony_ci *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | 90162306a36Sopenharmony_ci (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); 90262306a36Sopenharmony_ci *topt++ = htonl(tsval); 90362306a36Sopenharmony_ci *topt++ = htonl(tsecr); 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (mrst) 90762306a36Sopenharmony_ci *topt++ = mrst; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 91062306a36Sopenharmony_ci if (key) { 91162306a36Sopenharmony_ci *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | 91262306a36Sopenharmony_ci (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); 91362306a36Sopenharmony_ci tcp_v6_md5_hash_hdr((__u8 *)topt, key, 91462306a36Sopenharmony_ci &ipv6_hdr(skb)->saddr, 91562306a36Sopenharmony_ci &ipv6_hdr(skb)->daddr, t1); 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci#endif 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci memset(&fl6, 0, sizeof(fl6)); 92062306a36Sopenharmony_ci fl6.daddr = ipv6_hdr(skb)->saddr; 92162306a36Sopenharmony_ci fl6.saddr = ipv6_hdr(skb)->daddr; 92262306a36Sopenharmony_ci fl6.flowlabel = label; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci buff->ip_summed = CHECKSUM_PARTIAL; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci fl6.flowi6_proto = IPPROTO_TCP; 92962306a36Sopenharmony_ci if (rt6_need_strict(&fl6.daddr) && !oif) 93062306a36Sopenharmony_ci fl6.flowi6_oif = tcp_v6_iif(skb); 93162306a36Sopenharmony_ci else { 93262306a36Sopenharmony_ci if (!oif && netif_index_is_l3_master(net, skb->skb_iif)) 93362306a36Sopenharmony_ci oif = skb->skb_iif; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci fl6.flowi6_oif = oif; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (sk) { 93962306a36Sopenharmony_ci if (sk->sk_state == TCP_TIME_WAIT) 94062306a36Sopenharmony_ci mark = inet_twsk(sk)->tw_mark; 94162306a36Sopenharmony_ci else 94262306a36Sopenharmony_ci mark = READ_ONCE(sk->sk_mark); 94362306a36Sopenharmony_ci skb_set_delivery_time(buff, tcp_transmit_time(sk), true); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci if (txhash) { 94662306a36Sopenharmony_ci /* autoflowlabel/skb_get_hash_flowi6 rely on buff->hash */ 94762306a36Sopenharmony_ci skb_set_hash(buff, txhash, PKT_HASH_TYPE_L4); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark; 95062306a36Sopenharmony_ci fl6.fl6_dport = t1->dest; 95162306a36Sopenharmony_ci fl6.fl6_sport = t1->source; 95262306a36Sopenharmony_ci fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL); 95362306a36Sopenharmony_ci security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6)); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* Pass a socket to ip6_dst_lookup either it is for RST 95662306a36Sopenharmony_ci * Underlying function will use this to retrieve the network 95762306a36Sopenharmony_ci * namespace 95862306a36Sopenharmony_ci */ 95962306a36Sopenharmony_ci if (sk && sk->sk_state != TCP_TIME_WAIT) 96062306a36Sopenharmony_ci dst = ip6_dst_lookup_flow(net, sk, &fl6, NULL); /*sk's xfrm_policy can be referred*/ 96162306a36Sopenharmony_ci else 96262306a36Sopenharmony_ci dst = ip6_dst_lookup_flow(net, ctl_sk, &fl6, NULL); 96362306a36Sopenharmony_ci if (!IS_ERR(dst)) { 96462306a36Sopenharmony_ci skb_dst_set(buff, dst); 96562306a36Sopenharmony_ci ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, 96662306a36Sopenharmony_ci tclass & ~INET_ECN_MASK, priority); 96762306a36Sopenharmony_ci TCP_INC_STATS(net, TCP_MIB_OUTSEGS); 96862306a36Sopenharmony_ci if (rst) 96962306a36Sopenharmony_ci TCP_INC_STATS(net, TCP_MIB_OUTRSTS); 97062306a36Sopenharmony_ci return; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci kfree_skb(buff); 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci const struct tcphdr *th = tcp_hdr(skb); 97962306a36Sopenharmony_ci struct ipv6hdr *ipv6h = ipv6_hdr(skb); 98062306a36Sopenharmony_ci u32 seq = 0, ack_seq = 0; 98162306a36Sopenharmony_ci struct tcp_md5sig_key *key = NULL; 98262306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 98362306a36Sopenharmony_ci const __u8 *hash_location = NULL; 98462306a36Sopenharmony_ci unsigned char newhash[16]; 98562306a36Sopenharmony_ci int genhash; 98662306a36Sopenharmony_ci struct sock *sk1 = NULL; 98762306a36Sopenharmony_ci#endif 98862306a36Sopenharmony_ci __be32 label = 0; 98962306a36Sopenharmony_ci u32 priority = 0; 99062306a36Sopenharmony_ci struct net *net; 99162306a36Sopenharmony_ci u32 txhash = 0; 99262306a36Sopenharmony_ci int oif = 0; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (th->rst) 99562306a36Sopenharmony_ci return; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* If sk not NULL, it means we did a successful lookup and incoming 99862306a36Sopenharmony_ci * route had to be correct. prequeue might have dropped our dst. 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ci if (!sk && !ipv6_unicast_destination(skb)) 100162306a36Sopenharmony_ci return; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); 100462306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 100562306a36Sopenharmony_ci rcu_read_lock(); 100662306a36Sopenharmony_ci hash_location = tcp_parse_md5sig_option(th); 100762306a36Sopenharmony_ci if (sk && sk_fullsock(sk)) { 100862306a36Sopenharmony_ci int l3index; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci /* sdif set, means packet ingressed via a device 101162306a36Sopenharmony_ci * in an L3 domain and inet_iif is set to it. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ci l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0; 101462306a36Sopenharmony_ci key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr, l3index); 101562306a36Sopenharmony_ci } else if (hash_location) { 101662306a36Sopenharmony_ci int dif = tcp_v6_iif_l3_slave(skb); 101762306a36Sopenharmony_ci int sdif = tcp_v6_sdif(skb); 101862306a36Sopenharmony_ci int l3index; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* 102162306a36Sopenharmony_ci * active side is lost. Try to find listening socket through 102262306a36Sopenharmony_ci * source port, and then find md5 key through listening socket. 102362306a36Sopenharmony_ci * we are not loose security here: 102462306a36Sopenharmony_ci * Incoming packet is checked with md5 hash with finding key, 102562306a36Sopenharmony_ci * no RST generated if md5 hash doesn't match. 102662306a36Sopenharmony_ci */ 102762306a36Sopenharmony_ci sk1 = inet6_lookup_listener(net, net->ipv4.tcp_death_row.hashinfo, 102862306a36Sopenharmony_ci NULL, 0, &ipv6h->saddr, th->source, 102962306a36Sopenharmony_ci &ipv6h->daddr, ntohs(th->source), 103062306a36Sopenharmony_ci dif, sdif); 103162306a36Sopenharmony_ci if (!sk1) 103262306a36Sopenharmony_ci goto out; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* sdif set, means packet ingressed via a device 103562306a36Sopenharmony_ci * in an L3 domain and dif is set to it. 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_ci l3index = tcp_v6_sdif(skb) ? dif : 0; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr, l3index); 104062306a36Sopenharmony_ci if (!key) 104162306a36Sopenharmony_ci goto out; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, skb); 104462306a36Sopenharmony_ci if (genhash || memcmp(hash_location, newhash, 16) != 0) 104562306a36Sopenharmony_ci goto out; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci#endif 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (th->ack) 105062306a36Sopenharmony_ci seq = ntohl(th->ack_seq); 105162306a36Sopenharmony_ci else 105262306a36Sopenharmony_ci ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - 105362306a36Sopenharmony_ci (th->doff << 2); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (sk) { 105662306a36Sopenharmony_ci oif = sk->sk_bound_dev_if; 105762306a36Sopenharmony_ci if (sk_fullsock(sk)) { 105862306a36Sopenharmony_ci const struct ipv6_pinfo *np = tcp_inet6_sk(sk); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci trace_tcp_send_reset(sk, skb); 106162306a36Sopenharmony_ci if (np->repflow) 106262306a36Sopenharmony_ci label = ip6_flowlabel(ipv6h); 106362306a36Sopenharmony_ci priority = sk->sk_priority; 106462306a36Sopenharmony_ci txhash = sk->sk_txhash; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci if (sk->sk_state == TCP_TIME_WAIT) { 106762306a36Sopenharmony_ci label = cpu_to_be32(inet_twsk(sk)->tw_flowlabel); 106862306a36Sopenharmony_ci priority = inet_twsk(sk)->tw_priority; 106962306a36Sopenharmony_ci txhash = inet_twsk(sk)->tw_txhash; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci } else { 107262306a36Sopenharmony_ci if (net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_TCP_RESET) 107362306a36Sopenharmony_ci label = ip6_flowlabel(ipv6h); 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 107762306a36Sopenharmony_ci ipv6_get_dsfield(ipv6h), label, priority, txhash); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 108062306a36Sopenharmony_ciout: 108162306a36Sopenharmony_ci rcu_read_unlock(); 108262306a36Sopenharmony_ci#endif 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, 108662306a36Sopenharmony_ci u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, 108762306a36Sopenharmony_ci struct tcp_md5sig_key *key, u8 tclass, 108862306a36Sopenharmony_ci __be32 label, u32 priority, u32 txhash) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, 109162306a36Sopenharmony_ci tclass, label, priority, txhash); 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci struct inet_timewait_sock *tw = inet_twsk(sk); 109762306a36Sopenharmony_ci struct tcp_timewait_sock *tcptw = tcp_twsk(sk); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, 110062306a36Sopenharmony_ci tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, 110162306a36Sopenharmony_ci tcp_time_stamp_raw() + tcptw->tw_ts_offset, 110262306a36Sopenharmony_ci tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), 110362306a36Sopenharmony_ci tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), tw->tw_priority, 110462306a36Sopenharmony_ci tw->tw_txhash); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci inet_twsk_put(tw); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, 111062306a36Sopenharmony_ci struct request_sock *req) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci int l3index; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV 111762306a36Sopenharmony_ci * sk->sk_state == TCP_SYN_RECV -> for Fast Open. 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ci /* RFC 7323 2.3 112062306a36Sopenharmony_ci * The window field (SEG.WND) of every outgoing segment, with the 112162306a36Sopenharmony_ci * exception of <SYN> segments, MUST be right-shifted by 112262306a36Sopenharmony_ci * Rcv.Wind.Shift bits: 112362306a36Sopenharmony_ci */ 112462306a36Sopenharmony_ci tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? 112562306a36Sopenharmony_ci tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, 112662306a36Sopenharmony_ci tcp_rsk(req)->rcv_nxt, 112762306a36Sopenharmony_ci req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, 112862306a36Sopenharmony_ci tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, 112962306a36Sopenharmony_ci READ_ONCE(req->ts_recent), sk->sk_bound_dev_if, 113062306a36Sopenharmony_ci tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr, l3index), 113162306a36Sopenharmony_ci ipv6_get_dsfield(ipv6_hdr(skb)), 0, 113262306a36Sopenharmony_ci READ_ONCE(sk->sk_priority), 113362306a36Sopenharmony_ci READ_ONCE(tcp_rsk(req)->txhash)); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_cistatic struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci#ifdef CONFIG_SYN_COOKIES 114062306a36Sopenharmony_ci const struct tcphdr *th = tcp_hdr(skb); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (!th->syn) 114362306a36Sopenharmony_ci sk = cookie_v6_check(sk, skb); 114462306a36Sopenharmony_ci#endif 114562306a36Sopenharmony_ci return sk; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ciu16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph, 114962306a36Sopenharmony_ci struct tcphdr *th, u32 *cookie) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci u16 mss = 0; 115262306a36Sopenharmony_ci#ifdef CONFIG_SYN_COOKIES 115362306a36Sopenharmony_ci mss = tcp_get_syncookie_mss(&tcp6_request_sock_ops, 115462306a36Sopenharmony_ci &tcp_request_sock_ipv6_ops, sk, th); 115562306a36Sopenharmony_ci if (mss) { 115662306a36Sopenharmony_ci *cookie = __cookie_v6_init_sequence(iph, th, &mss); 115762306a36Sopenharmony_ci tcp_synq_overflow(sk); 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci#endif 116062306a36Sopenharmony_ci return mss; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) 116662306a36Sopenharmony_ci return tcp_v4_conn_request(sk, skb); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (!ipv6_unicast_destination(skb)) 116962306a36Sopenharmony_ci goto drop; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (ipv6_addr_v4mapped(&ipv6_hdr(skb)->saddr)) { 117262306a36Sopenharmony_ci __IP6_INC_STATS(sock_net(sk), NULL, IPSTATS_MIB_INHDRERRORS); 117362306a36Sopenharmony_ci return 0; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci return tcp_conn_request(&tcp6_request_sock_ops, 117762306a36Sopenharmony_ci &tcp_request_sock_ipv6_ops, sk, skb); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cidrop: 118062306a36Sopenharmony_ci tcp_listendrop(sk); 118162306a36Sopenharmony_ci return 0; /* don't send reset */ 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic void tcp_v6_restore_cb(struct sk_buff *skb) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci /* We need to move header back to the beginning if xfrm6_policy_check() 118762306a36Sopenharmony_ci * and tcp_v6_fill_cb() are going to be called again. 118862306a36Sopenharmony_ci * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. 118962306a36Sopenharmony_ci */ 119062306a36Sopenharmony_ci memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, 119162306a36Sopenharmony_ci sizeof(struct inet6_skb_parm)); 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_cistatic struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, 119562306a36Sopenharmony_ci struct request_sock *req, 119662306a36Sopenharmony_ci struct dst_entry *dst, 119762306a36Sopenharmony_ci struct request_sock *req_unhash, 119862306a36Sopenharmony_ci bool *own_req) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci struct inet_request_sock *ireq; 120162306a36Sopenharmony_ci struct ipv6_pinfo *newnp; 120262306a36Sopenharmony_ci const struct ipv6_pinfo *np = tcp_inet6_sk(sk); 120362306a36Sopenharmony_ci struct ipv6_txoptions *opt; 120462306a36Sopenharmony_ci struct inet_sock *newinet; 120562306a36Sopenharmony_ci bool found_dup_sk = false; 120662306a36Sopenharmony_ci struct tcp_sock *newtp; 120762306a36Sopenharmony_ci struct sock *newsk; 120862306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 120962306a36Sopenharmony_ci struct tcp_md5sig_key *key; 121062306a36Sopenharmony_ci int l3index; 121162306a36Sopenharmony_ci#endif 121262306a36Sopenharmony_ci struct flowi6 fl6; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) { 121562306a36Sopenharmony_ci /* 121662306a36Sopenharmony_ci * v6 mapped 121762306a36Sopenharmony_ci */ 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst, 122062306a36Sopenharmony_ci req_unhash, own_req); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (!newsk) 122362306a36Sopenharmony_ci return NULL; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci inet_sk(newsk)->pinet6 = tcp_inet6_sk(newsk); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci newnp = tcp_inet6_sk(newsk); 122862306a36Sopenharmony_ci newtp = tcp_sk(newsk); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci newnp->saddr = newsk->sk_v6_rcv_saddr; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; 123562306a36Sopenharmony_ci if (sk_is_mptcp(newsk)) 123662306a36Sopenharmony_ci mptcpv6_handle_mapped(newsk, true); 123762306a36Sopenharmony_ci newsk->sk_backlog_rcv = tcp_v4_do_rcv; 123862306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 123962306a36Sopenharmony_ci newtp->af_specific = &tcp_sock_ipv6_mapped_specific; 124062306a36Sopenharmony_ci#endif 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci newnp->ipv6_mc_list = NULL; 124362306a36Sopenharmony_ci newnp->ipv6_ac_list = NULL; 124462306a36Sopenharmony_ci newnp->ipv6_fl_list = NULL; 124562306a36Sopenharmony_ci newnp->pktoptions = NULL; 124662306a36Sopenharmony_ci newnp->opt = NULL; 124762306a36Sopenharmony_ci newnp->mcast_oif = inet_iif(skb); 124862306a36Sopenharmony_ci newnp->mcast_hops = ip_hdr(skb)->ttl; 124962306a36Sopenharmony_ci newnp->rcv_flowinfo = 0; 125062306a36Sopenharmony_ci if (np->repflow) 125162306a36Sopenharmony_ci newnp->flow_label = 0; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci /* 125462306a36Sopenharmony_ci * No need to charge this sock to the relevant IPv6 refcnt debug socks count 125562306a36Sopenharmony_ci * here, tcp_create_openreq_child now does this for us, see the comment in 125662306a36Sopenharmony_ci * that function for the gory details. -acme 125762306a36Sopenharmony_ci */ 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* It is tricky place. Until this moment IPv4 tcp 126062306a36Sopenharmony_ci worked with IPv6 icsk.icsk_af_ops. 126162306a36Sopenharmony_ci Sync it now. 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_ci tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci return newsk; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci ireq = inet_rsk(req); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (sk_acceptq_is_full(sk)) 127162306a36Sopenharmony_ci goto out_overflow; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (!dst) { 127462306a36Sopenharmony_ci dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_TCP); 127562306a36Sopenharmony_ci if (!dst) 127662306a36Sopenharmony_ci goto out; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci newsk = tcp_create_openreq_child(sk, req, skb); 128062306a36Sopenharmony_ci if (!newsk) 128162306a36Sopenharmony_ci goto out_nonewsk; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* 128462306a36Sopenharmony_ci * No need to charge this sock to the relevant IPv6 refcnt debug socks 128562306a36Sopenharmony_ci * count here, tcp_create_openreq_child now does this for us, see the 128662306a36Sopenharmony_ci * comment in that function for the gory details. -acme 128762306a36Sopenharmony_ci */ 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci newsk->sk_gso_type = SKB_GSO_TCPV6; 129062306a36Sopenharmony_ci ip6_dst_store(newsk, dst, NULL, NULL); 129162306a36Sopenharmony_ci inet6_sk_rx_dst_set(newsk, skb); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci inet_sk(newsk)->pinet6 = tcp_inet6_sk(newsk); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci newtp = tcp_sk(newsk); 129662306a36Sopenharmony_ci newinet = inet_sk(newsk); 129762306a36Sopenharmony_ci newnp = tcp_inet6_sk(newsk); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr; 130262306a36Sopenharmony_ci newnp->saddr = ireq->ir_v6_loc_addr; 130362306a36Sopenharmony_ci newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; 130462306a36Sopenharmony_ci newsk->sk_bound_dev_if = ireq->ir_iif; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci /* Now IPv6 options... 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci First: no IPv4 options. 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_ci newinet->inet_opt = NULL; 131162306a36Sopenharmony_ci newnp->ipv6_mc_list = NULL; 131262306a36Sopenharmony_ci newnp->ipv6_ac_list = NULL; 131362306a36Sopenharmony_ci newnp->ipv6_fl_list = NULL; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci /* Clone RX bits */ 131662306a36Sopenharmony_ci newnp->rxopt.all = np->rxopt.all; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci newnp->pktoptions = NULL; 131962306a36Sopenharmony_ci newnp->opt = NULL; 132062306a36Sopenharmony_ci newnp->mcast_oif = tcp_v6_iif(skb); 132162306a36Sopenharmony_ci newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 132262306a36Sopenharmony_ci newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); 132362306a36Sopenharmony_ci if (np->repflow) 132462306a36Sopenharmony_ci newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb)); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* Set ToS of the new socket based upon the value of incoming SYN. 132762306a36Sopenharmony_ci * ECT bits are set later in tcp_init_transfer(). 132862306a36Sopenharmony_ci */ 132962306a36Sopenharmony_ci if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reflect_tos)) 133062306a36Sopenharmony_ci newnp->tclass = tcp_rsk(req)->syn_tos & ~INET_ECN_MASK; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* Clone native IPv6 options from listening socket (if any) 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci Yes, keeping reference count would be much more clever, 133562306a36Sopenharmony_ci but we make one more one thing there: reattach optmem 133662306a36Sopenharmony_ci to newsk. 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_ci opt = ireq->ipv6_opt; 133962306a36Sopenharmony_ci if (!opt) 134062306a36Sopenharmony_ci opt = rcu_dereference(np->opt); 134162306a36Sopenharmony_ci if (opt) { 134262306a36Sopenharmony_ci opt = ipv6_dup_options(newsk, opt); 134362306a36Sopenharmony_ci RCU_INIT_POINTER(newnp->opt, opt); 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci inet_csk(newsk)->icsk_ext_hdr_len = 0; 134662306a36Sopenharmony_ci if (opt) 134762306a36Sopenharmony_ci inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen + 134862306a36Sopenharmony_ci opt->opt_flen; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci tcp_ca_openreq_child(newsk, dst); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci tcp_sync_mss(newsk, dst_mtu(dst)); 135362306a36Sopenharmony_ci newtp->advmss = tcp_mss_clamp(tcp_sk(sk), dst_metric_advmss(dst)); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci tcp_initialize_rcv_mss(newsk); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; 135862306a36Sopenharmony_ci newinet->inet_rcv_saddr = LOOPBACK4_IPV6; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 136162306a36Sopenharmony_ci l3index = l3mdev_master_ifindex_by_index(sock_net(sk), ireq->ir_iif); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci /* Copy over the MD5 key from the original socket */ 136462306a36Sopenharmony_ci key = tcp_v6_md5_do_lookup(sk, &newsk->sk_v6_daddr, l3index); 136562306a36Sopenharmony_ci if (key) { 136662306a36Sopenharmony_ci const union tcp_md5_addr *addr; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci addr = (union tcp_md5_addr *)&newsk->sk_v6_daddr; 136962306a36Sopenharmony_ci if (tcp_md5_key_copy(newsk, addr, AF_INET6, 128, l3index, key)) { 137062306a36Sopenharmony_ci inet_csk_prepare_forced_close(newsk); 137162306a36Sopenharmony_ci tcp_done(newsk); 137262306a36Sopenharmony_ci goto out; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci#endif 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (__inet_inherit_port(sk, newsk) < 0) { 137862306a36Sopenharmony_ci inet_csk_prepare_forced_close(newsk); 137962306a36Sopenharmony_ci tcp_done(newsk); 138062306a36Sopenharmony_ci goto out; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash), 138362306a36Sopenharmony_ci &found_dup_sk); 138462306a36Sopenharmony_ci if (*own_req) { 138562306a36Sopenharmony_ci tcp_move_syn(newtp, req); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci /* Clone pktoptions received with SYN, if we own the req */ 138862306a36Sopenharmony_ci if (ireq->pktopts) { 138962306a36Sopenharmony_ci newnp->pktoptions = skb_clone_and_charge_r(ireq->pktopts, newsk); 139062306a36Sopenharmony_ci consume_skb(ireq->pktopts); 139162306a36Sopenharmony_ci ireq->pktopts = NULL; 139262306a36Sopenharmony_ci if (newnp->pktoptions) 139362306a36Sopenharmony_ci tcp_v6_restore_cb(newnp->pktoptions); 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci } else { 139662306a36Sopenharmony_ci if (!req_unhash && found_dup_sk) { 139762306a36Sopenharmony_ci /* This code path should only be executed in the 139862306a36Sopenharmony_ci * syncookie case only 139962306a36Sopenharmony_ci */ 140062306a36Sopenharmony_ci bh_unlock_sock(newsk); 140162306a36Sopenharmony_ci sock_put(newsk); 140262306a36Sopenharmony_ci newsk = NULL; 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci return newsk; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ciout_overflow: 140962306a36Sopenharmony_ci __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); 141062306a36Sopenharmony_ciout_nonewsk: 141162306a36Sopenharmony_ci dst_release(dst); 141262306a36Sopenharmony_ciout: 141362306a36Sopenharmony_ci tcp_listendrop(sk); 141462306a36Sopenharmony_ci return NULL; 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *, 141862306a36Sopenharmony_ci u32)); 141962306a36Sopenharmony_ci/* The socket must have it's spinlock held when we get 142062306a36Sopenharmony_ci * here, unless it is a TCP_LISTEN socket. 142162306a36Sopenharmony_ci * 142262306a36Sopenharmony_ci * We have a potential double-lock case here, so even when 142362306a36Sopenharmony_ci * doing backlog processing we use the BH locking scheme. 142462306a36Sopenharmony_ci * This is because we cannot sleep with the original spinlock 142562306a36Sopenharmony_ci * held. 142662306a36Sopenharmony_ci */ 142762306a36Sopenharmony_ciINDIRECT_CALLABLE_SCOPE 142862306a36Sopenharmony_ciint tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) 142962306a36Sopenharmony_ci{ 143062306a36Sopenharmony_ci struct ipv6_pinfo *np = tcp_inet6_sk(sk); 143162306a36Sopenharmony_ci struct sk_buff *opt_skb = NULL; 143262306a36Sopenharmony_ci enum skb_drop_reason reason; 143362306a36Sopenharmony_ci struct tcp_sock *tp; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* Imagine: socket is IPv6. IPv4 packet arrives, 143662306a36Sopenharmony_ci goes to IPv4 receive handler and backlogged. 143762306a36Sopenharmony_ci From backlog it always goes here. Kerboom... 143862306a36Sopenharmony_ci Fortunately, tcp_rcv_established and rcv_established 143962306a36Sopenharmony_ci handle them correctly, but it is not case with 144062306a36Sopenharmony_ci tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK 144162306a36Sopenharmony_ci */ 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) 144462306a36Sopenharmony_ci return tcp_v4_do_rcv(sk, skb); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci /* 144762306a36Sopenharmony_ci * socket locking is here for SMP purposes as backlog rcv 144862306a36Sopenharmony_ci * is currently called with bh processing disabled. 144962306a36Sopenharmony_ci */ 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci /* Do Stevens' IPV6_PKTOPTIONS. 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci Yes, guys, it is the only place in our code, where we 145462306a36Sopenharmony_ci may make it not affecting IPv4. 145562306a36Sopenharmony_ci The rest of code is protocol independent, 145662306a36Sopenharmony_ci and I do not like idea to uglify IPv4. 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci Actually, all the idea behind IPV6_PKTOPTIONS 145962306a36Sopenharmony_ci looks not very well thought. For now we latch 146062306a36Sopenharmony_ci options, received in the last packet, enqueued 146162306a36Sopenharmony_ci by tcp. Feel free to propose better solution. 146262306a36Sopenharmony_ci --ANK (980728) 146362306a36Sopenharmony_ci */ 146462306a36Sopenharmony_ci if (np->rxopt.all) 146562306a36Sopenharmony_ci opt_skb = skb_clone_and_charge_r(skb, sk); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci reason = SKB_DROP_REASON_NOT_SPECIFIED; 146862306a36Sopenharmony_ci if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ 146962306a36Sopenharmony_ci struct dst_entry *dst; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci dst = rcu_dereference_protected(sk->sk_rx_dst, 147262306a36Sopenharmony_ci lockdep_sock_is_held(sk)); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci sock_rps_save_rxhash(sk, skb); 147562306a36Sopenharmony_ci sk_mark_napi_id(sk, skb); 147662306a36Sopenharmony_ci if (dst) { 147762306a36Sopenharmony_ci if (sk->sk_rx_dst_ifindex != skb->skb_iif || 147862306a36Sopenharmony_ci INDIRECT_CALL_1(dst->ops->check, ip6_dst_check, 147962306a36Sopenharmony_ci dst, sk->sk_rx_dst_cookie) == NULL) { 148062306a36Sopenharmony_ci RCU_INIT_POINTER(sk->sk_rx_dst, NULL); 148162306a36Sopenharmony_ci dst_release(dst); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci tcp_rcv_established(sk, skb); 148662306a36Sopenharmony_ci if (opt_skb) 148762306a36Sopenharmony_ci goto ipv6_pktoptions; 148862306a36Sopenharmony_ci return 0; 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (tcp_checksum_complete(skb)) 149262306a36Sopenharmony_ci goto csum_err; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) { 149562306a36Sopenharmony_ci struct sock *nsk = tcp_v6_cookie_check(sk, skb); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci if (!nsk) 149862306a36Sopenharmony_ci goto discard; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (nsk != sk) { 150162306a36Sopenharmony_ci if (tcp_child_process(sk, nsk, skb)) 150262306a36Sopenharmony_ci goto reset; 150362306a36Sopenharmony_ci if (opt_skb) 150462306a36Sopenharmony_ci __kfree_skb(opt_skb); 150562306a36Sopenharmony_ci return 0; 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci } else 150862306a36Sopenharmony_ci sock_rps_save_rxhash(sk, skb); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci if (tcp_rcv_state_process(sk, skb)) 151162306a36Sopenharmony_ci goto reset; 151262306a36Sopenharmony_ci if (opt_skb) 151362306a36Sopenharmony_ci goto ipv6_pktoptions; 151462306a36Sopenharmony_ci return 0; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cireset: 151762306a36Sopenharmony_ci tcp_v6_send_reset(sk, skb); 151862306a36Sopenharmony_cidiscard: 151962306a36Sopenharmony_ci if (opt_skb) 152062306a36Sopenharmony_ci __kfree_skb(opt_skb); 152162306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 152262306a36Sopenharmony_ci return 0; 152362306a36Sopenharmony_cicsum_err: 152462306a36Sopenharmony_ci reason = SKB_DROP_REASON_TCP_CSUM; 152562306a36Sopenharmony_ci trace_tcp_bad_csum(skb); 152662306a36Sopenharmony_ci TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS); 152762306a36Sopenharmony_ci TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS); 152862306a36Sopenharmony_ci goto discard; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ciipv6_pktoptions: 153262306a36Sopenharmony_ci /* Do you ask, what is it? 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci 1. skb was enqueued by tcp. 153562306a36Sopenharmony_ci 2. skb is added to tail of read queue, rather than out of order. 153662306a36Sopenharmony_ci 3. socket is not in passive state. 153762306a36Sopenharmony_ci 4. Finally, it really contains options, which user wants to receive. 153862306a36Sopenharmony_ci */ 153962306a36Sopenharmony_ci tp = tcp_sk(sk); 154062306a36Sopenharmony_ci if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt && 154162306a36Sopenharmony_ci !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { 154262306a36Sopenharmony_ci if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) 154362306a36Sopenharmony_ci np->mcast_oif = tcp_v6_iif(opt_skb); 154462306a36Sopenharmony_ci if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) 154562306a36Sopenharmony_ci np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; 154662306a36Sopenharmony_ci if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) 154762306a36Sopenharmony_ci np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); 154862306a36Sopenharmony_ci if (np->repflow) 154962306a36Sopenharmony_ci np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); 155062306a36Sopenharmony_ci if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) { 155162306a36Sopenharmony_ci tcp_v6_restore_cb(opt_skb); 155262306a36Sopenharmony_ci opt_skb = xchg(&np->pktoptions, opt_skb); 155362306a36Sopenharmony_ci } else { 155462306a36Sopenharmony_ci __kfree_skb(opt_skb); 155562306a36Sopenharmony_ci opt_skb = xchg(&np->pktoptions, NULL); 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci consume_skb(opt_skb); 156062306a36Sopenharmony_ci return 0; 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, 156462306a36Sopenharmony_ci const struct tcphdr *th) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci /* This is tricky: we move IP6CB at its correct location into 156762306a36Sopenharmony_ci * TCP_SKB_CB(). It must be done after xfrm6_policy_check(), because 156862306a36Sopenharmony_ci * _decode_session6() uses IP6CB(). 156962306a36Sopenharmony_ci * barrier() makes sure compiler won't play aliasing games. 157062306a36Sopenharmony_ci */ 157162306a36Sopenharmony_ci memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb), 157262306a36Sopenharmony_ci sizeof(struct inet6_skb_parm)); 157362306a36Sopenharmony_ci barrier(); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci TCP_SKB_CB(skb)->seq = ntohl(th->seq); 157662306a36Sopenharmony_ci TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + 157762306a36Sopenharmony_ci skb->len - th->doff*4); 157862306a36Sopenharmony_ci TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); 157962306a36Sopenharmony_ci TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); 158062306a36Sopenharmony_ci TCP_SKB_CB(skb)->tcp_tw_isn = 0; 158162306a36Sopenharmony_ci TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); 158262306a36Sopenharmony_ci TCP_SKB_CB(skb)->sacked = 0; 158362306a36Sopenharmony_ci TCP_SKB_CB(skb)->has_rxtstamp = 158462306a36Sopenharmony_ci skb->tstamp || skb_hwtstamps(skb)->hwtstamp; 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ciINDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) 158862306a36Sopenharmony_ci{ 158962306a36Sopenharmony_ci enum skb_drop_reason drop_reason; 159062306a36Sopenharmony_ci int sdif = inet6_sdif(skb); 159162306a36Sopenharmony_ci int dif = inet6_iif(skb); 159262306a36Sopenharmony_ci const struct tcphdr *th; 159362306a36Sopenharmony_ci const struct ipv6hdr *hdr; 159462306a36Sopenharmony_ci bool refcounted; 159562306a36Sopenharmony_ci struct sock *sk; 159662306a36Sopenharmony_ci int ret; 159762306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_NOT_SPECIFIED; 160062306a36Sopenharmony_ci if (skb->pkt_type != PACKET_HOST) 160162306a36Sopenharmony_ci goto discard_it; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci /* 160462306a36Sopenharmony_ci * Count it even if it's bad. 160562306a36Sopenharmony_ci */ 160662306a36Sopenharmony_ci __TCP_INC_STATS(net, TCP_MIB_INSEGS); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct tcphdr))) 160962306a36Sopenharmony_ci goto discard_it; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci th = (const struct tcphdr *)skb->data; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci if (unlikely(th->doff < sizeof(struct tcphdr) / 4)) { 161462306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_PKT_TOO_SMALL; 161562306a36Sopenharmony_ci goto bad_packet; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci if (!pskb_may_pull(skb, th->doff*4)) 161862306a36Sopenharmony_ci goto discard_it; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (skb_checksum_init(skb, IPPROTO_TCP, ip6_compute_pseudo)) 162162306a36Sopenharmony_ci goto csum_error; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci th = (const struct tcphdr *)skb->data; 162462306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_cilookup: 162762306a36Sopenharmony_ci sk = __inet6_lookup_skb(net->ipv4.tcp_death_row.hashinfo, skb, __tcp_hdrlen(th), 162862306a36Sopenharmony_ci th->source, th->dest, inet6_iif(skb), sdif, 162962306a36Sopenharmony_ci &refcounted); 163062306a36Sopenharmony_ci if (!sk) 163162306a36Sopenharmony_ci goto no_tcp_socket; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ciprocess: 163462306a36Sopenharmony_ci if (sk->sk_state == TCP_TIME_WAIT) 163562306a36Sopenharmony_ci goto do_time_wait; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci if (sk->sk_state == TCP_NEW_SYN_RECV) { 163862306a36Sopenharmony_ci struct request_sock *req = inet_reqsk(sk); 163962306a36Sopenharmony_ci bool req_stolen = false; 164062306a36Sopenharmony_ci struct sock *nsk; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci sk = req->rsk_listener; 164362306a36Sopenharmony_ci if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) 164462306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_XFRM_POLICY; 164562306a36Sopenharmony_ci else 164662306a36Sopenharmony_ci drop_reason = tcp_inbound_md5_hash(sk, skb, 164762306a36Sopenharmony_ci &hdr->saddr, &hdr->daddr, 164862306a36Sopenharmony_ci AF_INET6, dif, sdif); 164962306a36Sopenharmony_ci if (drop_reason) { 165062306a36Sopenharmony_ci sk_drops_add(sk, skb); 165162306a36Sopenharmony_ci reqsk_put(req); 165262306a36Sopenharmony_ci goto discard_it; 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci if (tcp_checksum_complete(skb)) { 165562306a36Sopenharmony_ci reqsk_put(req); 165662306a36Sopenharmony_ci goto csum_error; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci if (unlikely(sk->sk_state != TCP_LISTEN)) { 165962306a36Sopenharmony_ci nsk = reuseport_migrate_sock(sk, req_to_sk(req), skb); 166062306a36Sopenharmony_ci if (!nsk) { 166162306a36Sopenharmony_ci inet_csk_reqsk_queue_drop_and_put(sk, req); 166262306a36Sopenharmony_ci goto lookup; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci sk = nsk; 166562306a36Sopenharmony_ci /* reuseport_migrate_sock() has already held one sk_refcnt 166662306a36Sopenharmony_ci * before returning. 166762306a36Sopenharmony_ci */ 166862306a36Sopenharmony_ci } else { 166962306a36Sopenharmony_ci sock_hold(sk); 167062306a36Sopenharmony_ci } 167162306a36Sopenharmony_ci refcounted = true; 167262306a36Sopenharmony_ci nsk = NULL; 167362306a36Sopenharmony_ci if (!tcp_filter(sk, skb)) { 167462306a36Sopenharmony_ci th = (const struct tcphdr *)skb->data; 167562306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 167662306a36Sopenharmony_ci tcp_v6_fill_cb(skb, hdr, th); 167762306a36Sopenharmony_ci nsk = tcp_check_req(sk, skb, req, false, &req_stolen); 167862306a36Sopenharmony_ci } else { 167962306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_SOCKET_FILTER; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci if (!nsk) { 168262306a36Sopenharmony_ci reqsk_put(req); 168362306a36Sopenharmony_ci if (req_stolen) { 168462306a36Sopenharmony_ci /* Another cpu got exclusive access to req 168562306a36Sopenharmony_ci * and created a full blown socket. 168662306a36Sopenharmony_ci * Try to feed this packet to this socket 168762306a36Sopenharmony_ci * instead of discarding it. 168862306a36Sopenharmony_ci */ 168962306a36Sopenharmony_ci tcp_v6_restore_cb(skb); 169062306a36Sopenharmony_ci sock_put(sk); 169162306a36Sopenharmony_ci goto lookup; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci goto discard_and_relse; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci nf_reset_ct(skb); 169662306a36Sopenharmony_ci if (nsk == sk) { 169762306a36Sopenharmony_ci reqsk_put(req); 169862306a36Sopenharmony_ci tcp_v6_restore_cb(skb); 169962306a36Sopenharmony_ci } else if (tcp_child_process(sk, nsk, skb)) { 170062306a36Sopenharmony_ci tcp_v6_send_reset(nsk, skb); 170162306a36Sopenharmony_ci goto discard_and_relse; 170262306a36Sopenharmony_ci } else { 170362306a36Sopenharmony_ci sock_put(sk); 170462306a36Sopenharmony_ci return 0; 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci if (static_branch_unlikely(&ip6_min_hopcount)) { 170962306a36Sopenharmony_ci /* min_hopcount can be changed concurrently from do_ipv6_setsockopt() */ 171062306a36Sopenharmony_ci if (unlikely(hdr->hop_limit < READ_ONCE(tcp_inet6_sk(sk)->min_hopcount))) { 171162306a36Sopenharmony_ci __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); 171262306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_TCP_MINTTL; 171362306a36Sopenharmony_ci goto discard_and_relse; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { 171862306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_XFRM_POLICY; 171962306a36Sopenharmony_ci goto discard_and_relse; 172062306a36Sopenharmony_ci } 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci drop_reason = tcp_inbound_md5_hash(sk, skb, &hdr->saddr, &hdr->daddr, 172362306a36Sopenharmony_ci AF_INET6, dif, sdif); 172462306a36Sopenharmony_ci if (drop_reason) 172562306a36Sopenharmony_ci goto discard_and_relse; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci nf_reset_ct(skb); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (tcp_filter(sk, skb)) { 173062306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_SOCKET_FILTER; 173162306a36Sopenharmony_ci goto discard_and_relse; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci th = (const struct tcphdr *)skb->data; 173462306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 173562306a36Sopenharmony_ci tcp_v6_fill_cb(skb, hdr, th); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci skb->dev = NULL; 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) { 174062306a36Sopenharmony_ci ret = tcp_v6_do_rcv(sk, skb); 174162306a36Sopenharmony_ci goto put_and_return; 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci sk_incoming_cpu_update(sk); 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci bh_lock_sock_nested(sk); 174762306a36Sopenharmony_ci tcp_segs_in(tcp_sk(sk), skb); 174862306a36Sopenharmony_ci ret = 0; 174962306a36Sopenharmony_ci if (!sock_owned_by_user(sk)) { 175062306a36Sopenharmony_ci ret = tcp_v6_do_rcv(sk, skb); 175162306a36Sopenharmony_ci } else { 175262306a36Sopenharmony_ci if (tcp_add_backlog(sk, skb, &drop_reason)) 175362306a36Sopenharmony_ci goto discard_and_relse; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci bh_unlock_sock(sk); 175662306a36Sopenharmony_ciput_and_return: 175762306a36Sopenharmony_ci if (refcounted) 175862306a36Sopenharmony_ci sock_put(sk); 175962306a36Sopenharmony_ci return ret ? -1 : 0; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_cino_tcp_socket: 176262306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_NO_SOCKET; 176362306a36Sopenharmony_ci if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 176462306a36Sopenharmony_ci goto discard_it; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci tcp_v6_fill_cb(skb, hdr, th); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci if (tcp_checksum_complete(skb)) { 176962306a36Sopenharmony_cicsum_error: 177062306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_TCP_CSUM; 177162306a36Sopenharmony_ci trace_tcp_bad_csum(skb); 177262306a36Sopenharmony_ci __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); 177362306a36Sopenharmony_cibad_packet: 177462306a36Sopenharmony_ci __TCP_INC_STATS(net, TCP_MIB_INERRS); 177562306a36Sopenharmony_ci } else { 177662306a36Sopenharmony_ci tcp_v6_send_reset(NULL, skb); 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_cidiscard_it: 178062306a36Sopenharmony_ci SKB_DR_OR(drop_reason, NOT_SPECIFIED); 178162306a36Sopenharmony_ci kfree_skb_reason(skb, drop_reason); 178262306a36Sopenharmony_ci return 0; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_cidiscard_and_relse: 178562306a36Sopenharmony_ci sk_drops_add(sk, skb); 178662306a36Sopenharmony_ci if (refcounted) 178762306a36Sopenharmony_ci sock_put(sk); 178862306a36Sopenharmony_ci goto discard_it; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_cido_time_wait: 179162306a36Sopenharmony_ci if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { 179262306a36Sopenharmony_ci drop_reason = SKB_DROP_REASON_XFRM_POLICY; 179362306a36Sopenharmony_ci inet_twsk_put(inet_twsk(sk)); 179462306a36Sopenharmony_ci goto discard_it; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci tcp_v6_fill_cb(skb, hdr, th); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci if (tcp_checksum_complete(skb)) { 180062306a36Sopenharmony_ci inet_twsk_put(inet_twsk(sk)); 180162306a36Sopenharmony_ci goto csum_error; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) { 180562306a36Sopenharmony_ci case TCP_TW_SYN: 180662306a36Sopenharmony_ci { 180762306a36Sopenharmony_ci struct sock *sk2; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci sk2 = inet6_lookup_listener(net, net->ipv4.tcp_death_row.hashinfo, 181062306a36Sopenharmony_ci skb, __tcp_hdrlen(th), 181162306a36Sopenharmony_ci &ipv6_hdr(skb)->saddr, th->source, 181262306a36Sopenharmony_ci &ipv6_hdr(skb)->daddr, 181362306a36Sopenharmony_ci ntohs(th->dest), 181462306a36Sopenharmony_ci tcp_v6_iif_l3_slave(skb), 181562306a36Sopenharmony_ci sdif); 181662306a36Sopenharmony_ci if (sk2) { 181762306a36Sopenharmony_ci struct inet_timewait_sock *tw = inet_twsk(sk); 181862306a36Sopenharmony_ci inet_twsk_deschedule_put(tw); 181962306a36Sopenharmony_ci sk = sk2; 182062306a36Sopenharmony_ci tcp_v6_restore_cb(skb); 182162306a36Sopenharmony_ci refcounted = false; 182262306a36Sopenharmony_ci goto process; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci /* to ACK */ 182662306a36Sopenharmony_ci fallthrough; 182762306a36Sopenharmony_ci case TCP_TW_ACK: 182862306a36Sopenharmony_ci tcp_v6_timewait_ack(sk, skb); 182962306a36Sopenharmony_ci break; 183062306a36Sopenharmony_ci case TCP_TW_RST: 183162306a36Sopenharmony_ci tcp_v6_send_reset(sk, skb); 183262306a36Sopenharmony_ci inet_twsk_deschedule_put(inet_twsk(sk)); 183362306a36Sopenharmony_ci goto discard_it; 183462306a36Sopenharmony_ci case TCP_TW_SUCCESS: 183562306a36Sopenharmony_ci ; 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci goto discard_it; 183862306a36Sopenharmony_ci} 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_civoid tcp_v6_early_demux(struct sk_buff *skb) 184162306a36Sopenharmony_ci{ 184262306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 184362306a36Sopenharmony_ci const struct ipv6hdr *hdr; 184462306a36Sopenharmony_ci const struct tcphdr *th; 184562306a36Sopenharmony_ci struct sock *sk; 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci if (skb->pkt_type != PACKET_HOST) 184862306a36Sopenharmony_ci return; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr))) 185162306a36Sopenharmony_ci return; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci hdr = ipv6_hdr(skb); 185462306a36Sopenharmony_ci th = tcp_hdr(skb); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci if (th->doff < sizeof(struct tcphdr) / 4) 185762306a36Sopenharmony_ci return; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci /* Note : We use inet6_iif() here, not tcp_v6_iif() */ 186062306a36Sopenharmony_ci sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, 186162306a36Sopenharmony_ci &hdr->saddr, th->source, 186262306a36Sopenharmony_ci &hdr->daddr, ntohs(th->dest), 186362306a36Sopenharmony_ci inet6_iif(skb), inet6_sdif(skb)); 186462306a36Sopenharmony_ci if (sk) { 186562306a36Sopenharmony_ci skb->sk = sk; 186662306a36Sopenharmony_ci skb->destructor = sock_edemux; 186762306a36Sopenharmony_ci if (sk_fullsock(sk)) { 186862306a36Sopenharmony_ci struct dst_entry *dst = rcu_dereference(sk->sk_rx_dst); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (dst) 187162306a36Sopenharmony_ci dst = dst_check(dst, sk->sk_rx_dst_cookie); 187262306a36Sopenharmony_ci if (dst && 187362306a36Sopenharmony_ci sk->sk_rx_dst_ifindex == skb->skb_iif) 187462306a36Sopenharmony_ci skb_dst_set_noref(skb, dst); 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_cistatic struct timewait_sock_ops tcp6_timewait_sock_ops = { 188062306a36Sopenharmony_ci .twsk_obj_size = sizeof(struct tcp6_timewait_sock), 188162306a36Sopenharmony_ci .twsk_unique = tcp_twsk_unique, 188262306a36Sopenharmony_ci .twsk_destructor = tcp_twsk_destructor, 188362306a36Sopenharmony_ci}; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ciINDIRECT_CALLABLE_SCOPE void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) 188662306a36Sopenharmony_ci{ 188762306a36Sopenharmony_ci __tcp_v6_send_check(skb, &sk->sk_v6_rcv_saddr, &sk->sk_v6_daddr); 188862306a36Sopenharmony_ci} 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ciconst struct inet_connection_sock_af_ops ipv6_specific = { 189162306a36Sopenharmony_ci .queue_xmit = inet6_csk_xmit, 189262306a36Sopenharmony_ci .send_check = tcp_v6_send_check, 189362306a36Sopenharmony_ci .rebuild_header = inet6_sk_rebuild_header, 189462306a36Sopenharmony_ci .sk_rx_dst_set = inet6_sk_rx_dst_set, 189562306a36Sopenharmony_ci .conn_request = tcp_v6_conn_request, 189662306a36Sopenharmony_ci .syn_recv_sock = tcp_v6_syn_recv_sock, 189762306a36Sopenharmony_ci .net_header_len = sizeof(struct ipv6hdr), 189862306a36Sopenharmony_ci .net_frag_header_len = sizeof(struct frag_hdr), 189962306a36Sopenharmony_ci .setsockopt = ipv6_setsockopt, 190062306a36Sopenharmony_ci .getsockopt = ipv6_getsockopt, 190162306a36Sopenharmony_ci .addr2sockaddr = inet6_csk_addr2sockaddr, 190262306a36Sopenharmony_ci .sockaddr_len = sizeof(struct sockaddr_in6), 190362306a36Sopenharmony_ci .mtu_reduced = tcp_v6_mtu_reduced, 190462306a36Sopenharmony_ci}; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 190762306a36Sopenharmony_cistatic const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { 190862306a36Sopenharmony_ci .md5_lookup = tcp_v6_md5_lookup, 190962306a36Sopenharmony_ci .calc_md5_hash = tcp_v6_md5_hash_skb, 191062306a36Sopenharmony_ci .md5_parse = tcp_v6_parse_md5_keys, 191162306a36Sopenharmony_ci}; 191262306a36Sopenharmony_ci#endif 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci/* 191562306a36Sopenharmony_ci * TCP over IPv4 via INET6 API 191662306a36Sopenharmony_ci */ 191762306a36Sopenharmony_cistatic const struct inet_connection_sock_af_ops ipv6_mapped = { 191862306a36Sopenharmony_ci .queue_xmit = ip_queue_xmit, 191962306a36Sopenharmony_ci .send_check = tcp_v4_send_check, 192062306a36Sopenharmony_ci .rebuild_header = inet_sk_rebuild_header, 192162306a36Sopenharmony_ci .sk_rx_dst_set = inet_sk_rx_dst_set, 192262306a36Sopenharmony_ci .conn_request = tcp_v6_conn_request, 192362306a36Sopenharmony_ci .syn_recv_sock = tcp_v6_syn_recv_sock, 192462306a36Sopenharmony_ci .net_header_len = sizeof(struct iphdr), 192562306a36Sopenharmony_ci .setsockopt = ipv6_setsockopt, 192662306a36Sopenharmony_ci .getsockopt = ipv6_getsockopt, 192762306a36Sopenharmony_ci .addr2sockaddr = inet6_csk_addr2sockaddr, 192862306a36Sopenharmony_ci .sockaddr_len = sizeof(struct sockaddr_in6), 192962306a36Sopenharmony_ci .mtu_reduced = tcp_v4_mtu_reduced, 193062306a36Sopenharmony_ci}; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 193362306a36Sopenharmony_cistatic const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { 193462306a36Sopenharmony_ci .md5_lookup = tcp_v4_md5_lookup, 193562306a36Sopenharmony_ci .calc_md5_hash = tcp_v4_md5_hash_skb, 193662306a36Sopenharmony_ci .md5_parse = tcp_v6_parse_md5_keys, 193762306a36Sopenharmony_ci}; 193862306a36Sopenharmony_ci#endif 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci/* NOTE: A lot of things set to zero explicitly by call to 194162306a36Sopenharmony_ci * sk_alloc() so need not be done here. 194262306a36Sopenharmony_ci */ 194362306a36Sopenharmony_cistatic int tcp_v6_init_sock(struct sock *sk) 194462306a36Sopenharmony_ci{ 194562306a36Sopenharmony_ci struct inet_connection_sock *icsk = inet_csk(sk); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci tcp_init_sock(sk); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci icsk->icsk_af_ops = &ipv6_specific; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci#ifdef CONFIG_TCP_MD5SIG 195262306a36Sopenharmony_ci tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific; 195362306a36Sopenharmony_ci#endif 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci return 0; 195662306a36Sopenharmony_ci} 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 195962306a36Sopenharmony_ci/* Proc filesystem TCPv6 sock list dumping. */ 196062306a36Sopenharmony_cistatic void get_openreq6(struct seq_file *seq, 196162306a36Sopenharmony_ci const struct request_sock *req, int i) 196262306a36Sopenharmony_ci{ 196362306a36Sopenharmony_ci long ttd = req->rsk_timer.expires - jiffies; 196462306a36Sopenharmony_ci const struct in6_addr *src = &inet_rsk(req)->ir_v6_loc_addr; 196562306a36Sopenharmony_ci const struct in6_addr *dest = &inet_rsk(req)->ir_v6_rmt_addr; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (ttd < 0) 196862306a36Sopenharmony_ci ttd = 0; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci seq_printf(seq, 197162306a36Sopenharmony_ci "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " 197262306a36Sopenharmony_ci "%02X %08X:%08X %02X:%08lX %08X %5u %8d %d %d %pK\n", 197362306a36Sopenharmony_ci i, 197462306a36Sopenharmony_ci src->s6_addr32[0], src->s6_addr32[1], 197562306a36Sopenharmony_ci src->s6_addr32[2], src->s6_addr32[3], 197662306a36Sopenharmony_ci inet_rsk(req)->ir_num, 197762306a36Sopenharmony_ci dest->s6_addr32[0], dest->s6_addr32[1], 197862306a36Sopenharmony_ci dest->s6_addr32[2], dest->s6_addr32[3], 197962306a36Sopenharmony_ci ntohs(inet_rsk(req)->ir_rmt_port), 198062306a36Sopenharmony_ci TCP_SYN_RECV, 198162306a36Sopenharmony_ci 0, 0, /* could print option size, but that is af dependent. */ 198262306a36Sopenharmony_ci 1, /* timers active (only the expire timer) */ 198362306a36Sopenharmony_ci jiffies_to_clock_t(ttd), 198462306a36Sopenharmony_ci req->num_timeout, 198562306a36Sopenharmony_ci from_kuid_munged(seq_user_ns(seq), 198662306a36Sopenharmony_ci sock_i_uid(req->rsk_listener)), 198762306a36Sopenharmony_ci 0, /* non standard timer */ 198862306a36Sopenharmony_ci 0, /* open_requests have no inode */ 198962306a36Sopenharmony_ci 0, req); 199062306a36Sopenharmony_ci} 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_cistatic void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) 199362306a36Sopenharmony_ci{ 199462306a36Sopenharmony_ci const struct in6_addr *dest, *src; 199562306a36Sopenharmony_ci __u16 destp, srcp; 199662306a36Sopenharmony_ci int timer_active; 199762306a36Sopenharmony_ci unsigned long timer_expires; 199862306a36Sopenharmony_ci const struct inet_sock *inet = inet_sk(sp); 199962306a36Sopenharmony_ci const struct tcp_sock *tp = tcp_sk(sp); 200062306a36Sopenharmony_ci const struct inet_connection_sock *icsk = inet_csk(sp); 200162306a36Sopenharmony_ci const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq; 200262306a36Sopenharmony_ci int rx_queue; 200362306a36Sopenharmony_ci int state; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci dest = &sp->sk_v6_daddr; 200662306a36Sopenharmony_ci src = &sp->sk_v6_rcv_saddr; 200762306a36Sopenharmony_ci destp = ntohs(inet->inet_dport); 200862306a36Sopenharmony_ci srcp = ntohs(inet->inet_sport); 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci if (icsk->icsk_pending == ICSK_TIME_RETRANS || 201162306a36Sopenharmony_ci icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT || 201262306a36Sopenharmony_ci icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { 201362306a36Sopenharmony_ci timer_active = 1; 201462306a36Sopenharmony_ci timer_expires = icsk->icsk_timeout; 201562306a36Sopenharmony_ci } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { 201662306a36Sopenharmony_ci timer_active = 4; 201762306a36Sopenharmony_ci timer_expires = icsk->icsk_timeout; 201862306a36Sopenharmony_ci } else if (timer_pending(&sp->sk_timer)) { 201962306a36Sopenharmony_ci timer_active = 2; 202062306a36Sopenharmony_ci timer_expires = sp->sk_timer.expires; 202162306a36Sopenharmony_ci } else { 202262306a36Sopenharmony_ci timer_active = 0; 202362306a36Sopenharmony_ci timer_expires = jiffies; 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci state = inet_sk_state_load(sp); 202762306a36Sopenharmony_ci if (state == TCP_LISTEN) 202862306a36Sopenharmony_ci rx_queue = READ_ONCE(sp->sk_ack_backlog); 202962306a36Sopenharmony_ci else 203062306a36Sopenharmony_ci /* Because we don't lock the socket, 203162306a36Sopenharmony_ci * we might find a transient negative value. 203262306a36Sopenharmony_ci */ 203362306a36Sopenharmony_ci rx_queue = max_t(int, READ_ONCE(tp->rcv_nxt) - 203462306a36Sopenharmony_ci READ_ONCE(tp->copied_seq), 0); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci seq_printf(seq, 203762306a36Sopenharmony_ci "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " 203862306a36Sopenharmony_ci "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %lu %lu %u %u %d\n", 203962306a36Sopenharmony_ci i, 204062306a36Sopenharmony_ci src->s6_addr32[0], src->s6_addr32[1], 204162306a36Sopenharmony_ci src->s6_addr32[2], src->s6_addr32[3], srcp, 204262306a36Sopenharmony_ci dest->s6_addr32[0], dest->s6_addr32[1], 204362306a36Sopenharmony_ci dest->s6_addr32[2], dest->s6_addr32[3], destp, 204462306a36Sopenharmony_ci state, 204562306a36Sopenharmony_ci READ_ONCE(tp->write_seq) - tp->snd_una, 204662306a36Sopenharmony_ci rx_queue, 204762306a36Sopenharmony_ci timer_active, 204862306a36Sopenharmony_ci jiffies_delta_to_clock_t(timer_expires - jiffies), 204962306a36Sopenharmony_ci icsk->icsk_retransmits, 205062306a36Sopenharmony_ci from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), 205162306a36Sopenharmony_ci icsk->icsk_probes_out, 205262306a36Sopenharmony_ci sock_i_ino(sp), 205362306a36Sopenharmony_ci refcount_read(&sp->sk_refcnt), sp, 205462306a36Sopenharmony_ci jiffies_to_clock_t(icsk->icsk_rto), 205562306a36Sopenharmony_ci jiffies_to_clock_t(icsk->icsk_ack.ato), 205662306a36Sopenharmony_ci (icsk->icsk_ack.quick << 1) | inet_csk_in_pingpong_mode(sp), 205762306a36Sopenharmony_ci tcp_snd_cwnd(tp), 205862306a36Sopenharmony_ci state == TCP_LISTEN ? 205962306a36Sopenharmony_ci fastopenq->max_qlen : 206062306a36Sopenharmony_ci (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh) 206162306a36Sopenharmony_ci ); 206262306a36Sopenharmony_ci} 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_cistatic void get_timewait6_sock(struct seq_file *seq, 206562306a36Sopenharmony_ci struct inet_timewait_sock *tw, int i) 206662306a36Sopenharmony_ci{ 206762306a36Sopenharmony_ci long delta = tw->tw_timer.expires - jiffies; 206862306a36Sopenharmony_ci const struct in6_addr *dest, *src; 206962306a36Sopenharmony_ci __u16 destp, srcp; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci dest = &tw->tw_v6_daddr; 207262306a36Sopenharmony_ci src = &tw->tw_v6_rcv_saddr; 207362306a36Sopenharmony_ci destp = ntohs(tw->tw_dport); 207462306a36Sopenharmony_ci srcp = ntohs(tw->tw_sport); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci seq_printf(seq, 207762306a36Sopenharmony_ci "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " 207862306a36Sopenharmony_ci "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n", 207962306a36Sopenharmony_ci i, 208062306a36Sopenharmony_ci src->s6_addr32[0], src->s6_addr32[1], 208162306a36Sopenharmony_ci src->s6_addr32[2], src->s6_addr32[3], srcp, 208262306a36Sopenharmony_ci dest->s6_addr32[0], dest->s6_addr32[1], 208362306a36Sopenharmony_ci dest->s6_addr32[2], dest->s6_addr32[3], destp, 208462306a36Sopenharmony_ci tw->tw_substate, 0, 0, 208562306a36Sopenharmony_ci 3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0, 208662306a36Sopenharmony_ci refcount_read(&tw->tw_refcnt), tw); 208762306a36Sopenharmony_ci} 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_cistatic int tcp6_seq_show(struct seq_file *seq, void *v) 209062306a36Sopenharmony_ci{ 209162306a36Sopenharmony_ci struct tcp_iter_state *st; 209262306a36Sopenharmony_ci struct sock *sk = v; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 209562306a36Sopenharmony_ci seq_puts(seq, 209662306a36Sopenharmony_ci " sl " 209762306a36Sopenharmony_ci "local_address " 209862306a36Sopenharmony_ci "remote_address " 209962306a36Sopenharmony_ci "st tx_queue rx_queue tr tm->when retrnsmt" 210062306a36Sopenharmony_ci " uid timeout inode\n"); 210162306a36Sopenharmony_ci goto out; 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci st = seq->private; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (sk->sk_state == TCP_TIME_WAIT) 210662306a36Sopenharmony_ci get_timewait6_sock(seq, v, st->num); 210762306a36Sopenharmony_ci else if (sk->sk_state == TCP_NEW_SYN_RECV) 210862306a36Sopenharmony_ci get_openreq6(seq, v, st->num); 210962306a36Sopenharmony_ci else 211062306a36Sopenharmony_ci get_tcp6_sock(seq, v, st->num); 211162306a36Sopenharmony_ciout: 211262306a36Sopenharmony_ci return 0; 211362306a36Sopenharmony_ci} 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_cistatic const struct seq_operations tcp6_seq_ops = { 211662306a36Sopenharmony_ci .show = tcp6_seq_show, 211762306a36Sopenharmony_ci .start = tcp_seq_start, 211862306a36Sopenharmony_ci .next = tcp_seq_next, 211962306a36Sopenharmony_ci .stop = tcp_seq_stop, 212062306a36Sopenharmony_ci}; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_cistatic struct tcp_seq_afinfo tcp6_seq_afinfo = { 212362306a36Sopenharmony_ci .family = AF_INET6, 212462306a36Sopenharmony_ci}; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ciint __net_init tcp6_proc_init(struct net *net) 212762306a36Sopenharmony_ci{ 212862306a36Sopenharmony_ci if (!proc_create_net_data("tcp6", 0444, net->proc_net, &tcp6_seq_ops, 212962306a36Sopenharmony_ci sizeof(struct tcp_iter_state), &tcp6_seq_afinfo)) 213062306a36Sopenharmony_ci return -ENOMEM; 213162306a36Sopenharmony_ci return 0; 213262306a36Sopenharmony_ci} 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_civoid tcp6_proc_exit(struct net *net) 213562306a36Sopenharmony_ci{ 213662306a36Sopenharmony_ci remove_proc_entry("tcp6", net->proc_net); 213762306a36Sopenharmony_ci} 213862306a36Sopenharmony_ci#endif 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_cistruct proto tcpv6_prot = { 214162306a36Sopenharmony_ci .name = "TCPv6", 214262306a36Sopenharmony_ci .owner = THIS_MODULE, 214362306a36Sopenharmony_ci .close = tcp_close, 214462306a36Sopenharmony_ci .pre_connect = tcp_v6_pre_connect, 214562306a36Sopenharmony_ci .connect = tcp_v6_connect, 214662306a36Sopenharmony_ci .disconnect = tcp_disconnect, 214762306a36Sopenharmony_ci .accept = inet_csk_accept, 214862306a36Sopenharmony_ci .ioctl = tcp_ioctl, 214962306a36Sopenharmony_ci .init = tcp_v6_init_sock, 215062306a36Sopenharmony_ci .destroy = tcp_v4_destroy_sock, 215162306a36Sopenharmony_ci .shutdown = tcp_shutdown, 215262306a36Sopenharmony_ci .setsockopt = tcp_setsockopt, 215362306a36Sopenharmony_ci .getsockopt = tcp_getsockopt, 215462306a36Sopenharmony_ci .bpf_bypass_getsockopt = tcp_bpf_bypass_getsockopt, 215562306a36Sopenharmony_ci .keepalive = tcp_set_keepalive, 215662306a36Sopenharmony_ci .recvmsg = tcp_recvmsg, 215762306a36Sopenharmony_ci .sendmsg = tcp_sendmsg, 215862306a36Sopenharmony_ci .splice_eof = tcp_splice_eof, 215962306a36Sopenharmony_ci .backlog_rcv = tcp_v6_do_rcv, 216062306a36Sopenharmony_ci .release_cb = tcp_release_cb, 216162306a36Sopenharmony_ci .hash = inet6_hash, 216262306a36Sopenharmony_ci .unhash = inet_unhash, 216362306a36Sopenharmony_ci .get_port = inet_csk_get_port, 216462306a36Sopenharmony_ci .put_port = inet_put_port, 216562306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 216662306a36Sopenharmony_ci .psock_update_sk_prot = tcp_bpf_update_proto, 216762306a36Sopenharmony_ci#endif 216862306a36Sopenharmony_ci .enter_memory_pressure = tcp_enter_memory_pressure, 216962306a36Sopenharmony_ci .leave_memory_pressure = tcp_leave_memory_pressure, 217062306a36Sopenharmony_ci .stream_memory_free = tcp_stream_memory_free, 217162306a36Sopenharmony_ci .sockets_allocated = &tcp_sockets_allocated, 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci .memory_allocated = &tcp_memory_allocated, 217462306a36Sopenharmony_ci .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci .memory_pressure = &tcp_memory_pressure, 217762306a36Sopenharmony_ci .orphan_count = &tcp_orphan_count, 217862306a36Sopenharmony_ci .sysctl_mem = sysctl_tcp_mem, 217962306a36Sopenharmony_ci .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_tcp_wmem), 218062306a36Sopenharmony_ci .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), 218162306a36Sopenharmony_ci .max_header = MAX_TCP_HEADER, 218262306a36Sopenharmony_ci .obj_size = sizeof(struct tcp6_sock), 218362306a36Sopenharmony_ci .ipv6_pinfo_offset = offsetof(struct tcp6_sock, inet6), 218462306a36Sopenharmony_ci .slab_flags = SLAB_TYPESAFE_BY_RCU, 218562306a36Sopenharmony_ci .twsk_prot = &tcp6_timewait_sock_ops, 218662306a36Sopenharmony_ci .rsk_prot = &tcp6_request_sock_ops, 218762306a36Sopenharmony_ci .h.hashinfo = NULL, 218862306a36Sopenharmony_ci .no_autobind = true, 218962306a36Sopenharmony_ci .diag_destroy = tcp_abort, 219062306a36Sopenharmony_ci}; 219162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tcpv6_prot); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_cistatic const struct inet6_protocol tcpv6_protocol = { 219462306a36Sopenharmony_ci .handler = tcp_v6_rcv, 219562306a36Sopenharmony_ci .err_handler = tcp_v6_err, 219662306a36Sopenharmony_ci .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 219762306a36Sopenharmony_ci}; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cistatic struct inet_protosw tcpv6_protosw = { 220062306a36Sopenharmony_ci .type = SOCK_STREAM, 220162306a36Sopenharmony_ci .protocol = IPPROTO_TCP, 220262306a36Sopenharmony_ci .prot = &tcpv6_prot, 220362306a36Sopenharmony_ci .ops = &inet6_stream_ops, 220462306a36Sopenharmony_ci .flags = INET_PROTOSW_PERMANENT | 220562306a36Sopenharmony_ci INET_PROTOSW_ICSK, 220662306a36Sopenharmony_ci}; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_cistatic int __net_init tcpv6_net_init(struct net *net) 220962306a36Sopenharmony_ci{ 221062306a36Sopenharmony_ci return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, 221162306a36Sopenharmony_ci SOCK_RAW, IPPROTO_TCP, net); 221262306a36Sopenharmony_ci} 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_cistatic void __net_exit tcpv6_net_exit(struct net *net) 221562306a36Sopenharmony_ci{ 221662306a36Sopenharmony_ci inet_ctl_sock_destroy(net->ipv6.tcp_sk); 221762306a36Sopenharmony_ci} 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_cistatic void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci tcp_twsk_purge(net_exit_list, AF_INET6); 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_cistatic struct pernet_operations tcpv6_net_ops = { 222562306a36Sopenharmony_ci .init = tcpv6_net_init, 222662306a36Sopenharmony_ci .exit = tcpv6_net_exit, 222762306a36Sopenharmony_ci .exit_batch = tcpv6_net_exit_batch, 222862306a36Sopenharmony_ci}; 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ciint __init tcpv6_init(void) 223162306a36Sopenharmony_ci{ 223262306a36Sopenharmony_ci int ret; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP); 223562306a36Sopenharmony_ci if (ret) 223662306a36Sopenharmony_ci goto out; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci /* register inet6 protocol */ 223962306a36Sopenharmony_ci ret = inet6_register_protosw(&tcpv6_protosw); 224062306a36Sopenharmony_ci if (ret) 224162306a36Sopenharmony_ci goto out_tcpv6_protocol; 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci ret = register_pernet_subsys(&tcpv6_net_ops); 224462306a36Sopenharmony_ci if (ret) 224562306a36Sopenharmony_ci goto out_tcpv6_protosw; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci ret = mptcpv6_init(); 224862306a36Sopenharmony_ci if (ret) 224962306a36Sopenharmony_ci goto out_tcpv6_pernet_subsys; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ciout: 225262306a36Sopenharmony_ci return ret; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ciout_tcpv6_pernet_subsys: 225562306a36Sopenharmony_ci unregister_pernet_subsys(&tcpv6_net_ops); 225662306a36Sopenharmony_ciout_tcpv6_protosw: 225762306a36Sopenharmony_ci inet6_unregister_protosw(&tcpv6_protosw); 225862306a36Sopenharmony_ciout_tcpv6_protocol: 225962306a36Sopenharmony_ci inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); 226062306a36Sopenharmony_ci goto out; 226162306a36Sopenharmony_ci} 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_civoid tcpv6_exit(void) 226462306a36Sopenharmony_ci{ 226562306a36Sopenharmony_ci unregister_pernet_subsys(&tcpv6_net_ops); 226662306a36Sopenharmony_ci inet6_unregister_protosw(&tcpv6_protosw); 226762306a36Sopenharmony_ci inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); 226862306a36Sopenharmony_ci} 2269