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 /* 233e95bd4aSAnders Persson * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 24f012ee0cSGordon Ross * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 258e935259SBryan Cantrill * Copyright 2015, Joyent, Inc. All rights reserved. 26d865fc92SAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/systm.h> 337c478bd9Sstevel@tonic-gate #include <sys/buf.h> 347c478bd9Sstevel@tonic-gate #include <sys/conf.h> 357c478bd9Sstevel@tonic-gate #include <sys/cred.h> 367c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 39aa59c4cbSrsb #include <sys/vfs_opreg.h> 407c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 417c478bd9Sstevel@tonic-gate #include <sys/debug.h> 427c478bd9Sstevel@tonic-gate #include <sys/errno.h> 437c478bd9Sstevel@tonic-gate #include <sys/time.h> 447c478bd9Sstevel@tonic-gate #include <sys/file.h> 457c478bd9Sstevel@tonic-gate #include <sys/open.h> 467c478bd9Sstevel@tonic-gate #include <sys/user.h> 477c478bd9Sstevel@tonic-gate #include <sys/termios.h> 487c478bd9Sstevel@tonic-gate #include <sys/stream.h> 497c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 507c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 517c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 527c478bd9Sstevel@tonic-gate #include <sys/flock.h> 537c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 567c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 577c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 587c478bd9Sstevel@tonic-gate #include <sys/stat.h> 597c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 607c478bd9Sstevel@tonic-gate #include <sys/fs/dv_node.h> 617c478bd9Sstevel@tonic-gate #include <sys/zone.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <sys/socket.h> 647c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 657c478bd9Sstevel@tonic-gate #include <netinet/in.h> 667c478bd9Sstevel@tonic-gate #include <sys/un.h> 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> 760f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h> 773e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h> 780f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h> 790f1702c5SYu Xiangning #include <fs/sockfs/socktpi_impl.h> 80bbc000e5SAnders Persson #include <fs/sockfs/sodirect.h> 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * Macros that operate on struct cmsghdr. 847c478bd9Sstevel@tonic-gate * The CMSG_VALID macro does not assume that the last option buffer is padded. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate #define CMSG_CONTENT(cmsg) (&((cmsg)[1])) 877c478bd9Sstevel@tonic-gate #define CMSG_CONTENTLEN(cmsg) ((cmsg)->cmsg_len - sizeof (struct cmsghdr)) 887c478bd9Sstevel@tonic-gate #define CMSG_VALID(cmsg, start, end) \ 897c478bd9Sstevel@tonic-gate (ISALIGNED_cmsghdr(cmsg) && \ 907c478bd9Sstevel@tonic-gate ((uintptr_t)(cmsg) >= (uintptr_t)(start)) && \ 917c478bd9Sstevel@tonic-gate ((uintptr_t)(cmsg) < (uintptr_t)(end)) && \ 927c478bd9Sstevel@tonic-gate ((ssize_t)(cmsg)->cmsg_len >= sizeof (struct cmsghdr)) && \ 937c478bd9Sstevel@tonic-gate ((uintptr_t)(cmsg) + (cmsg)->cmsg_len <= (uintptr_t)(end))) 947c478bd9Sstevel@tonic-gate #define SO_LOCK_WAKEUP_TIME 3000 /* Wakeup time in milliseconds */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate dev_t sockdev; /* For fsid in getattr */ 976cefaae1SJack Meng int sockfs_defer_nl7c_init = 0; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate struct socklist socklist; 1007c478bd9Sstevel@tonic-gate 1010f1702c5SYu Xiangning struct kmem_cache *socket_cache; 1020f1702c5SYu Xiangning 1033e95bd4aSAnders Persson /* 1043e95bd4aSAnders Persson * sockconf_lock protects the socket configuration (socket types and 1053e95bd4aSAnders Persson * socket filters) which is changed via the sockconfig system call. 1063e95bd4aSAnders Persson */ 1073e95bd4aSAnders Persson krwlock_t sockconf_lock; 1083e95bd4aSAnders Persson 1097c478bd9Sstevel@tonic-gate static int sockfs_update(kstat_t *, int); 1107c478bd9Sstevel@tonic-gate static int sockfs_snapshot(kstat_t *, void *, int); 1110f1702c5SYu Xiangning extern smod_info_t *sotpi_smod_create(void); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate extern void sendfile_init(); 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate extern void nl7c_init(void); 1167c478bd9Sstevel@tonic-gate 1176cefaae1SJack Meng extern int modrootloaded; 1186cefaae1SJack Meng 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Translate from a device pathname (e.g. "/dev/tcp") to a vnode. 1217c478bd9Sstevel@tonic-gate * Returns with the vnode held. 1227c478bd9Sstevel@tonic-gate */ 1230f1702c5SYu Xiangning int 1247c478bd9Sstevel@tonic-gate sogetvp(char *devpath, vnode_t **vpp, int uioflag) 1257c478bd9Sstevel@tonic-gate { 1267c478bd9Sstevel@tonic-gate struct snode *csp; 1277c478bd9Sstevel@tonic-gate vnode_t *vp, *dvp; 1287c478bd9Sstevel@tonic-gate major_t maj; 1297c478bd9Sstevel@tonic-gate int error; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate ASSERT(uioflag == UIO_SYSSPACE || uioflag == UIO_USERSPACE); 1320f1702c5SYu Xiangning 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Lookup the underlying filesystem vnode. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate error = lookupname(devpath, uioflag, FOLLOW, NULLVPP, &vp); 1377c478bd9Sstevel@tonic-gate if (error) 1387c478bd9Sstevel@tonic-gate return (error); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* Check that it is the correct vnode */ 1417c478bd9Sstevel@tonic-gate if (vp->v_type != VCHR) { 1427c478bd9Sstevel@tonic-gate VN_RELE(vp); 1437c478bd9Sstevel@tonic-gate return (ENOTSOCK); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * If devpath went through devfs, the device should already 1487c478bd9Sstevel@tonic-gate * be configured. If devpath is a mknod file, however, we 1497c478bd9Sstevel@tonic-gate * need to make sure the device is properly configured. 1507c478bd9Sstevel@tonic-gate * To do this, we do something similar to spec_open() 1517c478bd9Sstevel@tonic-gate * except that we resolve to the minor/leaf level since 1527c478bd9Sstevel@tonic-gate * we need to return a vnode. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate csp = VTOS(VTOS(vp)->s_commonvp); 1557c478bd9Sstevel@tonic-gate if (!(csp->s_flag & SDIPSET)) { 1567c478bd9Sstevel@tonic-gate char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1577c478bd9Sstevel@tonic-gate error = ddi_dev_pathname(vp->v_rdev, S_IFCHR, pathname); 1587c478bd9Sstevel@tonic-gate if (error == 0) 1597c478bd9Sstevel@tonic-gate error = devfs_lookupname(pathname, NULLVPP, &dvp); 1607c478bd9Sstevel@tonic-gate VN_RELE(vp); 1617c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 1627c478bd9Sstevel@tonic-gate if (error != 0) 1637c478bd9Sstevel@tonic-gate return (ENXIO); 1647c478bd9Sstevel@tonic-gate vp = dvp; /* use the devfs vp */ 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* device is configured at this point */ 1687c478bd9Sstevel@tonic-gate maj = getmajor(vp->v_rdev); 1697c478bd9Sstevel@tonic-gate if (!STREAMSTAB(maj)) { 1707c478bd9Sstevel@tonic-gate VN_RELE(vp); 1717c478bd9Sstevel@tonic-gate return (ENOSTR); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate *vpp = vp; 1757c478bd9Sstevel@tonic-gate return (0); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* 1797c478bd9Sstevel@tonic-gate * Update the accessed, updated, or changed times in an sonode 1807c478bd9Sstevel@tonic-gate * with the current time. 1817c478bd9Sstevel@tonic-gate * 1827c478bd9Sstevel@tonic-gate * Note that both SunOS 4.X and 4.4BSD sockets do not present reasonable 1837c478bd9Sstevel@tonic-gate * attributes in a fstat call. (They return the current time and 0 for 1847c478bd9Sstevel@tonic-gate * all timestamps, respectively.) We maintain the current timestamps 1857c478bd9Sstevel@tonic-gate * here primarily so that should sockmod be popped the resulting 1867c478bd9Sstevel@tonic-gate * file descriptor will behave like a stream w.r.t. the timestamps. 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate void 1897c478bd9Sstevel@tonic-gate so_update_attrs(struct sonode *so, int flag) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate time_t now = gethrestime_sec(); 1927c478bd9Sstevel@tonic-gate 1930f1702c5SYu Xiangning if (SOCK_IS_NONSTR(so)) 1940f1702c5SYu Xiangning return; 1950f1702c5SYu Xiangning 1967c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1977c478bd9Sstevel@tonic-gate so->so_flag |= flag; 1987c478bd9Sstevel@tonic-gate if (flag & SOACC) 1990f1702c5SYu Xiangning SOTOTPI(so)->sti_atime = now; 2007c478bd9Sstevel@tonic-gate if (flag & SOMOD) 2010f1702c5SYu Xiangning SOTOTPI(so)->sti_mtime = now; 2027c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2050f1702c5SYu Xiangning extern so_create_func_t sock_comm_create_function; 2060f1702c5SYu Xiangning extern so_destroy_func_t sock_comm_destroy_function; 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Init function called when sockfs is loaded. 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate int 2117c478bd9Sstevel@tonic-gate sockinit(int fstype, char *name) 2127c478bd9Sstevel@tonic-gate { 2137c478bd9Sstevel@tonic-gate static const fs_operation_def_t sock_vfsops_template[] = { 2147c478bd9Sstevel@tonic-gate NULL, NULL 2157c478bd9Sstevel@tonic-gate }; 2167c478bd9Sstevel@tonic-gate int error; 2177c478bd9Sstevel@tonic-gate major_t dev; 2187c478bd9Sstevel@tonic-gate char *err_str; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstype, sock_vfsops_template, NULL); 2217c478bd9Sstevel@tonic-gate if (error != 0) { 2222caf0dcdSrshoaib zcmn_err(GLOBAL_ZONEID, CE_WARN, 2232caf0dcdSrshoaib "sockinit: bad vfs ops template"); 2247c478bd9Sstevel@tonic-gate return (error); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2270f1702c5SYu Xiangning error = vn_make_ops(name, socket_vnodeops_template, 2280f1702c5SYu Xiangning &socket_vnodeops); 2297c478bd9Sstevel@tonic-gate if (error != 0) { 2300f1702c5SYu Xiangning err_str = "sockinit: bad socket vnode ops template"; 2317c478bd9Sstevel@tonic-gate /* vn_make_ops() does not reset socktpi_vnodeops on failure. */ 2320f1702c5SYu Xiangning socket_vnodeops = NULL; 2337c478bd9Sstevel@tonic-gate goto failure; 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2360f1702c5SYu Xiangning socket_cache = kmem_cache_create("socket_cache", 2370f1702c5SYu Xiangning sizeof (struct sonode), 0, sonode_constructor, 2380f1702c5SYu Xiangning sonode_destructor, NULL, NULL, NULL, 0); 2397c478bd9Sstevel@tonic-gate 2403e95bd4aSAnders Persson rw_init(&sockconf_lock, NULL, RW_DEFAULT, NULL); 2413e95bd4aSAnders Persson 2420f1702c5SYu Xiangning error = socktpi_init(); 24374e20cfeSnh145002 if (error != 0) { 24474e20cfeSnh145002 err_str = NULL; 24574e20cfeSnh145002 goto failure; 24674e20cfeSnh145002 } 24774e20cfeSnh145002 248bbc000e5SAnders Persson error = sod_init(); 24917169044Sbrutus if (error != 0) { 25017169044Sbrutus err_str = NULL; 25117169044Sbrutus goto failure; 25217169044Sbrutus } 25317169044Sbrutus 2547c478bd9Sstevel@tonic-gate /* 2550f1702c5SYu Xiangning * Set up the default create and destroy functions 2567c478bd9Sstevel@tonic-gate */ 2570f1702c5SYu Xiangning sock_comm_create_function = socket_sonode_create; 2580f1702c5SYu Xiangning sock_comm_destroy_function = socket_sonode_destroy; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate * Build initial list mapping socket parameters to vnode. 2627c478bd9Sstevel@tonic-gate */ 2630f1702c5SYu Xiangning smod_init(); 2640f1702c5SYu Xiangning smod_add(sotpi_smod_create()); 2650f1702c5SYu Xiangning 2660f1702c5SYu Xiangning sockparams_init(); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * If sockets are needed before init runs /sbin/soconfig 2707c478bd9Sstevel@tonic-gate * it is possible to preload the sockparams list here using 2717c478bd9Sstevel@tonic-gate * calls like: 2727c478bd9Sstevel@tonic-gate * sockconfig(1,2,3, "/dev/tcp", 0); 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * Create a unique dev_t for use in so_fsid. 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if ((dev = getudev()) == (major_t)-1) 2807c478bd9Sstevel@tonic-gate dev = 0; 2817c478bd9Sstevel@tonic-gate sockdev = makedevice(dev, 0); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate mutex_init(&socklist.sl_lock, NULL, MUTEX_DEFAULT, NULL); 2847c478bd9Sstevel@tonic-gate sendfile_init(); 2856cefaae1SJack Meng if (!modrootloaded) { 2866cefaae1SJack Meng sockfs_defer_nl7c_init = 1; 2876cefaae1SJack Meng } else { 2887c478bd9Sstevel@tonic-gate nl7c_init(); 2896cefaae1SJack Meng } 2907c478bd9Sstevel@tonic-gate 2913e95bd4aSAnders Persson /* Initialize socket filters */ 2923e95bd4aSAnders Persson sof_init(); 2933e95bd4aSAnders Persson 2947c478bd9Sstevel@tonic-gate return (0); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate failure: 2977c478bd9Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 2980f1702c5SYu Xiangning if (socket_vnodeops != NULL) 2990f1702c5SYu Xiangning vn_freevnodeops(socket_vnodeops); 3007c478bd9Sstevel@tonic-gate if (err_str != NULL) 3012caf0dcdSrshoaib zcmn_err(GLOBAL_ZONEID, CE_WARN, err_str); 3027c478bd9Sstevel@tonic-gate return (error); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate /* 3067c478bd9Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOLOCKED. 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate void 3097c478bd9Sstevel@tonic-gate so_lock_single(struct sonode *so) 3107c478bd9Sstevel@tonic-gate { 3117c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate while (so->so_flag & (SOLOCKED | SOASYNC_UNBIND)) { 3146a571a2dSAnders Persson cv_wait_stop(&so->so_single_cv, &so->so_lock, 3157c478bd9Sstevel@tonic-gate SO_LOCK_WAKEUP_TIME); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate so->so_flag |= SOLOCKED; 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * Caller must hold the mutex and pass in SOLOCKED or SOASYNC_UNBIND. 3227c478bd9Sstevel@tonic-gate * Used to clear SOLOCKED or SOASYNC_UNBIND. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate void 3257c478bd9Sstevel@tonic-gate so_unlock_single(struct sonode *so, int flag) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 3287c478bd9Sstevel@tonic-gate ASSERT(flag & (SOLOCKED|SOASYNC_UNBIND)); 3297c478bd9Sstevel@tonic-gate ASSERT((flag & ~(SOLOCKED|SOASYNC_UNBIND)) == 0); 3307c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & flag); 3317c478bd9Sstevel@tonic-gate /* 3320f1702c5SYu Xiangning * Process the T_DISCON_IND on sti_discon_ind_mp. 3337c478bd9Sstevel@tonic-gate * 3347c478bd9Sstevel@tonic-gate * Call to so_drain_discon_ind will result in so_lock 3357c478bd9Sstevel@tonic-gate * being dropped and re-acquired later. 3367c478bd9Sstevel@tonic-gate */ 3370f1702c5SYu Xiangning if (!SOCK_IS_NONSTR(so)) { 3380f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 3390f1702c5SYu Xiangning 3400f1702c5SYu Xiangning if (sti->sti_discon_ind_mp != NULL) 3417c478bd9Sstevel@tonic-gate so_drain_discon_ind(so); 3420f1702c5SYu Xiangning } 3437c478bd9Sstevel@tonic-gate 3446a571a2dSAnders Persson cv_signal(&so->so_single_cv); 3456a571a2dSAnders Persson so->so_flag &= ~flag; 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOREADLOCKED. 3507c478bd9Sstevel@tonic-gate * If the caller wants nonblocking behavior it should set fmode. 3517c478bd9Sstevel@tonic-gate */ 3527c478bd9Sstevel@tonic-gate int 3537c478bd9Sstevel@tonic-gate so_lock_read(struct sonode *so, int fmode) 3547c478bd9Sstevel@tonic-gate { 3557c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 3587c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 3597c478bd9Sstevel@tonic-gate return (EWOULDBLOCK); 3606a571a2dSAnders Persson cv_wait_stop(&so->so_read_cv, &so->so_lock, 3617c478bd9Sstevel@tonic-gate SO_LOCK_WAKEUP_TIME); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 3647c478bd9Sstevel@tonic-gate return (0); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Like so_lock_read above but allows signals. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate int 3717c478bd9Sstevel@tonic-gate so_lock_read_intr(struct sonode *so, int fmode) 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 3767c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 3777c478bd9Sstevel@tonic-gate return (EWOULDBLOCK); 3786a571a2dSAnders Persson if (!cv_wait_sig(&so->so_read_cv, &so->so_lock)) 3797c478bd9Sstevel@tonic-gate return (EINTR); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 3827c478bd9Sstevel@tonic-gate return (0); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Caller must hold the mutex. Used to clear SOREADLOCKED, 3877c478bd9Sstevel@tonic-gate * set in so_lock_read() or so_lock_read_intr(). 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate void 3907c478bd9Sstevel@tonic-gate so_unlock_read(struct sonode *so) 3917c478bd9Sstevel@tonic-gate { 3927c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 3937c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & SOREADLOCKED); 3947c478bd9Sstevel@tonic-gate 3956a571a2dSAnders Persson cv_signal(&so->so_read_cv); 3966a571a2dSAnders Persson so->so_flag &= ~SOREADLOCKED; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* 4007c478bd9Sstevel@tonic-gate * Verify that the specified offset falls within the mblk and 4017c478bd9Sstevel@tonic-gate * that the resulting pointer is aligned. 4027c478bd9Sstevel@tonic-gate * Returns NULL if not. 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate void * 4057c478bd9Sstevel@tonic-gate sogetoff(mblk_t *mp, t_uscalar_t offset, 4067c478bd9Sstevel@tonic-gate t_uscalar_t length, uint_t align_size) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate uintptr_t ptr1, ptr2; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate ASSERT(mp && mp->b_wptr >= mp->b_rptr); 4117c478bd9Sstevel@tonic-gate ptr1 = (uintptr_t)mp->b_rptr + offset; 4127c478bd9Sstevel@tonic-gate ptr2 = (uintptr_t)ptr1 + length; 4137c478bd9Sstevel@tonic-gate if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) { 4147c478bd9Sstevel@tonic-gate eprintline(0); 4157c478bd9Sstevel@tonic-gate return (NULL); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate if ((ptr1 & (align_size - 1)) != 0) { 4187c478bd9Sstevel@tonic-gate eprintline(0); 4197c478bd9Sstevel@tonic-gate return (NULL); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate return ((void *)ptr1); 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * Return the AF_UNIX underlying filesystem vnode matching a given name. 4267c478bd9Sstevel@tonic-gate * Makes sure the sending and the destination sonodes are compatible. 4277c478bd9Sstevel@tonic-gate * The vnode is returned held. 4287c478bd9Sstevel@tonic-gate * 4297c478bd9Sstevel@tonic-gate * The underlying filesystem VSOCK vnode has a v_stream pointer that 4307c478bd9Sstevel@tonic-gate * references the actual stream head (hence indirectly the actual sonode). 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate static int 4337c478bd9Sstevel@tonic-gate so_ux_lookup(struct sonode *so, struct sockaddr_un *soun, int checkaccess, 4347c478bd9Sstevel@tonic-gate vnode_t **vpp) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate vnode_t *vp; /* Underlying filesystem vnode */ 4379bf9355bSRic Aleshire vnode_t *rvp; /* real vnode */ 4387c478bd9Sstevel@tonic-gate vnode_t *svp; /* sockfs vnode */ 4397c478bd9Sstevel@tonic-gate struct sonode *so2; 4407c478bd9Sstevel@tonic-gate int error; 4417c478bd9Sstevel@tonic-gate 4423eceedbbSrh87107 dprintso(so, 1, ("so_ux_lookup(%p) name <%s>\n", (void *)so, 4433eceedbbSrh87107 soun->sun_path)); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate error = lookupname(soun->sun_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 4467c478bd9Sstevel@tonic-gate if (error) { 4477c478bd9Sstevel@tonic-gate eprintsoline(so, error); 4487c478bd9Sstevel@tonic-gate return (error); 4497c478bd9Sstevel@tonic-gate } 4509bf9355bSRic Aleshire 4519bf9355bSRic Aleshire /* 4529bf9355bSRic Aleshire * Traverse lofs mounts get the real vnode 4539bf9355bSRic Aleshire */ 4549bf9355bSRic Aleshire if (VOP_REALVP(vp, &rvp, NULL) == 0) { 4559bf9355bSRic Aleshire VN_HOLD(rvp); /* hold the real vnode */ 4569bf9355bSRic Aleshire VN_RELE(vp); /* release hold from lookup */ 4579bf9355bSRic Aleshire vp = rvp; 4589bf9355bSRic Aleshire } 4599bf9355bSRic Aleshire 4607c478bd9Sstevel@tonic-gate if (vp->v_type != VSOCK) { 4617c478bd9Sstevel@tonic-gate error = ENOTSOCK; 4627c478bd9Sstevel@tonic-gate eprintsoline(so, error); 4637c478bd9Sstevel@tonic-gate goto done2; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (checkaccess) { 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * Check that we have permissions to access the destination 4697c478bd9Sstevel@tonic-gate * vnode. This check is not done in BSD but it is required 4707c478bd9Sstevel@tonic-gate * by X/Open. 4717c478bd9Sstevel@tonic-gate */ 472da6c28aaSamw if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL)) { 4737c478bd9Sstevel@tonic-gate eprintsoline(so, error); 4747c478bd9Sstevel@tonic-gate goto done2; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * Check if the remote socket has been closed. 4807c478bd9Sstevel@tonic-gate * 4817c478bd9Sstevel@tonic-gate * Synchronize with vn_rele_stream by holding v_lock while traversing 4827c478bd9Sstevel@tonic-gate * v_stream->sd_vnode. 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock); 4857c478bd9Sstevel@tonic-gate if (vp->v_stream == NULL) { 4867c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 4877c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_DGRAM) 4887c478bd9Sstevel@tonic-gate error = EDESTADDRREQ; 4897c478bd9Sstevel@tonic-gate else 4907c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate eprintsoline(so, error); 4937c478bd9Sstevel@tonic-gate goto done2; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate ASSERT(vp->v_stream->sd_vnode); 4967c478bd9Sstevel@tonic-gate svp = vp->v_stream->sd_vnode; 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * holding v_lock on underlying filesystem vnode and acquiring 4997c478bd9Sstevel@tonic-gate * it on sockfs vnode. Assumes that no code ever attempts to 5007c478bd9Sstevel@tonic-gate * acquire these locks in the reverse order. 5017c478bd9Sstevel@tonic-gate */ 5027c478bd9Sstevel@tonic-gate VN_HOLD(svp); 5037c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if (svp->v_type != VSOCK) { 5067c478bd9Sstevel@tonic-gate error = ENOTSOCK; 5077c478bd9Sstevel@tonic-gate eprintsoline(so, error); 5087c478bd9Sstevel@tonic-gate goto done; 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate so2 = VTOSO(svp); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate if (so->so_type != so2->so_type) { 5147c478bd9Sstevel@tonic-gate error = EPROTOTYPE; 5157c478bd9Sstevel@tonic-gate eprintsoline(so, error); 5167c478bd9Sstevel@tonic-gate goto done; 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate VN_RELE(svp); 5207c478bd9Sstevel@tonic-gate *vpp = vp; 5217c478bd9Sstevel@tonic-gate return (0); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate done: 5247c478bd9Sstevel@tonic-gate VN_RELE(svp); 5257c478bd9Sstevel@tonic-gate done2: 5267c478bd9Sstevel@tonic-gate VN_RELE(vp); 5277c478bd9Sstevel@tonic-gate return (error); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate /* 5317c478bd9Sstevel@tonic-gate * Verify peer address for connect and sendto/sendmsg. 5327c478bd9Sstevel@tonic-gate * Since sendto/sendmsg would not get synchronous errors from the transport 5337c478bd9Sstevel@tonic-gate * provider we have to do these ugly checks in the socket layer to 5347c478bd9Sstevel@tonic-gate * preserve compatibility with SunOS 4.X. 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate int 5377c478bd9Sstevel@tonic-gate so_addr_verify(struct sonode *so, const struct sockaddr *name, 5387c478bd9Sstevel@tonic-gate socklen_t namelen) 5397c478bd9Sstevel@tonic-gate { 5407c478bd9Sstevel@tonic-gate int family; 5417c478bd9Sstevel@tonic-gate 542903a11ebSrh87107 dprintso(so, 1, ("so_addr_verify(%p, %p, %d)\n", 543903a11ebSrh87107 (void *)so, (void *)name, namelen)); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate ASSERT(name != NULL); 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate family = so->so_family; 5487c478bd9Sstevel@tonic-gate switch (family) { 5497c478bd9Sstevel@tonic-gate case AF_INET: 5507c478bd9Sstevel@tonic-gate if (name->sa_family != family) { 5517c478bd9Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 5527c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in)) { 5557c478bd9Sstevel@tonic-gate eprintsoline(so, EINVAL); 5567c478bd9Sstevel@tonic-gate return (EINVAL); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate break; 5597c478bd9Sstevel@tonic-gate case AF_INET6: { 5607c478bd9Sstevel@tonic-gate #ifdef DEBUG 5617c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 5627c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate if (name->sa_family != family) { 5657c478bd9Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 5667c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) { 5697c478bd9Sstevel@tonic-gate eprintsoline(so, EINVAL); 5707c478bd9Sstevel@tonic-gate return (EINVAL); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate #ifdef DEBUG 5737c478bd9Sstevel@tonic-gate /* Verify that apps don't forget to clear sin6_scope_id etc */ 5747c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)name; 5757c478bd9Sstevel@tonic-gate if (sin6->sin6_scope_id != 0 && 5767c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 5772caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 5787c478bd9Sstevel@tonic-gate "connect/send* with uninitialized sin6_scope_id " 5797c478bd9Sstevel@tonic-gate "(%d) on socket. Pid = %d\n", 5807c478bd9Sstevel@tonic-gate (int)sin6->sin6_scope_id, (int)curproc->p_pid); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 5837c478bd9Sstevel@tonic-gate break; 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate case AF_UNIX: 5860f1702c5SYu Xiangning if (SOTOTPI(so)->sti_faddr_noxlate) { 5877c478bd9Sstevel@tonic-gate return (0); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate if (namelen < (socklen_t)sizeof (short)) { 5907c478bd9Sstevel@tonic-gate eprintsoline(so, ENOENT); 5917c478bd9Sstevel@tonic-gate return (ENOENT); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate if (name->sa_family != family) { 5947c478bd9Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 5957c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 5987c478bd9Sstevel@tonic-gate if (namelen > (socklen_t)(MAXPATHLEN + sizeof (short) + 1)) { 5997c478bd9Sstevel@tonic-gate eprintsoline(so, ENAMETOOLONG); 6007c478bd9Sstevel@tonic-gate return (ENAMETOOLONG); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate break; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate default: 6067c478bd9Sstevel@tonic-gate /* 6077c478bd9Sstevel@tonic-gate * Default is don't do any length or sa_family check 6087c478bd9Sstevel@tonic-gate * to allow non-sockaddr style addresses. 6097c478bd9Sstevel@tonic-gate */ 6107c478bd9Sstevel@tonic-gate break; 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate return (0); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* 6187c478bd9Sstevel@tonic-gate * Translate an AF_UNIX sockaddr_un to the transport internal name. 619f012ee0cSGordon Ross * Assumes caller has called so_addr_verify first. The translated 620f012ee0cSGordon Ross * (internal form) address is stored in sti->sti_ux_taddr. 6217c478bd9Sstevel@tonic-gate */ 6227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6237c478bd9Sstevel@tonic-gate int 6247c478bd9Sstevel@tonic-gate so_ux_addr_xlate(struct sonode *so, struct sockaddr *name, 6257c478bd9Sstevel@tonic-gate socklen_t namelen, int checkaccess, 6267c478bd9Sstevel@tonic-gate void **addrp, socklen_t *addrlenp) 6277c478bd9Sstevel@tonic-gate { 6287c478bd9Sstevel@tonic-gate int error; 6297c478bd9Sstevel@tonic-gate struct sockaddr_un *soun; 6307c478bd9Sstevel@tonic-gate vnode_t *vp; 6317c478bd9Sstevel@tonic-gate void *addr; 6327c478bd9Sstevel@tonic-gate socklen_t addrlen; 6330f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate dprintso(so, 1, ("so_ux_addr_xlate(%p, %p, %d, %d)\n", 636903a11ebSrh87107 (void *)so, (void *)name, namelen, checkaccess)); 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate ASSERT(name != NULL); 6397c478bd9Sstevel@tonic-gate ASSERT(so->so_family == AF_UNIX); 6400f1702c5SYu Xiangning ASSERT(!sti->sti_faddr_noxlate); 6417c478bd9Sstevel@tonic-gate ASSERT(namelen >= (socklen_t)sizeof (short)); 6427c478bd9Sstevel@tonic-gate ASSERT(name->sa_family == AF_UNIX); 6437c478bd9Sstevel@tonic-gate soun = (struct sockaddr_un *)name; 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * Lookup vnode for the specified path name and verify that 6467c478bd9Sstevel@tonic-gate * it is a socket. 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate error = so_ux_lookup(so, soun, checkaccess, &vp); 6497c478bd9Sstevel@tonic-gate if (error) { 6507c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6517c478bd9Sstevel@tonic-gate return (error); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate /* 6547c478bd9Sstevel@tonic-gate * Use the address of the peer vnode as the address to send 6557c478bd9Sstevel@tonic-gate * to. We release the peer vnode here. In case it has been 656d28d4716SJerry Jelinek * closed by the time the T_CONN_REQ or T_UNITDATA_REQ reaches the 6577c478bd9Sstevel@tonic-gate * transport the message will get an error or be dropped. 658f012ee0cSGordon Ross * Note that that soua_vp is never dereferenced; it's just a 659f012ee0cSGordon Ross * convenient value by which we can identify the peer. 6607c478bd9Sstevel@tonic-gate */ 661f012ee0cSGordon Ross sti->sti_ux_taddr.soua_vp = vp; 662f012ee0cSGordon Ross sti->sti_ux_taddr.soua_magic = SOU_MAGIC_EXPLICIT; 663f012ee0cSGordon Ross addr = &sti->sti_ux_taddr; 664f012ee0cSGordon Ross addrlen = (socklen_t)sizeof (sti->sti_ux_taddr); 665903a11ebSrh87107 dprintso(so, 1, ("ux_xlate UNIX: addrlen %d, vp %p\n", 666903a11ebSrh87107 addrlen, (void *)vp)); 6677c478bd9Sstevel@tonic-gate VN_RELE(vp); 6687c478bd9Sstevel@tonic-gate *addrp = addr; 6697c478bd9Sstevel@tonic-gate *addrlenp = (socklen_t)addrlen; 6707c478bd9Sstevel@tonic-gate return (0); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* 6747c478bd9Sstevel@tonic-gate * Esballoc free function for messages that contain SO_FILEP option. 6757c478bd9Sstevel@tonic-gate * Decrement the reference count on the file pointers using closef. 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate void 6787c478bd9Sstevel@tonic-gate fdbuf_free(struct fdbuf *fdbuf) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate int i; 6817c478bd9Sstevel@tonic-gate struct file *fp; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_free: %d fds\n", fdbuf->fd_numfd)); 6847c478bd9Sstevel@tonic-gate for (i = 0; i < fdbuf->fd_numfd; i++) { 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 6877c478bd9Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 6887c478bd9Sstevel@tonic-gate * the option headers and values are only 4 bytes 6897c478bd9Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 6907c478bd9Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 6917c478bd9Sstevel@tonic-gate */ 6927c478bd9Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 693903a11ebSrh87107 dprint(1, ("fdbuf_free: [%d] = %p\n", i, (void *)fp)); 6947c478bd9Sstevel@tonic-gate (void) closef(fp); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate if (fdbuf->fd_ebuf != NULL) 6977c478bd9Sstevel@tonic-gate kmem_free(fdbuf->fd_ebuf, fdbuf->fd_ebuflen); 6987c478bd9Sstevel@tonic-gate kmem_free(fdbuf, fdbuf->fd_size); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 702bd118333Smeem * Allocate an esballoc'ed message for AF_UNIX file descriptor passing. 703bd118333Smeem * Waits if memory is not available. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate mblk_t * 7067c478bd9Sstevel@tonic-gate fdbuf_allocmsg(int size, struct fdbuf *fdbuf) 7077c478bd9Sstevel@tonic-gate { 708bd118333Smeem uchar_t *buf; 7097c478bd9Sstevel@tonic-gate mblk_t *mp; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_allocmsg: size %d, %d fds\n", size, fdbuf->fd_numfd)); 7127c478bd9Sstevel@tonic-gate buf = kmem_alloc(size, KM_SLEEP); 7137c478bd9Sstevel@tonic-gate fdbuf->fd_ebuf = (caddr_t)buf; 7147c478bd9Sstevel@tonic-gate fdbuf->fd_ebuflen = size; 7157c478bd9Sstevel@tonic-gate fdbuf->fd_frtn.free_func = fdbuf_free; 7167c478bd9Sstevel@tonic-gate fdbuf->fd_frtn.free_arg = (caddr_t)fdbuf; 7177c478bd9Sstevel@tonic-gate 718bd118333Smeem mp = esballoc_wait(buf, size, BPRI_MED, &fdbuf->fd_frtn); 7197c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 7207c478bd9Sstevel@tonic-gate return (mp); 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate /* 7247c478bd9Sstevel@tonic-gate * Extract file descriptors from a fdbuf. 7257c478bd9Sstevel@tonic-gate * Return list in rights/rightslen. 7267c478bd9Sstevel@tonic-gate */ 7277c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7287c478bd9Sstevel@tonic-gate static int 7297c478bd9Sstevel@tonic-gate fdbuf_extract(struct fdbuf *fdbuf, void *rights, int rightslen) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate int i, fd; 7327c478bd9Sstevel@tonic-gate int *rp; 7337c478bd9Sstevel@tonic-gate struct file *fp; 7347c478bd9Sstevel@tonic-gate int numfd; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_extract: %d fds, len %d\n", 7377c478bd9Sstevel@tonic-gate fdbuf->fd_numfd, rightslen)); 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate numfd = fdbuf->fd_numfd; 7407c478bd9Sstevel@tonic-gate ASSERT(rightslen == numfd * (int)sizeof (int)); 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* 7437c478bd9Sstevel@tonic-gate * Allocate a file descriptor and increment the f_count. 7447c478bd9Sstevel@tonic-gate * The latter is needed since we always call fdbuf_free 7457c478bd9Sstevel@tonic-gate * which performs a closef. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate rp = (int *)rights; 7487c478bd9Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 7497c478bd9Sstevel@tonic-gate if ((fd = ufalloc(0)) == -1) 7507c478bd9Sstevel@tonic-gate goto cleanup; 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 7537c478bd9Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 7547c478bd9Sstevel@tonic-gate * the option headers and values are only 4 bytes 7557c478bd9Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 7567c478bd9Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 7597c478bd9Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 7607c478bd9Sstevel@tonic-gate fp->f_count++; 7617c478bd9Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 7627c478bd9Sstevel@tonic-gate setf(fd, fp); 7637c478bd9Sstevel@tonic-gate *rp++ = fd; 764005d3febSMarek Pospisil if (AU_AUDITING()) 7657c478bd9Sstevel@tonic-gate audit_fdrecv(fd, fp); 7667c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_extract: [%d] = %d, %p refcnt %d\n", 767903a11ebSrh87107 i, fd, (void *)fp, fp->f_count)); 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate return (0); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate cleanup: 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * Undo whatever partial work the loop above has done. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate { 7767c478bd9Sstevel@tonic-gate int j; 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate rp = (int *)rights; 7797c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) { 7807c478bd9Sstevel@tonic-gate dprint(0, 7817c478bd9Sstevel@tonic-gate ("fdbuf_extract: cleanup[%d] = %d\n", j, *rp)); 7827c478bd9Sstevel@tonic-gate (void) closeandsetf(*rp++, NULL); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate return (EMFILE); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate /* 7907c478bd9Sstevel@tonic-gate * Insert file descriptors into an fdbuf. 7917c478bd9Sstevel@tonic-gate * Returns a kmem_alloc'ed fdbuf. The fdbuf should be freed 7927c478bd9Sstevel@tonic-gate * by calling fdbuf_free(). 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate int 7957c478bd9Sstevel@tonic-gate fdbuf_create(void *rights, int rightslen, struct fdbuf **fdbufp) 7967c478bd9Sstevel@tonic-gate { 7977c478bd9Sstevel@tonic-gate int numfd, i; 7987c478bd9Sstevel@tonic-gate int *fds; 7997c478bd9Sstevel@tonic-gate struct file *fp; 8007c478bd9Sstevel@tonic-gate struct fdbuf *fdbuf; 8017c478bd9Sstevel@tonic-gate int fdbufsize; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_create: len %d\n", rightslen)); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate fdbufsize = (int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *)); 8087c478bd9Sstevel@tonic-gate fdbuf = kmem_alloc(fdbufsize, KM_SLEEP); 8097c478bd9Sstevel@tonic-gate fdbuf->fd_size = fdbufsize; 8107c478bd9Sstevel@tonic-gate fdbuf->fd_numfd = 0; 8117c478bd9Sstevel@tonic-gate fdbuf->fd_ebuf = NULL; 8127c478bd9Sstevel@tonic-gate fdbuf->fd_ebuflen = 0; 8137c478bd9Sstevel@tonic-gate fds = (int *)rights; 8147c478bd9Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 8157c478bd9Sstevel@tonic-gate if ((fp = getf(fds[i])) == NULL) { 8167c478bd9Sstevel@tonic-gate fdbuf_free(fdbuf); 8177c478bd9Sstevel@tonic-gate return (EBADF); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_create: [%d] = %d, %p refcnt %d\n", 820903a11ebSrh87107 i, fds[i], (void *)fp, fp->f_count)); 8217c478bd9Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 8227c478bd9Sstevel@tonic-gate fp->f_count++; 8237c478bd9Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 8247c478bd9Sstevel@tonic-gate /* 8257c478bd9Sstevel@tonic-gate * The maximum alignment for fdbuf (or any option header 8267c478bd9Sstevel@tonic-gate * and its value) it 4 bytes. On a LP64 kernel, the alignment 8277c478bd9Sstevel@tonic-gate * is not sufficient for pointers (fd_fds in this case). Since 8287c478bd9Sstevel@tonic-gate * we just did a kmem_alloc (we get a double word alignment), 8297c478bd9Sstevel@tonic-gate * we don't need to do anything on the send side (we loose 8307c478bd9Sstevel@tonic-gate * the double word alignment because fdbuf goes after an 8317c478bd9Sstevel@tonic-gate * option header (eg T_unitdata_req) which is only 4 byte 8327c478bd9Sstevel@tonic-gate * aligned). We take care of this when we extract the file 8337c478bd9Sstevel@tonic-gate * descriptor in fdbuf_extract or fdbuf_free. 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate fdbuf->fd_fds[i] = fp; 8367c478bd9Sstevel@tonic-gate fdbuf->fd_numfd++; 8377c478bd9Sstevel@tonic-gate releasef(fds[i]); 838005d3febSMarek Pospisil if (AU_AUDITING()) 8397c478bd9Sstevel@tonic-gate audit_fdsend(fds[i], fp, 0); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate *fdbufp = fdbuf; 8427c478bd9Sstevel@tonic-gate return (0); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate static int 8467c478bd9Sstevel@tonic-gate fdbuf_optlen(int rightslen) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate int numfd; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate return ((int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *))); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate static t_uscalar_t 8567c478bd9Sstevel@tonic-gate fdbuf_cmsglen(int fdbuflen) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate return (t_uscalar_t)((fdbuflen - FDBUF_HDRSIZE) / 8597c478bd9Sstevel@tonic-gate (int)sizeof (struct file *) * (int)sizeof (int)); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * Return non-zero if the mblk and fdbuf are consistent. 8657c478bd9Sstevel@tonic-gate */ 8667c478bd9Sstevel@tonic-gate static int 8677c478bd9Sstevel@tonic-gate fdbuf_verify(mblk_t *mp, struct fdbuf *fdbuf, int fdbuflen) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate if (fdbuflen >= FDBUF_HDRSIZE && 8707c478bd9Sstevel@tonic-gate fdbuflen == fdbuf->fd_size) { 8717c478bd9Sstevel@tonic-gate frtn_t *frp = mp->b_datap->db_frtnp; 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * Check that the SO_FILEP portion of the 8747c478bd9Sstevel@tonic-gate * message has not been modified by 8757c478bd9Sstevel@tonic-gate * the loopback transport. The sending sockfs generates 8767c478bd9Sstevel@tonic-gate * a message that is esballoc'ed with the free function 8777c478bd9Sstevel@tonic-gate * being fdbuf_free() and where free_arg contains the 8787c478bd9Sstevel@tonic-gate * identical information as the SO_FILEP content. 8797c478bd9Sstevel@tonic-gate * 8807c478bd9Sstevel@tonic-gate * If any of these constraints are not satisfied we 8817c478bd9Sstevel@tonic-gate * silently ignore the option. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate ASSERT(mp); 8847c478bd9Sstevel@tonic-gate if (frp != NULL && 8857c478bd9Sstevel@tonic-gate frp->free_func == fdbuf_free && 8867c478bd9Sstevel@tonic-gate frp->free_arg != NULL && 8877c478bd9Sstevel@tonic-gate bcmp(frp->free_arg, fdbuf, fdbuflen) == 0) { 8887c478bd9Sstevel@tonic-gate dprint(1, ("fdbuf_verify: fdbuf %p len %d\n", 889903a11ebSrh87107 (void *)fdbuf, fdbuflen)); 8907c478bd9Sstevel@tonic-gate return (1); 8917c478bd9Sstevel@tonic-gate } else { 8922caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 8937c478bd9Sstevel@tonic-gate "sockfs: mismatched fdbuf content (%p)", 8947c478bd9Sstevel@tonic-gate (void *)mp); 8957c478bd9Sstevel@tonic-gate return (0); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate } else { 8982caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 8997c478bd9Sstevel@tonic-gate "sockfs: mismatched fdbuf len %d, %d\n", 9007c478bd9Sstevel@tonic-gate fdbuflen, fdbuf->fd_size); 9017c478bd9Sstevel@tonic-gate return (0); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* 9067c478bd9Sstevel@tonic-gate * When the file descriptors returned by sorecvmsg can not be passed 9077c478bd9Sstevel@tonic-gate * to the application this routine will cleanup the references on 9087c478bd9Sstevel@tonic-gate * the files. Start at startoff bytes into the buffer. 9097c478bd9Sstevel@tonic-gate */ 9107c478bd9Sstevel@tonic-gate static void 9117c478bd9Sstevel@tonic-gate close_fds(void *fdbuf, int fdbuflen, int startoff) 9127c478bd9Sstevel@tonic-gate { 9137c478bd9Sstevel@tonic-gate int *fds = (int *)fdbuf; 9147c478bd9Sstevel@tonic-gate int numfd = fdbuflen / (int)sizeof (int); 9157c478bd9Sstevel@tonic-gate int i; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate dprint(1, ("close_fds(%p, %d, %d)\n", fdbuf, fdbuflen, startoff)); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 9207c478bd9Sstevel@tonic-gate if (startoff < 0) 9217c478bd9Sstevel@tonic-gate startoff = 0; 9227c478bd9Sstevel@tonic-gate if (startoff < (int)sizeof (int)) { 9237c478bd9Sstevel@tonic-gate /* 9247c478bd9Sstevel@tonic-gate * This file descriptor is partially or fully after 9257c478bd9Sstevel@tonic-gate * the offset 9267c478bd9Sstevel@tonic-gate */ 9277c478bd9Sstevel@tonic-gate dprint(0, 9287c478bd9Sstevel@tonic-gate ("close_fds: cleanup[%d] = %d\n", i, fds[i])); 9297c478bd9Sstevel@tonic-gate (void) closeandsetf(fds[i], NULL); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate startoff -= (int)sizeof (int); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * Close all file descriptors contained in the control part starting at 9377c478bd9Sstevel@tonic-gate * the startoffset. 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate void 9407c478bd9Sstevel@tonic-gate so_closefds(void *control, t_uscalar_t controllen, int oldflg, 9417c478bd9Sstevel@tonic-gate int startoff) 9427c478bd9Sstevel@tonic-gate { 9437c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate if (control == NULL) 9467c478bd9Sstevel@tonic-gate return; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if (oldflg) { 9497c478bd9Sstevel@tonic-gate close_fds(control, controllen, startoff); 9507c478bd9Sstevel@tonic-gate return; 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate /* Scan control part for file descriptors. */ 9537c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 9547c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 9557c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 9567c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 9577c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 9587c478bd9Sstevel@tonic-gate close_fds(CMSG_CONTENT(cmsg), 9597c478bd9Sstevel@tonic-gate (int)CMSG_CONTENTLEN(cmsg), 9607c478bd9Sstevel@tonic-gate startoff - (int)sizeof (struct cmsghdr)); 9617c478bd9Sstevel@tonic-gate } 962d865fc92SAndy Fiddaman startoff -= ROUNDUP_cmsglen(cmsg->cmsg_len); 963d865fc92SAndy Fiddaman } 964d865fc92SAndy Fiddaman } 965d865fc92SAndy Fiddaman 966d865fc92SAndy Fiddaman /* 967d865fc92SAndy Fiddaman * Handle truncation of a cmsg when the receive buffer is not big enough. 968d865fc92SAndy Fiddaman * Adjust the cmsg_len header field in the last cmsg that will be included in 969d865fc92SAndy Fiddaman * the buffer to reflect the number of bytes included. 970d865fc92SAndy Fiddaman */ 971d865fc92SAndy Fiddaman void 972d865fc92SAndy Fiddaman so_truncatecmsg(void *control, t_uscalar_t controllen, uint_t maxlen) 973d865fc92SAndy Fiddaman { 974d865fc92SAndy Fiddaman struct cmsghdr *cmsg; 975d865fc92SAndy Fiddaman uint_t len = 0; 976d865fc92SAndy Fiddaman 977d865fc92SAndy Fiddaman if (control == NULL) 978d865fc92SAndy Fiddaman return; 979d865fc92SAndy Fiddaman 980d865fc92SAndy Fiddaman for (cmsg = control; 981d865fc92SAndy Fiddaman CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 982d865fc92SAndy Fiddaman cmsg = CMSG_NEXT(cmsg)) { 983d865fc92SAndy Fiddaman 984d865fc92SAndy Fiddaman len += ROUNDUP_cmsglen(cmsg->cmsg_len); 985d865fc92SAndy Fiddaman 986d865fc92SAndy Fiddaman if (len > maxlen) { 987d865fc92SAndy Fiddaman /* 988d865fc92SAndy Fiddaman * This cmsg is the last one that will be included in 989d865fc92SAndy Fiddaman * the truncated buffer. 990d865fc92SAndy Fiddaman */ 991d865fc92SAndy Fiddaman socklen_t diff = len - maxlen; 992d865fc92SAndy Fiddaman 993d865fc92SAndy Fiddaman if (diff < CMSG_CONTENTLEN(cmsg)) { 994d865fc92SAndy Fiddaman dprint(1, ("so_truncatecmsg: %d -> %d\n", 995d865fc92SAndy Fiddaman cmsg->cmsg_len, cmsg->cmsg_len - diff)); 996d865fc92SAndy Fiddaman cmsg->cmsg_len -= diff; 997d865fc92SAndy Fiddaman } else { 998d865fc92SAndy Fiddaman cmsg->cmsg_len = sizeof (struct cmsghdr); 999d865fc92SAndy Fiddaman } 1000d865fc92SAndy Fiddaman break; 1001d865fc92SAndy Fiddaman } 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate /* 10067c478bd9Sstevel@tonic-gate * Returns a pointer/length for the file descriptors contained 10077c478bd9Sstevel@tonic-gate * in the control buffer. Returns with *fdlenp == -1 if there are no 10087c478bd9Sstevel@tonic-gate * file descriptor options present. This is different than there being 10097c478bd9Sstevel@tonic-gate * a zero-length file descriptor option. 10107c478bd9Sstevel@tonic-gate * Fail if there are multiple SCM_RIGHT cmsgs. 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate int 10137c478bd9Sstevel@tonic-gate so_getfdopt(void *control, t_uscalar_t controllen, int oldflg, 10147c478bd9Sstevel@tonic-gate void **fdsp, int *fdlenp) 10157c478bd9Sstevel@tonic-gate { 10167c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 10177c478bd9Sstevel@tonic-gate void *fds; 10187c478bd9Sstevel@tonic-gate int fdlen; 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate if (control == NULL) { 10217c478bd9Sstevel@tonic-gate *fdsp = NULL; 10227c478bd9Sstevel@tonic-gate *fdlenp = -1; 10237c478bd9Sstevel@tonic-gate return (0); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate if (oldflg) { 10277c478bd9Sstevel@tonic-gate *fdsp = control; 10287c478bd9Sstevel@tonic-gate if (controllen == 0) 10297c478bd9Sstevel@tonic-gate *fdlenp = -1; 10307c478bd9Sstevel@tonic-gate else 10317c478bd9Sstevel@tonic-gate *fdlenp = controllen; 10327c478bd9Sstevel@tonic-gate dprint(1, ("so_getfdopt: old %d\n", *fdlenp)); 10337c478bd9Sstevel@tonic-gate return (0); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate fds = NULL; 10377c478bd9Sstevel@tonic-gate fdlen = 0; 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 10407c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 10417c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 10427c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 10437c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 10447c478bd9Sstevel@tonic-gate if (fds != NULL) 10457c478bd9Sstevel@tonic-gate return (EINVAL); 10467c478bd9Sstevel@tonic-gate fds = CMSG_CONTENT(cmsg); 10477c478bd9Sstevel@tonic-gate fdlen = (int)CMSG_CONTENTLEN(cmsg); 10481e0267ddSkrgopi dprint(1, ("so_getfdopt: new %lu\n", 10491e0267ddSkrgopi (size_t)CMSG_CONTENTLEN(cmsg))); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate if (fds == NULL) { 10537c478bd9Sstevel@tonic-gate dprint(1, ("so_getfdopt: NONE\n")); 10547c478bd9Sstevel@tonic-gate *fdlenp = -1; 10557c478bd9Sstevel@tonic-gate } else 10567c478bd9Sstevel@tonic-gate *fdlenp = fdlen; 10577c478bd9Sstevel@tonic-gate *fdsp = fds; 10587c478bd9Sstevel@tonic-gate return (0); 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate /* 10627c478bd9Sstevel@tonic-gate * Return the length of the options including any file descriptor options. 10637c478bd9Sstevel@tonic-gate */ 10647c478bd9Sstevel@tonic-gate t_uscalar_t 10657c478bd9Sstevel@tonic-gate so_optlen(void *control, t_uscalar_t controllen, int oldflg) 10667c478bd9Sstevel@tonic-gate { 10677c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 10687c478bd9Sstevel@tonic-gate t_uscalar_t optlen = 0; 10697c478bd9Sstevel@tonic-gate t_uscalar_t len; 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate if (control == NULL) 10727c478bd9Sstevel@tonic-gate return (0); 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if (oldflg) 10757c478bd9Sstevel@tonic-gate return ((t_uscalar_t)(sizeof (struct T_opthdr) + 10767c478bd9Sstevel@tonic-gate fdbuf_optlen(controllen))); 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 10797c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 10807c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 10817c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 10827c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 10837c478bd9Sstevel@tonic-gate len = fdbuf_optlen((int)CMSG_CONTENTLEN(cmsg)); 10847c478bd9Sstevel@tonic-gate } else { 10857c478bd9Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate optlen += (t_uscalar_t)(_TPI_ALIGN_TOPT(len) + 10887c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate dprint(1, ("so_optlen: controllen %d, flg %d -> optlen %d\n", 10917c478bd9Sstevel@tonic-gate controllen, oldflg, optlen)); 10927c478bd9Sstevel@tonic-gate return (optlen); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate * Copy options from control to the mblk. Skip any file descriptor options. 10977c478bd9Sstevel@tonic-gate */ 10987c478bd9Sstevel@tonic-gate void 10997c478bd9Sstevel@tonic-gate so_cmsg2opt(void *control, t_uscalar_t controllen, int oldflg, mblk_t *mp) 11007c478bd9Sstevel@tonic-gate { 11017c478bd9Sstevel@tonic-gate struct T_opthdr toh; 11027c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate if (control == NULL) 11057c478bd9Sstevel@tonic-gate return; 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate if (oldflg) { 11087c478bd9Sstevel@tonic-gate /* No real options - caller has handled file descriptors */ 11097c478bd9Sstevel@tonic-gate return; 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 11127c478bd9Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 11137c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 11147c478bd9Sstevel@tonic-gate /* 11157c478bd9Sstevel@tonic-gate * Note: The caller handles file descriptors prior 11167c478bd9Sstevel@tonic-gate * to calling this function. 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate t_uscalar_t len; 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 11217c478bd9Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) 11227c478bd9Sstevel@tonic-gate continue; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 11257c478bd9Sstevel@tonic-gate toh.level = cmsg->cmsg_level; 11267c478bd9Sstevel@tonic-gate toh.name = cmsg->cmsg_type; 11277c478bd9Sstevel@tonic-gate toh.len = len + (t_uscalar_t)sizeof (struct T_opthdr); 11287c478bd9Sstevel@tonic-gate toh.status = 0; 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate soappendmsg(mp, &toh, sizeof (toh)); 11317c478bd9Sstevel@tonic-gate soappendmsg(mp, CMSG_CONTENT(cmsg), len); 11327c478bd9Sstevel@tonic-gate mp->b_wptr += _TPI_ALIGN_TOPT(len) - len; 11337c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr <= mp->b_datap->db_lim); 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate /* 11387c478bd9Sstevel@tonic-gate * Return the length of the control message derived from the options. 11397c478bd9Sstevel@tonic-gate * Exclude SO_SRCADDR and SO_UNIX_CLOSE options. Include SO_FILEP. 11407c478bd9Sstevel@tonic-gate * When oldflg is set only include SO_FILEP. 11410d204002Sgt145670 * so_opt2cmsg and so_cmsglen are inter-related since so_cmsglen 11420d204002Sgt145670 * allocates the space that so_opt2cmsg fills. If one changes, the other should 11430d204002Sgt145670 * also be checked for any possible impacts. 11447c478bd9Sstevel@tonic-gate */ 11457c478bd9Sstevel@tonic-gate t_uscalar_t 11467c478bd9Sstevel@tonic-gate so_cmsglen(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg) 11477c478bd9Sstevel@tonic-gate { 11487c478bd9Sstevel@tonic-gate t_uscalar_t cmsglen = 0; 11497c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 11507c478bd9Sstevel@tonic-gate t_uscalar_t len; 11517c478bd9Sstevel@tonic-gate t_uscalar_t last_roundup = 0; 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 11567c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 11577c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 11587c478bd9Sstevel@tonic-gate dprint(1, ("so_cmsglen: level 0x%x, name %d, len %d\n", 11597c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 11607c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 11617c478bd9Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 11627c478bd9Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 11637c478bd9Sstevel@tonic-gate continue; 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 11667c478bd9Sstevel@tonic-gate struct fdbuf *fdbuf; 11677c478bd9Sstevel@tonic-gate int fdbuflen; 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 11707c478bd9Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 11737c478bd9Sstevel@tonic-gate continue; 11747c478bd9Sstevel@tonic-gate if (oldflg) { 11757c478bd9Sstevel@tonic-gate cmsglen += fdbuf_cmsglen(fdbuflen); 11767c478bd9Sstevel@tonic-gate continue; 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate len = fdbuf_cmsglen(fdbuflen); 11790d204002Sgt145670 } else if (tohp->level == SOL_SOCKET && 11800d204002Sgt145670 tohp->name == SCM_TIMESTAMP) { 11810d204002Sgt145670 if (oldflg) 11820d204002Sgt145670 continue; 11830d204002Sgt145670 11840d204002Sgt145670 if (get_udatamodel() == DATAMODEL_NATIVE) { 11850d204002Sgt145670 len = sizeof (struct timeval); 11860d204002Sgt145670 } else { 11870d204002Sgt145670 len = sizeof (struct timeval32); 11880d204002Sgt145670 } 11897c478bd9Sstevel@tonic-gate } else { 11907c478bd9Sstevel@tonic-gate if (oldflg) 11917c478bd9Sstevel@tonic-gate continue; 11927c478bd9Sstevel@tonic-gate len = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate /* 11950d204002Sgt145670 * Exclude roundup for last option to not set 11967c478bd9Sstevel@tonic-gate * MSG_CTRUNC when the cmsg fits but the padding doesn't fit. 11977c478bd9Sstevel@tonic-gate */ 11987c478bd9Sstevel@tonic-gate last_roundup = (t_uscalar_t) 11997c478bd9Sstevel@tonic-gate (ROUNDUP_cmsglen(len + (int)sizeof (struct cmsghdr)) - 12007c478bd9Sstevel@tonic-gate (len + (int)sizeof (struct cmsghdr))); 12017c478bd9Sstevel@tonic-gate cmsglen += (t_uscalar_t)(len + (int)sizeof (struct cmsghdr)) + 12027c478bd9Sstevel@tonic-gate last_roundup; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate cmsglen -= last_roundup; 12057c478bd9Sstevel@tonic-gate dprint(1, ("so_cmsglen: optlen %d, flg %d -> cmsglen %d\n", 12067c478bd9Sstevel@tonic-gate optlen, oldflg, cmsglen)); 12077c478bd9Sstevel@tonic-gate return (cmsglen); 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate /* 12117c478bd9Sstevel@tonic-gate * Copy options from options to the control. Convert SO_FILEP to 12127c478bd9Sstevel@tonic-gate * file descriptors. 12137c478bd9Sstevel@tonic-gate * Returns errno or zero. 12140d204002Sgt145670 * so_opt2cmsg and so_cmsglen are inter-related since so_cmsglen 12150d204002Sgt145670 * allocates the space that so_opt2cmsg fills. If one changes, the other should 12160d204002Sgt145670 * also be checked for any possible impacts. 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate int 12197c478bd9Sstevel@tonic-gate so_opt2cmsg(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg, 12207c478bd9Sstevel@tonic-gate void *control, t_uscalar_t controllen) 12217c478bd9Sstevel@tonic-gate { 12227c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 12237c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 12247c478bd9Sstevel@tonic-gate struct fdbuf *fdbuf; 12257c478bd9Sstevel@tonic-gate int fdbuflen; 12267c478bd9Sstevel@tonic-gate int error; 12270d204002Sgt145670 #if defined(DEBUG) || defined(__lint) 12280d204002Sgt145670 struct cmsghdr *cend = (struct cmsghdr *) 12290d204002Sgt145670 (((uint8_t *)control) + ROUNDUP_cmsglen(controllen)); 12300d204002Sgt145670 #endif 12317c478bd9Sstevel@tonic-gate cmsg = (struct cmsghdr *)control; 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 12367c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 12377c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 12387c478bd9Sstevel@tonic-gate dprint(1, ("so_opt2cmsg: level 0x%x, name %d, len %d\n", 12397c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 12427c478bd9Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 12437c478bd9Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 12447c478bd9Sstevel@tonic-gate continue; 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)cmsg <= (uintptr_t)control + controllen); 12477c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 12487c478bd9Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 12497c478bd9Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 12527c478bd9Sstevel@tonic-gate return (EPROTO); 12537c478bd9Sstevel@tonic-gate if (oldflg) { 12547c478bd9Sstevel@tonic-gate error = fdbuf_extract(fdbuf, control, 12557c478bd9Sstevel@tonic-gate (int)controllen); 12567c478bd9Sstevel@tonic-gate if (error != 0) 12577c478bd9Sstevel@tonic-gate return (error); 12587c478bd9Sstevel@tonic-gate continue; 12597c478bd9Sstevel@tonic-gate } else { 12607c478bd9Sstevel@tonic-gate int fdlen; 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate fdlen = (int)fdbuf_cmsglen( 12637c478bd9Sstevel@tonic-gate (int)_TPI_TOPT_DATALEN(tohp)); 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 12667c478bd9Sstevel@tonic-gate cmsg->cmsg_type = SCM_RIGHTS; 12677c478bd9Sstevel@tonic-gate cmsg->cmsg_len = (socklen_t)(fdlen + 12687c478bd9Sstevel@tonic-gate sizeof (struct cmsghdr)); 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate error = fdbuf_extract(fdbuf, 12717c478bd9Sstevel@tonic-gate CMSG_CONTENT(cmsg), fdlen); 12727c478bd9Sstevel@tonic-gate if (error != 0) 12737c478bd9Sstevel@tonic-gate return (error); 12747c478bd9Sstevel@tonic-gate } 1275e4f35dbaSgt145670 } else if (tohp->level == SOL_SOCKET && 1276e4f35dbaSgt145670 tohp->name == SCM_TIMESTAMP) { 1277e4f35dbaSgt145670 timestruc_t *timestamp; 1278e4f35dbaSgt145670 1279e4f35dbaSgt145670 if (oldflg) 1280e4f35dbaSgt145670 continue; 1281e4f35dbaSgt145670 1282e4f35dbaSgt145670 cmsg->cmsg_level = tohp->level; 1283e4f35dbaSgt145670 cmsg->cmsg_type = tohp->name; 1284e4f35dbaSgt145670 1285e4f35dbaSgt145670 timestamp = 1286e4f35dbaSgt145670 (timestruc_t *)P2ROUNDUP((intptr_t)&tohp[1], 1287e4f35dbaSgt145670 sizeof (intptr_t)); 1288e4f35dbaSgt145670 1289e4f35dbaSgt145670 if (get_udatamodel() == DATAMODEL_NATIVE) { 12900d204002Sgt145670 struct timeval tv; 1291e4f35dbaSgt145670 1292e4f35dbaSgt145670 cmsg->cmsg_len = sizeof (struct timeval) + 1293e4f35dbaSgt145670 sizeof (struct cmsghdr); 12940d204002Sgt145670 tv.tv_sec = timestamp->tv_sec; 12950d204002Sgt145670 tv.tv_usec = timestamp->tv_nsec / 12960d204002Sgt145670 (NANOSEC / MICROSEC); 12970d204002Sgt145670 /* 12980d204002Sgt145670 * on LP64 systems, the struct timeval in 12990d204002Sgt145670 * the destination will not be 8-byte aligned, 13000d204002Sgt145670 * so use bcopy to avoid alignment trouble 13010d204002Sgt145670 */ 13020d204002Sgt145670 bcopy(&tv, CMSG_CONTENT(cmsg), sizeof (tv)); 1303e4f35dbaSgt145670 } else { 1304e4f35dbaSgt145670 struct timeval32 *time32; 1305e4f35dbaSgt145670 1306e4f35dbaSgt145670 cmsg->cmsg_len = sizeof (struct timeval32) + 1307e4f35dbaSgt145670 sizeof (struct cmsghdr); 1308e4f35dbaSgt145670 time32 = (struct timeval32 *)CMSG_CONTENT(cmsg); 1309e4f35dbaSgt145670 time32->tv_sec = (time32_t)timestamp->tv_sec; 1310e4f35dbaSgt145670 time32->tv_usec = 1311e4f35dbaSgt145670 (int32_t)(timestamp->tv_nsec / 1312e4f35dbaSgt145670 (NANOSEC / MICROSEC)); 1313e4f35dbaSgt145670 } 1314e4f35dbaSgt145670 13157c478bd9Sstevel@tonic-gate } else { 13167c478bd9Sstevel@tonic-gate if (oldflg) 13177c478bd9Sstevel@tonic-gate continue; 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 13207c478bd9Sstevel@tonic-gate cmsg->cmsg_type = tohp->name; 1321*221e47fbSAndy Fiddaman cmsg->cmsg_len = (socklen_t)sizeof (struct cmsghdr); 1322*221e47fbSAndy Fiddaman if (tohp->level == IPPROTO_IP && 1323*221e47fbSAndy Fiddaman (tohp->name == IP_RECVTOS || 1324*221e47fbSAndy Fiddaman tohp->name == IP_RECVTTL)) { 1325*221e47fbSAndy Fiddaman /* 1326*221e47fbSAndy Fiddaman * The data for these is a uint8_t but, in 1327*221e47fbSAndy Fiddaman * order to maintain alignment for any 1328*221e47fbSAndy Fiddaman * following TPI primitives in the message, 1329*221e47fbSAndy Fiddaman * there will be some trailing padding bytes 1330*221e47fbSAndy Fiddaman * which are included in the TPI_TOPT_DATALEN. 1331*221e47fbSAndy Fiddaman * For these types, we set the cmsg_len 1332*221e47fbSAndy Fiddaman * explicitly to the correct value. 1333*221e47fbSAndy Fiddaman */ 1334*221e47fbSAndy Fiddaman cmsg->cmsg_len += (socklen_t)sizeof (uint8_t); 1335*221e47fbSAndy Fiddaman } else { 1336*221e47fbSAndy Fiddaman cmsg->cmsg_len += 1337*221e47fbSAndy Fiddaman (socklen_t)(_TPI_TOPT_DATALEN(tohp)); 1338*221e47fbSAndy Fiddaman } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate /* copy content to control data part */ 13417c478bd9Sstevel@tonic-gate bcopy(&tohp[1], CMSG_CONTENT(cmsg), 13427c478bd9Sstevel@tonic-gate CMSG_CONTENTLEN(cmsg)); 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate /* move to next CMSG structure! */ 13457c478bd9Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 13467c478bd9Sstevel@tonic-gate } 13470d204002Sgt145670 dprint(1, ("so_opt2cmsg: buf %p len %d; cend %p; final cmsg %p\n", 1348903a11ebSrh87107 control, controllen, (void *)cend, (void *)cmsg)); 13490d204002Sgt145670 ASSERT(cmsg <= cend); 13507c478bd9Sstevel@tonic-gate return (0); 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate /* 13547c478bd9Sstevel@tonic-gate * Extract the SO_SRCADDR option value if present. 13557c478bd9Sstevel@tonic-gate */ 13567c478bd9Sstevel@tonic-gate void 13577c478bd9Sstevel@tonic-gate so_getopt_srcaddr(void *opt, t_uscalar_t optlen, void **srcp, 13587c478bd9Sstevel@tonic-gate t_uscalar_t *srclenp) 13597c478bd9Sstevel@tonic-gate { 13607c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate ASSERT(srcp != NULL && srclenp != NULL); 13657c478bd9Sstevel@tonic-gate *srcp = NULL; 13667c478bd9Sstevel@tonic-gate *srclenp = 0; 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 13697c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 13707c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 13717c478bd9Sstevel@tonic-gate dprint(1, ("so_getopt_srcaddr: level 0x%x, name %d, len %d\n", 13727c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 13737c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 13747c478bd9Sstevel@tonic-gate tohp->name == SO_SRCADDR) { 13757c478bd9Sstevel@tonic-gate *srcp = _TPI_TOPT_DATA(tohp); 13767c478bd9Sstevel@tonic-gate *srclenp = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * Verify if the SO_UNIX_CLOSE option is present. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate int 13857c478bd9Sstevel@tonic-gate so_getopt_unix_close(void *opt, t_uscalar_t optlen) 13867c478bd9Sstevel@tonic-gate { 13877c478bd9Sstevel@tonic-gate struct T_opthdr *tohp; 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 13927c478bd9Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 13937c478bd9Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 13947c478bd9Sstevel@tonic-gate dprint(1, 13957c478bd9Sstevel@tonic-gate ("so_getopt_unix_close: level 0x%x, name %d, len %d\n", 13967c478bd9Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 13977c478bd9Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 13987c478bd9Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE) 13997c478bd9Sstevel@tonic-gate return (1); 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate return (0); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * Allocate an M_PROTO message. 14067c478bd9Sstevel@tonic-gate * 14077c478bd9Sstevel@tonic-gate * If allocation fails the behavior depends on sleepflg: 14087c478bd9Sstevel@tonic-gate * _ALLOC_NOSLEEP fail immediately 14097c478bd9Sstevel@tonic-gate * _ALLOC_INTR sleep for memory until a signal is caught 14107c478bd9Sstevel@tonic-gate * _ALLOC_SLEEP sleep forever. Don't return NULL. 14117c478bd9Sstevel@tonic-gate */ 14127c478bd9Sstevel@tonic-gate mblk_t * 1413de8c4a14SErik Nordmark soallocproto(size_t size, int sleepflg, cred_t *cr) 14147c478bd9Sstevel@tonic-gate { 14157c478bd9Sstevel@tonic-gate mblk_t *mp; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* Round up size for reuse */ 14187c478bd9Sstevel@tonic-gate size = MAX(size, 64); 1419de8c4a14SErik Nordmark if (cr != NULL) 1420de8c4a14SErik Nordmark mp = allocb_cred(size, cr, curproc->p_pid); 1421de8c4a14SErik Nordmark else 14227c478bd9Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 1423de8c4a14SErik Nordmark 14247c478bd9Sstevel@tonic-gate if (mp == NULL) { 14257c478bd9Sstevel@tonic-gate int error; /* Dummy - error not returned to caller */ 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate switch (sleepflg) { 14287c478bd9Sstevel@tonic-gate case _ALLOC_SLEEP: 1429de8c4a14SErik Nordmark if (cr != NULL) { 1430de8c4a14SErik Nordmark mp = allocb_cred_wait(size, STR_NOSIG, &error, 1431de8c4a14SErik Nordmark cr, curproc->p_pid); 1432de8c4a14SErik Nordmark } else { 1433de8c4a14SErik Nordmark mp = allocb_wait(size, BPRI_MED, STR_NOSIG, 1434de8c4a14SErik Nordmark &error); 1435de8c4a14SErik Nordmark } 14367c478bd9Sstevel@tonic-gate ASSERT(mp); 14377c478bd9Sstevel@tonic-gate break; 14387c478bd9Sstevel@tonic-gate case _ALLOC_INTR: 1439de8c4a14SErik Nordmark if (cr != NULL) { 1440de8c4a14SErik Nordmark mp = allocb_cred_wait(size, 0, &error, cr, 1441de8c4a14SErik Nordmark curproc->p_pid); 1442de8c4a14SErik Nordmark } else { 14437c478bd9Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 1444de8c4a14SErik Nordmark } 14457c478bd9Sstevel@tonic-gate if (mp == NULL) { 14467c478bd9Sstevel@tonic-gate /* Caught signal while sleeping for memory */ 14477c478bd9Sstevel@tonic-gate eprintline(ENOBUFS); 14487c478bd9Sstevel@tonic-gate return (NULL); 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate break; 14517c478bd9Sstevel@tonic-gate case _ALLOC_NOSLEEP: 14527c478bd9Sstevel@tonic-gate default: 14537c478bd9Sstevel@tonic-gate eprintline(ENOBUFS); 14547c478bd9Sstevel@tonic-gate return (NULL); 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 14587c478bd9Sstevel@tonic-gate return (mp); 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate /* 14627c478bd9Sstevel@tonic-gate * Allocate an M_PROTO message with a single component. 14637c478bd9Sstevel@tonic-gate * len is the length of buf. size is the amount to allocate. 14647c478bd9Sstevel@tonic-gate * 14657c478bd9Sstevel@tonic-gate * buf can be NULL with a non-zero len. 14667c478bd9Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 14677c478bd9Sstevel@tonic-gate */ 14687c478bd9Sstevel@tonic-gate mblk_t * 1469de8c4a14SErik Nordmark soallocproto1(const void *buf, ssize_t len, ssize_t size, int sleepflg, 1470de8c4a14SErik Nordmark cred_t *cr) 14717c478bd9Sstevel@tonic-gate { 14727c478bd9Sstevel@tonic-gate mblk_t *mp; 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate if (size == 0) 14757c478bd9Sstevel@tonic-gate size = len; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate ASSERT(size >= len); 14787c478bd9Sstevel@tonic-gate /* Round up size for reuse */ 14797c478bd9Sstevel@tonic-gate size = MAX(size, 64); 1480de8c4a14SErik Nordmark mp = soallocproto(size, sleepflg, cr); 14817c478bd9Sstevel@tonic-gate if (mp == NULL) 14827c478bd9Sstevel@tonic-gate return (NULL); 14837c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 14847c478bd9Sstevel@tonic-gate if (len != 0) { 14857c478bd9Sstevel@tonic-gate if (buf != NULL) 14867c478bd9Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 14877c478bd9Sstevel@tonic-gate else 14887c478bd9Sstevel@tonic-gate bzero(mp->b_wptr, len); 14897c478bd9Sstevel@tonic-gate mp->b_wptr += len; 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate return (mp); 14927c478bd9Sstevel@tonic-gate } 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate /* 14957c478bd9Sstevel@tonic-gate * Append buf/len to mp. 14967c478bd9Sstevel@tonic-gate * The caller has to ensure that there is enough room in the mblk. 14977c478bd9Sstevel@tonic-gate * 14987c478bd9Sstevel@tonic-gate * buf can be NULL with a non-zero len. 14997c478bd9Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 15007c478bd9Sstevel@tonic-gate */ 15017c478bd9Sstevel@tonic-gate void 15027c478bd9Sstevel@tonic-gate soappendmsg(mblk_t *mp, const void *buf, ssize_t len) 15037c478bd9Sstevel@tonic-gate { 15047c478bd9Sstevel@tonic-gate ASSERT(mp); 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate if (len != 0) { 15077c478bd9Sstevel@tonic-gate /* Assert for room left */ 15087c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_lim - mp->b_wptr >= len); 15097c478bd9Sstevel@tonic-gate if (buf != NULL) 15107c478bd9Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 15117c478bd9Sstevel@tonic-gate else 15127c478bd9Sstevel@tonic-gate bzero(mp->b_wptr, len); 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate mp->b_wptr += len; 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate /* 15187c478bd9Sstevel@tonic-gate * Create a message using two kernel buffers. 15197c478bd9Sstevel@tonic-gate * If size is set that will determine the allocation size (e.g. for future 15207c478bd9Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 15217c478bd9Sstevel@tonic-gate * lengths. 15227c478bd9Sstevel@tonic-gate */ 15237c478bd9Sstevel@tonic-gate mblk_t * 15247c478bd9Sstevel@tonic-gate soallocproto2(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 1525de8c4a14SErik Nordmark ssize_t size, int sleepflg, cred_t *cr) 15267c478bd9Sstevel@tonic-gate { 15277c478bd9Sstevel@tonic-gate mblk_t *mp; 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate if (size == 0) 15307c478bd9Sstevel@tonic-gate size = len1 + len2; 15317c478bd9Sstevel@tonic-gate ASSERT(size >= len1 + len2); 15327c478bd9Sstevel@tonic-gate 1533de8c4a14SErik Nordmark mp = soallocproto1(buf1, len1, size, sleepflg, cr); 15347c478bd9Sstevel@tonic-gate if (mp) 15357c478bd9Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 15367c478bd9Sstevel@tonic-gate return (mp); 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate /* 15407c478bd9Sstevel@tonic-gate * Create a message using three kernel buffers. 15417c478bd9Sstevel@tonic-gate * If size is set that will determine the allocation size (for future 15427c478bd9Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 15437c478bd9Sstevel@tonic-gate * lengths. 15447c478bd9Sstevel@tonic-gate */ 15457c478bd9Sstevel@tonic-gate mblk_t * 15467c478bd9Sstevel@tonic-gate soallocproto3(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 1547de8c4a14SErik Nordmark const void *buf3, ssize_t len3, ssize_t size, int sleepflg, cred_t *cr) 15487c478bd9Sstevel@tonic-gate { 15497c478bd9Sstevel@tonic-gate mblk_t *mp; 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate if (size == 0) 15527c478bd9Sstevel@tonic-gate size = len1 + len2 +len3; 15537c478bd9Sstevel@tonic-gate ASSERT(size >= len1 + len2 + len3); 15547c478bd9Sstevel@tonic-gate 1555de8c4a14SErik Nordmark mp = soallocproto1(buf1, len1, size, sleepflg, cr); 15567c478bd9Sstevel@tonic-gate if (mp != NULL) { 15577c478bd9Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 15587c478bd9Sstevel@tonic-gate soappendmsg(mp, buf3, len3); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate return (mp); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate #ifdef DEBUG 15647c478bd9Sstevel@tonic-gate char * 15657c478bd9Sstevel@tonic-gate pr_state(uint_t state, uint_t mode) 15667c478bd9Sstevel@tonic-gate { 15677c478bd9Sstevel@tonic-gate static char buf[1024]; 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate buf[0] = 0; 15707c478bd9Sstevel@tonic-gate if (state & SS_ISCONNECTED) 1571903a11ebSrh87107 (void) strcat(buf, "ISCONNECTED "); 15727c478bd9Sstevel@tonic-gate if (state & SS_ISCONNECTING) 1573903a11ebSrh87107 (void) strcat(buf, "ISCONNECTING "); 15747c478bd9Sstevel@tonic-gate if (state & SS_ISDISCONNECTING) 1575903a11ebSrh87107 (void) strcat(buf, "ISDISCONNECTING "); 15767c478bd9Sstevel@tonic-gate if (state & SS_CANTSENDMORE) 1577903a11ebSrh87107 (void) strcat(buf, "CANTSENDMORE "); 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate if (state & SS_CANTRCVMORE) 1580903a11ebSrh87107 (void) strcat(buf, "CANTRCVMORE "); 15817c478bd9Sstevel@tonic-gate if (state & SS_ISBOUND) 1582903a11ebSrh87107 (void) strcat(buf, "ISBOUND "); 15837c478bd9Sstevel@tonic-gate if (state & SS_NDELAY) 1584903a11ebSrh87107 (void) strcat(buf, "NDELAY "); 15857c478bd9Sstevel@tonic-gate if (state & SS_NONBLOCK) 1586903a11ebSrh87107 (void) strcat(buf, "NONBLOCK "); 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate if (state & SS_ASYNC) 1589903a11ebSrh87107 (void) strcat(buf, "ASYNC "); 15907c478bd9Sstevel@tonic-gate if (state & SS_ACCEPTCONN) 1591903a11ebSrh87107 (void) strcat(buf, "ACCEPTCONN "); 15927c478bd9Sstevel@tonic-gate if (state & SS_SAVEDEOR) 1593903a11ebSrh87107 (void) strcat(buf, "SAVEDEOR "); 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate if (state & SS_RCVATMARK) 1596903a11ebSrh87107 (void) strcat(buf, "RCVATMARK "); 15977c478bd9Sstevel@tonic-gate if (state & SS_OOBPEND) 1598903a11ebSrh87107 (void) strcat(buf, "OOBPEND "); 15997c478bd9Sstevel@tonic-gate if (state & SS_HAVEOOBDATA) 1600903a11ebSrh87107 (void) strcat(buf, "HAVEOOBDATA "); 16017c478bd9Sstevel@tonic-gate if (state & SS_HADOOBDATA) 1602903a11ebSrh87107 (void) strcat(buf, "HADOOBDATA "); 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate if (mode & SM_PRIV) 1605903a11ebSrh87107 (void) strcat(buf, "PRIV "); 16067c478bd9Sstevel@tonic-gate if (mode & SM_ATOMIC) 1607903a11ebSrh87107 (void) strcat(buf, "ATOMIC "); 16087c478bd9Sstevel@tonic-gate if (mode & SM_ADDR) 1609903a11ebSrh87107 (void) strcat(buf, "ADDR "); 16107c478bd9Sstevel@tonic-gate if (mode & SM_CONNREQUIRED) 1611903a11ebSrh87107 (void) strcat(buf, "CONNREQUIRED "); 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate if (mode & SM_FDPASSING) 1614903a11ebSrh87107 (void) strcat(buf, "FDPASSING "); 16157c478bd9Sstevel@tonic-gate if (mode & SM_EXDATA) 1616903a11ebSrh87107 (void) strcat(buf, "EXDATA "); 16177c478bd9Sstevel@tonic-gate if (mode & SM_OPTDATA) 1618903a11ebSrh87107 (void) strcat(buf, "OPTDATA "); 16197c478bd9Sstevel@tonic-gate if (mode & SM_BYTESTREAM) 1620903a11ebSrh87107 (void) strcat(buf, "BYTESTREAM "); 16217c478bd9Sstevel@tonic-gate return (buf); 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate char * 16257c478bd9Sstevel@tonic-gate pr_addr(int family, struct sockaddr *addr, t_uscalar_t addrlen) 16267c478bd9Sstevel@tonic-gate { 16277c478bd9Sstevel@tonic-gate static char buf[1024]; 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate if (addr == NULL || addrlen == 0) { 1630903a11ebSrh87107 (void) sprintf(buf, "(len %d) %p", addrlen, (void *)addr); 16317c478bd9Sstevel@tonic-gate return (buf); 16327c478bd9Sstevel@tonic-gate } 16337c478bd9Sstevel@tonic-gate switch (family) { 16347c478bd9Sstevel@tonic-gate case AF_INET: { 16357c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate bcopy(addr, &sin, sizeof (sin)); 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate (void) sprintf(buf, "(len %d) %x/%d", 1640b5fca8f8Stomee addrlen, ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); 16417c478bd9Sstevel@tonic-gate break; 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate case AF_INET6: { 16447c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 16457c478bd9Sstevel@tonic-gate uint16_t *piece = (uint16_t *)&sin6.sin6_addr; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate bcopy((char *)addr, (char *)&sin6, sizeof (sin6)); 1648903a11ebSrh87107 (void) sprintf(buf, "(len %d) %x:%x:%x:%x:%x:%x:%x:%x/%d", 16497c478bd9Sstevel@tonic-gate addrlen, 16507c478bd9Sstevel@tonic-gate ntohs(piece[0]), ntohs(piece[1]), 16517c478bd9Sstevel@tonic-gate ntohs(piece[2]), ntohs(piece[3]), 16527c478bd9Sstevel@tonic-gate ntohs(piece[4]), ntohs(piece[5]), 16537c478bd9Sstevel@tonic-gate ntohs(piece[6]), ntohs(piece[7]), 16547c478bd9Sstevel@tonic-gate ntohs(sin6.sin6_port)); 16557c478bd9Sstevel@tonic-gate break; 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate case AF_UNIX: { 16587c478bd9Sstevel@tonic-gate struct sockaddr_un *soun = (struct sockaddr_un *)addr; 16597c478bd9Sstevel@tonic-gate 1660b5fca8f8Stomee (void) sprintf(buf, "(len %d) %s", addrlen, 16617c478bd9Sstevel@tonic-gate (soun == NULL) ? "(none)" : soun->sun_path); 16627c478bd9Sstevel@tonic-gate break; 16637c478bd9Sstevel@tonic-gate } 16647c478bd9Sstevel@tonic-gate default: 16657c478bd9Sstevel@tonic-gate (void) sprintf(buf, "(unknown af %d)", family); 16667c478bd9Sstevel@tonic-gate break; 16677c478bd9Sstevel@tonic-gate } 16687c478bd9Sstevel@tonic-gate return (buf); 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate /* The logical equivalence operator (a if-and-only-if b) */ 167256f33205SJonathan Adams #define EQUIVALENT(a, b) (((a) && (b)) || (!(a) && (!(b)))) 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate /* 16757c478bd9Sstevel@tonic-gate * Verify limitations and invariants on oob state. 16767c478bd9Sstevel@tonic-gate * Return 1 if OK, otherwise 0 so that it can be used as 16777c478bd9Sstevel@tonic-gate * ASSERT(verify_oobstate(so)); 16787c478bd9Sstevel@tonic-gate */ 16797c478bd9Sstevel@tonic-gate int 16807c478bd9Sstevel@tonic-gate so_verify_oobstate(struct sonode *so) 16817c478bd9Sstevel@tonic-gate { 16820f1702c5SYu Xiangning boolean_t havemark; 16830f1702c5SYu Xiangning 16847c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate /* 16877c478bd9Sstevel@tonic-gate * The possible state combinations are: 16887c478bd9Sstevel@tonic-gate * 0 16897c478bd9Sstevel@tonic-gate * SS_OOBPEND 16907c478bd9Sstevel@tonic-gate * SS_OOBPEND|SS_HAVEOOBDATA 16917c478bd9Sstevel@tonic-gate * SS_OOBPEND|SS_HADOOBDATA 16927c478bd9Sstevel@tonic-gate * SS_HADOOBDATA 16937c478bd9Sstevel@tonic-gate */ 16947c478bd9Sstevel@tonic-gate switch (so->so_state & (SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA)) { 16957c478bd9Sstevel@tonic-gate case 0: 16967c478bd9Sstevel@tonic-gate case SS_OOBPEND: 16977c478bd9Sstevel@tonic-gate case SS_OOBPEND|SS_HAVEOOBDATA: 16987c478bd9Sstevel@tonic-gate case SS_OOBPEND|SS_HADOOBDATA: 16997c478bd9Sstevel@tonic-gate case SS_HADOOBDATA: 17007c478bd9Sstevel@tonic-gate break; 17017c478bd9Sstevel@tonic-gate default: 17020f1702c5SYu Xiangning printf("Bad oob state 1 (%p): state %s\n", 17030f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode)); 17047c478bd9Sstevel@tonic-gate return (0); 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate /* SS_RCVATMARK should only be set when SS_OOBPEND is set */ 17087c478bd9Sstevel@tonic-gate if ((so->so_state & (SS_RCVATMARK|SS_OOBPEND)) == SS_RCVATMARK) { 17090f1702c5SYu Xiangning printf("Bad oob state 2 (%p): state %s\n", 17100f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode)); 17117c478bd9Sstevel@tonic-gate return (0); 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate /* 17150f1702c5SYu Xiangning * (havemark != 0 or SS_RCVATMARK) iff SS_OOBPEND 17160f1702c5SYu Xiangning * For TPI, the presence of a "mark" is indicated by sti_oobsigcnt. 17177c478bd9Sstevel@tonic-gate */ 17180f1702c5SYu Xiangning havemark = (SOCK_IS_NONSTR(so)) ? so->so_oobmark > 0 : 17190f1702c5SYu Xiangning SOTOTPI(so)->sti_oobsigcnt > 0; 17200f1702c5SYu Xiangning 172156f33205SJonathan Adams if (!EQUIVALENT(havemark || (so->so_state & SS_RCVATMARK), 17227c478bd9Sstevel@tonic-gate so->so_state & SS_OOBPEND)) { 17230f1702c5SYu Xiangning printf("Bad oob state 3 (%p): state %s\n", 17240f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode)); 17257c478bd9Sstevel@tonic-gate return (0); 17267c478bd9Sstevel@tonic-gate } 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate /* 17297c478bd9Sstevel@tonic-gate * Unless SO_OOBINLINE we have so_oobmsg != NULL iff SS_HAVEOOBDATA 17307c478bd9Sstevel@tonic-gate */ 17317c478bd9Sstevel@tonic-gate if (!(so->so_options & SO_OOBINLINE) && 173256f33205SJonathan Adams !EQUIVALENT(so->so_oobmsg != NULL, so->so_state & SS_HAVEOOBDATA)) { 17330f1702c5SYu Xiangning printf("Bad oob state 4 (%p): state %s\n", 17340f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode)); 17357c478bd9Sstevel@tonic-gate return (0); 17367c478bd9Sstevel@tonic-gate } 17370f1702c5SYu Xiangning 17380f1702c5SYu Xiangning if (!SOCK_IS_NONSTR(so) && 17390f1702c5SYu Xiangning SOTOTPI(so)->sti_oobsigcnt < SOTOTPI(so)->sti_oobcnt) { 17407c478bd9Sstevel@tonic-gate printf("Bad oob state 5 (%p): counts %d/%d state %s\n", 17410f1702c5SYu Xiangning (void *)so, SOTOTPI(so)->sti_oobsigcnt, 17420f1702c5SYu Xiangning SOTOTPI(so)->sti_oobcnt, 17430f1702c5SYu Xiangning pr_state(so->so_state, so->so_mode)); 17447c478bd9Sstevel@tonic-gate return (0); 17457c478bd9Sstevel@tonic-gate } 17460f1702c5SYu Xiangning 17477c478bd9Sstevel@tonic-gate return (1); 17487c478bd9Sstevel@tonic-gate } 174956f33205SJonathan Adams #undef EQUIVALENT 17507c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate /* initialize sockfs zone specific kstat related items */ 17537c478bd9Sstevel@tonic-gate void * 17547c478bd9Sstevel@tonic-gate sock_kstat_init(zoneid_t zoneid) 17557c478bd9Sstevel@tonic-gate { 17567c478bd9Sstevel@tonic-gate kstat_t *ksp; 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate ksp = kstat_create_zone("sockfs", 0, "sock_unix_list", "misc", 17597c478bd9Sstevel@tonic-gate KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE|KSTAT_FLAG_VIRTUAL, zoneid); 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate if (ksp != NULL) { 17627c478bd9Sstevel@tonic-gate ksp->ks_update = sockfs_update; 17637c478bd9Sstevel@tonic-gate ksp->ks_snapshot = sockfs_snapshot; 17647c478bd9Sstevel@tonic-gate ksp->ks_lock = &socklist.sl_lock; 17657c478bd9Sstevel@tonic-gate ksp->ks_private = (void *)(uintptr_t)zoneid; 17667c478bd9Sstevel@tonic-gate kstat_install(ksp); 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate return (ksp); 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate /* tear down sockfs zone specific kstat related items */ 17737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17747c478bd9Sstevel@tonic-gate void 17757c478bd9Sstevel@tonic-gate sock_kstat_fini(zoneid_t zoneid, void *arg) 17767c478bd9Sstevel@tonic-gate { 17777c478bd9Sstevel@tonic-gate kstat_t *ksp = (kstat_t *)arg; 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate if (ksp != NULL) { 17807c478bd9Sstevel@tonic-gate ASSERT(zoneid == (zoneid_t)(uintptr_t)ksp->ks_private); 17817c478bd9Sstevel@tonic-gate kstat_delete(ksp); 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate } 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate /* 17867c478bd9Sstevel@tonic-gate * Zones: 17877c478bd9Sstevel@tonic-gate * Note that nactive is going to be different for each zone. 17887c478bd9Sstevel@tonic-gate * This means we require kstat to call sockfs_update and then sockfs_snapshot 17897c478bd9Sstevel@tonic-gate * for the same zone, or sockfs_snapshot will be taken into the wrong size 17907c478bd9Sstevel@tonic-gate * buffer. This is safe, but if the buffer is too small, user will not be 17917c478bd9Sstevel@tonic-gate * given details of all sockets. However, as this kstat has a ks_lock, kstat 17927c478bd9Sstevel@tonic-gate * driver will keep it locked between the update and the snapshot, so no 17937c478bd9Sstevel@tonic-gate * other process (zone) can currently get inbetween resulting in a wrong size 17947c478bd9Sstevel@tonic-gate * buffer allocation. 17957c478bd9Sstevel@tonic-gate */ 17967c478bd9Sstevel@tonic-gate static int 17977c478bd9Sstevel@tonic-gate sockfs_update(kstat_t *ksp, int rw) 17987c478bd9Sstevel@tonic-gate { 17997c478bd9Sstevel@tonic-gate uint_t nactive = 0; /* # of active AF_UNIX sockets */ 18007c478bd9Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 18017c478bd9Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 18067c478bd9Sstevel@tonic-gate return (EACCES); 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate 18090f1702c5SYu Xiangning for (so = socklist.sl_list; so != NULL; so = SOTOTPI(so)->sti_next_so) { 18100f1702c5SYu Xiangning if (so->so_count != 0 && so->so_zoneid == myzoneid) { 18117c478bd9Sstevel@tonic-gate nactive++; 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate } 18147c478bd9Sstevel@tonic-gate ksp->ks_ndata = nactive; 181578a2e113SAndy Fiddaman ksp->ks_data_size = nactive * sizeof (struct sockinfo); 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate return (0); 18187c478bd9Sstevel@tonic-gate } 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate static int 18217c478bd9Sstevel@tonic-gate sockfs_snapshot(kstat_t *ksp, void *buf, int rw) 18227c478bd9Sstevel@tonic-gate { 18237c478bd9Sstevel@tonic-gate int ns; /* # of sonodes we've copied */ 18247c478bd9Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 182578a2e113SAndy Fiddaman struct sockinfo *psi; /* where we put sockinfo data */ 18267c478bd9Sstevel@tonic-gate t_uscalar_t sn_len; /* soa_len */ 18277c478bd9Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 18280f1702c5SYu Xiangning sotpi_info_t *sti; 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate ksp->ks_snaptime = gethrtime(); 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 18357c478bd9Sstevel@tonic-gate return (EACCES); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate /* 183978a2e113SAndy Fiddaman * For each sonode on the socklist, we massage the important 184078a2e113SAndy Fiddaman * info into buf, in sockinfo format. 18417c478bd9Sstevel@tonic-gate */ 184278a2e113SAndy Fiddaman psi = (struct sockinfo *)buf; 18430f1702c5SYu Xiangning ns = 0; 18440f1702c5SYu Xiangning for (so = socklist.sl_list; so != NULL; so = SOTOTPI(so)->sti_next_so) { 184578a2e113SAndy Fiddaman vattr_t attr; 184678a2e113SAndy Fiddaman 18477c478bd9Sstevel@tonic-gate /* only stuff active sonodes and the same zone: */ 18480f1702c5SYu Xiangning if (so->so_count == 0 || so->so_zoneid != myzoneid) { 18497c478bd9Sstevel@tonic-gate continue; 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate /* 18537c478bd9Sstevel@tonic-gate * If the sonode was activated between the update and the 18547c478bd9Sstevel@tonic-gate * snapshot, we're done - as this is only a snapshot. 18557c478bd9Sstevel@tonic-gate */ 185678a2e113SAndy Fiddaman if ((caddr_t)(psi) >= (caddr_t)buf + ksp->ks_data_size) { 18577c478bd9Sstevel@tonic-gate break; 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate 18600f1702c5SYu Xiangning sti = SOTOTPI(so); 18617c478bd9Sstevel@tonic-gate /* copy important info into buf: */ 186278a2e113SAndy Fiddaman psi->si_size = sizeof (struct sockinfo); 186378a2e113SAndy Fiddaman psi->si_family = so->so_family; 186478a2e113SAndy Fiddaman psi->si_type = so->so_type; 186578a2e113SAndy Fiddaman psi->si_flag = so->so_flag; 186678a2e113SAndy Fiddaman psi->si_state = so->so_state; 186778a2e113SAndy Fiddaman psi->si_serv_type = sti->sti_serv_type; 186878a2e113SAndy Fiddaman psi->si_ux_laddr_sou_magic = sti->sti_ux_laddr.soua_magic; 186978a2e113SAndy Fiddaman psi->si_ux_faddr_sou_magic = sti->sti_ux_faddr.soua_magic; 187078a2e113SAndy Fiddaman psi->si_laddr_soa_len = sti->sti_laddr.soa_len; 187178a2e113SAndy Fiddaman psi->si_faddr_soa_len = sti->sti_faddr.soa_len; 187278a2e113SAndy Fiddaman psi->si_szoneid = so->so_zoneid; 187378a2e113SAndy Fiddaman psi->si_faddr_noxlate = sti->sti_faddr_noxlate; 187478a2e113SAndy Fiddaman 187578a2e113SAndy Fiddaman /* 187678a2e113SAndy Fiddaman * Grab the inode, if possible. 187778a2e113SAndy Fiddaman * This must be done before entering so_lock as VOP_GETATTR 187878a2e113SAndy Fiddaman * will acquire it. 187978a2e113SAndy Fiddaman */ 188078a2e113SAndy Fiddaman if (so->so_vnode == NULL || 188178a2e113SAndy Fiddaman VOP_GETATTR(so->so_vnode, &attr, 0, CRED(), NULL) != 0) 188278a2e113SAndy Fiddaman attr.va_nodeid = 0; 188378a2e113SAndy Fiddaman 188478a2e113SAndy Fiddaman psi->si_inode = attr.va_nodeid; 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18877c478bd9Sstevel@tonic-gate 18880f1702c5SYu Xiangning if (sti->sti_laddr_sa != NULL) { 18890f1702c5SYu Xiangning ASSERT(sti->sti_laddr_sa->sa_data != NULL); 18900f1702c5SYu Xiangning sn_len = sti->sti_laddr_len; 18917c478bd9Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 189278a2e113SAndy Fiddaman sizeof (psi->si_laddr_sun_path)); 18937c478bd9Sstevel@tonic-gate 189478a2e113SAndy Fiddaman psi->si_laddr_family = 18950f1702c5SYu Xiangning sti->sti_laddr_sa->sa_family; 18967c478bd9Sstevel@tonic-gate if (sn_len != 0) { 18977c478bd9Sstevel@tonic-gate /* AF_UNIX socket names are NULL terminated */ 189878a2e113SAndy Fiddaman (void) strncpy(psi->si_laddr_sun_path, 18990f1702c5SYu Xiangning sti->sti_laddr_sa->sa_data, 190078a2e113SAndy Fiddaman sizeof (psi->si_laddr_sun_path)); 190178a2e113SAndy Fiddaman sn_len = strlen(psi->si_laddr_sun_path); 19027c478bd9Sstevel@tonic-gate } 190378a2e113SAndy Fiddaman psi->si_laddr_sun_path[sn_len] = 0; 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate 19060f1702c5SYu Xiangning if (sti->sti_faddr_sa != NULL) { 19070f1702c5SYu Xiangning ASSERT(sti->sti_faddr_sa->sa_data != NULL); 19080f1702c5SYu Xiangning sn_len = sti->sti_faddr_len; 19097c478bd9Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 191078a2e113SAndy Fiddaman sizeof (psi->si_faddr_sun_path)); 19117c478bd9Sstevel@tonic-gate 191278a2e113SAndy Fiddaman psi->si_faddr_family = 19130f1702c5SYu Xiangning sti->sti_faddr_sa->sa_family; 19147c478bd9Sstevel@tonic-gate if (sn_len != 0) { 191578a2e113SAndy Fiddaman (void) strncpy(psi->si_faddr_sun_path, 19160f1702c5SYu Xiangning sti->sti_faddr_sa->sa_data, 191778a2e113SAndy Fiddaman sizeof (psi->si_faddr_sun_path)); 191878a2e113SAndy Fiddaman sn_len = strlen(psi->si_faddr_sun_path); 19197c478bd9Sstevel@tonic-gate } 192078a2e113SAndy Fiddaman psi->si_faddr_sun_path[sn_len] = 0; 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19247c478bd9Sstevel@tonic-gate 192578a2e113SAndy Fiddaman (void) snprintf(psi->si_son_straddr, 192678a2e113SAndy Fiddaman sizeof (psi->si_son_straddr), "%p", (void *)so); 192778a2e113SAndy Fiddaman (void) snprintf(psi->si_lvn_straddr, 192878a2e113SAndy Fiddaman sizeof (psi->si_lvn_straddr), "%p", 19290f1702c5SYu Xiangning (void *)sti->sti_ux_laddr.soua_vp); 193078a2e113SAndy Fiddaman (void) snprintf(psi->si_fvn_straddr, 193178a2e113SAndy Fiddaman sizeof (psi->si_fvn_straddr), "%p", 19320f1702c5SYu Xiangning (void *)sti->sti_ux_faddr.soua_vp); 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate ns++; 193578a2e113SAndy Fiddaman psi++; 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate ksp->ks_ndata = ns; 19397c478bd9Sstevel@tonic-gate return (0); 19407c478bd9Sstevel@tonic-gate } 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate ssize_t 19437c478bd9Sstevel@tonic-gate soreadfile(file_t *fp, uchar_t *buf, u_offset_t fileoff, int *err, size_t size) 19447c478bd9Sstevel@tonic-gate { 19457c478bd9Sstevel@tonic-gate struct uio auio; 19468e935259SBryan Cantrill struct iovec aiov[1]; 19477c478bd9Sstevel@tonic-gate register vnode_t *vp; 19487c478bd9Sstevel@tonic-gate int ioflag, rwflag; 19497c478bd9Sstevel@tonic-gate ssize_t cnt; 19507c478bd9Sstevel@tonic-gate int error = 0; 19517c478bd9Sstevel@tonic-gate int iovcnt = 0; 19527c478bd9Sstevel@tonic-gate short fflag; 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 19557c478bd9Sstevel@tonic-gate fflag = fp->f_flag; 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate rwflag = 0; 19587c478bd9Sstevel@tonic-gate aiov[0].iov_base = (caddr_t)buf; 19597c478bd9Sstevel@tonic-gate aiov[0].iov_len = size; 19607c478bd9Sstevel@tonic-gate iovcnt = 1; 19617c478bd9Sstevel@tonic-gate cnt = (ssize_t)size; 19627c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 19657c478bd9Sstevel@tonic-gate auio.uio_iov = aiov; 19667c478bd9Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 19677c478bd9Sstevel@tonic-gate auio.uio_resid = cnt; 19687c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 19697c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 19707c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 19717c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 19767c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 19777c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 19787c478bd9Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 19797c478bd9Sstevel@tonic-gate cnt -= auio.uio_resid; 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate if (error == EINTR && cnt != 0) 19847c478bd9Sstevel@tonic-gate error = 0; 19857c478bd9Sstevel@tonic-gate out: 19867c478bd9Sstevel@tonic-gate if (error != 0) { 19877c478bd9Sstevel@tonic-gate *err = error; 19887c478bd9Sstevel@tonic-gate return (0); 19897c478bd9Sstevel@tonic-gate } else { 19907c478bd9Sstevel@tonic-gate *err = 0; 19917c478bd9Sstevel@tonic-gate return (cnt); 19927c478bd9Sstevel@tonic-gate } 19937c478bd9Sstevel@tonic-gate } 19940f1702c5SYu Xiangning 19950f1702c5SYu Xiangning int 19960f1702c5SYu Xiangning so_copyin(const void *from, void *to, size_t size, int fromkernel) 19970f1702c5SYu Xiangning { 19980f1702c5SYu Xiangning if (fromkernel) { 19990f1702c5SYu Xiangning bcopy(from, to, size); 20000f1702c5SYu Xiangning return (0); 20010f1702c5SYu Xiangning } 20020f1702c5SYu Xiangning return (xcopyin(from, to, size)); 20030f1702c5SYu Xiangning } 20040f1702c5SYu Xiangning 20050f1702c5SYu Xiangning int 20060f1702c5SYu Xiangning so_copyout(const void *from, void *to, size_t size, int tokernel) 20070f1702c5SYu Xiangning { 20080f1702c5SYu Xiangning if (tokernel) { 20090f1702c5SYu Xiangning bcopy(from, to, size); 20100f1702c5SYu Xiangning return (0); 20110f1702c5SYu Xiangning } 20120f1702c5SYu Xiangning return (xcopyout(from, to, size)); 20130f1702c5SYu Xiangning } 2014