1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/buf.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/flock.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/kmem_impl.h> 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 62*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 65*7c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 66*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #include <c2/audit.h> 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate int so_default_version = SOV_SOCKSTREAM; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 73*7c478bd9Sstevel@tonic-gate /* Set sockdebug to print debug messages when SO_DEBUG is set */ 74*7c478bd9Sstevel@tonic-gate int sockdebug = 0; 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /* Set sockprinterr to print error messages when SO_DEBUG is set */ 77*7c478bd9Sstevel@tonic-gate int sockprinterr = 0; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * Set so_default_options to SO_DEBUG is all sockets should be created 81*7c478bd9Sstevel@tonic-gate * with SO_DEBUG set. This is needed to get debug printouts from the 82*7c478bd9Sstevel@tonic-gate * socket() call itself. 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate int so_default_options = 0; 85*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 88*7c478bd9Sstevel@tonic-gate /* 89*7c478bd9Sstevel@tonic-gate * Set to number of ticks to limit cv_waits for code coverage testing. 90*7c478bd9Sstevel@tonic-gate * Set to 1000 when SO_DEBUG is set to 2. 91*7c478bd9Sstevel@tonic-gate */ 92*7c478bd9Sstevel@tonic-gate clock_t sock_test_timelimit = 0; 93*7c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */ 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* 96*7c478bd9Sstevel@tonic-gate * For concurrency testing of e.g. opening /dev/ip which does not 97*7c478bd9Sstevel@tonic-gate * handle T_INFO_REQ messages. 98*7c478bd9Sstevel@tonic-gate */ 99*7c478bd9Sstevel@tonic-gate int so_no_tinfo = 0; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate /* 102*7c478bd9Sstevel@tonic-gate * Timeout for getting a T_CAPABILITY_ACK - it is possible for a provider 103*7c478bd9Sstevel@tonic-gate * to simply ignore the T_CAPABILITY_REQ. 104*7c478bd9Sstevel@tonic-gate */ 105*7c478bd9Sstevel@tonic-gate clock_t sock_capability_timeout = 2; /* seconds */ 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate static int do_tcapability(struct sonode *so, t_uscalar_t cap_bits1); 108*7c478bd9Sstevel@tonic-gate static void so_removehooks(struct sonode *so); 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate static mblk_t *strsock_proto(vnode_t *vp, mblk_t *mp, 111*7c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 112*7c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 113*7c478bd9Sstevel@tonic-gate static mblk_t *strsock_misc(vnode_t *vp, mblk_t *mp, 114*7c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 115*7c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate static int tlitosyserr(int terr); 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* 120*7c478bd9Sstevel@tonic-gate * Convert a socket to a stream. Invoked when the illusory sockmod 121*7c478bd9Sstevel@tonic-gate * is popped from the stream. 122*7c478bd9Sstevel@tonic-gate * Change the stream head back to default operation without losing 123*7c478bd9Sstevel@tonic-gate * any messages (T_conn_ind's are moved to the stream head queue). 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate int 126*7c478bd9Sstevel@tonic-gate so_sock2stream(struct sonode *so) 127*7c478bd9Sstevel@tonic-gate { 128*7c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 129*7c478bd9Sstevel@tonic-gate queue_t *rq; 130*7c478bd9Sstevel@tonic-gate mblk_t *mp; 131*7c478bd9Sstevel@tonic-gate int error = 0; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_plumb_lock)); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 136*7c478bd9Sstevel@tonic-gate so_lock_single(so); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate ASSERT(so->so_version != SOV_STREAM); 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* tell the transport below that sockmod is being popped */ 141*7c478bd9Sstevel@tonic-gate if ((so->so_state & SS_TCP_FAST_ACCEPT) != 0) { 142*7c478bd9Sstevel@tonic-gate int rval; 143*7c478bd9Sstevel@tonic-gate mblk_t **mpp; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 146*7c478bd9Sstevel@tonic-gate error = strioctl(vp, SIOCPOPSOCKFS, NULL, 0, K_TO_K, CRED(), 147*7c478bd9Sstevel@tonic-gate &rval); 148*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 149*7c478bd9Sstevel@tonic-gate if (error != 0) { 150*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 151*7c478bd9Sstevel@tonic-gate ("so_sock2stream(%p): SIOCPOPSOCKFS failed\n", so)); 152*7c478bd9Sstevel@tonic-gate goto exit; 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate so->so_state &= ~SS_TCP_FAST_ACCEPT; 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate for (mpp = &so->so_conn_ind_head; (mp = *mpp) != NULL; 157*7c478bd9Sstevel@tonic-gate mpp = &mp->b_next) { 158*7c478bd9Sstevel@tonic-gate struct T_conn_ind *conn_ind; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate /* 161*7c478bd9Sstevel@tonic-gate * strsock_proto() has already verified the length of 162*7c478bd9Sstevel@tonic-gate * this message block. 163*7c478bd9Sstevel@tonic-gate */ 164*7c478bd9Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct T_conn_ind)); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 167*7c478bd9Sstevel@tonic-gate if (conn_ind->OPT_length == 0 && 168*7c478bd9Sstevel@tonic-gate conn_ind->OPT_offset == 0) 169*7c478bd9Sstevel@tonic-gate continue; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate if (DB_REF(mp) > 1) { 172*7c478bd9Sstevel@tonic-gate mblk_t *newmp; 173*7c478bd9Sstevel@tonic-gate size_t length; 174*7c478bd9Sstevel@tonic-gate cred_t *cr; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* 177*7c478bd9Sstevel@tonic-gate * Copy the message block because it is used 178*7c478bd9Sstevel@tonic-gate * elsewhere, too. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate length = MBLKL(mp); 181*7c478bd9Sstevel@tonic-gate newmp = soallocproto(length, _ALLOC_INTR); 182*7c478bd9Sstevel@tonic-gate if (newmp == NULL) { 183*7c478bd9Sstevel@tonic-gate error = EINTR; 184*7c478bd9Sstevel@tonic-gate goto exit; 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, newmp->b_wptr, length); 187*7c478bd9Sstevel@tonic-gate newmp->b_wptr += length; 188*7c478bd9Sstevel@tonic-gate newmp->b_next = mp->b_next; 189*7c478bd9Sstevel@tonic-gate cr = DB_CRED(mp); 190*7c478bd9Sstevel@tonic-gate if (cr != NULL) 191*7c478bd9Sstevel@tonic-gate mblk_setcred(newmp, cr); 192*7c478bd9Sstevel@tonic-gate DB_CPID(newmp) = DB_CPID(mp); 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate /* 195*7c478bd9Sstevel@tonic-gate * Link the new message block into the queue 196*7c478bd9Sstevel@tonic-gate * and free the old one. 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate *mpp = newmp; 199*7c478bd9Sstevel@tonic-gate mp->b_next = NULL; 200*7c478bd9Sstevel@tonic-gate freemsg(mp); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate mp = newmp; 203*7c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate * Remove options added by TCP for accept fast-path. 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate conn_ind->OPT_length = 0; 210*7c478bd9Sstevel@tonic-gate conn_ind->OPT_offset = 0; 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate so->so_version = SOV_STREAM; 215*7c478bd9Sstevel@tonic-gate so->so_priv = NULL; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head to avoid queuing more 219*7c478bd9Sstevel@tonic-gate * packets in sockfs. 220*7c478bd9Sstevel@tonic-gate */ 221*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 222*7c478bd9Sstevel@tonic-gate so_removehooks(so); 223*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * Clear any state related to urgent data. Leave any T_EXDATA_IND 227*7c478bd9Sstevel@tonic-gate * on the queue - the behavior of urgent data after a switch is 228*7c478bd9Sstevel@tonic-gate * left undefined. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate so->so_error = so->so_delayed_error = 0; 231*7c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 232*7c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 233*7c478bd9Sstevel@tonic-gate so->so_oobsigcnt = so->so_oobcnt = 0; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_RCVATMARK|SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA| 236*7c478bd9Sstevel@tonic-gate SS_HASCONNIND|SS_SAVEDEOR); 237*7c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate freemsg(so->so_ack_mp); 240*7c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* 243*7c478bd9Sstevel@tonic-gate * Flush the T_DISCON_IND on so_discon_ind_mp. 244*7c478bd9Sstevel@tonic-gate */ 245*7c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* 248*7c478bd9Sstevel@tonic-gate * Move any queued T_CONN_IND messages to stream head queue. 249*7c478bd9Sstevel@tonic-gate */ 250*7c478bd9Sstevel@tonic-gate rq = RD(strvp2wq(vp)); 251*7c478bd9Sstevel@tonic-gate while ((mp = so->so_conn_ind_head) != NULL) { 252*7c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp->b_next; 253*7c478bd9Sstevel@tonic-gate mp->b_next = NULL; 254*7c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 255*7c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == mp); 256*7c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = NULL; 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 259*7c478bd9Sstevel@tonic-gate ("so_sock2stream(%p): moving T_CONN_IND\n", 260*7c478bd9Sstevel@tonic-gate so)); 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate /* Drop lock across put() */ 263*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 264*7c478bd9Sstevel@tonic-gate put(rq, mp); 265*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate exit: 269*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 270*7c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 271*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 272*7c478bd9Sstevel@tonic-gate return (error); 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * Covert a stream back to a socket. This is invoked when the illusory 277*7c478bd9Sstevel@tonic-gate * sockmod is pushed on a stream (where the stream was "created" by 278*7c478bd9Sstevel@tonic-gate * popping the illusory sockmod). 279*7c478bd9Sstevel@tonic-gate * This routine can not recreate the socket state (certain aspects of 280*7c478bd9Sstevel@tonic-gate * it like urgent data state and the bound/connected addresses for AF_UNIX 281*7c478bd9Sstevel@tonic-gate * sockets can not be recreated by asking the transport for information). 282*7c478bd9Sstevel@tonic-gate * Thus this routine implicitly assumes that the socket is in an initial 283*7c478bd9Sstevel@tonic-gate * state (as if it was just created). It flushes any messages queued on the 284*7c478bd9Sstevel@tonic-gate * read queue to avoid dealing with e.g. TPI acks or T_exdata_ind messages. 285*7c478bd9Sstevel@tonic-gate */ 286*7c478bd9Sstevel@tonic-gate void 287*7c478bd9Sstevel@tonic-gate so_stream2sock(struct sonode *so) 288*7c478bd9Sstevel@tonic-gate { 289*7c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_plumb_lock)); 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 294*7c478bd9Sstevel@tonic-gate so_lock_single(so); 295*7c478bd9Sstevel@tonic-gate ASSERT(so->so_version == SOV_STREAM); 296*7c478bd9Sstevel@tonic-gate so->so_version = SOV_SOCKSTREAM; 297*7c478bd9Sstevel@tonic-gate so->so_pushcnt = 0; 298*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate /* 301*7c478bd9Sstevel@tonic-gate * Set a permenent error to force any thread in sorecvmsg to 302*7c478bd9Sstevel@tonic-gate * return (and drop SOREADLOCKED). Clear the error once 303*7c478bd9Sstevel@tonic-gate * we have SOREADLOCKED. 304*7c478bd9Sstevel@tonic-gate * This makes a read sleeping during the I_PUSH of sockmod return 305*7c478bd9Sstevel@tonic-gate * EIO. 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), EIO, 1, NULL); 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* 310*7c478bd9Sstevel@tonic-gate * Get the read lock before flushing data to avoid 311*7c478bd9Sstevel@tonic-gate * problems with the T_EXDATA_IND MSG_PEEK code in sorecvmsg. 312*7c478bd9Sstevel@tonic-gate */ 313*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 314*7c478bd9Sstevel@tonic-gate (void) so_lock_read(so, 0); /* Set SOREADLOCKED */ 315*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, NULL); 318*7c478bd9Sstevel@tonic-gate so_installhooks(so); 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate /* 321*7c478bd9Sstevel@tonic-gate * Flush everything on the read queue. 322*7c478bd9Sstevel@tonic-gate * This ensures that no T_CONN_IND remain and that no T_EXDATA_IND 323*7c478bd9Sstevel@tonic-gate * remain; those types of messages would confuse sockfs. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate strflushrq(vp, FLUSHALL); 326*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * Flush the T_DISCON_IND on so_discon_ind_mp. 330*7c478bd9Sstevel@tonic-gate */ 331*7c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 332*7c478bd9Sstevel@tonic-gate so_unlock_read(so); /* Clear SOREADLOCKED */ 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 335*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* 339*7c478bd9Sstevel@tonic-gate * Install the hooks in the stream head. 340*7c478bd9Sstevel@tonic-gate */ 341*7c478bd9Sstevel@tonic-gate void 342*7c478bd9Sstevel@tonic-gate so_installhooks(struct sonode *so) 343*7c478bd9Sstevel@tonic-gate { 344*7c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate strsetrputhooks(vp, SH_SIGALLDATA | SH_IGN_ZEROLEN | SH_CONSOL_DATA, 347*7c478bd9Sstevel@tonic-gate strsock_proto, strsock_misc); 348*7c478bd9Sstevel@tonic-gate strsetwputhooks(vp, SH_SIGPIPE | SH_RECHECK_ERR, 0); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head. 353*7c478bd9Sstevel@tonic-gate */ 354*7c478bd9Sstevel@tonic-gate static void 355*7c478bd9Sstevel@tonic-gate so_removehooks(struct sonode *so) 356*7c478bd9Sstevel@tonic-gate { 357*7c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate strsetrputhooks(vp, 0, NULL, NULL); 360*7c478bd9Sstevel@tonic-gate strsetwputhooks(vp, 0, STRTIMOUT); 361*7c478bd9Sstevel@tonic-gate /* 362*7c478bd9Sstevel@tonic-gate * Leave read behavior as it would have been for a normal 363*7c478bd9Sstevel@tonic-gate * stream i.e. a read of an M_PROTO will fail. 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate /* 368*7c478bd9Sstevel@tonic-gate * Initialize the streams side of a socket including 369*7c478bd9Sstevel@tonic-gate * T_info_req/ack processing. If tso is not NULL its values are used thereby 370*7c478bd9Sstevel@tonic-gate * avoiding the T_INFO_REQ. 371*7c478bd9Sstevel@tonic-gate */ 372*7c478bd9Sstevel@tonic-gate int 373*7c478bd9Sstevel@tonic-gate so_strinit(struct sonode *so, struct sonode *tso) 374*7c478bd9Sstevel@tonic-gate { 375*7c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 376*7c478bd9Sstevel@tonic-gate struct stdata *stp; 377*7c478bd9Sstevel@tonic-gate mblk_t *mp; 378*7c478bd9Sstevel@tonic-gate int error; 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("so_strinit(%p)\n", so)); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* Preallocate an unbind_req message */ 383*7c478bd9Sstevel@tonic-gate mp = soallocproto(sizeof (struct T_unbind_req), _ALLOC_SLEEP); 384*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 385*7c478bd9Sstevel@tonic-gate so->so_unbind_mp = mp; 386*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 387*7c478bd9Sstevel@tonic-gate so->so_options = so_default_options; 388*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 389*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate so_installhooks(so); 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate /* 394*7c478bd9Sstevel@tonic-gate * The T_CAPABILITY_REQ should be the first message sent down because 395*7c478bd9Sstevel@tonic-gate * at least TCP has a fast-path for this which avoids timeouts while 396*7c478bd9Sstevel@tonic-gate * waiting for the T_CAPABILITY_ACK under high system load. 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate if (tso == NULL) { 399*7c478bd9Sstevel@tonic-gate error = do_tcapability(so, TC1_ACCEPTOR_ID | TC1_INFO); 400*7c478bd9Sstevel@tonic-gate if (error) 401*7c478bd9Sstevel@tonic-gate return (error); 402*7c478bd9Sstevel@tonic-gate } else { 403*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 404*7c478bd9Sstevel@tonic-gate so->so_tsdu_size = tso->so_tsdu_size; 405*7c478bd9Sstevel@tonic-gate so->so_etsdu_size = tso->so_etsdu_size; 406*7c478bd9Sstevel@tonic-gate so->so_addr_size = tso->so_addr_size; 407*7c478bd9Sstevel@tonic-gate so->so_opt_size = tso->so_opt_size; 408*7c478bd9Sstevel@tonic-gate so->so_tidu_size = tso->so_tidu_size; 409*7c478bd9Sstevel@tonic-gate so->so_serv_type = tso->so_serv_type; 410*7c478bd9Sstevel@tonic-gate so->so_mode = tso->so_mode & ~SM_ACCEPTOR_ID; 411*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate /* the following do_tcapability may update so->so_mode */ 414*7c478bd9Sstevel@tonic-gate if ((tso->so_serv_type != T_CLTS) && 415*7c478bd9Sstevel@tonic-gate ((so->so_state & SS_TCP_FAST_ACCEPT) == 0)) { 416*7c478bd9Sstevel@tonic-gate error = do_tcapability(so, TC1_ACCEPTOR_ID); 417*7c478bd9Sstevel@tonic-gate if (error) 418*7c478bd9Sstevel@tonic-gate return (error); 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate /* 422*7c478bd9Sstevel@tonic-gate * If the addr_size is 0 we treat it as already bound 423*7c478bd9Sstevel@tonic-gate * and connected. This is used by the routing socket. 424*7c478bd9Sstevel@tonic-gate * We set the addr_size to something to allocate a the address 425*7c478bd9Sstevel@tonic-gate * structures. 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate if (so->so_addr_size == 0) { 428*7c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND | SS_ISCONNECTED; 429*7c478bd9Sstevel@tonic-gate /* Address size can vary with address families. */ 430*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET6) 431*7c478bd9Sstevel@tonic-gate so->so_addr_size = 432*7c478bd9Sstevel@tonic-gate (t_scalar_t)sizeof (struct sockaddr_in6); 433*7c478bd9Sstevel@tonic-gate else 434*7c478bd9Sstevel@tonic-gate so->so_addr_size = 435*7c478bd9Sstevel@tonic-gate (t_scalar_t)sizeof (struct sockaddr_in); 436*7c478bd9Sstevel@tonic-gate ASSERT(so->so_unbind_mp); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate /* 439*7c478bd9Sstevel@tonic-gate * Allocate the addresses. 440*7c478bd9Sstevel@tonic-gate */ 441*7c478bd9Sstevel@tonic-gate ASSERT(so->so_laddr_sa == NULL && so->so_faddr_sa == NULL); 442*7c478bd9Sstevel@tonic-gate ASSERT(so->so_laddr_len == 0 && so->so_faddr_len == 0); 443*7c478bd9Sstevel@tonic-gate so->so_laddr_maxlen = so->so_faddr_maxlen = 444*7c478bd9Sstevel@tonic-gate P2ROUNDUP(so->so_addr_size, KMEM_ALIGN); 445*7c478bd9Sstevel@tonic-gate so->so_laddr_sa = kmem_alloc(so->so_laddr_maxlen * 2, KM_SLEEP); 446*7c478bd9Sstevel@tonic-gate so->so_faddr_sa = (struct sockaddr *)((caddr_t)so->so_laddr_sa 447*7c478bd9Sstevel@tonic-gate + so->so_laddr_maxlen); 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX) { 450*7c478bd9Sstevel@tonic-gate /* 451*7c478bd9Sstevel@tonic-gate * Initialize AF_UNIX related fields. 452*7c478bd9Sstevel@tonic-gate */ 453*7c478bd9Sstevel@tonic-gate bzero(&so->so_ux_laddr, sizeof (so->so_ux_laddr)); 454*7c478bd9Sstevel@tonic-gate bzero(&so->so_ux_faddr, sizeof (so->so_ux_faddr)); 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate stp = vp->v_stream; 458*7c478bd9Sstevel@tonic-gate /* 459*7c478bd9Sstevel@tonic-gate * Have to keep minpsz at zero in order to allow write/send of zero 460*7c478bd9Sstevel@tonic-gate * bytes. 461*7c478bd9Sstevel@tonic-gate */ 462*7c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 463*7c478bd9Sstevel@tonic-gate if (stp->sd_qn_minpsz == 1) 464*7c478bd9Sstevel@tonic-gate stp->sd_qn_minpsz = 0; 465*7c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate return (0); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate static void 471*7c478bd9Sstevel@tonic-gate copy_tinfo(struct sonode *so, struct T_info_ack *tia) 472*7c478bd9Sstevel@tonic-gate { 473*7c478bd9Sstevel@tonic-gate so->so_tsdu_size = tia->TSDU_size; 474*7c478bd9Sstevel@tonic-gate so->so_etsdu_size = tia->ETSDU_size; 475*7c478bd9Sstevel@tonic-gate so->so_addr_size = tia->ADDR_size; 476*7c478bd9Sstevel@tonic-gate so->so_opt_size = tia->OPT_size; 477*7c478bd9Sstevel@tonic-gate so->so_tidu_size = tia->TIDU_size; 478*7c478bd9Sstevel@tonic-gate so->so_serv_type = tia->SERV_type; 479*7c478bd9Sstevel@tonic-gate switch (tia->CURRENT_state) { 480*7c478bd9Sstevel@tonic-gate case TS_UNBND: 481*7c478bd9Sstevel@tonic-gate break; 482*7c478bd9Sstevel@tonic-gate case TS_IDLE: 483*7c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND; 484*7c478bd9Sstevel@tonic-gate so->so_laddr_len = 0; 485*7c478bd9Sstevel@tonic-gate so->so_state &= ~SS_LADDR_VALID; 486*7c478bd9Sstevel@tonic-gate break; 487*7c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 488*7c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND|SS_ISCONNECTED; 489*7c478bd9Sstevel@tonic-gate so->so_laddr_len = 0; 490*7c478bd9Sstevel@tonic-gate so->so_faddr_len = 0; 491*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_LADDR_VALID | SS_FADDR_VALID); 492*7c478bd9Sstevel@tonic-gate break; 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate /* 496*7c478bd9Sstevel@tonic-gate * Heuristics for determining the socket mode flags 497*7c478bd9Sstevel@tonic-gate * (SM_ATOMIC, SM_CONNREQUIRED, SM_ADDR, SM_FDPASSING, 498*7c478bd9Sstevel@tonic-gate * and SM_EXDATA, SM_OPTDATA, and SM_BYTESTREAM) 499*7c478bd9Sstevel@tonic-gate * from the info ack. 500*7c478bd9Sstevel@tonic-gate */ 501*7c478bd9Sstevel@tonic-gate if (so->so_serv_type == T_CLTS) { 502*7c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC | SM_ADDR; 503*7c478bd9Sstevel@tonic-gate } else { 504*7c478bd9Sstevel@tonic-gate so->so_mode |= SM_CONNREQUIRED; 505*7c478bd9Sstevel@tonic-gate if (so->so_etsdu_size != 0 && so->so_etsdu_size != -2) 506*7c478bd9Sstevel@tonic-gate so->so_mode |= SM_EXDATA; 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_SEQPACKET || so->so_type == SOCK_RAW) { 509*7c478bd9Sstevel@tonic-gate /* Semantics are to discard tail end of messages */ 510*7c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC; 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX) { 513*7c478bd9Sstevel@tonic-gate so->so_mode |= SM_FDPASSING | SM_OPTDATA; 514*7c478bd9Sstevel@tonic-gate if (so->so_addr_size == -1) { 515*7c478bd9Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 516*7c478bd9Sstevel@tonic-gate so->so_addr_size = (t_scalar_t)(MAXPATHLEN + 517*7c478bd9Sstevel@tonic-gate sizeof (short) + 1); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_STREAM) { 520*7c478bd9Sstevel@tonic-gate /* 521*7c478bd9Sstevel@tonic-gate * Make it into a byte-stream transport. 522*7c478bd9Sstevel@tonic-gate * SOCK_SEQPACKET sockets are unchanged. 523*7c478bd9Sstevel@tonic-gate */ 524*7c478bd9Sstevel@tonic-gate so->so_tsdu_size = 0; 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate } else if (so->so_addr_size == -1) { 527*7c478bd9Sstevel@tonic-gate /* 528*7c478bd9Sstevel@tonic-gate * Logic extracted from sockmod - have to pick some max address 529*7c478bd9Sstevel@tonic-gate * length in order to preallocate the addresses. 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate so->so_addr_size = SOA_DEFSIZE; 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate if (so->so_tsdu_size == 0) 534*7c478bd9Sstevel@tonic-gate so->so_mode |= SM_BYTESTREAM; 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate static int 538*7c478bd9Sstevel@tonic-gate check_tinfo(struct sonode *so) 539*7c478bd9Sstevel@tonic-gate { 540*7c478bd9Sstevel@tonic-gate /* Consistency checks */ 541*7c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_DGRAM && so->so_serv_type != T_CLTS) { 542*7c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 543*7c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 544*7c478bd9Sstevel@tonic-gate return (EPROTO); 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_STREAM && so->so_serv_type == T_CLTS) { 547*7c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 548*7c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 549*7c478bd9Sstevel@tonic-gate return (EPROTO); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_SEQPACKET && so->so_serv_type == T_CLTS) { 552*7c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 553*7c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 554*7c478bd9Sstevel@tonic-gate return (EPROTO); 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET && 557*7c478bd9Sstevel@tonic-gate so->so_addr_size != (t_scalar_t)sizeof (struct sockaddr_in)) { 558*7c478bd9Sstevel@tonic-gate eprintso(so, 559*7c478bd9Sstevel@tonic-gate ("AF_INET must have sockaddr_in address length. Got %d\n", 560*7c478bd9Sstevel@tonic-gate so->so_addr_size)); 561*7c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 562*7c478bd9Sstevel@tonic-gate return (EMSGSIZE); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET6 && 565*7c478bd9Sstevel@tonic-gate so->so_addr_size != (t_scalar_t)sizeof (struct sockaddr_in6)) { 566*7c478bd9Sstevel@tonic-gate eprintso(so, 567*7c478bd9Sstevel@tonic-gate ("AF_INET6 must have sockaddr_in6 address length. Got %d\n", 568*7c478bd9Sstevel@tonic-gate so->so_addr_size)); 569*7c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 570*7c478bd9Sstevel@tonic-gate return (EMSGSIZE); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ( 574*7c478bd9Sstevel@tonic-gate "tinfo: serv %d tsdu %d, etsdu %d, addr %d, opt %d, tidu %d\n", 575*7c478bd9Sstevel@tonic-gate so->so_serv_type, so->so_tsdu_size, so->so_etsdu_size, 576*7c478bd9Sstevel@tonic-gate so->so_addr_size, so->so_opt_size, 577*7c478bd9Sstevel@tonic-gate so->so_tidu_size)); 578*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("tinfo: so_state %s\n", 579*7c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 580*7c478bd9Sstevel@tonic-gate return (0); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate /* 584*7c478bd9Sstevel@tonic-gate * Send down T_info_req and wait for the ack. 585*7c478bd9Sstevel@tonic-gate * Record interesting T_info_ack values in the sonode. 586*7c478bd9Sstevel@tonic-gate */ 587*7c478bd9Sstevel@tonic-gate static int 588*7c478bd9Sstevel@tonic-gate do_tinfo(struct sonode *so) 589*7c478bd9Sstevel@tonic-gate { 590*7c478bd9Sstevel@tonic-gate struct T_info_req tir; 591*7c478bd9Sstevel@tonic-gate mblk_t *mp; 592*7c478bd9Sstevel@tonic-gate int error; 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 597*7c478bd9Sstevel@tonic-gate so->so_addr_size = 0; 598*7c478bd9Sstevel@tonic-gate return (0); 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("do_tinfo(%p)\n", so)); 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* Send T_INFO_REQ */ 604*7c478bd9Sstevel@tonic-gate tir.PRIM_type = T_INFO_REQ; 605*7c478bd9Sstevel@tonic-gate mp = soallocproto1(&tir, sizeof (tir), 606*7c478bd9Sstevel@tonic-gate sizeof (struct T_info_req) + sizeof (struct T_info_ack), 607*7c478bd9Sstevel@tonic-gate _ALLOC_INTR); 608*7c478bd9Sstevel@tonic-gate if (mp == NULL) { 609*7c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 610*7c478bd9Sstevel@tonic-gate return (ENOBUFS); 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate /* T_INFO_REQ has to be M_PCPROTO */ 613*7c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 616*7c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 617*7c478bd9Sstevel@tonic-gate if (error) { 618*7c478bd9Sstevel@tonic-gate eprintsoline(so, error); 619*7c478bd9Sstevel@tonic-gate return (error); 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 622*7c478bd9Sstevel@tonic-gate /* Wait for T_INFO_ACK */ 623*7c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_INFO_REQ, T_INFO_ACK, 624*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_info_ack), &mp, 0))) { 625*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 626*7c478bd9Sstevel@tonic-gate eprintsoline(so, error); 627*7c478bd9Sstevel@tonic-gate return (error); 628*7c478bd9Sstevel@tonic-gate } 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate ASSERT(mp); 631*7c478bd9Sstevel@tonic-gate copy_tinfo(so, (struct T_info_ack *)mp->b_rptr); 632*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 633*7c478bd9Sstevel@tonic-gate freemsg(mp); 634*7c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate /* 638*7c478bd9Sstevel@tonic-gate * Send down T_capability_req and wait for the ack. 639*7c478bd9Sstevel@tonic-gate * Record interesting T_capability_ack values in the sonode. 640*7c478bd9Sstevel@tonic-gate */ 641*7c478bd9Sstevel@tonic-gate static int 642*7c478bd9Sstevel@tonic-gate do_tcapability(struct sonode *so, t_uscalar_t cap_bits1) 643*7c478bd9Sstevel@tonic-gate { 644*7c478bd9Sstevel@tonic-gate struct T_capability_req tcr; 645*7c478bd9Sstevel@tonic-gate struct T_capability_ack *tca; 646*7c478bd9Sstevel@tonic-gate mblk_t *mp; 647*7c478bd9Sstevel@tonic-gate int error; 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate ASSERT(cap_bits1 != 0); 650*7c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & ~(TC1_ACCEPTOR_ID | TC1_INFO)) == 0); 651*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate if (so->so_provinfo->tpi_capability == PI_NO) 654*7c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 657*7c478bd9Sstevel@tonic-gate so->so_addr_size = 0; 658*7c478bd9Sstevel@tonic-gate if ((cap_bits1 &= ~TC1_INFO) == 0) 659*7c478bd9Sstevel@tonic-gate return (0); 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("do_tcapability(%p)\n", so)); 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate /* Send T_CAPABILITY_REQ */ 665*7c478bd9Sstevel@tonic-gate tcr.PRIM_type = T_CAPABILITY_REQ; 666*7c478bd9Sstevel@tonic-gate tcr.CAP_bits1 = cap_bits1; 667*7c478bd9Sstevel@tonic-gate mp = soallocproto1(&tcr, sizeof (tcr), 668*7c478bd9Sstevel@tonic-gate sizeof (struct T_capability_req) + sizeof (struct T_capability_ack), 669*7c478bd9Sstevel@tonic-gate _ALLOC_INTR); 670*7c478bd9Sstevel@tonic-gate if (mp == NULL) { 671*7c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 672*7c478bd9Sstevel@tonic-gate return (ENOBUFS); 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate /* T_CAPABILITY_REQ should be M_PCPROTO here */ 675*7c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 678*7c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 679*7c478bd9Sstevel@tonic-gate if (error) { 680*7c478bd9Sstevel@tonic-gate eprintsoline(so, error); 681*7c478bd9Sstevel@tonic-gate return (error); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 684*7c478bd9Sstevel@tonic-gate /* Wait for T_CAPABILITY_ACK */ 685*7c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_CAPABILITY_REQ, T_CAPABILITY_ACK, 686*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (*tca), &mp, sock_capability_timeout * hz))) { 687*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 688*7c478bd9Sstevel@tonic-gate PI_PROVLOCK(so->so_provinfo); 689*7c478bd9Sstevel@tonic-gate if (so->so_provinfo->tpi_capability == PI_DONTKNOW) 690*7c478bd9Sstevel@tonic-gate so->so_provinfo->tpi_capability = PI_NO; 691*7c478bd9Sstevel@tonic-gate PI_PROVUNLOCK(so->so_provinfo); 692*7c478bd9Sstevel@tonic-gate ASSERT((so->so_mode & SM_ACCEPTOR_ID) == 0); 693*7c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 694*7c478bd9Sstevel@tonic-gate /* 695*7c478bd9Sstevel@tonic-gate * If the T_CAPABILITY_REQ timed out and then a 696*7c478bd9Sstevel@tonic-gate * T_INFO_REQ gets a protocol error, most likely 697*7c478bd9Sstevel@tonic-gate * the capability was slow (vs. unsupported). Return 698*7c478bd9Sstevel@tonic-gate * ENOSR for this case as a best guess. 699*7c478bd9Sstevel@tonic-gate */ 700*7c478bd9Sstevel@tonic-gate if (error == ETIME) { 701*7c478bd9Sstevel@tonic-gate return ((error = do_tinfo(so)) == EPROTO ? 702*7c478bd9Sstevel@tonic-gate ENOSR : error); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate return (0); 707*7c478bd9Sstevel@tonic-gate } 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate if (so->so_provinfo->tpi_capability == PI_DONTKNOW) { 710*7c478bd9Sstevel@tonic-gate PI_PROVLOCK(so->so_provinfo); 711*7c478bd9Sstevel@tonic-gate so->so_provinfo->tpi_capability = PI_YES; 712*7c478bd9Sstevel@tonic-gate PI_PROVUNLOCK(so->so_provinfo); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate ASSERT(mp); 716*7c478bd9Sstevel@tonic-gate tca = (struct T_capability_ack *)mp->b_rptr; 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & TC1_INFO) == (tca->CAP_bits1 & TC1_INFO)); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate cap_bits1 = tca->CAP_bits1; 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_ACCEPTOR_ID) { 723*7c478bd9Sstevel@tonic-gate so->so_acceptor_id = tca->ACCEPTOR_id; 724*7c478bd9Sstevel@tonic-gate so->so_mode |= SM_ACCEPTOR_ID; 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) 728*7c478bd9Sstevel@tonic-gate copy_tinfo(so, &tca->INFO_ack); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 731*7c478bd9Sstevel@tonic-gate freemsg(mp); 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) 734*7c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate return (0); 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate /* 740*7c478bd9Sstevel@tonic-gate * Retrieve and clear the socket error. 741*7c478bd9Sstevel@tonic-gate */ 742*7c478bd9Sstevel@tonic-gate int 743*7c478bd9Sstevel@tonic-gate sogeterr(struct sonode *so) 744*7c478bd9Sstevel@tonic-gate { 745*7c478bd9Sstevel@tonic-gate int error; 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate error = so->so_error; 750*7c478bd9Sstevel@tonic-gate so->so_error = 0; 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate return (error); 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate /* 756*7c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve read 757*7c478bd9Sstevel@tonic-gate * side errors. 758*7c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 759*7c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 760*7c478bd9Sstevel@tonic-gate */ 761*7c478bd9Sstevel@tonic-gate int 762*7c478bd9Sstevel@tonic-gate sogetrderr(vnode_t *vp, int ispeek, int *clearerr) 763*7c478bd9Sstevel@tonic-gate { 764*7c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 765*7c478bd9Sstevel@tonic-gate int error; 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 768*7c478bd9Sstevel@tonic-gate if (ispeek) { 769*7c478bd9Sstevel@tonic-gate error = so->so_error; 770*7c478bd9Sstevel@tonic-gate *clearerr = 0; 771*7c478bd9Sstevel@tonic-gate } else { 772*7c478bd9Sstevel@tonic-gate error = so->so_error; 773*7c478bd9Sstevel@tonic-gate so->so_error = 0; 774*7c478bd9Sstevel@tonic-gate *clearerr = 1; 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 777*7c478bd9Sstevel@tonic-gate return (error); 778*7c478bd9Sstevel@tonic-gate } 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate /* 781*7c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve write 782*7c478bd9Sstevel@tonic-gate * side errors. 783*7c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 784*7c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 785*7c478bd9Sstevel@tonic-gate */ 786*7c478bd9Sstevel@tonic-gate int 787*7c478bd9Sstevel@tonic-gate sogetwrerr(vnode_t *vp, int ispeek, int *clearerr) 788*7c478bd9Sstevel@tonic-gate { 789*7c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 790*7c478bd9Sstevel@tonic-gate int error; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 793*7c478bd9Sstevel@tonic-gate if (so->so_state & SS_CANTSENDMORE) { 794*7c478bd9Sstevel@tonic-gate error = EPIPE; 795*7c478bd9Sstevel@tonic-gate *clearerr = 0; 796*7c478bd9Sstevel@tonic-gate } else { 797*7c478bd9Sstevel@tonic-gate error = so->so_error; 798*7c478bd9Sstevel@tonic-gate if (ispeek) { 799*7c478bd9Sstevel@tonic-gate *clearerr = 0; 800*7c478bd9Sstevel@tonic-gate } else { 801*7c478bd9Sstevel@tonic-gate so->so_error = 0; 802*7c478bd9Sstevel@tonic-gate *clearerr = 1; 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 806*7c478bd9Sstevel@tonic-gate return (error); 807*7c478bd9Sstevel@tonic-gate } 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate /* 810*7c478bd9Sstevel@tonic-gate * Set a nonpersistent read and write error on the socket. 811*7c478bd9Sstevel@tonic-gate * Used when there is a T_uderror_ind for a connected socket. 812*7c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror and strsetwerror 813*7c478bd9Sstevel@tonic-gate * after dropping the lock. 814*7c478bd9Sstevel@tonic-gate */ 815*7c478bd9Sstevel@tonic-gate void 816*7c478bd9Sstevel@tonic-gate soseterror(struct sonode *so, int error) 817*7c478bd9Sstevel@tonic-gate { 818*7c478bd9Sstevel@tonic-gate ASSERT(error != 0); 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 821*7c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate void 825*7c478bd9Sstevel@tonic-gate soisconnecting(struct sonode *so) 826*7c478bd9Sstevel@tonic-gate { 827*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 828*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); 829*7c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTING; 830*7c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 831*7c478bd9Sstevel@tonic-gate } 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate void 834*7c478bd9Sstevel@tonic-gate soisconnected(struct sonode *so) 835*7c478bd9Sstevel@tonic-gate { 836*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 837*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING); 838*7c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTED; 839*7c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate /* 843*7c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror, strsetwerror and strseteof. 844*7c478bd9Sstevel@tonic-gate */ 845*7c478bd9Sstevel@tonic-gate void 846*7c478bd9Sstevel@tonic-gate soisdisconnected(struct sonode *so, int error) 847*7c478bd9Sstevel@tonic-gate { 848*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 849*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING| 850*7c478bd9Sstevel@tonic-gate SS_LADDR_VALID|SS_FADDR_VALID); 851*7c478bd9Sstevel@tonic-gate so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); 852*7c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 853*7c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) { 854*7c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 855*7c478bd9Sstevel@tonic-gate so->so_peercred = NULL; 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 858*7c478bd9Sstevel@tonic-gate } 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate /* 861*7c478bd9Sstevel@tonic-gate * For connected AF_UNIX SOCK_DGRAM sockets when the peer closes. 862*7c478bd9Sstevel@tonic-gate * Does not affect write side. 863*7c478bd9Sstevel@tonic-gate * The caller also has to call strsetrerror. 864*7c478bd9Sstevel@tonic-gate */ 865*7c478bd9Sstevel@tonic-gate static void 866*7c478bd9Sstevel@tonic-gate sobreakconn(struct sonode *so, int error) 867*7c478bd9Sstevel@tonic-gate { 868*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 869*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 870*7c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 871*7c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate /* 875*7c478bd9Sstevel@tonic-gate * Can no longer send. 876*7c478bd9Sstevel@tonic-gate * Caller must also call strsetwerror. 877*7c478bd9Sstevel@tonic-gate * 878*7c478bd9Sstevel@tonic-gate * We mark the peer address as no longer valid for getpeername, but 879*7c478bd9Sstevel@tonic-gate * leave it around for so_unix_close to notify the peer (that 880*7c478bd9Sstevel@tonic-gate * transport has no addressing held at that layer). 881*7c478bd9Sstevel@tonic-gate */ 882*7c478bd9Sstevel@tonic-gate void 883*7c478bd9Sstevel@tonic-gate socantsendmore(struct sonode *so) 884*7c478bd9Sstevel@tonic-gate { 885*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 886*7c478bd9Sstevel@tonic-gate so->so_state = so->so_state & ~SS_FADDR_VALID | SS_CANTSENDMORE; 887*7c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 888*7c478bd9Sstevel@tonic-gate } 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate /* 891*7c478bd9Sstevel@tonic-gate * The caller must call strseteof(,1) as well as this routine 892*7c478bd9Sstevel@tonic-gate * to change the socket state. 893*7c478bd9Sstevel@tonic-gate */ 894*7c478bd9Sstevel@tonic-gate void 895*7c478bd9Sstevel@tonic-gate socantrcvmore(struct sonode *so) 896*7c478bd9Sstevel@tonic-gate { 897*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 898*7c478bd9Sstevel@tonic-gate so->so_state |= SS_CANTRCVMORE; 899*7c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* 903*7c478bd9Sstevel@tonic-gate * The caller has sent down a "request_prim" primitive and wants to wait for 904*7c478bd9Sstevel@tonic-gate * an ack ("ack_prim") or an T_ERROR_ACK for it. 905*7c478bd9Sstevel@tonic-gate * The specified "ack_prim" can be a T_OK_ACK. 906*7c478bd9Sstevel@tonic-gate * 907*7c478bd9Sstevel@tonic-gate * Assumes that all the TPI acks are M_PCPROTO messages. 908*7c478bd9Sstevel@tonic-gate * 909*7c478bd9Sstevel@tonic-gate * Note that the socket is single-threaded (using so_lock_single) 910*7c478bd9Sstevel@tonic-gate * for all operations that generate TPI ack messages. Since 911*7c478bd9Sstevel@tonic-gate * only TPI ack messages are M_PCPROTO we should never receive 912*7c478bd9Sstevel@tonic-gate * anything except either the ack we are expecting or a T_ERROR_ACK 913*7c478bd9Sstevel@tonic-gate * for the same primitive. 914*7c478bd9Sstevel@tonic-gate */ 915*7c478bd9Sstevel@tonic-gate int 916*7c478bd9Sstevel@tonic-gate sowaitprim(struct sonode *so, t_scalar_t request_prim, t_scalar_t ack_prim, 917*7c478bd9Sstevel@tonic-gate t_uscalar_t min_size, mblk_t **mpp, clock_t wait) 918*7c478bd9Sstevel@tonic-gate { 919*7c478bd9Sstevel@tonic-gate mblk_t *mp; 920*7c478bd9Sstevel@tonic-gate union T_primitives *tpr; 921*7c478bd9Sstevel@tonic-gate int error; 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitprim(%p, %d, %d, %d, %p, %lu)\n", 924*7c478bd9Sstevel@tonic-gate so, request_prim, ack_prim, min_size, mpp, wait)); 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate error = sowaitack(so, &mp, wait); 929*7c478bd9Sstevel@tonic-gate if (error) 930*7c478bd9Sstevel@tonic-gate return (error); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("got msg %p\n", mp)); 933*7c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO || 934*7c478bd9Sstevel@tonic-gate MBLKL(mp) < sizeof (tpr->type)) { 935*7c478bd9Sstevel@tonic-gate freemsg(mp); 936*7c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 937*7c478bd9Sstevel@tonic-gate return (EPROTO); 938*7c478bd9Sstevel@tonic-gate } 939*7c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 940*7c478bd9Sstevel@tonic-gate /* 941*7c478bd9Sstevel@tonic-gate * Did we get the primitive that we were asking for? 942*7c478bd9Sstevel@tonic-gate * For T_OK_ACK we also check that it matches the request primitive. 943*7c478bd9Sstevel@tonic-gate */ 944*7c478bd9Sstevel@tonic-gate if (tpr->type == ack_prim && 945*7c478bd9Sstevel@tonic-gate (ack_prim != T_OK_ACK || 946*7c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == request_prim)) { 947*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= (ssize_t)min_size) { 948*7c478bd9Sstevel@tonic-gate /* Found what we are looking for */ 949*7c478bd9Sstevel@tonic-gate *mpp = mp; 950*7c478bd9Sstevel@tonic-gate return (0); 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate /* Too short */ 953*7c478bd9Sstevel@tonic-gate freemsg(mp); 954*7c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 955*7c478bd9Sstevel@tonic-gate return (EPROTO); 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK && 959*7c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == request_prim) { 960*7c478bd9Sstevel@tonic-gate /* Error to the primitive we were looking for */ 961*7c478bd9Sstevel@tonic-gate if (tpr->error_ack.TLI_error == TSYSERR) { 962*7c478bd9Sstevel@tonic-gate error = tpr->error_ack.UNIX_error; 963*7c478bd9Sstevel@tonic-gate } else { 964*7c478bd9Sstevel@tonic-gate error = tlitosyserr(tpr->error_ack.TLI_error); 965*7c478bd9Sstevel@tonic-gate } 966*7c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d ->%d\n", 967*7c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim, 968*7c478bd9Sstevel@tonic-gate tpr->error_ack.TLI_error, 969*7c478bd9Sstevel@tonic-gate tpr->error_ack.UNIX_error, 970*7c478bd9Sstevel@tonic-gate error)); 971*7c478bd9Sstevel@tonic-gate freemsg(mp); 972*7c478bd9Sstevel@tonic-gate return (error); 973*7c478bd9Sstevel@tonic-gate } 974*7c478bd9Sstevel@tonic-gate /* 975*7c478bd9Sstevel@tonic-gate * Wrong primitive or T_ERROR_ACK for the wrong primitive 976*7c478bd9Sstevel@tonic-gate */ 977*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 978*7c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK) { 979*7c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d\n", 980*7c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim, 981*7c478bd9Sstevel@tonic-gate tpr->error_ack.TLI_error, 982*7c478bd9Sstevel@tonic-gate tpr->error_ack.UNIX_error)); 983*7c478bd9Sstevel@tonic-gate } else if (tpr->type == T_OK_ACK) { 984*7c478bd9Sstevel@tonic-gate dprintso(so, 0, ("ok_ack for %d, expected %d for %d\n", 985*7c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim, 986*7c478bd9Sstevel@tonic-gate ack_prim, request_prim)); 987*7c478bd9Sstevel@tonic-gate } else { 988*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 989*7c478bd9Sstevel@tonic-gate ("unexpected primitive %d, expected %d for %d\n", 990*7c478bd9Sstevel@tonic-gate tpr->type, ack_prim, request_prim)); 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate freemsg(mp); 995*7c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 996*7c478bd9Sstevel@tonic-gate return (EPROTO); 997*7c478bd9Sstevel@tonic-gate } 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate /* 1000*7c478bd9Sstevel@tonic-gate * Wait for a T_OK_ACK for the specified primitive. 1001*7c478bd9Sstevel@tonic-gate */ 1002*7c478bd9Sstevel@tonic-gate int 1003*7c478bd9Sstevel@tonic-gate sowaitokack(struct sonode *so, t_scalar_t request_prim) 1004*7c478bd9Sstevel@tonic-gate { 1005*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1006*7c478bd9Sstevel@tonic-gate int error; 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate error = sowaitprim(so, request_prim, T_OK_ACK, 1009*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_ok_ack), &mp, 0); 1010*7c478bd9Sstevel@tonic-gate if (error) 1011*7c478bd9Sstevel@tonic-gate return (error); 1012*7c478bd9Sstevel@tonic-gate freemsg(mp); 1013*7c478bd9Sstevel@tonic-gate return (0); 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate /* 1017*7c478bd9Sstevel@tonic-gate * Queue a received TPI ack message on so_ack_mp. 1018*7c478bd9Sstevel@tonic-gate */ 1019*7c478bd9Sstevel@tonic-gate void 1020*7c478bd9Sstevel@tonic-gate soqueueack(struct sonode *so, mblk_t *mp) 1021*7c478bd9Sstevel@tonic-gate { 1022*7c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO) { 1023*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1024*7c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PROTO TPI ack. Prim %d\n", 1025*7c478bd9Sstevel@tonic-gate *(t_scalar_t *)mp->b_rptr); 1026*7c478bd9Sstevel@tonic-gate freemsg(mp); 1027*7c478bd9Sstevel@tonic-gate return; 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1031*7c478bd9Sstevel@tonic-gate if (so->so_ack_mp != NULL) { 1032*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("so_ack_mp already set\n")); 1033*7c478bd9Sstevel@tonic-gate freemsg(so->so_ack_mp); 1034*7c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate so->so_ack_mp = mp; 1037*7c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_ack_cv); 1038*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate /* 1042*7c478bd9Sstevel@tonic-gate * Wait for a TPI ack ignoring signals and errors. 1043*7c478bd9Sstevel@tonic-gate */ 1044*7c478bd9Sstevel@tonic-gate int 1045*7c478bd9Sstevel@tonic-gate sowaitack(struct sonode *so, mblk_t **mpp, clock_t wait) 1046*7c478bd9Sstevel@tonic-gate { 1047*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1048*7c478bd9Sstevel@tonic-gate 1049*7c478bd9Sstevel@tonic-gate while (so->so_ack_mp == NULL) { 1050*7c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 1051*7c478bd9Sstevel@tonic-gate if (wait == 0 && sock_test_timelimit != 0) 1052*7c478bd9Sstevel@tonic-gate wait = sock_test_timelimit; 1053*7c478bd9Sstevel@tonic-gate #endif 1054*7c478bd9Sstevel@tonic-gate if (wait != 0) { 1055*7c478bd9Sstevel@tonic-gate /* 1056*7c478bd9Sstevel@tonic-gate * Only wait for the time limit. 1057*7c478bd9Sstevel@tonic-gate */ 1058*7c478bd9Sstevel@tonic-gate clock_t now; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate time_to_wait(&now, wait); 1061*7c478bd9Sstevel@tonic-gate if (cv_timedwait(&so->so_ack_cv, &so->so_lock, 1062*7c478bd9Sstevel@tonic-gate now) == -1) { 1063*7c478bd9Sstevel@tonic-gate eprintsoline(so, ETIME); 1064*7c478bd9Sstevel@tonic-gate return (ETIME); 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate else 1068*7c478bd9Sstevel@tonic-gate cv_wait(&so->so_ack_cv, &so->so_lock); 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate *mpp = so->so_ack_mp; 1071*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1072*7c478bd9Sstevel@tonic-gate { 1073*7c478bd9Sstevel@tonic-gate union T_primitives *tpr; 1074*7c478bd9Sstevel@tonic-gate mblk_t *mp = *mpp; 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 1077*7c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PCPROTO); 1078*7c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_OK_ACK || 1079*7c478bd9Sstevel@tonic-gate tpr->type == T_ERROR_ACK || 1080*7c478bd9Sstevel@tonic-gate tpr->type == T_BIND_ACK || 1081*7c478bd9Sstevel@tonic-gate tpr->type == T_CAPABILITY_ACK || 1082*7c478bd9Sstevel@tonic-gate tpr->type == T_INFO_ACK || 1083*7c478bd9Sstevel@tonic-gate tpr->type == T_OPTMGMT_ACK); 1084*7c478bd9Sstevel@tonic-gate } 1085*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1086*7c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 1087*7c478bd9Sstevel@tonic-gate return (0); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate /* 1091*7c478bd9Sstevel@tonic-gate * Queue a received T_CONN_IND message on so_conn_ind_head/tail. 1092*7c478bd9Sstevel@tonic-gate */ 1093*7c478bd9Sstevel@tonic-gate void 1094*7c478bd9Sstevel@tonic-gate soqueueconnind(struct sonode *so, mblk_t *mp) 1095*7c478bd9Sstevel@tonic-gate { 1096*7c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PROTO) { 1097*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1098*7c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PCPROTO T_CONN_IND\n"); 1099*7c478bd9Sstevel@tonic-gate freemsg(mp); 1100*7c478bd9Sstevel@tonic-gate return; 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1104*7c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 1105*7c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 1106*7c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp; 1107*7c478bd9Sstevel@tonic-gate so->so_state |= SS_HASCONNIND; 1108*7c478bd9Sstevel@tonic-gate } else { 1109*7c478bd9Sstevel@tonic-gate ASSERT(so->so_state & SS_HASCONNIND); 1110*7c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail->b_next == NULL); 1111*7c478bd9Sstevel@tonic-gate so->so_conn_ind_tail->b_next = mp; 1112*7c478bd9Sstevel@tonic-gate } 1113*7c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = mp; 1114*7c478bd9Sstevel@tonic-gate /* Wakeup a single consumer of the T_CONN_IND */ 1115*7c478bd9Sstevel@tonic-gate cv_signal(&so->so_connind_cv); 1116*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* 1120*7c478bd9Sstevel@tonic-gate * Wait for a T_CONN_IND. 1121*7c478bd9Sstevel@tonic-gate * Don't wait if nonblocking. 1122*7c478bd9Sstevel@tonic-gate * Accept signals and socket errors. 1123*7c478bd9Sstevel@tonic-gate */ 1124*7c478bd9Sstevel@tonic-gate int 1125*7c478bd9Sstevel@tonic-gate sowaitconnind(struct sonode *so, int fmode, mblk_t **mpp) 1126*7c478bd9Sstevel@tonic-gate { 1127*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1128*7c478bd9Sstevel@tonic-gate int error = 0; 1129*7c478bd9Sstevel@tonic-gate 1130*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 1131*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1132*7c478bd9Sstevel@tonic-gate check_error: 1133*7c478bd9Sstevel@tonic-gate if (so->so_error) { 1134*7c478bd9Sstevel@tonic-gate error = sogeterr(so); 1135*7c478bd9Sstevel@tonic-gate if (error) { 1136*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1137*7c478bd9Sstevel@tonic-gate return (error); 1138*7c478bd9Sstevel@tonic-gate } 1139*7c478bd9Sstevel@tonic-gate } 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 1142*7c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) { 1143*7c478bd9Sstevel@tonic-gate error = EWOULDBLOCK; 1144*7c478bd9Sstevel@tonic-gate goto done; 1145*7c478bd9Sstevel@tonic-gate } 1146*7c478bd9Sstevel@tonic-gate if (!cv_wait_sig_swap(&so->so_connind_cv, &so->so_lock)) { 1147*7c478bd9Sstevel@tonic-gate error = EINTR; 1148*7c478bd9Sstevel@tonic-gate goto done; 1149*7c478bd9Sstevel@tonic-gate } 1150*7c478bd9Sstevel@tonic-gate goto check_error; 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate mp = so->so_conn_ind_head; 1153*7c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp->b_next; 1154*7c478bd9Sstevel@tonic-gate mp->b_next = NULL; 1155*7c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 1156*7c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == mp); 1157*7c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = NULL; 1158*7c478bd9Sstevel@tonic-gate so->so_state &= ~SS_HASCONNIND; 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate *mpp = mp; 1161*7c478bd9Sstevel@tonic-gate done: 1162*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1163*7c478bd9Sstevel@tonic-gate return (error); 1164*7c478bd9Sstevel@tonic-gate } 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate /* 1167*7c478bd9Sstevel@tonic-gate * Flush a T_CONN_IND matching the sequence number from the list. 1168*7c478bd9Sstevel@tonic-gate * Return zero if found; non-zero otherwise. 1169*7c478bd9Sstevel@tonic-gate * This is called very infrequently thus it is ok to do a linear search. 1170*7c478bd9Sstevel@tonic-gate */ 1171*7c478bd9Sstevel@tonic-gate int 1172*7c478bd9Sstevel@tonic-gate soflushconnind(struct sonode *so, t_scalar_t seqno) 1173*7c478bd9Sstevel@tonic-gate { 1174*7c478bd9Sstevel@tonic-gate mblk_t *prevmp, *mp; 1175*7c478bd9Sstevel@tonic-gate struct T_conn_ind *tci; 1176*7c478bd9Sstevel@tonic-gate 1177*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1178*7c478bd9Sstevel@tonic-gate for (prevmp = NULL, mp = so->so_conn_ind_head; mp != NULL; 1179*7c478bd9Sstevel@tonic-gate prevmp = mp, mp = mp->b_next) { 1180*7c478bd9Sstevel@tonic-gate tci = (struct T_conn_ind *)mp->b_rptr; 1181*7c478bd9Sstevel@tonic-gate if (tci->SEQ_number == seqno) { 1182*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 1183*7c478bd9Sstevel@tonic-gate ("t_discon_ind: found T_CONN_IND %d\n", seqno)); 1184*7c478bd9Sstevel@tonic-gate /* Deleting last? */ 1185*7c478bd9Sstevel@tonic-gate if (so->so_conn_ind_tail == mp) { 1186*7c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = prevmp; 1187*7c478bd9Sstevel@tonic-gate } 1188*7c478bd9Sstevel@tonic-gate if (prevmp == NULL) { 1189*7c478bd9Sstevel@tonic-gate /* Deleting first */ 1190*7c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp->b_next; 1191*7c478bd9Sstevel@tonic-gate } else { 1192*7c478bd9Sstevel@tonic-gate prevmp->b_next = mp->b_next; 1193*7c478bd9Sstevel@tonic-gate } 1194*7c478bd9Sstevel@tonic-gate mp->b_next = NULL; 1195*7c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 1196*7c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 1197*7c478bd9Sstevel@tonic-gate so->so_state &= ~SS_HASCONNIND; 1198*7c478bd9Sstevel@tonic-gate } else { 1199*7c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail != NULL); 1200*7c478bd9Sstevel@tonic-gate } 1201*7c478bd9Sstevel@tonic-gate so->so_error = ECONNABORTED; 1202*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1203*7c478bd9Sstevel@tonic-gate freemsg(mp); 1204*7c478bd9Sstevel@tonic-gate return (0); 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate } 1207*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1208*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("t_discon_ind: NOT found T_CONN_IND %d\n", seqno)); 1209*7c478bd9Sstevel@tonic-gate return (-1); 1210*7c478bd9Sstevel@tonic-gate } 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * Wait until the socket is connected or there is an error. 1214*7c478bd9Sstevel@tonic-gate * fmode should contain any nonblocking flags. nosig should be 1215*7c478bd9Sstevel@tonic-gate * set if the caller does not want the wait to be interrupted by a signal. 1216*7c478bd9Sstevel@tonic-gate */ 1217*7c478bd9Sstevel@tonic-gate int 1218*7c478bd9Sstevel@tonic-gate sowaitconnected(struct sonode *so, int fmode, int nosig) 1219*7c478bd9Sstevel@tonic-gate { 1220*7c478bd9Sstevel@tonic-gate int error; 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate while ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 1225*7c478bd9Sstevel@tonic-gate SS_ISCONNECTING && so->so_error == 0) { 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("waiting for SS_ISCONNECTED on %p\n", so)); 1228*7c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 1229*7c478bd9Sstevel@tonic-gate return (EINPROGRESS); 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate if (nosig) 1232*7c478bd9Sstevel@tonic-gate cv_wait(&so->so_state_cv, &so->so_lock); 1233*7c478bd9Sstevel@tonic-gate else if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) { 1234*7c478bd9Sstevel@tonic-gate /* 1235*7c478bd9Sstevel@tonic-gate * Return EINTR and let the application use 1236*7c478bd9Sstevel@tonic-gate * nonblocking techniques for detecting when 1237*7c478bd9Sstevel@tonic-gate * the connection has been established. 1238*7c478bd9Sstevel@tonic-gate */ 1239*7c478bd9Sstevel@tonic-gate return (EINTR); 1240*7c478bd9Sstevel@tonic-gate } 1241*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("awoken on %p\n", so)); 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate 1244*7c478bd9Sstevel@tonic-gate if (so->so_error != 0) { 1245*7c478bd9Sstevel@tonic-gate error = sogeterr(so); 1246*7c478bd9Sstevel@tonic-gate ASSERT(error != 0); 1247*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 1248*7c478bd9Sstevel@tonic-gate return (error); 1249*7c478bd9Sstevel@tonic-gate } 1250*7c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ISCONNECTED)) { 1251*7c478bd9Sstevel@tonic-gate /* 1252*7c478bd9Sstevel@tonic-gate * Could have received a T_ORDREL_IND or a T_DISCON_IND with 1253*7c478bd9Sstevel@tonic-gate * zero errno. Or another thread could have consumed so_error 1254*7c478bd9Sstevel@tonic-gate * e.g. by calling read. 1255*7c478bd9Sstevel@tonic-gate */ 1256*7c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 1257*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 1258*7c478bd9Sstevel@tonic-gate return (error); 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate return (0); 1261*7c478bd9Sstevel@tonic-gate } 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate /* 1265*7c478bd9Sstevel@tonic-gate * Handle the signal generation aspect of urgent data. 1266*7c478bd9Sstevel@tonic-gate */ 1267*7c478bd9Sstevel@tonic-gate static void 1268*7c478bd9Sstevel@tonic-gate so_oob_sig(struct sonode *so, int extrasig, 1269*7c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 1270*7c478bd9Sstevel@tonic-gate { 1271*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1272*7c478bd9Sstevel@tonic-gate 1273*7c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 1274*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt >= so->so_oobcnt); 1275*7c478bd9Sstevel@tonic-gate if (so->so_oobsigcnt > so->so_oobcnt) { 1276*7c478bd9Sstevel@tonic-gate /* 1277*7c478bd9Sstevel@tonic-gate * Signal has already been generated once for this 1278*7c478bd9Sstevel@tonic-gate * urgent "event". However, since TCP can receive updated 1279*7c478bd9Sstevel@tonic-gate * urgent pointers we still generate a signal. 1280*7c478bd9Sstevel@tonic-gate */ 1281*7c478bd9Sstevel@tonic-gate ASSERT(so->so_state & SS_OOBPEND); 1282*7c478bd9Sstevel@tonic-gate if (extrasig) { 1283*7c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 1284*7c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate return; 1287*7c478bd9Sstevel@tonic-gate } 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate so->so_oobsigcnt++; 1290*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt > 0); /* Wraparound */ 1291*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt > so->so_oobcnt); 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate /* 1294*7c478bd9Sstevel@tonic-gate * Record (for select/poll) that urgent data is pending. 1295*7c478bd9Sstevel@tonic-gate */ 1296*7c478bd9Sstevel@tonic-gate so->so_state |= SS_OOBPEND; 1297*7c478bd9Sstevel@tonic-gate /* 1298*7c478bd9Sstevel@tonic-gate * New urgent data on the way so forget about any old 1299*7c478bd9Sstevel@tonic-gate * urgent data. 1300*7c478bd9Sstevel@tonic-gate */ 1301*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA); 1302*7c478bd9Sstevel@tonic-gate if (so->so_oobmsg != NULL) { 1303*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sock: discarding old oob\n")); 1304*7c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 1305*7c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 1306*7c478bd9Sstevel@tonic-gate } 1307*7c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 1308*7c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 1309*7c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate /* 1313*7c478bd9Sstevel@tonic-gate * Handle the processing of the T_EXDATA_IND with urgent data. 1314*7c478bd9Sstevel@tonic-gate * Returns the T_EXDATA_IND if it should be queued on the read queue. 1315*7c478bd9Sstevel@tonic-gate */ 1316*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 1317*7c478bd9Sstevel@tonic-gate static mblk_t * 1318*7c478bd9Sstevel@tonic-gate so_oob_exdata(struct sonode *so, mblk_t *mp, 1319*7c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 1320*7c478bd9Sstevel@tonic-gate { 1321*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1322*7c478bd9Sstevel@tonic-gate 1323*7c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 1324*7c478bd9Sstevel@tonic-gate 1325*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt > so->so_oobcnt); 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate so->so_oobcnt++; 1328*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobcnt > 0); /* wraparound? */ 1329*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt >= so->so_oobcnt); 1330*7c478bd9Sstevel@tonic-gate 1331*7c478bd9Sstevel@tonic-gate /* 1332*7c478bd9Sstevel@tonic-gate * Set MSGMARK for SIOCATMARK. 1333*7c478bd9Sstevel@tonic-gate */ 1334*7c478bd9Sstevel@tonic-gate mp->b_flag |= MSGMARK; 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 1337*7c478bd9Sstevel@tonic-gate return (mp); 1338*7c478bd9Sstevel@tonic-gate } 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate /* 1341*7c478bd9Sstevel@tonic-gate * Handle the processing of the actual urgent data. 1342*7c478bd9Sstevel@tonic-gate * Returns the data mblk if it should be queued on the read queue. 1343*7c478bd9Sstevel@tonic-gate */ 1344*7c478bd9Sstevel@tonic-gate static mblk_t * 1345*7c478bd9Sstevel@tonic-gate so_oob_data(struct sonode *so, mblk_t *mp, 1346*7c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 1347*7c478bd9Sstevel@tonic-gate { 1348*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1349*7c478bd9Sstevel@tonic-gate 1350*7c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 1351*7c478bd9Sstevel@tonic-gate 1352*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt >= so->so_oobcnt); 1353*7c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 1354*7c478bd9Sstevel@tonic-gate /* 1355*7c478bd9Sstevel@tonic-gate * For OOBINLINE we keep the data in the T_EXDATA_IND. 1356*7c478bd9Sstevel@tonic-gate * Otherwise we store it in so_oobmsg. 1357*7c478bd9Sstevel@tonic-gate */ 1358*7c478bd9Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 1359*7c478bd9Sstevel@tonic-gate if (so->so_options & SO_OOBINLINE) { 1360*7c478bd9Sstevel@tonic-gate *pollwakeups |= POLLIN | POLLRDNORM | POLLRDBAND; 1361*7c478bd9Sstevel@tonic-gate *signals |= S_INPUT | S_RDNORM; 1362*7c478bd9Sstevel@tonic-gate } else { 1363*7c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 1364*7c478bd9Sstevel@tonic-gate so->so_state |= SS_HAVEOOBDATA; 1365*7c478bd9Sstevel@tonic-gate so->so_oobmsg = mp; 1366*7c478bd9Sstevel@tonic-gate mp = NULL; 1367*7c478bd9Sstevel@tonic-gate } 1368*7c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 1369*7c478bd9Sstevel@tonic-gate return (mp); 1370*7c478bd9Sstevel@tonic-gate } 1371*7c478bd9Sstevel@tonic-gate 1372*7c478bd9Sstevel@tonic-gate /* 1373*7c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 1374*7c478bd9Sstevel@tonic-gate * For delayed processing, save the T_DISCON_IND received 1375*7c478bd9Sstevel@tonic-gate * from below on so_discon_ind_mp. 1376*7c478bd9Sstevel@tonic-gate * When the message is processed the framework will call: 1377*7c478bd9Sstevel@tonic-gate * (*func)(so, mp); 1378*7c478bd9Sstevel@tonic-gate */ 1379*7c478bd9Sstevel@tonic-gate static void 1380*7c478bd9Sstevel@tonic-gate so_save_discon_ind(struct sonode *so, 1381*7c478bd9Sstevel@tonic-gate mblk_t *mp, 1382*7c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *)) 1383*7c478bd9Sstevel@tonic-gate { 1384*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate /* 1387*7c478bd9Sstevel@tonic-gate * Discard new T_DISCON_IND if we have already received another. 1388*7c478bd9Sstevel@tonic-gate * Currently the earlier message can either be on so_discon_ind_mp 1389*7c478bd9Sstevel@tonic-gate * or being processed. 1390*7c478bd9Sstevel@tonic-gate */ 1391*7c478bd9Sstevel@tonic-gate if (so->so_discon_ind_mp != NULL || (so->so_flag & SOASYNC_UNBIND)) { 1392*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1393*7c478bd9Sstevel@tonic-gate "sockfs: received unexpected additional T_DISCON_IND\n"); 1394*7c478bd9Sstevel@tonic-gate freemsg(mp); 1395*7c478bd9Sstevel@tonic-gate return; 1396*7c478bd9Sstevel@tonic-gate } 1397*7c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)func; 1398*7c478bd9Sstevel@tonic-gate mp->b_next = NULL; 1399*7c478bd9Sstevel@tonic-gate so->so_discon_ind_mp = mp; 1400*7c478bd9Sstevel@tonic-gate } 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate /* 1403*7c478bd9Sstevel@tonic-gate * Caller must hold the mutex and make sure that either SOLOCKED 1404*7c478bd9Sstevel@tonic-gate * or SOASYNC_UNBIND is set. Called from so_unlock_single(). 1405*7c478bd9Sstevel@tonic-gate * Perform delayed processing of T_DISCON_IND message on so_discon_ind_mp. 1406*7c478bd9Sstevel@tonic-gate * Need to ensure that strsock_proto() will not end up sleeping for 1407*7c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND, while executing this function. 1408*7c478bd9Sstevel@tonic-gate */ 1409*7c478bd9Sstevel@tonic-gate void 1410*7c478bd9Sstevel@tonic-gate so_drain_discon_ind(struct sonode *so) 1411*7c478bd9Sstevel@tonic-gate { 1412*7c478bd9Sstevel@tonic-gate mblk_t *bp; 1413*7c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *); 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1416*7c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & (SOLOCKED|SOASYNC_UNBIND)); 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate /* Process T_DISCON_IND on so_discon_ind_mp */ 1419*7c478bd9Sstevel@tonic-gate if ((bp = so->so_discon_ind_mp) != NULL) { 1420*7c478bd9Sstevel@tonic-gate so->so_discon_ind_mp = NULL; 1421*7c478bd9Sstevel@tonic-gate func = (void (*)())bp->b_prev; 1422*7c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate /* 1425*7c478bd9Sstevel@tonic-gate * This (*func) is supposed to generate a message downstream 1426*7c478bd9Sstevel@tonic-gate * and we need to have a flag set until the corresponding 1427*7c478bd9Sstevel@tonic-gate * upstream message reaches stream head. 1428*7c478bd9Sstevel@tonic-gate * When processing T_DISCON_IND in strsock_discon_ind 1429*7c478bd9Sstevel@tonic-gate * we hold SOASYN_UNBIND when sending T_UNBIND_REQ down and 1430*7c478bd9Sstevel@tonic-gate * drop the flag after we get the ACK in strsock_proto. 1431*7c478bd9Sstevel@tonic-gate */ 1432*7c478bd9Sstevel@tonic-gate (void) (*func)(so, bp); 1433*7c478bd9Sstevel@tonic-gate } 1434*7c478bd9Sstevel@tonic-gate } 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate /* 1437*7c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 1438*7c478bd9Sstevel@tonic-gate * Remove the T_DISCON_IND on so_discon_ind_mp. 1439*7c478bd9Sstevel@tonic-gate */ 1440*7c478bd9Sstevel@tonic-gate void 1441*7c478bd9Sstevel@tonic-gate so_flush_discon_ind(struct sonode *so) 1442*7c478bd9Sstevel@tonic-gate { 1443*7c478bd9Sstevel@tonic-gate mblk_t *bp; 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1446*7c478bd9Sstevel@tonic-gate 1447*7c478bd9Sstevel@tonic-gate /* 1448*7c478bd9Sstevel@tonic-gate * Remove T_DISCON_IND mblk at so_discon_ind_mp. 1449*7c478bd9Sstevel@tonic-gate */ 1450*7c478bd9Sstevel@tonic-gate if ((bp = so->so_discon_ind_mp) != NULL) { 1451*7c478bd9Sstevel@tonic-gate so->so_discon_ind_mp = NULL; 1452*7c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 1453*7c478bd9Sstevel@tonic-gate freemsg(bp); 1454*7c478bd9Sstevel@tonic-gate } 1455*7c478bd9Sstevel@tonic-gate } 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate /* 1458*7c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 1459*7c478bd9Sstevel@tonic-gate * 1460*7c478bd9Sstevel@tonic-gate * This function is used to process the T_DISCON_IND message. It does 1461*7c478bd9Sstevel@tonic-gate * immediate processing when called from strsock_proto and delayed 1462*7c478bd9Sstevel@tonic-gate * processing of discon_ind saved on so_discon_ind_mp when called from 1463*7c478bd9Sstevel@tonic-gate * so_drain_discon_ind. When a T_DISCON_IND message is saved in 1464*7c478bd9Sstevel@tonic-gate * so_discon_ind_mp for delayed processing, this function is registered 1465*7c478bd9Sstevel@tonic-gate * as the callback function to process the message. 1466*7c478bd9Sstevel@tonic-gate * 1467*7c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND should be held in this function, during the non-blocking 1468*7c478bd9Sstevel@tonic-gate * unbind operation, and should be released only after we receive the ACK 1469*7c478bd9Sstevel@tonic-gate * in strsock_proto, for the T_UNBIND_REQ sent here. Since SOLOCKED is not set, 1470*7c478bd9Sstevel@tonic-gate * no TPI messages would be sent down at this time. This is to prevent M_FLUSH 1471*7c478bd9Sstevel@tonic-gate * sent from either this function or tcp_unbind(), flushing away any TPI 1472*7c478bd9Sstevel@tonic-gate * message that is being sent down and stays in a lower module's queue. 1473*7c478bd9Sstevel@tonic-gate * 1474*7c478bd9Sstevel@tonic-gate * This function drops so_lock and grabs it again. 1475*7c478bd9Sstevel@tonic-gate */ 1476*7c478bd9Sstevel@tonic-gate static void 1477*7c478bd9Sstevel@tonic-gate strsock_discon_ind(struct sonode *so, mblk_t *discon_mp) 1478*7c478bd9Sstevel@tonic-gate { 1479*7c478bd9Sstevel@tonic-gate struct vnode *vp; 1480*7c478bd9Sstevel@tonic-gate struct stdata *stp; 1481*7c478bd9Sstevel@tonic-gate union T_primitives *tpr; 1482*7c478bd9Sstevel@tonic-gate struct T_unbind_req *ubr; 1483*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1484*7c478bd9Sstevel@tonic-gate int error; 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 1487*7c478bd9Sstevel@tonic-gate ASSERT(discon_mp); 1488*7c478bd9Sstevel@tonic-gate ASSERT(discon_mp->b_rptr); 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)discon_mp->b_rptr; 1491*7c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_DISCON_IND); 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate vp = SOTOV(so); 1494*7c478bd9Sstevel@tonic-gate stp = vp->v_stream; 1495*7c478bd9Sstevel@tonic-gate ASSERT(stp); 1496*7c478bd9Sstevel@tonic-gate 1497*7c478bd9Sstevel@tonic-gate /* 1498*7c478bd9Sstevel@tonic-gate * Not a listener 1499*7c478bd9Sstevel@tonic-gate */ 1500*7c478bd9Sstevel@tonic-gate ASSERT((so->so_state & SS_ACCEPTCONN) == 0); 1501*7c478bd9Sstevel@tonic-gate 1502*7c478bd9Sstevel@tonic-gate /* 1503*7c478bd9Sstevel@tonic-gate * This assumes that the name space for DISCON_reason 1504*7c478bd9Sstevel@tonic-gate * is the errno name space. 1505*7c478bd9Sstevel@tonic-gate */ 1506*7c478bd9Sstevel@tonic-gate soisdisconnected(so, tpr->discon_ind.DISCON_reason); 1507*7c478bd9Sstevel@tonic-gate 1508*7c478bd9Sstevel@tonic-gate /* 1509*7c478bd9Sstevel@tonic-gate * Unbind with the transport without blocking. 1510*7c478bd9Sstevel@tonic-gate * If we've already received a T_DISCON_IND do not unbind. 1511*7c478bd9Sstevel@tonic-gate * 1512*7c478bd9Sstevel@tonic-gate * If there is no preallocated unbind message, we have already 1513*7c478bd9Sstevel@tonic-gate * unbound with the transport 1514*7c478bd9Sstevel@tonic-gate * 1515*7c478bd9Sstevel@tonic-gate * If the socket is not bound, no need to unbind. 1516*7c478bd9Sstevel@tonic-gate */ 1517*7c478bd9Sstevel@tonic-gate mp = so->so_unbind_mp; 1518*7c478bd9Sstevel@tonic-gate if (mp == NULL) { 1519*7c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & SS_ISBOUND)); 1520*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1521*7c478bd9Sstevel@tonic-gate } else if (!(so->so_state & SS_ISBOUND)) { 1522*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1523*7c478bd9Sstevel@tonic-gate } else { 1524*7c478bd9Sstevel@tonic-gate so->so_unbind_mp = NULL; 1525*7c478bd9Sstevel@tonic-gate 1526*7c478bd9Sstevel@tonic-gate /* 1527*7c478bd9Sstevel@tonic-gate * Is another T_DISCON_IND being processed. 1528*7c478bd9Sstevel@tonic-gate */ 1529*7c478bd9Sstevel@tonic-gate ASSERT((so->so_flag & SOASYNC_UNBIND) == 0); 1530*7c478bd9Sstevel@tonic-gate 1531*7c478bd9Sstevel@tonic-gate /* 1532*7c478bd9Sstevel@tonic-gate * Make strsock_proto ignore T_OK_ACK and T_ERROR_ACK for 1533*7c478bd9Sstevel@tonic-gate * this unbind. Set SOASYNC_UNBIND. This should be cleared 1534*7c478bd9Sstevel@tonic-gate * only after we receive the ACK in strsock_proto. 1535*7c478bd9Sstevel@tonic-gate */ 1536*7c478bd9Sstevel@tonic-gate so->so_flag |= SOASYNC_UNBIND; 1537*7c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING))); 1538*7c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISBOUND|SS_ACCEPTCONN|SS_LADDR_VALID); 1539*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate /* 1542*7c478bd9Sstevel@tonic-gate * Send down T_UNBIND_REQ ignoring flow control. 1543*7c478bd9Sstevel@tonic-gate * XXX Assumes that MSG_IGNFLOW implies that this thread 1544*7c478bd9Sstevel@tonic-gate * does not run service procedures. 1545*7c478bd9Sstevel@tonic-gate */ 1546*7c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO); 1547*7c478bd9Sstevel@tonic-gate ubr = (struct T_unbind_req *)mp->b_rptr; 1548*7c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (*ubr); 1549*7c478bd9Sstevel@tonic-gate ubr->PRIM_type = T_UNBIND_REQ; 1550*7c478bd9Sstevel@tonic-gate 1551*7c478bd9Sstevel@tonic-gate /* 1552*7c478bd9Sstevel@tonic-gate * Flush the read and write side (except stream head read queue) 1553*7c478bd9Sstevel@tonic-gate * and send down T_UNBIND_REQ. 1554*7c478bd9Sstevel@tonic-gate */ 1555*7c478bd9Sstevel@tonic-gate (void) putnextctl1(strvp2wq(SOTOV(so)), M_FLUSH, FLUSHRW); 1556*7c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 1557*7c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0); 1558*7c478bd9Sstevel@tonic-gate /* LINTED - warning: statement has no consequent: if */ 1559*7c478bd9Sstevel@tonic-gate if (error) { 1560*7c478bd9Sstevel@tonic-gate eprintsoline(so, error); 1561*7c478bd9Sstevel@tonic-gate } 1562*7c478bd9Sstevel@tonic-gate } 1563*7c478bd9Sstevel@tonic-gate 1564*7c478bd9Sstevel@tonic-gate if (tpr->discon_ind.DISCON_reason != 0) 1565*7c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 1566*7c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 1567*7c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 1568*7c478bd9Sstevel@tonic-gate /* 1569*7c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 1570*7c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 1571*7c478bd9Sstevel@tonic-gate */ 1572*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("T_DISCON_IND: error %d\n", so->so_error)); 1573*7c478bd9Sstevel@tonic-gate freemsg(discon_mp); 1574*7c478bd9Sstevel@tonic-gate 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLOUT); 1577*7c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate /* 1580*7c478bd9Sstevel@tonic-gate * Wake sleeping write 1581*7c478bd9Sstevel@tonic-gate */ 1582*7c478bd9Sstevel@tonic-gate if (stp->sd_flag & WSLEEP) { 1583*7c478bd9Sstevel@tonic-gate stp->sd_flag &= ~WSLEEP; 1584*7c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_wrq->q_wait); 1585*7c478bd9Sstevel@tonic-gate } 1586*7c478bd9Sstevel@tonic-gate 1587*7c478bd9Sstevel@tonic-gate /* 1588*7c478bd9Sstevel@tonic-gate * strsendsig can handle multiple signals with a 1589*7c478bd9Sstevel@tonic-gate * single call. Send SIGPOLL for S_OUTPUT event. 1590*7c478bd9Sstevel@tonic-gate */ 1591*7c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_OUTPUT) 1592*7c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_OUTPUT, 0, 0); 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 1595*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1596*7c478bd9Sstevel@tonic-gate } 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate /* 1599*7c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive M_PROTO 1600*7c478bd9Sstevel@tonic-gate * and M_PCPROTO messages. 1601*7c478bd9Sstevel@tonic-gate * 1602*7c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 1603*7c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed (and queued) by the stream 1604*7c478bd9Sstevel@tonic-gate * head. 1605*7c478bd9Sstevel@tonic-gate * 1606*7c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 1607*7c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. Note that since 1608*7c478bd9Sstevel@tonic-gate * sockets always deliver SIGIO for every new piece of data this routine 1609*7c478bd9Sstevel@tonic-gate * never sets *firstmsgsigs; any signals are returned in *allmsgsigs. 1610*7c478bd9Sstevel@tonic-gate * 1611*7c478bd9Sstevel@tonic-gate * This routine handles all data related TPI messages independent of 1612*7c478bd9Sstevel@tonic-gate * the type of the socket i.e. it doesn't care if T_UNITDATA_IND message 1613*7c478bd9Sstevel@tonic-gate * arrive on a SOCK_STREAM. 1614*7c478bd9Sstevel@tonic-gate */ 1615*7c478bd9Sstevel@tonic-gate static mblk_t * 1616*7c478bd9Sstevel@tonic-gate strsock_proto(vnode_t *vp, mblk_t *mp, 1617*7c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 1618*7c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 1619*7c478bd9Sstevel@tonic-gate { 1620*7c478bd9Sstevel@tonic-gate union T_primitives *tpr; 1621*7c478bd9Sstevel@tonic-gate struct sonode *so; 1622*7c478bd9Sstevel@tonic-gate 1623*7c478bd9Sstevel@tonic-gate so = VTOSO(vp); 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_proto(%p, %p)\n", vp, mp)); 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate /* Set default return values */ 1628*7c478bd9Sstevel@tonic-gate *firstmsgsigs = *wakeups = *allmsgsigs = *pollwakeups = 0; 1629*7c478bd9Sstevel@tonic-gate 1630*7c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO || 1631*7c478bd9Sstevel@tonic-gate DB_TYPE(mp) == M_PCPROTO); 1632*7c478bd9Sstevel@tonic-gate 1633*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (tpr->type)) { 1634*7c478bd9Sstevel@tonic-gate /* The message is too short to even contain the primitive */ 1635*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1636*7c478bd9Sstevel@tonic-gate "sockfs: Too short TPI message received. Len = %ld\n", 1637*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 1638*7c478bd9Sstevel@tonic-gate freemsg(mp); 1639*7c478bd9Sstevel@tonic-gate return (NULL); 1640*7c478bd9Sstevel@tonic-gate } 1641*7c478bd9Sstevel@tonic-gate if (!__TPI_PRIM_ISALIGNED(mp->b_rptr)) { 1642*7c478bd9Sstevel@tonic-gate /* The read pointer is not aligned correctly for TPI */ 1643*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1644*7c478bd9Sstevel@tonic-gate "sockfs: Unaligned TPI message received. rptr = %p\n", 1645*7c478bd9Sstevel@tonic-gate (void *)mp->b_rptr); 1646*7c478bd9Sstevel@tonic-gate freemsg(mp); 1647*7c478bd9Sstevel@tonic-gate return (NULL); 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 1650*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_proto: primitive %d\n", tpr->type)); 1651*7c478bd9Sstevel@tonic-gate 1652*7c478bd9Sstevel@tonic-gate switch (tpr->type) { 1653*7c478bd9Sstevel@tonic-gate 1654*7c478bd9Sstevel@tonic-gate case T_DATA_IND: 1655*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_data_ind)) { 1656*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1657*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_DATA_IND. Len = %ld\n", 1658*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 1659*7c478bd9Sstevel@tonic-gate freemsg(mp); 1660*7c478bd9Sstevel@tonic-gate return (NULL); 1661*7c478bd9Sstevel@tonic-gate } 1662*7c478bd9Sstevel@tonic-gate /* 1663*7c478bd9Sstevel@tonic-gate * Ignore zero-length T_DATA_IND messages. These might be 1664*7c478bd9Sstevel@tonic-gate * generated by some transports. 1665*7c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 1666*7c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 1667*7c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 1668*7c478bd9Sstevel@tonic-gate * that data is available). 1669*7c478bd9Sstevel@tonic-gate */ 1670*7c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 1671*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 1672*7c478bd9Sstevel@tonic-gate ("strsock_proto: zero length T_DATA_IND\n")); 1673*7c478bd9Sstevel@tonic-gate freemsg(mp); 1674*7c478bd9Sstevel@tonic-gate return (NULL); 1675*7c478bd9Sstevel@tonic-gate } 1676*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 1677*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 1678*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 1679*7c478bd9Sstevel@tonic-gate return (mp); 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate case T_UNITDATA_IND: { 1682*7c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi = &tpr->unitdata_ind; 1683*7c478bd9Sstevel@tonic-gate void *addr; 1684*7c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_unitdata_ind)) { 1687*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1688*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_UNITDATA_IND. Len = %ld\n", 1689*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 1690*7c478bd9Sstevel@tonic-gate freemsg(mp); 1691*7c478bd9Sstevel@tonic-gate return (NULL); 1692*7c478bd9Sstevel@tonic-gate } 1693*7c478bd9Sstevel@tonic-gate 1694*7c478bd9Sstevel@tonic-gate /* Is this is not a connected datagram socket? */ 1695*7c478bd9Sstevel@tonic-gate if ((so->so_mode & SM_CONNREQUIRED) || 1696*7c478bd9Sstevel@tonic-gate !(so->so_state & SS_ISCONNECTED)) { 1697*7c478bd9Sstevel@tonic-gate /* 1698*7c478bd9Sstevel@tonic-gate * Not a connected datagram socket. Look for 1699*7c478bd9Sstevel@tonic-gate * the SO_UNIX_CLOSE option. If such an option is found 1700*7c478bd9Sstevel@tonic-gate * discard the message (since it has no meaning 1701*7c478bd9Sstevel@tonic-gate * unless connected). 1702*7c478bd9Sstevel@tonic-gate */ 1703*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp) == 0 && 1704*7c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 1705*7c478bd9Sstevel@tonic-gate void *opt; 1706*7c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 1707*7c478bd9Sstevel@tonic-gate 1708*7c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 1709*7c478bd9Sstevel@tonic-gate optlen, __TPI_ALIGN_SIZE); 1710*7c478bd9Sstevel@tonic-gate if (opt == NULL) { 1711*7c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 1712*7c478bd9Sstevel@tonic-gate freemsg(mp); 1713*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1714*7c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 1715*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1716*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1717*7c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with " 1718*7c478bd9Sstevel@tonic-gate "invalid optlen/offset %u/%d\n", 1719*7c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 1720*7c478bd9Sstevel@tonic-gate return (NULL); 1721*7c478bd9Sstevel@tonic-gate } 1722*7c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 1723*7c478bd9Sstevel@tonic-gate freemsg(mp); 1724*7c478bd9Sstevel@tonic-gate return (NULL); 1725*7c478bd9Sstevel@tonic-gate } 1726*7c478bd9Sstevel@tonic-gate } 1727*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 1728*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 1729*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 1730*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 1731*7c478bd9Sstevel@tonic-gate if (audit_active) 1732*7c478bd9Sstevel@tonic-gate audit_sock(T_UNITDATA_IND, strvp2wq(vp), 1733*7c478bd9Sstevel@tonic-gate mp, 0); 1734*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */ 1735*7c478bd9Sstevel@tonic-gate return (mp); 1736*7c478bd9Sstevel@tonic-gate } 1737*7c478bd9Sstevel@tonic-gate 1738*7c478bd9Sstevel@tonic-gate /* 1739*7c478bd9Sstevel@tonic-gate * A connect datagram socket. For AF_INET{,6} we verify that 1740*7c478bd9Sstevel@tonic-gate * the source address matches the "connected to" address. 1741*7c478bd9Sstevel@tonic-gate * The semantics of AF_UNIX sockets is to not verify 1742*7c478bd9Sstevel@tonic-gate * the source address. 1743*7c478bd9Sstevel@tonic-gate * Note that this source address verification is transport 1744*7c478bd9Sstevel@tonic-gate * specific. Thus the real fix would be to extent TPI 1745*7c478bd9Sstevel@tonic-gate * to allow T_CONN_REQ messages to be send to connectionless 1746*7c478bd9Sstevel@tonic-gate * transport providers and always let the transport provider 1747*7c478bd9Sstevel@tonic-gate * do whatever filtering is needed. 1748*7c478bd9Sstevel@tonic-gate * 1749*7c478bd9Sstevel@tonic-gate * The verification/filtering semantics for transports 1750*7c478bd9Sstevel@tonic-gate * other than AF_INET and AF_UNIX are unknown. The choice 1751*7c478bd9Sstevel@tonic-gate * would be to either filter using bcmp or let all messages 1752*7c478bd9Sstevel@tonic-gate * get through. This code does not filter other address 1753*7c478bd9Sstevel@tonic-gate * families since this at least allows the application to 1754*7c478bd9Sstevel@tonic-gate * work around any missing filtering. 1755*7c478bd9Sstevel@tonic-gate * 1756*7c478bd9Sstevel@tonic-gate * XXX Should we move filtering to UDP/ICMP??? 1757*7c478bd9Sstevel@tonic-gate * That would require passing e.g. a T_DISCON_REQ to UDP 1758*7c478bd9Sstevel@tonic-gate * when the socket becomes unconnected. 1759*7c478bd9Sstevel@tonic-gate */ 1760*7c478bd9Sstevel@tonic-gate addrlen = tudi->SRC_length; 1761*7c478bd9Sstevel@tonic-gate /* 1762*7c478bd9Sstevel@tonic-gate * The alignment restriction is really to strict but 1763*7c478bd9Sstevel@tonic-gate * we want enough alignment to inspect the fields of 1764*7c478bd9Sstevel@tonic-gate * a sockaddr_in. 1765*7c478bd9Sstevel@tonic-gate */ 1766*7c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->SRC_offset, addrlen, 1767*7c478bd9Sstevel@tonic-gate __TPI_ALIGN_SIZE); 1768*7c478bd9Sstevel@tonic-gate if (addr == NULL) { 1769*7c478bd9Sstevel@tonic-gate freemsg(mp); 1770*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1771*7c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 1772*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1773*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1774*7c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with invalid " 1775*7c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 1776*7c478bd9Sstevel@tonic-gate addrlen, tudi->SRC_offset); 1777*7c478bd9Sstevel@tonic-gate return (NULL); 1778*7c478bd9Sstevel@tonic-gate } 1779*7c478bd9Sstevel@tonic-gate 1780*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET) { 1781*7c478bd9Sstevel@tonic-gate /* 1782*7c478bd9Sstevel@tonic-gate * For AF_INET we allow wildcarding both sin_addr 1783*7c478bd9Sstevel@tonic-gate * and sin_port. 1784*7c478bd9Sstevel@tonic-gate */ 1785*7c478bd9Sstevel@tonic-gate struct sockaddr_in *faddr, *sin; 1786*7c478bd9Sstevel@tonic-gate 1787*7c478bd9Sstevel@tonic-gate /* Prevent so_faddr_sa from changing while accessed */ 1788*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1789*7c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_len == 1790*7c478bd9Sstevel@tonic-gate (socklen_t)sizeof (struct sockaddr_in)); 1791*7c478bd9Sstevel@tonic-gate faddr = (struct sockaddr_in *)so->so_faddr_sa; 1792*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)addr; 1793*7c478bd9Sstevel@tonic-gate if (addrlen != 1794*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct sockaddr_in) || 1795*7c478bd9Sstevel@tonic-gate (sin->sin_addr.s_addr != faddr->sin_addr.s_addr && 1796*7c478bd9Sstevel@tonic-gate faddr->sin_addr.s_addr != INADDR_ANY) || 1797*7c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 1798*7c478bd9Sstevel@tonic-gate sin->sin_port != faddr->sin_port && 1799*7c478bd9Sstevel@tonic-gate faddr->sin_port != 0)) { 1800*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1801*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 1802*7c478bd9Sstevel@tonic-gate ("sockfs: T_UNITDATA_IND mismatch: %s", 1803*7c478bd9Sstevel@tonic-gate pr_addr(so->so_family, 1804*7c478bd9Sstevel@tonic-gate (struct sockaddr *)addr, 1805*7c478bd9Sstevel@tonic-gate addrlen))); 1806*7c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 1807*7c478bd9Sstevel@tonic-gate pr_addr(so->so_family, so->so_faddr_sa, 1808*7c478bd9Sstevel@tonic-gate (t_uscalar_t)so->so_faddr_len))); 1809*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1810*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1811*7c478bd9Sstevel@tonic-gate freemsg(mp); 1812*7c478bd9Sstevel@tonic-gate return (NULL); 1813*7c478bd9Sstevel@tonic-gate } 1814*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1815*7c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_INET6) { 1816*7c478bd9Sstevel@tonic-gate /* 1817*7c478bd9Sstevel@tonic-gate * For AF_INET6 we allow wildcarding both sin6_addr 1818*7c478bd9Sstevel@tonic-gate * and sin6_port. 1819*7c478bd9Sstevel@tonic-gate */ 1820*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *faddr6, *sin6; 1821*7c478bd9Sstevel@tonic-gate static struct in6_addr zeroes; /* inits to all zeros */ 1822*7c478bd9Sstevel@tonic-gate 1823*7c478bd9Sstevel@tonic-gate /* Prevent so_faddr_sa from changing while accessed */ 1824*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1825*7c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_len == 1826*7c478bd9Sstevel@tonic-gate (socklen_t)sizeof (struct sockaddr_in6)); 1827*7c478bd9Sstevel@tonic-gate faddr6 = (struct sockaddr_in6 *)so->so_faddr_sa; 1828*7c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)addr; 1829*7c478bd9Sstevel@tonic-gate /* XXX could we get a mapped address ::ffff:0.0.0.0 ? */ 1830*7c478bd9Sstevel@tonic-gate if (addrlen != 1831*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct sockaddr_in6) || 1832*7c478bd9Sstevel@tonic-gate (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 1833*7c478bd9Sstevel@tonic-gate &faddr6->sin6_addr) && 1834*7c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&faddr6->sin6_addr, &zeroes)) || 1835*7c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 1836*7c478bd9Sstevel@tonic-gate sin6->sin6_port != faddr6->sin6_port && 1837*7c478bd9Sstevel@tonic-gate faddr6->sin6_port != 0)) { 1838*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1839*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 1840*7c478bd9Sstevel@tonic-gate ("sockfs: T_UNITDATA_IND mismatch: %s", 1841*7c478bd9Sstevel@tonic-gate pr_addr(so->so_family, 1842*7c478bd9Sstevel@tonic-gate (struct sockaddr *)addr, 1843*7c478bd9Sstevel@tonic-gate addrlen))); 1844*7c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 1845*7c478bd9Sstevel@tonic-gate pr_addr(so->so_family, so->so_faddr_sa, 1846*7c478bd9Sstevel@tonic-gate (t_uscalar_t)so->so_faddr_len))); 1847*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1848*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1849*7c478bd9Sstevel@tonic-gate freemsg(mp); 1850*7c478bd9Sstevel@tonic-gate return (NULL); 1851*7c478bd9Sstevel@tonic-gate } 1852*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1853*7c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_UNIX && 1854*7c478bd9Sstevel@tonic-gate msgdsize(mp->b_cont) == 0 && 1855*7c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 1856*7c478bd9Sstevel@tonic-gate /* 1857*7c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX 1858*7c478bd9Sstevel@tonic-gate * SO_UNIX_CLOSE indication from options. 1859*7c478bd9Sstevel@tonic-gate */ 1860*7c478bd9Sstevel@tonic-gate void *opt; 1861*7c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 1862*7c478bd9Sstevel@tonic-gate 1863*7c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 1864*7c478bd9Sstevel@tonic-gate optlen, __TPI_ALIGN_SIZE); 1865*7c478bd9Sstevel@tonic-gate if (opt == NULL) { 1866*7c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 1867*7c478bd9Sstevel@tonic-gate freemsg(mp); 1868*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1869*7c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 1870*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1871*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1872*7c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with invalid " 1873*7c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 1874*7c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 1875*7c478bd9Sstevel@tonic-gate return (NULL); 1876*7c478bd9Sstevel@tonic-gate } 1877*7c478bd9Sstevel@tonic-gate /* 1878*7c478bd9Sstevel@tonic-gate * If we received a unix close indication mark the 1879*7c478bd9Sstevel@tonic-gate * socket and discard this message. 1880*7c478bd9Sstevel@tonic-gate */ 1881*7c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 1882*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1883*7c478bd9Sstevel@tonic-gate sobreakconn(so, ECONNRESET); 1884*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1885*7c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 1886*7c478bd9Sstevel@tonic-gate freemsg(mp); 1887*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 1888*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 1889*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 1890*7c478bd9Sstevel@tonic-gate return (NULL); 1891*7c478bd9Sstevel@tonic-gate } 1892*7c478bd9Sstevel@tonic-gate } 1893*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 1894*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 1895*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 1896*7c478bd9Sstevel@tonic-gate return (mp); 1897*7c478bd9Sstevel@tonic-gate } 1898*7c478bd9Sstevel@tonic-gate 1899*7c478bd9Sstevel@tonic-gate case T_OPTDATA_IND: { 1900*7c478bd9Sstevel@tonic-gate struct T_optdata_ind *tdi = &tpr->optdata_ind; 1901*7c478bd9Sstevel@tonic-gate 1902*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optdata_ind)) { 1903*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1904*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTDATA_IND. Len = %ld\n", 1905*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 1906*7c478bd9Sstevel@tonic-gate freemsg(mp); 1907*7c478bd9Sstevel@tonic-gate return (NULL); 1908*7c478bd9Sstevel@tonic-gate } 1909*7c478bd9Sstevel@tonic-gate /* 1910*7c478bd9Sstevel@tonic-gate * Allow zero-length messages carrying options. 1911*7c478bd9Sstevel@tonic-gate * This is used when carrying the SO_UNIX_CLOSE option. 1912*7c478bd9Sstevel@tonic-gate */ 1913*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp->b_cont) == 0 && 1914*7c478bd9Sstevel@tonic-gate tdi->OPT_length != 0) { 1915*7c478bd9Sstevel@tonic-gate /* 1916*7c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX close indication 1917*7c478bd9Sstevel@tonic-gate * from the options. Ignore any other options - 1918*7c478bd9Sstevel@tonic-gate * those are handled once the message is removed 1919*7c478bd9Sstevel@tonic-gate * from the queue. 1920*7c478bd9Sstevel@tonic-gate * The close indication message should not carry data. 1921*7c478bd9Sstevel@tonic-gate */ 1922*7c478bd9Sstevel@tonic-gate void *opt; 1923*7c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tdi->OPT_length; 1924*7c478bd9Sstevel@tonic-gate 1925*7c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tdi->OPT_offset, 1926*7c478bd9Sstevel@tonic-gate optlen, __TPI_ALIGN_SIZE); 1927*7c478bd9Sstevel@tonic-gate if (opt == NULL) { 1928*7c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 1929*7c478bd9Sstevel@tonic-gate freemsg(mp); 1930*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1931*7c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 1932*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1933*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1934*7c478bd9Sstevel@tonic-gate "sockfs: T_optdata_ind with invalid " 1935*7c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 1936*7c478bd9Sstevel@tonic-gate optlen, tdi->OPT_offset); 1937*7c478bd9Sstevel@tonic-gate return (NULL); 1938*7c478bd9Sstevel@tonic-gate } 1939*7c478bd9Sstevel@tonic-gate /* 1940*7c478bd9Sstevel@tonic-gate * If we received a close indication mark the 1941*7c478bd9Sstevel@tonic-gate * socket and discard this message. 1942*7c478bd9Sstevel@tonic-gate */ 1943*7c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 1944*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1945*7c478bd9Sstevel@tonic-gate socantsendmore(so); 1946*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1947*7c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 1948*7c478bd9Sstevel@tonic-gate freemsg(mp); 1949*7c478bd9Sstevel@tonic-gate return (NULL); 1950*7c478bd9Sstevel@tonic-gate } 1951*7c478bd9Sstevel@tonic-gate } 1952*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 1953*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 1954*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 1955*7c478bd9Sstevel@tonic-gate return (mp); 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate case T_EXDATA_IND: { 1959*7c478bd9Sstevel@tonic-gate mblk_t *mctl, *mdata; 1960*7c478bd9Sstevel@tonic-gate 1961*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_exdata_ind)) { 1962*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 1963*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_EXDATA_IND. Len = %ld\n", 1964*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 1965*7c478bd9Sstevel@tonic-gate freemsg(mp); 1966*7c478bd9Sstevel@tonic-gate return (NULL); 1967*7c478bd9Sstevel@tonic-gate } 1968*7c478bd9Sstevel@tonic-gate /* 1969*7c478bd9Sstevel@tonic-gate * Ignore zero-length T_EXDATA_IND messages. These might be 1970*7c478bd9Sstevel@tonic-gate * generated by some transports. 1971*7c478bd9Sstevel@tonic-gate * 1972*7c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 1973*7c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 1974*7c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 1975*7c478bd9Sstevel@tonic-gate * that data is available). 1976*7c478bd9Sstevel@tonic-gate */ 1977*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 1978*7c478bd9Sstevel@tonic-gate ("T_EXDATA_IND(%p): counts %d/%d state %s\n", 1979*7c478bd9Sstevel@tonic-gate vp, so->so_oobsigcnt, so->so_oobcnt, 1980*7c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 1981*7c478bd9Sstevel@tonic-gate 1982*7c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 1983*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 1984*7c478bd9Sstevel@tonic-gate ("strsock_proto: zero length T_EXDATA_IND\n")); 1985*7c478bd9Sstevel@tonic-gate freemsg(mp); 1986*7c478bd9Sstevel@tonic-gate return (NULL); 1987*7c478bd9Sstevel@tonic-gate } 1988*7c478bd9Sstevel@tonic-gate 1989*7c478bd9Sstevel@tonic-gate /* 1990*7c478bd9Sstevel@tonic-gate * Split into the T_EXDATA_IND and the M_DATA part. 1991*7c478bd9Sstevel@tonic-gate * We process these three pieces separately: 1992*7c478bd9Sstevel@tonic-gate * signal generation 1993*7c478bd9Sstevel@tonic-gate * handling T_EXDATA_IND 1994*7c478bd9Sstevel@tonic-gate * handling M_DATA component 1995*7c478bd9Sstevel@tonic-gate */ 1996*7c478bd9Sstevel@tonic-gate mctl = mp; 1997*7c478bd9Sstevel@tonic-gate mdata = mctl->b_cont; 1998*7c478bd9Sstevel@tonic-gate mctl->b_cont = NULL; 1999*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2000*7c478bd9Sstevel@tonic-gate so_oob_sig(so, 0, allmsgsigs, pollwakeups); 2001*7c478bd9Sstevel@tonic-gate mctl = so_oob_exdata(so, mctl, allmsgsigs, pollwakeups); 2002*7c478bd9Sstevel@tonic-gate mdata = so_oob_data(so, mdata, allmsgsigs, pollwakeups); 2003*7c478bd9Sstevel@tonic-gate 2004*7c478bd9Sstevel@tonic-gate /* 2005*7c478bd9Sstevel@tonic-gate * Pass the T_EXDATA_IND and the M_DATA back separately 2006*7c478bd9Sstevel@tonic-gate * by using b_next linkage. (The stream head will queue any 2007*7c478bd9Sstevel@tonic-gate * b_next linked messages separately.) This is needed 2008*7c478bd9Sstevel@tonic-gate * since MSGMARK applies to the last by of the message 2009*7c478bd9Sstevel@tonic-gate * hence we can not have any M_DATA component attached 2010*7c478bd9Sstevel@tonic-gate * to the marked T_EXDATA_IND. Note that the stream head 2011*7c478bd9Sstevel@tonic-gate * will not consolidate M_DATA messages onto an MSGMARK'ed 2012*7c478bd9Sstevel@tonic-gate * message in order to preserve the constraint that 2013*7c478bd9Sstevel@tonic-gate * the T_EXDATA_IND always is a separate message. 2014*7c478bd9Sstevel@tonic-gate */ 2015*7c478bd9Sstevel@tonic-gate ASSERT(mctl != NULL); 2016*7c478bd9Sstevel@tonic-gate mctl->b_next = mdata; 2017*7c478bd9Sstevel@tonic-gate mp = mctl; 2018*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2019*7c478bd9Sstevel@tonic-gate if (mdata == NULL) { 2020*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 2021*7c478bd9Sstevel@tonic-gate ("after outofline T_EXDATA_IND(%p): " 2022*7c478bd9Sstevel@tonic-gate "counts %d/%d poll 0x%x sig 0x%x state %s\n", 2023*7c478bd9Sstevel@tonic-gate vp, so->so_oobsigcnt, 2024*7c478bd9Sstevel@tonic-gate so->so_oobcnt, *pollwakeups, *allmsgsigs, 2025*7c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 2026*7c478bd9Sstevel@tonic-gate } else { 2027*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 2028*7c478bd9Sstevel@tonic-gate ("after inline T_EXDATA_IND(%p): " 2029*7c478bd9Sstevel@tonic-gate "counts %d/%d poll 0x%x sig 0x%x state %s\n", 2030*7c478bd9Sstevel@tonic-gate vp, so->so_oobsigcnt, 2031*7c478bd9Sstevel@tonic-gate so->so_oobcnt, *pollwakeups, *allmsgsigs, 2032*7c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 2033*7c478bd9Sstevel@tonic-gate } 2034*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2035*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2036*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 2037*7c478bd9Sstevel@tonic-gate return (mp); 2038*7c478bd9Sstevel@tonic-gate } 2039*7c478bd9Sstevel@tonic-gate 2040*7c478bd9Sstevel@tonic-gate case T_CONN_CON: { 2041*7c478bd9Sstevel@tonic-gate struct T_conn_con *conn_con; 2042*7c478bd9Sstevel@tonic-gate void *addr; 2043*7c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 2044*7c478bd9Sstevel@tonic-gate 2045*7c478bd9Sstevel@tonic-gate /* 2046*7c478bd9Sstevel@tonic-gate * Verify the state, update the state to ISCONNECTED, 2047*7c478bd9Sstevel@tonic-gate * record the potentially new address in the message, 2048*7c478bd9Sstevel@tonic-gate * and drop the message. 2049*7c478bd9Sstevel@tonic-gate */ 2050*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_con)) { 2051*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2052*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_CON. Len = %ld\n", 2053*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2054*7c478bd9Sstevel@tonic-gate freemsg(mp); 2055*7c478bd9Sstevel@tonic-gate return (NULL); 2056*7c478bd9Sstevel@tonic-gate } 2057*7c478bd9Sstevel@tonic-gate 2058*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2059*7c478bd9Sstevel@tonic-gate if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) != 2060*7c478bd9Sstevel@tonic-gate SS_ISCONNECTING) { 2061*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2062*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 2063*7c478bd9Sstevel@tonic-gate ("T_CONN_CON: state %x\n", so->so_state)); 2064*7c478bd9Sstevel@tonic-gate freemsg(mp); 2065*7c478bd9Sstevel@tonic-gate return (NULL); 2066*7c478bd9Sstevel@tonic-gate } 2067*7c478bd9Sstevel@tonic-gate 2068*7c478bd9Sstevel@tonic-gate conn_con = &tpr->conn_con; 2069*7c478bd9Sstevel@tonic-gate addrlen = conn_con->RES_length; 2070*7c478bd9Sstevel@tonic-gate /* 2071*7c478bd9Sstevel@tonic-gate * Allow the address to be of different size than sent down 2072*7c478bd9Sstevel@tonic-gate * in the T_CONN_REQ as long as it doesn't exceed the maxlen. 2073*7c478bd9Sstevel@tonic-gate * For AF_UNIX require the identical length. 2074*7c478bd9Sstevel@tonic-gate */ 2075*7c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX ? 2076*7c478bd9Sstevel@tonic-gate addrlen != (t_uscalar_t)sizeof (so->so_ux_laddr) : 2077*7c478bd9Sstevel@tonic-gate addrlen > (t_uscalar_t)so->so_faddr_maxlen) { 2078*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2079*7c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with different " 2080*7c478bd9Sstevel@tonic-gate "length %u/%d\n", 2081*7c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_length); 2082*7c478bd9Sstevel@tonic-gate soisdisconnected(so, EPROTO); 2083*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2084*7c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 2085*7c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 2086*7c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 2087*7c478bd9Sstevel@tonic-gate freemsg(mp); 2088*7c478bd9Sstevel@tonic-gate /* 2089*7c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 2090*7c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 2091*7c478bd9Sstevel@tonic-gate */ 2092*7c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 2093*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 2094*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 2095*7c478bd9Sstevel@tonic-gate return (NULL); 2096*7c478bd9Sstevel@tonic-gate } 2097*7c478bd9Sstevel@tonic-gate addr = sogetoff(mp, conn_con->RES_offset, addrlen, 1); 2098*7c478bd9Sstevel@tonic-gate if (addr == NULL) { 2099*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2100*7c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with invalid " 2101*7c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 2102*7c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_offset); 2103*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2104*7c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 2105*7c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 2106*7c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 2107*7c478bd9Sstevel@tonic-gate freemsg(mp); 2108*7c478bd9Sstevel@tonic-gate /* 2109*7c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 2110*7c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 2111*7c478bd9Sstevel@tonic-gate */ 2112*7c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 2113*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 2114*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 2115*7c478bd9Sstevel@tonic-gate return (NULL); 2116*7c478bd9Sstevel@tonic-gate } 2117*7c478bd9Sstevel@tonic-gate 2118*7c478bd9Sstevel@tonic-gate /* 2119*7c478bd9Sstevel@tonic-gate * Save for getpeername. 2120*7c478bd9Sstevel@tonic-gate */ 2121*7c478bd9Sstevel@tonic-gate if (so->so_family != AF_UNIX) { 2122*7c478bd9Sstevel@tonic-gate so->so_faddr_len = (socklen_t)addrlen; 2123*7c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_len <= so->so_faddr_maxlen); 2124*7c478bd9Sstevel@tonic-gate bcopy(addr, so->so_faddr_sa, addrlen); 2125*7c478bd9Sstevel@tonic-gate so->so_state |= SS_FADDR_VALID; 2126*7c478bd9Sstevel@tonic-gate } 2127*7c478bd9Sstevel@tonic-gate 2128*7c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 2129*7c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 2130*7c478bd9Sstevel@tonic-gate so->so_peercred = DB_CRED(mp); 2131*7c478bd9Sstevel@tonic-gate so->so_cpid = DB_CPID(mp); 2132*7c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 2133*7c478bd9Sstevel@tonic-gate crhold(so->so_peercred); 2134*7c478bd9Sstevel@tonic-gate 2135*7c478bd9Sstevel@tonic-gate /* Wakeup anybody sleeping in sowaitconnected */ 2136*7c478bd9Sstevel@tonic-gate soisconnected(so); 2137*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2138*7c478bd9Sstevel@tonic-gate 2139*7c478bd9Sstevel@tonic-gate /* 2140*7c478bd9Sstevel@tonic-gate * The socket is now available for sending data. 2141*7c478bd9Sstevel@tonic-gate */ 2142*7c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 2143*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 2144*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 2145*7c478bd9Sstevel@tonic-gate freemsg(mp); 2146*7c478bd9Sstevel@tonic-gate return (NULL); 2147*7c478bd9Sstevel@tonic-gate } 2148*7c478bd9Sstevel@tonic-gate 2149*7c478bd9Sstevel@tonic-gate case T_CONN_IND: 2150*7c478bd9Sstevel@tonic-gate /* 2151*7c478bd9Sstevel@tonic-gate * Verify the min size and queue the message on 2152*7c478bd9Sstevel@tonic-gate * the so_conn_ind_head/tail list. 2153*7c478bd9Sstevel@tonic-gate */ 2154*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_ind)) { 2155*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2156*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_IND. Len = %ld\n", 2157*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2158*7c478bd9Sstevel@tonic-gate freemsg(mp); 2159*7c478bd9Sstevel@tonic-gate return (NULL); 2160*7c478bd9Sstevel@tonic-gate } 2161*7c478bd9Sstevel@tonic-gate 2162*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT 2163*7c478bd9Sstevel@tonic-gate if (audit_active) 2164*7c478bd9Sstevel@tonic-gate audit_sock(T_CONN_IND, strvp2wq(vp), mp, 0); 2165*7c478bd9Sstevel@tonic-gate #endif /* C2_AUDIT */ 2166*7c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ACCEPTCONN)) { 2167*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2168*7c478bd9Sstevel@tonic-gate "sockfs: T_conn_ind on non-listening socket\n"); 2169*7c478bd9Sstevel@tonic-gate freemsg(mp); 2170*7c478bd9Sstevel@tonic-gate return (NULL); 2171*7c478bd9Sstevel@tonic-gate } 2172*7c478bd9Sstevel@tonic-gate soqueueconnind(so, mp); 2173*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 2174*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 2175*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 2176*7c478bd9Sstevel@tonic-gate return (NULL); 2177*7c478bd9Sstevel@tonic-gate 2178*7c478bd9Sstevel@tonic-gate case T_ORDREL_IND: 2179*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ordrel_ind)) { 2180*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2181*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_ORDREL_IND. Len = %ld\n", 2182*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2183*7c478bd9Sstevel@tonic-gate freemsg(mp); 2184*7c478bd9Sstevel@tonic-gate return (NULL); 2185*7c478bd9Sstevel@tonic-gate } 2186*7c478bd9Sstevel@tonic-gate 2187*7c478bd9Sstevel@tonic-gate /* 2188*7c478bd9Sstevel@tonic-gate * Some providers send this when not fully connected. 2189*7c478bd9Sstevel@tonic-gate * SunLink X.25 needs to retrieve disconnect reason after 2190*7c478bd9Sstevel@tonic-gate * disconnect for compatibility. It uses T_ORDREL_IND 2191*7c478bd9Sstevel@tonic-gate * instead of T_DISCON_IND so that it may use the 2192*7c478bd9Sstevel@tonic-gate * endpoint after a connect failure to retrieve the 2193*7c478bd9Sstevel@tonic-gate * reason using an ioctl. Thus we explicitly clear 2194*7c478bd9Sstevel@tonic-gate * SS_ISCONNECTING here for SunLink X.25. 2195*7c478bd9Sstevel@tonic-gate * This is a needed TPI violation. 2196*7c478bd9Sstevel@tonic-gate */ 2197*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2198*7c478bd9Sstevel@tonic-gate so->so_state &= ~SS_ISCONNECTING; 2199*7c478bd9Sstevel@tonic-gate socantrcvmore(so); 2200*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2201*7c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 2202*7c478bd9Sstevel@tonic-gate /* 2203*7c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 2204*7c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 2205*7c478bd9Sstevel@tonic-gate */ 2206*7c478bd9Sstevel@tonic-gate freemsg(mp); 2207*7c478bd9Sstevel@tonic-gate return (NULL); 2208*7c478bd9Sstevel@tonic-gate 2209*7c478bd9Sstevel@tonic-gate case T_DISCON_IND: 2210*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_discon_ind)) { 2211*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2212*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_DISCON_IND. Len = %ld\n", 2213*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2214*7c478bd9Sstevel@tonic-gate freemsg(mp); 2215*7c478bd9Sstevel@tonic-gate return (NULL); 2216*7c478bd9Sstevel@tonic-gate } 2217*7c478bd9Sstevel@tonic-gate if (so->so_state & SS_ACCEPTCONN) { 2218*7c478bd9Sstevel@tonic-gate /* 2219*7c478bd9Sstevel@tonic-gate * This is a listener. Look for a queued T_CONN_IND 2220*7c478bd9Sstevel@tonic-gate * with a matching sequence number and remove it 2221*7c478bd9Sstevel@tonic-gate * from the list. 2222*7c478bd9Sstevel@tonic-gate * It is normal to not find the sequence number since 2223*7c478bd9Sstevel@tonic-gate * the soaccept might have already dequeued it 2224*7c478bd9Sstevel@tonic-gate * (in which case the T_CONN_RES will fail with 2225*7c478bd9Sstevel@tonic-gate * TBADSEQ). 2226*7c478bd9Sstevel@tonic-gate */ 2227*7c478bd9Sstevel@tonic-gate (void) soflushconnind(so, tpr->discon_ind.SEQ_number); 2228*7c478bd9Sstevel@tonic-gate freemsg(mp); 2229*7c478bd9Sstevel@tonic-gate return (0); 2230*7c478bd9Sstevel@tonic-gate } 2231*7c478bd9Sstevel@tonic-gate 2232*7c478bd9Sstevel@tonic-gate /* 2233*7c478bd9Sstevel@tonic-gate * Not a listener 2234*7c478bd9Sstevel@tonic-gate * 2235*7c478bd9Sstevel@tonic-gate * If SS_CANTRCVMORE for AF_UNIX ignore the discon_reason. 2236*7c478bd9Sstevel@tonic-gate * Such a discon_ind appears when the peer has first done 2237*7c478bd9Sstevel@tonic-gate * a shutdown() followed by a close() in which case we just 2238*7c478bd9Sstevel@tonic-gate * want to record socantsendmore. 2239*7c478bd9Sstevel@tonic-gate * In this case sockfs first receives a T_ORDREL_IND followed 2240*7c478bd9Sstevel@tonic-gate * by a T_DISCON_IND. 2241*7c478bd9Sstevel@tonic-gate * Note that for other transports (e.g. TCP) we need to handle 2242*7c478bd9Sstevel@tonic-gate * the discon_ind in this case since it signals an error. 2243*7c478bd9Sstevel@tonic-gate */ 2244*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2245*7c478bd9Sstevel@tonic-gate if ((so->so_state & SS_CANTRCVMORE) && 2246*7c478bd9Sstevel@tonic-gate (so->so_family == AF_UNIX)) { 2247*7c478bd9Sstevel@tonic-gate socantsendmore(so); 2248*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2249*7c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 2250*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 2251*7c478bd9Sstevel@tonic-gate ("T_DISCON_IND: error %d\n", so->so_error)); 2252*7c478bd9Sstevel@tonic-gate freemsg(mp); 2253*7c478bd9Sstevel@tonic-gate /* 2254*7c478bd9Sstevel@tonic-gate * Set these variables for caller to process them. 2255*7c478bd9Sstevel@tonic-gate * For the else part where T_DISCON_IND is processed, 2256*7c478bd9Sstevel@tonic-gate * this will be done in the function being called 2257*7c478bd9Sstevel@tonic-gate * (strsock_discon_ind()) 2258*7c478bd9Sstevel@tonic-gate */ 2259*7c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 2260*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 2261*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 2262*7c478bd9Sstevel@tonic-gate } else if (so->so_flag & (SOASYNC_UNBIND | SOLOCKED)) { 2263*7c478bd9Sstevel@tonic-gate /* 2264*7c478bd9Sstevel@tonic-gate * Deferred processing of T_DISCON_IND 2265*7c478bd9Sstevel@tonic-gate */ 2266*7c478bd9Sstevel@tonic-gate so_save_discon_ind(so, mp, strsock_discon_ind); 2267*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2268*7c478bd9Sstevel@tonic-gate } else { 2269*7c478bd9Sstevel@tonic-gate /* 2270*7c478bd9Sstevel@tonic-gate * Process T_DISCON_IND now 2271*7c478bd9Sstevel@tonic-gate */ 2272*7c478bd9Sstevel@tonic-gate (void) strsock_discon_ind(so, mp); 2273*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2274*7c478bd9Sstevel@tonic-gate } 2275*7c478bd9Sstevel@tonic-gate return (NULL); 2276*7c478bd9Sstevel@tonic-gate 2277*7c478bd9Sstevel@tonic-gate case T_UDERROR_IND: { 2278*7c478bd9Sstevel@tonic-gate struct T_uderror_ind *tudi = &tpr->uderror_ind; 2279*7c478bd9Sstevel@tonic-gate void *addr; 2280*7c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 2281*7c478bd9Sstevel@tonic-gate int error; 2282*7c478bd9Sstevel@tonic-gate 2283*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 2284*7c478bd9Sstevel@tonic-gate ("T_UDERROR_IND: error %d\n", tudi->ERROR_type)); 2285*7c478bd9Sstevel@tonic-gate 2286*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_uderror_ind)) { 2287*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2288*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_UDERROR_IND. Len = %ld\n", 2289*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2290*7c478bd9Sstevel@tonic-gate freemsg(mp); 2291*7c478bd9Sstevel@tonic-gate return (NULL); 2292*7c478bd9Sstevel@tonic-gate } 2293*7c478bd9Sstevel@tonic-gate /* Ignore on connection-oriented transports */ 2294*7c478bd9Sstevel@tonic-gate if (so->so_mode & SM_CONNREQUIRED) { 2295*7c478bd9Sstevel@tonic-gate freemsg(mp); 2296*7c478bd9Sstevel@tonic-gate eprintsoline(so, 0); 2297*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2298*7c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind on connection-oriented " 2299*7c478bd9Sstevel@tonic-gate "transport\n"); 2300*7c478bd9Sstevel@tonic-gate return (NULL); 2301*7c478bd9Sstevel@tonic-gate } 2302*7c478bd9Sstevel@tonic-gate addrlen = tudi->DEST_length; 2303*7c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->DEST_offset, addrlen, 1); 2304*7c478bd9Sstevel@tonic-gate if (addr == NULL) { 2305*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2306*7c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind with invalid " 2307*7c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 2308*7c478bd9Sstevel@tonic-gate addrlen, tudi->DEST_offset); 2309*7c478bd9Sstevel@tonic-gate freemsg(mp); 2310*7c478bd9Sstevel@tonic-gate return (NULL); 2311*7c478bd9Sstevel@tonic-gate } 2312*7c478bd9Sstevel@tonic-gate 2313*7c478bd9Sstevel@tonic-gate /* Verify source address for connected socket. */ 2314*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2315*7c478bd9Sstevel@tonic-gate if (so->so_state & SS_ISCONNECTED) { 2316*7c478bd9Sstevel@tonic-gate void *faddr; 2317*7c478bd9Sstevel@tonic-gate t_uscalar_t faddr_len; 2318*7c478bd9Sstevel@tonic-gate boolean_t match = B_FALSE; 2319*7c478bd9Sstevel@tonic-gate 2320*7c478bd9Sstevel@tonic-gate switch (so->so_family) { 2321*7c478bd9Sstevel@tonic-gate case AF_INET: { 2322*7c478bd9Sstevel@tonic-gate /* Compare just IP address and port */ 2323*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin1, *sin2; 2324*7c478bd9Sstevel@tonic-gate 2325*7c478bd9Sstevel@tonic-gate sin1 = (struct sockaddr_in *)so->so_faddr_sa; 2326*7c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in *)addr; 2327*7c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in) && 2328*7c478bd9Sstevel@tonic-gate sin1->sin_port == sin2->sin_port && 2329*7c478bd9Sstevel@tonic-gate sin1->sin_addr.s_addr == 2330*7c478bd9Sstevel@tonic-gate sin2->sin_addr.s_addr) 2331*7c478bd9Sstevel@tonic-gate match = B_TRUE; 2332*7c478bd9Sstevel@tonic-gate break; 2333*7c478bd9Sstevel@tonic-gate } 2334*7c478bd9Sstevel@tonic-gate case AF_INET6: { 2335*7c478bd9Sstevel@tonic-gate /* Compare just IP address and port. Not flow */ 2336*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin1, *sin2; 2337*7c478bd9Sstevel@tonic-gate 2338*7c478bd9Sstevel@tonic-gate sin1 = (struct sockaddr_in6 *)so->so_faddr_sa; 2339*7c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in6 *)addr; 2340*7c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in6) && 2341*7c478bd9Sstevel@tonic-gate sin1->sin6_port == sin2->sin6_port && 2342*7c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr, 2343*7c478bd9Sstevel@tonic-gate &sin2->sin6_addr)) 2344*7c478bd9Sstevel@tonic-gate match = B_TRUE; 2345*7c478bd9Sstevel@tonic-gate break; 2346*7c478bd9Sstevel@tonic-gate } 2347*7c478bd9Sstevel@tonic-gate case AF_UNIX: 2348*7c478bd9Sstevel@tonic-gate faddr = &so->so_ux_faddr; 2349*7c478bd9Sstevel@tonic-gate faddr_len = 2350*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (so->so_ux_faddr); 2351*7c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 2352*7c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 2353*7c478bd9Sstevel@tonic-gate match = B_TRUE; 2354*7c478bd9Sstevel@tonic-gate break; 2355*7c478bd9Sstevel@tonic-gate default: 2356*7c478bd9Sstevel@tonic-gate faddr = so->so_faddr_sa; 2357*7c478bd9Sstevel@tonic-gate faddr_len = (t_uscalar_t)so->so_faddr_len; 2358*7c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 2359*7c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 2360*7c478bd9Sstevel@tonic-gate match = B_TRUE; 2361*7c478bd9Sstevel@tonic-gate break; 2362*7c478bd9Sstevel@tonic-gate } 2363*7c478bd9Sstevel@tonic-gate 2364*7c478bd9Sstevel@tonic-gate if (!match) { 2365*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2366*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 2367*7c478bd9Sstevel@tonic-gate ("sockfs: T_UDERR_IND mismatch: %s - ", 2368*7c478bd9Sstevel@tonic-gate pr_addr(so->so_family, 2369*7c478bd9Sstevel@tonic-gate (struct sockaddr *)addr, 2370*7c478bd9Sstevel@tonic-gate addrlen))); 2371*7c478bd9Sstevel@tonic-gate dprintso(so, 0, ("%s\n", 2372*7c478bd9Sstevel@tonic-gate pr_addr(so->so_family, so->so_faddr_sa, 2373*7c478bd9Sstevel@tonic-gate so->so_faddr_len))); 2374*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2375*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2376*7c478bd9Sstevel@tonic-gate freemsg(mp); 2377*7c478bd9Sstevel@tonic-gate return (NULL); 2378*7c478bd9Sstevel@tonic-gate } 2379*7c478bd9Sstevel@tonic-gate /* 2380*7c478bd9Sstevel@tonic-gate * Make the write error nonpersistent. If the error 2381*7c478bd9Sstevel@tonic-gate * is zero we use ECONNRESET. 2382*7c478bd9Sstevel@tonic-gate * This assumes that the name space for ERROR_type 2383*7c478bd9Sstevel@tonic-gate * is the errno name space. 2384*7c478bd9Sstevel@tonic-gate */ 2385*7c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 2386*7c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 2387*7c478bd9Sstevel@tonic-gate else 2388*7c478bd9Sstevel@tonic-gate error = ECONNRESET; 2389*7c478bd9Sstevel@tonic-gate 2390*7c478bd9Sstevel@tonic-gate soseterror(so, error); 2391*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2392*7c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 2393*7c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 2394*7c478bd9Sstevel@tonic-gate *wakeups = RSLEEP | WSLEEP; 2395*7c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM | S_OUTPUT; 2396*7c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM | POLLOUT; 2397*7c478bd9Sstevel@tonic-gate freemsg(mp); 2398*7c478bd9Sstevel@tonic-gate return (NULL); 2399*7c478bd9Sstevel@tonic-gate } 2400*7c478bd9Sstevel@tonic-gate /* 2401*7c478bd9Sstevel@tonic-gate * If the application asked for delayed errors 2402*7c478bd9Sstevel@tonic-gate * record the T_UDERROR_IND so_eaddr_mp and the reason in 2403*7c478bd9Sstevel@tonic-gate * so_delayed_error for delayed error posting. If the reason 2404*7c478bd9Sstevel@tonic-gate * is zero use ECONNRESET. 2405*7c478bd9Sstevel@tonic-gate * Note that delayed error indications do not make sense for 2406*7c478bd9Sstevel@tonic-gate * AF_UNIX sockets since sendto checks that the destination 2407*7c478bd9Sstevel@tonic-gate * address is valid at the time of the sendto. 2408*7c478bd9Sstevel@tonic-gate */ 2409*7c478bd9Sstevel@tonic-gate if (!(so->so_options & SO_DGRAM_ERRIND)) { 2410*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2411*7c478bd9Sstevel@tonic-gate freemsg(mp); 2412*7c478bd9Sstevel@tonic-gate return (NULL); 2413*7c478bd9Sstevel@tonic-gate } 2414*7c478bd9Sstevel@tonic-gate if (so->so_eaddr_mp != NULL) 2415*7c478bd9Sstevel@tonic-gate freemsg(so->so_eaddr_mp); 2416*7c478bd9Sstevel@tonic-gate 2417*7c478bd9Sstevel@tonic-gate so->so_eaddr_mp = mp; 2418*7c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 2419*7c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 2420*7c478bd9Sstevel@tonic-gate else 2421*7c478bd9Sstevel@tonic-gate error = ECONNRESET; 2422*7c478bd9Sstevel@tonic-gate so->so_delayed_error = (ushort_t)error; 2423*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2424*7c478bd9Sstevel@tonic-gate return (NULL); 2425*7c478bd9Sstevel@tonic-gate } 2426*7c478bd9Sstevel@tonic-gate 2427*7c478bd9Sstevel@tonic-gate case T_ERROR_ACK: 2428*7c478bd9Sstevel@tonic-gate dprintso(so, 0, 2429*7c478bd9Sstevel@tonic-gate ("strsock_proto: T_ERROR_ACK for %d, error %d/%d\n", 2430*7c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim, 2431*7c478bd9Sstevel@tonic-gate tpr->error_ack.TLI_error, 2432*7c478bd9Sstevel@tonic-gate tpr->error_ack.UNIX_error)); 2433*7c478bd9Sstevel@tonic-gate 2434*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_error_ack)) { 2435*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2436*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_ERROR_ACK. Len = %ld\n", 2437*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2438*7c478bd9Sstevel@tonic-gate freemsg(mp); 2439*7c478bd9Sstevel@tonic-gate return (NULL); 2440*7c478bd9Sstevel@tonic-gate } 2441*7c478bd9Sstevel@tonic-gate /* 2442*7c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 2443*7c478bd9Sstevel@tonic-gate */ 2444*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2445*7c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 2446*7c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == T_UNBIND_REQ) { 2447*7c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 2448*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2449*7c478bd9Sstevel@tonic-gate freemsg(mp); 2450*7c478bd9Sstevel@tonic-gate return (NULL); 2451*7c478bd9Sstevel@tonic-gate } 2452*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2453*7c478bd9Sstevel@tonic-gate soqueueack(so, mp); 2454*7c478bd9Sstevel@tonic-gate return (NULL); 2455*7c478bd9Sstevel@tonic-gate 2456*7c478bd9Sstevel@tonic-gate case T_OK_ACK: 2457*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ok_ack)) { 2458*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2459*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_OK_ACK. Len = %ld\n", 2460*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2461*7c478bd9Sstevel@tonic-gate freemsg(mp); 2462*7c478bd9Sstevel@tonic-gate return (NULL); 2463*7c478bd9Sstevel@tonic-gate } 2464*7c478bd9Sstevel@tonic-gate /* 2465*7c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 2466*7c478bd9Sstevel@tonic-gate */ 2467*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2468*7c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 2469*7c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == T_UNBIND_REQ) { 2470*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 2471*7c478bd9Sstevel@tonic-gate ("strsock_proto: T_OK_ACK async unbind\n")); 2472*7c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 2473*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2474*7c478bd9Sstevel@tonic-gate freemsg(mp); 2475*7c478bd9Sstevel@tonic-gate return (NULL); 2476*7c478bd9Sstevel@tonic-gate } 2477*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2478*7c478bd9Sstevel@tonic-gate soqueueack(so, mp); 2479*7c478bd9Sstevel@tonic-gate return (NULL); 2480*7c478bd9Sstevel@tonic-gate 2481*7c478bd9Sstevel@tonic-gate case T_INFO_ACK: 2482*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_info_ack)) { 2483*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2484*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_INFO_ACK. Len = %ld\n", 2485*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2486*7c478bd9Sstevel@tonic-gate freemsg(mp); 2487*7c478bd9Sstevel@tonic-gate return (NULL); 2488*7c478bd9Sstevel@tonic-gate } 2489*7c478bd9Sstevel@tonic-gate soqueueack(so, mp); 2490*7c478bd9Sstevel@tonic-gate return (NULL); 2491*7c478bd9Sstevel@tonic-gate 2492*7c478bd9Sstevel@tonic-gate case T_CAPABILITY_ACK: 2493*7c478bd9Sstevel@tonic-gate /* 2494*7c478bd9Sstevel@tonic-gate * A T_capability_ack need only be large enough to hold 2495*7c478bd9Sstevel@tonic-gate * the PRIM_type and CAP_bits1 fields; checking for anything 2496*7c478bd9Sstevel@tonic-gate * larger might reject a correct response from an older 2497*7c478bd9Sstevel@tonic-gate * provider. 2498*7c478bd9Sstevel@tonic-gate */ 2499*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < 2 * sizeof (t_uscalar_t)) { 2500*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2501*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_CAPABILITY_ACK. Len = %ld\n", 2502*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2503*7c478bd9Sstevel@tonic-gate freemsg(mp); 2504*7c478bd9Sstevel@tonic-gate return (NULL); 2505*7c478bd9Sstevel@tonic-gate } 2506*7c478bd9Sstevel@tonic-gate soqueueack(so, mp); 2507*7c478bd9Sstevel@tonic-gate return (NULL); 2508*7c478bd9Sstevel@tonic-gate 2509*7c478bd9Sstevel@tonic-gate case T_BIND_ACK: 2510*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_bind_ack)) { 2511*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2512*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_BIND_ACK. Len = %ld\n", 2513*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2514*7c478bd9Sstevel@tonic-gate freemsg(mp); 2515*7c478bd9Sstevel@tonic-gate return (NULL); 2516*7c478bd9Sstevel@tonic-gate } 2517*7c478bd9Sstevel@tonic-gate soqueueack(so, mp); 2518*7c478bd9Sstevel@tonic-gate return (NULL); 2519*7c478bd9Sstevel@tonic-gate 2520*7c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK: 2521*7c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optmgmt_ack)) { 2522*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2523*7c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTMGMT_ACK. Len = %ld\n", 2524*7c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 2525*7c478bd9Sstevel@tonic-gate freemsg(mp); 2526*7c478bd9Sstevel@tonic-gate return (NULL); 2527*7c478bd9Sstevel@tonic-gate } 2528*7c478bd9Sstevel@tonic-gate soqueueack(so, mp); 2529*7c478bd9Sstevel@tonic-gate return (NULL); 2530*7c478bd9Sstevel@tonic-gate default: 2531*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2532*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 2533*7c478bd9Sstevel@tonic-gate "sockfs: unknown TPI primitive %d received\n", 2534*7c478bd9Sstevel@tonic-gate tpr->type); 2535*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2536*7c478bd9Sstevel@tonic-gate freemsg(mp); 2537*7c478bd9Sstevel@tonic-gate return (NULL); 2538*7c478bd9Sstevel@tonic-gate } 2539*7c478bd9Sstevel@tonic-gate } 2540*7c478bd9Sstevel@tonic-gate 2541*7c478bd9Sstevel@tonic-gate /* 2542*7c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive other 2543*7c478bd9Sstevel@tonic-gate * (non-data, and non-proto) messages. 2544*7c478bd9Sstevel@tonic-gate * 2545*7c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 2546*7c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed by the stream head. 2547*7c478bd9Sstevel@tonic-gate * 2548*7c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 2549*7c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. 2550*7c478bd9Sstevel@tonic-gate */ 2551*7c478bd9Sstevel@tonic-gate static mblk_t * 2552*7c478bd9Sstevel@tonic-gate strsock_misc(vnode_t *vp, mblk_t *mp, 2553*7c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 2554*7c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 2555*7c478bd9Sstevel@tonic-gate { 2556*7c478bd9Sstevel@tonic-gate struct sonode *so; 2557*7c478bd9Sstevel@tonic-gate 2558*7c478bd9Sstevel@tonic-gate so = VTOSO(vp); 2559*7c478bd9Sstevel@tonic-gate 2560*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_misc(%p, %p, 0x%x)\n", 2561*7c478bd9Sstevel@tonic-gate vp, mp, DB_TYPE(mp))); 2562*7c478bd9Sstevel@tonic-gate 2563*7c478bd9Sstevel@tonic-gate /* Set default return values */ 2564*7c478bd9Sstevel@tonic-gate *wakeups = *allmsgsigs = *firstmsgsigs = *pollwakeups = 0; 2565*7c478bd9Sstevel@tonic-gate 2566*7c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 2567*7c478bd9Sstevel@tonic-gate case M_PCSIG: 2568*7c478bd9Sstevel@tonic-gate /* 2569*7c478bd9Sstevel@tonic-gate * This assumes that an M_PCSIG for the urgent data arrives 2570*7c478bd9Sstevel@tonic-gate * before the corresponding T_EXDATA_IND. 2571*7c478bd9Sstevel@tonic-gate * 2572*7c478bd9Sstevel@tonic-gate * Note: Just like in SunOS 4.X and 4.4BSD a poll will be 2573*7c478bd9Sstevel@tonic-gate * awoken before the urgent data shows up. 2574*7c478bd9Sstevel@tonic-gate * For OOBINLINE this can result in select returning 2575*7c478bd9Sstevel@tonic-gate * only exceptions as opposed to except|read. 2576*7c478bd9Sstevel@tonic-gate */ 2577*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr == SIGURG) { 2578*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2579*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 2580*7c478bd9Sstevel@tonic-gate ("SIGURG(%p): counts %d/%d state %s\n", 2581*7c478bd9Sstevel@tonic-gate vp, so->so_oobsigcnt, 2582*7c478bd9Sstevel@tonic-gate so->so_oobcnt, 2583*7c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 2584*7c478bd9Sstevel@tonic-gate so_oob_sig(so, 1, allmsgsigs, pollwakeups); 2585*7c478bd9Sstevel@tonic-gate dprintso(so, 1, 2586*7c478bd9Sstevel@tonic-gate ("after SIGURG(%p): counts %d/%d " 2587*7c478bd9Sstevel@tonic-gate " poll 0x%x sig 0x%x state %s\n", 2588*7c478bd9Sstevel@tonic-gate vp, so->so_oobsigcnt, 2589*7c478bd9Sstevel@tonic-gate so->so_oobcnt, *pollwakeups, *allmsgsigs, 2590*7c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 2591*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2592*7c478bd9Sstevel@tonic-gate } 2593*7c478bd9Sstevel@tonic-gate freemsg(mp); 2594*7c478bd9Sstevel@tonic-gate return (NULL); 2595*7c478bd9Sstevel@tonic-gate 2596*7c478bd9Sstevel@tonic-gate case M_SIG: 2597*7c478bd9Sstevel@tonic-gate case M_HANGUP: 2598*7c478bd9Sstevel@tonic-gate case M_UNHANGUP: 2599*7c478bd9Sstevel@tonic-gate case M_ERROR: 2600*7c478bd9Sstevel@tonic-gate /* M_ERRORs etc are ignored */ 2601*7c478bd9Sstevel@tonic-gate freemsg(mp); 2602*7c478bd9Sstevel@tonic-gate return (NULL); 2603*7c478bd9Sstevel@tonic-gate 2604*7c478bd9Sstevel@tonic-gate case M_FLUSH: 2605*7c478bd9Sstevel@tonic-gate /* 2606*7c478bd9Sstevel@tonic-gate * Do not flush read queue. If the M_FLUSH 2607*7c478bd9Sstevel@tonic-gate * arrives because of an impending T_discon_ind 2608*7c478bd9Sstevel@tonic-gate * we still have to keep any queued data - this is part of 2609*7c478bd9Sstevel@tonic-gate * socket semantics. 2610*7c478bd9Sstevel@tonic-gate */ 2611*7c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 2612*7c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHR; 2613*7c478bd9Sstevel@tonic-gate return (mp); 2614*7c478bd9Sstevel@tonic-gate } 2615*7c478bd9Sstevel@tonic-gate freemsg(mp); 2616*7c478bd9Sstevel@tonic-gate return (NULL); 2617*7c478bd9Sstevel@tonic-gate 2618*7c478bd9Sstevel@tonic-gate default: 2619*7c478bd9Sstevel@tonic-gate return (mp); 2620*7c478bd9Sstevel@tonic-gate } 2621*7c478bd9Sstevel@tonic-gate } 2622*7c478bd9Sstevel@tonic-gate 2623*7c478bd9Sstevel@tonic-gate 2624*7c478bd9Sstevel@tonic-gate /* Register to receive signals for certain events */ 2625*7c478bd9Sstevel@tonic-gate int 2626*7c478bd9Sstevel@tonic-gate so_set_asyncsigs(vnode_t *vp, pid_t pgrp, int events, int mode, cred_t *cr) 2627*7c478bd9Sstevel@tonic-gate { 2628*7c478bd9Sstevel@tonic-gate struct strsigset ss; 2629*7c478bd9Sstevel@tonic-gate int32_t rval; 2630*7c478bd9Sstevel@tonic-gate 2631*7c478bd9Sstevel@tonic-gate /* 2632*7c478bd9Sstevel@tonic-gate * Note that SOLOCKED will be set except for the call from soaccept(). 2633*7c478bd9Sstevel@tonic-gate */ 2634*7c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&VTOSO(vp)->so_lock)); 2635*7c478bd9Sstevel@tonic-gate ss.ss_pid = pgrp; 2636*7c478bd9Sstevel@tonic-gate ss.ss_events = events; 2637*7c478bd9Sstevel@tonic-gate return (strioctl(vp, I_ESETSIG, (intptr_t)&ss, mode, K_TO_K, cr, 2638*7c478bd9Sstevel@tonic-gate &rval)); 2639*7c478bd9Sstevel@tonic-gate } 2640*7c478bd9Sstevel@tonic-gate 2641*7c478bd9Sstevel@tonic-gate 2642*7c478bd9Sstevel@tonic-gate /* Register for events matching the SS_ASYNC flag */ 2643*7c478bd9Sstevel@tonic-gate int 2644*7c478bd9Sstevel@tonic-gate so_set_events(struct sonode *so, vnode_t *vp, cred_t *cr) 2645*7c478bd9Sstevel@tonic-gate { 2646*7c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 2647*7c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 2648*7c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 2649*7c478bd9Sstevel@tonic-gate 2650*7c478bd9Sstevel@tonic-gate return (so_set_asyncsigs(vp, so->so_pgrp, events, 0, cr)); 2651*7c478bd9Sstevel@tonic-gate } 2652*7c478bd9Sstevel@tonic-gate 2653*7c478bd9Sstevel@tonic-gate 2654*7c478bd9Sstevel@tonic-gate /* Change the SS_ASYNC flag, and update signal delivery if needed */ 2655*7c478bd9Sstevel@tonic-gate int 2656*7c478bd9Sstevel@tonic-gate so_flip_async(struct sonode *so, vnode_t *vp, int mode, cred_t *cr) 2657*7c478bd9Sstevel@tonic-gate { 2658*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 2659*7c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 2660*7c478bd9Sstevel@tonic-gate int error; 2661*7c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? /* Old flag */ 2662*7c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG : /* New sigs */ 2663*7c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT; 2664*7c478bd9Sstevel@tonic-gate 2665*7c478bd9Sstevel@tonic-gate so_lock_single(so); 2666*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2667*7c478bd9Sstevel@tonic-gate 2668*7c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, events, mode, cr); 2669*7c478bd9Sstevel@tonic-gate 2670*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2671*7c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 2672*7c478bd9Sstevel@tonic-gate if (error) 2673*7c478bd9Sstevel@tonic-gate return (error); 2674*7c478bd9Sstevel@tonic-gate } 2675*7c478bd9Sstevel@tonic-gate so->so_state ^= SS_ASYNC; 2676*7c478bd9Sstevel@tonic-gate return (0); 2677*7c478bd9Sstevel@tonic-gate } 2678*7c478bd9Sstevel@tonic-gate 2679*7c478bd9Sstevel@tonic-gate /* 2680*7c478bd9Sstevel@tonic-gate * Set new pid/pgrp for SIGPOLL (or SIGIO for FIOASYNC mode), replacing 2681*7c478bd9Sstevel@tonic-gate * any existing one. If passed zero, just clear the existing one. 2682*7c478bd9Sstevel@tonic-gate */ 2683*7c478bd9Sstevel@tonic-gate int 2684*7c478bd9Sstevel@tonic-gate so_set_siggrp(struct sonode *so, vnode_t *vp, pid_t pgrp, int mode, cred_t *cr) 2685*7c478bd9Sstevel@tonic-gate { 2686*7c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 2687*7c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 2688*7c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 2689*7c478bd9Sstevel@tonic-gate int error; 2690*7c478bd9Sstevel@tonic-gate 2691*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 2692*7c478bd9Sstevel@tonic-gate 2693*7c478bd9Sstevel@tonic-gate /* 2694*7c478bd9Sstevel@tonic-gate * Change socket process (group). 2695*7c478bd9Sstevel@tonic-gate * 2696*7c478bd9Sstevel@tonic-gate * strioctl (via so_set_asyncsigs) will perform permission check and 2697*7c478bd9Sstevel@tonic-gate * also keep a PID_HOLD to prevent the pid from being reused. 2698*7c478bd9Sstevel@tonic-gate */ 2699*7c478bd9Sstevel@tonic-gate so_lock_single(so); 2700*7c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2701*7c478bd9Sstevel@tonic-gate 2702*7c478bd9Sstevel@tonic-gate if (pgrp != 0) { 2703*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: adding pgrp %d ev 0x%x\n", 2704*7c478bd9Sstevel@tonic-gate pgrp, events)); 2705*7c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, pgrp, events, mode, cr); 2706*7c478bd9Sstevel@tonic-gate if (error != 0) { 2707*7c478bd9Sstevel@tonic-gate eprintsoline(so, error); 2708*7c478bd9Sstevel@tonic-gate goto bad; 2709*7c478bd9Sstevel@tonic-gate } 2710*7c478bd9Sstevel@tonic-gate } 2711*7c478bd9Sstevel@tonic-gate /* Remove the previously registered process/group */ 2712*7c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 2713*7c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: removing pgrp %d\n", so->so_pgrp)); 2714*7c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, 0, mode, cr); 2715*7c478bd9Sstevel@tonic-gate if (error != 0) { 2716*7c478bd9Sstevel@tonic-gate eprintsoline(so, error); 2717*7c478bd9Sstevel@tonic-gate error = 0; 2718*7c478bd9Sstevel@tonic-gate } 2719*7c478bd9Sstevel@tonic-gate } 2720*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2721*7c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 2722*7c478bd9Sstevel@tonic-gate so->so_pgrp = pgrp; 2723*7c478bd9Sstevel@tonic-gate return (0); 2724*7c478bd9Sstevel@tonic-gate bad: 2725*7c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2726*7c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 2727*7c478bd9Sstevel@tonic-gate return (error); 2728*7c478bd9Sstevel@tonic-gate } 2729*7c478bd9Sstevel@tonic-gate 2730*7c478bd9Sstevel@tonic-gate 2731*7c478bd9Sstevel@tonic-gate 2732*7c478bd9Sstevel@tonic-gate /* 2733*7c478bd9Sstevel@tonic-gate * Translate a TLI(/XTI) error into a system error as best we can. 2734*7c478bd9Sstevel@tonic-gate */ 2735*7c478bd9Sstevel@tonic-gate static const int tli_errs[] = { 2736*7c478bd9Sstevel@tonic-gate 0, /* no error */ 2737*7c478bd9Sstevel@tonic-gate EADDRNOTAVAIL, /* TBADADDR */ 2738*7c478bd9Sstevel@tonic-gate ENOPROTOOPT, /* TBADOPT */ 2739*7c478bd9Sstevel@tonic-gate EACCES, /* TACCES */ 2740*7c478bd9Sstevel@tonic-gate EBADF, /* TBADF */ 2741*7c478bd9Sstevel@tonic-gate EADDRNOTAVAIL, /* TNOADDR */ 2742*7c478bd9Sstevel@tonic-gate EPROTO, /* TOUTSTATE */ 2743*7c478bd9Sstevel@tonic-gate ECONNABORTED, /* TBADSEQ */ 2744*7c478bd9Sstevel@tonic-gate 0, /* TSYSERR - will never get */ 2745*7c478bd9Sstevel@tonic-gate EPROTO, /* TLOOK - should never be sent by transport */ 2746*7c478bd9Sstevel@tonic-gate EMSGSIZE, /* TBADDATA */ 2747*7c478bd9Sstevel@tonic-gate EMSGSIZE, /* TBUFOVFLW */ 2748*7c478bd9Sstevel@tonic-gate EPROTO, /* TFLOW */ 2749*7c478bd9Sstevel@tonic-gate EWOULDBLOCK, /* TNODATA */ 2750*7c478bd9Sstevel@tonic-gate EPROTO, /* TNODIS */ 2751*7c478bd9Sstevel@tonic-gate EPROTO, /* TNOUDERR */ 2752*7c478bd9Sstevel@tonic-gate EINVAL, /* TBADFLAG */ 2753*7c478bd9Sstevel@tonic-gate EPROTO, /* TNOREL */ 2754*7c478bd9Sstevel@tonic-gate EOPNOTSUPP, /* TNOTSUPPORT */ 2755*7c478bd9Sstevel@tonic-gate EPROTO, /* TSTATECHNG */ 2756*7c478bd9Sstevel@tonic-gate /* following represent error namespace expansion with XTI */ 2757*7c478bd9Sstevel@tonic-gate EPROTO, /* TNOSTRUCTYPE - never sent by transport */ 2758*7c478bd9Sstevel@tonic-gate EPROTO, /* TBADNAME - never sent by transport */ 2759*7c478bd9Sstevel@tonic-gate EPROTO, /* TBADQLEN - never sent by transport */ 2760*7c478bd9Sstevel@tonic-gate EADDRINUSE, /* TADDRBUSY */ 2761*7c478bd9Sstevel@tonic-gate EBADF, /* TINDOUT */ 2762*7c478bd9Sstevel@tonic-gate EBADF, /* TPROVMISMATCH */ 2763*7c478bd9Sstevel@tonic-gate EBADF, /* TRESQLEN */ 2764*7c478bd9Sstevel@tonic-gate EBADF, /* TRESADDR */ 2765*7c478bd9Sstevel@tonic-gate EPROTO, /* TQFULL - never sent by transport */ 2766*7c478bd9Sstevel@tonic-gate EPROTO, /* TPROTO */ 2767*7c478bd9Sstevel@tonic-gate }; 2768*7c478bd9Sstevel@tonic-gate 2769*7c478bd9Sstevel@tonic-gate static int 2770*7c478bd9Sstevel@tonic-gate tlitosyserr(int terr) 2771*7c478bd9Sstevel@tonic-gate { 2772*7c478bd9Sstevel@tonic-gate ASSERT(terr != TSYSERR); 2773*7c478bd9Sstevel@tonic-gate if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))) 2774*7c478bd9Sstevel@tonic-gate return (EPROTO); 2775*7c478bd9Sstevel@tonic-gate else 2776*7c478bd9Sstevel@tonic-gate return (tli_errs[terr]); 2777*7c478bd9Sstevel@tonic-gate } 2778