17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52caf0dcdSrshoaib * Common Development and Distribution License (the "License"). 62caf0dcdSrshoaib * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 212caf0dcdSrshoaib 227c478bd9Sstevel@tonic-gate /* 23*d3e55dcdSgww * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 317c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/buf.h> 357c478bd9Sstevel@tonic-gate #include <sys/conf.h> 367c478bd9Sstevel@tonic-gate #include <sys/cred.h> 377c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 397c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 407c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 417c478bd9Sstevel@tonic-gate #include <sys/debug.h> 427c478bd9Sstevel@tonic-gate #include <sys/errno.h> 437c478bd9Sstevel@tonic-gate #include <sys/time.h> 447c478bd9Sstevel@tonic-gate #include <sys/file.h> 457c478bd9Sstevel@tonic-gate #include <sys/user.h> 467c478bd9Sstevel@tonic-gate #include <sys/stream.h> 477c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 487c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 497c478bd9Sstevel@tonic-gate #include <sys/flock.h> 507c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 517c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 527c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 537c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 547c478bd9Sstevel@tonic-gate #include <sys/proc.h> 557c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 567c478bd9Sstevel@tonic-gate #include <sys/kmem_impl.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 597c478bd9Sstevel@tonic-gate #include <sys/socket.h> 607c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 617c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 627c478bd9Sstevel@tonic-gate #include <netinet/in.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 657c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 667c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 677c478bd9Sstevel@tonic-gate 68c28749e9Skais #include <inet/kssl/ksslapi.h> 69c28749e9Skais 707c478bd9Sstevel@tonic-gate #include <c2/audit.h> 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate int so_default_version = SOV_SOCKSTREAM; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #ifdef DEBUG 757c478bd9Sstevel@tonic-gate /* Set sockdebug to print debug messages when SO_DEBUG is set */ 767c478bd9Sstevel@tonic-gate int sockdebug = 0; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* Set sockprinterr to print error messages when SO_DEBUG is set */ 797c478bd9Sstevel@tonic-gate int sockprinterr = 0; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Set so_default_options to SO_DEBUG is all sockets should be created 837c478bd9Sstevel@tonic-gate * with SO_DEBUG set. This is needed to get debug printouts from the 847c478bd9Sstevel@tonic-gate * socket() call itself. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate int so_default_options = 0; 877c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Set to number of ticks to limit cv_waits for code coverage testing. 927c478bd9Sstevel@tonic-gate * Set to 1000 when SO_DEBUG is set to 2. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate clock_t sock_test_timelimit = 0; 957c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */ 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * For concurrency testing of e.g. opening /dev/ip which does not 997c478bd9Sstevel@tonic-gate * handle T_INFO_REQ messages. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate int so_no_tinfo = 0; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * Timeout for getting a T_CAPABILITY_ACK - it is possible for a provider 1057c478bd9Sstevel@tonic-gate * to simply ignore the T_CAPABILITY_REQ. 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate clock_t sock_capability_timeout = 2; /* seconds */ 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate static int do_tcapability(struct sonode *so, t_uscalar_t cap_bits1); 1107c478bd9Sstevel@tonic-gate static void so_removehooks(struct sonode *so); 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate static mblk_t *strsock_proto(vnode_t *vp, mblk_t *mp, 1137c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 1147c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 1157c478bd9Sstevel@tonic-gate static mblk_t *strsock_misc(vnode_t *vp, mblk_t *mp, 1167c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 1177c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate static int tlitosyserr(int terr); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* 1227c478bd9Sstevel@tonic-gate * Convert a socket to a stream. Invoked when the illusory sockmod 1237c478bd9Sstevel@tonic-gate * is popped from the stream. 1247c478bd9Sstevel@tonic-gate * Change the stream head back to default operation without losing 1257c478bd9Sstevel@tonic-gate * any messages (T_conn_ind's are moved to the stream head queue). 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate int 1287c478bd9Sstevel@tonic-gate so_sock2stream(struct sonode *so) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 1317c478bd9Sstevel@tonic-gate queue_t *rq; 1327c478bd9Sstevel@tonic-gate mblk_t *mp; 1337c478bd9Sstevel@tonic-gate int error = 0; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_plumb_lock)); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1387c478bd9Sstevel@tonic-gate so_lock_single(so); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate ASSERT(so->so_version != SOV_STREAM); 1417c478bd9Sstevel@tonic-gate 142ff550d0eSmasputra if (so->so_state & SS_DIRECT) { 143ff550d0eSmasputra mblk_t **mpp; 144ff550d0eSmasputra int rval; 1457c478bd9Sstevel@tonic-gate 146ff550d0eSmasputra /* 147ff550d0eSmasputra * Tell the transport below that sockmod is being popped 148ff550d0eSmasputra */ 1497c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 150ff550d0eSmasputra error = strioctl(vp, _SIOCSOCKFALLBACK, 0, 0, K_TO_K, CRED(), 1517c478bd9Sstevel@tonic-gate &rval); 1527c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1537c478bd9Sstevel@tonic-gate if (error != 0) { 154ff550d0eSmasputra dprintso(so, 0, ("so_sock2stream(%p): " 155ff550d0eSmasputra "_SIOCSOCKFALLBACK failed\n", so)); 1567c478bd9Sstevel@tonic-gate goto exit; 1577c478bd9Sstevel@tonic-gate } 158ff550d0eSmasputra so->so_state &= ~SS_DIRECT; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate for (mpp = &so->so_conn_ind_head; (mp = *mpp) != NULL; 1617c478bd9Sstevel@tonic-gate mpp = &mp->b_next) { 1627c478bd9Sstevel@tonic-gate struct T_conn_ind *conn_ind; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * strsock_proto() has already verified the length of 1667c478bd9Sstevel@tonic-gate * this message block. 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct T_conn_ind)); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 1717c478bd9Sstevel@tonic-gate if (conn_ind->OPT_length == 0 && 1727c478bd9Sstevel@tonic-gate conn_ind->OPT_offset == 0) 1737c478bd9Sstevel@tonic-gate continue; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate if (DB_REF(mp) > 1) { 1767c478bd9Sstevel@tonic-gate mblk_t *newmp; 1777c478bd9Sstevel@tonic-gate size_t length; 1787c478bd9Sstevel@tonic-gate cred_t *cr; 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * Copy the message block because it is used 1827c478bd9Sstevel@tonic-gate * elsewhere, too. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate length = MBLKL(mp); 1857c478bd9Sstevel@tonic-gate newmp = soallocproto(length, _ALLOC_INTR); 1867c478bd9Sstevel@tonic-gate if (newmp == NULL) { 1877c478bd9Sstevel@tonic-gate error = EINTR; 1887c478bd9Sstevel@tonic-gate goto exit; 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, newmp->b_wptr, length); 1917c478bd9Sstevel@tonic-gate newmp->b_wptr += length; 1927c478bd9Sstevel@tonic-gate newmp->b_next = mp->b_next; 1937c478bd9Sstevel@tonic-gate cr = DB_CRED(mp); 1947c478bd9Sstevel@tonic-gate if (cr != NULL) 1957c478bd9Sstevel@tonic-gate mblk_setcred(newmp, cr); 1967c478bd9Sstevel@tonic-gate DB_CPID(newmp) = DB_CPID(mp); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Link the new message block into the queue 2007c478bd9Sstevel@tonic-gate * and free the old one. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate *mpp = newmp; 2037c478bd9Sstevel@tonic-gate mp->b_next = NULL; 2047c478bd9Sstevel@tonic-gate freemsg(mp); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate mp = newmp; 2077c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * Remove options added by TCP for accept fast-path. 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate conn_ind->OPT_length = 0; 2147c478bd9Sstevel@tonic-gate conn_ind->OPT_offset = 0; 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate so->so_version = SOV_STREAM; 2197c478bd9Sstevel@tonic-gate so->so_priv = NULL; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* 2227c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head to avoid queuing more 2237c478bd9Sstevel@tonic-gate * packets in sockfs. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2267c478bd9Sstevel@tonic-gate so_removehooks(so); 2277c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * Clear any state related to urgent data. Leave any T_EXDATA_IND 2317c478bd9Sstevel@tonic-gate * on the queue - the behavior of urgent data after a switch is 2327c478bd9Sstevel@tonic-gate * left undefined. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate so->so_error = so->so_delayed_error = 0; 2357c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 2367c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 2377c478bd9Sstevel@tonic-gate so->so_oobsigcnt = so->so_oobcnt = 0; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_RCVATMARK|SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA| 2407c478bd9Sstevel@tonic-gate SS_HASCONNIND|SS_SAVEDEOR); 2417c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate freemsg(so->so_ack_mp); 2447c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * Flush the T_DISCON_IND on so_discon_ind_mp. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * Move any queued T_CONN_IND messages to stream head queue. 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate rq = RD(strvp2wq(vp)); 2557c478bd9Sstevel@tonic-gate while ((mp = so->so_conn_ind_head) != NULL) { 2567c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp->b_next; 2577c478bd9Sstevel@tonic-gate mp->b_next = NULL; 2587c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 2597c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == mp); 2607c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = NULL; 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate dprintso(so, 0, 263*d3e55dcdSgww ("so_sock2stream(%p): moving T_CONN_IND\n", 264*d3e55dcdSgww so)); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* Drop lock across put() */ 2677c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2687c478bd9Sstevel@tonic-gate put(rq, mp); 2697c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate exit: 2737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 2747c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 2757c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2767c478bd9Sstevel@tonic-gate return (error); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Covert a stream back to a socket. This is invoked when the illusory 2817c478bd9Sstevel@tonic-gate * sockmod is pushed on a stream (where the stream was "created" by 2827c478bd9Sstevel@tonic-gate * popping the illusory sockmod). 2837c478bd9Sstevel@tonic-gate * This routine can not recreate the socket state (certain aspects of 2847c478bd9Sstevel@tonic-gate * it like urgent data state and the bound/connected addresses for AF_UNIX 2857c478bd9Sstevel@tonic-gate * sockets can not be recreated by asking the transport for information). 2867c478bd9Sstevel@tonic-gate * Thus this routine implicitly assumes that the socket is in an initial 2877c478bd9Sstevel@tonic-gate * state (as if it was just created). It flushes any messages queued on the 2887c478bd9Sstevel@tonic-gate * read queue to avoid dealing with e.g. TPI acks or T_exdata_ind messages. 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate void 2917c478bd9Sstevel@tonic-gate so_stream2sock(struct sonode *so) 2927c478bd9Sstevel@tonic-gate { 2937c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_plumb_lock)); 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2987c478bd9Sstevel@tonic-gate so_lock_single(so); 2997c478bd9Sstevel@tonic-gate ASSERT(so->so_version == SOV_STREAM); 3007c478bd9Sstevel@tonic-gate so->so_version = SOV_SOCKSTREAM; 3017c478bd9Sstevel@tonic-gate so->so_pushcnt = 0; 3027c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * Set a permenent error to force any thread in sorecvmsg to 3067c478bd9Sstevel@tonic-gate * return (and drop SOREADLOCKED). Clear the error once 3077c478bd9Sstevel@tonic-gate * we have SOREADLOCKED. 3087c478bd9Sstevel@tonic-gate * This makes a read sleeping during the I_PUSH of sockmod return 3097c478bd9Sstevel@tonic-gate * EIO. 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), EIO, 1, NULL); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* 3147c478bd9Sstevel@tonic-gate * Get the read lock before flushing data to avoid 3157c478bd9Sstevel@tonic-gate * problems with the T_EXDATA_IND MSG_PEEK code in sorecvmsg. 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3187c478bd9Sstevel@tonic-gate (void) so_lock_read(so, 0); /* Set SOREADLOCKED */ 3197c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, NULL); 3227c478bd9Sstevel@tonic-gate so_installhooks(so); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate /* 3257c478bd9Sstevel@tonic-gate * Flush everything on the read queue. 3267c478bd9Sstevel@tonic-gate * This ensures that no T_CONN_IND remain and that no T_EXDATA_IND 3277c478bd9Sstevel@tonic-gate * remain; those types of messages would confuse sockfs. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate strflushrq(vp, FLUSHALL); 3307c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * Flush the T_DISCON_IND on so_discon_ind_mp. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 3367c478bd9Sstevel@tonic-gate so_unlock_read(so); /* Clear SOREADLOCKED */ 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 3397c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * Install the hooks in the stream head. 3447c478bd9Sstevel@tonic-gate */ 3457c478bd9Sstevel@tonic-gate void 3467c478bd9Sstevel@tonic-gate so_installhooks(struct sonode *so) 3477c478bd9Sstevel@tonic-gate { 3487c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate strsetrputhooks(vp, SH_SIGALLDATA | SH_IGN_ZEROLEN | SH_CONSOL_DATA, 3517c478bd9Sstevel@tonic-gate strsock_proto, strsock_misc); 3527c478bd9Sstevel@tonic-gate strsetwputhooks(vp, SH_SIGPIPE | SH_RECHECK_ERR, 0); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate static void 3597c478bd9Sstevel@tonic-gate so_removehooks(struct sonode *so) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate strsetrputhooks(vp, 0, NULL, NULL); 3647c478bd9Sstevel@tonic-gate strsetwputhooks(vp, 0, STRTIMOUT); 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * Leave read behavior as it would have been for a normal 3677c478bd9Sstevel@tonic-gate * stream i.e. a read of an M_PROTO will fail. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* 3727c478bd9Sstevel@tonic-gate * Initialize the streams side of a socket including 3737c478bd9Sstevel@tonic-gate * T_info_req/ack processing. If tso is not NULL its values are used thereby 3747c478bd9Sstevel@tonic-gate * avoiding the T_INFO_REQ. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate int 3777c478bd9Sstevel@tonic-gate so_strinit(struct sonode *so, struct sonode *tso) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3807c478bd9Sstevel@tonic-gate struct stdata *stp; 3817c478bd9Sstevel@tonic-gate mblk_t *mp; 3827c478bd9Sstevel@tonic-gate int error; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate dprintso(so, 1, ("so_strinit(%p)\n", so)); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* Preallocate an unbind_req message */ 3877c478bd9Sstevel@tonic-gate mp = soallocproto(sizeof (struct T_unbind_req), _ALLOC_SLEEP); 3887c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3897c478bd9Sstevel@tonic-gate so->so_unbind_mp = mp; 3907c478bd9Sstevel@tonic-gate #ifdef DEBUG 3917c478bd9Sstevel@tonic-gate so->so_options = so_default_options; 3927c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3937c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate so_installhooks(so); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * The T_CAPABILITY_REQ should be the first message sent down because 3997c478bd9Sstevel@tonic-gate * at least TCP has a fast-path for this which avoids timeouts while 4007c478bd9Sstevel@tonic-gate * waiting for the T_CAPABILITY_ACK under high system load. 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate if (tso == NULL) { 4037c478bd9Sstevel@tonic-gate error = do_tcapability(so, TC1_ACCEPTOR_ID | TC1_INFO); 4047c478bd9Sstevel@tonic-gate if (error) 4057c478bd9Sstevel@tonic-gate return (error); 4067c478bd9Sstevel@tonic-gate } else { 4077c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 4087c478bd9Sstevel@tonic-gate so->so_tsdu_size = tso->so_tsdu_size; 4097c478bd9Sstevel@tonic-gate so->so_etsdu_size = tso->so_etsdu_size; 4107c478bd9Sstevel@tonic-gate so->so_addr_size = tso->so_addr_size; 4117c478bd9Sstevel@tonic-gate so->so_opt_size = tso->so_opt_size; 4127c478bd9Sstevel@tonic-gate so->so_tidu_size = tso->so_tidu_size; 4137c478bd9Sstevel@tonic-gate so->so_serv_type = tso->so_serv_type; 4147c478bd9Sstevel@tonic-gate so->so_mode = tso->so_mode & ~SM_ACCEPTOR_ID; 4157c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* the following do_tcapability may update so->so_mode */ 4187c478bd9Sstevel@tonic-gate if ((tso->so_serv_type != T_CLTS) && 4197d6c035bSja !(tso->so_state & SS_DIRECT)) { 4207c478bd9Sstevel@tonic-gate error = do_tcapability(so, TC1_ACCEPTOR_ID); 4217c478bd9Sstevel@tonic-gate if (error) 4227c478bd9Sstevel@tonic-gate return (error); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate /* 4267c478bd9Sstevel@tonic-gate * If the addr_size is 0 we treat it as already bound 4277c478bd9Sstevel@tonic-gate * and connected. This is used by the routing socket. 4287c478bd9Sstevel@tonic-gate * We set the addr_size to something to allocate a the address 4297c478bd9Sstevel@tonic-gate * structures. 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate if (so->so_addr_size == 0) { 4327c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND | SS_ISCONNECTED; 4337c478bd9Sstevel@tonic-gate /* Address size can vary with address families. */ 4347c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET6) 4357c478bd9Sstevel@tonic-gate so->so_addr_size = 4367c478bd9Sstevel@tonic-gate (t_scalar_t)sizeof (struct sockaddr_in6); 4377c478bd9Sstevel@tonic-gate else 4387c478bd9Sstevel@tonic-gate so->so_addr_size = 4397c478bd9Sstevel@tonic-gate (t_scalar_t)sizeof (struct sockaddr_in); 4407c478bd9Sstevel@tonic-gate ASSERT(so->so_unbind_mp); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * Allocate the addresses. 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate ASSERT(so->so_laddr_sa == NULL && so->so_faddr_sa == NULL); 4467c478bd9Sstevel@tonic-gate ASSERT(so->so_laddr_len == 0 && so->so_faddr_len == 0); 4477c478bd9Sstevel@tonic-gate so->so_laddr_maxlen = so->so_faddr_maxlen = 448*d3e55dcdSgww P2ROUNDUP(so->so_addr_size, KMEM_ALIGN); 4497c478bd9Sstevel@tonic-gate so->so_laddr_sa = kmem_alloc(so->so_laddr_maxlen * 2, KM_SLEEP); 4507c478bd9Sstevel@tonic-gate so->so_faddr_sa = (struct sockaddr *)((caddr_t)so->so_laddr_sa 451*d3e55dcdSgww + so->so_laddr_maxlen); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX) { 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Initialize AF_UNIX related fields. 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate bzero(&so->so_ux_laddr, sizeof (so->so_ux_laddr)); 4587c478bd9Sstevel@tonic-gate bzero(&so->so_ux_faddr, sizeof (so->so_ux_faddr)); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate stp = vp->v_stream; 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * Have to keep minpsz at zero in order to allow write/send of zero 4647c478bd9Sstevel@tonic-gate * bytes. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 4677c478bd9Sstevel@tonic-gate if (stp->sd_qn_minpsz == 1) 4687c478bd9Sstevel@tonic-gate stp->sd_qn_minpsz = 0; 4697c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate return (0); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate static void 4757c478bd9Sstevel@tonic-gate copy_tinfo(struct sonode *so, struct T_info_ack *tia) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate so->so_tsdu_size = tia->TSDU_size; 4787c478bd9Sstevel@tonic-gate so->so_etsdu_size = tia->ETSDU_size; 4797c478bd9Sstevel@tonic-gate so->so_addr_size = tia->ADDR_size; 4807c478bd9Sstevel@tonic-gate so->so_opt_size = tia->OPT_size; 4817c478bd9Sstevel@tonic-gate so->so_tidu_size = tia->TIDU_size; 4827c478bd9Sstevel@tonic-gate so->so_serv_type = tia->SERV_type; 4837c478bd9Sstevel@tonic-gate switch (tia->CURRENT_state) { 4847c478bd9Sstevel@tonic-gate case TS_UNBND: 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate case TS_IDLE: 4877c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND; 4887c478bd9Sstevel@tonic-gate so->so_laddr_len = 0; 4897c478bd9Sstevel@tonic-gate so->so_state &= ~SS_LADDR_VALID; 4907c478bd9Sstevel@tonic-gate break; 4917c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 4927c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND|SS_ISCONNECTED; 4937c478bd9Sstevel@tonic-gate so->so_laddr_len = 0; 4947c478bd9Sstevel@tonic-gate so->so_faddr_len = 0; 4957c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_LADDR_VALID | SS_FADDR_VALID); 4967c478bd9Sstevel@tonic-gate break; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /* 5007c478bd9Sstevel@tonic-gate * Heuristics for determining the socket mode flags 5017c478bd9Sstevel@tonic-gate * (SM_ATOMIC, SM_CONNREQUIRED, SM_ADDR, SM_FDPASSING, 5027c478bd9Sstevel@tonic-gate * and SM_EXDATA, SM_OPTDATA, and SM_BYTESTREAM) 5037c478bd9Sstevel@tonic-gate * from the info ack. 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate if (so->so_serv_type == T_CLTS) { 5067c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC | SM_ADDR; 5077c478bd9Sstevel@tonic-gate } else { 5087c478bd9Sstevel@tonic-gate so->so_mode |= SM_CONNREQUIRED; 5097c478bd9Sstevel@tonic-gate if (so->so_etsdu_size != 0 && so->so_etsdu_size != -2) 5107c478bd9Sstevel@tonic-gate so->so_mode |= SM_EXDATA; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_SEQPACKET || so->so_type == SOCK_RAW) { 5137c478bd9Sstevel@tonic-gate /* Semantics are to discard tail end of messages */ 5147c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC; 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX) { 5177c478bd9Sstevel@tonic-gate so->so_mode |= SM_FDPASSING | SM_OPTDATA; 5187c478bd9Sstevel@tonic-gate if (so->so_addr_size == -1) { 5197c478bd9Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 5207c478bd9Sstevel@tonic-gate so->so_addr_size = (t_scalar_t)(MAXPATHLEN + 521*d3e55dcdSgww sizeof (short) + 1); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_STREAM) { 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * Make it into a byte-stream transport. 5267c478bd9Sstevel@tonic-gate * SOCK_SEQPACKET sockets are unchanged. 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate so->so_tsdu_size = 0; 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate } else if (so->so_addr_size == -1) { 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Logic extracted from sockmod - have to pick some max address 5337c478bd9Sstevel@tonic-gate * length in order to preallocate the addresses. 5347c478bd9Sstevel@tonic-gate */ 5357c478bd9Sstevel@tonic-gate so->so_addr_size = SOA_DEFSIZE; 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate if (so->so_tsdu_size == 0) 5387c478bd9Sstevel@tonic-gate so->so_mode |= SM_BYTESTREAM; 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate static int 5427c478bd9Sstevel@tonic-gate check_tinfo(struct sonode *so) 5437c478bd9Sstevel@tonic-gate { 5447c478bd9Sstevel@tonic-gate /* Consistency checks */ 5457c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_DGRAM && so->so_serv_type != T_CLTS) { 5467c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5477c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5487c478bd9Sstevel@tonic-gate return (EPROTO); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_STREAM && so->so_serv_type == T_CLTS) { 5517c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5527c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5537c478bd9Sstevel@tonic-gate return (EPROTO); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_SEQPACKET && so->so_serv_type == T_CLTS) { 5567c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5577c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5587c478bd9Sstevel@tonic-gate return (EPROTO); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET && 5617c478bd9Sstevel@tonic-gate so->so_addr_size != (t_scalar_t)sizeof (struct sockaddr_in)) { 5627c478bd9Sstevel@tonic-gate eprintso(so, 5637c478bd9Sstevel@tonic-gate ("AF_INET must have sockaddr_in address length. Got %d\n", 5647c478bd9Sstevel@tonic-gate so->so_addr_size)); 5657c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 5667c478bd9Sstevel@tonic-gate return (EMSGSIZE); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET6 && 5697c478bd9Sstevel@tonic-gate so->so_addr_size != (t_scalar_t)sizeof (struct sockaddr_in6)) { 5707c478bd9Sstevel@tonic-gate eprintso(so, 5717c478bd9Sstevel@tonic-gate ("AF_INET6 must have sockaddr_in6 address length. Got %d\n", 5727c478bd9Sstevel@tonic-gate so->so_addr_size)); 5737c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 5747c478bd9Sstevel@tonic-gate return (EMSGSIZE); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate dprintso(so, 1, ( 5787c478bd9Sstevel@tonic-gate "tinfo: serv %d tsdu %d, etsdu %d, addr %d, opt %d, tidu %d\n", 5797c478bd9Sstevel@tonic-gate so->so_serv_type, so->so_tsdu_size, so->so_etsdu_size, 5807c478bd9Sstevel@tonic-gate so->so_addr_size, so->so_opt_size, 5817c478bd9Sstevel@tonic-gate so->so_tidu_size)); 5827c478bd9Sstevel@tonic-gate dprintso(so, 1, ("tinfo: so_state %s\n", 583*d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 5847c478bd9Sstevel@tonic-gate return (0); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * Send down T_info_req and wait for the ack. 5897c478bd9Sstevel@tonic-gate * Record interesting T_info_ack values in the sonode. 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate static int 5927c478bd9Sstevel@tonic-gate do_tinfo(struct sonode *so) 5937c478bd9Sstevel@tonic-gate { 5947c478bd9Sstevel@tonic-gate struct T_info_req tir; 5957c478bd9Sstevel@tonic-gate mblk_t *mp; 5967c478bd9Sstevel@tonic-gate int error; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 6017c478bd9Sstevel@tonic-gate so->so_addr_size = 0; 6027c478bd9Sstevel@tonic-gate return (0); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate dprintso(so, 1, ("do_tinfo(%p)\n", so)); 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* Send T_INFO_REQ */ 6087c478bd9Sstevel@tonic-gate tir.PRIM_type = T_INFO_REQ; 6097c478bd9Sstevel@tonic-gate mp = soallocproto1(&tir, sizeof (tir), 6107c478bd9Sstevel@tonic-gate sizeof (struct T_info_req) + sizeof (struct T_info_ack), 6117c478bd9Sstevel@tonic-gate _ALLOC_INTR); 6127c478bd9Sstevel@tonic-gate if (mp == NULL) { 6137c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 6147c478bd9Sstevel@tonic-gate return (ENOBUFS); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate /* T_INFO_REQ has to be M_PCPROTO */ 6177c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 620*d3e55dcdSgww MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 6217c478bd9Sstevel@tonic-gate if (error) { 6227c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6237c478bd9Sstevel@tonic-gate return (error); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 6267c478bd9Sstevel@tonic-gate /* Wait for T_INFO_ACK */ 6277c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_INFO_REQ, T_INFO_ACK, 6287c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_info_ack), &mp, 0))) { 6297c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6307c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6317c478bd9Sstevel@tonic-gate return (error); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate ASSERT(mp); 6357c478bd9Sstevel@tonic-gate copy_tinfo(so, (struct T_info_ack *)mp->b_rptr); 6367c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6377c478bd9Sstevel@tonic-gate freemsg(mp); 6387c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * Send down T_capability_req and wait for the ack. 6437c478bd9Sstevel@tonic-gate * Record interesting T_capability_ack values in the sonode. 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate static int 6467c478bd9Sstevel@tonic-gate do_tcapability(struct sonode *so, t_uscalar_t cap_bits1) 6477c478bd9Sstevel@tonic-gate { 6487c478bd9Sstevel@tonic-gate struct T_capability_req tcr; 6497c478bd9Sstevel@tonic-gate struct T_capability_ack *tca; 6507c478bd9Sstevel@tonic-gate mblk_t *mp; 6517c478bd9Sstevel@tonic-gate int error; 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate ASSERT(cap_bits1 != 0); 6547c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & ~(TC1_ACCEPTOR_ID | TC1_INFO)) == 0); 6557c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate if (so->so_provinfo->tpi_capability == PI_NO) 6587c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 6617c478bd9Sstevel@tonic-gate so->so_addr_size = 0; 6627c478bd9Sstevel@tonic-gate if ((cap_bits1 &= ~TC1_INFO) == 0) 6637c478bd9Sstevel@tonic-gate return (0); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate dprintso(so, 1, ("do_tcapability(%p)\n", so)); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* Send T_CAPABILITY_REQ */ 6697c478bd9Sstevel@tonic-gate tcr.PRIM_type = T_CAPABILITY_REQ; 6707c478bd9Sstevel@tonic-gate tcr.CAP_bits1 = cap_bits1; 6717c478bd9Sstevel@tonic-gate mp = soallocproto1(&tcr, sizeof (tcr), 6727c478bd9Sstevel@tonic-gate sizeof (struct T_capability_req) + sizeof (struct T_capability_ack), 6737c478bd9Sstevel@tonic-gate _ALLOC_INTR); 6747c478bd9Sstevel@tonic-gate if (mp == NULL) { 6757c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 6767c478bd9Sstevel@tonic-gate return (ENOBUFS); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate /* T_CAPABILITY_REQ should be M_PCPROTO here */ 6797c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 6827c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 6837c478bd9Sstevel@tonic-gate if (error) { 6847c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6857c478bd9Sstevel@tonic-gate return (error); 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 6887c478bd9Sstevel@tonic-gate /* Wait for T_CAPABILITY_ACK */ 6897c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_CAPABILITY_REQ, T_CAPABILITY_ACK, 6907c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (*tca), &mp, sock_capability_timeout * hz))) { 6917c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6927c478bd9Sstevel@tonic-gate PI_PROVLOCK(so->so_provinfo); 6937c478bd9Sstevel@tonic-gate if (so->so_provinfo->tpi_capability == PI_DONTKNOW) 6947c478bd9Sstevel@tonic-gate so->so_provinfo->tpi_capability = PI_NO; 6957c478bd9Sstevel@tonic-gate PI_PROVUNLOCK(so->so_provinfo); 6967c478bd9Sstevel@tonic-gate ASSERT((so->so_mode & SM_ACCEPTOR_ID) == 0); 6977c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 6987c478bd9Sstevel@tonic-gate /* 6997c478bd9Sstevel@tonic-gate * If the T_CAPABILITY_REQ timed out and then a 7007c478bd9Sstevel@tonic-gate * T_INFO_REQ gets a protocol error, most likely 7017c478bd9Sstevel@tonic-gate * the capability was slow (vs. unsupported). Return 7027c478bd9Sstevel@tonic-gate * ENOSR for this case as a best guess. 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate if (error == ETIME) { 7057c478bd9Sstevel@tonic-gate return ((error = do_tinfo(so)) == EPROTO ? 7067c478bd9Sstevel@tonic-gate ENOSR : error); 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate return (0); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate if (so->so_provinfo->tpi_capability == PI_DONTKNOW) { 7147c478bd9Sstevel@tonic-gate PI_PROVLOCK(so->so_provinfo); 7157c478bd9Sstevel@tonic-gate so->so_provinfo->tpi_capability = PI_YES; 7167c478bd9Sstevel@tonic-gate PI_PROVUNLOCK(so->so_provinfo); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate ASSERT(mp); 7207c478bd9Sstevel@tonic-gate tca = (struct T_capability_ack *)mp->b_rptr; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & TC1_INFO) == (tca->CAP_bits1 & TC1_INFO)); 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate cap_bits1 = tca->CAP_bits1; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_ACCEPTOR_ID) { 7277c478bd9Sstevel@tonic-gate so->so_acceptor_id = tca->ACCEPTOR_id; 7287c478bd9Sstevel@tonic-gate so->so_mode |= SM_ACCEPTOR_ID; 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) 7327c478bd9Sstevel@tonic-gate copy_tinfo(so, &tca->INFO_ack); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 7357c478bd9Sstevel@tonic-gate freemsg(mp); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) 7387c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate return (0); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * Retrieve and clear the socket error. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate int 7477c478bd9Sstevel@tonic-gate sogeterr(struct sonode *so) 7487c478bd9Sstevel@tonic-gate { 7497c478bd9Sstevel@tonic-gate int error; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate error = so->so_error; 7547c478bd9Sstevel@tonic-gate so->so_error = 0; 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate return (error); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate /* 7607c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve read 7617c478bd9Sstevel@tonic-gate * side errors. 7627c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 7637c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate int 7667c478bd9Sstevel@tonic-gate sogetrderr(vnode_t *vp, int ispeek, int *clearerr) 7677c478bd9Sstevel@tonic-gate { 7687c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 7697c478bd9Sstevel@tonic-gate int error; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 7727c478bd9Sstevel@tonic-gate if (ispeek) { 7737c478bd9Sstevel@tonic-gate error = so->so_error; 7747c478bd9Sstevel@tonic-gate *clearerr = 0; 7757c478bd9Sstevel@tonic-gate } else { 7767c478bd9Sstevel@tonic-gate error = so->so_error; 7777c478bd9Sstevel@tonic-gate so->so_error = 0; 7787c478bd9Sstevel@tonic-gate *clearerr = 1; 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 7817c478bd9Sstevel@tonic-gate return (error); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate /* 7857c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve write 7867c478bd9Sstevel@tonic-gate * side errors. 7877c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 7887c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate int 7917c478bd9Sstevel@tonic-gate sogetwrerr(vnode_t *vp, int ispeek, int *clearerr) 7927c478bd9Sstevel@tonic-gate { 7937c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 7947c478bd9Sstevel@tonic-gate int error; 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 7977c478bd9Sstevel@tonic-gate if (so->so_state & SS_CANTSENDMORE) { 7987c478bd9Sstevel@tonic-gate error = EPIPE; 7997c478bd9Sstevel@tonic-gate *clearerr = 0; 8007c478bd9Sstevel@tonic-gate } else { 8017c478bd9Sstevel@tonic-gate error = so->so_error; 8027c478bd9Sstevel@tonic-gate if (ispeek) { 8037c478bd9Sstevel@tonic-gate *clearerr = 0; 8047c478bd9Sstevel@tonic-gate } else { 8057c478bd9Sstevel@tonic-gate so->so_error = 0; 8067c478bd9Sstevel@tonic-gate *clearerr = 1; 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 8107c478bd9Sstevel@tonic-gate return (error); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* 8147c478bd9Sstevel@tonic-gate * Set a nonpersistent read and write error on the socket. 8157c478bd9Sstevel@tonic-gate * Used when there is a T_uderror_ind for a connected socket. 8167c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror and strsetwerror 8177c478bd9Sstevel@tonic-gate * after dropping the lock. 8187c478bd9Sstevel@tonic-gate */ 8197c478bd9Sstevel@tonic-gate void 8207c478bd9Sstevel@tonic-gate soseterror(struct sonode *so, int error) 8217c478bd9Sstevel@tonic-gate { 8227c478bd9Sstevel@tonic-gate ASSERT(error != 0); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8257c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate void 8297c478bd9Sstevel@tonic-gate soisconnecting(struct sonode *so) 8307c478bd9Sstevel@tonic-gate { 8317c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8327c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); 8337c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTING; 8347c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate void 8387c478bd9Sstevel@tonic-gate soisconnected(struct sonode *so) 8397c478bd9Sstevel@tonic-gate { 8407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8417c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING); 8427c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTED; 8437c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate /* 8477c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror, strsetwerror and strseteof. 8487c478bd9Sstevel@tonic-gate */ 8497c478bd9Sstevel@tonic-gate void 8507c478bd9Sstevel@tonic-gate soisdisconnected(struct sonode *so, int error) 8517c478bd9Sstevel@tonic-gate { 8527c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8537c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING| 8547c478bd9Sstevel@tonic-gate SS_LADDR_VALID|SS_FADDR_VALID); 8557c478bd9Sstevel@tonic-gate so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); 8567c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8577c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) { 8587c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 8597c478bd9Sstevel@tonic-gate so->so_peercred = NULL; 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * For connected AF_UNIX SOCK_DGRAM sockets when the peer closes. 8667c478bd9Sstevel@tonic-gate * Does not affect write side. 8677c478bd9Sstevel@tonic-gate * The caller also has to call strsetrerror. 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate static void 8707c478bd9Sstevel@tonic-gate sobreakconn(struct sonode *so, int error) 8717c478bd9Sstevel@tonic-gate { 8727c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8737c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 8747c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8757c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * Can no longer send. 8807c478bd9Sstevel@tonic-gate * Caller must also call strsetwerror. 8817c478bd9Sstevel@tonic-gate * 8827c478bd9Sstevel@tonic-gate * We mark the peer address as no longer valid for getpeername, but 8837c478bd9Sstevel@tonic-gate * leave it around for so_unix_close to notify the peer (that 8847c478bd9Sstevel@tonic-gate * transport has no addressing held at that layer). 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate void 8877c478bd9Sstevel@tonic-gate socantsendmore(struct sonode *so) 8887c478bd9Sstevel@tonic-gate { 8897c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8907c478bd9Sstevel@tonic-gate so->so_state = so->so_state & ~SS_FADDR_VALID | SS_CANTSENDMORE; 8917c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate /* 8957c478bd9Sstevel@tonic-gate * The caller must call strseteof(,1) as well as this routine 8967c478bd9Sstevel@tonic-gate * to change the socket state. 8977c478bd9Sstevel@tonic-gate */ 8987c478bd9Sstevel@tonic-gate void 8997c478bd9Sstevel@tonic-gate socantrcvmore(struct sonode *so) 9007c478bd9Sstevel@tonic-gate { 9017c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9027c478bd9Sstevel@tonic-gate so->so_state |= SS_CANTRCVMORE; 9037c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * The caller has sent down a "request_prim" primitive and wants to wait for 9087c478bd9Sstevel@tonic-gate * an ack ("ack_prim") or an T_ERROR_ACK for it. 9097c478bd9Sstevel@tonic-gate * The specified "ack_prim" can be a T_OK_ACK. 9107c478bd9Sstevel@tonic-gate * 9117c478bd9Sstevel@tonic-gate * Assumes that all the TPI acks are M_PCPROTO messages. 9127c478bd9Sstevel@tonic-gate * 9137c478bd9Sstevel@tonic-gate * Note that the socket is single-threaded (using so_lock_single) 9147c478bd9Sstevel@tonic-gate * for all operations that generate TPI ack messages. Since 9157c478bd9Sstevel@tonic-gate * only TPI ack messages are M_PCPROTO we should never receive 9167c478bd9Sstevel@tonic-gate * anything except either the ack we are expecting or a T_ERROR_ACK 9177c478bd9Sstevel@tonic-gate * for the same primitive. 9187c478bd9Sstevel@tonic-gate */ 9197c478bd9Sstevel@tonic-gate int 9207c478bd9Sstevel@tonic-gate sowaitprim(struct sonode *so, t_scalar_t request_prim, t_scalar_t ack_prim, 9217c478bd9Sstevel@tonic-gate t_uscalar_t min_size, mblk_t **mpp, clock_t wait) 9227c478bd9Sstevel@tonic-gate { 9237c478bd9Sstevel@tonic-gate mblk_t *mp; 9247c478bd9Sstevel@tonic-gate union T_primitives *tpr; 9257c478bd9Sstevel@tonic-gate int error; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitprim(%p, %d, %d, %d, %p, %lu)\n", 928*d3e55dcdSgww so, request_prim, ack_prim, min_size, mpp, wait)); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate error = sowaitack(so, &mp, wait); 9337c478bd9Sstevel@tonic-gate if (error) 9347c478bd9Sstevel@tonic-gate return (error); 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate dprintso(so, 1, ("got msg %p\n", mp)); 9377c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO || 9387c478bd9Sstevel@tonic-gate MBLKL(mp) < sizeof (tpr->type)) { 9397c478bd9Sstevel@tonic-gate freemsg(mp); 9407c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 9417c478bd9Sstevel@tonic-gate return (EPROTO); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 9447c478bd9Sstevel@tonic-gate /* 9457c478bd9Sstevel@tonic-gate * Did we get the primitive that we were asking for? 9467c478bd9Sstevel@tonic-gate * For T_OK_ACK we also check that it matches the request primitive. 9477c478bd9Sstevel@tonic-gate */ 9487c478bd9Sstevel@tonic-gate if (tpr->type == ack_prim && 9497c478bd9Sstevel@tonic-gate (ack_prim != T_OK_ACK || 9507c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == request_prim)) { 9517c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= (ssize_t)min_size) { 9527c478bd9Sstevel@tonic-gate /* Found what we are looking for */ 9537c478bd9Sstevel@tonic-gate *mpp = mp; 9547c478bd9Sstevel@tonic-gate return (0); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate /* Too short */ 9577c478bd9Sstevel@tonic-gate freemsg(mp); 9587c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 9597c478bd9Sstevel@tonic-gate return (EPROTO); 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK && 9637c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == request_prim) { 9647c478bd9Sstevel@tonic-gate /* Error to the primitive we were looking for */ 9657c478bd9Sstevel@tonic-gate if (tpr->error_ack.TLI_error == TSYSERR) { 9667c478bd9Sstevel@tonic-gate error = tpr->error_ack.UNIX_error; 9677c478bd9Sstevel@tonic-gate } else { 9687c478bd9Sstevel@tonic-gate error = tlitosyserr(tpr->error_ack.TLI_error); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d ->%d\n", 971*d3e55dcdSgww tpr->error_ack.ERROR_prim, 972*d3e55dcdSgww tpr->error_ack.TLI_error, 973*d3e55dcdSgww tpr->error_ack.UNIX_error, 974*d3e55dcdSgww error)); 9757c478bd9Sstevel@tonic-gate freemsg(mp); 9767c478bd9Sstevel@tonic-gate return (error); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * Wrong primitive or T_ERROR_ACK for the wrong primitive 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate #ifdef DEBUG 9827c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK) { 9837c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d\n", 984*d3e55dcdSgww tpr->error_ack.ERROR_prim, 985*d3e55dcdSgww tpr->error_ack.TLI_error, 986*d3e55dcdSgww tpr->error_ack.UNIX_error)); 9877c478bd9Sstevel@tonic-gate } else if (tpr->type == T_OK_ACK) { 9887c478bd9Sstevel@tonic-gate dprintso(so, 0, ("ok_ack for %d, expected %d for %d\n", 989*d3e55dcdSgww tpr->ok_ack.CORRECT_prim, 990*d3e55dcdSgww ack_prim, request_prim)); 9917c478bd9Sstevel@tonic-gate } else { 9927c478bd9Sstevel@tonic-gate dprintso(so, 0, 993*d3e55dcdSgww ("unexpected primitive %d, expected %d for %d\n", 994*d3e55dcdSgww tpr->type, ack_prim, request_prim)); 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate freemsg(mp); 9997c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 10007c478bd9Sstevel@tonic-gate return (EPROTO); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate /* 10047c478bd9Sstevel@tonic-gate * Wait for a T_OK_ACK for the specified primitive. 10057c478bd9Sstevel@tonic-gate */ 10067c478bd9Sstevel@tonic-gate int 10077c478bd9Sstevel@tonic-gate sowaitokack(struct sonode *so, t_scalar_t request_prim) 10087c478bd9Sstevel@tonic-gate { 10097c478bd9Sstevel@tonic-gate mblk_t *mp; 10107c478bd9Sstevel@tonic-gate int error; 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate error = sowaitprim(so, request_prim, T_OK_ACK, 10137c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_ok_ack), &mp, 0); 10147c478bd9Sstevel@tonic-gate if (error) 10157c478bd9Sstevel@tonic-gate return (error); 10167c478bd9Sstevel@tonic-gate freemsg(mp); 10177c478bd9Sstevel@tonic-gate return (0); 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * Queue a received TPI ack message on so_ack_mp. 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate void 10247c478bd9Sstevel@tonic-gate soqueueack(struct sonode *so, mblk_t *mp) 10257c478bd9Sstevel@tonic-gate { 10267c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO) { 10272caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 10287c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PROTO TPI ack. Prim %d\n", 10297c478bd9Sstevel@tonic-gate *(t_scalar_t *)mp->b_rptr); 10307c478bd9Sstevel@tonic-gate freemsg(mp); 10317c478bd9Sstevel@tonic-gate return; 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 10357c478bd9Sstevel@tonic-gate if (so->so_ack_mp != NULL) { 10367c478bd9Sstevel@tonic-gate dprintso(so, 1, ("so_ack_mp already set\n")); 10377c478bd9Sstevel@tonic-gate freemsg(so->so_ack_mp); 10387c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate so->so_ack_mp = mp; 10417c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_ack_cv); 10427c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * Wait for a TPI ack ignoring signals and errors. 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate int 10497c478bd9Sstevel@tonic-gate sowaitack(struct sonode *so, mblk_t **mpp, clock_t wait) 10507c478bd9Sstevel@tonic-gate { 10517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate while (so->so_ack_mp == NULL) { 10547c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 10557c478bd9Sstevel@tonic-gate if (wait == 0 && sock_test_timelimit != 0) 10567c478bd9Sstevel@tonic-gate wait = sock_test_timelimit; 10577c478bd9Sstevel@tonic-gate #endif 10587c478bd9Sstevel@tonic-gate if (wait != 0) { 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * Only wait for the time limit. 10617c478bd9Sstevel@tonic-gate */ 10627c478bd9Sstevel@tonic-gate clock_t now; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate time_to_wait(&now, wait); 10657c478bd9Sstevel@tonic-gate if (cv_timedwait(&so->so_ack_cv, &so->so_lock, 10667c478bd9Sstevel@tonic-gate now) == -1) { 10677c478bd9Sstevel@tonic-gate eprintsoline(so, ETIME); 10687c478bd9Sstevel@tonic-gate return (ETIME); 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate else 10727c478bd9Sstevel@tonic-gate cv_wait(&so->so_ack_cv, &so->so_lock); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate *mpp = so->so_ack_mp; 10757c478bd9Sstevel@tonic-gate #ifdef DEBUG 10767c478bd9Sstevel@tonic-gate { 10777c478bd9Sstevel@tonic-gate union T_primitives *tpr; 10787c478bd9Sstevel@tonic-gate mblk_t *mp = *mpp; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 10817c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PCPROTO); 10827c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_OK_ACK || 1083*d3e55dcdSgww tpr->type == T_ERROR_ACK || 1084*d3e55dcdSgww tpr->type == T_BIND_ACK || 1085*d3e55dcdSgww tpr->type == T_CAPABILITY_ACK || 1086*d3e55dcdSgww tpr->type == T_INFO_ACK || 1087*d3e55dcdSgww tpr->type == T_OPTMGMT_ACK); 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 10907c478bd9Sstevel@tonic-gate so->so_ack_mp = NULL; 10917c478bd9Sstevel@tonic-gate return (0); 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate /* 10957c478bd9Sstevel@tonic-gate * Queue a received T_CONN_IND message on so_conn_ind_head/tail. 10967c478bd9Sstevel@tonic-gate */ 10977c478bd9Sstevel@tonic-gate void 10987c478bd9Sstevel@tonic-gate soqueueconnind(struct sonode *so, mblk_t *mp) 10997c478bd9Sstevel@tonic-gate { 11007c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PROTO) { 11012caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 11027c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PCPROTO T_CONN_IND\n"); 11037c478bd9Sstevel@tonic-gate freemsg(mp); 11047c478bd9Sstevel@tonic-gate return; 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 11087c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 11097c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 11107c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp; 11117c478bd9Sstevel@tonic-gate so->so_state |= SS_HASCONNIND; 11127c478bd9Sstevel@tonic-gate } else { 11137c478bd9Sstevel@tonic-gate ASSERT(so->so_state & SS_HASCONNIND); 11147c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail->b_next == NULL); 11157c478bd9Sstevel@tonic-gate so->so_conn_ind_tail->b_next = mp; 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = mp; 11187c478bd9Sstevel@tonic-gate /* Wakeup a single consumer of the T_CONN_IND */ 11197c478bd9Sstevel@tonic-gate cv_signal(&so->so_connind_cv); 11207c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate /* 11247c478bd9Sstevel@tonic-gate * Wait for a T_CONN_IND. 11257c478bd9Sstevel@tonic-gate * Don't wait if nonblocking. 11267c478bd9Sstevel@tonic-gate * Accept signals and socket errors. 11277c478bd9Sstevel@tonic-gate */ 11287c478bd9Sstevel@tonic-gate int 11297c478bd9Sstevel@tonic-gate sowaitconnind(struct sonode *so, int fmode, mblk_t **mpp) 11307c478bd9Sstevel@tonic-gate { 11317c478bd9Sstevel@tonic-gate mblk_t *mp; 11327c478bd9Sstevel@tonic-gate int error = 0; 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 11357c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 11367c478bd9Sstevel@tonic-gate check_error: 11377c478bd9Sstevel@tonic-gate if (so->so_error) { 11387c478bd9Sstevel@tonic-gate error = sogeterr(so); 11397c478bd9Sstevel@tonic-gate if (error) { 11407c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11417c478bd9Sstevel@tonic-gate return (error); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 11467c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) { 11477c478bd9Sstevel@tonic-gate error = EWOULDBLOCK; 11487c478bd9Sstevel@tonic-gate goto done; 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate if (!cv_wait_sig_swap(&so->so_connind_cv, &so->so_lock)) { 11517c478bd9Sstevel@tonic-gate error = EINTR; 11527c478bd9Sstevel@tonic-gate goto done; 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate goto check_error; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate mp = so->so_conn_ind_head; 11577c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp->b_next; 11587c478bd9Sstevel@tonic-gate mp->b_next = NULL; 11597c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 11607c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == mp); 11617c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = NULL; 11627c478bd9Sstevel@tonic-gate so->so_state &= ~SS_HASCONNIND; 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate *mpp = mp; 11657c478bd9Sstevel@tonic-gate done: 11667c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11677c478bd9Sstevel@tonic-gate return (error); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate /* 11717c478bd9Sstevel@tonic-gate * Flush a T_CONN_IND matching the sequence number from the list. 11727c478bd9Sstevel@tonic-gate * Return zero if found; non-zero otherwise. 11737c478bd9Sstevel@tonic-gate * This is called very infrequently thus it is ok to do a linear search. 11747c478bd9Sstevel@tonic-gate */ 11757c478bd9Sstevel@tonic-gate int 11767c478bd9Sstevel@tonic-gate soflushconnind(struct sonode *so, t_scalar_t seqno) 11777c478bd9Sstevel@tonic-gate { 11787c478bd9Sstevel@tonic-gate mblk_t *prevmp, *mp; 11797c478bd9Sstevel@tonic-gate struct T_conn_ind *tci; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 11827c478bd9Sstevel@tonic-gate for (prevmp = NULL, mp = so->so_conn_ind_head; mp != NULL; 11837c478bd9Sstevel@tonic-gate prevmp = mp, mp = mp->b_next) { 11847c478bd9Sstevel@tonic-gate tci = (struct T_conn_ind *)mp->b_rptr; 11857c478bd9Sstevel@tonic-gate if (tci->SEQ_number == seqno) { 11867c478bd9Sstevel@tonic-gate dprintso(so, 1, 1187*d3e55dcdSgww ("t_discon_ind: found T_CONN_IND %d\n", seqno)); 11887c478bd9Sstevel@tonic-gate /* Deleting last? */ 11897c478bd9Sstevel@tonic-gate if (so->so_conn_ind_tail == mp) { 11907c478bd9Sstevel@tonic-gate so->so_conn_ind_tail = prevmp; 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate if (prevmp == NULL) { 11937c478bd9Sstevel@tonic-gate /* Deleting first */ 11947c478bd9Sstevel@tonic-gate so->so_conn_ind_head = mp->b_next; 11957c478bd9Sstevel@tonic-gate } else { 11967c478bd9Sstevel@tonic-gate prevmp->b_next = mp->b_next; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate mp->b_next = NULL; 11997c478bd9Sstevel@tonic-gate if (so->so_conn_ind_head == NULL) { 12007c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail == NULL); 12017c478bd9Sstevel@tonic-gate so->so_state &= ~SS_HASCONNIND; 12027c478bd9Sstevel@tonic-gate } else { 12037c478bd9Sstevel@tonic-gate ASSERT(so->so_conn_ind_tail != NULL); 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate so->so_error = ECONNABORTED; 12067c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1207c28749e9Skais 1208c28749e9Skais /* 1209c28749e9Skais * T_KSSL_PROXY_CONN_IND may carry a handle for 1210c28749e9Skais * an SSL context, and needs to be released. 1211c28749e9Skais */ 1212c28749e9Skais if ((tci->PRIM_type == T_SSL_PROXY_CONN_IND) && 1213c28749e9Skais (mp->b_cont != NULL)) { 1214c28749e9Skais kssl_ctx_t kssl_ctx; 1215c28749e9Skais 1216c28749e9Skais ASSERT(MBLKL(mp->b_cont) == 1217c28749e9Skais sizeof (kssl_ctx_t)); 1218c28749e9Skais kssl_ctx = *((kssl_ctx_t *)mp->b_cont->b_rptr); 1219c28749e9Skais kssl_release_ctx(kssl_ctx); 1220c28749e9Skais } 12217c478bd9Sstevel@tonic-gate freemsg(mp); 12227c478bd9Sstevel@tonic-gate return (0); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 12267c478bd9Sstevel@tonic-gate dprintso(so, 1, ("t_discon_ind: NOT found T_CONN_IND %d\n", seqno)); 12277c478bd9Sstevel@tonic-gate return (-1); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * Wait until the socket is connected or there is an error. 12327c478bd9Sstevel@tonic-gate * fmode should contain any nonblocking flags. nosig should be 12337c478bd9Sstevel@tonic-gate * set if the caller does not want the wait to be interrupted by a signal. 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate int 12367c478bd9Sstevel@tonic-gate sowaitconnected(struct sonode *so, int fmode, int nosig) 12377c478bd9Sstevel@tonic-gate { 12387c478bd9Sstevel@tonic-gate int error; 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate while ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 1243*d3e55dcdSgww SS_ISCONNECTING && so->so_error == 0) { 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate dprintso(so, 1, ("waiting for SS_ISCONNECTED on %p\n", so)); 12467c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 12477c478bd9Sstevel@tonic-gate return (EINPROGRESS); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate if (nosig) 12507c478bd9Sstevel@tonic-gate cv_wait(&so->so_state_cv, &so->so_lock); 12517c478bd9Sstevel@tonic-gate else if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) { 12527c478bd9Sstevel@tonic-gate /* 12537c478bd9Sstevel@tonic-gate * Return EINTR and let the application use 12547c478bd9Sstevel@tonic-gate * nonblocking techniques for detecting when 12557c478bd9Sstevel@tonic-gate * the connection has been established. 12567c478bd9Sstevel@tonic-gate */ 12577c478bd9Sstevel@tonic-gate return (EINTR); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate dprintso(so, 1, ("awoken on %p\n", so)); 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate if (so->so_error != 0) { 12637c478bd9Sstevel@tonic-gate error = sogeterr(so); 12647c478bd9Sstevel@tonic-gate ASSERT(error != 0); 12657c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 12667c478bd9Sstevel@tonic-gate return (error); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ISCONNECTED)) { 12697c478bd9Sstevel@tonic-gate /* 12707c478bd9Sstevel@tonic-gate * Could have received a T_ORDREL_IND or a T_DISCON_IND with 12717c478bd9Sstevel@tonic-gate * zero errno. Or another thread could have consumed so_error 12727c478bd9Sstevel@tonic-gate * e.g. by calling read. 12737c478bd9Sstevel@tonic-gate */ 12747c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 12757c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 12767c478bd9Sstevel@tonic-gate return (error); 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate return (0); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate /* 12837c478bd9Sstevel@tonic-gate * Handle the signal generation aspect of urgent data. 12847c478bd9Sstevel@tonic-gate */ 12857c478bd9Sstevel@tonic-gate static void 12867c478bd9Sstevel@tonic-gate so_oob_sig(struct sonode *so, int extrasig, 12877c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 12887c478bd9Sstevel@tonic-gate { 12897c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 12927c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt >= so->so_oobcnt); 12937c478bd9Sstevel@tonic-gate if (so->so_oobsigcnt > so->so_oobcnt) { 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * Signal has already been generated once for this 12967c478bd9Sstevel@tonic-gate * urgent "event". However, since TCP can receive updated 12977c478bd9Sstevel@tonic-gate * urgent pointers we still generate a signal. 12987c478bd9Sstevel@tonic-gate */ 12997c478bd9Sstevel@tonic-gate ASSERT(so->so_state & SS_OOBPEND); 13007c478bd9Sstevel@tonic-gate if (extrasig) { 13017c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 13027c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate return; 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate so->so_oobsigcnt++; 13087c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt > 0); /* Wraparound */ 13097c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt > so->so_oobcnt); 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate /* 13127c478bd9Sstevel@tonic-gate * Record (for select/poll) that urgent data is pending. 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate so->so_state |= SS_OOBPEND; 13157c478bd9Sstevel@tonic-gate /* 13167c478bd9Sstevel@tonic-gate * New urgent data on the way so forget about any old 13177c478bd9Sstevel@tonic-gate * urgent data. 13187c478bd9Sstevel@tonic-gate */ 13197c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA); 13207c478bd9Sstevel@tonic-gate if (so->so_oobmsg != NULL) { 13217c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sock: discarding old oob\n")); 13227c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 13237c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 13267c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13277c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate /* 13317c478bd9Sstevel@tonic-gate * Handle the processing of the T_EXDATA_IND with urgent data. 13327c478bd9Sstevel@tonic-gate * Returns the T_EXDATA_IND if it should be queued on the read queue. 13337c478bd9Sstevel@tonic-gate */ 13347c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 13357c478bd9Sstevel@tonic-gate static mblk_t * 13367c478bd9Sstevel@tonic-gate so_oob_exdata(struct sonode *so, mblk_t *mp, 13377c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 13387c478bd9Sstevel@tonic-gate { 13397c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt > so->so_oobcnt); 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate so->so_oobcnt++; 13467c478bd9Sstevel@tonic-gate ASSERT(so->so_oobcnt > 0); /* wraparound? */ 13477c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt >= so->so_oobcnt); 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate /* 13507c478bd9Sstevel@tonic-gate * Set MSGMARK for SIOCATMARK. 13517c478bd9Sstevel@tonic-gate */ 13527c478bd9Sstevel@tonic-gate mp->b_flag |= MSGMARK; 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13557c478bd9Sstevel@tonic-gate return (mp); 13567c478bd9Sstevel@tonic-gate } 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate /* 13597c478bd9Sstevel@tonic-gate * Handle the processing of the actual urgent data. 13607c478bd9Sstevel@tonic-gate * Returns the data mblk if it should be queued on the read queue. 13617c478bd9Sstevel@tonic-gate */ 13627c478bd9Sstevel@tonic-gate static mblk_t * 13637c478bd9Sstevel@tonic-gate so_oob_data(struct sonode *so, mblk_t *mp, 13647c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 13657c478bd9Sstevel@tonic-gate { 13667c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate ASSERT(so->so_oobsigcnt >= so->so_oobcnt); 13717c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 13727c478bd9Sstevel@tonic-gate /* 13737c478bd9Sstevel@tonic-gate * For OOBINLINE we keep the data in the T_EXDATA_IND. 13747c478bd9Sstevel@tonic-gate * Otherwise we store it in so_oobmsg. 13757c478bd9Sstevel@tonic-gate */ 13767c478bd9Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 13777c478bd9Sstevel@tonic-gate if (so->so_options & SO_OOBINLINE) { 13787c478bd9Sstevel@tonic-gate *pollwakeups |= POLLIN | POLLRDNORM | POLLRDBAND; 13797c478bd9Sstevel@tonic-gate *signals |= S_INPUT | S_RDNORM; 13807c478bd9Sstevel@tonic-gate } else { 13817c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13827c478bd9Sstevel@tonic-gate so->so_state |= SS_HAVEOOBDATA; 13837c478bd9Sstevel@tonic-gate so->so_oobmsg = mp; 13847c478bd9Sstevel@tonic-gate mp = NULL; 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13877c478bd9Sstevel@tonic-gate return (mp); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate /* 13917c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 13927c478bd9Sstevel@tonic-gate * For delayed processing, save the T_DISCON_IND received 13937c478bd9Sstevel@tonic-gate * from below on so_discon_ind_mp. 13947c478bd9Sstevel@tonic-gate * When the message is processed the framework will call: 13957c478bd9Sstevel@tonic-gate * (*func)(so, mp); 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate static void 13987c478bd9Sstevel@tonic-gate so_save_discon_ind(struct sonode *so, 13997c478bd9Sstevel@tonic-gate mblk_t *mp, 14007c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *)) 14017c478bd9Sstevel@tonic-gate { 14027c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * Discard new T_DISCON_IND if we have already received another. 14067c478bd9Sstevel@tonic-gate * Currently the earlier message can either be on so_discon_ind_mp 14077c478bd9Sstevel@tonic-gate * or being processed. 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate if (so->so_discon_ind_mp != NULL || (so->so_flag & SOASYNC_UNBIND)) { 14102caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 14117c478bd9Sstevel@tonic-gate "sockfs: received unexpected additional T_DISCON_IND\n"); 14127c478bd9Sstevel@tonic-gate freemsg(mp); 14137c478bd9Sstevel@tonic-gate return; 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)func; 14167c478bd9Sstevel@tonic-gate mp->b_next = NULL; 14177c478bd9Sstevel@tonic-gate so->so_discon_ind_mp = mp; 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * Caller must hold the mutex and make sure that either SOLOCKED 14227c478bd9Sstevel@tonic-gate * or SOASYNC_UNBIND is set. Called from so_unlock_single(). 14237c478bd9Sstevel@tonic-gate * Perform delayed processing of T_DISCON_IND message on so_discon_ind_mp. 14247c478bd9Sstevel@tonic-gate * Need to ensure that strsock_proto() will not end up sleeping for 14257c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND, while executing this function. 14267c478bd9Sstevel@tonic-gate */ 14277c478bd9Sstevel@tonic-gate void 14287c478bd9Sstevel@tonic-gate so_drain_discon_ind(struct sonode *so) 14297c478bd9Sstevel@tonic-gate { 14307c478bd9Sstevel@tonic-gate mblk_t *bp; 14317c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *); 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14347c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & (SOLOCKED|SOASYNC_UNBIND)); 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate /* Process T_DISCON_IND on so_discon_ind_mp */ 14377c478bd9Sstevel@tonic-gate if ((bp = so->so_discon_ind_mp) != NULL) { 14387c478bd9Sstevel@tonic-gate so->so_discon_ind_mp = NULL; 14397c478bd9Sstevel@tonic-gate func = (void (*)())bp->b_prev; 14407c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /* 14437c478bd9Sstevel@tonic-gate * This (*func) is supposed to generate a message downstream 14447c478bd9Sstevel@tonic-gate * and we need to have a flag set until the corresponding 14457c478bd9Sstevel@tonic-gate * upstream message reaches stream head. 14467c478bd9Sstevel@tonic-gate * When processing T_DISCON_IND in strsock_discon_ind 14477c478bd9Sstevel@tonic-gate * we hold SOASYN_UNBIND when sending T_UNBIND_REQ down and 14487c478bd9Sstevel@tonic-gate * drop the flag after we get the ACK in strsock_proto. 14497c478bd9Sstevel@tonic-gate */ 14507c478bd9Sstevel@tonic-gate (void) (*func)(so, bp); 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate /* 14557c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 14567c478bd9Sstevel@tonic-gate * Remove the T_DISCON_IND on so_discon_ind_mp. 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate void 14597c478bd9Sstevel@tonic-gate so_flush_discon_ind(struct sonode *so) 14607c478bd9Sstevel@tonic-gate { 14617c478bd9Sstevel@tonic-gate mblk_t *bp; 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* 14667c478bd9Sstevel@tonic-gate * Remove T_DISCON_IND mblk at so_discon_ind_mp. 14677c478bd9Sstevel@tonic-gate */ 14687c478bd9Sstevel@tonic-gate if ((bp = so->so_discon_ind_mp) != NULL) { 14697c478bd9Sstevel@tonic-gate so->so_discon_ind_mp = NULL; 14707c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 14717c478bd9Sstevel@tonic-gate freemsg(bp); 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate /* 14767c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 14777c478bd9Sstevel@tonic-gate * 14787c478bd9Sstevel@tonic-gate * This function is used to process the T_DISCON_IND message. It does 14797c478bd9Sstevel@tonic-gate * immediate processing when called from strsock_proto and delayed 14807c478bd9Sstevel@tonic-gate * processing of discon_ind saved on so_discon_ind_mp when called from 14817c478bd9Sstevel@tonic-gate * so_drain_discon_ind. When a T_DISCON_IND message is saved in 14827c478bd9Sstevel@tonic-gate * so_discon_ind_mp for delayed processing, this function is registered 14837c478bd9Sstevel@tonic-gate * as the callback function to process the message. 14847c478bd9Sstevel@tonic-gate * 14857c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND should be held in this function, during the non-blocking 14867c478bd9Sstevel@tonic-gate * unbind operation, and should be released only after we receive the ACK 14877c478bd9Sstevel@tonic-gate * in strsock_proto, for the T_UNBIND_REQ sent here. Since SOLOCKED is not set, 14887c478bd9Sstevel@tonic-gate * no TPI messages would be sent down at this time. This is to prevent M_FLUSH 14897c478bd9Sstevel@tonic-gate * sent from either this function or tcp_unbind(), flushing away any TPI 14907c478bd9Sstevel@tonic-gate * message that is being sent down and stays in a lower module's queue. 14917c478bd9Sstevel@tonic-gate * 14927c478bd9Sstevel@tonic-gate * This function drops so_lock and grabs it again. 14937c478bd9Sstevel@tonic-gate */ 14947c478bd9Sstevel@tonic-gate static void 14957c478bd9Sstevel@tonic-gate strsock_discon_ind(struct sonode *so, mblk_t *discon_mp) 14967c478bd9Sstevel@tonic-gate { 14977c478bd9Sstevel@tonic-gate struct vnode *vp; 14987c478bd9Sstevel@tonic-gate struct stdata *stp; 14997c478bd9Sstevel@tonic-gate union T_primitives *tpr; 15007c478bd9Sstevel@tonic-gate struct T_unbind_req *ubr; 15017c478bd9Sstevel@tonic-gate mblk_t *mp; 15027c478bd9Sstevel@tonic-gate int error; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 15057c478bd9Sstevel@tonic-gate ASSERT(discon_mp); 15067c478bd9Sstevel@tonic-gate ASSERT(discon_mp->b_rptr); 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)discon_mp->b_rptr; 15097c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_DISCON_IND); 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate vp = SOTOV(so); 15127c478bd9Sstevel@tonic-gate stp = vp->v_stream; 15137c478bd9Sstevel@tonic-gate ASSERT(stp); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * Not a listener 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate ASSERT((so->so_state & SS_ACCEPTCONN) == 0); 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate /* 15217c478bd9Sstevel@tonic-gate * This assumes that the name space for DISCON_reason 15227c478bd9Sstevel@tonic-gate * is the errno name space. 15237c478bd9Sstevel@tonic-gate */ 15247c478bd9Sstevel@tonic-gate soisdisconnected(so, tpr->discon_ind.DISCON_reason); 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * Unbind with the transport without blocking. 15287c478bd9Sstevel@tonic-gate * If we've already received a T_DISCON_IND do not unbind. 15297c478bd9Sstevel@tonic-gate * 15307c478bd9Sstevel@tonic-gate * If there is no preallocated unbind message, we have already 15317c478bd9Sstevel@tonic-gate * unbound with the transport 15327c478bd9Sstevel@tonic-gate * 15337c478bd9Sstevel@tonic-gate * If the socket is not bound, no need to unbind. 15347c478bd9Sstevel@tonic-gate */ 15357c478bd9Sstevel@tonic-gate mp = so->so_unbind_mp; 15367c478bd9Sstevel@tonic-gate if (mp == NULL) { 15377c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & SS_ISBOUND)); 15387c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 15397c478bd9Sstevel@tonic-gate } else if (!(so->so_state & SS_ISBOUND)) { 15407c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 15417c478bd9Sstevel@tonic-gate } else { 15427c478bd9Sstevel@tonic-gate so->so_unbind_mp = NULL; 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate /* 15457c478bd9Sstevel@tonic-gate * Is another T_DISCON_IND being processed. 15467c478bd9Sstevel@tonic-gate */ 15477c478bd9Sstevel@tonic-gate ASSERT((so->so_flag & SOASYNC_UNBIND) == 0); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate /* 15507c478bd9Sstevel@tonic-gate * Make strsock_proto ignore T_OK_ACK and T_ERROR_ACK for 15517c478bd9Sstevel@tonic-gate * this unbind. Set SOASYNC_UNBIND. This should be cleared 15527c478bd9Sstevel@tonic-gate * only after we receive the ACK in strsock_proto. 15537c478bd9Sstevel@tonic-gate */ 15547c478bd9Sstevel@tonic-gate so->so_flag |= SOASYNC_UNBIND; 15557c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING))); 15567c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISBOUND|SS_ACCEPTCONN|SS_LADDR_VALID); 15577c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate /* 15607c478bd9Sstevel@tonic-gate * Send down T_UNBIND_REQ ignoring flow control. 15617c478bd9Sstevel@tonic-gate * XXX Assumes that MSG_IGNFLOW implies that this thread 15627c478bd9Sstevel@tonic-gate * does not run service procedures. 15637c478bd9Sstevel@tonic-gate */ 15647c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO); 15657c478bd9Sstevel@tonic-gate ubr = (struct T_unbind_req *)mp->b_rptr; 15667c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (*ubr); 15677c478bd9Sstevel@tonic-gate ubr->PRIM_type = T_UNBIND_REQ; 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate * Flush the read and write side (except stream head read queue) 15717c478bd9Sstevel@tonic-gate * and send down T_UNBIND_REQ. 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate (void) putnextctl1(strvp2wq(SOTOV(so)), M_FLUSH, FLUSHRW); 15747c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 1575*d3e55dcdSgww MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0); 15767c478bd9Sstevel@tonic-gate /* LINTED - warning: statement has no consequent: if */ 15777c478bd9Sstevel@tonic-gate if (error) { 15787c478bd9Sstevel@tonic-gate eprintsoline(so, error); 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate } 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate if (tpr->discon_ind.DISCON_reason != 0) 15837c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 15847c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 15857c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 15867c478bd9Sstevel@tonic-gate /* 15877c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 15887c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 15897c478bd9Sstevel@tonic-gate */ 15907c478bd9Sstevel@tonic-gate dprintso(so, 1, ("T_DISCON_IND: error %d\n", so->so_error)); 15917c478bd9Sstevel@tonic-gate freemsg(discon_mp); 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLOUT); 15957c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate /* 15987c478bd9Sstevel@tonic-gate * Wake sleeping write 15997c478bd9Sstevel@tonic-gate */ 16007c478bd9Sstevel@tonic-gate if (stp->sd_flag & WSLEEP) { 16017c478bd9Sstevel@tonic-gate stp->sd_flag &= ~WSLEEP; 16027c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_wrq->q_wait); 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * strsendsig can handle multiple signals with a 16077c478bd9Sstevel@tonic-gate * single call. Send SIGPOLL for S_OUTPUT event. 16087c478bd9Sstevel@tonic-gate */ 16097c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_OUTPUT) 16107c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_OUTPUT, 0, 0); 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 16137c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate /* 16177c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive M_PROTO 16187c478bd9Sstevel@tonic-gate * and M_PCPROTO messages. 16197c478bd9Sstevel@tonic-gate * 16207c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 16217c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed (and queued) by the stream 16227c478bd9Sstevel@tonic-gate * head. 16237c478bd9Sstevel@tonic-gate * 16247c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 16257c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. Note that since 16267c478bd9Sstevel@tonic-gate * sockets always deliver SIGIO for every new piece of data this routine 16277c478bd9Sstevel@tonic-gate * never sets *firstmsgsigs; any signals are returned in *allmsgsigs. 16287c478bd9Sstevel@tonic-gate * 16297c478bd9Sstevel@tonic-gate * This routine handles all data related TPI messages independent of 16307c478bd9Sstevel@tonic-gate * the type of the socket i.e. it doesn't care if T_UNITDATA_IND message 16317c478bd9Sstevel@tonic-gate * arrive on a SOCK_STREAM. 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate static mblk_t * 16347c478bd9Sstevel@tonic-gate strsock_proto(vnode_t *vp, mblk_t *mp, 16357c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 16367c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 16377c478bd9Sstevel@tonic-gate { 16387c478bd9Sstevel@tonic-gate union T_primitives *tpr; 16397c478bd9Sstevel@tonic-gate struct sonode *so; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate so = VTOSO(vp); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_proto(%p, %p)\n", vp, mp)); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate /* Set default return values */ 16467c478bd9Sstevel@tonic-gate *firstmsgsigs = *wakeups = *allmsgsigs = *pollwakeups = 0; 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO || 16497c478bd9Sstevel@tonic-gate DB_TYPE(mp) == M_PCPROTO); 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (tpr->type)) { 16527c478bd9Sstevel@tonic-gate /* The message is too short to even contain the primitive */ 16532caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 16547c478bd9Sstevel@tonic-gate "sockfs: Too short TPI message received. Len = %ld\n", 16557c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 16567c478bd9Sstevel@tonic-gate freemsg(mp); 16577c478bd9Sstevel@tonic-gate return (NULL); 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate if (!__TPI_PRIM_ISALIGNED(mp->b_rptr)) { 16607c478bd9Sstevel@tonic-gate /* The read pointer is not aligned correctly for TPI */ 16612caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 16627c478bd9Sstevel@tonic-gate "sockfs: Unaligned TPI message received. rptr = %p\n", 16637c478bd9Sstevel@tonic-gate (void *)mp->b_rptr); 16647c478bd9Sstevel@tonic-gate freemsg(mp); 16657c478bd9Sstevel@tonic-gate return (NULL); 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 16687c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_proto: primitive %d\n", tpr->type)); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate switch (tpr->type) { 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate case T_DATA_IND: 16737c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_data_ind)) { 16742caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 16757c478bd9Sstevel@tonic-gate "sockfs: Too short T_DATA_IND. Len = %ld\n", 16767c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 16777c478bd9Sstevel@tonic-gate freemsg(mp); 16787c478bd9Sstevel@tonic-gate return (NULL); 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate /* 16817c478bd9Sstevel@tonic-gate * Ignore zero-length T_DATA_IND messages. These might be 16827c478bd9Sstevel@tonic-gate * generated by some transports. 16837c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 16847c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 16857c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 16867c478bd9Sstevel@tonic-gate * that data is available). 16877c478bd9Sstevel@tonic-gate */ 16887c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 16897c478bd9Sstevel@tonic-gate dprintso(so, 0, 16907c478bd9Sstevel@tonic-gate ("strsock_proto: zero length T_DATA_IND\n")); 16917c478bd9Sstevel@tonic-gate freemsg(mp); 16927c478bd9Sstevel@tonic-gate return (NULL); 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 16957c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 16967c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 16977c478bd9Sstevel@tonic-gate return (mp); 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate case T_UNITDATA_IND: { 17007c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi = &tpr->unitdata_ind; 17017c478bd9Sstevel@tonic-gate void *addr; 17027c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_unitdata_ind)) { 17052caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17067c478bd9Sstevel@tonic-gate "sockfs: Too short T_UNITDATA_IND. Len = %ld\n", 17077c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 17087c478bd9Sstevel@tonic-gate freemsg(mp); 17097c478bd9Sstevel@tonic-gate return (NULL); 17107c478bd9Sstevel@tonic-gate } 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate /* Is this is not a connected datagram socket? */ 17137c478bd9Sstevel@tonic-gate if ((so->so_mode & SM_CONNREQUIRED) || 17147c478bd9Sstevel@tonic-gate !(so->so_state & SS_ISCONNECTED)) { 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * Not a connected datagram socket. Look for 17177c478bd9Sstevel@tonic-gate * the SO_UNIX_CLOSE option. If such an option is found 17187c478bd9Sstevel@tonic-gate * discard the message (since it has no meaning 17197c478bd9Sstevel@tonic-gate * unless connected). 17207c478bd9Sstevel@tonic-gate */ 17217c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp) == 0 && 17227c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 17237c478bd9Sstevel@tonic-gate void *opt; 17247c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 1727*d3e55dcdSgww optlen, __TPI_ALIGN_SIZE); 17287c478bd9Sstevel@tonic-gate if (opt == NULL) { 17297c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 17307c478bd9Sstevel@tonic-gate freemsg(mp); 17317c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 17327c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 17337c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 17342caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17357c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with " 17367c478bd9Sstevel@tonic-gate "invalid optlen/offset %u/%d\n", 17377c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 17387c478bd9Sstevel@tonic-gate return (NULL); 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 17417c478bd9Sstevel@tonic-gate freemsg(mp); 17427c478bd9Sstevel@tonic-gate return (NULL); 17437c478bd9Sstevel@tonic-gate } 17447c478bd9Sstevel@tonic-gate } 17457c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 17467c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 17477c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 17487c478bd9Sstevel@tonic-gate if (audit_active) 17497c478bd9Sstevel@tonic-gate audit_sock(T_UNITDATA_IND, strvp2wq(vp), 1750*d3e55dcdSgww mp, 0); 17517c478bd9Sstevel@tonic-gate return (mp); 17527c478bd9Sstevel@tonic-gate } 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * A connect datagram socket. For AF_INET{,6} we verify that 17567c478bd9Sstevel@tonic-gate * the source address matches the "connected to" address. 17577c478bd9Sstevel@tonic-gate * The semantics of AF_UNIX sockets is to not verify 17587c478bd9Sstevel@tonic-gate * the source address. 17597c478bd9Sstevel@tonic-gate * Note that this source address verification is transport 17607c478bd9Sstevel@tonic-gate * specific. Thus the real fix would be to extent TPI 17617c478bd9Sstevel@tonic-gate * to allow T_CONN_REQ messages to be send to connectionless 17627c478bd9Sstevel@tonic-gate * transport providers and always let the transport provider 17637c478bd9Sstevel@tonic-gate * do whatever filtering is needed. 17647c478bd9Sstevel@tonic-gate * 17657c478bd9Sstevel@tonic-gate * The verification/filtering semantics for transports 17667c478bd9Sstevel@tonic-gate * other than AF_INET and AF_UNIX are unknown. The choice 17677c478bd9Sstevel@tonic-gate * would be to either filter using bcmp or let all messages 17687c478bd9Sstevel@tonic-gate * get through. This code does not filter other address 17697c478bd9Sstevel@tonic-gate * families since this at least allows the application to 17707c478bd9Sstevel@tonic-gate * work around any missing filtering. 17717c478bd9Sstevel@tonic-gate * 17727c478bd9Sstevel@tonic-gate * XXX Should we move filtering to UDP/ICMP??? 17737c478bd9Sstevel@tonic-gate * That would require passing e.g. a T_DISCON_REQ to UDP 17747c478bd9Sstevel@tonic-gate * when the socket becomes unconnected. 17757c478bd9Sstevel@tonic-gate */ 17767c478bd9Sstevel@tonic-gate addrlen = tudi->SRC_length; 17777c478bd9Sstevel@tonic-gate /* 17787c478bd9Sstevel@tonic-gate * The alignment restriction is really to strict but 17797c478bd9Sstevel@tonic-gate * we want enough alignment to inspect the fields of 17807c478bd9Sstevel@tonic-gate * a sockaddr_in. 17817c478bd9Sstevel@tonic-gate */ 17827c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->SRC_offset, addrlen, 1783*d3e55dcdSgww __TPI_ALIGN_SIZE); 17847c478bd9Sstevel@tonic-gate if (addr == NULL) { 17857c478bd9Sstevel@tonic-gate freemsg(mp); 17867c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 17877c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 17887c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 17892caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17907c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with invalid " 17917c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 17927c478bd9Sstevel@tonic-gate addrlen, tudi->SRC_offset); 17937c478bd9Sstevel@tonic-gate return (NULL); 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET) { 17977c478bd9Sstevel@tonic-gate /* 17987c478bd9Sstevel@tonic-gate * For AF_INET we allow wildcarding both sin_addr 17997c478bd9Sstevel@tonic-gate * and sin_port. 18007c478bd9Sstevel@tonic-gate */ 18017c478bd9Sstevel@tonic-gate struct sockaddr_in *faddr, *sin; 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate /* Prevent so_faddr_sa from changing while accessed */ 18047c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18057c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_len == 1806*d3e55dcdSgww (socklen_t)sizeof (struct sockaddr_in)); 18077c478bd9Sstevel@tonic-gate faddr = (struct sockaddr_in *)so->so_faddr_sa; 18087c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)addr; 18097c478bd9Sstevel@tonic-gate if (addrlen != 1810*d3e55dcdSgww (t_uscalar_t)sizeof (struct sockaddr_in) || 18117c478bd9Sstevel@tonic-gate (sin->sin_addr.s_addr != faddr->sin_addr.s_addr && 18127c478bd9Sstevel@tonic-gate faddr->sin_addr.s_addr != INADDR_ANY) || 18137c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 18147c478bd9Sstevel@tonic-gate sin->sin_port != faddr->sin_port && 18157c478bd9Sstevel@tonic-gate faddr->sin_port != 0)) { 18167c478bd9Sstevel@tonic-gate #ifdef DEBUG 18177c478bd9Sstevel@tonic-gate dprintso(so, 0, 1818*d3e55dcdSgww ("sockfs: T_UNITDATA_IND mismatch: %s", 1819*d3e55dcdSgww pr_addr(so->so_family, 1820*d3e55dcdSgww (struct sockaddr *)addr, 1821*d3e55dcdSgww addrlen))); 18227c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 1823*d3e55dcdSgww pr_addr(so->so_family, so->so_faddr_sa, 1824*d3e55dcdSgww (t_uscalar_t)so->so_faddr_len))); 18257c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 18267c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18277c478bd9Sstevel@tonic-gate freemsg(mp); 18287c478bd9Sstevel@tonic-gate return (NULL); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18317c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_INET6) { 18327c478bd9Sstevel@tonic-gate /* 18337c478bd9Sstevel@tonic-gate * For AF_INET6 we allow wildcarding both sin6_addr 18347c478bd9Sstevel@tonic-gate * and sin6_port. 18357c478bd9Sstevel@tonic-gate */ 18367c478bd9Sstevel@tonic-gate struct sockaddr_in6 *faddr6, *sin6; 18377c478bd9Sstevel@tonic-gate static struct in6_addr zeroes; /* inits to all zeros */ 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate /* Prevent so_faddr_sa from changing while accessed */ 18407c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18417c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_len == 18427c478bd9Sstevel@tonic-gate (socklen_t)sizeof (struct sockaddr_in6)); 18437c478bd9Sstevel@tonic-gate faddr6 = (struct sockaddr_in6 *)so->so_faddr_sa; 18447c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)addr; 18457c478bd9Sstevel@tonic-gate /* XXX could we get a mapped address ::ffff:0.0.0.0 ? */ 18467c478bd9Sstevel@tonic-gate if (addrlen != 18477c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct sockaddr_in6) || 18487c478bd9Sstevel@tonic-gate (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 1849*d3e55dcdSgww &faddr6->sin6_addr) && 18507c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&faddr6->sin6_addr, &zeroes)) || 18517c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 18527c478bd9Sstevel@tonic-gate sin6->sin6_port != faddr6->sin6_port && 18537c478bd9Sstevel@tonic-gate faddr6->sin6_port != 0)) { 18547c478bd9Sstevel@tonic-gate #ifdef DEBUG 18557c478bd9Sstevel@tonic-gate dprintso(so, 0, 18567c478bd9Sstevel@tonic-gate ("sockfs: T_UNITDATA_IND mismatch: %s", 1857*d3e55dcdSgww pr_addr(so->so_family, 1858*d3e55dcdSgww (struct sockaddr *)addr, 1859*d3e55dcdSgww addrlen))); 18607c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 18617c478bd9Sstevel@tonic-gate pr_addr(so->so_family, so->so_faddr_sa, 1862*d3e55dcdSgww (t_uscalar_t)so->so_faddr_len))); 18637c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 18647c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18657c478bd9Sstevel@tonic-gate freemsg(mp); 18667c478bd9Sstevel@tonic-gate return (NULL); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18697c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_UNIX && 18707c478bd9Sstevel@tonic-gate msgdsize(mp->b_cont) == 0 && 18717c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 18727c478bd9Sstevel@tonic-gate /* 18737c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX 18747c478bd9Sstevel@tonic-gate * SO_UNIX_CLOSE indication from options. 18757c478bd9Sstevel@tonic-gate */ 18767c478bd9Sstevel@tonic-gate void *opt; 18777c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 1880*d3e55dcdSgww optlen, __TPI_ALIGN_SIZE); 18817c478bd9Sstevel@tonic-gate if (opt == NULL) { 18827c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 18837c478bd9Sstevel@tonic-gate freemsg(mp); 18847c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18857c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 18867c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18872caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 18887c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with invalid " 18897c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 18907c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 18917c478bd9Sstevel@tonic-gate return (NULL); 18927c478bd9Sstevel@tonic-gate } 18937c478bd9Sstevel@tonic-gate /* 18947c478bd9Sstevel@tonic-gate * If we received a unix close indication mark the 18957c478bd9Sstevel@tonic-gate * socket and discard this message. 18967c478bd9Sstevel@tonic-gate */ 18977c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 18987c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18997c478bd9Sstevel@tonic-gate sobreakconn(so, ECONNRESET); 19007c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19017c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 19027c478bd9Sstevel@tonic-gate freemsg(mp); 19037c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19047c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19057c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19067c478bd9Sstevel@tonic-gate return (NULL); 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19107c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19117c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19127c478bd9Sstevel@tonic-gate return (mp); 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate case T_OPTDATA_IND: { 19167c478bd9Sstevel@tonic-gate struct T_optdata_ind *tdi = &tpr->optdata_ind; 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optdata_ind)) { 19192caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 19207c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTDATA_IND. Len = %ld\n", 19217c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 19227c478bd9Sstevel@tonic-gate freemsg(mp); 19237c478bd9Sstevel@tonic-gate return (NULL); 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate /* 19267c478bd9Sstevel@tonic-gate * Allow zero-length messages carrying options. 19277c478bd9Sstevel@tonic-gate * This is used when carrying the SO_UNIX_CLOSE option. 19287c478bd9Sstevel@tonic-gate */ 19297c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp->b_cont) == 0 && 19307c478bd9Sstevel@tonic-gate tdi->OPT_length != 0) { 19317c478bd9Sstevel@tonic-gate /* 19327c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX close indication 19337c478bd9Sstevel@tonic-gate * from the options. Ignore any other options - 19347c478bd9Sstevel@tonic-gate * those are handled once the message is removed 19357c478bd9Sstevel@tonic-gate * from the queue. 19367c478bd9Sstevel@tonic-gate * The close indication message should not carry data. 19377c478bd9Sstevel@tonic-gate */ 19387c478bd9Sstevel@tonic-gate void *opt; 19397c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tdi->OPT_length; 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tdi->OPT_offset, 1942*d3e55dcdSgww optlen, __TPI_ALIGN_SIZE); 19437c478bd9Sstevel@tonic-gate if (opt == NULL) { 19447c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 19457c478bd9Sstevel@tonic-gate freemsg(mp); 19467c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 19477c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 19487c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19492caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 19507c478bd9Sstevel@tonic-gate "sockfs: T_optdata_ind with invalid " 19517c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 19527c478bd9Sstevel@tonic-gate optlen, tdi->OPT_offset); 19537c478bd9Sstevel@tonic-gate return (NULL); 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate /* 19567c478bd9Sstevel@tonic-gate * If we received a close indication mark the 19577c478bd9Sstevel@tonic-gate * socket and discard this message. 19587c478bd9Sstevel@tonic-gate */ 19597c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 19607c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 19617c478bd9Sstevel@tonic-gate socantsendmore(so); 19627c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19637c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 19647c478bd9Sstevel@tonic-gate freemsg(mp); 19657c478bd9Sstevel@tonic-gate return (NULL); 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate } 19687c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19697c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19707c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19717c478bd9Sstevel@tonic-gate return (mp); 19727c478bd9Sstevel@tonic-gate } 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate case T_EXDATA_IND: { 19757c478bd9Sstevel@tonic-gate mblk_t *mctl, *mdata; 1976e63f9565Sss mblk_t *lbp; 1977e63f9565Sss union T_primitives *tprp; 1978e63f9565Sss struct stdata *stp; 1979e63f9565Sss queue_t *qp; 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_exdata_ind)) { 19822caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 19837c478bd9Sstevel@tonic-gate "sockfs: Too short T_EXDATA_IND. Len = %ld\n", 19847c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 19857c478bd9Sstevel@tonic-gate freemsg(mp); 19867c478bd9Sstevel@tonic-gate return (NULL); 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate /* 19897c478bd9Sstevel@tonic-gate * Ignore zero-length T_EXDATA_IND messages. These might be 19907c478bd9Sstevel@tonic-gate * generated by some transports. 19917c478bd9Sstevel@tonic-gate * 19927c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 19937c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 19947c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 19957c478bd9Sstevel@tonic-gate * that data is available). 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate dprintso(so, 1, 1998*d3e55dcdSgww ("T_EXDATA_IND(%p): counts %d/%d state %s\n", 1999*d3e55dcdSgww vp, so->so_oobsigcnt, so->so_oobcnt, 2000*d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 20037c478bd9Sstevel@tonic-gate dprintso(so, 0, 2004*d3e55dcdSgww ("strsock_proto: zero length T_EXDATA_IND\n")); 20057c478bd9Sstevel@tonic-gate freemsg(mp); 20067c478bd9Sstevel@tonic-gate return (NULL); 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate /* 20107c478bd9Sstevel@tonic-gate * Split into the T_EXDATA_IND and the M_DATA part. 20117c478bd9Sstevel@tonic-gate * We process these three pieces separately: 20127c478bd9Sstevel@tonic-gate * signal generation 20137c478bd9Sstevel@tonic-gate * handling T_EXDATA_IND 20147c478bd9Sstevel@tonic-gate * handling M_DATA component 20157c478bd9Sstevel@tonic-gate */ 20167c478bd9Sstevel@tonic-gate mctl = mp; 20177c478bd9Sstevel@tonic-gate mdata = mctl->b_cont; 20187c478bd9Sstevel@tonic-gate mctl->b_cont = NULL; 20197c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 20207c478bd9Sstevel@tonic-gate so_oob_sig(so, 0, allmsgsigs, pollwakeups); 20217c478bd9Sstevel@tonic-gate mctl = so_oob_exdata(so, mctl, allmsgsigs, pollwakeups); 20227c478bd9Sstevel@tonic-gate mdata = so_oob_data(so, mdata, allmsgsigs, pollwakeups); 20237c478bd9Sstevel@tonic-gate 2024e63f9565Sss stp = vp->v_stream; 2025e63f9565Sss ASSERT(stp != NULL); 2026e63f9565Sss qp = _RD(stp->sd_wrq); 2027e63f9565Sss 2028e63f9565Sss mutex_enter(QLOCK(qp)); 2029e63f9565Sss lbp = qp->q_last; 2030e63f9565Sss 2031e63f9565Sss /* 2032e63f9565Sss * We want to avoid queueing up a string of T_EXDATA_IND 2033e63f9565Sss * messages with no intervening data messages at the stream 2034e63f9565Sss * head. These messages contribute to the total message 2035e63f9565Sss * count. Eventually this can lead to STREAMS flow contol 2036e63f9565Sss * and also cause TCP to advertise a zero window condition 2037e63f9565Sss * to the peer. This can happen in the degenerate case where 2038e63f9565Sss * the sender and receiver exchange only OOB data. The sender 2039e63f9565Sss * only sends messages with MSG_OOB flag and the receiver 2040e63f9565Sss * receives only MSG_OOB messages and does not use SO_OOBINLINE. 2041e63f9565Sss * An example of this scenario has been reported in applications 2042e63f9565Sss * that use OOB data to exchange heart beats. Flow control 2043e63f9565Sss * relief will never happen if the application only reads OOB 2044e63f9565Sss * data which is done directly by sorecvoob() and the 2045e63f9565Sss * T_EXDATA_IND messages at the streamhead won't be consumed. 2046e63f9565Sss * Note that there is no correctness issue in compressing the 2047e63f9565Sss * string of T_EXDATA_IND messages into a single T_EXDATA_IND 2048e63f9565Sss * message. A single read that does not specify MSG_OOB will 2049e63f9565Sss * read across all the marks in a loop in sotpi_recvmsg(). 2050e63f9565Sss * Each mark is individually distinguishable only if the 2051e63f9565Sss * T_EXDATA_IND messages are separated by data messages. 2052e63f9565Sss */ 2053e63f9565Sss if ((qp->q_first != NULL) && (DB_TYPE(lbp) == M_PROTO)) { 2054e63f9565Sss tprp = (union T_primitives *)lbp->b_rptr; 2055e63f9565Sss if ((tprp->type == T_EXDATA_IND) && 2056e63f9565Sss !(so->so_options & SO_OOBINLINE)) { 2057e63f9565Sss 2058e63f9565Sss /* 2059e63f9565Sss * free the new M_PROTO message 2060e63f9565Sss */ 2061e63f9565Sss freemsg(mctl); 2062e63f9565Sss 2063e63f9565Sss /* 2064e63f9565Sss * adjust the OOB count and OOB signal count 2065e63f9565Sss * just incremented for the new OOB data. 2066e63f9565Sss */ 2067e63f9565Sss so->so_oobcnt--; 2068e63f9565Sss so->so_oobsigcnt--; 2069e63f9565Sss mutex_exit(QLOCK(qp)); 2070e63f9565Sss mutex_exit(&so->so_lock); 2071e63f9565Sss return (NULL); 2072e63f9565Sss } 2073e63f9565Sss } 2074e63f9565Sss mutex_exit(QLOCK(qp)); 2075e63f9565Sss 20767c478bd9Sstevel@tonic-gate /* 20777c478bd9Sstevel@tonic-gate * Pass the T_EXDATA_IND and the M_DATA back separately 20787c478bd9Sstevel@tonic-gate * by using b_next linkage. (The stream head will queue any 20797c478bd9Sstevel@tonic-gate * b_next linked messages separately.) This is needed 20807c478bd9Sstevel@tonic-gate * since MSGMARK applies to the last by of the message 20817c478bd9Sstevel@tonic-gate * hence we can not have any M_DATA component attached 20827c478bd9Sstevel@tonic-gate * to the marked T_EXDATA_IND. Note that the stream head 20837c478bd9Sstevel@tonic-gate * will not consolidate M_DATA messages onto an MSGMARK'ed 20847c478bd9Sstevel@tonic-gate * message in order to preserve the constraint that 20857c478bd9Sstevel@tonic-gate * the T_EXDATA_IND always is a separate message. 20867c478bd9Sstevel@tonic-gate */ 20877c478bd9Sstevel@tonic-gate ASSERT(mctl != NULL); 20887c478bd9Sstevel@tonic-gate mctl->b_next = mdata; 20897c478bd9Sstevel@tonic-gate mp = mctl; 20907c478bd9Sstevel@tonic-gate #ifdef DEBUG 20917c478bd9Sstevel@tonic-gate if (mdata == NULL) { 20927c478bd9Sstevel@tonic-gate dprintso(so, 1, 2093*d3e55dcdSgww ("after outofline T_EXDATA_IND(%p): " 2094*d3e55dcdSgww "counts %d/%d poll 0x%x sig 0x%x state %s\n", 2095*d3e55dcdSgww vp, so->so_oobsigcnt, 2096*d3e55dcdSgww so->so_oobcnt, *pollwakeups, *allmsgsigs, 2097*d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 20987c478bd9Sstevel@tonic-gate } else { 20997c478bd9Sstevel@tonic-gate dprintso(so, 1, 2100*d3e55dcdSgww ("after inline T_EXDATA_IND(%p): " 2101*d3e55dcdSgww "counts %d/%d poll 0x%x sig 0x%x state %s\n", 2102*d3e55dcdSgww vp, so->so_oobsigcnt, 2103*d3e55dcdSgww so->so_oobcnt, *pollwakeups, *allmsgsigs, 2104*d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 21077c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21087c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 21097c478bd9Sstevel@tonic-gate return (mp); 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate case T_CONN_CON: { 21137c478bd9Sstevel@tonic-gate struct T_conn_con *conn_con; 21147c478bd9Sstevel@tonic-gate void *addr; 21157c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate /* 21187c478bd9Sstevel@tonic-gate * Verify the state, update the state to ISCONNECTED, 21197c478bd9Sstevel@tonic-gate * record the potentially new address in the message, 21207c478bd9Sstevel@tonic-gate * and drop the message. 21217c478bd9Sstevel@tonic-gate */ 21227c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_con)) { 21232caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 21247c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_CON. Len = %ld\n", 21257c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 21267c478bd9Sstevel@tonic-gate freemsg(mp); 21277c478bd9Sstevel@tonic-gate return (NULL); 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 21317c478bd9Sstevel@tonic-gate if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) != 21327c478bd9Sstevel@tonic-gate SS_ISCONNECTING) { 21337c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21347c478bd9Sstevel@tonic-gate dprintso(so, 1, 2135*d3e55dcdSgww ("T_CONN_CON: state %x\n", so->so_state)); 21367c478bd9Sstevel@tonic-gate freemsg(mp); 21377c478bd9Sstevel@tonic-gate return (NULL); 21387c478bd9Sstevel@tonic-gate } 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate conn_con = &tpr->conn_con; 21417c478bd9Sstevel@tonic-gate addrlen = conn_con->RES_length; 21427c478bd9Sstevel@tonic-gate /* 21437c478bd9Sstevel@tonic-gate * Allow the address to be of different size than sent down 21447c478bd9Sstevel@tonic-gate * in the T_CONN_REQ as long as it doesn't exceed the maxlen. 21457c478bd9Sstevel@tonic-gate * For AF_UNIX require the identical length. 21467c478bd9Sstevel@tonic-gate */ 21477c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX ? 21487c478bd9Sstevel@tonic-gate addrlen != (t_uscalar_t)sizeof (so->so_ux_laddr) : 21497c478bd9Sstevel@tonic-gate addrlen > (t_uscalar_t)so->so_faddr_maxlen) { 21502caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 21517c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with different " 21527c478bd9Sstevel@tonic-gate "length %u/%d\n", 21537c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_length); 21547c478bd9Sstevel@tonic-gate soisdisconnected(so, EPROTO); 21557c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21567c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 21577c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 21587c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 21597c478bd9Sstevel@tonic-gate freemsg(mp); 21607c478bd9Sstevel@tonic-gate /* 21617c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 21627c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 21637c478bd9Sstevel@tonic-gate */ 21647c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 21657c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 21667c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 21677c478bd9Sstevel@tonic-gate return (NULL); 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate addr = sogetoff(mp, conn_con->RES_offset, addrlen, 1); 21707c478bd9Sstevel@tonic-gate if (addr == NULL) { 21712caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 21727c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with invalid " 21737c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 21747c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_offset); 21757c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21767c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 21777c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 21787c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 21797c478bd9Sstevel@tonic-gate freemsg(mp); 21807c478bd9Sstevel@tonic-gate /* 21817c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 21827c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 21837c478bd9Sstevel@tonic-gate */ 21847c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 21857c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 21867c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 21877c478bd9Sstevel@tonic-gate return (NULL); 21887c478bd9Sstevel@tonic-gate } 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate /* 21917c478bd9Sstevel@tonic-gate * Save for getpeername. 21927c478bd9Sstevel@tonic-gate */ 21937c478bd9Sstevel@tonic-gate if (so->so_family != AF_UNIX) { 21947c478bd9Sstevel@tonic-gate so->so_faddr_len = (socklen_t)addrlen; 21957c478bd9Sstevel@tonic-gate ASSERT(so->so_faddr_len <= so->so_faddr_maxlen); 21967c478bd9Sstevel@tonic-gate bcopy(addr, so->so_faddr_sa, addrlen); 21977c478bd9Sstevel@tonic-gate so->so_state |= SS_FADDR_VALID; 21987c478bd9Sstevel@tonic-gate } 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 22017c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 22027c478bd9Sstevel@tonic-gate so->so_peercred = DB_CRED(mp); 22037c478bd9Sstevel@tonic-gate so->so_cpid = DB_CPID(mp); 22047c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 22057c478bd9Sstevel@tonic-gate crhold(so->so_peercred); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate /* Wakeup anybody sleeping in sowaitconnected */ 22087c478bd9Sstevel@tonic-gate soisconnected(so); 22097c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate /* 22127c478bd9Sstevel@tonic-gate * The socket is now available for sending data. 22137c478bd9Sstevel@tonic-gate */ 22147c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 22157c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 22167c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 22177c478bd9Sstevel@tonic-gate freemsg(mp); 22187c478bd9Sstevel@tonic-gate return (NULL); 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate 2221c28749e9Skais /* 2222c28749e9Skais * Extra processing in case of an SSL proxy, before queuing or 2223c28749e9Skais * forwarding to the fallback endpoint 2224c28749e9Skais */ 2225c28749e9Skais case T_SSL_PROXY_CONN_IND: 22267c478bd9Sstevel@tonic-gate case T_CONN_IND: 22277c478bd9Sstevel@tonic-gate /* 22287c478bd9Sstevel@tonic-gate * Verify the min size and queue the message on 22297c478bd9Sstevel@tonic-gate * the so_conn_ind_head/tail list. 22307c478bd9Sstevel@tonic-gate */ 22317c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_ind)) { 22322caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22337c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_IND. Len = %ld\n", 22347c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 22357c478bd9Sstevel@tonic-gate freemsg(mp); 22367c478bd9Sstevel@tonic-gate return (NULL); 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate 22397c478bd9Sstevel@tonic-gate if (audit_active) 22407c478bd9Sstevel@tonic-gate audit_sock(T_CONN_IND, strvp2wq(vp), mp, 0); 22417c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ACCEPTCONN)) { 22422caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22437c478bd9Sstevel@tonic-gate "sockfs: T_conn_ind on non-listening socket\n"); 22447c478bd9Sstevel@tonic-gate freemsg(mp); 22457c478bd9Sstevel@tonic-gate return (NULL); 22467c478bd9Sstevel@tonic-gate } 2247c28749e9Skais 2248c28749e9Skais if (tpr->type == T_SSL_PROXY_CONN_IND && mp->b_cont == NULL) { 2249c28749e9Skais /* No context: need to fall back */ 2250c28749e9Skais struct sonode *fbso; 2251c28749e9Skais stdata_t *fbstp; 2252c28749e9Skais 2253c28749e9Skais tpr->type = T_CONN_IND; 2254c28749e9Skais 2255c28749e9Skais fbso = kssl_find_fallback(so->so_kssl_ent); 2256c28749e9Skais 2257c28749e9Skais /* 2258c28749e9Skais * No fallback: the remote will timeout and 2259c28749e9Skais * disconnect. 2260c28749e9Skais */ 2261c28749e9Skais if (fbso == NULL) { 2262c28749e9Skais freemsg(mp); 2263c28749e9Skais return (NULL); 2264c28749e9Skais } 2265c28749e9Skais fbstp = SOTOV(fbso)->v_stream; 2266c28749e9Skais qreply(fbstp->sd_wrq->q_next, mp); 2267c28749e9Skais return (NULL); 2268c28749e9Skais } 22697c478bd9Sstevel@tonic-gate soqueueconnind(so, mp); 22707c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 22717c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 22727c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 22737c478bd9Sstevel@tonic-gate return (NULL); 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate case T_ORDREL_IND: 22767c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ordrel_ind)) { 22772caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22787c478bd9Sstevel@tonic-gate "sockfs: Too short T_ORDREL_IND. Len = %ld\n", 22797c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 22807c478bd9Sstevel@tonic-gate freemsg(mp); 22817c478bd9Sstevel@tonic-gate return (NULL); 22827c478bd9Sstevel@tonic-gate } 22837c478bd9Sstevel@tonic-gate 22847c478bd9Sstevel@tonic-gate /* 22857c478bd9Sstevel@tonic-gate * Some providers send this when not fully connected. 22867c478bd9Sstevel@tonic-gate * SunLink X.25 needs to retrieve disconnect reason after 22877c478bd9Sstevel@tonic-gate * disconnect for compatibility. It uses T_ORDREL_IND 22887c478bd9Sstevel@tonic-gate * instead of T_DISCON_IND so that it may use the 22897c478bd9Sstevel@tonic-gate * endpoint after a connect failure to retrieve the 22907c478bd9Sstevel@tonic-gate * reason using an ioctl. Thus we explicitly clear 22917c478bd9Sstevel@tonic-gate * SS_ISCONNECTING here for SunLink X.25. 22927c478bd9Sstevel@tonic-gate * This is a needed TPI violation. 22937c478bd9Sstevel@tonic-gate */ 22947c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 22957c478bd9Sstevel@tonic-gate so->so_state &= ~SS_ISCONNECTING; 22967c478bd9Sstevel@tonic-gate socantrcvmore(so); 22977c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 22987c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 22997c478bd9Sstevel@tonic-gate /* 23007c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 23017c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 23027c478bd9Sstevel@tonic-gate */ 23037c478bd9Sstevel@tonic-gate freemsg(mp); 23047c478bd9Sstevel@tonic-gate return (NULL); 23057c478bd9Sstevel@tonic-gate 23067c478bd9Sstevel@tonic-gate case T_DISCON_IND: 23077c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_discon_ind)) { 23082caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23097c478bd9Sstevel@tonic-gate "sockfs: Too short T_DISCON_IND. Len = %ld\n", 23107c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 23117c478bd9Sstevel@tonic-gate freemsg(mp); 23127c478bd9Sstevel@tonic-gate return (NULL); 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate if (so->so_state & SS_ACCEPTCONN) { 23157c478bd9Sstevel@tonic-gate /* 23167c478bd9Sstevel@tonic-gate * This is a listener. Look for a queued T_CONN_IND 23177c478bd9Sstevel@tonic-gate * with a matching sequence number and remove it 23187c478bd9Sstevel@tonic-gate * from the list. 23197c478bd9Sstevel@tonic-gate * It is normal to not find the sequence number since 23207c478bd9Sstevel@tonic-gate * the soaccept might have already dequeued it 23217c478bd9Sstevel@tonic-gate * (in which case the T_CONN_RES will fail with 23227c478bd9Sstevel@tonic-gate * TBADSEQ). 23237c478bd9Sstevel@tonic-gate */ 23247c478bd9Sstevel@tonic-gate (void) soflushconnind(so, tpr->discon_ind.SEQ_number); 23257c478bd9Sstevel@tonic-gate freemsg(mp); 23267c478bd9Sstevel@tonic-gate return (0); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate /* 23307c478bd9Sstevel@tonic-gate * Not a listener 23317c478bd9Sstevel@tonic-gate * 23327c478bd9Sstevel@tonic-gate * If SS_CANTRCVMORE for AF_UNIX ignore the discon_reason. 23337c478bd9Sstevel@tonic-gate * Such a discon_ind appears when the peer has first done 23347c478bd9Sstevel@tonic-gate * a shutdown() followed by a close() in which case we just 23357c478bd9Sstevel@tonic-gate * want to record socantsendmore. 23367c478bd9Sstevel@tonic-gate * In this case sockfs first receives a T_ORDREL_IND followed 23377c478bd9Sstevel@tonic-gate * by a T_DISCON_IND. 23387c478bd9Sstevel@tonic-gate * Note that for other transports (e.g. TCP) we need to handle 23397c478bd9Sstevel@tonic-gate * the discon_ind in this case since it signals an error. 23407c478bd9Sstevel@tonic-gate */ 23417c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 23427c478bd9Sstevel@tonic-gate if ((so->so_state & SS_CANTRCVMORE) && 23437c478bd9Sstevel@tonic-gate (so->so_family == AF_UNIX)) { 23447c478bd9Sstevel@tonic-gate socantsendmore(so); 23457c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23467c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 23477c478bd9Sstevel@tonic-gate dprintso(so, 1, 2348*d3e55dcdSgww ("T_DISCON_IND: error %d\n", so->so_error)); 23497c478bd9Sstevel@tonic-gate freemsg(mp); 23507c478bd9Sstevel@tonic-gate /* 23517c478bd9Sstevel@tonic-gate * Set these variables for caller to process them. 23527c478bd9Sstevel@tonic-gate * For the else part where T_DISCON_IND is processed, 23537c478bd9Sstevel@tonic-gate * this will be done in the function being called 23547c478bd9Sstevel@tonic-gate * (strsock_discon_ind()) 23557c478bd9Sstevel@tonic-gate */ 23567c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 23577c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 23587c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 23597c478bd9Sstevel@tonic-gate } else if (so->so_flag & (SOASYNC_UNBIND | SOLOCKED)) { 23607c478bd9Sstevel@tonic-gate /* 23617c478bd9Sstevel@tonic-gate * Deferred processing of T_DISCON_IND 23627c478bd9Sstevel@tonic-gate */ 23637c478bd9Sstevel@tonic-gate so_save_discon_ind(so, mp, strsock_discon_ind); 23647c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23657c478bd9Sstevel@tonic-gate } else { 23667c478bd9Sstevel@tonic-gate /* 23677c478bd9Sstevel@tonic-gate * Process T_DISCON_IND now 23687c478bd9Sstevel@tonic-gate */ 23697c478bd9Sstevel@tonic-gate (void) strsock_discon_ind(so, mp); 23707c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23717c478bd9Sstevel@tonic-gate } 23727c478bd9Sstevel@tonic-gate return (NULL); 23737c478bd9Sstevel@tonic-gate 23747c478bd9Sstevel@tonic-gate case T_UDERROR_IND: { 23757c478bd9Sstevel@tonic-gate struct T_uderror_ind *tudi = &tpr->uderror_ind; 23767c478bd9Sstevel@tonic-gate void *addr; 23777c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 23787c478bd9Sstevel@tonic-gate int error; 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate dprintso(so, 0, 2381*d3e55dcdSgww ("T_UDERROR_IND: error %d\n", tudi->ERROR_type)); 23827c478bd9Sstevel@tonic-gate 23837c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_uderror_ind)) { 23842caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23857c478bd9Sstevel@tonic-gate "sockfs: Too short T_UDERROR_IND. Len = %ld\n", 23867c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 23877c478bd9Sstevel@tonic-gate freemsg(mp); 23887c478bd9Sstevel@tonic-gate return (NULL); 23897c478bd9Sstevel@tonic-gate } 23907c478bd9Sstevel@tonic-gate /* Ignore on connection-oriented transports */ 23917c478bd9Sstevel@tonic-gate if (so->so_mode & SM_CONNREQUIRED) { 23927c478bd9Sstevel@tonic-gate freemsg(mp); 23937c478bd9Sstevel@tonic-gate eprintsoline(so, 0); 23942caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23957c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind on connection-oriented " 23967c478bd9Sstevel@tonic-gate "transport\n"); 23977c478bd9Sstevel@tonic-gate return (NULL); 23987c478bd9Sstevel@tonic-gate } 23997c478bd9Sstevel@tonic-gate addrlen = tudi->DEST_length; 24007c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->DEST_offset, addrlen, 1); 24017c478bd9Sstevel@tonic-gate if (addr == NULL) { 24022caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 24037c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind with invalid " 24047c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 24057c478bd9Sstevel@tonic-gate addrlen, tudi->DEST_offset); 24067c478bd9Sstevel@tonic-gate freemsg(mp); 24077c478bd9Sstevel@tonic-gate return (NULL); 24087c478bd9Sstevel@tonic-gate } 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate /* Verify source address for connected socket. */ 24117c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 24127c478bd9Sstevel@tonic-gate if (so->so_state & SS_ISCONNECTED) { 24137c478bd9Sstevel@tonic-gate void *faddr; 24147c478bd9Sstevel@tonic-gate t_uscalar_t faddr_len; 24157c478bd9Sstevel@tonic-gate boolean_t match = B_FALSE; 24167c478bd9Sstevel@tonic-gate 24177c478bd9Sstevel@tonic-gate switch (so->so_family) { 24187c478bd9Sstevel@tonic-gate case AF_INET: { 24197c478bd9Sstevel@tonic-gate /* Compare just IP address and port */ 24207c478bd9Sstevel@tonic-gate struct sockaddr_in *sin1, *sin2; 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate sin1 = (struct sockaddr_in *)so->so_faddr_sa; 24237c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in *)addr; 24247c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in) && 24257c478bd9Sstevel@tonic-gate sin1->sin_port == sin2->sin_port && 24267c478bd9Sstevel@tonic-gate sin1->sin_addr.s_addr == 24277c478bd9Sstevel@tonic-gate sin2->sin_addr.s_addr) 24287c478bd9Sstevel@tonic-gate match = B_TRUE; 24297c478bd9Sstevel@tonic-gate break; 24307c478bd9Sstevel@tonic-gate } 24317c478bd9Sstevel@tonic-gate case AF_INET6: { 24327c478bd9Sstevel@tonic-gate /* Compare just IP address and port. Not flow */ 24337c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin1, *sin2; 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate sin1 = (struct sockaddr_in6 *)so->so_faddr_sa; 24367c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in6 *)addr; 24377c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in6) && 24387c478bd9Sstevel@tonic-gate sin1->sin6_port == sin2->sin6_port && 24397c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr, 2440*d3e55dcdSgww &sin2->sin6_addr)) 24417c478bd9Sstevel@tonic-gate match = B_TRUE; 24427c478bd9Sstevel@tonic-gate break; 24437c478bd9Sstevel@tonic-gate } 24447c478bd9Sstevel@tonic-gate case AF_UNIX: 24457c478bd9Sstevel@tonic-gate faddr = &so->so_ux_faddr; 24467c478bd9Sstevel@tonic-gate faddr_len = 2447*d3e55dcdSgww (t_uscalar_t)sizeof (so->so_ux_faddr); 24487c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 24497c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 24507c478bd9Sstevel@tonic-gate match = B_TRUE; 24517c478bd9Sstevel@tonic-gate break; 24527c478bd9Sstevel@tonic-gate default: 24537c478bd9Sstevel@tonic-gate faddr = so->so_faddr_sa; 24547c478bd9Sstevel@tonic-gate faddr_len = (t_uscalar_t)so->so_faddr_len; 24557c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 24567c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 24577c478bd9Sstevel@tonic-gate match = B_TRUE; 24587c478bd9Sstevel@tonic-gate break; 24597c478bd9Sstevel@tonic-gate } 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate if (!match) { 24627c478bd9Sstevel@tonic-gate #ifdef DEBUG 24637c478bd9Sstevel@tonic-gate dprintso(so, 0, 2464*d3e55dcdSgww ("sockfs: T_UDERR_IND mismatch: %s - ", 2465*d3e55dcdSgww pr_addr(so->so_family, 2466*d3e55dcdSgww (struct sockaddr *)addr, 2467*d3e55dcdSgww addrlen))); 24687c478bd9Sstevel@tonic-gate dprintso(so, 0, ("%s\n", 2469*d3e55dcdSgww pr_addr(so->so_family, so->so_faddr_sa, 2470*d3e55dcdSgww so->so_faddr_len))); 24717c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 24727c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 24737c478bd9Sstevel@tonic-gate freemsg(mp); 24747c478bd9Sstevel@tonic-gate return (NULL); 24757c478bd9Sstevel@tonic-gate } 24767c478bd9Sstevel@tonic-gate /* 24777c478bd9Sstevel@tonic-gate * Make the write error nonpersistent. If the error 24787c478bd9Sstevel@tonic-gate * is zero we use ECONNRESET. 24797c478bd9Sstevel@tonic-gate * This assumes that the name space for ERROR_type 24807c478bd9Sstevel@tonic-gate * is the errno name space. 24817c478bd9Sstevel@tonic-gate */ 24827c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 24837c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 24847c478bd9Sstevel@tonic-gate else 24857c478bd9Sstevel@tonic-gate error = ECONNRESET; 24867c478bd9Sstevel@tonic-gate 24877c478bd9Sstevel@tonic-gate soseterror(so, error); 24887c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 24897c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 24907c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 24917c478bd9Sstevel@tonic-gate *wakeups = RSLEEP | WSLEEP; 24927c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM | S_OUTPUT; 24937c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM | POLLOUT; 24947c478bd9Sstevel@tonic-gate freemsg(mp); 24957c478bd9Sstevel@tonic-gate return (NULL); 24967c478bd9Sstevel@tonic-gate } 24977c478bd9Sstevel@tonic-gate /* 24987c478bd9Sstevel@tonic-gate * If the application asked for delayed errors 24997c478bd9Sstevel@tonic-gate * record the T_UDERROR_IND so_eaddr_mp and the reason in 25007c478bd9Sstevel@tonic-gate * so_delayed_error for delayed error posting. If the reason 25017c478bd9Sstevel@tonic-gate * is zero use ECONNRESET. 25027c478bd9Sstevel@tonic-gate * Note that delayed error indications do not make sense for 25037c478bd9Sstevel@tonic-gate * AF_UNIX sockets since sendto checks that the destination 25047c478bd9Sstevel@tonic-gate * address is valid at the time of the sendto. 25057c478bd9Sstevel@tonic-gate */ 25067c478bd9Sstevel@tonic-gate if (!(so->so_options & SO_DGRAM_ERRIND)) { 25077c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25087c478bd9Sstevel@tonic-gate freemsg(mp); 25097c478bd9Sstevel@tonic-gate return (NULL); 25107c478bd9Sstevel@tonic-gate } 25117c478bd9Sstevel@tonic-gate if (so->so_eaddr_mp != NULL) 25127c478bd9Sstevel@tonic-gate freemsg(so->so_eaddr_mp); 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate so->so_eaddr_mp = mp; 25157c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 25167c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 25177c478bd9Sstevel@tonic-gate else 25187c478bd9Sstevel@tonic-gate error = ECONNRESET; 25197c478bd9Sstevel@tonic-gate so->so_delayed_error = (ushort_t)error; 25207c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25217c478bd9Sstevel@tonic-gate return (NULL); 25227c478bd9Sstevel@tonic-gate } 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate case T_ERROR_ACK: 25257c478bd9Sstevel@tonic-gate dprintso(so, 0, 2526*d3e55dcdSgww ("strsock_proto: T_ERROR_ACK for %d, error %d/%d\n", 2527*d3e55dcdSgww tpr->error_ack.ERROR_prim, 2528*d3e55dcdSgww tpr->error_ack.TLI_error, 2529*d3e55dcdSgww tpr->error_ack.UNIX_error)); 25307c478bd9Sstevel@tonic-gate 25317c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_error_ack)) { 25322caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25337c478bd9Sstevel@tonic-gate "sockfs: Too short T_ERROR_ACK. Len = %ld\n", 25347c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 25357c478bd9Sstevel@tonic-gate freemsg(mp); 25367c478bd9Sstevel@tonic-gate return (NULL); 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate /* 25397c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 25407c478bd9Sstevel@tonic-gate */ 25417c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 25427c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 25437c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == T_UNBIND_REQ) { 25447c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 25457c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25467c478bd9Sstevel@tonic-gate freemsg(mp); 25477c478bd9Sstevel@tonic-gate return (NULL); 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25507c478bd9Sstevel@tonic-gate soqueueack(so, mp); 25517c478bd9Sstevel@tonic-gate return (NULL); 25527c478bd9Sstevel@tonic-gate 25537c478bd9Sstevel@tonic-gate case T_OK_ACK: 25547c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ok_ack)) { 25552caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25567c478bd9Sstevel@tonic-gate "sockfs: Too short T_OK_ACK. Len = %ld\n", 25577c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 25587c478bd9Sstevel@tonic-gate freemsg(mp); 25597c478bd9Sstevel@tonic-gate return (NULL); 25607c478bd9Sstevel@tonic-gate } 25617c478bd9Sstevel@tonic-gate /* 25627c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 25637c478bd9Sstevel@tonic-gate */ 25647c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 25657c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 25667c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == T_UNBIND_REQ) { 25677c478bd9Sstevel@tonic-gate dprintso(so, 1, 2568*d3e55dcdSgww ("strsock_proto: T_OK_ACK async unbind\n")); 25697c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 25707c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25717c478bd9Sstevel@tonic-gate freemsg(mp); 25727c478bd9Sstevel@tonic-gate return (NULL); 25737c478bd9Sstevel@tonic-gate } 25747c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25757c478bd9Sstevel@tonic-gate soqueueack(so, mp); 25767c478bd9Sstevel@tonic-gate return (NULL); 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate case T_INFO_ACK: 25797c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_info_ack)) { 25802caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25817c478bd9Sstevel@tonic-gate "sockfs: Too short T_INFO_ACK. Len = %ld\n", 25827c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 25837c478bd9Sstevel@tonic-gate freemsg(mp); 25847c478bd9Sstevel@tonic-gate return (NULL); 25857c478bd9Sstevel@tonic-gate } 25867c478bd9Sstevel@tonic-gate soqueueack(so, mp); 25877c478bd9Sstevel@tonic-gate return (NULL); 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate case T_CAPABILITY_ACK: 25907c478bd9Sstevel@tonic-gate /* 25917c478bd9Sstevel@tonic-gate * A T_capability_ack need only be large enough to hold 25927c478bd9Sstevel@tonic-gate * the PRIM_type and CAP_bits1 fields; checking for anything 25937c478bd9Sstevel@tonic-gate * larger might reject a correct response from an older 25947c478bd9Sstevel@tonic-gate * provider. 25957c478bd9Sstevel@tonic-gate */ 25967c478bd9Sstevel@tonic-gate if (MBLKL(mp) < 2 * sizeof (t_uscalar_t)) { 25972caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25987c478bd9Sstevel@tonic-gate "sockfs: Too short T_CAPABILITY_ACK. Len = %ld\n", 25997c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26007c478bd9Sstevel@tonic-gate freemsg(mp); 26017c478bd9Sstevel@tonic-gate return (NULL); 26027c478bd9Sstevel@tonic-gate } 26037c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26047c478bd9Sstevel@tonic-gate return (NULL); 26057c478bd9Sstevel@tonic-gate 26067c478bd9Sstevel@tonic-gate case T_BIND_ACK: 26077c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_bind_ack)) { 26082caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26097c478bd9Sstevel@tonic-gate "sockfs: Too short T_BIND_ACK. Len = %ld\n", 26107c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26117c478bd9Sstevel@tonic-gate freemsg(mp); 26127c478bd9Sstevel@tonic-gate return (NULL); 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26157c478bd9Sstevel@tonic-gate return (NULL); 26167c478bd9Sstevel@tonic-gate 26177c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK: 26187c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optmgmt_ack)) { 26192caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26207c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTMGMT_ACK. Len = %ld\n", 26217c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26227c478bd9Sstevel@tonic-gate freemsg(mp); 26237c478bd9Sstevel@tonic-gate return (NULL); 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26267c478bd9Sstevel@tonic-gate return (NULL); 26277c478bd9Sstevel@tonic-gate default: 26287c478bd9Sstevel@tonic-gate #ifdef DEBUG 26292caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 2630*d3e55dcdSgww "sockfs: unknown TPI primitive %d received\n", 2631*d3e55dcdSgww tpr->type); 26327c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 26337c478bd9Sstevel@tonic-gate freemsg(mp); 26347c478bd9Sstevel@tonic-gate return (NULL); 26357c478bd9Sstevel@tonic-gate } 26367c478bd9Sstevel@tonic-gate } 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate /* 26397c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive other 26407c478bd9Sstevel@tonic-gate * (non-data, and non-proto) messages. 26417c478bd9Sstevel@tonic-gate * 26427c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 26437c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed by the stream head. 26447c478bd9Sstevel@tonic-gate * 26457c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 26467c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. 26477c478bd9Sstevel@tonic-gate */ 26487c478bd9Sstevel@tonic-gate static mblk_t * 26497c478bd9Sstevel@tonic-gate strsock_misc(vnode_t *vp, mblk_t *mp, 26507c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 26517c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 26527c478bd9Sstevel@tonic-gate { 26537c478bd9Sstevel@tonic-gate struct sonode *so; 26547c478bd9Sstevel@tonic-gate 26557c478bd9Sstevel@tonic-gate so = VTOSO(vp); 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_misc(%p, %p, 0x%x)\n", 2658*d3e55dcdSgww vp, mp, DB_TYPE(mp))); 26597c478bd9Sstevel@tonic-gate 26607c478bd9Sstevel@tonic-gate /* Set default return values */ 26617c478bd9Sstevel@tonic-gate *wakeups = *allmsgsigs = *firstmsgsigs = *pollwakeups = 0; 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 26647c478bd9Sstevel@tonic-gate case M_PCSIG: 26657c478bd9Sstevel@tonic-gate /* 26667c478bd9Sstevel@tonic-gate * This assumes that an M_PCSIG for the urgent data arrives 26677c478bd9Sstevel@tonic-gate * before the corresponding T_EXDATA_IND. 26687c478bd9Sstevel@tonic-gate * 26697c478bd9Sstevel@tonic-gate * Note: Just like in SunOS 4.X and 4.4BSD a poll will be 26707c478bd9Sstevel@tonic-gate * awoken before the urgent data shows up. 26717c478bd9Sstevel@tonic-gate * For OOBINLINE this can result in select returning 26727c478bd9Sstevel@tonic-gate * only exceptions as opposed to except|read. 26737c478bd9Sstevel@tonic-gate */ 26747c478bd9Sstevel@tonic-gate if (*mp->b_rptr == SIGURG) { 26757c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 26767c478bd9Sstevel@tonic-gate dprintso(so, 1, 2677*d3e55dcdSgww ("SIGURG(%p): counts %d/%d state %s\n", 2678*d3e55dcdSgww vp, so->so_oobsigcnt, 2679*d3e55dcdSgww so->so_oobcnt, 2680*d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 26817c478bd9Sstevel@tonic-gate so_oob_sig(so, 1, allmsgsigs, pollwakeups); 26827c478bd9Sstevel@tonic-gate dprintso(so, 1, 2683*d3e55dcdSgww ("after SIGURG(%p): counts %d/%d " 2684*d3e55dcdSgww " poll 0x%x sig 0x%x state %s\n", 2685*d3e55dcdSgww vp, so->so_oobsigcnt, 2686*d3e55dcdSgww so->so_oobcnt, *pollwakeups, *allmsgsigs, 2687*d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 26887c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 26897c478bd9Sstevel@tonic-gate } 26907c478bd9Sstevel@tonic-gate freemsg(mp); 26917c478bd9Sstevel@tonic-gate return (NULL); 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate case M_SIG: 26947c478bd9Sstevel@tonic-gate case M_HANGUP: 26957c478bd9Sstevel@tonic-gate case M_UNHANGUP: 26967c478bd9Sstevel@tonic-gate case M_ERROR: 26977c478bd9Sstevel@tonic-gate /* M_ERRORs etc are ignored */ 26987c478bd9Sstevel@tonic-gate freemsg(mp); 26997c478bd9Sstevel@tonic-gate return (NULL); 27007c478bd9Sstevel@tonic-gate 27017c478bd9Sstevel@tonic-gate case M_FLUSH: 27027c478bd9Sstevel@tonic-gate /* 27037c478bd9Sstevel@tonic-gate * Do not flush read queue. If the M_FLUSH 27047c478bd9Sstevel@tonic-gate * arrives because of an impending T_discon_ind 27057c478bd9Sstevel@tonic-gate * we still have to keep any queued data - this is part of 27067c478bd9Sstevel@tonic-gate * socket semantics. 27077c478bd9Sstevel@tonic-gate */ 27087c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 27097c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHR; 27107c478bd9Sstevel@tonic-gate return (mp); 27117c478bd9Sstevel@tonic-gate } 27127c478bd9Sstevel@tonic-gate freemsg(mp); 27137c478bd9Sstevel@tonic-gate return (NULL); 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate default: 27167c478bd9Sstevel@tonic-gate return (mp); 27177c478bd9Sstevel@tonic-gate } 27187c478bd9Sstevel@tonic-gate } 27197c478bd9Sstevel@tonic-gate 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate /* Register to receive signals for certain events */ 27227c478bd9Sstevel@tonic-gate int 27237c478bd9Sstevel@tonic-gate so_set_asyncsigs(vnode_t *vp, pid_t pgrp, int events, int mode, cred_t *cr) 27247c478bd9Sstevel@tonic-gate { 27257c478bd9Sstevel@tonic-gate struct strsigset ss; 27267c478bd9Sstevel@tonic-gate int32_t rval; 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate /* 27297c478bd9Sstevel@tonic-gate * Note that SOLOCKED will be set except for the call from soaccept(). 27307c478bd9Sstevel@tonic-gate */ 27317c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&VTOSO(vp)->so_lock)); 27327c478bd9Sstevel@tonic-gate ss.ss_pid = pgrp; 27337c478bd9Sstevel@tonic-gate ss.ss_events = events; 27347c478bd9Sstevel@tonic-gate return (strioctl(vp, I_ESETSIG, (intptr_t)&ss, mode, K_TO_K, cr, 27357c478bd9Sstevel@tonic-gate &rval)); 27367c478bd9Sstevel@tonic-gate } 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate 27397c478bd9Sstevel@tonic-gate /* Register for events matching the SS_ASYNC flag */ 27407c478bd9Sstevel@tonic-gate int 27417c478bd9Sstevel@tonic-gate so_set_events(struct sonode *so, vnode_t *vp, cred_t *cr) 27427c478bd9Sstevel@tonic-gate { 27437c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 27447c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 27457c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate return (so_set_asyncsigs(vp, so->so_pgrp, events, 0, cr)); 27487c478bd9Sstevel@tonic-gate } 27497c478bd9Sstevel@tonic-gate 27507c478bd9Sstevel@tonic-gate 27517c478bd9Sstevel@tonic-gate /* Change the SS_ASYNC flag, and update signal delivery if needed */ 27527c478bd9Sstevel@tonic-gate int 27537c478bd9Sstevel@tonic-gate so_flip_async(struct sonode *so, vnode_t *vp, int mode, cred_t *cr) 27547c478bd9Sstevel@tonic-gate { 27557c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 27567c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 27577c478bd9Sstevel@tonic-gate int error; 27587c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? /* Old flag */ 27597c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG : /* New sigs */ 27607c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT; 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate so_lock_single(so); 27637c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, events, mode, cr); 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 27687c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 27697c478bd9Sstevel@tonic-gate if (error) 27707c478bd9Sstevel@tonic-gate return (error); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate so->so_state ^= SS_ASYNC; 27737c478bd9Sstevel@tonic-gate return (0); 27747c478bd9Sstevel@tonic-gate } 27757c478bd9Sstevel@tonic-gate 27767c478bd9Sstevel@tonic-gate /* 27777c478bd9Sstevel@tonic-gate * Set new pid/pgrp for SIGPOLL (or SIGIO for FIOASYNC mode), replacing 27787c478bd9Sstevel@tonic-gate * any existing one. If passed zero, just clear the existing one. 27797c478bd9Sstevel@tonic-gate */ 27807c478bd9Sstevel@tonic-gate int 27817c478bd9Sstevel@tonic-gate so_set_siggrp(struct sonode *so, vnode_t *vp, pid_t pgrp, int mode, cred_t *cr) 27827c478bd9Sstevel@tonic-gate { 27837c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 27847c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 27857c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 27867c478bd9Sstevel@tonic-gate int error; 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 27897c478bd9Sstevel@tonic-gate 27907c478bd9Sstevel@tonic-gate /* 27917c478bd9Sstevel@tonic-gate * Change socket process (group). 27927c478bd9Sstevel@tonic-gate * 27937c478bd9Sstevel@tonic-gate * strioctl (via so_set_asyncsigs) will perform permission check and 27947c478bd9Sstevel@tonic-gate * also keep a PID_HOLD to prevent the pid from being reused. 27957c478bd9Sstevel@tonic-gate */ 27967c478bd9Sstevel@tonic-gate so_lock_single(so); 27977c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate if (pgrp != 0) { 28007c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: adding pgrp %d ev 0x%x\n", 28017c478bd9Sstevel@tonic-gate pgrp, events)); 28027c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, pgrp, events, mode, cr); 28037c478bd9Sstevel@tonic-gate if (error != 0) { 28047c478bd9Sstevel@tonic-gate eprintsoline(so, error); 28057c478bd9Sstevel@tonic-gate goto bad; 28067c478bd9Sstevel@tonic-gate } 28077c478bd9Sstevel@tonic-gate } 28087c478bd9Sstevel@tonic-gate /* Remove the previously registered process/group */ 28097c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 28107c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: removing pgrp %d\n", so->so_pgrp)); 28117c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, 0, mode, cr); 28127c478bd9Sstevel@tonic-gate if (error != 0) { 28137c478bd9Sstevel@tonic-gate eprintsoline(so, error); 28147c478bd9Sstevel@tonic-gate error = 0; 28157c478bd9Sstevel@tonic-gate } 28167c478bd9Sstevel@tonic-gate } 28177c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 28187c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 28197c478bd9Sstevel@tonic-gate so->so_pgrp = pgrp; 28207c478bd9Sstevel@tonic-gate return (0); 28217c478bd9Sstevel@tonic-gate bad: 28227c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 28237c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 28247c478bd9Sstevel@tonic-gate return (error); 28257c478bd9Sstevel@tonic-gate } 28267c478bd9Sstevel@tonic-gate 28277c478bd9Sstevel@tonic-gate 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate /* 28307c478bd9Sstevel@tonic-gate * Translate a TLI(/XTI) error into a system error as best we can. 28317c478bd9Sstevel@tonic-gate */ 28327c478bd9Sstevel@tonic-gate static const int tli_errs[] = { 28337c478bd9Sstevel@tonic-gate 0, /* no error */ 28347c478bd9Sstevel@tonic-gate EADDRNOTAVAIL, /* TBADADDR */ 28357c478bd9Sstevel@tonic-gate ENOPROTOOPT, /* TBADOPT */ 28367c478bd9Sstevel@tonic-gate EACCES, /* TACCES */ 28377c478bd9Sstevel@tonic-gate EBADF, /* TBADF */ 28387c478bd9Sstevel@tonic-gate EADDRNOTAVAIL, /* TNOADDR */ 28397c478bd9Sstevel@tonic-gate EPROTO, /* TOUTSTATE */ 28407c478bd9Sstevel@tonic-gate ECONNABORTED, /* TBADSEQ */ 28417c478bd9Sstevel@tonic-gate 0, /* TSYSERR - will never get */ 28427c478bd9Sstevel@tonic-gate EPROTO, /* TLOOK - should never be sent by transport */ 28437c478bd9Sstevel@tonic-gate EMSGSIZE, /* TBADDATA */ 28447c478bd9Sstevel@tonic-gate EMSGSIZE, /* TBUFOVFLW */ 28457c478bd9Sstevel@tonic-gate EPROTO, /* TFLOW */ 28467c478bd9Sstevel@tonic-gate EWOULDBLOCK, /* TNODATA */ 28477c478bd9Sstevel@tonic-gate EPROTO, /* TNODIS */ 28487c478bd9Sstevel@tonic-gate EPROTO, /* TNOUDERR */ 28497c478bd9Sstevel@tonic-gate EINVAL, /* TBADFLAG */ 28507c478bd9Sstevel@tonic-gate EPROTO, /* TNOREL */ 28517c478bd9Sstevel@tonic-gate EOPNOTSUPP, /* TNOTSUPPORT */ 28527c478bd9Sstevel@tonic-gate EPROTO, /* TSTATECHNG */ 28537c478bd9Sstevel@tonic-gate /* following represent error namespace expansion with XTI */ 28547c478bd9Sstevel@tonic-gate EPROTO, /* TNOSTRUCTYPE - never sent by transport */ 28557c478bd9Sstevel@tonic-gate EPROTO, /* TBADNAME - never sent by transport */ 28567c478bd9Sstevel@tonic-gate EPROTO, /* TBADQLEN - never sent by transport */ 28577c478bd9Sstevel@tonic-gate EADDRINUSE, /* TADDRBUSY */ 28587c478bd9Sstevel@tonic-gate EBADF, /* TINDOUT */ 28597c478bd9Sstevel@tonic-gate EBADF, /* TPROVMISMATCH */ 28607c478bd9Sstevel@tonic-gate EBADF, /* TRESQLEN */ 28617c478bd9Sstevel@tonic-gate EBADF, /* TRESADDR */ 28627c478bd9Sstevel@tonic-gate EPROTO, /* TQFULL - never sent by transport */ 28637c478bd9Sstevel@tonic-gate EPROTO, /* TPROTO */ 28647c478bd9Sstevel@tonic-gate }; 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate static int 28677c478bd9Sstevel@tonic-gate tlitosyserr(int terr) 28687c478bd9Sstevel@tonic-gate { 28697c478bd9Sstevel@tonic-gate ASSERT(terr != TSYSERR); 28707c478bd9Sstevel@tonic-gate if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))) 28717c478bd9Sstevel@tonic-gate return (EPROTO); 28727c478bd9Sstevel@tonic-gate else 28737c478bd9Sstevel@tonic-gate return (tli_errs[terr]); 28747c478bd9Sstevel@tonic-gate } 2875