18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/net/sunrpc/svcsock.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * These are the RPC server socket internals. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * The server scheduling algorithm does not always distribute the load 88c2ecf20Sopenharmony_ci * evenly when servicing a single client. May need to modify the 98c2ecf20Sopenharmony_ci * svc_xprt_enqueue procedure... 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * TCP support is largely untested and may be a little slow. The problem 128c2ecf20Sopenharmony_ci * is that we currently do two separate recvfrom's, one for the 4-byte 138c2ecf20Sopenharmony_ci * record length, and the second for the actual record. This could possibly 148c2ecf20Sopenharmony_ci * be improved by always reading a minimum size of around 100 bytes and 158c2ecf20Sopenharmony_ci * tucking any superfluous bytes away in a temporary store. Still, that 168c2ecf20Sopenharmony_ci * leaves write requests out in the rain. An alternative may be to peek at 178c2ecf20Sopenharmony_ci * the first skb in the queue, and if it matches the next TCP sequence 188c2ecf20Sopenharmony_ci * number, to extract the record marker. Yuck. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/sched.h> 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/errno.h> 278c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 288c2ecf20Sopenharmony_ci#include <linux/net.h> 298c2ecf20Sopenharmony_ci#include <linux/in.h> 308c2ecf20Sopenharmony_ci#include <linux/inet.h> 318c2ecf20Sopenharmony_ci#include <linux/udp.h> 328c2ecf20Sopenharmony_ci#include <linux/tcp.h> 338c2ecf20Sopenharmony_ci#include <linux/unistd.h> 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 368c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 378c2ecf20Sopenharmony_ci#include <linux/file.h> 388c2ecf20Sopenharmony_ci#include <linux/freezer.h> 398c2ecf20Sopenharmony_ci#include <net/sock.h> 408c2ecf20Sopenharmony_ci#include <net/checksum.h> 418c2ecf20Sopenharmony_ci#include <net/ip.h> 428c2ecf20Sopenharmony_ci#include <net/ipv6.h> 438c2ecf20Sopenharmony_ci#include <net/udp.h> 448c2ecf20Sopenharmony_ci#include <net/tcp.h> 458c2ecf20Sopenharmony_ci#include <net/tcp_states.h> 468c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 478c2ecf20Sopenharmony_ci#include <linux/highmem.h> 488c2ecf20Sopenharmony_ci#include <asm/ioctls.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <linux/sunrpc/types.h> 518c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h> 528c2ecf20Sopenharmony_ci#include <linux/sunrpc/xdr.h> 538c2ecf20Sopenharmony_ci#include <linux/sunrpc/msg_prot.h> 548c2ecf20Sopenharmony_ci#include <linux/sunrpc/svcsock.h> 558c2ecf20Sopenharmony_ci#include <linux/sunrpc/stats.h> 568c2ecf20Sopenharmony_ci#include <linux/sunrpc/xprt.h> 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#include <trace/events/sunrpc.h> 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#include "socklib.h" 618c2ecf20Sopenharmony_ci#include "sunrpc.h" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define RPCDBG_FACILITY RPCDBG_SVCXPRT 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, 678c2ecf20Sopenharmony_ci int flags); 688c2ecf20Sopenharmony_cistatic int svc_udp_recvfrom(struct svc_rqst *); 698c2ecf20Sopenharmony_cistatic int svc_udp_sendto(struct svc_rqst *); 708c2ecf20Sopenharmony_cistatic void svc_sock_detach(struct svc_xprt *); 718c2ecf20Sopenharmony_cistatic void svc_tcp_sock_detach(struct svc_xprt *); 728c2ecf20Sopenharmony_cistatic void svc_sock_free(struct svc_xprt *); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic struct svc_xprt *svc_create_socket(struct svc_serv *, int, 758c2ecf20Sopenharmony_ci struct net *, struct sockaddr *, 768c2ecf20Sopenharmony_ci int, int); 778c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_LOCK_ALLOC 788c2ecf20Sopenharmony_cistatic struct lock_class_key svc_key[2]; 798c2ecf20Sopenharmony_cistatic struct lock_class_key svc_slock_key[2]; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void svc_reclassify_socket(struct socket *sock) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!sock_allow_reclassification(sk))) 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci switch (sk->sk_family) { 898c2ecf20Sopenharmony_ci case AF_INET: 908c2ecf20Sopenharmony_ci sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD", 918c2ecf20Sopenharmony_ci &svc_slock_key[0], 928c2ecf20Sopenharmony_ci "sk_xprt.xpt_lock-AF_INET-NFSD", 938c2ecf20Sopenharmony_ci &svc_key[0]); 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci case AF_INET6: 978c2ecf20Sopenharmony_ci sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFSD", 988c2ecf20Sopenharmony_ci &svc_slock_key[1], 998c2ecf20Sopenharmony_ci "sk_xprt.xpt_lock-AF_INET6-NFSD", 1008c2ecf20Sopenharmony_ci &svc_key[1]); 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci default: 1048c2ecf20Sopenharmony_ci BUG(); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci#else 1088c2ecf20Sopenharmony_cistatic void svc_reclassify_socket(struct socket *sock) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/** 1148c2ecf20Sopenharmony_ci * svc_tcp_release_rqst - Release transport-related resources 1158c2ecf20Sopenharmony_ci * @rqstp: request structure with resources to be released 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic void svc_tcp_release_rqst(struct svc_rqst *rqstp) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct sk_buff *skb = rqstp->rq_xprt_ctxt; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (skb) { 1238c2ecf20Sopenharmony_ci struct svc_sock *svsk = 1248c2ecf20Sopenharmony_ci container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci rqstp->rq_xprt_ctxt = NULL; 1278c2ecf20Sopenharmony_ci skb_free_datagram_locked(svsk->sk_sk, skb); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * svc_udp_release_rqst - Release transport-related resources 1338c2ecf20Sopenharmony_ci * @rqstp: request structure with resources to be released 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_cistatic void svc_udp_release_rqst(struct svc_rqst *rqstp) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct sk_buff *skb = rqstp->rq_xprt_ctxt; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (skb) { 1418c2ecf20Sopenharmony_ci rqstp->rq_xprt_ctxt = NULL; 1428c2ecf20Sopenharmony_ci consume_skb(skb); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciunion svc_pktinfo_u { 1478c2ecf20Sopenharmony_ci struct in_pktinfo pkti; 1488c2ecf20Sopenharmony_ci struct in6_pktinfo pkti6; 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci#define SVC_PKTINFO_SPACE \ 1518c2ecf20Sopenharmony_ci CMSG_SPACE(sizeof(union svc_pktinfo_u)) 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct svc_sock *svsk = 1568c2ecf20Sopenharmony_ci container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); 1578c2ecf20Sopenharmony_ci switch (svsk->sk_sk->sk_family) { 1588c2ecf20Sopenharmony_ci case AF_INET: { 1598c2ecf20Sopenharmony_ci struct in_pktinfo *pki = CMSG_DATA(cmh); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci cmh->cmsg_level = SOL_IP; 1628c2ecf20Sopenharmony_ci cmh->cmsg_type = IP_PKTINFO; 1638c2ecf20Sopenharmony_ci pki->ipi_ifindex = 0; 1648c2ecf20Sopenharmony_ci pki->ipi_spec_dst.s_addr = 1658c2ecf20Sopenharmony_ci svc_daddr_in(rqstp)->sin_addr.s_addr; 1668c2ecf20Sopenharmony_ci cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci case AF_INET6: { 1718c2ecf20Sopenharmony_ci struct in6_pktinfo *pki = CMSG_DATA(cmh); 1728c2ecf20Sopenharmony_ci struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci cmh->cmsg_level = SOL_IPV6; 1758c2ecf20Sopenharmony_ci cmh->cmsg_type = IPV6_PKTINFO; 1768c2ecf20Sopenharmony_ci pki->ipi6_ifindex = daddr->sin6_scope_id; 1778c2ecf20Sopenharmony_ci pki->ipi6_addr = daddr->sin6_addr; 1788c2ecf20Sopenharmony_ci cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int svc_sock_read_payload(struct svc_rqst *rqstp, unsigned int offset, 1858c2ecf20Sopenharmony_ci unsigned int length) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * Report socket names for nfsdfs 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_cistatic int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci const struct sock *sk = svsk->sk_sk; 1968c2ecf20Sopenharmony_ci const char *proto_name = sk->sk_protocol == IPPROTO_UDP ? 1978c2ecf20Sopenharmony_ci "udp" : "tcp"; 1988c2ecf20Sopenharmony_ci int len; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci switch (sk->sk_family) { 2018c2ecf20Sopenharmony_ci case PF_INET: 2028c2ecf20Sopenharmony_ci len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n", 2038c2ecf20Sopenharmony_ci proto_name, 2048c2ecf20Sopenharmony_ci &inet_sk(sk)->inet_rcv_saddr, 2058c2ecf20Sopenharmony_ci inet_sk(sk)->inet_num); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 2088c2ecf20Sopenharmony_ci case PF_INET6: 2098c2ecf20Sopenharmony_ci len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n", 2108c2ecf20Sopenharmony_ci proto_name, 2118c2ecf20Sopenharmony_ci &sk->sk_v6_rcv_saddr, 2128c2ecf20Sopenharmony_ci inet_sk(sk)->inet_num); 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci#endif 2158c2ecf20Sopenharmony_ci default: 2168c2ecf20Sopenharmony_ci len = snprintf(buf, remaining, "*unknown-%d*\n", 2178c2ecf20Sopenharmony_ci sk->sk_family); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (len >= remaining) { 2218c2ecf20Sopenharmony_ci *buf = '\0'; 2228c2ecf20Sopenharmony_ci return -ENAMETOOLONG; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci return len; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 2288c2ecf20Sopenharmony_cistatic void svc_flush_bvec(const struct bio_vec *bvec, size_t size, size_t seek) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct bvec_iter bi = { 2318c2ecf20Sopenharmony_ci .bi_size = size + seek, 2328c2ecf20Sopenharmony_ci }; 2338c2ecf20Sopenharmony_ci struct bio_vec bv; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci bvec_iter_advance(bvec, &bi, seek & PAGE_MASK); 2368c2ecf20Sopenharmony_ci for_each_bvec(bv, bvec, bi, bi) 2378c2ecf20Sopenharmony_ci flush_dcache_page(bv.bv_page); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci#else 2408c2ecf20Sopenharmony_cistatic inline void svc_flush_bvec(const struct bio_vec *bvec, size_t size, 2418c2ecf20Sopenharmony_ci size_t seek) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci#endif 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* 2478c2ecf20Sopenharmony_ci * Read from @rqstp's transport socket. The incoming message fills whole 2488c2ecf20Sopenharmony_ci * pages in @rqstp's rq_pages array until the last page of the message 2498c2ecf20Sopenharmony_ci * has been received into a partial page. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistatic ssize_t svc_tcp_read_msg(struct svc_rqst *rqstp, size_t buflen, 2528c2ecf20Sopenharmony_ci size_t seek) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct svc_sock *svsk = 2558c2ecf20Sopenharmony_ci container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); 2568c2ecf20Sopenharmony_ci struct bio_vec *bvec = rqstp->rq_bvec; 2578c2ecf20Sopenharmony_ci struct msghdr msg = { NULL }; 2588c2ecf20Sopenharmony_ci unsigned int i; 2598c2ecf20Sopenharmony_ci ssize_t len; 2608c2ecf20Sopenharmony_ci size_t t; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci rqstp->rq_xprt_hlen = 0; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci for (i = 0, t = 0; t < buflen; i++, t += PAGE_SIZE) { 2678c2ecf20Sopenharmony_ci bvec[i].bv_page = rqstp->rq_pages[i]; 2688c2ecf20Sopenharmony_ci bvec[i].bv_len = PAGE_SIZE; 2698c2ecf20Sopenharmony_ci bvec[i].bv_offset = 0; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci rqstp->rq_respages = &rqstp->rq_pages[i]; 2728c2ecf20Sopenharmony_ci rqstp->rq_next_page = rqstp->rq_respages + 1; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, READ, bvec, i, buflen); 2758c2ecf20Sopenharmony_ci if (seek) { 2768c2ecf20Sopenharmony_ci iov_iter_advance(&msg.msg_iter, seek); 2778c2ecf20Sopenharmony_ci buflen -= seek; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT); 2808c2ecf20Sopenharmony_ci if (len > 0) 2818c2ecf20Sopenharmony_ci svc_flush_bvec(bvec, len, seek); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* If we read a full record, then assume there may be more 2848c2ecf20Sopenharmony_ci * data to read (stream based sockets only!) 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci if (len == buflen) 2878c2ecf20Sopenharmony_ci set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return len; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* 2938c2ecf20Sopenharmony_ci * Set socket snd and rcv buffer lengths 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_cistatic void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci unsigned int max_mesg = svsk->sk_xprt.xpt_server->sv_max_mesg; 2988c2ecf20Sopenharmony_ci struct socket *sock = svsk->sk_sock; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci nreqs = min(nreqs, INT_MAX / 2 / max_mesg); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci lock_sock(sock->sk); 3038c2ecf20Sopenharmony_ci sock->sk->sk_sndbuf = nreqs * max_mesg * 2; 3048c2ecf20Sopenharmony_ci sock->sk->sk_rcvbuf = nreqs * max_mesg * 2; 3058c2ecf20Sopenharmony_ci sock->sk->sk_write_space(sock->sk); 3068c2ecf20Sopenharmony_ci release_sock(sock->sk); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void svc_sock_secure_port(struct svc_rqst *rqstp) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci if (svc_port_is_privileged(svc_addr(rqstp))) 3128c2ecf20Sopenharmony_ci set_bit(RQ_SECURE, &rqstp->rq_flags); 3138c2ecf20Sopenharmony_ci else 3148c2ecf20Sopenharmony_ci clear_bit(RQ_SECURE, &rqstp->rq_flags); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* 3188c2ecf20Sopenharmony_ci * INET callback when data has been received on the socket. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_cistatic void svc_data_ready(struct sock *sk) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (svsk) { 3258c2ecf20Sopenharmony_ci /* Refer to svc_setup_socket() for details. */ 3268c2ecf20Sopenharmony_ci rmb(); 3278c2ecf20Sopenharmony_ci svsk->sk_odata(sk); 3288c2ecf20Sopenharmony_ci trace_svcsock_data_ready(&svsk->sk_xprt, 0); 3298c2ecf20Sopenharmony_ci if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags)) 3308c2ecf20Sopenharmony_ci svc_xprt_enqueue(&svsk->sk_xprt); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * INET callback when space is newly available on the socket. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistatic void svc_write_space(struct sock *sk) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (svsk) { 3428c2ecf20Sopenharmony_ci /* Refer to svc_setup_socket() for details. */ 3438c2ecf20Sopenharmony_ci rmb(); 3448c2ecf20Sopenharmony_ci trace_svcsock_write_space(&svsk->sk_xprt, 0); 3458c2ecf20Sopenharmony_ci svsk->sk_owspace(sk); 3468c2ecf20Sopenharmony_ci svc_xprt_enqueue(&svsk->sk_xprt); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int svc_tcp_has_wspace(struct svc_xprt *xprt) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) 3558c2ecf20Sopenharmony_ci return 1; 3568c2ecf20Sopenharmony_ci return !test_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void svc_tcp_kill_temp_xprt(struct svc_xprt *xprt) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci sock_no_linger(svsk->sk_sock->sk); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* 3678c2ecf20Sopenharmony_ci * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_cistatic int svc_udp_get_dest_address4(struct svc_rqst *rqstp, 3708c2ecf20Sopenharmony_ci struct cmsghdr *cmh) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct in_pktinfo *pki = CMSG_DATA(cmh); 3738c2ecf20Sopenharmony_ci struct sockaddr_in *daddr = svc_daddr_in(rqstp); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (cmh->cmsg_type != IP_PKTINFO) 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci daddr->sin_family = AF_INET; 3798c2ecf20Sopenharmony_ci daddr->sin_addr.s_addr = pki->ipi_spec_dst.s_addr; 3808c2ecf20Sopenharmony_ci return 1; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/* 3848c2ecf20Sopenharmony_ci * See net/ipv6/datagram.c : ip6_datagram_recv_ctl 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_cistatic int svc_udp_get_dest_address6(struct svc_rqst *rqstp, 3878c2ecf20Sopenharmony_ci struct cmsghdr *cmh) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct in6_pktinfo *pki = CMSG_DATA(cmh); 3908c2ecf20Sopenharmony_ci struct sockaddr_in6 *daddr = svc_daddr_in6(rqstp); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (cmh->cmsg_type != IPV6_PKTINFO) 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci daddr->sin6_family = AF_INET6; 3968c2ecf20Sopenharmony_ci daddr->sin6_addr = pki->ipi6_addr; 3978c2ecf20Sopenharmony_ci daddr->sin6_scope_id = pki->ipi6_ifindex; 3988c2ecf20Sopenharmony_ci return 1; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/* 4028c2ecf20Sopenharmony_ci * Copy the UDP datagram's destination address to the rqstp structure. 4038c2ecf20Sopenharmony_ci * The 'destination' address in this case is the address to which the 4048c2ecf20Sopenharmony_ci * peer sent the datagram, i.e. our local address. For multihomed 4058c2ecf20Sopenharmony_ci * hosts, this can change from msg to msg. Note that only the IP 4068c2ecf20Sopenharmony_ci * address changes, the port number should remain the same. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_cistatic int svc_udp_get_dest_address(struct svc_rqst *rqstp, 4098c2ecf20Sopenharmony_ci struct cmsghdr *cmh) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci switch (cmh->cmsg_level) { 4128c2ecf20Sopenharmony_ci case SOL_IP: 4138c2ecf20Sopenharmony_ci return svc_udp_get_dest_address4(rqstp, cmh); 4148c2ecf20Sopenharmony_ci case SOL_IPV6: 4158c2ecf20Sopenharmony_ci return svc_udp_get_dest_address6(rqstp, cmh); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/** 4228c2ecf20Sopenharmony_ci * svc_udp_recvfrom - Receive a datagram from a UDP socket. 4238c2ecf20Sopenharmony_ci * @rqstp: request structure into which to receive an RPC Call 4248c2ecf20Sopenharmony_ci * 4258c2ecf20Sopenharmony_ci * Called in a loop when XPT_DATA has been set. 4268c2ecf20Sopenharmony_ci * 4278c2ecf20Sopenharmony_ci * Returns: 4288c2ecf20Sopenharmony_ci * On success, the number of bytes in a received RPC Call, or 4298c2ecf20Sopenharmony_ci * %0 if a complete RPC Call message was not ready to return 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_cistatic int svc_udp_recvfrom(struct svc_rqst *rqstp) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct svc_sock *svsk = 4348c2ecf20Sopenharmony_ci container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); 4358c2ecf20Sopenharmony_ci struct svc_serv *serv = svsk->sk_xprt.xpt_server; 4368c2ecf20Sopenharmony_ci struct sk_buff *skb; 4378c2ecf20Sopenharmony_ci union { 4388c2ecf20Sopenharmony_ci struct cmsghdr hdr; 4398c2ecf20Sopenharmony_ci long all[SVC_PKTINFO_SPACE / sizeof(long)]; 4408c2ecf20Sopenharmony_ci } buffer; 4418c2ecf20Sopenharmony_ci struct cmsghdr *cmh = &buffer.hdr; 4428c2ecf20Sopenharmony_ci struct msghdr msg = { 4438c2ecf20Sopenharmony_ci .msg_name = svc_addr(rqstp), 4448c2ecf20Sopenharmony_ci .msg_control = cmh, 4458c2ecf20Sopenharmony_ci .msg_controllen = sizeof(buffer), 4468c2ecf20Sopenharmony_ci .msg_flags = MSG_DONTWAIT, 4478c2ecf20Sopenharmony_ci }; 4488c2ecf20Sopenharmony_ci size_t len; 4498c2ecf20Sopenharmony_ci int err; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) 4528c2ecf20Sopenharmony_ci /* udp sockets need large rcvbuf as all pending 4538c2ecf20Sopenharmony_ci * requests are still in that buffer. sndbuf must 4548c2ecf20Sopenharmony_ci * also be large enough that there is enough space 4558c2ecf20Sopenharmony_ci * for one reply per thread. We count all threads 4568c2ecf20Sopenharmony_ci * rather than threads in a particular pool, which 4578c2ecf20Sopenharmony_ci * provides an upper bound on the number of threads 4588c2ecf20Sopenharmony_ci * which will access the socket. 4598c2ecf20Sopenharmony_ci */ 4608c2ecf20Sopenharmony_ci svc_sock_setbufsize(svsk, serv->sv_nrthreads + 3); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); 4638c2ecf20Sopenharmony_ci err = kernel_recvmsg(svsk->sk_sock, &msg, NULL, 4648c2ecf20Sopenharmony_ci 0, 0, MSG_PEEK | MSG_DONTWAIT); 4658c2ecf20Sopenharmony_ci if (err < 0) 4668c2ecf20Sopenharmony_ci goto out_recv_err; 4678c2ecf20Sopenharmony_ci skb = skb_recv_udp(svsk->sk_sk, 0, 1, &err); 4688c2ecf20Sopenharmony_ci if (!skb) 4698c2ecf20Sopenharmony_ci goto out_recv_err; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci len = svc_addr_len(svc_addr(rqstp)); 4728c2ecf20Sopenharmony_ci rqstp->rq_addrlen = len; 4738c2ecf20Sopenharmony_ci if (skb->tstamp == 0) { 4748c2ecf20Sopenharmony_ci skb->tstamp = ktime_get_real(); 4758c2ecf20Sopenharmony_ci /* Don't enable netstamp, sunrpc doesn't 4768c2ecf20Sopenharmony_ci need that much accuracy */ 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci sock_write_timestamp(svsk->sk_sk, skb->tstamp); 4798c2ecf20Sopenharmony_ci set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); /* there may be more data... */ 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci len = skb->len; 4828c2ecf20Sopenharmony_ci rqstp->rq_arg.len = len; 4838c2ecf20Sopenharmony_ci trace_svcsock_udp_recv(&svsk->sk_xprt, len); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci rqstp->rq_prot = IPPROTO_UDP; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (!svc_udp_get_dest_address(rqstp, cmh)) 4888c2ecf20Sopenharmony_ci goto out_cmsg_err; 4898c2ecf20Sopenharmony_ci rqstp->rq_daddrlen = svc_addr_len(svc_daddr(rqstp)); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (skb_is_nonlinear(skb)) { 4928c2ecf20Sopenharmony_ci /* we have to copy */ 4938c2ecf20Sopenharmony_ci local_bh_disable(); 4948c2ecf20Sopenharmony_ci if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb)) 4958c2ecf20Sopenharmony_ci goto out_bh_enable; 4968c2ecf20Sopenharmony_ci local_bh_enable(); 4978c2ecf20Sopenharmony_ci consume_skb(skb); 4988c2ecf20Sopenharmony_ci } else { 4998c2ecf20Sopenharmony_ci /* we can use it in-place */ 5008c2ecf20Sopenharmony_ci rqstp->rq_arg.head[0].iov_base = skb->data; 5018c2ecf20Sopenharmony_ci rqstp->rq_arg.head[0].iov_len = len; 5028c2ecf20Sopenharmony_ci if (skb_checksum_complete(skb)) 5038c2ecf20Sopenharmony_ci goto out_free; 5048c2ecf20Sopenharmony_ci rqstp->rq_xprt_ctxt = skb; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci rqstp->rq_arg.page_base = 0; 5088c2ecf20Sopenharmony_ci if (len <= rqstp->rq_arg.head[0].iov_len) { 5098c2ecf20Sopenharmony_ci rqstp->rq_arg.head[0].iov_len = len; 5108c2ecf20Sopenharmony_ci rqstp->rq_arg.page_len = 0; 5118c2ecf20Sopenharmony_ci rqstp->rq_respages = rqstp->rq_pages+1; 5128c2ecf20Sopenharmony_ci } else { 5138c2ecf20Sopenharmony_ci rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len; 5148c2ecf20Sopenharmony_ci rqstp->rq_respages = rqstp->rq_pages + 1 + 5158c2ecf20Sopenharmony_ci DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci rqstp->rq_next_page = rqstp->rq_respages+1; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (serv->sv_stats) 5208c2ecf20Sopenharmony_ci serv->sv_stats->netudpcnt++; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return len; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciout_recv_err: 5258c2ecf20Sopenharmony_ci if (err != -EAGAIN) { 5268c2ecf20Sopenharmony_ci /* possibly an icmp error */ 5278c2ecf20Sopenharmony_ci set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci trace_svcsock_udp_recv_err(&svsk->sk_xprt, err); 5308c2ecf20Sopenharmony_ci return 0; 5318c2ecf20Sopenharmony_ciout_cmsg_err: 5328c2ecf20Sopenharmony_ci net_warn_ratelimited("svc: received unknown control message %d/%d; dropping RPC reply datagram\n", 5338c2ecf20Sopenharmony_ci cmh->cmsg_level, cmh->cmsg_type); 5348c2ecf20Sopenharmony_ci goto out_free; 5358c2ecf20Sopenharmony_ciout_bh_enable: 5368c2ecf20Sopenharmony_ci local_bh_enable(); 5378c2ecf20Sopenharmony_ciout_free: 5388c2ecf20Sopenharmony_ci kfree_skb(skb); 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/** 5438c2ecf20Sopenharmony_ci * svc_udp_sendto - Send out a reply on a UDP socket 5448c2ecf20Sopenharmony_ci * @rqstp: completed svc_rqst 5458c2ecf20Sopenharmony_ci * 5468c2ecf20Sopenharmony_ci * xpt_mutex ensures @rqstp's whole message is written to the socket 5478c2ecf20Sopenharmony_ci * without interruption. 5488c2ecf20Sopenharmony_ci * 5498c2ecf20Sopenharmony_ci * Returns the number of bytes sent, or a negative errno. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_cistatic int svc_udp_sendto(struct svc_rqst *rqstp) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct svc_xprt *xprt = rqstp->rq_xprt; 5548c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 5558c2ecf20Sopenharmony_ci struct xdr_buf *xdr = &rqstp->rq_res; 5568c2ecf20Sopenharmony_ci union { 5578c2ecf20Sopenharmony_ci struct cmsghdr hdr; 5588c2ecf20Sopenharmony_ci long all[SVC_PKTINFO_SPACE / sizeof(long)]; 5598c2ecf20Sopenharmony_ci } buffer; 5608c2ecf20Sopenharmony_ci struct cmsghdr *cmh = &buffer.hdr; 5618c2ecf20Sopenharmony_ci struct msghdr msg = { 5628c2ecf20Sopenharmony_ci .msg_name = &rqstp->rq_addr, 5638c2ecf20Sopenharmony_ci .msg_namelen = rqstp->rq_addrlen, 5648c2ecf20Sopenharmony_ci .msg_control = cmh, 5658c2ecf20Sopenharmony_ci .msg_controllen = sizeof(buffer), 5668c2ecf20Sopenharmony_ci }; 5678c2ecf20Sopenharmony_ci unsigned int sent; 5688c2ecf20Sopenharmony_ci int err; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci svc_udp_release_rqst(rqstp); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci svc_set_cmsg_data(rqstp, cmh); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci mutex_lock(&xprt->xpt_mutex); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (svc_xprt_is_dead(xprt)) 5778c2ecf20Sopenharmony_ci goto out_notconn; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent); 5808c2ecf20Sopenharmony_ci xdr_free_bvec(xdr); 5818c2ecf20Sopenharmony_ci if (err == -ECONNREFUSED) { 5828c2ecf20Sopenharmony_ci /* ICMP error on earlier request. */ 5838c2ecf20Sopenharmony_ci err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent); 5848c2ecf20Sopenharmony_ci xdr_free_bvec(xdr); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci trace_svcsock_udp_send(xprt, err); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci mutex_unlock(&xprt->xpt_mutex); 5898c2ecf20Sopenharmony_ci if (err < 0) 5908c2ecf20Sopenharmony_ci return err; 5918c2ecf20Sopenharmony_ci return sent; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ciout_notconn: 5948c2ecf20Sopenharmony_ci mutex_unlock(&xprt->xpt_mutex); 5958c2ecf20Sopenharmony_ci return -ENOTCONN; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int svc_udp_has_wspace(struct svc_xprt *xprt) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 6018c2ecf20Sopenharmony_ci struct svc_serv *serv = xprt->xpt_server; 6028c2ecf20Sopenharmony_ci unsigned long required; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* 6058c2ecf20Sopenharmony_ci * Set the SOCK_NOSPACE flag before checking the available 6068c2ecf20Sopenharmony_ci * sock space. 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); 6098c2ecf20Sopenharmony_ci required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg; 6108c2ecf20Sopenharmony_ci if (required*2 > sock_wspace(svsk->sk_sk)) 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); 6138c2ecf20Sopenharmony_ci return 1; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci BUG(); 6198c2ecf20Sopenharmony_ci return NULL; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic void svc_udp_kill_temp_xprt(struct svc_xprt *xprt) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic struct svc_xprt *svc_udp_create(struct svc_serv *serv, 6278c2ecf20Sopenharmony_ci struct net *net, 6288c2ecf20Sopenharmony_ci struct sockaddr *sa, int salen, 6298c2ecf20Sopenharmony_ci int flags) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci return svc_create_socket(serv, IPPROTO_UDP, net, sa, salen, flags); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic const struct svc_xprt_ops svc_udp_ops = { 6358c2ecf20Sopenharmony_ci .xpo_create = svc_udp_create, 6368c2ecf20Sopenharmony_ci .xpo_recvfrom = svc_udp_recvfrom, 6378c2ecf20Sopenharmony_ci .xpo_sendto = svc_udp_sendto, 6388c2ecf20Sopenharmony_ci .xpo_read_payload = svc_sock_read_payload, 6398c2ecf20Sopenharmony_ci .xpo_release_rqst = svc_udp_release_rqst, 6408c2ecf20Sopenharmony_ci .xpo_detach = svc_sock_detach, 6418c2ecf20Sopenharmony_ci .xpo_free = svc_sock_free, 6428c2ecf20Sopenharmony_ci .xpo_has_wspace = svc_udp_has_wspace, 6438c2ecf20Sopenharmony_ci .xpo_accept = svc_udp_accept, 6448c2ecf20Sopenharmony_ci .xpo_secure_port = svc_sock_secure_port, 6458c2ecf20Sopenharmony_ci .xpo_kill_temp_xprt = svc_udp_kill_temp_xprt, 6468c2ecf20Sopenharmony_ci}; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic struct svc_xprt_class svc_udp_class = { 6498c2ecf20Sopenharmony_ci .xcl_name = "udp", 6508c2ecf20Sopenharmony_ci .xcl_owner = THIS_MODULE, 6518c2ecf20Sopenharmony_ci .xcl_ops = &svc_udp_ops, 6528c2ecf20Sopenharmony_ci .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP, 6538c2ecf20Sopenharmony_ci .xcl_ident = XPRT_TRANSPORT_UDP, 6548c2ecf20Sopenharmony_ci}; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class, 6598c2ecf20Sopenharmony_ci &svsk->sk_xprt, serv); 6608c2ecf20Sopenharmony_ci clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); 6618c2ecf20Sopenharmony_ci svsk->sk_sk->sk_data_ready = svc_data_ready; 6628c2ecf20Sopenharmony_ci svsk->sk_sk->sk_write_space = svc_write_space; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* initialise setting must have enough space to 6658c2ecf20Sopenharmony_ci * receive and respond to one request. 6668c2ecf20Sopenharmony_ci * svc_udp_recvfrom will re-adjust if necessary 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ci svc_sock_setbufsize(svsk, 3); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* data might have come in before data_ready set up */ 6718c2ecf20Sopenharmony_ci set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); 6728c2ecf20Sopenharmony_ci set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* make sure we get destination address info */ 6758c2ecf20Sopenharmony_ci switch (svsk->sk_sk->sk_family) { 6768c2ecf20Sopenharmony_ci case AF_INET: 6778c2ecf20Sopenharmony_ci ip_sock_set_pktinfo(svsk->sk_sock->sk); 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci case AF_INET6: 6808c2ecf20Sopenharmony_ci ip6_sock_set_recvpktinfo(svsk->sk_sock->sk); 6818c2ecf20Sopenharmony_ci break; 6828c2ecf20Sopenharmony_ci default: 6838c2ecf20Sopenharmony_ci BUG(); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/* 6888c2ecf20Sopenharmony_ci * A data_ready event on a listening socket means there's a connection 6898c2ecf20Sopenharmony_ci * pending. Do not use state_change as a substitute for it. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_cistatic void svc_tcp_listen_data_ready(struct sock *sk) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * This callback may called twice when a new connection 6978c2ecf20Sopenharmony_ci * is established as a child socket inherits everything 6988c2ecf20Sopenharmony_ci * from a parent LISTEN socket. 6998c2ecf20Sopenharmony_ci * 1) data_ready method of the parent socket will be called 7008c2ecf20Sopenharmony_ci * when one of child sockets become ESTABLISHED. 7018c2ecf20Sopenharmony_ci * 2) data_ready method of the child socket may be called 7028c2ecf20Sopenharmony_ci * when it receives data before the socket is accepted. 7038c2ecf20Sopenharmony_ci * In case of 2, we should ignore it silently and DO NOT 7048c2ecf20Sopenharmony_ci * dereference svsk. 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_LISTEN) 7078c2ecf20Sopenharmony_ci return; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (svsk) { 7108c2ecf20Sopenharmony_ci /* Refer to svc_setup_socket() for details. */ 7118c2ecf20Sopenharmony_ci rmb(); 7128c2ecf20Sopenharmony_ci svsk->sk_odata(sk); 7138c2ecf20Sopenharmony_ci set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags); 7148c2ecf20Sopenharmony_ci svc_xprt_enqueue(&svsk->sk_xprt); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci/* 7198c2ecf20Sopenharmony_ci * A state change on a connected socket means it's dying or dead. 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_cistatic void svc_tcp_state_change(struct sock *sk) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (svsk) { 7268c2ecf20Sopenharmony_ci /* Refer to svc_setup_socket() for details. */ 7278c2ecf20Sopenharmony_ci rmb(); 7288c2ecf20Sopenharmony_ci svsk->sk_ostate(sk); 7298c2ecf20Sopenharmony_ci trace_svcsock_tcp_state(&svsk->sk_xprt, svsk->sk_sock); 7308c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) { 7318c2ecf20Sopenharmony_ci set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); 7328c2ecf20Sopenharmony_ci svc_xprt_enqueue(&svsk->sk_xprt); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci/* 7388c2ecf20Sopenharmony_ci * Accept a TCP connection 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_cistatic struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 7438c2ecf20Sopenharmony_ci struct sockaddr_storage addr; 7448c2ecf20Sopenharmony_ci struct sockaddr *sin = (struct sockaddr *) &addr; 7458c2ecf20Sopenharmony_ci struct svc_serv *serv = svsk->sk_xprt.xpt_server; 7468c2ecf20Sopenharmony_ci struct socket *sock = svsk->sk_sock; 7478c2ecf20Sopenharmony_ci struct socket *newsock; 7488c2ecf20Sopenharmony_ci struct svc_sock *newsvsk; 7498c2ecf20Sopenharmony_ci int err, slen; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (!sock) 7528c2ecf20Sopenharmony_ci return NULL; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags); 7558c2ecf20Sopenharmony_ci err = kernel_accept(sock, &newsock, O_NONBLOCK); 7568c2ecf20Sopenharmony_ci if (err < 0) { 7578c2ecf20Sopenharmony_ci if (err == -ENOMEM) 7588c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: no more sockets!\n", 7598c2ecf20Sopenharmony_ci serv->sv_name); 7608c2ecf20Sopenharmony_ci else if (err != -EAGAIN) 7618c2ecf20Sopenharmony_ci net_warn_ratelimited("%s: accept failed (err %d)!\n", 7628c2ecf20Sopenharmony_ci serv->sv_name, -err); 7638c2ecf20Sopenharmony_ci trace_svcsock_accept_err(xprt, serv->sv_name, err); 7648c2ecf20Sopenharmony_ci return NULL; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci err = kernel_getpeername(newsock, sin); 7698c2ecf20Sopenharmony_ci if (err < 0) { 7708c2ecf20Sopenharmony_ci trace_svcsock_getpeername_err(xprt, serv->sv_name, err); 7718c2ecf20Sopenharmony_ci goto failed; /* aborted connection or whatever */ 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci slen = err; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* Reset the inherited callbacks before calling svc_setup_socket */ 7768c2ecf20Sopenharmony_ci newsock->sk->sk_state_change = svsk->sk_ostate; 7778c2ecf20Sopenharmony_ci newsock->sk->sk_data_ready = svsk->sk_odata; 7788c2ecf20Sopenharmony_ci newsock->sk->sk_write_space = svsk->sk_owspace; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* make sure that a write doesn't block forever when 7818c2ecf20Sopenharmony_ci * low on memory 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_ci newsock->sk->sk_sndtimeo = HZ*30; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci newsvsk = svc_setup_socket(serv, newsock, 7868c2ecf20Sopenharmony_ci (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY)); 7878c2ecf20Sopenharmony_ci if (IS_ERR(newsvsk)) 7888c2ecf20Sopenharmony_ci goto failed; 7898c2ecf20Sopenharmony_ci svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen); 7908c2ecf20Sopenharmony_ci err = kernel_getsockname(newsock, sin); 7918c2ecf20Sopenharmony_ci slen = err; 7928c2ecf20Sopenharmony_ci if (unlikely(err < 0)) 7938c2ecf20Sopenharmony_ci slen = offsetof(struct sockaddr, sa_data); 7948c2ecf20Sopenharmony_ci svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (sock_is_loopback(newsock->sk)) 7978c2ecf20Sopenharmony_ci set_bit(XPT_LOCAL, &newsvsk->sk_xprt.xpt_flags); 7988c2ecf20Sopenharmony_ci else 7998c2ecf20Sopenharmony_ci clear_bit(XPT_LOCAL, &newsvsk->sk_xprt.xpt_flags); 8008c2ecf20Sopenharmony_ci if (serv->sv_stats) 8018c2ecf20Sopenharmony_ci serv->sv_stats->nettcpconn++; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return &newsvsk->sk_xprt; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cifailed: 8068c2ecf20Sopenharmony_ci sock_release(newsock); 8078c2ecf20Sopenharmony_ci return NULL; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic size_t svc_tcp_restore_pages(struct svc_sock *svsk, 8118c2ecf20Sopenharmony_ci struct svc_rqst *rqstp) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci size_t len = svsk->sk_datalen; 8148c2ecf20Sopenharmony_ci unsigned int i, npages; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (!len) 8178c2ecf20Sopenharmony_ci return 0; 8188c2ecf20Sopenharmony_ci npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; 8198c2ecf20Sopenharmony_ci for (i = 0; i < npages; i++) { 8208c2ecf20Sopenharmony_ci if (rqstp->rq_pages[i] != NULL) 8218c2ecf20Sopenharmony_ci put_page(rqstp->rq_pages[i]); 8228c2ecf20Sopenharmony_ci BUG_ON(svsk->sk_pages[i] == NULL); 8238c2ecf20Sopenharmony_ci rqstp->rq_pages[i] = svsk->sk_pages[i]; 8248c2ecf20Sopenharmony_ci svsk->sk_pages[i] = NULL; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci rqstp->rq_arg.head[0].iov_base = page_address(rqstp->rq_pages[0]); 8278c2ecf20Sopenharmony_ci return len; 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci unsigned int i, len, npages; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (svsk->sk_datalen == 0) 8358c2ecf20Sopenharmony_ci return; 8368c2ecf20Sopenharmony_ci len = svsk->sk_datalen; 8378c2ecf20Sopenharmony_ci npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; 8388c2ecf20Sopenharmony_ci for (i = 0; i < npages; i++) { 8398c2ecf20Sopenharmony_ci svsk->sk_pages[i] = rqstp->rq_pages[i]; 8408c2ecf20Sopenharmony_ci rqstp->rq_pages[i] = NULL; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic void svc_tcp_clear_pages(struct svc_sock *svsk) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci unsigned int i, len, npages; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (svsk->sk_datalen == 0) 8498c2ecf20Sopenharmony_ci goto out; 8508c2ecf20Sopenharmony_ci len = svsk->sk_datalen; 8518c2ecf20Sopenharmony_ci npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; 8528c2ecf20Sopenharmony_ci for (i = 0; i < npages; i++) { 8538c2ecf20Sopenharmony_ci if (svsk->sk_pages[i] == NULL) { 8548c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 8558c2ecf20Sopenharmony_ci continue; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci put_page(svsk->sk_pages[i]); 8588c2ecf20Sopenharmony_ci svsk->sk_pages[i] = NULL; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ciout: 8618c2ecf20Sopenharmony_ci svsk->sk_tcplen = 0; 8628c2ecf20Sopenharmony_ci svsk->sk_datalen = 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci/* 8668c2ecf20Sopenharmony_ci * Receive fragment record header into sk_marker. 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_cistatic ssize_t svc_tcp_read_marker(struct svc_sock *svsk, 8698c2ecf20Sopenharmony_ci struct svc_rqst *rqstp) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci ssize_t want, len; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* If we haven't gotten the record length yet, 8748c2ecf20Sopenharmony_ci * get the next four bytes. 8758c2ecf20Sopenharmony_ci */ 8768c2ecf20Sopenharmony_ci if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) { 8778c2ecf20Sopenharmony_ci struct msghdr msg = { NULL }; 8788c2ecf20Sopenharmony_ci struct kvec iov; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci want = sizeof(rpc_fraghdr) - svsk->sk_tcplen; 8818c2ecf20Sopenharmony_ci iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen; 8828c2ecf20Sopenharmony_ci iov.iov_len = want; 8838c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, want); 8848c2ecf20Sopenharmony_ci len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT); 8858c2ecf20Sopenharmony_ci if (len < 0) 8868c2ecf20Sopenharmony_ci return len; 8878c2ecf20Sopenharmony_ci svsk->sk_tcplen += len; 8888c2ecf20Sopenharmony_ci if (len < want) { 8898c2ecf20Sopenharmony_ci /* call again to read the remaining bytes */ 8908c2ecf20Sopenharmony_ci goto err_short; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci trace_svcsock_marker(&svsk->sk_xprt, svsk->sk_marker); 8938c2ecf20Sopenharmony_ci if (svc_sock_reclen(svsk) + svsk->sk_datalen > 8948c2ecf20Sopenharmony_ci svsk->sk_xprt.xpt_server->sv_max_mesg) 8958c2ecf20Sopenharmony_ci goto err_too_large; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci return svc_sock_reclen(svsk); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cierr_too_large: 9008c2ecf20Sopenharmony_ci net_notice_ratelimited("svc: %s %s RPC fragment too large: %d\n", 9018c2ecf20Sopenharmony_ci __func__, svsk->sk_xprt.xpt_server->sv_name, 9028c2ecf20Sopenharmony_ci svc_sock_reclen(svsk)); 9038c2ecf20Sopenharmony_ci set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); 9048c2ecf20Sopenharmony_cierr_short: 9058c2ecf20Sopenharmony_ci return -EAGAIN; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt; 9118c2ecf20Sopenharmony_ci struct rpc_rqst *req = NULL; 9128c2ecf20Sopenharmony_ci struct kvec *src, *dst; 9138c2ecf20Sopenharmony_ci __be32 *p = (__be32 *)rqstp->rq_arg.head[0].iov_base; 9148c2ecf20Sopenharmony_ci __be32 xid; 9158c2ecf20Sopenharmony_ci __be32 calldir; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci xid = *p++; 9188c2ecf20Sopenharmony_ci calldir = *p; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (!bc_xprt) 9218c2ecf20Sopenharmony_ci return -EAGAIN; 9228c2ecf20Sopenharmony_ci spin_lock(&bc_xprt->queue_lock); 9238c2ecf20Sopenharmony_ci req = xprt_lookup_rqst(bc_xprt, xid); 9248c2ecf20Sopenharmony_ci if (!req) 9258c2ecf20Sopenharmony_ci goto unlock_notfound; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf)); 9288c2ecf20Sopenharmony_ci /* 9298c2ecf20Sopenharmony_ci * XXX!: cheating for now! Only copying HEAD. 9308c2ecf20Sopenharmony_ci * But we know this is good enough for now (in fact, for any 9318c2ecf20Sopenharmony_ci * callback reply in the forseeable future). 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_ci dst = &req->rq_private_buf.head[0]; 9348c2ecf20Sopenharmony_ci src = &rqstp->rq_arg.head[0]; 9358c2ecf20Sopenharmony_ci if (dst->iov_len < src->iov_len) 9368c2ecf20Sopenharmony_ci goto unlock_eagain; /* whatever; just giving up. */ 9378c2ecf20Sopenharmony_ci memcpy(dst->iov_base, src->iov_base, src->iov_len); 9388c2ecf20Sopenharmony_ci xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); 9398c2ecf20Sopenharmony_ci rqstp->rq_arg.len = 0; 9408c2ecf20Sopenharmony_ci spin_unlock(&bc_xprt->queue_lock); 9418c2ecf20Sopenharmony_ci return 0; 9428c2ecf20Sopenharmony_ciunlock_notfound: 9438c2ecf20Sopenharmony_ci printk(KERN_NOTICE 9448c2ecf20Sopenharmony_ci "%s: Got unrecognized reply: " 9458c2ecf20Sopenharmony_ci "calldir 0x%x xpt_bc_xprt %p xid %08x\n", 9468c2ecf20Sopenharmony_ci __func__, ntohl(calldir), 9478c2ecf20Sopenharmony_ci bc_xprt, ntohl(xid)); 9488c2ecf20Sopenharmony_ciunlock_eagain: 9498c2ecf20Sopenharmony_ci spin_unlock(&bc_xprt->queue_lock); 9508c2ecf20Sopenharmony_ci return -EAGAIN; 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic void svc_tcp_fragment_received(struct svc_sock *svsk) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci /* If we have more data, signal svc_xprt_enqueue() to try again */ 9568c2ecf20Sopenharmony_ci svsk->sk_tcplen = 0; 9578c2ecf20Sopenharmony_ci svsk->sk_marker = xdr_zero; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci/** 9618c2ecf20Sopenharmony_ci * svc_tcp_recvfrom - Receive data from a TCP socket 9628c2ecf20Sopenharmony_ci * @rqstp: request structure into which to receive an RPC Call 9638c2ecf20Sopenharmony_ci * 9648c2ecf20Sopenharmony_ci * Called in a loop when XPT_DATA has been set. 9658c2ecf20Sopenharmony_ci * 9668c2ecf20Sopenharmony_ci * Read the 4-byte stream record marker, then use the record length 9678c2ecf20Sopenharmony_ci * in that marker to set up exactly the resources needed to receive 9688c2ecf20Sopenharmony_ci * the next RPC message into @rqstp. 9698c2ecf20Sopenharmony_ci * 9708c2ecf20Sopenharmony_ci * Returns: 9718c2ecf20Sopenharmony_ci * On success, the number of bytes in a received RPC Call, or 9728c2ecf20Sopenharmony_ci * %0 if a complete RPC Call message was not ready to return 9738c2ecf20Sopenharmony_ci * 9748c2ecf20Sopenharmony_ci * The zero return case handles partial receives and callback Replies. 9758c2ecf20Sopenharmony_ci * The state of a partial receive is preserved in the svc_sock for 9768c2ecf20Sopenharmony_ci * the next call to svc_tcp_recvfrom. 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_cistatic int svc_tcp_recvfrom(struct svc_rqst *rqstp) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct svc_sock *svsk = 9818c2ecf20Sopenharmony_ci container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt); 9828c2ecf20Sopenharmony_ci struct svc_serv *serv = svsk->sk_xprt.xpt_server; 9838c2ecf20Sopenharmony_ci size_t want, base; 9848c2ecf20Sopenharmony_ci ssize_t len; 9858c2ecf20Sopenharmony_ci __be32 *p; 9868c2ecf20Sopenharmony_ci __be32 calldir; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); 9898c2ecf20Sopenharmony_ci len = svc_tcp_read_marker(svsk, rqstp); 9908c2ecf20Sopenharmony_ci if (len < 0) 9918c2ecf20Sopenharmony_ci goto error; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci base = svc_tcp_restore_pages(svsk, rqstp); 9948c2ecf20Sopenharmony_ci want = len - (svsk->sk_tcplen - sizeof(rpc_fraghdr)); 9958c2ecf20Sopenharmony_ci len = svc_tcp_read_msg(rqstp, base + want, base); 9968c2ecf20Sopenharmony_ci if (len >= 0) { 9978c2ecf20Sopenharmony_ci trace_svcsock_tcp_recv(&svsk->sk_xprt, len); 9988c2ecf20Sopenharmony_ci svsk->sk_tcplen += len; 9998c2ecf20Sopenharmony_ci svsk->sk_datalen += len; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci if (len != want || !svc_sock_final_rec(svsk)) 10028c2ecf20Sopenharmony_ci goto err_incomplete; 10038c2ecf20Sopenharmony_ci if (svsk->sk_datalen < 8) 10048c2ecf20Sopenharmony_ci goto err_nuts; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci rqstp->rq_arg.len = svsk->sk_datalen; 10078c2ecf20Sopenharmony_ci rqstp->rq_arg.page_base = 0; 10088c2ecf20Sopenharmony_ci if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { 10098c2ecf20Sopenharmony_ci rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; 10108c2ecf20Sopenharmony_ci rqstp->rq_arg.page_len = 0; 10118c2ecf20Sopenharmony_ci } else 10128c2ecf20Sopenharmony_ci rqstp->rq_arg.page_len = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci rqstp->rq_xprt_ctxt = NULL; 10158c2ecf20Sopenharmony_ci rqstp->rq_prot = IPPROTO_TCP; 10168c2ecf20Sopenharmony_ci if (test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags)) 10178c2ecf20Sopenharmony_ci set_bit(RQ_LOCAL, &rqstp->rq_flags); 10188c2ecf20Sopenharmony_ci else 10198c2ecf20Sopenharmony_ci clear_bit(RQ_LOCAL, &rqstp->rq_flags); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci p = (__be32 *)rqstp->rq_arg.head[0].iov_base; 10228c2ecf20Sopenharmony_ci calldir = p[1]; 10238c2ecf20Sopenharmony_ci if (calldir) 10248c2ecf20Sopenharmony_ci len = receive_cb_reply(svsk, rqstp); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* Reset TCP read info */ 10278c2ecf20Sopenharmony_ci svsk->sk_datalen = 0; 10288c2ecf20Sopenharmony_ci svc_tcp_fragment_received(svsk); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (len < 0) 10318c2ecf20Sopenharmony_ci goto error; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt); 10348c2ecf20Sopenharmony_ci if (serv->sv_stats) 10358c2ecf20Sopenharmony_ci serv->sv_stats->nettcpcnt++; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci return rqstp->rq_arg.len; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cierr_incomplete: 10408c2ecf20Sopenharmony_ci svc_tcp_save_pages(svsk, rqstp); 10418c2ecf20Sopenharmony_ci if (len < 0 && len != -EAGAIN) 10428c2ecf20Sopenharmony_ci goto err_delete; 10438c2ecf20Sopenharmony_ci if (len == want) 10448c2ecf20Sopenharmony_ci svc_tcp_fragment_received(svsk); 10458c2ecf20Sopenharmony_ci else 10468c2ecf20Sopenharmony_ci trace_svcsock_tcp_recv_short(&svsk->sk_xprt, 10478c2ecf20Sopenharmony_ci svc_sock_reclen(svsk), 10488c2ecf20Sopenharmony_ci svsk->sk_tcplen - sizeof(rpc_fraghdr)); 10498c2ecf20Sopenharmony_ci goto err_noclose; 10508c2ecf20Sopenharmony_cierror: 10518c2ecf20Sopenharmony_ci if (len != -EAGAIN) 10528c2ecf20Sopenharmony_ci goto err_delete; 10538c2ecf20Sopenharmony_ci trace_svcsock_tcp_recv_eagain(&svsk->sk_xprt, 0); 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_cierr_nuts: 10568c2ecf20Sopenharmony_ci svsk->sk_datalen = 0; 10578c2ecf20Sopenharmony_cierr_delete: 10588c2ecf20Sopenharmony_ci trace_svcsock_tcp_recv_err(&svsk->sk_xprt, len); 10598c2ecf20Sopenharmony_ci set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); 10608c2ecf20Sopenharmony_cierr_noclose: 10618c2ecf20Sopenharmony_ci return 0; /* record not complete */ 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic int svc_tcp_send_kvec(struct socket *sock, const struct kvec *vec, 10658c2ecf20Sopenharmony_ci int flags) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci return kernel_sendpage(sock, virt_to_page(vec->iov_base), 10688c2ecf20Sopenharmony_ci offset_in_page(vec->iov_base), 10698c2ecf20Sopenharmony_ci vec->iov_len, flags); 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci/* 10738c2ecf20Sopenharmony_ci * kernel_sendpage() is used exclusively to reduce the number of 10748c2ecf20Sopenharmony_ci * copy operations in this path. Therefore the caller must ensure 10758c2ecf20Sopenharmony_ci * that the pages backing @xdr are unchanging. 10768c2ecf20Sopenharmony_ci * 10778c2ecf20Sopenharmony_ci * In addition, the logic assumes that * .bv_len is never larger 10788c2ecf20Sopenharmony_ci * than PAGE_SIZE. 10798c2ecf20Sopenharmony_ci */ 10808c2ecf20Sopenharmony_cistatic int svc_tcp_sendmsg(struct socket *sock, struct msghdr *msg, 10818c2ecf20Sopenharmony_ci struct xdr_buf *xdr, rpc_fraghdr marker, 10828c2ecf20Sopenharmony_ci unsigned int *sentp) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci const struct kvec *head = xdr->head; 10858c2ecf20Sopenharmony_ci const struct kvec *tail = xdr->tail; 10868c2ecf20Sopenharmony_ci struct kvec rm = { 10878c2ecf20Sopenharmony_ci .iov_base = &marker, 10888c2ecf20Sopenharmony_ci .iov_len = sizeof(marker), 10898c2ecf20Sopenharmony_ci }; 10908c2ecf20Sopenharmony_ci int flags, ret; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci *sentp = 0; 10938c2ecf20Sopenharmony_ci ret = xdr_alloc_bvec(xdr, GFP_KERNEL); 10948c2ecf20Sopenharmony_ci if (ret < 0) 10958c2ecf20Sopenharmony_ci return ret; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci msg->msg_flags = MSG_MORE; 10988c2ecf20Sopenharmony_ci ret = kernel_sendmsg(sock, msg, &rm, 1, rm.iov_len); 10998c2ecf20Sopenharmony_ci if (ret < 0) 11008c2ecf20Sopenharmony_ci return ret; 11018c2ecf20Sopenharmony_ci *sentp += ret; 11028c2ecf20Sopenharmony_ci if (ret != rm.iov_len) 11038c2ecf20Sopenharmony_ci return -EAGAIN; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci flags = head->iov_len < xdr->len ? MSG_MORE | MSG_SENDPAGE_NOTLAST : 0; 11068c2ecf20Sopenharmony_ci ret = svc_tcp_send_kvec(sock, head, flags); 11078c2ecf20Sopenharmony_ci if (ret < 0) 11088c2ecf20Sopenharmony_ci return ret; 11098c2ecf20Sopenharmony_ci *sentp += ret; 11108c2ecf20Sopenharmony_ci if (ret != head->iov_len) 11118c2ecf20Sopenharmony_ci goto out; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (xdr->page_len) { 11148c2ecf20Sopenharmony_ci unsigned int offset, len, remaining; 11158c2ecf20Sopenharmony_ci struct bio_vec *bvec; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci bvec = xdr->bvec + (xdr->page_base >> PAGE_SHIFT); 11188c2ecf20Sopenharmony_ci offset = offset_in_page(xdr->page_base); 11198c2ecf20Sopenharmony_ci remaining = xdr->page_len; 11208c2ecf20Sopenharmony_ci flags = MSG_MORE | MSG_SENDPAGE_NOTLAST; 11218c2ecf20Sopenharmony_ci while (remaining > 0) { 11228c2ecf20Sopenharmony_ci if (remaining <= PAGE_SIZE && tail->iov_len == 0) 11238c2ecf20Sopenharmony_ci flags = 0; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci len = min(remaining, bvec->bv_len - offset); 11268c2ecf20Sopenharmony_ci ret = kernel_sendpage(sock, bvec->bv_page, 11278c2ecf20Sopenharmony_ci bvec->bv_offset + offset, 11288c2ecf20Sopenharmony_ci len, flags); 11298c2ecf20Sopenharmony_ci if (ret < 0) 11308c2ecf20Sopenharmony_ci return ret; 11318c2ecf20Sopenharmony_ci *sentp += ret; 11328c2ecf20Sopenharmony_ci if (ret != len) 11338c2ecf20Sopenharmony_ci goto out; 11348c2ecf20Sopenharmony_ci remaining -= len; 11358c2ecf20Sopenharmony_ci offset = 0; 11368c2ecf20Sopenharmony_ci bvec++; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (tail->iov_len) { 11418c2ecf20Sopenharmony_ci ret = svc_tcp_send_kvec(sock, tail, 0); 11428c2ecf20Sopenharmony_ci if (ret < 0) 11438c2ecf20Sopenharmony_ci return ret; 11448c2ecf20Sopenharmony_ci *sentp += ret; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ciout: 11488c2ecf20Sopenharmony_ci return 0; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci/** 11528c2ecf20Sopenharmony_ci * svc_tcp_sendto - Send out a reply on a TCP socket 11538c2ecf20Sopenharmony_ci * @rqstp: completed svc_rqst 11548c2ecf20Sopenharmony_ci * 11558c2ecf20Sopenharmony_ci * xpt_mutex ensures @rqstp's whole message is written to the socket 11568c2ecf20Sopenharmony_ci * without interruption. 11578c2ecf20Sopenharmony_ci * 11588c2ecf20Sopenharmony_ci * Returns the number of bytes sent, or a negative errno. 11598c2ecf20Sopenharmony_ci */ 11608c2ecf20Sopenharmony_cistatic int svc_tcp_sendto(struct svc_rqst *rqstp) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci struct svc_xprt *xprt = rqstp->rq_xprt; 11638c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 11648c2ecf20Sopenharmony_ci struct xdr_buf *xdr = &rqstp->rq_res; 11658c2ecf20Sopenharmony_ci rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT | 11668c2ecf20Sopenharmony_ci (u32)xdr->len); 11678c2ecf20Sopenharmony_ci struct msghdr msg = { 11688c2ecf20Sopenharmony_ci .msg_flags = 0, 11698c2ecf20Sopenharmony_ci }; 11708c2ecf20Sopenharmony_ci unsigned int sent; 11718c2ecf20Sopenharmony_ci int err; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci svc_tcp_release_rqst(rqstp); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci mutex_lock(&xprt->xpt_mutex); 11768c2ecf20Sopenharmony_ci if (svc_xprt_is_dead(xprt)) 11778c2ecf20Sopenharmony_ci goto out_notconn; 11788c2ecf20Sopenharmony_ci err = svc_tcp_sendmsg(svsk->sk_sock, &msg, xdr, marker, &sent); 11798c2ecf20Sopenharmony_ci xdr_free_bvec(xdr); 11808c2ecf20Sopenharmony_ci trace_svcsock_tcp_send(xprt, err < 0 ? (long)err : sent); 11818c2ecf20Sopenharmony_ci if (err < 0 || sent != (xdr->len + sizeof(marker))) 11828c2ecf20Sopenharmony_ci goto out_close; 11838c2ecf20Sopenharmony_ci mutex_unlock(&xprt->xpt_mutex); 11848c2ecf20Sopenharmony_ci return sent; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ciout_notconn: 11878c2ecf20Sopenharmony_ci mutex_unlock(&xprt->xpt_mutex); 11888c2ecf20Sopenharmony_ci return -ENOTCONN; 11898c2ecf20Sopenharmony_ciout_close: 11908c2ecf20Sopenharmony_ci pr_notice("rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n", 11918c2ecf20Sopenharmony_ci xprt->xpt_server->sv_name, 11928c2ecf20Sopenharmony_ci (err < 0) ? "got error" : "sent", 11938c2ecf20Sopenharmony_ci (err < 0) ? err : sent, xdr->len); 11948c2ecf20Sopenharmony_ci set_bit(XPT_CLOSE, &xprt->xpt_flags); 11958c2ecf20Sopenharmony_ci svc_xprt_enqueue(xprt); 11968c2ecf20Sopenharmony_ci mutex_unlock(&xprt->xpt_mutex); 11978c2ecf20Sopenharmony_ci return -EAGAIN; 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic struct svc_xprt *svc_tcp_create(struct svc_serv *serv, 12018c2ecf20Sopenharmony_ci struct net *net, 12028c2ecf20Sopenharmony_ci struct sockaddr *sa, int salen, 12038c2ecf20Sopenharmony_ci int flags) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags); 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_cistatic const struct svc_xprt_ops svc_tcp_ops = { 12098c2ecf20Sopenharmony_ci .xpo_create = svc_tcp_create, 12108c2ecf20Sopenharmony_ci .xpo_recvfrom = svc_tcp_recvfrom, 12118c2ecf20Sopenharmony_ci .xpo_sendto = svc_tcp_sendto, 12128c2ecf20Sopenharmony_ci .xpo_read_payload = svc_sock_read_payload, 12138c2ecf20Sopenharmony_ci .xpo_release_rqst = svc_tcp_release_rqst, 12148c2ecf20Sopenharmony_ci .xpo_detach = svc_tcp_sock_detach, 12158c2ecf20Sopenharmony_ci .xpo_free = svc_sock_free, 12168c2ecf20Sopenharmony_ci .xpo_has_wspace = svc_tcp_has_wspace, 12178c2ecf20Sopenharmony_ci .xpo_accept = svc_tcp_accept, 12188c2ecf20Sopenharmony_ci .xpo_secure_port = svc_sock_secure_port, 12198c2ecf20Sopenharmony_ci .xpo_kill_temp_xprt = svc_tcp_kill_temp_xprt, 12208c2ecf20Sopenharmony_ci}; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_cistatic struct svc_xprt_class svc_tcp_class = { 12238c2ecf20Sopenharmony_ci .xcl_name = "tcp", 12248c2ecf20Sopenharmony_ci .xcl_owner = THIS_MODULE, 12258c2ecf20Sopenharmony_ci .xcl_ops = &svc_tcp_ops, 12268c2ecf20Sopenharmony_ci .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, 12278c2ecf20Sopenharmony_ci .xcl_ident = XPRT_TRANSPORT_TCP, 12288c2ecf20Sopenharmony_ci}; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_civoid svc_init_xprt_sock(void) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci svc_reg_xprt_class(&svc_tcp_class); 12338c2ecf20Sopenharmony_ci svc_reg_xprt_class(&svc_udp_class); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_civoid svc_cleanup_xprt_sock(void) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci svc_unreg_xprt_class(&svc_tcp_class); 12398c2ecf20Sopenharmony_ci svc_unreg_xprt_class(&svc_udp_class); 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cistatic void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci struct sock *sk = svsk->sk_sk; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_tcp_class, 12478c2ecf20Sopenharmony_ci &svsk->sk_xprt, serv); 12488c2ecf20Sopenharmony_ci set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); 12498c2ecf20Sopenharmony_ci set_bit(XPT_CONG_CTRL, &svsk->sk_xprt.xpt_flags); 12508c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) { 12518c2ecf20Sopenharmony_ci strcpy(svsk->sk_xprt.xpt_remotebuf, "listener"); 12528c2ecf20Sopenharmony_ci set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags); 12538c2ecf20Sopenharmony_ci sk->sk_data_ready = svc_tcp_listen_data_ready; 12548c2ecf20Sopenharmony_ci set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags); 12558c2ecf20Sopenharmony_ci } else { 12568c2ecf20Sopenharmony_ci sk->sk_state_change = svc_tcp_state_change; 12578c2ecf20Sopenharmony_ci sk->sk_data_ready = svc_data_ready; 12588c2ecf20Sopenharmony_ci sk->sk_write_space = svc_write_space; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci svsk->sk_marker = xdr_zero; 12618c2ecf20Sopenharmony_ci svsk->sk_tcplen = 0; 12628c2ecf20Sopenharmony_ci svsk->sk_datalen = 0; 12638c2ecf20Sopenharmony_ci memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); 12688c2ecf20Sopenharmony_ci switch (sk->sk_state) { 12698c2ecf20Sopenharmony_ci case TCP_SYN_RECV: 12708c2ecf20Sopenharmony_ci case TCP_ESTABLISHED: 12718c2ecf20Sopenharmony_ci break; 12728c2ecf20Sopenharmony_ci default: 12738c2ecf20Sopenharmony_ci set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_civoid svc_sock_update_bufs(struct svc_serv *serv) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci /* 12818c2ecf20Sopenharmony_ci * The number of server threads has changed. Update 12828c2ecf20Sopenharmony_ci * rcvbuf and sndbuf accordingly on all sockets 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci struct svc_sock *svsk; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci spin_lock_bh(&serv->sv_lock); 12878c2ecf20Sopenharmony_ci list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) 12888c2ecf20Sopenharmony_ci set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags); 12898c2ecf20Sopenharmony_ci spin_unlock_bh(&serv->sv_lock); 12908c2ecf20Sopenharmony_ci} 12918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_sock_update_bufs); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci/* 12948c2ecf20Sopenharmony_ci * Initialize socket for RPC use and create svc_sock struct 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_cistatic struct svc_sock *svc_setup_socket(struct svc_serv *serv, 12978c2ecf20Sopenharmony_ci struct socket *sock, 12988c2ecf20Sopenharmony_ci int flags) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct svc_sock *svsk; 13018c2ecf20Sopenharmony_ci struct sock *inet; 13028c2ecf20Sopenharmony_ci int pmap_register = !(flags & SVC_SOCK_ANONYMOUS); 13038c2ecf20Sopenharmony_ci int err = 0; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci svsk = kzalloc(sizeof(*svsk), GFP_KERNEL); 13068c2ecf20Sopenharmony_ci if (!svsk) 13078c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci inet = sock->sk; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* Register socket with portmapper */ 13128c2ecf20Sopenharmony_ci if (pmap_register) 13138c2ecf20Sopenharmony_ci err = svc_register(serv, sock_net(sock->sk), inet->sk_family, 13148c2ecf20Sopenharmony_ci inet->sk_protocol, 13158c2ecf20Sopenharmony_ci ntohs(inet_sk(inet)->inet_sport)); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci if (err < 0) { 13188c2ecf20Sopenharmony_ci kfree(svsk); 13198c2ecf20Sopenharmony_ci return ERR_PTR(err); 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci svsk->sk_sock = sock; 13238c2ecf20Sopenharmony_ci svsk->sk_sk = inet; 13248c2ecf20Sopenharmony_ci svsk->sk_ostate = inet->sk_state_change; 13258c2ecf20Sopenharmony_ci svsk->sk_odata = inet->sk_data_ready; 13268c2ecf20Sopenharmony_ci svsk->sk_owspace = inet->sk_write_space; 13278c2ecf20Sopenharmony_ci /* 13288c2ecf20Sopenharmony_ci * This barrier is necessary in order to prevent race condition 13298c2ecf20Sopenharmony_ci * with svc_data_ready(), svc_listen_data_ready() and others 13308c2ecf20Sopenharmony_ci * when calling callbacks above. 13318c2ecf20Sopenharmony_ci */ 13328c2ecf20Sopenharmony_ci wmb(); 13338c2ecf20Sopenharmony_ci inet->sk_user_data = svsk; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* Initialize the socket */ 13368c2ecf20Sopenharmony_ci if (sock->type == SOCK_DGRAM) 13378c2ecf20Sopenharmony_ci svc_udp_init(svsk, serv); 13388c2ecf20Sopenharmony_ci else 13398c2ecf20Sopenharmony_ci svc_tcp_init(svsk, serv); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci trace_svcsock_new_socket(sock); 13428c2ecf20Sopenharmony_ci return svsk; 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cibool svc_alien_sock(struct net *net, int fd) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci int err; 13488c2ecf20Sopenharmony_ci struct socket *sock = sockfd_lookup(fd, &err); 13498c2ecf20Sopenharmony_ci bool ret = false; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (!sock) 13528c2ecf20Sopenharmony_ci goto out; 13538c2ecf20Sopenharmony_ci if (sock_net(sock->sk) != net) 13548c2ecf20Sopenharmony_ci ret = true; 13558c2ecf20Sopenharmony_ci sockfd_put(sock); 13568c2ecf20Sopenharmony_ciout: 13578c2ecf20Sopenharmony_ci return ret; 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_alien_sock); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci/** 13628c2ecf20Sopenharmony_ci * svc_addsock - add a listener socket to an RPC service 13638c2ecf20Sopenharmony_ci * @serv: pointer to RPC service to which to add a new listener 13648c2ecf20Sopenharmony_ci * @fd: file descriptor of the new listener 13658c2ecf20Sopenharmony_ci * @name_return: pointer to buffer to fill in with name of listener 13668c2ecf20Sopenharmony_ci * @len: size of the buffer 13678c2ecf20Sopenharmony_ci * @cred: credential 13688c2ecf20Sopenharmony_ci * 13698c2ecf20Sopenharmony_ci * Fills in socket name and returns positive length of name if successful. 13708c2ecf20Sopenharmony_ci * Name is terminated with '\n'. On error, returns a negative errno 13718c2ecf20Sopenharmony_ci * value. 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_ciint svc_addsock(struct svc_serv *serv, const int fd, char *name_return, 13748c2ecf20Sopenharmony_ci const size_t len, const struct cred *cred) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci int err = 0; 13778c2ecf20Sopenharmony_ci struct socket *so = sockfd_lookup(fd, &err); 13788c2ecf20Sopenharmony_ci struct svc_sock *svsk = NULL; 13798c2ecf20Sopenharmony_ci struct sockaddr_storage addr; 13808c2ecf20Sopenharmony_ci struct sockaddr *sin = (struct sockaddr *)&addr; 13818c2ecf20Sopenharmony_ci int salen; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (!so) 13848c2ecf20Sopenharmony_ci return err; 13858c2ecf20Sopenharmony_ci err = -EAFNOSUPPORT; 13868c2ecf20Sopenharmony_ci if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6)) 13878c2ecf20Sopenharmony_ci goto out; 13888c2ecf20Sopenharmony_ci err = -EPROTONOSUPPORT; 13898c2ecf20Sopenharmony_ci if (so->sk->sk_protocol != IPPROTO_TCP && 13908c2ecf20Sopenharmony_ci so->sk->sk_protocol != IPPROTO_UDP) 13918c2ecf20Sopenharmony_ci goto out; 13928c2ecf20Sopenharmony_ci err = -EISCONN; 13938c2ecf20Sopenharmony_ci if (so->state > SS_UNCONNECTED) 13948c2ecf20Sopenharmony_ci goto out; 13958c2ecf20Sopenharmony_ci err = -ENOENT; 13968c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 13978c2ecf20Sopenharmony_ci goto out; 13988c2ecf20Sopenharmony_ci svsk = svc_setup_socket(serv, so, SVC_SOCK_DEFAULTS); 13998c2ecf20Sopenharmony_ci if (IS_ERR(svsk)) { 14008c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 14018c2ecf20Sopenharmony_ci err = PTR_ERR(svsk); 14028c2ecf20Sopenharmony_ci goto out; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci salen = kernel_getsockname(svsk->sk_sock, sin); 14058c2ecf20Sopenharmony_ci if (salen >= 0) 14068c2ecf20Sopenharmony_ci svc_xprt_set_local(&svsk->sk_xprt, sin, salen); 14078c2ecf20Sopenharmony_ci svsk->sk_xprt.xpt_cred = get_cred(cred); 14088c2ecf20Sopenharmony_ci svc_add_new_perm_xprt(serv, &svsk->sk_xprt); 14098c2ecf20Sopenharmony_ci return svc_one_sock_name(svsk, name_return, len); 14108c2ecf20Sopenharmony_ciout: 14118c2ecf20Sopenharmony_ci sockfd_put(so); 14128c2ecf20Sopenharmony_ci return err; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_addsock); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci/* 14178c2ecf20Sopenharmony_ci * Create socket for RPC service. 14188c2ecf20Sopenharmony_ci */ 14198c2ecf20Sopenharmony_cistatic struct svc_xprt *svc_create_socket(struct svc_serv *serv, 14208c2ecf20Sopenharmony_ci int protocol, 14218c2ecf20Sopenharmony_ci struct net *net, 14228c2ecf20Sopenharmony_ci struct sockaddr *sin, int len, 14238c2ecf20Sopenharmony_ci int flags) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci struct svc_sock *svsk; 14268c2ecf20Sopenharmony_ci struct socket *sock; 14278c2ecf20Sopenharmony_ci int error; 14288c2ecf20Sopenharmony_ci int type; 14298c2ecf20Sopenharmony_ci struct sockaddr_storage addr; 14308c2ecf20Sopenharmony_ci struct sockaddr *newsin = (struct sockaddr *)&addr; 14318c2ecf20Sopenharmony_ci int newlen; 14328c2ecf20Sopenharmony_ci int family; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) { 14358c2ecf20Sopenharmony_ci printk(KERN_WARNING "svc: only UDP and TCP " 14368c2ecf20Sopenharmony_ci "sockets supported\n"); 14378c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; 14418c2ecf20Sopenharmony_ci switch (sin->sa_family) { 14428c2ecf20Sopenharmony_ci case AF_INET6: 14438c2ecf20Sopenharmony_ci family = PF_INET6; 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci case AF_INET: 14468c2ecf20Sopenharmony_ci family = PF_INET; 14478c2ecf20Sopenharmony_ci break; 14488c2ecf20Sopenharmony_ci default: 14498c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci error = __sock_create(net, family, type, protocol, &sock, 1); 14538c2ecf20Sopenharmony_ci if (error < 0) 14548c2ecf20Sopenharmony_ci return ERR_PTR(error); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci svc_reclassify_socket(sock); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* 14598c2ecf20Sopenharmony_ci * If this is an PF_INET6 listener, we want to avoid 14608c2ecf20Sopenharmony_ci * getting requests from IPv4 remotes. Those should 14618c2ecf20Sopenharmony_ci * be shunted to a PF_INET listener via rpcbind. 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci if (family == PF_INET6) 14648c2ecf20Sopenharmony_ci ip6_sock_set_v6only(sock->sk); 14658c2ecf20Sopenharmony_ci if (type == SOCK_STREAM) 14668c2ecf20Sopenharmony_ci sock->sk->sk_reuse = SK_CAN_REUSE; /* allow address reuse */ 14678c2ecf20Sopenharmony_ci error = kernel_bind(sock, sin, len); 14688c2ecf20Sopenharmony_ci if (error < 0) 14698c2ecf20Sopenharmony_ci goto bummer; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci error = kernel_getsockname(sock, newsin); 14728c2ecf20Sopenharmony_ci if (error < 0) 14738c2ecf20Sopenharmony_ci goto bummer; 14748c2ecf20Sopenharmony_ci newlen = error; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci if (protocol == IPPROTO_TCP) { 14778c2ecf20Sopenharmony_ci if ((error = kernel_listen(sock, 64)) < 0) 14788c2ecf20Sopenharmony_ci goto bummer; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci svsk = svc_setup_socket(serv, sock, flags); 14828c2ecf20Sopenharmony_ci if (IS_ERR(svsk)) { 14838c2ecf20Sopenharmony_ci error = PTR_ERR(svsk); 14848c2ecf20Sopenharmony_ci goto bummer; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen); 14878c2ecf20Sopenharmony_ci return (struct svc_xprt *)svsk; 14888c2ecf20Sopenharmony_cibummer: 14898c2ecf20Sopenharmony_ci sock_release(sock); 14908c2ecf20Sopenharmony_ci return ERR_PTR(error); 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci/* 14948c2ecf20Sopenharmony_ci * Detach the svc_sock from the socket so that no 14958c2ecf20Sopenharmony_ci * more callbacks occur. 14968c2ecf20Sopenharmony_ci */ 14978c2ecf20Sopenharmony_cistatic void svc_sock_detach(struct svc_xprt *xprt) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 15008c2ecf20Sopenharmony_ci struct sock *sk = svsk->sk_sk; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci /* put back the old socket callbacks */ 15038c2ecf20Sopenharmony_ci lock_sock(sk); 15048c2ecf20Sopenharmony_ci sk->sk_state_change = svsk->sk_ostate; 15058c2ecf20Sopenharmony_ci sk->sk_data_ready = svsk->sk_odata; 15068c2ecf20Sopenharmony_ci sk->sk_write_space = svsk->sk_owspace; 15078c2ecf20Sopenharmony_ci sk->sk_user_data = NULL; 15088c2ecf20Sopenharmony_ci release_sock(sk); 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci/* 15128c2ecf20Sopenharmony_ci * Disconnect the socket, and reset the callbacks 15138c2ecf20Sopenharmony_ci */ 15148c2ecf20Sopenharmony_cistatic void svc_tcp_sock_detach(struct svc_xprt *xprt) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci svc_sock_detach(xprt); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (!test_bit(XPT_LISTENER, &xprt->xpt_flags)) { 15218c2ecf20Sopenharmony_ci svc_tcp_clear_pages(svsk); 15228c2ecf20Sopenharmony_ci kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR); 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci} 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci/* 15278c2ecf20Sopenharmony_ci * Free the svc_sock's socket resources and the svc_sock itself. 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_cistatic void svc_sock_free(struct svc_xprt *xprt) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (svsk->sk_sock->file) 15348c2ecf20Sopenharmony_ci sockfd_put(svsk->sk_sock); 15358c2ecf20Sopenharmony_ci else 15368c2ecf20Sopenharmony_ci sock_release(svsk->sk_sock); 15378c2ecf20Sopenharmony_ci kfree(svsk); 15388c2ecf20Sopenharmony_ci} 1539