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 /*
2312643SAnders.Persson@Sun.COM * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/t_lock.h>
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/buf.h>
310Sstevel@tonic-gate #include <sys/conf.h>
320Sstevel@tonic-gate #include <sys/cred.h>
330Sstevel@tonic-gate #include <sys/kmem.h>
340Sstevel@tonic-gate #include <sys/sysmacros.h>
350Sstevel@tonic-gate #include <sys/vfs.h>
360Sstevel@tonic-gate #include <sys/vnode.h>
370Sstevel@tonic-gate #include <sys/debug.h>
380Sstevel@tonic-gate #include <sys/errno.h>
390Sstevel@tonic-gate #include <sys/time.h>
400Sstevel@tonic-gate #include <sys/file.h>
410Sstevel@tonic-gate #include <sys/user.h>
420Sstevel@tonic-gate #include <sys/stream.h>
430Sstevel@tonic-gate #include <sys/strsubr.h>
440Sstevel@tonic-gate #include <sys/strsun.h>
454173Spr14459 #include <sys/sunddi.h>
460Sstevel@tonic-gate #include <sys/esunddi.h>
470Sstevel@tonic-gate #include <sys/flock.h>
480Sstevel@tonic-gate #include <sys/modctl.h>
490Sstevel@tonic-gate #include <sys/cmn_err.h>
500Sstevel@tonic-gate #include <sys/vmsystm.h>
510Sstevel@tonic-gate #include <sys/policy.h>
520Sstevel@tonic-gate
530Sstevel@tonic-gate #include <sys/socket.h>
540Sstevel@tonic-gate #include <sys/socketvar.h>
550Sstevel@tonic-gate
560Sstevel@tonic-gate #include <sys/isa_defs.h>
570Sstevel@tonic-gate #include <sys/inttypes.h>
580Sstevel@tonic-gate #include <sys/systm.h>
590Sstevel@tonic-gate #include <sys/cpuvar.h>
600Sstevel@tonic-gate #include <sys/filio.h>
610Sstevel@tonic-gate #include <sys/sendfile.h>
620Sstevel@tonic-gate #include <sys/ddi.h>
630Sstevel@tonic-gate #include <vm/seg.h>
640Sstevel@tonic-gate #include <vm/seg_map.h>
650Sstevel@tonic-gate #include <vm/seg_kpm.h>
668348SEric.Yu@Sun.COM
670Sstevel@tonic-gate #include <fs/sockfs/nl7c.h>
688348SEric.Yu@Sun.COM #include <fs/sockfs/sockcommon.h>
6912643SAnders.Persson@Sun.COM #include <fs/sockfs/sockfilter_impl.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
7812643SAnders.Persson@Sun.COM extern int xnet_truncate_print;
7912643SAnders.Persson@Sun.COM
8012643SAnders.Persson@Sun.COM extern void nl7c_init(void);
8112643SAnders.Persson@Sun.COM extern int sockfs_defer_nl7c_init;
820Sstevel@tonic-gate
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c"
850Sstevel@tonic-gate * as there isn't a formal definition of IOV_MAX ???
860Sstevel@tonic-gate */
870Sstevel@tonic-gate #define MSG_MAXIOVLEN 16
880Sstevel@tonic-gate
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate * Kernel component of socket creation.
910Sstevel@tonic-gate *
920Sstevel@tonic-gate * The socket library determines which version number to use.
930Sstevel@tonic-gate * First the library calls this with a NULL devpath. If this fails
940Sstevel@tonic-gate * to find a transport (using solookup) the library will look in /etc/netconfig
950Sstevel@tonic-gate * for the appropriate transport. If one is found it will pass in the
960Sstevel@tonic-gate * devpath for the kernel to use.
970Sstevel@tonic-gate */
980Sstevel@tonic-gate int
so_socket(int family,int type,int protocol,char * devpath,int version)998348SEric.Yu@Sun.COM so_socket(int family, int type, int protocol, char *devpath, int version)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate struct sonode *so;
1020Sstevel@tonic-gate vnode_t *vp;
1030Sstevel@tonic-gate struct file *fp;
1040Sstevel@tonic-gate int fd;
1050Sstevel@tonic-gate int error;
1060Sstevel@tonic-gate
1078348SEric.Yu@Sun.COM if (devpath != NULL) {
1088348SEric.Yu@Sun.COM char *buf;
1098348SEric.Yu@Sun.COM size_t kdevpathlen = 0;
1100Sstevel@tonic-gate
1118348SEric.Yu@Sun.COM buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1128348SEric.Yu@Sun.COM if ((error = copyinstr(devpath, buf,
1138348SEric.Yu@Sun.COM MAXPATHLEN, &kdevpathlen)) != 0) {
1148348SEric.Yu@Sun.COM kmem_free(buf, MAXPATHLEN);
1150Sstevel@tonic-gate return (set_errno(error));
1160Sstevel@tonic-gate }
1178348SEric.Yu@Sun.COM so = socket_create(family, type, protocol, buf, NULL,
1188348SEric.Yu@Sun.COM SOCKET_SLEEP, version, CRED(), &error);
1198348SEric.Yu@Sun.COM kmem_free(buf, MAXPATHLEN);
1208348SEric.Yu@Sun.COM } else {
1218348SEric.Yu@Sun.COM so = socket_create(family, type, protocol, NULL, NULL,
1228348SEric.Yu@Sun.COM SOCKET_SLEEP, version, CRED(), &error);
1230Sstevel@tonic-gate }
1248348SEric.Yu@Sun.COM if (so == NULL)
1250Sstevel@tonic-gate return (set_errno(error));
1260Sstevel@tonic-gate
1278348SEric.Yu@Sun.COM /* Allocate a file descriptor for the socket */
1280Sstevel@tonic-gate vp = SOTOV(so);
1290Sstevel@tonic-gate if (error = falloc(vp, FWRITE|FREAD, &fp, &fd)) {
1308348SEric.Yu@Sun.COM (void) socket_close(so, 0, CRED());
1318348SEric.Yu@Sun.COM socket_destroy(so);
1320Sstevel@tonic-gate return (set_errno(error));
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate * Now fill in the entries that falloc reserved
1370Sstevel@tonic-gate */
1380Sstevel@tonic-gate mutex_exit(&fp->f_tlock);
1390Sstevel@tonic-gate setf(fd, fp);
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate return (fd);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate * Map from a file descriptor to a socket node.
1460Sstevel@tonic-gate * Returns with the file descriptor held i.e. the caller has to
1470Sstevel@tonic-gate * use releasef when done with the file descriptor.
1480Sstevel@tonic-gate */
1495227Stz204579 struct sonode *
getsonode(int sock,int * errorp,file_t ** fpp)1500Sstevel@tonic-gate getsonode(int sock, int *errorp, file_t **fpp)
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate file_t *fp;
1530Sstevel@tonic-gate vnode_t *vp;
1540Sstevel@tonic-gate struct sonode *so;
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate if ((fp = getf(sock)) == NULL) {
1570Sstevel@tonic-gate *errorp = EBADF;
1580Sstevel@tonic-gate eprintline(*errorp);
1590Sstevel@tonic-gate return (NULL);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate vp = fp->f_vnode;
1620Sstevel@tonic-gate /* Check if it is a socket */
1630Sstevel@tonic-gate if (vp->v_type != VSOCK) {
1640Sstevel@tonic-gate releasef(sock);
1650Sstevel@tonic-gate *errorp = ENOTSOCK;
1660Sstevel@tonic-gate eprintline(*errorp);
1670Sstevel@tonic-gate return (NULL);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate * Use the stream head to find the real socket vnode.
1710Sstevel@tonic-gate * This is needed when namefs sits above sockfs.
1720Sstevel@tonic-gate */
1730Sstevel@tonic-gate if (vp->v_stream) {
1740Sstevel@tonic-gate ASSERT(vp->v_stream->sd_vnode);
1750Sstevel@tonic-gate vp = vp->v_stream->sd_vnode;
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate so = VTOSO(vp);
1780Sstevel@tonic-gate if (so->so_version == SOV_STREAM) {
1790Sstevel@tonic-gate releasef(sock);
1800Sstevel@tonic-gate *errorp = ENOTSOCK;
1810Sstevel@tonic-gate eprintsoline(so, *errorp);
1820Sstevel@tonic-gate return (NULL);
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate } else {
1850Sstevel@tonic-gate so = VTOSO(vp);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate if (fpp)
1880Sstevel@tonic-gate *fpp = fp;
1890Sstevel@tonic-gate return (so);
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate * Allocate and copyin a sockaddr.
1940Sstevel@tonic-gate * Ensures NULL termination for AF_UNIX addresses by extending them
1950Sstevel@tonic-gate * with one NULL byte if need be. Verifies that the length is not
1960Sstevel@tonic-gate * excessive to prevent an application from consuming all of kernel
1970Sstevel@tonic-gate * memory. Returns NULL when an error occurred.
1980Sstevel@tonic-gate */
1990Sstevel@tonic-gate static struct sockaddr *
copyin_name(struct sonode * so,struct sockaddr * name,socklen_t * namelenp,int * errorp)2000Sstevel@tonic-gate copyin_name(struct sonode *so, struct sockaddr *name, socklen_t *namelenp,
2010Sstevel@tonic-gate int *errorp)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate char *faddr;
2040Sstevel@tonic-gate size_t namelen = (size_t)*namelenp;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate ASSERT(namelen != 0);
2070Sstevel@tonic-gate if (namelen > SO_MAXARGSIZE) {
2080Sstevel@tonic-gate *errorp = EINVAL;
2090Sstevel@tonic-gate eprintsoline(so, *errorp);
2100Sstevel@tonic-gate return (NULL);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate faddr = (char *)kmem_alloc(namelen, KM_SLEEP);
2140Sstevel@tonic-gate if (copyin(name, faddr, namelen)) {
2150Sstevel@tonic-gate kmem_free(faddr, namelen);
2160Sstevel@tonic-gate *errorp = EFAULT;
2170Sstevel@tonic-gate eprintsoline(so, *errorp);
2180Sstevel@tonic-gate return (NULL);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate * Add space for NULL termination if needed.
2230Sstevel@tonic-gate * Do a quick check if the last byte is NUL.
2240Sstevel@tonic-gate */
2250Sstevel@tonic-gate if (so->so_family == AF_UNIX && faddr[namelen - 1] != '\0') {
2260Sstevel@tonic-gate /* Check if there is any NULL termination */
2270Sstevel@tonic-gate size_t i;
2280Sstevel@tonic-gate int foundnull = 0;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate for (i = sizeof (name->sa_family); i < namelen; i++) {
2310Sstevel@tonic-gate if (faddr[i] == '\0') {
2320Sstevel@tonic-gate foundnull = 1;
2330Sstevel@tonic-gate break;
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate if (!foundnull) {
2370Sstevel@tonic-gate /* Add extra byte for NUL padding */
2380Sstevel@tonic-gate char *nfaddr;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate nfaddr = (char *)kmem_alloc(namelen + 1, KM_SLEEP);
2410Sstevel@tonic-gate bcopy(faddr, nfaddr, namelen);
2420Sstevel@tonic-gate kmem_free(faddr, namelen);
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate /* NUL terminate */
2450Sstevel@tonic-gate nfaddr[namelen] = '\0';
2460Sstevel@tonic-gate namelen++;
2470Sstevel@tonic-gate ASSERT((socklen_t)namelen == namelen);
2480Sstevel@tonic-gate *namelenp = (socklen_t)namelen;
2490Sstevel@tonic-gate faddr = nfaddr;
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate return ((struct sockaddr *)faddr);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate static int
copyout_arg(void * uaddr,socklen_t ulen,void * ulenp,void * kaddr,socklen_t klen)2590Sstevel@tonic-gate copyout_arg(void *uaddr, socklen_t ulen, void *ulenp,
2600Sstevel@tonic-gate void *kaddr, socklen_t klen)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate if (uaddr != NULL) {
2630Sstevel@tonic-gate if (ulen > klen)
2640Sstevel@tonic-gate ulen = klen;
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate if (ulen != 0) {
2670Sstevel@tonic-gate if (copyout(kaddr, uaddr, ulen))
2680Sstevel@tonic-gate return (EFAULT);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate } else
2710Sstevel@tonic-gate ulen = 0;
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate if (ulenp != NULL) {
2740Sstevel@tonic-gate if (copyout(&ulen, ulenp, sizeof (ulen)))
2750Sstevel@tonic-gate return (EFAULT);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate return (0);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
2820Sstevel@tonic-gate * If klen is greater than ulen it still uses the non-truncated
2830Sstevel@tonic-gate * klen to update ulenp.
2840Sstevel@tonic-gate */
2850Sstevel@tonic-gate static int
copyout_name(void * uaddr,socklen_t ulen,void * ulenp,void * kaddr,socklen_t klen)2860Sstevel@tonic-gate copyout_name(void *uaddr, socklen_t ulen, void *ulenp,
2870Sstevel@tonic-gate void *kaddr, socklen_t klen)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate if (uaddr != NULL) {
2900Sstevel@tonic-gate if (ulen >= klen)
2910Sstevel@tonic-gate ulen = klen;
2920Sstevel@tonic-gate else if (ulen != 0 && xnet_truncate_print) {
2930Sstevel@tonic-gate printf("sockfs: truncating copyout of address using "
2940Sstevel@tonic-gate "XNET semantics for pid = %d. Lengths %d, %d\n",
2950Sstevel@tonic-gate curproc->p_pid, klen, ulen);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate if (ulen != 0) {
2990Sstevel@tonic-gate if (copyout(kaddr, uaddr, ulen))
3000Sstevel@tonic-gate return (EFAULT);
3010Sstevel@tonic-gate } else
3020Sstevel@tonic-gate klen = 0;
3030Sstevel@tonic-gate } else
3040Sstevel@tonic-gate klen = 0;
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate if (ulenp != NULL) {
3070Sstevel@tonic-gate if (copyout(&klen, ulenp, sizeof (klen)))
3080Sstevel@tonic-gate return (EFAULT);
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate return (0);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate * The socketpair() code in libsocket creates two sockets (using
3150Sstevel@tonic-gate * the /etc/netconfig fallback if needed) before calling this routine
3160Sstevel@tonic-gate * to connect the two sockets together.
3170Sstevel@tonic-gate *
3180Sstevel@tonic-gate * For a SOCK_STREAM socketpair a listener is needed - in that case this
3190Sstevel@tonic-gate * routine will create a new file descriptor as part of accepting the
3200Sstevel@tonic-gate * connection. The library socketpair() will check if svs[2] has changed
3210Sstevel@tonic-gate * in which case it will close the changed fd.
3220Sstevel@tonic-gate *
3230Sstevel@tonic-gate * Note that this code could use the TPI feature of accepting the connection
3240Sstevel@tonic-gate * on the listening endpoint. However, that would require significant changes
3250Sstevel@tonic-gate * to soaccept.
3260Sstevel@tonic-gate */
3270Sstevel@tonic-gate int
so_socketpair(int sv[2])3280Sstevel@tonic-gate so_socketpair(int sv[2])
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate int svs[2];
3310Sstevel@tonic-gate struct sonode *so1, *so2;
3320Sstevel@tonic-gate int error;
3330Sstevel@tonic-gate struct sockaddr_ux *name;
3340Sstevel@tonic-gate size_t namelen;
3358348SEric.Yu@Sun.COM sotpi_info_t *sti1;
3368348SEric.Yu@Sun.COM sotpi_info_t *sti2;
3370Sstevel@tonic-gate
3387240Srh87107 dprint(1, ("so_socketpair(%p)\n", (void *)sv));
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate error = useracc(sv, sizeof (svs), B_WRITE);
3410Sstevel@tonic-gate if (error && do_useracc)
3420Sstevel@tonic-gate return (set_errno(EFAULT));
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate if (copyin(sv, svs, sizeof (svs)))
3450Sstevel@tonic-gate return (set_errno(EFAULT));
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate if ((so1 = getsonode(svs[0], &error, NULL)) == NULL)
3480Sstevel@tonic-gate return (set_errno(error));
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate if ((so2 = getsonode(svs[1], &error, NULL)) == NULL) {
3510Sstevel@tonic-gate releasef(svs[0]);
3520Sstevel@tonic-gate return (set_errno(error));
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate if (so1->so_family != AF_UNIX || so2->so_family != AF_UNIX) {
3560Sstevel@tonic-gate error = EOPNOTSUPP;
3570Sstevel@tonic-gate goto done;
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate
3608348SEric.Yu@Sun.COM sti1 = SOTOTPI(so1);
3618348SEric.Yu@Sun.COM sti2 = SOTOTPI(so2);
3628348SEric.Yu@Sun.COM
3630Sstevel@tonic-gate /*
3640Sstevel@tonic-gate * The code below makes assumptions about the "sockfs" implementation.
3650Sstevel@tonic-gate * So make sure that the correct implementation is really used.
3660Sstevel@tonic-gate */
3670Sstevel@tonic-gate ASSERT(so1->so_ops == &sotpi_sonodeops);
3680Sstevel@tonic-gate ASSERT(so2->so_ops == &sotpi_sonodeops);
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate if (so1->so_type == SOCK_DGRAM) {
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate * Bind both sockets and connect them with each other.
3730Sstevel@tonic-gate * Need to allocate name/namelen for soconnect.
3740Sstevel@tonic-gate */
3758348SEric.Yu@Sun.COM error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC, CRED());
3760Sstevel@tonic-gate if (error) {
3770Sstevel@tonic-gate eprintsoline(so1, error);
3780Sstevel@tonic-gate goto done;
3790Sstevel@tonic-gate }
3808348SEric.Yu@Sun.COM error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
3810Sstevel@tonic-gate if (error) {
3820Sstevel@tonic-gate eprintsoline(so2, error);
3830Sstevel@tonic-gate goto done;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate namelen = sizeof (struct sockaddr_ux);
3860Sstevel@tonic-gate name = kmem_alloc(namelen, KM_SLEEP);
3870Sstevel@tonic-gate name->sou_family = AF_UNIX;
3888348SEric.Yu@Sun.COM name->sou_addr = sti2->sti_ux_laddr;
3898348SEric.Yu@Sun.COM error = socket_connect(so1,
3905227Stz204579 (struct sockaddr *)name,
3915227Stz204579 (socklen_t)namelen,
3928348SEric.Yu@Sun.COM 0, _SOCONNECT_NOXLATE, CRED());
3930Sstevel@tonic-gate if (error) {
3940Sstevel@tonic-gate kmem_free(name, namelen);
3950Sstevel@tonic-gate eprintsoline(so1, error);
3960Sstevel@tonic-gate goto done;
3970Sstevel@tonic-gate }
3988348SEric.Yu@Sun.COM name->sou_addr = sti1->sti_ux_laddr;
3998348SEric.Yu@Sun.COM error = socket_connect(so2,
4005227Stz204579 (struct sockaddr *)name,
4015227Stz204579 (socklen_t)namelen,
4028348SEric.Yu@Sun.COM 0, _SOCONNECT_NOXLATE, CRED());
4030Sstevel@tonic-gate kmem_free(name, namelen);
4040Sstevel@tonic-gate if (error) {
4050Sstevel@tonic-gate eprintsoline(so2, error);
4060Sstevel@tonic-gate goto done;
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate releasef(svs[0]);
4090Sstevel@tonic-gate releasef(svs[1]);
4100Sstevel@tonic-gate } else {
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate * Bind both sockets, with so1 being a listener.
4130Sstevel@tonic-gate * Connect so2 to so1 - nonblocking to avoid waiting for
4140Sstevel@tonic-gate * soaccept to complete.
4150Sstevel@tonic-gate * Accept a connection on so1. Pass out the new fd as sv[0].
4160Sstevel@tonic-gate * The library will detect the changed fd and close
4170Sstevel@tonic-gate * the original one.
4180Sstevel@tonic-gate */
4190Sstevel@tonic-gate struct sonode *nso;
4200Sstevel@tonic-gate struct vnode *nvp;
4210Sstevel@tonic-gate struct file *nfp;
4220Sstevel@tonic-gate int nfd;
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate /*
4258348SEric.Yu@Sun.COM * We could simply call socket_listen() here (which would do the
4260Sstevel@tonic-gate * binding automatically) if the code didn't rely on passing
4278348SEric.Yu@Sun.COM * _SOBIND_NOXLATE to the TPI implementation of socket_bind().
4280Sstevel@tonic-gate */
4298348SEric.Yu@Sun.COM error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC|
4308348SEric.Yu@Sun.COM _SOBIND_NOXLATE|_SOBIND_LISTEN|_SOBIND_SOCKETPAIR,
4318348SEric.Yu@Sun.COM CRED());
4320Sstevel@tonic-gate if (error) {
4330Sstevel@tonic-gate eprintsoline(so1, error);
4340Sstevel@tonic-gate goto done;
4350Sstevel@tonic-gate }
4368348SEric.Yu@Sun.COM error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
4370Sstevel@tonic-gate if (error) {
4380Sstevel@tonic-gate eprintsoline(so2, error);
4390Sstevel@tonic-gate goto done;
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate namelen = sizeof (struct sockaddr_ux);
4430Sstevel@tonic-gate name = kmem_alloc(namelen, KM_SLEEP);
4440Sstevel@tonic-gate name->sou_family = AF_UNIX;
4458348SEric.Yu@Sun.COM name->sou_addr = sti1->sti_ux_laddr;
4468348SEric.Yu@Sun.COM error = socket_connect(so2,
4475227Stz204579 (struct sockaddr *)name,
4485227Stz204579 (socklen_t)namelen,
4498348SEric.Yu@Sun.COM FNONBLOCK, _SOCONNECT_NOXLATE, CRED());
4500Sstevel@tonic-gate kmem_free(name, namelen);
4510Sstevel@tonic-gate if (error) {
4520Sstevel@tonic-gate if (error != EINPROGRESS) {
4538348SEric.Yu@Sun.COM eprintsoline(so2, error); goto done;
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate
4578348SEric.Yu@Sun.COM error = socket_accept(so1, 0, CRED(), &nso);
4580Sstevel@tonic-gate if (error) {
4590Sstevel@tonic-gate eprintsoline(so1, error);
4600Sstevel@tonic-gate goto done;
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /* wait for so2 being SS_CONNECTED ignoring signals */
4640Sstevel@tonic-gate mutex_enter(&so2->so_lock);
4650Sstevel@tonic-gate error = sowaitconnected(so2, 0, 1);
4660Sstevel@tonic-gate mutex_exit(&so2->so_lock);
4670Sstevel@tonic-gate if (error != 0) {
4688348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED());
4698348SEric.Yu@Sun.COM socket_destroy(nso);
4700Sstevel@tonic-gate eprintsoline(so2, error);
4710Sstevel@tonic-gate goto done;
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate
4748348SEric.Yu@Sun.COM nvp = SOTOV(nso);
4750Sstevel@tonic-gate if (error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd)) {
4768348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED());
4778348SEric.Yu@Sun.COM socket_destroy(nso);
4780Sstevel@tonic-gate eprintsoline(nso, error);
4790Sstevel@tonic-gate goto done;
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate /*
4820Sstevel@tonic-gate * fill in the entries that falloc reserved
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate mutex_exit(&nfp->f_tlock);
4850Sstevel@tonic-gate setf(nfd, nfp);
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate releasef(svs[0]);
4880Sstevel@tonic-gate releasef(svs[1]);
4890Sstevel@tonic-gate svs[0] = nfd;
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate /*
4920Sstevel@tonic-gate * The socketpair library routine will close the original
4930Sstevel@tonic-gate * svs[0] when this code passes out a different file
4940Sstevel@tonic-gate * descriptor.
4950Sstevel@tonic-gate */
4960Sstevel@tonic-gate if (copyout(svs, sv, sizeof (svs))) {
4970Sstevel@tonic-gate (void) closeandsetf(nfd, NULL);
4980Sstevel@tonic-gate eprintline(EFAULT);
4990Sstevel@tonic-gate return (set_errno(EFAULT));
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate return (0);
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate done:
5050Sstevel@tonic-gate releasef(svs[0]);
5060Sstevel@tonic-gate releasef(svs[1]);
5070Sstevel@tonic-gate return (set_errno(error));
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate int
bind(int sock,struct sockaddr * name,socklen_t namelen,int version)5110Sstevel@tonic-gate bind(int sock, struct sockaddr *name, socklen_t namelen, int version)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate struct sonode *so;
5140Sstevel@tonic-gate int error;
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate dprint(1, ("bind(%d, %p, %d)\n",
5177240Srh87107 sock, (void *)name, namelen));
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
5200Sstevel@tonic-gate return (set_errno(error));
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate /* Allocate and copyin name */
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate * X/Open test does not expect EFAULT with NULL name and non-zero
5250Sstevel@tonic-gate * namelen.
5260Sstevel@tonic-gate */
5270Sstevel@tonic-gate if (name != NULL && namelen != 0) {
5280Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
5290Sstevel@tonic-gate name = copyin_name(so, name, &namelen, &error);
5300Sstevel@tonic-gate if (name == NULL) {
5310Sstevel@tonic-gate releasef(sock);
5320Sstevel@tonic-gate return (set_errno(error));
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate } else {
5350Sstevel@tonic-gate name = NULL;
5360Sstevel@tonic-gate namelen = 0;
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate switch (version) {
5400Sstevel@tonic-gate default:
5418348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, 0, CRED());
5420Sstevel@tonic-gate break;
5430Sstevel@tonic-gate case SOV_XPG4_2:
5448348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, _SOBIND_XPG4_2, CRED());
5450Sstevel@tonic-gate break;
5460Sstevel@tonic-gate case SOV_SOCKBSD:
5478348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, _SOBIND_SOCKBSD, CRED());
5480Sstevel@tonic-gate break;
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate done:
5510Sstevel@tonic-gate releasef(sock);
5520Sstevel@tonic-gate if (name != NULL)
5530Sstevel@tonic-gate kmem_free(name, (size_t)namelen);
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate if (error)
5560Sstevel@tonic-gate return (set_errno(error));
5570Sstevel@tonic-gate return (0);
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate /* ARGSUSED2 */
5610Sstevel@tonic-gate int
listen(int sock,int backlog,int version)5620Sstevel@tonic-gate listen(int sock, int backlog, int version)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate struct sonode *so;
5650Sstevel@tonic-gate int error;
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate dprint(1, ("listen(%d, %d)\n",
5685227Stz204579 sock, backlog));
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
5710Sstevel@tonic-gate return (set_errno(error));
5720Sstevel@tonic-gate
5738348SEric.Yu@Sun.COM error = socket_listen(so, backlog, CRED());
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate releasef(sock);
5760Sstevel@tonic-gate if (error)
5770Sstevel@tonic-gate return (set_errno(error));
5780Sstevel@tonic-gate return (0);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate /*ARGSUSED3*/
5820Sstevel@tonic-gate int
accept(int sock,struct sockaddr * name,socklen_t * namelenp,int version)5830Sstevel@tonic-gate accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
5840Sstevel@tonic-gate {
5850Sstevel@tonic-gate struct sonode *so;
5860Sstevel@tonic-gate file_t *fp;
5870Sstevel@tonic-gate int error;
5880Sstevel@tonic-gate socklen_t namelen;
5890Sstevel@tonic-gate struct sonode *nso;
5900Sstevel@tonic-gate struct vnode *nvp;
5910Sstevel@tonic-gate struct file *nfp;
5920Sstevel@tonic-gate int nfd;
5938348SEric.Yu@Sun.COM struct sockaddr *addrp;
5948348SEric.Yu@Sun.COM socklen_t addrlen;
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate dprint(1, ("accept(%d, %p, %p)\n",
5977240Srh87107 sock, (void *)name, (void *)namelenp));
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
6000Sstevel@tonic-gate return (set_errno(error));
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate if (name != NULL) {
6030Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6040Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen))) {
6050Sstevel@tonic-gate releasef(sock);
6060Sstevel@tonic-gate return (set_errno(EFAULT));
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate if (namelen != 0) {
6090Sstevel@tonic-gate error = useracc(name, (size_t)namelen, B_WRITE);
6100Sstevel@tonic-gate if (error && do_useracc) {
6110Sstevel@tonic-gate releasef(sock);
6120Sstevel@tonic-gate return (set_errno(EFAULT));
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate } else
6150Sstevel@tonic-gate name = NULL;
6160Sstevel@tonic-gate } else {
6170Sstevel@tonic-gate namelen = 0;
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate /*
6218348SEric.Yu@Sun.COM * Allocate the user fd before socket_accept() in order to
6228348SEric.Yu@Sun.COM * catch EMFILE errors before calling socket_accept().
6230Sstevel@tonic-gate */
6240Sstevel@tonic-gate if ((nfd = ufalloc(0)) == -1) {
6250Sstevel@tonic-gate eprintsoline(so, EMFILE);
6260Sstevel@tonic-gate releasef(sock);
6270Sstevel@tonic-gate return (set_errno(EMFILE));
6280Sstevel@tonic-gate }
6298348SEric.Yu@Sun.COM error = socket_accept(so, fp->f_flag, CRED(), &nso);
6300Sstevel@tonic-gate if (error) {
6310Sstevel@tonic-gate setf(nfd, NULL);
63211436SJayakara.Kini@Sun.COM releasef(sock);
6330Sstevel@tonic-gate return (set_errno(error));
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate nvp = SOTOV(nso);
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&nso->so_lock));
6398348SEric.Yu@Sun.COM if (namelen != 0) {
6408348SEric.Yu@Sun.COM addrlen = so->so_max_addr_len;
6418348SEric.Yu@Sun.COM addrp = (struct sockaddr *)kmem_alloc(addrlen, KM_SLEEP);
6428348SEric.Yu@Sun.COM
6438348SEric.Yu@Sun.COM if ((error = socket_getpeername(nso, (struct sockaddr *)addrp,
6448348SEric.Yu@Sun.COM &addrlen, B_TRUE, CRED())) == 0) {
6458348SEric.Yu@Sun.COM error = copyout_name(name, namelen, namelenp,
6468348SEric.Yu@Sun.COM addrp, addrlen);
6478348SEric.Yu@Sun.COM } else {
6488348SEric.Yu@Sun.COM ASSERT(error == EINVAL || error == ENOTCONN);
6498348SEric.Yu@Sun.COM error = ECONNABORTED;
6508348SEric.Yu@Sun.COM }
6518348SEric.Yu@Sun.COM kmem_free(addrp, so->so_max_addr_len);
6528348SEric.Yu@Sun.COM }
6538348SEric.Yu@Sun.COM
6540Sstevel@tonic-gate if (error) {
6550Sstevel@tonic-gate setf(nfd, NULL);
6568348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED());
6578348SEric.Yu@Sun.COM socket_destroy(nso);
65811436SJayakara.Kini@Sun.COM releasef(sock);
6590Sstevel@tonic-gate return (set_errno(error));
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate if (error = falloc(NULL, FWRITE|FREAD, &nfp, NULL)) {
6620Sstevel@tonic-gate setf(nfd, NULL);
6638348SEric.Yu@Sun.COM (void) socket_close(nso, 0, CRED());
6648348SEric.Yu@Sun.COM socket_destroy(nso);
6650Sstevel@tonic-gate eprintsoline(so, error);
66611436SJayakara.Kini@Sun.COM releasef(sock);
6670Sstevel@tonic-gate return (set_errno(error));
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate * fill in the entries that falloc reserved
6710Sstevel@tonic-gate */
6720Sstevel@tonic-gate nfp->f_vnode = nvp;
6730Sstevel@tonic-gate mutex_exit(&nfp->f_tlock);
6740Sstevel@tonic-gate setf(nfd, nfp);
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate * Copy FNDELAY and FNONBLOCK from listener to acceptor
6780Sstevel@tonic-gate */
6790Sstevel@tonic-gate if (so->so_state & (SS_NDELAY|SS_NONBLOCK)) {
6800Sstevel@tonic-gate uint_t oflag = nfp->f_flag;
6810Sstevel@tonic-gate int arg = 0;
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate if (so->so_state & SS_NONBLOCK)
6840Sstevel@tonic-gate arg |= FNONBLOCK;
6850Sstevel@tonic-gate else if (so->so_state & SS_NDELAY)
6860Sstevel@tonic-gate arg |= FNDELAY;
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /*
6890Sstevel@tonic-gate * This code is a simplification of the F_SETFL code in fcntl()
6900Sstevel@tonic-gate * Ignore any errors from VOP_SETFL.
6910Sstevel@tonic-gate */
6925331Samw if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL))
6935331Samw != 0) {
6940Sstevel@tonic-gate eprintsoline(so, error);
6950Sstevel@tonic-gate error = 0;
6960Sstevel@tonic-gate } else {
6970Sstevel@tonic-gate mutex_enter(&nfp->f_tlock);
6980Sstevel@tonic-gate nfp->f_flag &= ~FMASK | (FREAD|FWRITE);
6990Sstevel@tonic-gate nfp->f_flag |= arg;
7000Sstevel@tonic-gate mutex_exit(&nfp->f_tlock);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate }
70311436SJayakara.Kini@Sun.COM releasef(sock);
7040Sstevel@tonic-gate return (nfd);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate int
connect(int sock,struct sockaddr * name,socklen_t namelen,int version)7080Sstevel@tonic-gate connect(int sock, struct sockaddr *name, socklen_t namelen, int version)
7090Sstevel@tonic-gate {
7100Sstevel@tonic-gate struct sonode *so;
7110Sstevel@tonic-gate file_t *fp;
7120Sstevel@tonic-gate int error;
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate dprint(1, ("connect(%d, %p, %d)\n",
7157240Srh87107 sock, (void *)name, namelen));
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
7180Sstevel@tonic-gate return (set_errno(error));
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate /* Allocate and copyin name */
7210Sstevel@tonic-gate if (namelen != 0) {
7220Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
7230Sstevel@tonic-gate name = copyin_name(so, name, &namelen, &error);
7240Sstevel@tonic-gate if (name == NULL) {
7250Sstevel@tonic-gate releasef(sock);
7260Sstevel@tonic-gate return (set_errno(error));
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate } else
7290Sstevel@tonic-gate name = NULL;
7300Sstevel@tonic-gate
7318348SEric.Yu@Sun.COM error = socket_connect(so, name, namelen, fp->f_flag,
7328348SEric.Yu@Sun.COM (version != SOV_XPG4_2) ? 0 : _SOCONNECT_XPG4_2, CRED());
7330Sstevel@tonic-gate releasef(sock);
7340Sstevel@tonic-gate if (name)
7350Sstevel@tonic-gate kmem_free(name, (size_t)namelen);
7360Sstevel@tonic-gate if (error)
7370Sstevel@tonic-gate return (set_errno(error));
7380Sstevel@tonic-gate return (0);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate /*ARGSUSED2*/
7420Sstevel@tonic-gate int
shutdown(int sock,int how,int version)7430Sstevel@tonic-gate shutdown(int sock, int how, int version)
7440Sstevel@tonic-gate {
7450Sstevel@tonic-gate struct sonode *so;
7460Sstevel@tonic-gate int error;
7470Sstevel@tonic-gate
7480Sstevel@tonic-gate dprint(1, ("shutdown(%d, %d)\n",
7495227Stz204579 sock, how));
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
7520Sstevel@tonic-gate return (set_errno(error));
7530Sstevel@tonic-gate
7548348SEric.Yu@Sun.COM error = socket_shutdown(so, how, CRED());
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate releasef(sock);
7570Sstevel@tonic-gate if (error)
7580Sstevel@tonic-gate return (set_errno(error));
7590Sstevel@tonic-gate return (0);
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate * Common receive routine.
7640Sstevel@tonic-gate */
7650Sstevel@tonic-gate static ssize_t
recvit(int sock,struct nmsghdr * msg,struct uio * uiop,int flags,socklen_t * namelenp,socklen_t * controllenp,int * flagsp)7660Sstevel@tonic-gate recvit(int sock,
7670Sstevel@tonic-gate struct nmsghdr *msg,
7680Sstevel@tonic-gate struct uio *uiop,
7690Sstevel@tonic-gate int flags,
7700Sstevel@tonic-gate socklen_t *namelenp,
7710Sstevel@tonic-gate socklen_t *controllenp,
7720Sstevel@tonic-gate int *flagsp)
7730Sstevel@tonic-gate {
7740Sstevel@tonic-gate struct sonode *so;
7750Sstevel@tonic-gate file_t *fp;
7760Sstevel@tonic-gate void *name;
7770Sstevel@tonic-gate socklen_t namelen;
7780Sstevel@tonic-gate void *control;
7790Sstevel@tonic-gate socklen_t controllen;
7800Sstevel@tonic-gate ssize_t len;
7810Sstevel@tonic-gate int error;
7820Sstevel@tonic-gate
7830Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
7840Sstevel@tonic-gate return (set_errno(error));
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate len = uiop->uio_resid;
7870Sstevel@tonic-gate uiop->uio_fmode = fp->f_flag;
7880Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_CACHED;
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate name = msg->msg_name;
7910Sstevel@tonic-gate namelen = msg->msg_namelen;
7920Sstevel@tonic-gate control = msg->msg_control;
7930Sstevel@tonic-gate controllen = msg->msg_controllen;
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
7960Sstevel@tonic-gate MSG_DONTWAIT | MSG_XPG4_2);
7970Sstevel@tonic-gate
7988348SEric.Yu@Sun.COM error = socket_recvmsg(so, msg, uiop, CRED());
7990Sstevel@tonic-gate if (error) {
8000Sstevel@tonic-gate releasef(sock);
8010Sstevel@tonic-gate return (set_errno(error));
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate lwp_stat_update(LWP_STAT_MSGRCV, 1);
8040Sstevel@tonic-gate releasef(sock);
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate error = copyout_name(name, namelen, namelenp,
8070Sstevel@tonic-gate msg->msg_name, msg->msg_namelen);
8080Sstevel@tonic-gate if (error)
8090Sstevel@tonic-gate goto err;
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate if (flagsp != NULL) {
8120Sstevel@tonic-gate /*
8130Sstevel@tonic-gate * Clear internal flag.
8140Sstevel@tonic-gate */
8150Sstevel@tonic-gate msg->msg_flags &= ~MSG_XPG4_2;
8160Sstevel@tonic-gate
8170Sstevel@tonic-gate /*
8180Sstevel@tonic-gate * Determine MSG_CTRUNC. sorecvmsg sets MSG_CTRUNC only
8190Sstevel@tonic-gate * when controllen is zero and there is control data to
8200Sstevel@tonic-gate * copy out.
8210Sstevel@tonic-gate */
8220Sstevel@tonic-gate if (controllen != 0 &&
8230Sstevel@tonic-gate (msg->msg_controllen > controllen || control == NULL)) {
8240Sstevel@tonic-gate dprint(1, ("recvit: CTRUNC %d %d %p\n",
8250Sstevel@tonic-gate msg->msg_controllen, controllen, control));
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate msg->msg_flags |= MSG_CTRUNC;
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate if (copyout(&msg->msg_flags, flagsp,
8300Sstevel@tonic-gate sizeof (msg->msg_flags))) {
8310Sstevel@tonic-gate error = EFAULT;
8320Sstevel@tonic-gate goto err;
8330Sstevel@tonic-gate }
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate /*
8360Sstevel@tonic-gate * Note: This MUST be done last. There can be no "goto err" after this
8370Sstevel@tonic-gate * point since it could make so_closefds run twice on some part
8380Sstevel@tonic-gate * of the file descriptor array.
8390Sstevel@tonic-gate */
8400Sstevel@tonic-gate if (controllen != 0) {
8410Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) {
8420Sstevel@tonic-gate /*
8430Sstevel@tonic-gate * Good old msg_accrights can only return a multiple
8440Sstevel@tonic-gate * of 4 bytes.
8450Sstevel@tonic-gate */
8460Sstevel@tonic-gate controllen &= ~((int)sizeof (uint32_t) - 1);
8470Sstevel@tonic-gate }
8480Sstevel@tonic-gate error = copyout_arg(control, controllen, controllenp,
8490Sstevel@tonic-gate msg->msg_control, msg->msg_controllen);
8500Sstevel@tonic-gate if (error)
8510Sstevel@tonic-gate goto err;
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate if (msg->msg_controllen > controllen || control == NULL) {
8540Sstevel@tonic-gate if (control == NULL)
8550Sstevel@tonic-gate controllen = 0;
8560Sstevel@tonic-gate so_closefds(msg->msg_control, msg->msg_controllen,
8570Sstevel@tonic-gate !(flags & MSG_XPG4_2), controllen);
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate if (msg->msg_namelen != 0)
8610Sstevel@tonic-gate kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
8620Sstevel@tonic-gate if (msg->msg_controllen != 0)
8630Sstevel@tonic-gate kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
8640Sstevel@tonic-gate return (len - uiop->uio_resid);
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate err:
8670Sstevel@tonic-gate /*
8680Sstevel@tonic-gate * If we fail and the control part contains file descriptors
8690Sstevel@tonic-gate * we have to close the fd's.
8700Sstevel@tonic-gate */
8710Sstevel@tonic-gate if (msg->msg_controllen != 0)
8720Sstevel@tonic-gate so_closefds(msg->msg_control, msg->msg_controllen,
8730Sstevel@tonic-gate !(flags & MSG_XPG4_2), 0);
8740Sstevel@tonic-gate if (msg->msg_namelen != 0)
8750Sstevel@tonic-gate kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
8760Sstevel@tonic-gate if (msg->msg_controllen != 0)
8770Sstevel@tonic-gate kmem_free(msg->msg_control, (size_t)msg->msg_controllen);
8780Sstevel@tonic-gate return (set_errno(error));
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate
8810Sstevel@tonic-gate /*
8820Sstevel@tonic-gate * Native system call
8830Sstevel@tonic-gate */
8840Sstevel@tonic-gate ssize_t
recv(int sock,void * buffer,size_t len,int flags)8850Sstevel@tonic-gate recv(int sock, void *buffer, size_t len, int flags)
8860Sstevel@tonic-gate {
8870Sstevel@tonic-gate struct nmsghdr lmsg;
8880Sstevel@tonic-gate struct uio auio;
8890Sstevel@tonic-gate struct iovec aiov[1];
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate dprint(1, ("recv(%d, %p, %ld, %d)\n",
8925227Stz204579 sock, buffer, len, flags));
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate if ((ssize_t)len < 0) {
8950Sstevel@tonic-gate return (set_errno(EINVAL));
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate aiov[0].iov_base = buffer;
8990Sstevel@tonic-gate aiov[0].iov_len = len;
9000Sstevel@tonic-gate auio.uio_loffset = 0;
9010Sstevel@tonic-gate auio.uio_iov = aiov;
9020Sstevel@tonic-gate auio.uio_iovcnt = 1;
9030Sstevel@tonic-gate auio.uio_resid = len;
9040Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
9050Sstevel@tonic-gate auio.uio_limit = 0;
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate lmsg.msg_namelen = 0;
9080Sstevel@tonic-gate lmsg.msg_controllen = 0;
9090Sstevel@tonic-gate lmsg.msg_flags = 0;
9100Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags, NULL, NULL, NULL));
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate ssize_t
recvfrom(int sock,void * buffer,size_t len,int flags,struct sockaddr * name,socklen_t * namelenp)9140Sstevel@tonic-gate recvfrom(int sock, void *buffer, size_t len, int flags,
9150Sstevel@tonic-gate struct sockaddr *name, socklen_t *namelenp)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate struct nmsghdr lmsg;
9180Sstevel@tonic-gate struct uio auio;
9190Sstevel@tonic-gate struct iovec aiov[1];
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate dprint(1, ("recvfrom(%d, %p, %ld, %d, %p, %p)\n",
9227240Srh87107 sock, buffer, len, flags, (void *)name, (void *)namelenp));
9230Sstevel@tonic-gate
9240Sstevel@tonic-gate if ((ssize_t)len < 0) {
9250Sstevel@tonic-gate return (set_errno(EINVAL));
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate aiov[0].iov_base = buffer;
9290Sstevel@tonic-gate aiov[0].iov_len = len;
9300Sstevel@tonic-gate auio.uio_loffset = 0;
9310Sstevel@tonic-gate auio.uio_iov = aiov;
9320Sstevel@tonic-gate auio.uio_iovcnt = 1;
9330Sstevel@tonic-gate auio.uio_resid = len;
9340Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
9350Sstevel@tonic-gate auio.uio_limit = 0;
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate lmsg.msg_name = (char *)name;
9380Sstevel@tonic-gate if (namelenp != NULL) {
9390Sstevel@tonic-gate if (copyin(namelenp, &lmsg.msg_namelen,
9400Sstevel@tonic-gate sizeof (lmsg.msg_namelen)))
9410Sstevel@tonic-gate return (set_errno(EFAULT));
9420Sstevel@tonic-gate } else {
9430Sstevel@tonic-gate lmsg.msg_namelen = 0;
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate lmsg.msg_controllen = 0;
9460Sstevel@tonic-gate lmsg.msg_flags = 0;
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags, namelenp, NULL, NULL));
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate /*
9520Sstevel@tonic-gate * Uses the MSG_XPG4_2 flag to determine if the caller is using
9530Sstevel@tonic-gate * struct omsghdr or struct nmsghdr.
9540Sstevel@tonic-gate */
9550Sstevel@tonic-gate ssize_t
recvmsg(int sock,struct nmsghdr * msg,int flags)9560Sstevel@tonic-gate recvmsg(int sock, struct nmsghdr *msg, int flags)
9570Sstevel@tonic-gate {
9580Sstevel@tonic-gate STRUCT_DECL(nmsghdr, u_lmsg);
9590Sstevel@tonic-gate STRUCT_HANDLE(nmsghdr, umsgptr);
9600Sstevel@tonic-gate struct nmsghdr lmsg;
9610Sstevel@tonic-gate struct uio auio;
9620Sstevel@tonic-gate struct iovec aiov[MSG_MAXIOVLEN];
9630Sstevel@tonic-gate int iovcnt;
9640Sstevel@tonic-gate ssize_t len;
9650Sstevel@tonic-gate int i;
9660Sstevel@tonic-gate int *flagsp;
9670Sstevel@tonic-gate model_t model;
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate dprint(1, ("recvmsg(%d, %p, %d)\n",
9707240Srh87107 sock, (void *)msg, flags));
9710Sstevel@tonic-gate
9720Sstevel@tonic-gate model = get_udatamodel();
9730Sstevel@tonic-gate STRUCT_INIT(u_lmsg, model);
9740Sstevel@tonic-gate STRUCT_SET_HANDLE(umsgptr, model, msg);
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate if (flags & MSG_XPG4_2) {
9770Sstevel@tonic-gate if (copyin(msg, STRUCT_BUF(u_lmsg), STRUCT_SIZE(u_lmsg)))
9780Sstevel@tonic-gate return (set_errno(EFAULT));
9790Sstevel@tonic-gate flagsp = STRUCT_FADDR(umsgptr, msg_flags);
9800Sstevel@tonic-gate } else {
9810Sstevel@tonic-gate /*
9820Sstevel@tonic-gate * Assumes that nmsghdr and omsghdr are identically shaped
9830Sstevel@tonic-gate * except for the added msg_flags field.
9840Sstevel@tonic-gate */
9850Sstevel@tonic-gate if (copyin(msg, STRUCT_BUF(u_lmsg),
9860Sstevel@tonic-gate SIZEOF_STRUCT(omsghdr, model)))
9870Sstevel@tonic-gate return (set_errno(EFAULT));
9880Sstevel@tonic-gate STRUCT_FSET(u_lmsg, msg_flags, 0);
9890Sstevel@tonic-gate flagsp = NULL;
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate /*
9930Sstevel@tonic-gate * Code below us will kmem_alloc memory and hang it
9940Sstevel@tonic-gate * off msg_control and msg_name fields. This forces
9950Sstevel@tonic-gate * us to copy the structure to its native form.
9960Sstevel@tonic-gate */
9970Sstevel@tonic-gate lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
9980Sstevel@tonic-gate lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
9990Sstevel@tonic-gate lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
10000Sstevel@tonic-gate lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
10010Sstevel@tonic-gate lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
10020Sstevel@tonic-gate lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
10030Sstevel@tonic-gate lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate iovcnt = lmsg.msg_iovlen;
10060Sstevel@tonic-gate
10070Sstevel@tonic-gate if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
10080Sstevel@tonic-gate return (set_errno(EMSGSIZE));
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate
10110Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, while ensuring
10140Sstevel@tonic-gate * that they can't move more than 2Gbytes of data in a single call.
10150Sstevel@tonic-gate */
10160Sstevel@tonic-gate if (model == DATAMODEL_ILP32) {
10170Sstevel@tonic-gate struct iovec32 aiov32[MSG_MAXIOVLEN];
10180Sstevel@tonic-gate ssize32_t count32;
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
10210Sstevel@tonic-gate iovcnt * sizeof (struct iovec32)))
10220Sstevel@tonic-gate return (set_errno(EFAULT));
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate count32 = 0;
10250Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
10260Sstevel@tonic-gate ssize32_t iovlen32;
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate iovlen32 = aiov32[i].iov_len;
10290Sstevel@tonic-gate count32 += iovlen32;
10300Sstevel@tonic-gate if (iovlen32 < 0 || count32 < 0)
10310Sstevel@tonic-gate return (set_errno(EINVAL));
10320Sstevel@tonic-gate aiov[i].iov_len = iovlen32;
10330Sstevel@tonic-gate aiov[i].iov_base =
10340Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base;
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate } else
10370Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
10380Sstevel@tonic-gate if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) {
10390Sstevel@tonic-gate return (set_errno(EFAULT));
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate len = 0;
10420Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
10430Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len;
10440Sstevel@tonic-gate len += iovlen;
10450Sstevel@tonic-gate if (iovlen < 0 || len < 0) {
10460Sstevel@tonic-gate return (set_errno(EINVAL));
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate auio.uio_loffset = 0;
10500Sstevel@tonic-gate auio.uio_iov = aiov;
10510Sstevel@tonic-gate auio.uio_iovcnt = iovcnt;
10520Sstevel@tonic-gate auio.uio_resid = len;
10530Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
10540Sstevel@tonic-gate auio.uio_limit = 0;
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate if (lmsg.msg_control != NULL &&
10570Sstevel@tonic-gate (do_useracc == 0 ||
10580Sstevel@tonic-gate useracc(lmsg.msg_control, lmsg.msg_controllen,
10595227Stz204579 B_WRITE) != 0)) {
10600Sstevel@tonic-gate return (set_errno(EFAULT));
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags,
10645227Stz204579 STRUCT_FADDR(umsgptr, msg_namelen),
10655227Stz204579 STRUCT_FADDR(umsgptr, msg_controllen), flagsp));
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate /*
10690Sstevel@tonic-gate * Common send function.
10700Sstevel@tonic-gate */
10710Sstevel@tonic-gate static ssize_t
sendit(int sock,struct nmsghdr * msg,struct uio * uiop,int flags)10720Sstevel@tonic-gate sendit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags)
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate struct sonode *so;
10750Sstevel@tonic-gate file_t *fp;
10760Sstevel@tonic-gate void *name;
10770Sstevel@tonic-gate socklen_t namelen;
10780Sstevel@tonic-gate void *control;
10790Sstevel@tonic-gate socklen_t controllen;
10800Sstevel@tonic-gate ssize_t len;
10810Sstevel@tonic-gate int error;
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
10840Sstevel@tonic-gate return (set_errno(error));
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate uiop->uio_fmode = fp->f_flag;
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate if (so->so_family == AF_UNIX)
10890Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_CACHED;
10900Sstevel@tonic-gate else
10910Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_DEFAULT;
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate /* Allocate and copyin name and control */
10940Sstevel@tonic-gate name = msg->msg_name;
10950Sstevel@tonic-gate namelen = msg->msg_namelen;
10960Sstevel@tonic-gate if (name != NULL && namelen != 0) {
10970Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
10980Sstevel@tonic-gate name = copyin_name(so,
10995227Stz204579 (struct sockaddr *)name,
11005227Stz204579 &namelen, &error);
11010Sstevel@tonic-gate if (name == NULL)
11020Sstevel@tonic-gate goto done3;
11030Sstevel@tonic-gate /* copyin_name null terminates addresses for AF_UNIX */
11040Sstevel@tonic-gate msg->msg_namelen = namelen;
11050Sstevel@tonic-gate msg->msg_name = name;
11060Sstevel@tonic-gate } else {
11070Sstevel@tonic-gate msg->msg_name = name = NULL;
11080Sstevel@tonic-gate msg->msg_namelen = namelen = 0;
11090Sstevel@tonic-gate }
11100Sstevel@tonic-gate
11110Sstevel@tonic-gate control = msg->msg_control;
11120Sstevel@tonic-gate controllen = msg->msg_controllen;
11130Sstevel@tonic-gate if ((control != NULL) && (controllen != 0)) {
11140Sstevel@tonic-gate /*
11150Sstevel@tonic-gate * Verify that the length is not excessive to prevent
11160Sstevel@tonic-gate * an application from consuming all of kernel memory.
11170Sstevel@tonic-gate */
11180Sstevel@tonic-gate if (controllen > SO_MAXARGSIZE) {
11190Sstevel@tonic-gate error = EINVAL;
11200Sstevel@tonic-gate goto done2;
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate control = kmem_alloc(controllen, KM_SLEEP);
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
11250Sstevel@tonic-gate if (copyin(msg->msg_control, control, controllen)) {
11260Sstevel@tonic-gate error = EFAULT;
11270Sstevel@tonic-gate goto done1;
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate msg->msg_control = control;
11300Sstevel@tonic-gate } else {
11310Sstevel@tonic-gate msg->msg_control = control = NULL;
11320Sstevel@tonic-gate msg->msg_controllen = controllen = 0;
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate
11350Sstevel@tonic-gate len = uiop->uio_resid;
11360Sstevel@tonic-gate msg->msg_flags = flags;
11370Sstevel@tonic-gate
11388348SEric.Yu@Sun.COM error = socket_sendmsg(so, msg, uiop, CRED());
11390Sstevel@tonic-gate done1:
11400Sstevel@tonic-gate if (control != NULL)
11410Sstevel@tonic-gate kmem_free(control, controllen);
11420Sstevel@tonic-gate done2:
11430Sstevel@tonic-gate if (name != NULL)
11440Sstevel@tonic-gate kmem_free(name, namelen);
11450Sstevel@tonic-gate done3:
11460Sstevel@tonic-gate if (error != 0) {
11470Sstevel@tonic-gate releasef(sock);
11480Sstevel@tonic-gate return (set_errno(error));
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate lwp_stat_update(LWP_STAT_MSGSND, 1);
11510Sstevel@tonic-gate releasef(sock);
11520Sstevel@tonic-gate return (len - uiop->uio_resid);
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate
11550Sstevel@tonic-gate /*
11560Sstevel@tonic-gate * Native system call
11570Sstevel@tonic-gate */
11580Sstevel@tonic-gate ssize_t
send(int sock,void * buffer,size_t len,int flags)11590Sstevel@tonic-gate send(int sock, void *buffer, size_t len, int flags)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate struct nmsghdr lmsg;
11620Sstevel@tonic-gate struct uio auio;
11630Sstevel@tonic-gate struct iovec aiov[1];
11640Sstevel@tonic-gate
11650Sstevel@tonic-gate dprint(1, ("send(%d, %p, %ld, %d)\n",
11665227Stz204579 sock, buffer, len, flags));
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate if ((ssize_t)len < 0) {
11690Sstevel@tonic-gate return (set_errno(EINVAL));
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate
11720Sstevel@tonic-gate aiov[0].iov_base = buffer;
11730Sstevel@tonic-gate aiov[0].iov_len = len;
11740Sstevel@tonic-gate auio.uio_loffset = 0;
11750Sstevel@tonic-gate auio.uio_iov = aiov;
11760Sstevel@tonic-gate auio.uio_iovcnt = 1;
11770Sstevel@tonic-gate auio.uio_resid = len;
11780Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
11790Sstevel@tonic-gate auio.uio_limit = 0;
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate lmsg.msg_name = NULL;
11820Sstevel@tonic-gate lmsg.msg_control = NULL;
11830Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) {
11840Sstevel@tonic-gate /*
11850Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod
11860Sstevel@tonic-gate * implementation we set EOR for all send* calls.
11870Sstevel@tonic-gate */
11880Sstevel@tonic-gate flags |= MSG_EOR;
11890Sstevel@tonic-gate }
11900Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags));
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /*
11940Sstevel@tonic-gate * Uses the MSG_XPG4_2 flag to determine if the caller is using
11950Sstevel@tonic-gate * struct omsghdr or struct nmsghdr.
11960Sstevel@tonic-gate */
11970Sstevel@tonic-gate ssize_t
sendmsg(int sock,struct nmsghdr * msg,int flags)11980Sstevel@tonic-gate sendmsg(int sock, struct nmsghdr *msg, int flags)
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate struct nmsghdr lmsg;
12010Sstevel@tonic-gate STRUCT_DECL(nmsghdr, u_lmsg);
12020Sstevel@tonic-gate struct uio auio;
12030Sstevel@tonic-gate struct iovec aiov[MSG_MAXIOVLEN];
12040Sstevel@tonic-gate int iovcnt;
12050Sstevel@tonic-gate ssize_t len;
12060Sstevel@tonic-gate int i;
12070Sstevel@tonic-gate model_t model;
12080Sstevel@tonic-gate
12097240Srh87107 dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags));
12100Sstevel@tonic-gate
12110Sstevel@tonic-gate model = get_udatamodel();
12120Sstevel@tonic-gate STRUCT_INIT(u_lmsg, model);
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate if (flags & MSG_XPG4_2) {
12150Sstevel@tonic-gate if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
12160Sstevel@tonic-gate STRUCT_SIZE(u_lmsg)))
12170Sstevel@tonic-gate return (set_errno(EFAULT));
12180Sstevel@tonic-gate } else {
12190Sstevel@tonic-gate /*
12200Sstevel@tonic-gate * Assumes that nmsghdr and omsghdr are identically shaped
12210Sstevel@tonic-gate * except for the added msg_flags field.
12220Sstevel@tonic-gate */
12230Sstevel@tonic-gate if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
12240Sstevel@tonic-gate SIZEOF_STRUCT(omsghdr, model)))
12250Sstevel@tonic-gate return (set_errno(EFAULT));
12260Sstevel@tonic-gate /*
12270Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod
12280Sstevel@tonic-gate * implementation we set EOR for all send* calls.
12290Sstevel@tonic-gate */
12300Sstevel@tonic-gate flags |= MSG_EOR;
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate
12330Sstevel@tonic-gate /*
12340Sstevel@tonic-gate * Code below us will kmem_alloc memory and hang it
12350Sstevel@tonic-gate * off msg_control and msg_name fields. This forces
12360Sstevel@tonic-gate * us to copy the structure to its native form.
12370Sstevel@tonic-gate */
12380Sstevel@tonic-gate lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
12390Sstevel@tonic-gate lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
12400Sstevel@tonic-gate lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
12410Sstevel@tonic-gate lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
12420Sstevel@tonic-gate lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
12430Sstevel@tonic-gate lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
12440Sstevel@tonic-gate lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate iovcnt = lmsg.msg_iovlen;
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
12490Sstevel@tonic-gate /*
12500Sstevel@tonic-gate * Unless this is XPG 4.2 we allow iovcnt == 0 to
12510Sstevel@tonic-gate * be compatible with SunOS 4.X and 4.4BSD.
12520Sstevel@tonic-gate */
12530Sstevel@tonic-gate if (iovcnt != 0 || (flags & MSG_XPG4_2))
12540Sstevel@tonic-gate return (set_errno(EMSGSIZE));
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
12580Sstevel@tonic-gate /*
12590Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, while ensuring
12600Sstevel@tonic-gate * that they can't move more than 2Gbytes of data in a single call.
12610Sstevel@tonic-gate */
12620Sstevel@tonic-gate if (model == DATAMODEL_ILP32) {
12630Sstevel@tonic-gate struct iovec32 aiov32[MSG_MAXIOVLEN];
12640Sstevel@tonic-gate ssize32_t count32;
12650Sstevel@tonic-gate
12660Sstevel@tonic-gate if (iovcnt != 0 &&
12670Sstevel@tonic-gate copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
12680Sstevel@tonic-gate iovcnt * sizeof (struct iovec32)))
12690Sstevel@tonic-gate return (set_errno(EFAULT));
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate count32 = 0;
12720Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
12730Sstevel@tonic-gate ssize32_t iovlen32;
12740Sstevel@tonic-gate
12750Sstevel@tonic-gate iovlen32 = aiov32[i].iov_len;
12760Sstevel@tonic-gate count32 += iovlen32;
12770Sstevel@tonic-gate if (iovlen32 < 0 || count32 < 0)
12780Sstevel@tonic-gate return (set_errno(EINVAL));
12790Sstevel@tonic-gate aiov[i].iov_len = iovlen32;
12800Sstevel@tonic-gate aiov[i].iov_base =
12810Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base;
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate } else
12840Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
12850Sstevel@tonic-gate if (iovcnt != 0 &&
12860Sstevel@tonic-gate copyin(lmsg.msg_iov, aiov,
12870Sstevel@tonic-gate (unsigned)iovcnt * sizeof (struct iovec))) {
12880Sstevel@tonic-gate return (set_errno(EFAULT));
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate len = 0;
12910Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
12920Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len;
12930Sstevel@tonic-gate len += iovlen;
12940Sstevel@tonic-gate if (iovlen < 0 || len < 0) {
12950Sstevel@tonic-gate return (set_errno(EINVAL));
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate auio.uio_loffset = 0;
12990Sstevel@tonic-gate auio.uio_iov = aiov;
13000Sstevel@tonic-gate auio.uio_iovcnt = iovcnt;
13010Sstevel@tonic-gate auio.uio_resid = len;
13020Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
13030Sstevel@tonic-gate auio.uio_limit = 0;
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags));
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate ssize_t
sendto(int sock,void * buffer,size_t len,int flags,struct sockaddr * name,socklen_t namelen)13090Sstevel@tonic-gate sendto(int sock, void *buffer, size_t len, int flags,
13100Sstevel@tonic-gate struct sockaddr *name, socklen_t namelen)
13110Sstevel@tonic-gate {
13120Sstevel@tonic-gate struct nmsghdr lmsg;
13130Sstevel@tonic-gate struct uio auio;
13140Sstevel@tonic-gate struct iovec aiov[1];
13150Sstevel@tonic-gate
13160Sstevel@tonic-gate dprint(1, ("sendto(%d, %p, %ld, %d, %p, %d)\n",
13177240Srh87107 sock, buffer, len, flags, (void *)name, namelen));
13180Sstevel@tonic-gate
13190Sstevel@tonic-gate if ((ssize_t)len < 0) {
13200Sstevel@tonic-gate return (set_errno(EINVAL));
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate aiov[0].iov_base = buffer;
13240Sstevel@tonic-gate aiov[0].iov_len = len;
13250Sstevel@tonic-gate auio.uio_loffset = 0;
13260Sstevel@tonic-gate auio.uio_iov = aiov;
13270Sstevel@tonic-gate auio.uio_iovcnt = 1;
13280Sstevel@tonic-gate auio.uio_resid = len;
13290Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
13300Sstevel@tonic-gate auio.uio_limit = 0;
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate lmsg.msg_name = (char *)name;
13330Sstevel@tonic-gate lmsg.msg_namelen = namelen;
13340Sstevel@tonic-gate lmsg.msg_control = NULL;
13350Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) {
13360Sstevel@tonic-gate /*
13370Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod
13380Sstevel@tonic-gate * implementation we set EOR for all send* calls.
13390Sstevel@tonic-gate */
13400Sstevel@tonic-gate flags |= MSG_EOR;
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags));
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate
13450Sstevel@tonic-gate /*ARGSUSED3*/
13460Sstevel@tonic-gate int
getpeername(int sock,struct sockaddr * name,socklen_t * namelenp,int version)13470Sstevel@tonic-gate getpeername(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
13480Sstevel@tonic-gate {
13490Sstevel@tonic-gate struct sonode *so;
13500Sstevel@tonic-gate int error;
13510Sstevel@tonic-gate socklen_t namelen;
13528348SEric.Yu@Sun.COM socklen_t sock_addrlen;
13538348SEric.Yu@Sun.COM struct sockaddr *sock_addrp;
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate dprint(1, ("getpeername(%d, %p, %p)\n",
13567240Srh87107 sock, (void *)name, (void *)namelenp));
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
13590Sstevel@tonic-gate goto bad;
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
13620Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen)) ||
13630Sstevel@tonic-gate (name == NULL && namelen != 0)) {
13640Sstevel@tonic-gate error = EFAULT;
13650Sstevel@tonic-gate goto rel_out;
13660Sstevel@tonic-gate }
13678348SEric.Yu@Sun.COM sock_addrlen = so->so_max_addr_len;
13688348SEric.Yu@Sun.COM sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
13690Sstevel@tonic-gate
13708348SEric.Yu@Sun.COM if ((error = socket_getpeername(so, sock_addrp, &sock_addrlen,
13718348SEric.Yu@Sun.COM B_FALSE, CRED())) == 0) {
13728348SEric.Yu@Sun.COM ASSERT(sock_addrlen <= so->so_max_addr_len);
13738348SEric.Yu@Sun.COM error = copyout_name(name, namelen, namelenp,
13748348SEric.Yu@Sun.COM (void *)sock_addrp, sock_addrlen);
13750Sstevel@tonic-gate }
13768348SEric.Yu@Sun.COM kmem_free(sock_addrp, so->so_max_addr_len);
13770Sstevel@tonic-gate rel_out:
13780Sstevel@tonic-gate releasef(sock);
13790Sstevel@tonic-gate bad: return (error != 0 ? set_errno(error) : 0);
13800Sstevel@tonic-gate }
13810Sstevel@tonic-gate
13820Sstevel@tonic-gate /*ARGSUSED3*/
13830Sstevel@tonic-gate int
getsockname(int sock,struct sockaddr * name,socklen_t * namelenp,int version)13840Sstevel@tonic-gate getsockname(int sock, struct sockaddr *name,
13850Sstevel@tonic-gate socklen_t *namelenp, int version)
13860Sstevel@tonic-gate {
13870Sstevel@tonic-gate struct sonode *so;
13880Sstevel@tonic-gate int error;
13898348SEric.Yu@Sun.COM socklen_t namelen, sock_addrlen;
13908348SEric.Yu@Sun.COM struct sockaddr *sock_addrp;
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate dprint(1, ("getsockname(%d, %p, %p)\n",
13937240Srh87107 sock, (void *)name, (void *)namelenp));
13940Sstevel@tonic-gate
13950Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
13960Sstevel@tonic-gate goto bad;
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
13990Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen)) ||
14000Sstevel@tonic-gate (name == NULL && namelen != 0)) {
14010Sstevel@tonic-gate error = EFAULT;
14020Sstevel@tonic-gate goto rel_out;
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate
14058348SEric.Yu@Sun.COM sock_addrlen = so->so_max_addr_len;
14068348SEric.Yu@Sun.COM sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
14078348SEric.Yu@Sun.COM if ((error = socket_getsockname(so, sock_addrp, &sock_addrlen,
14088348SEric.Yu@Sun.COM CRED())) == 0) {
14098348SEric.Yu@Sun.COM ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14108348SEric.Yu@Sun.COM ASSERT(sock_addrlen <= so->so_max_addr_len);
14118348SEric.Yu@Sun.COM error = copyout_name(name, namelen, namelenp,
14128348SEric.Yu@Sun.COM (void *)sock_addrp, sock_addrlen);
14130Sstevel@tonic-gate }
14148348SEric.Yu@Sun.COM kmem_free(sock_addrp, so->so_max_addr_len);
14150Sstevel@tonic-gate rel_out:
14160Sstevel@tonic-gate releasef(sock);
14170Sstevel@tonic-gate bad: return (error != 0 ? set_errno(error) : 0);
14180Sstevel@tonic-gate }
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate /*ARGSUSED5*/
14210Sstevel@tonic-gate int
getsockopt(int sock,int level,int option_name,void * option_value,socklen_t * option_lenp,int version)14220Sstevel@tonic-gate getsockopt(int sock,
14230Sstevel@tonic-gate int level,
14240Sstevel@tonic-gate int option_name,
14250Sstevel@tonic-gate void *option_value,
14260Sstevel@tonic-gate socklen_t *option_lenp,
14270Sstevel@tonic-gate int version)
14280Sstevel@tonic-gate {
14290Sstevel@tonic-gate struct sonode *so;
14300Sstevel@tonic-gate socklen_t optlen, optlen_res;
14310Sstevel@tonic-gate void *optval;
14320Sstevel@tonic-gate int error;
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate dprint(1, ("getsockopt(%d, %d, %d, %p, %p)\n",
14357240Srh87107 sock, level, option_name, option_value, (void *)option_lenp));
14360Sstevel@tonic-gate
14370Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
14380Sstevel@tonic-gate return (set_errno(error));
14390Sstevel@tonic-gate
14400Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
14410Sstevel@tonic-gate if (copyin(option_lenp, &optlen, sizeof (optlen))) {
14420Sstevel@tonic-gate releasef(sock);
14430Sstevel@tonic-gate return (set_errno(EFAULT));
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate /*
14460Sstevel@tonic-gate * Verify that the length is not excessive to prevent
14470Sstevel@tonic-gate * an application from consuming all of kernel memory.
14480Sstevel@tonic-gate */
14490Sstevel@tonic-gate if (optlen > SO_MAXARGSIZE) {
14500Sstevel@tonic-gate error = EINVAL;
14510Sstevel@tonic-gate releasef(sock);
14520Sstevel@tonic-gate return (set_errno(error));
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate optval = kmem_alloc(optlen, KM_SLEEP);
14550Sstevel@tonic-gate optlen_res = optlen;
14568348SEric.Yu@Sun.COM error = socket_getsockopt(so, level, option_name, optval,
14578348SEric.Yu@Sun.COM &optlen_res, (version != SOV_XPG4_2) ? 0 : _SOGETSOCKOPT_XPG4_2,
14588348SEric.Yu@Sun.COM CRED());
14590Sstevel@tonic-gate releasef(sock);
14600Sstevel@tonic-gate if (error) {
14610Sstevel@tonic-gate kmem_free(optval, optlen);
14620Sstevel@tonic-gate return (set_errno(error));
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate error = copyout_arg(option_value, optlen, option_lenp,
14650Sstevel@tonic-gate optval, optlen_res);
14660Sstevel@tonic-gate kmem_free(optval, optlen);
14670Sstevel@tonic-gate if (error)
14680Sstevel@tonic-gate return (set_errno(error));
14690Sstevel@tonic-gate return (0);
14700Sstevel@tonic-gate }
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate /*ARGSUSED5*/
14730Sstevel@tonic-gate int
setsockopt(int sock,int level,int option_name,void * option_value,socklen_t option_len,int version)14740Sstevel@tonic-gate setsockopt(int sock,
14750Sstevel@tonic-gate int level,
14760Sstevel@tonic-gate int option_name,
14770Sstevel@tonic-gate void *option_value,
14780Sstevel@tonic-gate socklen_t option_len,
14790Sstevel@tonic-gate int version)
14800Sstevel@tonic-gate {
14810Sstevel@tonic-gate struct sonode *so;
14820Sstevel@tonic-gate intptr_t buffer[2];
14830Sstevel@tonic-gate void *optval = NULL;
14840Sstevel@tonic-gate int error;
14850Sstevel@tonic-gate
14860Sstevel@tonic-gate dprint(1, ("setsockopt(%d, %d, %d, %p, %d)\n",
14875227Stz204579 sock, level, option_name, option_value, option_len));
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
14900Sstevel@tonic-gate return (set_errno(error));
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate if (option_value != NULL) {
14930Sstevel@tonic-gate if (option_len != 0) {
14940Sstevel@tonic-gate /*
14950Sstevel@tonic-gate * Verify that the length is not excessive to prevent
14960Sstevel@tonic-gate * an application from consuming all of kernel memory.
14970Sstevel@tonic-gate */
14980Sstevel@tonic-gate if (option_len > SO_MAXARGSIZE) {
14990Sstevel@tonic-gate error = EINVAL;
15000Sstevel@tonic-gate goto done2;
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate optval = option_len <= sizeof (buffer) ?
15030Sstevel@tonic-gate &buffer : kmem_alloc((size_t)option_len, KM_SLEEP);
15040Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15050Sstevel@tonic-gate if (copyin(option_value, optval, (size_t)option_len)) {
15060Sstevel@tonic-gate error = EFAULT;
15070Sstevel@tonic-gate goto done1;
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate }
15100Sstevel@tonic-gate } else
15110Sstevel@tonic-gate option_len = 0;
15120Sstevel@tonic-gate
15138348SEric.Yu@Sun.COM error = socket_setsockopt(so, level, option_name, optval,
15148348SEric.Yu@Sun.COM (t_uscalar_t)option_len, CRED());
15150Sstevel@tonic-gate done1:
15160Sstevel@tonic-gate if (optval != buffer)
15170Sstevel@tonic-gate kmem_free(optval, (size_t)option_len);
15180Sstevel@tonic-gate done2:
15190Sstevel@tonic-gate releasef(sock);
15200Sstevel@tonic-gate if (error)
15210Sstevel@tonic-gate return (set_errno(error));
15220Sstevel@tonic-gate return (0);
15230Sstevel@tonic-gate }
15240Sstevel@tonic-gate
152512643SAnders.Persson@Sun.COM static int
sockconf_add_sock(int family,int type,int protocol,char * name)152612643SAnders.Persson@Sun.COM sockconf_add_sock(int family, int type, int protocol, char *name)
152712643SAnders.Persson@Sun.COM {
152812643SAnders.Persson@Sun.COM int error = 0;
152912643SAnders.Persson@Sun.COM char *kdevpath = NULL;
153012643SAnders.Persson@Sun.COM char *kmodule = NULL;
153112643SAnders.Persson@Sun.COM char *buf = NULL;
153212643SAnders.Persson@Sun.COM size_t pathlen = 0;
153312643SAnders.Persson@Sun.COM struct sockparams *sp;
153412643SAnders.Persson@Sun.COM
153512643SAnders.Persson@Sun.COM if (name == NULL)
153612643SAnders.Persson@Sun.COM return (EINVAL);
153712643SAnders.Persson@Sun.COM /*
153812643SAnders.Persson@Sun.COM * Copyin the name.
153912643SAnders.Persson@Sun.COM * This also makes it possible to check for too long pathnames.
154012643SAnders.Persson@Sun.COM * Compress the space needed for the name before passing it
154112643SAnders.Persson@Sun.COM * to soconfig - soconfig will store the string until
154212643SAnders.Persson@Sun.COM * the configuration is removed.
154312643SAnders.Persson@Sun.COM */
154412643SAnders.Persson@Sun.COM buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
154512643SAnders.Persson@Sun.COM if ((error = copyinstr(name, buf, MAXPATHLEN, &pathlen)) != 0) {
154612643SAnders.Persson@Sun.COM kmem_free(buf, MAXPATHLEN);
154712643SAnders.Persson@Sun.COM return (error);
154812643SAnders.Persson@Sun.COM }
154912643SAnders.Persson@Sun.COM if (strncmp(buf, "/dev", strlen("/dev")) == 0) {
155012643SAnders.Persson@Sun.COM /* For device */
155112643SAnders.Persson@Sun.COM
155212643SAnders.Persson@Sun.COM /*
155312643SAnders.Persson@Sun.COM * Special handling for NCA:
155412643SAnders.Persson@Sun.COM *
155512643SAnders.Persson@Sun.COM * DEV_NCA is never opened even if an application
155612643SAnders.Persson@Sun.COM * requests for AF_NCA. The device opened is instead a
155712643SAnders.Persson@Sun.COM * predefined AF_INET transport (NCA_INET_DEV).
155812643SAnders.Persson@Sun.COM *
155912643SAnders.Persson@Sun.COM * Prior to Volo (PSARC/2007/587) NCA would determine
156012643SAnders.Persson@Sun.COM * the device using a lookup, which worked then because
156112643SAnders.Persson@Sun.COM * all protocols were based on TPI. Since TPI is no
156212643SAnders.Persson@Sun.COM * longer the default, we have to explicitly state
156312643SAnders.Persson@Sun.COM * which device to use.
156412643SAnders.Persson@Sun.COM */
156512643SAnders.Persson@Sun.COM if (strcmp(buf, NCA_DEV) == 0) {
156612643SAnders.Persson@Sun.COM /* only support entry <28, 2, 0> */
156712643SAnders.Persson@Sun.COM if (family != AF_NCA || type != SOCK_STREAM ||
156812643SAnders.Persson@Sun.COM protocol != 0) {
156912643SAnders.Persson@Sun.COM kmem_free(buf, MAXPATHLEN);
157012643SAnders.Persson@Sun.COM return (EINVAL);
157112643SAnders.Persson@Sun.COM }
157212643SAnders.Persson@Sun.COM
157312643SAnders.Persson@Sun.COM pathlen = strlen(NCA_INET_DEV) + 1;
157412643SAnders.Persson@Sun.COM kdevpath = kmem_alloc(pathlen, KM_SLEEP);
157512643SAnders.Persson@Sun.COM bcopy(NCA_INET_DEV, kdevpath, pathlen);
157612643SAnders.Persson@Sun.COM kdevpath[pathlen - 1] = '\0';
157712643SAnders.Persson@Sun.COM } else {
157812643SAnders.Persson@Sun.COM kdevpath = kmem_alloc(pathlen, KM_SLEEP);
157912643SAnders.Persson@Sun.COM bcopy(buf, kdevpath, pathlen);
158012643SAnders.Persson@Sun.COM kdevpath[pathlen - 1] = '\0';
158112643SAnders.Persson@Sun.COM }
158212643SAnders.Persson@Sun.COM } else {
158312643SAnders.Persson@Sun.COM /* For socket module */
158412643SAnders.Persson@Sun.COM kmodule = kmem_alloc(pathlen, KM_SLEEP);
158512643SAnders.Persson@Sun.COM bcopy(buf, kmodule, pathlen);
158612643SAnders.Persson@Sun.COM kmodule[pathlen - 1] = '\0';
158712643SAnders.Persson@Sun.COM pathlen = 0;
158812643SAnders.Persson@Sun.COM }
158912643SAnders.Persson@Sun.COM kmem_free(buf, MAXPATHLEN);
159012643SAnders.Persson@Sun.COM
159112643SAnders.Persson@Sun.COM /* sockparams_create frees mod name and devpath upon failure */
159212643SAnders.Persson@Sun.COM sp = sockparams_create(family, type, protocol, kmodule,
159312643SAnders.Persson@Sun.COM kdevpath, pathlen, 0, KM_SLEEP, &error);
159412643SAnders.Persson@Sun.COM if (sp != NULL) {
159512643SAnders.Persson@Sun.COM error = sockparams_add(sp);
159612643SAnders.Persson@Sun.COM if (error != 0)
159712643SAnders.Persson@Sun.COM sockparams_destroy(sp);
159812643SAnders.Persson@Sun.COM }
159912643SAnders.Persson@Sun.COM
160012643SAnders.Persson@Sun.COM return (error);
160112643SAnders.Persson@Sun.COM }
160212643SAnders.Persson@Sun.COM
160312643SAnders.Persson@Sun.COM static int
sockconf_remove_sock(int family,int type,int protocol)160412643SAnders.Persson@Sun.COM sockconf_remove_sock(int family, int type, int protocol)
160512643SAnders.Persson@Sun.COM {
160612643SAnders.Persson@Sun.COM return (sockparams_delete(family, type, protocol));
160712643SAnders.Persson@Sun.COM }
160812643SAnders.Persson@Sun.COM
160912643SAnders.Persson@Sun.COM static int
sockconfig_remove_filter(const char * uname)161012643SAnders.Persson@Sun.COM sockconfig_remove_filter(const char *uname)
161112643SAnders.Persson@Sun.COM {
161212643SAnders.Persson@Sun.COM char kname[SOF_MAXNAMELEN];
161312643SAnders.Persson@Sun.COM size_t len;
161412643SAnders.Persson@Sun.COM int error;
161512643SAnders.Persson@Sun.COM sof_entry_t *ent;
161612643SAnders.Persson@Sun.COM
161712643SAnders.Persson@Sun.COM if ((error = copyinstr(uname, kname, SOF_MAXNAMELEN, &len)) != 0)
161812643SAnders.Persson@Sun.COM return (error);
161912643SAnders.Persson@Sun.COM
162012643SAnders.Persson@Sun.COM ent = sof_entry_remove_by_name(kname);
162112643SAnders.Persson@Sun.COM if (ent == NULL)
162212643SAnders.Persson@Sun.COM return (ENXIO);
162312643SAnders.Persson@Sun.COM
162412643SAnders.Persson@Sun.COM mutex_enter(&ent->sofe_lock);
162512643SAnders.Persson@Sun.COM ASSERT(!(ent->sofe_flags & SOFEF_CONDEMED));
162612643SAnders.Persson@Sun.COM if (ent->sofe_refcnt == 0) {
162712643SAnders.Persson@Sun.COM mutex_exit(&ent->sofe_lock);
162812643SAnders.Persson@Sun.COM sof_entry_free(ent);
162912643SAnders.Persson@Sun.COM } else {
163012643SAnders.Persson@Sun.COM /* let the last socket free the filter */
163112643SAnders.Persson@Sun.COM ent->sofe_flags |= SOFEF_CONDEMED;
163212643SAnders.Persson@Sun.COM mutex_exit(&ent->sofe_lock);
163312643SAnders.Persson@Sun.COM }
163412643SAnders.Persson@Sun.COM
163512643SAnders.Persson@Sun.COM return (0);
163612643SAnders.Persson@Sun.COM }
163712643SAnders.Persson@Sun.COM
163812643SAnders.Persson@Sun.COM static int
sockconfig_add_filter(const char * uname,void * ufilpropp)163912643SAnders.Persson@Sun.COM sockconfig_add_filter(const char *uname, void *ufilpropp)
164012643SAnders.Persson@Sun.COM {
164112643SAnders.Persson@Sun.COM struct sockconfig_filter_props filprop;
164212643SAnders.Persson@Sun.COM sof_entry_t *ent;
164312643SAnders.Persson@Sun.COM int error;
164412643SAnders.Persson@Sun.COM size_t tuplesz, len;
164512643SAnders.Persson@Sun.COM char hintbuf[SOF_MAXNAMELEN];
164612643SAnders.Persson@Sun.COM
164712643SAnders.Persson@Sun.COM ent = kmem_zalloc(sizeof (sof_entry_t), KM_SLEEP);
164812643SAnders.Persson@Sun.COM mutex_init(&ent->sofe_lock, NULL, MUTEX_DEFAULT, NULL);
164912643SAnders.Persson@Sun.COM
165012643SAnders.Persson@Sun.COM if ((error = copyinstr(uname, ent->sofe_name, SOF_MAXNAMELEN,
165112643SAnders.Persson@Sun.COM &len)) != 0) {
165212643SAnders.Persson@Sun.COM sof_entry_free(ent);
165312643SAnders.Persson@Sun.COM return (error);
165412643SAnders.Persson@Sun.COM }
165512643SAnders.Persson@Sun.COM
165612643SAnders.Persson@Sun.COM if (get_udatamodel() == DATAMODEL_NATIVE) {
165712643SAnders.Persson@Sun.COM if (copyin(ufilpropp, &filprop, sizeof (filprop)) != 0) {
165812643SAnders.Persson@Sun.COM sof_entry_free(ent);
165912643SAnders.Persson@Sun.COM return (EFAULT);
166012643SAnders.Persson@Sun.COM }
166112643SAnders.Persson@Sun.COM }
166212643SAnders.Persson@Sun.COM #ifdef _SYSCALL32_IMPL
166312643SAnders.Persson@Sun.COM else {
166412643SAnders.Persson@Sun.COM struct sockconfig_filter_props32 filprop32;
166512643SAnders.Persson@Sun.COM
166612643SAnders.Persson@Sun.COM if (copyin(ufilpropp, &filprop32, sizeof (filprop32)) != 0) {
166712643SAnders.Persson@Sun.COM sof_entry_free(ent);
166812643SAnders.Persson@Sun.COM return (EFAULT);
166912643SAnders.Persson@Sun.COM }
167012643SAnders.Persson@Sun.COM filprop.sfp_modname = (char *)(uintptr_t)filprop32.sfp_modname;
167112643SAnders.Persson@Sun.COM filprop.sfp_autoattach = filprop32.sfp_autoattach;
167212643SAnders.Persson@Sun.COM filprop.sfp_hint = filprop32.sfp_hint;
167312643SAnders.Persson@Sun.COM filprop.sfp_hintarg = (char *)(uintptr_t)filprop32.sfp_hintarg;
167412643SAnders.Persson@Sun.COM filprop.sfp_socktuple_cnt = filprop32.sfp_socktuple_cnt;
167512643SAnders.Persson@Sun.COM filprop.sfp_socktuple =
167612643SAnders.Persson@Sun.COM (sof_socktuple_t *)(uintptr_t)filprop32.sfp_socktuple;
167712643SAnders.Persson@Sun.COM }
167812643SAnders.Persson@Sun.COM #endif /* _SYSCALL32_IMPL */
167912643SAnders.Persson@Sun.COM
168012643SAnders.Persson@Sun.COM if ((error = copyinstr(filprop.sfp_modname, ent->sofe_modname,
168112643SAnders.Persson@Sun.COM sizeof (ent->sofe_modname), &len)) != 0) {
168212643SAnders.Persson@Sun.COM sof_entry_free(ent);
168312643SAnders.Persson@Sun.COM return (error);
168412643SAnders.Persson@Sun.COM }
168512643SAnders.Persson@Sun.COM
168612643SAnders.Persson@Sun.COM /*
168712643SAnders.Persson@Sun.COM * A filter must specify at least one socket tuple.
168812643SAnders.Persson@Sun.COM */
168912643SAnders.Persson@Sun.COM if (filprop.sfp_socktuple_cnt == 0 ||
169012643SAnders.Persson@Sun.COM filprop.sfp_socktuple_cnt > SOF_MAXSOCKTUPLECNT) {
169112643SAnders.Persson@Sun.COM sof_entry_free(ent);
169212643SAnders.Persson@Sun.COM return (EINVAL);
169312643SAnders.Persson@Sun.COM }
169412643SAnders.Persson@Sun.COM ent->sofe_flags = filprop.sfp_autoattach ? SOFEF_AUTO : SOFEF_PROG;
169512643SAnders.Persson@Sun.COM ent->sofe_hint = filprop.sfp_hint;
169612643SAnders.Persson@Sun.COM
169712643SAnders.Persson@Sun.COM /*
169812643SAnders.Persson@Sun.COM * Verify the hint, and copy in the hint argument, if necessary.
169912643SAnders.Persson@Sun.COM */
170012643SAnders.Persson@Sun.COM switch (ent->sofe_hint) {
170112643SAnders.Persson@Sun.COM case SOF_HINT_BEFORE:
170212643SAnders.Persson@Sun.COM case SOF_HINT_AFTER:
170312643SAnders.Persson@Sun.COM if ((error = copyinstr(filprop.sfp_hintarg, hintbuf,
170412643SAnders.Persson@Sun.COM sizeof (hintbuf), &len)) != 0) {
170512643SAnders.Persson@Sun.COM sof_entry_free(ent);
170612643SAnders.Persson@Sun.COM return (error);
170712643SAnders.Persson@Sun.COM }
170812643SAnders.Persson@Sun.COM ent->sofe_hintarg = kmem_alloc(len, KM_SLEEP);
170912643SAnders.Persson@Sun.COM bcopy(hintbuf, ent->sofe_hintarg, len);
171012643SAnders.Persson@Sun.COM /* FALLTHRU */
171112643SAnders.Persson@Sun.COM case SOF_HINT_TOP:
171212643SAnders.Persson@Sun.COM case SOF_HINT_BOTTOM:
171312643SAnders.Persson@Sun.COM /* hints cannot be used with programmatic filters */
171412643SAnders.Persson@Sun.COM if (ent->sofe_flags & SOFEF_PROG) {
171512643SAnders.Persson@Sun.COM sof_entry_free(ent);
171612643SAnders.Persson@Sun.COM return (EINVAL);
171712643SAnders.Persson@Sun.COM }
171812643SAnders.Persson@Sun.COM break;
171912643SAnders.Persson@Sun.COM case SOF_HINT_NONE:
172012643SAnders.Persson@Sun.COM break;
172112643SAnders.Persson@Sun.COM default:
172212643SAnders.Persson@Sun.COM /* bad hint value */
172312643SAnders.Persson@Sun.COM sof_entry_free(ent);
172412643SAnders.Persson@Sun.COM return (EINVAL);
172512643SAnders.Persson@Sun.COM }
172612643SAnders.Persson@Sun.COM
172712643SAnders.Persson@Sun.COM ent->sofe_socktuple_cnt = filprop.sfp_socktuple_cnt;
172812643SAnders.Persson@Sun.COM tuplesz = sizeof (sof_socktuple_t) * ent->sofe_socktuple_cnt;
172912643SAnders.Persson@Sun.COM ent->sofe_socktuple = kmem_alloc(tuplesz, KM_SLEEP);
173012643SAnders.Persson@Sun.COM
173112643SAnders.Persson@Sun.COM if (get_udatamodel() == DATAMODEL_NATIVE) {
173212643SAnders.Persson@Sun.COM if (copyin(filprop.sfp_socktuple, ent->sofe_socktuple,
173312643SAnders.Persson@Sun.COM tuplesz)) {
173412643SAnders.Persson@Sun.COM sof_entry_free(ent);
173512643SAnders.Persson@Sun.COM return (EFAULT);
173612643SAnders.Persson@Sun.COM }
173712643SAnders.Persson@Sun.COM }
173812643SAnders.Persson@Sun.COM #ifdef _SYSCALL32_IMPL
173912643SAnders.Persson@Sun.COM else {
174012643SAnders.Persson@Sun.COM int i;
174112643SAnders.Persson@Sun.COM caddr_t data = (caddr_t)filprop.sfp_socktuple;
174212643SAnders.Persson@Sun.COM sof_socktuple_t *tup = ent->sofe_socktuple;
174312643SAnders.Persson@Sun.COM sof_socktuple32_t tup32;
174412643SAnders.Persson@Sun.COM
174512643SAnders.Persson@Sun.COM tup = ent->sofe_socktuple;
174612643SAnders.Persson@Sun.COM for (i = 0; i < ent->sofe_socktuple_cnt; i++, tup++) {
174712643SAnders.Persson@Sun.COM ASSERT(tup < ent->sofe_socktuple + tuplesz);
174812643SAnders.Persson@Sun.COM
174912643SAnders.Persson@Sun.COM if (copyin(data, &tup32, sizeof (tup32)) != 0) {
175012643SAnders.Persson@Sun.COM sof_entry_free(ent);
175112643SAnders.Persson@Sun.COM return (EFAULT);
175212643SAnders.Persson@Sun.COM }
175312643SAnders.Persson@Sun.COM tup->sofst_family = tup32.sofst_family;
175412643SAnders.Persson@Sun.COM tup->sofst_type = tup32.sofst_type;
175512643SAnders.Persson@Sun.COM tup->sofst_protocol = tup32.sofst_protocol;
175612643SAnders.Persson@Sun.COM
175712643SAnders.Persson@Sun.COM data += sizeof (tup32);
175812643SAnders.Persson@Sun.COM }
175912643SAnders.Persson@Sun.COM }
176012643SAnders.Persson@Sun.COM #endif /* _SYSCALL32_IMPL */
176112643SAnders.Persson@Sun.COM
176212643SAnders.Persson@Sun.COM /* Sockets can start using the filter as soon as the filter is added */
176312643SAnders.Persson@Sun.COM if ((error = sof_entry_add(ent)) != 0)
176412643SAnders.Persson@Sun.COM sof_entry_free(ent);
176512643SAnders.Persson@Sun.COM
176612643SAnders.Persson@Sun.COM return (error);
176712643SAnders.Persson@Sun.COM }
176812643SAnders.Persson@Sun.COM
17690Sstevel@tonic-gate /*
177012643SAnders.Persson@Sun.COM * Socket configuration system call. It is used to add and remove
177112643SAnders.Persson@Sun.COM * socket types.
17720Sstevel@tonic-gate */
17730Sstevel@tonic-gate int
sockconfig(int cmd,void * arg1,void * arg2,void * arg3,void * arg4)177412643SAnders.Persson@Sun.COM sockconfig(int cmd, void *arg1, void *arg2, void *arg3, void *arg4)
17750Sstevel@tonic-gate {
17760Sstevel@tonic-gate int error = 0;
17770Sstevel@tonic-gate
17780Sstevel@tonic-gate if (secpolicy_net_config(CRED(), B_FALSE) != 0)
17790Sstevel@tonic-gate return (set_errno(EPERM));
17800Sstevel@tonic-gate
178112643SAnders.Persson@Sun.COM if (sockfs_defer_nl7c_init) {
178212643SAnders.Persson@Sun.COM nl7c_init();
178312643SAnders.Persson@Sun.COM sockfs_defer_nl7c_init = 0;
178412643SAnders.Persson@Sun.COM }
17858348SEric.Yu@Sun.COM
178612643SAnders.Persson@Sun.COM switch (cmd) {
178712643SAnders.Persson@Sun.COM case SOCKCONFIG_ADD_SOCK:
178812643SAnders.Persson@Sun.COM error = sockconf_add_sock((int)(uintptr_t)arg1,
178912643SAnders.Persson@Sun.COM (int)(uintptr_t)arg2, (int)(uintptr_t)arg3, arg4);
179012643SAnders.Persson@Sun.COM break;
179112643SAnders.Persson@Sun.COM case SOCKCONFIG_REMOVE_SOCK:
179212643SAnders.Persson@Sun.COM error = sockconf_remove_sock((int)(uintptr_t)arg1,
179312643SAnders.Persson@Sun.COM (int)(uintptr_t)arg2, (int)(uintptr_t)arg3);
179412643SAnders.Persson@Sun.COM break;
179512643SAnders.Persson@Sun.COM case SOCKCONFIG_ADD_FILTER:
179612643SAnders.Persson@Sun.COM error = sockconfig_add_filter((const char *)arg1, arg2);
179712643SAnders.Persson@Sun.COM break;
179812643SAnders.Persson@Sun.COM case SOCKCONFIG_REMOVE_FILTER:
179912643SAnders.Persson@Sun.COM error = sockconfig_remove_filter((const char *)arg1);
180012643SAnders.Persson@Sun.COM break;
180112643SAnders.Persson@Sun.COM default:
180212643SAnders.Persson@Sun.COM #ifdef DEBUG
180312643SAnders.Persson@Sun.COM cmn_err(CE_NOTE, "sockconfig: unkonwn subcommand %d", cmd);
180412643SAnders.Persson@Sun.COM #endif
180512643SAnders.Persson@Sun.COM error = EINVAL;
180612643SAnders.Persson@Sun.COM break;
180712643SAnders.Persson@Sun.COM }
18080Sstevel@tonic-gate
180912643SAnders.Persson@Sun.COM if (error != 0) {
18100Sstevel@tonic-gate eprintline(error);
18110Sstevel@tonic-gate return (set_errno(error));
18120Sstevel@tonic-gate }
18130Sstevel@tonic-gate return (0);
18140Sstevel@tonic-gate }
18150Sstevel@tonic-gate
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate /*
18180Sstevel@tonic-gate * Sendfile is implemented through two schemes, direct I/O or by
18190Sstevel@tonic-gate * caching in the filesystem page cache. We cache the input file by
18200Sstevel@tonic-gate * default and use direct I/O only if sendfile_max_size is set
18210Sstevel@tonic-gate * appropriately as explained below. Note that this logic is consistent
18220Sstevel@tonic-gate * with other filesystems where caching is turned on by default
18230Sstevel@tonic-gate * unless explicitly turned off by using the DIRECTIO ioctl.
18240Sstevel@tonic-gate *
18250Sstevel@tonic-gate * We choose a slightly different scheme here. One can turn off
18260Sstevel@tonic-gate * caching by setting sendfile_max_size to 0. One can also enable
18270Sstevel@tonic-gate * caching of files <= sendfile_max_size by setting sendfile_max_size
18280Sstevel@tonic-gate * to an appropriate value. By default sendfile_max_size is set to the
18290Sstevel@tonic-gate * maximum value so that all files are cached. In future, we may provide
18300Sstevel@tonic-gate * better interfaces for caching the file.
18310Sstevel@tonic-gate *
18320Sstevel@tonic-gate * Sendfile through Direct I/O (Zero copy)
18330Sstevel@tonic-gate * --------------------------------------
18340Sstevel@tonic-gate *
18350Sstevel@tonic-gate * As disks are normally slower than the network, we can't have a
18360Sstevel@tonic-gate * single thread that reads the disk and writes to the network. We
18370Sstevel@tonic-gate * need to have parallelism. This is done by having the sendfile
18380Sstevel@tonic-gate * thread create another thread that reads from the filesystem
18390Sstevel@tonic-gate * and queues it for network processing. In this scheme, the data
18400Sstevel@tonic-gate * is never copied anywhere i.e it is zero copy unlike the other
18410Sstevel@tonic-gate * scheme.
18420Sstevel@tonic-gate *
18430Sstevel@tonic-gate * We have a sendfile queue (snfq) where each sendfile
18440Sstevel@tonic-gate * request (snf_req_t) is queued for processing by a thread. Number
18450Sstevel@tonic-gate * of threads is dynamically allocated and they exit if they are idling
18460Sstevel@tonic-gate * beyond a specified amount of time. When each request (snf_req_t) is
18470Sstevel@tonic-gate * processed by a thread, it produces a number of mblk_t structures to
18480Sstevel@tonic-gate * be consumed by the sendfile thread. snf_deque and snf_enque are
18490Sstevel@tonic-gate * used for consuming and producing mblks. Size of the filesystem
18505331Samw * read is determined by the tunable (sendfile_read_size). A single
18510Sstevel@tonic-gate * mblk holds sendfile_read_size worth of data (except the last
18520Sstevel@tonic-gate * read of the file) which is sent down as a whole to the network.
18530Sstevel@tonic-gate * sendfile_read_size is set to 1 MB as this seems to be the optimal
18540Sstevel@tonic-gate * value for the UFS filesystem backed by a striped storage array.
18550Sstevel@tonic-gate *
18560Sstevel@tonic-gate * Synchronisation between read (producer) and write (consumer) threads.
18570Sstevel@tonic-gate * --------------------------------------------------------------------
18580Sstevel@tonic-gate *
18590Sstevel@tonic-gate * sr_lock protects sr_ib_head and sr_ib_tail. The lock is held while
18600Sstevel@tonic-gate * adding and deleting items in this list. Error can happen anytime
18610Sstevel@tonic-gate * during read or write. There could be unprocessed mblks in the
18620Sstevel@tonic-gate * sr_ib_XXX list when a read or write error occurs. Whenever error
18630Sstevel@tonic-gate * is encountered, we need two things to happen :
18640Sstevel@tonic-gate *
18650Sstevel@tonic-gate * a) One of the threads need to clean the mblks.
18660Sstevel@tonic-gate * b) When one thread encounters an error, the other should stop.
18670Sstevel@tonic-gate *
18685331Samw * For (a), we don't want to penalize the reader thread as it could do
18690Sstevel@tonic-gate * some useful work processing other requests. For (b), the error can
18700Sstevel@tonic-gate * be detected by examining sr_read_error or sr_write_error.
18710Sstevel@tonic-gate * sr_lock protects sr_read_error and sr_write_error. If both reader and
18720Sstevel@tonic-gate * writer encounters error, we need to report the write error back to
18730Sstevel@tonic-gate * the application as that's what would have happened if the operations
18740Sstevel@tonic-gate * were done sequentially. With this in mind, following should work :
18750Sstevel@tonic-gate *
18760Sstevel@tonic-gate * - Check for errors before read or write.
18770Sstevel@tonic-gate * - If the reader encounters error, set the error in sr_read_error.
18780Sstevel@tonic-gate * Check sr_write_error, if it is set, send cv_signal as it is
18790Sstevel@tonic-gate * waiting for reader to complete. If it is not set, the writer
18800Sstevel@tonic-gate * is either running sinking data to the network or blocked
18810Sstevel@tonic-gate * because of flow control. For handling the latter case, we
18820Sstevel@tonic-gate * always send a signal. In any case, it will examine sr_read_error
18830Sstevel@tonic-gate * and return. sr_read_error is marked with SR_READ_DONE to tell
18840Sstevel@tonic-gate * the writer that the reader is done in all the cases.
18850Sstevel@tonic-gate * - If the writer encounters error, set the error in sr_write_error.
18860Sstevel@tonic-gate * The reader thread is either blocked because of flow control or
18870Sstevel@tonic-gate * running reading data from the disk. For the former, we need to
18880Sstevel@tonic-gate * wakeup the thread. Again to keep it simple, we always wake up
18890Sstevel@tonic-gate * the reader thread. Then, wait for the read thread to complete
18900Sstevel@tonic-gate * if it is not done yet. Cleanup and return.
18910Sstevel@tonic-gate *
18920Sstevel@tonic-gate * High and low water marks for the read thread.
18930Sstevel@tonic-gate * --------------------------------------------
18940Sstevel@tonic-gate *
18950Sstevel@tonic-gate * If sendfile() is used to send data over a slow network, we need to
18960Sstevel@tonic-gate * make sure that the read thread does not produce data at a faster
18970Sstevel@tonic-gate * rate than the network. This can happen if the disk is faster than
18980Sstevel@tonic-gate * the network. In such a case, we don't want to build a very large queue.
18990Sstevel@tonic-gate * But we would still like to get all of the network throughput possible.
19000Sstevel@tonic-gate * This implies that network should never block waiting for data.
19010Sstevel@tonic-gate * As there are lot of disk throughput/network throughput combinations
19020Sstevel@tonic-gate * possible, it is difficult to come up with an accurate number.
19030Sstevel@tonic-gate * A typical 10K RPM disk has a max seek latency 17ms and rotational
19040Sstevel@tonic-gate * latency of 3ms for reading a disk block. Thus, the total latency to
19050Sstevel@tonic-gate * initiate a new read, transfer data from the disk and queue for
19060Sstevel@tonic-gate * transmission would take about a max of 25ms. Todays max transfer rate
19070Sstevel@tonic-gate * for network is 100MB/sec. If the thread is blocked because of flow
19080Sstevel@tonic-gate * control, it would take 25ms to get new data ready for transmission.
19090Sstevel@tonic-gate * We have to make sure that network is not idling, while we are initiating
19100Sstevel@tonic-gate * new transfers. So, at 100MB/sec, to keep network busy we would need
19115331Samw * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data.
19120Sstevel@tonic-gate * We need to pick a high water mark so that the woken up thread would
19130Sstevel@tonic-gate * do considerable work before blocking again to prevent thrashing. Currently,
19140Sstevel@tonic-gate * we pick this to be 10 times that of the low water mark.
19150Sstevel@tonic-gate *
19160Sstevel@tonic-gate * Sendfile with segmap caching (One copy from page cache to mblks).
19170Sstevel@tonic-gate * ----------------------------------------------------------------
19180Sstevel@tonic-gate *
19190Sstevel@tonic-gate * We use the segmap cache for caching the file, if the size of file
19200Sstevel@tonic-gate * is <= sendfile_max_size. In this case we don't use threads as VM
19210Sstevel@tonic-gate * is reasonably fast enough to keep up with the network. If the underlying
19220Sstevel@tonic-gate * transport allows, we call segmap_getmapflt() to map MAXBSIZE (8K) worth
19230Sstevel@tonic-gate * of data into segmap space, and use the virtual address from segmap
19240Sstevel@tonic-gate * directly through desballoc() to avoid copy. Once the transport is done
19250Sstevel@tonic-gate * with the data, the mapping will be released through segmap_release()
19260Sstevel@tonic-gate * called by the call-back routine.
19270Sstevel@tonic-gate *
19280Sstevel@tonic-gate * If zero-copy is not allowed by the transport, we simply call VOP_READ()
19290Sstevel@tonic-gate * to copy the data from the filesystem into our temporary network buffer.
19300Sstevel@tonic-gate *
19310Sstevel@tonic-gate * To disable caching, set sendfile_max_size to 0.
19320Sstevel@tonic-gate */
19330Sstevel@tonic-gate
19340Sstevel@tonic-gate uint_t sendfile_read_size = 1024 * 1024;
19350Sstevel@tonic-gate #define SENDFILE_REQ_LOWAT 3 * 1024 * 1024
19360Sstevel@tonic-gate uint_t sendfile_req_lowat = SENDFILE_REQ_LOWAT;
19370Sstevel@tonic-gate uint_t sendfile_req_hiwat = 10 * SENDFILE_REQ_LOWAT;
19380Sstevel@tonic-gate struct sendfile_stats sf_stats;
19390Sstevel@tonic-gate struct sendfile_queue *snfq;
19400Sstevel@tonic-gate clock_t snfq_timeout;
19410Sstevel@tonic-gate off64_t sendfile_max_size;
19420Sstevel@tonic-gate
19430Sstevel@tonic-gate static void snf_enque(snf_req_t *, mblk_t *);
19440Sstevel@tonic-gate static mblk_t *snf_deque(snf_req_t *);
19450Sstevel@tonic-gate
19460Sstevel@tonic-gate void
sendfile_init(void)19470Sstevel@tonic-gate sendfile_init(void)
19480Sstevel@tonic-gate {
19490Sstevel@tonic-gate snfq = kmem_zalloc(sizeof (struct sendfile_queue), KM_SLEEP);
19500Sstevel@tonic-gate
19510Sstevel@tonic-gate mutex_init(&snfq->snfq_lock, NULL, MUTEX_DEFAULT, NULL);
19520Sstevel@tonic-gate cv_init(&snfq->snfq_cv, NULL, CV_DEFAULT, NULL);
19530Sstevel@tonic-gate snfq->snfq_max_threads = max_ncpus;
19540Sstevel@tonic-gate snfq_timeout = SNFQ_TIMEOUT;
19550Sstevel@tonic-gate /* Cache all files by default. */
19560Sstevel@tonic-gate sendfile_max_size = MAXOFFSET_T;
19570Sstevel@tonic-gate }
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate /*
19600Sstevel@tonic-gate * Queues a mblk_t for network processing.
19610Sstevel@tonic-gate */
19620Sstevel@tonic-gate static void
snf_enque(snf_req_t * sr,mblk_t * mp)19630Sstevel@tonic-gate snf_enque(snf_req_t *sr, mblk_t *mp)
19640Sstevel@tonic-gate {
19650Sstevel@tonic-gate mp->b_next = NULL;
19660Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
19670Sstevel@tonic-gate if (sr->sr_mp_head == NULL) {
19680Sstevel@tonic-gate sr->sr_mp_head = sr->sr_mp_tail = mp;
19690Sstevel@tonic-gate cv_signal(&sr->sr_cv);
19700Sstevel@tonic-gate } else {
19710Sstevel@tonic-gate sr->sr_mp_tail->b_next = mp;
19720Sstevel@tonic-gate sr->sr_mp_tail = mp;
19730Sstevel@tonic-gate }
19740Sstevel@tonic-gate sr->sr_qlen += MBLKL(mp);
19750Sstevel@tonic-gate while ((sr->sr_qlen > sr->sr_hiwat) &&
19760Sstevel@tonic-gate (sr->sr_write_error == 0)) {
19770Sstevel@tonic-gate sf_stats.ss_full_waits++;
19780Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock);
19790Sstevel@tonic-gate }
19800Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
19810Sstevel@tonic-gate }
19820Sstevel@tonic-gate
19830Sstevel@tonic-gate /*
19840Sstevel@tonic-gate * De-queues a mblk_t for network processing.
19850Sstevel@tonic-gate */
19860Sstevel@tonic-gate static mblk_t *
snf_deque(snf_req_t * sr)19870Sstevel@tonic-gate snf_deque(snf_req_t *sr)
19880Sstevel@tonic-gate {
19890Sstevel@tonic-gate mblk_t *mp;
19900Sstevel@tonic-gate
19910Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
19920Sstevel@tonic-gate /*
19930Sstevel@tonic-gate * If we have encountered an error on read or read is
19940Sstevel@tonic-gate * completed and no more mblks, return NULL.
19950Sstevel@tonic-gate * We need to check for NULL sr_mp_head also as
19960Sstevel@tonic-gate * the reads could have completed and there is
19970Sstevel@tonic-gate * nothing more to come.
19980Sstevel@tonic-gate */
19990Sstevel@tonic-gate if (((sr->sr_read_error & ~SR_READ_DONE) != 0) ||
20000Sstevel@tonic-gate ((sr->sr_read_error & SR_READ_DONE) &&
20010Sstevel@tonic-gate sr->sr_mp_head == NULL)) {
20020Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
20030Sstevel@tonic-gate return (NULL);
20040Sstevel@tonic-gate }
20050Sstevel@tonic-gate /*
20060Sstevel@tonic-gate * To start with neither SR_READ_DONE is marked nor
20070Sstevel@tonic-gate * the error is set. When we wake up from cv_wait,
20080Sstevel@tonic-gate * following are the possibilities :
20090Sstevel@tonic-gate *
20100Sstevel@tonic-gate * a) sr_read_error is zero and mblks are queued.
20110Sstevel@tonic-gate * b) sr_read_error is set to SR_READ_DONE
20120Sstevel@tonic-gate * and mblks are queued.
20130Sstevel@tonic-gate * c) sr_read_error is set to SR_READ_DONE
20140Sstevel@tonic-gate * and no mblks.
20150Sstevel@tonic-gate * d) sr_read_error is set to some error other
20160Sstevel@tonic-gate * than SR_READ_DONE.
20170Sstevel@tonic-gate */
20180Sstevel@tonic-gate
20190Sstevel@tonic-gate while ((sr->sr_read_error == 0) && (sr->sr_mp_head == NULL)) {
20200Sstevel@tonic-gate sf_stats.ss_empty_waits++;
20210Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock);
20220Sstevel@tonic-gate }
20230Sstevel@tonic-gate /* Handle (a) and (b) first - the normal case. */
20240Sstevel@tonic-gate if (((sr->sr_read_error & ~SR_READ_DONE) == 0) &&
20250Sstevel@tonic-gate (sr->sr_mp_head != NULL)) {
20260Sstevel@tonic-gate mp = sr->sr_mp_head;
20270Sstevel@tonic-gate sr->sr_mp_head = mp->b_next;
20280Sstevel@tonic-gate sr->sr_qlen -= MBLKL(mp);
20290Sstevel@tonic-gate if (sr->sr_qlen < sr->sr_lowat)
20300Sstevel@tonic-gate cv_signal(&sr->sr_cv);
20310Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
20320Sstevel@tonic-gate mp->b_next = NULL;
20330Sstevel@tonic-gate return (mp);
20340Sstevel@tonic-gate }
20350Sstevel@tonic-gate /* Handle (c) and (d). */
20360Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
20370Sstevel@tonic-gate return (NULL);
20380Sstevel@tonic-gate }
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate /*
20410Sstevel@tonic-gate * Reads data from the filesystem and queues it for network processing.
20420Sstevel@tonic-gate */
20430Sstevel@tonic-gate void
snf_async_read(snf_req_t * sr)20440Sstevel@tonic-gate snf_async_read(snf_req_t *sr)
20450Sstevel@tonic-gate {
20460Sstevel@tonic-gate size_t iosize;
20470Sstevel@tonic-gate u_offset_t fileoff;
20480Sstevel@tonic-gate u_offset_t size;
20490Sstevel@tonic-gate int ret_size;
20500Sstevel@tonic-gate int error;
20510Sstevel@tonic-gate file_t *fp;
20520Sstevel@tonic-gate mblk_t *mp;
20536240Skrishna struct vnode *vp;
20546240Skrishna int extra = 0;
20558171SPrakash.Jalan@Sun.COM int maxblk = 0;
20568171SPrakash.Jalan@Sun.COM int wroff = 0;
20578171SPrakash.Jalan@Sun.COM struct sonode *so;
20580Sstevel@tonic-gate
20590Sstevel@tonic-gate fp = sr->sr_fp;
20600Sstevel@tonic-gate size = sr->sr_file_size;
20610Sstevel@tonic-gate fileoff = sr->sr_file_off;
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate /*
20640Sstevel@tonic-gate * Ignore the error for filesystems that doesn't support DIRECTIO.
20650Sstevel@tonic-gate */
20660Sstevel@tonic-gate (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0,
20675331Samw kcred, NULL, NULL);
20680Sstevel@tonic-gate
20698171SPrakash.Jalan@Sun.COM vp = sr->sr_vp;
20706240Skrishna if (vp->v_type == VSOCK) {
20716240Skrishna stdata_t *stp;
20726240Skrishna
20736240Skrishna /*
20746240Skrishna * Get the extra space to insert a header and a trailer.
20756240Skrishna */
20768171SPrakash.Jalan@Sun.COM so = VTOSO(vp);
20776240Skrishna stp = vp->v_stream;
20788348SEric.Yu@Sun.COM if (stp == NULL) {
20798348SEric.Yu@Sun.COM wroff = so->so_proto_props.sopp_wroff;
20808348SEric.Yu@Sun.COM maxblk = so->so_proto_props.sopp_maxblk;
20818348SEric.Yu@Sun.COM extra = wroff + so->so_proto_props.sopp_tail;
20828348SEric.Yu@Sun.COM } else {
20838348SEric.Yu@Sun.COM wroff = (int)(stp->sd_wroff);
20848348SEric.Yu@Sun.COM maxblk = (int)(stp->sd_maxblk);
20858348SEric.Yu@Sun.COM extra = wroff + (int)(stp->sd_tail);
20868348SEric.Yu@Sun.COM }
20876240Skrishna }
20886240Skrishna
20890Sstevel@tonic-gate while ((size != 0) && (sr->sr_write_error == 0)) {
20900Sstevel@tonic-gate
20910Sstevel@tonic-gate iosize = (int)MIN(sr->sr_maxpsz, size);
20920Sstevel@tonic-gate
20938171SPrakash.Jalan@Sun.COM /*
209412643SAnders.Persson@Sun.COM * Socket filters can limit the mblk size,
209512643SAnders.Persson@Sun.COM * so limit reads to maxblk if there are
209612643SAnders.Persson@Sun.COM * filters present.
20978171SPrakash.Jalan@Sun.COM */
209812643SAnders.Persson@Sun.COM if (vp->v_type == VSOCK &&
2099*12644SAnders.Persson@Sun.COM so->so_filter_active > 0 && maxblk != INFPSZ)
21008171SPrakash.Jalan@Sun.COM iosize = (int)MIN(iosize, maxblk);
21018171SPrakash.Jalan@Sun.COM
21028778SErik.Nordmark@Sun.COM if (is_system_labeled()) {
21038778SErik.Nordmark@Sun.COM mp = allocb_cred(iosize + extra, CRED(),
21048778SErik.Nordmark@Sun.COM curproc->p_pid);
21058778SErik.Nordmark@Sun.COM } else {
21068778SErik.Nordmark@Sun.COM mp = allocb(iosize + extra, BPRI_MED);
21078778SErik.Nordmark@Sun.COM }
21088778SErik.Nordmark@Sun.COM if (mp == NULL) {
21090Sstevel@tonic-gate error = EAGAIN;
21100Sstevel@tonic-gate break;
21110Sstevel@tonic-gate }
21128171SPrakash.Jalan@Sun.COM
21138171SPrakash.Jalan@Sun.COM mp->b_rptr += wroff;
21148171SPrakash.Jalan@Sun.COM
21150Sstevel@tonic-gate ret_size = soreadfile(fp, mp->b_rptr, fileoff, &error, iosize);
21160Sstevel@tonic-gate
21170Sstevel@tonic-gate /* Error or Reached EOF ? */
21180Sstevel@tonic-gate if ((error != 0) || (ret_size == 0)) {
21190Sstevel@tonic-gate freeb(mp);
21200Sstevel@tonic-gate break;
21210Sstevel@tonic-gate }
21220Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + ret_size;
21230Sstevel@tonic-gate
21240Sstevel@tonic-gate snf_enque(sr, mp);
21250Sstevel@tonic-gate size -= ret_size;
21260Sstevel@tonic-gate fileoff += ret_size;
21270Sstevel@tonic-gate }
21280Sstevel@tonic-gate (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0,
21295331Samw kcred, NULL, NULL);
21300Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
21310Sstevel@tonic-gate sr->sr_read_error = error;
21320Sstevel@tonic-gate sr->sr_read_error |= SR_READ_DONE;
21330Sstevel@tonic-gate cv_signal(&sr->sr_cv);
21340Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
21350Sstevel@tonic-gate }
21360Sstevel@tonic-gate
21370Sstevel@tonic-gate void
snf_async_thread(void)21380Sstevel@tonic-gate snf_async_thread(void)
21390Sstevel@tonic-gate {
21400Sstevel@tonic-gate snf_req_t *sr;
21410Sstevel@tonic-gate callb_cpr_t cprinfo;
21420Sstevel@tonic-gate clock_t time_left = 1;
21430Sstevel@tonic-gate
21440Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &snfq->snfq_lock, callb_generic_cpr, "snfq");
21450Sstevel@tonic-gate
21460Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock);
21470Sstevel@tonic-gate for (;;) {
21480Sstevel@tonic-gate /*
21490Sstevel@tonic-gate * If we didn't find a entry, then block until woken up
21500Sstevel@tonic-gate * again and then look through the queues again.
21510Sstevel@tonic-gate */
21520Sstevel@tonic-gate while ((sr = snfq->snfq_req_head) == NULL) {
21530Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo);
21540Sstevel@tonic-gate if (time_left <= 0) {
21550Sstevel@tonic-gate snfq->snfq_svc_threads--;
21560Sstevel@tonic-gate CALLB_CPR_EXIT(&cprinfo);
21570Sstevel@tonic-gate thread_exit();
21580Sstevel@tonic-gate /* NOTREACHED */
21590Sstevel@tonic-gate }
21600Sstevel@tonic-gate snfq->snfq_idle_cnt++;
21610Sstevel@tonic-gate
216211066Srafael.vanoni@sun.com time_left = cv_reltimedwait(&snfq->snfq_cv,
216311066Srafael.vanoni@sun.com &snfq->snfq_lock, snfq_timeout, TR_CLOCK_TICK);
21640Sstevel@tonic-gate snfq->snfq_idle_cnt--;
21650Sstevel@tonic-gate
21660Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &snfq->snfq_lock);
21670Sstevel@tonic-gate }
21680Sstevel@tonic-gate snfq->snfq_req_head = sr->sr_next;
21690Sstevel@tonic-gate snfq->snfq_req_cnt--;
21700Sstevel@tonic-gate mutex_exit(&snfq->snfq_lock);
21710Sstevel@tonic-gate snf_async_read(sr);
21720Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock);
21730Sstevel@tonic-gate }
21740Sstevel@tonic-gate }
21750Sstevel@tonic-gate
21760Sstevel@tonic-gate
21770Sstevel@tonic-gate snf_req_t *
create_thread(int operation,struct vnode * vp,file_t * fp,u_offset_t fileoff,u_offset_t size)21780Sstevel@tonic-gate create_thread(int operation, struct vnode *vp, file_t *fp,
21790Sstevel@tonic-gate u_offset_t fileoff, u_offset_t size)
21800Sstevel@tonic-gate {
21810Sstevel@tonic-gate snf_req_t *sr;
21820Sstevel@tonic-gate stdata_t *stp;
21830Sstevel@tonic-gate
21840Sstevel@tonic-gate sr = (snf_req_t *)kmem_zalloc(sizeof (snf_req_t), KM_SLEEP);
21850Sstevel@tonic-gate
21860Sstevel@tonic-gate sr->sr_vp = vp;
21870Sstevel@tonic-gate sr->sr_fp = fp;
21880Sstevel@tonic-gate stp = vp->v_stream;
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate /*
21910Sstevel@tonic-gate * store sd_qn_maxpsz into sr_maxpsz while we have stream head.
21920Sstevel@tonic-gate * stream might be closed before thread returns from snf_async_read.
21930Sstevel@tonic-gate */
21948348SEric.Yu@Sun.COM if (stp != NULL && stp->sd_qn_maxpsz > 0) {
21950Sstevel@tonic-gate sr->sr_maxpsz = MIN(MAXBSIZE, stp->sd_qn_maxpsz);
21960Sstevel@tonic-gate } else {
21970Sstevel@tonic-gate sr->sr_maxpsz = MAXBSIZE;
21980Sstevel@tonic-gate }
21990Sstevel@tonic-gate
22000Sstevel@tonic-gate sr->sr_operation = operation;
22010Sstevel@tonic-gate sr->sr_file_off = fileoff;
22020Sstevel@tonic-gate sr->sr_file_size = size;
22030Sstevel@tonic-gate sr->sr_hiwat = sendfile_req_hiwat;
22040Sstevel@tonic-gate sr->sr_lowat = sendfile_req_lowat;
22050Sstevel@tonic-gate mutex_init(&sr->sr_lock, NULL, MUTEX_DEFAULT, NULL);
22060Sstevel@tonic-gate cv_init(&sr->sr_cv, NULL, CV_DEFAULT, NULL);
22070Sstevel@tonic-gate /*
22080Sstevel@tonic-gate * See whether we need another thread for servicing this
22090Sstevel@tonic-gate * request. If there are already enough requests queued
22100Sstevel@tonic-gate * for the threads, create one if not exceeding
22110Sstevel@tonic-gate * snfq_max_threads.
22120Sstevel@tonic-gate */
22130Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock);
22140Sstevel@tonic-gate if (snfq->snfq_req_cnt >= snfq->snfq_idle_cnt &&
22150Sstevel@tonic-gate snfq->snfq_svc_threads < snfq->snfq_max_threads) {
22160Sstevel@tonic-gate (void) thread_create(NULL, 0, &snf_async_thread, 0, 0, &p0,
22170Sstevel@tonic-gate TS_RUN, minclsyspri);
22180Sstevel@tonic-gate snfq->snfq_svc_threads++;
22190Sstevel@tonic-gate }
22200Sstevel@tonic-gate if (snfq->snfq_req_head == NULL) {
22210Sstevel@tonic-gate snfq->snfq_req_head = snfq->snfq_req_tail = sr;
22220Sstevel@tonic-gate cv_signal(&snfq->snfq_cv);
22230Sstevel@tonic-gate } else {
22240Sstevel@tonic-gate snfq->snfq_req_tail->sr_next = sr;
22250Sstevel@tonic-gate snfq->snfq_req_tail = sr;
22260Sstevel@tonic-gate }
22270Sstevel@tonic-gate snfq->snfq_req_cnt++;
22280Sstevel@tonic-gate mutex_exit(&snfq->snfq_lock);
22290Sstevel@tonic-gate return (sr);
22300Sstevel@tonic-gate }
22310Sstevel@tonic-gate
22320Sstevel@tonic-gate int
snf_direct_io(file_t * fp,file_t * rfp,u_offset_t fileoff,u_offset_t size,ssize_t * count)22330Sstevel@tonic-gate snf_direct_io(file_t *fp, file_t *rfp, u_offset_t fileoff, u_offset_t size,
22340Sstevel@tonic-gate ssize_t *count)
22350Sstevel@tonic-gate {
22360Sstevel@tonic-gate snf_req_t *sr;
22370Sstevel@tonic-gate mblk_t *mp;
22380Sstevel@tonic-gate int iosize;
22390Sstevel@tonic-gate int error = 0;
22400Sstevel@tonic-gate short fflag;
22410Sstevel@tonic-gate struct vnode *vp;
22420Sstevel@tonic-gate int ksize;
22438348SEric.Yu@Sun.COM struct nmsghdr msg;
22440Sstevel@tonic-gate
22450Sstevel@tonic-gate ksize = 0;
22460Sstevel@tonic-gate *count = 0;
22478348SEric.Yu@Sun.COM bzero(&msg, sizeof (msg));
22480Sstevel@tonic-gate
22490Sstevel@tonic-gate vp = fp->f_vnode;
22500Sstevel@tonic-gate fflag = fp->f_flag;
22510Sstevel@tonic-gate if ((sr = create_thread(READ_OP, vp, rfp, fileoff, size)) == NULL)
22520Sstevel@tonic-gate return (EAGAIN);
22530Sstevel@tonic-gate
22540Sstevel@tonic-gate /*
22550Sstevel@tonic-gate * We check for read error in snf_deque. It has to check
22560Sstevel@tonic-gate * for successful READ_DONE and return NULL, and we might
22570Sstevel@tonic-gate * as well make an additional check there.
22580Sstevel@tonic-gate */
22590Sstevel@tonic-gate while ((mp = snf_deque(sr)) != NULL) {
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) {
22620Sstevel@tonic-gate freeb(mp);
22630Sstevel@tonic-gate error = EINTR;
22640Sstevel@tonic-gate break;
22650Sstevel@tonic-gate }
22660Sstevel@tonic-gate iosize = MBLKL(mp);
22670Sstevel@tonic-gate
22688348SEric.Yu@Sun.COM error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
22698348SEric.Yu@Sun.COM
22708348SEric.Yu@Sun.COM if (error != 0) {
22718348SEric.Yu@Sun.COM if (mp != NULL)
22728348SEric.Yu@Sun.COM freeb(mp);
22730Sstevel@tonic-gate break;
22740Sstevel@tonic-gate }
22750Sstevel@tonic-gate ksize += iosize;
22760Sstevel@tonic-gate }
22770Sstevel@tonic-gate *count = ksize;
22780Sstevel@tonic-gate
22790Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
22800Sstevel@tonic-gate sr->sr_write_error = error;
22810Sstevel@tonic-gate /* Look at the big comments on why we cv_signal here. */
22820Sstevel@tonic-gate cv_signal(&sr->sr_cv);
22830Sstevel@tonic-gate
22840Sstevel@tonic-gate /* Wait for the reader to complete always. */
22850Sstevel@tonic-gate while (!(sr->sr_read_error & SR_READ_DONE)) {
22860Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock);
22870Sstevel@tonic-gate }
22880Sstevel@tonic-gate /* If there is no write error, check for read error. */
22890Sstevel@tonic-gate if (error == 0)
22900Sstevel@tonic-gate error = (sr->sr_read_error & ~SR_READ_DONE);
22910Sstevel@tonic-gate
22920Sstevel@tonic-gate if (error != 0) {
22930Sstevel@tonic-gate mblk_t *next_mp;
22940Sstevel@tonic-gate
22950Sstevel@tonic-gate mp = sr->sr_mp_head;
22960Sstevel@tonic-gate while (mp != NULL) {
22970Sstevel@tonic-gate next_mp = mp->b_next;
22980Sstevel@tonic-gate mp->b_next = NULL;
22990Sstevel@tonic-gate freeb(mp);
23000Sstevel@tonic-gate mp = next_mp;
23010Sstevel@tonic-gate }
23020Sstevel@tonic-gate }
23030Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
23040Sstevel@tonic-gate kmem_free(sr, sizeof (snf_req_t));
23050Sstevel@tonic-gate return (error);
23060Sstevel@tonic-gate }
23070Sstevel@tonic-gate
23089344SVasumathi.Sundaram@Sun.COM /* Maximum no.of pages allocated by vpm for sendfile at a time */
23099301SVasumathi.Sundaram@Sun.COM #define SNF_VPMMAXPGS (VPMMAXPGS/2)
23109344SVasumathi.Sundaram@Sun.COM
23119344SVasumathi.Sundaram@Sun.COM /*
23129344SVasumathi.Sundaram@Sun.COM * Maximum no.of elements in the list returned by vpm, including
23139344SVasumathi.Sundaram@Sun.COM * NULL for the last entry
23149344SVasumathi.Sundaram@Sun.COM */
23159301SVasumathi.Sundaram@Sun.COM #define SNF_MAXVMAPS (SNF_VPMMAXPGS + 1)
23169301SVasumathi.Sundaram@Sun.COM
23179301SVasumathi.Sundaram@Sun.COM typedef struct {
23189344SVasumathi.Sundaram@Sun.COM unsigned int snfv_ref;
23199344SVasumathi.Sundaram@Sun.COM frtn_t snfv_frtn;
23209344SVasumathi.Sundaram@Sun.COM vnode_t *snfv_vp;
23219344SVasumathi.Sundaram@Sun.COM struct vmap snfv_vml[SNF_MAXVMAPS];
23229301SVasumathi.Sundaram@Sun.COM } snf_vmap_desbinfo;
23239301SVasumathi.Sundaram@Sun.COM
23240Sstevel@tonic-gate typedef struct {
23250Sstevel@tonic-gate frtn_t snfi_frtn;
23260Sstevel@tonic-gate caddr_t snfi_base;
23270Sstevel@tonic-gate uint_t snfi_mapoff;
23280Sstevel@tonic-gate size_t snfi_len;
23290Sstevel@tonic-gate vnode_t *snfi_vp;
23300Sstevel@tonic-gate } snf_smap_desbinfo;
23310Sstevel@tonic-gate
23329344SVasumathi.Sundaram@Sun.COM /*
23339344SVasumathi.Sundaram@Sun.COM * The callback function used for vpm mapped mblks called when the last ref of
23349344SVasumathi.Sundaram@Sun.COM * the mblk is dropped which normally occurs when TCP receives the ack. But it
23359344SVasumathi.Sundaram@Sun.COM * can be the driver too due to lazy reclaim.
23369344SVasumathi.Sundaram@Sun.COM */
23379301SVasumathi.Sundaram@Sun.COM void
snf_vmap_desbfree(snf_vmap_desbinfo * snfv)23389301SVasumathi.Sundaram@Sun.COM snf_vmap_desbfree(snf_vmap_desbinfo *snfv)
23399301SVasumathi.Sundaram@Sun.COM {
23409344SVasumathi.Sundaram@Sun.COM ASSERT(snfv->snfv_ref != 0);
23419344SVasumathi.Sundaram@Sun.COM if (atomic_add_32_nv(&snfv->snfv_ref, -1) == 0) {
23429344SVasumathi.Sundaram@Sun.COM vpm_unmap_pages(snfv->snfv_vml, S_READ);
23439301SVasumathi.Sundaram@Sun.COM VN_RELE(snfv->snfv_vp);
23449301SVasumathi.Sundaram@Sun.COM kmem_free(snfv, sizeof (snf_vmap_desbinfo));
23459301SVasumathi.Sundaram@Sun.COM }
23469301SVasumathi.Sundaram@Sun.COM }
23479301SVasumathi.Sundaram@Sun.COM
23480Sstevel@tonic-gate /*
23499344SVasumathi.Sundaram@Sun.COM * The callback function used for segmap'ped mblks called when the last ref of
23509344SVasumathi.Sundaram@Sun.COM * the mblk is dropped which normally occurs when TCP receives the ack. But it
23519344SVasumathi.Sundaram@Sun.COM * can be the driver too due to lazy reclaim.
23520Sstevel@tonic-gate */
23530Sstevel@tonic-gate void
snf_smap_desbfree(snf_smap_desbinfo * snfi)23540Sstevel@tonic-gate snf_smap_desbfree(snf_smap_desbinfo *snfi)
23550Sstevel@tonic-gate {
23567568SJayakara.Kini@Sun.COM if (! IS_KPM_ADDR(snfi->snfi_base)) {
23570Sstevel@tonic-gate /*
23580Sstevel@tonic-gate * We don't need to call segmap_fault(F_SOFTUNLOCK) for
23590Sstevel@tonic-gate * segmap_kpm as long as the latter never falls back to
23600Sstevel@tonic-gate * "use_segmap_range". (See segmap_getmapflt().)
23610Sstevel@tonic-gate *
23620Sstevel@tonic-gate * Using S_OTHER saves an redundant hat_setref() in
23630Sstevel@tonic-gate * segmap_unlock()
23640Sstevel@tonic-gate */
23650Sstevel@tonic-gate (void) segmap_fault(kas.a_hat, segkmap,
2366408Skrgopi (caddr_t)(uintptr_t)(((uintptr_t)snfi->snfi_base +
2367408Skrgopi snfi->snfi_mapoff) & PAGEMASK), snfi->snfi_len,
2368408Skrgopi F_SOFTUNLOCK, S_OTHER);
23690Sstevel@tonic-gate }
23700Sstevel@tonic-gate (void) segmap_release(segkmap, snfi->snfi_base, SM_DONTNEED);
23710Sstevel@tonic-gate VN_RELE(snfi->snfi_vp);
23720Sstevel@tonic-gate kmem_free(snfi, sizeof (*snfi));
23730Sstevel@tonic-gate }
23740Sstevel@tonic-gate
23750Sstevel@tonic-gate /*
23769344SVasumathi.Sundaram@Sun.COM * Use segmap or vpm instead of bcopy to send down a desballoca'ed, mblk.
23779344SVasumathi.Sundaram@Sun.COM * When segmap is used, the mblk contains a segmap slot of no more
23789344SVasumathi.Sundaram@Sun.COM * than MAXBSIZE.
23799344SVasumathi.Sundaram@Sun.COM *
23809344SVasumathi.Sundaram@Sun.COM * With vpm, a maximum of SNF_MAXVMAPS page-sized mappings can be obtained
23819344SVasumathi.Sundaram@Sun.COM * in each iteration and sent by socket_sendmblk until an error occurs or
23829344SVasumathi.Sundaram@Sun.COM * the requested size has been transferred. An mblk is esballoca'ed from
23839344SVasumathi.Sundaram@Sun.COM * each mapped page and a chain of these mblk is sent to the transport layer.
23849344SVasumathi.Sundaram@Sun.COM * vpm will be called to unmap the pages when all mblks have been freed by
23859344SVasumathi.Sundaram@Sun.COM * free_func.
23860Sstevel@tonic-gate *
23870Sstevel@tonic-gate * At the end of the whole sendfile() operation, we wait till the data from
23880Sstevel@tonic-gate * the last mblk is ack'ed by the transport before returning so that the
23890Sstevel@tonic-gate * caller of sendfile() can safely modify the file content.
23900Sstevel@tonic-gate */
23910Sstevel@tonic-gate int
snf_segmap(file_t * fp,vnode_t * fvp,u_offset_t fileoff,u_offset_t total_size,ssize_t * count,boolean_t nowait)23929344SVasumathi.Sundaram@Sun.COM snf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t total_size,
23937568SJayakara.Kini@Sun.COM ssize_t *count, boolean_t nowait)
23940Sstevel@tonic-gate {
23950Sstevel@tonic-gate caddr_t base;
23960Sstevel@tonic-gate int mapoff;
23970Sstevel@tonic-gate vnode_t *vp;
23989344SVasumathi.Sundaram@Sun.COM mblk_t *mp = NULL;
23999344SVasumathi.Sundaram@Sun.COM int chain_size;
24000Sstevel@tonic-gate int error;
240112039SBrian.Utterback@Sun.COM clock_t deadlk_wait;
24020Sstevel@tonic-gate short fflag;
24030Sstevel@tonic-gate int ksize;
24040Sstevel@tonic-gate struct vattr va;
24050Sstevel@tonic-gate boolean_t dowait = B_FALSE;
24068348SEric.Yu@Sun.COM struct nmsghdr msg;
24070Sstevel@tonic-gate
24080Sstevel@tonic-gate vp = fp->f_vnode;
24090Sstevel@tonic-gate fflag = fp->f_flag;
24100Sstevel@tonic-gate ksize = 0;
24118348SEric.Yu@Sun.COM bzero(&msg, sizeof (msg));
24128348SEric.Yu@Sun.COM
24130Sstevel@tonic-gate for (;;) {
24140Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) {
24150Sstevel@tonic-gate error = EINTR;
24160Sstevel@tonic-gate break;
24170Sstevel@tonic-gate }
24187568SJayakara.Kini@Sun.COM
24199344SVasumathi.Sundaram@Sun.COM if (vpm_enable) {
24209344SVasumathi.Sundaram@Sun.COM snf_vmap_desbinfo *snfv;
24219344SVasumathi.Sundaram@Sun.COM mblk_t *nmp;
24229344SVasumathi.Sundaram@Sun.COM int mblk_size;
24239344SVasumathi.Sundaram@Sun.COM int maxsize;
24249344SVasumathi.Sundaram@Sun.COM int i;
24259301SVasumathi.Sundaram@Sun.COM
24269344SVasumathi.Sundaram@Sun.COM mapoff = fileoff & PAGEOFFSET;
24279344SVasumathi.Sundaram@Sun.COM maxsize = MIN((SNF_VPMMAXPGS * PAGESIZE), total_size);
24289344SVasumathi.Sundaram@Sun.COM
24299344SVasumathi.Sundaram@Sun.COM snfv = kmem_zalloc(sizeof (snf_vmap_desbinfo),
24309344SVasumathi.Sundaram@Sun.COM KM_SLEEP);
24319344SVasumathi.Sundaram@Sun.COM
243212039SBrian.Utterback@Sun.COM /*
243312039SBrian.Utterback@Sun.COM * Get vpm mappings for maxsize with read access.
243412039SBrian.Utterback@Sun.COM * If the pages aren't available yet, we get
243512039SBrian.Utterback@Sun.COM * DEADLK, so wait and try again a little later using
243612039SBrian.Utterback@Sun.COM * an increasing wait. We might be here a long time.
243712039SBrian.Utterback@Sun.COM *
243812039SBrian.Utterback@Sun.COM * If delay_sig returns EINTR, be sure to exit and
243912039SBrian.Utterback@Sun.COM * pass it up to the caller.
244012039SBrian.Utterback@Sun.COM */
244112039SBrian.Utterback@Sun.COM deadlk_wait = 0;
244212039SBrian.Utterback@Sun.COM while ((error = vpm_map_pages(fvp, fileoff,
244312039SBrian.Utterback@Sun.COM (size_t)maxsize, (VPM_FETCHPAGE), snfv->snfv_vml,
244412039SBrian.Utterback@Sun.COM SNF_MAXVMAPS, NULL, S_READ)) == EDEADLK) {
244512039SBrian.Utterback@Sun.COM deadlk_wait += (deadlk_wait < 5) ? 1 : 4;
244612039SBrian.Utterback@Sun.COM if ((error = delay_sig(deadlk_wait)) != 0) {
244712039SBrian.Utterback@Sun.COM break;
244812039SBrian.Utterback@Sun.COM }
244912039SBrian.Utterback@Sun.COM }
245012039SBrian.Utterback@Sun.COM if (error != 0) {
24519301SVasumathi.Sundaram@Sun.COM kmem_free(snfv, sizeof (snf_vmap_desbinfo));
245212039SBrian.Utterback@Sun.COM error = (error == EINTR) ? EINTR : EIO;
24539301SVasumathi.Sundaram@Sun.COM goto out;
24549301SVasumathi.Sundaram@Sun.COM }
24559301SVasumathi.Sundaram@Sun.COM snfv->snfv_frtn.free_func = snf_vmap_desbfree;
24569301SVasumathi.Sundaram@Sun.COM snfv->snfv_frtn.free_arg = (caddr_t)snfv;
24579301SVasumathi.Sundaram@Sun.COM
24589344SVasumathi.Sundaram@Sun.COM /* Construct the mblk chain from the page mappings */
24599344SVasumathi.Sundaram@Sun.COM chain_size = 0;
24609344SVasumathi.Sundaram@Sun.COM for (i = 0; (snfv->snfv_vml[i].vs_addr != NULL) &&
24619344SVasumathi.Sundaram@Sun.COM total_size > 0; i++) {
24629344SVasumathi.Sundaram@Sun.COM ASSERT(chain_size < maxsize);
24639344SVasumathi.Sundaram@Sun.COM mblk_size = MIN(snfv->snfv_vml[i].vs_len -
24649344SVasumathi.Sundaram@Sun.COM mapoff, total_size);
24659344SVasumathi.Sundaram@Sun.COM nmp = esballoca(
24669344SVasumathi.Sundaram@Sun.COM (uchar_t *)snfv->snfv_vml[i].vs_addr +
24679344SVasumathi.Sundaram@Sun.COM mapoff, mblk_size, BPRI_HI,
24689344SVasumathi.Sundaram@Sun.COM &snfv->snfv_frtn);
24699301SVasumathi.Sundaram@Sun.COM
24709344SVasumathi.Sundaram@Sun.COM /*
24719344SVasumathi.Sundaram@Sun.COM * We return EAGAIN after unmapping the pages
24729344SVasumathi.Sundaram@Sun.COM * if we cannot allocate the the head of the
24739344SVasumathi.Sundaram@Sun.COM * chain. Otherwise, we continue sending the
24749344SVasumathi.Sundaram@Sun.COM * mblks constructed so far.
24759344SVasumathi.Sundaram@Sun.COM */
24769344SVasumathi.Sundaram@Sun.COM if (nmp == NULL) {
24779344SVasumathi.Sundaram@Sun.COM if (i == 0) {
24789344SVasumathi.Sundaram@Sun.COM vpm_unmap_pages(snfv->snfv_vml,
24799344SVasumathi.Sundaram@Sun.COM S_READ);
24809344SVasumathi.Sundaram@Sun.COM kmem_free(snfv,
24819344SVasumathi.Sundaram@Sun.COM sizeof (snf_vmap_desbinfo));
24829344SVasumathi.Sundaram@Sun.COM error = EAGAIN;
24839344SVasumathi.Sundaram@Sun.COM goto out;
24849344SVasumathi.Sundaram@Sun.COM }
24859344SVasumathi.Sundaram@Sun.COM break;
24869301SVasumathi.Sundaram@Sun.COM }
24879344SVasumathi.Sundaram@Sun.COM /* Mark this dblk with the zero-copy flag */
24889344SVasumathi.Sundaram@Sun.COM nmp->b_datap->db_struioflag |= STRUIO_ZC;
24899344SVasumathi.Sundaram@Sun.COM nmp->b_wptr += mblk_size;
24909344SVasumathi.Sundaram@Sun.COM chain_size += mblk_size;
24919344SVasumathi.Sundaram@Sun.COM fileoff += mblk_size;
24929344SVasumathi.Sundaram@Sun.COM total_size -= mblk_size;
24939344SVasumathi.Sundaram@Sun.COM snfv->snfv_ref++;
24949344SVasumathi.Sundaram@Sun.COM mapoff = 0;
24959344SVasumathi.Sundaram@Sun.COM if (i > 0)
24969344SVasumathi.Sundaram@Sun.COM linkb(mp, nmp);
24979344SVasumathi.Sundaram@Sun.COM else
24989344SVasumathi.Sundaram@Sun.COM mp = nmp;
24999301SVasumathi.Sundaram@Sun.COM }
25009301SVasumathi.Sundaram@Sun.COM VN_HOLD(fvp);
25019301SVasumathi.Sundaram@Sun.COM snfv->snfv_vp = fvp;
25029301SVasumathi.Sundaram@Sun.COM } else {
25039344SVasumathi.Sundaram@Sun.COM /* vpm not supported. fallback to segmap */
25049344SVasumathi.Sundaram@Sun.COM snf_smap_desbinfo *snfi;
25050Sstevel@tonic-gate
25069301SVasumathi.Sundaram@Sun.COM mapoff = fileoff & MAXBOFFSET;
25079344SVasumathi.Sundaram@Sun.COM chain_size = MAXBSIZE - mapoff;
25089344SVasumathi.Sundaram@Sun.COM if (chain_size > total_size)
25099344SVasumathi.Sundaram@Sun.COM chain_size = total_size;
25109301SVasumathi.Sundaram@Sun.COM /*
25119301SVasumathi.Sundaram@Sun.COM * we don't forcefault because we'll call
25129301SVasumathi.Sundaram@Sun.COM * segmap_fault(F_SOFTLOCK) next.
25139301SVasumathi.Sundaram@Sun.COM *
25149301SVasumathi.Sundaram@Sun.COM * S_READ will get the ref bit set (by either
25159301SVasumathi.Sundaram@Sun.COM * segmap_getmapflt() or segmap_fault()) and page
25169301SVasumathi.Sundaram@Sun.COM * shared locked.
25179301SVasumathi.Sundaram@Sun.COM */
25189344SVasumathi.Sundaram@Sun.COM base = segmap_getmapflt(segkmap, fvp, fileoff,
25199344SVasumathi.Sundaram@Sun.COM chain_size, segmap_kpm ? SM_FAULT : 0, S_READ);
25209301SVasumathi.Sundaram@Sun.COM
25219301SVasumathi.Sundaram@Sun.COM snfi = kmem_alloc(sizeof (*snfi), KM_SLEEP);
25229344SVasumathi.Sundaram@Sun.COM snfi->snfi_len = (size_t)roundup(mapoff+chain_size,
25239301SVasumathi.Sundaram@Sun.COM PAGESIZE)- (mapoff & PAGEMASK);
25249301SVasumathi.Sundaram@Sun.COM /*
25259301SVasumathi.Sundaram@Sun.COM * We must call segmap_fault() even for segmap_kpm
25269301SVasumathi.Sundaram@Sun.COM * because that's how error gets returned.
25279301SVasumathi.Sundaram@Sun.COM * (segmap_getmapflt() never fails but segmap_fault()
25289301SVasumathi.Sundaram@Sun.COM * does.)
252912039SBrian.Utterback@Sun.COM *
253012039SBrian.Utterback@Sun.COM * If the pages aren't available yet, we get
253112039SBrian.Utterback@Sun.COM * DEADLK, so wait and try again a little later using
253212039SBrian.Utterback@Sun.COM * an increasing wait. We might be here a long time.
253312039SBrian.Utterback@Sun.COM *
253412039SBrian.Utterback@Sun.COM * If delay_sig returns EINTR, be sure to exit and
253512039SBrian.Utterback@Sun.COM * pass it up to the caller.
25369301SVasumathi.Sundaram@Sun.COM */
253712039SBrian.Utterback@Sun.COM deadlk_wait = 0;
253812039SBrian.Utterback@Sun.COM while ((error = FC_ERRNO(segmap_fault(kas.a_hat,
253912039SBrian.Utterback@Sun.COM segkmap, (caddr_t)(uintptr_t)(((uintptr_t)base +
254012039SBrian.Utterback@Sun.COM mapoff) & PAGEMASK), snfi->snfi_len, F_SOFTLOCK,
254112039SBrian.Utterback@Sun.COM S_READ))) == EDEADLK) {
254212039SBrian.Utterback@Sun.COM deadlk_wait += (deadlk_wait < 5) ? 1 : 4;
254312039SBrian.Utterback@Sun.COM if ((error = delay_sig(deadlk_wait)) != 0) {
254412039SBrian.Utterback@Sun.COM break;
254512039SBrian.Utterback@Sun.COM }
254612039SBrian.Utterback@Sun.COM }
254712039SBrian.Utterback@Sun.COM if (error != 0) {
25489301SVasumathi.Sundaram@Sun.COM (void) segmap_release(segkmap, base, 0);
25499301SVasumathi.Sundaram@Sun.COM kmem_free(snfi, sizeof (*snfi));
255012039SBrian.Utterback@Sun.COM error = (error == EINTR) ? EINTR : EIO;
25519301SVasumathi.Sundaram@Sun.COM goto out;
25529301SVasumathi.Sundaram@Sun.COM }
25539301SVasumathi.Sundaram@Sun.COM snfi->snfi_frtn.free_func = snf_smap_desbfree;
25549301SVasumathi.Sundaram@Sun.COM snfi->snfi_frtn.free_arg = (caddr_t)snfi;
25559301SVasumathi.Sundaram@Sun.COM snfi->snfi_base = base;
25569301SVasumathi.Sundaram@Sun.COM snfi->snfi_mapoff = mapoff;
25579344SVasumathi.Sundaram@Sun.COM mp = esballoca((uchar_t *)base + mapoff, chain_size,
25589301SVasumathi.Sundaram@Sun.COM BPRI_HI, &snfi->snfi_frtn);
25599301SVasumathi.Sundaram@Sun.COM
25609301SVasumathi.Sundaram@Sun.COM if (mp == NULL) {
25619301SVasumathi.Sundaram@Sun.COM (void) segmap_fault(kas.a_hat, segkmap,
25629344SVasumathi.Sundaram@Sun.COM (caddr_t)(uintptr_t)(((uintptr_t)base +
25639344SVasumathi.Sundaram@Sun.COM mapoff) & PAGEMASK), snfi->snfi_len,
25649301SVasumathi.Sundaram@Sun.COM F_SOFTUNLOCK, S_OTHER);
25659301SVasumathi.Sundaram@Sun.COM (void) segmap_release(segkmap, base, 0);
25669301SVasumathi.Sundaram@Sun.COM kmem_free(snfi, sizeof (*snfi));
25679301SVasumathi.Sundaram@Sun.COM freemsg(mp);
25689301SVasumathi.Sundaram@Sun.COM error = EAGAIN;
25699301SVasumathi.Sundaram@Sun.COM goto out;
25709301SVasumathi.Sundaram@Sun.COM }
25719301SVasumathi.Sundaram@Sun.COM VN_HOLD(fvp);
25729301SVasumathi.Sundaram@Sun.COM snfi->snfi_vp = fvp;
25739344SVasumathi.Sundaram@Sun.COM mp->b_wptr += chain_size;
25749301SVasumathi.Sundaram@Sun.COM
25759301SVasumathi.Sundaram@Sun.COM /* Mark this dblk with the zero-copy flag */
25769301SVasumathi.Sundaram@Sun.COM mp->b_datap->db_struioflag |= STRUIO_ZC;
25779344SVasumathi.Sundaram@Sun.COM fileoff += chain_size;
25789344SVasumathi.Sundaram@Sun.COM total_size -= chain_size;
25797568SJayakara.Kini@Sun.COM }
25800Sstevel@tonic-gate
25819344SVasumathi.Sundaram@Sun.COM if (total_size == 0 && !nowait) {
25820Sstevel@tonic-gate ASSERT(!dowait);
25830Sstevel@tonic-gate dowait = B_TRUE;
25847568SJayakara.Kini@Sun.COM mp->b_datap->db_struioflag |= STRUIO_ZCNOTIFY;
25850Sstevel@tonic-gate }
25860Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
25878348SEric.Yu@Sun.COM error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
25888348SEric.Yu@Sun.COM if (error != 0) {
25899344SVasumathi.Sundaram@Sun.COM /*
25909344SVasumathi.Sundaram@Sun.COM * mp contains the mblks that were not sent by
25919344SVasumathi.Sundaram@Sun.COM * socket_sendmblk. Use its size to update *count
25929344SVasumathi.Sundaram@Sun.COM */
25939344SVasumathi.Sundaram@Sun.COM *count = ksize + (chain_size - msgdsize(mp));
25948348SEric.Yu@Sun.COM if (mp != NULL)
25958348SEric.Yu@Sun.COM freemsg(mp);
25960Sstevel@tonic-gate return (error);
25970Sstevel@tonic-gate }
25989344SVasumathi.Sundaram@Sun.COM ksize += chain_size;
25999344SVasumathi.Sundaram@Sun.COM if (total_size == 0)
26000Sstevel@tonic-gate goto done;
26010Sstevel@tonic-gate
26020Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
26030Sstevel@tonic-gate va.va_mask = AT_SIZE;
26045331Samw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
26050Sstevel@tonic-gate if (error)
26060Sstevel@tonic-gate break;
26070Sstevel@tonic-gate /* Read as much as possible. */
26080Sstevel@tonic-gate if (fileoff >= va.va_size)
26090Sstevel@tonic-gate break;
26109344SVasumathi.Sundaram@Sun.COM if (total_size + fileoff > va.va_size)
26119344SVasumathi.Sundaram@Sun.COM total_size = va.va_size - fileoff;
26120Sstevel@tonic-gate }
26130Sstevel@tonic-gate out:
26140Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
26150Sstevel@tonic-gate done:
26160Sstevel@tonic-gate *count = ksize;
26170Sstevel@tonic-gate if (dowait) {
26180Sstevel@tonic-gate stdata_t *stp;
26190Sstevel@tonic-gate
26200Sstevel@tonic-gate stp = vp->v_stream;
26218348SEric.Yu@Sun.COM if (stp == NULL) {
26228348SEric.Yu@Sun.COM struct sonode *so;
26238348SEric.Yu@Sun.COM so = VTOSO(vp);
26248348SEric.Yu@Sun.COM error = so_zcopy_wait(so);
26258348SEric.Yu@Sun.COM } else {
26268348SEric.Yu@Sun.COM mutex_enter(&stp->sd_lock);
26278348SEric.Yu@Sun.COM while (!(stp->sd_flag & STZCNOTIFY)) {
26288348SEric.Yu@Sun.COM if (cv_wait_sig(&stp->sd_zcopy_wait,
26298348SEric.Yu@Sun.COM &stp->sd_lock) == 0) {
26308348SEric.Yu@Sun.COM error = EINTR;
26318348SEric.Yu@Sun.COM break;
26328348SEric.Yu@Sun.COM }
26333415Samehta }
26348348SEric.Yu@Sun.COM stp->sd_flag &= ~STZCNOTIFY;
26358348SEric.Yu@Sun.COM mutex_exit(&stp->sd_lock);
26360Sstevel@tonic-gate }
26370Sstevel@tonic-gate }
26380Sstevel@tonic-gate return (error);
26390Sstevel@tonic-gate }
26400Sstevel@tonic-gate
26410Sstevel@tonic-gate int
snf_cache(file_t * fp,vnode_t * fvp,u_offset_t fileoff,u_offset_t size,uint_t maxpsz,ssize_t * count)26420Sstevel@tonic-gate snf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
26430Sstevel@tonic-gate uint_t maxpsz, ssize_t *count)
26440Sstevel@tonic-gate {
26450Sstevel@tonic-gate struct vnode *vp;
26460Sstevel@tonic-gate mblk_t *mp;
26470Sstevel@tonic-gate int iosize;
26486240Skrishna int extra = 0;
26490Sstevel@tonic-gate int error;
26500Sstevel@tonic-gate short fflag;
26510Sstevel@tonic-gate int ksize;
26520Sstevel@tonic-gate int ioflag;
26530Sstevel@tonic-gate struct uio auio;
26540Sstevel@tonic-gate struct iovec aiov;
26550Sstevel@tonic-gate struct vattr va;
26568171SPrakash.Jalan@Sun.COM int maxblk = 0;
26578171SPrakash.Jalan@Sun.COM int wroff = 0;
26588171SPrakash.Jalan@Sun.COM struct sonode *so;
26598348SEric.Yu@Sun.COM struct nmsghdr msg;
26600Sstevel@tonic-gate
26610Sstevel@tonic-gate vp = fp->f_vnode;
26626240Skrishna if (vp->v_type == VSOCK) {
26636240Skrishna stdata_t *stp;
26646240Skrishna
26656240Skrishna /*
26666240Skrishna * Get the extra space to insert a header and a trailer.
26676240Skrishna */
26688171SPrakash.Jalan@Sun.COM so = VTOSO(vp);
26696240Skrishna stp = vp->v_stream;
26708348SEric.Yu@Sun.COM if (stp == NULL) {
26718348SEric.Yu@Sun.COM wroff = so->so_proto_props.sopp_wroff;
26728348SEric.Yu@Sun.COM maxblk = so->so_proto_props.sopp_maxblk;
26738348SEric.Yu@Sun.COM extra = wroff + so->so_proto_props.sopp_tail;
26748348SEric.Yu@Sun.COM } else {
26758348SEric.Yu@Sun.COM wroff = (int)(stp->sd_wroff);
26768348SEric.Yu@Sun.COM maxblk = (int)(stp->sd_maxblk);
26778348SEric.Yu@Sun.COM extra = wroff + (int)(stp->sd_tail);
26788348SEric.Yu@Sun.COM }
26796240Skrishna }
26808348SEric.Yu@Sun.COM bzero(&msg, sizeof (msg));
26810Sstevel@tonic-gate fflag = fp->f_flag;
26820Sstevel@tonic-gate ksize = 0;
26830Sstevel@tonic-gate auio.uio_iov = &aiov;
26840Sstevel@tonic-gate auio.uio_iovcnt = 1;
26850Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE;
26860Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T;
26870Sstevel@tonic-gate auio.uio_fmode = fflag;
26880Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED;
26890Sstevel@tonic-gate ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
26900Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */
26910Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0)
26920Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC);
26930Sstevel@tonic-gate for (;;) {
26940Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) {
26950Sstevel@tonic-gate error = EINTR;
26960Sstevel@tonic-gate break;
26970Sstevel@tonic-gate }
26980Sstevel@tonic-gate iosize = (int)MIN(maxpsz, size);
26998171SPrakash.Jalan@Sun.COM
27008171SPrakash.Jalan@Sun.COM /*
270112643SAnders.Persson@Sun.COM * Socket filters can limit the mblk size,
270212643SAnders.Persson@Sun.COM * so limit reads to maxblk if there are
2703*12644SAnders.Persson@Sun.COM * filters present.
27048171SPrakash.Jalan@Sun.COM */
270512643SAnders.Persson@Sun.COM if (vp->v_type == VSOCK &&
270612643SAnders.Persson@Sun.COM so->so_filter_active > 0 && maxblk != INFPSZ)
27078171SPrakash.Jalan@Sun.COM iosize = (int)MIN(iosize, maxblk);
27088171SPrakash.Jalan@Sun.COM
27098778SErik.Nordmark@Sun.COM if (is_system_labeled()) {
27108778SErik.Nordmark@Sun.COM mp = allocb_cred(iosize + extra, CRED(),
27118778SErik.Nordmark@Sun.COM curproc->p_pid);
27128778SErik.Nordmark@Sun.COM } else {
27138778SErik.Nordmark@Sun.COM mp = allocb(iosize + extra, BPRI_MED);
27148778SErik.Nordmark@Sun.COM }
27158778SErik.Nordmark@Sun.COM if (mp == NULL) {
27160Sstevel@tonic-gate error = EAGAIN;
27170Sstevel@tonic-gate break;
27180Sstevel@tonic-gate }
27198171SPrakash.Jalan@Sun.COM
27208171SPrakash.Jalan@Sun.COM mp->b_rptr += wroff;
27218171SPrakash.Jalan@Sun.COM
27220Sstevel@tonic-gate aiov.iov_base = (caddr_t)mp->b_rptr;
27230Sstevel@tonic-gate aiov.iov_len = iosize;
27240Sstevel@tonic-gate auio.uio_loffset = fileoff;
27250Sstevel@tonic-gate auio.uio_resid = iosize;
27260Sstevel@tonic-gate
27270Sstevel@tonic-gate error = VOP_READ(fvp, &auio, ioflag, fp->f_cred, NULL);
27280Sstevel@tonic-gate iosize -= auio.uio_resid;
27290Sstevel@tonic-gate
27300Sstevel@tonic-gate if (error == EINTR && iosize != 0)
27310Sstevel@tonic-gate error = 0;
27320Sstevel@tonic-gate
27330Sstevel@tonic-gate if (error != 0 || iosize == 0) {
27340Sstevel@tonic-gate freeb(mp);
27350Sstevel@tonic-gate break;
27360Sstevel@tonic-gate }
27370Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + iosize;
27380Sstevel@tonic-gate
27390Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
27408348SEric.Yu@Sun.COM
27418348SEric.Yu@Sun.COM error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
27428348SEric.Yu@Sun.COM
27438348SEric.Yu@Sun.COM if (error != 0) {
27440Sstevel@tonic-gate *count = ksize;
27458348SEric.Yu@Sun.COM if (mp != NULL)
27468348SEric.Yu@Sun.COM freeb(mp);
27470Sstevel@tonic-gate return (error);
27480Sstevel@tonic-gate }
27490Sstevel@tonic-gate ksize += iosize;
27500Sstevel@tonic-gate size -= iosize;
27510Sstevel@tonic-gate if (size == 0)
27520Sstevel@tonic-gate goto done;
27530Sstevel@tonic-gate
27540Sstevel@tonic-gate fileoff += iosize;
27550Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
27560Sstevel@tonic-gate va.va_mask = AT_SIZE;
27575331Samw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
27580Sstevel@tonic-gate if (error)
27590Sstevel@tonic-gate break;
27600Sstevel@tonic-gate /* Read as much as possible. */
27610Sstevel@tonic-gate if (fileoff >= va.va_size)
27620Sstevel@tonic-gate size = 0;
27630Sstevel@tonic-gate else if (size + fileoff > va.va_size)
27640Sstevel@tonic-gate size = va.va_size - fileoff;
27650Sstevel@tonic-gate }
27660Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
27670Sstevel@tonic-gate done:
27680Sstevel@tonic-gate *count = ksize;
27690Sstevel@tonic-gate return (error);
27700Sstevel@tonic-gate }
27710Sstevel@tonic-gate
27720Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
27730Sstevel@tonic-gate /*
27740Sstevel@tonic-gate * Largefile support for 32 bit applications only.
27750Sstevel@tonic-gate */
27760Sstevel@tonic-gate int
sosendfile64(file_t * fp,file_t * rfp,const struct ksendfilevec64 * sfv,ssize32_t * count32)27770Sstevel@tonic-gate sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
27780Sstevel@tonic-gate ssize32_t *count32)
27790Sstevel@tonic-gate {
27800Sstevel@tonic-gate ssize32_t sfv_len;
27810Sstevel@tonic-gate u_offset_t sfv_off, va_size;
27820Sstevel@tonic-gate struct vnode *vp, *fvp, *realvp;
27830Sstevel@tonic-gate struct vattr va;
27840Sstevel@tonic-gate stdata_t *stp;
27850Sstevel@tonic-gate ssize_t count = 0;
27860Sstevel@tonic-gate int error = 0;
27870Sstevel@tonic-gate boolean_t dozcopy = B_FALSE;
27880Sstevel@tonic-gate uint_t maxpsz;
27890Sstevel@tonic-gate
27900Sstevel@tonic-gate sfv_len = (ssize32_t)sfv->sfv_len;
27910Sstevel@tonic-gate if (sfv_len < 0) {
27920Sstevel@tonic-gate error = EINVAL;
27930Sstevel@tonic-gate goto out;
27940Sstevel@tonic-gate }
27950Sstevel@tonic-gate
27960Sstevel@tonic-gate if (sfv_len == 0) goto out;
27970Sstevel@tonic-gate
27980Sstevel@tonic-gate sfv_off = (u_offset_t)sfv->sfv_off;
27990Sstevel@tonic-gate
28000Sstevel@tonic-gate /* Same checks as in pread */
28010Sstevel@tonic-gate if (sfv_off > MAXOFFSET_T) {
28020Sstevel@tonic-gate error = EINVAL;
28030Sstevel@tonic-gate goto out;
28040Sstevel@tonic-gate }
28050Sstevel@tonic-gate if (sfv_off + sfv_len > MAXOFFSET_T)
28060Sstevel@tonic-gate sfv_len = (ssize32_t)(MAXOFFSET_T - sfv_off);
28070Sstevel@tonic-gate
28080Sstevel@tonic-gate /*
28090Sstevel@tonic-gate * There are no more checks on sfv_len. So, we cast it to
28100Sstevel@tonic-gate * u_offset_t and share the snf_direct_io/snf_cache code between
28110Sstevel@tonic-gate * 32 bit and 64 bit.
28120Sstevel@tonic-gate *
28130Sstevel@tonic-gate * TODO: should do nbl_need_check() like read()?
28140Sstevel@tonic-gate */
28150Sstevel@tonic-gate if (sfv_len > sendfile_max_size) {
28160Sstevel@tonic-gate sf_stats.ss_file_not_cached++;
28170Sstevel@tonic-gate error = snf_direct_io(fp, rfp, sfv_off, (u_offset_t)sfv_len,
28180Sstevel@tonic-gate &count);
28190Sstevel@tonic-gate goto out;
28200Sstevel@tonic-gate }
28210Sstevel@tonic-gate fvp = rfp->f_vnode;
28225331Samw if (VOP_REALVP(fvp, &realvp, NULL) == 0)
28230Sstevel@tonic-gate fvp = realvp;
28240Sstevel@tonic-gate /*
28250Sstevel@tonic-gate * Grab the lock as a reader to prevent the file size
28260Sstevel@tonic-gate * from changing underneath.
28270Sstevel@tonic-gate */
28280Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28290Sstevel@tonic-gate va.va_mask = AT_SIZE;
28305331Samw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
28310Sstevel@tonic-gate va_size = va.va_size;
28324649Sdm120769 if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) {
28330Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28340Sstevel@tonic-gate goto out;
28350Sstevel@tonic-gate }
28360Sstevel@tonic-gate /* Read as much as possible. */
28370Sstevel@tonic-gate if (sfv_off + sfv_len > va_size)
28380Sstevel@tonic-gate sfv_len = va_size - sfv_off;
28390Sstevel@tonic-gate
28400Sstevel@tonic-gate vp = fp->f_vnode;
28410Sstevel@tonic-gate stp = vp->v_stream;
28420Sstevel@tonic-gate /*
28430Sstevel@tonic-gate * When the NOWAIT flag is not set, we enable zero-copy only if the
28440Sstevel@tonic-gate * transfer size is large enough. This prevents performance loss
28450Sstevel@tonic-gate * when the caller sends the file piece by piece.
28460Sstevel@tonic-gate */
28470Sstevel@tonic-gate if (sfv_len >= MAXBSIZE && (sfv_len >= (va_size >> 1) ||
28480Sstevel@tonic-gate (sfv->sfv_flag & SFV_NOWAIT) || sfv_len >= 0x1000000) &&
28494173Spr14459 !vn_has_flocks(fvp) && !(fvp->v_flag & VNOMAP)) {
28508348SEric.Yu@Sun.COM uint_t copyflag;
28518348SEric.Yu@Sun.COM copyflag = stp != NULL ? stp->sd_copyflag :
28528348SEric.Yu@Sun.COM VTOSO(vp)->so_proto_props.sopp_zcopyflag;
28538348SEric.Yu@Sun.COM if ((copyflag & (STZCVMSAFE|STZCVMUNSAFE)) == 0) {
28540Sstevel@tonic-gate int on = 1;
28550Sstevel@tonic-gate
28568348SEric.Yu@Sun.COM if (socket_setsockopt(VTOSO(vp), SOL_SOCKET,
28578348SEric.Yu@Sun.COM SO_SND_COPYAVOID, &on, sizeof (on), CRED()) == 0)
28580Sstevel@tonic-gate dozcopy = B_TRUE;
28590Sstevel@tonic-gate } else {
28608348SEric.Yu@Sun.COM dozcopy = copyflag & STZCVMSAFE;
28610Sstevel@tonic-gate }
28620Sstevel@tonic-gate }
28630Sstevel@tonic-gate if (dozcopy) {
28640Sstevel@tonic-gate sf_stats.ss_file_segmap++;
28650Sstevel@tonic-gate error = snf_segmap(fp, fvp, sfv_off, (u_offset_t)sfv_len,
28667568SJayakara.Kini@Sun.COM &count, ((sfv->sfv_flag & SFV_NOWAIT) != 0));
28670Sstevel@tonic-gate } else {
28688348SEric.Yu@Sun.COM if (vp->v_type == VSOCK && stp == NULL) {
28698348SEric.Yu@Sun.COM sonode_t *so = VTOSO(vp);
28708348SEric.Yu@Sun.COM maxpsz = so->so_proto_props.sopp_maxpsz;
28718348SEric.Yu@Sun.COM } else if (stp != NULL) {
28728348SEric.Yu@Sun.COM maxpsz = stp->sd_qn_maxpsz;
28738348SEric.Yu@Sun.COM } else {
28748348SEric.Yu@Sun.COM maxpsz = maxphys;
28758348SEric.Yu@Sun.COM }
28768348SEric.Yu@Sun.COM
28778348SEric.Yu@Sun.COM if (maxpsz == INFPSZ)
28787568SJayakara.Kini@Sun.COM maxpsz = maxphys;
28797568SJayakara.Kini@Sun.COM else
28808348SEric.Yu@Sun.COM maxpsz = roundup(maxpsz, MAXBSIZE);
28810Sstevel@tonic-gate sf_stats.ss_file_cached++;
28820Sstevel@tonic-gate error = snf_cache(fp, fvp, sfv_off, (u_offset_t)sfv_len,
28830Sstevel@tonic-gate maxpsz, &count);
28840Sstevel@tonic-gate }
28850Sstevel@tonic-gate out:
28860Sstevel@tonic-gate releasef(sfv->sfv_fd);
28870Sstevel@tonic-gate *count32 = (ssize32_t)count;
28880Sstevel@tonic-gate return (error);
28890Sstevel@tonic-gate }
28900Sstevel@tonic-gate #endif
28910Sstevel@tonic-gate
28920Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
28930Sstevel@tonic-gate /*
28940Sstevel@tonic-gate * recv32(), recvfrom32(), send32(), sendto32(): intentionally return a
28950Sstevel@tonic-gate * ssize_t rather than ssize32_t; see the comments above read32 for details.
28960Sstevel@tonic-gate */
28970Sstevel@tonic-gate
28980Sstevel@tonic-gate ssize_t
recv32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags)28990Sstevel@tonic-gate recv32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
29000Sstevel@tonic-gate {
29010Sstevel@tonic-gate return (recv(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
29020Sstevel@tonic-gate }
29030Sstevel@tonic-gate
29040Sstevel@tonic-gate ssize_t
recvfrom32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags,caddr32_t name,caddr32_t namelenp)29050Sstevel@tonic-gate recvfrom32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
29060Sstevel@tonic-gate caddr32_t name, caddr32_t namelenp)
29070Sstevel@tonic-gate {
29080Sstevel@tonic-gate return (recvfrom(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
29090Sstevel@tonic-gate (void *)(uintptr_t)name, (void *)(uintptr_t)namelenp));
29100Sstevel@tonic-gate }
29110Sstevel@tonic-gate
29120Sstevel@tonic-gate ssize_t
send32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags)29130Sstevel@tonic-gate send32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
29140Sstevel@tonic-gate {
29150Sstevel@tonic-gate return (send(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
29160Sstevel@tonic-gate }
29170Sstevel@tonic-gate
29180Sstevel@tonic-gate ssize_t
sendto32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags,caddr32_t name,socklen_t namelen)29190Sstevel@tonic-gate sendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
29200Sstevel@tonic-gate caddr32_t name, socklen_t namelen)
29210Sstevel@tonic-gate {
29220Sstevel@tonic-gate return (sendto(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
29230Sstevel@tonic-gate (void *)(uintptr_t)name, namelen));
29240Sstevel@tonic-gate }
29250Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
29260Sstevel@tonic-gate
29270Sstevel@tonic-gate /*
29285331Samw * Function wrappers (mostly around the sonode switch) for
29290Sstevel@tonic-gate * backward compatibility.
29300Sstevel@tonic-gate */
29310Sstevel@tonic-gate
29320Sstevel@tonic-gate int
soaccept(struct sonode * so,int fflag,struct sonode ** nsop)29330Sstevel@tonic-gate soaccept(struct sonode *so, int fflag, struct sonode **nsop)
29340Sstevel@tonic-gate {
29358348SEric.Yu@Sun.COM return (socket_accept(so, fflag, CRED(), nsop));
29360Sstevel@tonic-gate }
29370Sstevel@tonic-gate
29380Sstevel@tonic-gate int
sobind(struct sonode * so,struct sockaddr * name,socklen_t namelen,int backlog,int flags)29390Sstevel@tonic-gate sobind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
29400Sstevel@tonic-gate int backlog, int flags)
29410Sstevel@tonic-gate {
29420Sstevel@tonic-gate int error;
29430Sstevel@tonic-gate
29448348SEric.Yu@Sun.COM error = socket_bind(so, name, namelen, flags, CRED());
29450Sstevel@tonic-gate if (error == 0 && backlog != 0)
29468348SEric.Yu@Sun.COM return (socket_listen(so, backlog, CRED()));
29470Sstevel@tonic-gate
29480Sstevel@tonic-gate return (error);
29490Sstevel@tonic-gate }
29500Sstevel@tonic-gate
29510Sstevel@tonic-gate int
solisten(struct sonode * so,int backlog)29520Sstevel@tonic-gate solisten(struct sonode *so, int backlog)
29530Sstevel@tonic-gate {
29548348SEric.Yu@Sun.COM return (socket_listen(so, backlog, CRED()));
29550Sstevel@tonic-gate }
29560Sstevel@tonic-gate
29570Sstevel@tonic-gate int
soconnect(struct sonode * so,struct sockaddr * name,socklen_t namelen,int fflag,int flags)295812643SAnders.Persson@Sun.COM soconnect(struct sonode *so, struct sockaddr *name, socklen_t namelen,
29590Sstevel@tonic-gate int fflag, int flags)
29600Sstevel@tonic-gate {
29618348SEric.Yu@Sun.COM return (socket_connect(so, name, namelen, fflag, flags, CRED()));
29620Sstevel@tonic-gate }
29630Sstevel@tonic-gate
29640Sstevel@tonic-gate int
sorecvmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop)29650Sstevel@tonic-gate sorecvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
29660Sstevel@tonic-gate {
29678348SEric.Yu@Sun.COM return (socket_recvmsg(so, msg, uiop, CRED()));
29680Sstevel@tonic-gate }
29690Sstevel@tonic-gate
29700Sstevel@tonic-gate int
sosendmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop)29710Sstevel@tonic-gate sosendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
29720Sstevel@tonic-gate {
29738348SEric.Yu@Sun.COM return (socket_sendmsg(so, msg, uiop, CRED()));
29740Sstevel@tonic-gate }
29750Sstevel@tonic-gate
29760Sstevel@tonic-gate int
soshutdown(struct sonode * so,int how)29770Sstevel@tonic-gate soshutdown(struct sonode *so, int how)
29780Sstevel@tonic-gate {
29798348SEric.Yu@Sun.COM return (socket_shutdown(so, how, CRED()));
29800Sstevel@tonic-gate }
29810Sstevel@tonic-gate
29820Sstevel@tonic-gate int
sogetsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,int flags)29830Sstevel@tonic-gate sogetsockopt(struct sonode *so, int level, int option_name, void *optval,
29840Sstevel@tonic-gate socklen_t *optlenp, int flags)
29850Sstevel@tonic-gate {
29868348SEric.Yu@Sun.COM return (socket_getsockopt(so, level, option_name, optval, optlenp,
29878348SEric.Yu@Sun.COM flags, CRED()));
29880Sstevel@tonic-gate }
29890Sstevel@tonic-gate
29900Sstevel@tonic-gate int
sosetsockopt(struct sonode * so,int level,int option_name,const void * optval,t_uscalar_t optlen)29910Sstevel@tonic-gate sosetsockopt(struct sonode *so, int level, int option_name, const void *optval,
29920Sstevel@tonic-gate t_uscalar_t optlen)
29930Sstevel@tonic-gate {
29948348SEric.Yu@Sun.COM return (socket_setsockopt(so, level, option_name, optval, optlen,
29958348SEric.Yu@Sun.COM CRED()));
29960Sstevel@tonic-gate }
29970Sstevel@tonic-gate
29980Sstevel@tonic-gate /*
29990Sstevel@tonic-gate * Because this is backward compatibility interface it only needs to be
30000Sstevel@tonic-gate * able to handle the creation of TPI sockfs sockets.
30010Sstevel@tonic-gate */
30020Sstevel@tonic-gate struct sonode *
socreate(struct sockparams * sp,int family,int type,int protocol,int version,int * errorp)30038348SEric.Yu@Sun.COM socreate(struct sockparams *sp, int family, int type, int protocol, int version,
30048348SEric.Yu@Sun.COM int *errorp)
30050Sstevel@tonic-gate {
30068348SEric.Yu@Sun.COM struct sonode *so;
30078348SEric.Yu@Sun.COM
30088348SEric.Yu@Sun.COM ASSERT(sp != NULL);
30098348SEric.Yu@Sun.COM
30108348SEric.Yu@Sun.COM so = sp->sp_smod_info->smod_sock_create_func(sp, family, type, protocol,
30118348SEric.Yu@Sun.COM version, SOCKET_SLEEP, errorp, CRED());
30128348SEric.Yu@Sun.COM if (so == NULL) {
30138348SEric.Yu@Sun.COM SOCKPARAMS_DEC_REF(sp);
30148348SEric.Yu@Sun.COM } else {
30158348SEric.Yu@Sun.COM if ((*errorp = SOP_INIT(so, NULL, CRED(), SOCKET_SLEEP)) == 0) {
30168348SEric.Yu@Sun.COM /* Cannot fail, only bumps so_count */
30178348SEric.Yu@Sun.COM (void) VOP_OPEN(&SOTOV(so), FREAD|FWRITE, CRED(), NULL);
30188348SEric.Yu@Sun.COM } else {
30198348SEric.Yu@Sun.COM socket_destroy(so);
30208348SEric.Yu@Sun.COM so = NULL;
30218348SEric.Yu@Sun.COM }
30228348SEric.Yu@Sun.COM }
30238348SEric.Yu@Sun.COM return (so);
30240Sstevel@tonic-gate }
3025