10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51548Srshoaib * Common Development and Distribution License (the "License"). 61548Srshoaib * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211548Srshoaib 220Sstevel@tonic-gate /* 23*11436SJayakara.Kini@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <sys/types.h> 280Sstevel@tonic-gate #include <sys/t_lock.h> 290Sstevel@tonic-gate #include <sys/param.h> 300Sstevel@tonic-gate #include <sys/systm.h> 310Sstevel@tonic-gate #include <sys/buf.h> 320Sstevel@tonic-gate #include <sys/conf.h> 330Sstevel@tonic-gate #include <sys/cred.h> 340Sstevel@tonic-gate #include <sys/kmem.h> 350Sstevel@tonic-gate #include <sys/sysmacros.h> 360Sstevel@tonic-gate #include <sys/vfs.h> 370Sstevel@tonic-gate #include <sys/vnode.h> 380Sstevel@tonic-gate #include <sys/debug.h> 390Sstevel@tonic-gate #include <sys/errno.h> 400Sstevel@tonic-gate #include <sys/time.h> 410Sstevel@tonic-gate #include <sys/file.h> 420Sstevel@tonic-gate #include <sys/user.h> 430Sstevel@tonic-gate #include <sys/stream.h> 440Sstevel@tonic-gate #include <sys/strsubr.h> 450Sstevel@tonic-gate #include <sys/strsun.h> 464173Spr14459 #include <sys/sunddi.h> 470Sstevel@tonic-gate #include <sys/esunddi.h> 480Sstevel@tonic-gate #include <sys/flock.h> 490Sstevel@tonic-gate #include <sys/modctl.h> 500Sstevel@tonic-gate #include <sys/cmn_err.h> 510Sstevel@tonic-gate #include <sys/vmsystm.h> 520Sstevel@tonic-gate #include <sys/policy.h> 530Sstevel@tonic-gate 540Sstevel@tonic-gate #include <sys/socket.h> 550Sstevel@tonic-gate #include <sys/socketvar.h> 560Sstevel@tonic-gate 570Sstevel@tonic-gate #include <sys/isa_defs.h> 580Sstevel@tonic-gate #include <sys/inttypes.h> 590Sstevel@tonic-gate #include <sys/systm.h> 600Sstevel@tonic-gate #include <sys/cpuvar.h> 610Sstevel@tonic-gate #include <sys/filio.h> 620Sstevel@tonic-gate #include <sys/sendfile.h> 630Sstevel@tonic-gate #include <sys/ddi.h> 640Sstevel@tonic-gate #include <vm/seg.h> 650Sstevel@tonic-gate #include <vm/seg_map.h> 660Sstevel@tonic-gate #include <vm/seg_kpm.h> 678348SEric.Yu@Sun.COM 680Sstevel@tonic-gate #include <fs/sockfs/nl7c.h> 698348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h> 708348SEric.Yu@Sun.COM #include <fs/sockfs/socktpi.h> 710Sstevel@tonic-gate 720Sstevel@tonic-gate #ifdef SOCK_TEST 730Sstevel@tonic-gate int do_useracc = 1; /* Controlled by setting SO_DEBUG to 4 */ 740Sstevel@tonic-gate #else 750Sstevel@tonic-gate #define do_useracc 1 760Sstevel@tonic-gate #endif /* SOCK_TEST */ 770Sstevel@tonic-gate 780Sstevel@tonic-gate extern int xnet_truncate_print; 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* 810Sstevel@tonic-gate * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c" 820Sstevel@tonic-gate * as there isn't a formal definition of IOV_MAX ??? 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate #define MSG_MAXIOVLEN 16 850Sstevel@tonic-gate 860Sstevel@tonic-gate /* 870Sstevel@tonic-gate * Kernel component of socket creation. 880Sstevel@tonic-gate * 890Sstevel@tonic-gate * The socket library determines which version number to use. 900Sstevel@tonic-gate * First the library calls this with a NULL devpath. If this fails 910Sstevel@tonic-gate * to find a transport (using solookup) the library will look in /etc/netconfig 920Sstevel@tonic-gate * for the appropriate transport. If one is found it will pass in the 930Sstevel@tonic-gate * devpath for the kernel to use. 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate int 968348SEric.Yu@Sun.COM so_socket(int family, int type, int protocol, char *devpath, int version) 970Sstevel@tonic-gate { 980Sstevel@tonic-gate struct sonode *so; 990Sstevel@tonic-gate vnode_t *vp; 1000Sstevel@tonic-gate struct file *fp; 1010Sstevel@tonic-gate int fd; 1020Sstevel@tonic-gate int error; 1030Sstevel@tonic-gate 1048348SEric.Yu@Sun.COM if (devpath != NULL) { 1058348SEric.Yu@Sun.COM char *buf; 1068348SEric.Yu@Sun.COM size_t kdevpathlen = 0; 1070Sstevel@tonic-gate 1088348SEric.Yu@Sun.COM buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1098348SEric.Yu@Sun.COM if ((error = copyinstr(devpath, buf, 1108348SEric.Yu@Sun.COM MAXPATHLEN, &kdevpathlen)) != 0) { 1118348SEric.Yu@Sun.COM kmem_free(buf, MAXPATHLEN); 1120Sstevel@tonic-gate return (set_errno(error)); 1130Sstevel@tonic-gate } 1148348SEric.Yu@Sun.COM so = socket_create(family, type, protocol, buf, NULL, 1158348SEric.Yu@Sun.COM SOCKET_SLEEP, version, CRED(), &error); 1168348SEric.Yu@Sun.COM kmem_free(buf, MAXPATHLEN); 1178348SEric.Yu@Sun.COM } else { 1188348SEric.Yu@Sun.COM so = socket_create(family, type, protocol, NULL, NULL, 1198348SEric.Yu@Sun.COM SOCKET_SLEEP, version, CRED(), &error); 1200Sstevel@tonic-gate } 1218348SEric.Yu@Sun.COM if (so == NULL) 1220Sstevel@tonic-gate return (set_errno(error)); 1230Sstevel@tonic-gate 1248348SEric.Yu@Sun.COM /* Allocate a file descriptor for the socket */ 1250Sstevel@tonic-gate vp = SOTOV(so); 1260Sstevel@tonic-gate if (error = falloc(vp, FWRITE|FREAD, &fp, &fd)) { 1278348SEric.Yu@Sun.COM (void) socket_close(so, 0, CRED()); 1288348SEric.Yu@Sun.COM socket_destroy(so); 1290Sstevel@tonic-gate return (set_errno(error)); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * Now fill in the entries that falloc reserved 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 1360Sstevel@tonic-gate setf(fd, fp); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate return (fd); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* 1420Sstevel@tonic-gate * Map from a file descriptor to a socket node. 1430Sstevel@tonic-gate * Returns with the file descriptor held i.e. the caller has to 1440Sstevel@tonic-gate * use releasef when done with the file descriptor. 1450Sstevel@tonic-gate */ 1465227Stz204579 struct sonode * 1470Sstevel@tonic-gate getsonode(int sock, int *errorp, file_t **fpp) 1480Sstevel@tonic-gate { 1490Sstevel@tonic-gate file_t *fp; 1500Sstevel@tonic-gate vnode_t *vp; 1510Sstevel@tonic-gate struct sonode *so; 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate if ((fp = getf(sock)) == NULL) { 1540Sstevel@tonic-gate *errorp = EBADF; 1550Sstevel@tonic-gate eprintline(*errorp); 1560Sstevel@tonic-gate return (NULL); 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate vp = fp->f_vnode; 1590Sstevel@tonic-gate /* Check if it is a socket */ 1600Sstevel@tonic-gate if (vp->v_type != VSOCK) { 1610Sstevel@tonic-gate releasef(sock); 1620Sstevel@tonic-gate *errorp = ENOTSOCK; 1630Sstevel@tonic-gate eprintline(*errorp); 1640Sstevel@tonic-gate return (NULL); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate /* 1670Sstevel@tonic-gate * Use the stream head to find the real socket vnode. 1680Sstevel@tonic-gate * This is needed when namefs sits above sockfs. 1690Sstevel@tonic-gate */ 1700Sstevel@tonic-gate if (vp->v_stream) { 1710Sstevel@tonic-gate ASSERT(vp->v_stream->sd_vnode); 1720Sstevel@tonic-gate vp = vp->v_stream->sd_vnode; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate so = VTOSO(vp); 1750Sstevel@tonic-gate if (so->so_version == SOV_STREAM) { 1760Sstevel@tonic-gate releasef(sock); 1770Sstevel@tonic-gate *errorp = ENOTSOCK; 1780Sstevel@tonic-gate eprintsoline(so, *errorp); 1790Sstevel@tonic-gate return (NULL); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate } else { 1820Sstevel@tonic-gate so = VTOSO(vp); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate if (fpp) 1850Sstevel@tonic-gate *fpp = fp; 1860Sstevel@tonic-gate return (so); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * Allocate and copyin a sockaddr. 1910Sstevel@tonic-gate * Ensures NULL termination for AF_UNIX addresses by extending them 1920Sstevel@tonic-gate * with one NULL byte if need be. Verifies that the length is not 1930Sstevel@tonic-gate * excessive to prevent an application from consuming all of kernel 1940Sstevel@tonic-gate * memory. Returns NULL when an error occurred. 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate static struct sockaddr * 1970Sstevel@tonic-gate copyin_name(struct sonode *so, struct sockaddr *name, socklen_t *namelenp, 1980Sstevel@tonic-gate int *errorp) 1990Sstevel@tonic-gate { 2000Sstevel@tonic-gate char *faddr; 2010Sstevel@tonic-gate size_t namelen = (size_t)*namelenp; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate ASSERT(namelen != 0); 2040Sstevel@tonic-gate if (namelen > SO_MAXARGSIZE) { 2050Sstevel@tonic-gate *errorp = EINVAL; 2060Sstevel@tonic-gate eprintsoline(so, *errorp); 2070Sstevel@tonic-gate return (NULL); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate faddr = (char *)kmem_alloc(namelen, KM_SLEEP); 2110Sstevel@tonic-gate if (copyin(name, faddr, namelen)) { 2120Sstevel@tonic-gate kmem_free(faddr, namelen); 2130Sstevel@tonic-gate *errorp = EFAULT; 2140Sstevel@tonic-gate eprintsoline(so, *errorp); 2150Sstevel@tonic-gate return (NULL); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * Add space for NULL termination if needed. 2200Sstevel@tonic-gate * Do a quick check if the last byte is NUL. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate if (so->so_family == AF_UNIX && faddr[namelen - 1] != '\0') { 2230Sstevel@tonic-gate /* Check if there is any NULL termination */ 2240Sstevel@tonic-gate size_t i; 2250Sstevel@tonic-gate int foundnull = 0; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate for (i = sizeof (name->sa_family); i < namelen; i++) { 2280Sstevel@tonic-gate if (faddr[i] == '\0') { 2290Sstevel@tonic-gate foundnull = 1; 2300Sstevel@tonic-gate break; 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate if (!foundnull) { 2340Sstevel@tonic-gate /* Add extra byte for NUL padding */ 2350Sstevel@tonic-gate char *nfaddr; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate nfaddr = (char *)kmem_alloc(namelen + 1, KM_SLEEP); 2380Sstevel@tonic-gate bcopy(faddr, nfaddr, namelen); 2390Sstevel@tonic-gate kmem_free(faddr, namelen); 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* NUL terminate */ 2420Sstevel@tonic-gate nfaddr[namelen] = '\0'; 2430Sstevel@tonic-gate namelen++; 2440Sstevel@tonic-gate ASSERT((socklen_t)namelen == namelen); 2450Sstevel@tonic-gate *namelenp = (socklen_t)namelen; 2460Sstevel@tonic-gate faddr = nfaddr; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate return ((struct sockaddr *)faddr); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL. 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate static int 2560Sstevel@tonic-gate copyout_arg(void *uaddr, socklen_t ulen, void *ulenp, 2570Sstevel@tonic-gate void *kaddr, socklen_t klen) 2580Sstevel@tonic-gate { 2590Sstevel@tonic-gate if (uaddr != NULL) { 2600Sstevel@tonic-gate if (ulen > klen) 2610Sstevel@tonic-gate ulen = klen; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate if (ulen != 0) { 2640Sstevel@tonic-gate if (copyout(kaddr, uaddr, ulen)) 2650Sstevel@tonic-gate return (EFAULT); 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate } else 2680Sstevel@tonic-gate ulen = 0; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate if (ulenp != NULL) { 2710Sstevel@tonic-gate if (copyout(&ulen, ulenp, sizeof (ulen))) 2720Sstevel@tonic-gate return (EFAULT); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate return (0); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* 2780Sstevel@tonic-gate * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL. 2790Sstevel@tonic-gate * If klen is greater than ulen it still uses the non-truncated 2800Sstevel@tonic-gate * klen to update ulenp. 2810Sstevel@tonic-gate */ 2820Sstevel@tonic-gate static int 2830Sstevel@tonic-gate copyout_name(void *uaddr, socklen_t ulen, void *ulenp, 2840Sstevel@tonic-gate void *kaddr, socklen_t klen) 2850Sstevel@tonic-gate { 2860Sstevel@tonic-gate if (uaddr != NULL) { 2870Sstevel@tonic-gate if (ulen >= klen) 2880Sstevel@tonic-gate ulen = klen; 2890Sstevel@tonic-gate else if (ulen != 0 && xnet_truncate_print) { 2900Sstevel@tonic-gate printf("sockfs: truncating copyout of address using " 2910Sstevel@tonic-gate "XNET semantics for pid = %d. Lengths %d, %d\n", 2920Sstevel@tonic-gate curproc->p_pid, klen, ulen); 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate if (ulen != 0) { 2960Sstevel@tonic-gate if (copyout(kaddr, uaddr, ulen)) 2970Sstevel@tonic-gate return (EFAULT); 2980Sstevel@tonic-gate } else 2990Sstevel@tonic-gate klen = 0; 3000Sstevel@tonic-gate } else 3010Sstevel@tonic-gate klen = 0; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if (ulenp != NULL) { 3040Sstevel@tonic-gate if (copyout(&klen, ulenp, sizeof (klen))) 3050Sstevel@tonic-gate return (EFAULT); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate return (0); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* 3110Sstevel@tonic-gate * The socketpair() code in libsocket creates two sockets (using 3120Sstevel@tonic-gate * the /etc/netconfig fallback if needed) before calling this routine 3130Sstevel@tonic-gate * to connect the two sockets together. 3140Sstevel@tonic-gate * 3150Sstevel@tonic-gate * For a SOCK_STREAM socketpair a listener is needed - in that case this 3160Sstevel@tonic-gate * routine will create a new file descriptor as part of accepting the 3170Sstevel@tonic-gate * connection. The library socketpair() will check if svs[2] has changed 3180Sstevel@tonic-gate * in which case it will close the changed fd. 3190Sstevel@tonic-gate * 3200Sstevel@tonic-gate * Note that this code could use the TPI feature of accepting the connection 3210Sstevel@tonic-gate * on the listening endpoint. However, that would require significant changes 3220Sstevel@tonic-gate * to soaccept. 3230Sstevel@tonic-gate */ 3240Sstevel@tonic-gate int 3250Sstevel@tonic-gate so_socketpair(int sv[2]) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate int svs[2]; 3280Sstevel@tonic-gate struct sonode *so1, *so2; 3290Sstevel@tonic-gate int error; 3300Sstevel@tonic-gate struct sockaddr_ux *name; 3310Sstevel@tonic-gate size_t namelen; 3328348SEric.Yu@Sun.COM sotpi_info_t *sti1; 3338348SEric.Yu@Sun.COM sotpi_info_t *sti2; 3340Sstevel@tonic-gate 3357240Srh87107 dprint(1, ("so_socketpair(%p)\n", (void *)sv)); 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate error = useracc(sv, sizeof (svs), B_WRITE); 3380Sstevel@tonic-gate if (error && do_useracc) 3390Sstevel@tonic-gate return (set_errno(EFAULT)); 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate if (copyin(sv, svs, sizeof (svs))) 3420Sstevel@tonic-gate return (set_errno(EFAULT)); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if ((so1 = getsonode(svs[0], &error, NULL)) == NULL) 3450Sstevel@tonic-gate return (set_errno(error)); 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate if ((so2 = getsonode(svs[1], &error, NULL)) == NULL) { 3480Sstevel@tonic-gate releasef(svs[0]); 3490Sstevel@tonic-gate return (set_errno(error)); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate if (so1->so_family != AF_UNIX || so2->so_family != AF_UNIX) { 3530Sstevel@tonic-gate error = EOPNOTSUPP; 3540Sstevel@tonic-gate goto done; 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3578348SEric.Yu@Sun.COM sti1 = SOTOTPI(so1); 3588348SEric.Yu@Sun.COM sti2 = SOTOTPI(so2); 3598348SEric.Yu@Sun.COM 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * The code below makes assumptions about the "sockfs" implementation. 3620Sstevel@tonic-gate * So make sure that the correct implementation is really used. 3630Sstevel@tonic-gate */ 3640Sstevel@tonic-gate ASSERT(so1->so_ops == &sotpi_sonodeops); 3650Sstevel@tonic-gate ASSERT(so2->so_ops == &sotpi_sonodeops); 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate if (so1->so_type == SOCK_DGRAM) { 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * Bind both sockets and connect them with each other. 3700Sstevel@tonic-gate * Need to allocate name/namelen for soconnect. 3710Sstevel@tonic-gate */ 3728348SEric.Yu@Sun.COM error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC, CRED()); 3730Sstevel@tonic-gate if (error) { 3740Sstevel@tonic-gate eprintsoline(so1, error); 3750Sstevel@tonic-gate goto done; 3760Sstevel@tonic-gate } 3778348SEric.Yu@Sun.COM error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED()); 3780Sstevel@tonic-gate if (error) { 3790Sstevel@tonic-gate eprintsoline(so2, error); 3800Sstevel@tonic-gate goto done; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate namelen = sizeof (struct sockaddr_ux); 3830Sstevel@tonic-gate name = kmem_alloc(namelen, KM_SLEEP); 3840Sstevel@tonic-gate name->sou_family = AF_UNIX; 3858348SEric.Yu@Sun.COM name->sou_addr = sti2->sti_ux_laddr; 3868348SEric.Yu@Sun.COM error = socket_connect(so1, 3875227Stz204579 (struct sockaddr *)name, 3885227Stz204579 (socklen_t)namelen, 3898348SEric.Yu@Sun.COM 0, _SOCONNECT_NOXLATE, CRED()); 3900Sstevel@tonic-gate if (error) { 3910Sstevel@tonic-gate kmem_free(name, namelen); 3920Sstevel@tonic-gate eprintsoline(so1, error); 3930Sstevel@tonic-gate goto done; 3940Sstevel@tonic-gate } 3958348SEric.Yu@Sun.COM name->sou_addr = sti1->sti_ux_laddr; 3968348SEric.Yu@Sun.COM error = socket_connect(so2, 3975227Stz204579 (struct sockaddr *)name, 3985227Stz204579 (socklen_t)namelen, 3998348SEric.Yu@Sun.COM 0, _SOCONNECT_NOXLATE, CRED()); 4000Sstevel@tonic-gate kmem_free(name, namelen); 4010Sstevel@tonic-gate if (error) { 4020Sstevel@tonic-gate eprintsoline(so2, error); 4030Sstevel@tonic-gate goto done; 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate releasef(svs[0]); 4060Sstevel@tonic-gate releasef(svs[1]); 4070Sstevel@tonic-gate } else { 4080Sstevel@tonic-gate /* 4090Sstevel@tonic-gate * Bind both sockets, with so1 being a listener. 4100Sstevel@tonic-gate * Connect so2 to so1 - nonblocking to avoid waiting for 4110Sstevel@tonic-gate * soaccept to complete. 4120Sstevel@tonic-gate * Accept a connection on so1. Pass out the new fd as sv[0]. 4130Sstevel@tonic-gate * The library will detect the changed fd and close 4140Sstevel@tonic-gate * the original one. 4150Sstevel@tonic-gate */ 4160Sstevel@tonic-gate struct sonode *nso; 4170Sstevel@tonic-gate struct vnode *nvp; 4180Sstevel@tonic-gate struct file *nfp; 4190Sstevel@tonic-gate int nfd; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4228348SEric.Yu@Sun.COM * We could simply call socket_listen() here (which would do the 4230Sstevel@tonic-gate * binding automatically) if the code didn't rely on passing 4248348SEric.Yu@Sun.COM * _SOBIND_NOXLATE to the TPI implementation of socket_bind(). 4250Sstevel@tonic-gate */ 4268348SEric.Yu@Sun.COM error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC| 4278348SEric.Yu@Sun.COM _SOBIND_NOXLATE|_SOBIND_LISTEN|_SOBIND_SOCKETPAIR, 4288348SEric.Yu@Sun.COM CRED()); 4290Sstevel@tonic-gate if (error) { 4300Sstevel@tonic-gate eprintsoline(so1, error); 4310Sstevel@tonic-gate goto done; 4320Sstevel@tonic-gate } 4338348SEric.Yu@Sun.COM error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED()); 4340Sstevel@tonic-gate if (error) { 4350Sstevel@tonic-gate eprintsoline(so2, error); 4360Sstevel@tonic-gate goto done; 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate namelen = sizeof (struct sockaddr_ux); 4400Sstevel@tonic-gate name = kmem_alloc(namelen, KM_SLEEP); 4410Sstevel@tonic-gate name->sou_family = AF_UNIX; 4428348SEric.Yu@Sun.COM name->sou_addr = sti1->sti_ux_laddr; 4438348SEric.Yu@Sun.COM error = socket_connect(so2, 4445227Stz204579 (struct sockaddr *)name, 4455227Stz204579 (socklen_t)namelen, 4468348SEric.Yu@Sun.COM FNONBLOCK, _SOCONNECT_NOXLATE, CRED()); 4470Sstevel@tonic-gate kmem_free(name, namelen); 4480Sstevel@tonic-gate if (error) { 4490Sstevel@tonic-gate if (error != EINPROGRESS) { 4508348SEric.Yu@Sun.COM eprintsoline(so2, error); goto done; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4548348SEric.Yu@Sun.COM error = socket_accept(so1, 0, CRED(), &nso); 4550Sstevel@tonic-gate if (error) { 4560Sstevel@tonic-gate eprintsoline(so1, error); 4570Sstevel@tonic-gate goto done; 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* wait for so2 being SS_CONNECTED ignoring signals */ 4610Sstevel@tonic-gate mutex_enter(&so2->so_lock); 4620Sstevel@tonic-gate error = sowaitconnected(so2, 0, 1); 4630Sstevel@tonic-gate mutex_exit(&so2->so_lock); 4640Sstevel@tonic-gate if (error != 0) { 4658348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED()); 4668348SEric.Yu@Sun.COM socket_destroy(nso); 4670Sstevel@tonic-gate eprintsoline(so2, error); 4680Sstevel@tonic-gate goto done; 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4718348SEric.Yu@Sun.COM nvp = SOTOV(nso); 4720Sstevel@tonic-gate if (error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd)) { 4738348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED()); 4748348SEric.Yu@Sun.COM socket_destroy(nso); 4750Sstevel@tonic-gate eprintsoline(nso, error); 4760Sstevel@tonic-gate goto done; 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * fill in the entries that falloc reserved 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate mutex_exit(&nfp->f_tlock); 4820Sstevel@tonic-gate setf(nfd, nfp); 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate releasef(svs[0]); 4850Sstevel@tonic-gate releasef(svs[1]); 4860Sstevel@tonic-gate svs[0] = nfd; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* 4890Sstevel@tonic-gate * The socketpair library routine will close the original 4900Sstevel@tonic-gate * svs[0] when this code passes out a different file 4910Sstevel@tonic-gate * descriptor. 4920Sstevel@tonic-gate */ 4930Sstevel@tonic-gate if (copyout(svs, sv, sizeof (svs))) { 4940Sstevel@tonic-gate (void) closeandsetf(nfd, NULL); 4950Sstevel@tonic-gate eprintline(EFAULT); 4960Sstevel@tonic-gate return (set_errno(EFAULT)); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate return (0); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate done: 5020Sstevel@tonic-gate releasef(svs[0]); 5030Sstevel@tonic-gate releasef(svs[1]); 5040Sstevel@tonic-gate return (set_errno(error)); 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate int 5080Sstevel@tonic-gate bind(int sock, struct sockaddr *name, socklen_t namelen, int version) 5090Sstevel@tonic-gate { 5100Sstevel@tonic-gate struct sonode *so; 5110Sstevel@tonic-gate int error; 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate dprint(1, ("bind(%d, %p, %d)\n", 5147240Srh87107 sock, (void *)name, namelen)); 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL) 5170Sstevel@tonic-gate return (set_errno(error)); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate /* Allocate and copyin name */ 5200Sstevel@tonic-gate /* 5210Sstevel@tonic-gate * X/Open test does not expect EFAULT with NULL name and non-zero 5220Sstevel@tonic-gate * namelen. 5230Sstevel@tonic-gate */ 5240Sstevel@tonic-gate if (name != NULL && namelen != 0) { 5250Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 5260Sstevel@tonic-gate name = copyin_name(so, name, &namelen, &error); 5270Sstevel@tonic-gate if (name == NULL) { 5280Sstevel@tonic-gate releasef(sock); 5290Sstevel@tonic-gate return (set_errno(error)); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate } else { 5320Sstevel@tonic-gate name = NULL; 5330Sstevel@tonic-gate namelen = 0; 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate switch (version) { 5370Sstevel@tonic-gate default: 5388348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, 0, CRED()); 5390Sstevel@tonic-gate break; 5400Sstevel@tonic-gate case SOV_XPG4_2: 5418348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, _SOBIND_XPG4_2, CRED()); 5420Sstevel@tonic-gate break; 5430Sstevel@tonic-gate case SOV_SOCKBSD: 5448348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, _SOBIND_SOCKBSD, CRED()); 5450Sstevel@tonic-gate break; 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate done: 5480Sstevel@tonic-gate releasef(sock); 5490Sstevel@tonic-gate if (name != NULL) 5500Sstevel@tonic-gate kmem_free(name, (size_t)namelen); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate if (error) 5530Sstevel@tonic-gate return (set_errno(error)); 5540Sstevel@tonic-gate return (0); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate /* ARGSUSED2 */ 5580Sstevel@tonic-gate int 5590Sstevel@tonic-gate listen(int sock, int backlog, int version) 5600Sstevel@tonic-gate { 5610Sstevel@tonic-gate struct sonode *so; 5620Sstevel@tonic-gate int error; 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate dprint(1, ("listen(%d, %d)\n", 5655227Stz204579 sock, backlog)); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL) 5680Sstevel@tonic-gate return (set_errno(error)); 5690Sstevel@tonic-gate 5708348SEric.Yu@Sun.COM error = socket_listen(so, backlog, CRED()); 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate releasef(sock); 5730Sstevel@tonic-gate if (error) 5740Sstevel@tonic-gate return (set_errno(error)); 5750Sstevel@tonic-gate return (0); 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /*ARGSUSED3*/ 5790Sstevel@tonic-gate int 5800Sstevel@tonic-gate accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version) 5810Sstevel@tonic-gate { 5820Sstevel@tonic-gate struct sonode *so; 5830Sstevel@tonic-gate file_t *fp; 5840Sstevel@tonic-gate int error; 5850Sstevel@tonic-gate socklen_t namelen; 5860Sstevel@tonic-gate struct sonode *nso; 5870Sstevel@tonic-gate struct vnode *nvp; 5880Sstevel@tonic-gate struct file *nfp; 5890Sstevel@tonic-gate int nfd; 5908348SEric.Yu@Sun.COM struct sockaddr *addrp; 5918348SEric.Yu@Sun.COM socklen_t addrlen; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate dprint(1, ("accept(%d, %p, %p)\n", 5947240Srh87107 sock, (void *)name, (void *)namelenp)); 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL) 5970Sstevel@tonic-gate return (set_errno(error)); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate if (name != NULL) { 6000Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6010Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen))) { 6020Sstevel@tonic-gate releasef(sock); 6030Sstevel@tonic-gate return (set_errno(EFAULT)); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate if (namelen != 0) { 6060Sstevel@tonic-gate error = useracc(name, (size_t)namelen, B_WRITE); 6070Sstevel@tonic-gate if (error && do_useracc) { 6080Sstevel@tonic-gate releasef(sock); 6090Sstevel@tonic-gate return (set_errno(EFAULT)); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate } else 6120Sstevel@tonic-gate name = NULL; 6130Sstevel@tonic-gate } else { 6140Sstevel@tonic-gate namelen = 0; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate /* 6188348SEric.Yu@Sun.COM * Allocate the user fd before socket_accept() in order to 6198348SEric.Yu@Sun.COM * catch EMFILE errors before calling socket_accept(). 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate if ((nfd = ufalloc(0)) == -1) { 6220Sstevel@tonic-gate eprintsoline(so, EMFILE); 6230Sstevel@tonic-gate releasef(sock); 6240Sstevel@tonic-gate return (set_errno(EMFILE)); 6250Sstevel@tonic-gate } 6268348SEric.Yu@Sun.COM error = socket_accept(so, fp->f_flag, CRED(), &nso); 6270Sstevel@tonic-gate if (error) { 6280Sstevel@tonic-gate setf(nfd, NULL); 629*11436SJayakara.Kini@Sun.COM releasef(sock); 6300Sstevel@tonic-gate return (set_errno(error)); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate nvp = SOTOV(nso); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&nso->so_lock)); 6368348SEric.Yu@Sun.COM if (namelen != 0) { 6378348SEric.Yu@Sun.COM addrlen = so->so_max_addr_len; 6388348SEric.Yu@Sun.COM addrp = (struct sockaddr *)kmem_alloc(addrlen, KM_SLEEP); 6398348SEric.Yu@Sun.COM 6408348SEric.Yu@Sun.COM if ((error = socket_getpeername(nso, (struct sockaddr *)addrp, 6418348SEric.Yu@Sun.COM &addrlen, B_TRUE, CRED())) == 0) { 6428348SEric.Yu@Sun.COM error = copyout_name(name, namelen, namelenp, 6438348SEric.Yu@Sun.COM addrp, addrlen); 6448348SEric.Yu@Sun.COM } else { 6458348SEric.Yu@Sun.COM ASSERT(error == EINVAL || error == ENOTCONN); 6468348SEric.Yu@Sun.COM error = ECONNABORTED; 6478348SEric.Yu@Sun.COM } 6488348SEric.Yu@Sun.COM kmem_free(addrp, so->so_max_addr_len); 6498348SEric.Yu@Sun.COM } 6508348SEric.Yu@Sun.COM 6510Sstevel@tonic-gate if (error) { 6520Sstevel@tonic-gate setf(nfd, NULL); 6538348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED()); 6548348SEric.Yu@Sun.COM socket_destroy(nso); 655*11436SJayakara.Kini@Sun.COM releasef(sock); 6560Sstevel@tonic-gate return (set_errno(error)); 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate if (error = falloc(NULL, FWRITE|FREAD, &nfp, NULL)) { 6590Sstevel@tonic-gate setf(nfd, NULL); 6608348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED()); 6618348SEric.Yu@Sun.COM socket_destroy(nso); 6620Sstevel@tonic-gate eprintsoline(so, error); 663*11436SJayakara.Kini@Sun.COM releasef(sock); 6640Sstevel@tonic-gate return (set_errno(error)); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * fill in the entries that falloc reserved 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate nfp->f_vnode = nvp; 6700Sstevel@tonic-gate mutex_exit(&nfp->f_tlock); 6710Sstevel@tonic-gate setf(nfd, nfp); 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* 6740Sstevel@tonic-gate * Copy FNDELAY and FNONBLOCK from listener to acceptor 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate if (so->so_state & (SS_NDELAY|SS_NONBLOCK)) { 6770Sstevel@tonic-gate uint_t oflag = nfp->f_flag; 6780Sstevel@tonic-gate int arg = 0; 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate if (so->so_state & SS_NONBLOCK) 6810Sstevel@tonic-gate arg |= FNONBLOCK; 6820Sstevel@tonic-gate else if (so->so_state & SS_NDELAY) 6830Sstevel@tonic-gate arg |= FNDELAY; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * This code is a simplification of the F_SETFL code in fcntl() 6870Sstevel@tonic-gate * Ignore any errors from VOP_SETFL. 6880Sstevel@tonic-gate */ 6895331Samw if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL)) 6905331Samw != 0) { 6910Sstevel@tonic-gate eprintsoline(so, error); 6920Sstevel@tonic-gate error = 0; 6930Sstevel@tonic-gate } else { 6940Sstevel@tonic-gate mutex_enter(&nfp->f_tlock); 6950Sstevel@tonic-gate nfp->f_flag &= ~FMASK | (FREAD|FWRITE); 6960Sstevel@tonic-gate nfp->f_flag |= arg; 6970Sstevel@tonic-gate mutex_exit(&nfp->f_tlock); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate } 700*11436SJayakara.Kini@Sun.COM releasef(sock); 7010Sstevel@tonic-gate return (nfd); 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate int 7050Sstevel@tonic-gate connect(int sock, struct sockaddr *name, socklen_t namelen, int version) 7060Sstevel@tonic-gate { 7070Sstevel@tonic-gate struct sonode *so; 7080Sstevel@tonic-gate file_t *fp; 7090Sstevel@tonic-gate int error; 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate dprint(1, ("connect(%d, %p, %d)\n", 7127240Srh87107 sock, (void *)name, namelen)); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL) 7150Sstevel@tonic-gate return (set_errno(error)); 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate /* Allocate and copyin name */ 7180Sstevel@tonic-gate if (namelen != 0) { 7190Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 7200Sstevel@tonic-gate name = copyin_name(so, name, &namelen, &error); 7210Sstevel@tonic-gate if (name == NULL) { 7220Sstevel@tonic-gate releasef(sock); 7230Sstevel@tonic-gate return (set_errno(error)); 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate } else 7260Sstevel@tonic-gate name = NULL; 7270Sstevel@tonic-gate 7288348SEric.Yu@Sun.COM error = socket_connect(so, name, namelen, fp->f_flag, 7298348SEric.Yu@Sun.COM (version != SOV_XPG4_2) ? 0 : _SOCONNECT_XPG4_2, CRED()); 7300Sstevel@tonic-gate releasef(sock); 7310Sstevel@tonic-gate if (name) 7320Sstevel@tonic-gate kmem_free(name, (size_t)namelen); 7330Sstevel@tonic-gate if (error) 7340Sstevel@tonic-gate return (set_errno(error)); 7350Sstevel@tonic-gate return (0); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate /*ARGSUSED2*/ 7390Sstevel@tonic-gate int 7400Sstevel@tonic-gate shutdown(int sock, int how, int version) 7410Sstevel@tonic-gate { 7420Sstevel@tonic-gate struct sonode *so; 7430Sstevel@tonic-gate int error; 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate dprint(1, ("shutdown(%d, %d)\n", 7465227Stz204579 sock, how)); 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL) 7490Sstevel@tonic-gate return (set_errno(error)); 7500Sstevel@tonic-gate 7518348SEric.Yu@Sun.COM error = socket_shutdown(so, how, CRED()); 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate releasef(sock); 7540Sstevel@tonic-gate if (error) 7550Sstevel@tonic-gate return (set_errno(error)); 7560Sstevel@tonic-gate return (0); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate /* 7600Sstevel@tonic-gate * Common receive routine. 7610Sstevel@tonic-gate */ 7620Sstevel@tonic-gate static ssize_t 7630Sstevel@tonic-gate recvit(int sock, 7640Sstevel@tonic-gate struct nmsghdr *msg, 7650Sstevel@tonic-gate struct uio *uiop, 7660Sstevel@tonic-gate int flags, 7670Sstevel@tonic-gate socklen_t *namelenp, 7680Sstevel@tonic-gate socklen_t *controllenp, 7690Sstevel@tonic-gate int *flagsp) 7700Sstevel@tonic-gate { 7710Sstevel@tonic-gate struct sonode *so; 7720Sstevel@tonic-gate file_t *fp; 7730Sstevel@tonic-gate void *name; 7740Sstevel@tonic-gate socklen_t namelen; 7750Sstevel@tonic-gate void *control; 7760Sstevel@tonic-gate socklen_t controllen; 7770Sstevel@tonic-gate ssize_t len; 7780Sstevel@tonic-gate int error; 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL) 7810Sstevel@tonic-gate return (set_errno(error)); 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate len = uiop->uio_resid; 7840Sstevel@tonic-gate uiop->uio_fmode = fp->f_flag; 7850Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_CACHED; 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate name = msg->msg_name; 7880Sstevel@tonic-gate namelen = msg->msg_namelen; 7890Sstevel@tonic-gate control = msg->msg_control; 7900Sstevel@tonic-gate controllen = msg->msg_controllen; 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL | 7930Sstevel@tonic-gate MSG_DONTWAIT | MSG_XPG4_2); 7940Sstevel@tonic-gate 7958348SEric.Yu@Sun.COM error = socket_recvmsg(so, msg, uiop, CRED()); 7960Sstevel@tonic-gate if (error) { 7970Sstevel@tonic-gate releasef(sock); 7980Sstevel@tonic-gate return (set_errno(error)); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate lwp_stat_update(LWP_STAT_MSGRCV, 1); 8010Sstevel@tonic-gate releasef(sock); 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate error = copyout_name(name, namelen, namelenp, 8040Sstevel@tonic-gate msg->msg_name, msg->msg_namelen); 8050Sstevel@tonic-gate if (error) 8060Sstevel@tonic-gate goto err; 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate if (flagsp != NULL) { 8090Sstevel@tonic-gate /* 8100Sstevel@tonic-gate * Clear internal flag. 8110Sstevel@tonic-gate */ 8120Sstevel@tonic-gate msg->msg_flags &= ~MSG_XPG4_2; 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* 8150Sstevel@tonic-gate * Determine MSG_CTRUNC. sorecvmsg sets MSG_CTRUNC only 8160Sstevel@tonic-gate * when controllen is zero and there is control data to 8170Sstevel@tonic-gate * copy out. 8180Sstevel@tonic-gate */ 8190Sstevel@tonic-gate if (controllen != 0 && 8200Sstevel@tonic-gate (msg->msg_controllen > controllen || control == NULL)) { 8210Sstevel@tonic-gate dprint(1, ("recvit: CTRUNC %d %d %p\n", 8220Sstevel@tonic-gate msg->msg_controllen, controllen, control)); 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate msg->msg_flags |= MSG_CTRUNC; 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate if (copyout(&msg->msg_flags, flagsp, 8270Sstevel@tonic-gate sizeof (msg->msg_flags))) { 8280Sstevel@tonic-gate error = EFAULT; 8290Sstevel@tonic-gate goto err; 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate /* 8330Sstevel@tonic-gate * Note: This MUST be done last. There can be no "goto err" after this 8340Sstevel@tonic-gate * point since it could make so_closefds run twice on some part 8350Sstevel@tonic-gate * of the file descriptor array. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate if (controllen != 0) { 8380Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) { 8390Sstevel@tonic-gate /* 8400Sstevel@tonic-gate * Good old msg_accrights can only return a multiple 8410Sstevel@tonic-gate * of 4 bytes. 8420Sstevel@tonic-gate */ 8430Sstevel@tonic-gate controllen &= ~((int)sizeof (uint32_t) - 1); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate error = copyout_arg(control, controllen, controllenp, 8460Sstevel@tonic-gate msg->msg_control, msg->msg_controllen); 8470Sstevel@tonic-gate if (error) 8480Sstevel@tonic-gate goto err; 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate if (msg->msg_controllen > controllen || control == NULL) { 8510Sstevel@tonic-gate if (control == NULL) 8520Sstevel@tonic-gate controllen = 0; 8530Sstevel@tonic-gate so_closefds(msg->msg_control, msg->msg_controllen, 8540Sstevel@tonic-gate !(flags & MSG_XPG4_2), controllen); 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate if (msg->msg_namelen != 0) 8580Sstevel@tonic-gate kmem_free(msg->msg_name, (size_t)msg->msg_namelen); 8590Sstevel@tonic-gate if (msg->msg_controllen != 0) 8600Sstevel@tonic-gate kmem_free(msg->msg_control, (size_t)msg->msg_controllen); 8610Sstevel@tonic-gate return (len - uiop->uio_resid); 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate err: 8640Sstevel@tonic-gate /* 8650Sstevel@tonic-gate * If we fail and the control part contains file descriptors 8660Sstevel@tonic-gate * we have to close the fd's. 8670Sstevel@tonic-gate */ 8680Sstevel@tonic-gate if (msg->msg_controllen != 0) 8690Sstevel@tonic-gate so_closefds(msg->msg_control, msg->msg_controllen, 8700Sstevel@tonic-gate !(flags & MSG_XPG4_2), 0); 8710Sstevel@tonic-gate if (msg->msg_namelen != 0) 8720Sstevel@tonic-gate kmem_free(msg->msg_name, (size_t)msg->msg_namelen); 8730Sstevel@tonic-gate if (msg->msg_controllen != 0) 8740Sstevel@tonic-gate kmem_free(msg->msg_control, (size_t)msg->msg_controllen); 8750Sstevel@tonic-gate return (set_errno(error)); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate /* 8790Sstevel@tonic-gate * Native system call 8800Sstevel@tonic-gate */ 8810Sstevel@tonic-gate ssize_t 8820Sstevel@tonic-gate recv(int sock, void *buffer, size_t len, int flags) 8830Sstevel@tonic-gate { 8840Sstevel@tonic-gate struct nmsghdr lmsg; 8850Sstevel@tonic-gate struct uio auio; 8860Sstevel@tonic-gate struct iovec aiov[1]; 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate dprint(1, ("recv(%d, %p, %ld, %d)\n", 8895227Stz204579 sock, buffer, len, flags)); 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate if ((ssize_t)len < 0) { 8920Sstevel@tonic-gate return (set_errno(EINVAL)); 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate aiov[0].iov_base = buffer; 8960Sstevel@tonic-gate aiov[0].iov_len = len; 8970Sstevel@tonic-gate auio.uio_loffset = 0; 8980Sstevel@tonic-gate auio.uio_iov = aiov; 8990Sstevel@tonic-gate auio.uio_iovcnt = 1; 9000Sstevel@tonic-gate auio.uio_resid = len; 9010Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 9020Sstevel@tonic-gate auio.uio_limit = 0; 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate lmsg.msg_namelen = 0; 9050Sstevel@tonic-gate lmsg.msg_controllen = 0; 9060Sstevel@tonic-gate lmsg.msg_flags = 0; 9070Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags, NULL, NULL, NULL)); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate ssize_t 9110Sstevel@tonic-gate recvfrom(int sock, void *buffer, size_t len, int flags, 9120Sstevel@tonic-gate struct sockaddr *name, socklen_t *namelenp) 9130Sstevel@tonic-gate { 9140Sstevel@tonic-gate struct nmsghdr lmsg; 9150Sstevel@tonic-gate struct uio auio; 9160Sstevel@tonic-gate struct iovec aiov[1]; 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate dprint(1, ("recvfrom(%d, %p, %ld, %d, %p, %p)\n", 9197240Srh87107 sock, buffer, len, flags, (void *)name, (void *)namelenp)); 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate if ((ssize_t)len < 0) { 9220Sstevel@tonic-gate return (set_errno(EINVAL)); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate aiov[0].iov_base = buffer; 9260Sstevel@tonic-gate aiov[0].iov_len = len; 9270Sstevel@tonic-gate auio.uio_loffset = 0; 9280Sstevel@tonic-gate auio.uio_iov = aiov; 9290Sstevel@tonic-gate auio.uio_iovcnt = 1; 9300Sstevel@tonic-gate auio.uio_resid = len; 9310Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 9320Sstevel@tonic-gate auio.uio_limit = 0; 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate lmsg.msg_name = (char *)name; 9350Sstevel@tonic-gate if (namelenp != NULL) { 9360Sstevel@tonic-gate if (copyin(namelenp, &lmsg.msg_namelen, 9370Sstevel@tonic-gate sizeof (lmsg.msg_namelen))) 9380Sstevel@tonic-gate return (set_errno(EFAULT)); 9390Sstevel@tonic-gate } else { 9400Sstevel@tonic-gate lmsg.msg_namelen = 0; 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate lmsg.msg_controllen = 0; 9430Sstevel@tonic-gate lmsg.msg_flags = 0; 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags, namelenp, NULL, NULL)); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate /* 9490Sstevel@tonic-gate * Uses the MSG_XPG4_2 flag to determine if the caller is using 9500Sstevel@tonic-gate * struct omsghdr or struct nmsghdr. 9510Sstevel@tonic-gate */ 9520Sstevel@tonic-gate ssize_t 9530Sstevel@tonic-gate recvmsg(int sock, struct nmsghdr *msg, int flags) 9540Sstevel@tonic-gate { 9550Sstevel@tonic-gate STRUCT_DECL(nmsghdr, u_lmsg); 9560Sstevel@tonic-gate STRUCT_HANDLE(nmsghdr, umsgptr); 9570Sstevel@tonic-gate struct nmsghdr lmsg; 9580Sstevel@tonic-gate struct uio auio; 9590Sstevel@tonic-gate struct iovec aiov[MSG_MAXIOVLEN]; 9600Sstevel@tonic-gate int iovcnt; 9610Sstevel@tonic-gate ssize_t len; 9620Sstevel@tonic-gate int i; 9630Sstevel@tonic-gate int *flagsp; 9640Sstevel@tonic-gate model_t model; 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate dprint(1, ("recvmsg(%d, %p, %d)\n", 9677240Srh87107 sock, (void *)msg, flags)); 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate model = get_udatamodel(); 9700Sstevel@tonic-gate STRUCT_INIT(u_lmsg, model); 9710Sstevel@tonic-gate STRUCT_SET_HANDLE(umsgptr, model, msg); 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate if (flags & MSG_XPG4_2) { 9740Sstevel@tonic-gate if (copyin(msg, STRUCT_BUF(u_lmsg), STRUCT_SIZE(u_lmsg))) 9750Sstevel@tonic-gate return (set_errno(EFAULT)); 9760Sstevel@tonic-gate flagsp = STRUCT_FADDR(umsgptr, msg_flags); 9770Sstevel@tonic-gate } else { 9780Sstevel@tonic-gate /* 9790Sstevel@tonic-gate * Assumes that nmsghdr and omsghdr are identically shaped 9800Sstevel@tonic-gate * except for the added msg_flags field. 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate if (copyin(msg, STRUCT_BUF(u_lmsg), 9830Sstevel@tonic-gate SIZEOF_STRUCT(omsghdr, model))) 9840Sstevel@tonic-gate return (set_errno(EFAULT)); 9850Sstevel@tonic-gate STRUCT_FSET(u_lmsg, msg_flags, 0); 9860Sstevel@tonic-gate flagsp = NULL; 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate /* 9900Sstevel@tonic-gate * Code below us will kmem_alloc memory and hang it 9910Sstevel@tonic-gate * off msg_control and msg_name fields. This forces 9920Sstevel@tonic-gate * us to copy the structure to its native form. 9930Sstevel@tonic-gate */ 9940Sstevel@tonic-gate lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name); 9950Sstevel@tonic-gate lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen); 9960Sstevel@tonic-gate lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov); 9970Sstevel@tonic-gate lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen); 9980Sstevel@tonic-gate lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control); 9990Sstevel@tonic-gate lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen); 10000Sstevel@tonic-gate lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags); 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate iovcnt = lmsg.msg_iovlen; 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) { 10050Sstevel@tonic-gate return (set_errno(EMSGSIZE)); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 10090Sstevel@tonic-gate /* 10100Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, while ensuring 10110Sstevel@tonic-gate * that they can't move more than 2Gbytes of data in a single call. 10120Sstevel@tonic-gate */ 10130Sstevel@tonic-gate if (model == DATAMODEL_ILP32) { 10140Sstevel@tonic-gate struct iovec32 aiov32[MSG_MAXIOVLEN]; 10150Sstevel@tonic-gate ssize32_t count32; 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32, 10180Sstevel@tonic-gate iovcnt * sizeof (struct iovec32))) 10190Sstevel@tonic-gate return (set_errno(EFAULT)); 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate count32 = 0; 10220Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 10230Sstevel@tonic-gate ssize32_t iovlen32; 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate iovlen32 = aiov32[i].iov_len; 10260Sstevel@tonic-gate count32 += iovlen32; 10270Sstevel@tonic-gate if (iovlen32 < 0 || count32 < 0) 10280Sstevel@tonic-gate return (set_errno(EINVAL)); 10290Sstevel@tonic-gate aiov[i].iov_len = iovlen32; 10300Sstevel@tonic-gate aiov[i].iov_base = 10310Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base; 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate } else 10340Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 10350Sstevel@tonic-gate if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) { 10360Sstevel@tonic-gate return (set_errno(EFAULT)); 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate len = 0; 10390Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 10400Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len; 10410Sstevel@tonic-gate len += iovlen; 10420Sstevel@tonic-gate if (iovlen < 0 || len < 0) { 10430Sstevel@tonic-gate return (set_errno(EINVAL)); 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate auio.uio_loffset = 0; 10470Sstevel@tonic-gate auio.uio_iov = aiov; 10480Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 10490Sstevel@tonic-gate auio.uio_resid = len; 10500Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 10510Sstevel@tonic-gate auio.uio_limit = 0; 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate if (lmsg.msg_control != NULL && 10540Sstevel@tonic-gate (do_useracc == 0 || 10550Sstevel@tonic-gate useracc(lmsg.msg_control, lmsg.msg_controllen, 10565227Stz204579 B_WRITE) != 0)) { 10570Sstevel@tonic-gate return (set_errno(EFAULT)); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags, 10615227Stz204579 STRUCT_FADDR(umsgptr, msg_namelen), 10625227Stz204579 STRUCT_FADDR(umsgptr, msg_controllen), flagsp)); 10630Sstevel@tonic-gate } 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate /* 10660Sstevel@tonic-gate * Common send function. 10670Sstevel@tonic-gate */ 10680Sstevel@tonic-gate static ssize_t 10690Sstevel@tonic-gate sendit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags) 10700Sstevel@tonic-gate { 10710Sstevel@tonic-gate struct sonode *so; 10720Sstevel@tonic-gate file_t *fp; 10730Sstevel@tonic-gate void *name; 10740Sstevel@tonic-gate socklen_t namelen; 10750Sstevel@tonic-gate void *control; 10760Sstevel@tonic-gate socklen_t controllen; 10770Sstevel@tonic-gate ssize_t len; 10780Sstevel@tonic-gate int error; 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL) 10810Sstevel@tonic-gate return (set_errno(error)); 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate uiop->uio_fmode = fp->f_flag; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate if (so->so_family == AF_UNIX) 10860Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_CACHED; 10870Sstevel@tonic-gate else 10880Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_DEFAULT; 10890Sstevel@tonic-gate 10900Sstevel@tonic-gate /* Allocate and copyin name and control */ 10910Sstevel@tonic-gate name = msg->msg_name; 10920Sstevel@tonic-gate namelen = msg->msg_namelen; 10930Sstevel@tonic-gate if (name != NULL && namelen != 0) { 10940Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 10950Sstevel@tonic-gate name = copyin_name(so, 10965227Stz204579 (struct sockaddr *)name, 10975227Stz204579 &namelen, &error); 10980Sstevel@tonic-gate if (name == NULL) 10990Sstevel@tonic-gate goto done3; 11000Sstevel@tonic-gate /* copyin_name null terminates addresses for AF_UNIX */ 11010Sstevel@tonic-gate msg->msg_namelen = namelen; 11020Sstevel@tonic-gate msg->msg_name = name; 11030Sstevel@tonic-gate } else { 11040Sstevel@tonic-gate msg->msg_name = name = NULL; 11050Sstevel@tonic-gate msg->msg_namelen = namelen = 0; 11060Sstevel@tonic-gate } 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate control = msg->msg_control; 11090Sstevel@tonic-gate controllen = msg->msg_controllen; 11100Sstevel@tonic-gate if ((control != NULL) && (controllen != 0)) { 11110Sstevel@tonic-gate /* 11120Sstevel@tonic-gate * Verify that the length is not excessive to prevent 11130Sstevel@tonic-gate * an application from consuming all of kernel memory. 11140Sstevel@tonic-gate */ 11150Sstevel@tonic-gate if (controllen > SO_MAXARGSIZE) { 11160Sstevel@tonic-gate error = EINVAL; 11170Sstevel@tonic-gate goto done2; 11180Sstevel@tonic-gate } 11190Sstevel@tonic-gate control = kmem_alloc(controllen, KM_SLEEP); 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 11220Sstevel@tonic-gate if (copyin(msg->msg_control, control, controllen)) { 11230Sstevel@tonic-gate error = EFAULT; 11240Sstevel@tonic-gate goto done1; 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate msg->msg_control = control; 11270Sstevel@tonic-gate } else { 11280Sstevel@tonic-gate msg->msg_control = control = NULL; 11290Sstevel@tonic-gate msg->msg_controllen = controllen = 0; 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate len = uiop->uio_resid; 11330Sstevel@tonic-gate msg->msg_flags = flags; 11340Sstevel@tonic-gate 11358348SEric.Yu@Sun.COM error = socket_sendmsg(so, msg, uiop, CRED()); 11360Sstevel@tonic-gate done1: 11370Sstevel@tonic-gate if (control != NULL) 11380Sstevel@tonic-gate kmem_free(control, controllen); 11390Sstevel@tonic-gate done2: 11400Sstevel@tonic-gate if (name != NULL) 11410Sstevel@tonic-gate kmem_free(name, namelen); 11420Sstevel@tonic-gate done3: 11430Sstevel@tonic-gate if (error != 0) { 11440Sstevel@tonic-gate releasef(sock); 11450Sstevel@tonic-gate return (set_errno(error)); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate lwp_stat_update(LWP_STAT_MSGSND, 1); 11480Sstevel@tonic-gate releasef(sock); 11490Sstevel@tonic-gate return (len - uiop->uio_resid); 11500Sstevel@tonic-gate } 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * Native system call 11540Sstevel@tonic-gate */ 11550Sstevel@tonic-gate ssize_t 11560Sstevel@tonic-gate send(int sock, void *buffer, size_t len, int flags) 11570Sstevel@tonic-gate { 11580Sstevel@tonic-gate struct nmsghdr lmsg; 11590Sstevel@tonic-gate struct uio auio; 11600Sstevel@tonic-gate struct iovec aiov[1]; 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate dprint(1, ("send(%d, %p, %ld, %d)\n", 11635227Stz204579 sock, buffer, len, flags)); 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate if ((ssize_t)len < 0) { 11660Sstevel@tonic-gate return (set_errno(EINVAL)); 11670Sstevel@tonic-gate } 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate aiov[0].iov_base = buffer; 11700Sstevel@tonic-gate aiov[0].iov_len = len; 11710Sstevel@tonic-gate auio.uio_loffset = 0; 11720Sstevel@tonic-gate auio.uio_iov = aiov; 11730Sstevel@tonic-gate auio.uio_iovcnt = 1; 11740Sstevel@tonic-gate auio.uio_resid = len; 11750Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 11760Sstevel@tonic-gate auio.uio_limit = 0; 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate lmsg.msg_name = NULL; 11790Sstevel@tonic-gate lmsg.msg_control = NULL; 11800Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) { 11810Sstevel@tonic-gate /* 11820Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod 11830Sstevel@tonic-gate * implementation we set EOR for all send* calls. 11840Sstevel@tonic-gate */ 11850Sstevel@tonic-gate flags |= MSG_EOR; 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags)); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate /* 11910Sstevel@tonic-gate * Uses the MSG_XPG4_2 flag to determine if the caller is using 11920Sstevel@tonic-gate * struct omsghdr or struct nmsghdr. 11930Sstevel@tonic-gate */ 11940Sstevel@tonic-gate ssize_t 11950Sstevel@tonic-gate sendmsg(int sock, struct nmsghdr *msg, int flags) 11960Sstevel@tonic-gate { 11970Sstevel@tonic-gate struct nmsghdr lmsg; 11980Sstevel@tonic-gate STRUCT_DECL(nmsghdr, u_lmsg); 11990Sstevel@tonic-gate struct uio auio; 12000Sstevel@tonic-gate struct iovec aiov[MSG_MAXIOVLEN]; 12010Sstevel@tonic-gate int iovcnt; 12020Sstevel@tonic-gate ssize_t len; 12030Sstevel@tonic-gate int i; 12040Sstevel@tonic-gate model_t model; 12050Sstevel@tonic-gate 12067240Srh87107 dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags)); 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate model = get_udatamodel(); 12090Sstevel@tonic-gate STRUCT_INIT(u_lmsg, model); 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate if (flags & MSG_XPG4_2) { 12120Sstevel@tonic-gate if (copyin(msg, (char *)STRUCT_BUF(u_lmsg), 12130Sstevel@tonic-gate STRUCT_SIZE(u_lmsg))) 12140Sstevel@tonic-gate return (set_errno(EFAULT)); 12150Sstevel@tonic-gate } else { 12160Sstevel@tonic-gate /* 12170Sstevel@tonic-gate * Assumes that nmsghdr and omsghdr are identically shaped 12180Sstevel@tonic-gate * except for the added msg_flags field. 12190Sstevel@tonic-gate */ 12200Sstevel@tonic-gate if (copyin(msg, (char *)STRUCT_BUF(u_lmsg), 12210Sstevel@tonic-gate SIZEOF_STRUCT(omsghdr, model))) 12220Sstevel@tonic-gate return (set_errno(EFAULT)); 12230Sstevel@tonic-gate /* 12240Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod 12250Sstevel@tonic-gate * implementation we set EOR for all send* calls. 12260Sstevel@tonic-gate */ 12270Sstevel@tonic-gate flags |= MSG_EOR; 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate /* 12310Sstevel@tonic-gate * Code below us will kmem_alloc memory and hang it 12320Sstevel@tonic-gate * off msg_control and msg_name fields. This forces 12330Sstevel@tonic-gate * us to copy the structure to its native form. 12340Sstevel@tonic-gate */ 12350Sstevel@tonic-gate lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name); 12360Sstevel@tonic-gate lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen); 12370Sstevel@tonic-gate lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov); 12380Sstevel@tonic-gate lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen); 12390Sstevel@tonic-gate lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control); 12400Sstevel@tonic-gate lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen); 12410Sstevel@tonic-gate lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags); 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate iovcnt = lmsg.msg_iovlen; 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) { 12460Sstevel@tonic-gate /* 12470Sstevel@tonic-gate * Unless this is XPG 4.2 we allow iovcnt == 0 to 12480Sstevel@tonic-gate * be compatible with SunOS 4.X and 4.4BSD. 12490Sstevel@tonic-gate */ 12500Sstevel@tonic-gate if (iovcnt != 0 || (flags & MSG_XPG4_2)) 12510Sstevel@tonic-gate return (set_errno(EMSGSIZE)); 12520Sstevel@tonic-gate } 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 12550Sstevel@tonic-gate /* 12560Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, while ensuring 12570Sstevel@tonic-gate * that they can't move more than 2Gbytes of data in a single call. 12580Sstevel@tonic-gate */ 12590Sstevel@tonic-gate if (model == DATAMODEL_ILP32) { 12600Sstevel@tonic-gate struct iovec32 aiov32[MSG_MAXIOVLEN]; 12610Sstevel@tonic-gate ssize32_t count32; 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate if (iovcnt != 0 && 12640Sstevel@tonic-gate copyin((struct iovec32 *)lmsg.msg_iov, aiov32, 12650Sstevel@tonic-gate iovcnt * sizeof (struct iovec32))) 12660Sstevel@tonic-gate return (set_errno(EFAULT)); 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate count32 = 0; 12690Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 12700Sstevel@tonic-gate ssize32_t iovlen32; 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate iovlen32 = aiov32[i].iov_len; 12730Sstevel@tonic-gate count32 += iovlen32; 12740Sstevel@tonic-gate if (iovlen32 < 0 || count32 < 0) 12750Sstevel@tonic-gate return (set_errno(EINVAL)); 12760Sstevel@tonic-gate aiov[i].iov_len = iovlen32; 12770Sstevel@tonic-gate aiov[i].iov_base = 12780Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base; 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate } else 12810Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 12820Sstevel@tonic-gate if (iovcnt != 0 && 12830Sstevel@tonic-gate copyin(lmsg.msg_iov, aiov, 12840Sstevel@tonic-gate (unsigned)iovcnt * sizeof (struct iovec))) { 12850Sstevel@tonic-gate return (set_errno(EFAULT)); 12860Sstevel@tonic-gate } 12870Sstevel@tonic-gate len = 0; 12880Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 12890Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len; 12900Sstevel@tonic-gate len += iovlen; 12910Sstevel@tonic-gate if (iovlen < 0 || len < 0) { 12920Sstevel@tonic-gate return (set_errno(EINVAL)); 12930Sstevel@tonic-gate } 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate auio.uio_loffset = 0; 12960Sstevel@tonic-gate auio.uio_iov = aiov; 12970Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 12980Sstevel@tonic-gate auio.uio_resid = len; 12990Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 13000Sstevel@tonic-gate auio.uio_limit = 0; 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags)); 13030Sstevel@tonic-gate } 13040Sstevel@tonic-gate 13050Sstevel@tonic-gate ssize_t 13060Sstevel@tonic-gate sendto(int sock, void *buffer, size_t len, int flags, 13070Sstevel@tonic-gate struct sockaddr *name, socklen_t namelen) 13080Sstevel@tonic-gate { 13090Sstevel@tonic-gate struct nmsghdr lmsg; 13100Sstevel@tonic-gate struct uio auio; 13110Sstevel@tonic-gate struct iovec aiov[1]; 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate dprint(1, ("sendto(%d, %p, %ld, %d, %p, %d)\n", 13147240Srh87107 sock, buffer, len, flags, (void *)name, namelen)); 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate if ((ssize_t)len < 0) { 13170Sstevel@tonic-gate return (set_errno(EINVAL)); 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate aiov[0].iov_base = buffer; 13210Sstevel@tonic-gate aiov[0].iov_len = len; 13220Sstevel@tonic-gate auio.uio_loffset = 0; 13230Sstevel@tonic-gate auio.uio_iov = aiov; 13240Sstevel@tonic-gate auio.uio_iovcnt = 1; 13250Sstevel@tonic-gate auio.uio_resid = len; 13260Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 13270Sstevel@tonic-gate auio.uio_limit = 0; 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate lmsg.msg_name = (char *)name; 13300Sstevel@tonic-gate lmsg.msg_namelen = namelen; 13310Sstevel@tonic-gate lmsg.msg_control = NULL; 13320Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) { 13330Sstevel@tonic-gate /* 13340Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod 13350Sstevel@tonic-gate * implementation we set EOR for all send* calls. 13360Sstevel@tonic-gate */ 13370Sstevel@tonic-gate flags |= MSG_EOR; 13380Sstevel@tonic-gate } 13390Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags)); 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate /*ARGSUSED3*/ 13430Sstevel@tonic-gate int 13440Sstevel@tonic-gate getpeername(int sock, struct sockaddr *name, socklen_t *namelenp, int version) 13450Sstevel@tonic-gate { 13460Sstevel@tonic-gate struct sonode *so; 13470Sstevel@tonic-gate int error; 13480Sstevel@tonic-gate socklen_t namelen; 13498348SEric.Yu@Sun.COM socklen_t sock_addrlen; 13508348SEric.Yu@Sun.COM struct sockaddr *sock_addrp; 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate dprint(1, ("getpeername(%d, %p, %p)\n", 13537240Srh87107 sock, (void *)name, (void *)namelenp)); 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL) 13560Sstevel@tonic-gate goto bad; 13570Sstevel@tonic-gate 13580Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 13590Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen)) || 13600Sstevel@tonic-gate (name == NULL && namelen != 0)) { 13610Sstevel@tonic-gate error = EFAULT; 13620Sstevel@tonic-gate goto rel_out; 13630Sstevel@tonic-gate } 13648348SEric.Yu@Sun.COM sock_addrlen = so->so_max_addr_len; 13658348SEric.Yu@Sun.COM sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP); 13660Sstevel@tonic-gate 13678348SEric.Yu@Sun.COM if ((error = socket_getpeername(so, sock_addrp, &sock_addrlen, 13688348SEric.Yu@Sun.COM B_FALSE, CRED())) == 0) { 13698348SEric.Yu@Sun.COM ASSERT(sock_addrlen <= so->so_max_addr_len); 13708348SEric.Yu@Sun.COM error = copyout_name(name, namelen, namelenp, 13718348SEric.Yu@Sun.COM (void *)sock_addrp, sock_addrlen); 13720Sstevel@tonic-gate } 13738348SEric.Yu@Sun.COM kmem_free(sock_addrp, so->so_max_addr_len); 13740Sstevel@tonic-gate rel_out: 13750Sstevel@tonic-gate releasef(sock); 13760Sstevel@tonic-gate bad: return (error != 0 ? set_errno(error) : 0); 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate /*ARGSUSED3*/ 13800Sstevel@tonic-gate int 13810Sstevel@tonic-gate getsockname(int sock, struct sockaddr *name, 13820Sstevel@tonic-gate socklen_t *namelenp, int version) 13830Sstevel@tonic-gate { 13840Sstevel@tonic-gate struct sonode *so; 13850Sstevel@tonic-gate int error; 13868348SEric.Yu@Sun.COM socklen_t namelen, sock_addrlen; 13878348SEric.Yu@Sun.COM struct sockaddr *sock_addrp; 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate dprint(1, ("getsockname(%d, %p, %p)\n", 13907240Srh87107 sock, (void *)name, (void *)namelenp)); 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL) 13930Sstevel@tonic-gate goto bad; 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 13960Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen)) || 13970Sstevel@tonic-gate (name == NULL && namelen != 0)) { 13980Sstevel@tonic-gate error = EFAULT; 13990Sstevel@tonic-gate goto rel_out; 14000Sstevel@tonic-gate } 14010Sstevel@tonic-gate 14028348SEric.Yu@Sun.COM sock_addrlen = so->so_max_addr_len; 14038348SEric.Yu@Sun.COM sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP); 14048348SEric.Yu@Sun.COM if ((error = socket_getsockname(so, sock_addrp, &sock_addrlen, 14058348SEric.Yu@Sun.COM CRED())) == 0) { 14068348SEric.Yu@Sun.COM ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 14078348SEric.Yu@Sun.COM ASSERT(sock_addrlen <= so->so_max_addr_len); 14088348SEric.Yu@Sun.COM error = copyout_name(name, namelen, namelenp, 14098348SEric.Yu@Sun.COM (void *)sock_addrp, sock_addrlen); 14100Sstevel@tonic-gate } 14118348SEric.Yu@Sun.COM kmem_free(sock_addrp, so->so_max_addr_len); 14120Sstevel@tonic-gate rel_out: 14130Sstevel@tonic-gate releasef(sock); 14140Sstevel@tonic-gate bad: return (error != 0 ? set_errno(error) : 0); 14150Sstevel@tonic-gate } 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate /*ARGSUSED5*/ 14180Sstevel@tonic-gate int 14190Sstevel@tonic-gate getsockopt(int sock, 14200Sstevel@tonic-gate int level, 14210Sstevel@tonic-gate int option_name, 14220Sstevel@tonic-gate void *option_value, 14230Sstevel@tonic-gate socklen_t *option_lenp, 14240Sstevel@tonic-gate int version) 14250Sstevel@tonic-gate { 14260Sstevel@tonic-gate struct sonode *so; 14270Sstevel@tonic-gate socklen_t optlen, optlen_res; 14280Sstevel@tonic-gate void *optval; 14290Sstevel@tonic-gate int error; 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate dprint(1, ("getsockopt(%d, %d, %d, %p, %p)\n", 14327240Srh87107 sock, level, option_name, option_value, (void *)option_lenp)); 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL) 14350Sstevel@tonic-gate return (set_errno(error)); 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 14380Sstevel@tonic-gate if (copyin(option_lenp, &optlen, sizeof (optlen))) { 14390Sstevel@tonic-gate releasef(sock); 14400Sstevel@tonic-gate return (set_errno(EFAULT)); 14410Sstevel@tonic-gate } 14420Sstevel@tonic-gate /* 14430Sstevel@tonic-gate * Verify that the length is not excessive to prevent 14440Sstevel@tonic-gate * an application from consuming all of kernel memory. 14450Sstevel@tonic-gate */ 14460Sstevel@tonic-gate if (optlen > SO_MAXARGSIZE) { 14470Sstevel@tonic-gate error = EINVAL; 14480Sstevel@tonic-gate releasef(sock); 14490Sstevel@tonic-gate return (set_errno(error)); 14500Sstevel@tonic-gate } 14510Sstevel@tonic-gate optval = kmem_alloc(optlen, KM_SLEEP); 14520Sstevel@tonic-gate optlen_res = optlen; 14538348SEric.Yu@Sun.COM error = socket_getsockopt(so, level, option_name, optval, 14548348SEric.Yu@Sun.COM &optlen_res, (version != SOV_XPG4_2) ? 0 : _SOGETSOCKOPT_XPG4_2, 14558348SEric.Yu@Sun.COM CRED()); 14560Sstevel@tonic-gate releasef(sock); 14570Sstevel@tonic-gate if (error) { 14580Sstevel@tonic-gate kmem_free(optval, optlen); 14590Sstevel@tonic-gate return (set_errno(error)); 14600Sstevel@tonic-gate } 14610Sstevel@tonic-gate error = copyout_arg(option_value, optlen, option_lenp, 14620Sstevel@tonic-gate optval, optlen_res); 14630Sstevel@tonic-gate kmem_free(optval, optlen); 14640Sstevel@tonic-gate if (error) 14650Sstevel@tonic-gate return (set_errno(error)); 14660Sstevel@tonic-gate return (0); 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate /*ARGSUSED5*/ 14700Sstevel@tonic-gate int 14710Sstevel@tonic-gate setsockopt(int sock, 14720Sstevel@tonic-gate int level, 14730Sstevel@tonic-gate int option_name, 14740Sstevel@tonic-gate void *option_value, 14750Sstevel@tonic-gate socklen_t option_len, 14760Sstevel@tonic-gate int version) 14770Sstevel@tonic-gate { 14780Sstevel@tonic-gate struct sonode *so; 14790Sstevel@tonic-gate intptr_t buffer[2]; 14800Sstevel@tonic-gate void *optval = NULL; 14810Sstevel@tonic-gate int error; 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate dprint(1, ("setsockopt(%d, %d, %d, %p, %d)\n", 14845227Stz204579 sock, level, option_name, option_value, option_len)); 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL) 14870Sstevel@tonic-gate return (set_errno(error)); 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate if (option_value != NULL) { 14900Sstevel@tonic-gate if (option_len != 0) { 14910Sstevel@tonic-gate /* 14920Sstevel@tonic-gate * Verify that the length is not excessive to prevent 14930Sstevel@tonic-gate * an application from consuming all of kernel memory. 14940Sstevel@tonic-gate */ 14950Sstevel@tonic-gate if (option_len > SO_MAXARGSIZE) { 14960Sstevel@tonic-gate error = EINVAL; 14970Sstevel@tonic-gate goto done2; 14980Sstevel@tonic-gate } 14990Sstevel@tonic-gate optval = option_len <= sizeof (buffer) ? 15000Sstevel@tonic-gate &buffer : kmem_alloc((size_t)option_len, KM_SLEEP); 15010Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 15020Sstevel@tonic-gate if (copyin(option_value, optval, (size_t)option_len)) { 15030Sstevel@tonic-gate error = EFAULT; 15040Sstevel@tonic-gate goto done1; 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate } else 15080Sstevel@tonic-gate option_len = 0; 15090Sstevel@tonic-gate 15108348SEric.Yu@Sun.COM error = socket_setsockopt(so, level, option_name, optval, 15118348SEric.Yu@Sun.COM (t_uscalar_t)option_len, CRED()); 15120Sstevel@tonic-gate done1: 15130Sstevel@tonic-gate if (optval != buffer) 15140Sstevel@tonic-gate kmem_free(optval, (size_t)option_len); 15150Sstevel@tonic-gate done2: 15160Sstevel@tonic-gate releasef(sock); 15170Sstevel@tonic-gate if (error) 15180Sstevel@tonic-gate return (set_errno(error)); 15190Sstevel@tonic-gate return (0); 15200Sstevel@tonic-gate } 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate /* 15238348SEric.Yu@Sun.COM * Add config info when name is non-NULL; delete info when name is NULL. 15248348SEric.Yu@Sun.COM * name could be a device name or a module name and are user address. 15250Sstevel@tonic-gate */ 15260Sstevel@tonic-gate int 15278348SEric.Yu@Sun.COM sockconfig(int family, int type, int protocol, char *name) 15280Sstevel@tonic-gate { 15298348SEric.Yu@Sun.COM char *kdevpath = NULL; /* Copied in devpath string */ 15308348SEric.Yu@Sun.COM char *kmodule = NULL; 15318348SEric.Yu@Sun.COM size_t pathlen = 0; 15320Sstevel@tonic-gate int error = 0; 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate dprint(1, ("sockconfig(%d, %d, %d, %p)\n", 15358348SEric.Yu@Sun.COM family, type, protocol, (void *)name)); 15360Sstevel@tonic-gate 15370Sstevel@tonic-gate if (secpolicy_net_config(CRED(), B_FALSE) != 0) 15380Sstevel@tonic-gate return (set_errno(EPERM)); 15390Sstevel@tonic-gate 15408348SEric.Yu@Sun.COM /* 15418348SEric.Yu@Sun.COM * By default set the kdevpath and kmodule to NULL to delete an entry. 15428348SEric.Yu@Sun.COM * Otherwise when name is not NULL, set the kdevpath or kmodule 15438348SEric.Yu@Sun.COM * value to add an entry. 15448348SEric.Yu@Sun.COM */ 15458348SEric.Yu@Sun.COM if (name != NULL) { 15460Sstevel@tonic-gate /* 15470Sstevel@tonic-gate * Adding an entry. 15488348SEric.Yu@Sun.COM * Copyin the name. 15490Sstevel@tonic-gate * This also makes it possible to check for too long pathnames. 15508348SEric.Yu@Sun.COM * Compress the space needed for the name before passing it 15510Sstevel@tonic-gate * to soconfig - soconfig will store the string until 15520Sstevel@tonic-gate * the configuration is removed. 15530Sstevel@tonic-gate */ 15540Sstevel@tonic-gate char *buf; 15550Sstevel@tonic-gate buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 15568348SEric.Yu@Sun.COM if ((error = copyinstr(name, buf, MAXPATHLEN, &pathlen)) != 0) { 15570Sstevel@tonic-gate kmem_free(buf, MAXPATHLEN); 15580Sstevel@tonic-gate goto done; 15590Sstevel@tonic-gate } 15608348SEric.Yu@Sun.COM if (strncmp(buf, "/dev", strlen("/dev")) == 0) { 15618348SEric.Yu@Sun.COM /* For device */ 15620Sstevel@tonic-gate 15638348SEric.Yu@Sun.COM /* 15648348SEric.Yu@Sun.COM * Special handling for NCA: 15658348SEric.Yu@Sun.COM * 15668348SEric.Yu@Sun.COM * DEV_NCA is never opened even if an application 15678348SEric.Yu@Sun.COM * requests for AF_NCA. The device opened is instead a 15688348SEric.Yu@Sun.COM * predefined AF_INET transport (NCA_INET_DEV). 15698348SEric.Yu@Sun.COM * 15708348SEric.Yu@Sun.COM * Prior to Volo (PSARC/2007/587) NCA would determine 15718348SEric.Yu@Sun.COM * the device using a lookup, which worked then because 15728348SEric.Yu@Sun.COM * all protocols were based on TPI. Since TPI is no 15738348SEric.Yu@Sun.COM * longer the default, we have to explicitly state 15748348SEric.Yu@Sun.COM * which device to use. 15758348SEric.Yu@Sun.COM */ 15768348SEric.Yu@Sun.COM if (strcmp(buf, NCA_DEV) == 0) { 15778348SEric.Yu@Sun.COM /* only support entry <28, 2, 0> */ 15788348SEric.Yu@Sun.COM if (family != AF_NCA || type != SOCK_STREAM || 15798348SEric.Yu@Sun.COM protocol != 0) { 15808348SEric.Yu@Sun.COM kmem_free(buf, MAXPATHLEN); 15818348SEric.Yu@Sun.COM error = EINVAL; 15828348SEric.Yu@Sun.COM goto done; 15838348SEric.Yu@Sun.COM } 15848348SEric.Yu@Sun.COM 15858348SEric.Yu@Sun.COM pathlen = strlen(NCA_INET_DEV) + 1; 15868348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, KM_SLEEP); 15878348SEric.Yu@Sun.COM bcopy(NCA_INET_DEV, kdevpath, pathlen); 15888348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 15898348SEric.Yu@Sun.COM } else { 15908348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, KM_SLEEP); 15918348SEric.Yu@Sun.COM bcopy(buf, kdevpath, pathlen); 15928348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 15938348SEric.Yu@Sun.COM } 15948348SEric.Yu@Sun.COM } else { 15958348SEric.Yu@Sun.COM /* For socket module */ 15968348SEric.Yu@Sun.COM kmodule = kmem_alloc(pathlen, KM_SLEEP); 15978348SEric.Yu@Sun.COM bcopy(buf, kmodule, pathlen); 15988348SEric.Yu@Sun.COM kmodule[pathlen - 1] = '\0'; 15998348SEric.Yu@Sun.COM 16008348SEric.Yu@Sun.COM pathlen = 0; 16018348SEric.Yu@Sun.COM if (strcmp(kmodule, "tcp") == 0) { 16028348SEric.Yu@Sun.COM /* Get the tcp device name for fallback */ 16038348SEric.Yu@Sun.COM if (family == 2) { 16048348SEric.Yu@Sun.COM pathlen = strlen("/dev/tcp") + 1; 16058348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, 16068348SEric.Yu@Sun.COM KM_SLEEP); 16078348SEric.Yu@Sun.COM bcopy("/dev/tcp", kdevpath, 16088348SEric.Yu@Sun.COM pathlen); 16098348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 16108348SEric.Yu@Sun.COM } else { 16118348SEric.Yu@Sun.COM ASSERT(family == 26); 16128348SEric.Yu@Sun.COM pathlen = strlen("/dev/tcp6") + 1; 16138348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, 16148348SEric.Yu@Sun.COM KM_SLEEP); 16158348SEric.Yu@Sun.COM bcopy("/dev/tcp6", kdevpath, pathlen); 16168348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 16178348SEric.Yu@Sun.COM } 16188348SEric.Yu@Sun.COM } else if (strcmp(kmodule, "udp") == 0) { 16198348SEric.Yu@Sun.COM /* Get the udp device name for fallback */ 16208348SEric.Yu@Sun.COM if (family == 2) { 16218348SEric.Yu@Sun.COM pathlen = strlen("/dev/udp") + 1; 16228348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, 16238348SEric.Yu@Sun.COM KM_SLEEP); 16248348SEric.Yu@Sun.COM bcopy("/dev/udp", kdevpath, pathlen); 16258348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 16268348SEric.Yu@Sun.COM } else { 16278348SEric.Yu@Sun.COM ASSERT(family == 26); 16288348SEric.Yu@Sun.COM pathlen = strlen("/dev/udp6") + 1; 16298348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, 16308348SEric.Yu@Sun.COM KM_SLEEP); 16318348SEric.Yu@Sun.COM bcopy("/dev/udp6", kdevpath, pathlen); 16328348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 16338348SEric.Yu@Sun.COM } 16348348SEric.Yu@Sun.COM } else if (strcmp(kmodule, "icmp") == 0) { 16358348SEric.Yu@Sun.COM /* Get the icmp device name for fallback */ 16368348SEric.Yu@Sun.COM if (family == 2) { 16378348SEric.Yu@Sun.COM pathlen = strlen("/dev/rawip") + 1; 16388348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, 16398348SEric.Yu@Sun.COM KM_SLEEP); 16408348SEric.Yu@Sun.COM bcopy("/dev/rawip", kdevpath, pathlen); 16418348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 16428348SEric.Yu@Sun.COM } else { 16438348SEric.Yu@Sun.COM ASSERT(family == 26); 16448348SEric.Yu@Sun.COM pathlen = strlen("/dev/rawip6") + 1; 16458348SEric.Yu@Sun.COM kdevpath = kmem_alloc(pathlen, 16468348SEric.Yu@Sun.COM KM_SLEEP); 16478348SEric.Yu@Sun.COM bcopy("/dev/rawip6", kdevpath, pathlen); 16488348SEric.Yu@Sun.COM kdevpath[pathlen - 1] = '\0'; 16498348SEric.Yu@Sun.COM } 16508348SEric.Yu@Sun.COM } 16518348SEric.Yu@Sun.COM } 16520Sstevel@tonic-gate 16530Sstevel@tonic-gate kmem_free(buf, MAXPATHLEN); 16540Sstevel@tonic-gate } 16558348SEric.Yu@Sun.COM error = soconfig(family, type, protocol, kdevpath, (int)pathlen, 16568348SEric.Yu@Sun.COM kmodule); 16570Sstevel@tonic-gate done: 16580Sstevel@tonic-gate if (error) { 16590Sstevel@tonic-gate eprintline(error); 16600Sstevel@tonic-gate return (set_errno(error)); 16610Sstevel@tonic-gate } 16620Sstevel@tonic-gate return (0); 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate 16650Sstevel@tonic-gate 16660Sstevel@tonic-gate /* 16670Sstevel@tonic-gate * Sendfile is implemented through two schemes, direct I/O or by 16680Sstevel@tonic-gate * caching in the filesystem page cache. We cache the input file by 16690Sstevel@tonic-gate * default and use direct I/O only if sendfile_max_size is set 16700Sstevel@tonic-gate * appropriately as explained below. Note that this logic is consistent 16710Sstevel@tonic-gate * with other filesystems where caching is turned on by default 16720Sstevel@tonic-gate * unless explicitly turned off by using the DIRECTIO ioctl. 16730Sstevel@tonic-gate * 16740Sstevel@tonic-gate * We choose a slightly different scheme here. One can turn off 16750Sstevel@tonic-gate * caching by setting sendfile_max_size to 0. One can also enable 16760Sstevel@tonic-gate * caching of files <= sendfile_max_size by setting sendfile_max_size 16770Sstevel@tonic-gate * to an appropriate value. By default sendfile_max_size is set to the 16780Sstevel@tonic-gate * maximum value so that all files are cached. In future, we may provide 16790Sstevel@tonic-gate * better interfaces for caching the file. 16800Sstevel@tonic-gate * 16810Sstevel@tonic-gate * Sendfile through Direct I/O (Zero copy) 16820Sstevel@tonic-gate * -------------------------------------- 16830Sstevel@tonic-gate * 16840Sstevel@tonic-gate * As disks are normally slower than the network, we can't have a 16850Sstevel@tonic-gate * single thread that reads the disk and writes to the network. We 16860Sstevel@tonic-gate * need to have parallelism. This is done by having the sendfile 16870Sstevel@tonic-gate * thread create another thread that reads from the filesystem 16880Sstevel@tonic-gate * and queues it for network processing. In this scheme, the data 16890Sstevel@tonic-gate * is never copied anywhere i.e it is zero copy unlike the other 16900Sstevel@tonic-gate * scheme. 16910Sstevel@tonic-gate * 16920Sstevel@tonic-gate * We have a sendfile queue (snfq) where each sendfile 16930Sstevel@tonic-gate * request (snf_req_t) is queued for processing by a thread. Number 16940Sstevel@tonic-gate * of threads is dynamically allocated and they exit if they are idling 16950Sstevel@tonic-gate * beyond a specified amount of time. When each request (snf_req_t) is 16960Sstevel@tonic-gate * processed by a thread, it produces a number of mblk_t structures to 16970Sstevel@tonic-gate * be consumed by the sendfile thread. snf_deque and snf_enque are 16980Sstevel@tonic-gate * used for consuming and producing mblks. Size of the filesystem 16995331Samw * read is determined by the tunable (sendfile_read_size). A single 17000Sstevel@tonic-gate * mblk holds sendfile_read_size worth of data (except the last 17010Sstevel@tonic-gate * read of the file) which is sent down as a whole to the network. 17020Sstevel@tonic-gate * sendfile_read_size is set to 1 MB as this seems to be the optimal 17030Sstevel@tonic-gate * value for the UFS filesystem backed by a striped storage array. 17040Sstevel@tonic-gate * 17050Sstevel@tonic-gate * Synchronisation between read (producer) and write (consumer) threads. 17060Sstevel@tonic-gate * -------------------------------------------------------------------- 17070Sstevel@tonic-gate * 17080Sstevel@tonic-gate * sr_lock protects sr_ib_head and sr_ib_tail. The lock is held while 17090Sstevel@tonic-gate * adding and deleting items in this list. Error can happen anytime 17100Sstevel@tonic-gate * during read or write. There could be unprocessed mblks in the 17110Sstevel@tonic-gate * sr_ib_XXX list when a read or write error occurs. Whenever error 17120Sstevel@tonic-gate * is encountered, we need two things to happen : 17130Sstevel@tonic-gate * 17140Sstevel@tonic-gate * a) One of the threads need to clean the mblks. 17150Sstevel@tonic-gate * b) When one thread encounters an error, the other should stop. 17160Sstevel@tonic-gate * 17175331Samw * For (a), we don't want to penalize the reader thread as it could do 17180Sstevel@tonic-gate * some useful work processing other requests. For (b), the error can 17190Sstevel@tonic-gate * be detected by examining sr_read_error or sr_write_error. 17200Sstevel@tonic-gate * sr_lock protects sr_read_error and sr_write_error. If both reader and 17210Sstevel@tonic-gate * writer encounters error, we need to report the write error back to 17220Sstevel@tonic-gate * the application as that's what would have happened if the operations 17230Sstevel@tonic-gate * were done sequentially. With this in mind, following should work : 17240Sstevel@tonic-gate * 17250Sstevel@tonic-gate * - Check for errors before read or write. 17260Sstevel@tonic-gate * - If the reader encounters error, set the error in sr_read_error. 17270Sstevel@tonic-gate * Check sr_write_error, if it is set, send cv_signal as it is 17280Sstevel@tonic-gate * waiting for reader to complete. If it is not set, the writer 17290Sstevel@tonic-gate * is either running sinking data to the network or blocked 17300Sstevel@tonic-gate * because of flow control. For handling the latter case, we 17310Sstevel@tonic-gate * always send a signal. In any case, it will examine sr_read_error 17320Sstevel@tonic-gate * and return. sr_read_error is marked with SR_READ_DONE to tell 17330Sstevel@tonic-gate * the writer that the reader is done in all the cases. 17340Sstevel@tonic-gate * - If the writer encounters error, set the error in sr_write_error. 17350Sstevel@tonic-gate * The reader thread is either blocked because of flow control or 17360Sstevel@tonic-gate * running reading data from the disk. For the former, we need to 17370Sstevel@tonic-gate * wakeup the thread. Again to keep it simple, we always wake up 17380Sstevel@tonic-gate * the reader thread. Then, wait for the read thread to complete 17390Sstevel@tonic-gate * if it is not done yet. Cleanup and return. 17400Sstevel@tonic-gate * 17410Sstevel@tonic-gate * High and low water marks for the read thread. 17420Sstevel@tonic-gate * -------------------------------------------- 17430Sstevel@tonic-gate * 17440Sstevel@tonic-gate * If sendfile() is used to send data over a slow network, we need to 17450Sstevel@tonic-gate * make sure that the read thread does not produce data at a faster 17460Sstevel@tonic-gate * rate than the network. This can happen if the disk is faster than 17470Sstevel@tonic-gate * the network. In such a case, we don't want to build a very large queue. 17480Sstevel@tonic-gate * But we would still like to get all of the network throughput possible. 17490Sstevel@tonic-gate * This implies that network should never block waiting for data. 17500Sstevel@tonic-gate * As there are lot of disk throughput/network throughput combinations 17510Sstevel@tonic-gate * possible, it is difficult to come up with an accurate number. 17520Sstevel@tonic-gate * A typical 10K RPM disk has a max seek latency 17ms and rotational 17530Sstevel@tonic-gate * latency of 3ms for reading a disk block. Thus, the total latency to 17540Sstevel@tonic-gate * initiate a new read, transfer data from the disk and queue for 17550Sstevel@tonic-gate * transmission would take about a max of 25ms. Todays max transfer rate 17560Sstevel@tonic-gate * for network is 100MB/sec. If the thread is blocked because of flow 17570Sstevel@tonic-gate * control, it would take 25ms to get new data ready for transmission. 17580Sstevel@tonic-gate * We have to make sure that network is not idling, while we are initiating 17590Sstevel@tonic-gate * new transfers. So, at 100MB/sec, to keep network busy we would need 17605331Samw * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data. 17610Sstevel@tonic-gate * We need to pick a high water mark so that the woken up thread would 17620Sstevel@tonic-gate * do considerable work before blocking again to prevent thrashing. Currently, 17630Sstevel@tonic-gate * we pick this to be 10 times that of the low water mark. 17640Sstevel@tonic-gate * 17650Sstevel@tonic-gate * Sendfile with segmap caching (One copy from page cache to mblks). 17660Sstevel@tonic-gate * ---------------------------------------------------------------- 17670Sstevel@tonic-gate * 17680Sstevel@tonic-gate * We use the segmap cache for caching the file, if the size of file 17690Sstevel@tonic-gate * is <= sendfile_max_size. In this case we don't use threads as VM 17700Sstevel@tonic-gate * is reasonably fast enough to keep up with the network. If the underlying 17710Sstevel@tonic-gate * transport allows, we call segmap_getmapflt() to map MAXBSIZE (8K) worth 17720Sstevel@tonic-gate * of data into segmap space, and use the virtual address from segmap 17730Sstevel@tonic-gate * directly through desballoc() to avoid copy. Once the transport is done 17740Sstevel@tonic-gate * with the data, the mapping will be released through segmap_release() 17750Sstevel@tonic-gate * called by the call-back routine. 17760Sstevel@tonic-gate * 17770Sstevel@tonic-gate * If zero-copy is not allowed by the transport, we simply call VOP_READ() 17780Sstevel@tonic-gate * to copy the data from the filesystem into our temporary network buffer. 17790Sstevel@tonic-gate * 17800Sstevel@tonic-gate * To disable caching, set sendfile_max_size to 0. 17810Sstevel@tonic-gate */ 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate uint_t sendfile_read_size = 1024 * 1024; 17840Sstevel@tonic-gate #define SENDFILE_REQ_LOWAT 3 * 1024 * 1024 17850Sstevel@tonic-gate uint_t sendfile_req_lowat = SENDFILE_REQ_LOWAT; 17860Sstevel@tonic-gate uint_t sendfile_req_hiwat = 10 * SENDFILE_REQ_LOWAT; 17870Sstevel@tonic-gate struct sendfile_stats sf_stats; 17880Sstevel@tonic-gate struct sendfile_queue *snfq; 17890Sstevel@tonic-gate clock_t snfq_timeout; 17900Sstevel@tonic-gate off64_t sendfile_max_size; 17910Sstevel@tonic-gate 17920Sstevel@tonic-gate static void snf_enque(snf_req_t *, mblk_t *); 17930Sstevel@tonic-gate static mblk_t *snf_deque(snf_req_t *); 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate void 17960Sstevel@tonic-gate sendfile_init(void) 17970Sstevel@tonic-gate { 17980Sstevel@tonic-gate snfq = kmem_zalloc(sizeof (struct sendfile_queue), KM_SLEEP); 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate mutex_init(&snfq->snfq_lock, NULL, MUTEX_DEFAULT, NULL); 18010Sstevel@tonic-gate cv_init(&snfq->snfq_cv, NULL, CV_DEFAULT, NULL); 18020Sstevel@tonic-gate snfq->snfq_max_threads = max_ncpus; 18030Sstevel@tonic-gate snfq_timeout = SNFQ_TIMEOUT; 18040Sstevel@tonic-gate /* Cache all files by default. */ 18050Sstevel@tonic-gate sendfile_max_size = MAXOFFSET_T; 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate /* 18090Sstevel@tonic-gate * Queues a mblk_t for network processing. 18100Sstevel@tonic-gate */ 18110Sstevel@tonic-gate static void 18120Sstevel@tonic-gate snf_enque(snf_req_t *sr, mblk_t *mp) 18130Sstevel@tonic-gate { 18140Sstevel@tonic-gate mp->b_next = NULL; 18150Sstevel@tonic-gate mutex_enter(&sr->sr_lock); 18160Sstevel@tonic-gate if (sr->sr_mp_head == NULL) { 18170Sstevel@tonic-gate sr->sr_mp_head = sr->sr_mp_tail = mp; 18180Sstevel@tonic-gate cv_signal(&sr->sr_cv); 18190Sstevel@tonic-gate } else { 18200Sstevel@tonic-gate sr->sr_mp_tail->b_next = mp; 18210Sstevel@tonic-gate sr->sr_mp_tail = mp; 18220Sstevel@tonic-gate } 18230Sstevel@tonic-gate sr->sr_qlen += MBLKL(mp); 18240Sstevel@tonic-gate while ((sr->sr_qlen > sr->sr_hiwat) && 18250Sstevel@tonic-gate (sr->sr_write_error == 0)) { 18260Sstevel@tonic-gate sf_stats.ss_full_waits++; 18270Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock); 18280Sstevel@tonic-gate } 18290Sstevel@tonic-gate mutex_exit(&sr->sr_lock); 18300Sstevel@tonic-gate } 18310Sstevel@tonic-gate 18320Sstevel@tonic-gate /* 18330Sstevel@tonic-gate * De-queues a mblk_t for network processing. 18340Sstevel@tonic-gate */ 18350Sstevel@tonic-gate static mblk_t * 18360Sstevel@tonic-gate snf_deque(snf_req_t *sr) 18370Sstevel@tonic-gate { 18380Sstevel@tonic-gate mblk_t *mp; 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate mutex_enter(&sr->sr_lock); 18410Sstevel@tonic-gate /* 18420Sstevel@tonic-gate * If we have encountered an error on read or read is 18430Sstevel@tonic-gate * completed and no more mblks, return NULL. 18440Sstevel@tonic-gate * We need to check for NULL sr_mp_head also as 18450Sstevel@tonic-gate * the reads could have completed and there is 18460Sstevel@tonic-gate * nothing more to come. 18470Sstevel@tonic-gate */ 18480Sstevel@tonic-gate if (((sr->sr_read_error & ~SR_READ_DONE) != 0) || 18490Sstevel@tonic-gate ((sr->sr_read_error & SR_READ_DONE) && 18500Sstevel@tonic-gate sr->sr_mp_head == NULL)) { 18510Sstevel@tonic-gate mutex_exit(&sr->sr_lock); 18520Sstevel@tonic-gate return (NULL); 18530Sstevel@tonic-gate } 18540Sstevel@tonic-gate /* 18550Sstevel@tonic-gate * To start with neither SR_READ_DONE is marked nor 18560Sstevel@tonic-gate * the error is set. When we wake up from cv_wait, 18570Sstevel@tonic-gate * following are the possibilities : 18580Sstevel@tonic-gate * 18590Sstevel@tonic-gate * a) sr_read_error is zero and mblks are queued. 18600Sstevel@tonic-gate * b) sr_read_error is set to SR_READ_DONE 18610Sstevel@tonic-gate * and mblks are queued. 18620Sstevel@tonic-gate * c) sr_read_error is set to SR_READ_DONE 18630Sstevel@tonic-gate * and no mblks. 18640Sstevel@tonic-gate * d) sr_read_error is set to some error other 18650Sstevel@tonic-gate * than SR_READ_DONE. 18660Sstevel@tonic-gate */ 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate while ((sr->sr_read_error == 0) && (sr->sr_mp_head == NULL)) { 18690Sstevel@tonic-gate sf_stats.ss_empty_waits++; 18700Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock); 18710Sstevel@tonic-gate } 18720Sstevel@tonic-gate /* Handle (a) and (b) first - the normal case. */ 18730Sstevel@tonic-gate if (((sr->sr_read_error & ~SR_READ_DONE) == 0) && 18740Sstevel@tonic-gate (sr->sr_mp_head != NULL)) { 18750Sstevel@tonic-gate mp = sr->sr_mp_head; 18760Sstevel@tonic-gate sr->sr_mp_head = mp->b_next; 18770Sstevel@tonic-gate sr->sr_qlen -= MBLKL(mp); 18780Sstevel@tonic-gate if (sr->sr_qlen < sr->sr_lowat) 18790Sstevel@tonic-gate cv_signal(&sr->sr_cv); 18800Sstevel@tonic-gate mutex_exit(&sr->sr_lock); 18810Sstevel@tonic-gate mp->b_next = NULL; 18820Sstevel@tonic-gate return (mp); 18830Sstevel@tonic-gate } 18840Sstevel@tonic-gate /* Handle (c) and (d). */ 18850Sstevel@tonic-gate mutex_exit(&sr->sr_lock); 18860Sstevel@tonic-gate return (NULL); 18870Sstevel@tonic-gate } 18880Sstevel@tonic-gate 18890Sstevel@tonic-gate /* 18900Sstevel@tonic-gate * Reads data from the filesystem and queues it for network processing. 18910Sstevel@tonic-gate */ 18920Sstevel@tonic-gate void 18930Sstevel@tonic-gate snf_async_read(snf_req_t *sr) 18940Sstevel@tonic-gate { 18950Sstevel@tonic-gate size_t iosize; 18960Sstevel@tonic-gate u_offset_t fileoff; 18970Sstevel@tonic-gate u_offset_t size; 18980Sstevel@tonic-gate int ret_size; 18990Sstevel@tonic-gate int error; 19000Sstevel@tonic-gate file_t *fp; 19010Sstevel@tonic-gate mblk_t *mp; 19026240Skrishna struct vnode *vp; 19036240Skrishna int extra = 0; 19048171SPrakash.Jalan@Sun.COM int maxblk = 0; 19058171SPrakash.Jalan@Sun.COM int wroff = 0; 19068171SPrakash.Jalan@Sun.COM struct sonode *so; 19070Sstevel@tonic-gate 19080Sstevel@tonic-gate fp = sr->sr_fp; 19090Sstevel@tonic-gate size = sr->sr_file_size; 19100Sstevel@tonic-gate fileoff = sr->sr_file_off; 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate /* 19130Sstevel@tonic-gate * Ignore the error for filesystems that doesn't support DIRECTIO. 19140Sstevel@tonic-gate */ 19150Sstevel@tonic-gate (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0, 19165331Samw kcred, NULL, NULL); 19170Sstevel@tonic-gate 19188171SPrakash.Jalan@Sun.COM vp = sr->sr_vp; 19196240Skrishna if (vp->v_type == VSOCK) { 19206240Skrishna stdata_t *stp; 19216240Skrishna 19226240Skrishna /* 19236240Skrishna * Get the extra space to insert a header and a trailer. 19246240Skrishna */ 19258171SPrakash.Jalan@Sun.COM so = VTOSO(vp); 19266240Skrishna stp = vp->v_stream; 19278348SEric.Yu@Sun.COM if (stp == NULL) { 19288348SEric.Yu@Sun.COM wroff = so->so_proto_props.sopp_wroff; 19298348SEric.Yu@Sun.COM maxblk = so->so_proto_props.sopp_maxblk; 19308348SEric.Yu@Sun.COM extra = wroff + so->so_proto_props.sopp_tail; 19318348SEric.Yu@Sun.COM } else { 19328348SEric.Yu@Sun.COM wroff = (int)(stp->sd_wroff); 19338348SEric.Yu@Sun.COM maxblk = (int)(stp->sd_maxblk); 19348348SEric.Yu@Sun.COM extra = wroff + (int)(stp->sd_tail); 19358348SEric.Yu@Sun.COM } 19366240Skrishna } 19376240Skrishna 19380Sstevel@tonic-gate while ((size != 0) && (sr->sr_write_error == 0)) { 19390Sstevel@tonic-gate 19400Sstevel@tonic-gate iosize = (int)MIN(sr->sr_maxpsz, size); 19410Sstevel@tonic-gate 19428171SPrakash.Jalan@Sun.COM /* 19438171SPrakash.Jalan@Sun.COM * For sockets acting as an SSL proxy, we 19448171SPrakash.Jalan@Sun.COM * need to adjust the size to the maximum 19458171SPrakash.Jalan@Sun.COM * SSL record size set in the stream head. 19468171SPrakash.Jalan@Sun.COM */ 19478348SEric.Yu@Sun.COM if (vp->v_type == VSOCK && !SOCK_IS_NONSTR(so) && 19488348SEric.Yu@Sun.COM SOTOTPI(so)->sti_kssl_ctx != NULL) 19498171SPrakash.Jalan@Sun.COM iosize = (int)MIN(iosize, maxblk); 19508171SPrakash.Jalan@Sun.COM 19518778SErik.Nordmark@Sun.COM if (is_system_labeled()) { 19528778SErik.Nordmark@Sun.COM mp = allocb_cred(iosize + extra, CRED(), 19538778SErik.Nordmark@Sun.COM curproc->p_pid); 19548778SErik.Nordmark@Sun.COM } else { 19558778SErik.Nordmark@Sun.COM mp = allocb(iosize + extra, BPRI_MED); 19568778SErik.Nordmark@Sun.COM } 19578778SErik.Nordmark@Sun.COM if (mp == NULL) { 19580Sstevel@tonic-gate error = EAGAIN; 19590Sstevel@tonic-gate break; 19600Sstevel@tonic-gate } 19618171SPrakash.Jalan@Sun.COM 19628171SPrakash.Jalan@Sun.COM mp->b_rptr += wroff; 19638171SPrakash.Jalan@Sun.COM 19640Sstevel@tonic-gate ret_size = soreadfile(fp, mp->b_rptr, fileoff, &error, iosize); 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate /* Error or Reached EOF ? */ 19670Sstevel@tonic-gate if ((error != 0) || (ret_size == 0)) { 19680Sstevel@tonic-gate freeb(mp); 19690Sstevel@tonic-gate break; 19700Sstevel@tonic-gate } 19710Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + ret_size; 19720Sstevel@tonic-gate 19730Sstevel@tonic-gate snf_enque(sr, mp); 19740Sstevel@tonic-gate size -= ret_size; 19750Sstevel@tonic-gate fileoff += ret_size; 19760Sstevel@tonic-gate } 19770Sstevel@tonic-gate (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0, 19785331Samw kcred, NULL, NULL); 19790Sstevel@tonic-gate mutex_enter(&sr->sr_lock); 19800Sstevel@tonic-gate sr->sr_read_error = error; 19810Sstevel@tonic-gate sr->sr_read_error |= SR_READ_DONE; 19820Sstevel@tonic-gate cv_signal(&sr->sr_cv); 19830Sstevel@tonic-gate mutex_exit(&sr->sr_lock); 19840Sstevel@tonic-gate } 19850Sstevel@tonic-gate 19860Sstevel@tonic-gate void 19870Sstevel@tonic-gate snf_async_thread(void) 19880Sstevel@tonic-gate { 19890Sstevel@tonic-gate snf_req_t *sr; 19900Sstevel@tonic-gate callb_cpr_t cprinfo; 19910Sstevel@tonic-gate clock_t time_left = 1; 19920Sstevel@tonic-gate 19930Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &snfq->snfq_lock, callb_generic_cpr, "snfq"); 19940Sstevel@tonic-gate 19950Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock); 19960Sstevel@tonic-gate for (;;) { 19970Sstevel@tonic-gate /* 19980Sstevel@tonic-gate * If we didn't find a entry, then block until woken up 19990Sstevel@tonic-gate * again and then look through the queues again. 20000Sstevel@tonic-gate */ 20010Sstevel@tonic-gate while ((sr = snfq->snfq_req_head) == NULL) { 20020Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 20030Sstevel@tonic-gate if (time_left <= 0) { 20040Sstevel@tonic-gate snfq->snfq_svc_threads--; 20050Sstevel@tonic-gate CALLB_CPR_EXIT(&cprinfo); 20060Sstevel@tonic-gate thread_exit(); 20070Sstevel@tonic-gate /* NOTREACHED */ 20080Sstevel@tonic-gate } 20090Sstevel@tonic-gate snfq->snfq_idle_cnt++; 20100Sstevel@tonic-gate 201111066Srafael.vanoni@sun.com time_left = cv_reltimedwait(&snfq->snfq_cv, 201211066Srafael.vanoni@sun.com &snfq->snfq_lock, snfq_timeout, TR_CLOCK_TICK); 20130Sstevel@tonic-gate snfq->snfq_idle_cnt--; 20140Sstevel@tonic-gate 20150Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &snfq->snfq_lock); 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate snfq->snfq_req_head = sr->sr_next; 20180Sstevel@tonic-gate snfq->snfq_req_cnt--; 20190Sstevel@tonic-gate mutex_exit(&snfq->snfq_lock); 20200Sstevel@tonic-gate snf_async_read(sr); 20210Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock); 20220Sstevel@tonic-gate } 20230Sstevel@tonic-gate } 20240Sstevel@tonic-gate 20250Sstevel@tonic-gate 20260Sstevel@tonic-gate snf_req_t * 20270Sstevel@tonic-gate create_thread(int operation, struct vnode *vp, file_t *fp, 20280Sstevel@tonic-gate u_offset_t fileoff, u_offset_t size) 20290Sstevel@tonic-gate { 20300Sstevel@tonic-gate snf_req_t *sr; 20310Sstevel@tonic-gate stdata_t *stp; 20320Sstevel@tonic-gate 20330Sstevel@tonic-gate sr = (snf_req_t *)kmem_zalloc(sizeof (snf_req_t), KM_SLEEP); 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate sr->sr_vp = vp; 20360Sstevel@tonic-gate sr->sr_fp = fp; 20370Sstevel@tonic-gate stp = vp->v_stream; 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate /* 20400Sstevel@tonic-gate * store sd_qn_maxpsz into sr_maxpsz while we have stream head. 20410Sstevel@tonic-gate * stream might be closed before thread returns from snf_async_read. 20420Sstevel@tonic-gate */ 20438348SEric.Yu@Sun.COM if (stp != NULL && stp->sd_qn_maxpsz > 0) { 20440Sstevel@tonic-gate sr->sr_maxpsz = MIN(MAXBSIZE, stp->sd_qn_maxpsz); 20450Sstevel@tonic-gate } else { 20460Sstevel@tonic-gate sr->sr_maxpsz = MAXBSIZE; 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate sr->sr_operation = operation; 20500Sstevel@tonic-gate sr->sr_file_off = fileoff; 20510Sstevel@tonic-gate sr->sr_file_size = size; 20520Sstevel@tonic-gate sr->sr_hiwat = sendfile_req_hiwat; 20530Sstevel@tonic-gate sr->sr_lowat = sendfile_req_lowat; 20540Sstevel@tonic-gate mutex_init(&sr->sr_lock, NULL, MUTEX_DEFAULT, NULL); 20550Sstevel@tonic-gate cv_init(&sr->sr_cv, NULL, CV_DEFAULT, NULL); 20560Sstevel@tonic-gate /* 20570Sstevel@tonic-gate * See whether we need another thread for servicing this 20580Sstevel@tonic-gate * request. If there are already enough requests queued 20590Sstevel@tonic-gate * for the threads, create one if not exceeding 20600Sstevel@tonic-gate * snfq_max_threads. 20610Sstevel@tonic-gate */ 20620Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock); 20630Sstevel@tonic-gate if (snfq->snfq_req_cnt >= snfq->snfq_idle_cnt && 20640Sstevel@tonic-gate snfq->snfq_svc_threads < snfq->snfq_max_threads) { 20650Sstevel@tonic-gate (void) thread_create(NULL, 0, &snf_async_thread, 0, 0, &p0, 20660Sstevel@tonic-gate TS_RUN, minclsyspri); 20670Sstevel@tonic-gate snfq->snfq_svc_threads++; 20680Sstevel@tonic-gate } 20690Sstevel@tonic-gate if (snfq->snfq_req_head == NULL) { 20700Sstevel@tonic-gate snfq->snfq_req_head = snfq->snfq_req_tail = sr; 20710Sstevel@tonic-gate cv_signal(&snfq->snfq_cv); 20720Sstevel@tonic-gate } else { 20730Sstevel@tonic-gate snfq->snfq_req_tail->sr_next = sr; 20740Sstevel@tonic-gate snfq->snfq_req_tail = sr; 20750Sstevel@tonic-gate } 20760Sstevel@tonic-gate snfq->snfq_req_cnt++; 20770Sstevel@tonic-gate mutex_exit(&snfq->snfq_lock); 20780Sstevel@tonic-gate return (sr); 20790Sstevel@tonic-gate } 20800Sstevel@tonic-gate 20810Sstevel@tonic-gate int 20820Sstevel@tonic-gate snf_direct_io(file_t *fp, file_t *rfp, u_offset_t fileoff, u_offset_t size, 20830Sstevel@tonic-gate ssize_t *count) 20840Sstevel@tonic-gate { 20850Sstevel@tonic-gate snf_req_t *sr; 20860Sstevel@tonic-gate mblk_t *mp; 20870Sstevel@tonic-gate int iosize; 20880Sstevel@tonic-gate int error = 0; 20890Sstevel@tonic-gate short fflag; 20900Sstevel@tonic-gate struct vnode *vp; 20910Sstevel@tonic-gate int ksize; 20928348SEric.Yu@Sun.COM struct nmsghdr msg; 20930Sstevel@tonic-gate 20940Sstevel@tonic-gate ksize = 0; 20950Sstevel@tonic-gate *count = 0; 20968348SEric.Yu@Sun.COM bzero(&msg, sizeof (msg)); 20970Sstevel@tonic-gate 20980Sstevel@tonic-gate vp = fp->f_vnode; 20990Sstevel@tonic-gate fflag = fp->f_flag; 21000Sstevel@tonic-gate if ((sr = create_thread(READ_OP, vp, rfp, fileoff, size)) == NULL) 21010Sstevel@tonic-gate return (EAGAIN); 21020Sstevel@tonic-gate 21030Sstevel@tonic-gate /* 21040Sstevel@tonic-gate * We check for read error in snf_deque. It has to check 21050Sstevel@tonic-gate * for successful READ_DONE and return NULL, and we might 21060Sstevel@tonic-gate * as well make an additional check there. 21070Sstevel@tonic-gate */ 21080Sstevel@tonic-gate while ((mp = snf_deque(sr)) != NULL) { 21090Sstevel@tonic-gate 21100Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) { 21110Sstevel@tonic-gate freeb(mp); 21120Sstevel@tonic-gate error = EINTR; 21130Sstevel@tonic-gate break; 21140Sstevel@tonic-gate } 21150Sstevel@tonic-gate iosize = MBLKL(mp); 21160Sstevel@tonic-gate 21178348SEric.Yu@Sun.COM error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp); 21188348SEric.Yu@Sun.COM 21198348SEric.Yu@Sun.COM if (error != 0) { 21208348SEric.Yu@Sun.COM if (mp != NULL) 21218348SEric.Yu@Sun.COM freeb(mp); 21220Sstevel@tonic-gate break; 21230Sstevel@tonic-gate } 21240Sstevel@tonic-gate ksize += iosize; 21250Sstevel@tonic-gate } 21260Sstevel@tonic-gate *count = ksize; 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate mutex_enter(&sr->sr_lock); 21290Sstevel@tonic-gate sr->sr_write_error = error; 21300Sstevel@tonic-gate /* Look at the big comments on why we cv_signal here. */ 21310Sstevel@tonic-gate cv_signal(&sr->sr_cv); 21320Sstevel@tonic-gate 21330Sstevel@tonic-gate /* Wait for the reader to complete always. */ 21340Sstevel@tonic-gate while (!(sr->sr_read_error & SR_READ_DONE)) { 21350Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock); 21360Sstevel@tonic-gate } 21370Sstevel@tonic-gate /* If there is no write error, check for read error. */ 21380Sstevel@tonic-gate if (error == 0) 21390Sstevel@tonic-gate error = (sr->sr_read_error & ~SR_READ_DONE); 21400Sstevel@tonic-gate 21410Sstevel@tonic-gate if (error != 0) { 21420Sstevel@tonic-gate mblk_t *next_mp; 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate mp = sr->sr_mp_head; 21450Sstevel@tonic-gate while (mp != NULL) { 21460Sstevel@tonic-gate next_mp = mp->b_next; 21470Sstevel@tonic-gate mp->b_next = NULL; 21480Sstevel@tonic-gate freeb(mp); 21490Sstevel@tonic-gate mp = next_mp; 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate } 21520Sstevel@tonic-gate mutex_exit(&sr->sr_lock); 21530Sstevel@tonic-gate kmem_free(sr, sizeof (snf_req_t)); 21540Sstevel@tonic-gate return (error); 21550Sstevel@tonic-gate } 21560Sstevel@tonic-gate 21579344SVasumathi.Sundaram@Sun.COM /* Maximum no.of pages allocated by vpm for sendfile at a time */ 21589301SVasumathi.Sundaram@Sun.COM #define SNF_VPMMAXPGS (VPMMAXPGS/2) 21599344SVasumathi.Sundaram@Sun.COM 21609344SVasumathi.Sundaram@Sun.COM /* 21619344SVasumathi.Sundaram@Sun.COM * Maximum no.of elements in the list returned by vpm, including 21629344SVasumathi.Sundaram@Sun.COM * NULL for the last entry 21639344SVasumathi.Sundaram@Sun.COM */ 21649301SVasumathi.Sundaram@Sun.COM #define SNF_MAXVMAPS (SNF_VPMMAXPGS + 1) 21659301SVasumathi.Sundaram@Sun.COM 21669301SVasumathi.Sundaram@Sun.COM typedef struct { 21679344SVasumathi.Sundaram@Sun.COM unsigned int snfv_ref; 21689344SVasumathi.Sundaram@Sun.COM frtn_t snfv_frtn; 21699344SVasumathi.Sundaram@Sun.COM vnode_t *snfv_vp; 21709344SVasumathi.Sundaram@Sun.COM struct vmap snfv_vml[SNF_MAXVMAPS]; 21719301SVasumathi.Sundaram@Sun.COM } snf_vmap_desbinfo; 21729301SVasumathi.Sundaram@Sun.COM 21730Sstevel@tonic-gate typedef struct { 21740Sstevel@tonic-gate frtn_t snfi_frtn; 21750Sstevel@tonic-gate caddr_t snfi_base; 21760Sstevel@tonic-gate uint_t snfi_mapoff; 21770Sstevel@tonic-gate size_t snfi_len; 21780Sstevel@tonic-gate vnode_t *snfi_vp; 21790Sstevel@tonic-gate } snf_smap_desbinfo; 21800Sstevel@tonic-gate 21819344SVasumathi.Sundaram@Sun.COM /* 21829344SVasumathi.Sundaram@Sun.COM * The callback function used for vpm mapped mblks called when the last ref of 21839344SVasumathi.Sundaram@Sun.COM * the mblk is dropped which normally occurs when TCP receives the ack. But it 21849344SVasumathi.Sundaram@Sun.COM * can be the driver too due to lazy reclaim. 21859344SVasumathi.Sundaram@Sun.COM */ 21869301SVasumathi.Sundaram@Sun.COM void 21879301SVasumathi.Sundaram@Sun.COM snf_vmap_desbfree(snf_vmap_desbinfo *snfv) 21889301SVasumathi.Sundaram@Sun.COM { 21899344SVasumathi.Sundaram@Sun.COM ASSERT(snfv->snfv_ref != 0); 21909344SVasumathi.Sundaram@Sun.COM if (atomic_add_32_nv(&snfv->snfv_ref, -1) == 0) { 21919344SVasumathi.Sundaram@Sun.COM vpm_unmap_pages(snfv->snfv_vml, S_READ); 21929301SVasumathi.Sundaram@Sun.COM VN_RELE(snfv->snfv_vp); 21939301SVasumathi.Sundaram@Sun.COM kmem_free(snfv, sizeof (snf_vmap_desbinfo)); 21949301SVasumathi.Sundaram@Sun.COM } 21959301SVasumathi.Sundaram@Sun.COM } 21969301SVasumathi.Sundaram@Sun.COM 21970Sstevel@tonic-gate /* 21989344SVasumathi.Sundaram@Sun.COM * The callback function used for segmap'ped mblks called when the last ref of 21999344SVasumathi.Sundaram@Sun.COM * the mblk is dropped which normally occurs when TCP receives the ack. But it 22009344SVasumathi.Sundaram@Sun.COM * can be the driver too due to lazy reclaim. 22010Sstevel@tonic-gate */ 22020Sstevel@tonic-gate void 22030Sstevel@tonic-gate snf_smap_desbfree(snf_smap_desbinfo *snfi) 22040Sstevel@tonic-gate { 22057568SJayakara.Kini@Sun.COM if (! IS_KPM_ADDR(snfi->snfi_base)) { 22060Sstevel@tonic-gate /* 22070Sstevel@tonic-gate * We don't need to call segmap_fault(F_SOFTUNLOCK) for 22080Sstevel@tonic-gate * segmap_kpm as long as the latter never falls back to 22090Sstevel@tonic-gate * "use_segmap_range". (See segmap_getmapflt().) 22100Sstevel@tonic-gate * 22110Sstevel@tonic-gate * Using S_OTHER saves an redundant hat_setref() in 22120Sstevel@tonic-gate * segmap_unlock() 22130Sstevel@tonic-gate */ 22140Sstevel@tonic-gate (void) segmap_fault(kas.a_hat, segkmap, 2215408Skrgopi (caddr_t)(uintptr_t)(((uintptr_t)snfi->snfi_base + 2216408Skrgopi snfi->snfi_mapoff) & PAGEMASK), snfi->snfi_len, 2217408Skrgopi F_SOFTUNLOCK, S_OTHER); 22180Sstevel@tonic-gate } 22190Sstevel@tonic-gate (void) segmap_release(segkmap, snfi->snfi_base, SM_DONTNEED); 22200Sstevel@tonic-gate VN_RELE(snfi->snfi_vp); 22210Sstevel@tonic-gate kmem_free(snfi, sizeof (*snfi)); 22220Sstevel@tonic-gate } 22230Sstevel@tonic-gate 22240Sstevel@tonic-gate /* 22259344SVasumathi.Sundaram@Sun.COM * Use segmap or vpm instead of bcopy to send down a desballoca'ed, mblk. 22269344SVasumathi.Sundaram@Sun.COM * When segmap is used, the mblk contains a segmap slot of no more 22279344SVasumathi.Sundaram@Sun.COM * than MAXBSIZE. 22289344SVasumathi.Sundaram@Sun.COM * 22299344SVasumathi.Sundaram@Sun.COM * With vpm, a maximum of SNF_MAXVMAPS page-sized mappings can be obtained 22309344SVasumathi.Sundaram@Sun.COM * in each iteration and sent by socket_sendmblk until an error occurs or 22319344SVasumathi.Sundaram@Sun.COM * the requested size has been transferred. An mblk is esballoca'ed from 22329344SVasumathi.Sundaram@Sun.COM * each mapped page and a chain of these mblk is sent to the transport layer. 22339344SVasumathi.Sundaram@Sun.COM * vpm will be called to unmap the pages when all mblks have been freed by 22349344SVasumathi.Sundaram@Sun.COM * free_func. 22350Sstevel@tonic-gate * 22360Sstevel@tonic-gate * At the end of the whole sendfile() operation, we wait till the data from 22370Sstevel@tonic-gate * the last mblk is ack'ed by the transport before returning so that the 22380Sstevel@tonic-gate * caller of sendfile() can safely modify the file content. 22390Sstevel@tonic-gate */ 22400Sstevel@tonic-gate int 22419344SVasumathi.Sundaram@Sun.COM snf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t total_size, 22427568SJayakara.Kini@Sun.COM ssize_t *count, boolean_t nowait) 22430Sstevel@tonic-gate { 22440Sstevel@tonic-gate caddr_t base; 22450Sstevel@tonic-gate int mapoff; 22460Sstevel@tonic-gate vnode_t *vp; 22479344SVasumathi.Sundaram@Sun.COM mblk_t *mp = NULL; 22489344SVasumathi.Sundaram@Sun.COM int chain_size; 22490Sstevel@tonic-gate int error; 22500Sstevel@tonic-gate short fflag; 22510Sstevel@tonic-gate int ksize; 22520Sstevel@tonic-gate struct vattr va; 22530Sstevel@tonic-gate boolean_t dowait = B_FALSE; 22548348SEric.Yu@Sun.COM struct nmsghdr msg; 22550Sstevel@tonic-gate 22560Sstevel@tonic-gate vp = fp->f_vnode; 22570Sstevel@tonic-gate fflag = fp->f_flag; 22580Sstevel@tonic-gate ksize = 0; 22598348SEric.Yu@Sun.COM bzero(&msg, sizeof (msg)); 22608348SEric.Yu@Sun.COM 22610Sstevel@tonic-gate for (;;) { 22620Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) { 22630Sstevel@tonic-gate error = EINTR; 22640Sstevel@tonic-gate break; 22650Sstevel@tonic-gate } 22667568SJayakara.Kini@Sun.COM 22679344SVasumathi.Sundaram@Sun.COM if (vpm_enable) { 22689344SVasumathi.Sundaram@Sun.COM snf_vmap_desbinfo *snfv; 22699344SVasumathi.Sundaram@Sun.COM mblk_t *nmp; 22709344SVasumathi.Sundaram@Sun.COM int mblk_size; 22719344SVasumathi.Sundaram@Sun.COM int maxsize; 22729344SVasumathi.Sundaram@Sun.COM int i; 22739301SVasumathi.Sundaram@Sun.COM 22749344SVasumathi.Sundaram@Sun.COM mapoff = fileoff & PAGEOFFSET; 22759344SVasumathi.Sundaram@Sun.COM maxsize = MIN((SNF_VPMMAXPGS * PAGESIZE), total_size); 22769344SVasumathi.Sundaram@Sun.COM 22779344SVasumathi.Sundaram@Sun.COM snfv = kmem_zalloc(sizeof (snf_vmap_desbinfo), 22789344SVasumathi.Sundaram@Sun.COM KM_SLEEP); 22799344SVasumathi.Sundaram@Sun.COM 22809344SVasumathi.Sundaram@Sun.COM /* Get vpm mappings for maxsize with read access */ 22819301SVasumathi.Sundaram@Sun.COM if (vpm_map_pages(fvp, fileoff, (size_t)maxsize, 22829344SVasumathi.Sundaram@Sun.COM (VPM_FETCHPAGE), snfv->snfv_vml, SNF_MAXVMAPS, 22839301SVasumathi.Sundaram@Sun.COM NULL, S_READ) != 0) { 22849301SVasumathi.Sundaram@Sun.COM kmem_free(snfv, sizeof (snf_vmap_desbinfo)); 22859301SVasumathi.Sundaram@Sun.COM error = EIO; 22869301SVasumathi.Sundaram@Sun.COM goto out; 22879301SVasumathi.Sundaram@Sun.COM } 22889301SVasumathi.Sundaram@Sun.COM snfv->snfv_frtn.free_func = snf_vmap_desbfree; 22899301SVasumathi.Sundaram@Sun.COM snfv->snfv_frtn.free_arg = (caddr_t)snfv; 22909301SVasumathi.Sundaram@Sun.COM 22919344SVasumathi.Sundaram@Sun.COM /* Construct the mblk chain from the page mappings */ 22929344SVasumathi.Sundaram@Sun.COM chain_size = 0; 22939344SVasumathi.Sundaram@Sun.COM for (i = 0; (snfv->snfv_vml[i].vs_addr != NULL) && 22949344SVasumathi.Sundaram@Sun.COM total_size > 0; i++) { 22959344SVasumathi.Sundaram@Sun.COM ASSERT(chain_size < maxsize); 22969344SVasumathi.Sundaram@Sun.COM mblk_size = MIN(snfv->snfv_vml[i].vs_len - 22979344SVasumathi.Sundaram@Sun.COM mapoff, total_size); 22989344SVasumathi.Sundaram@Sun.COM nmp = esballoca( 22999344SVasumathi.Sundaram@Sun.COM (uchar_t *)snfv->snfv_vml[i].vs_addr + 23009344SVasumathi.Sundaram@Sun.COM mapoff, mblk_size, BPRI_HI, 23019344SVasumathi.Sundaram@Sun.COM &snfv->snfv_frtn); 23029301SVasumathi.Sundaram@Sun.COM 23039344SVasumathi.Sundaram@Sun.COM /* 23049344SVasumathi.Sundaram@Sun.COM * We return EAGAIN after unmapping the pages 23059344SVasumathi.Sundaram@Sun.COM * if we cannot allocate the the head of the 23069344SVasumathi.Sundaram@Sun.COM * chain. Otherwise, we continue sending the 23079344SVasumathi.Sundaram@Sun.COM * mblks constructed so far. 23089344SVasumathi.Sundaram@Sun.COM */ 23099344SVasumathi.Sundaram@Sun.COM if (nmp == NULL) { 23109344SVasumathi.Sundaram@Sun.COM if (i == 0) { 23119344SVasumathi.Sundaram@Sun.COM vpm_unmap_pages(snfv->snfv_vml, 23129344SVasumathi.Sundaram@Sun.COM S_READ); 23139344SVasumathi.Sundaram@Sun.COM kmem_free(snfv, 23149344SVasumathi.Sundaram@Sun.COM sizeof (snf_vmap_desbinfo)); 23159344SVasumathi.Sundaram@Sun.COM error = EAGAIN; 23169344SVasumathi.Sundaram@Sun.COM goto out; 23179344SVasumathi.Sundaram@Sun.COM } 23189344SVasumathi.Sundaram@Sun.COM break; 23199301SVasumathi.Sundaram@Sun.COM } 23209344SVasumathi.Sundaram@Sun.COM /* Mark this dblk with the zero-copy flag */ 23219344SVasumathi.Sundaram@Sun.COM nmp->b_datap->db_struioflag |= STRUIO_ZC; 23229344SVasumathi.Sundaram@Sun.COM nmp->b_wptr += mblk_size; 23239344SVasumathi.Sundaram@Sun.COM chain_size += mblk_size; 23249344SVasumathi.Sundaram@Sun.COM fileoff += mblk_size; 23259344SVasumathi.Sundaram@Sun.COM total_size -= mblk_size; 23269344SVasumathi.Sundaram@Sun.COM snfv->snfv_ref++; 23279344SVasumathi.Sundaram@Sun.COM mapoff = 0; 23289344SVasumathi.Sundaram@Sun.COM if (i > 0) 23299344SVasumathi.Sundaram@Sun.COM linkb(mp, nmp); 23309344SVasumathi.Sundaram@Sun.COM else 23319344SVasumathi.Sundaram@Sun.COM mp = nmp; 23329301SVasumathi.Sundaram@Sun.COM } 23339301SVasumathi.Sundaram@Sun.COM VN_HOLD(fvp); 23349301SVasumathi.Sundaram@Sun.COM snfv->snfv_vp = fvp; 23359301SVasumathi.Sundaram@Sun.COM } else { 23369344SVasumathi.Sundaram@Sun.COM /* vpm not supported. fallback to segmap */ 23379344SVasumathi.Sundaram@Sun.COM snf_smap_desbinfo *snfi; 23380Sstevel@tonic-gate 23399301SVasumathi.Sundaram@Sun.COM mapoff = fileoff & MAXBOFFSET; 23409344SVasumathi.Sundaram@Sun.COM chain_size = MAXBSIZE - mapoff; 23419344SVasumathi.Sundaram@Sun.COM if (chain_size > total_size) 23429344SVasumathi.Sundaram@Sun.COM chain_size = total_size; 23439301SVasumathi.Sundaram@Sun.COM /* 23449301SVasumathi.Sundaram@Sun.COM * we don't forcefault because we'll call 23459301SVasumathi.Sundaram@Sun.COM * segmap_fault(F_SOFTLOCK) next. 23469301SVasumathi.Sundaram@Sun.COM * 23479301SVasumathi.Sundaram@Sun.COM * S_READ will get the ref bit set (by either 23489301SVasumathi.Sundaram@Sun.COM * segmap_getmapflt() or segmap_fault()) and page 23499301SVasumathi.Sundaram@Sun.COM * shared locked. 23509301SVasumathi.Sundaram@Sun.COM */ 23519344SVasumathi.Sundaram@Sun.COM base = segmap_getmapflt(segkmap, fvp, fileoff, 23529344SVasumathi.Sundaram@Sun.COM chain_size, segmap_kpm ? SM_FAULT : 0, S_READ); 23539301SVasumathi.Sundaram@Sun.COM 23549301SVasumathi.Sundaram@Sun.COM snfi = kmem_alloc(sizeof (*snfi), KM_SLEEP); 23559344SVasumathi.Sundaram@Sun.COM snfi->snfi_len = (size_t)roundup(mapoff+chain_size, 23569301SVasumathi.Sundaram@Sun.COM PAGESIZE)- (mapoff & PAGEMASK); 23579301SVasumathi.Sundaram@Sun.COM /* 23589301SVasumathi.Sundaram@Sun.COM * We must call segmap_fault() even for segmap_kpm 23599301SVasumathi.Sundaram@Sun.COM * because that's how error gets returned. 23609301SVasumathi.Sundaram@Sun.COM * (segmap_getmapflt() never fails but segmap_fault() 23619301SVasumathi.Sundaram@Sun.COM * does.) 23629301SVasumathi.Sundaram@Sun.COM */ 23639301SVasumathi.Sundaram@Sun.COM if (segmap_fault(kas.a_hat, segkmap, 23649344SVasumathi.Sundaram@Sun.COM (caddr_t)(uintptr_t)(((uintptr_t)base + mapoff) & 23659344SVasumathi.Sundaram@Sun.COM PAGEMASK), snfi->snfi_len, 23669301SVasumathi.Sundaram@Sun.COM F_SOFTLOCK, S_READ) != 0) { 23679301SVasumathi.Sundaram@Sun.COM (void) segmap_release(segkmap, base, 0); 23689301SVasumathi.Sundaram@Sun.COM kmem_free(snfi, sizeof (*snfi)); 23699301SVasumathi.Sundaram@Sun.COM error = EIO; 23709301SVasumathi.Sundaram@Sun.COM goto out; 23719301SVasumathi.Sundaram@Sun.COM } 23729301SVasumathi.Sundaram@Sun.COM snfi->snfi_frtn.free_func = snf_smap_desbfree; 23739301SVasumathi.Sundaram@Sun.COM snfi->snfi_frtn.free_arg = (caddr_t)snfi; 23749301SVasumathi.Sundaram@Sun.COM snfi->snfi_base = base; 23759301SVasumathi.Sundaram@Sun.COM snfi->snfi_mapoff = mapoff; 23769344SVasumathi.Sundaram@Sun.COM mp = esballoca((uchar_t *)base + mapoff, chain_size, 23779301SVasumathi.Sundaram@Sun.COM BPRI_HI, &snfi->snfi_frtn); 23789301SVasumathi.Sundaram@Sun.COM 23799301SVasumathi.Sundaram@Sun.COM if (mp == NULL) { 23809301SVasumathi.Sundaram@Sun.COM (void) segmap_fault(kas.a_hat, segkmap, 23819344SVasumathi.Sundaram@Sun.COM (caddr_t)(uintptr_t)(((uintptr_t)base + 23829344SVasumathi.Sundaram@Sun.COM mapoff) & PAGEMASK), snfi->snfi_len, 23839301SVasumathi.Sundaram@Sun.COM F_SOFTUNLOCK, S_OTHER); 23849301SVasumathi.Sundaram@Sun.COM (void) segmap_release(segkmap, base, 0); 23859301SVasumathi.Sundaram@Sun.COM kmem_free(snfi, sizeof (*snfi)); 23869301SVasumathi.Sundaram@Sun.COM freemsg(mp); 23879301SVasumathi.Sundaram@Sun.COM error = EAGAIN; 23889301SVasumathi.Sundaram@Sun.COM goto out; 23899301SVasumathi.Sundaram@Sun.COM } 23909301SVasumathi.Sundaram@Sun.COM VN_HOLD(fvp); 23919301SVasumathi.Sundaram@Sun.COM snfi->snfi_vp = fvp; 23929344SVasumathi.Sundaram@Sun.COM mp->b_wptr += chain_size; 23939301SVasumathi.Sundaram@Sun.COM 23949301SVasumathi.Sundaram@Sun.COM /* Mark this dblk with the zero-copy flag */ 23959301SVasumathi.Sundaram@Sun.COM mp->b_datap->db_struioflag |= STRUIO_ZC; 23969344SVasumathi.Sundaram@Sun.COM fileoff += chain_size; 23979344SVasumathi.Sundaram@Sun.COM total_size -= chain_size; 23987568SJayakara.Kini@Sun.COM } 23990Sstevel@tonic-gate 24009344SVasumathi.Sundaram@Sun.COM if (total_size == 0 && !nowait) { 24010Sstevel@tonic-gate ASSERT(!dowait); 24020Sstevel@tonic-gate dowait = B_TRUE; 24037568SJayakara.Kini@Sun.COM mp->b_datap->db_struioflag |= STRUIO_ZCNOTIFY; 24040Sstevel@tonic-gate } 24050Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL); 24068348SEric.Yu@Sun.COM error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp); 24078348SEric.Yu@Sun.COM if (error != 0) { 24089344SVasumathi.Sundaram@Sun.COM /* 24099344SVasumathi.Sundaram@Sun.COM * mp contains the mblks that were not sent by 24109344SVasumathi.Sundaram@Sun.COM * socket_sendmblk. Use its size to update *count 24119344SVasumathi.Sundaram@Sun.COM */ 24129344SVasumathi.Sundaram@Sun.COM *count = ksize + (chain_size - msgdsize(mp)); 24138348SEric.Yu@Sun.COM if (mp != NULL) 24148348SEric.Yu@Sun.COM freemsg(mp); 24150Sstevel@tonic-gate return (error); 24160Sstevel@tonic-gate } 24179344SVasumathi.Sundaram@Sun.COM ksize += chain_size; 24189344SVasumathi.Sundaram@Sun.COM if (total_size == 0) 24190Sstevel@tonic-gate goto done; 24200Sstevel@tonic-gate 24210Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL); 24220Sstevel@tonic-gate va.va_mask = AT_SIZE; 24235331Samw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL); 24240Sstevel@tonic-gate if (error) 24250Sstevel@tonic-gate break; 24260Sstevel@tonic-gate /* Read as much as possible. */ 24270Sstevel@tonic-gate if (fileoff >= va.va_size) 24280Sstevel@tonic-gate break; 24299344SVasumathi.Sundaram@Sun.COM if (total_size + fileoff > va.va_size) 24309344SVasumathi.Sundaram@Sun.COM total_size = va.va_size - fileoff; 24310Sstevel@tonic-gate } 24320Sstevel@tonic-gate out: 24330Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL); 24340Sstevel@tonic-gate done: 24350Sstevel@tonic-gate *count = ksize; 24360Sstevel@tonic-gate if (dowait) { 24370Sstevel@tonic-gate stdata_t *stp; 24380Sstevel@tonic-gate 24390Sstevel@tonic-gate stp = vp->v_stream; 24408348SEric.Yu@Sun.COM if (stp == NULL) { 24418348SEric.Yu@Sun.COM struct sonode *so; 24428348SEric.Yu@Sun.COM so = VTOSO(vp); 24438348SEric.Yu@Sun.COM error = so_zcopy_wait(so); 24448348SEric.Yu@Sun.COM } else { 24458348SEric.Yu@Sun.COM mutex_enter(&stp->sd_lock); 24468348SEric.Yu@Sun.COM while (!(stp->sd_flag & STZCNOTIFY)) { 24478348SEric.Yu@Sun.COM if (cv_wait_sig(&stp->sd_zcopy_wait, 24488348SEric.Yu@Sun.COM &stp->sd_lock) == 0) { 24498348SEric.Yu@Sun.COM error = EINTR; 24508348SEric.Yu@Sun.COM break; 24518348SEric.Yu@Sun.COM } 24523415Samehta } 24538348SEric.Yu@Sun.COM stp->sd_flag &= ~STZCNOTIFY; 24548348SEric.Yu@Sun.COM mutex_exit(&stp->sd_lock); 24550Sstevel@tonic-gate } 24560Sstevel@tonic-gate } 24570Sstevel@tonic-gate return (error); 24580Sstevel@tonic-gate } 24590Sstevel@tonic-gate 24600Sstevel@tonic-gate int 24610Sstevel@tonic-gate snf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size, 24620Sstevel@tonic-gate uint_t maxpsz, ssize_t *count) 24630Sstevel@tonic-gate { 24640Sstevel@tonic-gate struct vnode *vp; 24650Sstevel@tonic-gate mblk_t *mp; 24660Sstevel@tonic-gate int iosize; 24676240Skrishna int extra = 0; 24680Sstevel@tonic-gate int error; 24690Sstevel@tonic-gate short fflag; 24700Sstevel@tonic-gate int ksize; 24710Sstevel@tonic-gate int ioflag; 24720Sstevel@tonic-gate struct uio auio; 24730Sstevel@tonic-gate struct iovec aiov; 24740Sstevel@tonic-gate struct vattr va; 24758171SPrakash.Jalan@Sun.COM int maxblk = 0; 24768171SPrakash.Jalan@Sun.COM int wroff = 0; 24778171SPrakash.Jalan@Sun.COM struct sonode *so; 24788348SEric.Yu@Sun.COM struct nmsghdr msg; 24790Sstevel@tonic-gate 24800Sstevel@tonic-gate vp = fp->f_vnode; 24816240Skrishna if (vp->v_type == VSOCK) { 24826240Skrishna stdata_t *stp; 24836240Skrishna 24846240Skrishna /* 24856240Skrishna * Get the extra space to insert a header and a trailer. 24866240Skrishna */ 24878171SPrakash.Jalan@Sun.COM so = VTOSO(vp); 24886240Skrishna stp = vp->v_stream; 24898348SEric.Yu@Sun.COM if (stp == NULL) { 24908348SEric.Yu@Sun.COM wroff = so->so_proto_props.sopp_wroff; 24918348SEric.Yu@Sun.COM maxblk = so->so_proto_props.sopp_maxblk; 24928348SEric.Yu@Sun.COM extra = wroff + so->so_proto_props.sopp_tail; 24938348SEric.Yu@Sun.COM } else { 24948348SEric.Yu@Sun.COM wroff = (int)(stp->sd_wroff); 24958348SEric.Yu@Sun.COM maxblk = (int)(stp->sd_maxblk); 24968348SEric.Yu@Sun.COM extra = wroff + (int)(stp->sd_tail); 24978348SEric.Yu@Sun.COM } 24986240Skrishna } 24998348SEric.Yu@Sun.COM bzero(&msg, sizeof (msg)); 25000Sstevel@tonic-gate fflag = fp->f_flag; 25010Sstevel@tonic-gate ksize = 0; 25020Sstevel@tonic-gate auio.uio_iov = &aiov; 25030Sstevel@tonic-gate auio.uio_iovcnt = 1; 25040Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 25050Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 25060Sstevel@tonic-gate auio.uio_fmode = fflag; 25070Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 25080Sstevel@tonic-gate ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC); 25090Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 25100Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 25110Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 25120Sstevel@tonic-gate for (;;) { 25130Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) { 25140Sstevel@tonic-gate error = EINTR; 25150Sstevel@tonic-gate break; 25160Sstevel@tonic-gate } 25170Sstevel@tonic-gate iosize = (int)MIN(maxpsz, size); 25188171SPrakash.Jalan@Sun.COM 25198171SPrakash.Jalan@Sun.COM /* 25208171SPrakash.Jalan@Sun.COM * For sockets acting as an SSL proxy, we 25218171SPrakash.Jalan@Sun.COM * need to adjust the size to the maximum 25228171SPrakash.Jalan@Sun.COM * SSL record size set in the stream head. 25238171SPrakash.Jalan@Sun.COM */ 25248348SEric.Yu@Sun.COM if (vp->v_type == VSOCK && !SOCK_IS_NONSTR(so) && 25258348SEric.Yu@Sun.COM SOTOTPI(so)->sti_kssl_ctx != NULL) 25268171SPrakash.Jalan@Sun.COM iosize = (int)MIN(iosize, maxblk); 25278171SPrakash.Jalan@Sun.COM 25288778SErik.Nordmark@Sun.COM if (is_system_labeled()) { 25298778SErik.Nordmark@Sun.COM mp = allocb_cred(iosize + extra, CRED(), 25308778SErik.Nordmark@Sun.COM curproc->p_pid); 25318778SErik.Nordmark@Sun.COM } else { 25328778SErik.Nordmark@Sun.COM mp = allocb(iosize + extra, BPRI_MED); 25338778SErik.Nordmark@Sun.COM } 25348778SErik.Nordmark@Sun.COM if (mp == NULL) { 25350Sstevel@tonic-gate error = EAGAIN; 25360Sstevel@tonic-gate break; 25370Sstevel@tonic-gate } 25388171SPrakash.Jalan@Sun.COM 25398171SPrakash.Jalan@Sun.COM mp->b_rptr += wroff; 25408171SPrakash.Jalan@Sun.COM 25410Sstevel@tonic-gate aiov.iov_base = (caddr_t)mp->b_rptr; 25420Sstevel@tonic-gate aiov.iov_len = iosize; 25430Sstevel@tonic-gate auio.uio_loffset = fileoff; 25440Sstevel@tonic-gate auio.uio_resid = iosize; 25450Sstevel@tonic-gate 25460Sstevel@tonic-gate error = VOP_READ(fvp, &auio, ioflag, fp->f_cred, NULL); 25470Sstevel@tonic-gate iosize -= auio.uio_resid; 25480Sstevel@tonic-gate 25490Sstevel@tonic-gate if (error == EINTR && iosize != 0) 25500Sstevel@tonic-gate error = 0; 25510Sstevel@tonic-gate 25520Sstevel@tonic-gate if (error != 0 || iosize == 0) { 25530Sstevel@tonic-gate freeb(mp); 25540Sstevel@tonic-gate break; 25550Sstevel@tonic-gate } 25560Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + iosize; 25570Sstevel@tonic-gate 25580Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL); 25598348SEric.Yu@Sun.COM 25608348SEric.Yu@Sun.COM error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp); 25618348SEric.Yu@Sun.COM 25628348SEric.Yu@Sun.COM if (error != 0) { 25630Sstevel@tonic-gate *count = ksize; 25648348SEric.Yu@Sun.COM if (mp != NULL) 25658348SEric.Yu@Sun.COM freeb(mp); 25660Sstevel@tonic-gate return (error); 25670Sstevel@tonic-gate } 25680Sstevel@tonic-gate ksize += iosize; 25690Sstevel@tonic-gate size -= iosize; 25700Sstevel@tonic-gate if (size == 0) 25710Sstevel@tonic-gate goto done; 25720Sstevel@tonic-gate 25730Sstevel@tonic-gate fileoff += iosize; 25740Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL); 25750Sstevel@tonic-gate va.va_mask = AT_SIZE; 25765331Samw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL); 25770Sstevel@tonic-gate if (error) 25780Sstevel@tonic-gate break; 25790Sstevel@tonic-gate /* Read as much as possible. */ 25800Sstevel@tonic-gate if (fileoff >= va.va_size) 25810Sstevel@tonic-gate size = 0; 25820Sstevel@tonic-gate else if (size + fileoff > va.va_size) 25830Sstevel@tonic-gate size = va.va_size - fileoff; 25840Sstevel@tonic-gate } 25850Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL); 25860Sstevel@tonic-gate done: 25870Sstevel@tonic-gate *count = ksize; 25880Sstevel@tonic-gate return (error); 25890Sstevel@tonic-gate } 25900Sstevel@tonic-gate 25910Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32) 25920Sstevel@tonic-gate /* 25930Sstevel@tonic-gate * Largefile support for 32 bit applications only. 25940Sstevel@tonic-gate */ 25950Sstevel@tonic-gate int 25960Sstevel@tonic-gate sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv, 25970Sstevel@tonic-gate ssize32_t *count32) 25980Sstevel@tonic-gate { 25990Sstevel@tonic-gate ssize32_t sfv_len; 26000Sstevel@tonic-gate u_offset_t sfv_off, va_size; 26010Sstevel@tonic-gate struct vnode *vp, *fvp, *realvp; 26020Sstevel@tonic-gate struct vattr va; 26030Sstevel@tonic-gate stdata_t *stp; 26040Sstevel@tonic-gate ssize_t count = 0; 26050Sstevel@tonic-gate int error = 0; 26060Sstevel@tonic-gate boolean_t dozcopy = B_FALSE; 26070Sstevel@tonic-gate uint_t maxpsz; 26080Sstevel@tonic-gate 26090Sstevel@tonic-gate sfv_len = (ssize32_t)sfv->sfv_len; 26100Sstevel@tonic-gate if (sfv_len < 0) { 26110Sstevel@tonic-gate error = EINVAL; 26120Sstevel@tonic-gate goto out; 26130Sstevel@tonic-gate } 26140Sstevel@tonic-gate 26150Sstevel@tonic-gate if (sfv_len == 0) goto out; 26160Sstevel@tonic-gate 26170Sstevel@tonic-gate sfv_off = (u_offset_t)sfv->sfv_off; 26180Sstevel@tonic-gate 26190Sstevel@tonic-gate /* Same checks as in pread */ 26200Sstevel@tonic-gate if (sfv_off > MAXOFFSET_T) { 26210Sstevel@tonic-gate error = EINVAL; 26220Sstevel@tonic-gate goto out; 26230Sstevel@tonic-gate } 26240Sstevel@tonic-gate if (sfv_off + sfv_len > MAXOFFSET_T) 26250Sstevel@tonic-gate sfv_len = (ssize32_t)(MAXOFFSET_T - sfv_off); 26260Sstevel@tonic-gate 26270Sstevel@tonic-gate /* 26280Sstevel@tonic-gate * There are no more checks on sfv_len. So, we cast it to 26290Sstevel@tonic-gate * u_offset_t and share the snf_direct_io/snf_cache code between 26300Sstevel@tonic-gate * 32 bit and 64 bit. 26310Sstevel@tonic-gate * 26320Sstevel@tonic-gate * TODO: should do nbl_need_check() like read()? 26330Sstevel@tonic-gate */ 26340Sstevel@tonic-gate if (sfv_len > sendfile_max_size) { 26350Sstevel@tonic-gate sf_stats.ss_file_not_cached++; 26360Sstevel@tonic-gate error = snf_direct_io(fp, rfp, sfv_off, (u_offset_t)sfv_len, 26370Sstevel@tonic-gate &count); 26380Sstevel@tonic-gate goto out; 26390Sstevel@tonic-gate } 26400Sstevel@tonic-gate fvp = rfp->f_vnode; 26415331Samw if (VOP_REALVP(fvp, &realvp, NULL) == 0) 26420Sstevel@tonic-gate fvp = realvp; 26430Sstevel@tonic-gate /* 26440Sstevel@tonic-gate * Grab the lock as a reader to prevent the file size 26450Sstevel@tonic-gate * from changing underneath. 26460Sstevel@tonic-gate */ 26470Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL); 26480Sstevel@tonic-gate va.va_mask = AT_SIZE; 26495331Samw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL); 26500Sstevel@tonic-gate va_size = va.va_size; 26514649Sdm120769 if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) { 26520Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL); 26530Sstevel@tonic-gate goto out; 26540Sstevel@tonic-gate } 26550Sstevel@tonic-gate /* Read as much as possible. */ 26560Sstevel@tonic-gate if (sfv_off + sfv_len > va_size) 26570Sstevel@tonic-gate sfv_len = va_size - sfv_off; 26580Sstevel@tonic-gate 26590Sstevel@tonic-gate vp = fp->f_vnode; 26600Sstevel@tonic-gate stp = vp->v_stream; 26610Sstevel@tonic-gate /* 26620Sstevel@tonic-gate * When the NOWAIT flag is not set, we enable zero-copy only if the 26630Sstevel@tonic-gate * transfer size is large enough. This prevents performance loss 26640Sstevel@tonic-gate * when the caller sends the file piece by piece. 26650Sstevel@tonic-gate */ 26660Sstevel@tonic-gate if (sfv_len >= MAXBSIZE && (sfv_len >= (va_size >> 1) || 26670Sstevel@tonic-gate (sfv->sfv_flag & SFV_NOWAIT) || sfv_len >= 0x1000000) && 26684173Spr14459 !vn_has_flocks(fvp) && !(fvp->v_flag & VNOMAP)) { 26698348SEric.Yu@Sun.COM uint_t copyflag; 26708348SEric.Yu@Sun.COM copyflag = stp != NULL ? stp->sd_copyflag : 26718348SEric.Yu@Sun.COM VTOSO(vp)->so_proto_props.sopp_zcopyflag; 26728348SEric.Yu@Sun.COM if ((copyflag & (STZCVMSAFE|STZCVMUNSAFE)) == 0) { 26730Sstevel@tonic-gate int on = 1; 26740Sstevel@tonic-gate 26758348SEric.Yu@Sun.COM if (socket_setsockopt(VTOSO(vp), SOL_SOCKET, 26768348SEric.Yu@Sun.COM SO_SND_COPYAVOID, &on, sizeof (on), CRED()) == 0) 26770Sstevel@tonic-gate dozcopy = B_TRUE; 26780Sstevel@tonic-gate } else { 26798348SEric.Yu@Sun.COM dozcopy = copyflag & STZCVMSAFE; 26800Sstevel@tonic-gate } 26810Sstevel@tonic-gate } 26820Sstevel@tonic-gate if (dozcopy) { 26830Sstevel@tonic-gate sf_stats.ss_file_segmap++; 26840Sstevel@tonic-gate error = snf_segmap(fp, fvp, sfv_off, (u_offset_t)sfv_len, 26857568SJayakara.Kini@Sun.COM &count, ((sfv->sfv_flag & SFV_NOWAIT) != 0)); 26860Sstevel@tonic-gate } else { 26878348SEric.Yu@Sun.COM if (vp->v_type == VSOCK && stp == NULL) { 26888348SEric.Yu@Sun.COM sonode_t *so = VTOSO(vp); 26898348SEric.Yu@Sun.COM maxpsz = so->so_proto_props.sopp_maxpsz; 26908348SEric.Yu@Sun.COM } else if (stp != NULL) { 26918348SEric.Yu@Sun.COM maxpsz = stp->sd_qn_maxpsz; 26928348SEric.Yu@Sun.COM } else { 26938348SEric.Yu@Sun.COM maxpsz = maxphys; 26948348SEric.Yu@Sun.COM } 26958348SEric.Yu@Sun.COM 26968348SEric.Yu@Sun.COM if (maxpsz == INFPSZ) 26977568SJayakara.Kini@Sun.COM maxpsz = maxphys; 26987568SJayakara.Kini@Sun.COM else 26998348SEric.Yu@Sun.COM maxpsz = roundup(maxpsz, MAXBSIZE); 27000Sstevel@tonic-gate sf_stats.ss_file_cached++; 27010Sstevel@tonic-gate error = snf_cache(fp, fvp, sfv_off, (u_offset_t)sfv_len, 27020Sstevel@tonic-gate maxpsz, &count); 27030Sstevel@tonic-gate } 27040Sstevel@tonic-gate out: 27050Sstevel@tonic-gate releasef(sfv->sfv_fd); 27060Sstevel@tonic-gate *count32 = (ssize32_t)count; 27070Sstevel@tonic-gate return (error); 27080Sstevel@tonic-gate } 27090Sstevel@tonic-gate #endif 27100Sstevel@tonic-gate 27110Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 27120Sstevel@tonic-gate /* 27130Sstevel@tonic-gate * recv32(), recvfrom32(), send32(), sendto32(): intentionally return a 27140Sstevel@tonic-gate * ssize_t rather than ssize32_t; see the comments above read32 for details. 27150Sstevel@tonic-gate */ 27160Sstevel@tonic-gate 27170Sstevel@tonic-gate ssize_t 27180Sstevel@tonic-gate recv32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags) 27190Sstevel@tonic-gate { 27200Sstevel@tonic-gate return (recv(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags)); 27210Sstevel@tonic-gate } 27220Sstevel@tonic-gate 27230Sstevel@tonic-gate ssize_t 27240Sstevel@tonic-gate recvfrom32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags, 27250Sstevel@tonic-gate caddr32_t name, caddr32_t namelenp) 27260Sstevel@tonic-gate { 27270Sstevel@tonic-gate return (recvfrom(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags, 27280Sstevel@tonic-gate (void *)(uintptr_t)name, (void *)(uintptr_t)namelenp)); 27290Sstevel@tonic-gate } 27300Sstevel@tonic-gate 27310Sstevel@tonic-gate ssize_t 27320Sstevel@tonic-gate send32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags) 27330Sstevel@tonic-gate { 27340Sstevel@tonic-gate return (send(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags)); 27350Sstevel@tonic-gate } 27360Sstevel@tonic-gate 27370Sstevel@tonic-gate ssize_t 27380Sstevel@tonic-gate sendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags, 27390Sstevel@tonic-gate caddr32_t name, socklen_t namelen) 27400Sstevel@tonic-gate { 27410Sstevel@tonic-gate return (sendto(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags, 27420Sstevel@tonic-gate (void *)(uintptr_t)name, namelen)); 27430Sstevel@tonic-gate } 27440Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 27450Sstevel@tonic-gate 27460Sstevel@tonic-gate /* 27475331Samw * Function wrappers (mostly around the sonode switch) for 27480Sstevel@tonic-gate * backward compatibility. 27490Sstevel@tonic-gate */ 27500Sstevel@tonic-gate 27510Sstevel@tonic-gate int 27520Sstevel@tonic-gate soaccept(struct sonode *so, int fflag, struct sonode **nsop) 27530Sstevel@tonic-gate { 27548348SEric.Yu@Sun.COM return (socket_accept(so, fflag, CRED(), nsop)); 27550Sstevel@tonic-gate } 27560Sstevel@tonic-gate 27570Sstevel@tonic-gate int 27580Sstevel@tonic-gate sobind(struct sonode *so, struct sockaddr *name, socklen_t namelen, 27590Sstevel@tonic-gate int backlog, int flags) 27600Sstevel@tonic-gate { 27610Sstevel@tonic-gate int error; 27620Sstevel@tonic-gate 27638348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, flags, CRED()); 27640Sstevel@tonic-gate if (error == 0 && backlog != 0) 27658348SEric.Yu@Sun.COM return (socket_listen(so, backlog, CRED())); 27660Sstevel@tonic-gate 27670Sstevel@tonic-gate return (error); 27680Sstevel@tonic-gate } 27690Sstevel@tonic-gate 27700Sstevel@tonic-gate int 27710Sstevel@tonic-gate solisten(struct sonode *so, int backlog) 27720Sstevel@tonic-gate { 27738348SEric.Yu@Sun.COM return (socket_listen(so, backlog, CRED())); 27740Sstevel@tonic-gate } 27750Sstevel@tonic-gate 27760Sstevel@tonic-gate int 27770Sstevel@tonic-gate soconnect(struct sonode *so, const struct sockaddr *name, socklen_t namelen, 27780Sstevel@tonic-gate int fflag, int flags) 27790Sstevel@tonic-gate { 27808348SEric.Yu@Sun.COM return (socket_connect(so, name, namelen, fflag, flags, CRED())); 27810Sstevel@tonic-gate } 27820Sstevel@tonic-gate 27830Sstevel@tonic-gate int 27840Sstevel@tonic-gate sorecvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop) 27850Sstevel@tonic-gate { 27868348SEric.Yu@Sun.COM return (socket_recvmsg(so, msg, uiop, CRED())); 27870Sstevel@tonic-gate } 27880Sstevel@tonic-gate 27890Sstevel@tonic-gate int 27900Sstevel@tonic-gate sosendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop) 27910Sstevel@tonic-gate { 27928348SEric.Yu@Sun.COM return (socket_sendmsg(so, msg, uiop, CRED())); 27930Sstevel@tonic-gate } 27940Sstevel@tonic-gate 27950Sstevel@tonic-gate int 27960Sstevel@tonic-gate soshutdown(struct sonode *so, int how) 27970Sstevel@tonic-gate { 27988348SEric.Yu@Sun.COM return (socket_shutdown(so, how, CRED())); 27990Sstevel@tonic-gate } 28000Sstevel@tonic-gate 28010Sstevel@tonic-gate int 28020Sstevel@tonic-gate sogetsockopt(struct sonode *so, int level, int option_name, void *optval, 28030Sstevel@tonic-gate socklen_t *optlenp, int flags) 28040Sstevel@tonic-gate { 28058348SEric.Yu@Sun.COM return (socket_getsockopt(so, level, option_name, optval, optlenp, 28068348SEric.Yu@Sun.COM flags, CRED())); 28070Sstevel@tonic-gate } 28080Sstevel@tonic-gate 28090Sstevel@tonic-gate int 28100Sstevel@tonic-gate sosetsockopt(struct sonode *so, int level, int option_name, const void *optval, 28110Sstevel@tonic-gate t_uscalar_t optlen) 28120Sstevel@tonic-gate { 28138348SEric.Yu@Sun.COM return (socket_setsockopt(so, level, option_name, optval, optlen, 28148348SEric.Yu@Sun.COM CRED())); 28150Sstevel@tonic-gate } 28160Sstevel@tonic-gate 28170Sstevel@tonic-gate /* 28180Sstevel@tonic-gate * Because this is backward compatibility interface it only needs to be 28190Sstevel@tonic-gate * able to handle the creation of TPI sockfs sockets. 28200Sstevel@tonic-gate */ 28210Sstevel@tonic-gate struct sonode * 28228348SEric.Yu@Sun.COM socreate(struct sockparams *sp, int family, int type, int protocol, int version, 28238348SEric.Yu@Sun.COM int *errorp) 28240Sstevel@tonic-gate { 28258348SEric.Yu@Sun.COM struct sonode *so; 28268348SEric.Yu@Sun.COM 28278348SEric.Yu@Sun.COM ASSERT(sp != NULL); 28288348SEric.Yu@Sun.COM 28298348SEric.Yu@Sun.COM so = sp->sp_smod_info->smod_sock_create_func(sp, family, type, protocol, 28308348SEric.Yu@Sun.COM version, SOCKET_SLEEP, errorp, CRED()); 28318348SEric.Yu@Sun.COM if (so == NULL) { 28328348SEric.Yu@Sun.COM SOCKPARAMS_DEC_REF(sp); 28338348SEric.Yu@Sun.COM } else { 28348348SEric.Yu@Sun.COM if ((*errorp = SOP_INIT(so, NULL, CRED(), SOCKET_SLEEP)) == 0) { 28358348SEric.Yu@Sun.COM /* Cannot fail, only bumps so_count */ 28368348SEric.Yu@Sun.COM (void) VOP_OPEN(&SOTOV(so), FREAD|FWRITE, CRED(), NULL); 28378348SEric.Yu@Sun.COM } else { 28388348SEric.Yu@Sun.COM socket_destroy(so); 28398348SEric.Yu@Sun.COM so = NULL; 28408348SEric.Yu@Sun.COM } 28418348SEric.Yu@Sun.COM } 28428348SEric.Yu@Sun.COM return (so); 28430Sstevel@tonic-gate } 2844