162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PF_INET6 socket protocol family 462306a36Sopenharmony_ci * Linux INET6 implementation 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: 762306a36Sopenharmony_ci * Pedro Roque <roque@di.fc.ul.pt> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Adapted from linux/net/ipv4/af_inet.c 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Fixes: 1262306a36Sopenharmony_ci * piggy, Karl Knutson : Socket protocol table 1362306a36Sopenharmony_ci * Hideaki YOSHIFUJI : sin6_scope_id support 1462306a36Sopenharmony_ci * Arnaldo Melo : check proc_net_create return, cleanups 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) "IPv6: " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/capability.h> 2162306a36Sopenharmony_ci#include <linux/errno.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/socket.h> 2462306a36Sopenharmony_ci#include <linux/in.h> 2562306a36Sopenharmony_ci#include <linux/kernel.h> 2662306a36Sopenharmony_ci#include <linux/timer.h> 2762306a36Sopenharmony_ci#include <linux/string.h> 2862306a36Sopenharmony_ci#include <linux/sockios.h> 2962306a36Sopenharmony_ci#include <linux/net.h> 3062306a36Sopenharmony_ci#include <linux/fcntl.h> 3162306a36Sopenharmony_ci#include <linux/mm.h> 3262306a36Sopenharmony_ci#include <linux/interrupt.h> 3362306a36Sopenharmony_ci#include <linux/proc_fs.h> 3462306a36Sopenharmony_ci#include <linux/stat.h> 3562306a36Sopenharmony_ci#include <linux/init.h> 3662306a36Sopenharmony_ci#include <linux/slab.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <linux/inet.h> 3962306a36Sopenharmony_ci#include <linux/netdevice.h> 4062306a36Sopenharmony_ci#include <linux/icmpv6.h> 4162306a36Sopenharmony_ci#include <linux/netfilter_ipv6.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <net/ip.h> 4462306a36Sopenharmony_ci#include <net/ipv6.h> 4562306a36Sopenharmony_ci#include <net/udp.h> 4662306a36Sopenharmony_ci#include <net/udplite.h> 4762306a36Sopenharmony_ci#include <net/tcp.h> 4862306a36Sopenharmony_ci#include <net/ping.h> 4962306a36Sopenharmony_ci#include <net/protocol.h> 5062306a36Sopenharmony_ci#include <net/inet_common.h> 5162306a36Sopenharmony_ci#include <net/route.h> 5262306a36Sopenharmony_ci#include <net/transp_v6.h> 5362306a36Sopenharmony_ci#include <net/ip6_route.h> 5462306a36Sopenharmony_ci#include <net/addrconf.h> 5562306a36Sopenharmony_ci#include <net/ipv6_stubs.h> 5662306a36Sopenharmony_ci#include <net/ndisc.h> 5762306a36Sopenharmony_ci#ifdef CONFIG_IPV6_TUNNEL 5862306a36Sopenharmony_ci#include <net/ip6_tunnel.h> 5962306a36Sopenharmony_ci#endif 6062306a36Sopenharmony_ci#include <net/calipso.h> 6162306a36Sopenharmony_ci#include <net/seg6.h> 6262306a36Sopenharmony_ci#include <net/rpl.h> 6362306a36Sopenharmony_ci#include <net/compat.h> 6462306a36Sopenharmony_ci#include <net/xfrm.h> 6562306a36Sopenharmony_ci#include <net/ioam6.h> 6662306a36Sopenharmony_ci#include <net/rawv6.h> 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#include <linux/uaccess.h> 6962306a36Sopenharmony_ci#include <linux/mroute6.h> 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#include "ip6_offload.h" 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciMODULE_AUTHOR("Cast of dozens"); 7462306a36Sopenharmony_ciMODULE_DESCRIPTION("IPv6 protocol stack for Linux"); 7562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* The inetsw6 table contains everything that inet6_create needs to 7862306a36Sopenharmony_ci * build a new socket. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistatic struct list_head inetsw6[SOCK_MAX]; 8162306a36Sopenharmony_cistatic DEFINE_SPINLOCK(inetsw6_lock); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct ipv6_params ipv6_defaults = { 8462306a36Sopenharmony_ci .disable_ipv6 = 0, 8562306a36Sopenharmony_ci .autoconf = 1, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int disable_ipv6_mod; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cimodule_param_named(disable, disable_ipv6_mod, int, 0444); 9162306a36Sopenharmony_ciMODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional"); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cimodule_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444); 9462306a36Sopenharmony_ciMODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces"); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cimodule_param_named(autoconf, ipv6_defaults.autoconf, int, 0444); 9762306a36Sopenharmony_ciMODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces"); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cibool ipv6_mod_enabled(void) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci return disable_ipv6_mod == 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipv6_mod_enabled); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci const int offset = sk->sk_prot->ipv6_pinfo_offset; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return (struct ipv6_pinfo *)(((u8 *)sk) + offset); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_civoid inet6_sock_destruct(struct sock *sk) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci inet6_cleanup_sock(sk); 11562306a36Sopenharmony_ci inet_sock_destruct(sk); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(inet6_sock_destruct); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int inet6_create(struct net *net, struct socket *sock, int protocol, 12062306a36Sopenharmony_ci int kern) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct inet_sock *inet; 12362306a36Sopenharmony_ci struct ipv6_pinfo *np; 12462306a36Sopenharmony_ci struct sock *sk; 12562306a36Sopenharmony_ci struct inet_protosw *answer; 12662306a36Sopenharmony_ci struct proto *answer_prot; 12762306a36Sopenharmony_ci unsigned char answer_flags; 12862306a36Sopenharmony_ci int try_loading_module = 0; 12962306a36Sopenharmony_ci int err; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (protocol < 0 || protocol >= IPPROTO_MAX) 13262306a36Sopenharmony_ci return -EINVAL; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* Look for the requested type/protocol pair. */ 13562306a36Sopenharmony_cilookup_protocol: 13662306a36Sopenharmony_ci err = -ESOCKTNOSUPPORT; 13762306a36Sopenharmony_ci rcu_read_lock(); 13862306a36Sopenharmony_ci list_for_each_entry_rcu(answer, &inetsw6[sock->type], list) { 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci err = 0; 14162306a36Sopenharmony_ci /* Check the non-wild match. */ 14262306a36Sopenharmony_ci if (protocol == answer->protocol) { 14362306a36Sopenharmony_ci if (protocol != IPPROTO_IP) 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci } else { 14662306a36Sopenharmony_ci /* Check for the two wild cases. */ 14762306a36Sopenharmony_ci if (IPPROTO_IP == protocol) { 14862306a36Sopenharmony_ci protocol = answer->protocol; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci if (IPPROTO_IP == answer->protocol) 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci err = -EPROTONOSUPPORT; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (err) { 15862306a36Sopenharmony_ci if (try_loading_module < 2) { 15962306a36Sopenharmony_ci rcu_read_unlock(); 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * Be more specific, e.g. net-pf-10-proto-132-type-1 16262306a36Sopenharmony_ci * (net-pf-PF_INET6-proto-IPPROTO_SCTP-type-SOCK_STREAM) 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci if (++try_loading_module == 1) 16562306a36Sopenharmony_ci request_module("net-pf-%d-proto-%d-type-%d", 16662306a36Sopenharmony_ci PF_INET6, protocol, sock->type); 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * Fall back to generic, e.g. net-pf-10-proto-132 16962306a36Sopenharmony_ci * (net-pf-PF_INET6-proto-IPPROTO_SCTP) 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci else 17262306a36Sopenharmony_ci request_module("net-pf-%d-proto-%d", 17362306a36Sopenharmony_ci PF_INET6, protocol); 17462306a36Sopenharmony_ci goto lookup_protocol; 17562306a36Sopenharmony_ci } else 17662306a36Sopenharmony_ci goto out_rcu_unlock; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci err = -EPERM; 18062306a36Sopenharmony_ci if (sock->type == SOCK_RAW && !kern && 18162306a36Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_RAW)) 18262306a36Sopenharmony_ci goto out_rcu_unlock; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci sock->ops = answer->ops; 18562306a36Sopenharmony_ci answer_prot = answer->prot; 18662306a36Sopenharmony_ci answer_flags = answer->flags; 18762306a36Sopenharmony_ci rcu_read_unlock(); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci WARN_ON(!answer_prot->slab); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci err = -ENOBUFS; 19262306a36Sopenharmony_ci sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot, kern); 19362306a36Sopenharmony_ci if (!sk) 19462306a36Sopenharmony_ci goto out; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci sock_init_data(sock, sk); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci err = 0; 19962306a36Sopenharmony_ci if (INET_PROTOSW_REUSE & answer_flags) 20062306a36Sopenharmony_ci sk->sk_reuse = SK_CAN_REUSE; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (INET_PROTOSW_ICSK & answer_flags) 20362306a36Sopenharmony_ci inet_init_csk_locks(sk); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci inet = inet_sk(sk); 20662306a36Sopenharmony_ci inet_assign_bit(IS_ICSK, sk, INET_PROTOSW_ICSK & answer_flags); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (SOCK_RAW == sock->type) { 20962306a36Sopenharmony_ci inet->inet_num = protocol; 21062306a36Sopenharmony_ci if (IPPROTO_RAW == protocol) 21162306a36Sopenharmony_ci inet_set_bit(HDRINCL, sk); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci sk->sk_destruct = inet6_sock_destruct; 21562306a36Sopenharmony_ci sk->sk_family = PF_INET6; 21662306a36Sopenharmony_ci sk->sk_protocol = protocol; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci sk->sk_backlog_rcv = answer->prot->backlog_rcv; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); 22162306a36Sopenharmony_ci np->hop_limit = -1; 22262306a36Sopenharmony_ci np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; 22362306a36Sopenharmony_ci np->mc_loop = 1; 22462306a36Sopenharmony_ci np->mc_all = 1; 22562306a36Sopenharmony_ci np->pmtudisc = IPV6_PMTUDISC_WANT; 22662306a36Sopenharmony_ci np->repflow = net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ESTABLISHED; 22762306a36Sopenharmony_ci sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; 22862306a36Sopenharmony_ci sk->sk_txrehash = READ_ONCE(net->core.sysctl_txrehash); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Init the ipv4 part of the socket since we can have sockets 23162306a36Sopenharmony_ci * using v6 API for ipv4. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci inet->uc_ttl = -1; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci inet_set_bit(MC_LOOP, sk); 23662306a36Sopenharmony_ci inet->mc_ttl = 1; 23762306a36Sopenharmony_ci inet->mc_index = 0; 23862306a36Sopenharmony_ci RCU_INIT_POINTER(inet->mc_list, NULL); 23962306a36Sopenharmony_ci inet->rcv_tos = 0; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) 24262306a36Sopenharmony_ci inet->pmtudisc = IP_PMTUDISC_DONT; 24362306a36Sopenharmony_ci else 24462306a36Sopenharmony_ci inet->pmtudisc = IP_PMTUDISC_WANT; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (inet->inet_num) { 24762306a36Sopenharmony_ci /* It assumes that any protocol which allows 24862306a36Sopenharmony_ci * the user to assign a number at socket 24962306a36Sopenharmony_ci * creation time automatically shares. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci inet->inet_sport = htons(inet->inet_num); 25262306a36Sopenharmony_ci err = sk->sk_prot->hash(sk); 25362306a36Sopenharmony_ci if (err) { 25462306a36Sopenharmony_ci sk_common_release(sk); 25562306a36Sopenharmony_ci goto out; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci if (sk->sk_prot->init) { 25962306a36Sopenharmony_ci err = sk->sk_prot->init(sk); 26062306a36Sopenharmony_ci if (err) { 26162306a36Sopenharmony_ci sk_common_release(sk); 26262306a36Sopenharmony_ci goto out; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!kern) { 26762306a36Sopenharmony_ci err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk); 26862306a36Sopenharmony_ci if (err) { 26962306a36Sopenharmony_ci sk_common_release(sk); 27062306a36Sopenharmony_ci goto out; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ciout: 27462306a36Sopenharmony_ci return err; 27562306a36Sopenharmony_ciout_rcu_unlock: 27662306a36Sopenharmony_ci rcu_read_unlock(); 27762306a36Sopenharmony_ci goto out; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, 28162306a36Sopenharmony_ci u32 flags) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct sockaddr_in6 *addr = (struct sockaddr_in6 *)uaddr; 28462306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 28562306a36Sopenharmony_ci struct ipv6_pinfo *np = inet6_sk(sk); 28662306a36Sopenharmony_ci struct net *net = sock_net(sk); 28762306a36Sopenharmony_ci __be32 v4addr = 0; 28862306a36Sopenharmony_ci unsigned short snum; 28962306a36Sopenharmony_ci bool saved_ipv6only; 29062306a36Sopenharmony_ci int addr_type = 0; 29162306a36Sopenharmony_ci int err = 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (addr->sin6_family != AF_INET6) 29462306a36Sopenharmony_ci return -EAFNOSUPPORT; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci addr_type = ipv6_addr_type(&addr->sin6_addr); 29762306a36Sopenharmony_ci if ((addr_type & IPV6_ADDR_MULTICAST) && sk->sk_type == SOCK_STREAM) 29862306a36Sopenharmony_ci return -EINVAL; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci snum = ntohs(addr->sin6_port); 30162306a36Sopenharmony_ci if (!(flags & BIND_NO_CAP_NET_BIND_SERVICE) && 30262306a36Sopenharmony_ci snum && inet_port_requires_bind_service(net, snum) && 30362306a36Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 30462306a36Sopenharmony_ci return -EACCES; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (flags & BIND_WITH_LOCK) 30762306a36Sopenharmony_ci lock_sock(sk); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Check these errors (active socket, double bind). */ 31062306a36Sopenharmony_ci if (sk->sk_state != TCP_CLOSE || inet->inet_num) { 31162306a36Sopenharmony_ci err = -EINVAL; 31262306a36Sopenharmony_ci goto out; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Check if the address belongs to the host. */ 31662306a36Sopenharmony_ci if (addr_type == IPV6_ADDR_MAPPED) { 31762306a36Sopenharmony_ci struct net_device *dev = NULL; 31862306a36Sopenharmony_ci int chk_addr_ret; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Binding to v4-mapped address on a v6-only socket 32162306a36Sopenharmony_ci * makes no sense 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci if (ipv6_only_sock(sk)) { 32462306a36Sopenharmony_ci err = -EINVAL; 32562306a36Sopenharmony_ci goto out; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci rcu_read_lock(); 32962306a36Sopenharmony_ci if (sk->sk_bound_dev_if) { 33062306a36Sopenharmony_ci dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); 33162306a36Sopenharmony_ci if (!dev) { 33262306a36Sopenharmony_ci err = -ENODEV; 33362306a36Sopenharmony_ci goto out_unlock; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Reproduce AF_INET checks to make the bindings consistent */ 33862306a36Sopenharmony_ci v4addr = addr->sin6_addr.s6_addr32[3]; 33962306a36Sopenharmony_ci chk_addr_ret = inet_addr_type_dev_table(net, dev, v4addr); 34062306a36Sopenharmony_ci rcu_read_unlock(); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (!inet_addr_valid_or_nonlocal(net, inet, v4addr, 34362306a36Sopenharmony_ci chk_addr_ret)) { 34462306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 34562306a36Sopenharmony_ci goto out; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci if (addr_type != IPV6_ADDR_ANY) { 34962306a36Sopenharmony_ci struct net_device *dev = NULL; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci rcu_read_lock(); 35262306a36Sopenharmony_ci if (__ipv6_addr_needs_scope_id(addr_type)) { 35362306a36Sopenharmony_ci if (addr_len >= sizeof(struct sockaddr_in6) && 35462306a36Sopenharmony_ci addr->sin6_scope_id) { 35562306a36Sopenharmony_ci /* Override any existing binding, if another one 35662306a36Sopenharmony_ci * is supplied by user. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci sk->sk_bound_dev_if = addr->sin6_scope_id; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Binding to link-local address requires an interface */ 36262306a36Sopenharmony_ci if (!sk->sk_bound_dev_if) { 36362306a36Sopenharmony_ci err = -EINVAL; 36462306a36Sopenharmony_ci goto out_unlock; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (sk->sk_bound_dev_if) { 36962306a36Sopenharmony_ci dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); 37062306a36Sopenharmony_ci if (!dev) { 37162306a36Sopenharmony_ci err = -ENODEV; 37262306a36Sopenharmony_ci goto out_unlock; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* ipv4 addr of the socket is invalid. Only the 37762306a36Sopenharmony_ci * unspecified and mapped address have a v4 equivalent. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci v4addr = LOOPBACK4_IPV6; 38062306a36Sopenharmony_ci if (!(addr_type & IPV6_ADDR_MULTICAST)) { 38162306a36Sopenharmony_ci if (!ipv6_can_nonlocal_bind(net, inet) && 38262306a36Sopenharmony_ci !ipv6_chk_addr(net, &addr->sin6_addr, 38362306a36Sopenharmony_ci dev, 0)) { 38462306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 38562306a36Sopenharmony_ci goto out_unlock; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci rcu_read_unlock(); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci inet->inet_rcv_saddr = v4addr; 39362306a36Sopenharmony_ci inet->inet_saddr = v4addr; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci sk->sk_v6_rcv_saddr = addr->sin6_addr; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (!(addr_type & IPV6_ADDR_MULTICAST)) 39862306a36Sopenharmony_ci np->saddr = addr->sin6_addr; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci saved_ipv6only = sk->sk_ipv6only; 40162306a36Sopenharmony_ci if (addr_type != IPV6_ADDR_ANY && addr_type != IPV6_ADDR_MAPPED) 40262306a36Sopenharmony_ci sk->sk_ipv6only = 1; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* Make sure we are allowed to bind here. */ 40562306a36Sopenharmony_ci if (snum || !(inet_test_bit(BIND_ADDRESS_NO_PORT, sk) || 40662306a36Sopenharmony_ci (flags & BIND_FORCE_ADDRESS_NO_PORT))) { 40762306a36Sopenharmony_ci err = sk->sk_prot->get_port(sk, snum); 40862306a36Sopenharmony_ci if (err) { 40962306a36Sopenharmony_ci sk->sk_ipv6only = saved_ipv6only; 41062306a36Sopenharmony_ci inet_reset_saddr(sk); 41162306a36Sopenharmony_ci goto out; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci if (!(flags & BIND_FROM_BPF)) { 41462306a36Sopenharmony_ci err = BPF_CGROUP_RUN_PROG_INET6_POST_BIND(sk); 41562306a36Sopenharmony_ci if (err) { 41662306a36Sopenharmony_ci sk->sk_ipv6only = saved_ipv6only; 41762306a36Sopenharmony_ci inet_reset_saddr(sk); 41862306a36Sopenharmony_ci if (sk->sk_prot->put_port) 41962306a36Sopenharmony_ci sk->sk_prot->put_port(sk); 42062306a36Sopenharmony_ci goto out; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (addr_type != IPV6_ADDR_ANY) 42662306a36Sopenharmony_ci sk->sk_userlocks |= SOCK_BINDADDR_LOCK; 42762306a36Sopenharmony_ci if (snum) 42862306a36Sopenharmony_ci sk->sk_userlocks |= SOCK_BINDPORT_LOCK; 42962306a36Sopenharmony_ci inet->inet_sport = htons(inet->inet_num); 43062306a36Sopenharmony_ci inet->inet_dport = 0; 43162306a36Sopenharmony_ci inet->inet_daddr = 0; 43262306a36Sopenharmony_ciout: 43362306a36Sopenharmony_ci if (flags & BIND_WITH_LOCK) 43462306a36Sopenharmony_ci release_sock(sk); 43562306a36Sopenharmony_ci return err; 43662306a36Sopenharmony_ciout_unlock: 43762306a36Sopenharmony_ci rcu_read_unlock(); 43862306a36Sopenharmony_ci goto out; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ciint inet6_bind_sk(struct sock *sk, struct sockaddr *uaddr, int addr_len) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci u32 flags = BIND_WITH_LOCK; 44462306a36Sopenharmony_ci const struct proto *prot; 44562306a36Sopenharmony_ci int err = 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* IPV6_ADDRFORM can change sk->sk_prot under us. */ 44862306a36Sopenharmony_ci prot = READ_ONCE(sk->sk_prot); 44962306a36Sopenharmony_ci /* If the socket has its own bind function then use it. */ 45062306a36Sopenharmony_ci if (prot->bind) 45162306a36Sopenharmony_ci return prot->bind(sk, uaddr, addr_len); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (addr_len < SIN6_LEN_RFC2133) 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* BPF prog is run before any checks are done so that if the prog 45762306a36Sopenharmony_ci * changes context in a wrong way it will be caught. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci err = BPF_CGROUP_RUN_PROG_INET_BIND_LOCK(sk, uaddr, &addr_len, 46062306a36Sopenharmony_ci CGROUP_INET6_BIND, &flags); 46162306a36Sopenharmony_ci if (err) 46262306a36Sopenharmony_ci return err; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return __inet6_bind(sk, uaddr, addr_len, flags); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/* bind for INET6 API */ 46862306a36Sopenharmony_ciint inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci return inet6_bind_sk(sock->sk, uaddr, addr_len); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_bind); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ciint inet6_release(struct socket *sock) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct sock *sk = sock->sk; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (!sk) 47962306a36Sopenharmony_ci return -EINVAL; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* Free mc lists */ 48262306a36Sopenharmony_ci ipv6_sock_mc_close(sk); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Free ac lists */ 48562306a36Sopenharmony_ci ipv6_sock_ac_close(sk); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return inet_release(sock); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_release); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_civoid inet6_cleanup_sock(struct sock *sk) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct ipv6_pinfo *np = inet6_sk(sk); 49462306a36Sopenharmony_ci struct sk_buff *skb; 49562306a36Sopenharmony_ci struct ipv6_txoptions *opt; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* Release rx options */ 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci skb = xchg(&np->pktoptions, NULL); 50062306a36Sopenharmony_ci kfree_skb(skb); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci skb = xchg(&np->rxpmtu, NULL); 50362306a36Sopenharmony_ci kfree_skb(skb); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Free flowlabels */ 50662306a36Sopenharmony_ci fl6_free_socklist(sk); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* Free tx options */ 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL); 51162306a36Sopenharmony_ci if (opt) { 51262306a36Sopenharmony_ci atomic_sub(opt->tot_len, &sk->sk_omem_alloc); 51362306a36Sopenharmony_ci txopt_put(opt); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(inet6_cleanup_sock); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/* 51962306a36Sopenharmony_ci * This does both peername and sockname. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_ciint inet6_getname(struct socket *sock, struct sockaddr *uaddr, 52262306a36Sopenharmony_ci int peer) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct sockaddr_in6 *sin = (struct sockaddr_in6 *)uaddr; 52562306a36Sopenharmony_ci int sin_addr_len = sizeof(*sin); 52662306a36Sopenharmony_ci struct sock *sk = sock->sk; 52762306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 52862306a36Sopenharmony_ci struct ipv6_pinfo *np = inet6_sk(sk); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci sin->sin6_family = AF_INET6; 53162306a36Sopenharmony_ci sin->sin6_flowinfo = 0; 53262306a36Sopenharmony_ci sin->sin6_scope_id = 0; 53362306a36Sopenharmony_ci lock_sock(sk); 53462306a36Sopenharmony_ci if (peer) { 53562306a36Sopenharmony_ci if (!inet->inet_dport || 53662306a36Sopenharmony_ci (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && 53762306a36Sopenharmony_ci peer == 1)) { 53862306a36Sopenharmony_ci release_sock(sk); 53962306a36Sopenharmony_ci return -ENOTCONN; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci sin->sin6_port = inet->inet_dport; 54262306a36Sopenharmony_ci sin->sin6_addr = sk->sk_v6_daddr; 54362306a36Sopenharmony_ci if (np->sndflow) 54462306a36Sopenharmony_ci sin->sin6_flowinfo = np->flow_label; 54562306a36Sopenharmony_ci BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin, &sin_addr_len, 54662306a36Sopenharmony_ci CGROUP_INET6_GETPEERNAME); 54762306a36Sopenharmony_ci } else { 54862306a36Sopenharmony_ci if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) 54962306a36Sopenharmony_ci sin->sin6_addr = np->saddr; 55062306a36Sopenharmony_ci else 55162306a36Sopenharmony_ci sin->sin6_addr = sk->sk_v6_rcv_saddr; 55262306a36Sopenharmony_ci sin->sin6_port = inet->inet_sport; 55362306a36Sopenharmony_ci BPF_CGROUP_RUN_SA_PROG(sk, (struct sockaddr *)sin, &sin_addr_len, 55462306a36Sopenharmony_ci CGROUP_INET6_GETSOCKNAME); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci sin->sin6_scope_id = ipv6_iface_scope_id(&sin->sin6_addr, 55762306a36Sopenharmony_ci sk->sk_bound_dev_if); 55862306a36Sopenharmony_ci release_sock(sk); 55962306a36Sopenharmony_ci return sin_addr_len; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_getname); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ciint inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 56662306a36Sopenharmony_ci struct sock *sk = sock->sk; 56762306a36Sopenharmony_ci struct net *net = sock_net(sk); 56862306a36Sopenharmony_ci const struct proto *prot; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci switch (cmd) { 57162306a36Sopenharmony_ci case SIOCADDRT: 57262306a36Sopenharmony_ci case SIOCDELRT: { 57362306a36Sopenharmony_ci struct in6_rtmsg rtmsg; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (copy_from_user(&rtmsg, argp, sizeof(rtmsg))) 57662306a36Sopenharmony_ci return -EFAULT; 57762306a36Sopenharmony_ci return ipv6_route_ioctl(net, cmd, &rtmsg); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci case SIOCSIFADDR: 58062306a36Sopenharmony_ci return addrconf_add_ifaddr(net, argp); 58162306a36Sopenharmony_ci case SIOCDIFADDR: 58262306a36Sopenharmony_ci return addrconf_del_ifaddr(net, argp); 58362306a36Sopenharmony_ci case SIOCSIFDSTADDR: 58462306a36Sopenharmony_ci return addrconf_set_dstaddr(net, argp); 58562306a36Sopenharmony_ci default: 58662306a36Sopenharmony_ci /* IPV6_ADDRFORM can change sk->sk_prot under us. */ 58762306a36Sopenharmony_ci prot = READ_ONCE(sk->sk_prot); 58862306a36Sopenharmony_ci if (!prot->ioctl) 58962306a36Sopenharmony_ci return -ENOIOCTLCMD; 59062306a36Sopenharmony_ci return sk_ioctl(sk, cmd, (void __user *)arg); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci /*NOTREACHED*/ 59362306a36Sopenharmony_ci return 0; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_ioctl); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 59862306a36Sopenharmony_cistruct compat_in6_rtmsg { 59962306a36Sopenharmony_ci struct in6_addr rtmsg_dst; 60062306a36Sopenharmony_ci struct in6_addr rtmsg_src; 60162306a36Sopenharmony_ci struct in6_addr rtmsg_gateway; 60262306a36Sopenharmony_ci u32 rtmsg_type; 60362306a36Sopenharmony_ci u16 rtmsg_dst_len; 60462306a36Sopenharmony_ci u16 rtmsg_src_len; 60562306a36Sopenharmony_ci u32 rtmsg_metric; 60662306a36Sopenharmony_ci u32 rtmsg_info; 60762306a36Sopenharmony_ci u32 rtmsg_flags; 60862306a36Sopenharmony_ci s32 rtmsg_ifindex; 60962306a36Sopenharmony_ci}; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic int inet6_compat_routing_ioctl(struct sock *sk, unsigned int cmd, 61262306a36Sopenharmony_ci struct compat_in6_rtmsg __user *ur) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct in6_rtmsg rt; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (copy_from_user(&rt.rtmsg_dst, &ur->rtmsg_dst, 61762306a36Sopenharmony_ci 3 * sizeof(struct in6_addr)) || 61862306a36Sopenharmony_ci get_user(rt.rtmsg_type, &ur->rtmsg_type) || 61962306a36Sopenharmony_ci get_user(rt.rtmsg_dst_len, &ur->rtmsg_dst_len) || 62062306a36Sopenharmony_ci get_user(rt.rtmsg_src_len, &ur->rtmsg_src_len) || 62162306a36Sopenharmony_ci get_user(rt.rtmsg_metric, &ur->rtmsg_metric) || 62262306a36Sopenharmony_ci get_user(rt.rtmsg_info, &ur->rtmsg_info) || 62362306a36Sopenharmony_ci get_user(rt.rtmsg_flags, &ur->rtmsg_flags) || 62462306a36Sopenharmony_ci get_user(rt.rtmsg_ifindex, &ur->rtmsg_ifindex)) 62562306a36Sopenharmony_ci return -EFAULT; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return ipv6_route_ioctl(sock_net(sk), cmd, &rt); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ciint inet6_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci void __user *argp = compat_ptr(arg); 63462306a36Sopenharmony_ci struct sock *sk = sock->sk; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci switch (cmd) { 63762306a36Sopenharmony_ci case SIOCADDRT: 63862306a36Sopenharmony_ci case SIOCDELRT: 63962306a36Sopenharmony_ci return inet6_compat_routing_ioctl(sk, cmd, argp); 64062306a36Sopenharmony_ci default: 64162306a36Sopenharmony_ci return -ENOIOCTLCMD; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(inet6_compat_ioctl); 64562306a36Sopenharmony_ci#endif /* CONFIG_COMPAT */ 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(int udpv6_sendmsg(struct sock *, struct msghdr *, 64862306a36Sopenharmony_ci size_t)); 64962306a36Sopenharmony_ciint inet6_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct sock *sk = sock->sk; 65262306a36Sopenharmony_ci const struct proto *prot; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (unlikely(inet_send_prepare(sk))) 65562306a36Sopenharmony_ci return -EAGAIN; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* IPV6_ADDRFORM can change sk->sk_prot under us. */ 65862306a36Sopenharmony_ci prot = READ_ONCE(sk->sk_prot); 65962306a36Sopenharmony_ci return INDIRECT_CALL_2(prot->sendmsg, tcp_sendmsg, udpv6_sendmsg, 66062306a36Sopenharmony_ci sk, msg, size); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(int udpv6_recvmsg(struct sock *, struct msghdr *, 66462306a36Sopenharmony_ci size_t, int, int *)); 66562306a36Sopenharmony_ciint inet6_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, 66662306a36Sopenharmony_ci int flags) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct sock *sk = sock->sk; 66962306a36Sopenharmony_ci const struct proto *prot; 67062306a36Sopenharmony_ci int addr_len = 0; 67162306a36Sopenharmony_ci int err; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (likely(!(flags & MSG_ERRQUEUE))) 67462306a36Sopenharmony_ci sock_rps_record_flow(sk); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* IPV6_ADDRFORM can change sk->sk_prot under us. */ 67762306a36Sopenharmony_ci prot = READ_ONCE(sk->sk_prot); 67862306a36Sopenharmony_ci err = INDIRECT_CALL_2(prot->recvmsg, tcp_recvmsg, udpv6_recvmsg, 67962306a36Sopenharmony_ci sk, msg, size, flags, &addr_len); 68062306a36Sopenharmony_ci if (err >= 0) 68162306a36Sopenharmony_ci msg->msg_namelen = addr_len; 68262306a36Sopenharmony_ci return err; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ciconst struct proto_ops inet6_stream_ops = { 68662306a36Sopenharmony_ci .family = PF_INET6, 68762306a36Sopenharmony_ci .owner = THIS_MODULE, 68862306a36Sopenharmony_ci .release = inet6_release, 68962306a36Sopenharmony_ci .bind = inet6_bind, 69062306a36Sopenharmony_ci .connect = inet_stream_connect, /* ok */ 69162306a36Sopenharmony_ci .socketpair = sock_no_socketpair, /* a do nothing */ 69262306a36Sopenharmony_ci .accept = inet_accept, /* ok */ 69362306a36Sopenharmony_ci .getname = inet6_getname, 69462306a36Sopenharmony_ci .poll = tcp_poll, /* ok */ 69562306a36Sopenharmony_ci .ioctl = inet6_ioctl, /* must change */ 69662306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 69762306a36Sopenharmony_ci .listen = inet_listen, /* ok */ 69862306a36Sopenharmony_ci .shutdown = inet_shutdown, /* ok */ 69962306a36Sopenharmony_ci .setsockopt = sock_common_setsockopt, /* ok */ 70062306a36Sopenharmony_ci .getsockopt = sock_common_getsockopt, /* ok */ 70162306a36Sopenharmony_ci .sendmsg = inet6_sendmsg, /* retpoline's sake */ 70262306a36Sopenharmony_ci .recvmsg = inet6_recvmsg, /* retpoline's sake */ 70362306a36Sopenharmony_ci#ifdef CONFIG_MMU 70462306a36Sopenharmony_ci .mmap = tcp_mmap, 70562306a36Sopenharmony_ci#endif 70662306a36Sopenharmony_ci .splice_eof = inet_splice_eof, 70762306a36Sopenharmony_ci .sendmsg_locked = tcp_sendmsg_locked, 70862306a36Sopenharmony_ci .splice_read = tcp_splice_read, 70962306a36Sopenharmony_ci .read_sock = tcp_read_sock, 71062306a36Sopenharmony_ci .read_skb = tcp_read_skb, 71162306a36Sopenharmony_ci .peek_len = tcp_peek_len, 71262306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 71362306a36Sopenharmony_ci .compat_ioctl = inet6_compat_ioctl, 71462306a36Sopenharmony_ci#endif 71562306a36Sopenharmony_ci .set_rcvlowat = tcp_set_rcvlowat, 71662306a36Sopenharmony_ci}; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ciconst struct proto_ops inet6_dgram_ops = { 71962306a36Sopenharmony_ci .family = PF_INET6, 72062306a36Sopenharmony_ci .owner = THIS_MODULE, 72162306a36Sopenharmony_ci .release = inet6_release, 72262306a36Sopenharmony_ci .bind = inet6_bind, 72362306a36Sopenharmony_ci .connect = inet_dgram_connect, /* ok */ 72462306a36Sopenharmony_ci .socketpair = sock_no_socketpair, /* a do nothing */ 72562306a36Sopenharmony_ci .accept = sock_no_accept, /* a do nothing */ 72662306a36Sopenharmony_ci .getname = inet6_getname, 72762306a36Sopenharmony_ci .poll = udp_poll, /* ok */ 72862306a36Sopenharmony_ci .ioctl = inet6_ioctl, /* must change */ 72962306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 73062306a36Sopenharmony_ci .listen = sock_no_listen, /* ok */ 73162306a36Sopenharmony_ci .shutdown = inet_shutdown, /* ok */ 73262306a36Sopenharmony_ci .setsockopt = sock_common_setsockopt, /* ok */ 73362306a36Sopenharmony_ci .getsockopt = sock_common_getsockopt, /* ok */ 73462306a36Sopenharmony_ci .sendmsg = inet6_sendmsg, /* retpoline's sake */ 73562306a36Sopenharmony_ci .recvmsg = inet6_recvmsg, /* retpoline's sake */ 73662306a36Sopenharmony_ci .read_skb = udp_read_skb, 73762306a36Sopenharmony_ci .mmap = sock_no_mmap, 73862306a36Sopenharmony_ci .set_peek_off = sk_set_peek_off, 73962306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 74062306a36Sopenharmony_ci .compat_ioctl = inet6_compat_ioctl, 74162306a36Sopenharmony_ci#endif 74262306a36Sopenharmony_ci}; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic const struct net_proto_family inet6_family_ops = { 74562306a36Sopenharmony_ci .family = PF_INET6, 74662306a36Sopenharmony_ci .create = inet6_create, 74762306a36Sopenharmony_ci .owner = THIS_MODULE, 74862306a36Sopenharmony_ci}; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ciint inet6_register_protosw(struct inet_protosw *p) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct list_head *lh; 75362306a36Sopenharmony_ci struct inet_protosw *answer; 75462306a36Sopenharmony_ci struct list_head *last_perm; 75562306a36Sopenharmony_ci int protocol = p->protocol; 75662306a36Sopenharmony_ci int ret; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci spin_lock_bh(&inetsw6_lock); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci ret = -EINVAL; 76162306a36Sopenharmony_ci if (p->type >= SOCK_MAX) 76262306a36Sopenharmony_ci goto out_illegal; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* If we are trying to override a permanent protocol, bail. */ 76562306a36Sopenharmony_ci answer = NULL; 76662306a36Sopenharmony_ci ret = -EPERM; 76762306a36Sopenharmony_ci last_perm = &inetsw6[p->type]; 76862306a36Sopenharmony_ci list_for_each(lh, &inetsw6[p->type]) { 76962306a36Sopenharmony_ci answer = list_entry(lh, struct inet_protosw, list); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci /* Check only the non-wild match. */ 77262306a36Sopenharmony_ci if (INET_PROTOSW_PERMANENT & answer->flags) { 77362306a36Sopenharmony_ci if (protocol == answer->protocol) 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci last_perm = lh; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci answer = NULL; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci if (answer) 78162306a36Sopenharmony_ci goto out_permanent; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* Add the new entry after the last permanent entry if any, so that 78462306a36Sopenharmony_ci * the new entry does not override a permanent entry when matched with 78562306a36Sopenharmony_ci * a wild-card protocol. But it is allowed to override any existing 78662306a36Sopenharmony_ci * non-permanent entry. This means that when we remove this entry, the 78762306a36Sopenharmony_ci * system automatically returns to the old behavior. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_ci list_add_rcu(&p->list, last_perm); 79062306a36Sopenharmony_ci ret = 0; 79162306a36Sopenharmony_ciout: 79262306a36Sopenharmony_ci spin_unlock_bh(&inetsw6_lock); 79362306a36Sopenharmony_ci return ret; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ciout_permanent: 79662306a36Sopenharmony_ci pr_err("Attempt to override permanent protocol %d\n", protocol); 79762306a36Sopenharmony_ci goto out; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ciout_illegal: 80062306a36Sopenharmony_ci pr_err("Ignoring attempt to register invalid socket type %d\n", 80162306a36Sopenharmony_ci p->type); 80262306a36Sopenharmony_ci goto out; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_register_protosw); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_civoid 80762306a36Sopenharmony_ciinet6_unregister_protosw(struct inet_protosw *p) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci if (INET_PROTOSW_PERMANENT & p->flags) { 81062306a36Sopenharmony_ci pr_err("Attempt to unregister permanent protocol %d\n", 81162306a36Sopenharmony_ci p->protocol); 81262306a36Sopenharmony_ci } else { 81362306a36Sopenharmony_ci spin_lock_bh(&inetsw6_lock); 81462306a36Sopenharmony_ci list_del_rcu(&p->list); 81562306a36Sopenharmony_ci spin_unlock_bh(&inetsw6_lock); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci synchronize_net(); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_unregister_protosw); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ciint inet6_sk_rebuild_header(struct sock *sk) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct ipv6_pinfo *np = inet6_sk(sk); 82562306a36Sopenharmony_ci struct dst_entry *dst; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci dst = __sk_dst_check(sk, np->dst_cookie); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (!dst) { 83062306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 83162306a36Sopenharmony_ci struct in6_addr *final_p, final; 83262306a36Sopenharmony_ci struct flowi6 fl6; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci memset(&fl6, 0, sizeof(fl6)); 83562306a36Sopenharmony_ci fl6.flowi6_proto = sk->sk_protocol; 83662306a36Sopenharmony_ci fl6.daddr = sk->sk_v6_daddr; 83762306a36Sopenharmony_ci fl6.saddr = np->saddr; 83862306a36Sopenharmony_ci fl6.flowlabel = np->flow_label; 83962306a36Sopenharmony_ci fl6.flowi6_oif = sk->sk_bound_dev_if; 84062306a36Sopenharmony_ci fl6.flowi6_mark = sk->sk_mark; 84162306a36Sopenharmony_ci fl6.fl6_dport = inet->inet_dport; 84262306a36Sopenharmony_ci fl6.fl6_sport = inet->inet_sport; 84362306a36Sopenharmony_ci fl6.flowi6_uid = sk->sk_uid; 84462306a36Sopenharmony_ci security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci rcu_read_lock(); 84762306a36Sopenharmony_ci final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), 84862306a36Sopenharmony_ci &final); 84962306a36Sopenharmony_ci rcu_read_unlock(); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p); 85262306a36Sopenharmony_ci if (IS_ERR(dst)) { 85362306a36Sopenharmony_ci sk->sk_route_caps = 0; 85462306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err_soft, -PTR_ERR(dst)); 85562306a36Sopenharmony_ci return PTR_ERR(dst); 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci ip6_dst_store(sk, dst, NULL, NULL); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return 0; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(inet6_sk_rebuild_header); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cibool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, 86662306a36Sopenharmony_ci const struct inet6_skb_parm *opt) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci const struct ipv6_pinfo *np = inet6_sk(sk); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (np->rxopt.all) { 87162306a36Sopenharmony_ci if (((opt->flags & IP6SKB_HOPBYHOP) && 87262306a36Sopenharmony_ci (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) || 87362306a36Sopenharmony_ci (ip6_flowinfo((struct ipv6hdr *) skb_network_header(skb)) && 87462306a36Sopenharmony_ci np->rxopt.bits.rxflow) || 87562306a36Sopenharmony_ci (opt->srcrt && (np->rxopt.bits.srcrt || 87662306a36Sopenharmony_ci np->rxopt.bits.osrcrt)) || 87762306a36Sopenharmony_ci ((opt->dst1 || opt->dst0) && 87862306a36Sopenharmony_ci (np->rxopt.bits.dstopts || np->rxopt.bits.odstopts))) 87962306a36Sopenharmony_ci return true; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci return false; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipv6_opt_accepted); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic struct packet_type ipv6_packet_type __read_mostly = { 88662306a36Sopenharmony_ci .type = cpu_to_be16(ETH_P_IPV6), 88762306a36Sopenharmony_ci .func = ipv6_rcv, 88862306a36Sopenharmony_ci .list_func = ipv6_list_rcv, 88962306a36Sopenharmony_ci}; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int __init ipv6_packet_init(void) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci dev_add_pack(&ipv6_packet_type); 89462306a36Sopenharmony_ci return 0; 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic void ipv6_packet_cleanup(void) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci dev_remove_pack(&ipv6_packet_type); 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic int __net_init ipv6_init_mibs(struct net *net) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci int i; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci net->mib.udp_stats_in6 = alloc_percpu(struct udp_mib); 90762306a36Sopenharmony_ci if (!net->mib.udp_stats_in6) 90862306a36Sopenharmony_ci return -ENOMEM; 90962306a36Sopenharmony_ci net->mib.udplite_stats_in6 = alloc_percpu(struct udp_mib); 91062306a36Sopenharmony_ci if (!net->mib.udplite_stats_in6) 91162306a36Sopenharmony_ci goto err_udplite_mib; 91262306a36Sopenharmony_ci net->mib.ipv6_statistics = alloc_percpu(struct ipstats_mib); 91362306a36Sopenharmony_ci if (!net->mib.ipv6_statistics) 91462306a36Sopenharmony_ci goto err_ip_mib; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci for_each_possible_cpu(i) { 91762306a36Sopenharmony_ci struct ipstats_mib *af_inet6_stats; 91862306a36Sopenharmony_ci af_inet6_stats = per_cpu_ptr(net->mib.ipv6_statistics, i); 91962306a36Sopenharmony_ci u64_stats_init(&af_inet6_stats->syncp); 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci net->mib.icmpv6_statistics = alloc_percpu(struct icmpv6_mib); 92462306a36Sopenharmony_ci if (!net->mib.icmpv6_statistics) 92562306a36Sopenharmony_ci goto err_icmp_mib; 92662306a36Sopenharmony_ci net->mib.icmpv6msg_statistics = kzalloc(sizeof(struct icmpv6msg_mib), 92762306a36Sopenharmony_ci GFP_KERNEL); 92862306a36Sopenharmony_ci if (!net->mib.icmpv6msg_statistics) 92962306a36Sopenharmony_ci goto err_icmpmsg_mib; 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cierr_icmpmsg_mib: 93362306a36Sopenharmony_ci free_percpu(net->mib.icmpv6_statistics); 93462306a36Sopenharmony_cierr_icmp_mib: 93562306a36Sopenharmony_ci free_percpu(net->mib.ipv6_statistics); 93662306a36Sopenharmony_cierr_ip_mib: 93762306a36Sopenharmony_ci free_percpu(net->mib.udplite_stats_in6); 93862306a36Sopenharmony_cierr_udplite_mib: 93962306a36Sopenharmony_ci free_percpu(net->mib.udp_stats_in6); 94062306a36Sopenharmony_ci return -ENOMEM; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic void ipv6_cleanup_mibs(struct net *net) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci free_percpu(net->mib.udp_stats_in6); 94662306a36Sopenharmony_ci free_percpu(net->mib.udplite_stats_in6); 94762306a36Sopenharmony_ci free_percpu(net->mib.ipv6_statistics); 94862306a36Sopenharmony_ci free_percpu(net->mib.icmpv6_statistics); 94962306a36Sopenharmony_ci kfree(net->mib.icmpv6msg_statistics); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistatic int __net_init inet6_net_init(struct net *net) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci int err = 0; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci net->ipv6.sysctl.bindv6only = 0; 95762306a36Sopenharmony_ci net->ipv6.sysctl.icmpv6_time = 1*HZ; 95862306a36Sopenharmony_ci net->ipv6.sysctl.icmpv6_echo_ignore_all = 0; 95962306a36Sopenharmony_ci net->ipv6.sysctl.icmpv6_echo_ignore_multicast = 0; 96062306a36Sopenharmony_ci net->ipv6.sysctl.icmpv6_echo_ignore_anycast = 0; 96162306a36Sopenharmony_ci net->ipv6.sysctl.icmpv6_error_anycast_as_unicast = 0; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* By default, rate limit error messages. 96462306a36Sopenharmony_ci * Except for pmtu discovery, it would break it. 96562306a36Sopenharmony_ci * proc_do_large_bitmap needs pointer to the bitmap. 96662306a36Sopenharmony_ci */ 96762306a36Sopenharmony_ci bitmap_set(net->ipv6.sysctl.icmpv6_ratemask, 0, ICMPV6_ERRMSG_MAX + 1); 96862306a36Sopenharmony_ci bitmap_clear(net->ipv6.sysctl.icmpv6_ratemask, ICMPV6_PKT_TOOBIG, 1); 96962306a36Sopenharmony_ci net->ipv6.sysctl.icmpv6_ratemask_ptr = net->ipv6.sysctl.icmpv6_ratemask; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci net->ipv6.sysctl.flowlabel_consistency = 1; 97262306a36Sopenharmony_ci net->ipv6.sysctl.auto_flowlabels = IP6_DEFAULT_AUTO_FLOW_LABELS; 97362306a36Sopenharmony_ci net->ipv6.sysctl.idgen_retries = 3; 97462306a36Sopenharmony_ci net->ipv6.sysctl.idgen_delay = 1 * HZ; 97562306a36Sopenharmony_ci net->ipv6.sysctl.flowlabel_state_ranges = 0; 97662306a36Sopenharmony_ci net->ipv6.sysctl.max_dst_opts_cnt = IP6_DEFAULT_MAX_DST_OPTS_CNT; 97762306a36Sopenharmony_ci net->ipv6.sysctl.max_hbh_opts_cnt = IP6_DEFAULT_MAX_HBH_OPTS_CNT; 97862306a36Sopenharmony_ci net->ipv6.sysctl.max_dst_opts_len = IP6_DEFAULT_MAX_DST_OPTS_LEN; 97962306a36Sopenharmony_ci net->ipv6.sysctl.max_hbh_opts_len = IP6_DEFAULT_MAX_HBH_OPTS_LEN; 98062306a36Sopenharmony_ci net->ipv6.sysctl.fib_notify_on_flag_change = 0; 98162306a36Sopenharmony_ci atomic_set(&net->ipv6.fib6_sernum, 1); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci net->ipv6.sysctl.ioam6_id = IOAM6_DEFAULT_ID; 98462306a36Sopenharmony_ci net->ipv6.sysctl.ioam6_id_wide = IOAM6_DEFAULT_ID_WIDE; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci err = ipv6_init_mibs(net); 98762306a36Sopenharmony_ci if (err) 98862306a36Sopenharmony_ci return err; 98962306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 99062306a36Sopenharmony_ci err = udp6_proc_init(net); 99162306a36Sopenharmony_ci if (err) 99262306a36Sopenharmony_ci goto out; 99362306a36Sopenharmony_ci err = tcp6_proc_init(net); 99462306a36Sopenharmony_ci if (err) 99562306a36Sopenharmony_ci goto proc_tcp6_fail; 99662306a36Sopenharmony_ci err = ac6_proc_init(net); 99762306a36Sopenharmony_ci if (err) 99862306a36Sopenharmony_ci goto proc_ac6_fail; 99962306a36Sopenharmony_ci#endif 100062306a36Sopenharmony_ci return err; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 100362306a36Sopenharmony_ciproc_ac6_fail: 100462306a36Sopenharmony_ci tcp6_proc_exit(net); 100562306a36Sopenharmony_ciproc_tcp6_fail: 100662306a36Sopenharmony_ci udp6_proc_exit(net); 100762306a36Sopenharmony_ciout: 100862306a36Sopenharmony_ci ipv6_cleanup_mibs(net); 100962306a36Sopenharmony_ci return err; 101062306a36Sopenharmony_ci#endif 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic void __net_exit inet6_net_exit(struct net *net) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 101662306a36Sopenharmony_ci udp6_proc_exit(net); 101762306a36Sopenharmony_ci tcp6_proc_exit(net); 101862306a36Sopenharmony_ci ac6_proc_exit(net); 101962306a36Sopenharmony_ci#endif 102062306a36Sopenharmony_ci ipv6_cleanup_mibs(net); 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic struct pernet_operations inet6_net_ops = { 102462306a36Sopenharmony_ci .init = inet6_net_init, 102562306a36Sopenharmony_ci .exit = inet6_net_exit, 102662306a36Sopenharmony_ci}; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int ipv6_route_input(struct sk_buff *skb) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci ip6_route_input(skb); 103162306a36Sopenharmony_ci return skb_dst(skb)->error; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic const struct ipv6_stub ipv6_stub_impl = { 103562306a36Sopenharmony_ci .ipv6_sock_mc_join = ipv6_sock_mc_join, 103662306a36Sopenharmony_ci .ipv6_sock_mc_drop = ipv6_sock_mc_drop, 103762306a36Sopenharmony_ci .ipv6_dst_lookup_flow = ip6_dst_lookup_flow, 103862306a36Sopenharmony_ci .ipv6_route_input = ipv6_route_input, 103962306a36Sopenharmony_ci .fib6_get_table = fib6_get_table, 104062306a36Sopenharmony_ci .fib6_table_lookup = fib6_table_lookup, 104162306a36Sopenharmony_ci .fib6_lookup = fib6_lookup, 104262306a36Sopenharmony_ci .fib6_select_path = fib6_select_path, 104362306a36Sopenharmony_ci .ip6_mtu_from_fib6 = ip6_mtu_from_fib6, 104462306a36Sopenharmony_ci .fib6_nh_init = fib6_nh_init, 104562306a36Sopenharmony_ci .fib6_nh_release = fib6_nh_release, 104662306a36Sopenharmony_ci .fib6_nh_release_dsts = fib6_nh_release_dsts, 104762306a36Sopenharmony_ci .fib6_update_sernum = fib6_update_sernum_stub, 104862306a36Sopenharmony_ci .fib6_rt_update = fib6_rt_update, 104962306a36Sopenharmony_ci .ip6_del_rt = ip6_del_rt, 105062306a36Sopenharmony_ci .udpv6_encap_enable = udpv6_encap_enable, 105162306a36Sopenharmony_ci .ndisc_send_na = ndisc_send_na, 105262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_XFRM) 105362306a36Sopenharmony_ci .xfrm6_local_rxpmtu = xfrm6_local_rxpmtu, 105462306a36Sopenharmony_ci .xfrm6_udp_encap_rcv = xfrm6_udp_encap_rcv, 105562306a36Sopenharmony_ci .xfrm6_rcv_encap = xfrm6_rcv_encap, 105662306a36Sopenharmony_ci#endif 105762306a36Sopenharmony_ci .nd_tbl = &nd_tbl, 105862306a36Sopenharmony_ci .ipv6_fragment = ip6_fragment, 105962306a36Sopenharmony_ci .ipv6_dev_find = ipv6_dev_find, 106062306a36Sopenharmony_ci}; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic const struct ipv6_bpf_stub ipv6_bpf_stub_impl = { 106362306a36Sopenharmony_ci .inet6_bind = __inet6_bind, 106462306a36Sopenharmony_ci .udp6_lib_lookup = __udp6_lib_lookup, 106562306a36Sopenharmony_ci .ipv6_setsockopt = do_ipv6_setsockopt, 106662306a36Sopenharmony_ci .ipv6_getsockopt = do_ipv6_getsockopt, 106762306a36Sopenharmony_ci .ipv6_dev_get_saddr = ipv6_dev_get_saddr, 106862306a36Sopenharmony_ci}; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic int __init inet6_init(void) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci struct list_head *r; 107362306a36Sopenharmony_ci int err = 0; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci sock_skb_cb_check_size(sizeof(struct inet6_skb_parm)); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* Register the socket-side information for inet6_create. */ 107862306a36Sopenharmony_ci for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) 107962306a36Sopenharmony_ci INIT_LIST_HEAD(r); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci raw_hashinfo_init(&raw_v6_hashinfo); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (disable_ipv6_mod) { 108462306a36Sopenharmony_ci pr_info("Loaded, but administratively disabled, reboot required to enable\n"); 108562306a36Sopenharmony_ci goto out; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci err = proto_register(&tcpv6_prot, 1); 108962306a36Sopenharmony_ci if (err) 109062306a36Sopenharmony_ci goto out; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci err = proto_register(&udpv6_prot, 1); 109362306a36Sopenharmony_ci if (err) 109462306a36Sopenharmony_ci goto out_unregister_tcp_proto; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci err = proto_register(&udplitev6_prot, 1); 109762306a36Sopenharmony_ci if (err) 109862306a36Sopenharmony_ci goto out_unregister_udp_proto; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci err = proto_register(&rawv6_prot, 1); 110162306a36Sopenharmony_ci if (err) 110262306a36Sopenharmony_ci goto out_unregister_udplite_proto; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci err = proto_register(&pingv6_prot, 1); 110562306a36Sopenharmony_ci if (err) 110662306a36Sopenharmony_ci goto out_unregister_raw_proto; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci /* We MUST register RAW sockets before we create the ICMP6, 110962306a36Sopenharmony_ci * IGMP6, or NDISC control sockets. 111062306a36Sopenharmony_ci */ 111162306a36Sopenharmony_ci err = rawv6_init(); 111262306a36Sopenharmony_ci if (err) 111362306a36Sopenharmony_ci goto out_unregister_ping_proto; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* Register the family here so that the init calls below will 111662306a36Sopenharmony_ci * be able to create sockets. (?? is this dangerous ??) 111762306a36Sopenharmony_ci */ 111862306a36Sopenharmony_ci err = sock_register(&inet6_family_ops); 111962306a36Sopenharmony_ci if (err) 112062306a36Sopenharmony_ci goto out_sock_register_fail; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* 112362306a36Sopenharmony_ci * ipngwg API draft makes clear that the correct semantics 112462306a36Sopenharmony_ci * for TCP and UDP is to consider one TCP and UDP instance 112562306a36Sopenharmony_ci * in a host available by both INET and INET6 APIs and 112662306a36Sopenharmony_ci * able to communicate via both network protocols. 112762306a36Sopenharmony_ci */ 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci err = register_pernet_subsys(&inet6_net_ops); 113062306a36Sopenharmony_ci if (err) 113162306a36Sopenharmony_ci goto register_pernet_fail; 113262306a36Sopenharmony_ci err = ip6_mr_init(); 113362306a36Sopenharmony_ci if (err) 113462306a36Sopenharmony_ci goto ipmr_fail; 113562306a36Sopenharmony_ci err = icmpv6_init(); 113662306a36Sopenharmony_ci if (err) 113762306a36Sopenharmony_ci goto icmp_fail; 113862306a36Sopenharmony_ci err = ndisc_init(); 113962306a36Sopenharmony_ci if (err) 114062306a36Sopenharmony_ci goto ndisc_fail; 114162306a36Sopenharmony_ci err = igmp6_init(); 114262306a36Sopenharmony_ci if (err) 114362306a36Sopenharmony_ci goto igmp_fail; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci err = ipv6_netfilter_init(); 114662306a36Sopenharmony_ci if (err) 114762306a36Sopenharmony_ci goto netfilter_fail; 114862306a36Sopenharmony_ci /* Create /proc/foo6 entries. */ 114962306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 115062306a36Sopenharmony_ci err = -ENOMEM; 115162306a36Sopenharmony_ci if (raw6_proc_init()) 115262306a36Sopenharmony_ci goto proc_raw6_fail; 115362306a36Sopenharmony_ci if (udplite6_proc_init()) 115462306a36Sopenharmony_ci goto proc_udplite6_fail; 115562306a36Sopenharmony_ci if (ipv6_misc_proc_init()) 115662306a36Sopenharmony_ci goto proc_misc6_fail; 115762306a36Sopenharmony_ci if (if6_proc_init()) 115862306a36Sopenharmony_ci goto proc_if6_fail; 115962306a36Sopenharmony_ci#endif 116062306a36Sopenharmony_ci err = ip6_route_init(); 116162306a36Sopenharmony_ci if (err) 116262306a36Sopenharmony_ci goto ip6_route_fail; 116362306a36Sopenharmony_ci err = ndisc_late_init(); 116462306a36Sopenharmony_ci if (err) 116562306a36Sopenharmony_ci goto ndisc_late_fail; 116662306a36Sopenharmony_ci err = ip6_flowlabel_init(); 116762306a36Sopenharmony_ci if (err) 116862306a36Sopenharmony_ci goto ip6_flowlabel_fail; 116962306a36Sopenharmony_ci err = ipv6_anycast_init(); 117062306a36Sopenharmony_ci if (err) 117162306a36Sopenharmony_ci goto ipv6_anycast_fail; 117262306a36Sopenharmony_ci err = addrconf_init(); 117362306a36Sopenharmony_ci if (err) 117462306a36Sopenharmony_ci goto addrconf_fail; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* Init v6 extension headers. */ 117762306a36Sopenharmony_ci err = ipv6_exthdrs_init(); 117862306a36Sopenharmony_ci if (err) 117962306a36Sopenharmony_ci goto ipv6_exthdrs_fail; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci err = ipv6_frag_init(); 118262306a36Sopenharmony_ci if (err) 118362306a36Sopenharmony_ci goto ipv6_frag_fail; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* Init v6 transport protocols. */ 118662306a36Sopenharmony_ci err = udpv6_init(); 118762306a36Sopenharmony_ci if (err) 118862306a36Sopenharmony_ci goto udpv6_fail; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci err = udplitev6_init(); 119162306a36Sopenharmony_ci if (err) 119262306a36Sopenharmony_ci goto udplitev6_fail; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci err = udpv6_offload_init(); 119562306a36Sopenharmony_ci if (err) 119662306a36Sopenharmony_ci goto udpv6_offload_fail; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci err = tcpv6_init(); 119962306a36Sopenharmony_ci if (err) 120062306a36Sopenharmony_ci goto tcpv6_fail; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci err = ipv6_packet_init(); 120362306a36Sopenharmony_ci if (err) 120462306a36Sopenharmony_ci goto ipv6_packet_fail; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci err = pingv6_init(); 120762306a36Sopenharmony_ci if (err) 120862306a36Sopenharmony_ci goto pingv6_fail; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci err = calipso_init(); 121162306a36Sopenharmony_ci if (err) 121262306a36Sopenharmony_ci goto calipso_fail; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci err = seg6_init(); 121562306a36Sopenharmony_ci if (err) 121662306a36Sopenharmony_ci goto seg6_fail; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci err = rpl_init(); 121962306a36Sopenharmony_ci if (err) 122062306a36Sopenharmony_ci goto rpl_fail; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci err = ioam6_init(); 122362306a36Sopenharmony_ci if (err) 122462306a36Sopenharmony_ci goto ioam6_fail; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci err = igmp6_late_init(); 122762306a36Sopenharmony_ci if (err) 122862306a36Sopenharmony_ci goto igmp6_late_err; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 123162306a36Sopenharmony_ci err = ipv6_sysctl_register(); 123262306a36Sopenharmony_ci if (err) 123362306a36Sopenharmony_ci goto sysctl_fail; 123462306a36Sopenharmony_ci#endif 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* ensure that ipv6 stubs are visible only after ipv6 is ready */ 123762306a36Sopenharmony_ci wmb(); 123862306a36Sopenharmony_ci ipv6_stub = &ipv6_stub_impl; 123962306a36Sopenharmony_ci ipv6_bpf_stub = &ipv6_bpf_stub_impl; 124062306a36Sopenharmony_ciout: 124162306a36Sopenharmony_ci return err; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 124462306a36Sopenharmony_cisysctl_fail: 124562306a36Sopenharmony_ci igmp6_late_cleanup(); 124662306a36Sopenharmony_ci#endif 124762306a36Sopenharmony_ciigmp6_late_err: 124862306a36Sopenharmony_ci ioam6_exit(); 124962306a36Sopenharmony_ciioam6_fail: 125062306a36Sopenharmony_ci rpl_exit(); 125162306a36Sopenharmony_cirpl_fail: 125262306a36Sopenharmony_ci seg6_exit(); 125362306a36Sopenharmony_ciseg6_fail: 125462306a36Sopenharmony_ci calipso_exit(); 125562306a36Sopenharmony_cicalipso_fail: 125662306a36Sopenharmony_ci pingv6_exit(); 125762306a36Sopenharmony_cipingv6_fail: 125862306a36Sopenharmony_ci ipv6_packet_cleanup(); 125962306a36Sopenharmony_ciipv6_packet_fail: 126062306a36Sopenharmony_ci tcpv6_exit(); 126162306a36Sopenharmony_citcpv6_fail: 126262306a36Sopenharmony_ci udpv6_offload_exit(); 126362306a36Sopenharmony_ciudpv6_offload_fail: 126462306a36Sopenharmony_ci udplitev6_exit(); 126562306a36Sopenharmony_ciudplitev6_fail: 126662306a36Sopenharmony_ci udpv6_exit(); 126762306a36Sopenharmony_ciudpv6_fail: 126862306a36Sopenharmony_ci ipv6_frag_exit(); 126962306a36Sopenharmony_ciipv6_frag_fail: 127062306a36Sopenharmony_ci ipv6_exthdrs_exit(); 127162306a36Sopenharmony_ciipv6_exthdrs_fail: 127262306a36Sopenharmony_ci addrconf_cleanup(); 127362306a36Sopenharmony_ciaddrconf_fail: 127462306a36Sopenharmony_ci ipv6_anycast_cleanup(); 127562306a36Sopenharmony_ciipv6_anycast_fail: 127662306a36Sopenharmony_ci ip6_flowlabel_cleanup(); 127762306a36Sopenharmony_ciip6_flowlabel_fail: 127862306a36Sopenharmony_ci ndisc_late_cleanup(); 127962306a36Sopenharmony_cindisc_late_fail: 128062306a36Sopenharmony_ci ip6_route_cleanup(); 128162306a36Sopenharmony_ciip6_route_fail: 128262306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 128362306a36Sopenharmony_ci if6_proc_exit(); 128462306a36Sopenharmony_ciproc_if6_fail: 128562306a36Sopenharmony_ci ipv6_misc_proc_exit(); 128662306a36Sopenharmony_ciproc_misc6_fail: 128762306a36Sopenharmony_ci udplite6_proc_exit(); 128862306a36Sopenharmony_ciproc_udplite6_fail: 128962306a36Sopenharmony_ci raw6_proc_exit(); 129062306a36Sopenharmony_ciproc_raw6_fail: 129162306a36Sopenharmony_ci#endif 129262306a36Sopenharmony_ci ipv6_netfilter_fini(); 129362306a36Sopenharmony_cinetfilter_fail: 129462306a36Sopenharmony_ci igmp6_cleanup(); 129562306a36Sopenharmony_ciigmp_fail: 129662306a36Sopenharmony_ci ndisc_cleanup(); 129762306a36Sopenharmony_cindisc_fail: 129862306a36Sopenharmony_ci icmpv6_cleanup(); 129962306a36Sopenharmony_ciicmp_fail: 130062306a36Sopenharmony_ci ip6_mr_cleanup(); 130162306a36Sopenharmony_ciipmr_fail: 130262306a36Sopenharmony_ci unregister_pernet_subsys(&inet6_net_ops); 130362306a36Sopenharmony_ciregister_pernet_fail: 130462306a36Sopenharmony_ci sock_unregister(PF_INET6); 130562306a36Sopenharmony_ci rtnl_unregister_all(PF_INET6); 130662306a36Sopenharmony_ciout_sock_register_fail: 130762306a36Sopenharmony_ci rawv6_exit(); 130862306a36Sopenharmony_ciout_unregister_ping_proto: 130962306a36Sopenharmony_ci proto_unregister(&pingv6_prot); 131062306a36Sopenharmony_ciout_unregister_raw_proto: 131162306a36Sopenharmony_ci proto_unregister(&rawv6_prot); 131262306a36Sopenharmony_ciout_unregister_udplite_proto: 131362306a36Sopenharmony_ci proto_unregister(&udplitev6_prot); 131462306a36Sopenharmony_ciout_unregister_udp_proto: 131562306a36Sopenharmony_ci proto_unregister(&udpv6_prot); 131662306a36Sopenharmony_ciout_unregister_tcp_proto: 131762306a36Sopenharmony_ci proto_unregister(&tcpv6_prot); 131862306a36Sopenharmony_ci goto out; 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_cimodule_init(inet6_init); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_INET6); 1323