10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51548Srshoaib * Common Development and Distribution License (the "License"). 61548Srshoaib * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211548Srshoaib 220Sstevel@tonic-gate /* 23*6707Sbrutus * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/t_lock.h> 310Sstevel@tonic-gate #include <sys/param.h> 320Sstevel@tonic-gate #include <sys/systm.h> 330Sstevel@tonic-gate #include <sys/buf.h> 340Sstevel@tonic-gate #include <sys/conf.h> 350Sstevel@tonic-gate #include <sys/cred.h> 360Sstevel@tonic-gate #include <sys/kmem.h> 370Sstevel@tonic-gate #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/vfs.h> 393898Srsb #include <sys/vfs_opreg.h> 400Sstevel@tonic-gate #include <sys/vnode.h> 410Sstevel@tonic-gate #include <sys/debug.h> 420Sstevel@tonic-gate #include <sys/errno.h> 430Sstevel@tonic-gate #include <sys/time.h> 440Sstevel@tonic-gate #include <sys/file.h> 450Sstevel@tonic-gate #include <sys/open.h> 460Sstevel@tonic-gate #include <sys/user.h> 47*6707Sbrutus #include <sys/uio.h> 480Sstevel@tonic-gate #include <sys/termios.h> 490Sstevel@tonic-gate #include <sys/stream.h> 500Sstevel@tonic-gate #include <sys/strsubr.h> 510Sstevel@tonic-gate #include <sys/strsun.h> 520Sstevel@tonic-gate #include <sys/esunddi.h> 530Sstevel@tonic-gate #include <sys/flock.h> 540Sstevel@tonic-gate #include <sys/modctl.h> 550Sstevel@tonic-gate #include <sys/cmn_err.h> 560Sstevel@tonic-gate #include <sys/mkdev.h> 570Sstevel@tonic-gate #include <sys/pathname.h> 580Sstevel@tonic-gate #include <sys/ddi.h> 590Sstevel@tonic-gate #include <sys/stat.h> 600Sstevel@tonic-gate #include <sys/fs/snode.h> 610Sstevel@tonic-gate #include <sys/fs/dv_node.h> 620Sstevel@tonic-gate #include <sys/zone.h> 630Sstevel@tonic-gate 640Sstevel@tonic-gate #include <sys/socket.h> 650Sstevel@tonic-gate #include <sys/socketvar.h> 660Sstevel@tonic-gate #include <netinet/in.h> 670Sstevel@tonic-gate #include <sys/un.h> 680Sstevel@tonic-gate 690Sstevel@tonic-gate #include <sys/ucred.h> 700Sstevel@tonic-gate 710Sstevel@tonic-gate #include <sys/tiuser.h> 720Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 730Sstevel@tonic-gate #include <sys/tihdr.h> 740Sstevel@tonic-gate 750Sstevel@tonic-gate #include <c2/audit.h> 760Sstevel@tonic-gate 770Sstevel@tonic-gate #include <fs/sockfs/nl7c.h> 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* 800Sstevel@tonic-gate * Macros that operate on struct cmsghdr. 810Sstevel@tonic-gate * The CMSG_VALID macro does not assume that the last option buffer is padded. 820Sstevel@tonic-gate */ 830Sstevel@tonic-gate #define CMSG_CONTENT(cmsg) (&((cmsg)[1])) 840Sstevel@tonic-gate #define CMSG_CONTENTLEN(cmsg) ((cmsg)->cmsg_len - sizeof (struct cmsghdr)) 850Sstevel@tonic-gate #define CMSG_VALID(cmsg, start, end) \ 860Sstevel@tonic-gate (ISALIGNED_cmsghdr(cmsg) && \ 870Sstevel@tonic-gate ((uintptr_t)(cmsg) >= (uintptr_t)(start)) && \ 880Sstevel@tonic-gate ((uintptr_t)(cmsg) < (uintptr_t)(end)) && \ 890Sstevel@tonic-gate ((ssize_t)(cmsg)->cmsg_len >= sizeof (struct cmsghdr)) && \ 900Sstevel@tonic-gate ((uintptr_t)(cmsg) + (cmsg)->cmsg_len <= (uintptr_t)(end))) 910Sstevel@tonic-gate #define SO_LOCK_WAKEUP_TIME 3000 /* Wakeup time in milliseconds */ 920Sstevel@tonic-gate 930Sstevel@tonic-gate static struct kmem_cache *socktpi_cache, *socktpi_unix_cache; 94*6707Sbrutus struct kmem_cache *socktpi_sod_cache; 950Sstevel@tonic-gate 960Sstevel@tonic-gate dev_t sockdev; /* For fsid in getattr */ 970Sstevel@tonic-gate 980Sstevel@tonic-gate struct sockparams *sphead; 990Sstevel@tonic-gate krwlock_t splist_lock; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate struct socklist socklist; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate static int sockfs_update(kstat_t *, int); 1040Sstevel@tonic-gate static int sockfs_snapshot(kstat_t *, void *, int); 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate extern void sendfile_init(); 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate extern void nl7c_init(void); 1090Sstevel@tonic-gate 110*6707Sbrutus extern int sostr_init(); 111*6707Sbrutus 1120Sstevel@tonic-gate #define ADRSTRLEN (2 * sizeof (void *) + 1) 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * kernel structure for passing the sockinfo data back up to the user. 1150Sstevel@tonic-gate * the strings array allows us to convert AF_UNIX addresses into strings 1160Sstevel@tonic-gate * with a common method regardless of which n-bit kernel we're running. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate struct k_sockinfo { 1190Sstevel@tonic-gate struct sockinfo ks_si; 1200Sstevel@tonic-gate char ks_straddr[3][ADRSTRLEN]; 1210Sstevel@tonic-gate }; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate /* 1240Sstevel@tonic-gate * Translate from a device pathname (e.g. "/dev/tcp") to a vnode. 1250Sstevel@tonic-gate * Returns with the vnode held. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate static int 1280Sstevel@tonic-gate sogetvp(char *devpath, vnode_t **vpp, int uioflag) 1290Sstevel@tonic-gate { 1300Sstevel@tonic-gate struct snode *csp; 1310Sstevel@tonic-gate vnode_t *vp, *dvp; 1320Sstevel@tonic-gate major_t maj; 1330Sstevel@tonic-gate int error; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate ASSERT(uioflag == UIO_SYSSPACE || uioflag == UIO_USERSPACE); 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * Lookup the underlying filesystem vnode. 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate error = lookupname(devpath, uioflag, FOLLOW, NULLVPP, &vp); 1400Sstevel@tonic-gate if (error) 1410Sstevel@tonic-gate return (error); 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* Check that it is the correct vnode */ 1440Sstevel@tonic-gate if (vp->v_type != VCHR) { 1450Sstevel@tonic-gate VN_RELE(vp); 1460Sstevel@tonic-gate return (ENOTSOCK); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate /* 1500Sstevel@tonic-gate * If devpath went through devfs, the device should already 1510Sstevel@tonic-gate * be configured. If devpath is a mknod file, however, we 1520Sstevel@tonic-gate * need to make sure the device is properly configured. 1530Sstevel@tonic-gate * To do this, we do something similar to spec_open() 1540Sstevel@tonic-gate * except that we resolve to the minor/leaf level since 1550Sstevel@tonic-gate * we need to return a vnode. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate csp = VTOS(VTOS(vp)->s_commonvp); 1580Sstevel@tonic-gate if (!(csp->s_flag & SDIPSET)) { 1590Sstevel@tonic-gate char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1600Sstevel@tonic-gate error = ddi_dev_pathname(vp->v_rdev, S_IFCHR, pathname); 1610Sstevel@tonic-gate if (error == 0) 1620Sstevel@tonic-gate error = devfs_lookupname(pathname, NULLVPP, &dvp); 1630Sstevel@tonic-gate VN_RELE(vp); 1640Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 1650Sstevel@tonic-gate if (error != 0) 1660Sstevel@tonic-gate return (ENXIO); 1670Sstevel@tonic-gate vp = dvp; /* use the devfs vp */ 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate /* device is configured at this point */ 1710Sstevel@tonic-gate maj = getmajor(vp->v_rdev); 1720Sstevel@tonic-gate if (!STREAMSTAB(maj)) { 1730Sstevel@tonic-gate VN_RELE(vp); 1740Sstevel@tonic-gate return (ENOSTR); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate *vpp = vp; 1780Sstevel@tonic-gate return (0); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * Add or delete (latter if devpath is NULL) an enter to the sockparams 1830Sstevel@tonic-gate * table. If devpathlen is zero the devpath with not be kmem_freed. Otherwise 1840Sstevel@tonic-gate * this routine assumes that the caller has kmem_alloced devpath/devpathlen 1850Sstevel@tonic-gate * for this routine to consume. 1860Sstevel@tonic-gate * The zero devpathlen could be used if the kernel wants to create entries 1870Sstevel@tonic-gate * itself by calling sockconfig(1,2,3, "/dev/tcp", 0); 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate int 1900Sstevel@tonic-gate soconfig(int domain, int type, int protocol, 1910Sstevel@tonic-gate char *devpath, int devpathlen) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate struct sockparams **spp; 1940Sstevel@tonic-gate struct sockparams *sp; 1950Sstevel@tonic-gate int error = 0; 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate dprint(0, ("soconfig(%d,%d,%d,%s,%d)\n", 1985753Sgww domain, type, protocol, devpath, devpathlen)); 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* 2010Sstevel@tonic-gate * Look for an existing match. 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate rw_enter(&splist_lock, RW_WRITER); 2040Sstevel@tonic-gate for (spp = &sphead; (sp = *spp) != NULL; spp = &sp->sp_next) { 2050Sstevel@tonic-gate if (sp->sp_domain == domain && 2060Sstevel@tonic-gate sp->sp_type == type && 2070Sstevel@tonic-gate sp->sp_protocol == protocol) { 2080Sstevel@tonic-gate break; 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate if (devpath == NULL) { 2120Sstevel@tonic-gate ASSERT(devpathlen == 0); 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate /* Delete existing entry */ 2150Sstevel@tonic-gate if (sp == NULL) { 2160Sstevel@tonic-gate error = ENXIO; 2170Sstevel@tonic-gate goto done; 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate /* Unlink and free existing entry */ 2200Sstevel@tonic-gate *spp = sp->sp_next; 2210Sstevel@tonic-gate ASSERT(sp->sp_vnode); 2220Sstevel@tonic-gate VN_RELE(sp->sp_vnode); 2230Sstevel@tonic-gate if (sp->sp_devpathlen != 0) 2240Sstevel@tonic-gate kmem_free(sp->sp_devpath, sp->sp_devpathlen); 2250Sstevel@tonic-gate kmem_free(sp, sizeof (*sp)); 2260Sstevel@tonic-gate } else { 2270Sstevel@tonic-gate vnode_t *vp; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* Add new entry */ 2300Sstevel@tonic-gate if (sp != NULL) { 2310Sstevel@tonic-gate error = EEXIST; 2320Sstevel@tonic-gate goto done; 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate error = sogetvp(devpath, &vp, UIO_SYSSPACE); 2360Sstevel@tonic-gate if (error) { 2370Sstevel@tonic-gate dprint(0, ("soconfig: vp %s failed with %d\n", 2385753Sgww devpath, error)); 2390Sstevel@tonic-gate goto done; 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate dprint(0, ("soconfig: %s => vp %p, dev 0x%lx\n", 2430Sstevel@tonic-gate devpath, vp, vp->v_rdev)); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate sp = kmem_alloc(sizeof (*sp), KM_SLEEP); 2460Sstevel@tonic-gate sp->sp_domain = domain; 2470Sstevel@tonic-gate sp->sp_type = type; 2480Sstevel@tonic-gate sp->sp_protocol = protocol; 2490Sstevel@tonic-gate sp->sp_devpath = devpath; 2500Sstevel@tonic-gate sp->sp_devpathlen = devpathlen; 2510Sstevel@tonic-gate sp->sp_vnode = vp; 2520Sstevel@tonic-gate sp->sp_next = NULL; 2530Sstevel@tonic-gate *spp = sp; 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate done: 2560Sstevel@tonic-gate rw_exit(&splist_lock); 2570Sstevel@tonic-gate if (error) { 2580Sstevel@tonic-gate if (devpath != NULL) 2590Sstevel@tonic-gate kmem_free(devpath, devpathlen); 2600Sstevel@tonic-gate #ifdef SOCK_DEBUG 2610Sstevel@tonic-gate eprintline(error); 2620Sstevel@tonic-gate #endif /* SOCK_DEBUG */ 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate return (error); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate /* 2680Sstevel@tonic-gate * Lookup an entry in the sockparams list based on the triple. 2690Sstevel@tonic-gate * If no entry is found and devpath is not NULL translate devpath to a 2700Sstevel@tonic-gate * vnode. Note that devpath is a pointer to a user address! 2710Sstevel@tonic-gate * Returns with the vnode held. 2720Sstevel@tonic-gate * 2730Sstevel@tonic-gate * When this routine uses devpath it does not create an entry in the sockparams 2740Sstevel@tonic-gate * list since this routine can run on behalf of any user and one user 2750Sstevel@tonic-gate * should not be able to effect the transport used by another user. 2760Sstevel@tonic-gate * 2770Sstevel@tonic-gate * In order to return the correct error this routine has to do wildcard scans 2780Sstevel@tonic-gate * of the list. The errors are (in decreasing precedence): 2790Sstevel@tonic-gate * EAFNOSUPPORT - address family not in list 2800Sstevel@tonic-gate * EPROTONOSUPPORT - address family supported but not protocol. 2810Sstevel@tonic-gate * EPROTOTYPE - address family and protocol supported but not socket type. 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate vnode_t * 2840Sstevel@tonic-gate solookup(int domain, int type, int protocol, char *devpath, int *errorp) 2850Sstevel@tonic-gate { 2860Sstevel@tonic-gate struct sockparams *sp; 2870Sstevel@tonic-gate int error; 2880Sstevel@tonic-gate vnode_t *vp; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate rw_enter(&splist_lock, RW_READER); 2910Sstevel@tonic-gate for (sp = sphead; sp != NULL; sp = sp->sp_next) { 2920Sstevel@tonic-gate if (sp->sp_domain == domain && 2930Sstevel@tonic-gate sp->sp_type == type && 2940Sstevel@tonic-gate sp->sp_protocol == protocol) { 2950Sstevel@tonic-gate break; 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate if (sp == NULL) { 2990Sstevel@tonic-gate dprint(0, ("solookup(%d,%d,%d) not found\n", 3005753Sgww domain, type, protocol)); 3010Sstevel@tonic-gate if (devpath == NULL) { 3020Sstevel@tonic-gate /* Determine correct error code */ 3030Sstevel@tonic-gate int found = 0; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate for (sp = sphead; sp != NULL; sp = sp->sp_next) { 3060Sstevel@tonic-gate if (sp->sp_domain == domain && found < 1) 3070Sstevel@tonic-gate found = 1; 3080Sstevel@tonic-gate if (sp->sp_domain == domain && 3090Sstevel@tonic-gate sp->sp_protocol == protocol && found < 2) 3100Sstevel@tonic-gate found = 2; 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate rw_exit(&splist_lock); 3130Sstevel@tonic-gate switch (found) { 3140Sstevel@tonic-gate case 0: 3150Sstevel@tonic-gate *errorp = EAFNOSUPPORT; 3160Sstevel@tonic-gate break; 3170Sstevel@tonic-gate case 1: 3180Sstevel@tonic-gate *errorp = EPROTONOSUPPORT; 3190Sstevel@tonic-gate break; 3200Sstevel@tonic-gate case 2: 3210Sstevel@tonic-gate *errorp = EPROTOTYPE; 3220Sstevel@tonic-gate break; 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate return (NULL); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate rw_exit(&splist_lock); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * Return vp based on devpath. 3300Sstevel@tonic-gate * Do not enter into table to avoid random users 3310Sstevel@tonic-gate * modifying the sockparams list. 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate error = sogetvp(devpath, &vp, UIO_USERSPACE); 3340Sstevel@tonic-gate if (error) { 3350Sstevel@tonic-gate dprint(0, ("solookup: vp %p failed with %d\n", 3365753Sgww devpath, error)); 3370Sstevel@tonic-gate *errorp = EPROTONOSUPPORT; 3380Sstevel@tonic-gate return (NULL); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate dprint(0, ("solookup: %p => vp %p, dev 0x%lx\n", 3410Sstevel@tonic-gate devpath, vp, vp->v_rdev)); 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate return (vp); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate dprint(0, ("solookup(%d,%d,%d) vp %p devpath %s\n", 3465753Sgww domain, type, protocol, sp->sp_vnode, sp->sp_devpath)); 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate vp = sp->sp_vnode; 3490Sstevel@tonic-gate VN_HOLD(vp); 3500Sstevel@tonic-gate rw_exit(&splist_lock); 3510Sstevel@tonic-gate return (vp); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * Return a socket vnode. 3560Sstevel@tonic-gate * 3570Sstevel@tonic-gate * Assumes that the caller is "passing" an VN_HOLD for accessvp i.e. 3580Sstevel@tonic-gate * when the socket is freed a VN_RELE will take place. 3590Sstevel@tonic-gate * 3600Sstevel@tonic-gate * Note that sockets assume that the driver will clone (either itself 3610Sstevel@tonic-gate * or by using the clone driver) i.e. a socket() call will always 3620Sstevel@tonic-gate * result in a new vnode being created. 3630Sstevel@tonic-gate */ 3640Sstevel@tonic-gate struct vnode * 3650Sstevel@tonic-gate makesockvp(struct vnode *accessvp, int domain, int type, int protocol) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate kmem_cache_t *cp; 3680Sstevel@tonic-gate struct sonode *so; 3690Sstevel@tonic-gate struct vnode *vp; 3700Sstevel@tonic-gate time_t now; 3710Sstevel@tonic-gate dev_t dev; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate cp = (domain == AF_UNIX) ? socktpi_unix_cache : socktpi_cache; 3740Sstevel@tonic-gate so = kmem_cache_alloc(cp, KM_SLEEP); 3750Sstevel@tonic-gate so->so_cache = cp; 3760Sstevel@tonic-gate so->so_obj = so; 3770Sstevel@tonic-gate vp = SOTOV(so); 3780Sstevel@tonic-gate now = gethrestime_sec(); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate so->so_flag = 0; 3810Sstevel@tonic-gate ASSERT(so->so_accessvp == NULL); 3820Sstevel@tonic-gate so->so_accessvp = accessvp; 3830Sstevel@tonic-gate dev = accessvp->v_rdev; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate /* 3860Sstevel@tonic-gate * Record in so_flag that it is a clone. 3870Sstevel@tonic-gate */ 3880Sstevel@tonic-gate if (getmajor(dev) == clone_major) { 3890Sstevel@tonic-gate so->so_flag |= SOCLONE; 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate so->so_dev = dev; 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate so->so_state = 0; 3940Sstevel@tonic-gate so->so_mode = 0; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate so->so_fsid = sockdev; 3970Sstevel@tonic-gate so->so_atime = now; 3980Sstevel@tonic-gate so->so_mtime = now; 3990Sstevel@tonic-gate so->so_ctime = now; /* Never modified */ 4000Sstevel@tonic-gate so->so_count = 0; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate so->so_family = (short)domain; 4030Sstevel@tonic-gate so->so_type = (short)type; 4040Sstevel@tonic-gate so->so_protocol = (short)protocol; 4050Sstevel@tonic-gate so->so_pushcnt = 0; 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate so->so_options = 0; 4080Sstevel@tonic-gate so->so_linger.l_onoff = 0; 4090Sstevel@tonic-gate so->so_linger.l_linger = 0; 4100Sstevel@tonic-gate so->so_sndbuf = 0; 4110Sstevel@tonic-gate so->so_rcvbuf = 0; 4120Sstevel@tonic-gate so->so_sndlowat = 0; 4130Sstevel@tonic-gate so->so_rcvlowat = 0; 4140Sstevel@tonic-gate #ifdef notyet 4150Sstevel@tonic-gate so->so_sndtimeo = 0; 4160Sstevel@tonic-gate so->so_rcvtimeo = 0; 4170Sstevel@tonic-gate #endif /* notyet */ 4180Sstevel@tonic-gate so->so_error = 0; 4190Sstevel@tonic-gate so->so_delayed_error = 0; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 4220Sstevel@tonic-gate so->so_oobcnt = 0; 4230Sstevel@tonic-gate so->so_oobsigcnt = 0; 4240Sstevel@tonic-gate so->so_pgrp = 0; 4250Sstevel@tonic-gate so->so_provinfo = NULL; 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate ASSERT(so->so_laddr_sa == NULL && so->so_faddr_sa == NULL); 4280Sstevel@tonic-gate so->so_laddr_len = so->so_faddr_len = 0; 4290Sstevel@tonic-gate so->so_laddr_maxlen = so->so_faddr_maxlen = 0; 4300Sstevel@tonic-gate so->so_eaddr_mp = NULL; 4310Sstevel@tonic-gate so->so_priv = NULL; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate so->so_peercred = NULL; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate ASSERT(so->so_ack_mp == NULL); 4360Sstevel@tonic-gate ASSERT(so->so_conn_ind_head == NULL); 4370Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 4380Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 4390Sstevel@tonic-gate ASSERT(so->so_unbind_mp == NULL); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate vn_reinit(vp); 4420Sstevel@tonic-gate vp->v_vfsp = rootvfs; 4430Sstevel@tonic-gate vp->v_type = VSOCK; 4440Sstevel@tonic-gate vp->v_rdev = so->so_dev; 4450Sstevel@tonic-gate vn_exists(vp); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate return (vp); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate void 4510Sstevel@tonic-gate sockfree(struct sonode *so) 4520Sstevel@tonic-gate { 4530Sstevel@tonic-gate mblk_t *mp; 4540Sstevel@tonic-gate vnode_t *vp; 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate ASSERT(so->so_count == 0); 4570Sstevel@tonic-gate ASSERT(so->so_accessvp); 4580Sstevel@tonic-gate ASSERT(so->so_discon_ind_mp == NULL); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate vp = so->so_accessvp; 4610Sstevel@tonic-gate VN_RELE(vp); 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * Protect so->so_[lf]addr_sa so that sockfs_snapshot() can safely 4650Sstevel@tonic-gate * indirect them. It also uses so_accessvp as a validity test. 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate mutex_enter(&so->so_lock); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate so->so_accessvp = NULL; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate if (so->so_laddr_sa) { 4720Sstevel@tonic-gate ASSERT((caddr_t)so->so_faddr_sa == 4730Sstevel@tonic-gate (caddr_t)so->so_laddr_sa + so->so_laddr_maxlen); 4740Sstevel@tonic-gate ASSERT(so->so_faddr_maxlen == so->so_laddr_maxlen); 4750Sstevel@tonic-gate so->so_state &= ~(SS_LADDR_VALID | SS_FADDR_VALID); 4760Sstevel@tonic-gate kmem_free(so->so_laddr_sa, so->so_laddr_maxlen * 2); 4770Sstevel@tonic-gate so->so_laddr_sa = NULL; 4780Sstevel@tonic-gate so->so_laddr_len = so->so_laddr_maxlen = 0; 4790Sstevel@tonic-gate so->so_faddr_sa = NULL; 4800Sstevel@tonic-gate so->so_faddr_len = so->so_faddr_maxlen = 0; 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate mutex_exit(&so->so_lock); 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate if ((mp = so->so_eaddr_mp) != NULL) { 4860Sstevel@tonic-gate freemsg(mp); 4870Sstevel@tonic-gate so->so_eaddr_mp = NULL; 4880Sstevel@tonic-gate so->so_delayed_error = 0; 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate if ((mp = so->so_ack_mp) != NULL) { 4910Sstevel@tonic-gate freemsg(mp); 4920Sstevel@tonic-gate so->so_ack_mp = NULL; 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate if ((mp = so->so_conn_ind_head) != NULL) { 4950Sstevel@tonic-gate mblk_t *mp1; 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate while (mp) { 4980Sstevel@tonic-gate mp1 = mp->b_next; 4990Sstevel@tonic-gate mp->b_next = NULL; 5000Sstevel@tonic-gate freemsg(mp); 5010Sstevel@tonic-gate mp = mp1; 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate so->so_conn_ind_head = so->so_conn_ind_tail = NULL; 5040Sstevel@tonic-gate so->so_state &= ~SS_HASCONNIND; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate #ifdef DEBUG 5070Sstevel@tonic-gate mutex_enter(&so->so_lock); 5080Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 5090Sstevel@tonic-gate mutex_exit(&so->so_lock); 5100Sstevel@tonic-gate #endif /* DEBUG */ 5110Sstevel@tonic-gate if ((mp = so->so_oobmsg) != NULL) { 5120Sstevel@tonic-gate freemsg(mp); 5130Sstevel@tonic-gate so->so_oobmsg = NULL; 5140Sstevel@tonic-gate so->so_state &= ~(SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA); 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate if ((mp = so->so_nl7c_rcv_mp) != NULL) { 5180Sstevel@tonic-gate so->so_nl7c_rcv_mp = NULL; 5190Sstevel@tonic-gate freemsg(mp); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate so->so_nl7c_rcv_rval = 0; 5220Sstevel@tonic-gate if (so->so_nl7c_uri != NULL) { 5230Sstevel@tonic-gate nl7c_urifree(so); 5241974Sbrutus /* urifree() cleared nl7c_uri */ 5250Sstevel@tonic-gate } 5261974Sbrutus if (so->so_nl7c_flags) { 5271974Sbrutus so->so_nl7c_flags = 0; 5281974Sbrutus } 5290Sstevel@tonic-gate 530*6707Sbrutus if (so->so_direct != NULL) { 531*6707Sbrutus sodirect_t *sodp = so->so_direct; 532*6707Sbrutus 533*6707Sbrutus ASSERT(sodp->sod_uioafh == NULL); 534*6707Sbrutus 535*6707Sbrutus so->so_direct = NULL; 536*6707Sbrutus kmem_cache_free(socktpi_sod_cache, sodp); 537*6707Sbrutus } 538*6707Sbrutus 5390Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 5400Sstevel@tonic-gate if ((mp = so->so_unbind_mp) != NULL) { 5410Sstevel@tonic-gate freemsg(mp); 5420Sstevel@tonic-gate so->so_unbind_mp = NULL; 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate vn_invalid(SOTOV(so)); 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate if (so->so_peercred != NULL) 5470Sstevel@tonic-gate crfree(so->so_peercred); 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate kmem_cache_free(so->so_cache, so->so_obj); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate /* 5530Sstevel@tonic-gate * Update the accessed, updated, or changed times in an sonode 5540Sstevel@tonic-gate * with the current time. 5550Sstevel@tonic-gate * 5560Sstevel@tonic-gate * Note that both SunOS 4.X and 4.4BSD sockets do not present reasonable 5570Sstevel@tonic-gate * attributes in a fstat call. (They return the current time and 0 for 5580Sstevel@tonic-gate * all timestamps, respectively.) We maintain the current timestamps 5590Sstevel@tonic-gate * here primarily so that should sockmod be popped the resulting 5600Sstevel@tonic-gate * file descriptor will behave like a stream w.r.t. the timestamps. 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate void 5630Sstevel@tonic-gate so_update_attrs(struct sonode *so, int flag) 5640Sstevel@tonic-gate { 5650Sstevel@tonic-gate time_t now = gethrestime_sec(); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate mutex_enter(&so->so_lock); 5680Sstevel@tonic-gate so->so_flag |= flag; 5690Sstevel@tonic-gate if (flag & SOACC) 5700Sstevel@tonic-gate so->so_atime = now; 5710Sstevel@tonic-gate if (flag & SOMOD) 5720Sstevel@tonic-gate so->so_mtime = now; 5730Sstevel@tonic-gate mutex_exit(&so->so_lock); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /*ARGSUSED*/ 5770Sstevel@tonic-gate static int 5780Sstevel@tonic-gate socktpi_constructor(void *buf, void *cdrarg, int kmflags) 5790Sstevel@tonic-gate { 5800Sstevel@tonic-gate struct sonode *so = buf; 5810Sstevel@tonic-gate struct vnode *vp; 5820Sstevel@tonic-gate 583*6707Sbrutus so->so_direct = NULL; 584*6707Sbrutus 5850Sstevel@tonic-gate so->so_nl7c_flags = 0; 5860Sstevel@tonic-gate so->so_nl7c_uri = NULL; 5870Sstevel@tonic-gate so->so_nl7c_rcv_mp = NULL; 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate so->so_oobmsg = NULL; 5900Sstevel@tonic-gate so->so_ack_mp = NULL; 5910Sstevel@tonic-gate so->so_conn_ind_head = NULL; 5920Sstevel@tonic-gate so->so_conn_ind_tail = NULL; 5930Sstevel@tonic-gate so->so_discon_ind_mp = NULL; 5940Sstevel@tonic-gate so->so_ux_bound_vp = NULL; 5950Sstevel@tonic-gate so->so_unbind_mp = NULL; 5960Sstevel@tonic-gate so->so_accessvp = NULL; 5970Sstevel@tonic-gate so->so_laddr_sa = NULL; 5980Sstevel@tonic-gate so->so_faddr_sa = NULL; 5990Sstevel@tonic-gate so->so_ops = &sotpi_sonodeops; 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP); 6020Sstevel@tonic-gate so->so_vnode = vp; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate vn_setops(vp, socktpi_vnodeops); 6050Sstevel@tonic-gate vp->v_data = (caddr_t)so; 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate mutex_init(&so->so_lock, NULL, MUTEX_DEFAULT, NULL); 6080Sstevel@tonic-gate mutex_init(&so->so_plumb_lock, NULL, MUTEX_DEFAULT, NULL); 6090Sstevel@tonic-gate cv_init(&so->so_state_cv, NULL, CV_DEFAULT, NULL); 6100Sstevel@tonic-gate cv_init(&so->so_ack_cv, NULL, CV_DEFAULT, NULL); 6110Sstevel@tonic-gate cv_init(&so->so_connind_cv, NULL, CV_DEFAULT, NULL); 6120Sstevel@tonic-gate cv_init(&so->so_want_cv, NULL, CV_DEFAULT, NULL); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate return (0); 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate /*ARGSUSED1*/ 6180Sstevel@tonic-gate static void 6190Sstevel@tonic-gate socktpi_destructor(void *buf, void *cdrarg) 6200Sstevel@tonic-gate { 6210Sstevel@tonic-gate struct sonode *so = buf; 6220Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 6230Sstevel@tonic-gate 624*6707Sbrutus ASSERT(so->so_direct == NULL); 625*6707Sbrutus 6260Sstevel@tonic-gate ASSERT(so->so_nl7c_flags == 0); 6270Sstevel@tonic-gate ASSERT(so->so_nl7c_uri == NULL); 6280Sstevel@tonic-gate ASSERT(so->so_nl7c_rcv_mp == NULL); 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 6310Sstevel@tonic-gate ASSERT(so->so_ack_mp == NULL); 6320Sstevel@tonic-gate ASSERT(so->so_conn_ind_head == NULL); 6330Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 6340Sstevel@tonic-gate ASSERT(so->so_discon_ind_mp == NULL); 6350Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 6360Sstevel@tonic-gate ASSERT(so->so_unbind_mp == NULL); 6370Sstevel@tonic-gate ASSERT(so->so_ops == &sotpi_sonodeops); 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate ASSERT(vn_matchops(vp, socktpi_vnodeops)); 6400Sstevel@tonic-gate ASSERT(vp->v_data == (caddr_t)so); 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate vn_free(vp); 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate mutex_destroy(&so->so_lock); 6450Sstevel@tonic-gate mutex_destroy(&so->so_plumb_lock); 6460Sstevel@tonic-gate cv_destroy(&so->so_state_cv); 6470Sstevel@tonic-gate cv_destroy(&so->so_ack_cv); 6480Sstevel@tonic-gate cv_destroy(&so->so_connind_cv); 6490Sstevel@tonic-gate cv_destroy(&so->so_want_cv); 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate static int 6530Sstevel@tonic-gate socktpi_unix_constructor(void *buf, void *cdrarg, int kmflags) 6540Sstevel@tonic-gate { 6550Sstevel@tonic-gate int retval; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate if ((retval = socktpi_constructor(buf, cdrarg, kmflags)) == 0) { 6580Sstevel@tonic-gate struct sonode *so = (struct sonode *)buf; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate mutex_enter(&socklist.sl_lock); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate so->so_next = socklist.sl_list; 6630Sstevel@tonic-gate so->so_prev = NULL; 6640Sstevel@tonic-gate if (so->so_next != NULL) 6650Sstevel@tonic-gate so->so_next->so_prev = so; 6660Sstevel@tonic-gate socklist.sl_list = so; 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate mutex_exit(&socklist.sl_lock); 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate return (retval); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate static void 6750Sstevel@tonic-gate socktpi_unix_destructor(void *buf, void *cdrarg) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate struct sonode *so = (struct sonode *)buf; 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate mutex_enter(&socklist.sl_lock); 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate if (so->so_next != NULL) 6820Sstevel@tonic-gate so->so_next->so_prev = so->so_prev; 6830Sstevel@tonic-gate if (so->so_prev != NULL) 6840Sstevel@tonic-gate so->so_prev->so_next = so->so_next; 6850Sstevel@tonic-gate else 6860Sstevel@tonic-gate socklist.sl_list = so->so_next; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate mutex_exit(&socklist.sl_lock); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate socktpi_destructor(buf, cdrarg); 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate /* 6940Sstevel@tonic-gate * Init function called when sockfs is loaded. 6950Sstevel@tonic-gate */ 6960Sstevel@tonic-gate int 6970Sstevel@tonic-gate sockinit(int fstype, char *name) 6980Sstevel@tonic-gate { 6990Sstevel@tonic-gate static const fs_operation_def_t sock_vfsops_template[] = { 7000Sstevel@tonic-gate NULL, NULL 7010Sstevel@tonic-gate }; 7020Sstevel@tonic-gate int error; 7030Sstevel@tonic-gate major_t dev; 7040Sstevel@tonic-gate char *err_str; 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate error = vfs_setfsops(fstype, sock_vfsops_template, NULL); 7070Sstevel@tonic-gate if (error != 0) { 7081548Srshoaib zcmn_err(GLOBAL_ZONEID, CE_WARN, 7091548Srshoaib "sockinit: bad vfs ops template"); 7100Sstevel@tonic-gate return (error); 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate error = vn_make_ops(name, socktpi_vnodeops_template, &socktpi_vnodeops); 7140Sstevel@tonic-gate if (error != 0) { 7150Sstevel@tonic-gate err_str = "sockinit: bad sock vnode ops template"; 7160Sstevel@tonic-gate /* vn_make_ops() does not reset socktpi_vnodeops on failure. */ 7170Sstevel@tonic-gate socktpi_vnodeops = NULL; 7180Sstevel@tonic-gate goto failure; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate error = sosctp_init(); 7220Sstevel@tonic-gate if (error != 0) { 7230Sstevel@tonic-gate err_str = NULL; 7240Sstevel@tonic-gate goto failure; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 7273422Snh145002 error = sosdp_init(); 7283422Snh145002 if (error != 0) { 7293422Snh145002 err_str = NULL; 7303422Snh145002 goto failure; 7313422Snh145002 } 7323422Snh145002 733*6707Sbrutus error = sostr_init(); 734*6707Sbrutus if (error != 0) { 735*6707Sbrutus err_str = NULL; 736*6707Sbrutus goto failure; 737*6707Sbrutus } 738*6707Sbrutus 7390Sstevel@tonic-gate /* 7400Sstevel@tonic-gate * Create sonode caches. We create a special one for AF_UNIX so 7410Sstevel@tonic-gate * that we can track them for netstat(1m). 7420Sstevel@tonic-gate */ 7430Sstevel@tonic-gate socktpi_cache = kmem_cache_create("socktpi_cache", 7440Sstevel@tonic-gate sizeof (struct sonode), 0, socktpi_constructor, 7450Sstevel@tonic-gate socktpi_destructor, NULL, NULL, NULL, 0); 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate socktpi_unix_cache = kmem_cache_create("socktpi_unix_cache", 7480Sstevel@tonic-gate sizeof (struct sonode), 0, socktpi_unix_constructor, 7490Sstevel@tonic-gate socktpi_unix_destructor, NULL, NULL, NULL, 0); 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate /* 7520Sstevel@tonic-gate * Build initial list mapping socket parameters to vnode. 7530Sstevel@tonic-gate */ 7540Sstevel@tonic-gate rw_init(&splist_lock, NULL, RW_DEFAULT, NULL); 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* 7570Sstevel@tonic-gate * If sockets are needed before init runs /sbin/soconfig 7580Sstevel@tonic-gate * it is possible to preload the sockparams list here using 7590Sstevel@tonic-gate * calls like: 7600Sstevel@tonic-gate * sockconfig(1,2,3, "/dev/tcp", 0); 7610Sstevel@tonic-gate */ 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * Create a unique dev_t for use in so_fsid. 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate if ((dev = getudev()) == (major_t)-1) 7680Sstevel@tonic-gate dev = 0; 7690Sstevel@tonic-gate sockdev = makedevice(dev, 0); 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate mutex_init(&socklist.sl_lock, NULL, MUTEX_DEFAULT, NULL); 7720Sstevel@tonic-gate sendfile_init(); 7730Sstevel@tonic-gate nl7c_init(); 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate return (0); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate failure: 7780Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 7790Sstevel@tonic-gate if (socktpi_vnodeops != NULL) 7800Sstevel@tonic-gate vn_freevnodeops(socktpi_vnodeops); 7810Sstevel@tonic-gate if (err_str != NULL) 7821548Srshoaib zcmn_err(GLOBAL_ZONEID, CE_WARN, err_str); 7830Sstevel@tonic-gate return (error); 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate /* 7870Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOLOCKED. 7880Sstevel@tonic-gate */ 7890Sstevel@tonic-gate void 7900Sstevel@tonic-gate so_lock_single(struct sonode *so) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate while (so->so_flag & (SOLOCKED | SOASYNC_UNBIND)) { 7950Sstevel@tonic-gate so->so_flag |= SOWANT; 7960Sstevel@tonic-gate cv_wait_stop(&so->so_want_cv, &so->so_lock, 7975753Sgww SO_LOCK_WAKEUP_TIME); 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate so->so_flag |= SOLOCKED; 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* 8030Sstevel@tonic-gate * Caller must hold the mutex and pass in SOLOCKED or SOASYNC_UNBIND. 8040Sstevel@tonic-gate * Used to clear SOLOCKED or SOASYNC_UNBIND. 8050Sstevel@tonic-gate */ 8060Sstevel@tonic-gate void 8070Sstevel@tonic-gate so_unlock_single(struct sonode *so, int flag) 8080Sstevel@tonic-gate { 8090Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8100Sstevel@tonic-gate ASSERT(flag & (SOLOCKED|SOASYNC_UNBIND)); 8110Sstevel@tonic-gate ASSERT((flag & ~(SOLOCKED|SOASYNC_UNBIND)) == 0); 8120Sstevel@tonic-gate ASSERT(so->so_flag & flag); 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* 8150Sstevel@tonic-gate * Process the T_DISCON_IND on so_discon_ind_mp. 8160Sstevel@tonic-gate * 8170Sstevel@tonic-gate * Call to so_drain_discon_ind will result in so_lock 8180Sstevel@tonic-gate * being dropped and re-acquired later. 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate if (so->so_discon_ind_mp != NULL) 8210Sstevel@tonic-gate so_drain_discon_ind(so); 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate if (so->so_flag & SOWANT) 8240Sstevel@tonic-gate cv_broadcast(&so->so_want_cv); 8250Sstevel@tonic-gate so->so_flag &= ~(SOWANT|flag); 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate /* 8290Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOREADLOCKED. 8300Sstevel@tonic-gate * If the caller wants nonblocking behavior it should set fmode. 8310Sstevel@tonic-gate */ 8320Sstevel@tonic-gate int 8330Sstevel@tonic-gate so_lock_read(struct sonode *so, int fmode) 8340Sstevel@tonic-gate { 8350Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 8380Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 8390Sstevel@tonic-gate return (EWOULDBLOCK); 8400Sstevel@tonic-gate so->so_flag |= SOWANT; 8410Sstevel@tonic-gate cv_wait_stop(&so->so_want_cv, &so->so_lock, 8425753Sgww SO_LOCK_WAKEUP_TIME); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 8450Sstevel@tonic-gate return (0); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * Like so_lock_read above but allows signals. 8500Sstevel@tonic-gate */ 8510Sstevel@tonic-gate int 8520Sstevel@tonic-gate so_lock_read_intr(struct sonode *so, int fmode) 8530Sstevel@tonic-gate { 8540Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 8570Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 8580Sstevel@tonic-gate return (EWOULDBLOCK); 8590Sstevel@tonic-gate so->so_flag |= SOWANT; 8600Sstevel@tonic-gate if (!cv_wait_sig(&so->so_want_cv, &so->so_lock)) 8610Sstevel@tonic-gate return (EINTR); 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 8640Sstevel@tonic-gate return (0); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * Caller must hold the mutex. Used to clear SOREADLOCKED, 8690Sstevel@tonic-gate * set in so_lock_read() or so_lock_read_intr(). 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate void 8720Sstevel@tonic-gate so_unlock_read(struct sonode *so) 8730Sstevel@tonic-gate { 8740Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8750Sstevel@tonic-gate ASSERT(so->so_flag & SOREADLOCKED); 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate if (so->so_flag & SOWANT) 8780Sstevel@tonic-gate cv_broadcast(&so->so_want_cv); 8790Sstevel@tonic-gate so->so_flag &= ~(SOWANT|SOREADLOCKED); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * Verify that the specified offset falls within the mblk and 8840Sstevel@tonic-gate * that the resulting pointer is aligned. 8850Sstevel@tonic-gate * Returns NULL if not. 8860Sstevel@tonic-gate */ 8870Sstevel@tonic-gate void * 8880Sstevel@tonic-gate sogetoff(mblk_t *mp, t_uscalar_t offset, 8890Sstevel@tonic-gate t_uscalar_t length, uint_t align_size) 8900Sstevel@tonic-gate { 8910Sstevel@tonic-gate uintptr_t ptr1, ptr2; 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate ASSERT(mp && mp->b_wptr >= mp->b_rptr); 8940Sstevel@tonic-gate ptr1 = (uintptr_t)mp->b_rptr + offset; 8950Sstevel@tonic-gate ptr2 = (uintptr_t)ptr1 + length; 8960Sstevel@tonic-gate if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) { 8970Sstevel@tonic-gate eprintline(0); 8980Sstevel@tonic-gate return (NULL); 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate if ((ptr1 & (align_size - 1)) != 0) { 9010Sstevel@tonic-gate eprintline(0); 9020Sstevel@tonic-gate return (NULL); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate return ((void *)ptr1); 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate /* 9080Sstevel@tonic-gate * Return the AF_UNIX underlying filesystem vnode matching a given name. 9090Sstevel@tonic-gate * Makes sure the sending and the destination sonodes are compatible. 9100Sstevel@tonic-gate * The vnode is returned held. 9110Sstevel@tonic-gate * 9120Sstevel@tonic-gate * The underlying filesystem VSOCK vnode has a v_stream pointer that 9130Sstevel@tonic-gate * references the actual stream head (hence indirectly the actual sonode). 9140Sstevel@tonic-gate */ 9150Sstevel@tonic-gate static int 9160Sstevel@tonic-gate so_ux_lookup(struct sonode *so, struct sockaddr_un *soun, int checkaccess, 9170Sstevel@tonic-gate vnode_t **vpp) 9180Sstevel@tonic-gate { 9190Sstevel@tonic-gate vnode_t *vp; /* Underlying filesystem vnode */ 9200Sstevel@tonic-gate vnode_t *svp; /* sockfs vnode */ 9210Sstevel@tonic-gate struct sonode *so2; 9220Sstevel@tonic-gate int error; 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate dprintso(so, 1, ("so_ux_lookup(%p) name <%s>\n", 9255753Sgww so, soun->sun_path)); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate error = lookupname(soun->sun_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 9280Sstevel@tonic-gate if (error) { 9290Sstevel@tonic-gate eprintsoline(so, error); 9300Sstevel@tonic-gate return (error); 9310Sstevel@tonic-gate } 9320Sstevel@tonic-gate if (vp->v_type != VSOCK) { 9330Sstevel@tonic-gate error = ENOTSOCK; 9340Sstevel@tonic-gate eprintsoline(so, error); 9350Sstevel@tonic-gate goto done2; 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate if (checkaccess) { 9390Sstevel@tonic-gate /* 9400Sstevel@tonic-gate * Check that we have permissions to access the destination 9410Sstevel@tonic-gate * vnode. This check is not done in BSD but it is required 9420Sstevel@tonic-gate * by X/Open. 9430Sstevel@tonic-gate */ 9445331Samw if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL)) { 9450Sstevel@tonic-gate eprintsoline(so, error); 9460Sstevel@tonic-gate goto done2; 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate } 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate /* 9510Sstevel@tonic-gate * Check if the remote socket has been closed. 9520Sstevel@tonic-gate * 9530Sstevel@tonic-gate * Synchronize with vn_rele_stream by holding v_lock while traversing 9540Sstevel@tonic-gate * v_stream->sd_vnode. 9550Sstevel@tonic-gate */ 9560Sstevel@tonic-gate mutex_enter(&vp->v_lock); 9570Sstevel@tonic-gate if (vp->v_stream == NULL) { 9580Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9590Sstevel@tonic-gate if (so->so_type == SOCK_DGRAM) 9600Sstevel@tonic-gate error = EDESTADDRREQ; 9610Sstevel@tonic-gate else 9620Sstevel@tonic-gate error = ECONNREFUSED; 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate eprintsoline(so, error); 9650Sstevel@tonic-gate goto done2; 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate ASSERT(vp->v_stream->sd_vnode); 9680Sstevel@tonic-gate svp = vp->v_stream->sd_vnode; 9690Sstevel@tonic-gate /* 9700Sstevel@tonic-gate * holding v_lock on underlying filesystem vnode and acquiring 9710Sstevel@tonic-gate * it on sockfs vnode. Assumes that no code ever attempts to 9720Sstevel@tonic-gate * acquire these locks in the reverse order. 9730Sstevel@tonic-gate */ 9740Sstevel@tonic-gate VN_HOLD(svp); 9750Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate if (svp->v_type != VSOCK) { 9780Sstevel@tonic-gate error = ENOTSOCK; 9790Sstevel@tonic-gate eprintsoline(so, error); 9800Sstevel@tonic-gate goto done; 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate so2 = VTOSO(svp); 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate if (so->so_type != so2->so_type) { 9860Sstevel@tonic-gate error = EPROTOTYPE; 9870Sstevel@tonic-gate eprintsoline(so, error); 9880Sstevel@tonic-gate goto done; 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate VN_RELE(svp); 9920Sstevel@tonic-gate *vpp = vp; 9930Sstevel@tonic-gate return (0); 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate done: 9960Sstevel@tonic-gate VN_RELE(svp); 9970Sstevel@tonic-gate done2: 9980Sstevel@tonic-gate VN_RELE(vp); 9990Sstevel@tonic-gate return (error); 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate /* 10030Sstevel@tonic-gate * Verify peer address for connect and sendto/sendmsg. 10040Sstevel@tonic-gate * Since sendto/sendmsg would not get synchronous errors from the transport 10050Sstevel@tonic-gate * provider we have to do these ugly checks in the socket layer to 10060Sstevel@tonic-gate * preserve compatibility with SunOS 4.X. 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate int 10090Sstevel@tonic-gate so_addr_verify(struct sonode *so, const struct sockaddr *name, 10100Sstevel@tonic-gate socklen_t namelen) 10110Sstevel@tonic-gate { 10120Sstevel@tonic-gate int family; 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate dprintso(so, 1, ("so_addr_verify(%p, %p, %d)\n", so, name, namelen)); 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate ASSERT(name != NULL); 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate family = so->so_family; 10190Sstevel@tonic-gate switch (family) { 10200Sstevel@tonic-gate case AF_INET: 10210Sstevel@tonic-gate if (name->sa_family != family) { 10220Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 10230Sstevel@tonic-gate return (EAFNOSUPPORT); 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in)) { 10260Sstevel@tonic-gate eprintsoline(so, EINVAL); 10270Sstevel@tonic-gate return (EINVAL); 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate break; 10300Sstevel@tonic-gate case AF_INET6: { 10310Sstevel@tonic-gate #ifdef DEBUG 10320Sstevel@tonic-gate struct sockaddr_in6 *sin6; 10330Sstevel@tonic-gate #endif /* DEBUG */ 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate if (name->sa_family != family) { 10360Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 10370Sstevel@tonic-gate return (EAFNOSUPPORT); 10380Sstevel@tonic-gate } 10390Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) { 10400Sstevel@tonic-gate eprintsoline(so, EINVAL); 10410Sstevel@tonic-gate return (EINVAL); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate #ifdef DEBUG 10440Sstevel@tonic-gate /* Verify that apps don't forget to clear sin6_scope_id etc */ 10450Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)name; 10460Sstevel@tonic-gate if (sin6->sin6_scope_id != 0 && 10470Sstevel@tonic-gate !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 10481548Srshoaib zcmn_err(getzoneid(), CE_WARN, 10490Sstevel@tonic-gate "connect/send* with uninitialized sin6_scope_id " 10500Sstevel@tonic-gate "(%d) on socket. Pid = %d\n", 10510Sstevel@tonic-gate (int)sin6->sin6_scope_id, (int)curproc->p_pid); 10520Sstevel@tonic-gate } 10530Sstevel@tonic-gate #endif /* DEBUG */ 10540Sstevel@tonic-gate break; 10550Sstevel@tonic-gate } 10560Sstevel@tonic-gate case AF_UNIX: 10570Sstevel@tonic-gate if (so->so_state & SS_FADDR_NOXLATE) { 10580Sstevel@tonic-gate return (0); 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate if (namelen < (socklen_t)sizeof (short)) { 10610Sstevel@tonic-gate eprintsoline(so, ENOENT); 10620Sstevel@tonic-gate return (ENOENT); 10630Sstevel@tonic-gate } 10640Sstevel@tonic-gate if (name->sa_family != family) { 10650Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 10660Sstevel@tonic-gate return (EAFNOSUPPORT); 10670Sstevel@tonic-gate } 10680Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 10690Sstevel@tonic-gate if (namelen > (socklen_t)(MAXPATHLEN + sizeof (short) + 1)) { 10700Sstevel@tonic-gate eprintsoline(so, ENAMETOOLONG); 10710Sstevel@tonic-gate return (ENAMETOOLONG); 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate break; 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate default: 10770Sstevel@tonic-gate /* 10780Sstevel@tonic-gate * Default is don't do any length or sa_family check 10790Sstevel@tonic-gate * to allow non-sockaddr style addresses. 10800Sstevel@tonic-gate */ 10810Sstevel@tonic-gate break; 10820Sstevel@tonic-gate } 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate return (0); 10850Sstevel@tonic-gate } 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate /* 10890Sstevel@tonic-gate * Translate an AF_UNIX sockaddr_un to the transport internal name. 10900Sstevel@tonic-gate * Assumes caller has called so_addr_verify first. 10910Sstevel@tonic-gate */ 10920Sstevel@tonic-gate /*ARGSUSED*/ 10930Sstevel@tonic-gate int 10940Sstevel@tonic-gate so_ux_addr_xlate(struct sonode *so, struct sockaddr *name, 10950Sstevel@tonic-gate socklen_t namelen, int checkaccess, 10960Sstevel@tonic-gate void **addrp, socklen_t *addrlenp) 10970Sstevel@tonic-gate { 10980Sstevel@tonic-gate int error; 10990Sstevel@tonic-gate struct sockaddr_un *soun; 11000Sstevel@tonic-gate vnode_t *vp; 11010Sstevel@tonic-gate void *addr; 11020Sstevel@tonic-gate socklen_t addrlen; 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate dprintso(so, 1, ("so_ux_addr_xlate(%p, %p, %d, %d)\n", 11055753Sgww so, name, namelen, checkaccess)); 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate ASSERT(name != NULL); 11080Sstevel@tonic-gate ASSERT(so->so_family == AF_UNIX); 11090Sstevel@tonic-gate ASSERT(!(so->so_state & SS_FADDR_NOXLATE)); 11100Sstevel@tonic-gate ASSERT(namelen >= (socklen_t)sizeof (short)); 11110Sstevel@tonic-gate ASSERT(name->sa_family == AF_UNIX); 11120Sstevel@tonic-gate soun = (struct sockaddr_un *)name; 11130Sstevel@tonic-gate /* 11140Sstevel@tonic-gate * Lookup vnode for the specified path name and verify that 11150Sstevel@tonic-gate * it is a socket. 11160Sstevel@tonic-gate */ 11170Sstevel@tonic-gate error = so_ux_lookup(so, soun, checkaccess, &vp); 11180Sstevel@tonic-gate if (error) { 11190Sstevel@tonic-gate eprintsoline(so, error); 11200Sstevel@tonic-gate return (error); 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate /* 11230Sstevel@tonic-gate * Use the address of the peer vnode as the address to send 11240Sstevel@tonic-gate * to. We release the peer vnode here. In case it has been 11250Sstevel@tonic-gate * closed by the time the T_CONN_REQ or T_UNIDATA_REQ reaches the 11260Sstevel@tonic-gate * transport the message will get an error or be dropped. 11270Sstevel@tonic-gate */ 11280Sstevel@tonic-gate so->so_ux_faddr.soua_vp = vp; 11290Sstevel@tonic-gate so->so_ux_faddr.soua_magic = SOU_MAGIC_EXPLICIT; 11300Sstevel@tonic-gate addr = &so->so_ux_faddr; 11310Sstevel@tonic-gate addrlen = (socklen_t)sizeof (so->so_ux_faddr); 11320Sstevel@tonic-gate dprintso(so, 1, ("ux_xlate UNIX: addrlen %d, vp %p\n", 11335753Sgww addrlen, vp)); 11340Sstevel@tonic-gate VN_RELE(vp); 11350Sstevel@tonic-gate *addrp = addr; 11360Sstevel@tonic-gate *addrlenp = (socklen_t)addrlen; 11370Sstevel@tonic-gate return (0); 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate /* 11410Sstevel@tonic-gate * Esballoc free function for messages that contain SO_FILEP option. 11420Sstevel@tonic-gate * Decrement the reference count on the file pointers using closef. 11430Sstevel@tonic-gate */ 11440Sstevel@tonic-gate void 11450Sstevel@tonic-gate fdbuf_free(struct fdbuf *fdbuf) 11460Sstevel@tonic-gate { 11470Sstevel@tonic-gate int i; 11480Sstevel@tonic-gate struct file *fp; 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate dprint(1, ("fdbuf_free: %d fds\n", fdbuf->fd_numfd)); 11510Sstevel@tonic-gate for (i = 0; i < fdbuf->fd_numfd; i++) { 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 11540Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 11550Sstevel@tonic-gate * the option headers and values are only 4 bytes 11560Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 11570Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 11580Sstevel@tonic-gate */ 11590Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 11600Sstevel@tonic-gate dprint(1, ("fdbuf_free: [%d] = %p\n", i, fp)); 11610Sstevel@tonic-gate (void) closef(fp); 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate if (fdbuf->fd_ebuf != NULL) 11640Sstevel@tonic-gate kmem_free(fdbuf->fd_ebuf, fdbuf->fd_ebuflen); 11650Sstevel@tonic-gate kmem_free(fdbuf, fdbuf->fd_size); 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate /* 1169455Smeem * Allocate an esballoc'ed message for AF_UNIX file descriptor passing. 1170455Smeem * Waits if memory is not available. 11710Sstevel@tonic-gate */ 11720Sstevel@tonic-gate mblk_t * 11730Sstevel@tonic-gate fdbuf_allocmsg(int size, struct fdbuf *fdbuf) 11740Sstevel@tonic-gate { 1175455Smeem uchar_t *buf; 11760Sstevel@tonic-gate mblk_t *mp; 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate dprint(1, ("fdbuf_allocmsg: size %d, %d fds\n", size, fdbuf->fd_numfd)); 11790Sstevel@tonic-gate buf = kmem_alloc(size, KM_SLEEP); 11800Sstevel@tonic-gate fdbuf->fd_ebuf = (caddr_t)buf; 11810Sstevel@tonic-gate fdbuf->fd_ebuflen = size; 11820Sstevel@tonic-gate fdbuf->fd_frtn.free_func = fdbuf_free; 11830Sstevel@tonic-gate fdbuf->fd_frtn.free_arg = (caddr_t)fdbuf; 11840Sstevel@tonic-gate 1185455Smeem mp = esballoc_wait(buf, size, BPRI_MED, &fdbuf->fd_frtn); 11860Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 11870Sstevel@tonic-gate return (mp); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate /* 11910Sstevel@tonic-gate * Extract file descriptors from a fdbuf. 11920Sstevel@tonic-gate * Return list in rights/rightslen. 11930Sstevel@tonic-gate */ 11940Sstevel@tonic-gate /*ARGSUSED*/ 11950Sstevel@tonic-gate static int 11960Sstevel@tonic-gate fdbuf_extract(struct fdbuf *fdbuf, void *rights, int rightslen) 11970Sstevel@tonic-gate { 11980Sstevel@tonic-gate int i, fd; 11990Sstevel@tonic-gate int *rp; 12000Sstevel@tonic-gate struct file *fp; 12010Sstevel@tonic-gate int numfd; 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate dprint(1, ("fdbuf_extract: %d fds, len %d\n", 12045753Sgww fdbuf->fd_numfd, rightslen)); 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate numfd = fdbuf->fd_numfd; 12070Sstevel@tonic-gate ASSERT(rightslen == numfd * (int)sizeof (int)); 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate /* 12100Sstevel@tonic-gate * Allocate a file descriptor and increment the f_count. 12110Sstevel@tonic-gate * The latter is needed since we always call fdbuf_free 12120Sstevel@tonic-gate * which performs a closef. 12130Sstevel@tonic-gate */ 12140Sstevel@tonic-gate rp = (int *)rights; 12150Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 12160Sstevel@tonic-gate if ((fd = ufalloc(0)) == -1) 12170Sstevel@tonic-gate goto cleanup; 12180Sstevel@tonic-gate /* 12190Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 12200Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 12210Sstevel@tonic-gate * the option headers and values are only 4 bytes 12220Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 12230Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 12240Sstevel@tonic-gate */ 12250Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 12260Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 12270Sstevel@tonic-gate fp->f_count++; 12280Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 12290Sstevel@tonic-gate setf(fd, fp); 12300Sstevel@tonic-gate *rp++ = fd; 12310Sstevel@tonic-gate if (audit_active) 12320Sstevel@tonic-gate audit_fdrecv(fd, fp); 12330Sstevel@tonic-gate dprint(1, ("fdbuf_extract: [%d] = %d, %p refcnt %d\n", 12345753Sgww i, fd, fp, fp->f_count)); 12350Sstevel@tonic-gate } 12360Sstevel@tonic-gate return (0); 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate cleanup: 12390Sstevel@tonic-gate /* 12400Sstevel@tonic-gate * Undo whatever partial work the loop above has done. 12410Sstevel@tonic-gate */ 12420Sstevel@tonic-gate { 12430Sstevel@tonic-gate int j; 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate rp = (int *)rights; 12460Sstevel@tonic-gate for (j = 0; j < i; j++) { 12470Sstevel@tonic-gate dprint(0, 12480Sstevel@tonic-gate ("fdbuf_extract: cleanup[%d] = %d\n", j, *rp)); 12490Sstevel@tonic-gate (void) closeandsetf(*rp++, NULL); 12500Sstevel@tonic-gate } 12510Sstevel@tonic-gate } 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate return (EMFILE); 12540Sstevel@tonic-gate } 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate /* 12570Sstevel@tonic-gate * Insert file descriptors into an fdbuf. 12580Sstevel@tonic-gate * Returns a kmem_alloc'ed fdbuf. The fdbuf should be freed 12590Sstevel@tonic-gate * by calling fdbuf_free(). 12600Sstevel@tonic-gate */ 12610Sstevel@tonic-gate int 12620Sstevel@tonic-gate fdbuf_create(void *rights, int rightslen, struct fdbuf **fdbufp) 12630Sstevel@tonic-gate { 12640Sstevel@tonic-gate int numfd, i; 12650Sstevel@tonic-gate int *fds; 12660Sstevel@tonic-gate struct file *fp; 12670Sstevel@tonic-gate struct fdbuf *fdbuf; 12680Sstevel@tonic-gate int fdbufsize; 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate dprint(1, ("fdbuf_create: len %d\n", rightslen)); 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate fdbufsize = (int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *)); 12750Sstevel@tonic-gate fdbuf = kmem_alloc(fdbufsize, KM_SLEEP); 12760Sstevel@tonic-gate fdbuf->fd_size = fdbufsize; 12770Sstevel@tonic-gate fdbuf->fd_numfd = 0; 12780Sstevel@tonic-gate fdbuf->fd_ebuf = NULL; 12790Sstevel@tonic-gate fdbuf->fd_ebuflen = 0; 12800Sstevel@tonic-gate fds = (int *)rights; 12810Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 12820Sstevel@tonic-gate if ((fp = getf(fds[i])) == NULL) { 12830Sstevel@tonic-gate fdbuf_free(fdbuf); 12840Sstevel@tonic-gate return (EBADF); 12850Sstevel@tonic-gate } 12860Sstevel@tonic-gate dprint(1, ("fdbuf_create: [%d] = %d, %p refcnt %d\n", 12875753Sgww i, fds[i], fp, fp->f_count)); 12880Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 12890Sstevel@tonic-gate fp->f_count++; 12900Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 12910Sstevel@tonic-gate /* 12920Sstevel@tonic-gate * The maximum alignment for fdbuf (or any option header 12930Sstevel@tonic-gate * and its value) it 4 bytes. On a LP64 kernel, the alignment 12940Sstevel@tonic-gate * is not sufficient for pointers (fd_fds in this case). Since 12950Sstevel@tonic-gate * we just did a kmem_alloc (we get a double word alignment), 12960Sstevel@tonic-gate * we don't need to do anything on the send side (we loose 12970Sstevel@tonic-gate * the double word alignment because fdbuf goes after an 12980Sstevel@tonic-gate * option header (eg T_unitdata_req) which is only 4 byte 12990Sstevel@tonic-gate * aligned). We take care of this when we extract the file 13000Sstevel@tonic-gate * descriptor in fdbuf_extract or fdbuf_free. 13010Sstevel@tonic-gate */ 13020Sstevel@tonic-gate fdbuf->fd_fds[i] = fp; 13030Sstevel@tonic-gate fdbuf->fd_numfd++; 13040Sstevel@tonic-gate releasef(fds[i]); 13050Sstevel@tonic-gate if (audit_active) 13060Sstevel@tonic-gate audit_fdsend(fds[i], fp, 0); 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate *fdbufp = fdbuf; 13090Sstevel@tonic-gate return (0); 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate static int 13130Sstevel@tonic-gate fdbuf_optlen(int rightslen) 13140Sstevel@tonic-gate { 13150Sstevel@tonic-gate int numfd; 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate return ((int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *))); 13200Sstevel@tonic-gate } 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate static t_uscalar_t 13230Sstevel@tonic-gate fdbuf_cmsglen(int fdbuflen) 13240Sstevel@tonic-gate { 13250Sstevel@tonic-gate return (t_uscalar_t)((fdbuflen - FDBUF_HDRSIZE) / 13260Sstevel@tonic-gate (int)sizeof (struct file *) * (int)sizeof (int)); 13270Sstevel@tonic-gate } 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate /* 13310Sstevel@tonic-gate * Return non-zero if the mblk and fdbuf are consistent. 13320Sstevel@tonic-gate */ 13330Sstevel@tonic-gate static int 13340Sstevel@tonic-gate fdbuf_verify(mblk_t *mp, struct fdbuf *fdbuf, int fdbuflen) 13350Sstevel@tonic-gate { 13360Sstevel@tonic-gate if (fdbuflen >= FDBUF_HDRSIZE && 13370Sstevel@tonic-gate fdbuflen == fdbuf->fd_size) { 13380Sstevel@tonic-gate frtn_t *frp = mp->b_datap->db_frtnp; 13390Sstevel@tonic-gate /* 13400Sstevel@tonic-gate * Check that the SO_FILEP portion of the 13410Sstevel@tonic-gate * message has not been modified by 13420Sstevel@tonic-gate * the loopback transport. The sending sockfs generates 13430Sstevel@tonic-gate * a message that is esballoc'ed with the free function 13440Sstevel@tonic-gate * being fdbuf_free() and where free_arg contains the 13450Sstevel@tonic-gate * identical information as the SO_FILEP content. 13460Sstevel@tonic-gate * 13470Sstevel@tonic-gate * If any of these constraints are not satisfied we 13480Sstevel@tonic-gate * silently ignore the option. 13490Sstevel@tonic-gate */ 13500Sstevel@tonic-gate ASSERT(mp); 13510Sstevel@tonic-gate if (frp != NULL && 13520Sstevel@tonic-gate frp->free_func == fdbuf_free && 13530Sstevel@tonic-gate frp->free_arg != NULL && 13540Sstevel@tonic-gate bcmp(frp->free_arg, fdbuf, fdbuflen) == 0) { 13550Sstevel@tonic-gate dprint(1, ("fdbuf_verify: fdbuf %p len %d\n", 13565753Sgww fdbuf, fdbuflen)); 13570Sstevel@tonic-gate return (1); 13580Sstevel@tonic-gate } else { 13591548Srshoaib zcmn_err(getzoneid(), CE_WARN, 13600Sstevel@tonic-gate "sockfs: mismatched fdbuf content (%p)", 13610Sstevel@tonic-gate (void *)mp); 13620Sstevel@tonic-gate return (0); 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate } else { 13651548Srshoaib zcmn_err(getzoneid(), CE_WARN, 13660Sstevel@tonic-gate "sockfs: mismatched fdbuf len %d, %d\n", 13670Sstevel@tonic-gate fdbuflen, fdbuf->fd_size); 13680Sstevel@tonic-gate return (0); 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate /* 13730Sstevel@tonic-gate * When the file descriptors returned by sorecvmsg can not be passed 13740Sstevel@tonic-gate * to the application this routine will cleanup the references on 13750Sstevel@tonic-gate * the files. Start at startoff bytes into the buffer. 13760Sstevel@tonic-gate */ 13770Sstevel@tonic-gate static void 13780Sstevel@tonic-gate close_fds(void *fdbuf, int fdbuflen, int startoff) 13790Sstevel@tonic-gate { 13800Sstevel@tonic-gate int *fds = (int *)fdbuf; 13810Sstevel@tonic-gate int numfd = fdbuflen / (int)sizeof (int); 13820Sstevel@tonic-gate int i; 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate dprint(1, ("close_fds(%p, %d, %d)\n", fdbuf, fdbuflen, startoff)); 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 13870Sstevel@tonic-gate if (startoff < 0) 13880Sstevel@tonic-gate startoff = 0; 13890Sstevel@tonic-gate if (startoff < (int)sizeof (int)) { 13900Sstevel@tonic-gate /* 13910Sstevel@tonic-gate * This file descriptor is partially or fully after 13920Sstevel@tonic-gate * the offset 13930Sstevel@tonic-gate */ 13940Sstevel@tonic-gate dprint(0, 13950Sstevel@tonic-gate ("close_fds: cleanup[%d] = %d\n", i, fds[i])); 13960Sstevel@tonic-gate (void) closeandsetf(fds[i], NULL); 13970Sstevel@tonic-gate } 13980Sstevel@tonic-gate startoff -= (int)sizeof (int); 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate } 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate /* 14030Sstevel@tonic-gate * Close all file descriptors contained in the control part starting at 14040Sstevel@tonic-gate * the startoffset. 14050Sstevel@tonic-gate */ 14060Sstevel@tonic-gate void 14070Sstevel@tonic-gate so_closefds(void *control, t_uscalar_t controllen, int oldflg, 14080Sstevel@tonic-gate int startoff) 14090Sstevel@tonic-gate { 14100Sstevel@tonic-gate struct cmsghdr *cmsg; 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate if (control == NULL) 14130Sstevel@tonic-gate return; 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate if (oldflg) { 14160Sstevel@tonic-gate close_fds(control, controllen, startoff); 14170Sstevel@tonic-gate return; 14180Sstevel@tonic-gate } 14190Sstevel@tonic-gate /* Scan control part for file descriptors. */ 14200Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 14210Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 14220Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 14230Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 14240Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 14250Sstevel@tonic-gate close_fds(CMSG_CONTENT(cmsg), 14260Sstevel@tonic-gate (int)CMSG_CONTENTLEN(cmsg), 14270Sstevel@tonic-gate startoff - (int)sizeof (struct cmsghdr)); 14280Sstevel@tonic-gate } 14290Sstevel@tonic-gate startoff -= cmsg->cmsg_len; 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate /* 14340Sstevel@tonic-gate * Returns a pointer/length for the file descriptors contained 14350Sstevel@tonic-gate * in the control buffer. Returns with *fdlenp == -1 if there are no 14360Sstevel@tonic-gate * file descriptor options present. This is different than there being 14370Sstevel@tonic-gate * a zero-length file descriptor option. 14380Sstevel@tonic-gate * Fail if there are multiple SCM_RIGHT cmsgs. 14390Sstevel@tonic-gate */ 14400Sstevel@tonic-gate int 14410Sstevel@tonic-gate so_getfdopt(void *control, t_uscalar_t controllen, int oldflg, 14420Sstevel@tonic-gate void **fdsp, int *fdlenp) 14430Sstevel@tonic-gate { 14440Sstevel@tonic-gate struct cmsghdr *cmsg; 14450Sstevel@tonic-gate void *fds; 14460Sstevel@tonic-gate int fdlen; 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate if (control == NULL) { 14490Sstevel@tonic-gate *fdsp = NULL; 14500Sstevel@tonic-gate *fdlenp = -1; 14510Sstevel@tonic-gate return (0); 14520Sstevel@tonic-gate } 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate if (oldflg) { 14550Sstevel@tonic-gate *fdsp = control; 14560Sstevel@tonic-gate if (controllen == 0) 14570Sstevel@tonic-gate *fdlenp = -1; 14580Sstevel@tonic-gate else 14590Sstevel@tonic-gate *fdlenp = controllen; 14600Sstevel@tonic-gate dprint(1, ("so_getfdopt: old %d\n", *fdlenp)); 14610Sstevel@tonic-gate return (0); 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate fds = NULL; 14650Sstevel@tonic-gate fdlen = 0; 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 14680Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 14690Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 14700Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 14710Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 14720Sstevel@tonic-gate if (fds != NULL) 14730Sstevel@tonic-gate return (EINVAL); 14740Sstevel@tonic-gate fds = CMSG_CONTENT(cmsg); 14750Sstevel@tonic-gate fdlen = (int)CMSG_CONTENTLEN(cmsg); 1476408Skrgopi dprint(1, ("so_getfdopt: new %lu\n", 14775753Sgww (size_t)CMSG_CONTENTLEN(cmsg))); 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate if (fds == NULL) { 14810Sstevel@tonic-gate dprint(1, ("so_getfdopt: NONE\n")); 14820Sstevel@tonic-gate *fdlenp = -1; 14830Sstevel@tonic-gate } else 14840Sstevel@tonic-gate *fdlenp = fdlen; 14850Sstevel@tonic-gate *fdsp = fds; 14860Sstevel@tonic-gate return (0); 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate /* 14900Sstevel@tonic-gate * Return the length of the options including any file descriptor options. 14910Sstevel@tonic-gate */ 14920Sstevel@tonic-gate t_uscalar_t 14930Sstevel@tonic-gate so_optlen(void *control, t_uscalar_t controllen, int oldflg) 14940Sstevel@tonic-gate { 14950Sstevel@tonic-gate struct cmsghdr *cmsg; 14960Sstevel@tonic-gate t_uscalar_t optlen = 0; 14970Sstevel@tonic-gate t_uscalar_t len; 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate if (control == NULL) 15000Sstevel@tonic-gate return (0); 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate if (oldflg) 15030Sstevel@tonic-gate return ((t_uscalar_t)(sizeof (struct T_opthdr) + 15040Sstevel@tonic-gate fdbuf_optlen(controllen))); 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 15070Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 15080Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 15090Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 15100Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 15110Sstevel@tonic-gate len = fdbuf_optlen((int)CMSG_CONTENTLEN(cmsg)); 15120Sstevel@tonic-gate } else { 15130Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 15140Sstevel@tonic-gate } 15150Sstevel@tonic-gate optlen += (t_uscalar_t)(_TPI_ALIGN_TOPT(len) + 15160Sstevel@tonic-gate sizeof (struct T_opthdr)); 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate dprint(1, ("so_optlen: controllen %d, flg %d -> optlen %d\n", 15195753Sgww controllen, oldflg, optlen)); 15200Sstevel@tonic-gate return (optlen); 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate /* 15240Sstevel@tonic-gate * Copy options from control to the mblk. Skip any file descriptor options. 15250Sstevel@tonic-gate */ 15260Sstevel@tonic-gate void 15270Sstevel@tonic-gate so_cmsg2opt(void *control, t_uscalar_t controllen, int oldflg, mblk_t *mp) 15280Sstevel@tonic-gate { 15290Sstevel@tonic-gate struct T_opthdr toh; 15300Sstevel@tonic-gate struct cmsghdr *cmsg; 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate if (control == NULL) 15330Sstevel@tonic-gate return; 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate if (oldflg) { 15360Sstevel@tonic-gate /* No real options - caller has handled file descriptors */ 15370Sstevel@tonic-gate return; 15380Sstevel@tonic-gate } 15390Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 15400Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 15410Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 15420Sstevel@tonic-gate /* 15430Sstevel@tonic-gate * Note: The caller handles file descriptors prior 15440Sstevel@tonic-gate * to calling this function. 15450Sstevel@tonic-gate */ 15460Sstevel@tonic-gate t_uscalar_t len; 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 15490Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) 15500Sstevel@tonic-gate continue; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 15530Sstevel@tonic-gate toh.level = cmsg->cmsg_level; 15540Sstevel@tonic-gate toh.name = cmsg->cmsg_type; 15550Sstevel@tonic-gate toh.len = len + (t_uscalar_t)sizeof (struct T_opthdr); 15560Sstevel@tonic-gate toh.status = 0; 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate soappendmsg(mp, &toh, sizeof (toh)); 15590Sstevel@tonic-gate soappendmsg(mp, CMSG_CONTENT(cmsg), len); 15600Sstevel@tonic-gate mp->b_wptr += _TPI_ALIGN_TOPT(len) - len; 15610Sstevel@tonic-gate ASSERT(mp->b_wptr <= mp->b_datap->db_lim); 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate } 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate /* 15660Sstevel@tonic-gate * Return the length of the control message derived from the options. 15670Sstevel@tonic-gate * Exclude SO_SRCADDR and SO_UNIX_CLOSE options. Include SO_FILEP. 15680Sstevel@tonic-gate * When oldflg is set only include SO_FILEP. 15692280Sgt145670 * so_opt2cmsg and so_cmsglen are inter-related since so_cmsglen 15702280Sgt145670 * allocates the space that so_opt2cmsg fills. If one changes, the other should 15712280Sgt145670 * also be checked for any possible impacts. 15720Sstevel@tonic-gate */ 15730Sstevel@tonic-gate t_uscalar_t 15740Sstevel@tonic-gate so_cmsglen(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg) 15750Sstevel@tonic-gate { 15760Sstevel@tonic-gate t_uscalar_t cmsglen = 0; 15770Sstevel@tonic-gate struct T_opthdr *tohp; 15780Sstevel@tonic-gate t_uscalar_t len; 15790Sstevel@tonic-gate t_uscalar_t last_roundup = 0; 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 15840Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 15850Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 15860Sstevel@tonic-gate dprint(1, ("so_cmsglen: level 0x%x, name %d, len %d\n", 15875753Sgww tohp->level, tohp->name, tohp->len)); 15880Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 15890Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 15900Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 15910Sstevel@tonic-gate continue; 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 15940Sstevel@tonic-gate struct fdbuf *fdbuf; 15950Sstevel@tonic-gate int fdbuflen; 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 15980Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 16010Sstevel@tonic-gate continue; 16020Sstevel@tonic-gate if (oldflg) { 16030Sstevel@tonic-gate cmsglen += fdbuf_cmsglen(fdbuflen); 16040Sstevel@tonic-gate continue; 16050Sstevel@tonic-gate } 16060Sstevel@tonic-gate len = fdbuf_cmsglen(fdbuflen); 16072280Sgt145670 } else if (tohp->level == SOL_SOCKET && 16082280Sgt145670 tohp->name == SCM_TIMESTAMP) { 16092280Sgt145670 if (oldflg) 16102280Sgt145670 continue; 16112280Sgt145670 16122280Sgt145670 if (get_udatamodel() == DATAMODEL_NATIVE) { 16132280Sgt145670 len = sizeof (struct timeval); 16142280Sgt145670 } else { 16152280Sgt145670 len = sizeof (struct timeval32); 16162280Sgt145670 } 16170Sstevel@tonic-gate } else { 16180Sstevel@tonic-gate if (oldflg) 16190Sstevel@tonic-gate continue; 16200Sstevel@tonic-gate len = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate /* 16232280Sgt145670 * Exclude roundup for last option to not set 16240Sstevel@tonic-gate * MSG_CTRUNC when the cmsg fits but the padding doesn't fit. 16250Sstevel@tonic-gate */ 16260Sstevel@tonic-gate last_roundup = (t_uscalar_t) 16270Sstevel@tonic-gate (ROUNDUP_cmsglen(len + (int)sizeof (struct cmsghdr)) - 16280Sstevel@tonic-gate (len + (int)sizeof (struct cmsghdr))); 16290Sstevel@tonic-gate cmsglen += (t_uscalar_t)(len + (int)sizeof (struct cmsghdr)) + 16300Sstevel@tonic-gate last_roundup; 16310Sstevel@tonic-gate } 16320Sstevel@tonic-gate cmsglen -= last_roundup; 16330Sstevel@tonic-gate dprint(1, ("so_cmsglen: optlen %d, flg %d -> cmsglen %d\n", 16345753Sgww optlen, oldflg, cmsglen)); 16350Sstevel@tonic-gate return (cmsglen); 16360Sstevel@tonic-gate } 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate /* 16390Sstevel@tonic-gate * Copy options from options to the control. Convert SO_FILEP to 16400Sstevel@tonic-gate * file descriptors. 16410Sstevel@tonic-gate * Returns errno or zero. 16422280Sgt145670 * so_opt2cmsg and so_cmsglen are inter-related since so_cmsglen 16432280Sgt145670 * allocates the space that so_opt2cmsg fills. If one changes, the other should 16442280Sgt145670 * also be checked for any possible impacts. 16450Sstevel@tonic-gate */ 16460Sstevel@tonic-gate int 16470Sstevel@tonic-gate so_opt2cmsg(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg, 16480Sstevel@tonic-gate void *control, t_uscalar_t controllen) 16490Sstevel@tonic-gate { 16500Sstevel@tonic-gate struct T_opthdr *tohp; 16510Sstevel@tonic-gate struct cmsghdr *cmsg; 16520Sstevel@tonic-gate struct fdbuf *fdbuf; 16530Sstevel@tonic-gate int fdbuflen; 16540Sstevel@tonic-gate int error; 16552280Sgt145670 #if defined(DEBUG) || defined(__lint) 16562280Sgt145670 struct cmsghdr *cend = (struct cmsghdr *) 16572280Sgt145670 (((uint8_t *)control) + ROUNDUP_cmsglen(controllen)); 16582280Sgt145670 #endif 16590Sstevel@tonic-gate cmsg = (struct cmsghdr *)control; 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 16620Sstevel@tonic-gate 16630Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 16640Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 16650Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 16660Sstevel@tonic-gate dprint(1, ("so_opt2cmsg: level 0x%x, name %d, len %d\n", 16675753Sgww tohp->level, tohp->name, tohp->len)); 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 16700Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 16710Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 16720Sstevel@tonic-gate continue; 16730Sstevel@tonic-gate } 16740Sstevel@tonic-gate ASSERT((uintptr_t)cmsg <= (uintptr_t)control + controllen); 16750Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 16760Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 16770Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 16800Sstevel@tonic-gate return (EPROTO); 16810Sstevel@tonic-gate if (oldflg) { 16820Sstevel@tonic-gate error = fdbuf_extract(fdbuf, control, 16830Sstevel@tonic-gate (int)controllen); 16840Sstevel@tonic-gate if (error != 0) 16850Sstevel@tonic-gate return (error); 16860Sstevel@tonic-gate continue; 16870Sstevel@tonic-gate } else { 16880Sstevel@tonic-gate int fdlen; 16890Sstevel@tonic-gate 16900Sstevel@tonic-gate fdlen = (int)fdbuf_cmsglen( 16910Sstevel@tonic-gate (int)_TPI_TOPT_DATALEN(tohp)); 16920Sstevel@tonic-gate 16930Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 16940Sstevel@tonic-gate cmsg->cmsg_type = SCM_RIGHTS; 16950Sstevel@tonic-gate cmsg->cmsg_len = (socklen_t)(fdlen + 16965753Sgww sizeof (struct cmsghdr)); 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate error = fdbuf_extract(fdbuf, 16995753Sgww CMSG_CONTENT(cmsg), fdlen); 17000Sstevel@tonic-gate if (error != 0) 17010Sstevel@tonic-gate return (error); 17020Sstevel@tonic-gate } 17031673Sgt145670 } else if (tohp->level == SOL_SOCKET && 17041673Sgt145670 tohp->name == SCM_TIMESTAMP) { 17051673Sgt145670 timestruc_t *timestamp; 17061673Sgt145670 17071673Sgt145670 if (oldflg) 17081673Sgt145670 continue; 17091673Sgt145670 17101673Sgt145670 cmsg->cmsg_level = tohp->level; 17111673Sgt145670 cmsg->cmsg_type = tohp->name; 17121673Sgt145670 17131673Sgt145670 timestamp = 17141673Sgt145670 (timestruc_t *)P2ROUNDUP((intptr_t)&tohp[1], 17151673Sgt145670 sizeof (intptr_t)); 17161673Sgt145670 17171673Sgt145670 if (get_udatamodel() == DATAMODEL_NATIVE) { 17182280Sgt145670 struct timeval tv; 17191673Sgt145670 17201673Sgt145670 cmsg->cmsg_len = sizeof (struct timeval) + 17211673Sgt145670 sizeof (struct cmsghdr); 17222280Sgt145670 tv.tv_sec = timestamp->tv_sec; 17232280Sgt145670 tv.tv_usec = timestamp->tv_nsec / 17242280Sgt145670 (NANOSEC / MICROSEC); 17252280Sgt145670 /* 17262280Sgt145670 * on LP64 systems, the struct timeval in 17272280Sgt145670 * the destination will not be 8-byte aligned, 17282280Sgt145670 * so use bcopy to avoid alignment trouble 17292280Sgt145670 */ 17302280Sgt145670 bcopy(&tv, CMSG_CONTENT(cmsg), sizeof (tv)); 17311673Sgt145670 } else { 17321673Sgt145670 struct timeval32 *time32; 17331673Sgt145670 17341673Sgt145670 cmsg->cmsg_len = sizeof (struct timeval32) + 17351673Sgt145670 sizeof (struct cmsghdr); 17361673Sgt145670 time32 = (struct timeval32 *)CMSG_CONTENT(cmsg); 17371673Sgt145670 time32->tv_sec = (time32_t)timestamp->tv_sec; 17381673Sgt145670 time32->tv_usec = 17391673Sgt145670 (int32_t)(timestamp->tv_nsec / 17401673Sgt145670 (NANOSEC / MICROSEC)); 17411673Sgt145670 } 17421673Sgt145670 17430Sstevel@tonic-gate } else { 17440Sstevel@tonic-gate if (oldflg) 17450Sstevel@tonic-gate continue; 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 17480Sstevel@tonic-gate cmsg->cmsg_type = tohp->name; 17490Sstevel@tonic-gate cmsg->cmsg_len = (socklen_t)(_TPI_TOPT_DATALEN(tohp) + 17500Sstevel@tonic-gate sizeof (struct cmsghdr)); 17510Sstevel@tonic-gate 17520Sstevel@tonic-gate /* copy content to control data part */ 17530Sstevel@tonic-gate bcopy(&tohp[1], CMSG_CONTENT(cmsg), 17545753Sgww CMSG_CONTENTLEN(cmsg)); 17550Sstevel@tonic-gate } 17560Sstevel@tonic-gate /* move to next CMSG structure! */ 17570Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 17580Sstevel@tonic-gate } 17592280Sgt145670 dprint(1, ("so_opt2cmsg: buf %p len %d; cend %p; final cmsg %p\n", 17602280Sgt145670 control, controllen, cend, cmsg)); 17612280Sgt145670 ASSERT(cmsg <= cend); 17620Sstevel@tonic-gate return (0); 17630Sstevel@tonic-gate } 17640Sstevel@tonic-gate 17650Sstevel@tonic-gate /* 17660Sstevel@tonic-gate * Extract the SO_SRCADDR option value if present. 17670Sstevel@tonic-gate */ 17680Sstevel@tonic-gate void 17690Sstevel@tonic-gate so_getopt_srcaddr(void *opt, t_uscalar_t optlen, void **srcp, 17700Sstevel@tonic-gate t_uscalar_t *srclenp) 17710Sstevel@tonic-gate { 17720Sstevel@tonic-gate struct T_opthdr *tohp; 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate ASSERT(srcp != NULL && srclenp != NULL); 17770Sstevel@tonic-gate *srcp = NULL; 17780Sstevel@tonic-gate *srclenp = 0; 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 17810Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 17820Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 17830Sstevel@tonic-gate dprint(1, ("so_getopt_srcaddr: level 0x%x, name %d, len %d\n", 17845753Sgww tohp->level, tohp->name, tohp->len)); 17850Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 17860Sstevel@tonic-gate tohp->name == SO_SRCADDR) { 17870Sstevel@tonic-gate *srcp = _TPI_TOPT_DATA(tohp); 17880Sstevel@tonic-gate *srclenp = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 17890Sstevel@tonic-gate } 17900Sstevel@tonic-gate } 17910Sstevel@tonic-gate } 17920Sstevel@tonic-gate 17930Sstevel@tonic-gate /* 17940Sstevel@tonic-gate * Verify if the SO_UNIX_CLOSE option is present. 17950Sstevel@tonic-gate */ 17960Sstevel@tonic-gate int 17970Sstevel@tonic-gate so_getopt_unix_close(void *opt, t_uscalar_t optlen) 17980Sstevel@tonic-gate { 17990Sstevel@tonic-gate struct T_opthdr *tohp; 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 18040Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 18050Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 18060Sstevel@tonic-gate dprint(1, 18075753Sgww ("so_getopt_unix_close: level 0x%x, name %d, len %d\n", 18085753Sgww tohp->level, tohp->name, tohp->len)); 18090Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 18100Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE) 18110Sstevel@tonic-gate return (1); 18120Sstevel@tonic-gate } 18130Sstevel@tonic-gate return (0); 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate /* 18170Sstevel@tonic-gate * Allocate an M_PROTO message. 18180Sstevel@tonic-gate * 18190Sstevel@tonic-gate * If allocation fails the behavior depends on sleepflg: 18200Sstevel@tonic-gate * _ALLOC_NOSLEEP fail immediately 18210Sstevel@tonic-gate * _ALLOC_INTR sleep for memory until a signal is caught 18220Sstevel@tonic-gate * _ALLOC_SLEEP sleep forever. Don't return NULL. 18230Sstevel@tonic-gate */ 18240Sstevel@tonic-gate mblk_t * 18250Sstevel@tonic-gate soallocproto(size_t size, int sleepflg) 18260Sstevel@tonic-gate { 18270Sstevel@tonic-gate mblk_t *mp; 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate /* Round up size for reuse */ 18300Sstevel@tonic-gate size = MAX(size, 64); 18310Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 18320Sstevel@tonic-gate if (mp == NULL) { 18330Sstevel@tonic-gate int error; /* Dummy - error not returned to caller */ 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate switch (sleepflg) { 18360Sstevel@tonic-gate case _ALLOC_SLEEP: 18370Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, STR_NOSIG, &error); 18380Sstevel@tonic-gate ASSERT(mp); 18390Sstevel@tonic-gate break; 18400Sstevel@tonic-gate case _ALLOC_INTR: 18410Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 18420Sstevel@tonic-gate if (mp == NULL) { 18430Sstevel@tonic-gate /* Caught signal while sleeping for memory */ 18440Sstevel@tonic-gate eprintline(ENOBUFS); 18450Sstevel@tonic-gate return (NULL); 18460Sstevel@tonic-gate } 18470Sstevel@tonic-gate break; 18480Sstevel@tonic-gate case _ALLOC_NOSLEEP: 18490Sstevel@tonic-gate default: 18500Sstevel@tonic-gate eprintline(ENOBUFS); 18510Sstevel@tonic-gate return (NULL); 18520Sstevel@tonic-gate } 18530Sstevel@tonic-gate } 18540Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 18550Sstevel@tonic-gate return (mp); 18560Sstevel@tonic-gate } 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate /* 18590Sstevel@tonic-gate * Allocate an M_PROTO message with a single component. 18600Sstevel@tonic-gate * len is the length of buf. size is the amount to allocate. 18610Sstevel@tonic-gate * 18620Sstevel@tonic-gate * buf can be NULL with a non-zero len. 18630Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 18640Sstevel@tonic-gate */ 18650Sstevel@tonic-gate mblk_t * 18660Sstevel@tonic-gate soallocproto1(const void *buf, ssize_t len, ssize_t size, int sleepflg) 18670Sstevel@tonic-gate { 18680Sstevel@tonic-gate mblk_t *mp; 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate if (size == 0) 18710Sstevel@tonic-gate size = len; 18720Sstevel@tonic-gate 18730Sstevel@tonic-gate ASSERT(size >= len); 18740Sstevel@tonic-gate /* Round up size for reuse */ 18750Sstevel@tonic-gate size = MAX(size, 64); 18760Sstevel@tonic-gate mp = soallocproto(size, sleepflg); 18770Sstevel@tonic-gate if (mp == NULL) 18780Sstevel@tonic-gate return (NULL); 18790Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 18800Sstevel@tonic-gate if (len != 0) { 18810Sstevel@tonic-gate if (buf != NULL) 18820Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 18830Sstevel@tonic-gate else 18840Sstevel@tonic-gate bzero(mp->b_wptr, len); 18850Sstevel@tonic-gate mp->b_wptr += len; 18860Sstevel@tonic-gate } 18870Sstevel@tonic-gate return (mp); 18880Sstevel@tonic-gate } 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate /* 18910Sstevel@tonic-gate * Append buf/len to mp. 18920Sstevel@tonic-gate * The caller has to ensure that there is enough room in the mblk. 18930Sstevel@tonic-gate * 18940Sstevel@tonic-gate * buf can be NULL with a non-zero len. 18950Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 18960Sstevel@tonic-gate */ 18970Sstevel@tonic-gate void 18980Sstevel@tonic-gate soappendmsg(mblk_t *mp, const void *buf, ssize_t len) 18990Sstevel@tonic-gate { 19000Sstevel@tonic-gate ASSERT(mp); 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate if (len != 0) { 19030Sstevel@tonic-gate /* Assert for room left */ 19040Sstevel@tonic-gate ASSERT(mp->b_datap->db_lim - mp->b_wptr >= len); 19050Sstevel@tonic-gate if (buf != NULL) 19060Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 19070Sstevel@tonic-gate else 19080Sstevel@tonic-gate bzero(mp->b_wptr, len); 19090Sstevel@tonic-gate } 19100Sstevel@tonic-gate mp->b_wptr += len; 19110Sstevel@tonic-gate } 19120Sstevel@tonic-gate 19130Sstevel@tonic-gate /* 19140Sstevel@tonic-gate * Create a message using two kernel buffers. 19150Sstevel@tonic-gate * If size is set that will determine the allocation size (e.g. for future 19160Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 19170Sstevel@tonic-gate * lengths. 19180Sstevel@tonic-gate */ 19190Sstevel@tonic-gate mblk_t * 19200Sstevel@tonic-gate soallocproto2(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 19210Sstevel@tonic-gate ssize_t size, int sleepflg) 19220Sstevel@tonic-gate { 19230Sstevel@tonic-gate mblk_t *mp; 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate if (size == 0) 19260Sstevel@tonic-gate size = len1 + len2; 19270Sstevel@tonic-gate ASSERT(size >= len1 + len2); 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate mp = soallocproto1(buf1, len1, size, sleepflg); 19300Sstevel@tonic-gate if (mp) 19310Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 19320Sstevel@tonic-gate return (mp); 19330Sstevel@tonic-gate } 19340Sstevel@tonic-gate 19350Sstevel@tonic-gate /* 19360Sstevel@tonic-gate * Create a message using three kernel buffers. 19370Sstevel@tonic-gate * If size is set that will determine the allocation size (for future 19380Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 19390Sstevel@tonic-gate * lengths. 19400Sstevel@tonic-gate */ 19410Sstevel@tonic-gate mblk_t * 19420Sstevel@tonic-gate soallocproto3(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 19430Sstevel@tonic-gate const void *buf3, ssize_t len3, ssize_t size, int sleepflg) 19440Sstevel@tonic-gate { 19450Sstevel@tonic-gate mblk_t *mp; 19460Sstevel@tonic-gate 19470Sstevel@tonic-gate if (size == 0) 19480Sstevel@tonic-gate size = len1 + len2 +len3; 19490Sstevel@tonic-gate ASSERT(size >= len1 + len2 + len3); 19500Sstevel@tonic-gate 19510Sstevel@tonic-gate mp = soallocproto1(buf1, len1, size, sleepflg); 19520Sstevel@tonic-gate if (mp != NULL) { 19530Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 19540Sstevel@tonic-gate soappendmsg(mp, buf3, len3); 19550Sstevel@tonic-gate } 19560Sstevel@tonic-gate return (mp); 19570Sstevel@tonic-gate } 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate #ifdef DEBUG 19600Sstevel@tonic-gate char * 19610Sstevel@tonic-gate pr_state(uint_t state, uint_t mode) 19620Sstevel@tonic-gate { 19630Sstevel@tonic-gate static char buf[1024]; 19640Sstevel@tonic-gate 19650Sstevel@tonic-gate buf[0] = 0; 19660Sstevel@tonic-gate if (state & SS_ISCONNECTED) 19670Sstevel@tonic-gate strcat(buf, "ISCONNECTED "); 19680Sstevel@tonic-gate if (state & SS_ISCONNECTING) 19690Sstevel@tonic-gate strcat(buf, "ISCONNECTING "); 19700Sstevel@tonic-gate if (state & SS_ISDISCONNECTING) 19710Sstevel@tonic-gate strcat(buf, "ISDISCONNECTING "); 19720Sstevel@tonic-gate if (state & SS_CANTSENDMORE) 19730Sstevel@tonic-gate strcat(buf, "CANTSENDMORE "); 19740Sstevel@tonic-gate 19750Sstevel@tonic-gate if (state & SS_CANTRCVMORE) 19760Sstevel@tonic-gate strcat(buf, "CANTRCVMORE "); 19770Sstevel@tonic-gate if (state & SS_ISBOUND) 19780Sstevel@tonic-gate strcat(buf, "ISBOUND "); 19790Sstevel@tonic-gate if (state & SS_NDELAY) 19800Sstevel@tonic-gate strcat(buf, "NDELAY "); 19810Sstevel@tonic-gate if (state & SS_NONBLOCK) 19820Sstevel@tonic-gate strcat(buf, "NONBLOCK "); 19830Sstevel@tonic-gate 19840Sstevel@tonic-gate if (state & SS_ASYNC) 19850Sstevel@tonic-gate strcat(buf, "ASYNC "); 19860Sstevel@tonic-gate if (state & SS_ACCEPTCONN) 19870Sstevel@tonic-gate strcat(buf, "ACCEPTCONN "); 19880Sstevel@tonic-gate if (state & SS_HASCONNIND) 19890Sstevel@tonic-gate strcat(buf, "HASCONNIND "); 19900Sstevel@tonic-gate if (state & SS_SAVEDEOR) 19910Sstevel@tonic-gate strcat(buf, "SAVEDEOR "); 19920Sstevel@tonic-gate 19930Sstevel@tonic-gate if (state & SS_RCVATMARK) 19940Sstevel@tonic-gate strcat(buf, "RCVATMARK "); 19950Sstevel@tonic-gate if (state & SS_OOBPEND) 19960Sstevel@tonic-gate strcat(buf, "OOBPEND "); 19970Sstevel@tonic-gate if (state & SS_HAVEOOBDATA) 19980Sstevel@tonic-gate strcat(buf, "HAVEOOBDATA "); 19990Sstevel@tonic-gate if (state & SS_HADOOBDATA) 20000Sstevel@tonic-gate strcat(buf, "HADOOBDATA "); 20010Sstevel@tonic-gate 20020Sstevel@tonic-gate if (state & SS_FADDR_NOXLATE) 20030Sstevel@tonic-gate strcat(buf, "FADDR_NOXLATE "); 20040Sstevel@tonic-gate 20050Sstevel@tonic-gate if (mode & SM_PRIV) 20060Sstevel@tonic-gate strcat(buf, "PRIV "); 20070Sstevel@tonic-gate if (mode & SM_ATOMIC) 20080Sstevel@tonic-gate strcat(buf, "ATOMIC "); 20090Sstevel@tonic-gate if (mode & SM_ADDR) 20100Sstevel@tonic-gate strcat(buf, "ADDR "); 20110Sstevel@tonic-gate if (mode & SM_CONNREQUIRED) 20120Sstevel@tonic-gate strcat(buf, "CONNREQUIRED "); 20130Sstevel@tonic-gate 20140Sstevel@tonic-gate if (mode & SM_FDPASSING) 20150Sstevel@tonic-gate strcat(buf, "FDPASSING "); 20160Sstevel@tonic-gate if (mode & SM_EXDATA) 20170Sstevel@tonic-gate strcat(buf, "EXDATA "); 20180Sstevel@tonic-gate if (mode & SM_OPTDATA) 20190Sstevel@tonic-gate strcat(buf, "OPTDATA "); 20200Sstevel@tonic-gate if (mode & SM_BYTESTREAM) 20210Sstevel@tonic-gate strcat(buf, "BYTESTREAM "); 20220Sstevel@tonic-gate return (buf); 20230Sstevel@tonic-gate } 20240Sstevel@tonic-gate 20250Sstevel@tonic-gate char * 20260Sstevel@tonic-gate pr_addr(int family, struct sockaddr *addr, t_uscalar_t addrlen) 20270Sstevel@tonic-gate { 20280Sstevel@tonic-gate static char buf[1024]; 20290Sstevel@tonic-gate 20300Sstevel@tonic-gate if (addr == NULL || addrlen == 0) { 20310Sstevel@tonic-gate sprintf(buf, "(len %d) %p", addrlen, addr); 20320Sstevel@tonic-gate return (buf); 20330Sstevel@tonic-gate } 20340Sstevel@tonic-gate switch (family) { 20350Sstevel@tonic-gate case AF_INET: { 20360Sstevel@tonic-gate struct sockaddr_in sin; 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate bcopy(addr, &sin, sizeof (sin)); 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate (void) sprintf(buf, "(len %d) %x/%d", 20415753Sgww addrlen, ntohl(sin.sin_addr.s_addr), 20425753Sgww ntohs(sin.sin_port)); 20430Sstevel@tonic-gate break; 20440Sstevel@tonic-gate } 20450Sstevel@tonic-gate case AF_INET6: { 20460Sstevel@tonic-gate struct sockaddr_in6 sin6; 20470Sstevel@tonic-gate uint16_t *piece = (uint16_t *)&sin6.sin6_addr; 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate bcopy((char *)addr, (char *)&sin6, sizeof (sin6)); 20500Sstevel@tonic-gate sprintf(buf, "(len %d) %x:%x:%x:%x:%x:%x:%x:%x/%d", 20510Sstevel@tonic-gate addrlen, 20520Sstevel@tonic-gate ntohs(piece[0]), ntohs(piece[1]), 20530Sstevel@tonic-gate ntohs(piece[2]), ntohs(piece[3]), 20540Sstevel@tonic-gate ntohs(piece[4]), ntohs(piece[5]), 20550Sstevel@tonic-gate ntohs(piece[6]), ntohs(piece[7]), 20560Sstevel@tonic-gate ntohs(sin6.sin6_port)); 20570Sstevel@tonic-gate break; 20580Sstevel@tonic-gate } 20590Sstevel@tonic-gate case AF_UNIX: { 20600Sstevel@tonic-gate struct sockaddr_un *soun = (struct sockaddr_un *)addr; 20610Sstevel@tonic-gate 20620Sstevel@tonic-gate (void) sprintf(buf, "(len %d) %s", 20635753Sgww addrlen, 20645753Sgww (soun == NULL) ? "(none)" : soun->sun_path); 20650Sstevel@tonic-gate break; 20660Sstevel@tonic-gate } 20670Sstevel@tonic-gate default: 20680Sstevel@tonic-gate (void) sprintf(buf, "(unknown af %d)", family); 20690Sstevel@tonic-gate break; 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate return (buf); 20720Sstevel@tonic-gate } 20730Sstevel@tonic-gate 20740Sstevel@tonic-gate /* The logical equivalence operator (a if-and-only-if b) */ 20750Sstevel@tonic-gate #define EQUIV(a, b) (((a) && (b)) || (!(a) && (!(b)))) 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate /* 20780Sstevel@tonic-gate * Verify limitations and invariants on oob state. 20790Sstevel@tonic-gate * Return 1 if OK, otherwise 0 so that it can be used as 20800Sstevel@tonic-gate * ASSERT(verify_oobstate(so)); 20810Sstevel@tonic-gate */ 20820Sstevel@tonic-gate int 20830Sstevel@tonic-gate so_verify_oobstate(struct sonode *so) 20840Sstevel@tonic-gate { 20850Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 20860Sstevel@tonic-gate 20870Sstevel@tonic-gate /* 20880Sstevel@tonic-gate * The possible state combinations are: 20890Sstevel@tonic-gate * 0 20900Sstevel@tonic-gate * SS_OOBPEND 20910Sstevel@tonic-gate * SS_OOBPEND|SS_HAVEOOBDATA 20920Sstevel@tonic-gate * SS_OOBPEND|SS_HADOOBDATA 20930Sstevel@tonic-gate * SS_HADOOBDATA 20940Sstevel@tonic-gate */ 20950Sstevel@tonic-gate switch (so->so_state & (SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA)) { 20960Sstevel@tonic-gate case 0: 20970Sstevel@tonic-gate case SS_OOBPEND: 20980Sstevel@tonic-gate case SS_OOBPEND|SS_HAVEOOBDATA: 20990Sstevel@tonic-gate case SS_OOBPEND|SS_HADOOBDATA: 21000Sstevel@tonic-gate case SS_HADOOBDATA: 21010Sstevel@tonic-gate break; 21020Sstevel@tonic-gate default: 21030Sstevel@tonic-gate printf("Bad oob state 1 (%p): counts %d/%d state %s\n", 21045753Sgww so, so->so_oobsigcnt, 21055753Sgww so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21060Sstevel@tonic-gate return (0); 21070Sstevel@tonic-gate } 21080Sstevel@tonic-gate 21090Sstevel@tonic-gate /* SS_RCVATMARK should only be set when SS_OOBPEND is set */ 21100Sstevel@tonic-gate if ((so->so_state & (SS_RCVATMARK|SS_OOBPEND)) == SS_RCVATMARK) { 21110Sstevel@tonic-gate printf("Bad oob state 2 (%p): counts %d/%d state %s\n", 21125753Sgww so, so->so_oobsigcnt, 21135753Sgww so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21140Sstevel@tonic-gate return (0); 21150Sstevel@tonic-gate } 21160Sstevel@tonic-gate 21170Sstevel@tonic-gate /* 21180Sstevel@tonic-gate * (so_oobsigcnt != 0 or SS_RCVATMARK) iff SS_OOBPEND 21190Sstevel@tonic-gate */ 21200Sstevel@tonic-gate if (!EQUIV((so->so_oobsigcnt != 0) || (so->so_state & SS_RCVATMARK), 21215753Sgww so->so_state & SS_OOBPEND)) { 21220Sstevel@tonic-gate printf("Bad oob state 3 (%p): counts %d/%d state %s\n", 21235753Sgww so, so->so_oobsigcnt, 21245753Sgww so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21250Sstevel@tonic-gate return (0); 21260Sstevel@tonic-gate } 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate /* 21290Sstevel@tonic-gate * Unless SO_OOBINLINE we have so_oobmsg != NULL iff SS_HAVEOOBDATA 21300Sstevel@tonic-gate */ 21310Sstevel@tonic-gate if (!(so->so_options & SO_OOBINLINE) && 21320Sstevel@tonic-gate !EQUIV(so->so_oobmsg != NULL, so->so_state & SS_HAVEOOBDATA)) { 21330Sstevel@tonic-gate printf("Bad oob state 4 (%p): counts %d/%d state %s\n", 21345753Sgww so, so->so_oobsigcnt, 21355753Sgww so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21360Sstevel@tonic-gate return (0); 21370Sstevel@tonic-gate } 21380Sstevel@tonic-gate if (so->so_oobsigcnt < so->so_oobcnt) { 21390Sstevel@tonic-gate printf("Bad oob state 5 (%p): counts %d/%d state %s\n", 21405753Sgww so, so->so_oobsigcnt, 21415753Sgww so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21420Sstevel@tonic-gate return (0); 21430Sstevel@tonic-gate } 21440Sstevel@tonic-gate return (1); 21450Sstevel@tonic-gate } 21460Sstevel@tonic-gate #undef EQUIV 21470Sstevel@tonic-gate 21480Sstevel@tonic-gate #endif /* DEBUG */ 21490Sstevel@tonic-gate 21500Sstevel@tonic-gate /* initialize sockfs zone specific kstat related items */ 21510Sstevel@tonic-gate void * 21520Sstevel@tonic-gate sock_kstat_init(zoneid_t zoneid) 21530Sstevel@tonic-gate { 21540Sstevel@tonic-gate kstat_t *ksp; 21550Sstevel@tonic-gate 21560Sstevel@tonic-gate ksp = kstat_create_zone("sockfs", 0, "sock_unix_list", "misc", 21570Sstevel@tonic-gate KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE|KSTAT_FLAG_VIRTUAL, zoneid); 21580Sstevel@tonic-gate 21590Sstevel@tonic-gate if (ksp != NULL) { 21600Sstevel@tonic-gate ksp->ks_update = sockfs_update; 21610Sstevel@tonic-gate ksp->ks_snapshot = sockfs_snapshot; 21620Sstevel@tonic-gate ksp->ks_lock = &socklist.sl_lock; 21630Sstevel@tonic-gate ksp->ks_private = (void *)(uintptr_t)zoneid; 21640Sstevel@tonic-gate kstat_install(ksp); 21650Sstevel@tonic-gate } 21660Sstevel@tonic-gate 21670Sstevel@tonic-gate return (ksp); 21680Sstevel@tonic-gate } 21690Sstevel@tonic-gate 21700Sstevel@tonic-gate /* tear down sockfs zone specific kstat related items */ 21710Sstevel@tonic-gate /*ARGSUSED*/ 21720Sstevel@tonic-gate void 21730Sstevel@tonic-gate sock_kstat_fini(zoneid_t zoneid, void *arg) 21740Sstevel@tonic-gate { 21750Sstevel@tonic-gate kstat_t *ksp = (kstat_t *)arg; 21760Sstevel@tonic-gate 21770Sstevel@tonic-gate if (ksp != NULL) { 21780Sstevel@tonic-gate ASSERT(zoneid == (zoneid_t)(uintptr_t)ksp->ks_private); 21790Sstevel@tonic-gate kstat_delete(ksp); 21800Sstevel@tonic-gate } 21810Sstevel@tonic-gate } 21820Sstevel@tonic-gate 21830Sstevel@tonic-gate /* 21840Sstevel@tonic-gate * Zones: 21850Sstevel@tonic-gate * Note that nactive is going to be different for each zone. 21860Sstevel@tonic-gate * This means we require kstat to call sockfs_update and then sockfs_snapshot 21870Sstevel@tonic-gate * for the same zone, or sockfs_snapshot will be taken into the wrong size 21880Sstevel@tonic-gate * buffer. This is safe, but if the buffer is too small, user will not be 21890Sstevel@tonic-gate * given details of all sockets. However, as this kstat has a ks_lock, kstat 21900Sstevel@tonic-gate * driver will keep it locked between the update and the snapshot, so no 21910Sstevel@tonic-gate * other process (zone) can currently get inbetween resulting in a wrong size 21920Sstevel@tonic-gate * buffer allocation. 21930Sstevel@tonic-gate */ 21940Sstevel@tonic-gate static int 21950Sstevel@tonic-gate sockfs_update(kstat_t *ksp, int rw) 21960Sstevel@tonic-gate { 21970Sstevel@tonic-gate uint_t nactive = 0; /* # of active AF_UNIX sockets */ 21980Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 21990Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 22000Sstevel@tonic-gate 22010Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 22040Sstevel@tonic-gate return (EACCES); 22050Sstevel@tonic-gate } 22060Sstevel@tonic-gate 22070Sstevel@tonic-gate for (so = socklist.sl_list; so != NULL; so = so->so_next) { 22080Sstevel@tonic-gate if (so->so_accessvp != NULL && so->so_zoneid == myzoneid) { 22090Sstevel@tonic-gate nactive++; 22100Sstevel@tonic-gate } 22110Sstevel@tonic-gate } 22120Sstevel@tonic-gate ksp->ks_ndata = nactive; 22130Sstevel@tonic-gate ksp->ks_data_size = nactive * sizeof (struct k_sockinfo); 22140Sstevel@tonic-gate 22150Sstevel@tonic-gate return (0); 22160Sstevel@tonic-gate } 22170Sstevel@tonic-gate 22180Sstevel@tonic-gate static int 22190Sstevel@tonic-gate sockfs_snapshot(kstat_t *ksp, void *buf, int rw) 22200Sstevel@tonic-gate { 22210Sstevel@tonic-gate int ns; /* # of sonodes we've copied */ 22220Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 22230Sstevel@tonic-gate struct k_sockinfo *pksi; /* where we put sockinfo data */ 22240Sstevel@tonic-gate t_uscalar_t sn_len; /* soa_len */ 22250Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 22260Sstevel@tonic-gate 22270Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 22280Sstevel@tonic-gate 22290Sstevel@tonic-gate ksp->ks_snaptime = gethrtime(); 22300Sstevel@tonic-gate 22310Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 22320Sstevel@tonic-gate return (EACCES); 22330Sstevel@tonic-gate } 22340Sstevel@tonic-gate 22350Sstevel@tonic-gate /* 22360Sstevel@tonic-gate * for each sonode on the socklist, we massage the important 22370Sstevel@tonic-gate * info into buf, in k_sockinfo format. 22380Sstevel@tonic-gate */ 22390Sstevel@tonic-gate pksi = (struct k_sockinfo *)buf; 22400Sstevel@tonic-gate for (ns = 0, so = socklist.sl_list; so != NULL; so = so->so_next) { 22410Sstevel@tonic-gate /* only stuff active sonodes and the same zone: */ 22420Sstevel@tonic-gate if (so->so_accessvp == NULL || so->so_zoneid != myzoneid) { 22430Sstevel@tonic-gate continue; 22440Sstevel@tonic-gate } 22450Sstevel@tonic-gate 22460Sstevel@tonic-gate /* 22470Sstevel@tonic-gate * If the sonode was activated between the update and the 22480Sstevel@tonic-gate * snapshot, we're done - as this is only a snapshot. 22490Sstevel@tonic-gate */ 22500Sstevel@tonic-gate if ((caddr_t)(pksi) >= (caddr_t)buf + ksp->ks_data_size) { 22510Sstevel@tonic-gate break; 22520Sstevel@tonic-gate } 22530Sstevel@tonic-gate 22540Sstevel@tonic-gate /* copy important info into buf: */ 22550Sstevel@tonic-gate pksi->ks_si.si_size = sizeof (struct k_sockinfo); 22560Sstevel@tonic-gate pksi->ks_si.si_family = so->so_family; 22570Sstevel@tonic-gate pksi->ks_si.si_type = so->so_type; 22580Sstevel@tonic-gate pksi->ks_si.si_flag = so->so_flag; 22590Sstevel@tonic-gate pksi->ks_si.si_state = so->so_state; 22600Sstevel@tonic-gate pksi->ks_si.si_serv_type = so->so_serv_type; 22610Sstevel@tonic-gate pksi->ks_si.si_ux_laddr_sou_magic = so->so_ux_laddr.soua_magic; 22620Sstevel@tonic-gate pksi->ks_si.si_ux_faddr_sou_magic = so->so_ux_faddr.soua_magic; 22630Sstevel@tonic-gate pksi->ks_si.si_laddr_soa_len = so->so_laddr.soa_len; 22640Sstevel@tonic-gate pksi->ks_si.si_faddr_soa_len = so->so_faddr.soa_len; 22650Sstevel@tonic-gate pksi->ks_si.si_szoneid = so->so_zoneid; 22660Sstevel@tonic-gate 22670Sstevel@tonic-gate mutex_enter(&so->so_lock); 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate if (so->so_laddr_sa != NULL) { 22700Sstevel@tonic-gate ASSERT(so->so_laddr_sa->sa_data != NULL); 22710Sstevel@tonic-gate sn_len = so->so_laddr_len; 22720Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 22730Sstevel@tonic-gate sizeof (pksi->ks_si.si_laddr_sun_path)); 22740Sstevel@tonic-gate 22750Sstevel@tonic-gate pksi->ks_si.si_laddr_family = 22765753Sgww so->so_laddr_sa->sa_family; 22770Sstevel@tonic-gate if (sn_len != 0) { 22780Sstevel@tonic-gate /* AF_UNIX socket names are NULL terminated */ 22790Sstevel@tonic-gate (void) strncpy(pksi->ks_si.si_laddr_sun_path, 22800Sstevel@tonic-gate so->so_laddr_sa->sa_data, 22810Sstevel@tonic-gate sizeof (pksi->ks_si.si_laddr_sun_path)); 22820Sstevel@tonic-gate sn_len = strlen(pksi->ks_si.si_laddr_sun_path); 22830Sstevel@tonic-gate } 22840Sstevel@tonic-gate pksi->ks_si.si_laddr_sun_path[sn_len] = 0; 22850Sstevel@tonic-gate } 22860Sstevel@tonic-gate 22870Sstevel@tonic-gate if (so->so_faddr_sa != NULL) { 22880Sstevel@tonic-gate ASSERT(so->so_faddr_sa->sa_data != NULL); 22890Sstevel@tonic-gate sn_len = so->so_faddr_len; 22900Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 22910Sstevel@tonic-gate sizeof (pksi->ks_si.si_faddr_sun_path)); 22920Sstevel@tonic-gate 22930Sstevel@tonic-gate pksi->ks_si.si_faddr_family = 22940Sstevel@tonic-gate so->so_faddr_sa->sa_family; 22950Sstevel@tonic-gate if (sn_len != 0) { 22960Sstevel@tonic-gate (void) strncpy(pksi->ks_si.si_faddr_sun_path, 22970Sstevel@tonic-gate so->so_faddr_sa->sa_data, 22980Sstevel@tonic-gate sizeof (pksi->ks_si.si_faddr_sun_path)); 22990Sstevel@tonic-gate sn_len = strlen(pksi->ks_si.si_faddr_sun_path); 23000Sstevel@tonic-gate } 23010Sstevel@tonic-gate pksi->ks_si.si_faddr_sun_path[sn_len] = 0; 23020Sstevel@tonic-gate } 23030Sstevel@tonic-gate 23040Sstevel@tonic-gate mutex_exit(&so->so_lock); 23050Sstevel@tonic-gate 23060Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[0], "%p", (void *)so); 23070Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[1], "%p", 23080Sstevel@tonic-gate (void *)so->so_ux_laddr.soua_vp); 23090Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[2], "%p", 23100Sstevel@tonic-gate (void *)so->so_ux_faddr.soua_vp); 23110Sstevel@tonic-gate 23120Sstevel@tonic-gate ns++; 23130Sstevel@tonic-gate pksi++; 23140Sstevel@tonic-gate } 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate ksp->ks_ndata = ns; 23170Sstevel@tonic-gate return (0); 23180Sstevel@tonic-gate } 23190Sstevel@tonic-gate 23200Sstevel@tonic-gate ssize_t 23210Sstevel@tonic-gate soreadfile(file_t *fp, uchar_t *buf, u_offset_t fileoff, int *err, size_t size) 23220Sstevel@tonic-gate { 23230Sstevel@tonic-gate struct uio auio; 23240Sstevel@tonic-gate struct iovec aiov[MSG_MAXIOVLEN]; 23250Sstevel@tonic-gate register vnode_t *vp; 23260Sstevel@tonic-gate int ioflag, rwflag; 23270Sstevel@tonic-gate ssize_t cnt; 23280Sstevel@tonic-gate int error = 0; 23290Sstevel@tonic-gate int iovcnt = 0; 23300Sstevel@tonic-gate short fflag; 23310Sstevel@tonic-gate 23320Sstevel@tonic-gate vp = fp->f_vnode; 23330Sstevel@tonic-gate fflag = fp->f_flag; 23340Sstevel@tonic-gate 23350Sstevel@tonic-gate rwflag = 0; 23360Sstevel@tonic-gate aiov[0].iov_base = (caddr_t)buf; 23370Sstevel@tonic-gate aiov[0].iov_len = size; 23380Sstevel@tonic-gate iovcnt = 1; 23390Sstevel@tonic-gate cnt = (ssize_t)size; 23400Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 23410Sstevel@tonic-gate 23420Sstevel@tonic-gate auio.uio_loffset = fileoff; 23430Sstevel@tonic-gate auio.uio_iov = aiov; 23440Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 23450Sstevel@tonic-gate auio.uio_resid = cnt; 23460Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 23470Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 23480Sstevel@tonic-gate auio.uio_fmode = fflag; 23490Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 23500Sstevel@tonic-gate 23510Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 23520Sstevel@tonic-gate 23530Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 23540Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 23550Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 23560Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 23570Sstevel@tonic-gate cnt -= auio.uio_resid; 23580Sstevel@tonic-gate 23590Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 23600Sstevel@tonic-gate 23610Sstevel@tonic-gate if (error == EINTR && cnt != 0) 23620Sstevel@tonic-gate error = 0; 23630Sstevel@tonic-gate out: 23640Sstevel@tonic-gate if (error != 0) { 23650Sstevel@tonic-gate *err = error; 23660Sstevel@tonic-gate return (0); 23670Sstevel@tonic-gate } else { 23680Sstevel@tonic-gate *err = 0; 23690Sstevel@tonic-gate return (cnt); 23700Sstevel@tonic-gate } 23710Sstevel@tonic-gate } 2372