18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 48c2ecf20Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 58c2ecf20Sopenharmony_ci * interface as the means of communication with the user level. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * PF_INET protocol family socket handler. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Authors: Ross Biro 108c2ecf20Sopenharmony_ci * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 118c2ecf20Sopenharmony_ci * Florian La Roche, <flla@stud.uni-sb.de> 128c2ecf20Sopenharmony_ci * Alan Cox, <A.Cox@swansea.ac.uk> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Changes (see also sock.c) 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * piggy, 178c2ecf20Sopenharmony_ci * Karl Knutson : Socket protocol table 188c2ecf20Sopenharmony_ci * A.N.Kuznetsov : Socket death error in accept(). 198c2ecf20Sopenharmony_ci * John Richardson : Fix non blocking error in connect() 208c2ecf20Sopenharmony_ci * so sockets that fail to connect 218c2ecf20Sopenharmony_ci * don't return -EINPROGRESS. 228c2ecf20Sopenharmony_ci * Alan Cox : Asynchronous I/O support 238c2ecf20Sopenharmony_ci * Alan Cox : Keep correct socket pointer on sock 248c2ecf20Sopenharmony_ci * structures 258c2ecf20Sopenharmony_ci * when accept() ed 268c2ecf20Sopenharmony_ci * Alan Cox : Semantics of SO_LINGER aren't state 278c2ecf20Sopenharmony_ci * moved to close when you look carefully. 288c2ecf20Sopenharmony_ci * With this fixed and the accept bug fixed 298c2ecf20Sopenharmony_ci * some RPC stuff seems happier. 308c2ecf20Sopenharmony_ci * Niibe Yutaka : 4.4BSD style write async I/O 318c2ecf20Sopenharmony_ci * Alan Cox, 328c2ecf20Sopenharmony_ci * Tony Gale : Fixed reuse semantics. 338c2ecf20Sopenharmony_ci * Alan Cox : bind() shouldn't abort existing but dead 348c2ecf20Sopenharmony_ci * sockets. Stops FTP netin:.. I hope. 358c2ecf20Sopenharmony_ci * Alan Cox : bind() works correctly for RAW sockets. 368c2ecf20Sopenharmony_ci * Note that FreeBSD at least was broken 378c2ecf20Sopenharmony_ci * in this respect so be careful with 388c2ecf20Sopenharmony_ci * compatibility tests... 398c2ecf20Sopenharmony_ci * Alan Cox : routing cache support 408c2ecf20Sopenharmony_ci * Alan Cox : memzero the socket structure for 418c2ecf20Sopenharmony_ci * compactness. 428c2ecf20Sopenharmony_ci * Matt Day : nonblock connect error handler 438c2ecf20Sopenharmony_ci * Alan Cox : Allow large numbers of pending sockets 448c2ecf20Sopenharmony_ci * (eg for big web sites), but only if 458c2ecf20Sopenharmony_ci * specifically application requested. 468c2ecf20Sopenharmony_ci * Alan Cox : New buffering throughout IP. Used 478c2ecf20Sopenharmony_ci * dumbly. 488c2ecf20Sopenharmony_ci * Alan Cox : New buffering now used smartly. 498c2ecf20Sopenharmony_ci * Alan Cox : BSD rather than common sense 508c2ecf20Sopenharmony_ci * interpretation of listen. 518c2ecf20Sopenharmony_ci * Germano Caronni : Assorted small races. 528c2ecf20Sopenharmony_ci * Alan Cox : sendmsg/recvmsg basic support. 538c2ecf20Sopenharmony_ci * Alan Cox : Only sendmsg/recvmsg now supported. 548c2ecf20Sopenharmony_ci * Alan Cox : Locked down bind (see security list). 558c2ecf20Sopenharmony_ci * Alan Cox : Loosened bind a little. 568c2ecf20Sopenharmony_ci * Mike McLagan : ADD/DEL DLCI Ioctls 578c2ecf20Sopenharmony_ci * Willy Konynenberg : Transparent proxying support. 588c2ecf20Sopenharmony_ci * David S. Miller : New socket lookup architecture. 598c2ecf20Sopenharmony_ci * Some other random speedups. 608c2ecf20Sopenharmony_ci * Cyrus Durgin : Cleaned up file for kmod hacks. 618c2ecf20Sopenharmony_ci * Andi Kleen : Fix inet_stream_connect TCP race. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "IPv4: " fmt 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#include <linux/err.h> 678c2ecf20Sopenharmony_ci#include <linux/errno.h> 688c2ecf20Sopenharmony_ci#include <linux/types.h> 698c2ecf20Sopenharmony_ci#include <linux/socket.h> 708c2ecf20Sopenharmony_ci#include <linux/in.h> 718c2ecf20Sopenharmony_ci#include <linux/kernel.h> 728c2ecf20Sopenharmony_ci#include <linux/kmod.h> 738c2ecf20Sopenharmony_ci#include <linux/sched.h> 748c2ecf20Sopenharmony_ci#include <linux/timer.h> 758c2ecf20Sopenharmony_ci#include <linux/string.h> 768c2ecf20Sopenharmony_ci#include <linux/sockios.h> 778c2ecf20Sopenharmony_ci#include <linux/net.h> 788c2ecf20Sopenharmony_ci#include <linux/capability.h> 798c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 808c2ecf20Sopenharmony_ci#include <linux/mm.h> 818c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 828c2ecf20Sopenharmony_ci#include <linux/stat.h> 838c2ecf20Sopenharmony_ci#include <linux/init.h> 848c2ecf20Sopenharmony_ci#include <linux/poll.h> 858c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv4.h> 868c2ecf20Sopenharmony_ci#include <linux/random.h> 878c2ecf20Sopenharmony_ci#include <linux/slab.h> 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#include <linux/inet.h> 928c2ecf20Sopenharmony_ci#include <linux/igmp.h> 938c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 948c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 958c2ecf20Sopenharmony_ci#include <net/checksum.h> 968c2ecf20Sopenharmony_ci#include <net/ip.h> 978c2ecf20Sopenharmony_ci#include <net/protocol.h> 988c2ecf20Sopenharmony_ci#include <net/arp.h> 998c2ecf20Sopenharmony_ci#include <net/route.h> 1008c2ecf20Sopenharmony_ci#include <net/ip_fib.h> 1018c2ecf20Sopenharmony_ci#include <net/inet_connection_sock.h> 1028c2ecf20Sopenharmony_ci#include <net/tcp.h> 1038c2ecf20Sopenharmony_ci#include <net/udp.h> 1048c2ecf20Sopenharmony_ci#include <net/udplite.h> 1058c2ecf20Sopenharmony_ci#include <net/ping.h> 1068c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 1078c2ecf20Sopenharmony_ci#include <net/sock.h> 1088c2ecf20Sopenharmony_ci#include <net/raw.h> 1098c2ecf20Sopenharmony_ci#include <net/icmp.h> 1108c2ecf20Sopenharmony_ci#include <net/inet_common.h> 1118c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h> 1128c2ecf20Sopenharmony_ci#include <net/xfrm.h> 1138c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 1148c2ecf20Sopenharmony_ci#include <net/secure_seq.h> 1158c2ecf20Sopenharmony_ci#ifdef CONFIG_IP_MROUTE 1168c2ecf20Sopenharmony_ci#include <linux/mroute.h> 1178c2ecf20Sopenharmony_ci#endif 1188c2ecf20Sopenharmony_ci#include <net/l3mdev.h> 1198c2ecf20Sopenharmony_ci#include <net/compat.h> 1208c2ecf20Sopenharmony_ci#ifdef CONFIG_LOWPOWER_PROTOCOL 1218c2ecf20Sopenharmony_ci#include <net/lowpower_protocol.h> 1228c2ecf20Sopenharmony_ci#endif /* CONFIG_LOWPOWER_PROTOCOL */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#include <trace/events/sock.h> 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* The inetsw table contains everything that inet_create needs to 1278c2ecf20Sopenharmony_ci * build a new socket. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_cistatic struct list_head inetsw[SOCK_MAX]; 1308c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(inetsw_lock); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* New destruction routine */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_civoid inet_sock_destruct(struct sock *sk) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci __skb_queue_purge(&sk->sk_receive_queue); 1398c2ecf20Sopenharmony_ci if (sk->sk_rx_skb_cache) { 1408c2ecf20Sopenharmony_ci __kfree_skb(sk->sk_rx_skb_cache); 1418c2ecf20Sopenharmony_ci sk->sk_rx_skb_cache = NULL; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci __skb_queue_purge(&sk->sk_error_queue); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci sk_mem_reclaim(sk); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) { 1488c2ecf20Sopenharmony_ci pr_err("Attempt to release TCP socket in state %d %p\n", 1498c2ecf20Sopenharmony_ci sk->sk_state, sk); 1508c2ecf20Sopenharmony_ci return; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 1538c2ecf20Sopenharmony_ci pr_err("Attempt to release alive inet socket %p\n", sk); 1548c2ecf20Sopenharmony_ci return; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci WARN_ON(atomic_read(&sk->sk_rmem_alloc)); 1588c2ecf20Sopenharmony_ci WARN_ON(refcount_read(&sk->sk_wmem_alloc)); 1598c2ecf20Sopenharmony_ci WARN_ON(sk->sk_wmem_queued); 1608c2ecf20Sopenharmony_ci WARN_ON(sk->sk_forward_alloc); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci kfree(rcu_dereference_protected(inet->inet_opt, 1)); 1638c2ecf20Sopenharmony_ci dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1)); 1648c2ecf20Sopenharmony_ci dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1)); 1658c2ecf20Sopenharmony_ci sk_refcnt_debug_dec(sk); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_sock_destruct); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * The routines beyond this point handle the behaviour of an AF_INET 1718c2ecf20Sopenharmony_ci * socket object. Mostly it punts to the subprotocols of IP to do 1728c2ecf20Sopenharmony_ci * the work. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * Automatically bind an unbound socket. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int inet_autobind(struct sock *sk) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct inet_sock *inet; 1828c2ecf20Sopenharmony_ci /* We may need to bind the socket. */ 1838c2ecf20Sopenharmony_ci lock_sock(sk); 1848c2ecf20Sopenharmony_ci inet = inet_sk(sk); 1858c2ecf20Sopenharmony_ci if (!inet->inet_num) { 1868c2ecf20Sopenharmony_ci if (sk->sk_prot->get_port(sk, 0)) { 1878c2ecf20Sopenharmony_ci release_sock(sk); 1888c2ecf20Sopenharmony_ci return -EAGAIN; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci inet->inet_sport = htons(inet->inet_num); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci release_sock(sk); 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * Move a socket into listening state. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ciint inet_listen(struct socket *sock, int backlog) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 2028c2ecf20Sopenharmony_ci unsigned char old_state; 2038c2ecf20Sopenharmony_ci int err, tcp_fastopen; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci lock_sock(sk); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci err = -EINVAL; 2088c2ecf20Sopenharmony_ci if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) 2098c2ecf20Sopenharmony_ci goto out; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci old_state = sk->sk_state; 2128c2ecf20Sopenharmony_ci if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN))) 2138c2ecf20Sopenharmony_ci goto out; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_max_ack_backlog, backlog); 2168c2ecf20Sopenharmony_ci /* Really, if the socket is already in listen state 2178c2ecf20Sopenharmony_ci * we can only allow the backlog to be adjusted. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci if (old_state != TCP_LISTEN) { 2208c2ecf20Sopenharmony_ci /* Enable TFO w/o requiring TCP_FASTOPEN socket option. 2218c2ecf20Sopenharmony_ci * Note that only TCP sockets (SOCK_STREAM) will reach here. 2228c2ecf20Sopenharmony_ci * Also fastopen backlog may already been set via the option 2238c2ecf20Sopenharmony_ci * because the socket was in TCP_LISTEN state previously but 2248c2ecf20Sopenharmony_ci * was shutdown() rather than close(). 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci tcp_fastopen = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen); 2278c2ecf20Sopenharmony_ci if ((tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) && 2288c2ecf20Sopenharmony_ci (tcp_fastopen & TFO_SERVER_ENABLE) && 2298c2ecf20Sopenharmony_ci !inet_csk(sk)->icsk_accept_queue.fastopenq.max_qlen) { 2308c2ecf20Sopenharmony_ci fastopen_queue_tune(sk, backlog); 2318c2ecf20Sopenharmony_ci tcp_fastopen_init_key_once(sock_net(sk)); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci err = inet_csk_listen_start(sk, backlog); 2358c2ecf20Sopenharmony_ci if (err) 2368c2ecf20Sopenharmony_ci goto out; 2378c2ecf20Sopenharmony_ci tcp_call_bpf(sk, BPF_SOCK_OPS_TCP_LISTEN_CB, 0, NULL); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci err = 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ciout: 2428c2ecf20Sopenharmony_ci release_sock(sk); 2438c2ecf20Sopenharmony_ci return err; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_listen); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* 2488c2ecf20Sopenharmony_ci * Create an inet socket. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int inet_create(struct net *net, struct socket *sock, int protocol, 2528c2ecf20Sopenharmony_ci int kern) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct sock *sk; 2558c2ecf20Sopenharmony_ci struct inet_protosw *answer; 2568c2ecf20Sopenharmony_ci struct inet_sock *inet; 2578c2ecf20Sopenharmony_ci struct proto *answer_prot; 2588c2ecf20Sopenharmony_ci unsigned char answer_flags; 2598c2ecf20Sopenharmony_ci int try_loading_module = 0; 2608c2ecf20Sopenharmony_ci int err; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (protocol < 0 || protocol >= IPPROTO_MAX) 2638c2ecf20Sopenharmony_ci return -EINVAL; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Look for the requested type/protocol pair. */ 2688c2ecf20Sopenharmony_cilookup_protocol: 2698c2ecf20Sopenharmony_ci err = -ESOCKTNOSUPPORT; 2708c2ecf20Sopenharmony_ci rcu_read_lock(); 2718c2ecf20Sopenharmony_ci list_for_each_entry_rcu(answer, &inetsw[sock->type], list) { 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci err = 0; 2748c2ecf20Sopenharmony_ci /* Check the non-wild match. */ 2758c2ecf20Sopenharmony_ci if (protocol == answer->protocol) { 2768c2ecf20Sopenharmony_ci if (protocol != IPPROTO_IP) 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci } else { 2798c2ecf20Sopenharmony_ci /* Check for the two wild cases. */ 2808c2ecf20Sopenharmony_ci if (IPPROTO_IP == protocol) { 2818c2ecf20Sopenharmony_ci protocol = answer->protocol; 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci if (IPPROTO_IP == answer->protocol) 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci err = -EPROTONOSUPPORT; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (unlikely(err)) { 2918c2ecf20Sopenharmony_ci if (try_loading_module < 2) { 2928c2ecf20Sopenharmony_ci rcu_read_unlock(); 2938c2ecf20Sopenharmony_ci /* 2948c2ecf20Sopenharmony_ci * Be more specific, e.g. net-pf-2-proto-132-type-1 2958c2ecf20Sopenharmony_ci * (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM) 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci if (++try_loading_module == 1) 2988c2ecf20Sopenharmony_ci request_module("net-pf-%d-proto-%d-type-%d", 2998c2ecf20Sopenharmony_ci PF_INET, protocol, sock->type); 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * Fall back to generic, e.g. net-pf-2-proto-132 3028c2ecf20Sopenharmony_ci * (net-pf-PF_INET-proto-IPPROTO_SCTP) 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci request_module("net-pf-%d-proto-%d", 3068c2ecf20Sopenharmony_ci PF_INET, protocol); 3078c2ecf20Sopenharmony_ci goto lookup_protocol; 3088c2ecf20Sopenharmony_ci } else 3098c2ecf20Sopenharmony_ci goto out_rcu_unlock; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci err = -EPERM; 3138c2ecf20Sopenharmony_ci if (sock->type == SOCK_RAW && !kern && 3148c2ecf20Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_RAW)) 3158c2ecf20Sopenharmony_ci goto out_rcu_unlock; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci sock->ops = answer->ops; 3188c2ecf20Sopenharmony_ci answer_prot = answer->prot; 3198c2ecf20Sopenharmony_ci answer_flags = answer->flags; 3208c2ecf20Sopenharmony_ci rcu_read_unlock(); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci WARN_ON(!answer_prot->slab); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci err = -ENOBUFS; 3258c2ecf20Sopenharmony_ci sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern); 3268c2ecf20Sopenharmony_ci if (!sk) 3278c2ecf20Sopenharmony_ci goto out; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci err = 0; 3308c2ecf20Sopenharmony_ci if (INET_PROTOSW_REUSE & answer_flags) 3318c2ecf20Sopenharmony_ci sk->sk_reuse = SK_CAN_REUSE; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (INET_PROTOSW_ICSK & answer_flags) 3348c2ecf20Sopenharmony_ci inet_init_csk_locks(sk); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci inet = inet_sk(sk); 3378c2ecf20Sopenharmony_ci inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci inet->nodefrag = 0; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (SOCK_RAW == sock->type) { 3428c2ecf20Sopenharmony_ci inet->inet_num = protocol; 3438c2ecf20Sopenharmony_ci if (IPPROTO_RAW == protocol) 3448c2ecf20Sopenharmony_ci inet->hdrincl = 1; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) 3488c2ecf20Sopenharmony_ci inet->pmtudisc = IP_PMTUDISC_DONT; 3498c2ecf20Sopenharmony_ci else 3508c2ecf20Sopenharmony_ci inet->pmtudisc = IP_PMTUDISC_WANT; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci inet->inet_id = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci sk->sk_destruct = inet_sock_destruct; 3578c2ecf20Sopenharmony_ci sk->sk_protocol = protocol; 3588c2ecf20Sopenharmony_ci sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci inet->uc_ttl = -1; 3618c2ecf20Sopenharmony_ci inet->mc_loop = 1; 3628c2ecf20Sopenharmony_ci inet->mc_ttl = 1; 3638c2ecf20Sopenharmony_ci inet->mc_all = 1; 3648c2ecf20Sopenharmony_ci inet->mc_index = 0; 3658c2ecf20Sopenharmony_ci inet->mc_list = NULL; 3668c2ecf20Sopenharmony_ci inet->rcv_tos = 0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci sk_refcnt_debug_inc(sk); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (inet->inet_num) { 3718c2ecf20Sopenharmony_ci /* It assumes that any protocol which allows 3728c2ecf20Sopenharmony_ci * the user to assign a number at socket 3738c2ecf20Sopenharmony_ci * creation time automatically 3748c2ecf20Sopenharmony_ci * shares. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci inet->inet_sport = htons(inet->inet_num); 3778c2ecf20Sopenharmony_ci /* Add to protocol hash chains. */ 3788c2ecf20Sopenharmony_ci err = sk->sk_prot->hash(sk); 3798c2ecf20Sopenharmony_ci if (err) { 3808c2ecf20Sopenharmony_ci sk_common_release(sk); 3818c2ecf20Sopenharmony_ci goto out; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (sk->sk_prot->init) { 3868c2ecf20Sopenharmony_ci err = sk->sk_prot->init(sk); 3878c2ecf20Sopenharmony_ci if (err) { 3888c2ecf20Sopenharmony_ci sk_common_release(sk); 3898c2ecf20Sopenharmony_ci goto out; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (!kern) { 3948c2ecf20Sopenharmony_ci err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk); 3958c2ecf20Sopenharmony_ci if (err) { 3968c2ecf20Sopenharmony_ci sk_common_release(sk); 3978c2ecf20Sopenharmony_ci goto out; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ciout: 4018c2ecf20Sopenharmony_ci return err; 4028c2ecf20Sopenharmony_ciout_rcu_unlock: 4038c2ecf20Sopenharmony_ci rcu_read_unlock(); 4048c2ecf20Sopenharmony_ci goto out; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/* 4098c2ecf20Sopenharmony_ci * The peer socket should always be NULL (or else). When we call this 4108c2ecf20Sopenharmony_ci * function we are destroying the object and from then on nobody 4118c2ecf20Sopenharmony_ci * should refer to it. 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ciint inet_release(struct socket *sock) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (sk) { 4188c2ecf20Sopenharmony_ci long timeout; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (!sk->sk_kern_sock) 4218c2ecf20Sopenharmony_ci BPF_CGROUP_RUN_PROG_INET_SOCK_RELEASE(sk); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* Applications forget to leave groups before exiting */ 4248c2ecf20Sopenharmony_ci ip_mc_drop_socket(sk); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* If linger is set, we don't return until the close 4278c2ecf20Sopenharmony_ci * is complete. Otherwise we return immediately. The 4288c2ecf20Sopenharmony_ci * actually closing is done the same either way. 4298c2ecf20Sopenharmony_ci * 4308c2ecf20Sopenharmony_ci * If the close is due to the process exiting, we never 4318c2ecf20Sopenharmony_ci * linger.. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci timeout = 0; 4348c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_LINGER) && 4358c2ecf20Sopenharmony_ci !(current->flags & PF_EXITING)) 4368c2ecf20Sopenharmony_ci timeout = sk->sk_lingertime; 4378c2ecf20Sopenharmony_ci sk->sk_prot->close(sk, timeout); 4388c2ecf20Sopenharmony_ci sock->sk = NULL; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_release); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ciint inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4478c2ecf20Sopenharmony_ci int err; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* If the socket has its own bind function then use it. (RAW) */ 4508c2ecf20Sopenharmony_ci if (sk->sk_prot->bind) { 4518c2ecf20Sopenharmony_ci return sk->sk_prot->bind(sk, uaddr, addr_len); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci if (addr_len < sizeof(struct sockaddr_in)) 4548c2ecf20Sopenharmony_ci return -EINVAL; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* BPF prog is run before any checks are done so that if the prog 4578c2ecf20Sopenharmony_ci * changes context in a wrong way it will be caught. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci err = BPF_CGROUP_RUN_PROG_INET4_BIND(sk, uaddr); 4608c2ecf20Sopenharmony_ci if (err) 4618c2ecf20Sopenharmony_ci return err; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return __inet_bind(sk, uaddr, addr_len, BIND_WITH_LOCK); 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_bind); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ciint __inet_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, 4688c2ecf20Sopenharmony_ci u32 flags) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; 4718c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 4728c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 4738c2ecf20Sopenharmony_ci unsigned short snum; 4748c2ecf20Sopenharmony_ci int chk_addr_ret; 4758c2ecf20Sopenharmony_ci u32 tb_id = RT_TABLE_LOCAL; 4768c2ecf20Sopenharmony_ci int err; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (addr->sin_family != AF_INET) { 4798c2ecf20Sopenharmony_ci /* Compatibility games : accept AF_UNSPEC (mapped to AF_INET) 4808c2ecf20Sopenharmony_ci * only if s_addr is INADDR_ANY. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci err = -EAFNOSUPPORT; 4838c2ecf20Sopenharmony_ci if (addr->sin_family != AF_UNSPEC || 4848c2ecf20Sopenharmony_ci addr->sin_addr.s_addr != htonl(INADDR_ANY)) 4858c2ecf20Sopenharmony_ci goto out; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id; 4898c2ecf20Sopenharmony_ci chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Not specified by any standard per-se, however it breaks too 4928c2ecf20Sopenharmony_ci * many applications when removed. It is unfortunate since 4938c2ecf20Sopenharmony_ci * allowing applications to make a non-local bind solves 4948c2ecf20Sopenharmony_ci * several problems with systems using dynamic addressing. 4958c2ecf20Sopenharmony_ci * (ie. your servers still start up even if your ISDN link 4968c2ecf20Sopenharmony_ci * is temporarily down) 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci err = -EADDRNOTAVAIL; 4998c2ecf20Sopenharmony_ci if (!inet_can_nonlocal_bind(net, inet) && 5008c2ecf20Sopenharmony_ci addr->sin_addr.s_addr != htonl(INADDR_ANY) && 5018c2ecf20Sopenharmony_ci chk_addr_ret != RTN_LOCAL && 5028c2ecf20Sopenharmony_ci chk_addr_ret != RTN_MULTICAST && 5038c2ecf20Sopenharmony_ci chk_addr_ret != RTN_BROADCAST) 5048c2ecf20Sopenharmony_ci goto out; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci snum = ntohs(addr->sin_port); 5078c2ecf20Sopenharmony_ci err = -EACCES; 5088c2ecf20Sopenharmony_ci if (snum && inet_port_requires_bind_service(net, snum) && 5098c2ecf20Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 5108c2ecf20Sopenharmony_ci goto out; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* We keep a pair of addresses. rcv_saddr is the one 5138c2ecf20Sopenharmony_ci * used by hash lookups, and saddr is used for transmit. 5148c2ecf20Sopenharmony_ci * 5158c2ecf20Sopenharmony_ci * In the BSD API these are the same except where it 5168c2ecf20Sopenharmony_ci * would be illegal to use them (multicast/broadcast) in 5178c2ecf20Sopenharmony_ci * which case the sending device address is used. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci if (flags & BIND_WITH_LOCK) 5208c2ecf20Sopenharmony_ci lock_sock(sk); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* Check these errors (active socket, double bind). */ 5238c2ecf20Sopenharmony_ci err = -EINVAL; 5248c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_CLOSE || inet->inet_num) 5258c2ecf20Sopenharmony_ci goto out_release_sock; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; 5288c2ecf20Sopenharmony_ci if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) 5298c2ecf20Sopenharmony_ci inet->inet_saddr = 0; /* Use device */ 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* Make sure we are allowed to bind here. */ 5328c2ecf20Sopenharmony_ci if (snum || !(inet->bind_address_no_port || 5338c2ecf20Sopenharmony_ci (flags & BIND_FORCE_ADDRESS_NO_PORT))) { 5348c2ecf20Sopenharmony_ci if (sk->sk_prot->get_port(sk, snum)) { 5358c2ecf20Sopenharmony_ci inet->inet_saddr = inet->inet_rcv_saddr = 0; 5368c2ecf20Sopenharmony_ci err = -EADDRINUSE; 5378c2ecf20Sopenharmony_ci goto out_release_sock; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci if (!(flags & BIND_FROM_BPF)) { 5408c2ecf20Sopenharmony_ci err = BPF_CGROUP_RUN_PROG_INET4_POST_BIND(sk); 5418c2ecf20Sopenharmony_ci if (err) { 5428c2ecf20Sopenharmony_ci inet->inet_saddr = inet->inet_rcv_saddr = 0; 5438c2ecf20Sopenharmony_ci goto out_release_sock; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (inet->inet_rcv_saddr) 5498c2ecf20Sopenharmony_ci sk->sk_userlocks |= SOCK_BINDADDR_LOCK; 5508c2ecf20Sopenharmony_ci if (snum) 5518c2ecf20Sopenharmony_ci sk->sk_userlocks |= SOCK_BINDPORT_LOCK; 5528c2ecf20Sopenharmony_ci inet->inet_sport = htons(inet->inet_num); 5538c2ecf20Sopenharmony_ci inet->inet_daddr = 0; 5548c2ecf20Sopenharmony_ci inet->inet_dport = 0; 5558c2ecf20Sopenharmony_ci sk_dst_reset(sk); 5568c2ecf20Sopenharmony_ci err = 0; 5578c2ecf20Sopenharmony_ciout_release_sock: 5588c2ecf20Sopenharmony_ci if (flags & BIND_WITH_LOCK) 5598c2ecf20Sopenharmony_ci release_sock(sk); 5608c2ecf20Sopenharmony_ciout: 5618c2ecf20Sopenharmony_ci return err; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ciint inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr, 5658c2ecf20Sopenharmony_ci int addr_len, int flags) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5688c2ecf20Sopenharmony_ci const struct proto *prot; 5698c2ecf20Sopenharmony_ci int err; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (addr_len < sizeof(uaddr->sa_family)) 5728c2ecf20Sopenharmony_ci return -EINVAL; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* IPV6_ADDRFORM can change sk->sk_prot under us. */ 5758c2ecf20Sopenharmony_ci prot = READ_ONCE(sk->sk_prot); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (uaddr->sa_family == AF_UNSPEC) 5788c2ecf20Sopenharmony_ci return prot->disconnect(sk, flags); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (BPF_CGROUP_PRE_CONNECT_ENABLED(sk)) { 5818c2ecf20Sopenharmony_ci err = prot->pre_connect(sk, uaddr, addr_len); 5828c2ecf20Sopenharmony_ci if (err) 5838c2ecf20Sopenharmony_ci return err; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (data_race(!inet_sk(sk)->inet_num) && inet_autobind(sk)) 5878c2ecf20Sopenharmony_ci return -EAGAIN; 5888c2ecf20Sopenharmony_ci return prot->connect(sk, uaddr, addr_len); 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_dgram_connect); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic long inet_wait_for_connect(struct sock *sk, long timeo, int writebias) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci DEFINE_WAIT_FUNC(wait, woken_wake_function); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 5978c2ecf20Sopenharmony_ci sk->sk_write_pending += writebias; 5988c2ecf20Sopenharmony_ci sk->sk_wait_pending++; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Basic assumption: if someone sets sk->sk_err, he _must_ 6018c2ecf20Sopenharmony_ci * change state of the socket from TCP_SYN_*. 6028c2ecf20Sopenharmony_ci * Connect() does not allow to get error notifications 6038c2ecf20Sopenharmony_ci * without closing the socket. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci while ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { 6068c2ecf20Sopenharmony_ci release_sock(sk); 6078c2ecf20Sopenharmony_ci timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); 6088c2ecf20Sopenharmony_ci lock_sock(sk); 6098c2ecf20Sopenharmony_ci if (signal_pending(current) || !timeo) 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 6138c2ecf20Sopenharmony_ci sk->sk_write_pending -= writebias; 6148c2ecf20Sopenharmony_ci sk->sk_wait_pending--; 6158c2ecf20Sopenharmony_ci return timeo; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* 6198c2ecf20Sopenharmony_ci * Connect to a remote host. There is regrettably still a little 6208c2ecf20Sopenharmony_ci * TCP 'magic' in here. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ciint __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, 6238c2ecf20Sopenharmony_ci int addr_len, int flags, int is_sendmsg) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 6268c2ecf20Sopenharmony_ci int err; 6278c2ecf20Sopenharmony_ci long timeo; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * uaddr can be NULL and addr_len can be 0 if: 6318c2ecf20Sopenharmony_ci * sk is a TCP fastopen active socket and 6328c2ecf20Sopenharmony_ci * TCP_FASTOPEN_CONNECT sockopt is set and 6338c2ecf20Sopenharmony_ci * we already have a valid cookie for this socket. 6348c2ecf20Sopenharmony_ci * In this case, user can call write() after connect(). 6358c2ecf20Sopenharmony_ci * write() will invoke tcp_sendmsg_fastopen() which calls 6368c2ecf20Sopenharmony_ci * __inet_stream_connect(). 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci if (uaddr) { 6398c2ecf20Sopenharmony_ci if (addr_len < sizeof(uaddr->sa_family)) 6408c2ecf20Sopenharmony_ci return -EINVAL; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (uaddr->sa_family == AF_UNSPEC) { 6438c2ecf20Sopenharmony_ci err = sk->sk_prot->disconnect(sk, flags); 6448c2ecf20Sopenharmony_ci sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; 6458c2ecf20Sopenharmony_ci goto out; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci switch (sock->state) { 6508c2ecf20Sopenharmony_ci default: 6518c2ecf20Sopenharmony_ci err = -EINVAL; 6528c2ecf20Sopenharmony_ci goto out; 6538c2ecf20Sopenharmony_ci case SS_CONNECTED: 6548c2ecf20Sopenharmony_ci err = -EISCONN; 6558c2ecf20Sopenharmony_ci goto out; 6568c2ecf20Sopenharmony_ci case SS_CONNECTING: 6578c2ecf20Sopenharmony_ci if (inet_sk(sk)->defer_connect) 6588c2ecf20Sopenharmony_ci err = is_sendmsg ? -EINPROGRESS : -EISCONN; 6598c2ecf20Sopenharmony_ci else 6608c2ecf20Sopenharmony_ci err = -EALREADY; 6618c2ecf20Sopenharmony_ci /* Fall out of switch with err, set for this state */ 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci case SS_UNCONNECTED: 6648c2ecf20Sopenharmony_ci err = -EISCONN; 6658c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_CLOSE) 6668c2ecf20Sopenharmony_ci goto out; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (BPF_CGROUP_PRE_CONNECT_ENABLED(sk)) { 6698c2ecf20Sopenharmony_ci err = sk->sk_prot->pre_connect(sk, uaddr, addr_len); 6708c2ecf20Sopenharmony_ci if (err) 6718c2ecf20Sopenharmony_ci goto out; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci err = sk->sk_prot->connect(sk, uaddr, addr_len); 6758c2ecf20Sopenharmony_ci if (err < 0) 6768c2ecf20Sopenharmony_ci goto out; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci sock->state = SS_CONNECTING; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!err && inet_sk(sk)->defer_connect) 6818c2ecf20Sopenharmony_ci goto out; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* Just entered SS_CONNECTING state; the only 6848c2ecf20Sopenharmony_ci * difference is that return value in non-blocking 6858c2ecf20Sopenharmony_ci * case is EINPROGRESS, rather than EALREADY. 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ci err = -EINPROGRESS; 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { 6948c2ecf20Sopenharmony_ci int writebias = (sk->sk_protocol == IPPROTO_TCP) && 6958c2ecf20Sopenharmony_ci tcp_sk(sk)->fastopen_req && 6968c2ecf20Sopenharmony_ci tcp_sk(sk)->fastopen_req->data ? 1 : 0; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* Error code is set above */ 6998c2ecf20Sopenharmony_ci if (!timeo || !inet_wait_for_connect(sk, timeo, writebias)) 7008c2ecf20Sopenharmony_ci goto out; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci err = sock_intr_errno(timeo); 7038c2ecf20Sopenharmony_ci if (signal_pending(current)) 7048c2ecf20Sopenharmony_ci goto out; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Connection was closed by RST, timeout, ICMP error 7088c2ecf20Sopenharmony_ci * or another process disconnected us. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_CLOSE) 7118c2ecf20Sopenharmony_ci goto sock_error; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* sk->sk_err may be not zero now, if RECVERR was ordered by user 7148c2ecf20Sopenharmony_ci * and error was received after socket entered established state. 7158c2ecf20Sopenharmony_ci * Hence, it is handled normally after connect() return successfully. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci sock->state = SS_CONNECTED; 7198c2ecf20Sopenharmony_ci err = 0; 7208c2ecf20Sopenharmony_ciout: 7218c2ecf20Sopenharmony_ci return err; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cisock_error: 7248c2ecf20Sopenharmony_ci err = sock_error(sk) ? : -ECONNABORTED; 7258c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 7268c2ecf20Sopenharmony_ci if (sk->sk_prot->disconnect(sk, flags)) 7278c2ecf20Sopenharmony_ci sock->state = SS_DISCONNECTING; 7288c2ecf20Sopenharmony_ci goto out; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__inet_stream_connect); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ciint inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, 7338c2ecf20Sopenharmony_ci int addr_len, int flags) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci int err; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci lock_sock(sock->sk); 7388c2ecf20Sopenharmony_ci err = __inet_stream_connect(sock, uaddr, addr_len, flags, 0); 7398c2ecf20Sopenharmony_ci release_sock(sock->sk); 7408c2ecf20Sopenharmony_ci return err; 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_stream_connect); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/* 7458c2ecf20Sopenharmony_ci * Accept a pending connection. The TCP layer now gives BSD semantics. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ciint inet_accept(struct socket *sock, struct socket *newsock, int flags, 7498c2ecf20Sopenharmony_ci bool kern) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct sock *sk1 = sock->sk, *sk2; 7528c2ecf20Sopenharmony_ci int err = -EINVAL; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* IPV6_ADDRFORM can change sk->sk_prot under us. */ 7558c2ecf20Sopenharmony_ci sk2 = READ_ONCE(sk1->sk_prot)->accept(sk1, flags, &err, kern); 7568c2ecf20Sopenharmony_ci if (!sk2) 7578c2ecf20Sopenharmony_ci goto do_err; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci lock_sock(sk2); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci sock_rps_record_flow(sk2); 7628c2ecf20Sopenharmony_ci WARN_ON(!((1 << sk2->sk_state) & 7638c2ecf20Sopenharmony_ci (TCPF_ESTABLISHED | TCPF_SYN_RECV | 7648c2ecf20Sopenharmony_ci TCPF_FIN_WAIT1 | TCPF_FIN_WAIT2 | 7658c2ecf20Sopenharmony_ci TCPF_CLOSING | TCPF_CLOSE_WAIT | 7668c2ecf20Sopenharmony_ci TCPF_CLOSE))); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci sock_graft(sk2, newsock); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci newsock->state = SS_CONNECTED; 7718c2ecf20Sopenharmony_ci err = 0; 7728c2ecf20Sopenharmony_ci release_sock(sk2); 7738c2ecf20Sopenharmony_cido_err: 7748c2ecf20Sopenharmony_ci return err; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_accept); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci/* 7798c2ecf20Sopenharmony_ci * This does both peername and sockname. 7808c2ecf20Sopenharmony_ci */ 7818c2ecf20Sopenharmony_ciint inet_getname(struct socket *sock, struct sockaddr *uaddr, 7828c2ecf20Sopenharmony_ci int peer) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 7858c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 7868c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_in *, sin, uaddr); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci sin->sin_family = AF_INET; 7898c2ecf20Sopenharmony_ci if (peer) { 7908c2ecf20Sopenharmony_ci if (!inet->inet_dport || 7918c2ecf20Sopenharmony_ci (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && 7928c2ecf20Sopenharmony_ci peer == 1)) 7938c2ecf20Sopenharmony_ci return -ENOTCONN; 7948c2ecf20Sopenharmony_ci sin->sin_port = inet->inet_dport; 7958c2ecf20Sopenharmony_ci sin->sin_addr.s_addr = inet->inet_daddr; 7968c2ecf20Sopenharmony_ci } else { 7978c2ecf20Sopenharmony_ci __be32 addr = inet->inet_rcv_saddr; 7988c2ecf20Sopenharmony_ci if (!addr) 7998c2ecf20Sopenharmony_ci addr = inet->inet_saddr; 8008c2ecf20Sopenharmony_ci sin->sin_port = inet->inet_sport; 8018c2ecf20Sopenharmony_ci sin->sin_addr.s_addr = addr; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci if (cgroup_bpf_enabled) 8048c2ecf20Sopenharmony_ci BPF_CGROUP_RUN_SA_PROG_LOCK(sk, (struct sockaddr *)sin, 8058c2ecf20Sopenharmony_ci peer ? BPF_CGROUP_INET4_GETPEERNAME : 8068c2ecf20Sopenharmony_ci BPF_CGROUP_INET4_GETSOCKNAME, 8078c2ecf20Sopenharmony_ci NULL); 8088c2ecf20Sopenharmony_ci memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 8098c2ecf20Sopenharmony_ci return sizeof(*sin); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_getname); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ciint inet_send_prepare(struct sock *sk) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci sock_rps_record_flow(sk); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* We may need to bind the socket. */ 8188c2ecf20Sopenharmony_ci if (data_race(!inet_sk(sk)->inet_num) && !sk->sk_prot->no_autobind && 8198c2ecf20Sopenharmony_ci inet_autobind(sk)) 8208c2ecf20Sopenharmony_ci return -EAGAIN; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return 0; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(inet_send_prepare); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ciint inet_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (unlikely(inet_send_prepare(sk))) 8318c2ecf20Sopenharmony_ci return -EAGAIN; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return INDIRECT_CALL_2(sk->sk_prot->sendmsg, tcp_sendmsg, udp_sendmsg, 8348c2ecf20Sopenharmony_ci sk, msg, size); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_sendmsg); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cissize_t inet_sendpage(struct socket *sock, struct page *page, int offset, 8398c2ecf20Sopenharmony_ci size_t size, int flags) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8428c2ecf20Sopenharmony_ci const struct proto *prot; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (unlikely(inet_send_prepare(sk))) 8458c2ecf20Sopenharmony_ci return -EAGAIN; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* IPV6_ADDRFORM can change sk->sk_prot under us. */ 8488c2ecf20Sopenharmony_ci prot = READ_ONCE(sk->sk_prot); 8498c2ecf20Sopenharmony_ci if (prot->sendpage) 8508c2ecf20Sopenharmony_ci return prot->sendpage(sk, page, offset, size, flags); 8518c2ecf20Sopenharmony_ci return sock_no_sendpage(sock, page, offset, size, flags); 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_sendpage); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ciINDIRECT_CALLABLE_DECLARE(int udp_recvmsg(struct sock *, struct msghdr *, 8568c2ecf20Sopenharmony_ci size_t, int, int, int *)); 8578c2ecf20Sopenharmony_ciint inet_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, 8588c2ecf20Sopenharmony_ci int flags) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8618c2ecf20Sopenharmony_ci int addr_len = 0; 8628c2ecf20Sopenharmony_ci int err; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (likely(!(flags & MSG_ERRQUEUE))) 8658c2ecf20Sopenharmony_ci sock_rps_record_flow(sk); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci err = INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udp_recvmsg, 8688c2ecf20Sopenharmony_ci sk, msg, size, flags & MSG_DONTWAIT, 8698c2ecf20Sopenharmony_ci flags & ~MSG_DONTWAIT, &addr_len); 8708c2ecf20Sopenharmony_ci if (err >= 0) 8718c2ecf20Sopenharmony_ci msg->msg_namelen = addr_len; 8728c2ecf20Sopenharmony_ci return err; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_recvmsg); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ciint inet_shutdown(struct socket *sock, int how) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8798c2ecf20Sopenharmony_ci int err = 0; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* This should really check to make sure 8828c2ecf20Sopenharmony_ci * the socket is a TCP socket. (WHY AC...) 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_ci how++; /* maps 0->1 has the advantage of making bit 1 rcvs and 8858c2ecf20Sopenharmony_ci 1->2 bit 2 snds. 8868c2ecf20Sopenharmony_ci 2->3 */ 8878c2ecf20Sopenharmony_ci if ((how & ~SHUTDOWN_MASK) || !how) /* MAXINT->0 */ 8888c2ecf20Sopenharmony_ci return -EINVAL; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci lock_sock(sk); 8918c2ecf20Sopenharmony_ci if (sock->state == SS_CONNECTING) { 8928c2ecf20Sopenharmony_ci if ((1 << sk->sk_state) & 8938c2ecf20Sopenharmony_ci (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE)) 8948c2ecf20Sopenharmony_ci sock->state = SS_DISCONNECTING; 8958c2ecf20Sopenharmony_ci else 8968c2ecf20Sopenharmony_ci sock->state = SS_CONNECTED; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci switch (sk->sk_state) { 9008c2ecf20Sopenharmony_ci case TCP_CLOSE: 9018c2ecf20Sopenharmony_ci err = -ENOTCONN; 9028c2ecf20Sopenharmony_ci /* Hack to wake up other listeners, who can poll for 9038c2ecf20Sopenharmony_ci EPOLLHUP, even on eg. unconnected UDP sockets -- RR */ 9048c2ecf20Sopenharmony_ci fallthrough; 9058c2ecf20Sopenharmony_ci default: 9068c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_shutdown, sk->sk_shutdown | how); 9078c2ecf20Sopenharmony_ci if (sk->sk_prot->shutdown) 9088c2ecf20Sopenharmony_ci sk->sk_prot->shutdown(sk, how); 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* Remaining two branches are temporary solution for missing 9128c2ecf20Sopenharmony_ci * close() in multithreaded environment. It is _not_ a good idea, 9138c2ecf20Sopenharmony_ci * but we have no choice until close() is repaired at VFS level. 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_ci case TCP_LISTEN: 9168c2ecf20Sopenharmony_ci if (!(how & RCV_SHUTDOWN)) 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci fallthrough; 9198c2ecf20Sopenharmony_ci case TCP_SYN_SENT: 9208c2ecf20Sopenharmony_ci err = sk->sk_prot->disconnect(sk, O_NONBLOCK); 9218c2ecf20Sopenharmony_ci sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; 9228c2ecf20Sopenharmony_ci break; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Wake up anyone sleeping in poll. */ 9268c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 9278c2ecf20Sopenharmony_ci release_sock(sk); 9288c2ecf20Sopenharmony_ci return err; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_shutdown); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci/* 9338c2ecf20Sopenharmony_ci * ioctl() calls you can issue on an INET socket. Most of these are 9348c2ecf20Sopenharmony_ci * device configuration and stuff and very rarely used. Some ioctls 9358c2ecf20Sopenharmony_ci * pass on to the socket itself. 9368c2ecf20Sopenharmony_ci * 9378c2ecf20Sopenharmony_ci * NOTE: I like the idea of a module for the config stuff. ie ifconfig 9388c2ecf20Sopenharmony_ci * loads the devconfigure module does its configuring and unloads it. 9398c2ecf20Sopenharmony_ci * There's a good 20K of config code hanging around the kernel. 9408c2ecf20Sopenharmony_ci */ 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ciint inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 9458c2ecf20Sopenharmony_ci int err = 0; 9468c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 9478c2ecf20Sopenharmony_ci void __user *p = (void __user *)arg; 9488c2ecf20Sopenharmony_ci struct ifreq ifr; 9498c2ecf20Sopenharmony_ci struct rtentry rt; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci switch (cmd) { 9528c2ecf20Sopenharmony_ci case SIOCADDRT: 9538c2ecf20Sopenharmony_ci case SIOCDELRT: 9548c2ecf20Sopenharmony_ci if (copy_from_user(&rt, p, sizeof(struct rtentry))) 9558c2ecf20Sopenharmony_ci return -EFAULT; 9568c2ecf20Sopenharmony_ci err = ip_rt_ioctl(net, cmd, &rt); 9578c2ecf20Sopenharmony_ci break; 9588c2ecf20Sopenharmony_ci case SIOCRTMSG: 9598c2ecf20Sopenharmony_ci err = -EINVAL; 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci case SIOCDARP: 9628c2ecf20Sopenharmony_ci case SIOCGARP: 9638c2ecf20Sopenharmony_ci case SIOCSARP: 9648c2ecf20Sopenharmony_ci err = arp_ioctl(net, cmd, (void __user *)arg); 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci case SIOCGIFADDR: 9678c2ecf20Sopenharmony_ci case SIOCGIFBRDADDR: 9688c2ecf20Sopenharmony_ci case SIOCGIFNETMASK: 9698c2ecf20Sopenharmony_ci case SIOCGIFDSTADDR: 9708c2ecf20Sopenharmony_ci case SIOCGIFPFLAGS: 9718c2ecf20Sopenharmony_ci if (copy_from_user(&ifr, p, sizeof(struct ifreq))) 9728c2ecf20Sopenharmony_ci return -EFAULT; 9738c2ecf20Sopenharmony_ci err = devinet_ioctl(net, cmd, &ifr); 9748c2ecf20Sopenharmony_ci if (!err && copy_to_user(p, &ifr, sizeof(struct ifreq))) 9758c2ecf20Sopenharmony_ci err = -EFAULT; 9768c2ecf20Sopenharmony_ci break; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci case SIOCSIFADDR: 9798c2ecf20Sopenharmony_ci case SIOCSIFBRDADDR: 9808c2ecf20Sopenharmony_ci case SIOCSIFNETMASK: 9818c2ecf20Sopenharmony_ci case SIOCSIFDSTADDR: 9828c2ecf20Sopenharmony_ci case SIOCSIFPFLAGS: 9838c2ecf20Sopenharmony_ci case SIOCSIFFLAGS: 9848c2ecf20Sopenharmony_ci if (copy_from_user(&ifr, p, sizeof(struct ifreq))) 9858c2ecf20Sopenharmony_ci return -EFAULT; 9868c2ecf20Sopenharmony_ci err = devinet_ioctl(net, cmd, &ifr); 9878c2ecf20Sopenharmony_ci break; 9888c2ecf20Sopenharmony_ci default: 9898c2ecf20Sopenharmony_ci if (sk->sk_prot->ioctl) 9908c2ecf20Sopenharmony_ci err = sk->sk_prot->ioctl(sk, cmd, arg); 9918c2ecf20Sopenharmony_ci else 9928c2ecf20Sopenharmony_ci err = -ENOIOCTLCMD; 9938c2ecf20Sopenharmony_ci break; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci return err; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_ioctl); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 10008c2ecf20Sopenharmony_cistatic int inet_compat_routing_ioctl(struct sock *sk, unsigned int cmd, 10018c2ecf20Sopenharmony_ci struct compat_rtentry __user *ur) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci compat_uptr_t rtdev; 10048c2ecf20Sopenharmony_ci struct rtentry rt; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (copy_from_user(&rt.rt_dst, &ur->rt_dst, 10078c2ecf20Sopenharmony_ci 3 * sizeof(struct sockaddr)) || 10088c2ecf20Sopenharmony_ci get_user(rt.rt_flags, &ur->rt_flags) || 10098c2ecf20Sopenharmony_ci get_user(rt.rt_metric, &ur->rt_metric) || 10108c2ecf20Sopenharmony_ci get_user(rt.rt_mtu, &ur->rt_mtu) || 10118c2ecf20Sopenharmony_ci get_user(rt.rt_window, &ur->rt_window) || 10128c2ecf20Sopenharmony_ci get_user(rt.rt_irtt, &ur->rt_irtt) || 10138c2ecf20Sopenharmony_ci get_user(rtdev, &ur->rt_dev)) 10148c2ecf20Sopenharmony_ci return -EFAULT; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci rt.rt_dev = compat_ptr(rtdev); 10178c2ecf20Sopenharmony_ci return ip_rt_ioctl(sock_net(sk), cmd, &rt); 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cistatic int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci void __user *argp = compat_ptr(arg); 10238c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci switch (cmd) { 10268c2ecf20Sopenharmony_ci case SIOCADDRT: 10278c2ecf20Sopenharmony_ci case SIOCDELRT: 10288c2ecf20Sopenharmony_ci return inet_compat_routing_ioctl(sk, cmd, argp); 10298c2ecf20Sopenharmony_ci default: 10308c2ecf20Sopenharmony_ci if (!sk->sk_prot->compat_ioctl) 10318c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 10328c2ecf20Sopenharmony_ci return sk->sk_prot->compat_ioctl(sk, cmd, arg); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci#endif /* CONFIG_COMPAT */ 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ciconst struct proto_ops inet_stream_ops = { 10388c2ecf20Sopenharmony_ci .family = PF_INET, 10398c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10408c2ecf20Sopenharmony_ci .release = inet_release, 10418c2ecf20Sopenharmony_ci .bind = inet_bind, 10428c2ecf20Sopenharmony_ci .connect = inet_stream_connect, 10438c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 10448c2ecf20Sopenharmony_ci .accept = inet_accept, 10458c2ecf20Sopenharmony_ci .getname = inet_getname, 10468c2ecf20Sopenharmony_ci .poll = tcp_poll, 10478c2ecf20Sopenharmony_ci .ioctl = inet_ioctl, 10488c2ecf20Sopenharmony_ci .gettstamp = sock_gettstamp, 10498c2ecf20Sopenharmony_ci .listen = inet_listen, 10508c2ecf20Sopenharmony_ci .shutdown = inet_shutdown, 10518c2ecf20Sopenharmony_ci .setsockopt = sock_common_setsockopt, 10528c2ecf20Sopenharmony_ci .getsockopt = sock_common_getsockopt, 10538c2ecf20Sopenharmony_ci .sendmsg = inet_sendmsg, 10548c2ecf20Sopenharmony_ci .recvmsg = inet_recvmsg, 10558c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 10568c2ecf20Sopenharmony_ci .mmap = tcp_mmap, 10578c2ecf20Sopenharmony_ci#endif 10588c2ecf20Sopenharmony_ci .sendpage = inet_sendpage, 10598c2ecf20Sopenharmony_ci .splice_read = tcp_splice_read, 10608c2ecf20Sopenharmony_ci .read_sock = tcp_read_sock, 10618c2ecf20Sopenharmony_ci .sendmsg_locked = tcp_sendmsg_locked, 10628c2ecf20Sopenharmony_ci .sendpage_locked = tcp_sendpage_locked, 10638c2ecf20Sopenharmony_ci .peek_len = tcp_peek_len, 10648c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 10658c2ecf20Sopenharmony_ci .compat_ioctl = inet_compat_ioctl, 10668c2ecf20Sopenharmony_ci#endif 10678c2ecf20Sopenharmony_ci .set_rcvlowat = tcp_set_rcvlowat, 10688c2ecf20Sopenharmony_ci}; 10698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_stream_ops); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ciconst struct proto_ops inet_dgram_ops = { 10728c2ecf20Sopenharmony_ci .family = PF_INET, 10738c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10748c2ecf20Sopenharmony_ci .release = inet_release, 10758c2ecf20Sopenharmony_ci .bind = inet_bind, 10768c2ecf20Sopenharmony_ci .connect = inet_dgram_connect, 10778c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 10788c2ecf20Sopenharmony_ci .accept = sock_no_accept, 10798c2ecf20Sopenharmony_ci .getname = inet_getname, 10808c2ecf20Sopenharmony_ci .poll = udp_poll, 10818c2ecf20Sopenharmony_ci .ioctl = inet_ioctl, 10828c2ecf20Sopenharmony_ci .gettstamp = sock_gettstamp, 10838c2ecf20Sopenharmony_ci .listen = sock_no_listen, 10848c2ecf20Sopenharmony_ci .shutdown = inet_shutdown, 10858c2ecf20Sopenharmony_ci .setsockopt = sock_common_setsockopt, 10868c2ecf20Sopenharmony_ci .getsockopt = sock_common_getsockopt, 10878c2ecf20Sopenharmony_ci .sendmsg = inet_sendmsg, 10888c2ecf20Sopenharmony_ci .recvmsg = inet_recvmsg, 10898c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 10908c2ecf20Sopenharmony_ci .sendpage = inet_sendpage, 10918c2ecf20Sopenharmony_ci .set_peek_off = sk_set_peek_off, 10928c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 10938c2ecf20Sopenharmony_ci .compat_ioctl = inet_compat_ioctl, 10948c2ecf20Sopenharmony_ci#endif 10958c2ecf20Sopenharmony_ci}; 10968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_dgram_ops); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci/* 10998c2ecf20Sopenharmony_ci * For SOCK_RAW sockets; should be the same as inet_dgram_ops but without 11008c2ecf20Sopenharmony_ci * udp_poll 11018c2ecf20Sopenharmony_ci */ 11028c2ecf20Sopenharmony_cistatic const struct proto_ops inet_sockraw_ops = { 11038c2ecf20Sopenharmony_ci .family = PF_INET, 11048c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11058c2ecf20Sopenharmony_ci .release = inet_release, 11068c2ecf20Sopenharmony_ci .bind = inet_bind, 11078c2ecf20Sopenharmony_ci .connect = inet_dgram_connect, 11088c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 11098c2ecf20Sopenharmony_ci .accept = sock_no_accept, 11108c2ecf20Sopenharmony_ci .getname = inet_getname, 11118c2ecf20Sopenharmony_ci .poll = datagram_poll, 11128c2ecf20Sopenharmony_ci .ioctl = inet_ioctl, 11138c2ecf20Sopenharmony_ci .gettstamp = sock_gettstamp, 11148c2ecf20Sopenharmony_ci .listen = sock_no_listen, 11158c2ecf20Sopenharmony_ci .shutdown = inet_shutdown, 11168c2ecf20Sopenharmony_ci .setsockopt = sock_common_setsockopt, 11178c2ecf20Sopenharmony_ci .getsockopt = sock_common_getsockopt, 11188c2ecf20Sopenharmony_ci .sendmsg = inet_sendmsg, 11198c2ecf20Sopenharmony_ci .recvmsg = inet_recvmsg, 11208c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 11218c2ecf20Sopenharmony_ci .sendpage = inet_sendpage, 11228c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 11238c2ecf20Sopenharmony_ci .compat_ioctl = inet_compat_ioctl, 11248c2ecf20Sopenharmony_ci#endif 11258c2ecf20Sopenharmony_ci}; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic const struct net_proto_family inet_family_ops = { 11288c2ecf20Sopenharmony_ci .family = PF_INET, 11298c2ecf20Sopenharmony_ci .create = inet_create, 11308c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11318c2ecf20Sopenharmony_ci}; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci/* Upon startup we insert all the elements in inetsw_array[] into 11348c2ecf20Sopenharmony_ci * the linked list inetsw. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_cistatic struct inet_protosw inetsw_array[] = 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci { 11398c2ecf20Sopenharmony_ci .type = SOCK_STREAM, 11408c2ecf20Sopenharmony_ci .protocol = IPPROTO_TCP, 11418c2ecf20Sopenharmony_ci .prot = &tcp_prot, 11428c2ecf20Sopenharmony_ci .ops = &inet_stream_ops, 11438c2ecf20Sopenharmony_ci .flags = INET_PROTOSW_PERMANENT | 11448c2ecf20Sopenharmony_ci INET_PROTOSW_ICSK, 11458c2ecf20Sopenharmony_ci }, 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci { 11488c2ecf20Sopenharmony_ci .type = SOCK_DGRAM, 11498c2ecf20Sopenharmony_ci .protocol = IPPROTO_UDP, 11508c2ecf20Sopenharmony_ci .prot = &udp_prot, 11518c2ecf20Sopenharmony_ci .ops = &inet_dgram_ops, 11528c2ecf20Sopenharmony_ci .flags = INET_PROTOSW_PERMANENT, 11538c2ecf20Sopenharmony_ci }, 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci { 11568c2ecf20Sopenharmony_ci .type = SOCK_DGRAM, 11578c2ecf20Sopenharmony_ci .protocol = IPPROTO_ICMP, 11588c2ecf20Sopenharmony_ci .prot = &ping_prot, 11598c2ecf20Sopenharmony_ci .ops = &inet_sockraw_ops, 11608c2ecf20Sopenharmony_ci .flags = INET_PROTOSW_REUSE, 11618c2ecf20Sopenharmony_ci }, 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci { 11648c2ecf20Sopenharmony_ci .type = SOCK_RAW, 11658c2ecf20Sopenharmony_ci .protocol = IPPROTO_IP, /* wild card */ 11668c2ecf20Sopenharmony_ci .prot = &raw_prot, 11678c2ecf20Sopenharmony_ci .ops = &inet_sockraw_ops, 11688c2ecf20Sopenharmony_ci .flags = INET_PROTOSW_REUSE, 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci}; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci#define INETSW_ARRAY_LEN ARRAY_SIZE(inetsw_array) 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_civoid inet_register_protosw(struct inet_protosw *p) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci struct list_head *lh; 11778c2ecf20Sopenharmony_ci struct inet_protosw *answer; 11788c2ecf20Sopenharmony_ci int protocol = p->protocol; 11798c2ecf20Sopenharmony_ci struct list_head *last_perm; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci spin_lock_bh(&inetsw_lock); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (p->type >= SOCK_MAX) 11848c2ecf20Sopenharmony_ci goto out_illegal; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* If we are trying to override a permanent protocol, bail. */ 11878c2ecf20Sopenharmony_ci last_perm = &inetsw[p->type]; 11888c2ecf20Sopenharmony_ci list_for_each(lh, &inetsw[p->type]) { 11898c2ecf20Sopenharmony_ci answer = list_entry(lh, struct inet_protosw, list); 11908c2ecf20Sopenharmony_ci /* Check only the non-wild match. */ 11918c2ecf20Sopenharmony_ci if ((INET_PROTOSW_PERMANENT & answer->flags) == 0) 11928c2ecf20Sopenharmony_ci break; 11938c2ecf20Sopenharmony_ci if (protocol == answer->protocol) 11948c2ecf20Sopenharmony_ci goto out_permanent; 11958c2ecf20Sopenharmony_ci last_perm = lh; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* Add the new entry after the last permanent entry if any, so that 11998c2ecf20Sopenharmony_ci * the new entry does not override a permanent entry when matched with 12008c2ecf20Sopenharmony_ci * a wild-card protocol. But it is allowed to override any existing 12018c2ecf20Sopenharmony_ci * non-permanent entry. This means that when we remove this entry, the 12028c2ecf20Sopenharmony_ci * system automatically returns to the old behavior. 12038c2ecf20Sopenharmony_ci */ 12048c2ecf20Sopenharmony_ci list_add_rcu(&p->list, last_perm); 12058c2ecf20Sopenharmony_ciout: 12068c2ecf20Sopenharmony_ci spin_unlock_bh(&inetsw_lock); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci return; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ciout_permanent: 12118c2ecf20Sopenharmony_ci pr_err("Attempt to override permanent protocol %d\n", protocol); 12128c2ecf20Sopenharmony_ci goto out; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ciout_illegal: 12158c2ecf20Sopenharmony_ci pr_err("Ignoring attempt to register invalid socket type %d\n", 12168c2ecf20Sopenharmony_ci p->type); 12178c2ecf20Sopenharmony_ci goto out; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_register_protosw); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_civoid inet_unregister_protosw(struct inet_protosw *p) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci if (INET_PROTOSW_PERMANENT & p->flags) { 12248c2ecf20Sopenharmony_ci pr_err("Attempt to unregister permanent protocol %d\n", 12258c2ecf20Sopenharmony_ci p->protocol); 12268c2ecf20Sopenharmony_ci } else { 12278c2ecf20Sopenharmony_ci spin_lock_bh(&inetsw_lock); 12288c2ecf20Sopenharmony_ci list_del_rcu(&p->list); 12298c2ecf20Sopenharmony_ci spin_unlock_bh(&inetsw_lock); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci synchronize_net(); 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_unregister_protosw); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int inet_sk_reselect_saddr(struct sock *sk) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 12398c2ecf20Sopenharmony_ci __be32 old_saddr = inet->inet_saddr; 12408c2ecf20Sopenharmony_ci __be32 daddr = inet->inet_daddr; 12418c2ecf20Sopenharmony_ci struct flowi4 *fl4; 12428c2ecf20Sopenharmony_ci struct rtable *rt; 12438c2ecf20Sopenharmony_ci __be32 new_saddr; 12448c2ecf20Sopenharmony_ci struct ip_options_rcu *inet_opt; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci inet_opt = rcu_dereference_protected(inet->inet_opt, 12478c2ecf20Sopenharmony_ci lockdep_sock_is_held(sk)); 12488c2ecf20Sopenharmony_ci if (inet_opt && inet_opt->opt.srr) 12498c2ecf20Sopenharmony_ci daddr = inet_opt->opt.faddr; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* Query new route. */ 12528c2ecf20Sopenharmony_ci fl4 = &inet->cork.fl.u.ip4; 12538c2ecf20Sopenharmony_ci rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk), 12548c2ecf20Sopenharmony_ci sk->sk_bound_dev_if, sk->sk_protocol, 12558c2ecf20Sopenharmony_ci inet->inet_sport, inet->inet_dport, sk); 12568c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 12578c2ecf20Sopenharmony_ci return PTR_ERR(rt); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci sk_setup_caps(sk, &rt->dst); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci new_saddr = fl4->saddr; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci if (new_saddr == old_saddr) 12648c2ecf20Sopenharmony_ci return 0; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) > 1) { 12678c2ecf20Sopenharmony_ci pr_info("%s(): shifting inet->saddr from %pI4 to %pI4\n", 12688c2ecf20Sopenharmony_ci __func__, &old_saddr, &new_saddr); 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci inet->inet_saddr = inet->inet_rcv_saddr = new_saddr; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* 12748c2ecf20Sopenharmony_ci * XXX The only one ugly spot where we need to 12758c2ecf20Sopenharmony_ci * XXX really change the sockets identity after 12768c2ecf20Sopenharmony_ci * XXX it has entered the hashes. -DaveM 12778c2ecf20Sopenharmony_ci * 12788c2ecf20Sopenharmony_ci * Besides that, it does not check for connection 12798c2ecf20Sopenharmony_ci * uniqueness. Wait for troubles. 12808c2ecf20Sopenharmony_ci */ 12818c2ecf20Sopenharmony_ci return __sk_prot_rehash(sk); 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ciint inet_sk_rebuild_header(struct sock *sk) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 12878c2ecf20Sopenharmony_ci struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); 12888c2ecf20Sopenharmony_ci __be32 daddr; 12898c2ecf20Sopenharmony_ci struct ip_options_rcu *inet_opt; 12908c2ecf20Sopenharmony_ci struct flowi4 *fl4; 12918c2ecf20Sopenharmony_ci int err; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* Route is OK, nothing to do. */ 12948c2ecf20Sopenharmony_ci if (rt) 12958c2ecf20Sopenharmony_ci return 0; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* Reroute. */ 12988c2ecf20Sopenharmony_ci rcu_read_lock(); 12998c2ecf20Sopenharmony_ci inet_opt = rcu_dereference(inet->inet_opt); 13008c2ecf20Sopenharmony_ci daddr = inet->inet_daddr; 13018c2ecf20Sopenharmony_ci if (inet_opt && inet_opt->opt.srr) 13028c2ecf20Sopenharmony_ci daddr = inet_opt->opt.faddr; 13038c2ecf20Sopenharmony_ci rcu_read_unlock(); 13048c2ecf20Sopenharmony_ci fl4 = &inet->cork.fl.u.ip4; 13058c2ecf20Sopenharmony_ci rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, 13068c2ecf20Sopenharmony_ci inet->inet_dport, inet->inet_sport, 13078c2ecf20Sopenharmony_ci sk->sk_protocol, RT_CONN_FLAGS(sk), 13088c2ecf20Sopenharmony_ci sk->sk_bound_dev_if); 13098c2ecf20Sopenharmony_ci if (!IS_ERR(rt)) { 13108c2ecf20Sopenharmony_ci err = 0; 13118c2ecf20Sopenharmony_ci sk_setup_caps(sk, &rt->dst); 13128c2ecf20Sopenharmony_ci } else { 13138c2ecf20Sopenharmony_ci err = PTR_ERR(rt); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* Routing failed... */ 13168c2ecf20Sopenharmony_ci sk->sk_route_caps = 0; 13178c2ecf20Sopenharmony_ci /* 13188c2ecf20Sopenharmony_ci * Other protocols have to map its equivalent state to TCP_SYN_SENT. 13198c2ecf20Sopenharmony_ci * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme 13208c2ecf20Sopenharmony_ci */ 13218c2ecf20Sopenharmony_ci if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) || 13228c2ecf20Sopenharmony_ci sk->sk_state != TCP_SYN_SENT || 13238c2ecf20Sopenharmony_ci (sk->sk_userlocks & SOCK_BINDADDR_LOCK) || 13248c2ecf20Sopenharmony_ci (err = inet_sk_reselect_saddr(sk)) != 0) 13258c2ecf20Sopenharmony_ci sk->sk_err_soft = -err; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci return err; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_sk_rebuild_header); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_civoid inet_sk_set_state(struct sock *sk, int state) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci trace_inet_sock_set_state(sk, sk->sk_state, state); 13358c2ecf20Sopenharmony_ci sk->sk_state = state; 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_sk_set_state); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_civoid inet_sk_state_store(struct sock *sk, int newstate) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci trace_inet_sock_set_state(sk, sk->sk_state, newstate); 13428c2ecf20Sopenharmony_ci smp_store_release(&sk->sk_state, newstate); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistruct sk_buff *inet_gso_segment(struct sk_buff *skb, 13468c2ecf20Sopenharmony_ci netdev_features_t features) 13478c2ecf20Sopenharmony_ci{ 13488c2ecf20Sopenharmony_ci bool udpfrag = false, fixedid = false, gso_partial, encap; 13498c2ecf20Sopenharmony_ci struct sk_buff *segs = ERR_PTR(-EINVAL); 13508c2ecf20Sopenharmony_ci const struct net_offload *ops; 13518c2ecf20Sopenharmony_ci unsigned int offset = 0; 13528c2ecf20Sopenharmony_ci struct iphdr *iph; 13538c2ecf20Sopenharmony_ci int proto, tot_len; 13548c2ecf20Sopenharmony_ci int nhoff; 13558c2ecf20Sopenharmony_ci int ihl; 13568c2ecf20Sopenharmony_ci int id; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 13598c2ecf20Sopenharmony_ci nhoff = skb_network_header(skb) - skb_mac_header(skb); 13608c2ecf20Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) 13618c2ecf20Sopenharmony_ci goto out; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci iph = ip_hdr(skb); 13648c2ecf20Sopenharmony_ci ihl = iph->ihl * 4; 13658c2ecf20Sopenharmony_ci if (ihl < sizeof(*iph)) 13668c2ecf20Sopenharmony_ci goto out; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci id = ntohs(iph->id); 13698c2ecf20Sopenharmony_ci proto = iph->protocol; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci /* Warning: after this point, iph might be no longer valid */ 13728c2ecf20Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, ihl))) 13738c2ecf20Sopenharmony_ci goto out; 13748c2ecf20Sopenharmony_ci __skb_pull(skb, ihl); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci encap = SKB_GSO_CB(skb)->encap_level > 0; 13778c2ecf20Sopenharmony_ci if (encap) 13788c2ecf20Sopenharmony_ci features &= skb->dev->hw_enc_features; 13798c2ecf20Sopenharmony_ci SKB_GSO_CB(skb)->encap_level += ihl; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci segs = ERR_PTR(-EPROTONOSUPPORT); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (!skb->encapsulation || encap) { 13868c2ecf20Sopenharmony_ci udpfrag = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP); 13878c2ecf20Sopenharmony_ci fixedid = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* fixed ID is invalid if DF bit is not set */ 13908c2ecf20Sopenharmony_ci if (fixedid && !(ip_hdr(skb)->frag_off & htons(IP_DF))) 13918c2ecf20Sopenharmony_ci goto out; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci ops = rcu_dereference(inet_offloads[proto]); 13958c2ecf20Sopenharmony_ci if (likely(ops && ops->callbacks.gso_segment)) { 13968c2ecf20Sopenharmony_ci segs = ops->callbacks.gso_segment(skb, features); 13978c2ecf20Sopenharmony_ci if (!segs) 13988c2ecf20Sopenharmony_ci skb->network_header = skb_mac_header(skb) + nhoff - skb->head; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(segs)) 14028c2ecf20Sopenharmony_ci goto out; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci gso_partial = !!(skb_shinfo(segs)->gso_type & SKB_GSO_PARTIAL); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci skb = segs; 14078c2ecf20Sopenharmony_ci do { 14088c2ecf20Sopenharmony_ci iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); 14098c2ecf20Sopenharmony_ci if (udpfrag) { 14108c2ecf20Sopenharmony_ci iph->frag_off = htons(offset >> 3); 14118c2ecf20Sopenharmony_ci if (skb->next) 14128c2ecf20Sopenharmony_ci iph->frag_off |= htons(IP_MF); 14138c2ecf20Sopenharmony_ci offset += skb->len - nhoff - ihl; 14148c2ecf20Sopenharmony_ci tot_len = skb->len - nhoff; 14158c2ecf20Sopenharmony_ci } else if (skb_is_gso(skb)) { 14168c2ecf20Sopenharmony_ci if (!fixedid) { 14178c2ecf20Sopenharmony_ci iph->id = htons(id); 14188c2ecf20Sopenharmony_ci id += skb_shinfo(skb)->gso_segs; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (gso_partial) 14228c2ecf20Sopenharmony_ci tot_len = skb_shinfo(skb)->gso_size + 14238c2ecf20Sopenharmony_ci SKB_GSO_CB(skb)->data_offset + 14248c2ecf20Sopenharmony_ci skb->head - (unsigned char *)iph; 14258c2ecf20Sopenharmony_ci else 14268c2ecf20Sopenharmony_ci tot_len = skb->len - nhoff; 14278c2ecf20Sopenharmony_ci } else { 14288c2ecf20Sopenharmony_ci if (!fixedid) 14298c2ecf20Sopenharmony_ci iph->id = htons(id++); 14308c2ecf20Sopenharmony_ci tot_len = skb->len - nhoff; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci iph->tot_len = htons(tot_len); 14338c2ecf20Sopenharmony_ci ip_send_check(iph); 14348c2ecf20Sopenharmony_ci if (encap) 14358c2ecf20Sopenharmony_ci skb_reset_inner_headers(skb); 14368c2ecf20Sopenharmony_ci skb->network_header = (u8 *)iph - skb->head; 14378c2ecf20Sopenharmony_ci skb_reset_mac_len(skb); 14388c2ecf20Sopenharmony_ci } while ((skb = skb->next)); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ciout: 14418c2ecf20Sopenharmony_ci return segs; 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_gso_segment); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic struct sk_buff *ipip_gso_segment(struct sk_buff *skb, 14468c2ecf20Sopenharmony_ci netdev_features_t features) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP4)) 14498c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci return inet_gso_segment(skb, features); 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_cistruct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb) 14558c2ecf20Sopenharmony_ci{ 14568c2ecf20Sopenharmony_ci const struct net_offload *ops; 14578c2ecf20Sopenharmony_ci struct sk_buff *pp = NULL; 14588c2ecf20Sopenharmony_ci const struct iphdr *iph; 14598c2ecf20Sopenharmony_ci struct sk_buff *p; 14608c2ecf20Sopenharmony_ci unsigned int hlen; 14618c2ecf20Sopenharmony_ci unsigned int off; 14628c2ecf20Sopenharmony_ci unsigned int id; 14638c2ecf20Sopenharmony_ci int flush = 1; 14648c2ecf20Sopenharmony_ci int proto; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci off = skb_gro_offset(skb); 14678c2ecf20Sopenharmony_ci hlen = off + sizeof(*iph); 14688c2ecf20Sopenharmony_ci iph = skb_gro_header_fast(skb, off); 14698c2ecf20Sopenharmony_ci if (skb_gro_header_hard(skb, hlen)) { 14708c2ecf20Sopenharmony_ci iph = skb_gro_header_slow(skb, hlen, off); 14718c2ecf20Sopenharmony_ci if (unlikely(!iph)) 14728c2ecf20Sopenharmony_ci goto out; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci proto = iph->protocol; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci rcu_read_lock(); 14788c2ecf20Sopenharmony_ci ops = rcu_dereference(inet_offloads[proto]); 14798c2ecf20Sopenharmony_ci if (!ops || !ops->callbacks.gro_receive) 14808c2ecf20Sopenharmony_ci goto out_unlock; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci if (*(u8 *)iph != 0x45) 14838c2ecf20Sopenharmony_ci goto out_unlock; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci if (ip_is_fragment(iph)) 14868c2ecf20Sopenharmony_ci goto out_unlock; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (unlikely(ip_fast_csum((u8 *)iph, 5))) 14898c2ecf20Sopenharmony_ci goto out_unlock; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci id = ntohl(*(__be32 *)&iph->id); 14928c2ecf20Sopenharmony_ci flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF)); 14938c2ecf20Sopenharmony_ci id >>= 16; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci list_for_each_entry(p, head, list) { 14968c2ecf20Sopenharmony_ci struct iphdr *iph2; 14978c2ecf20Sopenharmony_ci u16 flush_id; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (!NAPI_GRO_CB(p)->same_flow) 15008c2ecf20Sopenharmony_ci continue; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci iph2 = (struct iphdr *)(p->data + off); 15038c2ecf20Sopenharmony_ci /* The above works because, with the exception of the top 15048c2ecf20Sopenharmony_ci * (inner most) layer, we only aggregate pkts with the same 15058c2ecf20Sopenharmony_ci * hdr length so all the hdrs we'll need to verify will start 15068c2ecf20Sopenharmony_ci * at the same offset. 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_ci if ((iph->protocol ^ iph2->protocol) | 15098c2ecf20Sopenharmony_ci ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) | 15108c2ecf20Sopenharmony_ci ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) { 15118c2ecf20Sopenharmony_ci NAPI_GRO_CB(p)->same_flow = 0; 15128c2ecf20Sopenharmony_ci continue; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* All fields must match except length and checksum. */ 15168c2ecf20Sopenharmony_ci NAPI_GRO_CB(p)->flush |= 15178c2ecf20Sopenharmony_ci (iph->ttl ^ iph2->ttl) | 15188c2ecf20Sopenharmony_ci (iph->tos ^ iph2->tos) | 15198c2ecf20Sopenharmony_ci ((iph->frag_off ^ iph2->frag_off) & htons(IP_DF)); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci NAPI_GRO_CB(p)->flush |= flush; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* We need to store of the IP ID check to be included later 15248c2ecf20Sopenharmony_ci * when we can verify that this packet does in fact belong 15258c2ecf20Sopenharmony_ci * to a given flow. 15268c2ecf20Sopenharmony_ci */ 15278c2ecf20Sopenharmony_ci flush_id = (u16)(id - ntohs(iph2->id)); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci /* This bit of code makes it much easier for us to identify 15308c2ecf20Sopenharmony_ci * the cases where we are doing atomic vs non-atomic IP ID 15318c2ecf20Sopenharmony_ci * checks. Specifically an atomic check can return IP ID 15328c2ecf20Sopenharmony_ci * values 0 - 0xFFFF, while a non-atomic check can only 15338c2ecf20Sopenharmony_ci * return 0 or 0xFFFF. 15348c2ecf20Sopenharmony_ci */ 15358c2ecf20Sopenharmony_ci if (!NAPI_GRO_CB(p)->is_atomic || 15368c2ecf20Sopenharmony_ci !(iph->frag_off & htons(IP_DF))) { 15378c2ecf20Sopenharmony_ci flush_id ^= NAPI_GRO_CB(p)->count; 15388c2ecf20Sopenharmony_ci flush_id = flush_id ? 0xFFFF : 0; 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci /* If the previous IP ID value was based on an atomic 15428c2ecf20Sopenharmony_ci * datagram we can overwrite the value and ignore it. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci if (NAPI_GRO_CB(skb)->is_atomic) 15458c2ecf20Sopenharmony_ci NAPI_GRO_CB(p)->flush_id = flush_id; 15468c2ecf20Sopenharmony_ci else 15478c2ecf20Sopenharmony_ci NAPI_GRO_CB(p)->flush_id |= flush_id; 15488c2ecf20Sopenharmony_ci } 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci NAPI_GRO_CB(skb)->is_atomic = !!(iph->frag_off & htons(IP_DF)); 15518c2ecf20Sopenharmony_ci NAPI_GRO_CB(skb)->flush |= flush; 15528c2ecf20Sopenharmony_ci skb_set_network_header(skb, off); 15538c2ecf20Sopenharmony_ci /* The above will be needed by the transport layer if there is one 15548c2ecf20Sopenharmony_ci * immediately following this IP hdr. 15558c2ecf20Sopenharmony_ci */ 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci /* Note : No need to call skb_gro_postpull_rcsum() here, 15588c2ecf20Sopenharmony_ci * as we already checked checksum over ipv4 header was 0 15598c2ecf20Sopenharmony_ci */ 15608c2ecf20Sopenharmony_ci skb_gro_pull(skb, sizeof(*iph)); 15618c2ecf20Sopenharmony_ci skb_set_transport_header(skb, skb_gro_offset(skb)); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci pp = indirect_call_gro_receive(tcp4_gro_receive, udp4_gro_receive, 15648c2ecf20Sopenharmony_ci ops->callbacks.gro_receive, head, skb); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ciout_unlock: 15678c2ecf20Sopenharmony_ci rcu_read_unlock(); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ciout: 15708c2ecf20Sopenharmony_ci skb_gro_flush_final(skb, pp, flush); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci return pp; 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_gro_receive); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic struct sk_buff *ipip_gro_receive(struct list_head *head, 15778c2ecf20Sopenharmony_ci struct sk_buff *skb) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci if (NAPI_GRO_CB(skb)->encap_mark) { 15808c2ecf20Sopenharmony_ci NAPI_GRO_CB(skb)->flush = 1; 15818c2ecf20Sopenharmony_ci return NULL; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci NAPI_GRO_CB(skb)->encap_mark = 1; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci return inet_gro_receive(head, skb); 15878c2ecf20Sopenharmony_ci} 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci#define SECONDS_PER_DAY 86400 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci/* inet_current_timestamp - Return IP network timestamp 15928c2ecf20Sopenharmony_ci * 15938c2ecf20Sopenharmony_ci * Return milliseconds since midnight in network byte order. 15948c2ecf20Sopenharmony_ci */ 15958c2ecf20Sopenharmony_ci__be32 inet_current_timestamp(void) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci u32 secs; 15988c2ecf20Sopenharmony_ci u32 msecs; 15998c2ecf20Sopenharmony_ci struct timespec64 ts; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci ktime_get_real_ts64(&ts); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci /* Get secs since midnight. */ 16048c2ecf20Sopenharmony_ci (void)div_u64_rem(ts.tv_sec, SECONDS_PER_DAY, &secs); 16058c2ecf20Sopenharmony_ci /* Convert to msecs. */ 16068c2ecf20Sopenharmony_ci msecs = secs * MSEC_PER_SEC; 16078c2ecf20Sopenharmony_ci /* Convert nsec to msec. */ 16088c2ecf20Sopenharmony_ci msecs += (u32)ts.tv_nsec / NSEC_PER_MSEC; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci /* Convert to network byte order. */ 16118c2ecf20Sopenharmony_ci return htonl(msecs); 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_current_timestamp); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ciint inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci unsigned int family = READ_ONCE(sk->sk_family); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci if (family == AF_INET) 16208c2ecf20Sopenharmony_ci return ip_recv_error(sk, msg, len, addr_len); 16218c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 16228c2ecf20Sopenharmony_ci if (family == AF_INET6) 16238c2ecf20Sopenharmony_ci return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len); 16248c2ecf20Sopenharmony_ci#endif 16258c2ecf20Sopenharmony_ci return -EINVAL; 16268c2ecf20Sopenharmony_ci} 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ciint inet_gro_complete(struct sk_buff *skb, int nhoff) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci __be16 newlen = htons(skb->len - nhoff); 16318c2ecf20Sopenharmony_ci struct iphdr *iph = (struct iphdr *)(skb->data + nhoff); 16328c2ecf20Sopenharmony_ci const struct net_offload *ops; 16338c2ecf20Sopenharmony_ci int proto = iph->protocol; 16348c2ecf20Sopenharmony_ci int err = -ENOSYS; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci if (skb->encapsulation) { 16378c2ecf20Sopenharmony_ci skb_set_inner_protocol(skb, cpu_to_be16(ETH_P_IP)); 16388c2ecf20Sopenharmony_ci skb_set_inner_network_header(skb, nhoff); 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci csum_replace2(&iph->check, iph->tot_len, newlen); 16428c2ecf20Sopenharmony_ci iph->tot_len = newlen; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci rcu_read_lock(); 16458c2ecf20Sopenharmony_ci ops = rcu_dereference(inet_offloads[proto]); 16468c2ecf20Sopenharmony_ci if (WARN_ON(!ops || !ops->callbacks.gro_complete)) 16478c2ecf20Sopenharmony_ci goto out_unlock; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* Only need to add sizeof(*iph) to get to the next hdr below 16508c2ecf20Sopenharmony_ci * because any hdr with option will have been flushed in 16518c2ecf20Sopenharmony_ci * inet_gro_receive(). 16528c2ecf20Sopenharmony_ci */ 16538c2ecf20Sopenharmony_ci err = INDIRECT_CALL_2(ops->callbacks.gro_complete, 16548c2ecf20Sopenharmony_ci tcp4_gro_complete, udp4_gro_complete, 16558c2ecf20Sopenharmony_ci skb, nhoff + sizeof(*iph)); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ciout_unlock: 16588c2ecf20Sopenharmony_ci rcu_read_unlock(); 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci return err; 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(inet_gro_complete); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_cistatic int ipip_gro_complete(struct sk_buff *skb, int nhoff) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci skb->encapsulation = 1; 16678c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP4; 16688c2ecf20Sopenharmony_ci return inet_gro_complete(skb, nhoff); 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ciint inet_ctl_sock_create(struct sock **sk, unsigned short family, 16728c2ecf20Sopenharmony_ci unsigned short type, unsigned char protocol, 16738c2ecf20Sopenharmony_ci struct net *net) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci struct socket *sock; 16768c2ecf20Sopenharmony_ci int rc = sock_create_kern(net, family, type, protocol, &sock); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (rc == 0) { 16798c2ecf20Sopenharmony_ci *sk = sock->sk; 16808c2ecf20Sopenharmony_ci (*sk)->sk_allocation = GFP_ATOMIC; 16818c2ecf20Sopenharmony_ci /* 16828c2ecf20Sopenharmony_ci * Unhash it so that IP input processing does not even see it, 16838c2ecf20Sopenharmony_ci * we do not wish this socket to see incoming packets. 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ci (*sk)->sk_prot->unhash(*sk); 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci return rc; 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(inet_ctl_sock_create); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ciu64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offt) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci return *(((unsigned long *)per_cpu_ptr(mib, cpu)) + offt); 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snmp_get_cpu_field); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ciunsigned long snmp_fold_field(void __percpu *mib, int offt) 16988c2ecf20Sopenharmony_ci{ 16998c2ecf20Sopenharmony_ci unsigned long res = 0; 17008c2ecf20Sopenharmony_ci int i; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci for_each_possible_cpu(i) 17038c2ecf20Sopenharmony_ci res += snmp_get_cpu_field(mib, i, offt); 17048c2ecf20Sopenharmony_ci return res; 17058c2ecf20Sopenharmony_ci} 17068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snmp_fold_field); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci#if BITS_PER_LONG==32 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ciu64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offt, 17118c2ecf20Sopenharmony_ci size_t syncp_offset) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci void *bhptr; 17148c2ecf20Sopenharmony_ci struct u64_stats_sync *syncp; 17158c2ecf20Sopenharmony_ci u64 v; 17168c2ecf20Sopenharmony_ci unsigned int start; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci bhptr = per_cpu_ptr(mib, cpu); 17198c2ecf20Sopenharmony_ci syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); 17208c2ecf20Sopenharmony_ci do { 17218c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(syncp); 17228c2ecf20Sopenharmony_ci v = *(((u64 *)bhptr) + offt); 17238c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(syncp, start)); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci return v; 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snmp_get_cpu_field64); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ciu64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_offset) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci u64 res = 0; 17328c2ecf20Sopenharmony_ci int cpu; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 17358c2ecf20Sopenharmony_ci res += snmp_get_cpu_field64(mib, cpu, offt, syncp_offset); 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci return res; 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snmp_fold_field64); 17408c2ecf20Sopenharmony_ci#endif 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci#ifdef CONFIG_IP_MULTICAST 17438c2ecf20Sopenharmony_cistatic const struct net_protocol igmp_protocol = { 17448c2ecf20Sopenharmony_ci .handler = igmp_rcv, 17458c2ecf20Sopenharmony_ci .netns_ok = 1, 17468c2ecf20Sopenharmony_ci}; 17478c2ecf20Sopenharmony_ci#endif 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic const struct net_protocol tcp_protocol = { 17508c2ecf20Sopenharmony_ci .handler = tcp_v4_rcv, 17518c2ecf20Sopenharmony_ci .err_handler = tcp_v4_err, 17528c2ecf20Sopenharmony_ci .no_policy = 1, 17538c2ecf20Sopenharmony_ci .netns_ok = 1, 17548c2ecf20Sopenharmony_ci .icmp_strict_tag_validation = 1, 17558c2ecf20Sopenharmony_ci}; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_cistatic const struct net_protocol udp_protocol = { 17588c2ecf20Sopenharmony_ci .handler = udp_rcv, 17598c2ecf20Sopenharmony_ci .err_handler = udp_err, 17608c2ecf20Sopenharmony_ci .no_policy = 1, 17618c2ecf20Sopenharmony_ci .netns_ok = 1, 17628c2ecf20Sopenharmony_ci}; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_cistatic const struct net_protocol icmp_protocol = { 17658c2ecf20Sopenharmony_ci .handler = icmp_rcv, 17668c2ecf20Sopenharmony_ci .err_handler = icmp_err, 17678c2ecf20Sopenharmony_ci .no_policy = 1, 17688c2ecf20Sopenharmony_ci .netns_ok = 1, 17698c2ecf20Sopenharmony_ci}; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_cistatic __net_init int ipv4_mib_init_net(struct net *net) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci int i; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci net->mib.tcp_statistics = alloc_percpu(struct tcp_mib); 17768c2ecf20Sopenharmony_ci if (!net->mib.tcp_statistics) 17778c2ecf20Sopenharmony_ci goto err_tcp_mib; 17788c2ecf20Sopenharmony_ci net->mib.ip_statistics = alloc_percpu(struct ipstats_mib); 17798c2ecf20Sopenharmony_ci if (!net->mib.ip_statistics) 17808c2ecf20Sopenharmony_ci goto err_ip_mib; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 17838c2ecf20Sopenharmony_ci struct ipstats_mib *af_inet_stats; 17848c2ecf20Sopenharmony_ci af_inet_stats = per_cpu_ptr(net->mib.ip_statistics, i); 17858c2ecf20Sopenharmony_ci u64_stats_init(&af_inet_stats->syncp); 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci net->mib.net_statistics = alloc_percpu(struct linux_mib); 17898c2ecf20Sopenharmony_ci if (!net->mib.net_statistics) 17908c2ecf20Sopenharmony_ci goto err_net_mib; 17918c2ecf20Sopenharmony_ci net->mib.udp_statistics = alloc_percpu(struct udp_mib); 17928c2ecf20Sopenharmony_ci if (!net->mib.udp_statistics) 17938c2ecf20Sopenharmony_ci goto err_udp_mib; 17948c2ecf20Sopenharmony_ci net->mib.udplite_statistics = alloc_percpu(struct udp_mib); 17958c2ecf20Sopenharmony_ci if (!net->mib.udplite_statistics) 17968c2ecf20Sopenharmony_ci goto err_udplite_mib; 17978c2ecf20Sopenharmony_ci net->mib.icmp_statistics = alloc_percpu(struct icmp_mib); 17988c2ecf20Sopenharmony_ci if (!net->mib.icmp_statistics) 17998c2ecf20Sopenharmony_ci goto err_icmp_mib; 18008c2ecf20Sopenharmony_ci net->mib.icmpmsg_statistics = kzalloc(sizeof(struct icmpmsg_mib), 18018c2ecf20Sopenharmony_ci GFP_KERNEL); 18028c2ecf20Sopenharmony_ci if (!net->mib.icmpmsg_statistics) 18038c2ecf20Sopenharmony_ci goto err_icmpmsg_mib; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci tcp_mib_init(net); 18068c2ecf20Sopenharmony_ci return 0; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cierr_icmpmsg_mib: 18098c2ecf20Sopenharmony_ci free_percpu(net->mib.icmp_statistics); 18108c2ecf20Sopenharmony_cierr_icmp_mib: 18118c2ecf20Sopenharmony_ci free_percpu(net->mib.udplite_statistics); 18128c2ecf20Sopenharmony_cierr_udplite_mib: 18138c2ecf20Sopenharmony_ci free_percpu(net->mib.udp_statistics); 18148c2ecf20Sopenharmony_cierr_udp_mib: 18158c2ecf20Sopenharmony_ci free_percpu(net->mib.net_statistics); 18168c2ecf20Sopenharmony_cierr_net_mib: 18178c2ecf20Sopenharmony_ci free_percpu(net->mib.ip_statistics); 18188c2ecf20Sopenharmony_cierr_ip_mib: 18198c2ecf20Sopenharmony_ci free_percpu(net->mib.tcp_statistics); 18208c2ecf20Sopenharmony_cierr_tcp_mib: 18218c2ecf20Sopenharmony_ci return -ENOMEM; 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic __net_exit void ipv4_mib_exit_net(struct net *net) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci kfree(net->mib.icmpmsg_statistics); 18278c2ecf20Sopenharmony_ci free_percpu(net->mib.icmp_statistics); 18288c2ecf20Sopenharmony_ci free_percpu(net->mib.udplite_statistics); 18298c2ecf20Sopenharmony_ci free_percpu(net->mib.udp_statistics); 18308c2ecf20Sopenharmony_ci free_percpu(net->mib.net_statistics); 18318c2ecf20Sopenharmony_ci free_percpu(net->mib.ip_statistics); 18328c2ecf20Sopenharmony_ci free_percpu(net->mib.tcp_statistics); 18338c2ecf20Sopenharmony_ci#ifdef CONFIG_MPTCP 18348c2ecf20Sopenharmony_ci /* allocated on demand, see mptcp_init_sock() */ 18358c2ecf20Sopenharmony_ci free_percpu(net->mib.mptcp_statistics); 18368c2ecf20Sopenharmony_ci#endif 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_cistatic __net_initdata struct pernet_operations ipv4_mib_ops = { 18408c2ecf20Sopenharmony_ci .init = ipv4_mib_init_net, 18418c2ecf20Sopenharmony_ci .exit = ipv4_mib_exit_net, 18428c2ecf20Sopenharmony_ci}; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cistatic int __init init_ipv4_mibs(void) 18458c2ecf20Sopenharmony_ci{ 18468c2ecf20Sopenharmony_ci return register_pernet_subsys(&ipv4_mib_ops); 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_cistatic __net_init int inet_init_net(struct net *net) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci /* 18528c2ecf20Sopenharmony_ci * Set defaults for local port range 18538c2ecf20Sopenharmony_ci */ 18548c2ecf20Sopenharmony_ci seqlock_init(&net->ipv4.ip_local_ports.lock); 18558c2ecf20Sopenharmony_ci net->ipv4.ip_local_ports.range[0] = 32768; 18568c2ecf20Sopenharmony_ci net->ipv4.ip_local_ports.range[1] = 60999; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci seqlock_init(&net->ipv4.ping_group_range.lock); 18598c2ecf20Sopenharmony_ci /* 18608c2ecf20Sopenharmony_ci * Sane defaults - nobody may create ping sockets. 18618c2ecf20Sopenharmony_ci * Boot scripts should set this to distro-specific group. 18628c2ecf20Sopenharmony_ci */ 18638c2ecf20Sopenharmony_ci net->ipv4.ping_group_range.range[0] = make_kgid(&init_user_ns, 1); 18648c2ecf20Sopenharmony_ci net->ipv4.ping_group_range.range[1] = make_kgid(&init_user_ns, 0); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci /* Default values for sysctl-controlled parameters. 18678c2ecf20Sopenharmony_ci * We set them here, in case sysctl is not compiled. 18688c2ecf20Sopenharmony_ci */ 18698c2ecf20Sopenharmony_ci net->ipv4.sysctl_ip_default_ttl = IPDEFTTL; 18708c2ecf20Sopenharmony_ci net->ipv4.sysctl_ip_fwd_update_priority = 1; 18718c2ecf20Sopenharmony_ci net->ipv4.sysctl_ip_dynaddr = 0; 18728c2ecf20Sopenharmony_ci net->ipv4.sysctl_ip_early_demux = 1; 18738c2ecf20Sopenharmony_ci net->ipv4.sysctl_udp_early_demux = 1; 18748c2ecf20Sopenharmony_ci net->ipv4.sysctl_tcp_early_demux = 1; 18758c2ecf20Sopenharmony_ci net->ipv4.sysctl_nexthop_compat_mode = 1; 18768c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSCTL 18778c2ecf20Sopenharmony_ci net->ipv4.sysctl_ip_prot_sock = PROT_SOCK; 18788c2ecf20Sopenharmony_ci#endif 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci /* Some igmp sysctl, whose values are always used */ 18818c2ecf20Sopenharmony_ci net->ipv4.sysctl_igmp_max_memberships = 20; 18828c2ecf20Sopenharmony_ci net->ipv4.sysctl_igmp_max_msf = 10; 18838c2ecf20Sopenharmony_ci /* IGMP reports for link-local multicast groups are enabled by default */ 18848c2ecf20Sopenharmony_ci net->ipv4.sysctl_igmp_llm_reports = 1; 18858c2ecf20Sopenharmony_ci net->ipv4.sysctl_igmp_qrv = 2; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci#ifdef CONFIG_LOWPOWER_PROTOCOL 18888c2ecf20Sopenharmony_ci lowpower_protocol_net_init(net); 18898c2ecf20Sopenharmony_ci#endif /* CONFIG_LOWPOWER_PROTOCOL */ 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic __net_initdata struct pernet_operations af_inet_ops = { 18948c2ecf20Sopenharmony_ci .init = inet_init_net, 18958c2ecf20Sopenharmony_ci}; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_cistatic int __init init_inet_pernet_ops(void) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci return register_pernet_subsys(&af_inet_ops); 19008c2ecf20Sopenharmony_ci} 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_cistatic int ipv4_proc_init(void); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci/* 19058c2ecf20Sopenharmony_ci * IP protocol layer initialiser 19068c2ecf20Sopenharmony_ci */ 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic struct packet_offload ip_packet_offload __read_mostly = { 19098c2ecf20Sopenharmony_ci .type = cpu_to_be16(ETH_P_IP), 19108c2ecf20Sopenharmony_ci .callbacks = { 19118c2ecf20Sopenharmony_ci .gso_segment = inet_gso_segment, 19128c2ecf20Sopenharmony_ci .gro_receive = inet_gro_receive, 19138c2ecf20Sopenharmony_ci .gro_complete = inet_gro_complete, 19148c2ecf20Sopenharmony_ci }, 19158c2ecf20Sopenharmony_ci}; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic const struct net_offload ipip_offload = { 19188c2ecf20Sopenharmony_ci .callbacks = { 19198c2ecf20Sopenharmony_ci .gso_segment = ipip_gso_segment, 19208c2ecf20Sopenharmony_ci .gro_receive = ipip_gro_receive, 19218c2ecf20Sopenharmony_ci .gro_complete = ipip_gro_complete, 19228c2ecf20Sopenharmony_ci }, 19238c2ecf20Sopenharmony_ci}; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic int __init ipip_offload_init(void) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci return inet_add_offload(&ipip_offload, IPPROTO_IPIP); 19288c2ecf20Sopenharmony_ci} 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_cistatic int __init ipv4_offload_init(void) 19318c2ecf20Sopenharmony_ci{ 19328c2ecf20Sopenharmony_ci /* 19338c2ecf20Sopenharmony_ci * Add offloads 19348c2ecf20Sopenharmony_ci */ 19358c2ecf20Sopenharmony_ci if (udpv4_offload_init() < 0) 19368c2ecf20Sopenharmony_ci pr_crit("%s: Cannot add UDP protocol offload\n", __func__); 19378c2ecf20Sopenharmony_ci if (tcpv4_offload_init() < 0) 19388c2ecf20Sopenharmony_ci pr_crit("%s: Cannot add TCP protocol offload\n", __func__); 19398c2ecf20Sopenharmony_ci if (ipip_offload_init() < 0) 19408c2ecf20Sopenharmony_ci pr_crit("%s: Cannot add IPIP protocol offload\n", __func__); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci dev_add_offload(&ip_packet_offload); 19438c2ecf20Sopenharmony_ci return 0; 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_cifs_initcall(ipv4_offload_init); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_cistatic struct packet_type ip_packet_type __read_mostly = { 19498c2ecf20Sopenharmony_ci .type = cpu_to_be16(ETH_P_IP), 19508c2ecf20Sopenharmony_ci .func = ip_rcv, 19518c2ecf20Sopenharmony_ci .list_func = ip_list_rcv, 19528c2ecf20Sopenharmony_ci}; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_cistatic int __init inet_init(void) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci struct inet_protosw *q; 19578c2ecf20Sopenharmony_ci struct list_head *r; 19588c2ecf20Sopenharmony_ci int rc; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci sock_skb_cb_check_size(sizeof(struct inet_skb_parm)); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci rc = proto_register(&tcp_prot, 1); 19638c2ecf20Sopenharmony_ci if (rc) 19648c2ecf20Sopenharmony_ci goto out; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci rc = proto_register(&udp_prot, 1); 19678c2ecf20Sopenharmony_ci if (rc) 19688c2ecf20Sopenharmony_ci goto out_unregister_tcp_proto; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci rc = proto_register(&raw_prot, 1); 19718c2ecf20Sopenharmony_ci if (rc) 19728c2ecf20Sopenharmony_ci goto out_unregister_udp_proto; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci rc = proto_register(&ping_prot, 1); 19758c2ecf20Sopenharmony_ci if (rc) 19768c2ecf20Sopenharmony_ci goto out_unregister_raw_proto; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci /* 19798c2ecf20Sopenharmony_ci * Tell SOCKET that we are alive... 19808c2ecf20Sopenharmony_ci */ 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci (void)sock_register(&inet_family_ops); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSCTL 19858c2ecf20Sopenharmony_ci ip_static_sysctl_init(); 19868c2ecf20Sopenharmony_ci#endif 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci /* 19898c2ecf20Sopenharmony_ci * Add all the base protocols. 19908c2ecf20Sopenharmony_ci */ 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) 19938c2ecf20Sopenharmony_ci pr_crit("%s: Cannot add ICMP protocol\n", __func__); 19948c2ecf20Sopenharmony_ci if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) 19958c2ecf20Sopenharmony_ci pr_crit("%s: Cannot add UDP protocol\n", __func__); 19968c2ecf20Sopenharmony_ci if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) 19978c2ecf20Sopenharmony_ci pr_crit("%s: Cannot add TCP protocol\n", __func__); 19988c2ecf20Sopenharmony_ci#ifdef CONFIG_IP_MULTICAST 19998c2ecf20Sopenharmony_ci if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) 20008c2ecf20Sopenharmony_ci pr_crit("%s: Cannot add IGMP protocol\n", __func__); 20018c2ecf20Sopenharmony_ci#endif 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci /* Register the socket-side information for inet_create. */ 20048c2ecf20Sopenharmony_ci for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r) 20058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(r); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q) 20088c2ecf20Sopenharmony_ci inet_register_protosw(q); 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci /* 20118c2ecf20Sopenharmony_ci * Set the ARP module up 20128c2ecf20Sopenharmony_ci */ 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci arp_init(); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci /* 20178c2ecf20Sopenharmony_ci * Set the IP module up 20188c2ecf20Sopenharmony_ci */ 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci ip_init(); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* Initialise per-cpu ipv4 mibs */ 20238c2ecf20Sopenharmony_ci if (init_ipv4_mibs()) 20248c2ecf20Sopenharmony_ci panic("%s: Cannot init ipv4 mibs\n", __func__); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci /* Setup TCP slab cache for open requests. */ 20278c2ecf20Sopenharmony_ci tcp_init(); 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci /* Setup UDP memory threshold */ 20308c2ecf20Sopenharmony_ci udp_init(); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci /* Add UDP-Lite (RFC 3828) */ 20338c2ecf20Sopenharmony_ci udplite4_register(); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci raw_init(); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci ping_init(); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci /* 20408c2ecf20Sopenharmony_ci * Set the ICMP layer up 20418c2ecf20Sopenharmony_ci */ 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci if (icmp_init() < 0) 20448c2ecf20Sopenharmony_ci panic("Failed to create the ICMP control socket.\n"); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci /* 20478c2ecf20Sopenharmony_ci * Initialise the multicast router 20488c2ecf20Sopenharmony_ci */ 20498c2ecf20Sopenharmony_ci#if defined(CONFIG_IP_MROUTE) 20508c2ecf20Sopenharmony_ci if (ip_mr_init()) 20518c2ecf20Sopenharmony_ci pr_crit("%s: Cannot init ipv4 mroute\n", __func__); 20528c2ecf20Sopenharmony_ci#endif 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci if (init_inet_pernet_ops()) 20558c2ecf20Sopenharmony_ci pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci ipv4_proc_init(); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci ipfrag_init(); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci dev_add_pack(&ip_packet_type); 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci ip_tunnel_core_init(); 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci rc = 0; 20668c2ecf20Sopenharmony_ciout: 20678c2ecf20Sopenharmony_ci return rc; 20688c2ecf20Sopenharmony_ciout_unregister_raw_proto: 20698c2ecf20Sopenharmony_ci proto_unregister(&raw_prot); 20708c2ecf20Sopenharmony_ciout_unregister_udp_proto: 20718c2ecf20Sopenharmony_ci proto_unregister(&udp_prot); 20728c2ecf20Sopenharmony_ciout_unregister_tcp_proto: 20738c2ecf20Sopenharmony_ci proto_unregister(&tcp_prot); 20748c2ecf20Sopenharmony_ci goto out; 20758c2ecf20Sopenharmony_ci} 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_cifs_initcall(inet_init); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */ 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 20828c2ecf20Sopenharmony_cistatic int __init ipv4_proc_init(void) 20838c2ecf20Sopenharmony_ci{ 20848c2ecf20Sopenharmony_ci int rc = 0; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (raw_proc_init()) 20878c2ecf20Sopenharmony_ci goto out_raw; 20888c2ecf20Sopenharmony_ci if (tcp4_proc_init()) 20898c2ecf20Sopenharmony_ci goto out_tcp; 20908c2ecf20Sopenharmony_ci if (udp4_proc_init()) 20918c2ecf20Sopenharmony_ci goto out_udp; 20928c2ecf20Sopenharmony_ci if (ping_proc_init()) 20938c2ecf20Sopenharmony_ci goto out_ping; 20948c2ecf20Sopenharmony_ci if (ip_misc_proc_init()) 20958c2ecf20Sopenharmony_ci goto out_misc; 20968c2ecf20Sopenharmony_ciout: 20978c2ecf20Sopenharmony_ci return rc; 20988c2ecf20Sopenharmony_ciout_misc: 20998c2ecf20Sopenharmony_ci ping_proc_exit(); 21008c2ecf20Sopenharmony_ciout_ping: 21018c2ecf20Sopenharmony_ci udp4_proc_exit(); 21028c2ecf20Sopenharmony_ciout_udp: 21038c2ecf20Sopenharmony_ci tcp4_proc_exit(); 21048c2ecf20Sopenharmony_ciout_tcp: 21058c2ecf20Sopenharmony_ci raw_proc_exit(); 21068c2ecf20Sopenharmony_ciout_raw: 21078c2ecf20Sopenharmony_ci rc = -ENOMEM; 21088c2ecf20Sopenharmony_ci goto out; 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci#else /* CONFIG_PROC_FS */ 21128c2ecf20Sopenharmony_cistatic int __init ipv4_proc_init(void) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci return 0; 21158c2ecf20Sopenharmony_ci} 21168c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 2117