17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52caf0dcdSrshoaib * Common Development and Distribution License (the "License"). 62caf0dcdSrshoaib * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 212caf0dcdSrshoaib 227c478bd9Sstevel@tonic-gate /* 2317169044Sbrutus * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <sys/buf.h> 327c478bd9Sstevel@tonic-gate #include <sys/conf.h> 337c478bd9Sstevel@tonic-gate #include <sys/cred.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 367c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 37aa59c4cbSrsb #include <sys/vfs_opreg.h> 387c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 397c478bd9Sstevel@tonic-gate #include <sys/debug.h> 407c478bd9Sstevel@tonic-gate #include <sys/errno.h> 417c478bd9Sstevel@tonic-gate #include <sys/time.h> 427c478bd9Sstevel@tonic-gate #include <sys/file.h> 437c478bd9Sstevel@tonic-gate #include <sys/open.h> 447c478bd9Sstevel@tonic-gate #include <sys/user.h> 4517169044Sbrutus #include <sys/uio.h> 467c478bd9Sstevel@tonic-gate #include <sys/termios.h> 477c478bd9Sstevel@tonic-gate #include <sys/stream.h> 487c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 497c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 507c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 517c478bd9Sstevel@tonic-gate #include <sys/flock.h> 527c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 537c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 547c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 557c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 567c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 577c478bd9Sstevel@tonic-gate #include <sys/stat.h> 587c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 597c478bd9Sstevel@tonic-gate #include <sys/fs/dv_node.h> 607c478bd9Sstevel@tonic-gate #include <sys/zone.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #include <sys/socket.h> 637c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 647c478bd9Sstevel@tonic-gate #include <netinet/in.h> 657c478bd9Sstevel@tonic-gate #include <sys/un.h> 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #include <sys/ucred.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 707c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 717c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <c2/audit.h> 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #include <fs/sockfs/nl7c.h> 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* 787c478bd9Sstevel@tonic-gate * Macros that operate on struct cmsghdr. 797c478bd9Sstevel@tonic-gate * The CMSG_VALID macro does not assume that the last option buffer is padded. 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate #define CMSG_CONTENT(cmsg) (&((cmsg)[1])) 827c478bd9Sstevel@tonic-gate #define CMSG_CONTENTLEN(cmsg) ((cmsg)->cmsg_len - sizeof (struct cmsghdr)) 837c478bd9Sstevel@tonic-gate #define CMSG_VALID(cmsg, start, end) \ 847c478bd9Sstevel@tonic-gate (ISALIGNED_cmsghdr(cmsg) && \ 857c478bd9Sstevel@tonic-gate ((uintptr_t)(cmsg) >= (uintptr_t)(start)) && \ 867c478bd9Sstevel@tonic-gate ((uintptr_t)(cmsg) < (uintptr_t)(end)) && \ 877c478bd9Sstevel@tonic-gate ((ssize_t)(cmsg)->cmsg_len >= sizeof (struct cmsghdr)) && \ 887c478bd9Sstevel@tonic-gate ((uintptr_t)(cmsg) + (cmsg)->cmsg_len <= (uintptr_t)(end))) 897c478bd9Sstevel@tonic-gate #define SO_LOCK_WAKEUP_TIME 3000 /* Wakeup time in milliseconds */ 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static struct kmem_cache *socktpi_cache, *socktpi_unix_cache; 9217169044Sbrutus struct kmem_cache *socktpi_sod_cache; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate dev_t sockdev; /* For fsid in getattr */ 95*6cefaae1SJack Meng int sockfs_defer_nl7c_init = 0; 967c478bd9Sstevel@tonic-gate struct sockparams *sphead; 977c478bd9Sstevel@tonic-gate krwlock_t splist_lock; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate struct socklist socklist; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate static int sockfs_update(kstat_t *, int); 1027c478bd9Sstevel@tonic-gate static int sockfs_snapshot(kstat_t *, void *, int); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate extern void sendfile_init(); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate extern void nl7c_init(void); 1077c478bd9Sstevel@tonic-gate 10817169044Sbrutus extern int sostr_init(); 10917169044Sbrutus 110*6cefaae1SJack Meng extern int modrootloaded; 111*6cefaae1SJack Meng 1127c478bd9Sstevel@tonic-gate #define ADRSTRLEN (2 * sizeof (void *) + 1) 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * kernel structure for passing the sockinfo data back up to the user. 1157c478bd9Sstevel@tonic-gate * the strings array allows us to convert AF_UNIX addresses into strings 1167c478bd9Sstevel@tonic-gate * with a common method regardless of which n-bit kernel we're running. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate struct k_sockinfo { 1197c478bd9Sstevel@tonic-gate struct sockinfo ks_si; 1207c478bd9Sstevel@tonic-gate char ks_straddr[3][ADRSTRLEN]; 1217c478bd9Sstevel@tonic-gate }; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * Translate from a device pathname (e.g. "/dev/tcp") to a vnode. 1257c478bd9Sstevel@tonic-gate * Returns with the vnode held. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate static int 1287c478bd9Sstevel@tonic-gate sogetvp(char *devpath, vnode_t **vpp, int uioflag) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate struct snode *csp; 1317c478bd9Sstevel@tonic-gate vnode_t *vp, *dvp; 1327c478bd9Sstevel@tonic-gate major_t maj; 1337c478bd9Sstevel@tonic-gate int error; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate ASSERT(uioflag == UIO_SYSSPACE || uioflag == UIO_USERSPACE); 1367c478bd9Sstevel@tonic-gate /* 1377c478bd9Sstevel@tonic-gate * Lookup the underlying filesystem vnode. 1387c478bd9Sstevel@tonic-gate */ 1397c478bd9Sstevel@tonic-gate error = lookupname(devpath, uioflag, FOLLOW, NULLVPP, &vp); 1407c478bd9Sstevel@tonic-gate if (error) 1417c478bd9Sstevel@tonic-gate return (error); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* Check that it is the correct vnode */ 1447c478bd9Sstevel@tonic-gate if (vp->v_type != VCHR) { 1457c478bd9Sstevel@tonic-gate VN_RELE(vp); 1467c478bd9Sstevel@tonic-gate return (ENOTSOCK); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * If devpath went through devfs, the device should already 1517c478bd9Sstevel@tonic-gate * be configured. If devpath is a mknod file, however, we 1527c478bd9Sstevel@tonic-gate * need to make sure the device is properly configured. 1537c478bd9Sstevel@tonic-gate * To do this, we do something similar to spec_open() 1547c478bd9Sstevel@tonic-gate * except that we resolve to the minor/leaf level since 1557c478bd9Sstevel@tonic-gate * we need to return a vnode. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate csp = VTOS(VTOS(vp)->s_commonvp); 1587c478bd9Sstevel@tonic-gate if (!(csp->s_flag & SDIPSET)) { 1597c478bd9Sstevel@tonic-gate char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1607c478bd9Sstevel@tonic-gate error = ddi_dev_pathname(vp->v_rdev, S_IFCHR, pathname); 1617c478bd9Sstevel@tonic-gate if (error == 0) 1627c478bd9Sstevel@tonic-gate error = devfs_lookupname(pathname, NULLVPP, &dvp); 1637c478bd9Sstevel@tonic-gate VN_RELE(vp); 1647c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 1657c478bd9Sstevel@tonic-gate if (error != 0) 1667c478bd9Sstevel@tonic-gate return (ENXIO); 1677c478bd9Sstevel@tonic-gate vp = dvp; /* use the devfs vp */ 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* device is configured at this point */ 1717c478bd9Sstevel@tonic-gate maj = getmajor(vp->v_rdev); 1727c478bd9Sstevel@tonic-gate if (!STREAMSTAB(maj)) { 1737c478bd9Sstevel@tonic-gate VN_RELE(vp); 1747c478bd9Sstevel@tonic-gate return (ENOSTR); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate *vpp = vp; 1787c478bd9Sstevel@tonic-gate return (0); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Add or delete (latter if devpath is NULL) an enter to the sockparams 1837c478bd9Sstevel@tonic-gate * table. If devpathlen is zero the devpath with not be kmem_freed. Otherwise 1847c478bd9Sstevel@tonic-gate * this routine assumes that the caller has kmem_alloced devpath/devpathlen 1857c478bd9Sstevel@tonic-gate * for this routine to consume. 1867c478bd9Sstevel@tonic-gate * The zero devpathlen could be used if the kernel wants to create entries 1877c478bd9Sstevel@tonic-gate * itself by calling sockconfig(1,2,3, "/dev/tcp", 0); 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate int 1907c478bd9Sstevel@tonic-gate soconfig(int domain, int type, int protocol, 1917c478bd9Sstevel@tonic-gate char *devpath, int devpathlen) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate struct sockparams **spp; 1947c478bd9Sstevel@tonic-gate struct sockparams *sp; 1957c478bd9Sstevel@tonic-gate int error = 0; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate dprint(0, ("soconfig(%d,%d,%d,%s,%d)\n", 1987c478bd9Sstevel@tonic-gate domain, type, protocol, devpath, devpathlen)); 1997c478bd9Sstevel@tonic-gate 200*6cefaae1SJack Meng if (sockfs_defer_nl7c_init) { 201*6cefaae1SJack Meng nl7c_init(); 202*6cefaae1SJack Meng sockfs_defer_nl7c_init = 0; 203*6cefaae1SJack Meng } 204*6cefaae1SJack Meng 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Look for an existing match. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate rw_enter(&splist_lock, RW_WRITER); 2097c478bd9Sstevel@tonic-gate for (spp = &sphead; (sp = *spp) != NULL; spp = &sp->sp_next) { 2107c478bd9Sstevel@tonic-gate if (sp->sp_domain == domain && 2117c478bd9Sstevel@tonic-gate sp->sp_type == type && 2127c478bd9Sstevel@tonic-gate sp->sp_protocol == protocol) { 2137c478bd9Sstevel@tonic-gate break; 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate if (devpath == NULL) { 2177c478bd9Sstevel@tonic-gate ASSERT(devpathlen == 0); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* Delete existing entry */ 2207c478bd9Sstevel@tonic-gate if (sp == NULL) { 2217c478bd9Sstevel@tonic-gate error = ENXIO; 2227c478bd9Sstevel@tonic-gate goto done; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate /* Unlink and free existing entry */ 2257c478bd9Sstevel@tonic-gate *spp = sp->sp_next; 2267c478bd9Sstevel@tonic-gate ASSERT(sp->sp_vnode); 2277c478bd9Sstevel@tonic-gate VN_RELE(sp->sp_vnode); 2287c478bd9Sstevel@tonic-gate if (sp->sp_devpathlen != 0) 2297c478bd9Sstevel@tonic-gate kmem_free(sp->sp_devpath, sp->sp_devpathlen); 2307c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (*sp)); 2317c478bd9Sstevel@tonic-gate } else { 2327c478bd9Sstevel@tonic-gate vnode_t *vp; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* Add new entry */ 2357c478bd9Sstevel@tonic-gate if (sp != NULL) { 2367c478bd9Sstevel@tonic-gate error = EEXIST; 2377c478bd9Sstevel@tonic-gate goto done; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate error = sogetvp(devpath, &vp, UIO_SYSSPACE); 2417c478bd9Sstevel@tonic-gate if (error) { 2427c478bd9Sstevel@tonic-gate dprint(0, ("soconfig: vp %s failed with %d\n", 2437c478bd9Sstevel@tonic-gate devpath, error)); 2447c478bd9Sstevel@tonic-gate goto done; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate dprint(0, ("soconfig: %s => vp %p, dev 0x%lx\n", 248903a11ebSrh87107 devpath, (void *)vp, vp->v_rdev)); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate sp = kmem_alloc(sizeof (*sp), KM_SLEEP); 2517c478bd9Sstevel@tonic-gate sp->sp_domain = domain; 2527c478bd9Sstevel@tonic-gate sp->sp_type = type; 2537c478bd9Sstevel@tonic-gate sp->sp_protocol = protocol; 2547c478bd9Sstevel@tonic-gate sp->sp_devpath = devpath; 2557c478bd9Sstevel@tonic-gate sp->sp_devpathlen = devpathlen; 2567c478bd9Sstevel@tonic-gate sp->sp_vnode = vp; 2577c478bd9Sstevel@tonic-gate sp->sp_next = NULL; 2587c478bd9Sstevel@tonic-gate *spp = sp; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate done: 2617c478bd9Sstevel@tonic-gate rw_exit(&splist_lock); 2627c478bd9Sstevel@tonic-gate if (error) { 2637c478bd9Sstevel@tonic-gate if (devpath != NULL) 2647c478bd9Sstevel@tonic-gate kmem_free(devpath, devpathlen); 2657c478bd9Sstevel@tonic-gate #ifdef SOCK_DEBUG 2667c478bd9Sstevel@tonic-gate eprintline(error); 2677c478bd9Sstevel@tonic-gate #endif /* SOCK_DEBUG */ 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate return (error); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * Lookup an entry in the sockparams list based on the triple. 2747c478bd9Sstevel@tonic-gate * If no entry is found and devpath is not NULL translate devpath to a 2757c478bd9Sstevel@tonic-gate * vnode. Note that devpath is a pointer to a user address! 2767c478bd9Sstevel@tonic-gate * Returns with the vnode held. 2777c478bd9Sstevel@tonic-gate * 2787c478bd9Sstevel@tonic-gate * When this routine uses devpath it does not create an entry in the sockparams 2797c478bd9Sstevel@tonic-gate * list since this routine can run on behalf of any user and one user 2807c478bd9Sstevel@tonic-gate * should not be able to effect the transport used by another user. 2817c478bd9Sstevel@tonic-gate * 2827c478bd9Sstevel@tonic-gate * In order to return the correct error this routine has to do wildcard scans 2837c478bd9Sstevel@tonic-gate * of the list. The errors are (in decreasing precedence): 2847c478bd9Sstevel@tonic-gate * EAFNOSUPPORT - address family not in list 2857c478bd9Sstevel@tonic-gate * EPROTONOSUPPORT - address family supported but not protocol. 2867c478bd9Sstevel@tonic-gate * EPROTOTYPE - address family and protocol supported but not socket type. 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate vnode_t * 2897c478bd9Sstevel@tonic-gate solookup(int domain, int type, int protocol, char *devpath, int *errorp) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate struct sockparams *sp; 2927c478bd9Sstevel@tonic-gate int error; 2937c478bd9Sstevel@tonic-gate vnode_t *vp; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate rw_enter(&splist_lock, RW_READER); 2967c478bd9Sstevel@tonic-gate for (sp = sphead; sp != NULL; sp = sp->sp_next) { 2977c478bd9Sstevel@tonic-gate if (sp->sp_domain == domain && 2987c478bd9Sstevel@tonic-gate sp->sp_type == type && 2997c478bd9Sstevel@tonic-gate sp->sp_protocol == protocol) { 3007c478bd9Sstevel@tonic-gate break; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate if (sp == NULL) { 3047c478bd9Sstevel@tonic-gate dprint(0, ("solookup(%d,%d,%d) not found\n", 3057c478bd9Sstevel@tonic-gate domain, type, protocol)); 3067c478bd9Sstevel@tonic-gate if (devpath == NULL) { 3077c478bd9Sstevel@tonic-gate /* Determine correct error code */ 3087c478bd9Sstevel@tonic-gate int found = 0; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate for (sp = sphead; sp != NULL; sp = sp->sp_next) { 3117c478bd9Sstevel@tonic-gate if (sp->sp_domain == domain && found < 1) 3127c478bd9Sstevel@tonic-gate found = 1; 3137c478bd9Sstevel@tonic-gate if (sp->sp_domain == domain && 3147c478bd9Sstevel@tonic-gate sp->sp_protocol == protocol && found < 2) 3157c478bd9Sstevel@tonic-gate found = 2; 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate rw_exit(&splist_lock); 3187c478bd9Sstevel@tonic-gate switch (found) { 3197c478bd9Sstevel@tonic-gate case 0: 3207c478bd9Sstevel@tonic-gate *errorp = EAFNOSUPPORT; 3217c478bd9Sstevel@tonic-gate break; 3227c478bd9Sstevel@tonic-gate case 1: 3237c478bd9Sstevel@tonic-gate *errorp = EPROTONOSUPPORT; 3247c478bd9Sstevel@tonic-gate break; 3257c478bd9Sstevel@tonic-gate case 2: 3267c478bd9Sstevel@tonic-gate *errorp = EPROTOTYPE; 3277c478bd9Sstevel@tonic-gate break; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate return (NULL); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate rw_exit(&splist_lock); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * Return vp based on devpath. 3357c478bd9Sstevel@tonic-gate * Do not enter into table to avoid random users 3367c478bd9Sstevel@tonic-gate * modifying the sockparams list. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate error = sogetvp(devpath, &vp, UIO_USERSPACE); 3397c478bd9Sstevel@tonic-gate if (error) { 3407c478bd9Sstevel@tonic-gate dprint(0, ("solookup: vp %p failed with %d\n", 341903a11ebSrh87107 (void *)devpath, error)); 3427c478bd9Sstevel@tonic-gate *errorp = EPROTONOSUPPORT; 3437c478bd9Sstevel@tonic-gate return (NULL); 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate dprint(0, ("solookup: %p => vp %p, dev 0x%lx\n", 346903a11ebSrh87107 (void *)devpath, (void *)vp, vp->v_rdev)); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate return (vp); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate dprint(0, ("solookup(%d,%d,%d) vp %p devpath %s\n", 351903a11ebSrh87107 domain, type, protocol, (void *)sp->sp_vnode, sp->sp_devpath)); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate vp = sp->sp_vnode; 3547c478bd9Sstevel@tonic-gate VN_HOLD(vp); 3557c478bd9Sstevel@tonic-gate rw_exit(&splist_lock); 3567c478bd9Sstevel@tonic-gate return (vp); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * Return a socket vnode. 3617c478bd9Sstevel@tonic-gate * 3627c478bd9Sstevel@tonic-gate * Assumes that the caller is "passing" an VN_HOLD for accessvp i.e. 3637c478bd9Sstevel@tonic-gate * when the socket is freed a VN_RELE will take place. 3647c478bd9Sstevel@tonic-gate * 3657c478bd9Sstevel@tonic-gate * Note that sockets assume that the driver will clone (either itself 3667c478bd9Sstevel@tonic-gate * or by using the clone driver) i.e. a socket() call will always 3677c478bd9Sstevel@tonic-gate * result in a new vnode being created. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate struct vnode * 3707c478bd9Sstevel@tonic-gate makesockvp(struct vnode *accessvp, int domain, int type, int protocol) 3717c478bd9Sstevel@tonic-gate { 3727c478bd9Sstevel@tonic-gate kmem_cache_t *cp; 3737c478bd9Sstevel@tonic-gate struct sonode *so; 3747c478bd9Sstevel@tonic-gate struct vnode *vp; 3757c478bd9Sstevel@tonic-gate time_t now; 3767c478bd9Sstevel@tonic-gate dev_t dev; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate cp = (domain == AF_UNIX) ? socktpi_unix_cache : socktpi_cache; 3797c478bd9Sstevel@tonic-gate so = kmem_cache_alloc(cp, KM_SLEEP); 3807c478bd9Sstevel@tonic-gate so->so_cache = cp; 3817c478bd9Sstevel@tonic-gate so->so_obj = so; 3827c478bd9Sstevel@tonic-gate vp = SOTOV(so); 3837c478bd9Sstevel@tonic-gate now = gethrestime_sec(); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate so->so_flag = 0; 3867c478bd9Sstevel@tonic-gate ASSERT(so->so_accessvp == NULL); 3877c478bd9Sstevel@tonic-gate so->so_accessvp = accessvp; 3887c478bd9Sstevel@tonic-gate dev = accessvp->v_rdev; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* 3917c478bd9Sstevel@tonic-gate * Record in so_flag that it is a clone. 3927c478bd9Sstevel@tonic-gate */ 3937c478bd9Sstevel@tonic-gate if (getmajor(dev) == clone_major) { 3947c478bd9Sstevel@tonic-gate so->so_flag |= SOCLONE; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate so->so_dev = dev; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate so->so_state = 0; 3997c478bd9Sstevel@tonic-gate so->so_mode = 0; 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate so->so_fsid = sockdev; 4027c478bd9Sstevel@tonic-gate so->so_atime = now; 4037c478bd9Sstevel@tonic-gate so->so_mtime = now; 4047c478bd9Sstevel@tonic-gate so->so_ctime = now; /* Never modified */ 4057c478bd9Sstevel@tonic-gate so->so_count = 0; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate so->so_family = (short)domain; 4087c478bd9Sstevel@tonic-gate so->so_type = (short)type; 4097c478bd9Sstevel@tonic-gate so->so_protocol = (short)protocol; 4107c478bd9Sstevel@tonic-gate so->so_pushcnt = 0; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate so->so_options = 0; 4137c478bd9Sstevel@tonic-gate so->so_linger.l_onoff = 0; 4147c478bd9Sstevel@tonic-gate so->so_linger.l_linger = 0; 4157c478bd9Sstevel@tonic-gate so->so_sndbuf = 0; 4167c478bd9Sstevel@tonic-gate so->so_rcvbuf = 0; 4177c478bd9Sstevel@tonic-gate so->so_sndlowat = 0; 4187c478bd9Sstevel@tonic-gate so->so_rcvlowat = 0; 4197c478bd9Sstevel@tonic-gate #ifdef notyet 4207c478bd9Sstevel@tonic-gate so->so_sndtimeo = 0; 4217c478bd9Sstevel@tonic-gate so->so_rcvtimeo = 0; 4227c478bd9Sstevel@tonic-gate #endif /* notyet */ 4237c478bd9Sstevel@tonic-gate so->so_error = 0; 4247c478bd9Sstevel@tonic-gate so->so_delayed_error = 0; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 4277c478bd9Sstevel@tonic-gate so->so_oobcnt = 0; 4287c478bd9Sstevel@tonic-gate so->so_oobsigcnt = 0; 4297c478bd9Sstevel@tonic-gate so->so_pgrp = 0; 4307c478bd9Sstevel@tonic-gate so->so_provinfo = NULL; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate ASSERT(so->so_laddr_sa == NULL && so->so_faddr_sa == NULL); 4337c478bd9Sstevel@tonic-gate so->so_laddr_len = so->so_faddr_len = 0; 4347c478bd9Sstevel@tonic-gate so->so_laddr_maxlen = so->so_faddr_maxlen = 0; 4357c478bd9Sstevel@tonic-gate so->so_eaddr_mp = NULL; 4367c478bd9Sstevel@tonic-gate so->so_priv = NULL; 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate so->so_peercred = NULL; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate ASSERT(so->so_ack_mp == NULL); 4417c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_head == NULL); 4427c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 4437c478bd9Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 4447c478bd9Sstevel@tonic-gate ASSERT(so->so_unbind_mp == NULL); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate vn_reinit(vp); 4477c478bd9Sstevel@tonic-gate vp->v_vfsp = rootvfs; 4487c478bd9Sstevel@tonic-gate vp->v_type = VSOCK; 4497c478bd9Sstevel@tonic-gate vp->v_rdev = so->so_dev; 4507c478bd9Sstevel@tonic-gate vn_exists(vp); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate return (vp); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate void 4567c478bd9Sstevel@tonic-gate sockfree(struct sonode *so) 4577c478bd9Sstevel@tonic-gate { 4587c478bd9Sstevel@tonic-gate mblk_t *mp; 4597c478bd9Sstevel@tonic-gate vnode_t *vp; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate ASSERT(so->so_count == 0); 4627c478bd9Sstevel@tonic-gate ASSERT(so->so_accessvp); 4637c478bd9Sstevel@tonic-gate ASSERT(so->so_discon_ind_mp == NULL); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate vp = so->so_accessvp; 4667c478bd9Sstevel@tonic-gate VN_RELE(vp); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Protect so->so_[lf]addr_sa so that sockfs_snapshot() can safely 4707c478bd9Sstevel@tonic-gate * indirect them. It also uses so_accessvp as a validity test. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate so->so_accessvp = NULL; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (so->so_laddr_sa) { 4777c478bd9Sstevel@tonic-gate ASSERT((caddr_t)so->so_faddr_sa == 4787c478bd9Sstevel@tonic-gate (caddr_t)so->so_laddr_sa + so->so_laddr_maxlen); 4797c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_maxlen == so->so_laddr_maxlen); 4807c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_LADDR_VALID | SS_FADDR_VALID); 4817c478bd9Sstevel@tonic-gate kmem_free(so->so_laddr_sa, so->so_laddr_maxlen * 2); 4827c478bd9Sstevel@tonic-gate so->so_laddr_sa = NULL; 4837c478bd9Sstevel@tonic-gate so->so_laddr_len = so->so_laddr_maxlen = 0; 4847c478bd9Sstevel@tonic-gate so->so_faddr_sa = NULL; 4857c478bd9Sstevel@tonic-gate so->so_faddr_len = so->so_faddr_maxlen = 0; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate if ((mp = so->so_eaddr_mp) != NULL) { 4917c478bd9Sstevel@tonic-gate freemsg(mp); 4927c478bd9Sstevel@tonic-gate so->so_eaddr_mp = NULL; 4937c478bd9Sstevel@tonic-gate so->so_delayed_error = 0; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate if ((mp = so->so_ack_mp) != NULL) { 4967c478bd9Sstevel@tonic-gate freemsg(mp); 4977c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate if ((mp = so->so_conn_ind_head) != NULL) { 5007c478bd9Sstevel@tonic-gate mblk_t *mp1; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate while (mp) { 5037c478bd9Sstevel@tonic-gate mp1 = mp->b_next; 5047c478bd9Sstevel@tonic-gate mp->b_next = NULL; 5057c478bd9Sstevel@tonic-gate freemsg(mp); 5067c478bd9Sstevel@tonic-gate mp = mp1; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate so->so_conn_ind_head = so->so_conn_ind_tail = NULL; 5097c478bd9Sstevel@tonic-gate so->so_state &= ~SS_HASCONNIND; 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate #ifdef DEBUG 5127c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 5137c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 5147c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 5157c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 5167c478bd9Sstevel@tonic-gate if ((mp = so->so_oobmsg) != NULL) { 5177c478bd9Sstevel@tonic-gate freemsg(mp); 5187c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 5197c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate if ((mp = so->so_nl7c_rcv_mp) != NULL) { 5237c478bd9Sstevel@tonic-gate so->so_nl7c_rcv_mp = NULL; 5247c478bd9Sstevel@tonic-gate freemsg(mp); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate so->so_nl7c_rcv_rval = 0; 5277c478bd9Sstevel@tonic-gate if (so->so_nl7c_uri != NULL) { 5287c478bd9Sstevel@tonic-gate nl7c_urifree(so); 5292c9e429eSbrutus /* urifree() cleared nl7c_uri */ 5307c478bd9Sstevel@tonic-gate } 5312c9e429eSbrutus if (so->so_nl7c_flags) { 5327c478bd9Sstevel@tonic-gate so->so_nl7c_flags = 0; 5332c9e429eSbrutus } 5347c478bd9Sstevel@tonic-gate 53517169044Sbrutus if (so->so_direct != NULL) { 53617169044Sbrutus sodirect_t *sodp = so->so_direct; 53717169044Sbrutus 53817169044Sbrutus ASSERT(sodp->sod_uioafh == NULL); 53917169044Sbrutus 54017169044Sbrutus so->so_direct = NULL; 54117169044Sbrutus kmem_cache_free(socktpi_sod_cache, sodp); 54217169044Sbrutus } 54317169044Sbrutus 5447c478bd9Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 5457c478bd9Sstevel@tonic-gate if ((mp = so->so_unbind_mp) != NULL) { 5467c478bd9Sstevel@tonic-gate freemsg(mp); 5477c478bd9Sstevel@tonic-gate so->so_unbind_mp = NULL; 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate vn_invalid(SOTOV(so)); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 5527c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate kmem_cache_free(so->so_cache, so->so_obj); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * Update the accessed, updated, or changed times in an sonode 5597c478bd9Sstevel@tonic-gate * with the current time. 5607c478bd9Sstevel@tonic-gate * 5617c478bd9Sstevel@tonic-gate * Note that both SunOS 4.X and 4.4BSD sockets do not present reasonable 5627c478bd9Sstevel@tonic-gate * attributes in a fstat call. (They return the current time and 0 for 5637c478bd9Sstevel@tonic-gate * all timestamps, respectively.) We maintain the current timestamps 5647c478bd9Sstevel@tonic-gate * here primarily so that should sockmod be popped the resulting 5657c478bd9Sstevel@tonic-gate * file descriptor will behave like a stream w.r.t. the timestamps. 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate void 5687c478bd9Sstevel@tonic-gate so_update_attrs(struct sonode *so, int flag) 5697c478bd9Sstevel@tonic-gate { 5707c478bd9Sstevel@tonic-gate time_t now = gethrestime_sec(); 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 5737c478bd9Sstevel@tonic-gate so->so_flag |= flag; 5747c478bd9Sstevel@tonic-gate if (flag & SOACC) 5757c478bd9Sstevel@tonic-gate so->so_atime = now; 5767c478bd9Sstevel@tonic-gate if (flag & SOMOD) 5777c478bd9Sstevel@tonic-gate so->so_mtime = now; 5787c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5827c478bd9Sstevel@tonic-gate static int 5837c478bd9Sstevel@tonic-gate socktpi_constructor(void *buf, void *cdrarg, int kmflags) 5847c478bd9Sstevel@tonic-gate { 5857c478bd9Sstevel@tonic-gate struct sonode *so = buf; 5867c478bd9Sstevel@tonic-gate struct vnode *vp; 5877c478bd9Sstevel@tonic-gate 588b5fca8f8Stomee vp = so->so_vnode = vn_alloc(kmflags); 589b5fca8f8Stomee if (vp == NULL) { 590b5fca8f8Stomee return (-1); 591b5fca8f8Stomee } 592b5fca8f8Stomee vn_setops(vp, socktpi_vnodeops); 593b5fca8f8Stomee vp->v_data = so; 594b5fca8f8Stomee 59517169044Sbrutus so->so_direct = NULL; 59617169044Sbrutus 5977c478bd9Sstevel@tonic-gate so->so_nl7c_flags = 0; 5987c478bd9Sstevel@tonic-gate so->so_nl7c_uri = NULL; 5997c478bd9Sstevel@tonic-gate so->so_nl7c_rcv_mp = NULL; 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 6027c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 6037c478bd9Sstevel@tonic-gate so->so_conn_ind_head = NULL; 6047c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = NULL; 6057c478bd9Sstevel@tonic-gate so->so_discon_ind_mp = NULL; 6067c478bd9Sstevel@tonic-gate so->so_ux_bound_vp = NULL; 6077c478bd9Sstevel@tonic-gate so->so_unbind_mp = NULL; 6087c478bd9Sstevel@tonic-gate so->so_accessvp = NULL; 6097c478bd9Sstevel@tonic-gate so->so_laddr_sa = NULL; 6107c478bd9Sstevel@tonic-gate so->so_faddr_sa = NULL; 6117c478bd9Sstevel@tonic-gate so->so_ops = &sotpi_sonodeops; 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate mutex_init(&so->so_lock, NULL, MUTEX_DEFAULT, NULL); 6147c478bd9Sstevel@tonic-gate mutex_init(&so->so_plumb_lock, NULL, MUTEX_DEFAULT, NULL); 6157c478bd9Sstevel@tonic-gate cv_init(&so->so_state_cv, NULL, CV_DEFAULT, NULL); 6167c478bd9Sstevel@tonic-gate cv_init(&so->so_ack_cv, NULL, CV_DEFAULT, NULL); 6177c478bd9Sstevel@tonic-gate cv_init(&so->so_connind_cv, NULL, CV_DEFAULT, NULL); 6187c478bd9Sstevel@tonic-gate cv_init(&so->so_want_cv, NULL, CV_DEFAULT, NULL); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate return (0); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 6247c478bd9Sstevel@tonic-gate static void 6257c478bd9Sstevel@tonic-gate socktpi_destructor(void *buf, void *cdrarg) 6267c478bd9Sstevel@tonic-gate { 6277c478bd9Sstevel@tonic-gate struct sonode *so = buf; 6287c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 6297c478bd9Sstevel@tonic-gate 63017169044Sbrutus ASSERT(so->so_direct == NULL); 63117169044Sbrutus 6327c478bd9Sstevel@tonic-gate ASSERT(so->so_nl7c_flags == 0); 6337c478bd9Sstevel@tonic-gate ASSERT(so->so_nl7c_uri == NULL); 6347c478bd9Sstevel@tonic-gate ASSERT(so->so_nl7c_rcv_mp == NULL); 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 6377c478bd9Sstevel@tonic-gate ASSERT(so->so_ack_mp == NULL); 6387c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_head == NULL); 6397c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 6407c478bd9Sstevel@tonic-gate ASSERT(so->so_discon_ind_mp == NULL); 6417c478bd9Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 6427c478bd9Sstevel@tonic-gate ASSERT(so->so_unbind_mp == NULL); 6437c478bd9Sstevel@tonic-gate ASSERT(so->so_ops == &sotpi_sonodeops); 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate ASSERT(vn_matchops(vp, socktpi_vnodeops)); 646b5fca8f8Stomee ASSERT(vp->v_data == so); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate vn_free(vp); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate mutex_destroy(&so->so_lock); 6517c478bd9Sstevel@tonic-gate mutex_destroy(&so->so_plumb_lock); 6527c478bd9Sstevel@tonic-gate cv_destroy(&so->so_state_cv); 6537c478bd9Sstevel@tonic-gate cv_destroy(&so->so_ack_cv); 6547c478bd9Sstevel@tonic-gate cv_destroy(&so->so_connind_cv); 6557c478bd9Sstevel@tonic-gate cv_destroy(&so->so_want_cv); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate static int 6597c478bd9Sstevel@tonic-gate socktpi_unix_constructor(void *buf, void *cdrarg, int kmflags) 6607c478bd9Sstevel@tonic-gate { 6617c478bd9Sstevel@tonic-gate int retval; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate if ((retval = socktpi_constructor(buf, cdrarg, kmflags)) == 0) { 6647c478bd9Sstevel@tonic-gate struct sonode *so = (struct sonode *)buf; 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate mutex_enter(&socklist.sl_lock); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate so->so_next = socklist.sl_list; 6697c478bd9Sstevel@tonic-gate so->so_prev = NULL; 6707c478bd9Sstevel@tonic-gate if (so->so_next != NULL) 6717c478bd9Sstevel@tonic-gate so->so_next->so_prev = so; 6727c478bd9Sstevel@tonic-gate socklist.sl_list = so; 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate mutex_exit(&socklist.sl_lock); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate return (retval); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate static void 6817c478bd9Sstevel@tonic-gate socktpi_unix_destructor(void *buf, void *cdrarg) 6827c478bd9Sstevel@tonic-gate { 6837c478bd9Sstevel@tonic-gate struct sonode *so = (struct sonode *)buf; 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate mutex_enter(&socklist.sl_lock); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate if (so->so_next != NULL) 6887c478bd9Sstevel@tonic-gate so->so_next->so_prev = so->so_prev; 6897c478bd9Sstevel@tonic-gate if (so->so_prev != NULL) 6907c478bd9Sstevel@tonic-gate so->so_prev->so_next = so->so_next; 6917c478bd9Sstevel@tonic-gate else 6927c478bd9Sstevel@tonic-gate socklist.sl_list = so->so_next; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate mutex_exit(&socklist.sl_lock); 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate socktpi_destructor(buf, cdrarg); 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * Init function called when sockfs is loaded. 7017c478bd9Sstevel@tonic-gate */ 7027c478bd9Sstevel@tonic-gate int 7037c478bd9Sstevel@tonic-gate sockinit(int fstype, char *name) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate static const fs_operation_def_t sock_vfsops_template[] = { 7067c478bd9Sstevel@tonic-gate NULL, NULL 7077c478bd9Sstevel@tonic-gate }; 7087c478bd9Sstevel@tonic-gate int error; 7097c478bd9Sstevel@tonic-gate major_t dev; 7107c478bd9Sstevel@tonic-gate char *err_str; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstype, sock_vfsops_template, NULL); 7137c478bd9Sstevel@tonic-gate if (error != 0) { 7142caf0dcdSrshoaib zcmn_err(GLOBAL_ZONEID, CE_WARN, 7152caf0dcdSrshoaib "sockinit: bad vfs ops template"); 7167c478bd9Sstevel@tonic-gate return (error); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate error = vn_make_ops(name, socktpi_vnodeops_template, &socktpi_vnodeops); 7207c478bd9Sstevel@tonic-gate if (error != 0) { 7217c478bd9Sstevel@tonic-gate err_str = "sockinit: bad sock vnode ops template"; 7227c478bd9Sstevel@tonic-gate /* vn_make_ops() does not reset socktpi_vnodeops on failure. */ 7237c478bd9Sstevel@tonic-gate socktpi_vnodeops = NULL; 7247c478bd9Sstevel@tonic-gate goto failure; 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate error = sosctp_init(); 7287c478bd9Sstevel@tonic-gate if (error != 0) { 7297c478bd9Sstevel@tonic-gate err_str = NULL; 7307c478bd9Sstevel@tonic-gate goto failure; 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 73374e20cfeSnh145002 error = sosdp_init(); 73474e20cfeSnh145002 if (error != 0) { 73574e20cfeSnh145002 err_str = NULL; 73674e20cfeSnh145002 goto failure; 73774e20cfeSnh145002 } 73874e20cfeSnh145002 73917169044Sbrutus error = sostr_init(); 74017169044Sbrutus if (error != 0) { 74117169044Sbrutus err_str = NULL; 74217169044Sbrutus goto failure; 74317169044Sbrutus } 74417169044Sbrutus 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * Create sonode caches. We create a special one for AF_UNIX so 7477c478bd9Sstevel@tonic-gate * that we can track them for netstat(1m). 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate socktpi_cache = kmem_cache_create("socktpi_cache", 7507c478bd9Sstevel@tonic-gate sizeof (struct sonode), 0, socktpi_constructor, 7517c478bd9Sstevel@tonic-gate socktpi_destructor, NULL, NULL, NULL, 0); 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate socktpi_unix_cache = kmem_cache_create("socktpi_unix_cache", 7547c478bd9Sstevel@tonic-gate sizeof (struct sonode), 0, socktpi_unix_constructor, 7557c478bd9Sstevel@tonic-gate socktpi_unix_destructor, NULL, NULL, NULL, 0); 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * Build initial list mapping socket parameters to vnode. 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate rw_init(&splist_lock, NULL, RW_DEFAULT, NULL); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * If sockets are needed before init runs /sbin/soconfig 7647c478bd9Sstevel@tonic-gate * it is possible to preload the sockparams list here using 7657c478bd9Sstevel@tonic-gate * calls like: 7667c478bd9Sstevel@tonic-gate * sockconfig(1,2,3, "/dev/tcp", 0); 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate /* 7707c478bd9Sstevel@tonic-gate * Create a unique dev_t for use in so_fsid. 7717c478bd9Sstevel@tonic-gate */ 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate if ((dev = getudev()) == (major_t)-1) 7747c478bd9Sstevel@tonic-gate dev = 0; 7757c478bd9Sstevel@tonic-gate sockdev = makedevice(dev, 0); 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate mutex_init(&socklist.sl_lock, NULL, MUTEX_DEFAULT, NULL); 7787c478bd9Sstevel@tonic-gate sendfile_init(); 779*6cefaae1SJack Meng if (!modrootloaded) { 780*6cefaae1SJack Meng sockfs_defer_nl7c_init = 1; 781*6cefaae1SJack Meng } else { 7827c478bd9Sstevel@tonic-gate nl7c_init(); 783*6cefaae1SJack Meng } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate return (0); 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate failure: 7887c478bd9Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 7897c478bd9Sstevel@tonic-gate if (socktpi_vnodeops != NULL) 7907c478bd9Sstevel@tonic-gate vn_freevnodeops(socktpi_vnodeops); 7917c478bd9Sstevel@tonic-gate if (err_str != NULL) 7922caf0dcdSrshoaib zcmn_err(GLOBAL_ZONEID, CE_WARN, err_str); 7937c478bd9Sstevel@tonic-gate return (error); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOLOCKED. 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate void 8007c478bd9Sstevel@tonic-gate so_lock_single(struct sonode *so) 8017c478bd9Sstevel@tonic-gate { 8027c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate while (so->so_flag & (SOLOCKED | SOASYNC_UNBIND)) { 8057c478bd9Sstevel@tonic-gate so->so_flag |= SOWANT; 8067c478bd9Sstevel@tonic-gate cv_wait_stop(&so->so_want_cv, &so->so_lock, 8077c478bd9Sstevel@tonic-gate SO_LOCK_WAKEUP_TIME); 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate so->so_flag |= SOLOCKED; 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate /* 8137c478bd9Sstevel@tonic-gate * Caller must hold the mutex and pass in SOLOCKED or SOASYNC_UNBIND. 8147c478bd9Sstevel@tonic-gate * Used to clear SOLOCKED or SOASYNC_UNBIND. 8157c478bd9Sstevel@tonic-gate */ 8167c478bd9Sstevel@tonic-gate void 8177c478bd9Sstevel@tonic-gate so_unlock_single(struct sonode *so, int flag) 8187c478bd9Sstevel@tonic-gate { 8197c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8207c478bd9Sstevel@tonic-gate ASSERT(flag & (SOLOCKED|SOASYNC_UNBIND)); 8217c478bd9Sstevel@tonic-gate ASSERT((flag & ~(SOLOCKED|SOASYNC_UNBIND)) == 0); 8227c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & flag); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate /* 8257c478bd9Sstevel@tonic-gate * Process the T_DISCON_IND on so_discon_ind_mp. 8267c478bd9Sstevel@tonic-gate * 8277c478bd9Sstevel@tonic-gate * Call to so_drain_discon_ind will result in so_lock 8287c478bd9Sstevel@tonic-gate * being dropped and re-acquired later. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate if (so->so_discon_ind_mp != NULL) 8317c478bd9Sstevel@tonic-gate so_drain_discon_ind(so); 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate if (so->so_flag & SOWANT) 8347c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_want_cv); 8357c478bd9Sstevel@tonic-gate so->so_flag &= ~(SOWANT|flag); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOREADLOCKED. 8407c478bd9Sstevel@tonic-gate * If the caller wants nonblocking behavior it should set fmode. 8417c478bd9Sstevel@tonic-gate */ 8427c478bd9Sstevel@tonic-gate int 8437c478bd9Sstevel@tonic-gate so_lock_read(struct sonode *so, int fmode) 8447c478bd9Sstevel@tonic-gate { 8457c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 8487c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 8497c478bd9Sstevel@tonic-gate return (EWOULDBLOCK); 8507c478bd9Sstevel@tonic-gate so->so_flag |= SOWANT; 8517c478bd9Sstevel@tonic-gate cv_wait_stop(&so->so_want_cv, &so->so_lock, 8527c478bd9Sstevel@tonic-gate SO_LOCK_WAKEUP_TIME); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 8557c478bd9Sstevel@tonic-gate return (0); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* 8597c478bd9Sstevel@tonic-gate * Like so_lock_read above but allows signals. 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate int 8627c478bd9Sstevel@tonic-gate so_lock_read_intr(struct sonode *so, int fmode) 8637c478bd9Sstevel@tonic-gate { 8647c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 8677c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 8687c478bd9Sstevel@tonic-gate return (EWOULDBLOCK); 8697c478bd9Sstevel@tonic-gate so->so_flag |= SOWANT; 8707c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&so->so_want_cv, &so->so_lock)) 8717c478bd9Sstevel@tonic-gate return (EINTR); 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 8747c478bd9Sstevel@tonic-gate return (0); 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * Caller must hold the mutex. Used to clear SOREADLOCKED, 8797c478bd9Sstevel@tonic-gate * set in so_lock_read() or so_lock_read_intr(). 8807c478bd9Sstevel@tonic-gate */ 8817c478bd9Sstevel@tonic-gate void 8827c478bd9Sstevel@tonic-gate so_unlock_read(struct sonode *so) 8837c478bd9Sstevel@tonic-gate { 8847c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8857c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & SOREADLOCKED); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate if (so->so_flag & SOWANT) 8887c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_want_cv); 8897c478bd9Sstevel@tonic-gate so->so_flag &= ~(SOWANT|SOREADLOCKED); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * Verify that the specified offset falls within the mblk and 8947c478bd9Sstevel@tonic-gate * that the resulting pointer is aligned. 8957c478bd9Sstevel@tonic-gate * Returns NULL if not. 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate void * 8987c478bd9Sstevel@tonic-gate sogetoff(mblk_t *mp, t_uscalar_t offset, 8997c478bd9Sstevel@tonic-gate t_uscalar_t length, uint_t align_size) 9007c478bd9Sstevel@tonic-gate { 9017c478bd9Sstevel@tonic-gate uintptr_t ptr1, ptr2; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate ASSERT(mp && mp->b_wptr >= mp->b_rptr); 9047c478bd9Sstevel@tonic-gate ptr1 = (uintptr_t)mp->b_rptr + offset; 9057c478bd9Sstevel@tonic-gate ptr2 = (uintptr_t)ptr1 + length; 9067c478bd9Sstevel@tonic-gate if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) { 9077c478bd9Sstevel@tonic-gate eprintline(0); 9087c478bd9Sstevel@tonic-gate return (NULL); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate if ((ptr1 & (align_size - 1)) != 0) { 9117c478bd9Sstevel@tonic-gate eprintline(0); 9127c478bd9Sstevel@tonic-gate return (NULL); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate return ((void *)ptr1); 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate /* 9187c478bd9Sstevel@tonic-gate * Return the AF_UNIX underlying filesystem vnode matching a given name. 9197c478bd9Sstevel@tonic-gate * Makes sure the sending and the destination sonodes are compatible. 9207c478bd9Sstevel@tonic-gate * The vnode is returned held. 9217c478bd9Sstevel@tonic-gate * 9227c478bd9Sstevel@tonic-gate * The underlying filesystem VSOCK vnode has a v_stream pointer that 9237c478bd9Sstevel@tonic-gate * references the actual stream head (hence indirectly the actual sonode). 9247c478bd9Sstevel@tonic-gate */ 9257c478bd9Sstevel@tonic-gate static int 9267c478bd9Sstevel@tonic-gate so_ux_lookup(struct sonode *so, struct sockaddr_un *soun, int checkaccess, 9277c478bd9Sstevel@tonic-gate vnode_t **vpp) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate vnode_t *vp; /* Underlying filesystem vnode */ 9309bf9355bSRic Aleshire vnode_t *rvp; /* real vnode */ 9317c478bd9Sstevel@tonic-gate vnode_t *svp; /* sockfs vnode */ 9327c478bd9Sstevel@tonic-gate struct sonode *so2; 9337c478bd9Sstevel@tonic-gate int error; 9347c478bd9Sstevel@tonic-gate 9353eceedbbSrh87107 dprintso(so, 1, ("so_ux_lookup(%p) name <%s>\n", (void *)so, 9363eceedbbSrh87107 soun->sun_path)); 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate error = lookupname(soun->sun_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 9397c478bd9Sstevel@tonic-gate if (error) { 9407c478bd9Sstevel@tonic-gate eprintsoline(so, error); 9417c478bd9Sstevel@tonic-gate return (error); 9427c478bd9Sstevel@tonic-gate } 9439bf9355bSRic Aleshire 9449bf9355bSRic Aleshire /* 9459bf9355bSRic Aleshire * Traverse lofs mounts get the real vnode 9469bf9355bSRic Aleshire */ 9479bf9355bSRic Aleshire if (VOP_REALVP(vp, &rvp, NULL) == 0) { 9489bf9355bSRic Aleshire VN_HOLD(rvp); /* hold the real vnode */ 9499bf9355bSRic Aleshire VN_RELE(vp); /* release hold from lookup */ 9509bf9355bSRic Aleshire vp = rvp; 9519bf9355bSRic Aleshire } 9529bf9355bSRic Aleshire 9537c478bd9Sstevel@tonic-gate if (vp->v_type != VSOCK) { 9547c478bd9Sstevel@tonic-gate error = ENOTSOCK; 9557c478bd9Sstevel@tonic-gate eprintsoline(so, error); 9567c478bd9Sstevel@tonic-gate goto done2; 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (checkaccess) { 9607c478bd9Sstevel@tonic-gate /* 9617c478bd9Sstevel@tonic-gate * Check that we have permissions to access the destination 9627c478bd9Sstevel@tonic-gate * vnode. This check is not done in BSD but it is required 9637c478bd9Sstevel@tonic-gate * by X/Open. 9647c478bd9Sstevel@tonic-gate */ 965da6c28aaSamw if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL)) { 9667c478bd9Sstevel@tonic-gate eprintsoline(so, error); 9677c478bd9Sstevel@tonic-gate goto done2; 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * Check if the remote socket has been closed. 9737c478bd9Sstevel@tonic-gate * 9747c478bd9Sstevel@tonic-gate * Synchronize with vn_rele_stream by holding v_lock while traversing 9757c478bd9Sstevel@tonic-gate * v_stream->sd_vnode. 9767c478bd9Sstevel@tonic-gate */ 9777c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock); 9787c478bd9Sstevel@tonic-gate if (vp->v_stream == NULL) { 9797c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9807c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_DGRAM) 9817c478bd9Sstevel@tonic-gate error = EDESTADDRREQ; 9827c478bd9Sstevel@tonic-gate else 9837c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate eprintsoline(so, error); 9867c478bd9Sstevel@tonic-gate goto done2; 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate ASSERT(vp->v_stream->sd_vnode); 9897c478bd9Sstevel@tonic-gate svp = vp->v_stream->sd_vnode; 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * holding v_lock on underlying filesystem vnode and acquiring 9927c478bd9Sstevel@tonic-gate * it on sockfs vnode. Assumes that no code ever attempts to 9937c478bd9Sstevel@tonic-gate * acquire these locks in the reverse order. 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate VN_HOLD(svp); 9967c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate if (svp->v_type != VSOCK) { 9997c478bd9Sstevel@tonic-gate error = ENOTSOCK; 10007c478bd9Sstevel@tonic-gate eprintsoline(so, error); 10017c478bd9Sstevel@tonic-gate goto done; 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate so2 = VTOSO(svp); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (so->so_type != so2->so_type) { 10077c478bd9Sstevel@tonic-gate error = EPROTOTYPE; 10087c478bd9Sstevel@tonic-gate eprintsoline(so, error); 10097c478bd9Sstevel@tonic-gate goto done; 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate VN_RELE(svp); 10137c478bd9Sstevel@tonic-gate *vpp = vp; 10147c478bd9Sstevel@tonic-gate return (0); 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate done: 10177c478bd9Sstevel@tonic-gate VN_RELE(svp); 10187c478bd9Sstevel@tonic-gate done2: 10197c478bd9Sstevel@tonic-gate VN_RELE(vp); 10207c478bd9Sstevel@tonic-gate return (error); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * Verify peer address for connect and sendto/sendmsg. 10257c478bd9Sstevel@tonic-gate * Since sendto/sendmsg would not get synchronous errors from the transport 10267c478bd9Sstevel@tonic-gate * provider we have to do these ugly checks in the socket layer to 10277c478bd9Sstevel@tonic-gate * preserve compatibility with SunOS 4.X. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate int 10307c478bd9Sstevel@tonic-gate so_addr_verify(struct sonode *so, const struct sockaddr *name, 10317c478bd9Sstevel@tonic-gate socklen_t namelen) 10327c478bd9Sstevel@tonic-gate { 10337c478bd9Sstevel@tonic-gate int family; 10347c478bd9Sstevel@tonic-gate 1035903a11ebSrh87107 dprintso(so, 1, ("so_addr_verify(%p, %p, %d)\n", 1036903a11ebSrh87107 (void *)so, (void *)name, namelen)); 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate ASSERT(name != NULL); 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate family = so->so_family; 10417c478bd9Sstevel@tonic-gate switch (family) { 10427c478bd9Sstevel@tonic-gate case AF_INET: 10437c478bd9Sstevel@tonic-gate if (name->sa_family != family) { 10447c478bd9Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 10457c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in)) { 10487c478bd9Sstevel@tonic-gate eprintsoline(so, EINVAL); 10497c478bd9Sstevel@tonic-gate return (EINVAL); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate break; 10527c478bd9Sstevel@tonic-gate case AF_INET6: { 10537c478bd9Sstevel@tonic-gate #ifdef DEBUG 10547c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 10557c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate if (name->sa_family != family) { 10587c478bd9Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 10597c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) { 10627c478bd9Sstevel@tonic-gate eprintsoline(so, EINVAL); 10637c478bd9Sstevel@tonic-gate return (EINVAL); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate #ifdef DEBUG 10667c478bd9Sstevel@tonic-gate /* Verify that apps don't forget to clear sin6_scope_id etc */ 10677c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)name; 10687c478bd9Sstevel@tonic-gate if (sin6->sin6_scope_id != 0 && 10697c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 10702caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 10717c478bd9Sstevel@tonic-gate "connect/send* with uninitialized sin6_scope_id " 10727c478bd9Sstevel@tonic-gate "(%d) on socket. Pid = %d\n", 10737c478bd9Sstevel@tonic-gate (int)sin6->sin6_scope_id, (int)curproc->p_pid); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 10767c478bd9Sstevel@tonic-gate break; 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate case AF_UNIX: 10797c478bd9Sstevel@tonic-gate if (so->so_state & SS_FADDR_NOXLATE) { 10807c478bd9Sstevel@tonic-gate return (0); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate if (namelen < (socklen_t)sizeof (short)) { 10837c478bd9Sstevel@tonic-gate eprintsoline(so, ENOENT); 10847c478bd9Sstevel@tonic-gate return (ENOENT); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate if (name->sa_family != family) { 10877c478bd9Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 10887c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 10917c478bd9Sstevel@tonic-gate if (namelen > (socklen_t)(MAXPATHLEN + sizeof (short) + 1)) { 10927c478bd9Sstevel@tonic-gate eprintsoline(so, ENAMETOOLONG); 10937c478bd9Sstevel@tonic-gate return (ENAMETOOLONG); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate break; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate default: 10997c478bd9Sstevel@tonic-gate /* 11007c478bd9Sstevel@tonic-gate * Default is don't do any length or sa_family check 11017c478bd9Sstevel@tonic-gate * to allow non-sockaddr style addresses. 11027c478bd9Sstevel@tonic-gate */ 11037c478bd9Sstevel@tonic-gate break; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate return (0); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 11117c478bd9Sstevel@tonic-gate * Translate an AF_UNIX sockaddr_un to the transport internal name. 11127c478bd9Sstevel@tonic-gate * Assumes caller has called so_addr_verify first. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11157c478bd9Sstevel@tonic-gate int 11167c478bd9Sstevel@tonic-gate so_ux_addr_xlate(struct sonode *so, struct sockaddr *name, 11177c478bd9Sstevel@tonic-gate socklen_t namelen, int checkaccess, 11187c478bd9Sstevel@tonic-gate void **addrp, socklen_t *addrlenp) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate int error; 11217c478bd9Sstevel@tonic-gate struct sockaddr_un *soun; 11227c478bd9Sstevel@tonic-gate vnode_t *vp; 11237c478bd9Sstevel@tonic-gate void *addr; 11247c478bd9Sstevel@tonic-gate socklen_t addrlen; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate dprintso(so, 1, ("so_ux_addr_xlate(%p, %p, %d, %d)\n", 1127903a11ebSrh87107 (void *)so, (void *)name, namelen, checkaccess)); 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate ASSERT(name != NULL); 11307c478bd9Sstevel@tonic-gate ASSERT(so->so_family == AF_UNIX); 11317c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & SS_FADDR_NOXLATE)); 11327c478bd9Sstevel@tonic-gate ASSERT(namelen >= (socklen_t)sizeof (short)); 11337c478bd9Sstevel@tonic-gate ASSERT(name->sa_family == AF_UNIX); 11347c478bd9Sstevel@tonic-gate soun = (struct sockaddr_un *)name; 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * Lookup vnode for the specified path name and verify that 11377c478bd9Sstevel@tonic-gate * it is a socket. 11387c478bd9Sstevel@tonic-gate */ 11397c478bd9Sstevel@tonic-gate error = so_ux_lookup(so, soun, checkaccess, &vp); 11407c478bd9Sstevel@tonic-gate if (error) { 11417c478bd9Sstevel@tonic-gate eprintsoline(so, error); 11427c478bd9Sstevel@tonic-gate return (error); 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate /* 11457c478bd9Sstevel@tonic-gate * Use the address of the peer vnode as the address to send 11467c478bd9Sstevel@tonic-gate * to. We release the peer vnode here. In case it has been 11477c478bd9Sstevel@tonic-gate * closed by the time the T_CONN_REQ or T_UNIDATA_REQ reaches the 11487c478bd9Sstevel@tonic-gate * transport the message will get an error or be dropped. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate so->so_ux_faddr.soua_vp = vp; 11517c478bd9Sstevel@tonic-gate so->so_ux_faddr.soua_magic = SOU_MAGIC_EXPLICIT; 11527c478bd9Sstevel@tonic-gate addr = &so->so_ux_faddr; 11537c478bd9Sstevel@tonic-gate addrlen = (socklen_t)sizeof (so->so_ux_faddr); 1154903a11ebSrh87107 dprintso(so, 1, ("ux_xlate UNIX: addrlen %d, vp %p\n", 1155903a11ebSrh87107 addrlen, (void *)vp)); 11567c478bd9Sstevel@tonic-gate VN_RELE(vp); 11577c478bd9Sstevel@tonic-gate *addrp = addr; 11587c478bd9Sstevel@tonic-gate *addrlenp = (socklen_t)addrlen; 11597c478bd9Sstevel@tonic-gate return (0); 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* 11637c478bd9Sstevel@tonic-gate * Esballoc free function for messages that contain SO_FILEP option. 11647c478bd9Sstevel@tonic-gate * Decrement the reference count on the file pointers using closef. 11657c478bd9Sstevel@tonic-gate */ 11667c478bd9Sstevel@tonic-gate void 11677c478bd9Sstevel@tonic-gate fdbuf_free(struct fdbuf *fdbuf) 11687c478bd9Sstevel@tonic-gate { 11697c478bd9Sstevel@tonic-gate int i; 11707c478bd9Sstevel@tonic-gate struct file *fp; 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_free: %d fds\n", fdbuf->fd_numfd)); 11737c478bd9Sstevel@tonic-gate for (i = 0; i < fdbuf->fd_numfd; i++) { 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 11767c478bd9Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 11777c478bd9Sstevel@tonic-gate * the option headers and values are only 4 bytes 11787c478bd9Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 11797c478bd9Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 11807c478bd9Sstevel@tonic-gate */ 11817c478bd9Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 1182903a11ebSrh87107 dprint(1, ("fdbuf_free: [%d] = %p\n", i, (void *)fp)); 11837c478bd9Sstevel@tonic-gate (void) closef(fp); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate if (fdbuf->fd_ebuf != NULL) 11867c478bd9Sstevel@tonic-gate kmem_free(fdbuf->fd_ebuf, fdbuf->fd_ebuflen); 11877c478bd9Sstevel@tonic-gate kmem_free(fdbuf, fdbuf->fd_size); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate /* 1191bd118333Smeem * Allocate an esballoc'ed message for AF_UNIX file descriptor passing. 1192bd118333Smeem * Waits if memory is not available. 11937c478bd9Sstevel@tonic-gate */ 11947c478bd9Sstevel@tonic-gate mblk_t * 11957c478bd9Sstevel@tonic-gate fdbuf_allocmsg(int size, struct fdbuf *fdbuf) 11967c478bd9Sstevel@tonic-gate { 1197bd118333Smeem uchar_t *buf; 11987c478bd9Sstevel@tonic-gate mblk_t *mp; 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_allocmsg: size %d, %d fds\n", size, fdbuf->fd_numfd)); 12017c478bd9Sstevel@tonic-gate buf = kmem_alloc(size, KM_SLEEP); 12027c478bd9Sstevel@tonic-gate fdbuf->fd_ebuf = (caddr_t)buf; 12037c478bd9Sstevel@tonic-gate fdbuf->fd_ebuflen = size; 12047c478bd9Sstevel@tonic-gate fdbuf->fd_frtn.free_func = fdbuf_free; 12057c478bd9Sstevel@tonic-gate fdbuf->fd_frtn.free_arg = (caddr_t)fdbuf; 12067c478bd9Sstevel@tonic-gate 1207bd118333Smeem mp = esballoc_wait(buf, size, BPRI_MED, &fdbuf->fd_frtn); 12087c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 12097c478bd9Sstevel@tonic-gate return (mp); 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate /* 12137c478bd9Sstevel@tonic-gate * Extract file descriptors from a fdbuf. 12147c478bd9Sstevel@tonic-gate * Return list in rights/rightslen. 12157c478bd9Sstevel@tonic-gate */ 12167c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12177c478bd9Sstevel@tonic-gate static int 12187c478bd9Sstevel@tonic-gate fdbuf_extract(struct fdbuf *fdbuf, void *rights, int rightslen) 12197c478bd9Sstevel@tonic-gate { 12207c478bd9Sstevel@tonic-gate int i, fd; 12217c478bd9Sstevel@tonic-gate int *rp; 12227c478bd9Sstevel@tonic-gate struct file *fp; 12237c478bd9Sstevel@tonic-gate int numfd; 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_extract: %d fds, len %d\n", 12267c478bd9Sstevel@tonic-gate fdbuf->fd_numfd, rightslen)); 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate numfd = fdbuf->fd_numfd; 12297c478bd9Sstevel@tonic-gate ASSERT(rightslen == numfd * (int)sizeof (int)); 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* 12327c478bd9Sstevel@tonic-gate * Allocate a file descriptor and increment the f_count. 12337c478bd9Sstevel@tonic-gate * The latter is needed since we always call fdbuf_free 12347c478bd9Sstevel@tonic-gate * which performs a closef. 12357c478bd9Sstevel@tonic-gate */ 12367c478bd9Sstevel@tonic-gate rp = (int *)rights; 12377c478bd9Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 12387c478bd9Sstevel@tonic-gate if ((fd = ufalloc(0)) == -1) 12397c478bd9Sstevel@tonic-gate goto cleanup; 12407c478bd9Sstevel@tonic-gate /* 12417c478bd9Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 12427c478bd9Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 12437c478bd9Sstevel@tonic-gate * the option headers and values are only 4 bytes 12447c478bd9Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 12457c478bd9Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 12467c478bd9Sstevel@tonic-gate */ 12477c478bd9Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 12487c478bd9Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 12497c478bd9Sstevel@tonic-gate fp->f_count++; 12507c478bd9Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 12517c478bd9Sstevel@tonic-gate setf(fd, fp); 12527c478bd9Sstevel@tonic-gate *rp++ = fd; 12537c478bd9Sstevel@tonic-gate if (audit_active) 12547c478bd9Sstevel@tonic-gate audit_fdrecv(fd, fp); 12557c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_extract: [%d] = %d, %p refcnt %d\n", 1256903a11ebSrh87107 i, fd, (void *)fp, fp->f_count)); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate return (0); 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate cleanup: 12617c478bd9Sstevel@tonic-gate /* 12627c478bd9Sstevel@tonic-gate * Undo whatever partial work the loop above has done. 12637c478bd9Sstevel@tonic-gate */ 12647c478bd9Sstevel@tonic-gate { 12657c478bd9Sstevel@tonic-gate int j; 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate rp = (int *)rights; 12687c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) { 12697c478bd9Sstevel@tonic-gate dprint(0, 12707c478bd9Sstevel@tonic-gate ("fdbuf_extract: cleanup[%d] = %d\n", j, *rp)); 12717c478bd9Sstevel@tonic-gate (void) closeandsetf(*rp++, NULL); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate return (EMFILE); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate /* 12797c478bd9Sstevel@tonic-gate * Insert file descriptors into an fdbuf. 12807c478bd9Sstevel@tonic-gate * Returns a kmem_alloc'ed fdbuf. The fdbuf should be freed 12817c478bd9Sstevel@tonic-gate * by calling fdbuf_free(). 12827c478bd9Sstevel@tonic-gate */ 12837c478bd9Sstevel@tonic-gate int 12847c478bd9Sstevel@tonic-gate fdbuf_create(void *rights, int rightslen, struct fdbuf **fdbufp) 12857c478bd9Sstevel@tonic-gate { 12867c478bd9Sstevel@tonic-gate int numfd, i; 12877c478bd9Sstevel@tonic-gate int *fds; 12887c478bd9Sstevel@tonic-gate struct file *fp; 12897c478bd9Sstevel@tonic-gate struct fdbuf *fdbuf; 12907c478bd9Sstevel@tonic-gate int fdbufsize; 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_create: len %d\n", rightslen)); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate fdbufsize = (int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *)); 12977c478bd9Sstevel@tonic-gate fdbuf = kmem_alloc(fdbufsize, KM_SLEEP); 12987c478bd9Sstevel@tonic-gate fdbuf->fd_size = fdbufsize; 12997c478bd9Sstevel@tonic-gate fdbuf->fd_numfd = 0; 13007c478bd9Sstevel@tonic-gate fdbuf->fd_ebuf = NULL; 13017c478bd9Sstevel@tonic-gate fdbuf->fd_ebuflen = 0; 13027c478bd9Sstevel@tonic-gate fds = (int *)rights; 13037c478bd9Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 13047c478bd9Sstevel@tonic-gate if ((fp = getf(fds[i])) == NULL) { 13057c478bd9Sstevel@tonic-gate fdbuf_free(fdbuf); 13067c478bd9Sstevel@tonic-gate return (EBADF); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_create: [%d] = %d, %p refcnt %d\n", 1309903a11ebSrh87107 i, fds[i], (void *)fp, fp->f_count)); 13107c478bd9Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 13117c478bd9Sstevel@tonic-gate fp->f_count++; 13127c478bd9Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 13137c478bd9Sstevel@tonic-gate /* 13147c478bd9Sstevel@tonic-gate * The maximum alignment for fdbuf (or any option header 13157c478bd9Sstevel@tonic-gate * and its value) it 4 bytes. On a LP64 kernel, the alignment 13167c478bd9Sstevel@tonic-gate * is not sufficient for pointers (fd_fds in this case). Since 13177c478bd9Sstevel@tonic-gate * we just did a kmem_alloc (we get a double word alignment), 13187c478bd9Sstevel@tonic-gate * we don't need to do anything on the send side (we loose 13197c478bd9Sstevel@tonic-gate * the double word alignment because fdbuf goes after an 13207c478bd9Sstevel@tonic-gate * option header (eg T_unitdata_req) which is only 4 byte 13217c478bd9Sstevel@tonic-gate * aligned). We take care of this when we extract the file 13227c478bd9Sstevel@tonic-gate * descriptor in fdbuf_extract or fdbuf_free. 13237c478bd9Sstevel@tonic-gate */ 13247c478bd9Sstevel@tonic-gate fdbuf->fd_fds[i] = fp; 13257c478bd9Sstevel@tonic-gate fdbuf->fd_numfd++; 13267c478bd9Sstevel@tonic-gate releasef(fds[i]); 13277c478bd9Sstevel@tonic-gate if (audit_active) 13287c478bd9Sstevel@tonic-gate audit_fdsend(fds[i], fp, 0); 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate *fdbufp = fdbuf; 13317c478bd9Sstevel@tonic-gate return (0); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate static int 13357c478bd9Sstevel@tonic-gate fdbuf_optlen(int rightslen) 13367c478bd9Sstevel@tonic-gate { 13377c478bd9Sstevel@tonic-gate int numfd; 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate return ((int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *))); 13427c478bd9Sstevel@tonic-gate } 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate static t_uscalar_t 13457c478bd9Sstevel@tonic-gate fdbuf_cmsglen(int fdbuflen) 13467c478bd9Sstevel@tonic-gate { 13477c478bd9Sstevel@tonic-gate return (t_uscalar_t)((fdbuflen - FDBUF_HDRSIZE) / 13487c478bd9Sstevel@tonic-gate (int)sizeof (struct file *) * (int)sizeof (int)); 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate /* 13537c478bd9Sstevel@tonic-gate * Return non-zero if the mblk and fdbuf are consistent. 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate static int 13567c478bd9Sstevel@tonic-gate fdbuf_verify(mblk_t *mp, struct fdbuf *fdbuf, int fdbuflen) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate if (fdbuflen >= FDBUF_HDRSIZE && 13597c478bd9Sstevel@tonic-gate fdbuflen == fdbuf->fd_size) { 13607c478bd9Sstevel@tonic-gate frtn_t *frp = mp->b_datap->db_frtnp; 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * Check that the SO_FILEP portion of the 13637c478bd9Sstevel@tonic-gate * message has not been modified by 13647c478bd9Sstevel@tonic-gate * the loopback transport. The sending sockfs generates 13657c478bd9Sstevel@tonic-gate * a message that is esballoc'ed with the free function 13667c478bd9Sstevel@tonic-gate * being fdbuf_free() and where free_arg contains the 13677c478bd9Sstevel@tonic-gate * identical information as the SO_FILEP content. 13687c478bd9Sstevel@tonic-gate * 13697c478bd9Sstevel@tonic-gate * If any of these constraints are not satisfied we 13707c478bd9Sstevel@tonic-gate * silently ignore the option. 13717c478bd9Sstevel@tonic-gate */ 13727c478bd9Sstevel@tonic-gate ASSERT(mp); 13737c478bd9Sstevel@tonic-gate if (frp != NULL && 13747c478bd9Sstevel@tonic-gate frp->free_func == fdbuf_free && 13757c478bd9Sstevel@tonic-gate frp->free_arg != NULL && 13767c478bd9Sstevel@tonic-gate bcmp(frp->free_arg, fdbuf, fdbuflen) == 0) { 13777c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_verify: fdbuf %p len %d\n", 1378903a11ebSrh87107 (void *)fdbuf, fdbuflen)); 13797c478bd9Sstevel@tonic-gate return (1); 13807c478bd9Sstevel@tonic-gate } else { 13812caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 13827c478bd9Sstevel@tonic-gate "sockfs: mismatched fdbuf content (%p)", 13837c478bd9Sstevel@tonic-gate (void *)mp); 13847c478bd9Sstevel@tonic-gate return (0); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate } else { 13872caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 13887c478bd9Sstevel@tonic-gate "sockfs: mismatched fdbuf len %d, %d\n", 13897c478bd9Sstevel@tonic-gate fdbuflen, fdbuf->fd_size); 13907c478bd9Sstevel@tonic-gate return (0); 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * When the file descriptors returned by sorecvmsg can not be passed 13967c478bd9Sstevel@tonic-gate * to the application this routine will cleanup the references on 13977c478bd9Sstevel@tonic-gate * the files. Start at startoff bytes into the buffer. 13987c478bd9Sstevel@tonic-gate */ 13997c478bd9Sstevel@tonic-gate static void 14007c478bd9Sstevel@tonic-gate close_fds(void *fdbuf, int fdbuflen, int startoff) 14017c478bd9Sstevel@tonic-gate { 14027c478bd9Sstevel@tonic-gate int *fds = (int *)fdbuf; 14037c478bd9Sstevel@tonic-gate int numfd = fdbuflen / (int)sizeof (int); 14047c478bd9Sstevel@tonic-gate int i; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate dprint(1, ("close_fds(%p, %d, %d)\n", fdbuf, fdbuflen, startoff)); 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 14097c478bd9Sstevel@tonic-gate if (startoff < 0) 14107c478bd9Sstevel@tonic-gate startoff = 0; 14117c478bd9Sstevel@tonic-gate if (startoff < (int)sizeof (int)) { 14127c478bd9Sstevel@tonic-gate /* 14137c478bd9Sstevel@tonic-gate * This file descriptor is partially or fully after 14147c478bd9Sstevel@tonic-gate * the offset 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate dprint(0, 14177c478bd9Sstevel@tonic-gate ("close_fds: cleanup[%d] = %d\n", i, fds[i])); 14187c478bd9Sstevel@tonic-gate (void) closeandsetf(fds[i], NULL); 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate startoff -= (int)sizeof (int); 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate /* 14257c478bd9Sstevel@tonic-gate * Close all file descriptors contained in the control part starting at 14267c478bd9Sstevel@tonic-gate * the startoffset. 14277c478bd9Sstevel@tonic-gate */ 14287c478bd9Sstevel@tonic-gate void 14297c478bd9Sstevel@tonic-gate so_closefds(void *control, t_uscalar_t controllen, int oldflg, 14307c478bd9Sstevel@tonic-gate int startoff) 14317c478bd9Sstevel@tonic-gate { 14327c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate if (control == NULL) 14357c478bd9Sstevel@tonic-gate return; 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate if (oldflg) { 14387c478bd9Sstevel@tonic-gate close_fds(control, controllen, startoff); 14397c478bd9Sstevel@tonic-gate return; 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate /* Scan control part for file descriptors. */ 14427c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 14437c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 14447c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 14457c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 14467c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 14477c478bd9Sstevel@tonic-gate close_fds(CMSG_CONTENT(cmsg), 14487c478bd9Sstevel@tonic-gate (int)CMSG_CONTENTLEN(cmsg), 14497c478bd9Sstevel@tonic-gate startoff - (int)sizeof (struct cmsghdr)); 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate startoff -= cmsg->cmsg_len; 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * Returns a pointer/length for the file descriptors contained 14577c478bd9Sstevel@tonic-gate * in the control buffer. Returns with *fdlenp == -1 if there are no 14587c478bd9Sstevel@tonic-gate * file descriptor options present. This is different than there being 14597c478bd9Sstevel@tonic-gate * a zero-length file descriptor option. 14607c478bd9Sstevel@tonic-gate * Fail if there are multiple SCM_RIGHT cmsgs. 14617c478bd9Sstevel@tonic-gate */ 14627c478bd9Sstevel@tonic-gate int 14637c478bd9Sstevel@tonic-gate so_getfdopt(void *control, t_uscalar_t controllen, int oldflg, 14647c478bd9Sstevel@tonic-gate void **fdsp, int *fdlenp) 14657c478bd9Sstevel@tonic-gate { 14667c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 14677c478bd9Sstevel@tonic-gate void *fds; 14687c478bd9Sstevel@tonic-gate int fdlen; 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (control == NULL) { 14717c478bd9Sstevel@tonic-gate *fdsp = NULL; 14727c478bd9Sstevel@tonic-gate *fdlenp = -1; 14737c478bd9Sstevel@tonic-gate return (0); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate if (oldflg) { 14777c478bd9Sstevel@tonic-gate *fdsp = control; 14787c478bd9Sstevel@tonic-gate if (controllen == 0) 14797c478bd9Sstevel@tonic-gate *fdlenp = -1; 14807c478bd9Sstevel@tonic-gate else 14817c478bd9Sstevel@tonic-gate *fdlenp = controllen; 14827c478bd9Sstevel@tonic-gate dprint(1, ("so_getfdopt: old %d\n", *fdlenp)); 14837c478bd9Sstevel@tonic-gate return (0); 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate fds = NULL; 14877c478bd9Sstevel@tonic-gate fdlen = 0; 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 14907c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 14917c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 14927c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 14937c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 14947c478bd9Sstevel@tonic-gate if (fds != NULL) 14957c478bd9Sstevel@tonic-gate return (EINVAL); 14967c478bd9Sstevel@tonic-gate fds = CMSG_CONTENT(cmsg); 14977c478bd9Sstevel@tonic-gate fdlen = (int)CMSG_CONTENTLEN(cmsg); 14981e0267ddSkrgopi dprint(1, ("so_getfdopt: new %lu\n", 14991e0267ddSkrgopi (size_t)CMSG_CONTENTLEN(cmsg))); 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate if (fds == NULL) { 15037c478bd9Sstevel@tonic-gate dprint(1, ("so_getfdopt: NONE\n")); 15047c478bd9Sstevel@tonic-gate *fdlenp = -1; 15057c478bd9Sstevel@tonic-gate } else 15067c478bd9Sstevel@tonic-gate *fdlenp = fdlen; 15077c478bd9Sstevel@tonic-gate *fdsp = fds; 15087c478bd9Sstevel@tonic-gate return (0); 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate /* 15127c478bd9Sstevel@tonic-gate * Return the length of the options including any file descriptor options. 15137c478bd9Sstevel@tonic-gate */ 15147c478bd9Sstevel@tonic-gate t_uscalar_t 15157c478bd9Sstevel@tonic-gate so_optlen(void *control, t_uscalar_t controllen, int oldflg) 15167c478bd9Sstevel@tonic-gate { 15177c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 15187c478bd9Sstevel@tonic-gate t_uscalar_t optlen = 0; 15197c478bd9Sstevel@tonic-gate t_uscalar_t len; 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate if (control == NULL) 15227c478bd9Sstevel@tonic-gate return (0); 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate if (oldflg) 15257c478bd9Sstevel@tonic-gate return ((t_uscalar_t)(sizeof (struct T_opthdr) + 15267c478bd9Sstevel@tonic-gate fdbuf_optlen(controllen))); 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 15297c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 15307c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 15317c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 15327c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 15337c478bd9Sstevel@tonic-gate len = fdbuf_optlen((int)CMSG_CONTENTLEN(cmsg)); 15347c478bd9Sstevel@tonic-gate } else { 15357c478bd9Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate optlen += (t_uscalar_t)(_TPI_ALIGN_TOPT(len) + 15387c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate dprint(1, ("so_optlen: controllen %d, flg %d -> optlen %d\n", 15417c478bd9Sstevel@tonic-gate controllen, oldflg, optlen)); 15427c478bd9Sstevel@tonic-gate return (optlen); 15437c478bd9Sstevel@tonic-gate } 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate /* 15467c478bd9Sstevel@tonic-gate * Copy options from control to the mblk. Skip any file descriptor options. 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate void 15497c478bd9Sstevel@tonic-gate so_cmsg2opt(void *control, t_uscalar_t controllen, int oldflg, mblk_t *mp) 15507c478bd9Sstevel@tonic-gate { 15517c478bd9Sstevel@tonic-gate struct T_opthdr toh; 15527c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate if (control == NULL) 15557c478bd9Sstevel@tonic-gate return; 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate if (oldflg) { 15587c478bd9Sstevel@tonic-gate /* No real options - caller has handled file descriptors */ 15597c478bd9Sstevel@tonic-gate return; 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 15627c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 15637c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 15647c478bd9Sstevel@tonic-gate /* 15657c478bd9Sstevel@tonic-gate * Note: The caller handles file descriptors prior 15667c478bd9Sstevel@tonic-gate * to calling this function. 15677c478bd9Sstevel@tonic-gate */ 15687c478bd9Sstevel@tonic-gate t_uscalar_t len; 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 15717c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) 15727c478bd9Sstevel@tonic-gate continue; 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 15757c478bd9Sstevel@tonic-gate toh.level = cmsg->cmsg_level; 15767c478bd9Sstevel@tonic-gate toh.name = cmsg->cmsg_type; 15777c478bd9Sstevel@tonic-gate toh.len = len + (t_uscalar_t)sizeof (struct T_opthdr); 15787c478bd9Sstevel@tonic-gate toh.status = 0; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate soappendmsg(mp, &toh, sizeof (toh)); 15817c478bd9Sstevel@tonic-gate soappendmsg(mp, CMSG_CONTENT(cmsg), len); 15827c478bd9Sstevel@tonic-gate mp->b_wptr += _TPI_ALIGN_TOPT(len) - len; 15837c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr <= mp->b_datap->db_lim); 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate /* 15887c478bd9Sstevel@tonic-gate * Return the length of the control message derived from the options. 15897c478bd9Sstevel@tonic-gate * Exclude SO_SRCADDR and SO_UNIX_CLOSE options. Include SO_FILEP. 15907c478bd9Sstevel@tonic-gate * When oldflg is set only include SO_FILEP. 15910d204002Sgt145670 * so_opt2cmsg and so_cmsglen are inter-related since so_cmsglen 15920d204002Sgt145670 * allocates the space that so_opt2cmsg fills. If one changes, the other should 15930d204002Sgt145670 * also be checked for any possible impacts. 15947c478bd9Sstevel@tonic-gate */ 15957c478bd9Sstevel@tonic-gate t_uscalar_t 15967c478bd9Sstevel@tonic-gate so_cmsglen(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg) 15977c478bd9Sstevel@tonic-gate { 15987c478bd9Sstevel@tonic-gate t_uscalar_t cmsglen = 0; 15997c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 16007c478bd9Sstevel@tonic-gate t_uscalar_t len; 16017c478bd9Sstevel@tonic-gate t_uscalar_t last_roundup = 0; 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 16067c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 16077c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 16087c478bd9Sstevel@tonic-gate dprint(1, ("so_cmsglen: level 0x%x, name %d, len %d\n", 16097c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 16107c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 16117c478bd9Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 16127c478bd9Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 16137c478bd9Sstevel@tonic-gate continue; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 16167c478bd9Sstevel@tonic-gate struct fdbuf *fdbuf; 16177c478bd9Sstevel@tonic-gate int fdbuflen; 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 16207c478bd9Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 16237c478bd9Sstevel@tonic-gate continue; 16247c478bd9Sstevel@tonic-gate if (oldflg) { 16257c478bd9Sstevel@tonic-gate cmsglen += fdbuf_cmsglen(fdbuflen); 16267c478bd9Sstevel@tonic-gate continue; 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate len = fdbuf_cmsglen(fdbuflen); 16290d204002Sgt145670 } else if (tohp->level == SOL_SOCKET && 16300d204002Sgt145670 tohp->name == SCM_TIMESTAMP) { 16310d204002Sgt145670 if (oldflg) 16320d204002Sgt145670 continue; 16330d204002Sgt145670 16340d204002Sgt145670 if (get_udatamodel() == DATAMODEL_NATIVE) { 16350d204002Sgt145670 len = sizeof (struct timeval); 16360d204002Sgt145670 } else { 16370d204002Sgt145670 len = sizeof (struct timeval32); 16380d204002Sgt145670 } 16397c478bd9Sstevel@tonic-gate } else { 16407c478bd9Sstevel@tonic-gate if (oldflg) 16417c478bd9Sstevel@tonic-gate continue; 16427c478bd9Sstevel@tonic-gate len = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate /* 16450d204002Sgt145670 * Exclude roundup for last option to not set 16467c478bd9Sstevel@tonic-gate * MSG_CTRUNC when the cmsg fits but the padding doesn't fit. 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate last_roundup = (t_uscalar_t) 16497c478bd9Sstevel@tonic-gate (ROUNDUP_cmsglen(len + (int)sizeof (struct cmsghdr)) - 16507c478bd9Sstevel@tonic-gate (len + (int)sizeof (struct cmsghdr))); 16517c478bd9Sstevel@tonic-gate cmsglen += (t_uscalar_t)(len + (int)sizeof (struct cmsghdr)) + 16527c478bd9Sstevel@tonic-gate last_roundup; 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate cmsglen -= last_roundup; 16557c478bd9Sstevel@tonic-gate dprint(1, ("so_cmsglen: optlen %d, flg %d -> cmsglen %d\n", 16567c478bd9Sstevel@tonic-gate optlen, oldflg, cmsglen)); 16577c478bd9Sstevel@tonic-gate return (cmsglen); 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * Copy options from options to the control. Convert SO_FILEP to 16627c478bd9Sstevel@tonic-gate * file descriptors. 16637c478bd9Sstevel@tonic-gate * Returns errno or zero. 16640d204002Sgt145670 * so_opt2cmsg and so_cmsglen are inter-related since so_cmsglen 16650d204002Sgt145670 * allocates the space that so_opt2cmsg fills. If one changes, the other should 16660d204002Sgt145670 * also be checked for any possible impacts. 16677c478bd9Sstevel@tonic-gate */ 16687c478bd9Sstevel@tonic-gate int 16697c478bd9Sstevel@tonic-gate so_opt2cmsg(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg, 16707c478bd9Sstevel@tonic-gate void *control, t_uscalar_t controllen) 16717c478bd9Sstevel@tonic-gate { 16727c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 16737c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 16747c478bd9Sstevel@tonic-gate struct fdbuf *fdbuf; 16757c478bd9Sstevel@tonic-gate int fdbuflen; 16767c478bd9Sstevel@tonic-gate int error; 16770d204002Sgt145670 #if defined(DEBUG) || defined(__lint) 16780d204002Sgt145670 struct cmsghdr *cend = (struct cmsghdr *) 16790d204002Sgt145670 (((uint8_t *)control) + ROUNDUP_cmsglen(controllen)); 16800d204002Sgt145670 #endif 16817c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)control; 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 16867c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 16877c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 16887c478bd9Sstevel@tonic-gate dprint(1, ("so_opt2cmsg: level 0x%x, name %d, len %d\n", 16897c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 16927c478bd9Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 16937c478bd9Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 16947c478bd9Sstevel@tonic-gate continue; 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)cmsg <= (uintptr_t)control + controllen); 16977c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 16987c478bd9Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 16997c478bd9Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 17027c478bd9Sstevel@tonic-gate return (EPROTO); 17037c478bd9Sstevel@tonic-gate if (oldflg) { 17047c478bd9Sstevel@tonic-gate error = fdbuf_extract(fdbuf, control, 17057c478bd9Sstevel@tonic-gate (int)controllen); 17067c478bd9Sstevel@tonic-gate if (error != 0) 17077c478bd9Sstevel@tonic-gate return (error); 17087c478bd9Sstevel@tonic-gate continue; 17097c478bd9Sstevel@tonic-gate } else { 17107c478bd9Sstevel@tonic-gate int fdlen; 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate fdlen = (int)fdbuf_cmsglen( 17137c478bd9Sstevel@tonic-gate (int)_TPI_TOPT_DATALEN(tohp)); 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 17167c478bd9Sstevel@tonic-gate cmsg->cmsg_type = SCM_RIGHTS; 17177c478bd9Sstevel@tonic-gate cmsg->cmsg_len = (socklen_t)(fdlen + 17187c478bd9Sstevel@tonic-gate sizeof (struct cmsghdr)); 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate error = fdbuf_extract(fdbuf, 17217c478bd9Sstevel@tonic-gate CMSG_CONTENT(cmsg), fdlen); 17227c478bd9Sstevel@tonic-gate if (error != 0) 17237c478bd9Sstevel@tonic-gate return (error); 17247c478bd9Sstevel@tonic-gate } 1725e4f35dbaSgt145670 } else if (tohp->level == SOL_SOCKET && 1726e4f35dbaSgt145670 tohp->name == SCM_TIMESTAMP) { 1727e4f35dbaSgt145670 timestruc_t *timestamp; 1728e4f35dbaSgt145670 1729e4f35dbaSgt145670 if (oldflg) 1730e4f35dbaSgt145670 continue; 1731e4f35dbaSgt145670 1732e4f35dbaSgt145670 cmsg->cmsg_level = tohp->level; 1733e4f35dbaSgt145670 cmsg->cmsg_type = tohp->name; 1734e4f35dbaSgt145670 1735e4f35dbaSgt145670 timestamp = 1736e4f35dbaSgt145670 (timestruc_t *)P2ROUNDUP((intptr_t)&tohp[1], 1737e4f35dbaSgt145670 sizeof (intptr_t)); 1738e4f35dbaSgt145670 1739e4f35dbaSgt145670 if (get_udatamodel() == DATAMODEL_NATIVE) { 17400d204002Sgt145670 struct timeval tv; 1741e4f35dbaSgt145670 1742e4f35dbaSgt145670 cmsg->cmsg_len = sizeof (struct timeval) + 1743e4f35dbaSgt145670 sizeof (struct cmsghdr); 17440d204002Sgt145670 tv.tv_sec = timestamp->tv_sec; 17450d204002Sgt145670 tv.tv_usec = timestamp->tv_nsec / 17460d204002Sgt145670 (NANOSEC / MICROSEC); 17470d204002Sgt145670 /* 17480d204002Sgt145670 * on LP64 systems, the struct timeval in 17490d204002Sgt145670 * the destination will not be 8-byte aligned, 17500d204002Sgt145670 * so use bcopy to avoid alignment trouble 17510d204002Sgt145670 */ 17520d204002Sgt145670 bcopy(&tv, CMSG_CONTENT(cmsg), sizeof (tv)); 1753e4f35dbaSgt145670 } else { 1754e4f35dbaSgt145670 struct timeval32 *time32; 1755e4f35dbaSgt145670 1756e4f35dbaSgt145670 cmsg->cmsg_len = sizeof (struct timeval32) + 1757e4f35dbaSgt145670 sizeof (struct cmsghdr); 1758e4f35dbaSgt145670 time32 = (struct timeval32 *)CMSG_CONTENT(cmsg); 1759e4f35dbaSgt145670 time32->tv_sec = (time32_t)timestamp->tv_sec; 1760e4f35dbaSgt145670 time32->tv_usec = 1761e4f35dbaSgt145670 (int32_t)(timestamp->tv_nsec / 1762e4f35dbaSgt145670 (NANOSEC / MICROSEC)); 1763e4f35dbaSgt145670 } 1764e4f35dbaSgt145670 17657c478bd9Sstevel@tonic-gate } else { 17667c478bd9Sstevel@tonic-gate if (oldflg) 17677c478bd9Sstevel@tonic-gate continue; 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 17707c478bd9Sstevel@tonic-gate cmsg->cmsg_type = tohp->name; 17717c478bd9Sstevel@tonic-gate cmsg->cmsg_len = (socklen_t)(_TPI_TOPT_DATALEN(tohp) + 17727c478bd9Sstevel@tonic-gate sizeof (struct cmsghdr)); 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate /* copy content to control data part */ 17757c478bd9Sstevel@tonic-gate bcopy(&tohp[1], CMSG_CONTENT(cmsg), 17767c478bd9Sstevel@tonic-gate CMSG_CONTENTLEN(cmsg)); 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate /* move to next CMSG structure! */ 17797c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 17807c478bd9Sstevel@tonic-gate } 17810d204002Sgt145670 dprint(1, ("so_opt2cmsg: buf %p len %d; cend %p; final cmsg %p\n", 1782903a11ebSrh87107 control, controllen, (void *)cend, (void *)cmsg)); 17830d204002Sgt145670 ASSERT(cmsg <= cend); 17847c478bd9Sstevel@tonic-gate return (0); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate /* 17887c478bd9Sstevel@tonic-gate * Extract the SO_SRCADDR option value if present. 17897c478bd9Sstevel@tonic-gate */ 17907c478bd9Sstevel@tonic-gate void 17917c478bd9Sstevel@tonic-gate so_getopt_srcaddr(void *opt, t_uscalar_t optlen, void **srcp, 17927c478bd9Sstevel@tonic-gate t_uscalar_t *srclenp) 17937c478bd9Sstevel@tonic-gate { 17947c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate ASSERT(srcp != NULL && srclenp != NULL); 17997c478bd9Sstevel@tonic-gate *srcp = NULL; 18007c478bd9Sstevel@tonic-gate *srclenp = 0; 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 18037c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 18047c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 18057c478bd9Sstevel@tonic-gate dprint(1, ("so_getopt_srcaddr: level 0x%x, name %d, len %d\n", 18067c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 18077c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 18087c478bd9Sstevel@tonic-gate tohp->name == SO_SRCADDR) { 18097c478bd9Sstevel@tonic-gate *srcp = _TPI_TOPT_DATA(tohp); 18107c478bd9Sstevel@tonic-gate *srclenp = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate } 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate /* 18167c478bd9Sstevel@tonic-gate * Verify if the SO_UNIX_CLOSE option is present. 18177c478bd9Sstevel@tonic-gate */ 18187c478bd9Sstevel@tonic-gate int 18197c478bd9Sstevel@tonic-gate so_getopt_unix_close(void *opt, t_uscalar_t optlen) 18207c478bd9Sstevel@tonic-gate { 18217c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 18267c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 18277c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 18287c478bd9Sstevel@tonic-gate dprint(1, 18297c478bd9Sstevel@tonic-gate ("so_getopt_unix_close: level 0x%x, name %d, len %d\n", 18307c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 18317c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 18327c478bd9Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE) 18337c478bd9Sstevel@tonic-gate return (1); 18347c478bd9Sstevel@tonic-gate } 18357c478bd9Sstevel@tonic-gate return (0); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate /* 18397c478bd9Sstevel@tonic-gate * Allocate an M_PROTO message. 18407c478bd9Sstevel@tonic-gate * 18417c478bd9Sstevel@tonic-gate * If allocation fails the behavior depends on sleepflg: 18427c478bd9Sstevel@tonic-gate * _ALLOC_NOSLEEP fail immediately 18437c478bd9Sstevel@tonic-gate * _ALLOC_INTR sleep for memory until a signal is caught 18447c478bd9Sstevel@tonic-gate * _ALLOC_SLEEP sleep forever. Don't return NULL. 18457c478bd9Sstevel@tonic-gate */ 18467c478bd9Sstevel@tonic-gate mblk_t * 18477c478bd9Sstevel@tonic-gate soallocproto(size_t size, int sleepflg) 18487c478bd9Sstevel@tonic-gate { 18497c478bd9Sstevel@tonic-gate mblk_t *mp; 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* Round up size for reuse */ 18527c478bd9Sstevel@tonic-gate size = MAX(size, 64); 18537c478bd9Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 18547c478bd9Sstevel@tonic-gate if (mp == NULL) { 18557c478bd9Sstevel@tonic-gate int error; /* Dummy - error not returned to caller */ 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate switch (sleepflg) { 18587c478bd9Sstevel@tonic-gate case _ALLOC_SLEEP: 18597c478bd9Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, STR_NOSIG, &error); 18607c478bd9Sstevel@tonic-gate ASSERT(mp); 18617c478bd9Sstevel@tonic-gate break; 18627c478bd9Sstevel@tonic-gate case _ALLOC_INTR: 18637c478bd9Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 18647c478bd9Sstevel@tonic-gate if (mp == NULL) { 18657c478bd9Sstevel@tonic-gate /* Caught signal while sleeping for memory */ 18667c478bd9Sstevel@tonic-gate eprintline(ENOBUFS); 18677c478bd9Sstevel@tonic-gate return (NULL); 18687c478bd9Sstevel@tonic-gate } 18697c478bd9Sstevel@tonic-gate break; 18707c478bd9Sstevel@tonic-gate case _ALLOC_NOSLEEP: 18717c478bd9Sstevel@tonic-gate default: 18727c478bd9Sstevel@tonic-gate eprintline(ENOBUFS); 18737c478bd9Sstevel@tonic-gate return (NULL); 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate } 18767c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 18777c478bd9Sstevel@tonic-gate return (mp); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate /* 18817c478bd9Sstevel@tonic-gate * Allocate an M_PROTO message with a single component. 18827c478bd9Sstevel@tonic-gate * len is the length of buf. size is the amount to allocate. 18837c478bd9Sstevel@tonic-gate * 18847c478bd9Sstevel@tonic-gate * buf can be NULL with a non-zero len. 18857c478bd9Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 18867c478bd9Sstevel@tonic-gate */ 18877c478bd9Sstevel@tonic-gate mblk_t * 18887c478bd9Sstevel@tonic-gate soallocproto1(const void *buf, ssize_t len, ssize_t size, int sleepflg) 18897c478bd9Sstevel@tonic-gate { 18907c478bd9Sstevel@tonic-gate mblk_t *mp; 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate if (size == 0) 18937c478bd9Sstevel@tonic-gate size = len; 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate ASSERT(size >= len); 18967c478bd9Sstevel@tonic-gate /* Round up size for reuse */ 18977c478bd9Sstevel@tonic-gate size = MAX(size, 64); 18987c478bd9Sstevel@tonic-gate mp = soallocproto(size, sleepflg); 18997c478bd9Sstevel@tonic-gate if (mp == NULL) 19007c478bd9Sstevel@tonic-gate return (NULL); 19017c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 19027c478bd9Sstevel@tonic-gate if (len != 0) { 19037c478bd9Sstevel@tonic-gate if (buf != NULL) 19047c478bd9Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 19057c478bd9Sstevel@tonic-gate else 19067c478bd9Sstevel@tonic-gate bzero(mp->b_wptr, len); 19077c478bd9Sstevel@tonic-gate mp->b_wptr += len; 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate return (mp); 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate /* 19137c478bd9Sstevel@tonic-gate * Append buf/len to mp. 19147c478bd9Sstevel@tonic-gate * The caller has to ensure that there is enough room in the mblk. 19157c478bd9Sstevel@tonic-gate * 19167c478bd9Sstevel@tonic-gate * buf can be NULL with a non-zero len. 19177c478bd9Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 19187c478bd9Sstevel@tonic-gate */ 19197c478bd9Sstevel@tonic-gate void 19207c478bd9Sstevel@tonic-gate soappendmsg(mblk_t *mp, const void *buf, ssize_t len) 19217c478bd9Sstevel@tonic-gate { 19227c478bd9Sstevel@tonic-gate ASSERT(mp); 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate if (len != 0) { 19257c478bd9Sstevel@tonic-gate /* Assert for room left */ 19267c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_lim - mp->b_wptr >= len); 19277c478bd9Sstevel@tonic-gate if (buf != NULL) 19287c478bd9Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 19297c478bd9Sstevel@tonic-gate else 19307c478bd9Sstevel@tonic-gate bzero(mp->b_wptr, len); 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate mp->b_wptr += len; 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate /* 19367c478bd9Sstevel@tonic-gate * Create a message using two kernel buffers. 19377c478bd9Sstevel@tonic-gate * If size is set that will determine the allocation size (e.g. for future 19387c478bd9Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 19397c478bd9Sstevel@tonic-gate * lengths. 19407c478bd9Sstevel@tonic-gate */ 19417c478bd9Sstevel@tonic-gate mblk_t * 19427c478bd9Sstevel@tonic-gate soallocproto2(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 19437c478bd9Sstevel@tonic-gate ssize_t size, int sleepflg) 19447c478bd9Sstevel@tonic-gate { 19457c478bd9Sstevel@tonic-gate mblk_t *mp; 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate if (size == 0) 19487c478bd9Sstevel@tonic-gate size = len1 + len2; 19497c478bd9Sstevel@tonic-gate ASSERT(size >= len1 + len2); 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate mp = soallocproto1(buf1, len1, size, sleepflg); 19527c478bd9Sstevel@tonic-gate if (mp) 19537c478bd9Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 19547c478bd9Sstevel@tonic-gate return (mp); 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate /* 19587c478bd9Sstevel@tonic-gate * Create a message using three kernel buffers. 19597c478bd9Sstevel@tonic-gate * If size is set that will determine the allocation size (for future 19607c478bd9Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 19617c478bd9Sstevel@tonic-gate * lengths. 19627c478bd9Sstevel@tonic-gate */ 19637c478bd9Sstevel@tonic-gate mblk_t * 19647c478bd9Sstevel@tonic-gate soallocproto3(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 19657c478bd9Sstevel@tonic-gate const void *buf3, ssize_t len3, ssize_t size, int sleepflg) 19667c478bd9Sstevel@tonic-gate { 19677c478bd9Sstevel@tonic-gate mblk_t *mp; 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate if (size == 0) 19707c478bd9Sstevel@tonic-gate size = len1 + len2 +len3; 19717c478bd9Sstevel@tonic-gate ASSERT(size >= len1 + len2 + len3); 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate mp = soallocproto1(buf1, len1, size, sleepflg); 19747c478bd9Sstevel@tonic-gate if (mp != NULL) { 19757c478bd9Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 19767c478bd9Sstevel@tonic-gate soappendmsg(mp, buf3, len3); 19777c478bd9Sstevel@tonic-gate } 19787c478bd9Sstevel@tonic-gate return (mp); 19797c478bd9Sstevel@tonic-gate } 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate #ifdef DEBUG 19827c478bd9Sstevel@tonic-gate char * 19837c478bd9Sstevel@tonic-gate pr_state(uint_t state, uint_t mode) 19847c478bd9Sstevel@tonic-gate { 19857c478bd9Sstevel@tonic-gate static char buf[1024]; 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate buf[0] = 0; 19887c478bd9Sstevel@tonic-gate if (state & SS_ISCONNECTED) 1989903a11ebSrh87107 (void) strcat(buf, "ISCONNECTED "); 19907c478bd9Sstevel@tonic-gate if (state & SS_ISCONNECTING) 1991903a11ebSrh87107 (void) strcat(buf, "ISCONNECTING "); 19927c478bd9Sstevel@tonic-gate if (state & SS_ISDISCONNECTING) 1993903a11ebSrh87107 (void) strcat(buf, "ISDISCONNECTING "); 19947c478bd9Sstevel@tonic-gate if (state & SS_CANTSENDMORE) 1995903a11ebSrh87107 (void) strcat(buf, "CANTSENDMORE "); 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate if (state & SS_CANTRCVMORE) 1998903a11ebSrh87107 (void) strcat(buf, "CANTRCVMORE "); 19997c478bd9Sstevel@tonic-gate if (state & SS_ISBOUND) 2000903a11ebSrh87107 (void) strcat(buf, "ISBOUND "); 20017c478bd9Sstevel@tonic-gate if (state & SS_NDELAY) 2002903a11ebSrh87107 (void) strcat(buf, "NDELAY "); 20037c478bd9Sstevel@tonic-gate if (state & SS_NONBLOCK) 2004903a11ebSrh87107 (void) strcat(buf, "NONBLOCK "); 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate if (state & SS_ASYNC) 2007903a11ebSrh87107 (void) strcat(buf, "ASYNC "); 20087c478bd9Sstevel@tonic-gate if (state & SS_ACCEPTCONN) 2009903a11ebSrh87107 (void) strcat(buf, "ACCEPTCONN "); 20107c478bd9Sstevel@tonic-gate if (state & SS_HASCONNIND) 2011903a11ebSrh87107 (void) strcat(buf, "HASCONNIND "); 20127c478bd9Sstevel@tonic-gate if (state & SS_SAVEDEOR) 2013903a11ebSrh87107 (void) strcat(buf, "SAVEDEOR "); 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate if (state & SS_RCVATMARK) 2016903a11ebSrh87107 (void) strcat(buf, "RCVATMARK "); 20177c478bd9Sstevel@tonic-gate if (state & SS_OOBPEND) 2018903a11ebSrh87107 (void) strcat(buf, "OOBPEND "); 20197c478bd9Sstevel@tonic-gate if (state & SS_HAVEOOBDATA) 2020903a11ebSrh87107 (void) strcat(buf, "HAVEOOBDATA "); 20217c478bd9Sstevel@tonic-gate if (state & SS_HADOOBDATA) 2022903a11ebSrh87107 (void) strcat(buf, "HADOOBDATA "); 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate if (state & SS_FADDR_NOXLATE) 2025903a11ebSrh87107 (void) strcat(buf, "FADDR_NOXLATE "); 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate if (mode & SM_PRIV) 2028903a11ebSrh87107 (void) strcat(buf, "PRIV "); 20297c478bd9Sstevel@tonic-gate if (mode & SM_ATOMIC) 2030903a11ebSrh87107 (void) strcat(buf, "ATOMIC "); 20317c478bd9Sstevel@tonic-gate if (mode & SM_ADDR) 2032903a11ebSrh87107 (void) strcat(buf, "ADDR "); 20337c478bd9Sstevel@tonic-gate if (mode & SM_CONNREQUIRED) 2034903a11ebSrh87107 (void) strcat(buf, "CONNREQUIRED "); 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate if (mode & SM_FDPASSING) 2037903a11ebSrh87107 (void) strcat(buf, "FDPASSING "); 20387c478bd9Sstevel@tonic-gate if (mode & SM_EXDATA) 2039903a11ebSrh87107 (void) strcat(buf, "EXDATA "); 20407c478bd9Sstevel@tonic-gate if (mode & SM_OPTDATA) 2041903a11ebSrh87107 (void) strcat(buf, "OPTDATA "); 20427c478bd9Sstevel@tonic-gate if (mode & SM_BYTESTREAM) 2043903a11ebSrh87107 (void) strcat(buf, "BYTESTREAM "); 20447c478bd9Sstevel@tonic-gate return (buf); 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate char * 20487c478bd9Sstevel@tonic-gate pr_addr(int family, struct sockaddr *addr, t_uscalar_t addrlen) 20497c478bd9Sstevel@tonic-gate { 20507c478bd9Sstevel@tonic-gate static char buf[1024]; 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate if (addr == NULL || addrlen == 0) { 2053903a11ebSrh87107 (void) sprintf(buf, "(len %d) %p", addrlen, (void *)addr); 20547c478bd9Sstevel@tonic-gate return (buf); 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate switch (family) { 20577c478bd9Sstevel@tonic-gate case AF_INET: { 20587c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate bcopy(addr, &sin, sizeof (sin)); 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate (void) sprintf(buf, "(len %d) %x/%d", 2063b5fca8f8Stomee addrlen, ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); 20647c478bd9Sstevel@tonic-gate break; 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate case AF_INET6: { 20677c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 20687c478bd9Sstevel@tonic-gate uint16_t *piece = (uint16_t *)&sin6.sin6_addr; 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate bcopy((char *)addr, (char *)&sin6, sizeof (sin6)); 2071903a11ebSrh87107 (void) sprintf(buf, "(len %d) %x:%x:%x:%x:%x:%x:%x:%x/%d", 20727c478bd9Sstevel@tonic-gate addrlen, 20737c478bd9Sstevel@tonic-gate ntohs(piece[0]), ntohs(piece[1]), 20747c478bd9Sstevel@tonic-gate ntohs(piece[2]), ntohs(piece[3]), 20757c478bd9Sstevel@tonic-gate ntohs(piece[4]), ntohs(piece[5]), 20767c478bd9Sstevel@tonic-gate ntohs(piece[6]), ntohs(piece[7]), 20777c478bd9Sstevel@tonic-gate ntohs(sin6.sin6_port)); 20787c478bd9Sstevel@tonic-gate break; 20797c478bd9Sstevel@tonic-gate } 20807c478bd9Sstevel@tonic-gate case AF_UNIX: { 20817c478bd9Sstevel@tonic-gate struct sockaddr_un *soun = (struct sockaddr_un *)addr; 20827c478bd9Sstevel@tonic-gate 2083b5fca8f8Stomee (void) sprintf(buf, "(len %d) %s", addrlen, 20847c478bd9Sstevel@tonic-gate (soun == NULL) ? "(none)" : soun->sun_path); 20857c478bd9Sstevel@tonic-gate break; 20867c478bd9Sstevel@tonic-gate } 20877c478bd9Sstevel@tonic-gate default: 20887c478bd9Sstevel@tonic-gate (void) sprintf(buf, "(unknown af %d)", family); 20897c478bd9Sstevel@tonic-gate break; 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate return (buf); 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate /* The logical equivalence operator (a if-and-only-if b) */ 20957c478bd9Sstevel@tonic-gate #define EQUIV(a, b) (((a) && (b)) || (!(a) && (!(b)))) 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate /* 20987c478bd9Sstevel@tonic-gate * Verify limitations and invariants on oob state. 20997c478bd9Sstevel@tonic-gate * Return 1 if OK, otherwise 0 so that it can be used as 21007c478bd9Sstevel@tonic-gate * ASSERT(verify_oobstate(so)); 21017c478bd9Sstevel@tonic-gate */ 21027c478bd9Sstevel@tonic-gate int 21037c478bd9Sstevel@tonic-gate so_verify_oobstate(struct sonode *so) 21047c478bd9Sstevel@tonic-gate { 21057c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate /* 21087c478bd9Sstevel@tonic-gate * The possible state combinations are: 21097c478bd9Sstevel@tonic-gate * 0 21107c478bd9Sstevel@tonic-gate * SS_OOBPEND 21117c478bd9Sstevel@tonic-gate * SS_OOBPEND|SS_HAVEOOBDATA 21127c478bd9Sstevel@tonic-gate * SS_OOBPEND|SS_HADOOBDATA 21137c478bd9Sstevel@tonic-gate * SS_HADOOBDATA 21147c478bd9Sstevel@tonic-gate */ 21157c478bd9Sstevel@tonic-gate switch (so->so_state & (SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA)) { 21167c478bd9Sstevel@tonic-gate case 0: 21177c478bd9Sstevel@tonic-gate case SS_OOBPEND: 21187c478bd9Sstevel@tonic-gate case SS_OOBPEND|SS_HAVEOOBDATA: 21197c478bd9Sstevel@tonic-gate case SS_OOBPEND|SS_HADOOBDATA: 21207c478bd9Sstevel@tonic-gate case SS_HADOOBDATA: 21217c478bd9Sstevel@tonic-gate break; 21227c478bd9Sstevel@tonic-gate default: 21237c478bd9Sstevel@tonic-gate printf("Bad oob state 1 (%p): counts %d/%d state %s\n", 2124903a11ebSrh87107 (void *)so, so->so_oobsigcnt, 21257c478bd9Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21267c478bd9Sstevel@tonic-gate return (0); 21277c478bd9Sstevel@tonic-gate } 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* SS_RCVATMARK should only be set when SS_OOBPEND is set */ 21307c478bd9Sstevel@tonic-gate if ((so->so_state & (SS_RCVATMARK|SS_OOBPEND)) == SS_RCVATMARK) { 21317c478bd9Sstevel@tonic-gate printf("Bad oob state 2 (%p): counts %d/%d state %s\n", 2132903a11ebSrh87107 (void *)so, so->so_oobsigcnt, 21337c478bd9Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21347c478bd9Sstevel@tonic-gate return (0); 21357c478bd9Sstevel@tonic-gate } 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate /* 21387c478bd9Sstevel@tonic-gate * (so_oobsigcnt != 0 or SS_RCVATMARK) iff SS_OOBPEND 21397c478bd9Sstevel@tonic-gate */ 21407c478bd9Sstevel@tonic-gate if (!EQUIV((so->so_oobsigcnt != 0) || (so->so_state & SS_RCVATMARK), 21417c478bd9Sstevel@tonic-gate so->so_state & SS_OOBPEND)) { 21427c478bd9Sstevel@tonic-gate printf("Bad oob state 3 (%p): counts %d/%d state %s\n", 2143903a11ebSrh87107 (void *)so, so->so_oobsigcnt, 21447c478bd9Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21457c478bd9Sstevel@tonic-gate return (0); 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate /* 21497c478bd9Sstevel@tonic-gate * Unless SO_OOBINLINE we have so_oobmsg != NULL iff SS_HAVEOOBDATA 21507c478bd9Sstevel@tonic-gate */ 21517c478bd9Sstevel@tonic-gate if (!(so->so_options & SO_OOBINLINE) && 21527c478bd9Sstevel@tonic-gate !EQUIV(so->so_oobmsg != NULL, so->so_state & SS_HAVEOOBDATA)) { 21537c478bd9Sstevel@tonic-gate printf("Bad oob state 4 (%p): counts %d/%d state %s\n", 2154903a11ebSrh87107 (void *)so, so->so_oobsigcnt, 21557c478bd9Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21567c478bd9Sstevel@tonic-gate return (0); 21577c478bd9Sstevel@tonic-gate } 21587c478bd9Sstevel@tonic-gate if (so->so_oobsigcnt < so->so_oobcnt) { 21597c478bd9Sstevel@tonic-gate printf("Bad oob state 5 (%p): counts %d/%d state %s\n", 2160903a11ebSrh87107 (void *)so, so->so_oobsigcnt, 21617c478bd9Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 21627c478bd9Sstevel@tonic-gate return (0); 21637c478bd9Sstevel@tonic-gate } 21647c478bd9Sstevel@tonic-gate return (1); 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate #undef EQUIV 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate /* initialize sockfs zone specific kstat related items */ 21717c478bd9Sstevel@tonic-gate void * 21727c478bd9Sstevel@tonic-gate sock_kstat_init(zoneid_t zoneid) 21737c478bd9Sstevel@tonic-gate { 21747c478bd9Sstevel@tonic-gate kstat_t *ksp; 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate ksp = kstat_create_zone("sockfs", 0, "sock_unix_list", "misc", 21777c478bd9Sstevel@tonic-gate KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE|KSTAT_FLAG_VIRTUAL, zoneid); 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate if (ksp != NULL) { 21807c478bd9Sstevel@tonic-gate ksp->ks_update = sockfs_update; 21817c478bd9Sstevel@tonic-gate ksp->ks_snapshot = sockfs_snapshot; 21827c478bd9Sstevel@tonic-gate ksp->ks_lock = &socklist.sl_lock; 21837c478bd9Sstevel@tonic-gate ksp->ks_private = (void *)(uintptr_t)zoneid; 21847c478bd9Sstevel@tonic-gate kstat_install(ksp); 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate return (ksp); 21887c478bd9Sstevel@tonic-gate } 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate /* tear down sockfs zone specific kstat related items */ 21917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 21927c478bd9Sstevel@tonic-gate void 21937c478bd9Sstevel@tonic-gate sock_kstat_fini(zoneid_t zoneid, void *arg) 21947c478bd9Sstevel@tonic-gate { 21957c478bd9Sstevel@tonic-gate kstat_t *ksp = (kstat_t *)arg; 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate if (ksp != NULL) { 21987c478bd9Sstevel@tonic-gate ASSERT(zoneid == (zoneid_t)(uintptr_t)ksp->ks_private); 21997c478bd9Sstevel@tonic-gate kstat_delete(ksp); 22007c478bd9Sstevel@tonic-gate } 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate /* 22047c478bd9Sstevel@tonic-gate * Zones: 22057c478bd9Sstevel@tonic-gate * Note that nactive is going to be different for each zone. 22067c478bd9Sstevel@tonic-gate * This means we require kstat to call sockfs_update and then sockfs_snapshot 22077c478bd9Sstevel@tonic-gate * for the same zone, or sockfs_snapshot will be taken into the wrong size 22087c478bd9Sstevel@tonic-gate * buffer. This is safe, but if the buffer is too small, user will not be 22097c478bd9Sstevel@tonic-gate * given details of all sockets. However, as this kstat has a ks_lock, kstat 22107c478bd9Sstevel@tonic-gate * driver will keep it locked between the update and the snapshot, so no 22117c478bd9Sstevel@tonic-gate * other process (zone) can currently get inbetween resulting in a wrong size 22127c478bd9Sstevel@tonic-gate * buffer allocation. 22137c478bd9Sstevel@tonic-gate */ 22147c478bd9Sstevel@tonic-gate static int 22157c478bd9Sstevel@tonic-gate sockfs_update(kstat_t *ksp, int rw) 22167c478bd9Sstevel@tonic-gate { 22177c478bd9Sstevel@tonic-gate uint_t nactive = 0; /* # of active AF_UNIX sockets */ 22187c478bd9Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 22197c478bd9Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 22247c478bd9Sstevel@tonic-gate return (EACCES); 22257c478bd9Sstevel@tonic-gate } 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate for (so = socklist.sl_list; so != NULL; so = so->so_next) { 22287c478bd9Sstevel@tonic-gate if (so->so_accessvp != NULL && so->so_zoneid == myzoneid) { 22297c478bd9Sstevel@tonic-gate nactive++; 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate } 22327c478bd9Sstevel@tonic-gate ksp->ks_ndata = nactive; 22337c478bd9Sstevel@tonic-gate ksp->ks_data_size = nactive * sizeof (struct k_sockinfo); 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate return (0); 22367c478bd9Sstevel@tonic-gate } 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate static int 22397c478bd9Sstevel@tonic-gate sockfs_snapshot(kstat_t *ksp, void *buf, int rw) 22407c478bd9Sstevel@tonic-gate { 22417c478bd9Sstevel@tonic-gate int ns; /* # of sonodes we've copied */ 22427c478bd9Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 22437c478bd9Sstevel@tonic-gate struct k_sockinfo *pksi; /* where we put sockinfo data */ 22447c478bd9Sstevel@tonic-gate t_uscalar_t sn_len; /* soa_len */ 22457c478bd9Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate ksp->ks_snaptime = gethrtime(); 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 22527c478bd9Sstevel@tonic-gate return (EACCES); 22537c478bd9Sstevel@tonic-gate } 22547c478bd9Sstevel@tonic-gate 22557c478bd9Sstevel@tonic-gate /* 22567c478bd9Sstevel@tonic-gate * for each sonode on the socklist, we massage the important 22577c478bd9Sstevel@tonic-gate * info into buf, in k_sockinfo format. 22587c478bd9Sstevel@tonic-gate */ 22597c478bd9Sstevel@tonic-gate pksi = (struct k_sockinfo *)buf; 22607c478bd9Sstevel@tonic-gate for (ns = 0, so = socklist.sl_list; so != NULL; so = so->so_next) { 22617c478bd9Sstevel@tonic-gate /* only stuff active sonodes and the same zone: */ 22627c478bd9Sstevel@tonic-gate if (so->so_accessvp == NULL || so->so_zoneid != myzoneid) { 22637c478bd9Sstevel@tonic-gate continue; 22647c478bd9Sstevel@tonic-gate } 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate /* 22677c478bd9Sstevel@tonic-gate * If the sonode was activated between the update and the 22687c478bd9Sstevel@tonic-gate * snapshot, we're done - as this is only a snapshot. 22697c478bd9Sstevel@tonic-gate */ 22707c478bd9Sstevel@tonic-gate if ((caddr_t)(pksi) >= (caddr_t)buf + ksp->ks_data_size) { 22717c478bd9Sstevel@tonic-gate break; 22727c478bd9Sstevel@tonic-gate } 22737c478bd9Sstevel@tonic-gate 22747c478bd9Sstevel@tonic-gate /* copy important info into buf: */ 22757c478bd9Sstevel@tonic-gate pksi->ks_si.si_size = sizeof (struct k_sockinfo); 22767c478bd9Sstevel@tonic-gate pksi->ks_si.si_family = so->so_family; 22777c478bd9Sstevel@tonic-gate pksi->ks_si.si_type = so->so_type; 22787c478bd9Sstevel@tonic-gate pksi->ks_si.si_flag = so->so_flag; 22797c478bd9Sstevel@tonic-gate pksi->ks_si.si_state = so->so_state; 22807c478bd9Sstevel@tonic-gate pksi->ks_si.si_serv_type = so->so_serv_type; 22817c478bd9Sstevel@tonic-gate pksi->ks_si.si_ux_laddr_sou_magic = so->so_ux_laddr.soua_magic; 22827c478bd9Sstevel@tonic-gate pksi->ks_si.si_ux_faddr_sou_magic = so->so_ux_faddr.soua_magic; 22837c478bd9Sstevel@tonic-gate pksi->ks_si.si_laddr_soa_len = so->so_laddr.soa_len; 22847c478bd9Sstevel@tonic-gate pksi->ks_si.si_faddr_soa_len = so->so_faddr.soa_len; 22857c478bd9Sstevel@tonic-gate pksi->ks_si.si_szoneid = so->so_zoneid; 22867c478bd9Sstevel@tonic-gate 22877c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate if (so->so_laddr_sa != NULL) { 22907c478bd9Sstevel@tonic-gate ASSERT(so->so_laddr_sa->sa_data != NULL); 22917c478bd9Sstevel@tonic-gate sn_len = so->so_laddr_len; 22927c478bd9Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 22937c478bd9Sstevel@tonic-gate sizeof (pksi->ks_si.si_laddr_sun_path)); 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate pksi->ks_si.si_laddr_family = 22967c478bd9Sstevel@tonic-gate so->so_laddr_sa->sa_family; 22977c478bd9Sstevel@tonic-gate if (sn_len != 0) { 22987c478bd9Sstevel@tonic-gate /* AF_UNIX socket names are NULL terminated */ 22997c478bd9Sstevel@tonic-gate (void) strncpy(pksi->ks_si.si_laddr_sun_path, 23007c478bd9Sstevel@tonic-gate so->so_laddr_sa->sa_data, 23017c478bd9Sstevel@tonic-gate sizeof (pksi->ks_si.si_laddr_sun_path)); 23027c478bd9Sstevel@tonic-gate sn_len = strlen(pksi->ks_si.si_laddr_sun_path); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate pksi->ks_si.si_laddr_sun_path[sn_len] = 0; 23057c478bd9Sstevel@tonic-gate } 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate if (so->so_faddr_sa != NULL) { 23087c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_sa->sa_data != NULL); 23097c478bd9Sstevel@tonic-gate sn_len = so->so_faddr_len; 23107c478bd9Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 23117c478bd9Sstevel@tonic-gate sizeof (pksi->ks_si.si_faddr_sun_path)); 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate pksi->ks_si.si_faddr_family = 23147c478bd9Sstevel@tonic-gate so->so_faddr_sa->sa_family; 23157c478bd9Sstevel@tonic-gate if (sn_len != 0) { 23167c478bd9Sstevel@tonic-gate (void) strncpy(pksi->ks_si.si_faddr_sun_path, 23177c478bd9Sstevel@tonic-gate so->so_faddr_sa->sa_data, 23187c478bd9Sstevel@tonic-gate sizeof (pksi->ks_si.si_faddr_sun_path)); 23197c478bd9Sstevel@tonic-gate sn_len = strlen(pksi->ks_si.si_faddr_sun_path); 23207c478bd9Sstevel@tonic-gate } 23217c478bd9Sstevel@tonic-gate pksi->ks_si.si_faddr_sun_path[sn_len] = 0; 23227c478bd9Sstevel@tonic-gate } 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[0], "%p", (void *)so); 23277c478bd9Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[1], "%p", 23287c478bd9Sstevel@tonic-gate (void *)so->so_ux_laddr.soua_vp); 23297c478bd9Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[2], "%p", 23307c478bd9Sstevel@tonic-gate (void *)so->so_ux_faddr.soua_vp); 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate ns++; 23337c478bd9Sstevel@tonic-gate pksi++; 23347c478bd9Sstevel@tonic-gate } 23357c478bd9Sstevel@tonic-gate 23367c478bd9Sstevel@tonic-gate ksp->ks_ndata = ns; 23377c478bd9Sstevel@tonic-gate return (0); 23387c478bd9Sstevel@tonic-gate } 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate ssize_t 23417c478bd9Sstevel@tonic-gate soreadfile(file_t *fp, uchar_t *buf, u_offset_t fileoff, int *err, size_t size) 23427c478bd9Sstevel@tonic-gate { 23437c478bd9Sstevel@tonic-gate struct uio auio; 23447c478bd9Sstevel@tonic-gate struct iovec aiov[MSG_MAXIOVLEN]; 23457c478bd9Sstevel@tonic-gate register vnode_t *vp; 23467c478bd9Sstevel@tonic-gate int ioflag, rwflag; 23477c478bd9Sstevel@tonic-gate ssize_t cnt; 23487c478bd9Sstevel@tonic-gate int error = 0; 23497c478bd9Sstevel@tonic-gate int iovcnt = 0; 23507c478bd9Sstevel@tonic-gate short fflag; 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 23537c478bd9Sstevel@tonic-gate fflag = fp->f_flag; 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate rwflag = 0; 23567c478bd9Sstevel@tonic-gate aiov[0].iov_base = (caddr_t)buf; 23577c478bd9Sstevel@tonic-gate aiov[0].iov_len = size; 23587c478bd9Sstevel@tonic-gate iovcnt = 1; 23597c478bd9Sstevel@tonic-gate cnt = (ssize_t)size; 23607c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 23637c478bd9Sstevel@tonic-gate auio.uio_iov = aiov; 23647c478bd9Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 23657c478bd9Sstevel@tonic-gate auio.uio_resid = cnt; 23667c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 23677c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 23687c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 23697c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 23747c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 23757c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 23767c478bd9Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 23777c478bd9Sstevel@tonic-gate cnt -= auio.uio_resid; 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate if (error == EINTR && cnt != 0) 23827c478bd9Sstevel@tonic-gate error = 0; 23837c478bd9Sstevel@tonic-gate out: 23847c478bd9Sstevel@tonic-gate if (error != 0) { 23857c478bd9Sstevel@tonic-gate *err = error; 23867c478bd9Sstevel@tonic-gate return (0); 23877c478bd9Sstevel@tonic-gate } else { 23887c478bd9Sstevel@tonic-gate *err = 0; 23897c478bd9Sstevel@tonic-gate return (cnt); 23907c478bd9Sstevel@tonic-gate } 23917c478bd9Sstevel@tonic-gate } 2392