1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/t_lock.h> 31*0Sstevel@tonic-gate #include <sys/param.h> 32*0Sstevel@tonic-gate #include <sys/systm.h> 33*0Sstevel@tonic-gate #include <sys/buf.h> 34*0Sstevel@tonic-gate #include <sys/conf.h> 35*0Sstevel@tonic-gate #include <sys/cred.h> 36*0Sstevel@tonic-gate #include <sys/kmem.h> 37*0Sstevel@tonic-gate #include <sys/sysmacros.h> 38*0Sstevel@tonic-gate #include <sys/vfs.h> 39*0Sstevel@tonic-gate #include <sys/vnode.h> 40*0Sstevel@tonic-gate #include <sys/debug.h> 41*0Sstevel@tonic-gate #include <sys/errno.h> 42*0Sstevel@tonic-gate #include <sys/time.h> 43*0Sstevel@tonic-gate #include <sys/file.h> 44*0Sstevel@tonic-gate #include <sys/open.h> 45*0Sstevel@tonic-gate #include <sys/user.h> 46*0Sstevel@tonic-gate #include <sys/termios.h> 47*0Sstevel@tonic-gate #include <sys/stream.h> 48*0Sstevel@tonic-gate #include <sys/strsubr.h> 49*0Sstevel@tonic-gate #include <sys/strsun.h> 50*0Sstevel@tonic-gate #include <sys/esunddi.h> 51*0Sstevel@tonic-gate #include <sys/flock.h> 52*0Sstevel@tonic-gate #include <sys/modctl.h> 53*0Sstevel@tonic-gate #include <sys/cmn_err.h> 54*0Sstevel@tonic-gate #include <sys/mkdev.h> 55*0Sstevel@tonic-gate #include <sys/pathname.h> 56*0Sstevel@tonic-gate #include <sys/ddi.h> 57*0Sstevel@tonic-gate #include <sys/stat.h> 58*0Sstevel@tonic-gate #include <sys/fs/snode.h> 59*0Sstevel@tonic-gate #include <sys/fs/dv_node.h> 60*0Sstevel@tonic-gate #include <sys/zone.h> 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate #include <sys/socket.h> 63*0Sstevel@tonic-gate #include <sys/socketvar.h> 64*0Sstevel@tonic-gate #include <netinet/in.h> 65*0Sstevel@tonic-gate #include <sys/un.h> 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate #include <sys/ucred.h> 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #include <sys/tiuser.h> 70*0Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 71*0Sstevel@tonic-gate #include <sys/tihdr.h> 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate #include <c2/audit.h> 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate #include <fs/sockfs/nl7c.h> 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate /* 78*0Sstevel@tonic-gate * Macros that operate on struct cmsghdr. 79*0Sstevel@tonic-gate * The CMSG_VALID macro does not assume that the last option buffer is padded. 80*0Sstevel@tonic-gate */ 81*0Sstevel@tonic-gate #define CMSG_CONTENT(cmsg) (&((cmsg)[1])) 82*0Sstevel@tonic-gate #define CMSG_CONTENTLEN(cmsg) ((cmsg)->cmsg_len - sizeof (struct cmsghdr)) 83*0Sstevel@tonic-gate #define CMSG_VALID(cmsg, start, end) \ 84*0Sstevel@tonic-gate (ISALIGNED_cmsghdr(cmsg) && \ 85*0Sstevel@tonic-gate ((uintptr_t)(cmsg) >= (uintptr_t)(start)) && \ 86*0Sstevel@tonic-gate ((uintptr_t)(cmsg) < (uintptr_t)(end)) && \ 87*0Sstevel@tonic-gate ((ssize_t)(cmsg)->cmsg_len >= sizeof (struct cmsghdr)) && \ 88*0Sstevel@tonic-gate ((uintptr_t)(cmsg) + (cmsg)->cmsg_len <= (uintptr_t)(end))) 89*0Sstevel@tonic-gate #define SO_LOCK_WAKEUP_TIME 3000 /* Wakeup time in milliseconds */ 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate static struct kmem_cache *socktpi_cache, *socktpi_unix_cache; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate dev_t sockdev; /* For fsid in getattr */ 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate struct sockparams *sphead; 96*0Sstevel@tonic-gate krwlock_t splist_lock; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate struct socklist socklist; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate static int sockfs_update(kstat_t *, int); 101*0Sstevel@tonic-gate static int sockfs_snapshot(kstat_t *, void *, int); 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate extern void sendfile_init(); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate extern void nl7c_init(void); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate #define ADRSTRLEN (2 * sizeof (void *) + 1) 108*0Sstevel@tonic-gate /* 109*0Sstevel@tonic-gate * kernel structure for passing the sockinfo data back up to the user. 110*0Sstevel@tonic-gate * the strings array allows us to convert AF_UNIX addresses into strings 111*0Sstevel@tonic-gate * with a common method regardless of which n-bit kernel we're running. 112*0Sstevel@tonic-gate */ 113*0Sstevel@tonic-gate struct k_sockinfo { 114*0Sstevel@tonic-gate struct sockinfo ks_si; 115*0Sstevel@tonic-gate char ks_straddr[3][ADRSTRLEN]; 116*0Sstevel@tonic-gate }; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* 119*0Sstevel@tonic-gate * Translate from a device pathname (e.g. "/dev/tcp") to a vnode. 120*0Sstevel@tonic-gate * Returns with the vnode held. 121*0Sstevel@tonic-gate */ 122*0Sstevel@tonic-gate static int 123*0Sstevel@tonic-gate sogetvp(char *devpath, vnode_t **vpp, int uioflag) 124*0Sstevel@tonic-gate { 125*0Sstevel@tonic-gate struct snode *csp; 126*0Sstevel@tonic-gate vnode_t *vp, *dvp; 127*0Sstevel@tonic-gate major_t maj; 128*0Sstevel@tonic-gate int error; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate ASSERT(uioflag == UIO_SYSSPACE || uioflag == UIO_USERSPACE); 131*0Sstevel@tonic-gate /* 132*0Sstevel@tonic-gate * Lookup the underlying filesystem vnode. 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate error = lookupname(devpath, uioflag, FOLLOW, NULLVPP, &vp); 135*0Sstevel@tonic-gate if (error) 136*0Sstevel@tonic-gate return (error); 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate /* Check that it is the correct vnode */ 139*0Sstevel@tonic-gate if (vp->v_type != VCHR) { 140*0Sstevel@tonic-gate VN_RELE(vp); 141*0Sstevel@tonic-gate return (ENOTSOCK); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate /* 145*0Sstevel@tonic-gate * If devpath went through devfs, the device should already 146*0Sstevel@tonic-gate * be configured. If devpath is a mknod file, however, we 147*0Sstevel@tonic-gate * need to make sure the device is properly configured. 148*0Sstevel@tonic-gate * To do this, we do something similar to spec_open() 149*0Sstevel@tonic-gate * except that we resolve to the minor/leaf level since 150*0Sstevel@tonic-gate * we need to return a vnode. 151*0Sstevel@tonic-gate */ 152*0Sstevel@tonic-gate csp = VTOS(VTOS(vp)->s_commonvp); 153*0Sstevel@tonic-gate if (!(csp->s_flag & SDIPSET)) { 154*0Sstevel@tonic-gate char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 155*0Sstevel@tonic-gate error = ddi_dev_pathname(vp->v_rdev, S_IFCHR, pathname); 156*0Sstevel@tonic-gate if (error == 0) 157*0Sstevel@tonic-gate error = devfs_lookupname(pathname, NULLVPP, &dvp); 158*0Sstevel@tonic-gate VN_RELE(vp); 159*0Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 160*0Sstevel@tonic-gate if (error != 0) 161*0Sstevel@tonic-gate return (ENXIO); 162*0Sstevel@tonic-gate vp = dvp; /* use the devfs vp */ 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate /* device is configured at this point */ 166*0Sstevel@tonic-gate maj = getmajor(vp->v_rdev); 167*0Sstevel@tonic-gate if (!STREAMSTAB(maj)) { 168*0Sstevel@tonic-gate VN_RELE(vp); 169*0Sstevel@tonic-gate return (ENOSTR); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate *vpp = vp; 173*0Sstevel@tonic-gate return (0); 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* 177*0Sstevel@tonic-gate * Add or delete (latter if devpath is NULL) an enter to the sockparams 178*0Sstevel@tonic-gate * table. If devpathlen is zero the devpath with not be kmem_freed. Otherwise 179*0Sstevel@tonic-gate * this routine assumes that the caller has kmem_alloced devpath/devpathlen 180*0Sstevel@tonic-gate * for this routine to consume. 181*0Sstevel@tonic-gate * The zero devpathlen could be used if the kernel wants to create entries 182*0Sstevel@tonic-gate * itself by calling sockconfig(1,2,3, "/dev/tcp", 0); 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate int 185*0Sstevel@tonic-gate soconfig(int domain, int type, int protocol, 186*0Sstevel@tonic-gate char *devpath, int devpathlen) 187*0Sstevel@tonic-gate { 188*0Sstevel@tonic-gate struct sockparams **spp; 189*0Sstevel@tonic-gate struct sockparams *sp; 190*0Sstevel@tonic-gate int error = 0; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate dprint(0, ("soconfig(%d,%d,%d,%s,%d)\n", 193*0Sstevel@tonic-gate domain, type, protocol, devpath, devpathlen)); 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* 196*0Sstevel@tonic-gate * Look for an existing match. 197*0Sstevel@tonic-gate */ 198*0Sstevel@tonic-gate rw_enter(&splist_lock, RW_WRITER); 199*0Sstevel@tonic-gate for (spp = &sphead; (sp = *spp) != NULL; spp = &sp->sp_next) { 200*0Sstevel@tonic-gate if (sp->sp_domain == domain && 201*0Sstevel@tonic-gate sp->sp_type == type && 202*0Sstevel@tonic-gate sp->sp_protocol == protocol) { 203*0Sstevel@tonic-gate break; 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate if (devpath == NULL) { 207*0Sstevel@tonic-gate ASSERT(devpathlen == 0); 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* Delete existing entry */ 210*0Sstevel@tonic-gate if (sp == NULL) { 211*0Sstevel@tonic-gate error = ENXIO; 212*0Sstevel@tonic-gate goto done; 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate /* Unlink and free existing entry */ 215*0Sstevel@tonic-gate *spp = sp->sp_next; 216*0Sstevel@tonic-gate ASSERT(sp->sp_vnode); 217*0Sstevel@tonic-gate VN_RELE(sp->sp_vnode); 218*0Sstevel@tonic-gate if (sp->sp_devpathlen != 0) 219*0Sstevel@tonic-gate kmem_free(sp->sp_devpath, sp->sp_devpathlen); 220*0Sstevel@tonic-gate kmem_free(sp, sizeof (*sp)); 221*0Sstevel@tonic-gate } else { 222*0Sstevel@tonic-gate vnode_t *vp; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* Add new entry */ 225*0Sstevel@tonic-gate if (sp != NULL) { 226*0Sstevel@tonic-gate error = EEXIST; 227*0Sstevel@tonic-gate goto done; 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate error = sogetvp(devpath, &vp, UIO_SYSSPACE); 231*0Sstevel@tonic-gate if (error) { 232*0Sstevel@tonic-gate dprint(0, ("soconfig: vp %s failed with %d\n", 233*0Sstevel@tonic-gate devpath, error)); 234*0Sstevel@tonic-gate goto done; 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate dprint(0, ("soconfig: %s => vp %p, dev 0x%lx\n", 238*0Sstevel@tonic-gate devpath, vp, vp->v_rdev)); 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate sp = kmem_alloc(sizeof (*sp), KM_SLEEP); 241*0Sstevel@tonic-gate sp->sp_domain = domain; 242*0Sstevel@tonic-gate sp->sp_type = type; 243*0Sstevel@tonic-gate sp->sp_protocol = protocol; 244*0Sstevel@tonic-gate sp->sp_devpath = devpath; 245*0Sstevel@tonic-gate sp->sp_devpathlen = devpathlen; 246*0Sstevel@tonic-gate sp->sp_vnode = vp; 247*0Sstevel@tonic-gate sp->sp_next = NULL; 248*0Sstevel@tonic-gate *spp = sp; 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate done: 251*0Sstevel@tonic-gate rw_exit(&splist_lock); 252*0Sstevel@tonic-gate if (error) { 253*0Sstevel@tonic-gate if (devpath != NULL) 254*0Sstevel@tonic-gate kmem_free(devpath, devpathlen); 255*0Sstevel@tonic-gate #ifdef SOCK_DEBUG 256*0Sstevel@tonic-gate eprintline(error); 257*0Sstevel@tonic-gate #endif /* SOCK_DEBUG */ 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate return (error); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * Lookup an entry in the sockparams list based on the triple. 264*0Sstevel@tonic-gate * If no entry is found and devpath is not NULL translate devpath to a 265*0Sstevel@tonic-gate * vnode. Note that devpath is a pointer to a user address! 266*0Sstevel@tonic-gate * Returns with the vnode held. 267*0Sstevel@tonic-gate * 268*0Sstevel@tonic-gate * When this routine uses devpath it does not create an entry in the sockparams 269*0Sstevel@tonic-gate * list since this routine can run on behalf of any user and one user 270*0Sstevel@tonic-gate * should not be able to effect the transport used by another user. 271*0Sstevel@tonic-gate * 272*0Sstevel@tonic-gate * In order to return the correct error this routine has to do wildcard scans 273*0Sstevel@tonic-gate * of the list. The errors are (in decreasing precedence): 274*0Sstevel@tonic-gate * EAFNOSUPPORT - address family not in list 275*0Sstevel@tonic-gate * EPROTONOSUPPORT - address family supported but not protocol. 276*0Sstevel@tonic-gate * EPROTOTYPE - address family and protocol supported but not socket type. 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate vnode_t * 279*0Sstevel@tonic-gate solookup(int domain, int type, int protocol, char *devpath, int *errorp) 280*0Sstevel@tonic-gate { 281*0Sstevel@tonic-gate struct sockparams *sp; 282*0Sstevel@tonic-gate int error; 283*0Sstevel@tonic-gate vnode_t *vp; 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate rw_enter(&splist_lock, RW_READER); 286*0Sstevel@tonic-gate for (sp = sphead; sp != NULL; sp = sp->sp_next) { 287*0Sstevel@tonic-gate if (sp->sp_domain == domain && 288*0Sstevel@tonic-gate sp->sp_type == type && 289*0Sstevel@tonic-gate sp->sp_protocol == protocol) { 290*0Sstevel@tonic-gate break; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate if (sp == NULL) { 294*0Sstevel@tonic-gate dprint(0, ("solookup(%d,%d,%d) not found\n", 295*0Sstevel@tonic-gate domain, type, protocol)); 296*0Sstevel@tonic-gate if (devpath == NULL) { 297*0Sstevel@tonic-gate /* Determine correct error code */ 298*0Sstevel@tonic-gate int found = 0; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate for (sp = sphead; sp != NULL; sp = sp->sp_next) { 301*0Sstevel@tonic-gate if (sp->sp_domain == domain && found < 1) 302*0Sstevel@tonic-gate found = 1; 303*0Sstevel@tonic-gate if (sp->sp_domain == domain && 304*0Sstevel@tonic-gate sp->sp_protocol == protocol && found < 2) 305*0Sstevel@tonic-gate found = 2; 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate rw_exit(&splist_lock); 308*0Sstevel@tonic-gate switch (found) { 309*0Sstevel@tonic-gate case 0: 310*0Sstevel@tonic-gate *errorp = EAFNOSUPPORT; 311*0Sstevel@tonic-gate break; 312*0Sstevel@tonic-gate case 1: 313*0Sstevel@tonic-gate *errorp = EPROTONOSUPPORT; 314*0Sstevel@tonic-gate break; 315*0Sstevel@tonic-gate case 2: 316*0Sstevel@tonic-gate *errorp = EPROTOTYPE; 317*0Sstevel@tonic-gate break; 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate return (NULL); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate rw_exit(&splist_lock); 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* 324*0Sstevel@tonic-gate * Return vp based on devpath. 325*0Sstevel@tonic-gate * Do not enter into table to avoid random users 326*0Sstevel@tonic-gate * modifying the sockparams list. 327*0Sstevel@tonic-gate */ 328*0Sstevel@tonic-gate error = sogetvp(devpath, &vp, UIO_USERSPACE); 329*0Sstevel@tonic-gate if (error) { 330*0Sstevel@tonic-gate dprint(0, ("solookup: vp %p failed with %d\n", 331*0Sstevel@tonic-gate devpath, error)); 332*0Sstevel@tonic-gate *errorp = EPROTONOSUPPORT; 333*0Sstevel@tonic-gate return (NULL); 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate dprint(0, ("solookup: %p => vp %p, dev 0x%lx\n", 336*0Sstevel@tonic-gate devpath, vp, vp->v_rdev)); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate return (vp); 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate dprint(0, ("solookup(%d,%d,%d) vp %p devpath %s\n", 341*0Sstevel@tonic-gate domain, type, protocol, sp->sp_vnode, sp->sp_devpath)); 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate vp = sp->sp_vnode; 344*0Sstevel@tonic-gate VN_HOLD(vp); 345*0Sstevel@tonic-gate rw_exit(&splist_lock); 346*0Sstevel@tonic-gate return (vp); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * Return a socket vnode. 351*0Sstevel@tonic-gate * 352*0Sstevel@tonic-gate * Assumes that the caller is "passing" an VN_HOLD for accessvp i.e. 353*0Sstevel@tonic-gate * when the socket is freed a VN_RELE will take place. 354*0Sstevel@tonic-gate * 355*0Sstevel@tonic-gate * Note that sockets assume that the driver will clone (either itself 356*0Sstevel@tonic-gate * or by using the clone driver) i.e. a socket() call will always 357*0Sstevel@tonic-gate * result in a new vnode being created. 358*0Sstevel@tonic-gate */ 359*0Sstevel@tonic-gate struct vnode * 360*0Sstevel@tonic-gate makesockvp(struct vnode *accessvp, int domain, int type, int protocol) 361*0Sstevel@tonic-gate { 362*0Sstevel@tonic-gate kmem_cache_t *cp; 363*0Sstevel@tonic-gate struct sonode *so; 364*0Sstevel@tonic-gate struct vnode *vp; 365*0Sstevel@tonic-gate time_t now; 366*0Sstevel@tonic-gate dev_t dev; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate cp = (domain == AF_UNIX) ? socktpi_unix_cache : socktpi_cache; 369*0Sstevel@tonic-gate so = kmem_cache_alloc(cp, KM_SLEEP); 370*0Sstevel@tonic-gate so->so_cache = cp; 371*0Sstevel@tonic-gate so->so_obj = so; 372*0Sstevel@tonic-gate vp = SOTOV(so); 373*0Sstevel@tonic-gate now = gethrestime_sec(); 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate so->so_flag = 0; 376*0Sstevel@tonic-gate ASSERT(so->so_accessvp == NULL); 377*0Sstevel@tonic-gate so->so_accessvp = accessvp; 378*0Sstevel@tonic-gate dev = accessvp->v_rdev; 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* 381*0Sstevel@tonic-gate * Record in so_flag that it is a clone. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate if (getmajor(dev) == clone_major) { 384*0Sstevel@tonic-gate so->so_flag |= SOCLONE; 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate so->so_dev = dev; 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate so->so_state = 0; 389*0Sstevel@tonic-gate so->so_mode = 0; 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate so->so_fsid = sockdev; 392*0Sstevel@tonic-gate so->so_atime = now; 393*0Sstevel@tonic-gate so->so_mtime = now; 394*0Sstevel@tonic-gate so->so_ctime = now; /* Never modified */ 395*0Sstevel@tonic-gate so->so_count = 0; 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate so->so_family = (short)domain; 398*0Sstevel@tonic-gate so->so_type = (short)type; 399*0Sstevel@tonic-gate so->so_protocol = (short)protocol; 400*0Sstevel@tonic-gate so->so_pushcnt = 0; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate so->so_options = 0; 403*0Sstevel@tonic-gate so->so_linger.l_onoff = 0; 404*0Sstevel@tonic-gate so->so_linger.l_linger = 0; 405*0Sstevel@tonic-gate so->so_sndbuf = 0; 406*0Sstevel@tonic-gate so->so_rcvbuf = 0; 407*0Sstevel@tonic-gate so->so_sndlowat = 0; 408*0Sstevel@tonic-gate so->so_rcvlowat = 0; 409*0Sstevel@tonic-gate #ifdef notyet 410*0Sstevel@tonic-gate so->so_sndtimeo = 0; 411*0Sstevel@tonic-gate so->so_rcvtimeo = 0; 412*0Sstevel@tonic-gate #endif /* notyet */ 413*0Sstevel@tonic-gate so->so_error = 0; 414*0Sstevel@tonic-gate so->so_delayed_error = 0; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 417*0Sstevel@tonic-gate so->so_oobcnt = 0; 418*0Sstevel@tonic-gate so->so_oobsigcnt = 0; 419*0Sstevel@tonic-gate so->so_pgrp = 0; 420*0Sstevel@tonic-gate so->so_provinfo = NULL; 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate ASSERT(so->so_laddr_sa == NULL && so->so_faddr_sa == NULL); 423*0Sstevel@tonic-gate so->so_laddr_len = so->so_faddr_len = 0; 424*0Sstevel@tonic-gate so->so_laddr_maxlen = so->so_faddr_maxlen = 0; 425*0Sstevel@tonic-gate so->so_eaddr_mp = NULL; 426*0Sstevel@tonic-gate so->so_priv = NULL; 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate so->so_peercred = NULL; 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate ASSERT(so->so_ack_mp == NULL); 431*0Sstevel@tonic-gate ASSERT(so->so_conn_ind_head == NULL); 432*0Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 433*0Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 434*0Sstevel@tonic-gate ASSERT(so->so_unbind_mp == NULL); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate vn_reinit(vp); 437*0Sstevel@tonic-gate vp->v_vfsp = rootvfs; 438*0Sstevel@tonic-gate vp->v_type = VSOCK; 439*0Sstevel@tonic-gate vp->v_rdev = so->so_dev; 440*0Sstevel@tonic-gate vn_exists(vp); 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate return (vp); 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate void 446*0Sstevel@tonic-gate sockfree(struct sonode *so) 447*0Sstevel@tonic-gate { 448*0Sstevel@tonic-gate mblk_t *mp; 449*0Sstevel@tonic-gate vnode_t *vp; 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate ASSERT(so->so_count == 0); 452*0Sstevel@tonic-gate ASSERT(so->so_accessvp); 453*0Sstevel@tonic-gate ASSERT(so->so_discon_ind_mp == NULL); 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate vp = so->so_accessvp; 456*0Sstevel@tonic-gate VN_RELE(vp); 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * Protect so->so_[lf]addr_sa so that sockfs_snapshot() can safely 460*0Sstevel@tonic-gate * indirect them. It also uses so_accessvp as a validity test. 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate mutex_enter(&so->so_lock); 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate so->so_accessvp = NULL; 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate if (so->so_laddr_sa) { 467*0Sstevel@tonic-gate ASSERT((caddr_t)so->so_faddr_sa == 468*0Sstevel@tonic-gate (caddr_t)so->so_laddr_sa + so->so_laddr_maxlen); 469*0Sstevel@tonic-gate ASSERT(so->so_faddr_maxlen == so->so_laddr_maxlen); 470*0Sstevel@tonic-gate so->so_state &= ~(SS_LADDR_VALID | SS_FADDR_VALID); 471*0Sstevel@tonic-gate kmem_free(so->so_laddr_sa, so->so_laddr_maxlen * 2); 472*0Sstevel@tonic-gate so->so_laddr_sa = NULL; 473*0Sstevel@tonic-gate so->so_laddr_len = so->so_laddr_maxlen = 0; 474*0Sstevel@tonic-gate so->so_faddr_sa = NULL; 475*0Sstevel@tonic-gate so->so_faddr_len = so->so_faddr_maxlen = 0; 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate mutex_exit(&so->so_lock); 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate if ((mp = so->so_eaddr_mp) != NULL) { 481*0Sstevel@tonic-gate freemsg(mp); 482*0Sstevel@tonic-gate so->so_eaddr_mp = NULL; 483*0Sstevel@tonic-gate so->so_delayed_error = 0; 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate if ((mp = so->so_ack_mp) != NULL) { 486*0Sstevel@tonic-gate freemsg(mp); 487*0Sstevel@tonic-gate so->so_ack_mp = NULL; 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate if ((mp = so->so_conn_ind_head) != NULL) { 490*0Sstevel@tonic-gate mblk_t *mp1; 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate while (mp) { 493*0Sstevel@tonic-gate mp1 = mp->b_next; 494*0Sstevel@tonic-gate mp->b_next = NULL; 495*0Sstevel@tonic-gate freemsg(mp); 496*0Sstevel@tonic-gate mp = mp1; 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate so->so_conn_ind_head = so->so_conn_ind_tail = NULL; 499*0Sstevel@tonic-gate so->so_state &= ~SS_HASCONNIND; 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate #ifdef DEBUG 502*0Sstevel@tonic-gate mutex_enter(&so->so_lock); 503*0Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 504*0Sstevel@tonic-gate mutex_exit(&so->so_lock); 505*0Sstevel@tonic-gate #endif /* DEBUG */ 506*0Sstevel@tonic-gate if ((mp = so->so_oobmsg) != NULL) { 507*0Sstevel@tonic-gate freemsg(mp); 508*0Sstevel@tonic-gate so->so_oobmsg = NULL; 509*0Sstevel@tonic-gate so->so_state &= ~(SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate if ((mp = so->so_nl7c_rcv_mp) != NULL) { 513*0Sstevel@tonic-gate so->so_nl7c_rcv_mp = NULL; 514*0Sstevel@tonic-gate freemsg(mp); 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate so->so_nl7c_rcv_rval = 0; 517*0Sstevel@tonic-gate if (so->so_nl7c_uri != NULL) { 518*0Sstevel@tonic-gate nl7c_urifree(so); 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate so->so_nl7c_flags = 0; 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 523*0Sstevel@tonic-gate if ((mp = so->so_unbind_mp) != NULL) { 524*0Sstevel@tonic-gate freemsg(mp); 525*0Sstevel@tonic-gate so->so_unbind_mp = NULL; 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate vn_invalid(SOTOV(so)); 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate if (so->so_peercred != NULL) 530*0Sstevel@tonic-gate crfree(so->so_peercred); 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate kmem_cache_free(so->so_cache, so->so_obj); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* 536*0Sstevel@tonic-gate * Update the accessed, updated, or changed times in an sonode 537*0Sstevel@tonic-gate * with the current time. 538*0Sstevel@tonic-gate * 539*0Sstevel@tonic-gate * Note that both SunOS 4.X and 4.4BSD sockets do not present reasonable 540*0Sstevel@tonic-gate * attributes in a fstat call. (They return the current time and 0 for 541*0Sstevel@tonic-gate * all timestamps, respectively.) We maintain the current timestamps 542*0Sstevel@tonic-gate * here primarily so that should sockmod be popped the resulting 543*0Sstevel@tonic-gate * file descriptor will behave like a stream w.r.t. the timestamps. 544*0Sstevel@tonic-gate */ 545*0Sstevel@tonic-gate void 546*0Sstevel@tonic-gate so_update_attrs(struct sonode *so, int flag) 547*0Sstevel@tonic-gate { 548*0Sstevel@tonic-gate time_t now = gethrestime_sec(); 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate mutex_enter(&so->so_lock); 551*0Sstevel@tonic-gate so->so_flag |= flag; 552*0Sstevel@tonic-gate if (flag & SOACC) 553*0Sstevel@tonic-gate so->so_atime = now; 554*0Sstevel@tonic-gate if (flag & SOMOD) 555*0Sstevel@tonic-gate so->so_mtime = now; 556*0Sstevel@tonic-gate mutex_exit(&so->so_lock); 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate /*ARGSUSED*/ 560*0Sstevel@tonic-gate static int 561*0Sstevel@tonic-gate socktpi_constructor(void *buf, void *cdrarg, int kmflags) 562*0Sstevel@tonic-gate { 563*0Sstevel@tonic-gate struct sonode *so = buf; 564*0Sstevel@tonic-gate struct vnode *vp; 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate so->so_nl7c_flags = 0; 567*0Sstevel@tonic-gate so->so_nl7c_uri = NULL; 568*0Sstevel@tonic-gate so->so_nl7c_rcv_mp = NULL; 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate so->so_oobmsg = NULL; 571*0Sstevel@tonic-gate so->so_ack_mp = NULL; 572*0Sstevel@tonic-gate so->so_conn_ind_head = NULL; 573*0Sstevel@tonic-gate so->so_conn_ind_tail = NULL; 574*0Sstevel@tonic-gate so->so_discon_ind_mp = NULL; 575*0Sstevel@tonic-gate so->so_ux_bound_vp = NULL; 576*0Sstevel@tonic-gate so->so_unbind_mp = NULL; 577*0Sstevel@tonic-gate so->so_accessvp = NULL; 578*0Sstevel@tonic-gate so->so_laddr_sa = NULL; 579*0Sstevel@tonic-gate so->so_faddr_sa = NULL; 580*0Sstevel@tonic-gate so->so_ops = &sotpi_sonodeops; 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP); 583*0Sstevel@tonic-gate so->so_vnode = vp; 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate vn_setops(vp, socktpi_vnodeops); 586*0Sstevel@tonic-gate vp->v_data = (caddr_t)so; 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate mutex_init(&so->so_lock, NULL, MUTEX_DEFAULT, NULL); 589*0Sstevel@tonic-gate mutex_init(&so->so_plumb_lock, NULL, MUTEX_DEFAULT, NULL); 590*0Sstevel@tonic-gate cv_init(&so->so_state_cv, NULL, CV_DEFAULT, NULL); 591*0Sstevel@tonic-gate cv_init(&so->so_ack_cv, NULL, CV_DEFAULT, NULL); 592*0Sstevel@tonic-gate cv_init(&so->so_connind_cv, NULL, CV_DEFAULT, NULL); 593*0Sstevel@tonic-gate cv_init(&so->so_want_cv, NULL, CV_DEFAULT, NULL); 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate return (0); 596*0Sstevel@tonic-gate } 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /*ARGSUSED1*/ 599*0Sstevel@tonic-gate static void 600*0Sstevel@tonic-gate socktpi_destructor(void *buf, void *cdrarg) 601*0Sstevel@tonic-gate { 602*0Sstevel@tonic-gate struct sonode *so = buf; 603*0Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate ASSERT(so->so_nl7c_flags == 0); 606*0Sstevel@tonic-gate ASSERT(so->so_nl7c_uri == NULL); 607*0Sstevel@tonic-gate ASSERT(so->so_nl7c_rcv_mp == NULL); 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 610*0Sstevel@tonic-gate ASSERT(so->so_ack_mp == NULL); 611*0Sstevel@tonic-gate ASSERT(so->so_conn_ind_head == NULL); 612*0Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 613*0Sstevel@tonic-gate ASSERT(so->so_discon_ind_mp == NULL); 614*0Sstevel@tonic-gate ASSERT(so->so_ux_bound_vp == NULL); 615*0Sstevel@tonic-gate ASSERT(so->so_unbind_mp == NULL); 616*0Sstevel@tonic-gate ASSERT(so->so_ops == &sotpi_sonodeops); 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate ASSERT(vn_matchops(vp, socktpi_vnodeops)); 619*0Sstevel@tonic-gate ASSERT(vp->v_data == (caddr_t)so); 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate vn_free(vp); 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate mutex_destroy(&so->so_lock); 624*0Sstevel@tonic-gate mutex_destroy(&so->so_plumb_lock); 625*0Sstevel@tonic-gate cv_destroy(&so->so_state_cv); 626*0Sstevel@tonic-gate cv_destroy(&so->so_ack_cv); 627*0Sstevel@tonic-gate cv_destroy(&so->so_connind_cv); 628*0Sstevel@tonic-gate cv_destroy(&so->so_want_cv); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate static int 632*0Sstevel@tonic-gate socktpi_unix_constructor(void *buf, void *cdrarg, int kmflags) 633*0Sstevel@tonic-gate { 634*0Sstevel@tonic-gate int retval; 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate if ((retval = socktpi_constructor(buf, cdrarg, kmflags)) == 0) { 637*0Sstevel@tonic-gate struct sonode *so = (struct sonode *)buf; 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate mutex_enter(&socklist.sl_lock); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate so->so_next = socklist.sl_list; 642*0Sstevel@tonic-gate so->so_prev = NULL; 643*0Sstevel@tonic-gate if (so->so_next != NULL) 644*0Sstevel@tonic-gate so->so_next->so_prev = so; 645*0Sstevel@tonic-gate socklist.sl_list = so; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate mutex_exit(&socklist.sl_lock); 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate } 650*0Sstevel@tonic-gate return (retval); 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate static void 654*0Sstevel@tonic-gate socktpi_unix_destructor(void *buf, void *cdrarg) 655*0Sstevel@tonic-gate { 656*0Sstevel@tonic-gate struct sonode *so = (struct sonode *)buf; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate mutex_enter(&socklist.sl_lock); 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate if (so->so_next != NULL) 661*0Sstevel@tonic-gate so->so_next->so_prev = so->so_prev; 662*0Sstevel@tonic-gate if (so->so_prev != NULL) 663*0Sstevel@tonic-gate so->so_prev->so_next = so->so_next; 664*0Sstevel@tonic-gate else 665*0Sstevel@tonic-gate socklist.sl_list = so->so_next; 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate mutex_exit(&socklist.sl_lock); 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate socktpi_destructor(buf, cdrarg); 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* 673*0Sstevel@tonic-gate * Init function called when sockfs is loaded. 674*0Sstevel@tonic-gate */ 675*0Sstevel@tonic-gate int 676*0Sstevel@tonic-gate sockinit(int fstype, char *name) 677*0Sstevel@tonic-gate { 678*0Sstevel@tonic-gate static const fs_operation_def_t sock_vfsops_template[] = { 679*0Sstevel@tonic-gate NULL, NULL 680*0Sstevel@tonic-gate }; 681*0Sstevel@tonic-gate int error; 682*0Sstevel@tonic-gate major_t dev; 683*0Sstevel@tonic-gate char *err_str; 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate error = vfs_setfsops(fstype, sock_vfsops_template, NULL); 686*0Sstevel@tonic-gate if (error != 0) { 687*0Sstevel@tonic-gate cmn_err(CE_WARN, "sockinit: bad vfs ops template"); 688*0Sstevel@tonic-gate return (error); 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate error = vn_make_ops(name, socktpi_vnodeops_template, &socktpi_vnodeops); 692*0Sstevel@tonic-gate if (error != 0) { 693*0Sstevel@tonic-gate err_str = "sockinit: bad sock vnode ops template"; 694*0Sstevel@tonic-gate /* vn_make_ops() does not reset socktpi_vnodeops on failure. */ 695*0Sstevel@tonic-gate socktpi_vnodeops = NULL; 696*0Sstevel@tonic-gate goto failure; 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate error = vn_make_ops("nca", socknca_vnodeops_template, 700*0Sstevel@tonic-gate &socknca_vnodeops); 701*0Sstevel@tonic-gate if (error != 0) { 702*0Sstevel@tonic-gate err_str = "sockinit: bad nca vnode ops template"; 703*0Sstevel@tonic-gate socknca_vnodeops = NULL; 704*0Sstevel@tonic-gate goto failure; 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate error = sosctp_init(); 708*0Sstevel@tonic-gate if (error != 0) { 709*0Sstevel@tonic-gate err_str = NULL; 710*0Sstevel@tonic-gate goto failure; 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate /* 714*0Sstevel@tonic-gate * Create sonode caches. We create a special one for AF_UNIX so 715*0Sstevel@tonic-gate * that we can track them for netstat(1m). 716*0Sstevel@tonic-gate */ 717*0Sstevel@tonic-gate socktpi_cache = kmem_cache_create("socktpi_cache", 718*0Sstevel@tonic-gate sizeof (struct sonode), 0, socktpi_constructor, 719*0Sstevel@tonic-gate socktpi_destructor, NULL, NULL, NULL, 0); 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate socktpi_unix_cache = kmem_cache_create("socktpi_unix_cache", 722*0Sstevel@tonic-gate sizeof (struct sonode), 0, socktpi_unix_constructor, 723*0Sstevel@tonic-gate socktpi_unix_destructor, NULL, NULL, NULL, 0); 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate /* 726*0Sstevel@tonic-gate * Build initial list mapping socket parameters to vnode. 727*0Sstevel@tonic-gate */ 728*0Sstevel@tonic-gate rw_init(&splist_lock, NULL, RW_DEFAULT, NULL); 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate /* 731*0Sstevel@tonic-gate * If sockets are needed before init runs /sbin/soconfig 732*0Sstevel@tonic-gate * it is possible to preload the sockparams list here using 733*0Sstevel@tonic-gate * calls like: 734*0Sstevel@tonic-gate * sockconfig(1,2,3, "/dev/tcp", 0); 735*0Sstevel@tonic-gate */ 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate /* 738*0Sstevel@tonic-gate * Create a unique dev_t for use in so_fsid. 739*0Sstevel@tonic-gate */ 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate if ((dev = getudev()) == (major_t)-1) 742*0Sstevel@tonic-gate dev = 0; 743*0Sstevel@tonic-gate sockdev = makedevice(dev, 0); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate mutex_init(&socklist.sl_lock, NULL, MUTEX_DEFAULT, NULL); 746*0Sstevel@tonic-gate sonca_init(); 747*0Sstevel@tonic-gate sendfile_init(); 748*0Sstevel@tonic-gate nl7c_init(); 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate return (0); 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate failure: 753*0Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 754*0Sstevel@tonic-gate if (socktpi_vnodeops != NULL) 755*0Sstevel@tonic-gate vn_freevnodeops(socktpi_vnodeops); 756*0Sstevel@tonic-gate if (socknca_vnodeops != NULL) 757*0Sstevel@tonic-gate vn_freevnodeops(socknca_vnodeops); 758*0Sstevel@tonic-gate if (err_str != NULL) 759*0Sstevel@tonic-gate cmn_err(CE_WARN, err_str); 760*0Sstevel@tonic-gate return (error); 761*0Sstevel@tonic-gate } 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate /* 764*0Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOLOCKED. 765*0Sstevel@tonic-gate */ 766*0Sstevel@tonic-gate void 767*0Sstevel@tonic-gate so_lock_single(struct sonode *so) 768*0Sstevel@tonic-gate { 769*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate while (so->so_flag & (SOLOCKED | SOASYNC_UNBIND)) { 772*0Sstevel@tonic-gate so->so_flag |= SOWANT; 773*0Sstevel@tonic-gate cv_wait_stop(&so->so_want_cv, &so->so_lock, 774*0Sstevel@tonic-gate SO_LOCK_WAKEUP_TIME); 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate so->so_flag |= SOLOCKED; 777*0Sstevel@tonic-gate } 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate /* 780*0Sstevel@tonic-gate * Caller must hold the mutex and pass in SOLOCKED or SOASYNC_UNBIND. 781*0Sstevel@tonic-gate * Used to clear SOLOCKED or SOASYNC_UNBIND. 782*0Sstevel@tonic-gate */ 783*0Sstevel@tonic-gate void 784*0Sstevel@tonic-gate so_unlock_single(struct sonode *so, int flag) 785*0Sstevel@tonic-gate { 786*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 787*0Sstevel@tonic-gate ASSERT(flag & (SOLOCKED|SOASYNC_UNBIND)); 788*0Sstevel@tonic-gate ASSERT((flag & ~(SOLOCKED|SOASYNC_UNBIND)) == 0); 789*0Sstevel@tonic-gate ASSERT(so->so_flag & flag); 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate /* 792*0Sstevel@tonic-gate * Process the T_DISCON_IND on so_discon_ind_mp. 793*0Sstevel@tonic-gate * 794*0Sstevel@tonic-gate * Call to so_drain_discon_ind will result in so_lock 795*0Sstevel@tonic-gate * being dropped and re-acquired later. 796*0Sstevel@tonic-gate */ 797*0Sstevel@tonic-gate if (so->so_discon_ind_mp != NULL) 798*0Sstevel@tonic-gate so_drain_discon_ind(so); 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate if (so->so_flag & SOWANT) 801*0Sstevel@tonic-gate cv_broadcast(&so->so_want_cv); 802*0Sstevel@tonic-gate so->so_flag &= ~(SOWANT|flag); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate /* 806*0Sstevel@tonic-gate * Caller must hold the mutex. Used to set SOREADLOCKED. 807*0Sstevel@tonic-gate * If the caller wants nonblocking behavior it should set fmode. 808*0Sstevel@tonic-gate */ 809*0Sstevel@tonic-gate int 810*0Sstevel@tonic-gate so_lock_read(struct sonode *so, int fmode) 811*0Sstevel@tonic-gate { 812*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 815*0Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 816*0Sstevel@tonic-gate return (EWOULDBLOCK); 817*0Sstevel@tonic-gate so->so_flag |= SOWANT; 818*0Sstevel@tonic-gate cv_wait_stop(&so->so_want_cv, &so->so_lock, 819*0Sstevel@tonic-gate SO_LOCK_WAKEUP_TIME); 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 822*0Sstevel@tonic-gate return (0); 823*0Sstevel@tonic-gate } 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate /* 826*0Sstevel@tonic-gate * Like so_lock_read above but allows signals. 827*0Sstevel@tonic-gate */ 828*0Sstevel@tonic-gate int 829*0Sstevel@tonic-gate so_lock_read_intr(struct sonode *so, int fmode) 830*0Sstevel@tonic-gate { 831*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate while (so->so_flag & SOREADLOCKED) { 834*0Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 835*0Sstevel@tonic-gate return (EWOULDBLOCK); 836*0Sstevel@tonic-gate so->so_flag |= SOWANT; 837*0Sstevel@tonic-gate if (!cv_wait_sig(&so->so_want_cv, &so->so_lock)) 838*0Sstevel@tonic-gate return (EINTR); 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate so->so_flag |= SOREADLOCKED; 841*0Sstevel@tonic-gate return (0); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate /* 845*0Sstevel@tonic-gate * Caller must hold the mutex. Used to clear SOREADLOCKED, 846*0Sstevel@tonic-gate * set in so_lock_read() or so_lock_read_intr(). 847*0Sstevel@tonic-gate */ 848*0Sstevel@tonic-gate void 849*0Sstevel@tonic-gate so_unlock_read(struct sonode *so) 850*0Sstevel@tonic-gate { 851*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 852*0Sstevel@tonic-gate ASSERT(so->so_flag & SOREADLOCKED); 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate if (so->so_flag & SOWANT) 855*0Sstevel@tonic-gate cv_broadcast(&so->so_want_cv); 856*0Sstevel@tonic-gate so->so_flag &= ~(SOWANT|SOREADLOCKED); 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate /* 860*0Sstevel@tonic-gate * Verify that the specified offset falls within the mblk and 861*0Sstevel@tonic-gate * that the resulting pointer is aligned. 862*0Sstevel@tonic-gate * Returns NULL if not. 863*0Sstevel@tonic-gate */ 864*0Sstevel@tonic-gate void * 865*0Sstevel@tonic-gate sogetoff(mblk_t *mp, t_uscalar_t offset, 866*0Sstevel@tonic-gate t_uscalar_t length, uint_t align_size) 867*0Sstevel@tonic-gate { 868*0Sstevel@tonic-gate uintptr_t ptr1, ptr2; 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate ASSERT(mp && mp->b_wptr >= mp->b_rptr); 871*0Sstevel@tonic-gate ptr1 = (uintptr_t)mp->b_rptr + offset; 872*0Sstevel@tonic-gate ptr2 = (uintptr_t)ptr1 + length; 873*0Sstevel@tonic-gate if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) { 874*0Sstevel@tonic-gate eprintline(0); 875*0Sstevel@tonic-gate return (NULL); 876*0Sstevel@tonic-gate } 877*0Sstevel@tonic-gate if ((ptr1 & (align_size - 1)) != 0) { 878*0Sstevel@tonic-gate eprintline(0); 879*0Sstevel@tonic-gate return (NULL); 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate return ((void *)ptr1); 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate /* 885*0Sstevel@tonic-gate * Return the AF_UNIX underlying filesystem vnode matching a given name. 886*0Sstevel@tonic-gate * Makes sure the sending and the destination sonodes are compatible. 887*0Sstevel@tonic-gate * The vnode is returned held. 888*0Sstevel@tonic-gate * 889*0Sstevel@tonic-gate * The underlying filesystem VSOCK vnode has a v_stream pointer that 890*0Sstevel@tonic-gate * references the actual stream head (hence indirectly the actual sonode). 891*0Sstevel@tonic-gate */ 892*0Sstevel@tonic-gate static int 893*0Sstevel@tonic-gate so_ux_lookup(struct sonode *so, struct sockaddr_un *soun, int checkaccess, 894*0Sstevel@tonic-gate vnode_t **vpp) 895*0Sstevel@tonic-gate { 896*0Sstevel@tonic-gate vnode_t *vp; /* Underlying filesystem vnode */ 897*0Sstevel@tonic-gate vnode_t *svp; /* sockfs vnode */ 898*0Sstevel@tonic-gate struct sonode *so2; 899*0Sstevel@tonic-gate int error; 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate dprintso(so, 1, ("so_ux_lookup(%p) name <%s>\n", 902*0Sstevel@tonic-gate so, soun->sun_path)); 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate error = lookupname(soun->sun_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 905*0Sstevel@tonic-gate if (error) { 906*0Sstevel@tonic-gate eprintsoline(so, error); 907*0Sstevel@tonic-gate return (error); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate if (vp->v_type != VSOCK) { 910*0Sstevel@tonic-gate error = ENOTSOCK; 911*0Sstevel@tonic-gate eprintsoline(so, error); 912*0Sstevel@tonic-gate goto done2; 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate if (checkaccess) { 916*0Sstevel@tonic-gate /* 917*0Sstevel@tonic-gate * Check that we have permissions to access the destination 918*0Sstevel@tonic-gate * vnode. This check is not done in BSD but it is required 919*0Sstevel@tonic-gate * by X/Open. 920*0Sstevel@tonic-gate */ 921*0Sstevel@tonic-gate if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED())) { 922*0Sstevel@tonic-gate eprintsoline(so, error); 923*0Sstevel@tonic-gate goto done2; 924*0Sstevel@tonic-gate } 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate /* 928*0Sstevel@tonic-gate * Check if the remote socket has been closed. 929*0Sstevel@tonic-gate * 930*0Sstevel@tonic-gate * Synchronize with vn_rele_stream by holding v_lock while traversing 931*0Sstevel@tonic-gate * v_stream->sd_vnode. 932*0Sstevel@tonic-gate */ 933*0Sstevel@tonic-gate mutex_enter(&vp->v_lock); 934*0Sstevel@tonic-gate if (vp->v_stream == NULL) { 935*0Sstevel@tonic-gate mutex_exit(&vp->v_lock); 936*0Sstevel@tonic-gate if (so->so_type == SOCK_DGRAM) 937*0Sstevel@tonic-gate error = EDESTADDRREQ; 938*0Sstevel@tonic-gate else 939*0Sstevel@tonic-gate error = ECONNREFUSED; 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate eprintsoline(so, error); 942*0Sstevel@tonic-gate goto done2; 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate ASSERT(vp->v_stream->sd_vnode); 945*0Sstevel@tonic-gate svp = vp->v_stream->sd_vnode; 946*0Sstevel@tonic-gate /* 947*0Sstevel@tonic-gate * holding v_lock on underlying filesystem vnode and acquiring 948*0Sstevel@tonic-gate * it on sockfs vnode. Assumes that no code ever attempts to 949*0Sstevel@tonic-gate * acquire these locks in the reverse order. 950*0Sstevel@tonic-gate */ 951*0Sstevel@tonic-gate VN_HOLD(svp); 952*0Sstevel@tonic-gate mutex_exit(&vp->v_lock); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate if (svp->v_type != VSOCK) { 955*0Sstevel@tonic-gate error = ENOTSOCK; 956*0Sstevel@tonic-gate eprintsoline(so, error); 957*0Sstevel@tonic-gate goto done; 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate so2 = VTOSO(svp); 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate if (so->so_type != so2->so_type) { 963*0Sstevel@tonic-gate error = EPROTOTYPE; 964*0Sstevel@tonic-gate eprintsoline(so, error); 965*0Sstevel@tonic-gate goto done; 966*0Sstevel@tonic-gate } 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate VN_RELE(svp); 969*0Sstevel@tonic-gate *vpp = vp; 970*0Sstevel@tonic-gate return (0); 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate done: 973*0Sstevel@tonic-gate VN_RELE(svp); 974*0Sstevel@tonic-gate done2: 975*0Sstevel@tonic-gate VN_RELE(vp); 976*0Sstevel@tonic-gate return (error); 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate /* 980*0Sstevel@tonic-gate * Verify peer address for connect and sendto/sendmsg. 981*0Sstevel@tonic-gate * Since sendto/sendmsg would not get synchronous errors from the transport 982*0Sstevel@tonic-gate * provider we have to do these ugly checks in the socket layer to 983*0Sstevel@tonic-gate * preserve compatibility with SunOS 4.X. 984*0Sstevel@tonic-gate */ 985*0Sstevel@tonic-gate int 986*0Sstevel@tonic-gate so_addr_verify(struct sonode *so, const struct sockaddr *name, 987*0Sstevel@tonic-gate socklen_t namelen) 988*0Sstevel@tonic-gate { 989*0Sstevel@tonic-gate int family; 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate dprintso(so, 1, ("so_addr_verify(%p, %p, %d)\n", so, name, namelen)); 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate ASSERT(name != NULL); 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate family = so->so_family; 996*0Sstevel@tonic-gate switch (family) { 997*0Sstevel@tonic-gate case AF_INET: 998*0Sstevel@tonic-gate if (name->sa_family != family) { 999*0Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 1000*0Sstevel@tonic-gate return (EAFNOSUPPORT); 1001*0Sstevel@tonic-gate } 1002*0Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in)) { 1003*0Sstevel@tonic-gate eprintsoline(so, EINVAL); 1004*0Sstevel@tonic-gate return (EINVAL); 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate break; 1007*0Sstevel@tonic-gate case AF_INET6: { 1008*0Sstevel@tonic-gate #ifdef DEBUG 1009*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 1010*0Sstevel@tonic-gate #endif /* DEBUG */ 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate if (name->sa_family != family) { 1013*0Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 1014*0Sstevel@tonic-gate return (EAFNOSUPPORT); 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) { 1017*0Sstevel@tonic-gate eprintsoline(so, EINVAL); 1018*0Sstevel@tonic-gate return (EINVAL); 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate #ifdef DEBUG 1021*0Sstevel@tonic-gate /* Verify that apps don't forget to clear sin6_scope_id etc */ 1022*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)name; 1023*0Sstevel@tonic-gate if (sin6->sin6_scope_id != 0 && 1024*0Sstevel@tonic-gate !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 1025*0Sstevel@tonic-gate cmn_err(CE_WARN, 1026*0Sstevel@tonic-gate "connect/send* with uninitialized sin6_scope_id " 1027*0Sstevel@tonic-gate "(%d) on socket. Pid = %d\n", 1028*0Sstevel@tonic-gate (int)sin6->sin6_scope_id, (int)curproc->p_pid); 1029*0Sstevel@tonic-gate } 1030*0Sstevel@tonic-gate #endif /* DEBUG */ 1031*0Sstevel@tonic-gate break; 1032*0Sstevel@tonic-gate } 1033*0Sstevel@tonic-gate case AF_UNIX: 1034*0Sstevel@tonic-gate if (so->so_state & SS_FADDR_NOXLATE) { 1035*0Sstevel@tonic-gate return (0); 1036*0Sstevel@tonic-gate } 1037*0Sstevel@tonic-gate if (namelen < (socklen_t)sizeof (short)) { 1038*0Sstevel@tonic-gate eprintsoline(so, ENOENT); 1039*0Sstevel@tonic-gate return (ENOENT); 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate if (name->sa_family != family) { 1042*0Sstevel@tonic-gate eprintsoline(so, EAFNOSUPPORT); 1043*0Sstevel@tonic-gate return (EAFNOSUPPORT); 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 1046*0Sstevel@tonic-gate if (namelen > (socklen_t)(MAXPATHLEN + sizeof (short) + 1)) { 1047*0Sstevel@tonic-gate eprintsoline(so, ENAMETOOLONG); 1048*0Sstevel@tonic-gate return (ENAMETOOLONG); 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate break; 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate default: 1054*0Sstevel@tonic-gate /* 1055*0Sstevel@tonic-gate * Default is don't do any length or sa_family check 1056*0Sstevel@tonic-gate * to allow non-sockaddr style addresses. 1057*0Sstevel@tonic-gate */ 1058*0Sstevel@tonic-gate break; 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate return (0); 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate 1065*0Sstevel@tonic-gate /* 1066*0Sstevel@tonic-gate * Translate an AF_UNIX sockaddr_un to the transport internal name. 1067*0Sstevel@tonic-gate * Assumes caller has called so_addr_verify first. 1068*0Sstevel@tonic-gate */ 1069*0Sstevel@tonic-gate /*ARGSUSED*/ 1070*0Sstevel@tonic-gate int 1071*0Sstevel@tonic-gate so_ux_addr_xlate(struct sonode *so, struct sockaddr *name, 1072*0Sstevel@tonic-gate socklen_t namelen, int checkaccess, 1073*0Sstevel@tonic-gate void **addrp, socklen_t *addrlenp) 1074*0Sstevel@tonic-gate { 1075*0Sstevel@tonic-gate int error; 1076*0Sstevel@tonic-gate struct sockaddr_un *soun; 1077*0Sstevel@tonic-gate vnode_t *vp; 1078*0Sstevel@tonic-gate void *addr; 1079*0Sstevel@tonic-gate socklen_t addrlen; 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate dprintso(so, 1, ("so_ux_addr_xlate(%p, %p, %d, %d)\n", 1082*0Sstevel@tonic-gate so, name, namelen, checkaccess)); 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate ASSERT(name != NULL); 1085*0Sstevel@tonic-gate ASSERT(so->so_family == AF_UNIX); 1086*0Sstevel@tonic-gate ASSERT(!(so->so_state & SS_FADDR_NOXLATE)); 1087*0Sstevel@tonic-gate ASSERT(namelen >= (socklen_t)sizeof (short)); 1088*0Sstevel@tonic-gate ASSERT(name->sa_family == AF_UNIX); 1089*0Sstevel@tonic-gate soun = (struct sockaddr_un *)name; 1090*0Sstevel@tonic-gate /* 1091*0Sstevel@tonic-gate * Lookup vnode for the specified path name and verify that 1092*0Sstevel@tonic-gate * it is a socket. 1093*0Sstevel@tonic-gate */ 1094*0Sstevel@tonic-gate error = so_ux_lookup(so, soun, checkaccess, &vp); 1095*0Sstevel@tonic-gate if (error) { 1096*0Sstevel@tonic-gate eprintsoline(so, error); 1097*0Sstevel@tonic-gate return (error); 1098*0Sstevel@tonic-gate } 1099*0Sstevel@tonic-gate /* 1100*0Sstevel@tonic-gate * Use the address of the peer vnode as the address to send 1101*0Sstevel@tonic-gate * to. We release the peer vnode here. In case it has been 1102*0Sstevel@tonic-gate * closed by the time the T_CONN_REQ or T_UNIDATA_REQ reaches the 1103*0Sstevel@tonic-gate * transport the message will get an error or be dropped. 1104*0Sstevel@tonic-gate */ 1105*0Sstevel@tonic-gate so->so_ux_faddr.soua_vp = vp; 1106*0Sstevel@tonic-gate so->so_ux_faddr.soua_magic = SOU_MAGIC_EXPLICIT; 1107*0Sstevel@tonic-gate addr = &so->so_ux_faddr; 1108*0Sstevel@tonic-gate addrlen = (socklen_t)sizeof (so->so_ux_faddr); 1109*0Sstevel@tonic-gate dprintso(so, 1, ("ux_xlate UNIX: addrlen %d, vp %p\n", 1110*0Sstevel@tonic-gate addrlen, vp)); 1111*0Sstevel@tonic-gate VN_RELE(vp); 1112*0Sstevel@tonic-gate *addrp = addr; 1113*0Sstevel@tonic-gate *addrlenp = (socklen_t)addrlen; 1114*0Sstevel@tonic-gate return (0); 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate /* 1118*0Sstevel@tonic-gate * Esballoc free function for messages that contain SO_FILEP option. 1119*0Sstevel@tonic-gate * Decrement the reference count on the file pointers using closef. 1120*0Sstevel@tonic-gate */ 1121*0Sstevel@tonic-gate void 1122*0Sstevel@tonic-gate fdbuf_free(struct fdbuf *fdbuf) 1123*0Sstevel@tonic-gate { 1124*0Sstevel@tonic-gate int i; 1125*0Sstevel@tonic-gate struct file *fp; 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate dprint(1, ("fdbuf_free: %d fds\n", fdbuf->fd_numfd)); 1128*0Sstevel@tonic-gate for (i = 0; i < fdbuf->fd_numfd; i++) { 1129*0Sstevel@tonic-gate /* 1130*0Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 1131*0Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 1132*0Sstevel@tonic-gate * the option headers and values are only 4 bytes 1133*0Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 1134*0Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 1135*0Sstevel@tonic-gate */ 1136*0Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 1137*0Sstevel@tonic-gate dprint(1, ("fdbuf_free: [%d] = %p\n", i, fp)); 1138*0Sstevel@tonic-gate (void) closef(fp); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate if (fdbuf->fd_ebuf != NULL) 1141*0Sstevel@tonic-gate kmem_free(fdbuf->fd_ebuf, fdbuf->fd_ebuflen); 1142*0Sstevel@tonic-gate kmem_free(fdbuf, fdbuf->fd_size); 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * Allocate an esballoc'ed message for use for AF_UNIX file descriptor 1147*0Sstevel@tonic-gate * passing. Sleep waiting for memory unless catching a signal in strwaitbuf. 1148*0Sstevel@tonic-gate */ 1149*0Sstevel@tonic-gate mblk_t * 1150*0Sstevel@tonic-gate fdbuf_allocmsg(int size, struct fdbuf *fdbuf) 1151*0Sstevel@tonic-gate { 1152*0Sstevel@tonic-gate void *buf; 1153*0Sstevel@tonic-gate mblk_t *mp; 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate dprint(1, ("fdbuf_allocmsg: size %d, %d fds\n", size, fdbuf->fd_numfd)); 1156*0Sstevel@tonic-gate buf = kmem_alloc(size, KM_SLEEP); 1157*0Sstevel@tonic-gate fdbuf->fd_ebuf = (caddr_t)buf; 1158*0Sstevel@tonic-gate fdbuf->fd_ebuflen = size; 1159*0Sstevel@tonic-gate fdbuf->fd_frtn.free_func = fdbuf_free; 1160*0Sstevel@tonic-gate fdbuf->fd_frtn.free_arg = (caddr_t)fdbuf; 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate while ((mp = esballoc((unsigned char *)buf, size, BPRI_MED, 1163*0Sstevel@tonic-gate &fdbuf->fd_frtn)) == NULL) { 1164*0Sstevel@tonic-gate if (strwaitbuf(sizeof (mblk_t), BPRI_MED) != 0) { 1165*0Sstevel@tonic-gate /* 1166*0Sstevel@tonic-gate * Got EINTR - pass out NULL. Caller will 1167*0Sstevel@tonic-gate * return something like ENOBUFS. 1168*0Sstevel@tonic-gate * XXX could use an esballoc_wait() type function. 1169*0Sstevel@tonic-gate */ 1170*0Sstevel@tonic-gate eprintline(ENOBUFS); 1171*0Sstevel@tonic-gate return (NULL); 1172*0Sstevel@tonic-gate } 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate if (mp == NULL) 1175*0Sstevel@tonic-gate return (NULL); 1176*0Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 1177*0Sstevel@tonic-gate return (mp); 1178*0Sstevel@tonic-gate } 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate /* 1181*0Sstevel@tonic-gate * Extract file descriptors from a fdbuf. 1182*0Sstevel@tonic-gate * Return list in rights/rightslen. 1183*0Sstevel@tonic-gate */ 1184*0Sstevel@tonic-gate /*ARGSUSED*/ 1185*0Sstevel@tonic-gate static int 1186*0Sstevel@tonic-gate fdbuf_extract(struct fdbuf *fdbuf, void *rights, int rightslen) 1187*0Sstevel@tonic-gate { 1188*0Sstevel@tonic-gate int i, fd; 1189*0Sstevel@tonic-gate int *rp; 1190*0Sstevel@tonic-gate struct file *fp; 1191*0Sstevel@tonic-gate int numfd; 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate dprint(1, ("fdbuf_extract: %d fds, len %d\n", 1194*0Sstevel@tonic-gate fdbuf->fd_numfd, rightslen)); 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate numfd = fdbuf->fd_numfd; 1197*0Sstevel@tonic-gate ASSERT(rightslen == numfd * (int)sizeof (int)); 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate /* 1200*0Sstevel@tonic-gate * Allocate a file descriptor and increment the f_count. 1201*0Sstevel@tonic-gate * The latter is needed since we always call fdbuf_free 1202*0Sstevel@tonic-gate * which performs a closef. 1203*0Sstevel@tonic-gate */ 1204*0Sstevel@tonic-gate rp = (int *)rights; 1205*0Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 1206*0Sstevel@tonic-gate if ((fd = ufalloc(0)) == -1) 1207*0Sstevel@tonic-gate goto cleanup; 1208*0Sstevel@tonic-gate /* 1209*0Sstevel@tonic-gate * We need pointer size alignment for fd_fds. On a LP64 1210*0Sstevel@tonic-gate * kernel, the required alignment is 8 bytes while 1211*0Sstevel@tonic-gate * the option headers and values are only 4 bytes 1212*0Sstevel@tonic-gate * aligned. So its safer to do a bcopy compared to 1213*0Sstevel@tonic-gate * assigning fdbuf->fd_fds[i] to fp. 1214*0Sstevel@tonic-gate */ 1215*0Sstevel@tonic-gate bcopy((char *)&fdbuf->fd_fds[i], (char *)&fp, sizeof (fp)); 1216*0Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 1217*0Sstevel@tonic-gate fp->f_count++; 1218*0Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 1219*0Sstevel@tonic-gate setf(fd, fp); 1220*0Sstevel@tonic-gate *rp++ = fd; 1221*0Sstevel@tonic-gate #ifdef C2_AUDIT 1222*0Sstevel@tonic-gate if (audit_active) 1223*0Sstevel@tonic-gate audit_fdrecv(fd, fp); 1224*0Sstevel@tonic-gate #endif 1225*0Sstevel@tonic-gate dprint(1, ("fdbuf_extract: [%d] = %d, %p refcnt %d\n", 1226*0Sstevel@tonic-gate i, fd, fp, fp->f_count)); 1227*0Sstevel@tonic-gate } 1228*0Sstevel@tonic-gate return (0); 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate cleanup: 1231*0Sstevel@tonic-gate /* 1232*0Sstevel@tonic-gate * Undo whatever partial work the loop above has done. 1233*0Sstevel@tonic-gate */ 1234*0Sstevel@tonic-gate { 1235*0Sstevel@tonic-gate int j; 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate rp = (int *)rights; 1238*0Sstevel@tonic-gate for (j = 0; j < i; j++) { 1239*0Sstevel@tonic-gate dprint(0, 1240*0Sstevel@tonic-gate ("fdbuf_extract: cleanup[%d] = %d\n", j, *rp)); 1241*0Sstevel@tonic-gate (void) closeandsetf(*rp++, NULL); 1242*0Sstevel@tonic-gate } 1243*0Sstevel@tonic-gate } 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate return (EMFILE); 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate /* 1249*0Sstevel@tonic-gate * Insert file descriptors into an fdbuf. 1250*0Sstevel@tonic-gate * Returns a kmem_alloc'ed fdbuf. The fdbuf should be freed 1251*0Sstevel@tonic-gate * by calling fdbuf_free(). 1252*0Sstevel@tonic-gate */ 1253*0Sstevel@tonic-gate int 1254*0Sstevel@tonic-gate fdbuf_create(void *rights, int rightslen, struct fdbuf **fdbufp) 1255*0Sstevel@tonic-gate { 1256*0Sstevel@tonic-gate int numfd, i; 1257*0Sstevel@tonic-gate int *fds; 1258*0Sstevel@tonic-gate struct file *fp; 1259*0Sstevel@tonic-gate struct fdbuf *fdbuf; 1260*0Sstevel@tonic-gate int fdbufsize; 1261*0Sstevel@tonic-gate 1262*0Sstevel@tonic-gate dprint(1, ("fdbuf_create: len %d\n", rightslen)); 1263*0Sstevel@tonic-gate 1264*0Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate fdbufsize = (int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *)); 1267*0Sstevel@tonic-gate fdbuf = kmem_alloc(fdbufsize, KM_SLEEP); 1268*0Sstevel@tonic-gate fdbuf->fd_size = fdbufsize; 1269*0Sstevel@tonic-gate fdbuf->fd_numfd = 0; 1270*0Sstevel@tonic-gate fdbuf->fd_ebuf = NULL; 1271*0Sstevel@tonic-gate fdbuf->fd_ebuflen = 0; 1272*0Sstevel@tonic-gate fds = (int *)rights; 1273*0Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 1274*0Sstevel@tonic-gate if ((fp = getf(fds[i])) == NULL) { 1275*0Sstevel@tonic-gate fdbuf_free(fdbuf); 1276*0Sstevel@tonic-gate return (EBADF); 1277*0Sstevel@tonic-gate } 1278*0Sstevel@tonic-gate dprint(1, ("fdbuf_create: [%d] = %d, %p refcnt %d\n", 1279*0Sstevel@tonic-gate i, fds[i], fp, fp->f_count)); 1280*0Sstevel@tonic-gate mutex_enter(&fp->f_tlock); 1281*0Sstevel@tonic-gate fp->f_count++; 1282*0Sstevel@tonic-gate mutex_exit(&fp->f_tlock); 1283*0Sstevel@tonic-gate /* 1284*0Sstevel@tonic-gate * The maximum alignment for fdbuf (or any option header 1285*0Sstevel@tonic-gate * and its value) it 4 bytes. On a LP64 kernel, the alignment 1286*0Sstevel@tonic-gate * is not sufficient for pointers (fd_fds in this case). Since 1287*0Sstevel@tonic-gate * we just did a kmem_alloc (we get a double word alignment), 1288*0Sstevel@tonic-gate * we don't need to do anything on the send side (we loose 1289*0Sstevel@tonic-gate * the double word alignment because fdbuf goes after an 1290*0Sstevel@tonic-gate * option header (eg T_unitdata_req) which is only 4 byte 1291*0Sstevel@tonic-gate * aligned). We take care of this when we extract the file 1292*0Sstevel@tonic-gate * descriptor in fdbuf_extract or fdbuf_free. 1293*0Sstevel@tonic-gate */ 1294*0Sstevel@tonic-gate fdbuf->fd_fds[i] = fp; 1295*0Sstevel@tonic-gate fdbuf->fd_numfd++; 1296*0Sstevel@tonic-gate releasef(fds[i]); 1297*0Sstevel@tonic-gate #ifdef C2_AUDIT 1298*0Sstevel@tonic-gate if (audit_active) 1299*0Sstevel@tonic-gate audit_fdsend(fds[i], fp, 0); 1300*0Sstevel@tonic-gate #endif 1301*0Sstevel@tonic-gate } 1302*0Sstevel@tonic-gate *fdbufp = fdbuf; 1303*0Sstevel@tonic-gate return (0); 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate static int 1307*0Sstevel@tonic-gate fdbuf_optlen(int rightslen) 1308*0Sstevel@tonic-gate { 1309*0Sstevel@tonic-gate int numfd; 1310*0Sstevel@tonic-gate 1311*0Sstevel@tonic-gate numfd = rightslen / (int)sizeof (int); 1312*0Sstevel@tonic-gate 1313*0Sstevel@tonic-gate return ((int)FDBUF_HDRSIZE + (numfd * (int)sizeof (struct file *))); 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate static t_uscalar_t 1317*0Sstevel@tonic-gate fdbuf_cmsglen(int fdbuflen) 1318*0Sstevel@tonic-gate { 1319*0Sstevel@tonic-gate return (t_uscalar_t)((fdbuflen - FDBUF_HDRSIZE) / 1320*0Sstevel@tonic-gate (int)sizeof (struct file *) * (int)sizeof (int)); 1321*0Sstevel@tonic-gate } 1322*0Sstevel@tonic-gate 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate /* 1325*0Sstevel@tonic-gate * Return non-zero if the mblk and fdbuf are consistent. 1326*0Sstevel@tonic-gate */ 1327*0Sstevel@tonic-gate static int 1328*0Sstevel@tonic-gate fdbuf_verify(mblk_t *mp, struct fdbuf *fdbuf, int fdbuflen) 1329*0Sstevel@tonic-gate { 1330*0Sstevel@tonic-gate if (fdbuflen >= FDBUF_HDRSIZE && 1331*0Sstevel@tonic-gate fdbuflen == fdbuf->fd_size) { 1332*0Sstevel@tonic-gate frtn_t *frp = mp->b_datap->db_frtnp; 1333*0Sstevel@tonic-gate /* 1334*0Sstevel@tonic-gate * Check that the SO_FILEP portion of the 1335*0Sstevel@tonic-gate * message has not been modified by 1336*0Sstevel@tonic-gate * the loopback transport. The sending sockfs generates 1337*0Sstevel@tonic-gate * a message that is esballoc'ed with the free function 1338*0Sstevel@tonic-gate * being fdbuf_free() and where free_arg contains the 1339*0Sstevel@tonic-gate * identical information as the SO_FILEP content. 1340*0Sstevel@tonic-gate * 1341*0Sstevel@tonic-gate * If any of these constraints are not satisfied we 1342*0Sstevel@tonic-gate * silently ignore the option. 1343*0Sstevel@tonic-gate */ 1344*0Sstevel@tonic-gate ASSERT(mp); 1345*0Sstevel@tonic-gate if (frp != NULL && 1346*0Sstevel@tonic-gate frp->free_func == fdbuf_free && 1347*0Sstevel@tonic-gate frp->free_arg != NULL && 1348*0Sstevel@tonic-gate bcmp(frp->free_arg, fdbuf, fdbuflen) == 0) { 1349*0Sstevel@tonic-gate dprint(1, ("fdbuf_verify: fdbuf %p len %d\n", 1350*0Sstevel@tonic-gate fdbuf, fdbuflen)); 1351*0Sstevel@tonic-gate return (1); 1352*0Sstevel@tonic-gate } else { 1353*0Sstevel@tonic-gate cmn_err(CE_WARN, 1354*0Sstevel@tonic-gate "sockfs: mismatched fdbuf content (%p)", 1355*0Sstevel@tonic-gate (void *)mp); 1356*0Sstevel@tonic-gate return (0); 1357*0Sstevel@tonic-gate } 1358*0Sstevel@tonic-gate } else { 1359*0Sstevel@tonic-gate cmn_err(CE_WARN, 1360*0Sstevel@tonic-gate "sockfs: mismatched fdbuf len %d, %d\n", 1361*0Sstevel@tonic-gate fdbuflen, fdbuf->fd_size); 1362*0Sstevel@tonic-gate return (0); 1363*0Sstevel@tonic-gate } 1364*0Sstevel@tonic-gate } 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate /* 1367*0Sstevel@tonic-gate * When the file descriptors returned by sorecvmsg can not be passed 1368*0Sstevel@tonic-gate * to the application this routine will cleanup the references on 1369*0Sstevel@tonic-gate * the files. Start at startoff bytes into the buffer. 1370*0Sstevel@tonic-gate */ 1371*0Sstevel@tonic-gate static void 1372*0Sstevel@tonic-gate close_fds(void *fdbuf, int fdbuflen, int startoff) 1373*0Sstevel@tonic-gate { 1374*0Sstevel@tonic-gate int *fds = (int *)fdbuf; 1375*0Sstevel@tonic-gate int numfd = fdbuflen / (int)sizeof (int); 1376*0Sstevel@tonic-gate int i; 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate dprint(1, ("close_fds(%p, %d, %d)\n", fdbuf, fdbuflen, startoff)); 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate for (i = 0; i < numfd; i++) { 1381*0Sstevel@tonic-gate if (startoff < 0) 1382*0Sstevel@tonic-gate startoff = 0; 1383*0Sstevel@tonic-gate if (startoff < (int)sizeof (int)) { 1384*0Sstevel@tonic-gate /* 1385*0Sstevel@tonic-gate * This file descriptor is partially or fully after 1386*0Sstevel@tonic-gate * the offset 1387*0Sstevel@tonic-gate */ 1388*0Sstevel@tonic-gate dprint(0, 1389*0Sstevel@tonic-gate ("close_fds: cleanup[%d] = %d\n", i, fds[i])); 1390*0Sstevel@tonic-gate (void) closeandsetf(fds[i], NULL); 1391*0Sstevel@tonic-gate } 1392*0Sstevel@tonic-gate startoff -= (int)sizeof (int); 1393*0Sstevel@tonic-gate } 1394*0Sstevel@tonic-gate } 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate /* 1397*0Sstevel@tonic-gate * Close all file descriptors contained in the control part starting at 1398*0Sstevel@tonic-gate * the startoffset. 1399*0Sstevel@tonic-gate */ 1400*0Sstevel@tonic-gate void 1401*0Sstevel@tonic-gate so_closefds(void *control, t_uscalar_t controllen, int oldflg, 1402*0Sstevel@tonic-gate int startoff) 1403*0Sstevel@tonic-gate { 1404*0Sstevel@tonic-gate struct cmsghdr *cmsg; 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate if (control == NULL) 1407*0Sstevel@tonic-gate return; 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate if (oldflg) { 1410*0Sstevel@tonic-gate close_fds(control, controllen, startoff); 1411*0Sstevel@tonic-gate return; 1412*0Sstevel@tonic-gate } 1413*0Sstevel@tonic-gate /* Scan control part for file descriptors. */ 1414*0Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 1415*0Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 1416*0Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 1417*0Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 1418*0Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 1419*0Sstevel@tonic-gate close_fds(CMSG_CONTENT(cmsg), 1420*0Sstevel@tonic-gate (int)CMSG_CONTENTLEN(cmsg), 1421*0Sstevel@tonic-gate startoff - (int)sizeof (struct cmsghdr)); 1422*0Sstevel@tonic-gate } 1423*0Sstevel@tonic-gate startoff -= cmsg->cmsg_len; 1424*0Sstevel@tonic-gate } 1425*0Sstevel@tonic-gate } 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate /* 1428*0Sstevel@tonic-gate * Returns a pointer/length for the file descriptors contained 1429*0Sstevel@tonic-gate * in the control buffer. Returns with *fdlenp == -1 if there are no 1430*0Sstevel@tonic-gate * file descriptor options present. This is different than there being 1431*0Sstevel@tonic-gate * a zero-length file descriptor option. 1432*0Sstevel@tonic-gate * Fail if there are multiple SCM_RIGHT cmsgs. 1433*0Sstevel@tonic-gate */ 1434*0Sstevel@tonic-gate int 1435*0Sstevel@tonic-gate so_getfdopt(void *control, t_uscalar_t controllen, int oldflg, 1436*0Sstevel@tonic-gate void **fdsp, int *fdlenp) 1437*0Sstevel@tonic-gate { 1438*0Sstevel@tonic-gate struct cmsghdr *cmsg; 1439*0Sstevel@tonic-gate void *fds; 1440*0Sstevel@tonic-gate int fdlen; 1441*0Sstevel@tonic-gate 1442*0Sstevel@tonic-gate if (control == NULL) { 1443*0Sstevel@tonic-gate *fdsp = NULL; 1444*0Sstevel@tonic-gate *fdlenp = -1; 1445*0Sstevel@tonic-gate return (0); 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate if (oldflg) { 1449*0Sstevel@tonic-gate *fdsp = control; 1450*0Sstevel@tonic-gate if (controllen == 0) 1451*0Sstevel@tonic-gate *fdlenp = -1; 1452*0Sstevel@tonic-gate else 1453*0Sstevel@tonic-gate *fdlenp = controllen; 1454*0Sstevel@tonic-gate dprint(1, ("so_getfdopt: old %d\n", *fdlenp)); 1455*0Sstevel@tonic-gate return (0); 1456*0Sstevel@tonic-gate } 1457*0Sstevel@tonic-gate 1458*0Sstevel@tonic-gate fds = NULL; 1459*0Sstevel@tonic-gate fdlen = 0; 1460*0Sstevel@tonic-gate 1461*0Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 1462*0Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 1463*0Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 1464*0Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 1465*0Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 1466*0Sstevel@tonic-gate if (fds != NULL) 1467*0Sstevel@tonic-gate return (EINVAL); 1468*0Sstevel@tonic-gate fds = CMSG_CONTENT(cmsg); 1469*0Sstevel@tonic-gate fdlen = (int)CMSG_CONTENTLEN(cmsg); 1470*0Sstevel@tonic-gate dprint(1, ("so_getfdopt: new %ld\n", 1471*0Sstevel@tonic-gate CMSG_CONTENTLEN(cmsg))); 1472*0Sstevel@tonic-gate } 1473*0Sstevel@tonic-gate } 1474*0Sstevel@tonic-gate if (fds == NULL) { 1475*0Sstevel@tonic-gate dprint(1, ("so_getfdopt: NONE\n")); 1476*0Sstevel@tonic-gate *fdlenp = -1; 1477*0Sstevel@tonic-gate } else 1478*0Sstevel@tonic-gate *fdlenp = fdlen; 1479*0Sstevel@tonic-gate *fdsp = fds; 1480*0Sstevel@tonic-gate return (0); 1481*0Sstevel@tonic-gate } 1482*0Sstevel@tonic-gate 1483*0Sstevel@tonic-gate /* 1484*0Sstevel@tonic-gate * Return the length of the options including any file descriptor options. 1485*0Sstevel@tonic-gate */ 1486*0Sstevel@tonic-gate t_uscalar_t 1487*0Sstevel@tonic-gate so_optlen(void *control, t_uscalar_t controllen, int oldflg) 1488*0Sstevel@tonic-gate { 1489*0Sstevel@tonic-gate struct cmsghdr *cmsg; 1490*0Sstevel@tonic-gate t_uscalar_t optlen = 0; 1491*0Sstevel@tonic-gate t_uscalar_t len; 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate if (control == NULL) 1494*0Sstevel@tonic-gate return (0); 1495*0Sstevel@tonic-gate 1496*0Sstevel@tonic-gate if (oldflg) 1497*0Sstevel@tonic-gate return ((t_uscalar_t)(sizeof (struct T_opthdr) + 1498*0Sstevel@tonic-gate fdbuf_optlen(controllen))); 1499*0Sstevel@tonic-gate 1500*0Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 1501*0Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 1502*0Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 1503*0Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 1504*0Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) { 1505*0Sstevel@tonic-gate len = fdbuf_optlen((int)CMSG_CONTENTLEN(cmsg)); 1506*0Sstevel@tonic-gate } else { 1507*0Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 1508*0Sstevel@tonic-gate } 1509*0Sstevel@tonic-gate optlen += (t_uscalar_t)(_TPI_ALIGN_TOPT(len) + 1510*0Sstevel@tonic-gate sizeof (struct T_opthdr)); 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate dprint(1, ("so_optlen: controllen %d, flg %d -> optlen %d\n", 1513*0Sstevel@tonic-gate controllen, oldflg, optlen)); 1514*0Sstevel@tonic-gate return (optlen); 1515*0Sstevel@tonic-gate } 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate /* 1518*0Sstevel@tonic-gate * Copy options from control to the mblk. Skip any file descriptor options. 1519*0Sstevel@tonic-gate */ 1520*0Sstevel@tonic-gate void 1521*0Sstevel@tonic-gate so_cmsg2opt(void *control, t_uscalar_t controllen, int oldflg, mblk_t *mp) 1522*0Sstevel@tonic-gate { 1523*0Sstevel@tonic-gate struct T_opthdr toh; 1524*0Sstevel@tonic-gate struct cmsghdr *cmsg; 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gate if (control == NULL) 1527*0Sstevel@tonic-gate return; 1528*0Sstevel@tonic-gate 1529*0Sstevel@tonic-gate if (oldflg) { 1530*0Sstevel@tonic-gate /* No real options - caller has handled file descriptors */ 1531*0Sstevel@tonic-gate return; 1532*0Sstevel@tonic-gate } 1533*0Sstevel@tonic-gate for (cmsg = (struct cmsghdr *)control; 1534*0Sstevel@tonic-gate CMSG_VALID(cmsg, control, (uintptr_t)control + controllen); 1535*0Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg)) { 1536*0Sstevel@tonic-gate /* 1537*0Sstevel@tonic-gate * Note: The caller handles file descriptors prior 1538*0Sstevel@tonic-gate * to calling this function. 1539*0Sstevel@tonic-gate */ 1540*0Sstevel@tonic-gate t_uscalar_t len; 1541*0Sstevel@tonic-gate 1542*0Sstevel@tonic-gate if (cmsg->cmsg_level == SOL_SOCKET && 1543*0Sstevel@tonic-gate cmsg->cmsg_type == SCM_RIGHTS) 1544*0Sstevel@tonic-gate continue; 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg); 1547*0Sstevel@tonic-gate toh.level = cmsg->cmsg_level; 1548*0Sstevel@tonic-gate toh.name = cmsg->cmsg_type; 1549*0Sstevel@tonic-gate toh.len = len + (t_uscalar_t)sizeof (struct T_opthdr); 1550*0Sstevel@tonic-gate toh.status = 0; 1551*0Sstevel@tonic-gate 1552*0Sstevel@tonic-gate soappendmsg(mp, &toh, sizeof (toh)); 1553*0Sstevel@tonic-gate soappendmsg(mp, CMSG_CONTENT(cmsg), len); 1554*0Sstevel@tonic-gate mp->b_wptr += _TPI_ALIGN_TOPT(len) - len; 1555*0Sstevel@tonic-gate ASSERT(mp->b_wptr <= mp->b_datap->db_lim); 1556*0Sstevel@tonic-gate } 1557*0Sstevel@tonic-gate } 1558*0Sstevel@tonic-gate 1559*0Sstevel@tonic-gate /* 1560*0Sstevel@tonic-gate * Return the length of the control message derived from the options. 1561*0Sstevel@tonic-gate * Exclude SO_SRCADDR and SO_UNIX_CLOSE options. Include SO_FILEP. 1562*0Sstevel@tonic-gate * When oldflg is set only include SO_FILEP. 1563*0Sstevel@tonic-gate */ 1564*0Sstevel@tonic-gate t_uscalar_t 1565*0Sstevel@tonic-gate so_cmsglen(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg) 1566*0Sstevel@tonic-gate { 1567*0Sstevel@tonic-gate t_uscalar_t cmsglen = 0; 1568*0Sstevel@tonic-gate struct T_opthdr *tohp; 1569*0Sstevel@tonic-gate t_uscalar_t len; 1570*0Sstevel@tonic-gate t_uscalar_t last_roundup = 0; 1571*0Sstevel@tonic-gate 1572*0Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 1573*0Sstevel@tonic-gate 1574*0Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 1575*0Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 1576*0Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 1577*0Sstevel@tonic-gate dprint(1, ("so_cmsglen: level 0x%x, name %d, len %d\n", 1578*0Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 1579*0Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 1580*0Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 1581*0Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 1582*0Sstevel@tonic-gate continue; 1583*0Sstevel@tonic-gate } 1584*0Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 1585*0Sstevel@tonic-gate struct fdbuf *fdbuf; 1586*0Sstevel@tonic-gate int fdbuflen; 1587*0Sstevel@tonic-gate 1588*0Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 1589*0Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 1592*0Sstevel@tonic-gate continue; 1593*0Sstevel@tonic-gate if (oldflg) { 1594*0Sstevel@tonic-gate cmsglen += fdbuf_cmsglen(fdbuflen); 1595*0Sstevel@tonic-gate continue; 1596*0Sstevel@tonic-gate } 1597*0Sstevel@tonic-gate len = fdbuf_cmsglen(fdbuflen); 1598*0Sstevel@tonic-gate } else { 1599*0Sstevel@tonic-gate if (oldflg) 1600*0Sstevel@tonic-gate continue; 1601*0Sstevel@tonic-gate len = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 1602*0Sstevel@tonic-gate } 1603*0Sstevel@tonic-gate /* 1604*0Sstevel@tonic-gate * Exlucde roundup for last option to not set 1605*0Sstevel@tonic-gate * MSG_CTRUNC when the cmsg fits but the padding doesn't fit. 1606*0Sstevel@tonic-gate */ 1607*0Sstevel@tonic-gate last_roundup = (t_uscalar_t) 1608*0Sstevel@tonic-gate (ROUNDUP_cmsglen(len + (int)sizeof (struct cmsghdr)) - 1609*0Sstevel@tonic-gate (len + (int)sizeof (struct cmsghdr))); 1610*0Sstevel@tonic-gate cmsglen += (t_uscalar_t)(len + (int)sizeof (struct cmsghdr)) + 1611*0Sstevel@tonic-gate last_roundup; 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate cmsglen -= last_roundup; 1614*0Sstevel@tonic-gate dprint(1, ("so_cmsglen: optlen %d, flg %d -> cmsglen %d\n", 1615*0Sstevel@tonic-gate optlen, oldflg, cmsglen)); 1616*0Sstevel@tonic-gate return (cmsglen); 1617*0Sstevel@tonic-gate } 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate /* 1620*0Sstevel@tonic-gate * Copy options from options to the control. Convert SO_FILEP to 1621*0Sstevel@tonic-gate * file descriptors. 1622*0Sstevel@tonic-gate * Returns errno or zero. 1623*0Sstevel@tonic-gate */ 1624*0Sstevel@tonic-gate int 1625*0Sstevel@tonic-gate so_opt2cmsg(mblk_t *mp, void *opt, t_uscalar_t optlen, int oldflg, 1626*0Sstevel@tonic-gate void *control, t_uscalar_t controllen) 1627*0Sstevel@tonic-gate { 1628*0Sstevel@tonic-gate struct T_opthdr *tohp; 1629*0Sstevel@tonic-gate struct cmsghdr *cmsg; 1630*0Sstevel@tonic-gate struct fdbuf *fdbuf; 1631*0Sstevel@tonic-gate int fdbuflen; 1632*0Sstevel@tonic-gate int error; 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate cmsg = (struct cmsghdr *)control; 1635*0Sstevel@tonic-gate 1636*0Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 1637*0Sstevel@tonic-gate 1638*0Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 1639*0Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 1640*0Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 1641*0Sstevel@tonic-gate dprint(1, ("so_opt2cmsg: level 0x%x, name %d, len %d\n", 1642*0Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 1645*0Sstevel@tonic-gate (tohp->name == SO_SRCADDR || 1646*0Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE)) { 1647*0Sstevel@tonic-gate continue; 1648*0Sstevel@tonic-gate } 1649*0Sstevel@tonic-gate ASSERT((uintptr_t)cmsg <= (uintptr_t)control + controllen); 1650*0Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && tohp->name == SO_FILEP) { 1651*0Sstevel@tonic-gate fdbuf = (struct fdbuf *)_TPI_TOPT_DATA(tohp); 1652*0Sstevel@tonic-gate fdbuflen = (int)_TPI_TOPT_DATALEN(tohp); 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gate if (!fdbuf_verify(mp, fdbuf, fdbuflen)) 1655*0Sstevel@tonic-gate return (EPROTO); 1656*0Sstevel@tonic-gate if (oldflg) { 1657*0Sstevel@tonic-gate error = fdbuf_extract(fdbuf, control, 1658*0Sstevel@tonic-gate (int)controllen); 1659*0Sstevel@tonic-gate if (error != 0) 1660*0Sstevel@tonic-gate return (error); 1661*0Sstevel@tonic-gate continue; 1662*0Sstevel@tonic-gate } else { 1663*0Sstevel@tonic-gate int fdlen; 1664*0Sstevel@tonic-gate 1665*0Sstevel@tonic-gate fdlen = (int)fdbuf_cmsglen( 1666*0Sstevel@tonic-gate (int)_TPI_TOPT_DATALEN(tohp)); 1667*0Sstevel@tonic-gate 1668*0Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 1669*0Sstevel@tonic-gate cmsg->cmsg_type = SCM_RIGHTS; 1670*0Sstevel@tonic-gate cmsg->cmsg_len = (socklen_t)(fdlen + 1671*0Sstevel@tonic-gate sizeof (struct cmsghdr)); 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate error = fdbuf_extract(fdbuf, 1674*0Sstevel@tonic-gate CMSG_CONTENT(cmsg), fdlen); 1675*0Sstevel@tonic-gate if (error != 0) 1676*0Sstevel@tonic-gate return (error); 1677*0Sstevel@tonic-gate } 1678*0Sstevel@tonic-gate } else { 1679*0Sstevel@tonic-gate if (oldflg) 1680*0Sstevel@tonic-gate continue; 1681*0Sstevel@tonic-gate 1682*0Sstevel@tonic-gate cmsg->cmsg_level = tohp->level; 1683*0Sstevel@tonic-gate cmsg->cmsg_type = tohp->name; 1684*0Sstevel@tonic-gate cmsg->cmsg_len = (socklen_t)(_TPI_TOPT_DATALEN(tohp) + 1685*0Sstevel@tonic-gate sizeof (struct cmsghdr)); 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate /* copy content to control data part */ 1688*0Sstevel@tonic-gate bcopy(&tohp[1], CMSG_CONTENT(cmsg), 1689*0Sstevel@tonic-gate CMSG_CONTENTLEN(cmsg)); 1690*0Sstevel@tonic-gate } 1691*0Sstevel@tonic-gate /* move to next CMSG structure! */ 1692*0Sstevel@tonic-gate cmsg = CMSG_NEXT(cmsg); 1693*0Sstevel@tonic-gate } 1694*0Sstevel@tonic-gate return (0); 1695*0Sstevel@tonic-gate } 1696*0Sstevel@tonic-gate 1697*0Sstevel@tonic-gate /* 1698*0Sstevel@tonic-gate * Extract the SO_SRCADDR option value if present. 1699*0Sstevel@tonic-gate */ 1700*0Sstevel@tonic-gate void 1701*0Sstevel@tonic-gate so_getopt_srcaddr(void *opt, t_uscalar_t optlen, void **srcp, 1702*0Sstevel@tonic-gate t_uscalar_t *srclenp) 1703*0Sstevel@tonic-gate { 1704*0Sstevel@tonic-gate struct T_opthdr *tohp; 1705*0Sstevel@tonic-gate 1706*0Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate ASSERT(srcp != NULL && srclenp != NULL); 1709*0Sstevel@tonic-gate *srcp = NULL; 1710*0Sstevel@tonic-gate *srclenp = 0; 1711*0Sstevel@tonic-gate 1712*0Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 1713*0Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 1714*0Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 1715*0Sstevel@tonic-gate dprint(1, ("so_getopt_srcaddr: level 0x%x, name %d, len %d\n", 1716*0Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 1717*0Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 1718*0Sstevel@tonic-gate tohp->name == SO_SRCADDR) { 1719*0Sstevel@tonic-gate *srcp = _TPI_TOPT_DATA(tohp); 1720*0Sstevel@tonic-gate *srclenp = (t_uscalar_t)_TPI_TOPT_DATALEN(tohp); 1721*0Sstevel@tonic-gate } 1722*0Sstevel@tonic-gate } 1723*0Sstevel@tonic-gate } 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate /* 1726*0Sstevel@tonic-gate * Verify if the SO_UNIX_CLOSE option is present. 1727*0Sstevel@tonic-gate */ 1728*0Sstevel@tonic-gate int 1729*0Sstevel@tonic-gate so_getopt_unix_close(void *opt, t_uscalar_t optlen) 1730*0Sstevel@tonic-gate { 1731*0Sstevel@tonic-gate struct T_opthdr *tohp; 1732*0Sstevel@tonic-gate 1733*0Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt)); 1734*0Sstevel@tonic-gate 1735*0Sstevel@tonic-gate for (tohp = (struct T_opthdr *)opt; 1736*0Sstevel@tonic-gate tohp && _TPI_TOPT_VALID(tohp, opt, (uintptr_t)opt + optlen); 1737*0Sstevel@tonic-gate tohp = _TPI_TOPT_NEXTHDR(opt, optlen, tohp)) { 1738*0Sstevel@tonic-gate dprint(1, 1739*0Sstevel@tonic-gate ("so_getopt_unix_close: level 0x%x, name %d, len %d\n", 1740*0Sstevel@tonic-gate tohp->level, tohp->name, tohp->len)); 1741*0Sstevel@tonic-gate if (tohp->level == SOL_SOCKET && 1742*0Sstevel@tonic-gate tohp->name == SO_UNIX_CLOSE) 1743*0Sstevel@tonic-gate return (1); 1744*0Sstevel@tonic-gate } 1745*0Sstevel@tonic-gate return (0); 1746*0Sstevel@tonic-gate } 1747*0Sstevel@tonic-gate 1748*0Sstevel@tonic-gate /* 1749*0Sstevel@tonic-gate * Allocate an M_PROTO message. 1750*0Sstevel@tonic-gate * 1751*0Sstevel@tonic-gate * If allocation fails the behavior depends on sleepflg: 1752*0Sstevel@tonic-gate * _ALLOC_NOSLEEP fail immediately 1753*0Sstevel@tonic-gate * _ALLOC_INTR sleep for memory until a signal is caught 1754*0Sstevel@tonic-gate * _ALLOC_SLEEP sleep forever. Don't return NULL. 1755*0Sstevel@tonic-gate */ 1756*0Sstevel@tonic-gate mblk_t * 1757*0Sstevel@tonic-gate soallocproto(size_t size, int sleepflg) 1758*0Sstevel@tonic-gate { 1759*0Sstevel@tonic-gate mblk_t *mp; 1760*0Sstevel@tonic-gate 1761*0Sstevel@tonic-gate /* Round up size for reuse */ 1762*0Sstevel@tonic-gate size = MAX(size, 64); 1763*0Sstevel@tonic-gate mp = allocb(size, BPRI_MED); 1764*0Sstevel@tonic-gate if (mp == NULL) { 1765*0Sstevel@tonic-gate int error; /* Dummy - error not returned to caller */ 1766*0Sstevel@tonic-gate 1767*0Sstevel@tonic-gate switch (sleepflg) { 1768*0Sstevel@tonic-gate case _ALLOC_SLEEP: 1769*0Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, STR_NOSIG, &error); 1770*0Sstevel@tonic-gate ASSERT(mp); 1771*0Sstevel@tonic-gate break; 1772*0Sstevel@tonic-gate case _ALLOC_INTR: 1773*0Sstevel@tonic-gate mp = allocb_wait(size, BPRI_MED, 0, &error); 1774*0Sstevel@tonic-gate if (mp == NULL) { 1775*0Sstevel@tonic-gate /* Caught signal while sleeping for memory */ 1776*0Sstevel@tonic-gate eprintline(ENOBUFS); 1777*0Sstevel@tonic-gate return (NULL); 1778*0Sstevel@tonic-gate } 1779*0Sstevel@tonic-gate break; 1780*0Sstevel@tonic-gate case _ALLOC_NOSLEEP: 1781*0Sstevel@tonic-gate default: 1782*0Sstevel@tonic-gate eprintline(ENOBUFS); 1783*0Sstevel@tonic-gate return (NULL); 1784*0Sstevel@tonic-gate } 1785*0Sstevel@tonic-gate } 1786*0Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 1787*0Sstevel@tonic-gate return (mp); 1788*0Sstevel@tonic-gate } 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gate /* 1791*0Sstevel@tonic-gate * Allocate an M_PROTO message with a single component. 1792*0Sstevel@tonic-gate * len is the length of buf. size is the amount to allocate. 1793*0Sstevel@tonic-gate * 1794*0Sstevel@tonic-gate * buf can be NULL with a non-zero len. 1795*0Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 1796*0Sstevel@tonic-gate */ 1797*0Sstevel@tonic-gate mblk_t * 1798*0Sstevel@tonic-gate soallocproto1(const void *buf, ssize_t len, ssize_t size, int sleepflg) 1799*0Sstevel@tonic-gate { 1800*0Sstevel@tonic-gate mblk_t *mp; 1801*0Sstevel@tonic-gate 1802*0Sstevel@tonic-gate if (size == 0) 1803*0Sstevel@tonic-gate size = len; 1804*0Sstevel@tonic-gate 1805*0Sstevel@tonic-gate ASSERT(size >= len); 1806*0Sstevel@tonic-gate /* Round up size for reuse */ 1807*0Sstevel@tonic-gate size = MAX(size, 64); 1808*0Sstevel@tonic-gate mp = soallocproto(size, sleepflg); 1809*0Sstevel@tonic-gate if (mp == NULL) 1810*0Sstevel@tonic-gate return (NULL); 1811*0Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 1812*0Sstevel@tonic-gate if (len != 0) { 1813*0Sstevel@tonic-gate if (buf != NULL) 1814*0Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 1815*0Sstevel@tonic-gate else 1816*0Sstevel@tonic-gate bzero(mp->b_wptr, len); 1817*0Sstevel@tonic-gate mp->b_wptr += len; 1818*0Sstevel@tonic-gate } 1819*0Sstevel@tonic-gate return (mp); 1820*0Sstevel@tonic-gate } 1821*0Sstevel@tonic-gate 1822*0Sstevel@tonic-gate /* 1823*0Sstevel@tonic-gate * Append buf/len to mp. 1824*0Sstevel@tonic-gate * The caller has to ensure that there is enough room in the mblk. 1825*0Sstevel@tonic-gate * 1826*0Sstevel@tonic-gate * buf can be NULL with a non-zero len. 1827*0Sstevel@tonic-gate * This results in a bzero'ed chunk being placed the message. 1828*0Sstevel@tonic-gate */ 1829*0Sstevel@tonic-gate void 1830*0Sstevel@tonic-gate soappendmsg(mblk_t *mp, const void *buf, ssize_t len) 1831*0Sstevel@tonic-gate { 1832*0Sstevel@tonic-gate ASSERT(mp); 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate if (len != 0) { 1835*0Sstevel@tonic-gate /* Assert for room left */ 1836*0Sstevel@tonic-gate ASSERT(mp->b_datap->db_lim - mp->b_wptr >= len); 1837*0Sstevel@tonic-gate if (buf != NULL) 1838*0Sstevel@tonic-gate bcopy(buf, mp->b_wptr, len); 1839*0Sstevel@tonic-gate else 1840*0Sstevel@tonic-gate bzero(mp->b_wptr, len); 1841*0Sstevel@tonic-gate } 1842*0Sstevel@tonic-gate mp->b_wptr += len; 1843*0Sstevel@tonic-gate } 1844*0Sstevel@tonic-gate 1845*0Sstevel@tonic-gate /* 1846*0Sstevel@tonic-gate * Create a message using two kernel buffers. 1847*0Sstevel@tonic-gate * If size is set that will determine the allocation size (e.g. for future 1848*0Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 1849*0Sstevel@tonic-gate * lengths. 1850*0Sstevel@tonic-gate */ 1851*0Sstevel@tonic-gate mblk_t * 1852*0Sstevel@tonic-gate soallocproto2(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 1853*0Sstevel@tonic-gate ssize_t size, int sleepflg) 1854*0Sstevel@tonic-gate { 1855*0Sstevel@tonic-gate mblk_t *mp; 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate if (size == 0) 1858*0Sstevel@tonic-gate size = len1 + len2; 1859*0Sstevel@tonic-gate ASSERT(size >= len1 + len2); 1860*0Sstevel@tonic-gate 1861*0Sstevel@tonic-gate mp = soallocproto1(buf1, len1, size, sleepflg); 1862*0Sstevel@tonic-gate if (mp) 1863*0Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 1864*0Sstevel@tonic-gate return (mp); 1865*0Sstevel@tonic-gate } 1866*0Sstevel@tonic-gate 1867*0Sstevel@tonic-gate /* 1868*0Sstevel@tonic-gate * Create a message using three kernel buffers. 1869*0Sstevel@tonic-gate * If size is set that will determine the allocation size (for future 1870*0Sstevel@tonic-gate * soappendmsg calls). If size is zero it is derived from the buffer 1871*0Sstevel@tonic-gate * lengths. 1872*0Sstevel@tonic-gate */ 1873*0Sstevel@tonic-gate mblk_t * 1874*0Sstevel@tonic-gate soallocproto3(const void *buf1, ssize_t len1, const void *buf2, ssize_t len2, 1875*0Sstevel@tonic-gate const void *buf3, ssize_t len3, ssize_t size, int sleepflg) 1876*0Sstevel@tonic-gate { 1877*0Sstevel@tonic-gate mblk_t *mp; 1878*0Sstevel@tonic-gate 1879*0Sstevel@tonic-gate if (size == 0) 1880*0Sstevel@tonic-gate size = len1 + len2 +len3; 1881*0Sstevel@tonic-gate ASSERT(size >= len1 + len2 + len3); 1882*0Sstevel@tonic-gate 1883*0Sstevel@tonic-gate mp = soallocproto1(buf1, len1, size, sleepflg); 1884*0Sstevel@tonic-gate if (mp != NULL) { 1885*0Sstevel@tonic-gate soappendmsg(mp, buf2, len2); 1886*0Sstevel@tonic-gate soappendmsg(mp, buf3, len3); 1887*0Sstevel@tonic-gate } 1888*0Sstevel@tonic-gate return (mp); 1889*0Sstevel@tonic-gate } 1890*0Sstevel@tonic-gate 1891*0Sstevel@tonic-gate #ifdef DEBUG 1892*0Sstevel@tonic-gate char * 1893*0Sstevel@tonic-gate pr_state(uint_t state, uint_t mode) 1894*0Sstevel@tonic-gate { 1895*0Sstevel@tonic-gate static char buf[1024]; 1896*0Sstevel@tonic-gate 1897*0Sstevel@tonic-gate buf[0] = 0; 1898*0Sstevel@tonic-gate if (state & SS_ISCONNECTED) 1899*0Sstevel@tonic-gate strcat(buf, "ISCONNECTED "); 1900*0Sstevel@tonic-gate if (state & SS_ISCONNECTING) 1901*0Sstevel@tonic-gate strcat(buf, "ISCONNECTING "); 1902*0Sstevel@tonic-gate if (state & SS_ISDISCONNECTING) 1903*0Sstevel@tonic-gate strcat(buf, "ISDISCONNECTING "); 1904*0Sstevel@tonic-gate if (state & SS_CANTSENDMORE) 1905*0Sstevel@tonic-gate strcat(buf, "CANTSENDMORE "); 1906*0Sstevel@tonic-gate 1907*0Sstevel@tonic-gate if (state & SS_CANTRCVMORE) 1908*0Sstevel@tonic-gate strcat(buf, "CANTRCVMORE "); 1909*0Sstevel@tonic-gate if (state & SS_ISBOUND) 1910*0Sstevel@tonic-gate strcat(buf, "ISBOUND "); 1911*0Sstevel@tonic-gate if (state & SS_NDELAY) 1912*0Sstevel@tonic-gate strcat(buf, "NDELAY "); 1913*0Sstevel@tonic-gate if (state & SS_NONBLOCK) 1914*0Sstevel@tonic-gate strcat(buf, "NONBLOCK "); 1915*0Sstevel@tonic-gate 1916*0Sstevel@tonic-gate if (state & SS_ASYNC) 1917*0Sstevel@tonic-gate strcat(buf, "ASYNC "); 1918*0Sstevel@tonic-gate if (state & SS_ACCEPTCONN) 1919*0Sstevel@tonic-gate strcat(buf, "ACCEPTCONN "); 1920*0Sstevel@tonic-gate if (state & SS_HASCONNIND) 1921*0Sstevel@tonic-gate strcat(buf, "HASCONNIND "); 1922*0Sstevel@tonic-gate if (state & SS_SAVEDEOR) 1923*0Sstevel@tonic-gate strcat(buf, "SAVEDEOR "); 1924*0Sstevel@tonic-gate 1925*0Sstevel@tonic-gate if (state & SS_RCVATMARK) 1926*0Sstevel@tonic-gate strcat(buf, "RCVATMARK "); 1927*0Sstevel@tonic-gate if (state & SS_OOBPEND) 1928*0Sstevel@tonic-gate strcat(buf, "OOBPEND "); 1929*0Sstevel@tonic-gate if (state & SS_HAVEOOBDATA) 1930*0Sstevel@tonic-gate strcat(buf, "HAVEOOBDATA "); 1931*0Sstevel@tonic-gate if (state & SS_HADOOBDATA) 1932*0Sstevel@tonic-gate strcat(buf, "HADOOBDATA "); 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate if (state & SS_FADDR_NOXLATE) 1935*0Sstevel@tonic-gate strcat(buf, "FADDR_NOXLATE "); 1936*0Sstevel@tonic-gate 1937*0Sstevel@tonic-gate if (mode & SM_PRIV) 1938*0Sstevel@tonic-gate strcat(buf, "PRIV "); 1939*0Sstevel@tonic-gate if (mode & SM_ATOMIC) 1940*0Sstevel@tonic-gate strcat(buf, "ATOMIC "); 1941*0Sstevel@tonic-gate if (mode & SM_ADDR) 1942*0Sstevel@tonic-gate strcat(buf, "ADDR "); 1943*0Sstevel@tonic-gate if (mode & SM_CONNREQUIRED) 1944*0Sstevel@tonic-gate strcat(buf, "CONNREQUIRED "); 1945*0Sstevel@tonic-gate 1946*0Sstevel@tonic-gate if (mode & SM_FDPASSING) 1947*0Sstevel@tonic-gate strcat(buf, "FDPASSING "); 1948*0Sstevel@tonic-gate if (mode & SM_EXDATA) 1949*0Sstevel@tonic-gate strcat(buf, "EXDATA "); 1950*0Sstevel@tonic-gate if (mode & SM_OPTDATA) 1951*0Sstevel@tonic-gate strcat(buf, "OPTDATA "); 1952*0Sstevel@tonic-gate if (mode & SM_BYTESTREAM) 1953*0Sstevel@tonic-gate strcat(buf, "BYTESTREAM "); 1954*0Sstevel@tonic-gate return (buf); 1955*0Sstevel@tonic-gate } 1956*0Sstevel@tonic-gate 1957*0Sstevel@tonic-gate char * 1958*0Sstevel@tonic-gate pr_addr(int family, struct sockaddr *addr, t_uscalar_t addrlen) 1959*0Sstevel@tonic-gate { 1960*0Sstevel@tonic-gate static char buf[1024]; 1961*0Sstevel@tonic-gate 1962*0Sstevel@tonic-gate if (addr == NULL || addrlen == 0) { 1963*0Sstevel@tonic-gate sprintf(buf, "(len %d) %p", addrlen, addr); 1964*0Sstevel@tonic-gate return (buf); 1965*0Sstevel@tonic-gate } 1966*0Sstevel@tonic-gate switch (family) { 1967*0Sstevel@tonic-gate case AF_INET: { 1968*0Sstevel@tonic-gate struct sockaddr_in sin; 1969*0Sstevel@tonic-gate 1970*0Sstevel@tonic-gate bcopy(addr, &sin, sizeof (sin)); 1971*0Sstevel@tonic-gate 1972*0Sstevel@tonic-gate (void) sprintf(buf, "(len %d) %x/%d", 1973*0Sstevel@tonic-gate addrlen, ntohl(sin.sin_addr.s_addr), 1974*0Sstevel@tonic-gate ntohs(sin.sin_port)); 1975*0Sstevel@tonic-gate break; 1976*0Sstevel@tonic-gate } 1977*0Sstevel@tonic-gate case AF_INET6: { 1978*0Sstevel@tonic-gate struct sockaddr_in6 sin6; 1979*0Sstevel@tonic-gate uint16_t *piece = (uint16_t *)&sin6.sin6_addr; 1980*0Sstevel@tonic-gate 1981*0Sstevel@tonic-gate bcopy((char *)addr, (char *)&sin6, sizeof (sin6)); 1982*0Sstevel@tonic-gate sprintf(buf, "(len %d) %x:%x:%x:%x:%x:%x:%x:%x/%d", 1983*0Sstevel@tonic-gate addrlen, 1984*0Sstevel@tonic-gate ntohs(piece[0]), ntohs(piece[1]), 1985*0Sstevel@tonic-gate ntohs(piece[2]), ntohs(piece[3]), 1986*0Sstevel@tonic-gate ntohs(piece[4]), ntohs(piece[5]), 1987*0Sstevel@tonic-gate ntohs(piece[6]), ntohs(piece[7]), 1988*0Sstevel@tonic-gate ntohs(sin6.sin6_port)); 1989*0Sstevel@tonic-gate break; 1990*0Sstevel@tonic-gate } 1991*0Sstevel@tonic-gate case AF_UNIX: { 1992*0Sstevel@tonic-gate struct sockaddr_un *soun = (struct sockaddr_un *)addr; 1993*0Sstevel@tonic-gate 1994*0Sstevel@tonic-gate (void) sprintf(buf, "(len %d) %s", 1995*0Sstevel@tonic-gate addrlen, 1996*0Sstevel@tonic-gate (soun == NULL) ? "(none)" : soun->sun_path); 1997*0Sstevel@tonic-gate break; 1998*0Sstevel@tonic-gate } 1999*0Sstevel@tonic-gate default: 2000*0Sstevel@tonic-gate (void) sprintf(buf, "(unknown af %d)", family); 2001*0Sstevel@tonic-gate break; 2002*0Sstevel@tonic-gate } 2003*0Sstevel@tonic-gate return (buf); 2004*0Sstevel@tonic-gate } 2005*0Sstevel@tonic-gate 2006*0Sstevel@tonic-gate /* The logical equivalence operator (a if-and-only-if b) */ 2007*0Sstevel@tonic-gate #define EQUIV(a, b) (((a) && (b)) || (!(a) && (!(b)))) 2008*0Sstevel@tonic-gate 2009*0Sstevel@tonic-gate /* 2010*0Sstevel@tonic-gate * Verify limitations and invariants on oob state. 2011*0Sstevel@tonic-gate * Return 1 if OK, otherwise 0 so that it can be used as 2012*0Sstevel@tonic-gate * ASSERT(verify_oobstate(so)); 2013*0Sstevel@tonic-gate */ 2014*0Sstevel@tonic-gate int 2015*0Sstevel@tonic-gate so_verify_oobstate(struct sonode *so) 2016*0Sstevel@tonic-gate { 2017*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 2018*0Sstevel@tonic-gate 2019*0Sstevel@tonic-gate /* 2020*0Sstevel@tonic-gate * The possible state combinations are: 2021*0Sstevel@tonic-gate * 0 2022*0Sstevel@tonic-gate * SS_OOBPEND 2023*0Sstevel@tonic-gate * SS_OOBPEND|SS_HAVEOOBDATA 2024*0Sstevel@tonic-gate * SS_OOBPEND|SS_HADOOBDATA 2025*0Sstevel@tonic-gate * SS_HADOOBDATA 2026*0Sstevel@tonic-gate */ 2027*0Sstevel@tonic-gate switch (so->so_state & (SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA)) { 2028*0Sstevel@tonic-gate case 0: 2029*0Sstevel@tonic-gate case SS_OOBPEND: 2030*0Sstevel@tonic-gate case SS_OOBPEND|SS_HAVEOOBDATA: 2031*0Sstevel@tonic-gate case SS_OOBPEND|SS_HADOOBDATA: 2032*0Sstevel@tonic-gate case SS_HADOOBDATA: 2033*0Sstevel@tonic-gate break; 2034*0Sstevel@tonic-gate default: 2035*0Sstevel@tonic-gate printf("Bad oob state 1 (%p): counts %d/%d state %s\n", 2036*0Sstevel@tonic-gate so, so->so_oobsigcnt, 2037*0Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 2038*0Sstevel@tonic-gate return (0); 2039*0Sstevel@tonic-gate } 2040*0Sstevel@tonic-gate 2041*0Sstevel@tonic-gate /* SS_RCVATMARK should only be set when SS_OOBPEND is set */ 2042*0Sstevel@tonic-gate if ((so->so_state & (SS_RCVATMARK|SS_OOBPEND)) == SS_RCVATMARK) { 2043*0Sstevel@tonic-gate printf("Bad oob state 2 (%p): counts %d/%d state %s\n", 2044*0Sstevel@tonic-gate so, so->so_oobsigcnt, 2045*0Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 2046*0Sstevel@tonic-gate return (0); 2047*0Sstevel@tonic-gate } 2048*0Sstevel@tonic-gate 2049*0Sstevel@tonic-gate /* 2050*0Sstevel@tonic-gate * (so_oobsigcnt != 0 or SS_RCVATMARK) iff SS_OOBPEND 2051*0Sstevel@tonic-gate */ 2052*0Sstevel@tonic-gate if (!EQUIV((so->so_oobsigcnt != 0) || (so->so_state & SS_RCVATMARK), 2053*0Sstevel@tonic-gate so->so_state & SS_OOBPEND)) { 2054*0Sstevel@tonic-gate printf("Bad oob state 3 (%p): counts %d/%d state %s\n", 2055*0Sstevel@tonic-gate so, so->so_oobsigcnt, 2056*0Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 2057*0Sstevel@tonic-gate return (0); 2058*0Sstevel@tonic-gate } 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate /* 2061*0Sstevel@tonic-gate * Unless SO_OOBINLINE we have so_oobmsg != NULL iff SS_HAVEOOBDATA 2062*0Sstevel@tonic-gate */ 2063*0Sstevel@tonic-gate if (!(so->so_options & SO_OOBINLINE) && 2064*0Sstevel@tonic-gate !EQUIV(so->so_oobmsg != NULL, so->so_state & SS_HAVEOOBDATA)) { 2065*0Sstevel@tonic-gate printf("Bad oob state 4 (%p): counts %d/%d state %s\n", 2066*0Sstevel@tonic-gate so, so->so_oobsigcnt, 2067*0Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 2068*0Sstevel@tonic-gate return (0); 2069*0Sstevel@tonic-gate } 2070*0Sstevel@tonic-gate if (so->so_oobsigcnt < so->so_oobcnt) { 2071*0Sstevel@tonic-gate printf("Bad oob state 5 (%p): counts %d/%d state %s\n", 2072*0Sstevel@tonic-gate so, so->so_oobsigcnt, 2073*0Sstevel@tonic-gate so->so_oobcnt, pr_state(so->so_state, so->so_mode)); 2074*0Sstevel@tonic-gate return (0); 2075*0Sstevel@tonic-gate } 2076*0Sstevel@tonic-gate return (1); 2077*0Sstevel@tonic-gate } 2078*0Sstevel@tonic-gate #undef EQUIV 2079*0Sstevel@tonic-gate 2080*0Sstevel@tonic-gate #endif /* DEBUG */ 2081*0Sstevel@tonic-gate 2082*0Sstevel@tonic-gate /* initialize sockfs zone specific kstat related items */ 2083*0Sstevel@tonic-gate void * 2084*0Sstevel@tonic-gate sock_kstat_init(zoneid_t zoneid) 2085*0Sstevel@tonic-gate { 2086*0Sstevel@tonic-gate kstat_t *ksp; 2087*0Sstevel@tonic-gate 2088*0Sstevel@tonic-gate ksp = kstat_create_zone("sockfs", 0, "sock_unix_list", "misc", 2089*0Sstevel@tonic-gate KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VAR_SIZE|KSTAT_FLAG_VIRTUAL, zoneid); 2090*0Sstevel@tonic-gate 2091*0Sstevel@tonic-gate if (ksp != NULL) { 2092*0Sstevel@tonic-gate ksp->ks_update = sockfs_update; 2093*0Sstevel@tonic-gate ksp->ks_snapshot = sockfs_snapshot; 2094*0Sstevel@tonic-gate ksp->ks_lock = &socklist.sl_lock; 2095*0Sstevel@tonic-gate ksp->ks_private = (void *)(uintptr_t)zoneid; 2096*0Sstevel@tonic-gate kstat_install(ksp); 2097*0Sstevel@tonic-gate } 2098*0Sstevel@tonic-gate 2099*0Sstevel@tonic-gate return (ksp); 2100*0Sstevel@tonic-gate } 2101*0Sstevel@tonic-gate 2102*0Sstevel@tonic-gate /* tear down sockfs zone specific kstat related items */ 2103*0Sstevel@tonic-gate /*ARGSUSED*/ 2104*0Sstevel@tonic-gate void 2105*0Sstevel@tonic-gate sock_kstat_fini(zoneid_t zoneid, void *arg) 2106*0Sstevel@tonic-gate { 2107*0Sstevel@tonic-gate kstat_t *ksp = (kstat_t *)arg; 2108*0Sstevel@tonic-gate 2109*0Sstevel@tonic-gate if (ksp != NULL) { 2110*0Sstevel@tonic-gate ASSERT(zoneid == (zoneid_t)(uintptr_t)ksp->ks_private); 2111*0Sstevel@tonic-gate kstat_delete(ksp); 2112*0Sstevel@tonic-gate } 2113*0Sstevel@tonic-gate } 2114*0Sstevel@tonic-gate 2115*0Sstevel@tonic-gate /* 2116*0Sstevel@tonic-gate * Zones: 2117*0Sstevel@tonic-gate * Note that nactive is going to be different for each zone. 2118*0Sstevel@tonic-gate * This means we require kstat to call sockfs_update and then sockfs_snapshot 2119*0Sstevel@tonic-gate * for the same zone, or sockfs_snapshot will be taken into the wrong size 2120*0Sstevel@tonic-gate * buffer. This is safe, but if the buffer is too small, user will not be 2121*0Sstevel@tonic-gate * given details of all sockets. However, as this kstat has a ks_lock, kstat 2122*0Sstevel@tonic-gate * driver will keep it locked between the update and the snapshot, so no 2123*0Sstevel@tonic-gate * other process (zone) can currently get inbetween resulting in a wrong size 2124*0Sstevel@tonic-gate * buffer allocation. 2125*0Sstevel@tonic-gate */ 2126*0Sstevel@tonic-gate static int 2127*0Sstevel@tonic-gate sockfs_update(kstat_t *ksp, int rw) 2128*0Sstevel@tonic-gate { 2129*0Sstevel@tonic-gate uint_t nactive = 0; /* # of active AF_UNIX sockets */ 2130*0Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 2131*0Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 2132*0Sstevel@tonic-gate 2133*0Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 2134*0Sstevel@tonic-gate 2135*0Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 2136*0Sstevel@tonic-gate return (EACCES); 2137*0Sstevel@tonic-gate } 2138*0Sstevel@tonic-gate 2139*0Sstevel@tonic-gate for (so = socklist.sl_list; so != NULL; so = so->so_next) { 2140*0Sstevel@tonic-gate if (so->so_accessvp != NULL && so->so_zoneid == myzoneid) { 2141*0Sstevel@tonic-gate nactive++; 2142*0Sstevel@tonic-gate } 2143*0Sstevel@tonic-gate } 2144*0Sstevel@tonic-gate ksp->ks_ndata = nactive; 2145*0Sstevel@tonic-gate ksp->ks_data_size = nactive * sizeof (struct k_sockinfo); 2146*0Sstevel@tonic-gate 2147*0Sstevel@tonic-gate return (0); 2148*0Sstevel@tonic-gate } 2149*0Sstevel@tonic-gate 2150*0Sstevel@tonic-gate static int 2151*0Sstevel@tonic-gate sockfs_snapshot(kstat_t *ksp, void *buf, int rw) 2152*0Sstevel@tonic-gate { 2153*0Sstevel@tonic-gate int ns; /* # of sonodes we've copied */ 2154*0Sstevel@tonic-gate struct sonode *so; /* current sonode on socklist */ 2155*0Sstevel@tonic-gate struct k_sockinfo *pksi; /* where we put sockinfo data */ 2156*0Sstevel@tonic-gate t_uscalar_t sn_len; /* soa_len */ 2157*0Sstevel@tonic-gate zoneid_t myzoneid = (zoneid_t)(uintptr_t)ksp->ks_private; 2158*0Sstevel@tonic-gate 2159*0Sstevel@tonic-gate ASSERT((zoneid_t)(uintptr_t)ksp->ks_private == getzoneid()); 2160*0Sstevel@tonic-gate 2161*0Sstevel@tonic-gate ksp->ks_snaptime = gethrtime(); 2162*0Sstevel@tonic-gate 2163*0Sstevel@tonic-gate if (rw == KSTAT_WRITE) { /* bounce all writes */ 2164*0Sstevel@tonic-gate return (EACCES); 2165*0Sstevel@tonic-gate } 2166*0Sstevel@tonic-gate 2167*0Sstevel@tonic-gate /* 2168*0Sstevel@tonic-gate * for each sonode on the socklist, we massage the important 2169*0Sstevel@tonic-gate * info into buf, in k_sockinfo format. 2170*0Sstevel@tonic-gate */ 2171*0Sstevel@tonic-gate pksi = (struct k_sockinfo *)buf; 2172*0Sstevel@tonic-gate for (ns = 0, so = socklist.sl_list; so != NULL; so = so->so_next) { 2173*0Sstevel@tonic-gate /* only stuff active sonodes and the same zone: */ 2174*0Sstevel@tonic-gate if (so->so_accessvp == NULL || so->so_zoneid != myzoneid) { 2175*0Sstevel@tonic-gate continue; 2176*0Sstevel@tonic-gate } 2177*0Sstevel@tonic-gate 2178*0Sstevel@tonic-gate /* 2179*0Sstevel@tonic-gate * If the sonode was activated between the update and the 2180*0Sstevel@tonic-gate * snapshot, we're done - as this is only a snapshot. 2181*0Sstevel@tonic-gate */ 2182*0Sstevel@tonic-gate if ((caddr_t)(pksi) >= (caddr_t)buf + ksp->ks_data_size) { 2183*0Sstevel@tonic-gate break; 2184*0Sstevel@tonic-gate } 2185*0Sstevel@tonic-gate 2186*0Sstevel@tonic-gate /* copy important info into buf: */ 2187*0Sstevel@tonic-gate pksi->ks_si.si_size = sizeof (struct k_sockinfo); 2188*0Sstevel@tonic-gate pksi->ks_si.si_family = so->so_family; 2189*0Sstevel@tonic-gate pksi->ks_si.si_type = so->so_type; 2190*0Sstevel@tonic-gate pksi->ks_si.si_flag = so->so_flag; 2191*0Sstevel@tonic-gate pksi->ks_si.si_state = so->so_state; 2192*0Sstevel@tonic-gate pksi->ks_si.si_serv_type = so->so_serv_type; 2193*0Sstevel@tonic-gate pksi->ks_si.si_ux_laddr_sou_magic = so->so_ux_laddr.soua_magic; 2194*0Sstevel@tonic-gate pksi->ks_si.si_ux_faddr_sou_magic = so->so_ux_faddr.soua_magic; 2195*0Sstevel@tonic-gate pksi->ks_si.si_laddr_soa_len = so->so_laddr.soa_len; 2196*0Sstevel@tonic-gate pksi->ks_si.si_faddr_soa_len = so->so_faddr.soa_len; 2197*0Sstevel@tonic-gate pksi->ks_si.si_szoneid = so->so_zoneid; 2198*0Sstevel@tonic-gate 2199*0Sstevel@tonic-gate mutex_enter(&so->so_lock); 2200*0Sstevel@tonic-gate 2201*0Sstevel@tonic-gate if (so->so_laddr_sa != NULL) { 2202*0Sstevel@tonic-gate ASSERT(so->so_laddr_sa->sa_data != NULL); 2203*0Sstevel@tonic-gate sn_len = so->so_laddr_len; 2204*0Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 2205*0Sstevel@tonic-gate sizeof (pksi->ks_si.si_laddr_sun_path)); 2206*0Sstevel@tonic-gate 2207*0Sstevel@tonic-gate pksi->ks_si.si_laddr_family = 2208*0Sstevel@tonic-gate so->so_laddr_sa->sa_family; 2209*0Sstevel@tonic-gate if (sn_len != 0) { 2210*0Sstevel@tonic-gate /* AF_UNIX socket names are NULL terminated */ 2211*0Sstevel@tonic-gate (void) strncpy(pksi->ks_si.si_laddr_sun_path, 2212*0Sstevel@tonic-gate so->so_laddr_sa->sa_data, 2213*0Sstevel@tonic-gate sizeof (pksi->ks_si.si_laddr_sun_path)); 2214*0Sstevel@tonic-gate sn_len = strlen(pksi->ks_si.si_laddr_sun_path); 2215*0Sstevel@tonic-gate } 2216*0Sstevel@tonic-gate pksi->ks_si.si_laddr_sun_path[sn_len] = 0; 2217*0Sstevel@tonic-gate } 2218*0Sstevel@tonic-gate 2219*0Sstevel@tonic-gate if (so->so_faddr_sa != NULL) { 2220*0Sstevel@tonic-gate ASSERT(so->so_faddr_sa->sa_data != NULL); 2221*0Sstevel@tonic-gate sn_len = so->so_faddr_len; 2222*0Sstevel@tonic-gate ASSERT(sn_len <= sizeof (short) + 2223*0Sstevel@tonic-gate sizeof (pksi->ks_si.si_faddr_sun_path)); 2224*0Sstevel@tonic-gate 2225*0Sstevel@tonic-gate pksi->ks_si.si_faddr_family = 2226*0Sstevel@tonic-gate so->so_faddr_sa->sa_family; 2227*0Sstevel@tonic-gate if (sn_len != 0) { 2228*0Sstevel@tonic-gate (void) strncpy(pksi->ks_si.si_faddr_sun_path, 2229*0Sstevel@tonic-gate so->so_faddr_sa->sa_data, 2230*0Sstevel@tonic-gate sizeof (pksi->ks_si.si_faddr_sun_path)); 2231*0Sstevel@tonic-gate sn_len = strlen(pksi->ks_si.si_faddr_sun_path); 2232*0Sstevel@tonic-gate } 2233*0Sstevel@tonic-gate pksi->ks_si.si_faddr_sun_path[sn_len] = 0; 2234*0Sstevel@tonic-gate } 2235*0Sstevel@tonic-gate 2236*0Sstevel@tonic-gate mutex_exit(&so->so_lock); 2237*0Sstevel@tonic-gate 2238*0Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[0], "%p", (void *)so); 2239*0Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[1], "%p", 2240*0Sstevel@tonic-gate (void *)so->so_ux_laddr.soua_vp); 2241*0Sstevel@tonic-gate (void) sprintf(pksi->ks_straddr[2], "%p", 2242*0Sstevel@tonic-gate (void *)so->so_ux_faddr.soua_vp); 2243*0Sstevel@tonic-gate 2244*0Sstevel@tonic-gate ns++; 2245*0Sstevel@tonic-gate pksi++; 2246*0Sstevel@tonic-gate } 2247*0Sstevel@tonic-gate 2248*0Sstevel@tonic-gate ksp->ks_ndata = ns; 2249*0Sstevel@tonic-gate return (0); 2250*0Sstevel@tonic-gate } 2251*0Sstevel@tonic-gate 2252*0Sstevel@tonic-gate ssize_t 2253*0Sstevel@tonic-gate soreadfile(file_t *fp, uchar_t *buf, u_offset_t fileoff, int *err, size_t size) 2254*0Sstevel@tonic-gate { 2255*0Sstevel@tonic-gate struct uio auio; 2256*0Sstevel@tonic-gate struct iovec aiov[MSG_MAXIOVLEN]; 2257*0Sstevel@tonic-gate register vnode_t *vp; 2258*0Sstevel@tonic-gate int ioflag, rwflag; 2259*0Sstevel@tonic-gate ssize_t cnt; 2260*0Sstevel@tonic-gate int error = 0; 2261*0Sstevel@tonic-gate int iovcnt = 0; 2262*0Sstevel@tonic-gate short fflag; 2263*0Sstevel@tonic-gate 2264*0Sstevel@tonic-gate vp = fp->f_vnode; 2265*0Sstevel@tonic-gate fflag = fp->f_flag; 2266*0Sstevel@tonic-gate 2267*0Sstevel@tonic-gate rwflag = 0; 2268*0Sstevel@tonic-gate aiov[0].iov_base = (caddr_t)buf; 2269*0Sstevel@tonic-gate aiov[0].iov_len = size; 2270*0Sstevel@tonic-gate iovcnt = 1; 2271*0Sstevel@tonic-gate cnt = (ssize_t)size; 2272*0Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 2273*0Sstevel@tonic-gate 2274*0Sstevel@tonic-gate auio.uio_loffset = fileoff; 2275*0Sstevel@tonic-gate auio.uio_iov = aiov; 2276*0Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 2277*0Sstevel@tonic-gate auio.uio_resid = cnt; 2278*0Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 2279*0Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 2280*0Sstevel@tonic-gate auio.uio_fmode = fflag; 2281*0Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 2282*0Sstevel@tonic-gate 2283*0Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 2284*0Sstevel@tonic-gate 2285*0Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 2286*0Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 2287*0Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 2288*0Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 2289*0Sstevel@tonic-gate cnt -= auio.uio_resid; 2290*0Sstevel@tonic-gate 2291*0Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 2292*0Sstevel@tonic-gate 2293*0Sstevel@tonic-gate if (error == EINTR && cnt != 0) 2294*0Sstevel@tonic-gate error = 0; 2295*0Sstevel@tonic-gate out: 2296*0Sstevel@tonic-gate if (error != 0) { 2297*0Sstevel@tonic-gate *err = error; 2298*0Sstevel@tonic-gate return (0); 2299*0Sstevel@tonic-gate } else { 2300*0Sstevel@tonic-gate *err = 0; 2301*0Sstevel@tonic-gate return (cnt); 2302*0Sstevel@tonic-gate } 2303*0Sstevel@tonic-gate } 2304