17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52caf0dcdSrshoaib * Common Development and Distribution License (the "License"). 62caf0dcdSrshoaib * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 212caf0dcdSrshoaib 227c478bd9Sstevel@tonic-gate /* 23*dd49f125SAnders Persson * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 287c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <sys/buf.h> 327c478bd9Sstevel@tonic-gate #include <sys/conf.h> 337c478bd9Sstevel@tonic-gate #include <sys/cred.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 367c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 377c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 387c478bd9Sstevel@tonic-gate #include <sys/debug.h> 397c478bd9Sstevel@tonic-gate #include <sys/errno.h> 407c478bd9Sstevel@tonic-gate #include <sys/time.h> 417c478bd9Sstevel@tonic-gate #include <sys/file.h> 427c478bd9Sstevel@tonic-gate #include <sys/user.h> 437c478bd9Sstevel@tonic-gate #include <sys/stream.h> 447c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 457c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 467c478bd9Sstevel@tonic-gate #include <sys/flock.h> 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 497c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 517c478bd9Sstevel@tonic-gate #include <sys/proc.h> 527c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 557c478bd9Sstevel@tonic-gate #include <sys/socket.h> 567c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 577c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 587c478bd9Sstevel@tonic-gate #include <netinet/in.h> 590f1702c5SYu Xiangning #include <inet/common.h> 600f1702c5SYu Xiangning #include <inet/proto_set.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 637c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 647c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #include <c2/audit.h> 677c478bd9Sstevel@tonic-gate 680f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h> 690f1702c5SYu Xiangning #include <fs/sockfs/socktpi_impl.h> 7017169044Sbrutus 717c478bd9Sstevel@tonic-gate int so_default_version = SOV_SOCKSTREAM; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #ifdef DEBUG 747c478bd9Sstevel@tonic-gate /* Set sockdebug to print debug messages when SO_DEBUG is set */ 757c478bd9Sstevel@tonic-gate int sockdebug = 0; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* Set sockprinterr to print error messages when SO_DEBUG is set */ 787c478bd9Sstevel@tonic-gate int sockprinterr = 0; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * Set so_default_options to SO_DEBUG is all sockets should be created 827c478bd9Sstevel@tonic-gate * with SO_DEBUG set. This is needed to get debug printouts from the 837c478bd9Sstevel@tonic-gate * socket() call itself. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate int so_default_options = 0; 867c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * Set to number of ticks to limit cv_waits for code coverage testing. 917c478bd9Sstevel@tonic-gate * Set to 1000 when SO_DEBUG is set to 2. 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate clock_t sock_test_timelimit = 0; 947c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * For concurrency testing of e.g. opening /dev/ip which does not 987c478bd9Sstevel@tonic-gate * handle T_INFO_REQ messages. 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate int so_no_tinfo = 0; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Timeout for getting a T_CAPABILITY_ACK - it is possible for a provider 1047c478bd9Sstevel@tonic-gate * to simply ignore the T_CAPABILITY_REQ. 1057c478bd9Sstevel@tonic-gate */ 1067c478bd9Sstevel@tonic-gate clock_t sock_capability_timeout = 2; /* seconds */ 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static int do_tcapability(struct sonode *so, t_uscalar_t cap_bits1); 1097c478bd9Sstevel@tonic-gate static void so_removehooks(struct sonode *so); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate static mblk_t *strsock_proto(vnode_t *vp, mblk_t *mp, 1127c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 1137c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 1147c478bd9Sstevel@tonic-gate static mblk_t *strsock_misc(vnode_t *vp, mblk_t *mp, 1157c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 1167c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups); 11717169044Sbrutus 11817169044Sbrutus /* 1197c478bd9Sstevel@tonic-gate * Convert a socket to a stream. Invoked when the illusory sockmod 1207c478bd9Sstevel@tonic-gate * is popped from the stream. 1217c478bd9Sstevel@tonic-gate * Change the stream head back to default operation without losing 1227c478bd9Sstevel@tonic-gate * any messages (T_conn_ind's are moved to the stream head queue). 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate int 1257c478bd9Sstevel@tonic-gate so_sock2stream(struct sonode *so) 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 1287c478bd9Sstevel@tonic-gate queue_t *rq; 1297c478bd9Sstevel@tonic-gate mblk_t *mp; 1307c478bd9Sstevel@tonic-gate int error = 0; 1310f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 1327c478bd9Sstevel@tonic-gate 1330f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&sti->sti_plumb_lock)); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1367c478bd9Sstevel@tonic-gate so_lock_single(so); 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate ASSERT(so->so_version != SOV_STREAM); 1397c478bd9Sstevel@tonic-gate 1400f1702c5SYu Xiangning if (sti->sti_direct) { 1417c478bd9Sstevel@tonic-gate mblk_t **mpp; 142ff550d0eSmasputra int rval; 1437c478bd9Sstevel@tonic-gate 144ff550d0eSmasputra /* 145ff550d0eSmasputra * Tell the transport below that sockmod is being popped 146ff550d0eSmasputra */ 1477c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 148ff550d0eSmasputra error = strioctl(vp, _SIOCSOCKFALLBACK, 0, 0, K_TO_K, CRED(), 1497c478bd9Sstevel@tonic-gate &rval); 1507c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 1517c478bd9Sstevel@tonic-gate if (error != 0) { 152ff550d0eSmasputra dprintso(so, 0, ("so_sock2stream(%p): " 153903a11ebSrh87107 "_SIOCSOCKFALLBACK failed\n", (void *)so)); 1547c478bd9Sstevel@tonic-gate goto exit; 1557c478bd9Sstevel@tonic-gate } 1560f1702c5SYu Xiangning sti->sti_direct = 0; 1577c478bd9Sstevel@tonic-gate 1580f1702c5SYu Xiangning for (mpp = &sti->sti_conn_ind_head; (mp = *mpp) != NULL; 1597c478bd9Sstevel@tonic-gate mpp = &mp->b_next) { 1607c478bd9Sstevel@tonic-gate struct T_conn_ind *conn_ind; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * strsock_proto() has already verified the length of 1647c478bd9Sstevel@tonic-gate * this message block. 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct T_conn_ind)); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 1697c478bd9Sstevel@tonic-gate if (conn_ind->OPT_length == 0 && 1707c478bd9Sstevel@tonic-gate conn_ind->OPT_offset == 0) 1717c478bd9Sstevel@tonic-gate continue; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate if (DB_REF(mp) > 1) { 1747c478bd9Sstevel@tonic-gate mblk_t *newmp; 1757c478bd9Sstevel@tonic-gate size_t length; 1767c478bd9Sstevel@tonic-gate cred_t *cr; 177de8c4a14SErik Nordmark pid_t cpid; 178de8c4a14SErik Nordmark int error; /* Dummy - error not returned */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * Copy the message block because it is used 1827c478bd9Sstevel@tonic-gate * elsewhere, too. 183de8c4a14SErik Nordmark * Can't use copyb since we want to wait 184de8c4a14SErik Nordmark * yet allow for EINTR. 1857c478bd9Sstevel@tonic-gate */ 186de8c4a14SErik Nordmark /* Round up size for reuse */ 187de8c4a14SErik Nordmark length = MAX(MBLKL(mp), 64); 188de8c4a14SErik Nordmark cr = msg_getcred(mp, &cpid); 189de8c4a14SErik Nordmark if (cr != NULL) { 190de8c4a14SErik Nordmark newmp = allocb_cred_wait(length, 0, 191de8c4a14SErik Nordmark &error, cr, cpid); 192de8c4a14SErik Nordmark } else { 193de8c4a14SErik Nordmark newmp = allocb_wait(length, 0, 0, 194de8c4a14SErik Nordmark &error); 195de8c4a14SErik Nordmark } 1967c478bd9Sstevel@tonic-gate if (newmp == NULL) { 1977c478bd9Sstevel@tonic-gate error = EINTR; 1987c478bd9Sstevel@tonic-gate goto exit; 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, newmp->b_wptr, length); 2017c478bd9Sstevel@tonic-gate newmp->b_wptr += length; 2027c478bd9Sstevel@tonic-gate newmp->b_next = mp->b_next; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate /* 2057c478bd9Sstevel@tonic-gate * Link the new message block into the queue 2067c478bd9Sstevel@tonic-gate * and free the old one. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate *mpp = newmp; 2097c478bd9Sstevel@tonic-gate mp->b_next = NULL; 2107c478bd9Sstevel@tonic-gate freemsg(mp); 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate mp = newmp; 2137c478bd9Sstevel@tonic-gate conn_ind = (struct T_conn_ind *)mp->b_rptr; 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * Remove options added by TCP for accept fast-path. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate conn_ind->OPT_length = 0; 2207c478bd9Sstevel@tonic-gate conn_ind->OPT_offset = 0; 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate so->so_version = SOV_STREAM; 2250f1702c5SYu Xiangning so->so_proto_handle = NULL; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head to avoid queuing more 2297c478bd9Sstevel@tonic-gate * packets in sockfs. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2327c478bd9Sstevel@tonic-gate so_removehooks(so); 2337c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Clear any state related to urgent data. Leave any T_EXDATA_IND 2377c478bd9Sstevel@tonic-gate * on the queue - the behavior of urgent data after a switch is 2387c478bd9Sstevel@tonic-gate * left undefined. 2397c478bd9Sstevel@tonic-gate */ 2400f1702c5SYu Xiangning so->so_error = sti->sti_delayed_error = 0; 2417c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 2427c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 2430f1702c5SYu Xiangning sti->sti_oobsigcnt = sti->sti_oobcnt = 0; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_RCVATMARK|SS_OOBPEND|SS_HAVEOOBDATA|SS_HADOOBDATA| 2460f1702c5SYu Xiangning SS_SAVEDEOR); 2477c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 2487c478bd9Sstevel@tonic-gate 2490f1702c5SYu Xiangning freemsg(sti->sti_ack_mp); 2500f1702c5SYu Xiangning sti->sti_ack_mp = NULL; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2530f1702c5SYu Xiangning * Flush the T_DISCON_IND on sti_discon_ind_mp. 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * Move any queued T_CONN_IND messages to stream head queue. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate rq = RD(strvp2wq(vp)); 2610f1702c5SYu Xiangning while ((mp = sti->sti_conn_ind_head) != NULL) { 2620f1702c5SYu Xiangning sti->sti_conn_ind_head = mp->b_next; 2637c478bd9Sstevel@tonic-gate mp->b_next = NULL; 2640f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 2650f1702c5SYu Xiangning ASSERT(sti->sti_conn_ind_tail == mp); 2660f1702c5SYu Xiangning sti->sti_conn_ind_tail = NULL; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate dprintso(so, 0, 2690f1702c5SYu Xiangning ("so_sock2stream(%p): moving T_CONN_IND\n", (void *)so)); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* Drop lock across put() */ 2727c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2737c478bd9Sstevel@tonic-gate put(rq, mp); 2747c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate exit: 2787c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 2797c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 2807c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 2817c478bd9Sstevel@tonic-gate return (error); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * Covert a stream back to a socket. This is invoked when the illusory 2867c478bd9Sstevel@tonic-gate * sockmod is pushed on a stream (where the stream was "created" by 2877c478bd9Sstevel@tonic-gate * popping the illusory sockmod). 2887c478bd9Sstevel@tonic-gate * This routine can not recreate the socket state (certain aspects of 2897c478bd9Sstevel@tonic-gate * it like urgent data state and the bound/connected addresses for AF_UNIX 2907c478bd9Sstevel@tonic-gate * sockets can not be recreated by asking the transport for information). 2917c478bd9Sstevel@tonic-gate * Thus this routine implicitly assumes that the socket is in an initial 2927c478bd9Sstevel@tonic-gate * state (as if it was just created). It flushes any messages queued on the 2937c478bd9Sstevel@tonic-gate * read queue to avoid dealing with e.g. TPI acks or T_exdata_ind messages. 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate void 2967c478bd9Sstevel@tonic-gate so_stream2sock(struct sonode *so) 2977c478bd9Sstevel@tonic-gate { 2987c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 2990f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 3007c478bd9Sstevel@tonic-gate 3010f1702c5SYu Xiangning ASSERT(MUTEX_HELD(&sti->sti_plumb_lock)); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3047c478bd9Sstevel@tonic-gate so_lock_single(so); 3057c478bd9Sstevel@tonic-gate ASSERT(so->so_version == SOV_STREAM); 3067c478bd9Sstevel@tonic-gate so->so_version = SOV_SOCKSTREAM; 3070f1702c5SYu Xiangning sti->sti_pushcnt = 0; 3087c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Set a permenent error to force any thread in sorecvmsg to 3127c478bd9Sstevel@tonic-gate * return (and drop SOREADLOCKED). Clear the error once 3137c478bd9Sstevel@tonic-gate * we have SOREADLOCKED. 3147c478bd9Sstevel@tonic-gate * This makes a read sleeping during the I_PUSH of sockmod return 3157c478bd9Sstevel@tonic-gate * EIO. 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), EIO, 1, NULL); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * Get the read lock before flushing data to avoid 3217c478bd9Sstevel@tonic-gate * problems with the T_EXDATA_IND MSG_PEEK code in sorecvmsg. 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3247c478bd9Sstevel@tonic-gate (void) so_lock_read(so, 0); /* Set SOREADLOCKED */ 3257c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, NULL); 3287c478bd9Sstevel@tonic-gate so_installhooks(so); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * Flush everything on the read queue. 3327c478bd9Sstevel@tonic-gate * This ensures that no T_CONN_IND remain and that no T_EXDATA_IND 3337c478bd9Sstevel@tonic-gate * remain; those types of messages would confuse sockfs. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate strflushrq(vp, FLUSHALL); 3367c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3390f1702c5SYu Xiangning * Flush the T_DISCON_IND on sti_discon_ind_mp. 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate so_flush_discon_ind(so); 3427c478bd9Sstevel@tonic-gate so_unlock_read(so); /* Clear SOREADLOCKED */ 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 3457c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * Install the hooks in the stream head. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate void 3527c478bd9Sstevel@tonic-gate so_installhooks(struct sonode *so) 3537c478bd9Sstevel@tonic-gate { 3547c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate strsetrputhooks(vp, SH_SIGALLDATA | SH_IGN_ZEROLEN | SH_CONSOL_DATA, 3577c478bd9Sstevel@tonic-gate strsock_proto, strsock_misc); 3587c478bd9Sstevel@tonic-gate strsetwputhooks(vp, SH_SIGPIPE | SH_RECHECK_ERR, 0); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * Remove the hooks in the stream head. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate static void 3657c478bd9Sstevel@tonic-gate so_removehooks(struct sonode *so) 3667c478bd9Sstevel@tonic-gate { 3677c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate strsetrputhooks(vp, 0, NULL, NULL); 3707c478bd9Sstevel@tonic-gate strsetwputhooks(vp, 0, STRTIMOUT); 3717c478bd9Sstevel@tonic-gate /* 3727c478bd9Sstevel@tonic-gate * Leave read behavior as it would have been for a normal 3737c478bd9Sstevel@tonic-gate * stream i.e. a read of an M_PROTO will fail. 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 3770f1702c5SYu Xiangning void 3780f1702c5SYu Xiangning so_basic_strinit(struct sonode *so) 3797c478bd9Sstevel@tonic-gate { 3807c478bd9Sstevel@tonic-gate struct vnode *vp = SOTOV(so); 3817c478bd9Sstevel@tonic-gate struct stdata *stp; 3827c478bd9Sstevel@tonic-gate mblk_t *mp; 3830f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* Preallocate an unbind_req message */ 386de8c4a14SErik Nordmark mp = soallocproto(sizeof (struct T_unbind_req), _ALLOC_SLEEP, CRED()); 3877c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 3880f1702c5SYu Xiangning sti->sti_unbind_mp = mp; 3897c478bd9Sstevel@tonic-gate #ifdef DEBUG 3907c478bd9Sstevel@tonic-gate so->so_options = so_default_options; 3917c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3927c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate so_installhooks(so); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate stp = vp->v_stream; 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Have to keep minpsz at zero in order to allow write/send of zero 3997c478bd9Sstevel@tonic-gate * bytes. 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 4027c478bd9Sstevel@tonic-gate if (stp->sd_qn_minpsz == 1) 4037c478bd9Sstevel@tonic-gate stp->sd_qn_minpsz = 0; 4047c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 4050f1702c5SYu Xiangning } 4060f1702c5SYu Xiangning 4070f1702c5SYu Xiangning /* 4080f1702c5SYu Xiangning * Initialize the streams side of a socket including 4090f1702c5SYu Xiangning * T_info_req/ack processing. If tso is not NULL its values are used thereby 4100f1702c5SYu Xiangning * avoiding the T_INFO_REQ. 4110f1702c5SYu Xiangning */ 4120f1702c5SYu Xiangning int 4130f1702c5SYu Xiangning so_strinit(struct sonode *so, struct sonode *tso) 4140f1702c5SYu Xiangning { 4150f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 4160f1702c5SYu Xiangning sotpi_info_t *tsti; 4170f1702c5SYu Xiangning int error; 4180f1702c5SYu Xiangning 4190f1702c5SYu Xiangning so_basic_strinit(so); 4200f1702c5SYu Xiangning 4210f1702c5SYu Xiangning /* 4220f1702c5SYu Xiangning * The T_CAPABILITY_REQ should be the first message sent down because 4230f1702c5SYu Xiangning * at least TCP has a fast-path for this which avoids timeouts while 4240f1702c5SYu Xiangning * waiting for the T_CAPABILITY_ACK under high system load. 4250f1702c5SYu Xiangning */ 4260f1702c5SYu Xiangning if (tso == NULL) { 4270f1702c5SYu Xiangning error = do_tcapability(so, TC1_ACCEPTOR_ID | TC1_INFO); 4280f1702c5SYu Xiangning if (error) 4290f1702c5SYu Xiangning return (error); 4300f1702c5SYu Xiangning } else { 4310f1702c5SYu Xiangning tsti = SOTOTPI(tso); 4320f1702c5SYu Xiangning 4330f1702c5SYu Xiangning mutex_enter(&so->so_lock); 4340f1702c5SYu Xiangning sti->sti_tsdu_size = tsti->sti_tsdu_size; 4350f1702c5SYu Xiangning sti->sti_etsdu_size = tsti->sti_etsdu_size; 4360f1702c5SYu Xiangning sti->sti_addr_size = tsti->sti_addr_size; 4370f1702c5SYu Xiangning sti->sti_opt_size = tsti->sti_opt_size; 4380f1702c5SYu Xiangning sti->sti_tidu_size = tsti->sti_tidu_size; 4390f1702c5SYu Xiangning sti->sti_serv_type = tsti->sti_serv_type; 4400f1702c5SYu Xiangning so->so_mode = tso->so_mode & ~SM_ACCEPTOR_ID; 4410f1702c5SYu Xiangning mutex_exit(&so->so_lock); 4420f1702c5SYu Xiangning 4430f1702c5SYu Xiangning /* the following do_tcapability may update so->so_mode */ 4440f1702c5SYu Xiangning if ((tsti->sti_serv_type != T_CLTS) && 4450f1702c5SYu Xiangning (sti->sti_direct == 0)) { 4460f1702c5SYu Xiangning error = do_tcapability(so, TC1_ACCEPTOR_ID); 4470f1702c5SYu Xiangning if (error) 4480f1702c5SYu Xiangning return (error); 4490f1702c5SYu Xiangning } 4500f1702c5SYu Xiangning } 4510f1702c5SYu Xiangning /* 4520f1702c5SYu Xiangning * If the addr_size is 0 we treat it as already bound 4530f1702c5SYu Xiangning * and connected. This is used by the routing socket. 4540f1702c5SYu Xiangning * We set the addr_size to something to allocate a the address 4550f1702c5SYu Xiangning * structures. 4560f1702c5SYu Xiangning */ 4570f1702c5SYu Xiangning if (sti->sti_addr_size == 0) { 4580f1702c5SYu Xiangning so->so_state |= SS_ISBOUND | SS_ISCONNECTED; 4590f1702c5SYu Xiangning /* Address size can vary with address families. */ 4600f1702c5SYu Xiangning if (so->so_family == AF_INET6) 4610f1702c5SYu Xiangning sti->sti_addr_size = 4620f1702c5SYu Xiangning (t_scalar_t)sizeof (struct sockaddr_in6); 4630f1702c5SYu Xiangning else 4640f1702c5SYu Xiangning sti->sti_addr_size = 4650f1702c5SYu Xiangning (t_scalar_t)sizeof (struct sockaddr_in); 4660f1702c5SYu Xiangning ASSERT(sti->sti_unbind_mp); 4670f1702c5SYu Xiangning } 4680f1702c5SYu Xiangning 4690f1702c5SYu Xiangning so_alloc_addr(so, sti->sti_addr_size); 47017169044Sbrutus 4717c478bd9Sstevel@tonic-gate return (0); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate static void 4757c478bd9Sstevel@tonic-gate copy_tinfo(struct sonode *so, struct T_info_ack *tia) 4767c478bd9Sstevel@tonic-gate { 4770f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 4780f1702c5SYu Xiangning 4790f1702c5SYu Xiangning sti->sti_tsdu_size = tia->TSDU_size; 4800f1702c5SYu Xiangning sti->sti_etsdu_size = tia->ETSDU_size; 4810f1702c5SYu Xiangning sti->sti_addr_size = tia->ADDR_size; 4820f1702c5SYu Xiangning sti->sti_opt_size = tia->OPT_size; 4830f1702c5SYu Xiangning sti->sti_tidu_size = tia->TIDU_size; 4840f1702c5SYu Xiangning sti->sti_serv_type = tia->SERV_type; 4857c478bd9Sstevel@tonic-gate switch (tia->CURRENT_state) { 4867c478bd9Sstevel@tonic-gate case TS_UNBND: 4877c478bd9Sstevel@tonic-gate break; 4887c478bd9Sstevel@tonic-gate case TS_IDLE: 4897c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND; 4900f1702c5SYu Xiangning sti->sti_laddr_len = 0; 4910f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 4927c478bd9Sstevel@tonic-gate break; 4937c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 4947c478bd9Sstevel@tonic-gate so->so_state |= SS_ISBOUND|SS_ISCONNECTED; 4950f1702c5SYu Xiangning sti->sti_laddr_len = 0; 4960f1702c5SYu Xiangning sti->sti_faddr_len = 0; 4970f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 4980f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 4997c478bd9Sstevel@tonic-gate break; 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * Heuristics for determining the socket mode flags 5047c478bd9Sstevel@tonic-gate * (SM_ATOMIC, SM_CONNREQUIRED, SM_ADDR, SM_FDPASSING, 5057c478bd9Sstevel@tonic-gate * and SM_EXDATA, SM_OPTDATA, and SM_BYTESTREAM) 5067c478bd9Sstevel@tonic-gate * from the info ack. 5077c478bd9Sstevel@tonic-gate */ 5080f1702c5SYu Xiangning if (sti->sti_serv_type == T_CLTS) { 5097c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC | SM_ADDR; 5107c478bd9Sstevel@tonic-gate } else { 5117c478bd9Sstevel@tonic-gate so->so_mode |= SM_CONNREQUIRED; 5120f1702c5SYu Xiangning if (sti->sti_etsdu_size != 0 && sti->sti_etsdu_size != -2) 5137c478bd9Sstevel@tonic-gate so->so_mode |= SM_EXDATA; 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_SEQPACKET || so->so_type == SOCK_RAW) { 5167c478bd9Sstevel@tonic-gate /* Semantics are to discard tail end of messages */ 5177c478bd9Sstevel@tonic-gate so->so_mode |= SM_ATOMIC; 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX) { 5207c478bd9Sstevel@tonic-gate so->so_mode |= SM_FDPASSING | SM_OPTDATA; 5210f1702c5SYu Xiangning if (sti->sti_addr_size == -1) { 5227c478bd9Sstevel@tonic-gate /* MAXPATHLEN + soun_family + nul termination */ 5230f1702c5SYu Xiangning sti->sti_addr_size = (t_scalar_t)(MAXPATHLEN + 5247c478bd9Sstevel@tonic-gate sizeof (short) + 1); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate if (so->so_type == SOCK_STREAM) { 5277c478bd9Sstevel@tonic-gate /* 5287c478bd9Sstevel@tonic-gate * Make it into a byte-stream transport. 5297c478bd9Sstevel@tonic-gate * SOCK_SEQPACKET sockets are unchanged. 5307c478bd9Sstevel@tonic-gate */ 5310f1702c5SYu Xiangning sti->sti_tsdu_size = 0; 5327c478bd9Sstevel@tonic-gate } 5330f1702c5SYu Xiangning } else if (sti->sti_addr_size == -1) { 5347c478bd9Sstevel@tonic-gate /* 5357c478bd9Sstevel@tonic-gate * Logic extracted from sockmod - have to pick some max address 5367c478bd9Sstevel@tonic-gate * length in order to preallocate the addresses. 5377c478bd9Sstevel@tonic-gate */ 5380f1702c5SYu Xiangning sti->sti_addr_size = SOA_DEFSIZE; 5397c478bd9Sstevel@tonic-gate } 5400f1702c5SYu Xiangning if (sti->sti_tsdu_size == 0) 5417c478bd9Sstevel@tonic-gate so->so_mode |= SM_BYTESTREAM; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate static int 5457c478bd9Sstevel@tonic-gate check_tinfo(struct sonode *so) 5467c478bd9Sstevel@tonic-gate { 5470f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 5480f1702c5SYu Xiangning 5497c478bd9Sstevel@tonic-gate /* Consistency checks */ 5500f1702c5SYu Xiangning if (so->so_type == SOCK_DGRAM && sti->sti_serv_type != T_CLTS) { 5517c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5527c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5537c478bd9Sstevel@tonic-gate return (EPROTO); 5547c478bd9Sstevel@tonic-gate } 5550f1702c5SYu Xiangning if (so->so_type == SOCK_STREAM && sti->sti_serv_type == T_CLTS) { 5567c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5577c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5587c478bd9Sstevel@tonic-gate return (EPROTO); 5597c478bd9Sstevel@tonic-gate } 5600f1702c5SYu Xiangning if (so->so_type == SOCK_SEQPACKET && sti->sti_serv_type == T_CLTS) { 5617c478bd9Sstevel@tonic-gate eprintso(so, ("service type and socket type mismatch\n")); 5627c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 5637c478bd9Sstevel@tonic-gate return (EPROTO); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET && 5660f1702c5SYu Xiangning sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in)) { 5677c478bd9Sstevel@tonic-gate eprintso(so, 5687c478bd9Sstevel@tonic-gate ("AF_INET must have sockaddr_in address length. Got %d\n", 5690f1702c5SYu Xiangning sti->sti_addr_size)); 5707c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 5717c478bd9Sstevel@tonic-gate return (EMSGSIZE); 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET6 && 5740f1702c5SYu Xiangning sti->sti_addr_size != (t_scalar_t)sizeof (struct sockaddr_in6)) { 5757c478bd9Sstevel@tonic-gate eprintso(so, 5767c478bd9Sstevel@tonic-gate ("AF_INET6 must have sockaddr_in6 address length. Got %d\n", 5770f1702c5SYu Xiangning sti->sti_addr_size)); 5787c478bd9Sstevel@tonic-gate eprintsoline(so, EMSGSIZE); 5797c478bd9Sstevel@tonic-gate return (EMSGSIZE); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate dprintso(so, 1, ( 5837c478bd9Sstevel@tonic-gate "tinfo: serv %d tsdu %d, etsdu %d, addr %d, opt %d, tidu %d\n", 5840f1702c5SYu Xiangning sti->sti_serv_type, sti->sti_tsdu_size, sti->sti_etsdu_size, 5850f1702c5SYu Xiangning sti->sti_addr_size, sti->sti_opt_size, 5860f1702c5SYu Xiangning sti->sti_tidu_size)); 5877c478bd9Sstevel@tonic-gate dprintso(so, 1, ("tinfo: so_state %s\n", 5887c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 5897c478bd9Sstevel@tonic-gate return (0); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* 5937c478bd9Sstevel@tonic-gate * Send down T_info_req and wait for the ack. 5947c478bd9Sstevel@tonic-gate * Record interesting T_info_ack values in the sonode. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate static int 5977c478bd9Sstevel@tonic-gate do_tinfo(struct sonode *so) 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate struct T_info_req tir; 6007c478bd9Sstevel@tonic-gate mblk_t *mp; 6017c478bd9Sstevel@tonic-gate int error; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 6060f1702c5SYu Xiangning SOTOTPI(so)->sti_addr_size = 0; 6077c478bd9Sstevel@tonic-gate return (0); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 610903a11ebSrh87107 dprintso(so, 1, ("do_tinfo(%p)\n", (void *)so)); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* Send T_INFO_REQ */ 6137c478bd9Sstevel@tonic-gate tir.PRIM_type = T_INFO_REQ; 6147c478bd9Sstevel@tonic-gate mp = soallocproto1(&tir, sizeof (tir), 6157c478bd9Sstevel@tonic-gate sizeof (struct T_info_req) + sizeof (struct T_info_ack), 616de8c4a14SErik Nordmark _ALLOC_INTR, CRED()); 6177c478bd9Sstevel@tonic-gate if (mp == NULL) { 6187c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 6197c478bd9Sstevel@tonic-gate return (ENOBUFS); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate /* T_INFO_REQ has to be M_PCPROTO */ 6227c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 6257c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 6267c478bd9Sstevel@tonic-gate if (error) { 6277c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6287c478bd9Sstevel@tonic-gate return (error); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 6317c478bd9Sstevel@tonic-gate /* Wait for T_INFO_ACK */ 6327c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_INFO_REQ, T_INFO_ACK, 6337c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_info_ack), &mp, 0))) { 6347c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6357c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6367c478bd9Sstevel@tonic-gate return (error); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate ASSERT(mp); 6407c478bd9Sstevel@tonic-gate copy_tinfo(so, (struct T_info_ack *)mp->b_rptr); 6417c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6427c478bd9Sstevel@tonic-gate freemsg(mp); 6437c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * Send down T_capability_req and wait for the ack. 6487c478bd9Sstevel@tonic-gate * Record interesting T_capability_ack values in the sonode. 6497c478bd9Sstevel@tonic-gate */ 6507c478bd9Sstevel@tonic-gate static int 6517c478bd9Sstevel@tonic-gate do_tcapability(struct sonode *so, t_uscalar_t cap_bits1) 6527c478bd9Sstevel@tonic-gate { 6537c478bd9Sstevel@tonic-gate struct T_capability_req tcr; 6547c478bd9Sstevel@tonic-gate struct T_capability_ack *tca; 6557c478bd9Sstevel@tonic-gate mblk_t *mp; 6567c478bd9Sstevel@tonic-gate int error; 6570f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate ASSERT(cap_bits1 != 0); 6607c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & ~(TC1_ACCEPTOR_ID | TC1_INFO)) == 0); 6617c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 6627c478bd9Sstevel@tonic-gate 6630f1702c5SYu Xiangning if (sti->sti_provinfo->tpi_capability == PI_NO) 6647c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate if (so_no_tinfo) { 6670f1702c5SYu Xiangning sti->sti_addr_size = 0; 6687c478bd9Sstevel@tonic-gate if ((cap_bits1 &= ~TC1_INFO) == 0) 6697c478bd9Sstevel@tonic-gate return (0); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 672903a11ebSrh87107 dprintso(so, 1, ("do_tcapability(%p)\n", (void *)so)); 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* Send T_CAPABILITY_REQ */ 6757c478bd9Sstevel@tonic-gate tcr.PRIM_type = T_CAPABILITY_REQ; 6767c478bd9Sstevel@tonic-gate tcr.CAP_bits1 = cap_bits1; 6777c478bd9Sstevel@tonic-gate mp = soallocproto1(&tcr, sizeof (tcr), 6787c478bd9Sstevel@tonic-gate sizeof (struct T_capability_req) + sizeof (struct T_capability_ack), 679de8c4a14SErik Nordmark _ALLOC_INTR, CRED()); 6807c478bd9Sstevel@tonic-gate if (mp == NULL) { 6817c478bd9Sstevel@tonic-gate eprintsoline(so, ENOBUFS); 6827c478bd9Sstevel@tonic-gate return (ENOBUFS); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate /* T_CAPABILITY_REQ should be M_PCPROTO here */ 6857c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PCPROTO; 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 6887c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR, 0); 6897c478bd9Sstevel@tonic-gate if (error) { 6907c478bd9Sstevel@tonic-gate eprintsoline(so, error); 6917c478bd9Sstevel@tonic-gate return (error); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 6947c478bd9Sstevel@tonic-gate /* Wait for T_CAPABILITY_ACK */ 6957c478bd9Sstevel@tonic-gate if ((error = sowaitprim(so, T_CAPABILITY_REQ, T_CAPABILITY_ACK, 6967c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (*tca), &mp, sock_capability_timeout * hz))) { 6977c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 6980f1702c5SYu Xiangning PI_PROVLOCK(sti->sti_provinfo); 6990f1702c5SYu Xiangning if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW) 7000f1702c5SYu Xiangning sti->sti_provinfo->tpi_capability = PI_NO; 7010f1702c5SYu Xiangning PI_PROVUNLOCK(sti->sti_provinfo); 7027c478bd9Sstevel@tonic-gate ASSERT((so->so_mode & SM_ACCEPTOR_ID) == 0); 7037c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 7047c478bd9Sstevel@tonic-gate /* 7057c478bd9Sstevel@tonic-gate * If the T_CAPABILITY_REQ timed out and then a 7067c478bd9Sstevel@tonic-gate * T_INFO_REQ gets a protocol error, most likely 7077c478bd9Sstevel@tonic-gate * the capability was slow (vs. unsupported). Return 7087c478bd9Sstevel@tonic-gate * ENOSR for this case as a best guess. 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate if (error == ETIME) { 7117c478bd9Sstevel@tonic-gate return ((error = do_tinfo(so)) == EPROTO ? 7127c478bd9Sstevel@tonic-gate ENOSR : error); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate return (do_tinfo(so)); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate return (0); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate ASSERT(mp); 7207c478bd9Sstevel@tonic-gate tca = (struct T_capability_ack *)mp->b_rptr; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate ASSERT((cap_bits1 & TC1_INFO) == (tca->CAP_bits1 & TC1_INFO)); 7230f1702c5SYu Xiangning so_proc_tcapability_ack(so, tca); 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate cap_bits1 = tca->CAP_bits1; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 7287c478bd9Sstevel@tonic-gate freemsg(mp); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) 7317c478bd9Sstevel@tonic-gate return (check_tinfo(so)); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate return (0); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate /* 7370f1702c5SYu Xiangning * Process a T_CAPABILITY_ACK 7380f1702c5SYu Xiangning */ 7390f1702c5SYu Xiangning void 7400f1702c5SYu Xiangning so_proc_tcapability_ack(struct sonode *so, struct T_capability_ack *tca) 7410f1702c5SYu Xiangning { 7420f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 7430f1702c5SYu Xiangning 7440f1702c5SYu Xiangning if (sti->sti_provinfo->tpi_capability == PI_DONTKNOW) { 7450f1702c5SYu Xiangning PI_PROVLOCK(sti->sti_provinfo); 7460f1702c5SYu Xiangning sti->sti_provinfo->tpi_capability = PI_YES; 7470f1702c5SYu Xiangning PI_PROVUNLOCK(sti->sti_provinfo); 7480f1702c5SYu Xiangning } 7490f1702c5SYu Xiangning 7500f1702c5SYu Xiangning if (tca->CAP_bits1 & TC1_ACCEPTOR_ID) { 7510f1702c5SYu Xiangning sti->sti_acceptor_id = tca->ACCEPTOR_id; 7520f1702c5SYu Xiangning so->so_mode |= SM_ACCEPTOR_ID; 7530f1702c5SYu Xiangning } 7540f1702c5SYu Xiangning 7550f1702c5SYu Xiangning if (tca->CAP_bits1 & TC1_INFO) 7560f1702c5SYu Xiangning copy_tinfo(so, &tca->INFO_ack); 7570f1702c5SYu Xiangning } 7580f1702c5SYu Xiangning 7590f1702c5SYu Xiangning /* 7600f1702c5SYu Xiangning * Retrieve socket error, clear error if not peek. 7617c478bd9Sstevel@tonic-gate */ 7627c478bd9Sstevel@tonic-gate int 7630f1702c5SYu Xiangning sogeterr(struct sonode *so, boolean_t clear_err) 7647c478bd9Sstevel@tonic-gate { 7657c478bd9Sstevel@tonic-gate int error; 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate error = so->so_error; 7700f1702c5SYu Xiangning if (clear_err) 7717c478bd9Sstevel@tonic-gate so->so_error = 0; 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate return (error); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve read 7787c478bd9Sstevel@tonic-gate * side errors. 7797c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 7807c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate int 7837c478bd9Sstevel@tonic-gate sogetrderr(vnode_t *vp, int ispeek, int *clearerr) 7847c478bd9Sstevel@tonic-gate { 7857c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 7867c478bd9Sstevel@tonic-gate int error; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 7897c478bd9Sstevel@tonic-gate if (ispeek) { 7907c478bd9Sstevel@tonic-gate error = so->so_error; 7917c478bd9Sstevel@tonic-gate *clearerr = 0; 7927c478bd9Sstevel@tonic-gate } else { 7937c478bd9Sstevel@tonic-gate error = so->so_error; 7947c478bd9Sstevel@tonic-gate so->so_error = 0; 7957c478bd9Sstevel@tonic-gate *clearerr = 1; 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 7987c478bd9Sstevel@tonic-gate return (error); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to retrieve write 8037c478bd9Sstevel@tonic-gate * side errors. 8047c478bd9Sstevel@tonic-gate * It does not clear the socket error for a peeking read side operation. 8057c478bd9Sstevel@tonic-gate * It the error is to be cleared it sets *clearerr. 8067c478bd9Sstevel@tonic-gate */ 8077c478bd9Sstevel@tonic-gate int 8087c478bd9Sstevel@tonic-gate sogetwrerr(vnode_t *vp, int ispeek, int *clearerr) 8097c478bd9Sstevel@tonic-gate { 8107c478bd9Sstevel@tonic-gate struct sonode *so = VTOSO(vp); 8117c478bd9Sstevel@tonic-gate int error; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 8147c478bd9Sstevel@tonic-gate if (so->so_state & SS_CANTSENDMORE) { 8157c478bd9Sstevel@tonic-gate error = EPIPE; 8167c478bd9Sstevel@tonic-gate *clearerr = 0; 8177c478bd9Sstevel@tonic-gate } else { 8187c478bd9Sstevel@tonic-gate error = so->so_error; 8197c478bd9Sstevel@tonic-gate if (ispeek) { 8207c478bd9Sstevel@tonic-gate *clearerr = 0; 8217c478bd9Sstevel@tonic-gate } else { 8227c478bd9Sstevel@tonic-gate so->so_error = 0; 8237c478bd9Sstevel@tonic-gate *clearerr = 1; 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 8277c478bd9Sstevel@tonic-gate return (error); 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate /* 8317c478bd9Sstevel@tonic-gate * Set a nonpersistent read and write error on the socket. 8327c478bd9Sstevel@tonic-gate * Used when there is a T_uderror_ind for a connected socket. 8337c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror and strsetwerror 8347c478bd9Sstevel@tonic-gate * after dropping the lock. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate void 8377c478bd9Sstevel@tonic-gate soseterror(struct sonode *so, int error) 8387c478bd9Sstevel@tonic-gate { 8397c478bd9Sstevel@tonic-gate ASSERT(error != 0); 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8427c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate void 8467c478bd9Sstevel@tonic-gate soisconnecting(struct sonode *so) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8497c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); 8507c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTING; 8517c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate void 8557c478bd9Sstevel@tonic-gate soisconnected(struct sonode *so) 8567c478bd9Sstevel@tonic-gate { 8577c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8587c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING); 8597c478bd9Sstevel@tonic-gate so->so_state |= SS_ISCONNECTED; 8607c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * The caller also needs to call strsetrerror, strsetwerror and strseteof. 8657c478bd9Sstevel@tonic-gate */ 8667c478bd9Sstevel@tonic-gate void 8677c478bd9Sstevel@tonic-gate soisdisconnected(struct sonode *so, int error) 8687c478bd9Sstevel@tonic-gate { 8697c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8700f1702c5SYu Xiangning so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 8717c478bd9Sstevel@tonic-gate so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); 8727c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8737c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) { 8747c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 8757c478bd9Sstevel@tonic-gate so->so_peercred = NULL; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* 8817c478bd9Sstevel@tonic-gate * For connected AF_UNIX SOCK_DGRAM sockets when the peer closes. 8827c478bd9Sstevel@tonic-gate * Does not affect write side. 8837c478bd9Sstevel@tonic-gate * The caller also has to call strsetrerror. 8847c478bd9Sstevel@tonic-gate */ 8857c478bd9Sstevel@tonic-gate static void 8867c478bd9Sstevel@tonic-gate sobreakconn(struct sonode *so, int error) 8877c478bd9Sstevel@tonic-gate { 8887c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 8897c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 8907c478bd9Sstevel@tonic-gate so->so_error = (ushort_t)error; 8917c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate /* 8957c478bd9Sstevel@tonic-gate * Can no longer send. 8967c478bd9Sstevel@tonic-gate * Caller must also call strsetwerror. 8977c478bd9Sstevel@tonic-gate * 8987c478bd9Sstevel@tonic-gate * We mark the peer address as no longer valid for getpeername, but 8997c478bd9Sstevel@tonic-gate * leave it around for so_unix_close to notify the peer (that 9007c478bd9Sstevel@tonic-gate * transport has no addressing held at that layer). 9017c478bd9Sstevel@tonic-gate */ 9027c478bd9Sstevel@tonic-gate void 9037c478bd9Sstevel@tonic-gate socantsendmore(struct sonode *so) 9047c478bd9Sstevel@tonic-gate { 9057c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9060f1702c5SYu Xiangning so->so_state |= SS_CANTSENDMORE; 9077c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate /* 9117c478bd9Sstevel@tonic-gate * The caller must call strseteof(,1) as well as this routine 9127c478bd9Sstevel@tonic-gate * to change the socket state. 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate void 9157c478bd9Sstevel@tonic-gate socantrcvmore(struct sonode *so) 9167c478bd9Sstevel@tonic-gate { 9177c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9187c478bd9Sstevel@tonic-gate so->so_state |= SS_CANTRCVMORE; 9197c478bd9Sstevel@tonic-gate cv_broadcast(&so->so_state_cv); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate /* 9237c478bd9Sstevel@tonic-gate * The caller has sent down a "request_prim" primitive and wants to wait for 9247c478bd9Sstevel@tonic-gate * an ack ("ack_prim") or an T_ERROR_ACK for it. 9257c478bd9Sstevel@tonic-gate * The specified "ack_prim" can be a T_OK_ACK. 9267c478bd9Sstevel@tonic-gate * 9277c478bd9Sstevel@tonic-gate * Assumes that all the TPI acks are M_PCPROTO messages. 9287c478bd9Sstevel@tonic-gate * 9297c478bd9Sstevel@tonic-gate * Note that the socket is single-threaded (using so_lock_single) 9307c478bd9Sstevel@tonic-gate * for all operations that generate TPI ack messages. Since 9317c478bd9Sstevel@tonic-gate * only TPI ack messages are M_PCPROTO we should never receive 9327c478bd9Sstevel@tonic-gate * anything except either the ack we are expecting or a T_ERROR_ACK 9337c478bd9Sstevel@tonic-gate * for the same primitive. 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate int 9367c478bd9Sstevel@tonic-gate sowaitprim(struct sonode *so, t_scalar_t request_prim, t_scalar_t ack_prim, 9377c478bd9Sstevel@tonic-gate t_uscalar_t min_size, mblk_t **mpp, clock_t wait) 9387c478bd9Sstevel@tonic-gate { 9397c478bd9Sstevel@tonic-gate mblk_t *mp; 9407c478bd9Sstevel@tonic-gate union T_primitives *tpr; 9417c478bd9Sstevel@tonic-gate int error; 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitprim(%p, %d, %d, %d, %p, %lu)\n", 944903a11ebSrh87107 (void *)so, request_prim, ack_prim, min_size, (void *)mpp, wait)); 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate error = sowaitack(so, &mp, wait); 9497c478bd9Sstevel@tonic-gate if (error) 9507c478bd9Sstevel@tonic-gate return (error); 9517c478bd9Sstevel@tonic-gate 952903a11ebSrh87107 dprintso(so, 1, ("got msg %p\n", (void *)mp)); 9537c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO || 9547c478bd9Sstevel@tonic-gate MBLKL(mp) < sizeof (tpr->type)) { 9557c478bd9Sstevel@tonic-gate freemsg(mp); 9567c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 9577c478bd9Sstevel@tonic-gate return (EPROTO); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 9607c478bd9Sstevel@tonic-gate /* 9617c478bd9Sstevel@tonic-gate * Did we get the primitive that we were asking for? 9627c478bd9Sstevel@tonic-gate * For T_OK_ACK we also check that it matches the request primitive. 9637c478bd9Sstevel@tonic-gate */ 9647c478bd9Sstevel@tonic-gate if (tpr->type == ack_prim && 9657c478bd9Sstevel@tonic-gate (ack_prim != T_OK_ACK || 9667c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == request_prim)) { 9677c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= (ssize_t)min_size) { 9687c478bd9Sstevel@tonic-gate /* Found what we are looking for */ 9697c478bd9Sstevel@tonic-gate *mpp = mp; 9707c478bd9Sstevel@tonic-gate return (0); 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate /* Too short */ 9737c478bd9Sstevel@tonic-gate freemsg(mp); 9747c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 9757c478bd9Sstevel@tonic-gate return (EPROTO); 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK && 9797c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == request_prim) { 9807c478bd9Sstevel@tonic-gate /* Error to the primitive we were looking for */ 9817c478bd9Sstevel@tonic-gate if (tpr->error_ack.TLI_error == TSYSERR) { 9827c478bd9Sstevel@tonic-gate error = tpr->error_ack.UNIX_error; 9837c478bd9Sstevel@tonic-gate } else { 9840f1702c5SYu Xiangning error = proto_tlitosyserr(tpr->error_ack.TLI_error); 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d ->%d\n", 9870f1702c5SYu Xiangning tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error, 9880f1702c5SYu Xiangning tpr->error_ack.UNIX_error, error)); 9897c478bd9Sstevel@tonic-gate freemsg(mp); 9907c478bd9Sstevel@tonic-gate return (error); 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate /* 9937c478bd9Sstevel@tonic-gate * Wrong primitive or T_ERROR_ACK for the wrong primitive 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate #ifdef DEBUG 9967c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK) { 9977c478bd9Sstevel@tonic-gate dprintso(so, 0, ("error_ack for %d: %d/%d\n", 9980f1702c5SYu Xiangning tpr->error_ack.ERROR_prim, tpr->error_ack.TLI_error, 9997c478bd9Sstevel@tonic-gate tpr->error_ack.UNIX_error)); 10007c478bd9Sstevel@tonic-gate } else if (tpr->type == T_OK_ACK) { 10017c478bd9Sstevel@tonic-gate dprintso(so, 0, ("ok_ack for %d, expected %d for %d\n", 10020f1702c5SYu Xiangning tpr->ok_ack.CORRECT_prim, ack_prim, request_prim)); 10037c478bd9Sstevel@tonic-gate } else { 10047c478bd9Sstevel@tonic-gate dprintso(so, 0, 10057c478bd9Sstevel@tonic-gate ("unexpected primitive %d, expected %d for %d\n", 10067c478bd9Sstevel@tonic-gate tpr->type, ack_prim, request_prim)); 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate freemsg(mp); 10117c478bd9Sstevel@tonic-gate eprintsoline(so, EPROTO); 10127c478bd9Sstevel@tonic-gate return (EPROTO); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate /* 10167c478bd9Sstevel@tonic-gate * Wait for a T_OK_ACK for the specified primitive. 10177c478bd9Sstevel@tonic-gate */ 10187c478bd9Sstevel@tonic-gate int 10197c478bd9Sstevel@tonic-gate sowaitokack(struct sonode *so, t_scalar_t request_prim) 10207c478bd9Sstevel@tonic-gate { 10217c478bd9Sstevel@tonic-gate mblk_t *mp; 10227c478bd9Sstevel@tonic-gate int error; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate error = sowaitprim(so, request_prim, T_OK_ACK, 10257c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_ok_ack), &mp, 0); 10267c478bd9Sstevel@tonic-gate if (error) 10277c478bd9Sstevel@tonic-gate return (error); 10287c478bd9Sstevel@tonic-gate freemsg(mp); 10297c478bd9Sstevel@tonic-gate return (0); 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10330f1702c5SYu Xiangning * Queue a received TPI ack message on sti_ack_mp. 10347c478bd9Sstevel@tonic-gate */ 10357c478bd9Sstevel@tonic-gate void 10367c478bd9Sstevel@tonic-gate soqueueack(struct sonode *so, mblk_t *mp) 10377c478bd9Sstevel@tonic-gate { 10380f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 10390f1702c5SYu Xiangning 10407c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PCPROTO) { 10412caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 10427c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PROTO TPI ack. Prim %d\n", 10437c478bd9Sstevel@tonic-gate *(t_scalar_t *)mp->b_rptr); 10447c478bd9Sstevel@tonic-gate freemsg(mp); 10457c478bd9Sstevel@tonic-gate return; 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 10490f1702c5SYu Xiangning if (sti->sti_ack_mp != NULL) { 10500f1702c5SYu Xiangning dprintso(so, 1, ("sti_ack_mp already set\n")); 10510f1702c5SYu Xiangning freemsg(sti->sti_ack_mp); 10520f1702c5SYu Xiangning sti->sti_ack_mp = NULL; 10537c478bd9Sstevel@tonic-gate } 10540f1702c5SYu Xiangning sti->sti_ack_mp = mp; 10550f1702c5SYu Xiangning cv_broadcast(&sti->sti_ack_cv); 10567c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * Wait for a TPI ack ignoring signals and errors. 10617c478bd9Sstevel@tonic-gate */ 10627c478bd9Sstevel@tonic-gate int 10637c478bd9Sstevel@tonic-gate sowaitack(struct sonode *so, mblk_t **mpp, clock_t wait) 10647c478bd9Sstevel@tonic-gate { 10650f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 10660f1702c5SYu Xiangning 10677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 10687c478bd9Sstevel@tonic-gate 10690f1702c5SYu Xiangning while (sti->sti_ack_mp == NULL) { 10707c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST 10717c478bd9Sstevel@tonic-gate if (wait == 0 && sock_test_timelimit != 0) 10727c478bd9Sstevel@tonic-gate wait = sock_test_timelimit; 10737c478bd9Sstevel@tonic-gate #endif 10747c478bd9Sstevel@tonic-gate if (wait != 0) { 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * Only wait for the time limit. 10777c478bd9Sstevel@tonic-gate */ 1078d3d50737SRafael Vanoni if (cv_reltimedwait(&sti->sti_ack_cv, &so->so_lock, 1079d3d50737SRafael Vanoni wait, TR_CLOCK_TICK) == -1) { 10807c478bd9Sstevel@tonic-gate eprintsoline(so, ETIME); 10817c478bd9Sstevel@tonic-gate return (ETIME); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate else 10850f1702c5SYu Xiangning cv_wait(&sti->sti_ack_cv, &so->so_lock); 10867c478bd9Sstevel@tonic-gate } 10870f1702c5SYu Xiangning *mpp = sti->sti_ack_mp; 10887c478bd9Sstevel@tonic-gate #ifdef DEBUG 10897c478bd9Sstevel@tonic-gate { 10907c478bd9Sstevel@tonic-gate union T_primitives *tpr; 10917c478bd9Sstevel@tonic-gate mblk_t *mp = *mpp; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 10947c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PCPROTO); 10957c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_OK_ACK || 10967c478bd9Sstevel@tonic-gate tpr->type == T_ERROR_ACK || 10977c478bd9Sstevel@tonic-gate tpr->type == T_BIND_ACK || 10987c478bd9Sstevel@tonic-gate tpr->type == T_CAPABILITY_ACK || 10997c478bd9Sstevel@tonic-gate tpr->type == T_INFO_ACK || 11007c478bd9Sstevel@tonic-gate tpr->type == T_OPTMGMT_ACK); 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 11030f1702c5SYu Xiangning sti->sti_ack_mp = NULL; 11047c478bd9Sstevel@tonic-gate return (0); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate /* 11080f1702c5SYu Xiangning * Queue a received T_CONN_IND message on sti_conn_ind_head/tail. 11097c478bd9Sstevel@tonic-gate */ 11107c478bd9Sstevel@tonic-gate void 11117c478bd9Sstevel@tonic-gate soqueueconnind(struct sonode *so, mblk_t *mp) 11127c478bd9Sstevel@tonic-gate { 11130f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 11140f1702c5SYu Xiangning 11157c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) != M_PROTO) { 11162caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 11177c478bd9Sstevel@tonic-gate "sockfs: received unexpected M_PCPROTO T_CONN_IND\n"); 11187c478bd9Sstevel@tonic-gate freemsg(mp); 11197c478bd9Sstevel@tonic-gate return; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 11237c478bd9Sstevel@tonic-gate ASSERT(mp->b_next == NULL); 11240f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 11250f1702c5SYu Xiangning sti->sti_conn_ind_head = mp; 11267c478bd9Sstevel@tonic-gate } else { 11270f1702c5SYu Xiangning ASSERT(sti->sti_conn_ind_tail->b_next == NULL); 11280f1702c5SYu Xiangning sti->sti_conn_ind_tail->b_next = mp; 11297c478bd9Sstevel@tonic-gate } 11300f1702c5SYu Xiangning sti->sti_conn_ind_tail = mp; 11317c478bd9Sstevel@tonic-gate /* Wakeup a single consumer of the T_CONN_IND */ 11320f1702c5SYu Xiangning cv_signal(&so->so_acceptq_cv); 11337c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * Wait for a T_CONN_IND. 11387c478bd9Sstevel@tonic-gate * Don't wait if nonblocking. 11397c478bd9Sstevel@tonic-gate * Accept signals and socket errors. 11407c478bd9Sstevel@tonic-gate */ 11417c478bd9Sstevel@tonic-gate int 11427c478bd9Sstevel@tonic-gate sowaitconnind(struct sonode *so, int fmode, mblk_t **mpp) 11437c478bd9Sstevel@tonic-gate { 11447c478bd9Sstevel@tonic-gate mblk_t *mp; 11450f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 11467c478bd9Sstevel@tonic-gate int error = 0; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock)); 11497c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 11507c478bd9Sstevel@tonic-gate check_error: 11517c478bd9Sstevel@tonic-gate if (so->so_error) { 11520f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 11537c478bd9Sstevel@tonic-gate if (error) { 11547c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11557c478bd9Sstevel@tonic-gate return (error); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate 11590f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 11607c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) { 11617c478bd9Sstevel@tonic-gate error = EWOULDBLOCK; 11627c478bd9Sstevel@tonic-gate goto done; 11637c478bd9Sstevel@tonic-gate } 11640f1702c5SYu Xiangning 11650f1702c5SYu Xiangning if (so->so_state & SS_CLOSING) { 11660f1702c5SYu Xiangning error = EINTR; 11670f1702c5SYu Xiangning goto done; 11680f1702c5SYu Xiangning } 11690f1702c5SYu Xiangning 11700f1702c5SYu Xiangning if (!cv_wait_sig_swap(&so->so_acceptq_cv, &so->so_lock)) { 11717c478bd9Sstevel@tonic-gate error = EINTR; 11727c478bd9Sstevel@tonic-gate goto done; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate goto check_error; 11757c478bd9Sstevel@tonic-gate } 11760f1702c5SYu Xiangning mp = sti->sti_conn_ind_head; 11770f1702c5SYu Xiangning sti->sti_conn_ind_head = mp->b_next; 11787c478bd9Sstevel@tonic-gate mp->b_next = NULL; 11790f1702c5SYu Xiangning if (sti->sti_conn_ind_head == NULL) { 11800f1702c5SYu Xiangning ASSERT(sti->sti_conn_ind_tail == mp); 11810f1702c5SYu Xiangning sti->sti_conn_ind_tail = NULL; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate *mpp = mp; 11847c478bd9Sstevel@tonic-gate done: 11857c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 11867c478bd9Sstevel@tonic-gate return (error); 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate /* 11907c478bd9Sstevel@tonic-gate * Flush a T_CONN_IND matching the sequence number from the list. 11917c478bd9Sstevel@tonic-gate * Return zero if found; non-zero otherwise. 11927c478bd9Sstevel@tonic-gate * This is called very infrequently thus it is ok to do a linear search. 11937c478bd9Sstevel@tonic-gate */ 11947c478bd9Sstevel@tonic-gate int 11957c478bd9Sstevel@tonic-gate soflushconnind(struct sonode *so, t_scalar_t seqno) 11967c478bd9Sstevel@tonic-gate { 11977c478bd9Sstevel@tonic-gate mblk_t *prevmp, *mp; 11987c478bd9Sstevel@tonic-gate struct T_conn_ind *tci; 11990f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 12020f1702c5SYu Xiangning for (prevmp = NULL, mp = sti->sti_conn_ind_head; mp != NULL; 12037c478bd9Sstevel@tonic-gate prevmp = mp, mp = mp->b_next) { 12047c478bd9Sstevel@tonic-gate tci = (struct T_conn_ind *)mp->b_rptr; 12057c478bd9Sstevel@tonic-gate if (tci->SEQ_number == seqno) { 12067c478bd9Sstevel@tonic-gate dprintso(so, 1, 12077c478bd9Sstevel@tonic-gate ("t_discon_ind: found T_CONN_IND %d\n", seqno)); 12087c478bd9Sstevel@tonic-gate /* Deleting last? */ 12090f1702c5SYu Xiangning if (sti->sti_conn_ind_tail == mp) { 12100f1702c5SYu Xiangning sti->sti_conn_ind_tail = prevmp; 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate if (prevmp == NULL) { 12137c478bd9Sstevel@tonic-gate /* Deleting first */ 12140f1702c5SYu Xiangning sti->sti_conn_ind_head = mp->b_next; 12157c478bd9Sstevel@tonic-gate } else { 12167c478bd9Sstevel@tonic-gate prevmp->b_next = mp->b_next; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate mp->b_next = NULL; 12190f1702c5SYu Xiangning 12200f1702c5SYu Xiangning ASSERT((sti->sti_conn_ind_head == NULL && 12210f1702c5SYu Xiangning sti->sti_conn_ind_tail == NULL) || 12220f1702c5SYu Xiangning (sti->sti_conn_ind_head != NULL && 12230f1702c5SYu Xiangning sti->sti_conn_ind_tail != NULL)); 12240f1702c5SYu Xiangning 12257c478bd9Sstevel@tonic-gate so->so_error = ECONNABORTED; 12267c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 1227c28749e9Skais 12287c478bd9Sstevel@tonic-gate freemsg(mp); 12297c478bd9Sstevel@tonic-gate return (0); 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 12337c478bd9Sstevel@tonic-gate dprintso(so, 1, ("t_discon_ind: NOT found T_CONN_IND %d\n", seqno)); 12347c478bd9Sstevel@tonic-gate return (-1); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate /* 12387c478bd9Sstevel@tonic-gate * Wait until the socket is connected or there is an error. 12397c478bd9Sstevel@tonic-gate * fmode should contain any nonblocking flags. nosig should be 12407c478bd9Sstevel@tonic-gate * set if the caller does not want the wait to be interrupted by a signal. 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate int 12437c478bd9Sstevel@tonic-gate sowaitconnected(struct sonode *so, int fmode, int nosig) 12447c478bd9Sstevel@tonic-gate { 12457c478bd9Sstevel@tonic-gate int error; 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate while ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 12507c478bd9Sstevel@tonic-gate SS_ISCONNECTING && so->so_error == 0) { 12517c478bd9Sstevel@tonic-gate 1252903a11ebSrh87107 dprintso(so, 1, ("waiting for SS_ISCONNECTED on %p\n", 1253903a11ebSrh87107 (void *)so)); 12547c478bd9Sstevel@tonic-gate if (fmode & (FNDELAY|FNONBLOCK)) 12557c478bd9Sstevel@tonic-gate return (EINPROGRESS); 12567c478bd9Sstevel@tonic-gate 12570f1702c5SYu Xiangning if (so->so_state & SS_CLOSING) 12580f1702c5SYu Xiangning return (EINTR); 12590f1702c5SYu Xiangning 12607c478bd9Sstevel@tonic-gate if (nosig) 12617c478bd9Sstevel@tonic-gate cv_wait(&so->so_state_cv, &so->so_lock); 12627c478bd9Sstevel@tonic-gate else if (!cv_wait_sig_swap(&so->so_state_cv, &so->so_lock)) { 12637c478bd9Sstevel@tonic-gate /* 12647c478bd9Sstevel@tonic-gate * Return EINTR and let the application use 12657c478bd9Sstevel@tonic-gate * nonblocking techniques for detecting when 12667c478bd9Sstevel@tonic-gate * the connection has been established. 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate return (EINTR); 12697c478bd9Sstevel@tonic-gate } 1270903a11ebSrh87107 dprintso(so, 1, ("awoken on %p\n", (void *)so)); 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate if (so->so_error != 0) { 12740f1702c5SYu Xiangning error = sogeterr(so, B_TRUE); 12757c478bd9Sstevel@tonic-gate ASSERT(error != 0); 12767c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 12777c478bd9Sstevel@tonic-gate return (error); 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ISCONNECTED)) { 12807c478bd9Sstevel@tonic-gate /* 12817c478bd9Sstevel@tonic-gate * Could have received a T_ORDREL_IND or a T_DISCON_IND with 12827c478bd9Sstevel@tonic-gate * zero errno. Or another thread could have consumed so_error 12837c478bd9Sstevel@tonic-gate * e.g. by calling read. 12847c478bd9Sstevel@tonic-gate */ 12857c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 12867c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sowaitconnected: error %d\n", error)); 12877c478bd9Sstevel@tonic-gate return (error); 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate return (0); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate /* 12947c478bd9Sstevel@tonic-gate * Handle the signal generation aspect of urgent data. 12957c478bd9Sstevel@tonic-gate */ 12967c478bd9Sstevel@tonic-gate static void 12977c478bd9Sstevel@tonic-gate so_oob_sig(struct sonode *so, int extrasig, 12987c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 12997c478bd9Sstevel@tonic-gate { 13000f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 13010f1702c5SYu Xiangning 13027c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13050f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt); 13060f1702c5SYu Xiangning if (sti->sti_oobsigcnt > sti->sti_oobcnt) { 13077c478bd9Sstevel@tonic-gate /* 13087c478bd9Sstevel@tonic-gate * Signal has already been generated once for this 13097c478bd9Sstevel@tonic-gate * urgent "event". However, since TCP can receive updated 13107c478bd9Sstevel@tonic-gate * urgent pointers we still generate a signal. 13117c478bd9Sstevel@tonic-gate */ 13127c478bd9Sstevel@tonic-gate ASSERT(so->so_state & SS_OOBPEND); 13137c478bd9Sstevel@tonic-gate if (extrasig) { 13147c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 13157c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate return; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13200f1702c5SYu Xiangning sti->sti_oobsigcnt++; 13210f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt > 0); /* Wraparound */ 13220f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt > sti->sti_oobcnt); 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* 13257c478bd9Sstevel@tonic-gate * Record (for select/poll) that urgent data is pending. 13267c478bd9Sstevel@tonic-gate */ 13277c478bd9Sstevel@tonic-gate so->so_state |= SS_OOBPEND; 13287c478bd9Sstevel@tonic-gate /* 13297c478bd9Sstevel@tonic-gate * New urgent data on the way so forget about any old 13307c478bd9Sstevel@tonic-gate * urgent data. 13317c478bd9Sstevel@tonic-gate */ 13327c478bd9Sstevel@tonic-gate so->so_state &= ~(SS_HAVEOOBDATA|SS_HADOOBDATA); 13337c478bd9Sstevel@tonic-gate if (so->so_oobmsg != NULL) { 13347c478bd9Sstevel@tonic-gate dprintso(so, 1, ("sock: discarding old oob\n")); 13357c478bd9Sstevel@tonic-gate freemsg(so->so_oobmsg); 13367c478bd9Sstevel@tonic-gate so->so_oobmsg = NULL; 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate *signals |= S_RDBAND; 13397c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13407c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate /* 13447c478bd9Sstevel@tonic-gate * Handle the processing of the T_EXDATA_IND with urgent data. 13457c478bd9Sstevel@tonic-gate * Returns the T_EXDATA_IND if it should be queued on the read queue. 13467c478bd9Sstevel@tonic-gate */ 13477c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 13487c478bd9Sstevel@tonic-gate static mblk_t * 13497c478bd9Sstevel@tonic-gate so_oob_exdata(struct sonode *so, mblk_t *mp, 13507c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 13517c478bd9Sstevel@tonic-gate { 13520f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 13530f1702c5SYu Xiangning 13547c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13577c478bd9Sstevel@tonic-gate 13580f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt > sti->sti_oobcnt); 13597c478bd9Sstevel@tonic-gate 13600f1702c5SYu Xiangning sti->sti_oobcnt++; 13610f1702c5SYu Xiangning ASSERT(sti->sti_oobcnt > 0); /* wraparound? */ 13620f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt); 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate /* 13657c478bd9Sstevel@tonic-gate * Set MSGMARK for SIOCATMARK. 13667c478bd9Sstevel@tonic-gate */ 13677c478bd9Sstevel@tonic-gate mp->b_flag |= MSGMARK; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13707c478bd9Sstevel@tonic-gate return (mp); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * Handle the processing of the actual urgent data. 13757c478bd9Sstevel@tonic-gate * Returns the data mblk if it should be queued on the read queue. 13767c478bd9Sstevel@tonic-gate */ 13777c478bd9Sstevel@tonic-gate static mblk_t * 13787c478bd9Sstevel@tonic-gate so_oob_data(struct sonode *so, mblk_t *mp, 13797c478bd9Sstevel@tonic-gate strsigset_t *signals, strpollset_t *pollwakeups) 13807c478bd9Sstevel@tonic-gate { 13810f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 13820f1702c5SYu Xiangning 13837c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 13867c478bd9Sstevel@tonic-gate 13870f1702c5SYu Xiangning ASSERT(sti->sti_oobsigcnt >= sti->sti_oobcnt); 13887c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * For OOBINLINE we keep the data in the T_EXDATA_IND. 13917c478bd9Sstevel@tonic-gate * Otherwise we store it in so_oobmsg. 13927c478bd9Sstevel@tonic-gate */ 13937c478bd9Sstevel@tonic-gate ASSERT(so->so_oobmsg == NULL); 13947c478bd9Sstevel@tonic-gate if (so->so_options & SO_OOBINLINE) { 13957c478bd9Sstevel@tonic-gate *pollwakeups |= POLLIN | POLLRDNORM | POLLRDBAND; 13967c478bd9Sstevel@tonic-gate *signals |= S_INPUT | S_RDNORM; 13977c478bd9Sstevel@tonic-gate } else { 13987c478bd9Sstevel@tonic-gate *pollwakeups |= POLLRDBAND; 13997c478bd9Sstevel@tonic-gate so->so_state |= SS_HAVEOOBDATA; 14007c478bd9Sstevel@tonic-gate so->so_oobmsg = mp; 14017c478bd9Sstevel@tonic-gate mp = NULL; 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate ASSERT(so_verify_oobstate(so)); 14047c478bd9Sstevel@tonic-gate return (mp); 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate /* 14087c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 14097c478bd9Sstevel@tonic-gate * For delayed processing, save the T_DISCON_IND received 14100f1702c5SYu Xiangning * from below on sti_discon_ind_mp. 14117c478bd9Sstevel@tonic-gate * When the message is processed the framework will call: 14127c478bd9Sstevel@tonic-gate * (*func)(so, mp); 14137c478bd9Sstevel@tonic-gate */ 14147c478bd9Sstevel@tonic-gate static void 14157c478bd9Sstevel@tonic-gate so_save_discon_ind(struct sonode *so, 14167c478bd9Sstevel@tonic-gate mblk_t *mp, 14177c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *)) 14187c478bd9Sstevel@tonic-gate { 14190f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 14200f1702c5SYu Xiangning 14217c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* 14247c478bd9Sstevel@tonic-gate * Discard new T_DISCON_IND if we have already received another. 14250f1702c5SYu Xiangning * Currently the earlier message can either be on sti_discon_ind_mp 14267c478bd9Sstevel@tonic-gate * or being processed. 14277c478bd9Sstevel@tonic-gate */ 14280f1702c5SYu Xiangning if (sti->sti_discon_ind_mp != NULL || (so->so_flag & SOASYNC_UNBIND)) { 14292caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 14307c478bd9Sstevel@tonic-gate "sockfs: received unexpected additional T_DISCON_IND\n"); 14317c478bd9Sstevel@tonic-gate freemsg(mp); 14327c478bd9Sstevel@tonic-gate return; 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate mp->b_prev = (mblk_t *)func; 14357c478bd9Sstevel@tonic-gate mp->b_next = NULL; 14360f1702c5SYu Xiangning sti->sti_discon_ind_mp = mp; 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * Caller must hold the mutex and make sure that either SOLOCKED 14417c478bd9Sstevel@tonic-gate * or SOASYNC_UNBIND is set. Called from so_unlock_single(). 14420f1702c5SYu Xiangning * Perform delayed processing of T_DISCON_IND message on sti_discon_ind_mp. 14437c478bd9Sstevel@tonic-gate * Need to ensure that strsock_proto() will not end up sleeping for 14447c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND, while executing this function. 14457c478bd9Sstevel@tonic-gate */ 14467c478bd9Sstevel@tonic-gate void 14477c478bd9Sstevel@tonic-gate so_drain_discon_ind(struct sonode *so) 14487c478bd9Sstevel@tonic-gate { 14497c478bd9Sstevel@tonic-gate mblk_t *bp; 14507c478bd9Sstevel@tonic-gate void (*func)(struct sonode *so, mblk_t *); 14510f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14547c478bd9Sstevel@tonic-gate ASSERT(so->so_flag & (SOLOCKED|SOASYNC_UNBIND)); 14557c478bd9Sstevel@tonic-gate 14560f1702c5SYu Xiangning /* Process T_DISCON_IND on sti_discon_ind_mp */ 14570f1702c5SYu Xiangning if ((bp = sti->sti_discon_ind_mp) != NULL) { 14580f1702c5SYu Xiangning sti->sti_discon_ind_mp = NULL; 14597c478bd9Sstevel@tonic-gate func = (void (*)())bp->b_prev; 14607c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * This (*func) is supposed to generate a message downstream 14647c478bd9Sstevel@tonic-gate * and we need to have a flag set until the corresponding 14657c478bd9Sstevel@tonic-gate * upstream message reaches stream head. 14667c478bd9Sstevel@tonic-gate * When processing T_DISCON_IND in strsock_discon_ind 14677c478bd9Sstevel@tonic-gate * we hold SOASYN_UNBIND when sending T_UNBIND_REQ down and 14687c478bd9Sstevel@tonic-gate * drop the flag after we get the ACK in strsock_proto. 14697c478bd9Sstevel@tonic-gate */ 14707c478bd9Sstevel@tonic-gate (void) (*func)(so, bp); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate /* 14757c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 14760f1702c5SYu Xiangning * Remove the T_DISCON_IND on sti_discon_ind_mp. 14777c478bd9Sstevel@tonic-gate */ 14787c478bd9Sstevel@tonic-gate void 14797c478bd9Sstevel@tonic-gate so_flush_discon_ind(struct sonode *so) 14807c478bd9Sstevel@tonic-gate { 14817c478bd9Sstevel@tonic-gate mblk_t *bp; 14820f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* 14870f1702c5SYu Xiangning * Remove T_DISCON_IND mblk at sti_discon_ind_mp. 14887c478bd9Sstevel@tonic-gate */ 14890f1702c5SYu Xiangning if ((bp = sti->sti_discon_ind_mp) != NULL) { 14900f1702c5SYu Xiangning sti->sti_discon_ind_mp = NULL; 14917c478bd9Sstevel@tonic-gate bp->b_prev = NULL; 14927c478bd9Sstevel@tonic-gate freemsg(bp); 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate /* 14977c478bd9Sstevel@tonic-gate * Caller must hold the mutex. 14987c478bd9Sstevel@tonic-gate * 14997c478bd9Sstevel@tonic-gate * This function is used to process the T_DISCON_IND message. It does 15007c478bd9Sstevel@tonic-gate * immediate processing when called from strsock_proto and delayed 15010f1702c5SYu Xiangning * processing of discon_ind saved on sti_discon_ind_mp when called from 15027c478bd9Sstevel@tonic-gate * so_drain_discon_ind. When a T_DISCON_IND message is saved in 15030f1702c5SYu Xiangning * sti_discon_ind_mp for delayed processing, this function is registered 15047c478bd9Sstevel@tonic-gate * as the callback function to process the message. 15057c478bd9Sstevel@tonic-gate * 15067c478bd9Sstevel@tonic-gate * SOASYNC_UNBIND should be held in this function, during the non-blocking 15077c478bd9Sstevel@tonic-gate * unbind operation, and should be released only after we receive the ACK 15087c478bd9Sstevel@tonic-gate * in strsock_proto, for the T_UNBIND_REQ sent here. Since SOLOCKED is not set, 15097c478bd9Sstevel@tonic-gate * no TPI messages would be sent down at this time. This is to prevent M_FLUSH 15107c478bd9Sstevel@tonic-gate * sent from either this function or tcp_unbind(), flushing away any TPI 15117c478bd9Sstevel@tonic-gate * message that is being sent down and stays in a lower module's queue. 15127c478bd9Sstevel@tonic-gate * 15137c478bd9Sstevel@tonic-gate * This function drops so_lock and grabs it again. 15147c478bd9Sstevel@tonic-gate */ 15157c478bd9Sstevel@tonic-gate static void 15167c478bd9Sstevel@tonic-gate strsock_discon_ind(struct sonode *so, mblk_t *discon_mp) 15177c478bd9Sstevel@tonic-gate { 15187c478bd9Sstevel@tonic-gate struct vnode *vp; 15197c478bd9Sstevel@tonic-gate struct stdata *stp; 15207c478bd9Sstevel@tonic-gate union T_primitives *tpr; 15217c478bd9Sstevel@tonic-gate struct T_unbind_req *ubr; 15227c478bd9Sstevel@tonic-gate mblk_t *mp; 15237c478bd9Sstevel@tonic-gate int error; 15240f1702c5SYu Xiangning sotpi_info_t *sti = SOTOTPI(so); 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&so->so_lock)); 15277c478bd9Sstevel@tonic-gate ASSERT(discon_mp); 15287c478bd9Sstevel@tonic-gate ASSERT(discon_mp->b_rptr); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)discon_mp->b_rptr; 15317c478bd9Sstevel@tonic-gate ASSERT(tpr->type == T_DISCON_IND); 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate vp = SOTOV(so); 15347c478bd9Sstevel@tonic-gate stp = vp->v_stream; 15357c478bd9Sstevel@tonic-gate ASSERT(stp); 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* 15387c478bd9Sstevel@tonic-gate * Not a listener 15397c478bd9Sstevel@tonic-gate */ 15407c478bd9Sstevel@tonic-gate ASSERT((so->so_state & SS_ACCEPTCONN) == 0); 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate /* 15437c478bd9Sstevel@tonic-gate * This assumes that the name space for DISCON_reason 15447c478bd9Sstevel@tonic-gate * is the errno name space. 15457c478bd9Sstevel@tonic-gate */ 15467c478bd9Sstevel@tonic-gate soisdisconnected(so, tpr->discon_ind.DISCON_reason); 15470f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 15480f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate /* 15517c478bd9Sstevel@tonic-gate * Unbind with the transport without blocking. 15527c478bd9Sstevel@tonic-gate * If we've already received a T_DISCON_IND do not unbind. 15537c478bd9Sstevel@tonic-gate * 15547c478bd9Sstevel@tonic-gate * If there is no preallocated unbind message, we have already 15557c478bd9Sstevel@tonic-gate * unbound with the transport 15567c478bd9Sstevel@tonic-gate * 15577c478bd9Sstevel@tonic-gate * If the socket is not bound, no need to unbind. 15587c478bd9Sstevel@tonic-gate */ 15590f1702c5SYu Xiangning mp = sti->sti_unbind_mp; 15607c478bd9Sstevel@tonic-gate if (mp == NULL) { 15617c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & SS_ISBOUND)); 15627c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 15637c478bd9Sstevel@tonic-gate } else if (!(so->so_state & SS_ISBOUND)) { 15647c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 15657c478bd9Sstevel@tonic-gate } else { 15660f1702c5SYu Xiangning sti->sti_unbind_mp = NULL; 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate /* 15697c478bd9Sstevel@tonic-gate * Is another T_DISCON_IND being processed. 15707c478bd9Sstevel@tonic-gate */ 15717c478bd9Sstevel@tonic-gate ASSERT((so->so_flag & SOASYNC_UNBIND) == 0); 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate /* 15747c478bd9Sstevel@tonic-gate * Make strsock_proto ignore T_OK_ACK and T_ERROR_ACK for 15757c478bd9Sstevel@tonic-gate * this unbind. Set SOASYNC_UNBIND. This should be cleared 15767c478bd9Sstevel@tonic-gate * only after we receive the ACK in strsock_proto. 15777c478bd9Sstevel@tonic-gate */ 15787c478bd9Sstevel@tonic-gate so->so_flag |= SOASYNC_UNBIND; 15797c478bd9Sstevel@tonic-gate ASSERT(!(so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING))); 15800f1702c5SYu Xiangning so->so_state &= ~(SS_ISBOUND|SS_ACCEPTCONN); 15810f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 15827c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate /* 15857c478bd9Sstevel@tonic-gate * Send down T_UNBIND_REQ ignoring flow control. 15867c478bd9Sstevel@tonic-gate * XXX Assumes that MSG_IGNFLOW implies that this thread 15877c478bd9Sstevel@tonic-gate * does not run service procedures. 15887c478bd9Sstevel@tonic-gate */ 15897c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO); 15907c478bd9Sstevel@tonic-gate ubr = (struct T_unbind_req *)mp->b_rptr; 15917c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (*ubr); 15927c478bd9Sstevel@tonic-gate ubr->PRIM_type = T_UNBIND_REQ; 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate /* 15957c478bd9Sstevel@tonic-gate * Flush the read and write side (except stream head read queue) 15967c478bd9Sstevel@tonic-gate * and send down T_UNBIND_REQ. 15977c478bd9Sstevel@tonic-gate */ 15987c478bd9Sstevel@tonic-gate (void) putnextctl1(strvp2wq(SOTOV(so)), M_FLUSH, FLUSHRW); 15997c478bd9Sstevel@tonic-gate error = kstrputmsg(SOTOV(so), mp, NULL, 0, 0, 16007c478bd9Sstevel@tonic-gate MSG_BAND|MSG_HOLDSIG|MSG_IGNERROR|MSG_IGNFLOW, 0); 16017c478bd9Sstevel@tonic-gate /* LINTED - warning: statement has no consequent: if */ 16027c478bd9Sstevel@tonic-gate if (error) { 16037c478bd9Sstevel@tonic-gate eprintsoline(so, error); 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate } 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate if (tpr->discon_ind.DISCON_reason != 0) 16087c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 16097c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 16107c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 16137c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 16147c478bd9Sstevel@tonic-gate */ 16157c478bd9Sstevel@tonic-gate dprintso(so, 1, ("T_DISCON_IND: error %d\n", so->so_error)); 16167c478bd9Sstevel@tonic-gate freemsg(discon_mp); 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate pollwakeup(&stp->sd_pollist, POLLOUT); 16207c478bd9Sstevel@tonic-gate mutex_enter(&stp->sd_lock); 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate /* 16237c478bd9Sstevel@tonic-gate * Wake sleeping write 16247c478bd9Sstevel@tonic-gate */ 16257c478bd9Sstevel@tonic-gate if (stp->sd_flag & WSLEEP) { 16267c478bd9Sstevel@tonic-gate stp->sd_flag &= ~WSLEEP; 16277c478bd9Sstevel@tonic-gate cv_broadcast(&stp->sd_wrq->q_wait); 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate /* 16317c478bd9Sstevel@tonic-gate * strsendsig can handle multiple signals with a 16327c478bd9Sstevel@tonic-gate * single call. Send SIGPOLL for S_OUTPUT event. 16337c478bd9Sstevel@tonic-gate */ 16347c478bd9Sstevel@tonic-gate if (stp->sd_sigflags & S_OUTPUT) 16357c478bd9Sstevel@tonic-gate strsendsig(stp->sd_siglist, S_OUTPUT, 0, 0); 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate mutex_exit(&stp->sd_lock); 16387c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate /* 16427c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive M_PROTO 16437c478bd9Sstevel@tonic-gate * and M_PCPROTO messages. 16447c478bd9Sstevel@tonic-gate * 16457c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 16467c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed (and queued) by the stream 16477c478bd9Sstevel@tonic-gate * head. 16487c478bd9Sstevel@tonic-gate * 16497c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 16507c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. Note that since 16517c478bd9Sstevel@tonic-gate * sockets always deliver SIGIO for every new piece of data this routine 16527c478bd9Sstevel@tonic-gate * never sets *firstmsgsigs; any signals are returned in *allmsgsigs. 16537c478bd9Sstevel@tonic-gate * 16547c478bd9Sstevel@tonic-gate * This routine handles all data related TPI messages independent of 16557c478bd9Sstevel@tonic-gate * the type of the socket i.e. it doesn't care if T_UNITDATA_IND message 16567c478bd9Sstevel@tonic-gate * arrive on a SOCK_STREAM. 16577c478bd9Sstevel@tonic-gate */ 16587c478bd9Sstevel@tonic-gate static mblk_t * 16597c478bd9Sstevel@tonic-gate strsock_proto(vnode_t *vp, mblk_t *mp, 16607c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 16617c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 16627c478bd9Sstevel@tonic-gate { 16637c478bd9Sstevel@tonic-gate union T_primitives *tpr; 16647c478bd9Sstevel@tonic-gate struct sonode *so; 16650f1702c5SYu Xiangning sotpi_info_t *sti; 1666005d3febSMarek Pospisil uint32_t auditing = AU_AUDITING(); 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate so = VTOSO(vp); 16690f1702c5SYu Xiangning sti = SOTOTPI(so); 16707c478bd9Sstevel@tonic-gate 1671903a11ebSrh87107 dprintso(so, 1, ("strsock_proto(%p, %p)\n", (void *)vp, (void *)mp)); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate /* Set default return values */ 16747c478bd9Sstevel@tonic-gate *firstmsgsigs = *wakeups = *allmsgsigs = *pollwakeups = 0; 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_PROTO || 16777c478bd9Sstevel@tonic-gate DB_TYPE(mp) == M_PCPROTO); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (tpr->type)) { 16807c478bd9Sstevel@tonic-gate /* The message is too short to even contain the primitive */ 16812caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 16827c478bd9Sstevel@tonic-gate "sockfs: Too short TPI message received. Len = %ld\n", 16837c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 16847c478bd9Sstevel@tonic-gate freemsg(mp); 16857c478bd9Sstevel@tonic-gate return (NULL); 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate if (!__TPI_PRIM_ISALIGNED(mp->b_rptr)) { 16887c478bd9Sstevel@tonic-gate /* The read pointer is not aligned correctly for TPI */ 16892caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 16907c478bd9Sstevel@tonic-gate "sockfs: Unaligned TPI message received. rptr = %p\n", 16917c478bd9Sstevel@tonic-gate (void *)mp->b_rptr); 16927c478bd9Sstevel@tonic-gate freemsg(mp); 16937c478bd9Sstevel@tonic-gate return (NULL); 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)mp->b_rptr; 16967c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_proto: primitive %d\n", tpr->type)); 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate switch (tpr->type) { 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate case T_DATA_IND: 17017c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_data_ind)) { 17022caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17037c478bd9Sstevel@tonic-gate "sockfs: Too short T_DATA_IND. Len = %ld\n", 17047c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 17057c478bd9Sstevel@tonic-gate freemsg(mp); 17067c478bd9Sstevel@tonic-gate return (NULL); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate /* 17097c478bd9Sstevel@tonic-gate * Ignore zero-length T_DATA_IND messages. These might be 17107c478bd9Sstevel@tonic-gate * generated by some transports. 17117c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 17127c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 17137c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 17147c478bd9Sstevel@tonic-gate * that data is available). 17157c478bd9Sstevel@tonic-gate */ 17167c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 17177c478bd9Sstevel@tonic-gate dprintso(so, 0, 17187c478bd9Sstevel@tonic-gate ("strsock_proto: zero length T_DATA_IND\n")); 17197c478bd9Sstevel@tonic-gate freemsg(mp); 17207c478bd9Sstevel@tonic-gate return (NULL); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 17237c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 17247c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 17257c478bd9Sstevel@tonic-gate return (mp); 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate case T_UNITDATA_IND: { 17287c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi = &tpr->unitdata_ind; 17297c478bd9Sstevel@tonic-gate void *addr; 17307c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_unitdata_ind)) { 17332caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17347c478bd9Sstevel@tonic-gate "sockfs: Too short T_UNITDATA_IND. Len = %ld\n", 17357c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 17367c478bd9Sstevel@tonic-gate freemsg(mp); 17377c478bd9Sstevel@tonic-gate return (NULL); 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate /* Is this is not a connected datagram socket? */ 17417c478bd9Sstevel@tonic-gate if ((so->so_mode & SM_CONNREQUIRED) || 17427c478bd9Sstevel@tonic-gate !(so->so_state & SS_ISCONNECTED)) { 17437c478bd9Sstevel@tonic-gate /* 17447c478bd9Sstevel@tonic-gate * Not a connected datagram socket. Look for 17457c478bd9Sstevel@tonic-gate * the SO_UNIX_CLOSE option. If such an option is found 17467c478bd9Sstevel@tonic-gate * discard the message (since it has no meaning 17477c478bd9Sstevel@tonic-gate * unless connected). 17487c478bd9Sstevel@tonic-gate */ 17497c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp) == 0 && 17507c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 17517c478bd9Sstevel@tonic-gate void *opt; 17527c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 17557c478bd9Sstevel@tonic-gate optlen, __TPI_ALIGN_SIZE); 17567c478bd9Sstevel@tonic-gate if (opt == NULL) { 17577c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 17587c478bd9Sstevel@tonic-gate freemsg(mp); 17597c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 17607c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 17617c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 17622caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 17637c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with " 17647c478bd9Sstevel@tonic-gate "invalid optlen/offset %u/%d\n", 17657c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 17667c478bd9Sstevel@tonic-gate return (NULL); 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 17697c478bd9Sstevel@tonic-gate freemsg(mp); 17707c478bd9Sstevel@tonic-gate return (NULL); 17717c478bd9Sstevel@tonic-gate } 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 17747c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 17757c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 1776005d3febSMarek Pospisil if (auditing) 17777c478bd9Sstevel@tonic-gate audit_sock(T_UNITDATA_IND, strvp2wq(vp), 17787c478bd9Sstevel@tonic-gate mp, 0); 17797c478bd9Sstevel@tonic-gate return (mp); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* 17837c478bd9Sstevel@tonic-gate * A connect datagram socket. For AF_INET{,6} we verify that 17847c478bd9Sstevel@tonic-gate * the source address matches the "connected to" address. 17857c478bd9Sstevel@tonic-gate * The semantics of AF_UNIX sockets is to not verify 17867c478bd9Sstevel@tonic-gate * the source address. 17877c478bd9Sstevel@tonic-gate * Note that this source address verification is transport 17887c478bd9Sstevel@tonic-gate * specific. Thus the real fix would be to extent TPI 17897c478bd9Sstevel@tonic-gate * to allow T_CONN_REQ messages to be send to connectionless 17907c478bd9Sstevel@tonic-gate * transport providers and always let the transport provider 17917c478bd9Sstevel@tonic-gate * do whatever filtering is needed. 17927c478bd9Sstevel@tonic-gate * 17937c478bd9Sstevel@tonic-gate * The verification/filtering semantics for transports 17947c478bd9Sstevel@tonic-gate * other than AF_INET and AF_UNIX are unknown. The choice 17957c478bd9Sstevel@tonic-gate * would be to either filter using bcmp or let all messages 17967c478bd9Sstevel@tonic-gate * get through. This code does not filter other address 17977c478bd9Sstevel@tonic-gate * families since this at least allows the application to 17987c478bd9Sstevel@tonic-gate * work around any missing filtering. 17997c478bd9Sstevel@tonic-gate * 18007c478bd9Sstevel@tonic-gate * XXX Should we move filtering to UDP/ICMP??? 18017c478bd9Sstevel@tonic-gate * That would require passing e.g. a T_DISCON_REQ to UDP 18027c478bd9Sstevel@tonic-gate * when the socket becomes unconnected. 18037c478bd9Sstevel@tonic-gate */ 18047c478bd9Sstevel@tonic-gate addrlen = tudi->SRC_length; 18057c478bd9Sstevel@tonic-gate /* 18067c478bd9Sstevel@tonic-gate * The alignment restriction is really to strict but 18077c478bd9Sstevel@tonic-gate * we want enough alignment to inspect the fields of 18087c478bd9Sstevel@tonic-gate * a sockaddr_in. 18097c478bd9Sstevel@tonic-gate */ 18107c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->SRC_offset, addrlen, 18117c478bd9Sstevel@tonic-gate __TPI_ALIGN_SIZE); 18127c478bd9Sstevel@tonic-gate if (addr == NULL) { 18137c478bd9Sstevel@tonic-gate freemsg(mp); 18147c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18157c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 18167c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18172caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 18187c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with invalid " 18197c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 18207c478bd9Sstevel@tonic-gate addrlen, tudi->SRC_offset); 18217c478bd9Sstevel@tonic-gate return (NULL); 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate if (so->so_family == AF_INET) { 18257c478bd9Sstevel@tonic-gate /* 18267c478bd9Sstevel@tonic-gate * For AF_INET we allow wildcarding both sin_addr 18277c478bd9Sstevel@tonic-gate * and sin_port. 18287c478bd9Sstevel@tonic-gate */ 18297c478bd9Sstevel@tonic-gate struct sockaddr_in *faddr, *sin; 18307c478bd9Sstevel@tonic-gate 18310f1702c5SYu Xiangning /* Prevent sti_faddr_sa from changing while accessed */ 18327c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18330f1702c5SYu Xiangning ASSERT(sti->sti_faddr_len == 18347c478bd9Sstevel@tonic-gate (socklen_t)sizeof (struct sockaddr_in)); 18350f1702c5SYu Xiangning faddr = (struct sockaddr_in *)sti->sti_faddr_sa; 18367c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)addr; 18377c478bd9Sstevel@tonic-gate if (addrlen != 18387c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct sockaddr_in) || 18397c478bd9Sstevel@tonic-gate (sin->sin_addr.s_addr != faddr->sin_addr.s_addr && 18407c478bd9Sstevel@tonic-gate faddr->sin_addr.s_addr != INADDR_ANY) || 18417c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 18427c478bd9Sstevel@tonic-gate sin->sin_port != faddr->sin_port && 18437c478bd9Sstevel@tonic-gate faddr->sin_port != 0)) { 18447c478bd9Sstevel@tonic-gate #ifdef DEBUG 18457c478bd9Sstevel@tonic-gate dprintso(so, 0, 18467c478bd9Sstevel@tonic-gate ("sockfs: T_UNITDATA_IND mismatch: %s", 18477c478bd9Sstevel@tonic-gate pr_addr(so->so_family, 18480f1702c5SYu Xiangning (struct sockaddr *)addr, addrlen))); 18497c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 18500f1702c5SYu Xiangning pr_addr(so->so_family, sti->sti_faddr_sa, 18510f1702c5SYu Xiangning (t_uscalar_t)sti->sti_faddr_len))); 18527c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 18537c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18547c478bd9Sstevel@tonic-gate freemsg(mp); 18557c478bd9Sstevel@tonic-gate return (NULL); 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18587c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_INET6) { 18597c478bd9Sstevel@tonic-gate /* 18607c478bd9Sstevel@tonic-gate * For AF_INET6 we allow wildcarding both sin6_addr 18617c478bd9Sstevel@tonic-gate * and sin6_port. 18627c478bd9Sstevel@tonic-gate */ 18637c478bd9Sstevel@tonic-gate struct sockaddr_in6 *faddr6, *sin6; 18647c478bd9Sstevel@tonic-gate static struct in6_addr zeroes; /* inits to all zeros */ 18657c478bd9Sstevel@tonic-gate 18660f1702c5SYu Xiangning /* Prevent sti_faddr_sa from changing while accessed */ 18677c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 18680f1702c5SYu Xiangning ASSERT(sti->sti_faddr_len == 18697c478bd9Sstevel@tonic-gate (socklen_t)sizeof (struct sockaddr_in6)); 18700f1702c5SYu Xiangning faddr6 = (struct sockaddr_in6 *)sti->sti_faddr_sa; 18717c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)addr; 18727c478bd9Sstevel@tonic-gate /* XXX could we get a mapped address ::ffff:0.0.0.0 ? */ 18737c478bd9Sstevel@tonic-gate if (addrlen != 18747c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct sockaddr_in6) || 18757c478bd9Sstevel@tonic-gate (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 18767c478bd9Sstevel@tonic-gate &faddr6->sin6_addr) && 18777c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&faddr6->sin6_addr, &zeroes)) || 18787c478bd9Sstevel@tonic-gate (so->so_type != SOCK_RAW && 18797c478bd9Sstevel@tonic-gate sin6->sin6_port != faddr6->sin6_port && 18807c478bd9Sstevel@tonic-gate faddr6->sin6_port != 0)) { 18817c478bd9Sstevel@tonic-gate #ifdef DEBUG 18827c478bd9Sstevel@tonic-gate dprintso(so, 0, 18837c478bd9Sstevel@tonic-gate ("sockfs: T_UNITDATA_IND mismatch: %s", 18847c478bd9Sstevel@tonic-gate pr_addr(so->so_family, 18850f1702c5SYu Xiangning (struct sockaddr *)addr, addrlen))); 18867c478bd9Sstevel@tonic-gate dprintso(so, 0, (" - %s\n", 18870f1702c5SYu Xiangning pr_addr(so->so_family, sti->sti_faddr_sa, 18880f1702c5SYu Xiangning (t_uscalar_t)sti->sti_faddr_len))); 18897c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 18907c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18917c478bd9Sstevel@tonic-gate freemsg(mp); 18927c478bd9Sstevel@tonic-gate return (NULL); 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 18957c478bd9Sstevel@tonic-gate } else if (so->so_family == AF_UNIX && 18967c478bd9Sstevel@tonic-gate msgdsize(mp->b_cont) == 0 && 18977c478bd9Sstevel@tonic-gate tudi->OPT_length != 0) { 18987c478bd9Sstevel@tonic-gate /* 18997c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX 19007c478bd9Sstevel@tonic-gate * SO_UNIX_CLOSE indication from options. 19017c478bd9Sstevel@tonic-gate */ 19027c478bd9Sstevel@tonic-gate void *opt; 19037c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tudi->OPT_length; 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tudi->OPT_offset, 19067c478bd9Sstevel@tonic-gate optlen, __TPI_ALIGN_SIZE); 19077c478bd9Sstevel@tonic-gate if (opt == NULL) { 19087c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 19097c478bd9Sstevel@tonic-gate freemsg(mp); 19107c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 19117c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 19127c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19132caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 19147c478bd9Sstevel@tonic-gate "sockfs: T_unidata_ind with invalid " 19157c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 19167c478bd9Sstevel@tonic-gate optlen, tudi->OPT_offset); 19177c478bd9Sstevel@tonic-gate return (NULL); 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate /* 19207c478bd9Sstevel@tonic-gate * If we received a unix close indication mark the 19217c478bd9Sstevel@tonic-gate * socket and discard this message. 19227c478bd9Sstevel@tonic-gate */ 19237c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 19247c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 19257c478bd9Sstevel@tonic-gate sobreakconn(so, ECONNRESET); 19267c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19277c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 19287c478bd9Sstevel@tonic-gate freemsg(mp); 19297c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19307c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19317c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19327c478bd9Sstevel@tonic-gate return (NULL); 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19367c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19377c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19387c478bd9Sstevel@tonic-gate return (mp); 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate case T_OPTDATA_IND: { 19427c478bd9Sstevel@tonic-gate struct T_optdata_ind *tdi = &tpr->optdata_ind; 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optdata_ind)) { 19452caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 19467c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTDATA_IND. Len = %ld\n", 19477c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 19487c478bd9Sstevel@tonic-gate freemsg(mp); 19497c478bd9Sstevel@tonic-gate return (NULL); 19507c478bd9Sstevel@tonic-gate } 19517c478bd9Sstevel@tonic-gate /* 19527c478bd9Sstevel@tonic-gate * Allow zero-length messages carrying options. 19537c478bd9Sstevel@tonic-gate * This is used when carrying the SO_UNIX_CLOSE option. 19547c478bd9Sstevel@tonic-gate */ 19557c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && msgdsize(mp->b_cont) == 0 && 19567c478bd9Sstevel@tonic-gate tdi->OPT_length != 0) { 19577c478bd9Sstevel@tonic-gate /* 19587c478bd9Sstevel@tonic-gate * Attempt to extract AF_UNIX close indication 19597c478bd9Sstevel@tonic-gate * from the options. Ignore any other options - 19607c478bd9Sstevel@tonic-gate * those are handled once the message is removed 19617c478bd9Sstevel@tonic-gate * from the queue. 19627c478bd9Sstevel@tonic-gate * The close indication message should not carry data. 19637c478bd9Sstevel@tonic-gate */ 19647c478bd9Sstevel@tonic-gate void *opt; 19657c478bd9Sstevel@tonic-gate t_uscalar_t optlen = tdi->OPT_length; 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate opt = sogetoff(mp, tdi->OPT_offset, 19687c478bd9Sstevel@tonic-gate optlen, __TPI_ALIGN_SIZE); 19697c478bd9Sstevel@tonic-gate if (opt == NULL) { 19707c478bd9Sstevel@tonic-gate /* The len/off falls outside mp */ 19717c478bd9Sstevel@tonic-gate freemsg(mp); 19727c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 19737c478bd9Sstevel@tonic-gate soseterror(so, EPROTO); 19747c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19752caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 19767c478bd9Sstevel@tonic-gate "sockfs: T_optdata_ind with invalid " 19777c478bd9Sstevel@tonic-gate "optlen/offset %u/%d\n", 19787c478bd9Sstevel@tonic-gate optlen, tdi->OPT_offset); 19797c478bd9Sstevel@tonic-gate return (NULL); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate /* 19827c478bd9Sstevel@tonic-gate * If we received a close indication mark the 19837c478bd9Sstevel@tonic-gate * socket and discard this message. 19847c478bd9Sstevel@tonic-gate */ 19857c478bd9Sstevel@tonic-gate if (so_getopt_unix_close(opt, optlen)) { 19867c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 19877c478bd9Sstevel@tonic-gate socantsendmore(so); 19880f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 19897c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 19907c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 19917c478bd9Sstevel@tonic-gate freemsg(mp); 19927c478bd9Sstevel@tonic-gate return (NULL); 19937c478bd9Sstevel@tonic-gate } 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 19967c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 19977c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 19987c478bd9Sstevel@tonic-gate return (mp); 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate case T_EXDATA_IND: { 20027c478bd9Sstevel@tonic-gate mblk_t *mctl, *mdata; 2003e63f9565Sss146032 mblk_t *lbp; 2004e63f9565Sss146032 union T_primitives *tprp; 2005e63f9565Sss146032 struct stdata *stp; 2006e63f9565Sss146032 queue_t *qp; 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_exdata_ind)) { 20092caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 20107c478bd9Sstevel@tonic-gate "sockfs: Too short T_EXDATA_IND. Len = %ld\n", 20117c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 20127c478bd9Sstevel@tonic-gate freemsg(mp); 20137c478bd9Sstevel@tonic-gate return (NULL); 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate /* 20167c478bd9Sstevel@tonic-gate * Ignore zero-length T_EXDATA_IND messages. These might be 20177c478bd9Sstevel@tonic-gate * generated by some transports. 20187c478bd9Sstevel@tonic-gate * 20197c478bd9Sstevel@tonic-gate * This is needed to prevent read (which skips the M_PROTO 20207c478bd9Sstevel@tonic-gate * part) to unexpectedly return 0 (or return EWOULDBLOCK 20217c478bd9Sstevel@tonic-gate * on a non-blocking socket after select/poll has indicated 20227c478bd9Sstevel@tonic-gate * that data is available). 20237c478bd9Sstevel@tonic-gate */ 20247c478bd9Sstevel@tonic-gate dprintso(so, 1, 20257c478bd9Sstevel@tonic-gate ("T_EXDATA_IND(%p): counts %d/%d state %s\n", 20260f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt, 20277c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate if (msgdsize(mp->b_cont) == 0) { 20307c478bd9Sstevel@tonic-gate dprintso(so, 0, 20317c478bd9Sstevel@tonic-gate ("strsock_proto: zero length T_EXDATA_IND\n")); 20327c478bd9Sstevel@tonic-gate freemsg(mp); 20337c478bd9Sstevel@tonic-gate return (NULL); 20347c478bd9Sstevel@tonic-gate } 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate /* 20377c478bd9Sstevel@tonic-gate * Split into the T_EXDATA_IND and the M_DATA part. 20387c478bd9Sstevel@tonic-gate * We process these three pieces separately: 20397c478bd9Sstevel@tonic-gate * signal generation 20407c478bd9Sstevel@tonic-gate * handling T_EXDATA_IND 20417c478bd9Sstevel@tonic-gate * handling M_DATA component 20427c478bd9Sstevel@tonic-gate */ 20437c478bd9Sstevel@tonic-gate mctl = mp; 20447c478bd9Sstevel@tonic-gate mdata = mctl->b_cont; 20457c478bd9Sstevel@tonic-gate mctl->b_cont = NULL; 20467c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 20477c478bd9Sstevel@tonic-gate so_oob_sig(so, 0, allmsgsigs, pollwakeups); 20487c478bd9Sstevel@tonic-gate mctl = so_oob_exdata(so, mctl, allmsgsigs, pollwakeups); 20497c478bd9Sstevel@tonic-gate mdata = so_oob_data(so, mdata, allmsgsigs, pollwakeups); 20507c478bd9Sstevel@tonic-gate 2051e63f9565Sss146032 stp = vp->v_stream; 2052e63f9565Sss146032 ASSERT(stp != NULL); 2053e63f9565Sss146032 qp = _RD(stp->sd_wrq); 2054e63f9565Sss146032 2055e63f9565Sss146032 mutex_enter(QLOCK(qp)); 2056e63f9565Sss146032 lbp = qp->q_last; 2057e63f9565Sss146032 2058e63f9565Sss146032 /* 2059e63f9565Sss146032 * We want to avoid queueing up a string of T_EXDATA_IND 2060e63f9565Sss146032 * messages with no intervening data messages at the stream 2061e63f9565Sss146032 * head. These messages contribute to the total message 2062e63f9565Sss146032 * count. Eventually this can lead to STREAMS flow contol 2063e63f9565Sss146032 * and also cause TCP to advertise a zero window condition 2064e63f9565Sss146032 * to the peer. This can happen in the degenerate case where 2065e63f9565Sss146032 * the sender and receiver exchange only OOB data. The sender 2066e63f9565Sss146032 * only sends messages with MSG_OOB flag and the receiver 2067e63f9565Sss146032 * receives only MSG_OOB messages and does not use SO_OOBINLINE. 2068e63f9565Sss146032 * An example of this scenario has been reported in applications 2069e63f9565Sss146032 * that use OOB data to exchange heart beats. Flow control 2070e63f9565Sss146032 * relief will never happen if the application only reads OOB 2071e63f9565Sss146032 * data which is done directly by sorecvoob() and the 2072e63f9565Sss146032 * T_EXDATA_IND messages at the streamhead won't be consumed. 2073e63f9565Sss146032 * Note that there is no correctness issue in compressing the 2074e63f9565Sss146032 * string of T_EXDATA_IND messages into a single T_EXDATA_IND 2075e63f9565Sss146032 * message. A single read that does not specify MSG_OOB will 2076e63f9565Sss146032 * read across all the marks in a loop in sotpi_recvmsg(). 2077e63f9565Sss146032 * Each mark is individually distinguishable only if the 2078e63f9565Sss146032 * T_EXDATA_IND messages are separated by data messages. 2079e63f9565Sss146032 */ 2080e63f9565Sss146032 if ((qp->q_first != NULL) && (DB_TYPE(lbp) == M_PROTO)) { 2081e63f9565Sss146032 tprp = (union T_primitives *)lbp->b_rptr; 2082e63f9565Sss146032 if ((tprp->type == T_EXDATA_IND) && 2083e63f9565Sss146032 !(so->so_options & SO_OOBINLINE)) { 2084e63f9565Sss146032 2085e63f9565Sss146032 /* 2086e63f9565Sss146032 * free the new M_PROTO message 2087e63f9565Sss146032 */ 2088e63f9565Sss146032 freemsg(mctl); 2089e63f9565Sss146032 2090e63f9565Sss146032 /* 2091e63f9565Sss146032 * adjust the OOB count and OOB signal count 2092e63f9565Sss146032 * just incremented for the new OOB data. 2093e63f9565Sss146032 */ 20940f1702c5SYu Xiangning sti->sti_oobcnt--; 20950f1702c5SYu Xiangning sti->sti_oobsigcnt--; 2096e63f9565Sss146032 mutex_exit(QLOCK(qp)); 2097e63f9565Sss146032 mutex_exit(&so->so_lock); 2098e63f9565Sss146032 return (NULL); 2099e63f9565Sss146032 } 2100e63f9565Sss146032 } 2101e63f9565Sss146032 mutex_exit(QLOCK(qp)); 2102e63f9565Sss146032 21037c478bd9Sstevel@tonic-gate /* 21047c478bd9Sstevel@tonic-gate * Pass the T_EXDATA_IND and the M_DATA back separately 21057c478bd9Sstevel@tonic-gate * by using b_next linkage. (The stream head will queue any 21067c478bd9Sstevel@tonic-gate * b_next linked messages separately.) This is needed 21077c478bd9Sstevel@tonic-gate * since MSGMARK applies to the last by of the message 21087c478bd9Sstevel@tonic-gate * hence we can not have any M_DATA component attached 21097c478bd9Sstevel@tonic-gate * to the marked T_EXDATA_IND. Note that the stream head 21107c478bd9Sstevel@tonic-gate * will not consolidate M_DATA messages onto an MSGMARK'ed 21117c478bd9Sstevel@tonic-gate * message in order to preserve the constraint that 21127c478bd9Sstevel@tonic-gate * the T_EXDATA_IND always is a separate message. 21137c478bd9Sstevel@tonic-gate */ 21147c478bd9Sstevel@tonic-gate ASSERT(mctl != NULL); 21157c478bd9Sstevel@tonic-gate mctl->b_next = mdata; 21167c478bd9Sstevel@tonic-gate mp = mctl; 21177c478bd9Sstevel@tonic-gate #ifdef DEBUG 21187c478bd9Sstevel@tonic-gate if (mdata == NULL) { 21197c478bd9Sstevel@tonic-gate dprintso(so, 1, 21207c478bd9Sstevel@tonic-gate ("after outofline T_EXDATA_IND(%p): " 21217c478bd9Sstevel@tonic-gate "counts %d/%d poll 0x%x sig 0x%x state %s\n", 21220f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, 21230f1702c5SYu Xiangning sti->sti_oobcnt, *pollwakeups, *allmsgsigs, 21247c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 21257c478bd9Sstevel@tonic-gate } else { 21267c478bd9Sstevel@tonic-gate dprintso(so, 1, 21277c478bd9Sstevel@tonic-gate ("after inline T_EXDATA_IND(%p): " 21287c478bd9Sstevel@tonic-gate "counts %d/%d poll 0x%x sig 0x%x state %s\n", 21290f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, 21300f1702c5SYu Xiangning sti->sti_oobcnt, *pollwakeups, *allmsgsigs, 21317c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 21347c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21357c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 21367c478bd9Sstevel@tonic-gate return (mp); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate case T_CONN_CON: { 21407c478bd9Sstevel@tonic-gate struct T_conn_con *conn_con; 21417c478bd9Sstevel@tonic-gate void *addr; 21427c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 21437c478bd9Sstevel@tonic-gate 21447c478bd9Sstevel@tonic-gate /* 21457c478bd9Sstevel@tonic-gate * Verify the state, update the state to ISCONNECTED, 21467c478bd9Sstevel@tonic-gate * record the potentially new address in the message, 21477c478bd9Sstevel@tonic-gate * and drop the message. 21487c478bd9Sstevel@tonic-gate */ 21497c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_con)) { 21502caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 21517c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_CON. Len = %ld\n", 21527c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 21537c478bd9Sstevel@tonic-gate freemsg(mp); 21547c478bd9Sstevel@tonic-gate return (NULL); 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 21587c478bd9Sstevel@tonic-gate if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) != 21597c478bd9Sstevel@tonic-gate SS_ISCONNECTING) { 21607c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21617c478bd9Sstevel@tonic-gate dprintso(so, 1, 21627c478bd9Sstevel@tonic-gate ("T_CONN_CON: state %x\n", so->so_state)); 21637c478bd9Sstevel@tonic-gate freemsg(mp); 21647c478bd9Sstevel@tonic-gate return (NULL); 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate conn_con = &tpr->conn_con; 21687c478bd9Sstevel@tonic-gate addrlen = conn_con->RES_length; 21697c478bd9Sstevel@tonic-gate /* 21707c478bd9Sstevel@tonic-gate * Allow the address to be of different size than sent down 21717c478bd9Sstevel@tonic-gate * in the T_CONN_REQ as long as it doesn't exceed the maxlen. 21727c478bd9Sstevel@tonic-gate * For AF_UNIX require the identical length. 21737c478bd9Sstevel@tonic-gate */ 21747c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX ? 21750f1702c5SYu Xiangning addrlen != (t_uscalar_t)sizeof (sti->sti_ux_laddr) : 21760f1702c5SYu Xiangning addrlen > (t_uscalar_t)sti->sti_faddr_maxlen) { 21772caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 21787c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with different " 21797c478bd9Sstevel@tonic-gate "length %u/%d\n", 21807c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_length); 21817c478bd9Sstevel@tonic-gate soisdisconnected(so, EPROTO); 21820f1702c5SYu Xiangning sti->sti_laddr_valid = 0; 21830f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 21847c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 21857c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 21867c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 21877c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 21887c478bd9Sstevel@tonic-gate freemsg(mp); 21897c478bd9Sstevel@tonic-gate /* 21907c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 21917c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 21927c478bd9Sstevel@tonic-gate */ 21937c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 21947c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 21957c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 21967c478bd9Sstevel@tonic-gate return (NULL); 21977c478bd9Sstevel@tonic-gate } 21987c478bd9Sstevel@tonic-gate addr = sogetoff(mp, conn_con->RES_offset, addrlen, 1); 21997c478bd9Sstevel@tonic-gate if (addr == NULL) { 22002caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22017c478bd9Sstevel@tonic-gate "sockfs: T_conn_con with invalid " 22027c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 22037c478bd9Sstevel@tonic-gate addrlen, conn_con->RES_offset); 22047c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 22057c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 22067c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 22077c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 22087c478bd9Sstevel@tonic-gate freemsg(mp); 22097c478bd9Sstevel@tonic-gate /* 22107c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 22117c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 22127c478bd9Sstevel@tonic-gate */ 22137c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 22147c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 22157c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 22167c478bd9Sstevel@tonic-gate return (NULL); 22177c478bd9Sstevel@tonic-gate } 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate /* 22207c478bd9Sstevel@tonic-gate * Save for getpeername. 22217c478bd9Sstevel@tonic-gate */ 22227c478bd9Sstevel@tonic-gate if (so->so_family != AF_UNIX) { 22230f1702c5SYu Xiangning sti->sti_faddr_len = (socklen_t)addrlen; 22240f1702c5SYu Xiangning ASSERT(sti->sti_faddr_len <= sti->sti_faddr_maxlen); 22250f1702c5SYu Xiangning bcopy(addr, sti->sti_faddr_sa, addrlen); 22260f1702c5SYu Xiangning sti->sti_faddr_valid = 1; 22277c478bd9Sstevel@tonic-gate } 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 22307c478bd9Sstevel@tonic-gate crfree(so->so_peercred); 2231de8c4a14SErik Nordmark so->so_peercred = msg_getcred(mp, &so->so_cpid); 22327c478bd9Sstevel@tonic-gate if (so->so_peercred != NULL) 22337c478bd9Sstevel@tonic-gate crhold(so->so_peercred); 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate /* Wakeup anybody sleeping in sowaitconnected */ 22367c478bd9Sstevel@tonic-gate soisconnected(so); 22377c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 22387c478bd9Sstevel@tonic-gate 22397c478bd9Sstevel@tonic-gate /* 22407c478bd9Sstevel@tonic-gate * The socket is now available for sending data. 22417c478bd9Sstevel@tonic-gate */ 22427c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 22437c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 22447c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 22457c478bd9Sstevel@tonic-gate freemsg(mp); 22467c478bd9Sstevel@tonic-gate return (NULL); 22477c478bd9Sstevel@tonic-gate } 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate case T_CONN_IND: 22507c478bd9Sstevel@tonic-gate /* 22517c478bd9Sstevel@tonic-gate * Verify the min size and queue the message on 22520f1702c5SYu Xiangning * the sti_conn_ind_head/tail list. 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_conn_ind)) { 22552caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22567c478bd9Sstevel@tonic-gate "sockfs: Too short T_CONN_IND. Len = %ld\n", 22577c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 22587c478bd9Sstevel@tonic-gate freemsg(mp); 22597c478bd9Sstevel@tonic-gate return (NULL); 22607c478bd9Sstevel@tonic-gate } 22617c478bd9Sstevel@tonic-gate 2262005d3febSMarek Pospisil if (auditing) 22637c478bd9Sstevel@tonic-gate audit_sock(T_CONN_IND, strvp2wq(vp), mp, 0); 22647c478bd9Sstevel@tonic-gate if (!(so->so_state & SS_ACCEPTCONN)) { 22652caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22667c478bd9Sstevel@tonic-gate "sockfs: T_conn_ind on non-listening socket\n"); 22677c478bd9Sstevel@tonic-gate freemsg(mp); 22687c478bd9Sstevel@tonic-gate return (NULL); 22697c478bd9Sstevel@tonic-gate } 2270c28749e9Skais 22717c478bd9Sstevel@tonic-gate soqueueconnind(so, mp); 22727c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM; 22737c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM; 22747c478bd9Sstevel@tonic-gate *wakeups = RSLEEP; 22757c478bd9Sstevel@tonic-gate return (NULL); 22767c478bd9Sstevel@tonic-gate 22777c478bd9Sstevel@tonic-gate case T_ORDREL_IND: 22787c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ordrel_ind)) { 22792caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 22807c478bd9Sstevel@tonic-gate "sockfs: Too short T_ORDREL_IND. Len = %ld\n", 22817c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 22827c478bd9Sstevel@tonic-gate freemsg(mp); 22837c478bd9Sstevel@tonic-gate return (NULL); 22847c478bd9Sstevel@tonic-gate } 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate /* 22877c478bd9Sstevel@tonic-gate * Some providers send this when not fully connected. 22887c478bd9Sstevel@tonic-gate * SunLink X.25 needs to retrieve disconnect reason after 22897c478bd9Sstevel@tonic-gate * disconnect for compatibility. It uses T_ORDREL_IND 22907c478bd9Sstevel@tonic-gate * instead of T_DISCON_IND so that it may use the 22917c478bd9Sstevel@tonic-gate * endpoint after a connect failure to retrieve the 22927c478bd9Sstevel@tonic-gate * reason using an ioctl. Thus we explicitly clear 22937c478bd9Sstevel@tonic-gate * SS_ISCONNECTING here for SunLink X.25. 22947c478bd9Sstevel@tonic-gate * This is a needed TPI violation. 22957c478bd9Sstevel@tonic-gate */ 22967c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 22977c478bd9Sstevel@tonic-gate so->so_state &= ~SS_ISCONNECTING; 22987c478bd9Sstevel@tonic-gate socantrcvmore(so); 22997c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23007c478bd9Sstevel@tonic-gate strseteof(SOTOV(so), 1); 23017c478bd9Sstevel@tonic-gate /* 23027c478bd9Sstevel@tonic-gate * strseteof takes care of read side wakeups, 23037c478bd9Sstevel@tonic-gate * pollwakeups, and signals. 23047c478bd9Sstevel@tonic-gate */ 23057c478bd9Sstevel@tonic-gate freemsg(mp); 23067c478bd9Sstevel@tonic-gate return (NULL); 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate case T_DISCON_IND: 23097c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_discon_ind)) { 23102caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23117c478bd9Sstevel@tonic-gate "sockfs: Too short T_DISCON_IND. Len = %ld\n", 23127c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 23137c478bd9Sstevel@tonic-gate freemsg(mp); 23147c478bd9Sstevel@tonic-gate return (NULL); 23157c478bd9Sstevel@tonic-gate } 23167c478bd9Sstevel@tonic-gate if (so->so_state & SS_ACCEPTCONN) { 23177c478bd9Sstevel@tonic-gate /* 23187c478bd9Sstevel@tonic-gate * This is a listener. Look for a queued T_CONN_IND 23197c478bd9Sstevel@tonic-gate * with a matching sequence number and remove it 23207c478bd9Sstevel@tonic-gate * from the list. 23217c478bd9Sstevel@tonic-gate * It is normal to not find the sequence number since 23227c478bd9Sstevel@tonic-gate * the soaccept might have already dequeued it 23237c478bd9Sstevel@tonic-gate * (in which case the T_CONN_RES will fail with 23247c478bd9Sstevel@tonic-gate * TBADSEQ). 23257c478bd9Sstevel@tonic-gate */ 23267c478bd9Sstevel@tonic-gate (void) soflushconnind(so, tpr->discon_ind.SEQ_number); 23277c478bd9Sstevel@tonic-gate freemsg(mp); 23287c478bd9Sstevel@tonic-gate return (0); 23297c478bd9Sstevel@tonic-gate } 23307c478bd9Sstevel@tonic-gate 23317c478bd9Sstevel@tonic-gate /* 23327c478bd9Sstevel@tonic-gate * Not a listener 23337c478bd9Sstevel@tonic-gate * 23347c478bd9Sstevel@tonic-gate * If SS_CANTRCVMORE for AF_UNIX ignore the discon_reason. 23357c478bd9Sstevel@tonic-gate * Such a discon_ind appears when the peer has first done 23367c478bd9Sstevel@tonic-gate * a shutdown() followed by a close() in which case we just 23377c478bd9Sstevel@tonic-gate * want to record socantsendmore. 23387c478bd9Sstevel@tonic-gate * In this case sockfs first receives a T_ORDREL_IND followed 23397c478bd9Sstevel@tonic-gate * by a T_DISCON_IND. 23407c478bd9Sstevel@tonic-gate * Note that for other transports (e.g. TCP) we need to handle 23417c478bd9Sstevel@tonic-gate * the discon_ind in this case since it signals an error. 23427c478bd9Sstevel@tonic-gate */ 23437c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 23447c478bd9Sstevel@tonic-gate if ((so->so_state & SS_CANTRCVMORE) && 23457c478bd9Sstevel@tonic-gate (so->so_family == AF_UNIX)) { 23467c478bd9Sstevel@tonic-gate socantsendmore(so); 23470f1702c5SYu Xiangning sti->sti_faddr_valid = 0; 23487c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23497c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 23507c478bd9Sstevel@tonic-gate dprintso(so, 1, 23517c478bd9Sstevel@tonic-gate ("T_DISCON_IND: error %d\n", so->so_error)); 23527c478bd9Sstevel@tonic-gate freemsg(mp); 23537c478bd9Sstevel@tonic-gate /* 23547c478bd9Sstevel@tonic-gate * Set these variables for caller to process them. 23557c478bd9Sstevel@tonic-gate * For the else part where T_DISCON_IND is processed, 23567c478bd9Sstevel@tonic-gate * this will be done in the function being called 23577c478bd9Sstevel@tonic-gate * (strsock_discon_ind()) 23587c478bd9Sstevel@tonic-gate */ 23597c478bd9Sstevel@tonic-gate *wakeups = WSLEEP; 23607c478bd9Sstevel@tonic-gate *allmsgsigs = S_OUTPUT; 23617c478bd9Sstevel@tonic-gate *pollwakeups = POLLOUT; 23627c478bd9Sstevel@tonic-gate } else if (so->so_flag & (SOASYNC_UNBIND | SOLOCKED)) { 23637c478bd9Sstevel@tonic-gate /* 23647c478bd9Sstevel@tonic-gate * Deferred processing of T_DISCON_IND 23657c478bd9Sstevel@tonic-gate */ 23667c478bd9Sstevel@tonic-gate so_save_discon_ind(so, mp, strsock_discon_ind); 23677c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23687c478bd9Sstevel@tonic-gate } else { 23697c478bd9Sstevel@tonic-gate /* 23707c478bd9Sstevel@tonic-gate * Process T_DISCON_IND now 23717c478bd9Sstevel@tonic-gate */ 23727c478bd9Sstevel@tonic-gate (void) strsock_discon_ind(so, mp); 23737c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate return (NULL); 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate case T_UDERROR_IND: { 23787c478bd9Sstevel@tonic-gate struct T_uderror_ind *tudi = &tpr->uderror_ind; 23797c478bd9Sstevel@tonic-gate void *addr; 23807c478bd9Sstevel@tonic-gate t_uscalar_t addrlen; 23817c478bd9Sstevel@tonic-gate int error; 23827c478bd9Sstevel@tonic-gate 23837c478bd9Sstevel@tonic-gate dprintso(so, 0, 23847c478bd9Sstevel@tonic-gate ("T_UDERROR_IND: error %d\n", tudi->ERROR_type)); 23857c478bd9Sstevel@tonic-gate 23867c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_uderror_ind)) { 23872caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23887c478bd9Sstevel@tonic-gate "sockfs: Too short T_UDERROR_IND. Len = %ld\n", 23897c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 23907c478bd9Sstevel@tonic-gate freemsg(mp); 23917c478bd9Sstevel@tonic-gate return (NULL); 23927c478bd9Sstevel@tonic-gate } 23937c478bd9Sstevel@tonic-gate /* Ignore on connection-oriented transports */ 23947c478bd9Sstevel@tonic-gate if (so->so_mode & SM_CONNREQUIRED) { 23957c478bd9Sstevel@tonic-gate freemsg(mp); 23967c478bd9Sstevel@tonic-gate eprintsoline(so, 0); 23972caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 23987c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind on connection-oriented " 23997c478bd9Sstevel@tonic-gate "transport\n"); 24007c478bd9Sstevel@tonic-gate return (NULL); 24017c478bd9Sstevel@tonic-gate } 24027c478bd9Sstevel@tonic-gate addrlen = tudi->DEST_length; 24037c478bd9Sstevel@tonic-gate addr = sogetoff(mp, tudi->DEST_offset, addrlen, 1); 24047c478bd9Sstevel@tonic-gate if (addr == NULL) { 24052caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 24067c478bd9Sstevel@tonic-gate "sockfs: T_uderror_ind with invalid " 24077c478bd9Sstevel@tonic-gate "addrlen/offset %u/%d\n", 24087c478bd9Sstevel@tonic-gate addrlen, tudi->DEST_offset); 24097c478bd9Sstevel@tonic-gate freemsg(mp); 24107c478bd9Sstevel@tonic-gate return (NULL); 24117c478bd9Sstevel@tonic-gate } 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate /* Verify source address for connected socket. */ 24147c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 24157c478bd9Sstevel@tonic-gate if (so->so_state & SS_ISCONNECTED) { 24167c478bd9Sstevel@tonic-gate void *faddr; 24177c478bd9Sstevel@tonic-gate t_uscalar_t faddr_len; 24187c478bd9Sstevel@tonic-gate boolean_t match = B_FALSE; 24197c478bd9Sstevel@tonic-gate 24207c478bd9Sstevel@tonic-gate switch (so->so_family) { 24217c478bd9Sstevel@tonic-gate case AF_INET: { 24227c478bd9Sstevel@tonic-gate /* Compare just IP address and port */ 24237c478bd9Sstevel@tonic-gate struct sockaddr_in *sin1, *sin2; 24247c478bd9Sstevel@tonic-gate 24250f1702c5SYu Xiangning sin1 = (struct sockaddr_in *)sti->sti_faddr_sa; 24267c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in *)addr; 24277c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in) && 24287c478bd9Sstevel@tonic-gate sin1->sin_port == sin2->sin_port && 24297c478bd9Sstevel@tonic-gate sin1->sin_addr.s_addr == 24307c478bd9Sstevel@tonic-gate sin2->sin_addr.s_addr) 24317c478bd9Sstevel@tonic-gate match = B_TRUE; 24327c478bd9Sstevel@tonic-gate break; 24337c478bd9Sstevel@tonic-gate } 24347c478bd9Sstevel@tonic-gate case AF_INET6: { 24357c478bd9Sstevel@tonic-gate /* Compare just IP address and port. Not flow */ 24367c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin1, *sin2; 24377c478bd9Sstevel@tonic-gate 24380f1702c5SYu Xiangning sin1 = (struct sockaddr_in6 *)sti->sti_faddr_sa; 24397c478bd9Sstevel@tonic-gate sin2 = (struct sockaddr_in6 *)addr; 24407c478bd9Sstevel@tonic-gate if (addrlen == sizeof (struct sockaddr_in6) && 24417c478bd9Sstevel@tonic-gate sin1->sin6_port == sin2->sin6_port && 24427c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr, 24437c478bd9Sstevel@tonic-gate &sin2->sin6_addr)) 24447c478bd9Sstevel@tonic-gate match = B_TRUE; 24457c478bd9Sstevel@tonic-gate break; 24467c478bd9Sstevel@tonic-gate } 24477c478bd9Sstevel@tonic-gate case AF_UNIX: 24480f1702c5SYu Xiangning faddr = &sti->sti_ux_faddr; 24497c478bd9Sstevel@tonic-gate faddr_len = 24500f1702c5SYu Xiangning (t_uscalar_t)sizeof (sti->sti_ux_faddr); 24517c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 24527c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 24537c478bd9Sstevel@tonic-gate match = B_TRUE; 24547c478bd9Sstevel@tonic-gate break; 24557c478bd9Sstevel@tonic-gate default: 24560f1702c5SYu Xiangning faddr = sti->sti_faddr_sa; 24570f1702c5SYu Xiangning faddr_len = (t_uscalar_t)sti->sti_faddr_len; 24587c478bd9Sstevel@tonic-gate if (faddr_len == addrlen && 24597c478bd9Sstevel@tonic-gate bcmp(addr, faddr, addrlen) == 0) 24607c478bd9Sstevel@tonic-gate match = B_TRUE; 24617c478bd9Sstevel@tonic-gate break; 24627c478bd9Sstevel@tonic-gate } 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate if (!match) { 24657c478bd9Sstevel@tonic-gate #ifdef DEBUG 24667c478bd9Sstevel@tonic-gate dprintso(so, 0, 24677c478bd9Sstevel@tonic-gate ("sockfs: T_UDERR_IND mismatch: %s - ", 24687c478bd9Sstevel@tonic-gate pr_addr(so->so_family, 24690f1702c5SYu Xiangning (struct sockaddr *)addr, addrlen))); 24707c478bd9Sstevel@tonic-gate dprintso(so, 0, ("%s\n", 24710f1702c5SYu Xiangning pr_addr(so->so_family, sti->sti_faddr_sa, 24720f1702c5SYu Xiangning sti->sti_faddr_len))); 24737c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 24747c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 24757c478bd9Sstevel@tonic-gate freemsg(mp); 24767c478bd9Sstevel@tonic-gate return (NULL); 24777c478bd9Sstevel@tonic-gate } 24787c478bd9Sstevel@tonic-gate /* 24797c478bd9Sstevel@tonic-gate * Make the write error nonpersistent. If the error 24807c478bd9Sstevel@tonic-gate * is zero we use ECONNRESET. 24817c478bd9Sstevel@tonic-gate * This assumes that the name space for ERROR_type 24827c478bd9Sstevel@tonic-gate * is the errno name space. 24837c478bd9Sstevel@tonic-gate */ 24847c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 24857c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 24867c478bd9Sstevel@tonic-gate else 24877c478bd9Sstevel@tonic-gate error = ECONNRESET; 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate soseterror(so, error); 24907c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 24917c478bd9Sstevel@tonic-gate strsetrerror(SOTOV(so), 0, 0, sogetrderr); 24927c478bd9Sstevel@tonic-gate strsetwerror(SOTOV(so), 0, 0, sogetwrerr); 24937c478bd9Sstevel@tonic-gate *wakeups = RSLEEP | WSLEEP; 24947c478bd9Sstevel@tonic-gate *allmsgsigs = S_INPUT | S_RDNORM | S_OUTPUT; 24957c478bd9Sstevel@tonic-gate *pollwakeups = POLLIN | POLLRDNORM | POLLOUT; 24967c478bd9Sstevel@tonic-gate freemsg(mp); 24977c478bd9Sstevel@tonic-gate return (NULL); 24987c478bd9Sstevel@tonic-gate } 24997c478bd9Sstevel@tonic-gate /* 25007c478bd9Sstevel@tonic-gate * If the application asked for delayed errors 25010f1702c5SYu Xiangning * record the T_UDERROR_IND sti_eaddr_mp and the reason in 25020f1702c5SYu Xiangning * sti_delayed_error for delayed error posting. If the reason 25037c478bd9Sstevel@tonic-gate * is zero use ECONNRESET. 25047c478bd9Sstevel@tonic-gate * Note that delayed error indications do not make sense for 25057c478bd9Sstevel@tonic-gate * AF_UNIX sockets since sendto checks that the destination 25067c478bd9Sstevel@tonic-gate * address is valid at the time of the sendto. 25077c478bd9Sstevel@tonic-gate */ 25087c478bd9Sstevel@tonic-gate if (!(so->so_options & SO_DGRAM_ERRIND)) { 25097c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25107c478bd9Sstevel@tonic-gate freemsg(mp); 25117c478bd9Sstevel@tonic-gate return (NULL); 25127c478bd9Sstevel@tonic-gate } 25130f1702c5SYu Xiangning if (sti->sti_eaddr_mp != NULL) 25140f1702c5SYu Xiangning freemsg(sti->sti_eaddr_mp); 25157c478bd9Sstevel@tonic-gate 25160f1702c5SYu Xiangning sti->sti_eaddr_mp = mp; 25177c478bd9Sstevel@tonic-gate if (tudi->ERROR_type != 0) 25187c478bd9Sstevel@tonic-gate error = tudi->ERROR_type; 25197c478bd9Sstevel@tonic-gate else 25207c478bd9Sstevel@tonic-gate error = ECONNRESET; 25210f1702c5SYu Xiangning sti->sti_delayed_error = (ushort_t)error; 25227c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25237c478bd9Sstevel@tonic-gate return (NULL); 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate case T_ERROR_ACK: 25277c478bd9Sstevel@tonic-gate dprintso(so, 0, 25287c478bd9Sstevel@tonic-gate ("strsock_proto: T_ERROR_ACK for %d, error %d/%d\n", 25297c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim, 25307c478bd9Sstevel@tonic-gate tpr->error_ack.TLI_error, 25317c478bd9Sstevel@tonic-gate tpr->error_ack.UNIX_error)); 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_error_ack)) { 25342caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25357c478bd9Sstevel@tonic-gate "sockfs: Too short T_ERROR_ACK. Len = %ld\n", 25367c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 25377c478bd9Sstevel@tonic-gate freemsg(mp); 25387c478bd9Sstevel@tonic-gate return (NULL); 25397c478bd9Sstevel@tonic-gate } 25407c478bd9Sstevel@tonic-gate /* 25417c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 25427c478bd9Sstevel@tonic-gate */ 25437c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 25447c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 25457c478bd9Sstevel@tonic-gate tpr->error_ack.ERROR_prim == T_UNBIND_REQ) { 25467c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 25477c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25487c478bd9Sstevel@tonic-gate freemsg(mp); 25497c478bd9Sstevel@tonic-gate return (NULL); 25507c478bd9Sstevel@tonic-gate } 25517c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25527c478bd9Sstevel@tonic-gate soqueueack(so, mp); 25537c478bd9Sstevel@tonic-gate return (NULL); 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate case T_OK_ACK: 25567c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_ok_ack)) { 25572caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25587c478bd9Sstevel@tonic-gate "sockfs: Too short T_OK_ACK. Len = %ld\n", 25597c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 25607c478bd9Sstevel@tonic-gate freemsg(mp); 25617c478bd9Sstevel@tonic-gate return (NULL); 25627c478bd9Sstevel@tonic-gate } 25637c478bd9Sstevel@tonic-gate /* 25647c478bd9Sstevel@tonic-gate * Check if we were waiting for the async message 25657c478bd9Sstevel@tonic-gate */ 25667c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 25677c478bd9Sstevel@tonic-gate if ((so->so_flag & SOASYNC_UNBIND) && 25687c478bd9Sstevel@tonic-gate tpr->ok_ack.CORRECT_prim == T_UNBIND_REQ) { 25697c478bd9Sstevel@tonic-gate dprintso(so, 1, 25707c478bd9Sstevel@tonic-gate ("strsock_proto: T_OK_ACK async unbind\n")); 25717c478bd9Sstevel@tonic-gate so_unlock_single(so, SOASYNC_UNBIND); 25727c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25737c478bd9Sstevel@tonic-gate freemsg(mp); 25747c478bd9Sstevel@tonic-gate return (NULL); 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 25777c478bd9Sstevel@tonic-gate soqueueack(so, mp); 25787c478bd9Sstevel@tonic-gate return (NULL); 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate case T_INFO_ACK: 25817c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_info_ack)) { 25822caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 25837c478bd9Sstevel@tonic-gate "sockfs: Too short T_INFO_ACK. Len = %ld\n", 25847c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 25857c478bd9Sstevel@tonic-gate freemsg(mp); 25867c478bd9Sstevel@tonic-gate return (NULL); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate soqueueack(so, mp); 25897c478bd9Sstevel@tonic-gate return (NULL); 25907c478bd9Sstevel@tonic-gate 25917c478bd9Sstevel@tonic-gate case T_CAPABILITY_ACK: 25927c478bd9Sstevel@tonic-gate /* 25937c478bd9Sstevel@tonic-gate * A T_capability_ack need only be large enough to hold 25947c478bd9Sstevel@tonic-gate * the PRIM_type and CAP_bits1 fields; checking for anything 25957c478bd9Sstevel@tonic-gate * larger might reject a correct response from an older 25967c478bd9Sstevel@tonic-gate * provider. 25977c478bd9Sstevel@tonic-gate */ 25987c478bd9Sstevel@tonic-gate if (MBLKL(mp) < 2 * sizeof (t_uscalar_t)) { 25992caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26007c478bd9Sstevel@tonic-gate "sockfs: Too short T_CAPABILITY_ACK. Len = %ld\n", 26017c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26027c478bd9Sstevel@tonic-gate freemsg(mp); 26037c478bd9Sstevel@tonic-gate return (NULL); 26047c478bd9Sstevel@tonic-gate } 26057c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26067c478bd9Sstevel@tonic-gate return (NULL); 26077c478bd9Sstevel@tonic-gate 26087c478bd9Sstevel@tonic-gate case T_BIND_ACK: 26097c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_bind_ack)) { 26102caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26117c478bd9Sstevel@tonic-gate "sockfs: Too short T_BIND_ACK. Len = %ld\n", 26127c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26137c478bd9Sstevel@tonic-gate freemsg(mp); 26147c478bd9Sstevel@tonic-gate return (NULL); 26157c478bd9Sstevel@tonic-gate } 26167c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26177c478bd9Sstevel@tonic-gate return (NULL); 26187c478bd9Sstevel@tonic-gate 26197c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK: 26207c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (struct T_optmgmt_ack)) { 26212caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26227c478bd9Sstevel@tonic-gate "sockfs: Too short T_OPTMGMT_ACK. Len = %ld\n", 26237c478bd9Sstevel@tonic-gate (ptrdiff_t)(MBLKL(mp))); 26247c478bd9Sstevel@tonic-gate freemsg(mp); 26257c478bd9Sstevel@tonic-gate return (NULL); 26267c478bd9Sstevel@tonic-gate } 26277c478bd9Sstevel@tonic-gate soqueueack(so, mp); 26287c478bd9Sstevel@tonic-gate return (NULL); 26297c478bd9Sstevel@tonic-gate default: 26307c478bd9Sstevel@tonic-gate #ifdef DEBUG 26312caf0dcdSrshoaib zcmn_err(getzoneid(), CE_WARN, 26327c478bd9Sstevel@tonic-gate "sockfs: unknown TPI primitive %d received\n", 26337c478bd9Sstevel@tonic-gate tpr->type); 26347c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 26357c478bd9Sstevel@tonic-gate freemsg(mp); 26367c478bd9Sstevel@tonic-gate return (NULL); 26377c478bd9Sstevel@tonic-gate } 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate 26407c478bd9Sstevel@tonic-gate /* 26417c478bd9Sstevel@tonic-gate * This routine is registered with the stream head to receive other 26427c478bd9Sstevel@tonic-gate * (non-data, and non-proto) messages. 26437c478bd9Sstevel@tonic-gate * 26447c478bd9Sstevel@tonic-gate * Returns NULL if the message was consumed. 26457c478bd9Sstevel@tonic-gate * Returns an mblk to make that mblk be processed by the stream head. 26467c478bd9Sstevel@tonic-gate * 26477c478bd9Sstevel@tonic-gate * Sets the return parameters (*wakeups, *firstmsgsigs, *allmsgsigs, and 26487c478bd9Sstevel@tonic-gate * *pollwakeups) for the stream head to take action on. 26497c478bd9Sstevel@tonic-gate */ 26507c478bd9Sstevel@tonic-gate static mblk_t * 26517c478bd9Sstevel@tonic-gate strsock_misc(vnode_t *vp, mblk_t *mp, 26527c478bd9Sstevel@tonic-gate strwakeup_t *wakeups, strsigset_t *firstmsgsigs, 26537c478bd9Sstevel@tonic-gate strsigset_t *allmsgsigs, strpollset_t *pollwakeups) 26547c478bd9Sstevel@tonic-gate { 26557c478bd9Sstevel@tonic-gate struct sonode *so; 26560f1702c5SYu Xiangning sotpi_info_t *sti; 26577c478bd9Sstevel@tonic-gate 26587c478bd9Sstevel@tonic-gate so = VTOSO(vp); 26590f1702c5SYu Xiangning sti = SOTOTPI(so); 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate dprintso(so, 1, ("strsock_misc(%p, %p, 0x%x)\n", 2662903a11ebSrh87107 (void *)vp, (void *)mp, DB_TYPE(mp))); 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate /* Set default return values */ 26657c478bd9Sstevel@tonic-gate *wakeups = *allmsgsigs = *firstmsgsigs = *pollwakeups = 0; 26667c478bd9Sstevel@tonic-gate 26677c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 26687c478bd9Sstevel@tonic-gate case M_PCSIG: 26697c478bd9Sstevel@tonic-gate /* 26707c478bd9Sstevel@tonic-gate * This assumes that an M_PCSIG for the urgent data arrives 26717c478bd9Sstevel@tonic-gate * before the corresponding T_EXDATA_IND. 26727c478bd9Sstevel@tonic-gate * 26737c478bd9Sstevel@tonic-gate * Note: Just like in SunOS 4.X and 4.4BSD a poll will be 26747c478bd9Sstevel@tonic-gate * awoken before the urgent data shows up. 26757c478bd9Sstevel@tonic-gate * For OOBINLINE this can result in select returning 26767c478bd9Sstevel@tonic-gate * only exceptions as opposed to except|read. 26777c478bd9Sstevel@tonic-gate */ 26787c478bd9Sstevel@tonic-gate if (*mp->b_rptr == SIGURG) { 26797c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 26807c478bd9Sstevel@tonic-gate dprintso(so, 1, 26817c478bd9Sstevel@tonic-gate ("SIGURG(%p): counts %d/%d state %s\n", 26820f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt, 26837c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 26847c478bd9Sstevel@tonic-gate so_oob_sig(so, 1, allmsgsigs, pollwakeups); 26857c478bd9Sstevel@tonic-gate dprintso(so, 1, 26867c478bd9Sstevel@tonic-gate ("after SIGURG(%p): counts %d/%d " 26877c478bd9Sstevel@tonic-gate " poll 0x%x sig 0x%x state %s\n", 26880f1702c5SYu Xiangning (void *)vp, sti->sti_oobsigcnt, sti->sti_oobcnt, 26890f1702c5SYu Xiangning *pollwakeups, *allmsgsigs, 26907c478bd9Sstevel@tonic-gate pr_state(so->so_state, so->so_mode))); 26917c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 26927c478bd9Sstevel@tonic-gate } 26937c478bd9Sstevel@tonic-gate freemsg(mp); 26947c478bd9Sstevel@tonic-gate return (NULL); 26957c478bd9Sstevel@tonic-gate 26967c478bd9Sstevel@tonic-gate case M_SIG: 26977c478bd9Sstevel@tonic-gate case M_HANGUP: 26987c478bd9Sstevel@tonic-gate case M_UNHANGUP: 26997c478bd9Sstevel@tonic-gate case M_ERROR: 27007c478bd9Sstevel@tonic-gate /* M_ERRORs etc are ignored */ 27017c478bd9Sstevel@tonic-gate freemsg(mp); 27027c478bd9Sstevel@tonic-gate return (NULL); 27037c478bd9Sstevel@tonic-gate 27047c478bd9Sstevel@tonic-gate case M_FLUSH: 27057c478bd9Sstevel@tonic-gate /* 27067c478bd9Sstevel@tonic-gate * Do not flush read queue. If the M_FLUSH 27077c478bd9Sstevel@tonic-gate * arrives because of an impending T_discon_ind 27087c478bd9Sstevel@tonic-gate * we still have to keep any queued data - this is part of 27097c478bd9Sstevel@tonic-gate * socket semantics. 27107c478bd9Sstevel@tonic-gate */ 27117c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 27127c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHR; 27137c478bd9Sstevel@tonic-gate return (mp); 27147c478bd9Sstevel@tonic-gate } 27157c478bd9Sstevel@tonic-gate freemsg(mp); 27167c478bd9Sstevel@tonic-gate return (NULL); 27177c478bd9Sstevel@tonic-gate 27187c478bd9Sstevel@tonic-gate default: 27197c478bd9Sstevel@tonic-gate return (mp); 27207c478bd9Sstevel@tonic-gate } 27217c478bd9Sstevel@tonic-gate } 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate 27247c478bd9Sstevel@tonic-gate /* Register to receive signals for certain events */ 27257c478bd9Sstevel@tonic-gate int 27267c478bd9Sstevel@tonic-gate so_set_asyncsigs(vnode_t *vp, pid_t pgrp, int events, int mode, cred_t *cr) 27277c478bd9Sstevel@tonic-gate { 27287c478bd9Sstevel@tonic-gate struct strsigset ss; 27297c478bd9Sstevel@tonic-gate int32_t rval; 27307c478bd9Sstevel@tonic-gate 27317c478bd9Sstevel@tonic-gate /* 27327c478bd9Sstevel@tonic-gate * Note that SOLOCKED will be set except for the call from soaccept(). 27337c478bd9Sstevel@tonic-gate */ 27347c478bd9Sstevel@tonic-gate ASSERT(!mutex_owned(&VTOSO(vp)->so_lock)); 27357c478bd9Sstevel@tonic-gate ss.ss_pid = pgrp; 27367c478bd9Sstevel@tonic-gate ss.ss_events = events; 27377c478bd9Sstevel@tonic-gate return (strioctl(vp, I_ESETSIG, (intptr_t)&ss, mode, K_TO_K, cr, 27387c478bd9Sstevel@tonic-gate &rval)); 27397c478bd9Sstevel@tonic-gate } 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate 27427c478bd9Sstevel@tonic-gate /* Register for events matching the SS_ASYNC flag */ 27437c478bd9Sstevel@tonic-gate int 27447c478bd9Sstevel@tonic-gate so_set_events(struct sonode *so, vnode_t *vp, cred_t *cr) 27457c478bd9Sstevel@tonic-gate { 27467c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 27477c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 27487c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 27497c478bd9Sstevel@tonic-gate 27507c478bd9Sstevel@tonic-gate return (so_set_asyncsigs(vp, so->so_pgrp, events, 0, cr)); 27517c478bd9Sstevel@tonic-gate } 27527c478bd9Sstevel@tonic-gate 27537c478bd9Sstevel@tonic-gate 27547c478bd9Sstevel@tonic-gate /* Change the SS_ASYNC flag, and update signal delivery if needed */ 27557c478bd9Sstevel@tonic-gate int 27567c478bd9Sstevel@tonic-gate so_flip_async(struct sonode *so, vnode_t *vp, int mode, cred_t *cr) 27577c478bd9Sstevel@tonic-gate { 27587c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 27597c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 27607c478bd9Sstevel@tonic-gate int error; 27617c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? /* Old flag */ 27627c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG : /* New sigs */ 27637c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT; 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate so_lock_single(so); 27667c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 27677c478bd9Sstevel@tonic-gate 27687c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, events, mode, cr); 27697c478bd9Sstevel@tonic-gate 27707c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 27717c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 27727c478bd9Sstevel@tonic-gate if (error) 27737c478bd9Sstevel@tonic-gate return (error); 27747c478bd9Sstevel@tonic-gate } 27757c478bd9Sstevel@tonic-gate so->so_state ^= SS_ASYNC; 27767c478bd9Sstevel@tonic-gate return (0); 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate /* 27807c478bd9Sstevel@tonic-gate * Set new pid/pgrp for SIGPOLL (or SIGIO for FIOASYNC mode), replacing 27817c478bd9Sstevel@tonic-gate * any existing one. If passed zero, just clear the existing one. 27827c478bd9Sstevel@tonic-gate */ 27837c478bd9Sstevel@tonic-gate int 27847c478bd9Sstevel@tonic-gate so_set_siggrp(struct sonode *so, vnode_t *vp, pid_t pgrp, int mode, cred_t *cr) 27857c478bd9Sstevel@tonic-gate { 27867c478bd9Sstevel@tonic-gate int events = so->so_state & SS_ASYNC ? 27877c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG | S_RDNORM | S_OUTPUT : 27887c478bd9Sstevel@tonic-gate S_RDBAND | S_BANDURG; 27897c478bd9Sstevel@tonic-gate int error; 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&so->so_lock)); 27927c478bd9Sstevel@tonic-gate 27937c478bd9Sstevel@tonic-gate /* 27947c478bd9Sstevel@tonic-gate * Change socket process (group). 27957c478bd9Sstevel@tonic-gate * 27967c478bd9Sstevel@tonic-gate * strioctl (via so_set_asyncsigs) will perform permission check and 27977c478bd9Sstevel@tonic-gate * also keep a PID_HOLD to prevent the pid from being reused. 27987c478bd9Sstevel@tonic-gate */ 27997c478bd9Sstevel@tonic-gate so_lock_single(so); 28007c478bd9Sstevel@tonic-gate mutex_exit(&so->so_lock); 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate if (pgrp != 0) { 28037c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: adding pgrp %d ev 0x%x\n", 28047c478bd9Sstevel@tonic-gate pgrp, events)); 28057c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, pgrp, events, mode, cr); 28067c478bd9Sstevel@tonic-gate if (error != 0) { 28077c478bd9Sstevel@tonic-gate eprintsoline(so, error); 28087c478bd9Sstevel@tonic-gate goto bad; 28097c478bd9Sstevel@tonic-gate } 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate /* Remove the previously registered process/group */ 28127c478bd9Sstevel@tonic-gate if (so->so_pgrp != 0) { 28137c478bd9Sstevel@tonic-gate dprintso(so, 1, ("setown: removing pgrp %d\n", so->so_pgrp)); 28147c478bd9Sstevel@tonic-gate error = so_set_asyncsigs(vp, so->so_pgrp, 0, mode, cr); 28157c478bd9Sstevel@tonic-gate if (error != 0) { 28167c478bd9Sstevel@tonic-gate eprintsoline(so, error); 28177c478bd9Sstevel@tonic-gate error = 0; 28187c478bd9Sstevel@tonic-gate } 28197c478bd9Sstevel@tonic-gate } 28207c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 28217c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 28227c478bd9Sstevel@tonic-gate so->so_pgrp = pgrp; 28237c478bd9Sstevel@tonic-gate return (0); 28247c478bd9Sstevel@tonic-gate bad: 28257c478bd9Sstevel@tonic-gate mutex_enter(&so->so_lock); 28267c478bd9Sstevel@tonic-gate so_unlock_single(so, SOLOCKED); 28277c478bd9Sstevel@tonic-gate return (error); 28287c478bd9Sstevel@tonic-gate } 28297c478bd9Sstevel@tonic-gate 28300f1702c5SYu Xiangning /* 28310f1702c5SYu Xiangning * Wrapper for getmsg. If the socket has been converted to a stream 28320f1702c5SYu Xiangning * pass the request to the stream head. 28330f1702c5SYu Xiangning */ 28340f1702c5SYu Xiangning int 28350f1702c5SYu Xiangning sock_getmsg( 28360f1702c5SYu Xiangning struct vnode *vp, 28370f1702c5SYu Xiangning struct strbuf *mctl, 28380f1702c5SYu Xiangning struct strbuf *mdata, 28390f1702c5SYu Xiangning uchar_t *prip, 28400f1702c5SYu Xiangning int *flagsp, 28410f1702c5SYu Xiangning int fmode, 28420f1702c5SYu Xiangning rval_t *rvp 28430f1702c5SYu Xiangning ) 28440f1702c5SYu Xiangning { 28450f1702c5SYu Xiangning struct sonode *so; 28467c478bd9Sstevel@tonic-gate 28470f1702c5SYu Xiangning ASSERT(vp->v_type == VSOCK); 28480f1702c5SYu Xiangning /* 28490f1702c5SYu Xiangning * Use the stream head to find the real socket vnode. 28500f1702c5SYu Xiangning * This is needed when namefs sits above sockfs. Some 28510f1702c5SYu Xiangning * sockets (like SCTP) are not streams. 28520f1702c5SYu Xiangning */ 28530f1702c5SYu Xiangning if (!vp->v_stream) { 28540f1702c5SYu Xiangning return (ENOSTR); 28550f1702c5SYu Xiangning } 28560f1702c5SYu Xiangning ASSERT(vp->v_stream->sd_vnode); 28570f1702c5SYu Xiangning vp = vp->v_stream->sd_vnode; 28580f1702c5SYu Xiangning ASSERT(vn_matchops(vp, socket_vnodeops)); 28590f1702c5SYu Xiangning so = VTOSO(vp); 28600f1702c5SYu Xiangning 28610f1702c5SYu Xiangning dprintso(so, 1, ("sock_getmsg(%p) %s\n", 28620f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode))); 28630f1702c5SYu Xiangning 28640f1702c5SYu Xiangning if (so->so_version == SOV_STREAM) { 28650f1702c5SYu Xiangning /* The imaginary "sockmod" has been popped - act as a stream */ 28660f1702c5SYu Xiangning return (strgetmsg(vp, mctl, mdata, prip, flagsp, fmode, rvp)); 28670f1702c5SYu Xiangning } 28680f1702c5SYu Xiangning eprintsoline(so, ENOSTR); 28690f1702c5SYu Xiangning return (ENOSTR); 28700f1702c5SYu Xiangning } 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate /* 28730f1702c5SYu Xiangning * Wrapper for putmsg. If the socket has been converted to a stream 28740f1702c5SYu Xiangning * pass the request to the stream head. 28750f1702c5SYu Xiangning * 28760f1702c5SYu Xiangning * Note that a while a regular socket (SOV_SOCKSTREAM) does support the 28770f1702c5SYu Xiangning * streams ioctl set it does not support putmsg and getmsg. 28780f1702c5SYu Xiangning * Allowing putmsg would prevent sockfs from tracking the state of 28790f1702c5SYu Xiangning * the socket/transport and would also invalidate the locking in sockfs. 28807c478bd9Sstevel@tonic-gate */ 28810f1702c5SYu Xiangning int 28820f1702c5SYu Xiangning sock_putmsg( 28830f1702c5SYu Xiangning struct vnode *vp, 28840f1702c5SYu Xiangning struct strbuf *mctl, 28850f1702c5SYu Xiangning struct strbuf *mdata, 28860f1702c5SYu Xiangning uchar_t pri, 28870f1702c5SYu Xiangning int flag, 28880f1702c5SYu Xiangning int fmode 28890f1702c5SYu Xiangning ) 28907c478bd9Sstevel@tonic-gate { 28910f1702c5SYu Xiangning struct sonode *so; 28920f1702c5SYu Xiangning 28930f1702c5SYu Xiangning ASSERT(vp->v_type == VSOCK); 28940f1702c5SYu Xiangning /* 28950f1702c5SYu Xiangning * Use the stream head to find the real socket vnode. 28960f1702c5SYu Xiangning * This is needed when namefs sits above sockfs. 28970f1702c5SYu Xiangning */ 28980f1702c5SYu Xiangning if (!vp->v_stream) { 28990f1702c5SYu Xiangning return (ENOSTR); 29000f1702c5SYu Xiangning } 29010f1702c5SYu Xiangning ASSERT(vp->v_stream->sd_vnode); 29020f1702c5SYu Xiangning vp = vp->v_stream->sd_vnode; 29030f1702c5SYu Xiangning ASSERT(vn_matchops(vp, socket_vnodeops)); 29040f1702c5SYu Xiangning so = VTOSO(vp); 29050f1702c5SYu Xiangning 29060f1702c5SYu Xiangning dprintso(so, 1, ("sock_putmsg(%p) %s\n", 29070f1702c5SYu Xiangning (void *)so, pr_state(so->so_state, so->so_mode))); 29080f1702c5SYu Xiangning 29090f1702c5SYu Xiangning if (so->so_version == SOV_STREAM) { 29100f1702c5SYu Xiangning /* The imaginary "sockmod" has been popped - act as a stream */ 29110f1702c5SYu Xiangning return (strputmsg(vp, mctl, mdata, pri, flag, fmode)); 29120f1702c5SYu Xiangning } 29130f1702c5SYu Xiangning eprintsoline(so, ENOSTR); 29140f1702c5SYu Xiangning return (ENOSTR); 29150f1702c5SYu Xiangning } 29160f1702c5SYu Xiangning 29170f1702c5SYu Xiangning /* 29180f1702c5SYu Xiangning * Special function called only from f_getfl(). 29190f1702c5SYu Xiangning * Returns FASYNC if the SS_ASYNC flag is set on a socket, else 0. 29200f1702c5SYu Xiangning * No locks are acquired here, so it is safe to use while uf_lock is held. 29210f1702c5SYu Xiangning * This exists solely for BSD fcntl() FASYNC compatibility. 29220f1702c5SYu Xiangning */ 29230f1702c5SYu Xiangning int 29240f1702c5SYu Xiangning sock_getfasync(vnode_t *vp) 29250f1702c5SYu Xiangning { 29260f1702c5SYu Xiangning struct sonode *so; 29270f1702c5SYu Xiangning 29280f1702c5SYu Xiangning ASSERT(vp->v_type == VSOCK); 29290f1702c5SYu Xiangning /* 29300f1702c5SYu Xiangning * For stream model, v_stream is used; For non-stream, v_stream always 29310f1702c5SYu Xiangning * equals NULL 29320f1702c5SYu Xiangning */ 29330f1702c5SYu Xiangning if (vp->v_stream != NULL) 29340f1702c5SYu Xiangning so = VTOSO(vp->v_stream->sd_vnode); 29357c478bd9Sstevel@tonic-gate else 29360f1702c5SYu Xiangning so = VTOSO(vp); 29370f1702c5SYu Xiangning 29380f1702c5SYu Xiangning if (so->so_version == SOV_STREAM || !(so->so_state & SS_ASYNC)) 29390f1702c5SYu Xiangning return (0); 29400f1702c5SYu Xiangning 29410f1702c5SYu Xiangning return (FASYNC); 29427c478bd9Sstevel@tonic-gate } 2943