17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52caf0dcdSrshoaib * Common Development and Distribution License (the "License"). 62caf0dcdSrshoaib * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 212caf0dcdSrshoaib 227c478bd9Sstevel@tonic-gate /* 2317169044Sbrutus * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 297c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 307c478bd9Sstevel@tonic-gate #include <sys/param.h> 317c478bd9Sstevel@tonic-gate #include <sys/systm.h> 327c478bd9Sstevel@tonic-gate #include <sys/buf.h> 337c478bd9Sstevel@tonic-gate #include <sys/conf.h> 347c478bd9Sstevel@tonic-gate #include <sys/cred.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 377c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 387c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 397c478bd9Sstevel@tonic-gate #include <sys/debug.h> 407c478bd9Sstevel@tonic-gate #include <sys/errno.h> 417c478bd9Sstevel@tonic-gate #include <sys/time.h> 427c478bd9Sstevel@tonic-gate #include <sys/file.h> 437c478bd9Sstevel@tonic-gate #include <sys/user.h> 447c478bd9Sstevel@tonic-gate #include <sys/stream.h> 457c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 467c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 477c478bd9Sstevel@tonic-gate #include <sys/flock.h> 487c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 497c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 507c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 517c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 527c478bd9Sstevel@tonic-gate #include <sys/proc.h> 537c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 567c478bd9Sstevel@tonic-gate #include <sys/socket.h> 577c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 587c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 59*0f1702c5SYu Xiangning #include <sys/sodirect.h> 607c478bd9Sstevel@tonic-gate #include <netinet/in.h> 61*0f1702c5SYu Xiangning #include <inet/common.h> 62*0f1702c5SYu Xiangning #include <inet/proto_set.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 72*0f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h> 73*0f1702c5SYu Xiangning #include <fs/sockfs/socktpi_impl.h> 7417169044Sbrutus #include <sys/dcopy.h> 7517169044Sbrutus 767c478bd9Sstevel@tonic-gate int so_default_version = SOV_SOCKSTREAM; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate #ifdef DEBUG 797c478bd9Sstevel@tonic-gate /* Set sockdebug to print debug messages when SO_DEBUG is set */ 807c478bd9Sstevel@tonic-gate int sockdebug = 0; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* Set sockprinterr to print error messages when SO_DEBUG is set */ 837c478bd9Sstevel@tonic-gate int sockprinterr = 0; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /* 867c478bd9Sstevel@tonic-gate * Set so_default_options to SO_DEBUG is all sockets should be created 877c478bd9Sstevel@tonic-gate * with SO_DEBUG set. This is needed to get debug printouts from the 887c478bd9Sstevel@tonic-gate * socket() call itself. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate int so_default_options = 0; 917c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * Set to number of ticks to limit cv_waits for code coverage testing. 967c478bd9Sstevel@tonic-gate * Set to 1000 when SO_DEBUG is set to 2. 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate clock_t sock_test_timelimit = 0; 997c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * For concurrency testing of e.g. opening /dev/ip which does not 1037c478bd9Sstevel@tonic-gate * handle T_INFO_REQ messages. 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate int so_no_tinfo = 0; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Timeout for getting a T_CAPABILITY_ACK - it is possible for a provider 1097c478bd9Sstevel@tonic-gate * to simply ignore the T_CAPABILITY_REQ. 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate clock_t sock_capability_timeout = 2; /* seconds */ 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static int do_tcapability(struct sonode *so, t_uscalar_t cap_bits1); 1147c478bd9Sstevel@tonic-gate static void so_removehooks(struct sonode *so); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate static mblk_t *strsock_proto(vnode_t *vp, mblk_t *mp, 1177c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 1187c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 1197c478bd9Sstevel@tonic-gate static mblk_t *strsock_misc(vnode_t *vp, mblk_t *mp, 1207c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 1217c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 12217169044Sbrutus /* 123*0f1702c5SYu Xiangning * STREAMS based sodirect put/wakeup functions. 12417169044Sbrutus */ 12517169044Sbrutus static int sodput(sodirect_t *, mblk_t *); 12617169044Sbrutus static void sodwakeup(sodirect_t *); 12717169044Sbrutus 12817169044Sbrutus /* 12917169044Sbrutus * Called by sockinit() when sockfs is loaded. 13017169044Sbrutus */ 13117169044Sbrutus int 13217169044Sbrutus sostr_init() 13317169044Sbrutus { 134*0f1702c5SYu Xiangning sod_init(); 13517169044Sbrutus return (0); 13617169044Sbrutus } 13717169044Sbrutus 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * Convert a socket to a stream. Invoked when the illusory sockmod 1407c478bd9Sstevel@tonic-gate * is popped from the stream. 1417c478bd9Sstevel@tonic-gate * Change the stream head back to default operation without losing 1427c478bd9Sstevel@tonic-gate * any messages (T_conn_ind's are moved to the stream head queue). 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate int 1457c478bd9Sstevel@tonic-gate so_sock2stream(struct sonode *so) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 1487c478bd9Sstevel@tonic-gate queue_t *rq; 1497c478bd9Sstevel@tonic-gate mblk_t *mp; 1507c478bd9Sstevel@tonic-gate int error = 0; 151*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1527c478bd9Sstevel@tonic-gate 153*0f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&sti->sti_plumb_lock)); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1567c478bd9Sstevel@tonic-gate so_lock_single(so); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate ASSERT(so->so_version != SOV_STREAM); 1597c478bd9Sstevel@tonic-gate 160*0f1702c5SYu Xiangning if (sti->sti_direct) { 161ff550d0eSmasputra mblk_t **mpp; 162ff550d0eSmasputra int rval; 1637c478bd9Sstevel@tonic-gate 164ff550d0eSmasputra /* 165ff550d0eSmasputra * Tell the transport below that sockmod is being popped 166ff550d0eSmasputra */ 1677c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 168ff550d0eSmasputra error = strioctl(vp, _SIOCSOCKFALLBACK, 0, 0, K_TO_K, CRED(), 1697c478bd9Sstevel@tonic-gate &rval); 1707c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1717c478bd9Sstevel@tonic-gate if (error != 0) { 172ff550d0eSmasputra dprintso(so, 0, ("so_sock2stream(%p): " 173903a11ebSrh "_SIOCSOCKFALLBACK failed\n", (void *)so)); 1747c478bd9Sstevel@tonic-gate goto exit; 1757c478bd9Sstevel@tonic-gate } 176*0f1702c5SYu Xiangning sti->sti_direct = 0; 1777c478bd9Sstevel@tonic-gate 178*0f1702c5SYu Xiangning for (mpp = &sti->sti_conn_ind_head; (mp = *mpp) != NULL; 1797c478bd9Sstevel@tonic-gate mpp = &mp->b_next) { 1807c478bd9Sstevel@tonic-gate struct T_conn_ind *conn_ind; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* 1837c478bd9Sstevel@tonic-gate * strsock_proto() has already verified the length of 1847c478bd9Sstevel@tonic-gate * this message block. 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct T_conn_ind)); 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 1897c478bd9Sstevel@tonic-gate if (conn_ind->OPT_length == 0 && 1907c478bd9Sstevel@tonic-gate conn_ind->OPT_offset == 0) 1917c478bd9Sstevel@tonic-gate continue; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if (DB_REF(mp) > 1) { 1947c478bd9Sstevel@tonic-gate mblk_t *newmp; 1957c478bd9Sstevel@tonic-gate size_t length; 1967c478bd9Sstevel@tonic-gate cred_t *cr; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Copy the message block because it is used 2007c478bd9Sstevel@tonic-gate * elsewhere, too. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate length = MBLKL(mp); 2037c478bd9Sstevel@tonic-gate newmp = soallocproto(length, _ALLOC_INTR); 2047c478bd9Sstevel@tonic-gate if (newmp == NULL) { 2057c478bd9Sstevel@tonic-gate error = EINTR; 2067c478bd9Sstevel@tonic-gate goto exit; 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, newmp->b_wptr, length); 2097c478bd9Sstevel@tonic-gate newmp->b_wptr += length; 2107c478bd9Sstevel@tonic-gate newmp->b_next = mp->b_next; 2117c478bd9Sstevel@tonic-gate cr = DB_CRED(mp); 2127c478bd9Sstevel@tonic-gate if (cr != NULL) 2137c478bd9Sstevel@tonic-gate mblk_setcred(newmp, cr); 2147c478bd9Sstevel@tonic-gate DB_CPID(newmp) = DB_CPID(mp); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * Link the new message block into the queue 2187c478bd9Sstevel@tonic-gate * and free the old one. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate *mpp = newmp; 2217c478bd9Sstevel@tonic-gate mp->b_next = NULL; 2227c478bd9Sstevel@tonic-gate freemsg(mp); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate mp = newmp; 2257c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Remove options added by TCP for accept fast-path. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate conn_ind->OPT_length = 0; 2327c478bd9Sstevel@tonic-gate conn_ind->OPT_offset = 0; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate so->so_version = SOV_STREAM; 237*0f1702c5SYu Xiangning so->so_proto_handle = NULL; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head to avoid queuing more 2417c478bd9Sstevel@tonic-gate * packets in sockfs. 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2447c478bd9Sstevel@tonic-gate so_removehooks(so); 2457c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate /* 2487c478bd9Sstevel@tonic-gate * Clear any state related to urgent data. Leave any T_EXDATA_IND 2497c478bd9Sstevel@tonic-gate * on the queue - the behavior of urgent data after a switch is 2507c478bd9Sstevel@tonic-gate * left undefined. 2517c478bd9Sstevel@tonic-gate */ 252*0f1702c5SYu Xiangning so->so_error = sti->sti_delayed_error = 0; 2537c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 2547c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 255*0f1702c5SYu Xiangning sti->sti_oobsigcnt = sti->sti_oobcnt = 0; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_RCVATMARK|SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA| 258*0f1702c5SYu Xiangning SS_SAVEDEOR); 2597c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 2607c478bd9Sstevel@tonic-gate 261*0f1702c5SYu Xiangning freemsg(sti->sti_ack_mp); 262*0f1702c5SYu Xiangning sti->sti_ack_mp = NULL; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 265*0f1702c5SYu Xiangning * Flush the T_DISCON_IND on sti_discon_ind_mp. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * Move any queued T_CONN_IND messages to stream head queue. 2717c478bd9Sstevel@tonic-gate */ 2727c478bd9Sstevel@tonic-gate rq = RD(strvp2wq(vp)); 273*0f1702c5SYu Xiangning while ((mp = sti->sti_conn_ind_head) != NULL) { 274*0f1702c5SYu Xiangning sti->sti_conn_ind_head = mp->b_next; 2757c478bd9Sstevel@tonic-gate mp->b_next = NULL; 276*0f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 277*0f1702c5SYu Xiangning ASSERT(sti->sti_conn_ind_tail == mp); 278*0f1702c5SYu Xiangning sti->sti_conn_ind_tail = NULL; 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate dprintso(so, 0, 281*0f1702c5SYu Xiangning ("so_sock2stream(%p): moving T_CONN_IND\n", (void *)so)); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* Drop lock across put() */ 2847c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2857c478bd9Sstevel@tonic-gate put(rq, mp); 2867c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate exit: 2907c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 2917c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 2927c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2937c478bd9Sstevel@tonic-gate return (error); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Covert a stream back to a socket. This is invoked when the illusory 2987c478bd9Sstevel@tonic-gate * sockmod is pushed on a stream (where the stream was "created" by 2997c478bd9Sstevel@tonic-gate * popping the illusory sockmod). 3007c478bd9Sstevel@tonic-gate * This routine can not recreate the socket state (certain aspects of 3017c478bd9Sstevel@tonic-gate * it like urgent data state and the bound/connected addresses for AF_UNIX 3027c478bd9Sstevel@tonic-gate * sockets can not be recreated by asking the transport for information). 3037c478bd9Sstevel@tonic-gate * Thus this routine implicitly assumes that the socket is in an initial 3047c478bd9Sstevel@tonic-gate * state (as if it was just created). It flushes any messages queued on the 3057c478bd9Sstevel@tonic-gate * read queue to avoid dealing with e.g. TPI acks or T_exdata_ind messages. 3067c478bd9Sstevel@tonic-gate */ 3077c478bd9Sstevel@tonic-gate void 3087c478bd9Sstevel@tonic-gate so_stream2sock(struct sonode *so) 3097c478bd9Sstevel@tonic-gate { 3107c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 311*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 3127c478bd9Sstevel@tonic-gate 313*0f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&sti->sti_plumb_lock)); 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3167c478bd9Sstevel@tonic-gate so_lock_single(so); 3177c478bd9Sstevel@tonic-gate ASSERT(so->so_version == SOV_STREAM); 3187c478bd9Sstevel@tonic-gate so->so_version = SOV_SOCKSTREAM; 319*0f1702c5SYu Xiangning sti->sti_pushcnt = 0; 3207c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* 3237c478bd9Sstevel@tonic-gate * Set a permenent error to force any thread in sorecvmsg to 3247c478bd9Sstevel@tonic-gate * return (and drop SOREADLOCKED). Clear the error once 3257c478bd9Sstevel@tonic-gate * we have SOREADLOCKED. 3267c478bd9Sstevel@tonic-gate * This makes a read sleeping during the I_PUSH of sockmod return 3277c478bd9Sstevel@tonic-gate * EIO. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), EIO, 1, NULL); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* 3327c478bd9Sstevel@tonic-gate * Get the read lock before flushing data to avoid 3337c478bd9Sstevel@tonic-gate * problems with the T_EXDATA_IND MSG_PEEK code in sorecvmsg. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3367c478bd9Sstevel@tonic-gate (void) so_lock_read(so, 0); /* Set SOREADLOCKED */ 3377c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, NULL); 3407c478bd9Sstevel@tonic-gate so_installhooks(so); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * Flush everything on the read queue. 3447c478bd9Sstevel@tonic-gate * This ensures that no T_CONN_IND remain and that no T_EXDATA_IND 3457c478bd9Sstevel@tonic-gate * remain; those types of messages would confuse sockfs. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate strflushrq(vp, FLUSHALL); 3487c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* 351*0f1702c5SYu Xiangning * Flush the T_DISCON_IND on sti_discon_ind_mp. 3527c478bd9Sstevel@tonic-gate */ 3537c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 3547c478bd9Sstevel@tonic-gate so_unlock_read(so); /* Clear SOREADLOCKED */ 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 3577c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * Install the hooks in the stream head. 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate void 3647c478bd9Sstevel@tonic-gate so_installhooks(struct sonode *so) 3657c478bd9Sstevel@tonic-gate { 3667c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate strsetrputhooks(vp, SH_SIGALLDATA | SH_IGN_ZEROLEN | SH_CONSOL_DATA, 3697c478bd9Sstevel@tonic-gate strsock_proto, strsock_misc); 3707c478bd9Sstevel@tonic-gate strsetwputhooks(vp, SH_SIGPIPE | SH_RECHECK_ERR, 0); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* 3747c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate static void 3777c478bd9Sstevel@tonic-gate so_removehooks(struct sonode *so) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate strsetrputhooks(vp, 0, NULL, NULL); 3827c478bd9Sstevel@tonic-gate strsetwputhooks(vp, 0, STRTIMOUT); 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Leave read behavior as it would have been for a normal 3857c478bd9Sstevel@tonic-gate * stream i.e. a read of an M_PROTO will fail. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 389*0f1702c5SYu Xiangning void 390*0f1702c5SYu Xiangning so_basic_strinit(struct sonode *so) 3917c478bd9Sstevel@tonic-gate { 3927c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3937c478bd9Sstevel@tonic-gate struct stdata *stp; 3947c478bd9Sstevel@tonic-gate mblk_t *mp; 395*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* Preallocate an unbind_req message */ 3987c478bd9Sstevel@tonic-gate mp = soallocproto(sizeof (struct T_unbind_req), _ALLOC_SLEEP); 3997c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 400*0f1702c5SYu Xiangning sti->sti_unbind_mp = mp; 4017c478bd9Sstevel@tonic-gate #ifdef DEBUG 4027c478bd9Sstevel@tonic-gate so->so_options = so_default_options; 4037c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 4047c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate so_installhooks(so); 4077c478bd9Sstevel@tonic-gate 408*0f1702c5SYu Xiangning stp = vp->v_stream; 409*0f1702c5SYu Xiangning /* 410*0f1702c5SYu Xiangning * Have to keep minpsz at zero in order to allow write/send of zero 411*0f1702c5SYu Xiangning * bytes. 412*0f1702c5SYu Xiangning */ 413*0f1702c5SYu Xiangning mutex_enter(&stp->sd_lock); 414*0f1702c5SYu Xiangning if (stp->sd_qn_minpsz == 1) 415*0f1702c5SYu Xiangning stp->sd_qn_minpsz = 0; 416*0f1702c5SYu Xiangning mutex_exit(&stp->sd_lock); 417*0f1702c5SYu Xiangning 418*0f1702c5SYu Xiangning /* 419*0f1702c5SYu Xiangning * If sodirect capable allocate and initialize sodirect_t. 420*0f1702c5SYu Xiangning * Note, SS_SODIRECT is set in socktpi_open(). 421*0f1702c5SYu Xiangning */ 422*0f1702c5SYu Xiangning if ((so->so_state & SS_SODIRECT) && 423*0f1702c5SYu Xiangning !(so->so_state & SS_FALLBACK_PENDING)) { 424*0f1702c5SYu Xiangning sod_sock_init(so, stp, sodput, sodwakeup, &stp->sd_lock); 425*0f1702c5SYu Xiangning } 426*0f1702c5SYu Xiangning } 427*0f1702c5SYu Xiangning 428*0f1702c5SYu Xiangning /* 429*0f1702c5SYu Xiangning * Initialize the streams side of a socket including 430*0f1702c5SYu Xiangning * T_info_req/ack processing. If tso is not NULL its values are used thereby 431*0f1702c5SYu Xiangning * avoiding the T_INFO_REQ. 432*0f1702c5SYu Xiangning */ 433*0f1702c5SYu Xiangning int 434*0f1702c5SYu Xiangning so_strinit(struct sonode *so, struct sonode *tso) 435*0f1702c5SYu Xiangning { 436*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 437*0f1702c5SYu Xiangning sotpi_info_t *tsti; 438*0f1702c5SYu Xiangning int error; 439*0f1702c5SYu Xiangning 440*0f1702c5SYu Xiangning so_basic_strinit(so); 441*0f1702c5SYu Xiangning 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * The T_CAPABILITY_REQ should be the first message sent down because 4447c478bd9Sstevel@tonic-gate * at least TCP has a fast-path for this which avoids timeouts while 4457c478bd9Sstevel@tonic-gate * waiting for the T_CAPABILITY_ACK under high system load. 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate if (tso == NULL) { 4487c478bd9Sstevel@tonic-gate error = do_tcapability(so, TC1_ACCEPTOR_ID | TC1_INFO); 4497c478bd9Sstevel@tonic-gate if (error) 4507c478bd9Sstevel@tonic-gate return (error); 4517c478bd9Sstevel@tonic-gate } else { 452*0f1702c5SYu Xiangning tsti = SOTOTPI(tso); 453*0f1702c5SYu Xiangning 4547c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 455*0f1702c5SYu Xiangning sti->sti_tsdu_size = tsti->sti_tsdu_size; 456*0f1702c5SYu Xiangning sti->sti_etsdu_size = tsti->sti_etsdu_size; 457*0f1702c5SYu Xiangning sti->sti_addr_size = tsti->sti_addr_size; 458*0f1702c5SYu Xiangning sti->sti_opt_size = tsti->sti_opt_size; 459*0f1702c5SYu Xiangning sti->sti_tidu_size = tsti->sti_tidu_size; 460*0f1702c5SYu Xiangning sti->sti_serv_type = tsti->sti_serv_type; 4617c478bd9Sstevel@tonic-gate so->so_mode = tso->so_mode & ~SM_ACCEPTOR_ID; 4627c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* the following do_tcapability may update so->so_mode */ 465*0f1702c5SYu Xiangning if ((tsti->sti_serv_type != T_CLTS) && 466*0f1702c5SYu Xiangning (sti->sti_direct == 0)) { 4677c478bd9Sstevel@tonic-gate error = do_tcapability(so, TC1_ACCEPTOR_ID); 4687c478bd9Sstevel@tonic-gate if (error) 4697c478bd9Sstevel@tonic-gate return (error); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate /* 4737c478bd9Sstevel@tonic-gate * If the addr_size is 0 we treat it as already bound 4747c478bd9Sstevel@tonic-gate * and connected. This is used by the routing socket. 4757c478bd9Sstevel@tonic-gate * We set the addr_size to something to allocate a the address 4767c478bd9Sstevel@tonic-gate * structures. 4777c478bd9Sstevel@tonic-gate */ 478*0f1702c5SYu Xiangning if (sti->sti_addr_size == 0) { 4797c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND | SS_ISCONNECTED; 4807c478bd9Sstevel@tonic-gate /* Address size can vary with address families. */ 4817c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET6) 482*0f1702c5SYu Xiangning sti->sti_addr_size = 4837c478bd9Sstevel@tonic-gate (t_scalar_t)sizeof (struct sockaddr_in6); 4847c478bd9Sstevel@tonic-gate else 485*0f1702c5SYu Xiangning sti->sti_addr_size = 4867c478bd9Sstevel@tonic-gate (t_scalar_t)sizeof (struct sockaddr_in); 487*0f1702c5SYu Xiangning ASSERT(sti->sti_unbind_mp); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 490*0f1702c5SYu Xiangning so_alloc_addr(so, sti->sti_addr_size); 49117169044Sbrutus 4927c478bd9Sstevel@tonic-gate return (0); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate static void 4967c478bd9Sstevel@tonic-gate copy_tinfo(struct sonode *so, struct T_info_ack *tia) 4977c478bd9Sstevel@tonic-gate { 498*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 499*0f1702c5SYu Xiangning 500*0f1702c5SYu Xiangning sti->sti_tsdu_size = tia->TSDU_size; 501*0f1702c5SYu Xiangning sti->sti_etsdu_size = tia->ETSDU_size; 502*0f1702c5SYu Xiangning sti->sti_addr_size = tia->ADDR_size; 503*0f1702c5SYu Xiangning sti->sti_opt_size = tia->OPT_size; 504*0f1702c5SYu Xiangning sti->sti_tidu_size = tia->TIDU_size; 505*0f1702c5SYu Xiangning sti->sti_serv_type = tia->SERV_type; 5067c478bd9Sstevel@tonic-gate switch (tia->CURRENT_state) { 5077c478bd9Sstevel@tonic-gate case TS_UNBND: 5087c478bd9Sstevel@tonic-gate break; 5097c478bd9Sstevel@tonic-gate case TS_IDLE: 5107c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND; 511*0f1702c5SYu Xiangning sti->sti_laddr_len = 0; 512*0f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 5137c478bd9Sstevel@tonic-gate break; 5147c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 5157c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND|SS_ISCONNECTED; 516*0f1702c5SYu Xiangning sti->sti_laddr_len = 0; 517*0f1702c5SYu Xiangning sti->sti_faddr_len = 0; 518*0f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 519*0f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 5207c478bd9Sstevel@tonic-gate break; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * Heuristics for determining the socket mode flags 5257c478bd9Sstevel@tonic-gate * (SM_ATOMIC, SM_CONNREQUIRED, SM_ADDR, SM_FDPASSING, 5267c478bd9Sstevel@tonic-gate * and SM_EXDATA, SM_OPTDATA, and SM_BYTESTREAM) 5277c478bd9Sstevel@tonic-gate * from the info ack. 5287c478bd9Sstevel@tonic-gate */ 529*0f1702c5SYu Xiangning if (sti->sti_serv_type == T_CLTS) { 5307c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC | SM_ADDR; 5317c478bd9Sstevel@tonic-gate } else { 5327c478bd9Sstevel@tonic-gate so->so_mode |= SM_CONNREQUIRED; 533*0f1702c5SYu Xiangning if (sti->sti_etsdu_size != 0 && sti->sti_etsdu_size != -2) 5347c478bd9Sstevel@tonic-gate so->so_mode |= SM_EXDATA; 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_SEQPACKET || so->so_type == SOCK_RAW) { 5377c478bd9Sstevel@tonic-gate /* Semantics are to discard tail end of messages */ 5387c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC; 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX) { 5417c478bd9Sstevel@tonic-gate so->so_mode |= SM_FDPASSING | SM_OPTDATA; 542*0f1702c5SYu Xiangning if (sti->sti_addr_size == -1) { 5437c478bd9Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 544*0f1702c5SYu Xiangning sti->sti_addr_size = (t_scalar_t)(MAXPATHLEN + 545d3e55dcdSgww sizeof (short) + 1); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_STREAM) { 5487c478bd9Sstevel@tonic-gate /* 5497c478bd9Sstevel@tonic-gate * Make it into a byte-stream transport. 5507c478bd9Sstevel@tonic-gate * SOCK_SEQPACKET sockets are unchanged. 5517c478bd9Sstevel@tonic-gate */ 552*0f1702c5SYu Xiangning sti->sti_tsdu_size = 0; 5537c478bd9Sstevel@tonic-gate } 554*0f1702c5SYu Xiangning } else if (sti->sti_addr_size == -1) { 5557c478bd9Sstevel@tonic-gate /* 5567c478bd9Sstevel@tonic-gate * Logic extracted from sockmod - have to pick some max address 5577c478bd9Sstevel@tonic-gate * length in order to preallocate the addresses. 5587c478bd9Sstevel@tonic-gate */ 559*0f1702c5SYu Xiangning sti->sti_addr_size = SOA_DEFSIZE; 5607c478bd9Sstevel@tonic-gate } 561*0f1702c5SYu Xiangning if (sti->sti_tsdu_size == 0) 5627c478bd9Sstevel@tonic-gate so->so_mode |= SM_BYTESTREAM; 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate static int 5667c478bd9Sstevel@tonic-gate check_tinfo(struct sonode *so) 5677c478bd9Sstevel@tonic-gate { 568*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 569*0f1702c5SYu Xiangning 5707c478bd9Sstevel@tonic-gate /* Consistency checks */ 571*0f1702c5SYu Xiangning if (so->so_type == SOCK_DGRAM && sti->sti_serv_type != T_CLTS) { 5727c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5737c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5747c478bd9Sstevel@tonic-gate return (EPROTO); 5757c478bd9Sstevel@tonic-gate } 576*0f1702c5SYu Xiangning if (so->so_type == SOCK_STREAM && sti->sti_serv_type == T_CLTS) { 5777c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5787c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5797c478bd9Sstevel@tonic-gate return (EPROTO); 5807c478bd9Sstevel@tonic-gate } 581*0f1702c5SYu Xiangning if (so->so_type == SOCK_SEQPACKET && sti->sti_serv_type == T_CLTS) { 5827c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5837c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5847c478bd9Sstevel@tonic-gate return (EPROTO); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET && 587*0f1702c5SYu Xiangning sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in)) { 5887c478bd9Sstevel@tonic-gate eprintso(so, 5897c478bd9Sstevel@tonic-gate ("AF_INET must have sockaddr_in address length. Got %d\n", 590*0f1702c5SYu Xiangning sti->sti_addr_size)); 5917c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 5927c478bd9Sstevel@tonic-gate return (EMSGSIZE); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET6 && 595*0f1702c5SYu Xiangning sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in6)) { 5967c478bd9Sstevel@tonic-gate eprintso(so, 5977c478bd9Sstevel@tonic-gate ("AF_INET6 must have sockaddr_in6 address length. Got %d\n", 598*0f1702c5SYu Xiangning sti->sti_addr_size)); 5997c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 6007c478bd9Sstevel@tonic-gate return (EMSGSIZE); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate dprintso(so, 1, ( 6047c478bd9Sstevel@tonic-gate "tinfo: serv %d tsdu %d, etsdu %d, addr %d, opt %d, tidu %d\n", 605*0f1702c5SYu Xiangning sti->sti_serv_type, sti->sti_tsdu_size, sti->sti_etsdu_size, 606*0f1702c5SYu Xiangning sti->sti_addr_size, sti->sti_opt_size, 607*0f1702c5SYu Xiangning sti->sti_tidu_size)); 6087c478bd9Sstevel@tonic-gate dprintso(so, 1, ("tinfo: so_state %s\n", 609d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 6107c478bd9Sstevel@tonic-gate return (0); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* 6147c478bd9Sstevel@tonic-gate * Send down T_info_req and wait for the ack. 6157c478bd9Sstevel@tonic-gate * Record interesting T_info_ack values in the sonode. 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate static int 6187c478bd9Sstevel@tonic-gate do_tinfo(struct sonode *so) 6197c478bd9Sstevel@tonic-gate { 6207c478bd9Sstevel@tonic-gate struct T_info_req tir; 6217c478bd9Sstevel@tonic-gate mblk_t *mp; 6227c478bd9Sstevel@tonic-gate int error; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 627*0f1702c5SYu Xiangning SOTOTPI(so)->sti_addr_size = 0; 6287c478bd9Sstevel@tonic-gate return (0); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 631903a11ebSrh dprintso(so, 1, ("do_tinfo(%p)\n", (void *)so)); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* Send T_INFO_REQ */ 6347c478bd9Sstevel@tonic-gate tir.PRIM_type = T_INFO_REQ; 6357c478bd9Sstevel@tonic-gate mp = soallocproto1(&tir, sizeof (tir), 6367c478bd9Sstevel@tonic-gate sizeof (struct T_info_req) + sizeof (struct T_info_ack), 6377c478bd9Sstevel@tonic-gate _ALLOC_INTR); 6387c478bd9Sstevel@tonic-gate if (mp == NULL) { 6397c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 6407c478bd9Sstevel@tonic-gate return (ENOBUFS); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate /* T_INFO_REQ has to be M_PCPROTO */ 6437c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 646d3e55dcdSgww MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 6477c478bd9Sstevel@tonic-gate if (error) { 6487c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6497c478bd9Sstevel@tonic-gate return (error); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 6527c478bd9Sstevel@tonic-gate /* Wait for T_INFO_ACK */ 6537c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_INFO_REQ, T_INFO_ACK, 6547c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_info_ack), &mp, 0))) { 6557c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6567c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6577c478bd9Sstevel@tonic-gate return (error); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate ASSERT(mp); 6617c478bd9Sstevel@tonic-gate copy_tinfo(so, (struct T_info_ack *)mp->b_rptr); 6627c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6637c478bd9Sstevel@tonic-gate freemsg(mp); 6647c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate * Send down T_capability_req and wait for the ack. 6697c478bd9Sstevel@tonic-gate * Record interesting T_capability_ack values in the sonode. 6707c478bd9Sstevel@tonic-gate */ 6717c478bd9Sstevel@tonic-gate static int 6727c478bd9Sstevel@tonic-gate do_tcapability(struct sonode *so, t_uscalar_t cap_bits1) 6737c478bd9Sstevel@tonic-gate { 6747c478bd9Sstevel@tonic-gate struct T_capability_req tcr; 6757c478bd9Sstevel@tonic-gate struct T_capability_ack *tca; 6767c478bd9Sstevel@tonic-gate mblk_t *mp; 6777c478bd9Sstevel@tonic-gate int error; 678*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate ASSERT(cap_bits1 != 0); 6817c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & ~(TC1_ACCEPTOR_ID | TC1_INFO)) == 0); 6827c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6837c478bd9Sstevel@tonic-gate 684*0f1702c5SYu Xiangning if (sti->sti_provinfo->tpi_capability == PI_NO) 6857c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 688*0f1702c5SYu Xiangning sti->sti_addr_size = 0; 6897c478bd9Sstevel@tonic-gate if ((cap_bits1 &= ~TC1_INFO) == 0) 6907c478bd9Sstevel@tonic-gate return (0); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 693903a11ebSrh dprintso(so, 1, ("do_tcapability(%p)\n", (void *)so)); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate /* Send T_CAPABILITY_REQ */ 6967c478bd9Sstevel@tonic-gate tcr.PRIM_type = T_CAPABILITY_REQ; 6977c478bd9Sstevel@tonic-gate tcr.CAP_bits1 = cap_bits1; 6987c478bd9Sstevel@tonic-gate mp = soallocproto1(&tcr, sizeof (tcr), 6997c478bd9Sstevel@tonic-gate sizeof (struct T_capability_req) + sizeof (struct T_capability_ack), 7007c478bd9Sstevel@tonic-gate _ALLOC_INTR); 7017c478bd9Sstevel@tonic-gate if (mp == NULL) { 7027c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 7037c478bd9Sstevel@tonic-gate return (ENOBUFS); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate /* T_CAPABILITY_REQ should be M_PCPROTO here */ 7067c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 7097c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 7107c478bd9Sstevel@tonic-gate if (error) { 7117c478bd9Sstevel@tonic-gate eprintsoline(so, error); 7127c478bd9Sstevel@tonic-gate return (error); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 7157c478bd9Sstevel@tonic-gate /* Wait for T_CAPABILITY_ACK */ 7167c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_CAPABILITY_REQ, T_CAPABILITY_ACK, 7177c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (*tca), &mp, sock_capability_timeout * hz))) { 7187c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 719*0f1702c5SYu Xiangning PI_PROVLOCK(sti->sti_provinfo); 720*0f1702c5SYu Xiangning if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW) 721*0f1702c5SYu Xiangning sti->sti_provinfo->tpi_capability = PI_NO; 722*0f1702c5SYu Xiangning PI_PROVUNLOCK(sti->sti_provinfo); 7237c478bd9Sstevel@tonic-gate ASSERT((so->so_mode & SM_ACCEPTOR_ID) == 0); 7247c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * If the T_CAPABILITY_REQ timed out and then a 7277c478bd9Sstevel@tonic-gate * T_INFO_REQ gets a protocol error, most likely 7287c478bd9Sstevel@tonic-gate * the capability was slow (vs. unsupported). Return 7297c478bd9Sstevel@tonic-gate * ENOSR for this case as a best guess. 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate if (error == ETIME) { 7327c478bd9Sstevel@tonic-gate return ((error = do_tinfo(so)) == EPROTO ? 7337c478bd9Sstevel@tonic-gate ENOSR : error); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate return (0); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate ASSERT(mp); 7417c478bd9Sstevel@tonic-gate tca = (struct T_capability_ack *)mp->b_rptr; 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & TC1_INFO) == (tca->CAP_bits1 & TC1_INFO)); 744*0f1702c5SYu Xiangning so_proc_tcapability_ack(so, tca); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate cap_bits1 = tca->CAP_bits1; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 7497c478bd9Sstevel@tonic-gate freemsg(mp); 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) 7527c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate return (0); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* 758*0f1702c5SYu Xiangning * Process a T_CAPABILITY_ACK 759*0f1702c5SYu Xiangning */ 760*0f1702c5SYu Xiangning void 761*0f1702c5SYu Xiangning so_proc_tcapability_ack(struct sonode *so, struct T_capability_ack *tca) 762*0f1702c5SYu Xiangning { 763*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 764*0f1702c5SYu Xiangning 765*0f1702c5SYu Xiangning if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW) { 766*0f1702c5SYu Xiangning PI_PROVLOCK(sti->sti_provinfo); 767*0f1702c5SYu Xiangning sti->sti_provinfo->tpi_capability = PI_YES; 768*0f1702c5SYu Xiangning PI_PROVUNLOCK(sti->sti_provinfo); 769*0f1702c5SYu Xiangning } 770*0f1702c5SYu Xiangning 771*0f1702c5SYu Xiangning if (tca->CAP_bits1 & TC1_ACCEPTOR_ID) { 772*0f1702c5SYu Xiangning sti->sti_acceptor_id = tca->ACCEPTOR_id; 773*0f1702c5SYu Xiangning so->so_mode |= SM_ACCEPTOR_ID; 774*0f1702c5SYu Xiangning } 775*0f1702c5SYu Xiangning 776*0f1702c5SYu Xiangning if (tca->CAP_bits1 & TC1_INFO) 777*0f1702c5SYu Xiangning copy_tinfo(so, &tca->INFO_ack); 778*0f1702c5SYu Xiangning } 779*0f1702c5SYu Xiangning 780*0f1702c5SYu Xiangning /* 781*0f1702c5SYu Xiangning * Retrieve socket error, clear error if not peek. 7827c478bd9Sstevel@tonic-gate */ 7837c478bd9Sstevel@tonic-gate int 784*0f1702c5SYu Xiangning sogeterr(struct sonode *so, boolean_t clear_err) 7857c478bd9Sstevel@tonic-gate { 7867c478bd9Sstevel@tonic-gate int error; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate error = so->so_error; 791*0f1702c5SYu Xiangning if (clear_err) 792*0f1702c5SYu Xiangning so->so_error = 0; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate return (error); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* 7987c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve read 7997c478bd9Sstevel@tonic-gate * side errors. 8007c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 8017c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate int 8047c478bd9Sstevel@tonic-gate sogetrderr(vnode_t *vp, int ispeek, int *clearerr) 8057c478bd9Sstevel@tonic-gate { 8067c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 8077c478bd9Sstevel@tonic-gate int error; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 8107c478bd9Sstevel@tonic-gate if (ispeek) { 8117c478bd9Sstevel@tonic-gate error = so->so_error; 8127c478bd9Sstevel@tonic-gate *clearerr = 0; 8137c478bd9Sstevel@tonic-gate } else { 8147c478bd9Sstevel@tonic-gate error = so->so_error; 8157c478bd9Sstevel@tonic-gate so->so_error = 0; 8167c478bd9Sstevel@tonic-gate *clearerr = 1; 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 8197c478bd9Sstevel@tonic-gate return (error); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve write 8247c478bd9Sstevel@tonic-gate * side errors. 8257c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 8267c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate int 8297c478bd9Sstevel@tonic-gate sogetwrerr(vnode_t *vp, int ispeek, int *clearerr) 8307c478bd9Sstevel@tonic-gate { 8317c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 8327c478bd9Sstevel@tonic-gate int error; 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 8357c478bd9Sstevel@tonic-gate if (so->so_state & SS_CANTSENDMORE) { 8367c478bd9Sstevel@tonic-gate error = EPIPE; 8377c478bd9Sstevel@tonic-gate *clearerr = 0; 8387c478bd9Sstevel@tonic-gate } else { 8397c478bd9Sstevel@tonic-gate error = so->so_error; 8407c478bd9Sstevel@tonic-gate if (ispeek) { 8417c478bd9Sstevel@tonic-gate *clearerr = 0; 8427c478bd9Sstevel@tonic-gate } else { 8437c478bd9Sstevel@tonic-gate so->so_error = 0; 8447c478bd9Sstevel@tonic-gate *clearerr = 1; 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 8487c478bd9Sstevel@tonic-gate return (error); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Set a nonpersistent read and write error on the socket. 8537c478bd9Sstevel@tonic-gate * Used when there is a T_uderror_ind for a connected socket. 8547c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror and strsetwerror 8557c478bd9Sstevel@tonic-gate * after dropping the lock. 8567c478bd9Sstevel@tonic-gate */ 8577c478bd9Sstevel@tonic-gate void 8587c478bd9Sstevel@tonic-gate soseterror(struct sonode *so, int error) 8597c478bd9Sstevel@tonic-gate { 8607c478bd9Sstevel@tonic-gate ASSERT(error != 0); 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8637c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate void 8677c478bd9Sstevel@tonic-gate soisconnecting(struct sonode *so) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8707c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); 8717c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTING; 8727c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate void 8767c478bd9Sstevel@tonic-gate soisconnected(struct sonode *so) 8777c478bd9Sstevel@tonic-gate { 8787c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8797c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING); 8807c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTED; 8817c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror, strsetwerror and strseteof. 8867c478bd9Sstevel@tonic-gate */ 8877c478bd9Sstevel@tonic-gate void 8887c478bd9Sstevel@tonic-gate soisdisconnected(struct sonode *so, int error) 8897c478bd9Sstevel@tonic-gate { 8907c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 891*0f1702c5SYu Xiangning so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 8927c478bd9Sstevel@tonic-gate so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); 8937c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8947c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) { 8957c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 8967c478bd9Sstevel@tonic-gate so->so_peercred = NULL; 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate /* 9027c478bd9Sstevel@tonic-gate * For connected AF_UNIX SOCK_DGRAM sockets when the peer closes. 9037c478bd9Sstevel@tonic-gate * Does not affect write side. 9047c478bd9Sstevel@tonic-gate * The caller also has to call strsetrerror. 9057c478bd9Sstevel@tonic-gate */ 9067c478bd9Sstevel@tonic-gate static void 9077c478bd9Sstevel@tonic-gate sobreakconn(struct sonode *so, int error) 9087c478bd9Sstevel@tonic-gate { 9097c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9107c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 9117c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 9127c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* 9167c478bd9Sstevel@tonic-gate * Can no longer send. 9177c478bd9Sstevel@tonic-gate * Caller must also call strsetwerror. 9187c478bd9Sstevel@tonic-gate * 9197c478bd9Sstevel@tonic-gate * We mark the peer address as no longer valid for getpeername, but 9207c478bd9Sstevel@tonic-gate * leave it around for so_unix_close to notify the peer (that 9217c478bd9Sstevel@tonic-gate * transport has no addressing held at that layer). 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate void 9247c478bd9Sstevel@tonic-gate socantsendmore(struct sonode *so) 9257c478bd9Sstevel@tonic-gate { 9267c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 927*0f1702c5SYu Xiangning so->so_state |= SS_CANTSENDMORE; 9287c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate /* 9327c478bd9Sstevel@tonic-gate * The caller must call strseteof(,1) as well as this routine 9337c478bd9Sstevel@tonic-gate * to change the socket state. 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate void 9367c478bd9Sstevel@tonic-gate socantrcvmore(struct sonode *so) 9377c478bd9Sstevel@tonic-gate { 9387c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9397c478bd9Sstevel@tonic-gate so->so_state |= SS_CANTRCVMORE; 9407c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate /* 9447c478bd9Sstevel@tonic-gate * The caller has sent down a "request_prim" primitive and wants to wait for 9457c478bd9Sstevel@tonic-gate * an ack ("ack_prim") or an T_ERROR_ACK for it. 9467c478bd9Sstevel@tonic-gate * The specified "ack_prim" can be a T_OK_ACK. 9477c478bd9Sstevel@tonic-gate * 9487c478bd9Sstevel@tonic-gate * Assumes that all the TPI acks are M_PCPROTO messages. 9497c478bd9Sstevel@tonic-gate * 9507c478bd9Sstevel@tonic-gate * Note that the socket is single-threaded (using so_lock_single) 9517c478bd9Sstevel@tonic-gate * for all operations that generate TPI ack messages. Since 9527c478bd9Sstevel@tonic-gate * only TPI ack messages are M_PCPROTO we should never receive 9537c478bd9Sstevel@tonic-gate * anything except either the ack we are expecting or a T_ERROR_ACK 9547c478bd9Sstevel@tonic-gate * for the same primitive. 9557c478bd9Sstevel@tonic-gate */ 9567c478bd9Sstevel@tonic-gate int 9577c478bd9Sstevel@tonic-gate sowaitprim(struct sonode *so, t_scalar_t request_prim, t_scalar_t ack_prim, 9587c478bd9Sstevel@tonic-gate t_uscalar_t min_size, mblk_t **mpp, clock_t wait) 9597c478bd9Sstevel@tonic-gate { 9607c478bd9Sstevel@tonic-gate mblk_t *mp; 9617c478bd9Sstevel@tonic-gate union T_primitives *tpr; 9627c478bd9Sstevel@tonic-gate int error; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitprim(%p, %d, %d, %d, %p, %lu)\n", 965903a11ebSrh (void *)so, request_prim, ack_prim, min_size, (void *)mpp, wait)); 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate error = sowaitack(so, &mp, wait); 9707c478bd9Sstevel@tonic-gate if (error) 9717c478bd9Sstevel@tonic-gate return (error); 9727c478bd9Sstevel@tonic-gate 973903a11ebSrh dprintso(so, 1, ("got msg %p\n", (void *)mp)); 9747c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO || 9757c478bd9Sstevel@tonic-gate MBLKL(mp) < sizeof (tpr->type)) { 9767c478bd9Sstevel@tonic-gate freemsg(mp); 9777c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 9787c478bd9Sstevel@tonic-gate return (EPROTO); 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * Did we get the primitive that we were asking for? 9837c478bd9Sstevel@tonic-gate * For T_OK_ACK we also check that it matches the request primitive. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate if (tpr->type == ack_prim && 9867c478bd9Sstevel@tonic-gate (ack_prim != T_OK_ACK || 9877c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == request_prim)) { 9887c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= (ssize_t)min_size) { 9897c478bd9Sstevel@tonic-gate /* Found what we are looking for */ 9907c478bd9Sstevel@tonic-gate *mpp = mp; 9917c478bd9Sstevel@tonic-gate return (0); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate /* Too short */ 9947c478bd9Sstevel@tonic-gate freemsg(mp); 9957c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 9967c478bd9Sstevel@tonic-gate return (EPROTO); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK && 10007c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == request_prim) { 10017c478bd9Sstevel@tonic-gate /* Error to the primitive we were looking for */ 10027c478bd9Sstevel@tonic-gate if (tpr->error_ack.TLI_error == TSYSERR) { 10037c478bd9Sstevel@tonic-gate error = tpr->error_ack.UNIX_error; 10047c478bd9Sstevel@tonic-gate } else { 1005*0f1702c5SYu Xiangning error = proto_tlitosyserr(tpr->error_ack.TLI_error); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d ->%d\n", 1008*0f1702c5SYu Xiangning tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error, 1009*0f1702c5SYu Xiangning tpr->error_ack.UNIX_error, error)); 10107c478bd9Sstevel@tonic-gate freemsg(mp); 10117c478bd9Sstevel@tonic-gate return (error); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * Wrong primitive or T_ERROR_ACK for the wrong primitive 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate #ifdef DEBUG 10177c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK) { 10187c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d\n", 1019*0f1702c5SYu Xiangning tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error, 1020d3e55dcdSgww tpr->error_ack.UNIX_error)); 10217c478bd9Sstevel@tonic-gate } else if (tpr->type == T_OK_ACK) { 10227c478bd9Sstevel@tonic-gate dprintso(so, 0, ("ok_ack for %d, expected %d for %d\n", 1023*0f1702c5SYu Xiangning tpr->ok_ack.CORRECT_prim, ack_prim, request_prim)); 10247c478bd9Sstevel@tonic-gate } else { 10257c478bd9Sstevel@tonic-gate dprintso(so, 0, 1026d3e55dcdSgww ("unexpected primitive %d, expected %d for %d\n", 1027d3e55dcdSgww tpr->type, ack_prim, request_prim)); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate freemsg(mp); 10327c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 10337c478bd9Sstevel@tonic-gate return (EPROTO); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * Wait for a T_OK_ACK for the specified primitive. 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate int 10407c478bd9Sstevel@tonic-gate sowaitokack(struct sonode *so, t_scalar_t request_prim) 10417c478bd9Sstevel@tonic-gate { 10427c478bd9Sstevel@tonic-gate mblk_t *mp; 10437c478bd9Sstevel@tonic-gate int error; 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate error = sowaitprim(so, request_prim, T_OK_ACK, 10467c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_ok_ack), &mp, 0); 10477c478bd9Sstevel@tonic-gate if (error) 10487c478bd9Sstevel@tonic-gate return (error); 10497c478bd9Sstevel@tonic-gate freemsg(mp); 10507c478bd9Sstevel@tonic-gate return (0); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate /* 1054*0f1702c5SYu Xiangning * Queue a received TPI ack message on sti_ack_mp. 10557c478bd9Sstevel@tonic-gate */ 10567c478bd9Sstevel@tonic-gate void 10577c478bd9Sstevel@tonic-gate soqueueack(struct sonode *so, mblk_t *mp) 10587c478bd9Sstevel@tonic-gate { 1059*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1060*0f1702c5SYu Xiangning 10617c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO) { 10622caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 10637c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PROTO TPI ack. Prim %d\n", 10647c478bd9Sstevel@tonic-gate *(t_scalar_t *)mp->b_rptr); 10657c478bd9Sstevel@tonic-gate freemsg(mp); 10667c478bd9Sstevel@tonic-gate return; 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1070*0f1702c5SYu Xiangning if (sti->sti_ack_mp != NULL) { 1071*0f1702c5SYu Xiangning dprintso(so, 1, ("sti_ack_mp already set\n")); 1072*0f1702c5SYu Xiangning freemsg(sti->sti_ack_mp); 1073*0f1702c5SYu Xiangning sti->sti_ack_mp = NULL; 10747c478bd9Sstevel@tonic-gate } 1075*0f1702c5SYu Xiangning sti->sti_ack_mp = mp; 1076*0f1702c5SYu Xiangning cv_broadcast(&sti->sti_ack_cv); 10777c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * Wait for a TPI ack ignoring signals and errors. 10827c478bd9Sstevel@tonic-gate */ 10837c478bd9Sstevel@tonic-gate int 10847c478bd9Sstevel@tonic-gate sowaitack(struct sonode *so, mblk_t **mpp, clock_t wait) 10857c478bd9Sstevel@tonic-gate { 1086*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1087*0f1702c5SYu Xiangning 10887c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 10897c478bd9Sstevel@tonic-gate 1090*0f1702c5SYu Xiangning while (sti->sti_ack_mp == NULL) { 10917c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 10927c478bd9Sstevel@tonic-gate if (wait == 0 && sock_test_timelimit != 0) 10937c478bd9Sstevel@tonic-gate wait = sock_test_timelimit; 10947c478bd9Sstevel@tonic-gate #endif 10957c478bd9Sstevel@tonic-gate if (wait != 0) { 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * Only wait for the time limit. 10987c478bd9Sstevel@tonic-gate */ 10997c478bd9Sstevel@tonic-gate clock_t now; 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate time_to_wait(&now, wait); 1102*0f1702c5SYu Xiangning if (cv_timedwait(&sti->sti_ack_cv, &so->so_lock, 11037c478bd9Sstevel@tonic-gate now) == -1) { 11047c478bd9Sstevel@tonic-gate eprintsoline(so, ETIME); 11057c478bd9Sstevel@tonic-gate return (ETIME); 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate else 1109*0f1702c5SYu Xiangning cv_wait(&sti->sti_ack_cv, &so->so_lock); 11107c478bd9Sstevel@tonic-gate } 1111*0f1702c5SYu Xiangning *mpp = sti->sti_ack_mp; 11127c478bd9Sstevel@tonic-gate #ifdef DEBUG 11137c478bd9Sstevel@tonic-gate { 11147c478bd9Sstevel@tonic-gate union T_primitives *tpr; 11157c478bd9Sstevel@tonic-gate mblk_t *mp = *mpp; 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 11187c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PCPROTO); 11197c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_OK_ACK || 1120d3e55dcdSgww tpr->type == T_ERROR_ACK || 1121d3e55dcdSgww tpr->type == T_BIND_ACK || 1122d3e55dcdSgww tpr->type == T_CAPABILITY_ACK || 1123d3e55dcdSgww tpr->type == T_INFO_ACK || 1124d3e55dcdSgww tpr->type == T_OPTMGMT_ACK); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1127*0f1702c5SYu Xiangning sti->sti_ack_mp = NULL; 11287c478bd9Sstevel@tonic-gate return (0); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate /* 1132*0f1702c5SYu Xiangning * Queue a received T_CONN_IND message on sti_conn_ind_head/tail. 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate void 11357c478bd9Sstevel@tonic-gate soqueueconnind(struct sonode *so, mblk_t *mp) 11367c478bd9Sstevel@tonic-gate { 1137*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1138*0f1702c5SYu Xiangning 11397c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PROTO) { 11402caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 11417c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PCPROTO T_CONN_IND\n"); 11427c478bd9Sstevel@tonic-gate freemsg(mp); 11437c478bd9Sstevel@tonic-gate return; 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 11477c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 1148*0f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 1149*0f1702c5SYu Xiangning sti->sti_conn_ind_head = mp; 11507c478bd9Sstevel@tonic-gate } else { 1151*0f1702c5SYu Xiangning ASSERT(sti->sti_conn_ind_tail->b_next == NULL); 1152*0f1702c5SYu Xiangning sti->sti_conn_ind_tail->b_next = mp; 11537c478bd9Sstevel@tonic-gate } 1154*0f1702c5SYu Xiangning sti->sti_conn_ind_tail = mp; 11557c478bd9Sstevel@tonic-gate /* Wakeup a single consumer of the T_CONN_IND */ 1156*0f1702c5SYu Xiangning cv_signal(&so->so_acceptq_cv); 11577c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * Wait for a T_CONN_IND. 11627c478bd9Sstevel@tonic-gate * Don't wait if nonblocking. 11637c478bd9Sstevel@tonic-gate * Accept signals and socket errors. 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate int 11667c478bd9Sstevel@tonic-gate sowaitconnind(struct sonode *so, int fmode, mblk_t **mpp) 11677c478bd9Sstevel@tonic-gate { 11687c478bd9Sstevel@tonic-gate mblk_t *mp; 1169*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 11707c478bd9Sstevel@tonic-gate int error = 0; 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 11737c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 11747c478bd9Sstevel@tonic-gate check_error: 11757c478bd9Sstevel@tonic-gate if (so->so_error) { 1176*0f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 11777c478bd9Sstevel@tonic-gate if (error) { 11787c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11797c478bd9Sstevel@tonic-gate return (error); 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 1183*0f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 11847c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) { 11857c478bd9Sstevel@tonic-gate error = EWOULDBLOCK; 11867c478bd9Sstevel@tonic-gate goto done; 11877c478bd9Sstevel@tonic-gate } 1188*0f1702c5SYu Xiangning 1189*0f1702c5SYu Xiangning if (so->so_state & SS_CLOSING) { 1190*0f1702c5SYu Xiangning error = EINTR; 1191*0f1702c5SYu Xiangning goto done; 1192*0f1702c5SYu Xiangning } 1193*0f1702c5SYu Xiangning 1194*0f1702c5SYu Xiangning if (!cv_wait_sig_swap(&so->so_acceptq_cv, &so->so_lock)) { 11957c478bd9Sstevel@tonic-gate error = EINTR; 11967c478bd9Sstevel@tonic-gate goto done; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate goto check_error; 11997c478bd9Sstevel@tonic-gate } 1200*0f1702c5SYu Xiangning mp = sti->sti_conn_ind_head; 1201*0f1702c5SYu Xiangning sti->sti_conn_ind_head = mp->b_next; 12027c478bd9Sstevel@tonic-gate mp->b_next = NULL; 1203*0f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 1204*0f1702c5SYu Xiangning ASSERT(sti->sti_conn_ind_tail == mp); 1205*0f1702c5SYu Xiangning sti->sti_conn_ind_tail = NULL; 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate *mpp = mp; 12087c478bd9Sstevel@tonic-gate done: 12097c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 12107c478bd9Sstevel@tonic-gate return (error); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate /* 12147c478bd9Sstevel@tonic-gate * Flush a T_CONN_IND matching the sequence number from the list. 12157c478bd9Sstevel@tonic-gate * Return zero if found; non-zero otherwise. 12167c478bd9Sstevel@tonic-gate * This is called very infrequently thus it is ok to do a linear search. 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate int 12197c478bd9Sstevel@tonic-gate soflushconnind(struct sonode *so, t_scalar_t seqno) 12207c478bd9Sstevel@tonic-gate { 12217c478bd9Sstevel@tonic-gate mblk_t *prevmp, *mp; 12227c478bd9Sstevel@tonic-gate struct T_conn_ind *tci; 1223*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1226*0f1702c5SYu Xiangning for (prevmp = NULL, mp = sti->sti_conn_ind_head; mp != NULL; 12277c478bd9Sstevel@tonic-gate prevmp = mp, mp = mp->b_next) { 12287c478bd9Sstevel@tonic-gate tci = (struct T_conn_ind *)mp->b_rptr; 12297c478bd9Sstevel@tonic-gate if (tci->SEQ_number == seqno) { 12307c478bd9Sstevel@tonic-gate dprintso(so, 1, 1231d3e55dcdSgww ("t_discon_ind: found T_CONN_IND %d\n", seqno)); 12327c478bd9Sstevel@tonic-gate /* Deleting last? */ 1233*0f1702c5SYu Xiangning if (sti->sti_conn_ind_tail == mp) { 1234*0f1702c5SYu Xiangning sti->sti_conn_ind_tail = prevmp; 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate if (prevmp == NULL) { 12377c478bd9Sstevel@tonic-gate /* Deleting first */ 1238*0f1702c5SYu Xiangning sti->sti_conn_ind_head = mp->b_next; 12397c478bd9Sstevel@tonic-gate } else { 12407c478bd9Sstevel@tonic-gate prevmp->b_next = mp->b_next; 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate mp->b_next = NULL; 1243*0f1702c5SYu Xiangning 1244*0f1702c5SYu Xiangning ASSERT((sti->sti_conn_ind_head == NULL && 1245*0f1702c5SYu Xiangning sti->sti_conn_ind_tail == NULL) || 1246*0f1702c5SYu Xiangning (sti->sti_conn_ind_head != NULL && 1247*0f1702c5SYu Xiangning sti->sti_conn_ind_tail != NULL)); 1248*0f1702c5SYu Xiangning 12497c478bd9Sstevel@tonic-gate so->so_error = ECONNABORTED; 12507c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1251c28749e9Skais 1252c28749e9Skais /* 1253c28749e9Skais * T_KSSL_PROXY_CONN_IND may carry a handle for 1254c28749e9Skais * an SSL context, and needs to be released. 1255c28749e9Skais */ 1256c28749e9Skais if ((tci->PRIM_type == T_SSL_PROXY_CONN_IND) && 1257c28749e9Skais (mp->b_cont != NULL)) { 1258c28749e9Skais kssl_ctx_t kssl_ctx; 1259c28749e9Skais 1260c28749e9Skais ASSERT(MBLKL(mp->b_cont) == 1261c28749e9Skais sizeof (kssl_ctx_t)); 1262c28749e9Skais kssl_ctx = *((kssl_ctx_t *)mp->b_cont->b_rptr); 1263c28749e9Skais kssl_release_ctx(kssl_ctx); 1264c28749e9Skais } 12657c478bd9Sstevel@tonic-gate freemsg(mp); 12667c478bd9Sstevel@tonic-gate return (0); 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 12707c478bd9Sstevel@tonic-gate dprintso(so, 1, ("t_discon_ind: NOT found T_CONN_IND %d\n", seqno)); 12717c478bd9Sstevel@tonic-gate return (-1); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* 12757c478bd9Sstevel@tonic-gate * Wait until the socket is connected or there is an error. 12767c478bd9Sstevel@tonic-gate * fmode should contain any nonblocking flags. nosig should be 12777c478bd9Sstevel@tonic-gate * set if the caller does not want the wait to be interrupted by a signal. 12787c478bd9Sstevel@tonic-gate */ 12797c478bd9Sstevel@tonic-gate int 12807c478bd9Sstevel@tonic-gate sowaitconnected(struct sonode *so, int fmode, int nosig) 12817c478bd9Sstevel@tonic-gate { 12827c478bd9Sstevel@tonic-gate int error; 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate while ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 1287d3e55dcdSgww SS_ISCONNECTING && so->so_error == 0) { 12887c478bd9Sstevel@tonic-gate 1289903a11ebSrh dprintso(so, 1, ("waiting for SS_ISCONNECTED on %p\n", 1290903a11ebSrh (void *)so)); 12917c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 12927c478bd9Sstevel@tonic-gate return (EINPROGRESS); 12937c478bd9Sstevel@tonic-gate 1294*0f1702c5SYu Xiangning if (so->so_state & SS_CLOSING) 1295*0f1702c5SYu Xiangning return (EINTR); 1296*0f1702c5SYu Xiangning 12977c478bd9Sstevel@tonic-gate if (nosig) 12987c478bd9Sstevel@tonic-gate cv_wait(&so->so_state_cv, &so->so_lock); 12997c478bd9Sstevel@tonic-gate else if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) { 13007c478bd9Sstevel@tonic-gate /* 13017c478bd9Sstevel@tonic-gate * Return EINTR and let the application use 13027c478bd9Sstevel@tonic-gate * nonblocking techniques for detecting when 13037c478bd9Sstevel@tonic-gate * the connection has been established. 13047c478bd9Sstevel@tonic-gate */ 13057c478bd9Sstevel@tonic-gate return (EINTR); 13067c478bd9Sstevel@tonic-gate } 1307903a11ebSrh dprintso(so, 1, ("awoken on %p\n", (void *)so)); 13087c478bd9Sstevel@tonic-gate } 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate if (so->so_error != 0) { 1311*0f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 13127c478bd9Sstevel@tonic-gate ASSERT(error != 0); 13137c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 13147c478bd9Sstevel@tonic-gate return (error); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ISCONNECTED)) { 13177c478bd9Sstevel@tonic-gate /* 13187c478bd9Sstevel@tonic-gate * Could have received a T_ORDREL_IND or a T_DISCON_IND with 13197c478bd9Sstevel@tonic-gate * zero errno. Or another thread could have consumed so_error 13207c478bd9Sstevel@tonic-gate * e.g. by calling read. 13217c478bd9Sstevel@tonic-gate */ 13227c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 13237c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 13247c478bd9Sstevel@tonic-gate return (error); 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate return (0); 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate /* 13317c478bd9Sstevel@tonic-gate * Handle the signal generation aspect of urgent data. 13327c478bd9Sstevel@tonic-gate */ 13337c478bd9Sstevel@tonic-gate static void 13347c478bd9Sstevel@tonic-gate so_oob_sig(struct sonode *so, int extrasig, 13357c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 13367c478bd9Sstevel@tonic-gate { 1337*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1338*0f1702c5SYu Xiangning 13397c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 1342*0f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt); 1343*0f1702c5SYu Xiangning if (sti->sti_oobsigcnt > sti->sti_oobcnt) { 13447c478bd9Sstevel@tonic-gate /* 13457c478bd9Sstevel@tonic-gate * Signal has already been generated once for this 13467c478bd9Sstevel@tonic-gate * urgent "event". However, since TCP can receive updated 13477c478bd9Sstevel@tonic-gate * urgent pointers we still generate a signal. 13487c478bd9Sstevel@tonic-gate */ 13497c478bd9Sstevel@tonic-gate ASSERT(so->so_state & SS_OOBPEND); 13507c478bd9Sstevel@tonic-gate if (extrasig) { 13517c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 13527c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate return; 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 1357*0f1702c5SYu Xiangning sti->sti_oobsigcnt++; 1358*0f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt > 0); /* Wraparound */ 1359*0f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt > sti->sti_oobcnt); 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * Record (for select/poll) that urgent data is pending. 13637c478bd9Sstevel@tonic-gate */ 13647c478bd9Sstevel@tonic-gate so->so_state |= SS_OOBPEND; 13657c478bd9Sstevel@tonic-gate /* 13667c478bd9Sstevel@tonic-gate * New urgent data on the way so forget about any old 13677c478bd9Sstevel@tonic-gate * urgent data. 13687c478bd9Sstevel@tonic-gate */ 13697c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA); 13707c478bd9Sstevel@tonic-gate if (so->so_oobmsg != NULL) { 13717c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sock: discarding old oob\n")); 13727c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 13737c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 13767c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13777c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* 13817c478bd9Sstevel@tonic-gate * Handle the processing of the T_EXDATA_IND with urgent data. 13827c478bd9Sstevel@tonic-gate * Returns the T_EXDATA_IND if it should be queued on the read queue. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 13857c478bd9Sstevel@tonic-gate static mblk_t * 13867c478bd9Sstevel@tonic-gate so_oob_exdata(struct sonode *so, mblk_t *mp, 13877c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 13887c478bd9Sstevel@tonic-gate { 1389*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1390*0f1702c5SYu Xiangning 13917c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13947c478bd9Sstevel@tonic-gate 1395*0f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt > sti->sti_oobcnt); 13967c478bd9Sstevel@tonic-gate 1397*0f1702c5SYu Xiangning sti->sti_oobcnt++; 1398*0f1702c5SYu Xiangning ASSERT(sti->sti_oobcnt > 0); /* wraparound? */ 1399*0f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt); 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* 14027c478bd9Sstevel@tonic-gate * Set MSGMARK for SIOCATMARK. 14037c478bd9Sstevel@tonic-gate */ 14047c478bd9Sstevel@tonic-gate mp->b_flag |= MSGMARK; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 14077c478bd9Sstevel@tonic-gate return (mp); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * Handle the processing of the actual urgent data. 14127c478bd9Sstevel@tonic-gate * Returns the data mblk if it should be queued on the read queue. 14137c478bd9Sstevel@tonic-gate */ 14147c478bd9Sstevel@tonic-gate static mblk_t * 14157c478bd9Sstevel@tonic-gate so_oob_data(struct sonode *so, mblk_t *mp, 14167c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 14177c478bd9Sstevel@tonic-gate { 1418*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1419*0f1702c5SYu Xiangning 14207c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 14237c478bd9Sstevel@tonic-gate 1424*0f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt); 14257c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * For OOBINLINE we keep the data in the T_EXDATA_IND. 14287c478bd9Sstevel@tonic-gate * Otherwise we store it in so_oobmsg. 14297c478bd9Sstevel@tonic-gate */ 14307c478bd9Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 14317c478bd9Sstevel@tonic-gate if (so->so_options & SO_OOBINLINE) { 14327c478bd9Sstevel@tonic-gate *pollwakeups |= POLLIN | POLLRDNORM | POLLRDBAND; 14337c478bd9Sstevel@tonic-gate *signals |= S_INPUT | S_RDNORM; 14347c478bd9Sstevel@tonic-gate } else { 14357c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 14367c478bd9Sstevel@tonic-gate so->so_state |= SS_HAVEOOBDATA; 14377c478bd9Sstevel@tonic-gate so->so_oobmsg = mp; 14387c478bd9Sstevel@tonic-gate mp = NULL; 14397c478bd9Sstevel@tonic-gate } 14407c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 14417c478bd9Sstevel@tonic-gate return (mp); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate /* 14457c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 14467c478bd9Sstevel@tonic-gate * For delayed processing, save the T_DISCON_IND received 1447*0f1702c5SYu Xiangning * from below on sti_discon_ind_mp. 14487c478bd9Sstevel@tonic-gate * When the message is processed the framework will call: 14497c478bd9Sstevel@tonic-gate * (*func)(so, mp); 14507c478bd9Sstevel@tonic-gate */ 14517c478bd9Sstevel@tonic-gate static void 14527c478bd9Sstevel@tonic-gate so_save_discon_ind(struct sonode *so, 14537c478bd9Sstevel@tonic-gate mblk_t *mp, 14547c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *)) 14557c478bd9Sstevel@tonic-gate { 1456*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1457*0f1702c5SYu Xiangning 14587c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* 14617c478bd9Sstevel@tonic-gate * Discard new T_DISCON_IND if we have already received another. 1462*0f1702c5SYu Xiangning * Currently the earlier message can either be on sti_discon_ind_mp 14637c478bd9Sstevel@tonic-gate * or being processed. 14647c478bd9Sstevel@tonic-gate */ 1465*0f1702c5SYu Xiangning if (sti->sti_discon_ind_mp != NULL || (so->so_flag & SOASYNC_UNBIND)) { 14662caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 14677c478bd9Sstevel@tonic-gate "sockfs: received unexpected additional T_DISCON_IND\n"); 14687c478bd9Sstevel@tonic-gate freemsg(mp); 14697c478bd9Sstevel@tonic-gate return; 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)func; 14727c478bd9Sstevel@tonic-gate mp->b_next = NULL; 1473*0f1702c5SYu Xiangning sti->sti_discon_ind_mp = mp; 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate /* 14777c478bd9Sstevel@tonic-gate * Caller must hold the mutex and make sure that either SOLOCKED 14787c478bd9Sstevel@tonic-gate * or SOASYNC_UNBIND is set. Called from so_unlock_single(). 1479*0f1702c5SYu Xiangning * Perform delayed processing of T_DISCON_IND message on sti_discon_ind_mp. 14807c478bd9Sstevel@tonic-gate * Need to ensure that strsock_proto() will not end up sleeping for 14817c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND, while executing this function. 14827c478bd9Sstevel@tonic-gate */ 14837c478bd9Sstevel@tonic-gate void 14847c478bd9Sstevel@tonic-gate so_drain_discon_ind(struct sonode *so) 14857c478bd9Sstevel@tonic-gate { 14867c478bd9Sstevel@tonic-gate mblk_t *bp; 14877c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *); 1488*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14917c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & (SOLOCKED|SOASYNC_UNBIND)); 14927c478bd9Sstevel@tonic-gate 1493*0f1702c5SYu Xiangning /* Process T_DISCON_IND on sti_discon_ind_mp */ 1494*0f1702c5SYu Xiangning if ((bp = sti->sti_discon_ind_mp) != NULL) { 1495*0f1702c5SYu Xiangning sti->sti_discon_ind_mp = NULL; 14967c478bd9Sstevel@tonic-gate func = (void (*)())bp->b_prev; 14977c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate /* 15007c478bd9Sstevel@tonic-gate * This (*func) is supposed to generate a message downstream 15017c478bd9Sstevel@tonic-gate * and we need to have a flag set until the corresponding 15027c478bd9Sstevel@tonic-gate * upstream message reaches stream head. 15037c478bd9Sstevel@tonic-gate * When processing T_DISCON_IND in strsock_discon_ind 15047c478bd9Sstevel@tonic-gate * we hold SOASYN_UNBIND when sending T_UNBIND_REQ down and 15057c478bd9Sstevel@tonic-gate * drop the flag after we get the ACK in strsock_proto. 15067c478bd9Sstevel@tonic-gate */ 15077c478bd9Sstevel@tonic-gate (void) (*func)(so, bp); 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate /* 15127c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 1513*0f1702c5SYu Xiangning * Remove the T_DISCON_IND on sti_discon_ind_mp. 15147c478bd9Sstevel@tonic-gate */ 15157c478bd9Sstevel@tonic-gate void 15167c478bd9Sstevel@tonic-gate so_flush_discon_ind(struct sonode *so) 15177c478bd9Sstevel@tonic-gate { 15187c478bd9Sstevel@tonic-gate mblk_t *bp; 1519*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate /* 1524*0f1702c5SYu Xiangning * Remove T_DISCON_IND mblk at sti_discon_ind_mp. 15257c478bd9Sstevel@tonic-gate */ 1526*0f1702c5SYu Xiangning if ((bp = sti->sti_discon_ind_mp) != NULL) { 1527*0f1702c5SYu Xiangning sti->sti_discon_ind_mp = NULL; 15287c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 15297c478bd9Sstevel@tonic-gate freemsg(bp); 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate /* 15347c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 15357c478bd9Sstevel@tonic-gate * 15367c478bd9Sstevel@tonic-gate * This function is used to process the T_DISCON_IND message. It does 15377c478bd9Sstevel@tonic-gate * immediate processing when called from strsock_proto and delayed 1538*0f1702c5SYu Xiangning * processing of discon_ind saved on sti_discon_ind_mp when called from 15397c478bd9Sstevel@tonic-gate * so_drain_discon_ind. When a T_DISCON_IND message is saved in 1540*0f1702c5SYu Xiangning * sti_discon_ind_mp for delayed processing, this function is registered 15417c478bd9Sstevel@tonic-gate * as the callback function to process the message. 15427c478bd9Sstevel@tonic-gate * 15437c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND should be held in this function, during the non-blocking 15447c478bd9Sstevel@tonic-gate * unbind operation, and should be released only after we receive the ACK 15457c478bd9Sstevel@tonic-gate * in strsock_proto, for the T_UNBIND_REQ sent here. Since SOLOCKED is not set, 15467c478bd9Sstevel@tonic-gate * no TPI messages would be sent down at this time. This is to prevent M_FLUSH 15477c478bd9Sstevel@tonic-gate * sent from either this function or tcp_unbind(), flushing away any TPI 15487c478bd9Sstevel@tonic-gate * message that is being sent down and stays in a lower module's queue. 15497c478bd9Sstevel@tonic-gate * 15507c478bd9Sstevel@tonic-gate * This function drops so_lock and grabs it again. 15517c478bd9Sstevel@tonic-gate */ 15527c478bd9Sstevel@tonic-gate static void 15537c478bd9Sstevel@tonic-gate strsock_discon_ind(struct sonode *so, mblk_t *discon_mp) 15547c478bd9Sstevel@tonic-gate { 15557c478bd9Sstevel@tonic-gate struct vnode *vp; 15567c478bd9Sstevel@tonic-gate struct stdata *stp; 15577c478bd9Sstevel@tonic-gate union T_primitives *tpr; 15587c478bd9Sstevel@tonic-gate struct T_unbind_req *ubr; 15597c478bd9Sstevel@tonic-gate mblk_t *mp; 15607c478bd9Sstevel@tonic-gate int error; 1561*0f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 15647c478bd9Sstevel@tonic-gate ASSERT(discon_mp); 15657c478bd9Sstevel@tonic-gate ASSERT(discon_mp->b_rptr); 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)discon_mp->b_rptr; 15687c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_DISCON_IND); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate vp = SOTOV(so); 15717c478bd9Sstevel@tonic-gate stp = vp->v_stream; 15727c478bd9Sstevel@tonic-gate ASSERT(stp); 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * Not a listener 15767c478bd9Sstevel@tonic-gate */ 15777c478bd9Sstevel@tonic-gate ASSERT((so->so_state & SS_ACCEPTCONN) == 0); 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate /* 15807c478bd9Sstevel@tonic-gate * This assumes that the name space for DISCON_reason 15817c478bd9Sstevel@tonic-gate * is the errno name space. 15827c478bd9Sstevel@tonic-gate */ 15837c478bd9Sstevel@tonic-gate soisdisconnected(so, tpr->discon_ind.DISCON_reason); 1584*0f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 1585*0f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate /* 15887c478bd9Sstevel@tonic-gate * Unbind with the transport without blocking. 15897c478bd9Sstevel@tonic-gate * If we've already received a T_DISCON_IND do not unbind. 15907c478bd9Sstevel@tonic-gate * 15917c478bd9Sstevel@tonic-gate * If there is no preallocated unbind message, we have already 15927c478bd9Sstevel@tonic-gate * unbound with the transport 15937c478bd9Sstevel@tonic-gate * 15947c478bd9Sstevel@tonic-gate * If the socket is not bound, no need to unbind. 15957c478bd9Sstevel@tonic-gate */ 1596*0f1702c5SYu Xiangning mp = sti->sti_unbind_mp; 15977c478bd9Sstevel@tonic-gate if (mp == NULL) { 15987c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & SS_ISBOUND)); 15997c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 16007c478bd9Sstevel@tonic-gate } else if (!(so->so_state & SS_ISBOUND)) { 16017c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 16027c478bd9Sstevel@tonic-gate } else { 1603*0f1702c5SYu Xiangning sti->sti_unbind_mp = NULL; 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * Is another T_DISCON_IND being processed. 16077c478bd9Sstevel@tonic-gate */ 16087c478bd9Sstevel@tonic-gate ASSERT((so->so_flag & SOASYNC_UNBIND) == 0); 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate /* 16117c478bd9Sstevel@tonic-gate * Make strsock_proto ignore T_OK_ACK and T_ERROR_ACK for 16127c478bd9Sstevel@tonic-gate * this unbind. Set SOASYNC_UNBIND. This should be cleared 16137c478bd9Sstevel@tonic-gate * only after we receive the ACK in strsock_proto. 16147c478bd9Sstevel@tonic-gate */ 16157c478bd9Sstevel@tonic-gate so->so_flag |= SOASYNC_UNBIND; 16167c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING))); 1617*0f1702c5SYu Xiangning so->so_state &= ~(SS_ISBOUND|SS_ACCEPTCONN); 1618*0f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 16197c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * Send down T_UNBIND_REQ ignoring flow control. 16237c478bd9Sstevel@tonic-gate * XXX Assumes that MSG_IGNFLOW implies that this thread 16247c478bd9Sstevel@tonic-gate * does not run service procedures. 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO); 16277c478bd9Sstevel@tonic-gate ubr = (struct T_unbind_req *)mp->b_rptr; 16287c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (*ubr); 16297c478bd9Sstevel@tonic-gate ubr->PRIM_type = T_UNBIND_REQ; 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate /* 16327c478bd9Sstevel@tonic-gate * Flush the read and write side (except stream head read queue) 16337c478bd9Sstevel@tonic-gate * and send down T_UNBIND_REQ. 16347c478bd9Sstevel@tonic-gate */ 16357c478bd9Sstevel@tonic-gate (void) putnextctl1(strvp2wq(SOTOV(so)), M_FLUSH, FLUSHRW); 16367c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 1637d3e55dcdSgww MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0); 16387c478bd9Sstevel@tonic-gate /* LINTED - warning: statement has no consequent: if */ 16397c478bd9Sstevel@tonic-gate if (error) { 16407c478bd9Sstevel@tonic-gate eprintsoline(so, error); 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate } 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate if (tpr->discon_ind.DISCON_reason != 0) 16457c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 16467c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 16477c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 16487c478bd9Sstevel@tonic-gate /* 16497c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 16507c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 16517c478bd9Sstevel@tonic-gate */ 16527c478bd9Sstevel@tonic-gate dprintso(so, 1, ("T_DISCON_IND: error %d\n", so->so_error)); 16537c478bd9Sstevel@tonic-gate freemsg(discon_mp); 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLOUT); 16577c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate /* 16607c478bd9Sstevel@tonic-gate * Wake sleeping write 16617c478bd9Sstevel@tonic-gate */ 16627c478bd9Sstevel@tonic-gate if (stp->sd_flag & WSLEEP) { 16637c478bd9Sstevel@tonic-gate stp->sd_flag &= ~WSLEEP; 16647c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_wrq->q_wait); 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate /* 16687c478bd9Sstevel@tonic-gate * strsendsig can handle multiple signals with a 16697c478bd9Sstevel@tonic-gate * single call. Send SIGPOLL for S_OUTPUT event. 16707c478bd9Sstevel@tonic-gate */ 16717c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_OUTPUT) 16727c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_OUTPUT, 0, 0); 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 16757c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate /* 16797c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive M_PROTO 16807c478bd9Sstevel@tonic-gate * and M_PCPROTO messages. 16817c478bd9Sstevel@tonic-gate * 16827c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 16837c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed (and queued) by the stream 16847c478bd9Sstevel@tonic-gate * head. 16857c478bd9Sstevel@tonic-gate * 16867c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 16877c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. Note that since 16887c478bd9Sstevel@tonic-gate * sockets always deliver SIGIO for every new piece of data this routine 16897c478bd9Sstevel@tonic-gate * never sets *firstmsgsigs; any signals are returned in *allmsgsigs. 16907c478bd9Sstevel@tonic-gate * 16917c478bd9Sstevel@tonic-gate * This routine handles all data related TPI messages independent of 16927c478bd9Sstevel@tonic-gate * the type of the socket i.e. it doesn't care if T_UNITDATA_IND message 16937c478bd9Sstevel@tonic-gate * arrive on a SOCK_STREAM. 16947c478bd9Sstevel@tonic-gate */ 16957c478bd9Sstevel@tonic-gate static mblk_t * 16967c478bd9Sstevel@tonic-gate strsock_proto(vnode_t *vp, mblk_t *mp, 16977c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 16987c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 16997c478bd9Sstevel@tonic-gate { 17007c478bd9Sstevel@tonic-gate union T_primitives *tpr; 17017c478bd9Sstevel@tonic-gate struct sonode *so; 1702*0f1702c5SYu Xiangning sotpi_info_t *sti; 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate so = VTOSO(vp); 1705*0f1702c5SYu Xiangning sti = SOTOTPI(so); 17067c478bd9Sstevel@tonic-gate 1707903a11ebSrh dprintso(so, 1, ("strsock_proto(%p, %p)\n", (void *)vp, (void *)mp)); 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate /* Set default return values */ 17107c478bd9Sstevel@tonic-gate *firstmsgsigs = *wakeups = *allmsgsigs = *pollwakeups = 0; 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO || 17137c478bd9Sstevel@tonic-gate DB_TYPE(mp) == M_PCPROTO); 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (tpr->type)) { 17167c478bd9Sstevel@tonic-gate /* The message is too short to even contain the primitive */ 17172caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17187c478bd9Sstevel@tonic-gate "sockfs: Too short TPI message received. Len = %ld\n", 17197c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 17207c478bd9Sstevel@tonic-gate freemsg(mp); 17217c478bd9Sstevel@tonic-gate return (NULL); 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate if (!__TPI_PRIM_ISALIGNED(mp->b_rptr)) { 17247c478bd9Sstevel@tonic-gate /* The read pointer is not aligned correctly for TPI */ 17252caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17267c478bd9Sstevel@tonic-gate "sockfs: Unaligned TPI message received. rptr = %p\n", 17277c478bd9Sstevel@tonic-gate (void *)mp->b_rptr); 17287c478bd9Sstevel@tonic-gate freemsg(mp); 17297c478bd9Sstevel@tonic-gate return (NULL); 17307c478bd9Sstevel@tonic-gate } 17317c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 17327c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_proto: primitive %d\n", tpr->type)); 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate switch (tpr->type) { 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate case T_DATA_IND: 17377c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_data_ind)) { 17382caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17397c478bd9Sstevel@tonic-gate "sockfs: Too short T_DATA_IND. Len = %ld\n", 17407c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 17417c478bd9Sstevel@tonic-gate freemsg(mp); 17427c478bd9Sstevel@tonic-gate return (NULL); 17437c478bd9Sstevel@tonic-gate } 17447c478bd9Sstevel@tonic-gate /* 17457c478bd9Sstevel@tonic-gate * Ignore zero-length T_DATA_IND messages. These might be 17467c478bd9Sstevel@tonic-gate * generated by some transports. 17477c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 17487c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 17497c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 17507c478bd9Sstevel@tonic-gate * that data is available). 17517c478bd9Sstevel@tonic-gate */ 17527c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 17537c478bd9Sstevel@tonic-gate dprintso(so, 0, 17547c478bd9Sstevel@tonic-gate ("strsock_proto: zero length T_DATA_IND\n")); 17557c478bd9Sstevel@tonic-gate freemsg(mp); 17567c478bd9Sstevel@tonic-gate return (NULL); 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 17597c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 17607c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 17617c478bd9Sstevel@tonic-gate return (mp); 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate case T_UNITDATA_IND: { 17647c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi = &tpr->unitdata_ind; 17657c478bd9Sstevel@tonic-gate void *addr; 17667c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_unitdata_ind)) { 17692caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17707c478bd9Sstevel@tonic-gate "sockfs: Too short T_UNITDATA_IND. Len = %ld\n", 17717c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 17727c478bd9Sstevel@tonic-gate freemsg(mp); 17737c478bd9Sstevel@tonic-gate return (NULL); 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate /* Is this is not a connected datagram socket? */ 17777c478bd9Sstevel@tonic-gate if ((so->so_mode & SM_CONNREQUIRED) || 17787c478bd9Sstevel@tonic-gate !(so->so_state & SS_ISCONNECTED)) { 17797c478bd9Sstevel@tonic-gate /* 17807c478bd9Sstevel@tonic-gate * Not a connected datagram socket. Look for 17817c478bd9Sstevel@tonic-gate * the SO_UNIX_CLOSE option. If such an option is found 17827c478bd9Sstevel@tonic-gate * discard the message (since it has no meaning 17837c478bd9Sstevel@tonic-gate * unless connected). 17847c478bd9Sstevel@tonic-gate */ 17857c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp) == 0 && 17867c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 17877c478bd9Sstevel@tonic-gate void *opt; 17887c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 1791d3e55dcdSgww optlen, __TPI_ALIGN_SIZE); 17927c478bd9Sstevel@tonic-gate if (opt == NULL) { 17937c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 17947c478bd9Sstevel@tonic-gate freemsg(mp); 17957c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 17967c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 17977c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 17982caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17997c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with " 18007c478bd9Sstevel@tonic-gate "invalid optlen/offset %u/%d\n", 18017c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 18027c478bd9Sstevel@tonic-gate return (NULL); 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 18057c478bd9Sstevel@tonic-gate freemsg(mp); 18067c478bd9Sstevel@tonic-gate return (NULL); 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 18107c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 18117c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 18127c478bd9Sstevel@tonic-gate if (audit_active) 18137c478bd9Sstevel@tonic-gate audit_sock(T_UNITDATA_IND, strvp2wq(vp), 1814d3e55dcdSgww mp, 0); 18157c478bd9Sstevel@tonic-gate return (mp); 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate 18187c478bd9Sstevel@tonic-gate /* 18197c478bd9Sstevel@tonic-gate * A connect datagram socket. For AF_INET{,6} we verify that 18207c478bd9Sstevel@tonic-gate * the source address matches the "connected to" address. 18217c478bd9Sstevel@tonic-gate * The semantics of AF_UNIX sockets is to not verify 18227c478bd9Sstevel@tonic-gate * the source address. 18237c478bd9Sstevel@tonic-gate * Note that this source address verification is transport 18247c478bd9Sstevel@tonic-gate * specific. Thus the real fix would be to extent TPI 18257c478bd9Sstevel@tonic-gate * to allow T_CONN_REQ messages to be send to connectionless 18267c478bd9Sstevel@tonic-gate * transport providers and always let the transport provider 18277c478bd9Sstevel@tonic-gate * do whatever filtering is needed. 18287c478bd9Sstevel@tonic-gate * 18297c478bd9Sstevel@tonic-gate * The verification/filtering semantics for transports 18307c478bd9Sstevel@tonic-gate * other than AF_INET and AF_UNIX are unknown. The choice 18317c478bd9Sstevel@tonic-gate * would be to either filter using bcmp or let all messages 18327c478bd9Sstevel@tonic-gate * get through. This code does not filter other address 18337c478bd9Sstevel@tonic-gate * families since this at least allows the application to 18347c478bd9Sstevel@tonic-gate * work around any missing filtering. 18357c478bd9Sstevel@tonic-gate * 18367c478bd9Sstevel@tonic-gate * XXX Should we move filtering to UDP/ICMP??? 18377c478bd9Sstevel@tonic-gate * That would require passing e.g. a T_DISCON_REQ to UDP 18387c478bd9Sstevel@tonic-gate * when the socket becomes unconnected. 18397c478bd9Sstevel@tonic-gate */ 18407c478bd9Sstevel@tonic-gate addrlen = tudi->SRC_length; 18417c478bd9Sstevel@tonic-gate /* 18427c478bd9Sstevel@tonic-gate * The alignment restriction is really to strict but 18437c478bd9Sstevel@tonic-gate * we want enough alignment to inspect the fields of 18447c478bd9Sstevel@tonic-gate * a sockaddr_in. 18457c478bd9Sstevel@tonic-gate */ 18467c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->SRC_offset, addrlen, 1847d3e55dcdSgww __TPI_ALIGN_SIZE); 18487c478bd9Sstevel@tonic-gate if (addr == NULL) { 18497c478bd9Sstevel@tonic-gate freemsg(mp); 18507c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18517c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 18527c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18532caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 18547c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with invalid " 18557c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 18567c478bd9Sstevel@tonic-gate addrlen, tudi->SRC_offset); 18577c478bd9Sstevel@tonic-gate return (NULL); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET) { 18617c478bd9Sstevel@tonic-gate /* 18627c478bd9Sstevel@tonic-gate * For AF_INET we allow wildcarding both sin_addr 18637c478bd9Sstevel@tonic-gate * and sin_port. 18647c478bd9Sstevel@tonic-gate */ 18657c478bd9Sstevel@tonic-gate struct sockaddr_in *faddr, *sin; 18667c478bd9Sstevel@tonic-gate 1867*0f1702c5SYu Xiangning /* Prevent sti_faddr_sa from changing while accessed */ 18687c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1869*0f1702c5SYu Xiangning ASSERT(sti->sti_faddr_len == 1870d3e55dcdSgww (socklen_t)sizeof (struct sockaddr_in)); 1871*0f1702c5SYu Xiangning faddr = (struct sockaddr_in *)sti->sti_faddr_sa; 18727c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)addr; 18737c478bd9Sstevel@tonic-gate if (addrlen != 1874d3e55dcdSgww (t_uscalar_t)sizeof (struct sockaddr_in) || 18757c478bd9Sstevel@tonic-gate (sin->sin_addr.s_addr != faddr->sin_addr.s_addr && 18767c478bd9Sstevel@tonic-gate faddr->sin_addr.s_addr != INADDR_ANY) || 18777c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 18787c478bd9Sstevel@tonic-gate sin->sin_port != faddr->sin_port && 18797c478bd9Sstevel@tonic-gate faddr->sin_port != 0)) { 18807c478bd9Sstevel@tonic-gate #ifdef DEBUG 18817c478bd9Sstevel@tonic-gate dprintso(so, 0, 1882d3e55dcdSgww ("sockfs: T_UNITDATA_IND mismatch: %s", 1883d3e55dcdSgww pr_addr(so->so_family, 1884*0f1702c5SYu Xiangning (struct sockaddr *)addr, addrlen))); 18857c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 1886*0f1702c5SYu Xiangning pr_addr(so->so_family, sti->sti_faddr_sa, 1887*0f1702c5SYu Xiangning (t_uscalar_t)sti->sti_faddr_len))); 18887c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 18897c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18907c478bd9Sstevel@tonic-gate freemsg(mp); 18917c478bd9Sstevel@tonic-gate return (NULL); 18927c478bd9Sstevel@tonic-gate } 18937c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18947c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_INET6) { 18957c478bd9Sstevel@tonic-gate /* 18967c478bd9Sstevel@tonic-gate * For AF_INET6 we allow wildcarding both sin6_addr 18977c478bd9Sstevel@tonic-gate * and sin6_port. 18987c478bd9Sstevel@tonic-gate */ 18997c478bd9Sstevel@tonic-gate struct sockaddr_in6 *faddr6, *sin6; 19007c478bd9Sstevel@tonic-gate static struct in6_addr zeroes; /* inits to all zeros */ 19017c478bd9Sstevel@tonic-gate 1902*0f1702c5SYu Xiangning /* Prevent sti_faddr_sa from changing while accessed */ 19037c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1904*0f1702c5SYu Xiangning ASSERT(sti->sti_faddr_len == 19057c478bd9Sstevel@tonic-gate (socklen_t)sizeof (struct sockaddr_in6)); 1906*0f1702c5SYu Xiangning faddr6 = (struct sockaddr_in6 *)sti->sti_faddr_sa; 19077c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)addr; 19087c478bd9Sstevel@tonic-gate /* XXX could we get a mapped address ::ffff:0.0.0.0 ? */ 19097c478bd9Sstevel@tonic-gate if (addrlen != 19107c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct sockaddr_in6) || 19117c478bd9Sstevel@tonic-gate (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 1912d3e55dcdSgww &faddr6->sin6_addr) && 19137c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&faddr6->sin6_addr, &zeroes)) || 19147c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 19157c478bd9Sstevel@tonic-gate sin6->sin6_port != faddr6->sin6_port && 19167c478bd9Sstevel@tonic-gate faddr6->sin6_port != 0)) { 19177c478bd9Sstevel@tonic-gate #ifdef DEBUG 19187c478bd9Sstevel@tonic-gate dprintso(so, 0, 19197c478bd9Sstevel@tonic-gate ("sockfs: T_UNITDATA_IND mismatch: %s", 1920d3e55dcdSgww pr_addr(so->so_family, 1921*0f1702c5SYu Xiangning (struct sockaddr *)addr, addrlen))); 19227c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 1923*0f1702c5SYu Xiangning pr_addr(so->so_family, sti->sti_faddr_sa, 1924*0f1702c5SYu Xiangning (t_uscalar_t)sti->sti_faddr_len))); 19257c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 19267c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19277c478bd9Sstevel@tonic-gate freemsg(mp); 19287c478bd9Sstevel@tonic-gate return (NULL); 19297c478bd9Sstevel@tonic-gate } 19307c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19317c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_UNIX && 19327c478bd9Sstevel@tonic-gate msgdsize(mp->b_cont) == 0 && 19337c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 19347c478bd9Sstevel@tonic-gate /* 19357c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX 19367c478bd9Sstevel@tonic-gate * SO_UNIX_CLOSE indication from options. 19377c478bd9Sstevel@tonic-gate */ 19387c478bd9Sstevel@tonic-gate void *opt; 19397c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 1942d3e55dcdSgww 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_unidata_ind with invalid " 19517c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 19527c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 19537c478bd9Sstevel@tonic-gate return (NULL); 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate /* 19567c478bd9Sstevel@tonic-gate * If we received a unix 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 sobreakconn(so, ECONNRESET); 19627c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19637c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 19647c478bd9Sstevel@tonic-gate freemsg(mp); 19657c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19667c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19677c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19687c478bd9Sstevel@tonic-gate return (NULL); 19697c478bd9Sstevel@tonic-gate } 19707c478bd9Sstevel@tonic-gate } 19717c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19727c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19737c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19747c478bd9Sstevel@tonic-gate return (mp); 19757c478bd9Sstevel@tonic-gate } 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate case T_OPTDATA_IND: { 19787c478bd9Sstevel@tonic-gate struct T_optdata_ind *tdi = &tpr->optdata_ind; 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optdata_ind)) { 19812caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 19827c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTDATA_IND. Len = %ld\n", 19837c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 19847c478bd9Sstevel@tonic-gate freemsg(mp); 19857c478bd9Sstevel@tonic-gate return (NULL); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate /* 19887c478bd9Sstevel@tonic-gate * Allow zero-length messages carrying options. 19897c478bd9Sstevel@tonic-gate * This is used when carrying the SO_UNIX_CLOSE option. 19907c478bd9Sstevel@tonic-gate */ 19917c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp->b_cont) == 0 && 19927c478bd9Sstevel@tonic-gate tdi->OPT_length != 0) { 19937c478bd9Sstevel@tonic-gate /* 19947c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX close indication 19957c478bd9Sstevel@tonic-gate * from the options. Ignore any other options - 19967c478bd9Sstevel@tonic-gate * those are handled once the message is removed 19977c478bd9Sstevel@tonic-gate * from the queue. 19987c478bd9Sstevel@tonic-gate * The close indication message should not carry data. 19997c478bd9Sstevel@tonic-gate */ 20007c478bd9Sstevel@tonic-gate void *opt; 20017c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tdi->OPT_length; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tdi->OPT_offset, 2004d3e55dcdSgww optlen, __TPI_ALIGN_SIZE); 20057c478bd9Sstevel@tonic-gate if (opt == NULL) { 20067c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 20077c478bd9Sstevel@tonic-gate freemsg(mp); 20087c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 20097c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 20107c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 20112caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 20127c478bd9Sstevel@tonic-gate "sockfs: T_optdata_ind with invalid " 20137c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 20147c478bd9Sstevel@tonic-gate optlen, tdi->OPT_offset); 20157c478bd9Sstevel@tonic-gate return (NULL); 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate /* 20187c478bd9Sstevel@tonic-gate * If we received a close indication mark the 20197c478bd9Sstevel@tonic-gate * socket and discard this message. 20207c478bd9Sstevel@tonic-gate */ 20217c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 20227c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 20237c478bd9Sstevel@tonic-gate socantsendmore(so); 2024*0f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 20257c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 20267c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 20277c478bd9Sstevel@tonic-gate freemsg(mp); 20287c478bd9Sstevel@tonic-gate return (NULL); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 20327c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 20337c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 20347c478bd9Sstevel@tonic-gate return (mp); 20357c478bd9Sstevel@tonic-gate } 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate case T_EXDATA_IND: { 20387c478bd9Sstevel@tonic-gate mblk_t *mctl, *mdata; 2039e63f9565Sss mblk_t *lbp; 2040e63f9565Sss union T_primitives *tprp; 2041e63f9565Sss struct stdata *stp; 2042e63f9565Sss queue_t *qp; 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_exdata_ind)) { 20452caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 20467c478bd9Sstevel@tonic-gate "sockfs: Too short T_EXDATA_IND. Len = %ld\n", 20477c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 20487c478bd9Sstevel@tonic-gate freemsg(mp); 20497c478bd9Sstevel@tonic-gate return (NULL); 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate /* 20527c478bd9Sstevel@tonic-gate * Ignore zero-length T_EXDATA_IND messages. These might be 20537c478bd9Sstevel@tonic-gate * generated by some transports. 20547c478bd9Sstevel@tonic-gate * 20557c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 20567c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 20577c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 20587c478bd9Sstevel@tonic-gate * that data is available). 20597c478bd9Sstevel@tonic-gate */ 20607c478bd9Sstevel@tonic-gate dprintso(so, 1, 2061d3e55dcdSgww ("T_EXDATA_IND(%p): counts %d/%d state %s\n", 2062*0f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt, 2063d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 20667c478bd9Sstevel@tonic-gate dprintso(so, 0, 2067d3e55dcdSgww ("strsock_proto: zero length T_EXDATA_IND\n")); 20687c478bd9Sstevel@tonic-gate freemsg(mp); 20697c478bd9Sstevel@tonic-gate return (NULL); 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * Split into the T_EXDATA_IND and the M_DATA part. 20747c478bd9Sstevel@tonic-gate * We process these three pieces separately: 20757c478bd9Sstevel@tonic-gate * signal generation 20767c478bd9Sstevel@tonic-gate * handling T_EXDATA_IND 20777c478bd9Sstevel@tonic-gate * handling M_DATA component 20787c478bd9Sstevel@tonic-gate */ 20797c478bd9Sstevel@tonic-gate mctl = mp; 20807c478bd9Sstevel@tonic-gate mdata = mctl->b_cont; 20817c478bd9Sstevel@tonic-gate mctl->b_cont = NULL; 20827c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 20837c478bd9Sstevel@tonic-gate so_oob_sig(so, 0, allmsgsigs, pollwakeups); 20847c478bd9Sstevel@tonic-gate mctl = so_oob_exdata(so, mctl, allmsgsigs, pollwakeups); 20857c478bd9Sstevel@tonic-gate mdata = so_oob_data(so, mdata, allmsgsigs, pollwakeups); 20867c478bd9Sstevel@tonic-gate 2087e63f9565Sss stp = vp->v_stream; 2088e63f9565Sss ASSERT(stp != NULL); 2089e63f9565Sss qp = _RD(stp->sd_wrq); 2090e63f9565Sss 2091e63f9565Sss mutex_enter(QLOCK(qp)); 2092e63f9565Sss lbp = qp->q_last; 2093e63f9565Sss 2094e63f9565Sss /* 2095e63f9565Sss * We want to avoid queueing up a string of T_EXDATA_IND 2096e63f9565Sss * messages with no intervening data messages at the stream 2097e63f9565Sss * head. These messages contribute to the total message 2098e63f9565Sss * count. Eventually this can lead to STREAMS flow contol 2099e63f9565Sss * and also cause TCP to advertise a zero window condition 2100e63f9565Sss * to the peer. This can happen in the degenerate case where 2101e63f9565Sss * the sender and receiver exchange only OOB data. The sender 2102e63f9565Sss * only sends messages with MSG_OOB flag and the receiver 2103e63f9565Sss * receives only MSG_OOB messages and does not use SO_OOBINLINE. 2104e63f9565Sss * An example of this scenario has been reported in applications 2105e63f9565Sss * that use OOB data to exchange heart beats. Flow control 2106e63f9565Sss * relief will never happen if the application only reads OOB 2107e63f9565Sss * data which is done directly by sorecvoob() and the 2108e63f9565Sss * T_EXDATA_IND messages at the streamhead won't be consumed. 2109e63f9565Sss * Note that there is no correctness issue in compressing the 2110e63f9565Sss * string of T_EXDATA_IND messages into a single T_EXDATA_IND 2111e63f9565Sss * message. A single read that does not specify MSG_OOB will 2112e63f9565Sss * read across all the marks in a loop in sotpi_recvmsg(). 2113e63f9565Sss * Each mark is individually distinguishable only if the 2114e63f9565Sss * T_EXDATA_IND messages are separated by data messages. 2115e63f9565Sss */ 2116e63f9565Sss if ((qp->q_first != NULL) && (DB_TYPE(lbp) == M_PROTO)) { 2117e63f9565Sss tprp = (union T_primitives *)lbp->b_rptr; 2118e63f9565Sss if ((tprp->type == T_EXDATA_IND) && 2119e63f9565Sss !(so->so_options & SO_OOBINLINE)) { 2120e63f9565Sss 2121e63f9565Sss /* 2122e63f9565Sss * free the new M_PROTO message 2123e63f9565Sss */ 2124e63f9565Sss freemsg(mctl); 2125e63f9565Sss 2126e63f9565Sss /* 2127e63f9565Sss * adjust the OOB count and OOB signal count 2128e63f9565Sss * just incremented for the new OOB data. 2129e63f9565Sss */ 2130*0f1702c5SYu Xiangning sti->sti_oobcnt--; 2131*0f1702c5SYu Xiangning sti->sti_oobsigcnt--; 2132e63f9565Sss mutex_exit(QLOCK(qp)); 2133e63f9565Sss mutex_exit(&so->so_lock); 2134e63f9565Sss return (NULL); 2135e63f9565Sss } 2136e63f9565Sss } 2137e63f9565Sss mutex_exit(QLOCK(qp)); 2138e63f9565Sss 21397c478bd9Sstevel@tonic-gate /* 21407c478bd9Sstevel@tonic-gate * Pass the T_EXDATA_IND and the M_DATA back separately 21417c478bd9Sstevel@tonic-gate * by using b_next linkage. (The stream head will queue any 21427c478bd9Sstevel@tonic-gate * b_next linked messages separately.) This is needed 21437c478bd9Sstevel@tonic-gate * since MSGMARK applies to the last by of the message 21447c478bd9Sstevel@tonic-gate * hence we can not have any M_DATA component attached 21457c478bd9Sstevel@tonic-gate * to the marked T_EXDATA_IND. Note that the stream head 21467c478bd9Sstevel@tonic-gate * will not consolidate M_DATA messages onto an MSGMARK'ed 21477c478bd9Sstevel@tonic-gate * message in order to preserve the constraint that 21487c478bd9Sstevel@tonic-gate * the T_EXDATA_IND always is a separate message. 21497c478bd9Sstevel@tonic-gate */ 21507c478bd9Sstevel@tonic-gate ASSERT(mctl != NULL); 21517c478bd9Sstevel@tonic-gate mctl->b_next = mdata; 21527c478bd9Sstevel@tonic-gate mp = mctl; 21537c478bd9Sstevel@tonic-gate #ifdef DEBUG 21547c478bd9Sstevel@tonic-gate if (mdata == NULL) { 21557c478bd9Sstevel@tonic-gate dprintso(so, 1, 2156d3e55dcdSgww ("after outofline T_EXDATA_IND(%p): " 2157d3e55dcdSgww "counts %d/%d poll 0x%x sig 0x%x state %s\n", 2158*0f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, 2159*0f1702c5SYu Xiangning sti->sti_oobcnt, *pollwakeups, *allmsgsigs, 2160d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 21617c478bd9Sstevel@tonic-gate } else { 21627c478bd9Sstevel@tonic-gate dprintso(so, 1, 2163d3e55dcdSgww ("after inline T_EXDATA_IND(%p): " 2164d3e55dcdSgww "counts %d/%d poll 0x%x sig 0x%x state %s\n", 2165*0f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, 2166*0f1702c5SYu Xiangning sti->sti_oobcnt, *pollwakeups, *allmsgsigs, 2167d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 21707c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21717c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 21727c478bd9Sstevel@tonic-gate return (mp); 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate 21757c478bd9Sstevel@tonic-gate case T_CONN_CON: { 21767c478bd9Sstevel@tonic-gate struct T_conn_con *conn_con; 21777c478bd9Sstevel@tonic-gate void *addr; 21787c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate /* 21817c478bd9Sstevel@tonic-gate * Verify the state, update the state to ISCONNECTED, 21827c478bd9Sstevel@tonic-gate * record the potentially new address in the message, 21837c478bd9Sstevel@tonic-gate * and drop the message. 21847c478bd9Sstevel@tonic-gate */ 21857c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_con)) { 21862caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 21877c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_CON. Len = %ld\n", 21887c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 21897c478bd9Sstevel@tonic-gate freemsg(mp); 21907c478bd9Sstevel@tonic-gate return (NULL); 21917c478bd9Sstevel@tonic-gate } 21927c478bd9Sstevel@tonic-gate 21937c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 21947c478bd9Sstevel@tonic-gate if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) != 21957c478bd9Sstevel@tonic-gate SS_ISCONNECTING) { 21967c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21977c478bd9Sstevel@tonic-gate dprintso(so, 1, 2198d3e55dcdSgww ("T_CONN_CON: state %x\n", so->so_state)); 21997c478bd9Sstevel@tonic-gate freemsg(mp); 22007c478bd9Sstevel@tonic-gate return (NULL); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate conn_con = &tpr->conn_con; 22047c478bd9Sstevel@tonic-gate addrlen = conn_con->RES_length; 22057c478bd9Sstevel@tonic-gate /* 22067c478bd9Sstevel@tonic-gate * Allow the address to be of different size than sent down 22077c478bd9Sstevel@tonic-gate * in the T_CONN_REQ as long as it doesn't exceed the maxlen. 22087c478bd9Sstevel@tonic-gate * For AF_UNIX require the identical length. 22097c478bd9Sstevel@tonic-gate */ 22107c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX ? 2211*0f1702c5SYu Xiangning addrlen != (t_uscalar_t)sizeof (sti->sti_ux_laddr) : 2212*0f1702c5SYu Xiangning addrlen > (t_uscalar_t)sti->sti_faddr_maxlen) { 22132caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22147c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with different " 22157c478bd9Sstevel@tonic-gate "length %u/%d\n", 22167c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_length); 22177c478bd9Sstevel@tonic-gate soisdisconnected(so, EPROTO); 2218*0f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 2219*0f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 22207c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 22217c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 22227c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 22237c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 22247c478bd9Sstevel@tonic-gate freemsg(mp); 22257c478bd9Sstevel@tonic-gate /* 22267c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 22277c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 22287c478bd9Sstevel@tonic-gate */ 22297c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 22307c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 22317c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 22327c478bd9Sstevel@tonic-gate return (NULL); 22337c478bd9Sstevel@tonic-gate } 22347c478bd9Sstevel@tonic-gate addr = sogetoff(mp, conn_con->RES_offset, addrlen, 1); 22357c478bd9Sstevel@tonic-gate if (addr == NULL) { 22362caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22377c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with invalid " 22387c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 22397c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_offset); 22407c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 22417c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 22427c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 22437c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 22447c478bd9Sstevel@tonic-gate freemsg(mp); 22457c478bd9Sstevel@tonic-gate /* 22467c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 22477c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 22487c478bd9Sstevel@tonic-gate */ 22497c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 22507c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 22517c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 22527c478bd9Sstevel@tonic-gate return (NULL); 22537c478bd9Sstevel@tonic-gate } 22547c478bd9Sstevel@tonic-gate 22557c478bd9Sstevel@tonic-gate /* 22567c478bd9Sstevel@tonic-gate * Save for getpeername. 22577c478bd9Sstevel@tonic-gate */ 22587c478bd9Sstevel@tonic-gate if (so->so_family != AF_UNIX) { 2259*0f1702c5SYu Xiangning sti->sti_faddr_len = (socklen_t)addrlen; 2260*0f1702c5SYu Xiangning ASSERT(sti->sti_faddr_len <= sti->sti_faddr_maxlen); 2261*0f1702c5SYu Xiangning bcopy(addr, sti->sti_faddr_sa, addrlen); 2262*0f1702c5SYu Xiangning sti->sti_faddr_valid = 1; 22637c478bd9Sstevel@tonic-gate } 22647c478bd9Sstevel@tonic-gate 22657c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 22667c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 22677c478bd9Sstevel@tonic-gate so->so_peercred = DB_CRED(mp); 22687c478bd9Sstevel@tonic-gate so->so_cpid = DB_CPID(mp); 22697c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 22707c478bd9Sstevel@tonic-gate crhold(so->so_peercred); 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate /* Wakeup anybody sleeping in sowaitconnected */ 22737c478bd9Sstevel@tonic-gate soisconnected(so); 22747c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate /* 22777c478bd9Sstevel@tonic-gate * The socket is now available for sending data. 22787c478bd9Sstevel@tonic-gate */ 22797c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 22807c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 22817c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 22827c478bd9Sstevel@tonic-gate freemsg(mp); 22837c478bd9Sstevel@tonic-gate return (NULL); 22847c478bd9Sstevel@tonic-gate } 22857c478bd9Sstevel@tonic-gate 2286c28749e9Skais /* 2287c28749e9Skais * Extra processing in case of an SSL proxy, before queuing or 2288c28749e9Skais * forwarding to the fallback endpoint 2289c28749e9Skais */ 2290c28749e9Skais case T_SSL_PROXY_CONN_IND: 22917c478bd9Sstevel@tonic-gate case T_CONN_IND: 22927c478bd9Sstevel@tonic-gate /* 22937c478bd9Sstevel@tonic-gate * Verify the min size and queue the message on 2294*0f1702c5SYu Xiangning * the sti_conn_ind_head/tail list. 22957c478bd9Sstevel@tonic-gate */ 22967c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_ind)) { 22972caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22987c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_IND. Len = %ld\n", 22997c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 23007c478bd9Sstevel@tonic-gate freemsg(mp); 23017c478bd9Sstevel@tonic-gate return (NULL); 23027c478bd9Sstevel@tonic-gate } 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate if (audit_active) 23057c478bd9Sstevel@tonic-gate audit_sock(T_CONN_IND, strvp2wq(vp), mp, 0); 23067c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ACCEPTCONN)) { 23072caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23087c478bd9Sstevel@tonic-gate "sockfs: T_conn_ind on non-listening socket\n"); 23097c478bd9Sstevel@tonic-gate freemsg(mp); 23107c478bd9Sstevel@tonic-gate return (NULL); 23117c478bd9Sstevel@tonic-gate } 2312c28749e9Skais 2313c28749e9Skais if (tpr->type == T_SSL_PROXY_CONN_IND && mp->b_cont == NULL) { 2314c28749e9Skais /* No context: need to fall back */ 2315c28749e9Skais struct sonode *fbso; 2316c28749e9Skais stdata_t *fbstp; 2317c28749e9Skais 2318c28749e9Skais tpr->type = T_CONN_IND; 2319c28749e9Skais 2320*0f1702c5SYu Xiangning fbso = kssl_find_fallback(sti->sti_kssl_ent); 2321c28749e9Skais 2322c28749e9Skais /* 2323c28749e9Skais * No fallback: the remote will timeout and 2324c28749e9Skais * disconnect. 2325c28749e9Skais */ 2326c28749e9Skais if (fbso == NULL) { 2327c28749e9Skais freemsg(mp); 2328c28749e9Skais return (NULL); 2329c28749e9Skais } 2330c28749e9Skais fbstp = SOTOV(fbso)->v_stream; 2331c28749e9Skais qreply(fbstp->sd_wrq->q_next, mp); 2332c28749e9Skais return (NULL); 2333c28749e9Skais } 23347c478bd9Sstevel@tonic-gate soqueueconnind(so, mp); 23357c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 23367c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 23377c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 23387c478bd9Sstevel@tonic-gate return (NULL); 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate case T_ORDREL_IND: 23417c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ordrel_ind)) { 23422caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23437c478bd9Sstevel@tonic-gate "sockfs: Too short T_ORDREL_IND. Len = %ld\n", 23447c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 23457c478bd9Sstevel@tonic-gate freemsg(mp); 23467c478bd9Sstevel@tonic-gate return (NULL); 23477c478bd9Sstevel@tonic-gate } 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate /* 23507c478bd9Sstevel@tonic-gate * Some providers send this when not fully connected. 23517c478bd9Sstevel@tonic-gate * SunLink X.25 needs to retrieve disconnect reason after 23527c478bd9Sstevel@tonic-gate * disconnect for compatibility. It uses T_ORDREL_IND 23537c478bd9Sstevel@tonic-gate * instead of T_DISCON_IND so that it may use the 23547c478bd9Sstevel@tonic-gate * endpoint after a connect failure to retrieve the 23557c478bd9Sstevel@tonic-gate * reason using an ioctl. Thus we explicitly clear 23567c478bd9Sstevel@tonic-gate * SS_ISCONNECTING here for SunLink X.25. 23577c478bd9Sstevel@tonic-gate * This is a needed TPI violation. 23587c478bd9Sstevel@tonic-gate */ 23597c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 23607c478bd9Sstevel@tonic-gate so->so_state &= ~SS_ISCONNECTING; 23617c478bd9Sstevel@tonic-gate socantrcvmore(so); 23627c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23637c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 23647c478bd9Sstevel@tonic-gate /* 23657c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 23667c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 23677c478bd9Sstevel@tonic-gate */ 23687c478bd9Sstevel@tonic-gate freemsg(mp); 23697c478bd9Sstevel@tonic-gate return (NULL); 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate case T_DISCON_IND: 23727c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_discon_ind)) { 23732caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23747c478bd9Sstevel@tonic-gate "sockfs: Too short T_DISCON_IND. Len = %ld\n", 23757c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 23767c478bd9Sstevel@tonic-gate freemsg(mp); 23777c478bd9Sstevel@tonic-gate return (NULL); 23787c478bd9Sstevel@tonic-gate } 23797c478bd9Sstevel@tonic-gate if (so->so_state & SS_ACCEPTCONN) { 23807c478bd9Sstevel@tonic-gate /* 23817c478bd9Sstevel@tonic-gate * This is a listener. Look for a queued T_CONN_IND 23827c478bd9Sstevel@tonic-gate * with a matching sequence number and remove it 23837c478bd9Sstevel@tonic-gate * from the list. 23847c478bd9Sstevel@tonic-gate * It is normal to not find the sequence number since 23857c478bd9Sstevel@tonic-gate * the soaccept might have already dequeued it 23867c478bd9Sstevel@tonic-gate * (in which case the T_CONN_RES will fail with 23877c478bd9Sstevel@tonic-gate * TBADSEQ). 23887c478bd9Sstevel@tonic-gate */ 23897c478bd9Sstevel@tonic-gate (void) soflushconnind(so, tpr->discon_ind.SEQ_number); 23907c478bd9Sstevel@tonic-gate freemsg(mp); 23917c478bd9Sstevel@tonic-gate return (0); 23927c478bd9Sstevel@tonic-gate } 23937c478bd9Sstevel@tonic-gate 23947c478bd9Sstevel@tonic-gate /* 23957c478bd9Sstevel@tonic-gate * Not a listener 23967c478bd9Sstevel@tonic-gate * 23977c478bd9Sstevel@tonic-gate * If SS_CANTRCVMORE for AF_UNIX ignore the discon_reason. 23987c478bd9Sstevel@tonic-gate * Such a discon_ind appears when the peer has first done 23997c478bd9Sstevel@tonic-gate * a shutdown() followed by a close() in which case we just 24007c478bd9Sstevel@tonic-gate * want to record socantsendmore. 24017c478bd9Sstevel@tonic-gate * In this case sockfs first receives a T_ORDREL_IND followed 24027c478bd9Sstevel@tonic-gate * by a T_DISCON_IND. 24037c478bd9Sstevel@tonic-gate * Note that for other transports (e.g. TCP) we need to handle 24047c478bd9Sstevel@tonic-gate * the discon_ind in this case since it signals an error. 24057c478bd9Sstevel@tonic-gate */ 24067c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 24077c478bd9Sstevel@tonic-gate if ((so->so_state & SS_CANTRCVMORE) && 24087c478bd9Sstevel@tonic-gate (so->so_family == AF_UNIX)) { 24097c478bd9Sstevel@tonic-gate socantsendmore(so); 2410*0f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 24117c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 24127c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 24137c478bd9Sstevel@tonic-gate dprintso(so, 1, 2414d3e55dcdSgww ("T_DISCON_IND: error %d\n", so->so_error)); 24157c478bd9Sstevel@tonic-gate freemsg(mp); 24167c478bd9Sstevel@tonic-gate /* 24177c478bd9Sstevel@tonic-gate * Set these variables for caller to process them. 24187c478bd9Sstevel@tonic-gate * For the else part where T_DISCON_IND is processed, 24197c478bd9Sstevel@tonic-gate * this will be done in the function being called 24207c478bd9Sstevel@tonic-gate * (strsock_discon_ind()) 24217c478bd9Sstevel@tonic-gate */ 24227c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 24237c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 24247c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 24257c478bd9Sstevel@tonic-gate } else if (so->so_flag & (SOASYNC_UNBIND | SOLOCKED)) { 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * Deferred processing of T_DISCON_IND 24287c478bd9Sstevel@tonic-gate */ 24297c478bd9Sstevel@tonic-gate so_save_discon_ind(so, mp, strsock_discon_ind); 24307c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 24317c478bd9Sstevel@tonic-gate } else { 24327c478bd9Sstevel@tonic-gate /* 24337c478bd9Sstevel@tonic-gate * Process T_DISCON_IND now 24347c478bd9Sstevel@tonic-gate */ 24357c478bd9Sstevel@tonic-gate (void) strsock_discon_ind(so, mp); 24367c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate return (NULL); 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate case T_UDERROR_IND: { 24417c478bd9Sstevel@tonic-gate struct T_uderror_ind *tudi = &tpr->uderror_ind; 24427c478bd9Sstevel@tonic-gate void *addr; 24437c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 24447c478bd9Sstevel@tonic-gate int error; 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate dprintso(so, 0, 2447d3e55dcdSgww ("T_UDERROR_IND: error %d\n", tudi->ERROR_type)); 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_uderror_ind)) { 24502caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 24517c478bd9Sstevel@tonic-gate "sockfs: Too short T_UDERROR_IND. Len = %ld\n", 24527c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 24537c478bd9Sstevel@tonic-gate freemsg(mp); 24547c478bd9Sstevel@tonic-gate return (NULL); 24557c478bd9Sstevel@tonic-gate } 24567c478bd9Sstevel@tonic-gate /* Ignore on connection-oriented transports */ 24577c478bd9Sstevel@tonic-gate if (so->so_mode & SM_CONNREQUIRED) { 24587c478bd9Sstevel@tonic-gate freemsg(mp); 24597c478bd9Sstevel@tonic-gate eprintsoline(so, 0); 24602caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 24617c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind on connection-oriented " 24627c478bd9Sstevel@tonic-gate "transport\n"); 24637c478bd9Sstevel@tonic-gate return (NULL); 24647c478bd9Sstevel@tonic-gate } 24657c478bd9Sstevel@tonic-gate addrlen = tudi->DEST_length; 24667c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->DEST_offset, addrlen, 1); 24677c478bd9Sstevel@tonic-gate if (addr == NULL) { 24682caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 24697c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind with invalid " 24707c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 24717c478bd9Sstevel@tonic-gate addrlen, tudi->DEST_offset); 24727c478bd9Sstevel@tonic-gate freemsg(mp); 24737c478bd9Sstevel@tonic-gate return (NULL); 24747c478bd9Sstevel@tonic-gate } 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate /* Verify source address for connected socket. */ 24777c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 24787c478bd9Sstevel@tonic-gate if (so->so_state & SS_ISCONNECTED) { 24797c478bd9Sstevel@tonic-gate void *faddr; 24807c478bd9Sstevel@tonic-gate t_uscalar_t faddr_len; 24817c478bd9Sstevel@tonic-gate boolean_t match = B_FALSE; 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate switch (so->so_family) { 24847c478bd9Sstevel@tonic-gate case AF_INET: { 24857c478bd9Sstevel@tonic-gate /* Compare just IP address and port */ 24867c478bd9Sstevel@tonic-gate struct sockaddr_in *sin1, *sin2; 24877c478bd9Sstevel@tonic-gate 2488*0f1702c5SYu Xiangning sin1 = (struct sockaddr_in *)sti->sti_faddr_sa; 24897c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in *)addr; 24907c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in) && 24917c478bd9Sstevel@tonic-gate sin1->sin_port == sin2->sin_port && 24927c478bd9Sstevel@tonic-gate sin1->sin_addr.s_addr == 24937c478bd9Sstevel@tonic-gate sin2->sin_addr.s_addr) 24947c478bd9Sstevel@tonic-gate match = B_TRUE; 24957c478bd9Sstevel@tonic-gate break; 24967c478bd9Sstevel@tonic-gate } 24977c478bd9Sstevel@tonic-gate case AF_INET6: { 24987c478bd9Sstevel@tonic-gate /* Compare just IP address and port. Not flow */ 24997c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin1, *sin2; 25007c478bd9Sstevel@tonic-gate 2501*0f1702c5SYu Xiangning sin1 = (struct sockaddr_in6 *)sti->sti_faddr_sa; 25027c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in6 *)addr; 25037c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in6) && 25047c478bd9Sstevel@tonic-gate sin1->sin6_port == sin2->sin6_port && 25057c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr, 2506d3e55dcdSgww &sin2->sin6_addr)) 25077c478bd9Sstevel@tonic-gate match = B_TRUE; 25087c478bd9Sstevel@tonic-gate break; 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate case AF_UNIX: 2511*0f1702c5SYu Xiangning faddr = &sti->sti_ux_faddr; 25127c478bd9Sstevel@tonic-gate faddr_len = 2513*0f1702c5SYu Xiangning (t_uscalar_t)sizeof (sti->sti_ux_faddr); 25147c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 25157c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 25167c478bd9Sstevel@tonic-gate match = B_TRUE; 25177c478bd9Sstevel@tonic-gate break; 25187c478bd9Sstevel@tonic-gate default: 2519*0f1702c5SYu Xiangning faddr = sti->sti_faddr_sa; 2520*0f1702c5SYu Xiangning faddr_len = (t_uscalar_t)sti->sti_faddr_len; 25217c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 25227c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 25237c478bd9Sstevel@tonic-gate match = B_TRUE; 25247c478bd9Sstevel@tonic-gate break; 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate if (!match) { 25287c478bd9Sstevel@tonic-gate #ifdef DEBUG 25297c478bd9Sstevel@tonic-gate dprintso(so, 0, 2530d3e55dcdSgww ("sockfs: T_UDERR_IND mismatch: %s - ", 2531d3e55dcdSgww pr_addr(so->so_family, 2532*0f1702c5SYu Xiangning (struct sockaddr *)addr, addrlen))); 25337c478bd9Sstevel@tonic-gate dprintso(so, 0, ("%s\n", 2534*0f1702c5SYu Xiangning pr_addr(so->so_family, sti->sti_faddr_sa, 2535*0f1702c5SYu Xiangning sti->sti_faddr_len))); 25367c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 25377c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25387c478bd9Sstevel@tonic-gate freemsg(mp); 25397c478bd9Sstevel@tonic-gate return (NULL); 25407c478bd9Sstevel@tonic-gate } 25417c478bd9Sstevel@tonic-gate /* 25427c478bd9Sstevel@tonic-gate * Make the write error nonpersistent. If the error 25437c478bd9Sstevel@tonic-gate * is zero we use ECONNRESET. 25447c478bd9Sstevel@tonic-gate * This assumes that the name space for ERROR_type 25457c478bd9Sstevel@tonic-gate * is the errno name space. 25467c478bd9Sstevel@tonic-gate */ 25477c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 25487c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 25497c478bd9Sstevel@tonic-gate else 25507c478bd9Sstevel@tonic-gate error = ECONNRESET; 25517c478bd9Sstevel@tonic-gate 25527c478bd9Sstevel@tonic-gate soseterror(so, error); 25537c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25547c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 25557c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 25567c478bd9Sstevel@tonic-gate *wakeups = RSLEEP | WSLEEP; 25577c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM | S_OUTPUT; 25587c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM | POLLOUT; 25597c478bd9Sstevel@tonic-gate freemsg(mp); 25607c478bd9Sstevel@tonic-gate return (NULL); 25617c478bd9Sstevel@tonic-gate } 25627c478bd9Sstevel@tonic-gate /* 25637c478bd9Sstevel@tonic-gate * If the application asked for delayed errors 2564*0f1702c5SYu Xiangning * record the T_UDERROR_IND sti_eaddr_mp and the reason in 2565*0f1702c5SYu Xiangning * sti_delayed_error for delayed error posting. If the reason 25667c478bd9Sstevel@tonic-gate * is zero use ECONNRESET. 25677c478bd9Sstevel@tonic-gate * Note that delayed error indications do not make sense for 25687c478bd9Sstevel@tonic-gate * AF_UNIX sockets since sendto checks that the destination 25697c478bd9Sstevel@tonic-gate * address is valid at the time of the sendto. 25707c478bd9Sstevel@tonic-gate */ 25717c478bd9Sstevel@tonic-gate if (!(so->so_options & SO_DGRAM_ERRIND)) { 25727c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25737c478bd9Sstevel@tonic-gate freemsg(mp); 25747c478bd9Sstevel@tonic-gate return (NULL); 25757c478bd9Sstevel@tonic-gate } 2576*0f1702c5SYu Xiangning if (sti->sti_eaddr_mp != NULL) 2577*0f1702c5SYu Xiangning freemsg(sti->sti_eaddr_mp); 25787c478bd9Sstevel@tonic-gate 2579*0f1702c5SYu Xiangning sti->sti_eaddr_mp = mp; 25807c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 25817c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 25827c478bd9Sstevel@tonic-gate else 25837c478bd9Sstevel@tonic-gate error = ECONNRESET; 2584*0f1702c5SYu Xiangning sti->sti_delayed_error = (ushort_t)error; 25857c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25867c478bd9Sstevel@tonic-gate return (NULL); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate case T_ERROR_ACK: 25907c478bd9Sstevel@tonic-gate dprintso(so, 0, 2591d3e55dcdSgww ("strsock_proto: T_ERROR_ACK for %d, error %d/%d\n", 2592d3e55dcdSgww tpr->error_ack.ERROR_prim, 2593d3e55dcdSgww tpr->error_ack.TLI_error, 2594d3e55dcdSgww tpr->error_ack.UNIX_error)); 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_error_ack)) { 25972caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25987c478bd9Sstevel@tonic-gate "sockfs: Too short T_ERROR_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 /* 26047c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 26057c478bd9Sstevel@tonic-gate */ 26067c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 26077c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 26087c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == T_UNBIND_REQ) { 26097c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 26107c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 26117c478bd9Sstevel@tonic-gate freemsg(mp); 26127c478bd9Sstevel@tonic-gate return (NULL); 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 26157c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26167c478bd9Sstevel@tonic-gate return (NULL); 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate case T_OK_ACK: 26197c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ok_ack)) { 26202caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26217c478bd9Sstevel@tonic-gate "sockfs: Too short T_OK_ACK. Len = %ld\n", 26227c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26237c478bd9Sstevel@tonic-gate freemsg(mp); 26247c478bd9Sstevel@tonic-gate return (NULL); 26257c478bd9Sstevel@tonic-gate } 26267c478bd9Sstevel@tonic-gate /* 26277c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 26287c478bd9Sstevel@tonic-gate */ 26297c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 26307c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 26317c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == T_UNBIND_REQ) { 26327c478bd9Sstevel@tonic-gate dprintso(so, 1, 2633d3e55dcdSgww ("strsock_proto: T_OK_ACK async unbind\n")); 26347c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 26357c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 26367c478bd9Sstevel@tonic-gate freemsg(mp); 26377c478bd9Sstevel@tonic-gate return (NULL); 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 26407c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26417c478bd9Sstevel@tonic-gate return (NULL); 26427c478bd9Sstevel@tonic-gate 26437c478bd9Sstevel@tonic-gate case T_INFO_ACK: 26447c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_info_ack)) { 26452caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26467c478bd9Sstevel@tonic-gate "sockfs: Too short T_INFO_ACK. Len = %ld\n", 26477c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26487c478bd9Sstevel@tonic-gate freemsg(mp); 26497c478bd9Sstevel@tonic-gate return (NULL); 26507c478bd9Sstevel@tonic-gate } 26517c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26527c478bd9Sstevel@tonic-gate return (NULL); 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate case T_CAPABILITY_ACK: 26557c478bd9Sstevel@tonic-gate /* 26567c478bd9Sstevel@tonic-gate * A T_capability_ack need only be large enough to hold 26577c478bd9Sstevel@tonic-gate * the PRIM_type and CAP_bits1 fields; checking for anything 26587c478bd9Sstevel@tonic-gate * larger might reject a correct response from an older 26597c478bd9Sstevel@tonic-gate * provider. 26607c478bd9Sstevel@tonic-gate */ 26617c478bd9Sstevel@tonic-gate if (MBLKL(mp) < 2 * sizeof (t_uscalar_t)) { 26622caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26637c478bd9Sstevel@tonic-gate "sockfs: Too short T_CAPABILITY_ACK. Len = %ld\n", 26647c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26657c478bd9Sstevel@tonic-gate freemsg(mp); 26667c478bd9Sstevel@tonic-gate return (NULL); 26677c478bd9Sstevel@tonic-gate } 26687c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26697c478bd9Sstevel@tonic-gate return (NULL); 26707c478bd9Sstevel@tonic-gate 26717c478bd9Sstevel@tonic-gate case T_BIND_ACK: 26727c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_bind_ack)) { 26732caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26747c478bd9Sstevel@tonic-gate "sockfs: Too short T_BIND_ACK. Len = %ld\n", 26757c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26767c478bd9Sstevel@tonic-gate freemsg(mp); 26777c478bd9Sstevel@tonic-gate return (NULL); 26787c478bd9Sstevel@tonic-gate } 26797c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26807c478bd9Sstevel@tonic-gate return (NULL); 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK: 26837c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optmgmt_ack)) { 26842caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26857c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTMGMT_ACK. Len = %ld\n", 26867c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26877c478bd9Sstevel@tonic-gate freemsg(mp); 26887c478bd9Sstevel@tonic-gate return (NULL); 26897c478bd9Sstevel@tonic-gate } 26907c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26917c478bd9Sstevel@tonic-gate return (NULL); 26927c478bd9Sstevel@tonic-gate default: 26937c478bd9Sstevel@tonic-gate #ifdef DEBUG 26942caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 2695d3e55dcdSgww "sockfs: unknown TPI primitive %d received\n", 2696d3e55dcdSgww tpr->type); 26977c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 26987c478bd9Sstevel@tonic-gate freemsg(mp); 26997c478bd9Sstevel@tonic-gate return (NULL); 27007c478bd9Sstevel@tonic-gate } 27017c478bd9Sstevel@tonic-gate } 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate /* 27047c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive other 27057c478bd9Sstevel@tonic-gate * (non-data, and non-proto) messages. 27067c478bd9Sstevel@tonic-gate * 27077c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 27087c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed by the stream head. 27097c478bd9Sstevel@tonic-gate * 27107c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 27117c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. 27127c478bd9Sstevel@tonic-gate */ 27137c478bd9Sstevel@tonic-gate static mblk_t * 27147c478bd9Sstevel@tonic-gate strsock_misc(vnode_t *vp, mblk_t *mp, 27157c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 27167c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 27177c478bd9Sstevel@tonic-gate { 27187c478bd9Sstevel@tonic-gate struct sonode *so; 2719*0f1702c5SYu Xiangning sotpi_info_t *sti; 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate so = VTOSO(vp); 2722*0f1702c5SYu Xiangning sti = SOTOTPI(so); 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_misc(%p, %p, 0x%x)\n", 2725903a11ebSrh (void *)vp, (void *)mp, DB_TYPE(mp))); 27267c478bd9Sstevel@tonic-gate 27277c478bd9Sstevel@tonic-gate /* Set default return values */ 27287c478bd9Sstevel@tonic-gate *wakeups = *allmsgsigs = *firstmsgsigs = *pollwakeups = 0; 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 27317c478bd9Sstevel@tonic-gate case M_PCSIG: 27327c478bd9Sstevel@tonic-gate /* 27337c478bd9Sstevel@tonic-gate * This assumes that an M_PCSIG for the urgent data arrives 27347c478bd9Sstevel@tonic-gate * before the corresponding T_EXDATA_IND. 27357c478bd9Sstevel@tonic-gate * 27367c478bd9Sstevel@tonic-gate * Note: Just like in SunOS 4.X and 4.4BSD a poll will be 27377c478bd9Sstevel@tonic-gate * awoken before the urgent data shows up. 27387c478bd9Sstevel@tonic-gate * For OOBINLINE this can result in select returning 27397c478bd9Sstevel@tonic-gate * only exceptions as opposed to except|read. 27407c478bd9Sstevel@tonic-gate */ 27417c478bd9Sstevel@tonic-gate if (*mp->b_rptr == SIGURG) { 27427c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 27437c478bd9Sstevel@tonic-gate dprintso(so, 1, 2744d3e55dcdSgww ("SIGURG(%p): counts %d/%d state %s\n", 2745*0f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt, 2746d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 27477c478bd9Sstevel@tonic-gate so_oob_sig(so, 1, allmsgsigs, pollwakeups); 27487c478bd9Sstevel@tonic-gate dprintso(so, 1, 2749d3e55dcdSgww ("after SIGURG(%p): counts %d/%d " 2750d3e55dcdSgww " poll 0x%x sig 0x%x state %s\n", 2751*0f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt, 2752*0f1702c5SYu Xiangning *pollwakeups, *allmsgsigs, 2753d3e55dcdSgww pr_state(so->so_state, so->so_mode))); 27547c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 27557c478bd9Sstevel@tonic-gate } 27567c478bd9Sstevel@tonic-gate freemsg(mp); 27577c478bd9Sstevel@tonic-gate return (NULL); 27587c478bd9Sstevel@tonic-gate 27597c478bd9Sstevel@tonic-gate case M_SIG: 27607c478bd9Sstevel@tonic-gate case M_HANGUP: 27617c478bd9Sstevel@tonic-gate case M_UNHANGUP: 27627c478bd9Sstevel@tonic-gate case M_ERROR: 27637c478bd9Sstevel@tonic-gate /* M_ERRORs etc are ignored */ 27647c478bd9Sstevel@tonic-gate freemsg(mp); 27657c478bd9Sstevel@tonic-gate return (NULL); 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate case M_FLUSH: 27687c478bd9Sstevel@tonic-gate /* 27697c478bd9Sstevel@tonic-gate * Do not flush read queue. If the M_FLUSH 27707c478bd9Sstevel@tonic-gate * arrives because of an impending T_discon_ind 27717c478bd9Sstevel@tonic-gate * we still have to keep any queued data - this is part of 27727c478bd9Sstevel@tonic-gate * socket semantics. 27737c478bd9Sstevel@tonic-gate */ 27747c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 27757c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHR; 27767c478bd9Sstevel@tonic-gate return (mp); 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate freemsg(mp); 27797c478bd9Sstevel@tonic-gate return (NULL); 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate default: 27827c478bd9Sstevel@tonic-gate return (mp); 27837c478bd9Sstevel@tonic-gate } 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate /* Register to receive signals for certain events */ 27887c478bd9Sstevel@tonic-gate int 27897c478bd9Sstevel@tonic-gate so_set_asyncsigs(vnode_t *vp, pid_t pgrp, int events, int mode, cred_t *cr) 27907c478bd9Sstevel@tonic-gate { 27917c478bd9Sstevel@tonic-gate struct strsigset ss; 27927c478bd9Sstevel@tonic-gate int32_t rval; 27937c478bd9Sstevel@tonic-gate 27947c478bd9Sstevel@tonic-gate /* 27957c478bd9Sstevel@tonic-gate * Note that SOLOCKED will be set except for the call from soaccept(). 27967c478bd9Sstevel@tonic-gate */ 27977c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&VTOSO(vp)->so_lock)); 27987c478bd9Sstevel@tonic-gate ss.ss_pid = pgrp; 27997c478bd9Sstevel@tonic-gate ss.ss_events = events; 28007c478bd9Sstevel@tonic-gate return (strioctl(vp, I_ESETSIG, (intptr_t)&ss, mode, K_TO_K, cr, 28017c478bd9Sstevel@tonic-gate &rval)); 28027c478bd9Sstevel@tonic-gate } 28037c478bd9Sstevel@tonic-gate 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate /* Register for events matching the SS_ASYNC flag */ 28067c478bd9Sstevel@tonic-gate int 28077c478bd9Sstevel@tonic-gate so_set_events(struct sonode *so, vnode_t *vp, cred_t *cr) 28087c478bd9Sstevel@tonic-gate { 28097c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 28107c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 28117c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 28127c478bd9Sstevel@tonic-gate 28137c478bd9Sstevel@tonic-gate return (so_set_asyncsigs(vp, so->so_pgrp, events, 0, cr)); 28147c478bd9Sstevel@tonic-gate } 28157c478bd9Sstevel@tonic-gate 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate /* Change the SS_ASYNC flag, and update signal delivery if needed */ 28187c478bd9Sstevel@tonic-gate int 28197c478bd9Sstevel@tonic-gate so_flip_async(struct sonode *so, vnode_t *vp, int mode, cred_t *cr) 28207c478bd9Sstevel@tonic-gate { 28217c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 28227c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 28237c478bd9Sstevel@tonic-gate int error; 28247c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? /* Old flag */ 28257c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG : /* New sigs */ 28267c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT; 28277c478bd9Sstevel@tonic-gate 28287c478bd9Sstevel@tonic-gate so_lock_single(so); 28297c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, events, mode, cr); 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 28347c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 28357c478bd9Sstevel@tonic-gate if (error) 28367c478bd9Sstevel@tonic-gate return (error); 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate so->so_state ^= SS_ASYNC; 28397c478bd9Sstevel@tonic-gate return (0); 28407c478bd9Sstevel@tonic-gate } 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate /* 28437c478bd9Sstevel@tonic-gate * Set new pid/pgrp for SIGPOLL (or SIGIO for FIOASYNC mode), replacing 28447c478bd9Sstevel@tonic-gate * any existing one. If passed zero, just clear the existing one. 28457c478bd9Sstevel@tonic-gate */ 28467c478bd9Sstevel@tonic-gate int 28477c478bd9Sstevel@tonic-gate so_set_siggrp(struct sonode *so, vnode_t *vp, pid_t pgrp, int mode, cred_t *cr) 28487c478bd9Sstevel@tonic-gate { 28497c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 28507c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 28517c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 28527c478bd9Sstevel@tonic-gate int error; 28537c478bd9Sstevel@tonic-gate 28547c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate /* 28577c478bd9Sstevel@tonic-gate * Change socket process (group). 28587c478bd9Sstevel@tonic-gate * 28597c478bd9Sstevel@tonic-gate * strioctl (via so_set_asyncsigs) will perform permission check and 28607c478bd9Sstevel@tonic-gate * also keep a PID_HOLD to prevent the pid from being reused. 28617c478bd9Sstevel@tonic-gate */ 28627c478bd9Sstevel@tonic-gate so_lock_single(so); 28637c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 28647c478bd9Sstevel@tonic-gate 28657c478bd9Sstevel@tonic-gate if (pgrp != 0) { 28667c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: adding pgrp %d ev 0x%x\n", 28677c478bd9Sstevel@tonic-gate pgrp, events)); 28687c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, pgrp, events, mode, cr); 28697c478bd9Sstevel@tonic-gate if (error != 0) { 28707c478bd9Sstevel@tonic-gate eprintsoline(so, error); 28717c478bd9Sstevel@tonic-gate goto bad; 28727c478bd9Sstevel@tonic-gate } 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate /* Remove the previously registered process/group */ 28757c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 28767c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: removing pgrp %d\n", so->so_pgrp)); 28777c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, 0, mode, cr); 28787c478bd9Sstevel@tonic-gate if (error != 0) { 28797c478bd9Sstevel@tonic-gate eprintsoline(so, error); 28807c478bd9Sstevel@tonic-gate error = 0; 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate } 28837c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 28847c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 28857c478bd9Sstevel@tonic-gate so->so_pgrp = pgrp; 28867c478bd9Sstevel@tonic-gate return (0); 28877c478bd9Sstevel@tonic-gate bad: 28887c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 28897c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 28907c478bd9Sstevel@tonic-gate return (error); 28917c478bd9Sstevel@tonic-gate } 28927c478bd9Sstevel@tonic-gate 2893*0f1702c5SYu Xiangning /* 2894*0f1702c5SYu Xiangning * Wrapper for getmsg. If the socket has been converted to a stream 2895*0f1702c5SYu Xiangning * pass the request to the stream head. 2896*0f1702c5SYu Xiangning */ 2897*0f1702c5SYu Xiangning int 2898*0f1702c5SYu Xiangning sock_getmsg( 2899*0f1702c5SYu Xiangning struct vnode *vp, 2900*0f1702c5SYu Xiangning struct strbuf *mctl, 2901*0f1702c5SYu Xiangning struct strbuf *mdata, 2902*0f1702c5SYu Xiangning uchar_t *prip, 2903*0f1702c5SYu Xiangning int *flagsp, 2904*0f1702c5SYu Xiangning int fmode, 2905*0f1702c5SYu Xiangning rval_t *rvp 2906*0f1702c5SYu Xiangning ) 2907*0f1702c5SYu Xiangning { 2908*0f1702c5SYu Xiangning struct sonode *so; 2909*0f1702c5SYu Xiangning 2910*0f1702c5SYu Xiangning ASSERT(vp->v_type == VSOCK); 2911*0f1702c5SYu Xiangning /* 2912*0f1702c5SYu Xiangning * Use the stream head to find the real socket vnode. 2913*0f1702c5SYu Xiangning * This is needed when namefs sits above sockfs. Some 2914*0f1702c5SYu Xiangning * sockets (like SCTP) are not streams. 2915*0f1702c5SYu Xiangning */ 2916*0f1702c5SYu Xiangning if (!vp->v_stream) { 2917*0f1702c5SYu Xiangning return (ENOSTR); 2918*0f1702c5SYu Xiangning } 2919*0f1702c5SYu Xiangning ASSERT(vp->v_stream->sd_vnode); 2920*0f1702c5SYu Xiangning vp = vp->v_stream->sd_vnode; 2921*0f1702c5SYu Xiangning ASSERT(vn_matchops(vp, socket_vnodeops)); 2922*0f1702c5SYu Xiangning so = VTOSO(vp); 29237c478bd9Sstevel@tonic-gate 2924*0f1702c5SYu Xiangning dprintso(so, 1, ("sock_getmsg(%p) %s\n", 2925*0f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode))); 2926*0f1702c5SYu Xiangning 2927*0f1702c5SYu Xiangning if (so->so_version == SOV_STREAM) { 2928*0f1702c5SYu Xiangning /* The imaginary "sockmod" has been popped - act as a stream */ 2929*0f1702c5SYu Xiangning return (strgetmsg(vp, mctl, mdata, prip, flagsp, fmode, rvp)); 2930*0f1702c5SYu Xiangning } 2931*0f1702c5SYu Xiangning eprintsoline(so, ENOSTR); 2932*0f1702c5SYu Xiangning return (ENOSTR); 2933*0f1702c5SYu Xiangning } 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate /* 2936*0f1702c5SYu Xiangning * Wrapper for putmsg. If the socket has been converted to a stream 2937*0f1702c5SYu Xiangning * pass the request to the stream head. 2938*0f1702c5SYu Xiangning * 2939*0f1702c5SYu Xiangning * Note that a while a regular socket (SOV_SOCKSTREAM) does support the 2940*0f1702c5SYu Xiangning * streams ioctl set it does not support putmsg and getmsg. 2941*0f1702c5SYu Xiangning * Allowing putmsg would prevent sockfs from tracking the state of 2942*0f1702c5SYu Xiangning * the socket/transport and would also invalidate the locking in sockfs. 29437c478bd9Sstevel@tonic-gate */ 2944*0f1702c5SYu Xiangning int 2945*0f1702c5SYu Xiangning sock_putmsg( 2946*0f1702c5SYu Xiangning struct vnode *vp, 2947*0f1702c5SYu Xiangning struct strbuf *mctl, 2948*0f1702c5SYu Xiangning struct strbuf *mdata, 2949*0f1702c5SYu Xiangning uchar_t pri, 2950*0f1702c5SYu Xiangning int flag, 2951*0f1702c5SYu Xiangning int fmode 2952*0f1702c5SYu Xiangning ) 2953*0f1702c5SYu Xiangning { 2954*0f1702c5SYu Xiangning struct sonode *so; 29557c478bd9Sstevel@tonic-gate 2956*0f1702c5SYu Xiangning ASSERT(vp->v_type == VSOCK); 2957*0f1702c5SYu Xiangning /* 2958*0f1702c5SYu Xiangning * Use the stream head to find the real socket vnode. 2959*0f1702c5SYu Xiangning * This is needed when namefs sits above sockfs. 2960*0f1702c5SYu Xiangning */ 2961*0f1702c5SYu Xiangning if (!vp->v_stream) { 2962*0f1702c5SYu Xiangning return (ENOSTR); 2963*0f1702c5SYu Xiangning } 2964*0f1702c5SYu Xiangning ASSERT(vp->v_stream->sd_vnode); 2965*0f1702c5SYu Xiangning vp = vp->v_stream->sd_vnode; 2966*0f1702c5SYu Xiangning ASSERT(vn_matchops(vp, socket_vnodeops)); 2967*0f1702c5SYu Xiangning so = VTOSO(vp); 2968*0f1702c5SYu Xiangning 2969*0f1702c5SYu Xiangning dprintso(so, 1, ("sock_putmsg(%p) %s\n", 2970*0f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode))); 2971*0f1702c5SYu Xiangning 2972*0f1702c5SYu Xiangning if (so->so_version == SOV_STREAM) { 2973*0f1702c5SYu Xiangning /* The imaginary "sockmod" has been popped - act as a stream */ 2974*0f1702c5SYu Xiangning return (strputmsg(vp, mctl, mdata, pri, flag, fmode)); 2975*0f1702c5SYu Xiangning } 2976*0f1702c5SYu Xiangning eprintsoline(so, ENOSTR); 2977*0f1702c5SYu Xiangning return (ENOSTR); 2978*0f1702c5SYu Xiangning } 2979*0f1702c5SYu Xiangning 2980*0f1702c5SYu Xiangning /* 2981*0f1702c5SYu Xiangning * Special function called only from f_getfl(). 2982*0f1702c5SYu Xiangning * Returns FASYNC if the SS_ASYNC flag is set on a socket, else 0. 2983*0f1702c5SYu Xiangning * No locks are acquired here, so it is safe to use while uf_lock is held. 2984*0f1702c5SYu Xiangning * This exists solely for BSD fcntl() FASYNC compatibility. 2985*0f1702c5SYu Xiangning */ 2986*0f1702c5SYu Xiangning int 2987*0f1702c5SYu Xiangning sock_getfasync(vnode_t *vp) 29887c478bd9Sstevel@tonic-gate { 2989*0f1702c5SYu Xiangning struct sonode *so; 2990*0f1702c5SYu Xiangning 2991*0f1702c5SYu Xiangning ASSERT(vp->v_type == VSOCK); 2992*0f1702c5SYu Xiangning /* 2993*0f1702c5SYu Xiangning * For stream model, v_stream is used; For non-stream, v_stream always 2994*0f1702c5SYu Xiangning * equals NULL 2995*0f1702c5SYu Xiangning */ 2996*0f1702c5SYu Xiangning if (vp->v_stream != NULL) 2997*0f1702c5SYu Xiangning so = VTOSO(vp->v_stream->sd_vnode); 29987c478bd9Sstevel@tonic-gate else 2999*0f1702c5SYu Xiangning so = VTOSO(vp); 3000*0f1702c5SYu Xiangning 3001*0f1702c5SYu Xiangning if (so->so_version == SOV_STREAM || !(so->so_state & SS_ASYNC)) 3002*0f1702c5SYu Xiangning return (0); 3003*0f1702c5SYu Xiangning 3004*0f1702c5SYu Xiangning return (FASYNC); 30057c478bd9Sstevel@tonic-gate } 300617169044Sbrutus 300717169044Sbrutus /* 300817169044Sbrutus * Sockfs sodirect STREAMS read put procedure. Called from sodirect enable 300917169044Sbrutus * transport driver/module with an mblk_t chain. 301017169044Sbrutus * 301117169044Sbrutus * Note, we in-line putq() for the fast-path cases of q is empty, q_last and 301217169044Sbrutus * bp are of type M_DATA. All other cases we call putq(). 301317169044Sbrutus * 301417169044Sbrutus * On success a zero will be return, else an errno will be returned. 301517169044Sbrutus */ 301617169044Sbrutus int 301717169044Sbrutus sodput(sodirect_t *sodp, mblk_t *bp) 301817169044Sbrutus { 301917169044Sbrutus queue_t *q = sodp->sod_q; 302017169044Sbrutus struct stdata *stp = (struct stdata *)q->q_ptr; 302117169044Sbrutus mblk_t *nbp; 302217169044Sbrutus mblk_t *last = q->q_last; 302317169044Sbrutus int bytecnt = 0; 302417169044Sbrutus int mblkcnt = 0; 302517169044Sbrutus 302617169044Sbrutus 302796e0e3daSYu Xiangning ASSERT(MUTEX_HELD(sodp->sod_lockp)); 302817169044Sbrutus 302917169044Sbrutus if (stp->sd_flag == STREOF) { 303096e0e3daSYu Xiangning do { 303196e0e3daSYu Xiangning if ((nbp = bp->b_next) != NULL) 303296e0e3daSYu Xiangning bp->b_next = NULL; 303396e0e3daSYu Xiangning freemsg(bp); 303496e0e3daSYu Xiangning } while ((bp = nbp) != NULL); 303596e0e3daSYu Xiangning 303696e0e3daSYu Xiangning return (0); 303717169044Sbrutus } 303817169044Sbrutus 303996e0e3daSYu Xiangning mutex_enter(QLOCK(q)); 304017169044Sbrutus if (q->q_first == NULL) { 304117169044Sbrutus /* Q empty, really fast fast-path */ 304217169044Sbrutus bp->b_prev = NULL; 304317169044Sbrutus bp->b_next = NULL; 304417169044Sbrutus q->q_first = bp; 304517169044Sbrutus q->q_last = bp; 304617169044Sbrutus 304717169044Sbrutus } else if (last->b_datap->db_type == M_DATA && 304817169044Sbrutus bp->b_datap->db_type == M_DATA) { 304917169044Sbrutus /* 305017169044Sbrutus * Last mblk_t chain and bp are both type M_DATA so 305117169044Sbrutus * in-line putq() here, if the DBLK_UIOA state match 305217169044Sbrutus * add bp to the end of the current last chain, else 305317169044Sbrutus * start a new last chain with bp. 305417169044Sbrutus */ 305517169044Sbrutus if ((last->b_datap->db_flags & DBLK_UIOA) == 305617169044Sbrutus (bp->b_datap->db_flags & DBLK_UIOA)) { 305717169044Sbrutus /* Added to end */ 305817169044Sbrutus while ((nbp = last->b_cont) != NULL) 305917169044Sbrutus last = nbp; 306017169044Sbrutus last->b_cont = bp; 306117169044Sbrutus } else { 306217169044Sbrutus /* New last */ 306396e0e3daSYu Xiangning ASSERT((bp->b_datap->db_flags & DBLK_UIOA) == 0 || 306496e0e3daSYu Xiangning msgdsize(bp) == sodp->sod_uioa.uioa_mbytes); 306517169044Sbrutus last->b_next = bp; 306617169044Sbrutus bp->b_next = NULL; 306717169044Sbrutus bp->b_prev = last; 306817169044Sbrutus q->q_last = bp; 306917169044Sbrutus } 307017169044Sbrutus } else { 307117169044Sbrutus /* 307217169044Sbrutus * Can't use q_last so just call putq(). 307317169044Sbrutus */ 307496e0e3daSYu Xiangning mutex_exit(QLOCK(q)); 307596e0e3daSYu Xiangning 307696e0e3daSYu Xiangning ASSERT((bp->b_datap->db_flags & DBLK_UIOA) == 0 || 307796e0e3daSYu Xiangning msgdsize(bp) == sodp->sod_uioa.uioa_mbytes); 307817169044Sbrutus (void) putq(q, bp); 307917169044Sbrutus return (0); 308017169044Sbrutus } 308117169044Sbrutus 308217169044Sbrutus /* Count bytes and mblk_t's */ 308317169044Sbrutus do { 308417169044Sbrutus bytecnt += MBLKL(bp); 308517169044Sbrutus mblkcnt++; 308617169044Sbrutus } while ((bp = bp->b_cont) != NULL); 308717169044Sbrutus q->q_count += bytecnt; 308817169044Sbrutus q->q_mblkcnt += mblkcnt; 308917169044Sbrutus 309017169044Sbrutus /* Check for QFULL */ 309117169044Sbrutus if (q->q_count >= q->q_hiwat + sodp->sod_want || 309217169044Sbrutus q->q_mblkcnt >= q->q_hiwat) { 309317169044Sbrutus q->q_flag |= QFULL; 309417169044Sbrutus } 309517169044Sbrutus 309696e0e3daSYu Xiangning mutex_exit(QLOCK(q)); 309717169044Sbrutus return (0); 309817169044Sbrutus } 309917169044Sbrutus 310017169044Sbrutus /* 310117169044Sbrutus * Sockfs sodirect read wakeup. Called from a sodirect enabled transport 310217169044Sbrutus * driver/module to indicate that read-side data is available. 310317169044Sbrutus * 310417169044Sbrutus * On return the sodirect_t.lock mutex will be exited so this must be the 310517169044Sbrutus * last sodirect_t call to guarantee atomic access of *sodp. 310617169044Sbrutus */ 310717169044Sbrutus void 310817169044Sbrutus sodwakeup(sodirect_t *sodp) 310917169044Sbrutus { 311017169044Sbrutus queue_t *q = sodp->sod_q; 311117169044Sbrutus struct stdata *stp = (struct stdata *)q->q_ptr; 311217169044Sbrutus 311396e0e3daSYu Xiangning ASSERT(MUTEX_HELD(sodp->sod_lockp)); 311417169044Sbrutus 311517169044Sbrutus if (stp->sd_flag & RSLEEP) { 311617169044Sbrutus stp->sd_flag &= ~RSLEEP; 311717169044Sbrutus cv_broadcast(&q->q_wait); 311817169044Sbrutus } 311917169044Sbrutus 312017169044Sbrutus if (stp->sd_rput_opt & SR_POLLIN) { 312117169044Sbrutus stp->sd_rput_opt &= ~SR_POLLIN; 312296e0e3daSYu Xiangning mutex_exit(sodp->sod_lockp); 312317169044Sbrutus pollwakeup(&stp->sd_pollist, POLLIN | POLLRDNORM); 312417169044Sbrutus } else 312596e0e3daSYu Xiangning mutex_exit(sodp->sod_lockp); 312617169044Sbrutus } 3127