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 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * 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 */ 217c478bd9Sstevel@tonic-gate /* 2256f33205SJonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 25b2d8fb89SDan Kruchinin /* 26b2d8fb89SDan Kruchinin * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 27bbaa8b60SDan Kruchinin * Copyright (c) 2012 by Delphix. All rights reserved. 28b2d8fb89SDan Kruchinin */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Multithreaded STREAMS Local Transport Provider. 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * OVERVIEW 347c478bd9Sstevel@tonic-gate * ======== 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * This driver provides TLI as well as socket semantics. It provides 377c478bd9Sstevel@tonic-gate * connectionless, connection oriented, and connection oriented with orderly 387c478bd9Sstevel@tonic-gate * release transports for TLI and sockets. Each transport type has separate name 397c478bd9Sstevel@tonic-gate * spaces (i.e. it is not possible to connect from a socket to a TLI endpoint) - 407c478bd9Sstevel@tonic-gate * this removes any name space conflicts when binding to socket style transport 417c478bd9Sstevel@tonic-gate * addresses. 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * NOTE: There is one exception: Socket ticots and ticotsord transports share 447c478bd9Sstevel@tonic-gate * the same namespace. In fact, sockets always use ticotsord type transport. 457c478bd9Sstevel@tonic-gate * 467c478bd9Sstevel@tonic-gate * The driver mode is specified during open() by the minor number used for 477c478bd9Sstevel@tonic-gate * open. 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * The sockets in addition have the following semantic differences: 507c478bd9Sstevel@tonic-gate * No support for passing up credentials (TL_SET[U]CRED). 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * Options are passed through transparently on T_CONN_REQ to T_CONN_IND, 537c478bd9Sstevel@tonic-gate * from T_UNITDATA_REQ to T_UNIDATA_IND, and from T_OPTDATA_REQ to 547c478bd9Sstevel@tonic-gate * T_OPTDATA_IND. 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * The T_CONN_CON is generated when processing the T_CONN_REQ i.e. before 577c478bd9Sstevel@tonic-gate * a T_CONN_RES is received from the acceptor. This means that a socket 587c478bd9Sstevel@tonic-gate * connect will complete before the peer has called accept. 597c478bd9Sstevel@tonic-gate * 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * MULTITHREADING 627c478bd9Sstevel@tonic-gate * ============== 637c478bd9Sstevel@tonic-gate * 647c478bd9Sstevel@tonic-gate * The driver does not use STREAMS protection mechanisms. Instead it uses a 657c478bd9Sstevel@tonic-gate * generic "serializer" abstraction. Most of the operations are executed behind 667c478bd9Sstevel@tonic-gate * the serializer and are, essentially single-threaded. All functions executed 677c478bd9Sstevel@tonic-gate * behind the same serializer are strictly serialized. So if one thread calls 687c478bd9Sstevel@tonic-gate * serializer_enter(serializer, foo, mp1, arg1); and another thread calls 697c478bd9Sstevel@tonic-gate * serializer_enter(serializer, bar, mp2, arg1); then (depending on which one 707c478bd9Sstevel@tonic-gate * was called) the actual sequence will be foo(mp1, arg1); bar(mp1, arg2) or 717c478bd9Sstevel@tonic-gate * bar(mp1, arg2); foo(mp1, arg1); But foo() and bar() will never run at the 727c478bd9Sstevel@tonic-gate * same time. 737c478bd9Sstevel@tonic-gate * 747c478bd9Sstevel@tonic-gate * Connectionless transport use a single serializer per transport type (one for 757c478bd9Sstevel@tonic-gate * TLI and one for sockets. Connection-oriented transports use finer-grained 767c478bd9Sstevel@tonic-gate * serializers. 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * All COTS-type endpoints start their life with private serializers. During 797c478bd9Sstevel@tonic-gate * connection request processing the endpoint serializer is switched to the 807c478bd9Sstevel@tonic-gate * listener's serializer and the rest of T_CONN_REQ processing is done on the 817c478bd9Sstevel@tonic-gate * listener serializer. During T_CONN_RES processing the eager serializer is 827c478bd9Sstevel@tonic-gate * switched from listener to acceptor serializer and after that point all 837c478bd9Sstevel@tonic-gate * processing for eager and acceptor happens on this serializer. To avoid races 847c478bd9Sstevel@tonic-gate * with endpoint closes while its serializer may be changing closes are blocked 857c478bd9Sstevel@tonic-gate * while serializers are manipulated. 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * References accounting 887c478bd9Sstevel@tonic-gate * --------------------- 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * Endpoints are reference counted and freed when the last reference is 917c478bd9Sstevel@tonic-gate * dropped. Functions within the serializer may access an endpoint state even 927c478bd9Sstevel@tonic-gate * after an endpoint closed. The te_closing being set on the endpoint indicates 937c478bd9Sstevel@tonic-gate * that the endpoint entered its close routine. 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * One reference is held for each opened endpoint instance. The reference 967c478bd9Sstevel@tonic-gate * counter is incremented when the endpoint is linked to another endpoint and 977c478bd9Sstevel@tonic-gate * decremented when the link disappears. It is also incremented when the 987c478bd9Sstevel@tonic-gate * endpoint is found by the hash table lookup. This increment is atomic with the 997c478bd9Sstevel@tonic-gate * lookup itself and happens while the hash table read lock is held. 1007c478bd9Sstevel@tonic-gate * 1017c478bd9Sstevel@tonic-gate * Close synchronization 1027c478bd9Sstevel@tonic-gate * --------------------- 1037c478bd9Sstevel@tonic-gate * 1047c478bd9Sstevel@tonic-gate * During close the endpoint as marked as closing using te_closing flag. It is 1057c478bd9Sstevel@tonic-gate * usually enough to check for te_closing flag since all other state changes 1067c478bd9Sstevel@tonic-gate * happen after this flag is set and the close entered serializer. Immediately 1077c478bd9Sstevel@tonic-gate * after setting te_closing flag tl_close() enters serializer and waits until 1087c478bd9Sstevel@tonic-gate * the callback finishes. This allows all functions called within serializer to 1097c478bd9Sstevel@tonic-gate * simply check te_closing without any locks. 1107c478bd9Sstevel@tonic-gate * 1117c478bd9Sstevel@tonic-gate * Serializer management. 1127c478bd9Sstevel@tonic-gate * --------------------- 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * For COTS transports serializers are created when the endpoint is constructed 1157c478bd9Sstevel@tonic-gate * and destroyed when the endpoint is destructed. CLTS transports use global 1167c478bd9Sstevel@tonic-gate * serializers - one for sockets and one for TLI. 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * COTS serializers have separate reference counts to deal with several 1197c478bd9Sstevel@tonic-gate * endpoints sharing the same serializer. There is a subtle problem related to 1207c478bd9Sstevel@tonic-gate * the serializer destruction. The serializer should never be destroyed by any 1217c478bd9Sstevel@tonic-gate * function executed inside serializer. This means that close has to wait till 1227c478bd9Sstevel@tonic-gate * all serializer activity for this endpoint is finished before it can drop the 1237c478bd9Sstevel@tonic-gate * last reference on the endpoint (which may as well free the serializer). This 1247c478bd9Sstevel@tonic-gate * is only relevant for COTS transports which manage serializers 1257c478bd9Sstevel@tonic-gate * dynamically. For CLTS transports close may complete without waiting for all 1267c478bd9Sstevel@tonic-gate * serializer activity to finish since serializer is only destroyed at driver 1277c478bd9Sstevel@tonic-gate * detach time. 1287c478bd9Sstevel@tonic-gate * 1297c478bd9Sstevel@tonic-gate * COTS endpoints keep track of the number of outstanding requests on the 1307c478bd9Sstevel@tonic-gate * serializer for the endpoint. The code handling accept() avoids changing 1317c478bd9Sstevel@tonic-gate * client serializer if it has any pending messages on the serializer and 1327c478bd9Sstevel@tonic-gate * instead moves acceptor to listener's serializer. 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * 1357c478bd9Sstevel@tonic-gate * Use of hash tables 1367c478bd9Sstevel@tonic-gate * ------------------ 1377c478bd9Sstevel@tonic-gate * 1387c478bd9Sstevel@tonic-gate * The driver uses modhash hash table implementation. Each transport uses two 1397c478bd9Sstevel@tonic-gate * hash tables - one for finding endpoints by acceptor ID and another one for 1407c478bd9Sstevel@tonic-gate * finding endpoints by address. For sockets TICOTS and TICOTSORD share the same 1417c478bd9Sstevel@tonic-gate * pair of hash tables since sockets only use TICOTSORD. 1427c478bd9Sstevel@tonic-gate * 1437c478bd9Sstevel@tonic-gate * All hash tables lookups increment a reference count for returned endpoints, 1447c478bd9Sstevel@tonic-gate * so we may safely check the endpoint state even when the endpoint is removed 1457c478bd9Sstevel@tonic-gate * from the hash by another thread immediately after it is found. 1467c478bd9Sstevel@tonic-gate * 1477c478bd9Sstevel@tonic-gate * 1487c478bd9Sstevel@tonic-gate * CLOSE processing 1497c478bd9Sstevel@tonic-gate * ================ 1507c478bd9Sstevel@tonic-gate * 1517c478bd9Sstevel@tonic-gate * The driver enters serializer twice on close(). The close sequence is the 1527c478bd9Sstevel@tonic-gate * following: 1537c478bd9Sstevel@tonic-gate * 1547c478bd9Sstevel@tonic-gate * 1) Wait until closing is safe (te_closewait becomes zero) 1557c478bd9Sstevel@tonic-gate * This step is needed to prevent close during serializer switches. In most 1567c478bd9Sstevel@tonic-gate * cases (close happening after connection establishment) te_closewait is 1577c478bd9Sstevel@tonic-gate * zero. 1587c478bd9Sstevel@tonic-gate * 1) Set te_closing. 1597c478bd9Sstevel@tonic-gate * 2) Call tl_close_ser() within serializer and wait for it to complete. 1607c478bd9Sstevel@tonic-gate * 1617c478bd9Sstevel@tonic-gate * te_close_ser simply marks endpoint and wakes up waiting tl_close(). 1627c478bd9Sstevel@tonic-gate * It also needs to clear write-side q_next pointers - this should be done 1637c478bd9Sstevel@tonic-gate * before qprocsoff(). 1647c478bd9Sstevel@tonic-gate * 1657c478bd9Sstevel@tonic-gate * This synchronous serializer entry during close is needed to ensure that 1667c478bd9Sstevel@tonic-gate * the queue is valid everywhere inside the serializer. 1677c478bd9Sstevel@tonic-gate * 1687c478bd9Sstevel@tonic-gate * Note that in many cases close will execute tl_close_ser() synchronously, 1697c478bd9Sstevel@tonic-gate * so it will not wait at all. 1707c478bd9Sstevel@tonic-gate * 1717c478bd9Sstevel@tonic-gate * 3) Calls qprocsoff(). 1727c478bd9Sstevel@tonic-gate * 4) Calls tl_close_finish_ser() within the serializer and waits for it to 1737c478bd9Sstevel@tonic-gate * complete (for COTS transports). For CLTS transport there is no wait. 1747c478bd9Sstevel@tonic-gate * 1757c478bd9Sstevel@tonic-gate * tl_close_finish_ser() Finishes the close process and wakes up waiting 1767c478bd9Sstevel@tonic-gate * close if there is any. 1777c478bd9Sstevel@tonic-gate * 1787c478bd9Sstevel@tonic-gate * Note that in most cases close will enter te_close_ser_finish() 1797c478bd9Sstevel@tonic-gate * synchronously and will not wait at all. 1807c478bd9Sstevel@tonic-gate * 1817c478bd9Sstevel@tonic-gate * 1827c478bd9Sstevel@tonic-gate * Flow Control 1837c478bd9Sstevel@tonic-gate * ============ 1847c478bd9Sstevel@tonic-gate * 1857c478bd9Sstevel@tonic-gate * The driver implements both read and write side service routines. No one calls 1867c478bd9Sstevel@tonic-gate * putq() on the read queue. The read side service routine tl_rsrv() is called 1877c478bd9Sstevel@tonic-gate * when the read side stream is back-enabled. It enters serializer synchronously 1887c478bd9Sstevel@tonic-gate * (waits till serializer processing is complete). Within serializer it 1897c478bd9Sstevel@tonic-gate * back-enables all endpoints blocked by the queue for connection-less 1907c478bd9Sstevel@tonic-gate * transports and enables write side service processing for the peer for 1917c478bd9Sstevel@tonic-gate * connection-oriented transports. 1927c478bd9Sstevel@tonic-gate * 1937c478bd9Sstevel@tonic-gate * Read and write side service routines use special mblk_sized space in the 1947c478bd9Sstevel@tonic-gate * endpoint structure to enter perimeter. 1957c478bd9Sstevel@tonic-gate * 1967c478bd9Sstevel@tonic-gate * Write-side flow control 1977c478bd9Sstevel@tonic-gate * ----------------------- 1987c478bd9Sstevel@tonic-gate * 1997c478bd9Sstevel@tonic-gate * Write side flow control is a bit tricky. The driver needs to deal with two 2007c478bd9Sstevel@tonic-gate * message queues - the explicit STREAMS message queue maintained by 2017c478bd9Sstevel@tonic-gate * putq()/getq()/putbq() and the implicit queue within the serializer. These two 2027c478bd9Sstevel@tonic-gate * queues should be synchronized to preserve message ordering and should 2037c478bd9Sstevel@tonic-gate * maintain a single order determined by the order in which messages enter 2047c478bd9Sstevel@tonic-gate * tl_wput(). In order to maintain the ordering between these two queues the 2057c478bd9Sstevel@tonic-gate * STREAMS queue is only manipulated within the serializer, so the ordering is 2067c478bd9Sstevel@tonic-gate * provided by the serializer. 2077c478bd9Sstevel@tonic-gate * 2087c478bd9Sstevel@tonic-gate * Functions called from the tl_wsrv() sometimes may call putbq(). To 2097c478bd9Sstevel@tonic-gate * immediately stop any further processing of the STREAMS message queues the 2107c478bd9Sstevel@tonic-gate * code calling putbq() also sets the te_nowsrv flag in the endpoint. The write 2117c478bd9Sstevel@tonic-gate * side service processing stops when the flag is set. 2127c478bd9Sstevel@tonic-gate * 2137c478bd9Sstevel@tonic-gate * The tl_wsrv() function enters serializer synchronously and waits for it to 2147c478bd9Sstevel@tonic-gate * complete. The serializer call-back tl_wsrv_ser() either drains all messages 2157c478bd9Sstevel@tonic-gate * on the STREAMS queue or terminates when it notices the te_nowsrv flag 2167c478bd9Sstevel@tonic-gate * set. Note that the maximum amount of messages processed by tl_wput_ser() is 2177c478bd9Sstevel@tonic-gate * always bounded by the amount of messages on the STREAMS queue at the time 2187c478bd9Sstevel@tonic-gate * tl_wsrv_ser() is entered. Any new messages may only appear on the STREAMS 2197c478bd9Sstevel@tonic-gate * queue from another serialized entry which can't happen in parallel. This 2207c478bd9Sstevel@tonic-gate * guarantees that tl_wput_ser() is complete in bounded time (there is no risk 2217c478bd9Sstevel@tonic-gate * of it draining forever while writer places new messages on the STREAMS 2227c478bd9Sstevel@tonic-gate * queue). 2237c478bd9Sstevel@tonic-gate * 2247c478bd9Sstevel@tonic-gate * Note that a closing endpoint never sets te_nowsrv and never calls putbq(). 2257c478bd9Sstevel@tonic-gate * 2267c478bd9Sstevel@tonic-gate * 2277c478bd9Sstevel@tonic-gate * Unix Domain Sockets 2287c478bd9Sstevel@tonic-gate * =================== 2297c478bd9Sstevel@tonic-gate * 2307c478bd9Sstevel@tonic-gate * The driver knows the structure of Unix Domain sockets addresses and treats 2317c478bd9Sstevel@tonic-gate * them differently from generic TLI addresses. For sockets implicit binds are 2327c478bd9Sstevel@tonic-gate * requested by setting SOU_MAGIC_IMPLICIT in the soua_magic part of the address 2337c478bd9Sstevel@tonic-gate * instead of using address length of zero. Explicit binds specify 2347c478bd9Sstevel@tonic-gate * SOU_MAGIC_EXPLICIT as magic. 2357c478bd9Sstevel@tonic-gate * 2367c478bd9Sstevel@tonic-gate * For implicit binds we always use minor number as soua_vp part of the address 2377c478bd9Sstevel@tonic-gate * and avoid any hash table lookups. This saves two hash tables lookups per 2387c478bd9Sstevel@tonic-gate * anonymous bind. 2397c478bd9Sstevel@tonic-gate * 2407c478bd9Sstevel@tonic-gate * For explicit address we hash the vnode pointer instead of hashing the 2417c478bd9Sstevel@tonic-gate * full-scale address+zone+length. Hashing by pointer is more efficient then 2427c478bd9Sstevel@tonic-gate * hashing by the full address. 2437c478bd9Sstevel@tonic-gate * 2447c478bd9Sstevel@tonic-gate * For unix domain sockets the te_ap is always pointing to te_uxaddr part of the 2457c478bd9Sstevel@tonic-gate * tep structure, so it should be never freed. 2467c478bd9Sstevel@tonic-gate * 2477c478bd9Sstevel@tonic-gate * Also for sockets the driver always uses minor number as acceptor id. 2487c478bd9Sstevel@tonic-gate * 2497c478bd9Sstevel@tonic-gate * TPI VIOLATIONS 2507c478bd9Sstevel@tonic-gate * -------------- 2517c478bd9Sstevel@tonic-gate * 2527c478bd9Sstevel@tonic-gate * This driver violates TPI in several respects for Unix Domain Sockets: 2537c478bd9Sstevel@tonic-gate * 2547c478bd9Sstevel@tonic-gate * 1) It treats O_T_BIND_REQ as T_BIND_REQ and refuses bind if an explicit bind 2557c478bd9Sstevel@tonic-gate * is requested and the endpoint is already in use. There is no point in 2567c478bd9Sstevel@tonic-gate * generating an unused address since this address will be rejected by 2577c478bd9Sstevel@tonic-gate * sockfs anyway. For implicit binds it always generates a new address 2587c478bd9Sstevel@tonic-gate * (sets soua_vp to its minor number). 2597c478bd9Sstevel@tonic-gate * 2607c478bd9Sstevel@tonic-gate * 2) It always uses minor number as acceptor ID and never uses queue 2617c478bd9Sstevel@tonic-gate * pointer. It is ok since sockets get acceptor ID from T_CAPABILITY_REQ 2627c478bd9Sstevel@tonic-gate * message and they do not use the queue pointer. 2637c478bd9Sstevel@tonic-gate * 2647c478bd9Sstevel@tonic-gate * 3) For Listener sockets the usual sequence is to issue bind() zero backlog 2657c478bd9Sstevel@tonic-gate * followed by listen(). The listen() should be issued with non-zero 2667c478bd9Sstevel@tonic-gate * backlog, so sotpi_listen() issues unbind request followed by bind 2677c478bd9Sstevel@tonic-gate * request to the same address but with a non-zero qlen value. Both 2687c478bd9Sstevel@tonic-gate * tl_bind() and tl_unbind() require write lock on the hash table to 2697c478bd9Sstevel@tonic-gate * insert/remove the address. The driver does not remove the address from 2707c478bd9Sstevel@tonic-gate * the hash for endpoints that are bound to the explicit address and have 2717c478bd9Sstevel@tonic-gate * backlog of zero. During T_BIND_REQ processing if the address requested 2727c478bd9Sstevel@tonic-gate * is equal to the address the endpoint already has it updates the backlog 2737c478bd9Sstevel@tonic-gate * without reinserting the address in the hash table. This optimization 2747c478bd9Sstevel@tonic-gate * avoids two hash table updates for each listener created. It always 2757c478bd9Sstevel@tonic-gate * avoids the problem of a "stolen" address when another listener may use 2767c478bd9Sstevel@tonic-gate * the same address between the unbind and bind and suddenly listen() fails 2777c478bd9Sstevel@tonic-gate * because address is in use even though the bind() succeeded. 2787c478bd9Sstevel@tonic-gate * 2797c478bd9Sstevel@tonic-gate * 2807c478bd9Sstevel@tonic-gate * CONNECTIONLESS TRANSPORTS 2817c478bd9Sstevel@tonic-gate * ========================= 2827c478bd9Sstevel@tonic-gate * 2837c478bd9Sstevel@tonic-gate * Connectionless transports all share the same serializer (one for TLI and one 2847c478bd9Sstevel@tonic-gate * for Sockets). Functions executing behind serializer can check or modify state 2857c478bd9Sstevel@tonic-gate * of any endpoint. 2867c478bd9Sstevel@tonic-gate * 2877c478bd9Sstevel@tonic-gate * When endpoint X talks to another endpoint Y it caches the pointer to Y in the 2887c478bd9Sstevel@tonic-gate * te_lastep field. The next time X talks to some address A it checks whether A 2897c478bd9Sstevel@tonic-gate * is the same as Y's address and if it is there is no need to lookup Y. If the 2907c478bd9Sstevel@tonic-gate * address is different or the state of Y is not appropriate (e.g. closed or not 2917c478bd9Sstevel@tonic-gate * idle) X does a lookup using tl_find_peer() and caches the new address. 2927c478bd9Sstevel@tonic-gate * NOTE: tl_find_peer() never returns closing endpoint and it places a refhold 2937c478bd9Sstevel@tonic-gate * on the endpoint found. 2947c478bd9Sstevel@tonic-gate * 2957c478bd9Sstevel@tonic-gate * During close of endpoint Y it doesn't try to remove itself from other 2967c478bd9Sstevel@tonic-gate * endpoints caches. They will detect that Y is gone and will search the peer 2977c478bd9Sstevel@tonic-gate * endpoint again. 2987c478bd9Sstevel@tonic-gate * 2997c478bd9Sstevel@tonic-gate * Flow Control Handling. 3007c478bd9Sstevel@tonic-gate * ---------------------- 3017c478bd9Sstevel@tonic-gate * 3027c478bd9Sstevel@tonic-gate * Each connectionless endpoint keeps a list of endpoints which are 3037c478bd9Sstevel@tonic-gate * flow-controlled by its queue. It also keeps a pointer to the queue which 3047c478bd9Sstevel@tonic-gate * flow-controls itself. Whenever flow control releases for endpoint X it 3057c478bd9Sstevel@tonic-gate * enables all queues from the list. During close it also back-enables everyone 3067c478bd9Sstevel@tonic-gate * in the list. If X is flow-controlled when it is closing it removes it from 3077c478bd9Sstevel@tonic-gate * the peers list. 3087c478bd9Sstevel@tonic-gate * 3097c478bd9Sstevel@tonic-gate * DATA STRUCTURES 3107c478bd9Sstevel@tonic-gate * =============== 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * Each endpoint is represented by the tl_endpt_t structure which keeps all the 3137c478bd9Sstevel@tonic-gate * endpoint state. For connection-oriented transports it has a keeps a list 3147c478bd9Sstevel@tonic-gate * of pending connections (tl_icon_t). For connectionless transports it keeps a 3157c478bd9Sstevel@tonic-gate * list of endpoints flow controlled by this one. 3167c478bd9Sstevel@tonic-gate * 3177c478bd9Sstevel@tonic-gate * Each transport type is represented by a per-transport data structure 3187c478bd9Sstevel@tonic-gate * tl_transport_state_t. It contains a pointer to an acceptor ID hash and the 3197c478bd9Sstevel@tonic-gate * endpoint address hash tables for each transport. It also contains pointer to 3207c478bd9Sstevel@tonic-gate * transport serializer for connectionless transports. 3217c478bd9Sstevel@tonic-gate * 3227c478bd9Sstevel@tonic-gate * Each endpoint keeps a link to its transport structure, so the code can find 3237c478bd9Sstevel@tonic-gate * all per-transport information quickly. 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate #include <sys/types.h> 3277c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 3287c478bd9Sstevel@tonic-gate #include <sys/stream.h> 3297c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 3307c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 3317c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 3327c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 3337c478bd9Sstevel@tonic-gate #include <sys/debug.h> 3347c478bd9Sstevel@tonic-gate #include <sys/cred.h> 3357c478bd9Sstevel@tonic-gate #include <sys/errno.h> 3367c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 3377c478bd9Sstevel@tonic-gate #include <sys/id_space.h> 3387c478bd9Sstevel@tonic-gate #include <sys/modhash.h> 3397c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 3407c478bd9Sstevel@tonic-gate #include <sys/tl.h> 3417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 3427c478bd9Sstevel@tonic-gate #include <sys/conf.h> 3437c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 3447c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 3457c478bd9Sstevel@tonic-gate #include <sys/socket.h> 3467c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 3477c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 3487c478bd9Sstevel@tonic-gate #include <sys/xti_xtiopt.h> 3497c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 3507c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 3517c478bd9Sstevel@tonic-gate #include <sys/zone.h> 3527c478bd9Sstevel@tonic-gate #include <inet/common.h> /* typedef int (*pfi_t)() for inet/optcom.h */ 3537c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 3547c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 3557c478bd9Sstevel@tonic-gate #include <sys/ucred.h> 3567c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 3577c478bd9Sstevel@tonic-gate #include <sys/list.h> 3587c478bd9Sstevel@tonic-gate #include <sys/serializer.h> 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * TBD List 3627c478bd9Sstevel@tonic-gate * 14 Eliminate state changes through table 3637c478bd9Sstevel@tonic-gate * 16. AF_UNIX socket options 3647c478bd9Sstevel@tonic-gate * 17. connect() for ticlts 3657c478bd9Sstevel@tonic-gate * 18. support for "netstat" to show AF_UNIX plus TLI local 3667c478bd9Sstevel@tonic-gate * transport connections 3677c478bd9Sstevel@tonic-gate * 21. sanity check to flushing on sending M_ERROR 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate /* 3717c478bd9Sstevel@tonic-gate * CONSTANT DECLARATIONS 3727c478bd9Sstevel@tonic-gate * -------------------- 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate /* 3767c478bd9Sstevel@tonic-gate * Local declarations 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate #define NEXTSTATE(EV, ST) ti_statetbl[EV][ST] 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate #define BADSEQNUM (-1) /* initial seq number used by T_DISCON_IND */ 3817c478bd9Sstevel@tonic-gate #define TL_BUFWAIT (10000) /* usecs to wait for allocb buffer timeout */ 3827c478bd9Sstevel@tonic-gate #define TL_TIDUSZ (64*1024) /* tidu size when "strmsgz" is unlimited (0) */ 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Hash tables size. 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate #define TL_HASH_SIZE 311 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * Definitions for module_info 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate #define TL_ID (104) /* module ID number */ 3927c478bd9Sstevel@tonic-gate #define TL_NAME "tl" /* module name */ 3937c478bd9Sstevel@tonic-gate #define TL_MINPSZ (0) /* min packet size */ 3947c478bd9Sstevel@tonic-gate #define TL_MAXPSZ INFPSZ /* max packet size ZZZ */ 3957c478bd9Sstevel@tonic-gate #define TL_HIWAT (16*1024) /* hi water mark */ 3967c478bd9Sstevel@tonic-gate #define TL_LOWAT (256) /* lo water mark */ 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Definition of minor numbers/modes for new transport provider modes. 3997c478bd9Sstevel@tonic-gate * We view the socket use as a separate mode to get a separate name space. 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate #define TL_TICOTS 0 /* connection oriented transport */ 4027c478bd9Sstevel@tonic-gate #define TL_TICOTSORD 1 /* COTS w/ orderly release */ 4037c478bd9Sstevel@tonic-gate #define TL_TICLTS 2 /* connectionless transport */ 4047c478bd9Sstevel@tonic-gate #define TL_UNUSED 3 4057c478bd9Sstevel@tonic-gate #define TL_SOCKET 4 /* Socket */ 4067c478bd9Sstevel@tonic-gate #define TL_SOCK_COTS (TL_SOCKET|TL_TICOTS) 4077c478bd9Sstevel@tonic-gate #define TL_SOCK_COTSORD (TL_SOCKET|TL_TICOTSORD) 4087c478bd9Sstevel@tonic-gate #define TL_SOCK_CLTS (TL_SOCKET|TL_TICLTS) 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate #define TL_MINOR_MASK 0x7 4117c478bd9Sstevel@tonic-gate #define TL_MINOR_START (TL_TICLTS + 1) 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * LOCAL MACROS 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate #define T_ALIGN(p) P2ROUNDUP((p), sizeof (t_scalar_t)) 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * EXTERNAL VARIABLE DECLARATIONS 4207c478bd9Sstevel@tonic-gate * ----------------------------- 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * state table defined in the OS space.c 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate extern char ti_statetbl[TE_NOEVENTS][TS_NOSTATES]; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * STREAMS DRIVER ENTRY POINTS PROTOTYPES 4297c478bd9Sstevel@tonic-gate */ 4307c478bd9Sstevel@tonic-gate static int tl_open(queue_t *, dev_t *, int, int, cred_t *); 4317c478bd9Sstevel@tonic-gate static int tl_close(queue_t *, int, cred_t *); 4327c478bd9Sstevel@tonic-gate static void tl_wput(queue_t *, mblk_t *); 4337c478bd9Sstevel@tonic-gate static void tl_wsrv(queue_t *); 4347c478bd9Sstevel@tonic-gate static void tl_rsrv(queue_t *); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate static int tl_attach(dev_info_t *, ddi_attach_cmd_t); 4377c478bd9Sstevel@tonic-gate static int tl_detach(dev_info_t *, ddi_detach_cmd_t); 4387c478bd9Sstevel@tonic-gate static int tl_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * GLOBAL DATA STRUCTURES AND VARIABLES 4437c478bd9Sstevel@tonic-gate * ----------------------------------- 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Table representing database of all options managed by T_SVR4_OPTMGMT_REQ 4487c478bd9Sstevel@tonic-gate * For now, we only manage the SO_RECVUCRED option but we also have 4497c478bd9Sstevel@tonic-gate * harmless dummy options to make things work with some common code we access. 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate opdes_t tl_opt_arr[] = { 4527c478bd9Sstevel@tonic-gate /* The SO_TYPE is needed for the hack below */ 4537c478bd9Sstevel@tonic-gate { 4547c478bd9Sstevel@tonic-gate SO_TYPE, 4557c478bd9Sstevel@tonic-gate SOL_SOCKET, 4567c478bd9Sstevel@tonic-gate OA_R, 4577c478bd9Sstevel@tonic-gate OA_R, 4587c478bd9Sstevel@tonic-gate OP_NP, 459bd670b35SErik Nordmark 0, 4607c478bd9Sstevel@tonic-gate sizeof (t_scalar_t), 4617c478bd9Sstevel@tonic-gate 0 4627c478bd9Sstevel@tonic-gate }, 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate SO_RECVUCRED, 4657c478bd9Sstevel@tonic-gate SOL_SOCKET, 4667c478bd9Sstevel@tonic-gate OA_RW, 4677c478bd9Sstevel@tonic-gate OA_RW, 4687c478bd9Sstevel@tonic-gate OP_NP, 469bd670b35SErik Nordmark 0, 4707c478bd9Sstevel@tonic-gate sizeof (int), 4717c478bd9Sstevel@tonic-gate 0 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate }; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * Table of all supported levels 4777c478bd9Sstevel@tonic-gate * Note: Some levels (e.g. XTI_GENERIC) may be valid but may not have 4787c478bd9Sstevel@tonic-gate * any supported options so we need this info separately. 4797c478bd9Sstevel@tonic-gate * 4807c478bd9Sstevel@tonic-gate * This is needed only for topmost tpi providers. 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate optlevel_t tl_valid_levels_arr[] = { 4837c478bd9Sstevel@tonic-gate XTI_GENERIC, 4847c478bd9Sstevel@tonic-gate SOL_SOCKET, 4857c478bd9Sstevel@tonic-gate TL_PROT_LEVEL 4867c478bd9Sstevel@tonic-gate }; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate #define TL_VALID_LEVELS_CNT A_CNT(tl_valid_levels_arr) 4897c478bd9Sstevel@tonic-gate /* 4907c478bd9Sstevel@tonic-gate * Current upper bound on the amount of space needed to return all options. 4917c478bd9Sstevel@tonic-gate * Additional options with data size of sizeof(long) are handled automatically. 4927c478bd9Sstevel@tonic-gate * Others need hand job. 4937c478bd9Sstevel@tonic-gate */ 4947c478bd9Sstevel@tonic-gate #define TL_MAX_OPT_BUF_LEN \ 4957c478bd9Sstevel@tonic-gate ((A_CNT(tl_opt_arr) << 2) + \ 4967c478bd9Sstevel@tonic-gate (A_CNT(tl_opt_arr) * sizeof (struct opthdr)) + \ 4977c478bd9Sstevel@tonic-gate + 64 + sizeof (struct T_optmgmt_ack)) 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate #define TL_OPT_ARR_CNT A_CNT(tl_opt_arr) 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * transport addr structure 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate typedef struct tl_addr { 5057c478bd9Sstevel@tonic-gate zoneid_t ta_zoneid; /* Zone scope of address */ 5067c478bd9Sstevel@tonic-gate t_scalar_t ta_alen; /* length of abuf */ 5077c478bd9Sstevel@tonic-gate void *ta_abuf; /* the addr itself */ 5087c478bd9Sstevel@tonic-gate } tl_addr_t; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * Refcounted version of serializer. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate typedef struct tl_serializer { 5147c478bd9Sstevel@tonic-gate uint_t ts_refcnt; 5157c478bd9Sstevel@tonic-gate serializer_t *ts_serializer; 5167c478bd9Sstevel@tonic-gate } tl_serializer_t; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* 5197c478bd9Sstevel@tonic-gate * Each transport type has a separate state. 5207c478bd9Sstevel@tonic-gate * Per-transport state. 5217c478bd9Sstevel@tonic-gate */ 5227c478bd9Sstevel@tonic-gate typedef struct tl_transport_state { 5237c478bd9Sstevel@tonic-gate char *tr_name; 5247c478bd9Sstevel@tonic-gate minor_t tr_minor; 5257c478bd9Sstevel@tonic-gate uint32_t tr_defaddr; 5267c478bd9Sstevel@tonic-gate mod_hash_t *tr_ai_hash; 5277c478bd9Sstevel@tonic-gate mod_hash_t *tr_addr_hash; 5287c478bd9Sstevel@tonic-gate tl_serializer_t *tr_serializer; 5297c478bd9Sstevel@tonic-gate } tl_transport_state_t; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate #define TL_DFADDR 0x1000 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate static tl_transport_state_t tl_transports[] = { 5347c478bd9Sstevel@tonic-gate { "ticots", TL_TICOTS, TL_DFADDR, NULL, NULL, NULL }, 5357c478bd9Sstevel@tonic-gate { "ticotsord", TL_TICOTSORD, TL_DFADDR, NULL, NULL, NULL }, 5367c478bd9Sstevel@tonic-gate { "ticlts", TL_TICLTS, TL_DFADDR, NULL, NULL, NULL }, 5377c478bd9Sstevel@tonic-gate { "undefined", TL_UNUSED, TL_DFADDR, NULL, NULL, NULL }, 5387c478bd9Sstevel@tonic-gate { "sticots", TL_SOCK_COTS, TL_DFADDR, NULL, NULL, NULL }, 5397c478bd9Sstevel@tonic-gate { "sticotsord", TL_SOCK_COTSORD, TL_DFADDR, NULL, NULL }, 5407c478bd9Sstevel@tonic-gate { "sticlts", TL_SOCK_CLTS, TL_DFADDR, NULL, NULL, NULL } 5417c478bd9Sstevel@tonic-gate }; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate #define TL_MAXTRANSPORT A_CNT(tl_transports) 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate struct tl_endpt; 5467c478bd9Sstevel@tonic-gate typedef struct tl_endpt tl_endpt_t; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate typedef void (tlproc_t)(mblk_t *, tl_endpt_t *); 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * Data structure used to represent pending connects. 5527c478bd9Sstevel@tonic-gate * Records enough information so that the connecting peer can close 5537c478bd9Sstevel@tonic-gate * before the connection gets accepted. 5547c478bd9Sstevel@tonic-gate */ 5557c478bd9Sstevel@tonic-gate typedef struct tl_icon { 5567c478bd9Sstevel@tonic-gate list_node_t ti_node; 5577c478bd9Sstevel@tonic-gate struct tl_endpt *ti_tep; /* NULL if peer has already closed */ 5587c478bd9Sstevel@tonic-gate mblk_t *ti_mp; /* b_next list of data + ordrel_ind */ 5597c478bd9Sstevel@tonic-gate t_scalar_t ti_seqno; /* Sequence number */ 5607c478bd9Sstevel@tonic-gate } tl_icon_t; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate typedef struct so_ux_addr soux_addr_t; 5637c478bd9Sstevel@tonic-gate #define TL_SOUX_ADDRLEN sizeof (soux_addr_t) 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* 566d87b1facSakolb * Maximum number of unaccepted connection indications allowed per listener. 567d87b1facSakolb */ 568d87b1facSakolb #define TL_MAXQLEN 4096 569d87b1facSakolb int tl_maxqlen = TL_MAXQLEN; 570d87b1facSakolb 571d87b1facSakolb /* 5727c478bd9Sstevel@tonic-gate * transport endpoint structure 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate struct tl_endpt { 5757c478bd9Sstevel@tonic-gate queue_t *te_rq; /* stream read queue */ 5767c478bd9Sstevel@tonic-gate queue_t *te_wq; /* stream write queue */ 5777c478bd9Sstevel@tonic-gate uint32_t te_refcnt; 5787c478bd9Sstevel@tonic-gate int32_t te_state; /* TPI state of endpoint */ 5797c478bd9Sstevel@tonic-gate minor_t te_minor; /* minor number */ 5807c478bd9Sstevel@tonic-gate #define te_seqno te_minor 5817c478bd9Sstevel@tonic-gate uint_t te_flag; /* flag field */ 5827c478bd9Sstevel@tonic-gate boolean_t te_nowsrv; 5837c478bd9Sstevel@tonic-gate tl_serializer_t *te_ser; /* Serializer to use */ 5847c478bd9Sstevel@tonic-gate #define te_serializer te_ser->ts_serializer 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate soux_addr_t te_uxaddr; /* Socket address */ 5877c478bd9Sstevel@tonic-gate #define te_magic te_uxaddr.soua_magic 5887c478bd9Sstevel@tonic-gate #define te_vp te_uxaddr.soua_vp 5897c478bd9Sstevel@tonic-gate tl_addr_t te_ap; /* addr bound to this endpt */ 5907c478bd9Sstevel@tonic-gate #define te_zoneid te_ap.ta_zoneid 5917c478bd9Sstevel@tonic-gate #define te_alen te_ap.ta_alen 5927c478bd9Sstevel@tonic-gate #define te_abuf te_ap.ta_abuf 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate tl_transport_state_t *te_transport; 5957c478bd9Sstevel@tonic-gate #define te_addrhash te_transport->tr_addr_hash 5967c478bd9Sstevel@tonic-gate #define te_aihash te_transport->tr_ai_hash 5977c478bd9Sstevel@tonic-gate #define te_defaddr te_transport->tr_defaddr 5987c478bd9Sstevel@tonic-gate cred_t *te_credp; /* endpoint user credentials */ 5997c478bd9Sstevel@tonic-gate mod_hash_hndl_t te_hash_hndl; /* Handle for address hash */ 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * State specific for connection-oriented and connectionless transports. 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate union { 6057c478bd9Sstevel@tonic-gate /* Connection-oriented state. */ 6067c478bd9Sstevel@tonic-gate struct { 6077c478bd9Sstevel@tonic-gate t_uscalar_t _te_nicon; /* count of conn requests */ 6087c478bd9Sstevel@tonic-gate t_uscalar_t _te_qlen; /* max conn requests */ 6097c478bd9Sstevel@tonic-gate tl_endpt_t *_te_oconp; /* conn request pending */ 6107c478bd9Sstevel@tonic-gate tl_endpt_t *_te_conp; /* connected endpt */ 6117c478bd9Sstevel@tonic-gate #ifndef _ILP32 6127c478bd9Sstevel@tonic-gate void *_te_pad; 6137c478bd9Sstevel@tonic-gate #endif 6147c478bd9Sstevel@tonic-gate list_t _te_iconp; /* list of conn ind. pending */ 6157c478bd9Sstevel@tonic-gate } _te_cots_state; 6167c478bd9Sstevel@tonic-gate /* Connection-less state. */ 6177c478bd9Sstevel@tonic-gate struct { 6187c478bd9Sstevel@tonic-gate tl_endpt_t *_te_lastep; /* last dest. endpoint */ 6197c478bd9Sstevel@tonic-gate tl_endpt_t *_te_flowq; /* flow controlled on whom */ 6207c478bd9Sstevel@tonic-gate list_node_t _te_flows; /* lists of connections */ 6217c478bd9Sstevel@tonic-gate list_t _te_flowlist; /* Who flowcontrols on me */ 6227c478bd9Sstevel@tonic-gate } _te_clts_state; 6237c478bd9Sstevel@tonic-gate } _te_transport_state; 6247c478bd9Sstevel@tonic-gate #define te_nicon _te_transport_state._te_cots_state._te_nicon 6257c478bd9Sstevel@tonic-gate #define te_qlen _te_transport_state._te_cots_state._te_qlen 6267c478bd9Sstevel@tonic-gate #define te_oconp _te_transport_state._te_cots_state._te_oconp 6277c478bd9Sstevel@tonic-gate #define te_conp _te_transport_state._te_cots_state._te_conp 6287c478bd9Sstevel@tonic-gate #define te_iconp _te_transport_state._te_cots_state._te_iconp 6297c478bd9Sstevel@tonic-gate #define te_lastep _te_transport_state._te_clts_state._te_lastep 6307c478bd9Sstevel@tonic-gate #define te_flowq _te_transport_state._te_clts_state._te_flowq 6317c478bd9Sstevel@tonic-gate #define te_flowlist _te_transport_state._te_clts_state._te_flowlist 6327c478bd9Sstevel@tonic-gate #define te_flows _te_transport_state._te_clts_state._te_flows 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate bufcall_id_t te_bufcid; /* outstanding bufcall id */ 6357c478bd9Sstevel@tonic-gate timeout_id_t te_timoutid; /* outstanding timeout id */ 6367c478bd9Sstevel@tonic-gate pid_t te_cpid; /* cached pid of endpoint */ 6377c478bd9Sstevel@tonic-gate t_uscalar_t te_acceptor_id; /* acceptor id for T_CONN_RES */ 6387c478bd9Sstevel@tonic-gate /* 6397c478bd9Sstevel@tonic-gate * Pieces of the endpoint state needed for closing. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate kmutex_t te_closelock; 6427c478bd9Sstevel@tonic-gate kcondvar_t te_closecv; 6437c478bd9Sstevel@tonic-gate uint8_t te_closing; /* The endpoint started closing */ 6447c478bd9Sstevel@tonic-gate uint8_t te_closewait; /* Wait in close until zero */ 6457c478bd9Sstevel@tonic-gate mblk_t te_closemp; /* for entering serializer on close */ 6467c478bd9Sstevel@tonic-gate mblk_t te_rsrvmp; /* for entering serializer on rsrv */ 6477c478bd9Sstevel@tonic-gate mblk_t te_wsrvmp; /* for entering serializer on wsrv */ 6487c478bd9Sstevel@tonic-gate kmutex_t te_srv_lock; 6497c478bd9Sstevel@tonic-gate kcondvar_t te_srv_cv; 6507c478bd9Sstevel@tonic-gate uint8_t te_rsrv_active; /* Running in tl_rsrv() */ 6517c478bd9Sstevel@tonic-gate uint8_t te_wsrv_active; /* Running in tl_wsrv() */ 6527c478bd9Sstevel@tonic-gate /* 6537c478bd9Sstevel@tonic-gate * Pieces of the endpoint state needed for serializer transitions. 6547c478bd9Sstevel@tonic-gate */ 6557c478bd9Sstevel@tonic-gate kmutex_t te_ser_lock; /* Protects the count below */ 6567c478bd9Sstevel@tonic-gate uint_t te_ser_count; /* Number of messages on serializer */ 6577c478bd9Sstevel@tonic-gate }; 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * Flag values. Lower 4 bits specify that transport used. 6617c478bd9Sstevel@tonic-gate * TL_LISTENER, TL_ACCEPTOR, TL_ACCEPTED and TL_EAGER are for debugging only, 6627c478bd9Sstevel@tonic-gate * they allow to identify the endpoint more easily. 6637c478bd9Sstevel@tonic-gate */ 6647c478bd9Sstevel@tonic-gate #define TL_LISTENER 0x00010 /* the listener endpoint */ 6657c478bd9Sstevel@tonic-gate #define TL_ACCEPTOR 0x00020 /* the accepting endpoint */ 6667c478bd9Sstevel@tonic-gate #define TL_EAGER 0x00040 /* connecting endpoint */ 6677c478bd9Sstevel@tonic-gate #define TL_ACCEPTED 0x00080 /* accepted connection */ 6687c478bd9Sstevel@tonic-gate #define TL_SETCRED 0x00100 /* flag to indicate sending of credentials */ 6697c478bd9Sstevel@tonic-gate #define TL_SETUCRED 0x00200 /* flag to indicate sending of ucred */ 6707c478bd9Sstevel@tonic-gate #define TL_SOCKUCRED 0x00400 /* flag to indicate sending of SCM_UCRED */ 6717c478bd9Sstevel@tonic-gate #define TL_ADDRHASHED 0x01000 /* Endpoint address is stored in te_addrhash */ 6727c478bd9Sstevel@tonic-gate #define TL_CLOSE_SER 0x10000 /* Endpoint close has entered the serializer */ 6737c478bd9Sstevel@tonic-gate /* 6747c478bd9Sstevel@tonic-gate * Boolean checks for the endpoint type. 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate #define IS_CLTS(x) (((x)->te_flag & TL_TICLTS) != 0) 6777c478bd9Sstevel@tonic-gate #define IS_COTS(x) (((x)->te_flag & TL_TICLTS) == 0) 6787c478bd9Sstevel@tonic-gate #define IS_COTSORD(x) (((x)->te_flag & TL_TICOTSORD) != 0) 6797c478bd9Sstevel@tonic-gate #define IS_SOCKET(x) (((x)->te_flag & TL_SOCKET) != 0) 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * Certain operations are always used together. These macros reduce the chance 6837c478bd9Sstevel@tonic-gate * of missing a part of a combination. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate #define TL_UNCONNECT(x) { tl_refrele(x); x = NULL; } 6867c478bd9Sstevel@tonic-gate #define TL_REMOVE_PEER(x) { if ((x) != NULL) TL_UNCONNECT(x) } 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate #define TL_PUTBQ(x, mp) { \ 6897c478bd9Sstevel@tonic-gate ASSERT(!((x)->te_flag & TL_CLOSE_SER)); \ 6907c478bd9Sstevel@tonic-gate (x)->te_nowsrv = B_TRUE; \ 6917c478bd9Sstevel@tonic-gate (void) putbq((x)->te_wq, mp); \ 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate #define TL_QENABLE(x) { (x)->te_nowsrv = B_FALSE; qenable((x)->te_wq); } 6957c478bd9Sstevel@tonic-gate #define TL_PUTQ(x, mp) { (x)->te_nowsrv = B_FALSE; (void)putq((x)->te_wq, mp); } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate /* 6987c478bd9Sstevel@tonic-gate * STREAMS driver glue data structures. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate static struct module_info tl_minfo = { 7017c478bd9Sstevel@tonic-gate TL_ID, /* mi_idnum */ 7027c478bd9Sstevel@tonic-gate TL_NAME, /* mi_idname */ 7037c478bd9Sstevel@tonic-gate TL_MINPSZ, /* mi_minpsz */ 7047c478bd9Sstevel@tonic-gate TL_MAXPSZ, /* mi_maxpsz */ 7057c478bd9Sstevel@tonic-gate TL_HIWAT, /* mi_hiwat */ 7067c478bd9Sstevel@tonic-gate TL_LOWAT /* mi_lowat */ 7077c478bd9Sstevel@tonic-gate }; 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate static struct qinit tl_rinit = { 7107c478bd9Sstevel@tonic-gate NULL, /* qi_putp */ 7117c478bd9Sstevel@tonic-gate (int (*)())tl_rsrv, /* qi_srvp */ 7127c478bd9Sstevel@tonic-gate tl_open, /* qi_qopen */ 7137c478bd9Sstevel@tonic-gate tl_close, /* qi_qclose */ 7147c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 7157c478bd9Sstevel@tonic-gate &tl_minfo, /* qi_minfo */ 7167c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 7177c478bd9Sstevel@tonic-gate }; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate static struct qinit tl_winit = { 7207c478bd9Sstevel@tonic-gate (int (*)())tl_wput, /* qi_putp */ 7217c478bd9Sstevel@tonic-gate (int (*)())tl_wsrv, /* qi_srvp */ 7227c478bd9Sstevel@tonic-gate NULL, /* qi_qopen */ 7237c478bd9Sstevel@tonic-gate NULL, /* qi_qclose */ 7247c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */ 7257c478bd9Sstevel@tonic-gate &tl_minfo, /* qi_minfo */ 7267c478bd9Sstevel@tonic-gate NULL /* qi_mstat */ 7277c478bd9Sstevel@tonic-gate }; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate static struct streamtab tlinfo = { 7307c478bd9Sstevel@tonic-gate &tl_rinit, /* st_rdinit */ 7317c478bd9Sstevel@tonic-gate &tl_winit, /* st_wrinit */ 7327c478bd9Sstevel@tonic-gate NULL, /* st_muxrinit */ 7337c478bd9Sstevel@tonic-gate NULL /* st_muxwrinit */ 7347c478bd9Sstevel@tonic-gate }; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(tl_devops, nulldev, nulldev, tl_attach, tl_detach, 73719397407SSherry Moore nulldev, tl_info, D_MP, &tlinfo, ddi_quiesce_not_supported); 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 7407c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module -- pseudo driver here */ 741903a11ebSrh87107 "TPI Local Transport (tl)", 7427c478bd9Sstevel@tonic-gate &tl_devops, /* driver ops */ 7437c478bd9Sstevel@tonic-gate }; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 7477c478bd9Sstevel@tonic-gate */ 7487c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 7497c478bd9Sstevel@tonic-gate MODREV_1, 7507c478bd9Sstevel@tonic-gate &modldrv, 7517c478bd9Sstevel@tonic-gate NULL 7527c478bd9Sstevel@tonic-gate }; 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * Templates for response to info request 7567c478bd9Sstevel@tonic-gate * Check sanity of unlimited connect data etc. 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate #define TL_CLTS_PROVIDER_FLAG (XPG4_1|SENDZERO) 7607c478bd9Sstevel@tonic-gate #define TL_COTS_PROVIDER_FLAG (XPG4_1|SENDZERO) 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate static struct T_info_ack tl_cots_info_ack = 7637c478bd9Sstevel@tonic-gate { 7647c478bd9Sstevel@tonic-gate T_INFO_ACK, /* PRIM_type -always T_INFO_ACK */ 7657c478bd9Sstevel@tonic-gate T_INFINITE, /* TSDU size */ 7667c478bd9Sstevel@tonic-gate T_INFINITE, /* ETSDU size */ 7677c478bd9Sstevel@tonic-gate T_INFINITE, /* CDATA_size */ 7687c478bd9Sstevel@tonic-gate T_INFINITE, /* DDATA_size */ 7697c478bd9Sstevel@tonic-gate T_INFINITE, /* ADDR_size */ 7707c478bd9Sstevel@tonic-gate T_INFINITE, /* OPT_size */ 7717c478bd9Sstevel@tonic-gate 0, /* TIDU_size - fill at run time */ 7727c478bd9Sstevel@tonic-gate T_COTS, /* SERV_type */ 7737c478bd9Sstevel@tonic-gate -1, /* CURRENT_state */ 7747c478bd9Sstevel@tonic-gate TL_COTS_PROVIDER_FLAG /* PROVIDER_flag */ 7757c478bd9Sstevel@tonic-gate }; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate static struct T_info_ack tl_clts_info_ack = 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate T_INFO_ACK, /* PRIM_type - always T_INFO_ACK */ 7807c478bd9Sstevel@tonic-gate 0, /* TSDU_size - fill at run time */ 7817c478bd9Sstevel@tonic-gate -2, /* ETSDU_size -2 => not supported */ 7827c478bd9Sstevel@tonic-gate -2, /* CDATA_size -2 => not supported */ 7837c478bd9Sstevel@tonic-gate -2, /* DDATA_size -2 => not supported */ 784b2d8fb89SDan Kruchinin -1, /* ADDR_size -1 => infinite */ 7857c478bd9Sstevel@tonic-gate -1, /* OPT_size */ 7867c478bd9Sstevel@tonic-gate 0, /* TIDU_size - fill at run time */ 7877c478bd9Sstevel@tonic-gate T_CLTS, /* SERV_type */ 7887c478bd9Sstevel@tonic-gate -1, /* CURRENT_state */ 7897c478bd9Sstevel@tonic-gate TL_CLTS_PROVIDER_FLAG /* PROVIDER_flag */ 7907c478bd9Sstevel@tonic-gate }; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* 7937c478bd9Sstevel@tonic-gate * private copy of devinfo pointer used in tl_info 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate static dev_info_t *tl_dip; 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* 7987c478bd9Sstevel@tonic-gate * Endpoints cache. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate static kmem_cache_t *tl_cache; 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * Minor number space. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate static id_space_t *tl_minors; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * Default Data Unit size. 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate static t_scalar_t tl_tidusz; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * Size of hash tables. 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate static size_t tl_hash_size = TL_HASH_SIZE; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate /* 8177c478bd9Sstevel@tonic-gate * Debug and test variable ONLY. Turn off T_CONN_IND queueing 8187c478bd9Sstevel@tonic-gate * for sockets. 8197c478bd9Sstevel@tonic-gate */ 8207c478bd9Sstevel@tonic-gate static int tl_disable_early_connect = 0; 8217c478bd9Sstevel@tonic-gate static int tl_client_closing_when_accepting; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate static int tl_serializer_noswitch; 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * LOCAL FUNCTION PROTOTYPES 8277c478bd9Sstevel@tonic-gate * ------------------------- 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate static boolean_t tl_eqaddr(tl_addr_t *, tl_addr_t *); 8307c478bd9Sstevel@tonic-gate static void tl_do_proto(mblk_t *, tl_endpt_t *); 8317c478bd9Sstevel@tonic-gate static void tl_do_ioctl(mblk_t *, tl_endpt_t *); 8327c478bd9Sstevel@tonic-gate static void tl_do_ioctl_ser(mblk_t *, tl_endpt_t *); 8337c478bd9Sstevel@tonic-gate static void tl_error_ack(queue_t *, mblk_t *, t_scalar_t, t_scalar_t, 8347c478bd9Sstevel@tonic-gate t_scalar_t); 8357c478bd9Sstevel@tonic-gate static void tl_bind(mblk_t *, tl_endpt_t *); 8367c478bd9Sstevel@tonic-gate static void tl_bind_ser(mblk_t *, tl_endpt_t *); 8377c478bd9Sstevel@tonic-gate static void tl_ok_ack(queue_t *, mblk_t *mp, t_scalar_t); 8387c478bd9Sstevel@tonic-gate static void tl_unbind(mblk_t *, tl_endpt_t *); 8397c478bd9Sstevel@tonic-gate static void tl_optmgmt(queue_t *, mblk_t *); 8407c478bd9Sstevel@tonic-gate static void tl_conn_req(queue_t *, mblk_t *); 8417c478bd9Sstevel@tonic-gate static void tl_conn_req_ser(mblk_t *, tl_endpt_t *); 8427c478bd9Sstevel@tonic-gate static void tl_conn_res(mblk_t *, tl_endpt_t *); 8437c478bd9Sstevel@tonic-gate static void tl_discon_req(mblk_t *, tl_endpt_t *); 8447c478bd9Sstevel@tonic-gate static void tl_capability_req(mblk_t *, tl_endpt_t *); 8457c478bd9Sstevel@tonic-gate static void tl_info_req_ser(mblk_t *, tl_endpt_t *); 846b2d8fb89SDan Kruchinin static void tl_addr_req_ser(mblk_t *, tl_endpt_t *); 8477c478bd9Sstevel@tonic-gate static void tl_info_req(mblk_t *, tl_endpt_t *); 8487c478bd9Sstevel@tonic-gate static void tl_addr_req(mblk_t *, tl_endpt_t *); 8497c478bd9Sstevel@tonic-gate static void tl_connected_cots_addr_req(mblk_t *, tl_endpt_t *); 8507c478bd9Sstevel@tonic-gate static void tl_data(mblk_t *, tl_endpt_t *); 8517c478bd9Sstevel@tonic-gate static void tl_exdata(mblk_t *, tl_endpt_t *); 8527c478bd9Sstevel@tonic-gate static void tl_ordrel(mblk_t *, tl_endpt_t *); 8537c478bd9Sstevel@tonic-gate static void tl_unitdata(mblk_t *, tl_endpt_t *); 8547c478bd9Sstevel@tonic-gate static void tl_unitdata_ser(mblk_t *, tl_endpt_t *); 8557c478bd9Sstevel@tonic-gate static void tl_uderr(queue_t *, mblk_t *, t_scalar_t); 8567c478bd9Sstevel@tonic-gate static tl_endpt_t *tl_find_peer(tl_endpt_t *, tl_addr_t *); 8577c478bd9Sstevel@tonic-gate static tl_endpt_t *tl_sock_find_peer(tl_endpt_t *, struct so_ux_addr *); 8587c478bd9Sstevel@tonic-gate static boolean_t tl_get_any_addr(tl_endpt_t *, tl_addr_t *); 8597c478bd9Sstevel@tonic-gate static void tl_cl_backenable(tl_endpt_t *); 8607c478bd9Sstevel@tonic-gate static void tl_co_unconnect(tl_endpt_t *); 8617c478bd9Sstevel@tonic-gate static mblk_t *tl_resizemp(mblk_t *, ssize_t); 8627c478bd9Sstevel@tonic-gate static void tl_discon_ind(tl_endpt_t *, uint32_t); 8637c478bd9Sstevel@tonic-gate static mblk_t *tl_discon_ind_alloc(uint32_t, t_scalar_t); 8647c478bd9Sstevel@tonic-gate static mblk_t *tl_ordrel_ind_alloc(void); 8657c478bd9Sstevel@tonic-gate static tl_icon_t *tl_icon_find(tl_endpt_t *, t_scalar_t); 8667c478bd9Sstevel@tonic-gate static void tl_icon_queuemsg(tl_endpt_t *, t_scalar_t, mblk_t *); 8677c478bd9Sstevel@tonic-gate static boolean_t tl_icon_hasprim(tl_endpt_t *, t_scalar_t, t_scalar_t); 8687c478bd9Sstevel@tonic-gate static void tl_icon_sendmsgs(tl_endpt_t *, mblk_t **); 8697c478bd9Sstevel@tonic-gate static void tl_icon_freemsgs(mblk_t **); 8707c478bd9Sstevel@tonic-gate static void tl_merror(queue_t *, mblk_t *, int); 87145916cd2Sjpk static void tl_fill_option(uchar_t *, cred_t *, pid_t, int, cred_t *); 8727c478bd9Sstevel@tonic-gate static int tl_default_opt(queue_t *, int, int, uchar_t *); 8737c478bd9Sstevel@tonic-gate static int tl_get_opt(queue_t *, int, int, uchar_t *); 8747c478bd9Sstevel@tonic-gate static int tl_set_opt(queue_t *, uint_t, int, int, uint_t, uchar_t *, uint_t *, 875bd670b35SErik Nordmark uchar_t *, void *, cred_t *); 8767c478bd9Sstevel@tonic-gate static void tl_memrecover(queue_t *, mblk_t *, size_t); 8777c478bd9Sstevel@tonic-gate static void tl_freetip(tl_endpt_t *, tl_icon_t *); 8787c478bd9Sstevel@tonic-gate static void tl_free(tl_endpt_t *); 8797c478bd9Sstevel@tonic-gate static int tl_constructor(void *, void *, int); 8807c478bd9Sstevel@tonic-gate static void tl_destructor(void *, void *); 8817c478bd9Sstevel@tonic-gate static void tl_find_callback(mod_hash_key_t, mod_hash_val_t); 8827c478bd9Sstevel@tonic-gate static tl_serializer_t *tl_serializer_alloc(int); 8837c478bd9Sstevel@tonic-gate static void tl_serializer_refhold(tl_serializer_t *); 8847c478bd9Sstevel@tonic-gate static void tl_serializer_refrele(tl_serializer_t *); 8857c478bd9Sstevel@tonic-gate static void tl_serializer_enter(tl_endpt_t *, tlproc_t, mblk_t *); 8867c478bd9Sstevel@tonic-gate static void tl_serializer_exit(tl_endpt_t *); 8877c478bd9Sstevel@tonic-gate static boolean_t tl_noclose(tl_endpt_t *); 8887c478bd9Sstevel@tonic-gate static void tl_closeok(tl_endpt_t *); 8897c478bd9Sstevel@tonic-gate static void tl_refhold(tl_endpt_t *); 8907c478bd9Sstevel@tonic-gate static void tl_refrele(tl_endpt_t *); 8917c478bd9Sstevel@tonic-gate static int tl_hash_cmp_addr(mod_hash_key_t, mod_hash_key_t); 8927c478bd9Sstevel@tonic-gate static uint_t tl_hash_by_addr(void *, mod_hash_key_t); 8937c478bd9Sstevel@tonic-gate static void tl_close_ser(mblk_t *, tl_endpt_t *); 8947c478bd9Sstevel@tonic-gate static void tl_close_finish_ser(mblk_t *, tl_endpt_t *); 8957c478bd9Sstevel@tonic-gate static void tl_wput_data_ser(mblk_t *, tl_endpt_t *); 8967c478bd9Sstevel@tonic-gate static void tl_proto_ser(mblk_t *, tl_endpt_t *); 8977c478bd9Sstevel@tonic-gate static void tl_putq_ser(mblk_t *, tl_endpt_t *); 8987c478bd9Sstevel@tonic-gate static void tl_wput_common_ser(mblk_t *, tl_endpt_t *); 8997c478bd9Sstevel@tonic-gate static void tl_wput_ser(mblk_t *, tl_endpt_t *); 9007c478bd9Sstevel@tonic-gate static void tl_wsrv_ser(mblk_t *, tl_endpt_t *); 9017c478bd9Sstevel@tonic-gate static void tl_rsrv_ser(mblk_t *, tl_endpt_t *); 9027c478bd9Sstevel@tonic-gate static void tl_addr_unbind(tl_endpt_t *); 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Intialize option database object for TL 9067c478bd9Sstevel@tonic-gate */ 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate optdb_obj_t tl_opt_obj = { 9097c478bd9Sstevel@tonic-gate tl_default_opt, /* TL default value function pointer */ 9107c478bd9Sstevel@tonic-gate tl_get_opt, /* TL get function pointer */ 9117c478bd9Sstevel@tonic-gate tl_set_opt, /* TL set function pointer */ 9127c478bd9Sstevel@tonic-gate TL_OPT_ARR_CNT, /* TL option database count of entries */ 9137c478bd9Sstevel@tonic-gate tl_opt_arr, /* TL option database */ 9147c478bd9Sstevel@tonic-gate TL_VALID_LEVELS_CNT, /* TL valid level count of entries */ 9157c478bd9Sstevel@tonic-gate tl_valid_levels_arr /* TL valid level array */ 9167c478bd9Sstevel@tonic-gate }; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate /* 9197c478bd9Sstevel@tonic-gate * LOCAL FUNCTIONS AND DRIVER ENTRY POINTS 9207c478bd9Sstevel@tonic-gate * --------------------------------------- 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate /* 9247c478bd9Sstevel@tonic-gate * Loadable module routines 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate int 9277c478bd9Sstevel@tonic-gate _init(void) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate int 9337c478bd9Sstevel@tonic-gate _fini(void) 9347c478bd9Sstevel@tonic-gate { 9357c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate int 9397c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 9407c478bd9Sstevel@tonic-gate { 9417c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* 9457c478bd9Sstevel@tonic-gate * Driver Entry Points and Other routines 9467c478bd9Sstevel@tonic-gate */ 9477c478bd9Sstevel@tonic-gate static int 9487c478bd9Sstevel@tonic-gate tl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 9497c478bd9Sstevel@tonic-gate { 9507c478bd9Sstevel@tonic-gate int i; 9517c478bd9Sstevel@tonic-gate char name[32]; 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate /* 9547c478bd9Sstevel@tonic-gate * Resume from a checkpoint state. 9557c478bd9Sstevel@tonic-gate */ 9567c478bd9Sstevel@tonic-gate if (cmd == DDI_RESUME) 9577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (cmd != DDI_ATTACH) 9607c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * Deduce TIDU size to use. Note: "strmsgsz" being 0 has semantics that 9647c478bd9Sstevel@tonic-gate * streams message sizes can be unlimited. We use a defined constant 9657c478bd9Sstevel@tonic-gate * instead. 9667c478bd9Sstevel@tonic-gate */ 9677c478bd9Sstevel@tonic-gate tl_tidusz = strmsgsz != 0 ? (t_scalar_t)strmsgsz : TL_TIDUSZ; 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * Create subdevices for each transport. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate for (i = 0; i < TL_UNUSED; i++) { 9737c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, 9747c478bd9Sstevel@tonic-gate tl_transports[i].tr_name, 9757c478bd9Sstevel@tonic-gate S_IFCHR, tl_transports[i].tr_minor, 9767c478bd9Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE) { 9777c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 9787c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate tl_cache = kmem_cache_create("tl_cache", sizeof (tl_endpt_t), 9837c478bd9Sstevel@tonic-gate 0, tl_constructor, tl_destructor, NULL, NULL, NULL, 0); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate if (tl_cache == NULL) { 9867c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 9877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate tl_minors = id_space_create("tl_minor_space", 9917c478bd9Sstevel@tonic-gate TL_MINOR_START, MAXMIN32 - TL_MINOR_START + 1); 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate /* 9947c478bd9Sstevel@tonic-gate * Create ID space for minor numbers 9957c478bd9Sstevel@tonic-gate */ 9967c478bd9Sstevel@tonic-gate for (i = 0; i < TL_MAXTRANSPORT; i++) { 9977c478bd9Sstevel@tonic-gate tl_transport_state_t *t = &tl_transports[i]; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate if (i == TL_UNUSED) 10007c478bd9Sstevel@tonic-gate continue; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate /* Socket COTSORD shares namespace with COTS */ 10037c478bd9Sstevel@tonic-gate if (i == TL_SOCK_COTSORD) { 10047c478bd9Sstevel@tonic-gate t->tr_ai_hash = 10057c478bd9Sstevel@tonic-gate tl_transports[TL_SOCK_COTS].tr_ai_hash; 10067c478bd9Sstevel@tonic-gate ASSERT(t->tr_ai_hash != NULL); 10077c478bd9Sstevel@tonic-gate t->tr_addr_hash = 10087c478bd9Sstevel@tonic-gate tl_transports[TL_SOCK_COTS].tr_addr_hash; 10097c478bd9Sstevel@tonic-gate ASSERT(t->tr_addr_hash != NULL); 10107c478bd9Sstevel@tonic-gate continue; 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * Create hash tables. 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "%s_ai_hash", 10177c478bd9Sstevel@tonic-gate t->tr_name); 10187c478bd9Sstevel@tonic-gate #ifdef _ILP32 10197c478bd9Sstevel@tonic-gate if (i & TL_SOCKET) 10207c478bd9Sstevel@tonic-gate t->tr_ai_hash = 10217c478bd9Sstevel@tonic-gate mod_hash_create_idhash(name, tl_hash_size - 1, 10227c478bd9Sstevel@tonic-gate mod_hash_null_valdtor); 10237c478bd9Sstevel@tonic-gate else 10247c478bd9Sstevel@tonic-gate t->tr_ai_hash = 10257c478bd9Sstevel@tonic-gate mod_hash_create_ptrhash(name, tl_hash_size, 10267c478bd9Sstevel@tonic-gate mod_hash_null_valdtor, sizeof (queue_t)); 10277c478bd9Sstevel@tonic-gate #else 10287c478bd9Sstevel@tonic-gate t->tr_ai_hash = 10297c478bd9Sstevel@tonic-gate mod_hash_create_idhash(name, tl_hash_size - 1, 10307c478bd9Sstevel@tonic-gate mod_hash_null_valdtor); 10317c478bd9Sstevel@tonic-gate #endif /* _ILP32 */ 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate if (i & TL_SOCKET) { 10347c478bd9Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "%s_sockaddr_hash", 10357c478bd9Sstevel@tonic-gate t->tr_name); 10367c478bd9Sstevel@tonic-gate t->tr_addr_hash = mod_hash_create_ptrhash(name, 10377c478bd9Sstevel@tonic-gate tl_hash_size, mod_hash_null_valdtor, 10387c478bd9Sstevel@tonic-gate sizeof (uintptr_t)); 10397c478bd9Sstevel@tonic-gate } else { 10407c478bd9Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "%s_addr_hash", 10417c478bd9Sstevel@tonic-gate t->tr_name); 10427c478bd9Sstevel@tonic-gate t->tr_addr_hash = mod_hash_create_extended(name, 10437c478bd9Sstevel@tonic-gate tl_hash_size, mod_hash_null_keydtor, 10447c478bd9Sstevel@tonic-gate mod_hash_null_valdtor, 10457c478bd9Sstevel@tonic-gate tl_hash_by_addr, NULL, tl_hash_cmp_addr, KM_SLEEP); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /* Create serializer for connectionless transports. */ 10497c478bd9Sstevel@tonic-gate if (i & TL_TICLTS) 10507c478bd9Sstevel@tonic-gate t->tr_serializer = tl_serializer_alloc(KM_SLEEP); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate tl_dip = devi; 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate static int 10597c478bd9Sstevel@tonic-gate tl_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 10607c478bd9Sstevel@tonic-gate { 10617c478bd9Sstevel@tonic-gate int i; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate if (cmd == DDI_SUSPEND) 10647c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate if (cmd != DDI_DETACH) 10677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate /* 10707c478bd9Sstevel@tonic-gate * Destroy arenas and hash tables. 10717c478bd9Sstevel@tonic-gate */ 10727c478bd9Sstevel@tonic-gate for (i = 0; i < TL_MAXTRANSPORT; i++) { 10737c478bd9Sstevel@tonic-gate tl_transport_state_t *t = &tl_transports[i]; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate if ((i == TL_UNUSED) || (i == TL_SOCK_COTSORD)) 10767c478bd9Sstevel@tonic-gate continue; 10777c478bd9Sstevel@tonic-gate 107856f33205SJonathan Adams EQUIV(i & TL_TICLTS, t->tr_serializer != NULL); 10797c478bd9Sstevel@tonic-gate if (t->tr_serializer != NULL) { 10807c478bd9Sstevel@tonic-gate tl_serializer_refrele(t->tr_serializer); 10817c478bd9Sstevel@tonic-gate t->tr_serializer = NULL; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate #ifdef _ILP32 10857c478bd9Sstevel@tonic-gate if (i & TL_SOCKET) 10867c478bd9Sstevel@tonic-gate mod_hash_destroy_idhash(t->tr_ai_hash); 10877c478bd9Sstevel@tonic-gate else 10887c478bd9Sstevel@tonic-gate mod_hash_destroy_ptrhash(t->tr_ai_hash); 10897c478bd9Sstevel@tonic-gate #else 10907c478bd9Sstevel@tonic-gate mod_hash_destroy_idhash(t->tr_ai_hash); 10917c478bd9Sstevel@tonic-gate #endif /* _ILP32 */ 10927c478bd9Sstevel@tonic-gate t->tr_ai_hash = NULL; 10937c478bd9Sstevel@tonic-gate if (i & TL_SOCKET) 10947c478bd9Sstevel@tonic-gate mod_hash_destroy_ptrhash(t->tr_addr_hash); 10957c478bd9Sstevel@tonic-gate else 10967c478bd9Sstevel@tonic-gate mod_hash_destroy_hash(t->tr_addr_hash); 10977c478bd9Sstevel@tonic-gate t->tr_addr_hash = NULL; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate kmem_cache_destroy(tl_cache); 11017c478bd9Sstevel@tonic-gate tl_cache = NULL; 11027c478bd9Sstevel@tonic-gate id_space_destroy(tl_minors); 11037c478bd9Sstevel@tonic-gate tl_minors = NULL; 11047c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 11057c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate /* ARGSUSED */ 11097c478bd9Sstevel@tonic-gate static int 11107c478bd9Sstevel@tonic-gate tl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 11117c478bd9Sstevel@tonic-gate { 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate int retcode = DDI_FAILURE; 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate switch (infocmd) { 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 11187c478bd9Sstevel@tonic-gate if (tl_dip != NULL) { 11197c478bd9Sstevel@tonic-gate *result = (void *)tl_dip; 11207c478bd9Sstevel@tonic-gate retcode = DDI_SUCCESS; 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate break; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 11257c478bd9Sstevel@tonic-gate *result = (void *)0; 11267c478bd9Sstevel@tonic-gate retcode = DDI_SUCCESS; 11277c478bd9Sstevel@tonic-gate break; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate default: 11307c478bd9Sstevel@tonic-gate break; 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate return (retcode); 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * Endpoint reference management. 11377c478bd9Sstevel@tonic-gate */ 11387c478bd9Sstevel@tonic-gate static void 11397c478bd9Sstevel@tonic-gate tl_refhold(tl_endpt_t *tep) 11407c478bd9Sstevel@tonic-gate { 1141*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&tep->te_refcnt); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate static void 11457c478bd9Sstevel@tonic-gate tl_refrele(tl_endpt_t *tep) 11467c478bd9Sstevel@tonic-gate { 11477c478bd9Sstevel@tonic-gate ASSERT(tep->te_refcnt != 0); 11487c478bd9Sstevel@tonic-gate 1149*1a5e258fSJosef 'Jeff' Sipek if (atomic_dec_32_nv(&tep->te_refcnt) == 0) 11507c478bd9Sstevel@tonic-gate tl_free(tep); 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11547c478bd9Sstevel@tonic-gate static int 11557c478bd9Sstevel@tonic-gate tl_constructor(void *buf, void *cdrarg, int kmflags) 11567c478bd9Sstevel@tonic-gate { 11577c478bd9Sstevel@tonic-gate tl_endpt_t *tep = buf; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate bzero(tep, sizeof (tl_endpt_t)); 11607c478bd9Sstevel@tonic-gate mutex_init(&tep->te_closelock, NULL, MUTEX_DEFAULT, NULL); 11617c478bd9Sstevel@tonic-gate cv_init(&tep->te_closecv, NULL, CV_DEFAULT, NULL); 11627c478bd9Sstevel@tonic-gate mutex_init(&tep->te_srv_lock, NULL, MUTEX_DEFAULT, NULL); 11637c478bd9Sstevel@tonic-gate cv_init(&tep->te_srv_cv, NULL, CV_DEFAULT, NULL); 11647c478bd9Sstevel@tonic-gate mutex_init(&tep->te_ser_lock, NULL, MUTEX_DEFAULT, NULL); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate return (0); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11707c478bd9Sstevel@tonic-gate static void 11717c478bd9Sstevel@tonic-gate tl_destructor(void *buf, void *cdrarg) 11727c478bd9Sstevel@tonic-gate { 11737c478bd9Sstevel@tonic-gate tl_endpt_t *tep = buf; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate mutex_destroy(&tep->te_closelock); 11767c478bd9Sstevel@tonic-gate cv_destroy(&tep->te_closecv); 11777c478bd9Sstevel@tonic-gate mutex_destroy(&tep->te_srv_lock); 11787c478bd9Sstevel@tonic-gate cv_destroy(&tep->te_srv_cv); 11797c478bd9Sstevel@tonic-gate mutex_destroy(&tep->te_ser_lock); 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate static void 11837c478bd9Sstevel@tonic-gate tl_free(tl_endpt_t *tep) 11847c478bd9Sstevel@tonic-gate { 11857c478bd9Sstevel@tonic-gate ASSERT(tep->te_refcnt == 0); 11867c478bd9Sstevel@tonic-gate ASSERT(tep->te_transport != NULL); 11877c478bd9Sstevel@tonic-gate ASSERT(tep->te_rq == NULL); 11887c478bd9Sstevel@tonic-gate ASSERT(tep->te_wq == NULL); 11897c478bd9Sstevel@tonic-gate ASSERT(tep->te_ser != NULL); 11907c478bd9Sstevel@tonic-gate ASSERT(tep->te_ser_count == 0); 11917c478bd9Sstevel@tonic-gate ASSERT(! (tep->te_flag & TL_ADDRHASHED)); 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) { 11947c478bd9Sstevel@tonic-gate ASSERT(tep->te_alen == TL_SOUX_ADDRLEN); 11957c478bd9Sstevel@tonic-gate ASSERT(tep->te_abuf == &tep->te_uxaddr); 11967c478bd9Sstevel@tonic-gate ASSERT(tep->te_vp == (void *)(uintptr_t)tep->te_minor); 11977c478bd9Sstevel@tonic-gate ASSERT(tep->te_magic == SOU_MAGIC_IMPLICIT); 11987c478bd9Sstevel@tonic-gate } else if (tep->te_abuf != NULL) { 11997c478bd9Sstevel@tonic-gate kmem_free(tep->te_abuf, tep->te_alen); 12007c478bd9Sstevel@tonic-gate tep->te_alen = -1; /* uninitialized */ 12017c478bd9Sstevel@tonic-gate tep->te_abuf = NULL; 12027c478bd9Sstevel@tonic-gate } else { 12037c478bd9Sstevel@tonic-gate ASSERT(tep->te_alen == -1); 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate id_free(tl_minors, tep->te_minor); 12077c478bd9Sstevel@tonic-gate ASSERT(tep->te_credp == NULL); 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate if (tep->te_hash_hndl != NULL) 12107c478bd9Sstevel@tonic-gate mod_hash_cancel(tep->te_addrhash, &tep->te_hash_hndl); 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 12137c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(tep->te_conp); 12147c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(tep->te_oconp); 12157c478bd9Sstevel@tonic-gate tl_serializer_refrele(tep->te_ser); 12167c478bd9Sstevel@tonic-gate tep->te_ser = NULL; 12177c478bd9Sstevel@tonic-gate ASSERT(tep->te_nicon == 0); 12187c478bd9Sstevel@tonic-gate ASSERT(list_head(&tep->te_iconp) == NULL); 12197c478bd9Sstevel@tonic-gate } else { 12207c478bd9Sstevel@tonic-gate ASSERT(tep->te_lastep == NULL); 12217c478bd9Sstevel@tonic-gate ASSERT(list_head(&tep->te_flowlist) == NULL); 12227c478bd9Sstevel@tonic-gate ASSERT(tep->te_flowq == NULL); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate ASSERT(tep->te_bufcid == 0); 12267c478bd9Sstevel@tonic-gate ASSERT(tep->te_timoutid == 0); 12277c478bd9Sstevel@tonic-gate bzero(&tep->te_ap, sizeof (tep->te_ap)); 12287c478bd9Sstevel@tonic-gate tep->te_acceptor_id = 0; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate ASSERT(tep->te_closewait == 0); 12317c478bd9Sstevel@tonic-gate ASSERT(!tep->te_rsrv_active); 12327c478bd9Sstevel@tonic-gate ASSERT(!tep->te_wsrv_active); 12337c478bd9Sstevel@tonic-gate tep->te_closing = 0; 12347c478bd9Sstevel@tonic-gate tep->te_nowsrv = B_FALSE; 12357c478bd9Sstevel@tonic-gate tep->te_flag = 0; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate kmem_cache_free(tl_cache, tep); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate /* 12417c478bd9Sstevel@tonic-gate * Allocate/free reference-counted wrappers for serializers. 12427c478bd9Sstevel@tonic-gate */ 12437c478bd9Sstevel@tonic-gate static tl_serializer_t * 12447c478bd9Sstevel@tonic-gate tl_serializer_alloc(int flags) 12457c478bd9Sstevel@tonic-gate { 12467c478bd9Sstevel@tonic-gate tl_serializer_t *s = kmem_alloc(sizeof (tl_serializer_t), flags); 12477c478bd9Sstevel@tonic-gate serializer_t *ser; 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate if (s == NULL) 12507c478bd9Sstevel@tonic-gate return (NULL); 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate ser = serializer_create(flags); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate if (ser == NULL) { 12557c478bd9Sstevel@tonic-gate kmem_free(s, sizeof (tl_serializer_t)); 12567c478bd9Sstevel@tonic-gate return (NULL); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate s->ts_refcnt = 1; 12607c478bd9Sstevel@tonic-gate s->ts_serializer = ser; 12617c478bd9Sstevel@tonic-gate return (s); 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate static void 12657c478bd9Sstevel@tonic-gate tl_serializer_refhold(tl_serializer_t *s) 12667c478bd9Sstevel@tonic-gate { 1267*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&s->ts_refcnt); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate static void 12717c478bd9Sstevel@tonic-gate tl_serializer_refrele(tl_serializer_t *s) 12727c478bd9Sstevel@tonic-gate { 1273*1a5e258fSJosef 'Jeff' Sipek if (atomic_dec_32_nv(&s->ts_refcnt) == 0) { 12747c478bd9Sstevel@tonic-gate serializer_destroy(s->ts_serializer); 12757c478bd9Sstevel@tonic-gate kmem_free(s, sizeof (tl_serializer_t)); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * Post a request on the endpoint serializer. For COTS transports keep track of 12817c478bd9Sstevel@tonic-gate * the number of pending requests. 12827c478bd9Sstevel@tonic-gate */ 12837c478bd9Sstevel@tonic-gate static void 12847c478bd9Sstevel@tonic-gate tl_serializer_enter(tl_endpt_t *tep, tlproc_t tlproc, mblk_t *mp) 12857c478bd9Sstevel@tonic-gate { 12867c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 12877c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_ser_lock); 12887c478bd9Sstevel@tonic-gate tep->te_ser_count++; 12897c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_ser_lock); 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate serializer_enter(tep->te_serializer, (srproc_t *)tlproc, mp, tep); 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * Complete processing the request on the serializer. Decrement the counter for 12967c478bd9Sstevel@tonic-gate * pending requests for COTS transports. 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate static void 12997c478bd9Sstevel@tonic-gate tl_serializer_exit(tl_endpt_t *tep) 13007c478bd9Sstevel@tonic-gate { 13017c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 13027c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_ser_lock); 13037c478bd9Sstevel@tonic-gate ASSERT(tep->te_ser_count != 0); 13047c478bd9Sstevel@tonic-gate tep->te_ser_count--; 13057c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_ser_lock); 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * Hash management functions. 13117c478bd9Sstevel@tonic-gate */ 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate /* 13147c478bd9Sstevel@tonic-gate * Return TRUE if two addresses are equal, false otherwise. 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate static boolean_t 13177c478bd9Sstevel@tonic-gate tl_eqaddr(tl_addr_t *ap1, tl_addr_t *ap2) 13187c478bd9Sstevel@tonic-gate { 13197c478bd9Sstevel@tonic-gate return ((ap1->ta_alen > 0) && 13207c478bd9Sstevel@tonic-gate (ap1->ta_alen == ap2->ta_alen) && 13217c478bd9Sstevel@tonic-gate (ap1->ta_zoneid == ap2->ta_zoneid) && 13227c478bd9Sstevel@tonic-gate (bcmp(ap1->ta_abuf, ap2->ta_abuf, ap1->ta_alen) == 0)); 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * This function is called whenever an endpoint is found in the hash table. 13277c478bd9Sstevel@tonic-gate */ 13287c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 13297c478bd9Sstevel@tonic-gate static void 13307c478bd9Sstevel@tonic-gate tl_find_callback(mod_hash_key_t key, mod_hash_val_t val) 13317c478bd9Sstevel@tonic-gate { 13327c478bd9Sstevel@tonic-gate tl_refhold((tl_endpt_t *)val); 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate /* 13367c478bd9Sstevel@tonic-gate * Address hash function. 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13397c478bd9Sstevel@tonic-gate static uint_t 13407c478bd9Sstevel@tonic-gate tl_hash_by_addr(void *hash_data, mod_hash_key_t key) 13417c478bd9Sstevel@tonic-gate { 13427c478bd9Sstevel@tonic-gate tl_addr_t *ap = (tl_addr_t *)key; 13437c478bd9Sstevel@tonic-gate size_t len = ap->ta_alen; 13447c478bd9Sstevel@tonic-gate uchar_t *p = ap->ta_abuf; 13457c478bd9Sstevel@tonic-gate uint_t i, g; 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate ASSERT((len > 0) && (p != NULL)); 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate for (i = ap->ta_zoneid; len -- != 0; p++) { 13507c478bd9Sstevel@tonic-gate i = (i << 4) + (*p); 13517c478bd9Sstevel@tonic-gate if ((g = (i & 0xf0000000U)) != 0) { 13527c478bd9Sstevel@tonic-gate i ^= (g >> 24); 13537c478bd9Sstevel@tonic-gate i ^= g; 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate return (i); 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate /* 13607c478bd9Sstevel@tonic-gate * This function is used by hash lookups. It compares two generic addresses. 13617c478bd9Sstevel@tonic-gate */ 13627c478bd9Sstevel@tonic-gate static int 13637c478bd9Sstevel@tonic-gate tl_hash_cmp_addr(mod_hash_key_t key1, mod_hash_key_t key2) 13647c478bd9Sstevel@tonic-gate { 13657c478bd9Sstevel@tonic-gate #ifdef DEBUG 13667c478bd9Sstevel@tonic-gate tl_addr_t *ap1 = (tl_addr_t *)key1; 13677c478bd9Sstevel@tonic-gate tl_addr_t *ap2 = (tl_addr_t *)key2; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate ASSERT(key1 != NULL); 13707c478bd9Sstevel@tonic-gate ASSERT(key2 != NULL); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate ASSERT(ap1->ta_abuf != NULL); 13737c478bd9Sstevel@tonic-gate ASSERT(ap2->ta_abuf != NULL); 13747c478bd9Sstevel@tonic-gate ASSERT(ap1->ta_alen > 0); 13757c478bd9Sstevel@tonic-gate ASSERT(ap2->ta_alen > 0); 13767c478bd9Sstevel@tonic-gate #endif 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate return (! tl_eqaddr((tl_addr_t *)key1, (tl_addr_t *)key2)); 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * Prevent endpoint from closing if possible. 13837c478bd9Sstevel@tonic-gate * Return B_TRUE on success, B_FALSE on failure. 13847c478bd9Sstevel@tonic-gate */ 13857c478bd9Sstevel@tonic-gate static boolean_t 13867c478bd9Sstevel@tonic-gate tl_noclose(tl_endpt_t *tep) 13877c478bd9Sstevel@tonic-gate { 13887c478bd9Sstevel@tonic-gate boolean_t rc = B_FALSE; 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_closelock); 13917c478bd9Sstevel@tonic-gate if (! tep->te_closing) { 13927c478bd9Sstevel@tonic-gate ASSERT(tep->te_closewait == 0); 13937c478bd9Sstevel@tonic-gate tep->te_closewait++; 13947c478bd9Sstevel@tonic-gate rc = B_TRUE; 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_closelock); 13977c478bd9Sstevel@tonic-gate return (rc); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* 14017c478bd9Sstevel@tonic-gate * Allow endpoint to close if needed. 14027c478bd9Sstevel@tonic-gate */ 14037c478bd9Sstevel@tonic-gate static void 14047c478bd9Sstevel@tonic-gate tl_closeok(tl_endpt_t *tep) 14057c478bd9Sstevel@tonic-gate { 14067c478bd9Sstevel@tonic-gate ASSERT(tep->te_closewait > 0); 14077c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_closelock); 14087c478bd9Sstevel@tonic-gate ASSERT(tep->te_closewait == 1); 14097c478bd9Sstevel@tonic-gate tep->te_closewait--; 14107c478bd9Sstevel@tonic-gate cv_signal(&tep->te_closecv); 14117c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_closelock); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * STREAMS open entry point. 14167c478bd9Sstevel@tonic-gate */ 14177c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14187c478bd9Sstevel@tonic-gate static int 14197c478bd9Sstevel@tonic-gate tl_open(queue_t *rq, dev_t *devp, int oflag, int sflag, cred_t *credp) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate tl_endpt_t *tep; 14227c478bd9Sstevel@tonic-gate minor_t minor = getminor(*devp); 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate /* 14257c478bd9Sstevel@tonic-gate * Driver is called directly. Both CLONEOPEN and MODOPEN 14267c478bd9Sstevel@tonic-gate * are illegal 14277c478bd9Sstevel@tonic-gate */ 14287c478bd9Sstevel@tonic-gate if ((sflag == CLONEOPEN) || (sflag == MODOPEN)) 14297c478bd9Sstevel@tonic-gate return (ENXIO); 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate if (rq->q_ptr != NULL) 14327c478bd9Sstevel@tonic-gate return (0); 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate /* Minor number should specify the mode used for the driver. */ 14357c478bd9Sstevel@tonic-gate if ((minor >= TL_UNUSED)) 14367c478bd9Sstevel@tonic-gate return (ENXIO); 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate if (oflag & SO_SOCKSTR) { 14397c478bd9Sstevel@tonic-gate minor |= TL_SOCKET; 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate tep = kmem_cache_alloc(tl_cache, KM_SLEEP); 14437c478bd9Sstevel@tonic-gate tep->te_refcnt = 1; 14447c478bd9Sstevel@tonic-gate tep->te_cpid = curproc->p_pid; 14457c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = tep; 14467c478bd9Sstevel@tonic-gate tep->te_state = TS_UNBND; 14477c478bd9Sstevel@tonic-gate tep->te_credp = credp; 14487c478bd9Sstevel@tonic-gate crhold(credp); 14497c478bd9Sstevel@tonic-gate tep->te_zoneid = getzoneid(); 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate tep->te_flag = minor & TL_MINOR_MASK; 14527c478bd9Sstevel@tonic-gate tep->te_transport = &tl_transports[minor]; 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate /* Allocate a unique minor number for this instance. */ 14557c478bd9Sstevel@tonic-gate tep->te_minor = (minor_t)id_alloc(tl_minors); 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate /* Reserve hash handle for bind(). */ 14587c478bd9Sstevel@tonic-gate (void) mod_hash_reserve(tep->te_addrhash, &tep->te_hash_hndl); 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* Transport-specific initialization */ 14617c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 14627c478bd9Sstevel@tonic-gate /* Use private serializer */ 14637c478bd9Sstevel@tonic-gate tep->te_ser = tl_serializer_alloc(KM_SLEEP); 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* Create list for pending connections */ 14667c478bd9Sstevel@tonic-gate list_create(&tep->te_iconp, sizeof (tl_icon_t), 14677c478bd9Sstevel@tonic-gate offsetof(tl_icon_t, ti_node)); 14687c478bd9Sstevel@tonic-gate tep->te_qlen = 0; 14697c478bd9Sstevel@tonic-gate tep->te_nicon = 0; 14707c478bd9Sstevel@tonic-gate tep->te_oconp = NULL; 14717c478bd9Sstevel@tonic-gate tep->te_conp = NULL; 14727c478bd9Sstevel@tonic-gate } else { 14737c478bd9Sstevel@tonic-gate /* Use shared serializer */ 14747c478bd9Sstevel@tonic-gate tep->te_ser = tep->te_transport->tr_serializer; 14757c478bd9Sstevel@tonic-gate bzero(&tep->te_flows, sizeof (list_node_t)); 14767c478bd9Sstevel@tonic-gate /* Create list for flow control */ 14777c478bd9Sstevel@tonic-gate list_create(&tep->te_flowlist, sizeof (tl_endpt_t), 14787c478bd9Sstevel@tonic-gate offsetof(tl_endpt_t, te_flows)); 14797c478bd9Sstevel@tonic-gate tep->te_flowq = NULL; 14807c478bd9Sstevel@tonic-gate tep->te_lastep = NULL; 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate /* Initialize endpoint address */ 14857c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) { 14867c478bd9Sstevel@tonic-gate /* Socket-specific address handling. */ 14877c478bd9Sstevel@tonic-gate tep->te_alen = TL_SOUX_ADDRLEN; 14887c478bd9Sstevel@tonic-gate tep->te_abuf = &tep->te_uxaddr; 14897c478bd9Sstevel@tonic-gate tep->te_vp = (void *)(uintptr_t)tep->te_minor; 14907c478bd9Sstevel@tonic-gate tep->te_magic = SOU_MAGIC_IMPLICIT; 14917c478bd9Sstevel@tonic-gate } else { 14927c478bd9Sstevel@tonic-gate tep->te_alen = -1; 14937c478bd9Sstevel@tonic-gate tep->te_abuf = NULL; 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate /* clone the driver */ 14977c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), tep->te_minor); 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate tep->te_rq = rq; 15007c478bd9Sstevel@tonic-gate tep->te_wq = WR(rq); 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate #ifdef _ILP32 15037c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) 15047c478bd9Sstevel@tonic-gate tep->te_acceptor_id = tep->te_minor; 15057c478bd9Sstevel@tonic-gate else 15067c478bd9Sstevel@tonic-gate tep->te_acceptor_id = (t_uscalar_t)rq; 15077c478bd9Sstevel@tonic-gate #else 15087c478bd9Sstevel@tonic-gate tep->te_acceptor_id = tep->te_minor; 15097c478bd9Sstevel@tonic-gate #endif /* _ILP32 */ 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate qprocson(rq); 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate /* 15157c478bd9Sstevel@tonic-gate * Insert acceptor ID in the hash. The AI hash always sleeps on 15167c478bd9Sstevel@tonic-gate * insertion so insertion can't fail. 15177c478bd9Sstevel@tonic-gate */ 15187c478bd9Sstevel@tonic-gate (void) mod_hash_insert(tep->te_transport->tr_ai_hash, 15197c478bd9Sstevel@tonic-gate (mod_hash_key_t)(uintptr_t)tep->te_acceptor_id, 15207c478bd9Sstevel@tonic-gate (mod_hash_val_t)tep); 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate return (0); 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate /* ARGSUSED1 */ 15267c478bd9Sstevel@tonic-gate static int 15277c478bd9Sstevel@tonic-gate tl_close(queue_t *rq, int flag, cred_t *credp) 15287c478bd9Sstevel@tonic-gate { 15297c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)rq->q_ptr; 15307c478bd9Sstevel@tonic-gate tl_endpt_t *elp = NULL; 15317c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 15327c478bd9Sstevel@tonic-gate int rc; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate ASSERT(wq == WR(rq)); 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate /* 15377c478bd9Sstevel@tonic-gate * Remove the endpoint from acceptor hash. 15387c478bd9Sstevel@tonic-gate */ 15397c478bd9Sstevel@tonic-gate rc = mod_hash_remove(tep->te_transport->tr_ai_hash, 15407c478bd9Sstevel@tonic-gate (mod_hash_key_t)(uintptr_t)tep->te_acceptor_id, 15417c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&elp); 15427c478bd9Sstevel@tonic-gate ASSERT(rc == 0 && tep == elp); 15437c478bd9Sstevel@tonic-gate if ((rc != 0) || (tep != elp)) { 15447c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 15457c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 15467c478bd9Sstevel@tonic-gate "tl_close:inconsistency in AI hash")); 15477c478bd9Sstevel@tonic-gate } 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate /* 15507c478bd9Sstevel@tonic-gate * Wait till close is safe, then mark endpoint as closing. 15517c478bd9Sstevel@tonic-gate */ 15527c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_closelock); 15537c478bd9Sstevel@tonic-gate while (tep->te_closewait) 15547c478bd9Sstevel@tonic-gate cv_wait(&tep->te_closecv, &tep->te_closelock); 15557c478bd9Sstevel@tonic-gate tep->te_closing = B_TRUE; 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * Will wait for the serializer part of the close to finish, so set 15587c478bd9Sstevel@tonic-gate * te_closewait now. 15597c478bd9Sstevel@tonic-gate */ 15607c478bd9Sstevel@tonic-gate tep->te_closewait = 1; 15617c478bd9Sstevel@tonic-gate tep->te_nowsrv = B_FALSE; 15627c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_closelock); 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* 15657c478bd9Sstevel@tonic-gate * tl_close_ser doesn't drop reference, so no need to tl_refhold. 15667c478bd9Sstevel@tonic-gate * It is safe because close will wait for tl_close_ser to finish. 15677c478bd9Sstevel@tonic-gate */ 15687c478bd9Sstevel@tonic-gate tl_serializer_enter(tep, tl_close_ser, &tep->te_closemp); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate /* 15717c478bd9Sstevel@tonic-gate * Wait for the first phase of close to complete before qprocsoff(). 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_closelock); 15747c478bd9Sstevel@tonic-gate while (tep->te_closewait) 15757c478bd9Sstevel@tonic-gate cv_wait(&tep->te_closecv, &tep->te_closelock); 15767c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_closelock); 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate qprocsoff(rq); 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate if (tep->te_bufcid) { 15817c478bd9Sstevel@tonic-gate qunbufcall(rq, tep->te_bufcid); 15827c478bd9Sstevel@tonic-gate tep->te_bufcid = 0; 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate if (tep->te_timoutid) { 15857c478bd9Sstevel@tonic-gate (void) quntimeout(rq, tep->te_timoutid); 15867c478bd9Sstevel@tonic-gate tep->te_timoutid = 0; 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * Finish close behind serializer. 15917c478bd9Sstevel@tonic-gate * 15927c478bd9Sstevel@tonic-gate * For a CLTS endpoint increase a refcount and continue close processing 15937c478bd9Sstevel@tonic-gate * with serializer protection. This processing may happen asynchronously 15947c478bd9Sstevel@tonic-gate * with the completion of tl_close(). 15957c478bd9Sstevel@tonic-gate * 15967c478bd9Sstevel@tonic-gate * Fot a COTS endpoint wait before destroying tep since the serializer 15977c478bd9Sstevel@tonic-gate * may go away together with tep and we need to destroy serializer 15987c478bd9Sstevel@tonic-gate * outside of serializer context. 15997c478bd9Sstevel@tonic-gate */ 16007c478bd9Sstevel@tonic-gate ASSERT(tep->te_closewait == 0); 16017c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) 16027c478bd9Sstevel@tonic-gate tep->te_closewait = 1; 16037c478bd9Sstevel@tonic-gate else 16047c478bd9Sstevel@tonic-gate tl_refhold(tep); 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate tl_serializer_enter(tep, tl_close_finish_ser, &tep->te_closemp); 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate /* 16097c478bd9Sstevel@tonic-gate * For connection-oriented transports wait for all serializer activity 16107c478bd9Sstevel@tonic-gate * to settle down. 16117c478bd9Sstevel@tonic-gate */ 16127c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 16137c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_closelock); 16147c478bd9Sstevel@tonic-gate while (tep->te_closewait) 16157c478bd9Sstevel@tonic-gate cv_wait(&tep->te_closecv, &tep->te_closelock); 16167c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_closelock); 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate crfree(tep->te_credp); 16207c478bd9Sstevel@tonic-gate tep->te_credp = NULL; 16217c478bd9Sstevel@tonic-gate tep->te_wq = NULL; 16227c478bd9Sstevel@tonic-gate tl_refrele(tep); 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * tep is likely to be destroyed now, so can't reference it any more. 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate rq->q_ptr = wq->q_ptr = NULL; 16287c478bd9Sstevel@tonic-gate return (0); 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate /* 16327c478bd9Sstevel@tonic-gate * First phase of close processing done behind the serializer. 16337c478bd9Sstevel@tonic-gate * 16347c478bd9Sstevel@tonic-gate * Do not drop the reference in the end - tl_close() wants this reference to 16357c478bd9Sstevel@tonic-gate * stay. 16367c478bd9Sstevel@tonic-gate */ 16377c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 16387c478bd9Sstevel@tonic-gate static void 16397c478bd9Sstevel@tonic-gate tl_close_ser(mblk_t *mp, tl_endpt_t *tep) 16407c478bd9Sstevel@tonic-gate { 16417c478bd9Sstevel@tonic-gate ASSERT(tep->te_closing); 16427c478bd9Sstevel@tonic-gate ASSERT(tep->te_closewait == 1); 16437c478bd9Sstevel@tonic-gate ASSERT(!(tep->te_flag & TL_CLOSE_SER)); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate tep->te_flag |= TL_CLOSE_SER; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * Drain out all messages on queue except for TL_TICOTS where the 16497c478bd9Sstevel@tonic-gate * abortive release semantics permit discarding of data on close 16507c478bd9Sstevel@tonic-gate */ 16517c478bd9Sstevel@tonic-gate if (tep->te_wq->q_first && (IS_CLTS(tep) || IS_COTSORD(tep))) { 16527c478bd9Sstevel@tonic-gate tl_wsrv_ser(NULL, tep); 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate /* Remove address from hash table. */ 16567c478bd9Sstevel@tonic-gate tl_addr_unbind(tep); 16577c478bd9Sstevel@tonic-gate /* 16587c478bd9Sstevel@tonic-gate * qprocsoff() gets confused when q->q_next is not NULL on the write 16597c478bd9Sstevel@tonic-gate * queue of the driver, so clear these before qprocsoff() is called. 16607c478bd9Sstevel@tonic-gate * Also clear q_next for the peer since this queue is going away. 16617c478bd9Sstevel@tonic-gate */ 16627c478bd9Sstevel@tonic-gate if (IS_COTS(tep) && !IS_SOCKET(tep)) { 16637c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = tep->te_conp; 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate tep->te_wq->q_next = NULL; 16667c478bd9Sstevel@tonic-gate if ((peer_tep != NULL) && !peer_tep->te_closing) 16677c478bd9Sstevel@tonic-gate peer_tep->te_wq->q_next = NULL; 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate tep->te_rq = NULL; 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate /* wake up tl_close() */ 16737c478bd9Sstevel@tonic-gate tl_closeok(tep); 16747c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate /* 16787c478bd9Sstevel@tonic-gate * Second phase of tl_close(). Should wakeup tl_close() for COTS mode and drop 16797c478bd9Sstevel@tonic-gate * the reference for CLTS. 16807c478bd9Sstevel@tonic-gate * 16817c478bd9Sstevel@tonic-gate * Called from serializer. Should drop reference count for CLTS only. 16827c478bd9Sstevel@tonic-gate */ 16837c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 16847c478bd9Sstevel@tonic-gate static void 16857c478bd9Sstevel@tonic-gate tl_close_finish_ser(mblk_t *mp, tl_endpt_t *tep) 16867c478bd9Sstevel@tonic-gate { 16877c478bd9Sstevel@tonic-gate ASSERT(tep->te_closing); 168856f33205SJonathan Adams IMPLY(IS_CLTS(tep), tep->te_closewait == 0); 168956f33205SJonathan Adams IMPLY(IS_COTS(tep), tep->te_closewait == 1); 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate tep->te_state = -1; /* Uninitialized */ 16927c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 16937c478bd9Sstevel@tonic-gate tl_co_unconnect(tep); 16947c478bd9Sstevel@tonic-gate } else { 16957c478bd9Sstevel@tonic-gate /* Connectionless specific cleanup */ 16967c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(tep->te_lastep); 16977c478bd9Sstevel@tonic-gate /* 16987c478bd9Sstevel@tonic-gate * Backenable anybody that is flow controlled waiting for 16997c478bd9Sstevel@tonic-gate * this endpoint. 17007c478bd9Sstevel@tonic-gate */ 17017c478bd9Sstevel@tonic-gate tl_cl_backenable(tep); 17027c478bd9Sstevel@tonic-gate if (tep->te_flowq != NULL) { 17037c478bd9Sstevel@tonic-gate list_remove(&(tep->te_flowq->te_flowlist), tep); 17047c478bd9Sstevel@tonic-gate tep->te_flowq = NULL; 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 17097c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) 17107c478bd9Sstevel@tonic-gate tl_closeok(tep); 17117c478bd9Sstevel@tonic-gate else 17127c478bd9Sstevel@tonic-gate tl_refrele(tep); 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * STREAMS write-side put procedure. 17177c478bd9Sstevel@tonic-gate * Enter serializer for most of the processing. 17187c478bd9Sstevel@tonic-gate * 17197c478bd9Sstevel@tonic-gate * The T_CONN_REQ is processed outside of serializer. 17207c478bd9Sstevel@tonic-gate */ 17217c478bd9Sstevel@tonic-gate static void 17227c478bd9Sstevel@tonic-gate tl_wput(queue_t *wq, mblk_t *mp) 17237c478bd9Sstevel@tonic-gate { 17247c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)wq->q_ptr; 17257c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp); 17267c478bd9Sstevel@tonic-gate union T_primitives *prim = (union T_primitives *)mp->b_rptr; 17277c478bd9Sstevel@tonic-gate tlproc_t *tl_proc = NULL; 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 17307c478bd9Sstevel@tonic-gate case M_DATA: 17317c478bd9Sstevel@tonic-gate /* Only valid for connection-oriented transports */ 17327c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 17337c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 17347c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 17357c478bd9Sstevel@tonic-gate "tl_wput:M_DATA invalid for ticlts driver")); 17367c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 1737049304ffSxy158873 return; 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate tl_proc = tl_wput_data_ser; 17407c478bd9Sstevel@tonic-gate break; 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate case M_IOCTL: 17437c478bd9Sstevel@tonic-gate switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 17447c478bd9Sstevel@tonic-gate case TL_IOC_CREDOPT: 17457c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 17467c478bd9Sstevel@tonic-gate case TL_IOC_UCREDOPT: 17477c478bd9Sstevel@tonic-gate /* 17487c478bd9Sstevel@tonic-gate * Serialize endpoint state change. 17497c478bd9Sstevel@tonic-gate */ 17507c478bd9Sstevel@tonic-gate tl_proc = tl_do_ioctl_ser; 17517c478bd9Sstevel@tonic-gate break; 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate default: 17547c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL); 17557c478bd9Sstevel@tonic-gate return; 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate break; 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate case M_FLUSH: 17607c478bd9Sstevel@tonic-gate /* 17617c478bd9Sstevel@tonic-gate * do canonical M_FLUSH processing 17627c478bd9Sstevel@tonic-gate */ 17637c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 17647c478bd9Sstevel@tonic-gate flushq(wq, FLUSHALL); 17657c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 17687c478bd9Sstevel@tonic-gate flushq(RD(wq), FLUSHALL); 17697c478bd9Sstevel@tonic-gate qreply(wq, mp); 17707c478bd9Sstevel@tonic-gate } else { 17717c478bd9Sstevel@tonic-gate freemsg(mp); 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate return; 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate case M_PROTO: 17767c478bd9Sstevel@tonic-gate if (msz < sizeof (prim->type)) { 17777c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 17787c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 17797c478bd9Sstevel@tonic-gate "tl_wput:M_PROTO data too short")); 17807c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 17817c478bd9Sstevel@tonic-gate return; 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate switch (prim->type) { 17847c478bd9Sstevel@tonic-gate case T_OPTMGMT_REQ: 17857c478bd9Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 17867c478bd9Sstevel@tonic-gate /* 17877c478bd9Sstevel@tonic-gate * Process TPI option management requests immediately 17887c478bd9Sstevel@tonic-gate * in put procedure regardless of in-order processing 17897c478bd9Sstevel@tonic-gate * of already queued messages. 17907c478bd9Sstevel@tonic-gate * (Note: This driver supports AF_UNIX socket 17917c478bd9Sstevel@tonic-gate * implementation. Unless we implement this processing, 17927c478bd9Sstevel@tonic-gate * setsockopt() on socket endpoint will block on flow 17937c478bd9Sstevel@tonic-gate * controlled endpoints which it should not. That is 17947c478bd9Sstevel@tonic-gate * required for successful execution of VSU socket tests 17957c478bd9Sstevel@tonic-gate * and is consistent with BSD socket behavior). 17967c478bd9Sstevel@tonic-gate */ 17977c478bd9Sstevel@tonic-gate tl_optmgmt(wq, mp); 17987c478bd9Sstevel@tonic-gate return; 17997c478bd9Sstevel@tonic-gate case O_T_BIND_REQ: 18007c478bd9Sstevel@tonic-gate case T_BIND_REQ: 18017c478bd9Sstevel@tonic-gate tl_proc = tl_bind_ser; 18027c478bd9Sstevel@tonic-gate break; 18037c478bd9Sstevel@tonic-gate case T_CONN_REQ: 18047c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 18057c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 18067c478bd9Sstevel@tonic-gate return; 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate tl_conn_req(wq, mp); 18097c478bd9Sstevel@tonic-gate return; 18107c478bd9Sstevel@tonic-gate case T_DATA_REQ: 18117c478bd9Sstevel@tonic-gate case T_OPTDATA_REQ: 18127c478bd9Sstevel@tonic-gate case T_EXDATA_REQ: 18137c478bd9Sstevel@tonic-gate case T_ORDREL_REQ: 18147c478bd9Sstevel@tonic-gate tl_proc = tl_putq_ser; 18157c478bd9Sstevel@tonic-gate break; 18167c478bd9Sstevel@tonic-gate case T_UNITDATA_REQ: 18177c478bd9Sstevel@tonic-gate if (IS_COTS(tep) || 18187c478bd9Sstevel@tonic-gate (msz < sizeof (struct T_unitdata_req))) { 18197c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 18207c478bd9Sstevel@tonic-gate return; 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate if ((tep->te_state == TS_IDLE) && !wq->q_first) { 18237c478bd9Sstevel@tonic-gate tl_proc = tl_unitdata_ser; 18247c478bd9Sstevel@tonic-gate } else { 18257c478bd9Sstevel@tonic-gate tl_proc = tl_putq_ser; 18267c478bd9Sstevel@tonic-gate } 18277c478bd9Sstevel@tonic-gate break; 18287c478bd9Sstevel@tonic-gate default: 18297c478bd9Sstevel@tonic-gate /* 18307c478bd9Sstevel@tonic-gate * process in service procedure if message already 18317c478bd9Sstevel@tonic-gate * queued (maintain in-order processing) 18327c478bd9Sstevel@tonic-gate */ 18337c478bd9Sstevel@tonic-gate if (wq->q_first != NULL) { 18347c478bd9Sstevel@tonic-gate tl_proc = tl_putq_ser; 18357c478bd9Sstevel@tonic-gate } else { 18367c478bd9Sstevel@tonic-gate tl_proc = tl_wput_ser; 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate break; 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate break; 18417c478bd9Sstevel@tonic-gate 18427c478bd9Sstevel@tonic-gate case M_PCPROTO: 18437c478bd9Sstevel@tonic-gate /* 18447c478bd9Sstevel@tonic-gate * Check that the message has enough data to figure out TPI 18457c478bd9Sstevel@tonic-gate * primitive. 18467c478bd9Sstevel@tonic-gate */ 18477c478bd9Sstevel@tonic-gate if (msz < sizeof (prim->type)) { 18487c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 18497c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 18507c478bd9Sstevel@tonic-gate "tl_wput:M_PCROTO data too short")); 18517c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 18527c478bd9Sstevel@tonic-gate return; 18537c478bd9Sstevel@tonic-gate } 18547c478bd9Sstevel@tonic-gate switch (prim->type) { 18557c478bd9Sstevel@tonic-gate case T_CAPABILITY_REQ: 18567c478bd9Sstevel@tonic-gate tl_capability_req(mp, tep); 18577c478bd9Sstevel@tonic-gate return; 18587c478bd9Sstevel@tonic-gate case T_INFO_REQ: 18597c478bd9Sstevel@tonic-gate tl_proc = tl_info_req_ser; 18607c478bd9Sstevel@tonic-gate break; 1861b2d8fb89SDan Kruchinin case T_ADDR_REQ: 1862b2d8fb89SDan Kruchinin tl_proc = tl_addr_req_ser; 1863b2d8fb89SDan Kruchinin break; 1864b2d8fb89SDan Kruchinin 18657c478bd9Sstevel@tonic-gate default: 18667c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 18677c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 18687c478bd9Sstevel@tonic-gate "tl_wput:unknown TPI msg primitive")); 18697c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 18707c478bd9Sstevel@tonic-gate return; 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate break; 18737c478bd9Sstevel@tonic-gate default: 18747c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 18757c478bd9Sstevel@tonic-gate "tl_wput:default:unexpected Streams message")); 18767c478bd9Sstevel@tonic-gate freemsg(mp); 18777c478bd9Sstevel@tonic-gate return; 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate /* 18817c478bd9Sstevel@tonic-gate * Continue processing via serializer. 18827c478bd9Sstevel@tonic-gate */ 18837c478bd9Sstevel@tonic-gate ASSERT(tl_proc != NULL); 18847c478bd9Sstevel@tonic-gate tl_refhold(tep); 18857c478bd9Sstevel@tonic-gate tl_serializer_enter(tep, tl_proc, mp); 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate /* 18897c478bd9Sstevel@tonic-gate * Place message on the queue while preserving order. 18907c478bd9Sstevel@tonic-gate */ 18917c478bd9Sstevel@tonic-gate static void 18927c478bd9Sstevel@tonic-gate tl_putq_ser(mblk_t *mp, tl_endpt_t *tep) 18937c478bd9Sstevel@tonic-gate { 18947c478bd9Sstevel@tonic-gate if (tep->te_closing) { 18957c478bd9Sstevel@tonic-gate tl_wput_ser(mp, tep); 18967c478bd9Sstevel@tonic-gate } else { 18977c478bd9Sstevel@tonic-gate TL_PUTQ(tep, mp); 18987c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 18997c478bd9Sstevel@tonic-gate tl_refrele(tep); 19007c478bd9Sstevel@tonic-gate } 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate static void 19057c478bd9Sstevel@tonic-gate tl_wput_common_ser(mblk_t *mp, tl_endpt_t *tep) 19067c478bd9Sstevel@tonic-gate { 19077c478bd9Sstevel@tonic-gate ASSERT((DB_TYPE(mp) == M_DATA) || (DB_TYPE(mp) == M_PROTO)); 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 19107c478bd9Sstevel@tonic-gate case M_DATA: 19117c478bd9Sstevel@tonic-gate tl_data(mp, tep); 19127c478bd9Sstevel@tonic-gate break; 19137c478bd9Sstevel@tonic-gate case M_PROTO: 19147c478bd9Sstevel@tonic-gate tl_do_proto(mp, tep); 19157c478bd9Sstevel@tonic-gate break; 19167c478bd9Sstevel@tonic-gate default: 19177c478bd9Sstevel@tonic-gate freemsg(mp); 19187c478bd9Sstevel@tonic-gate break; 19197c478bd9Sstevel@tonic-gate } 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* 19237c478bd9Sstevel@tonic-gate * Write side put procedure called from serializer. 19247c478bd9Sstevel@tonic-gate */ 19257c478bd9Sstevel@tonic-gate static void 19267c478bd9Sstevel@tonic-gate tl_wput_ser(mblk_t *mp, tl_endpt_t *tep) 19277c478bd9Sstevel@tonic-gate { 19287c478bd9Sstevel@tonic-gate tl_wput_common_ser(mp, tep); 19297c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 19307c478bd9Sstevel@tonic-gate tl_refrele(tep); 19317c478bd9Sstevel@tonic-gate } 19327c478bd9Sstevel@tonic-gate 19337c478bd9Sstevel@tonic-gate /* 19347c478bd9Sstevel@tonic-gate * M_DATA processing. Called from serializer. 19357c478bd9Sstevel@tonic-gate */ 19367c478bd9Sstevel@tonic-gate static void 19377c478bd9Sstevel@tonic-gate tl_wput_data_ser(mblk_t *mp, tl_endpt_t *tep) 19387c478bd9Sstevel@tonic-gate { 19397c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = tep->te_conp; 19407c478bd9Sstevel@tonic-gate queue_t *peer_rq; 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA); 19437c478bd9Sstevel@tonic-gate ASSERT(IS_COTS(tep)); 19447c478bd9Sstevel@tonic-gate 194556f33205SJonathan Adams IMPLY(peer_tep, tep->te_serializer == peer_tep->te_serializer); 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate /* 19487c478bd9Sstevel@tonic-gate * fastpath for data. Ignore flow control if tep is closing. 19497c478bd9Sstevel@tonic-gate */ 19507c478bd9Sstevel@tonic-gate if ((peer_tep != NULL) && 19517c478bd9Sstevel@tonic-gate !peer_tep->te_closing && 19527c478bd9Sstevel@tonic-gate ((tep->te_state == TS_DATA_XFER) || 19537c478bd9Sstevel@tonic-gate (tep->te_state == TS_WREQ_ORDREL)) && 19547c478bd9Sstevel@tonic-gate (tep->te_wq != NULL) && 19557c478bd9Sstevel@tonic-gate (tep->te_wq->q_first == NULL) && 19567c478bd9Sstevel@tonic-gate ((peer_tep->te_state == TS_DATA_XFER) || 19577c478bd9Sstevel@tonic-gate (peer_tep->te_state == TS_WREQ_ORDREL)) && 19587c478bd9Sstevel@tonic-gate ((peer_rq = peer_tep->te_rq) != NULL) && 19597c478bd9Sstevel@tonic-gate (canputnext(peer_rq) || tep->te_closing)) { 19607c478bd9Sstevel@tonic-gate putnext(peer_rq, mp); 19617c478bd9Sstevel@tonic-gate } else if (tep->te_closing) { 19627c478bd9Sstevel@tonic-gate /* 19637c478bd9Sstevel@tonic-gate * It is possible that by the time we got here tep started to 19647c478bd9Sstevel@tonic-gate * close. If the write queue is not empty, and the state is 19657c478bd9Sstevel@tonic-gate * TS_DATA_XFER the data should be delivered in order, so we 19667c478bd9Sstevel@tonic-gate * call putq() instead of freeing the data. 19677c478bd9Sstevel@tonic-gate */ 19687c478bd9Sstevel@tonic-gate if ((tep->te_wq != NULL) && 19697c478bd9Sstevel@tonic-gate ((tep->te_state == TS_DATA_XFER) || 19707c478bd9Sstevel@tonic-gate (tep->te_state == TS_WREQ_ORDREL))) { 19717c478bd9Sstevel@tonic-gate TL_PUTQ(tep, mp); 19727c478bd9Sstevel@tonic-gate } else { 19737c478bd9Sstevel@tonic-gate freemsg(mp); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate } else { 19767c478bd9Sstevel@tonic-gate TL_PUTQ(tep, mp); 19777c478bd9Sstevel@tonic-gate } 19787c478bd9Sstevel@tonic-gate 19797c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 19807c478bd9Sstevel@tonic-gate tl_refrele(tep); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate /* 19847c478bd9Sstevel@tonic-gate * Write side service routine. 19857c478bd9Sstevel@tonic-gate * 19867c478bd9Sstevel@tonic-gate * All actual processing happens within serializer which is entered 19877c478bd9Sstevel@tonic-gate * synchronously. It is possible that by the time tl_wsrv() wakes up, some new 19887c478bd9Sstevel@tonic-gate * messages that need processing may have arrived, so tl_wsrv repeats until 19897c478bd9Sstevel@tonic-gate * queue is empty or te_nowsrv is set. 19907c478bd9Sstevel@tonic-gate */ 19917c478bd9Sstevel@tonic-gate static void 19927c478bd9Sstevel@tonic-gate tl_wsrv(queue_t *wq) 19937c478bd9Sstevel@tonic-gate { 19947c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)wq->q_ptr; 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate while ((wq->q_first != NULL) && !tep->te_nowsrv) { 19977c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_srv_lock); 19987c478bd9Sstevel@tonic-gate ASSERT(tep->te_wsrv_active == B_FALSE); 19997c478bd9Sstevel@tonic-gate tep->te_wsrv_active = B_TRUE; 20007c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_srv_lock); 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate tl_serializer_enter(tep, tl_wsrv_ser, &tep->te_wsrvmp); 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate /* 20057c478bd9Sstevel@tonic-gate * Wait for serializer job to complete. 20067c478bd9Sstevel@tonic-gate */ 20077c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_srv_lock); 20087c478bd9Sstevel@tonic-gate while (tep->te_wsrv_active) { 20097c478bd9Sstevel@tonic-gate cv_wait(&tep->te_srv_cv, &tep->te_srv_lock); 20107c478bd9Sstevel@tonic-gate } 20117c478bd9Sstevel@tonic-gate cv_signal(&tep->te_srv_cv); 20127c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_srv_lock); 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate /* 20177c478bd9Sstevel@tonic-gate * Serialized write side processing of the STREAMS queue. 20187c478bd9Sstevel@tonic-gate * May be called either from tl_wsrv() or from tl_close() in which case ser_mp 20197c478bd9Sstevel@tonic-gate * is NULL. 20207c478bd9Sstevel@tonic-gate */ 20217c478bd9Sstevel@tonic-gate static void 20227c478bd9Sstevel@tonic-gate tl_wsrv_ser(mblk_t *ser_mp, tl_endpt_t *tep) 20237c478bd9Sstevel@tonic-gate { 20247c478bd9Sstevel@tonic-gate mblk_t *mp; 20257c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate ASSERT(wq != NULL); 20287c478bd9Sstevel@tonic-gate while (!tep->te_nowsrv && (mp = getq(wq)) != NULL) { 20297c478bd9Sstevel@tonic-gate tl_wput_common_ser(mp, tep); 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate /* 20337c478bd9Sstevel@tonic-gate * Wakeup service routine unless called from close. 20347c478bd9Sstevel@tonic-gate * If ser_mp is specified, the caller is tl_wsrv(). 20357c478bd9Sstevel@tonic-gate * Otherwise, the caller is tl_close_ser(). Since tl_close_ser() doesn't 20367c478bd9Sstevel@tonic-gate * call tl_serializer_enter() before calling tl_wsrv_ser(), there should 20377c478bd9Sstevel@tonic-gate * be no matching tl_serializer_exit() in this case. 20387c478bd9Sstevel@tonic-gate * Also, there is no need to wakeup anyone since tl_close_ser() is not 20397c478bd9Sstevel@tonic-gate * waiting on te_srv_cv. 20407c478bd9Sstevel@tonic-gate */ 20417c478bd9Sstevel@tonic-gate if (ser_mp != NULL) { 20427c478bd9Sstevel@tonic-gate /* 20437c478bd9Sstevel@tonic-gate * We are called from tl_wsrv. 20447c478bd9Sstevel@tonic-gate */ 20457c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_srv_lock); 20467c478bd9Sstevel@tonic-gate ASSERT(tep->te_wsrv_active); 20477c478bd9Sstevel@tonic-gate tep->te_wsrv_active = B_FALSE; 20487c478bd9Sstevel@tonic-gate cv_signal(&tep->te_srv_cv); 20497c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_srv_lock); 20507c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 20517c478bd9Sstevel@tonic-gate } 20527c478bd9Sstevel@tonic-gate } 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate /* 20557c478bd9Sstevel@tonic-gate * Called when the stream is backenabled. Enter serializer and qenable everyone 20567c478bd9Sstevel@tonic-gate * flow controlled by tep. 20577c478bd9Sstevel@tonic-gate * 20587c478bd9Sstevel@tonic-gate * NOTE: The service routine should enter serializer synchronously. Otherwise it 20597c478bd9Sstevel@tonic-gate * is possible that two instances of tl_rsrv will be running reusing the same 20607c478bd9Sstevel@tonic-gate * rsrv mblk. 20617c478bd9Sstevel@tonic-gate */ 20627c478bd9Sstevel@tonic-gate static void 20637c478bd9Sstevel@tonic-gate tl_rsrv(queue_t *rq) 20647c478bd9Sstevel@tonic-gate { 20657c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)rq->q_ptr; 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate ASSERT(rq->q_first == NULL); 20687c478bd9Sstevel@tonic-gate ASSERT(tep->te_rsrv_active == 0); 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate tep->te_rsrv_active = B_TRUE; 20717c478bd9Sstevel@tonic-gate tl_serializer_enter(tep, tl_rsrv_ser, &tep->te_rsrvmp); 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * Wait for serializer job to complete. 20747c478bd9Sstevel@tonic-gate */ 20757c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_srv_lock); 20767c478bd9Sstevel@tonic-gate while (tep->te_rsrv_active) { 20777c478bd9Sstevel@tonic-gate cv_wait(&tep->te_srv_cv, &tep->te_srv_lock); 20787c478bd9Sstevel@tonic-gate } 20797c478bd9Sstevel@tonic-gate cv_signal(&tep->te_srv_cv); 20807c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_srv_lock); 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 20847c478bd9Sstevel@tonic-gate static void 20857c478bd9Sstevel@tonic-gate tl_rsrv_ser(mblk_t *mp, tl_endpt_t *tep) 20867c478bd9Sstevel@tonic-gate { 20877c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep; 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate if (IS_CLTS(tep) && tep->te_state == TS_IDLE) { 20907c478bd9Sstevel@tonic-gate tl_cl_backenable(tep); 20917c478bd9Sstevel@tonic-gate } else if ( 20927c478bd9Sstevel@tonic-gate IS_COTS(tep) && 20937c478bd9Sstevel@tonic-gate ((peer_tep = tep->te_conp) != NULL) && 20947c478bd9Sstevel@tonic-gate !peer_tep->te_closing && 20957c478bd9Sstevel@tonic-gate ((tep->te_state == TS_DATA_XFER) || 20967c478bd9Sstevel@tonic-gate (tep->te_state == TS_WIND_ORDREL)|| 20977c478bd9Sstevel@tonic-gate (tep->te_state == TS_WREQ_ORDREL))) { 20987c478bd9Sstevel@tonic-gate TL_QENABLE(peer_tep); 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate /* 21027c478bd9Sstevel@tonic-gate * Wakeup read side service routine. 21037c478bd9Sstevel@tonic-gate */ 21047c478bd9Sstevel@tonic-gate mutex_enter(&tep->te_srv_lock); 21057c478bd9Sstevel@tonic-gate ASSERT(tep->te_rsrv_active); 21067c478bd9Sstevel@tonic-gate tep->te_rsrv_active = B_FALSE; 21077c478bd9Sstevel@tonic-gate cv_signal(&tep->te_srv_cv); 21087c478bd9Sstevel@tonic-gate mutex_exit(&tep->te_srv_lock); 21097c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate /* 21137c478bd9Sstevel@tonic-gate * process M_PROTO messages. Always called from serializer. 21147c478bd9Sstevel@tonic-gate */ 21157c478bd9Sstevel@tonic-gate static void 21167c478bd9Sstevel@tonic-gate tl_do_proto(mblk_t *mp, tl_endpt_t *tep) 21177c478bd9Sstevel@tonic-gate { 21187c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp); 21197c478bd9Sstevel@tonic-gate union T_primitives *prim = (union T_primitives *)mp->b_rptr; 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate /* Message size was validated by tl_wput(). */ 21227c478bd9Sstevel@tonic-gate ASSERT(msz >= sizeof (prim->type)); 21237c478bd9Sstevel@tonic-gate 21247c478bd9Sstevel@tonic-gate switch (prim->type) { 21257c478bd9Sstevel@tonic-gate case T_UNBIND_REQ: 21267c478bd9Sstevel@tonic-gate tl_unbind(mp, tep); 21277c478bd9Sstevel@tonic-gate break; 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate case T_ADDR_REQ: 21307c478bd9Sstevel@tonic-gate tl_addr_req(mp, tep); 21317c478bd9Sstevel@tonic-gate break; 21327c478bd9Sstevel@tonic-gate 21337c478bd9Sstevel@tonic-gate case O_T_CONN_RES: 21347c478bd9Sstevel@tonic-gate case T_CONN_RES: 21357c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 21367c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21377c478bd9Sstevel@tonic-gate break; 21387c478bd9Sstevel@tonic-gate } 21397c478bd9Sstevel@tonic-gate tl_conn_res(mp, tep); 21407c478bd9Sstevel@tonic-gate break; 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate case T_DISCON_REQ: 21437c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 21447c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21457c478bd9Sstevel@tonic-gate break; 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate tl_discon_req(mp, tep); 21487c478bd9Sstevel@tonic-gate break; 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate case T_DATA_REQ: 21517c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 21527c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21537c478bd9Sstevel@tonic-gate break; 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate tl_data(mp, tep); 21567c478bd9Sstevel@tonic-gate break; 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate case T_OPTDATA_REQ: 21597c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 21607c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21617c478bd9Sstevel@tonic-gate break; 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate tl_data(mp, tep); 21647c478bd9Sstevel@tonic-gate break; 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate case T_EXDATA_REQ: 21677c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 21687c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21697c478bd9Sstevel@tonic-gate break; 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate tl_exdata(mp, tep); 21727c478bd9Sstevel@tonic-gate break; 21737c478bd9Sstevel@tonic-gate 21747c478bd9Sstevel@tonic-gate case T_ORDREL_REQ: 21757c478bd9Sstevel@tonic-gate if (! IS_COTSORD(tep)) { 21767c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21777c478bd9Sstevel@tonic-gate break; 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate tl_ordrel(mp, tep); 21807c478bd9Sstevel@tonic-gate break; 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate case T_UNITDATA_REQ: 21837c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 21847c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21857c478bd9Sstevel@tonic-gate break; 21867c478bd9Sstevel@tonic-gate } 21877c478bd9Sstevel@tonic-gate tl_unitdata(mp, tep); 21887c478bd9Sstevel@tonic-gate break; 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate default: 21917c478bd9Sstevel@tonic-gate tl_merror(tep->te_wq, mp, EPROTO); 21927c478bd9Sstevel@tonic-gate break; 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate } 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate /* 21977c478bd9Sstevel@tonic-gate * Process ioctl from serializer. 21987c478bd9Sstevel@tonic-gate * This is a wrapper around tl_do_ioctl(). 21997c478bd9Sstevel@tonic-gate */ 22007c478bd9Sstevel@tonic-gate static void 22017c478bd9Sstevel@tonic-gate tl_do_ioctl_ser(mblk_t *mp, tl_endpt_t *tep) 22027c478bd9Sstevel@tonic-gate { 22037c478bd9Sstevel@tonic-gate if (! tep->te_closing) 22047c478bd9Sstevel@tonic-gate tl_do_ioctl(mp, tep); 22057c478bd9Sstevel@tonic-gate else 22067c478bd9Sstevel@tonic-gate freemsg(mp); 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 22097c478bd9Sstevel@tonic-gate tl_refrele(tep); 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate static void 22137c478bd9Sstevel@tonic-gate tl_do_ioctl(mblk_t *mp, tl_endpt_t *tep) 22147c478bd9Sstevel@tonic-gate { 22157c478bd9Sstevel@tonic-gate struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; 22167c478bd9Sstevel@tonic-gate int cmd = iocbp->ioc_cmd; 22177c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 22187c478bd9Sstevel@tonic-gate int error; 22197c478bd9Sstevel@tonic-gate int thisopt, otheropt; 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate ASSERT((cmd == TL_IOC_CREDOPT) || (cmd == TL_IOC_UCREDOPT)); 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate switch (cmd) { 22247c478bd9Sstevel@tonic-gate case TL_IOC_CREDOPT: 22257c478bd9Sstevel@tonic-gate if (cmd == TL_IOC_CREDOPT) { 22267c478bd9Sstevel@tonic-gate thisopt = TL_SETCRED; 22277c478bd9Sstevel@tonic-gate otheropt = TL_SETUCRED; 22287c478bd9Sstevel@tonic-gate } else { 22297c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 22307c478bd9Sstevel@tonic-gate case TL_IOC_UCREDOPT: 22317c478bd9Sstevel@tonic-gate thisopt = TL_SETUCRED; 22327c478bd9Sstevel@tonic-gate otheropt = TL_SETCRED; 22337c478bd9Sstevel@tonic-gate } 22347c478bd9Sstevel@tonic-gate /* 22357c478bd9Sstevel@tonic-gate * The credentials passing does not apply to sockets. 22367c478bd9Sstevel@tonic-gate * Only one of the cred options can be set at a given time. 22377c478bd9Sstevel@tonic-gate */ 22387c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep) || (tep->te_flag & otheropt)) { 22397c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL); 22407c478bd9Sstevel@tonic-gate return; 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate /* 22447c478bd9Sstevel@tonic-gate * Turn on generation of credential options for 22457c478bd9Sstevel@tonic-gate * T_conn_req, T_conn_con, T_unidata_ind. 22467c478bd9Sstevel@tonic-gate */ 22477c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uint32_t)); 22487c478bd9Sstevel@tonic-gate if (error != 0) { 22497c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error); 22507c478bd9Sstevel@tonic-gate return; 22517c478bd9Sstevel@tonic-gate } 22527c478bd9Sstevel@tonic-gate if (!IS_P2ALIGNED(mp->b_cont->b_rptr, sizeof (uint32_t))) { 22537c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL); 22547c478bd9Sstevel@tonic-gate return; 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate if (*(uint32_t *)mp->b_cont->b_rptr) 22587c478bd9Sstevel@tonic-gate tep->te_flag |= thisopt; 22597c478bd9Sstevel@tonic-gate else 22607c478bd9Sstevel@tonic-gate tep->te_flag &= ~thisopt; 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0); 22637c478bd9Sstevel@tonic-gate break; 22647c478bd9Sstevel@tonic-gate 22657c478bd9Sstevel@tonic-gate default: 22667c478bd9Sstevel@tonic-gate /* Should not be here */ 22677c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL); 22687c478bd9Sstevel@tonic-gate break; 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate /* 22747c478bd9Sstevel@tonic-gate * send T_ERROR_ACK 22757c478bd9Sstevel@tonic-gate * Note: assumes enough memory or caller passed big enough mp 22767c478bd9Sstevel@tonic-gate * - no recovery from allocb failures 22777c478bd9Sstevel@tonic-gate */ 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate static void 22807c478bd9Sstevel@tonic-gate tl_error_ack(queue_t *wq, mblk_t *mp, t_scalar_t tli_err, 22817c478bd9Sstevel@tonic-gate t_scalar_t unix_err, t_scalar_t type) 22827c478bd9Sstevel@tonic-gate { 22837c478bd9Sstevel@tonic-gate struct T_error_ack *err_ack; 22847c478bd9Sstevel@tonic-gate mblk_t *ackmp = tpi_ack_alloc(mp, sizeof (struct T_error_ack), 22857c478bd9Sstevel@tonic-gate M_PCPROTO, T_ERROR_ACK); 22867c478bd9Sstevel@tonic-gate 22877c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 22887c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, 0, 1, SL_TRACE|SL_ERROR, 22897c478bd9Sstevel@tonic-gate "tl_error_ack:out of mblk memory")); 22907c478bd9Sstevel@tonic-gate tl_merror(wq, NULL, ENOSR); 22917c478bd9Sstevel@tonic-gate return; 22927c478bd9Sstevel@tonic-gate } 22937c478bd9Sstevel@tonic-gate err_ack = (struct T_error_ack *)ackmp->b_rptr; 22947c478bd9Sstevel@tonic-gate err_ack->ERROR_prim = type; 22957c478bd9Sstevel@tonic-gate err_ack->TLI_error = tli_err; 22967c478bd9Sstevel@tonic-gate err_ack->UNIX_error = unix_err; 22977c478bd9Sstevel@tonic-gate 22987c478bd9Sstevel@tonic-gate /* 22997c478bd9Sstevel@tonic-gate * send error ack message 23007c478bd9Sstevel@tonic-gate */ 23017c478bd9Sstevel@tonic-gate qreply(wq, ackmp); 23027c478bd9Sstevel@tonic-gate } 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate 23067c478bd9Sstevel@tonic-gate /* 23077c478bd9Sstevel@tonic-gate * send T_OK_ACK 23087c478bd9Sstevel@tonic-gate * Note: assumes enough memory or caller passed big enough mp 23097c478bd9Sstevel@tonic-gate * - no recovery from allocb failures 23107c478bd9Sstevel@tonic-gate */ 23117c478bd9Sstevel@tonic-gate static void 23127c478bd9Sstevel@tonic-gate tl_ok_ack(queue_t *wq, mblk_t *mp, t_scalar_t type) 23137c478bd9Sstevel@tonic-gate { 23147c478bd9Sstevel@tonic-gate struct T_ok_ack *ok_ack; 23157c478bd9Sstevel@tonic-gate mblk_t *ackmp = tpi_ack_alloc(mp, sizeof (struct T_ok_ack), 23167c478bd9Sstevel@tonic-gate M_PCPROTO, T_OK_ACK); 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 23197c478bd9Sstevel@tonic-gate tl_merror(wq, NULL, ENOMEM); 23207c478bd9Sstevel@tonic-gate return; 23217c478bd9Sstevel@tonic-gate } 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate ok_ack = (struct T_ok_ack *)ackmp->b_rptr; 23247c478bd9Sstevel@tonic-gate ok_ack->CORRECT_prim = type; 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate (void) qreply(wq, ackmp); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate /* 23307c478bd9Sstevel@tonic-gate * Process T_BIND_REQ and O_T_BIND_REQ from serializer. 23317c478bd9Sstevel@tonic-gate * This is a wrapper around tl_bind(). 23327c478bd9Sstevel@tonic-gate */ 23337c478bd9Sstevel@tonic-gate static void 23347c478bd9Sstevel@tonic-gate tl_bind_ser(mblk_t *mp, tl_endpt_t *tep) 23357c478bd9Sstevel@tonic-gate { 23367c478bd9Sstevel@tonic-gate if (! tep->te_closing) 23377c478bd9Sstevel@tonic-gate tl_bind(mp, tep); 23387c478bd9Sstevel@tonic-gate else 23397c478bd9Sstevel@tonic-gate freemsg(mp); 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 23427c478bd9Sstevel@tonic-gate tl_refrele(tep); 23437c478bd9Sstevel@tonic-gate } 23447c478bd9Sstevel@tonic-gate 23457c478bd9Sstevel@tonic-gate /* 23467c478bd9Sstevel@tonic-gate * Process T_BIND_REQ and O_T_BIND_REQ TPI requests. 23477c478bd9Sstevel@tonic-gate * Assumes that the endpoint is in the unbound. 23487c478bd9Sstevel@tonic-gate */ 23497c478bd9Sstevel@tonic-gate static void 23507c478bd9Sstevel@tonic-gate tl_bind(mblk_t *mp, tl_endpt_t *tep) 23517c478bd9Sstevel@tonic-gate { 23527c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 23537c478bd9Sstevel@tonic-gate struct T_bind_ack *b_ack; 23547c478bd9Sstevel@tonic-gate struct T_bind_req *bind = (struct T_bind_req *)mp->b_rptr; 23557c478bd9Sstevel@tonic-gate mblk_t *ackmp, *bamp; 23567c478bd9Sstevel@tonic-gate soux_addr_t ux_addr; 23577c478bd9Sstevel@tonic-gate t_uscalar_t qlen = 0; 23587c478bd9Sstevel@tonic-gate t_scalar_t alen, aoff; 23597c478bd9Sstevel@tonic-gate tl_addr_t addr_req; 23607c478bd9Sstevel@tonic-gate void *addr_startp; 23617c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp), basize; 23627c478bd9Sstevel@tonic-gate t_scalar_t tli_err = 0, unix_err = 0; 23637c478bd9Sstevel@tonic-gate t_scalar_t save_prim_type = bind->PRIM_type; 23647c478bd9Sstevel@tonic-gate t_scalar_t save_state = tep->te_state; 23657c478bd9Sstevel@tonic-gate 23667c478bd9Sstevel@tonic-gate if (tep->te_state != TS_UNBND) { 23677c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 23687c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 23697c478bd9Sstevel@tonic-gate "tl_wput:bind_request:out of state, state=%d", 23707c478bd9Sstevel@tonic-gate tep->te_state)); 23717c478bd9Sstevel@tonic-gate tli_err = TOUTSTATE; 23727c478bd9Sstevel@tonic-gate goto error; 23737c478bd9Sstevel@tonic-gate } 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate if (msz < sizeof (struct T_bind_req)) { 23767c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = EINVAL; 23777c478bd9Sstevel@tonic-gate goto error; 23787c478bd9Sstevel@tonic-gate } 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_BIND_REQ, tep->te_state); 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate ASSERT((bind->PRIM_type == O_T_BIND_REQ) || 23837c478bd9Sstevel@tonic-gate (bind->PRIM_type == T_BIND_REQ)); 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate alen = bind->ADDR_length; 23867c478bd9Sstevel@tonic-gate aoff = bind->ADDR_offset; 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate /* negotiate max conn req pending */ 23897c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 23907c478bd9Sstevel@tonic-gate qlen = bind->CONIND_number; 2391d87b1facSakolb if (qlen > tl_maxqlen) 2392d87b1facSakolb qlen = tl_maxqlen; 23937c478bd9Sstevel@tonic-gate } 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate /* 23967c478bd9Sstevel@tonic-gate * Reserve hash handle. It can only be NULL if the endpoint is unbound 23977c478bd9Sstevel@tonic-gate * and bound again. 23987c478bd9Sstevel@tonic-gate */ 23997c478bd9Sstevel@tonic-gate if ((tep->te_hash_hndl == NULL) && 24007c478bd9Sstevel@tonic-gate ((tep->te_flag & TL_ADDRHASHED) == 0) && 24017c478bd9Sstevel@tonic-gate mod_hash_reserve_nosleep(tep->te_addrhash, 24027c478bd9Sstevel@tonic-gate &tep->te_hash_hndl) != 0) { 24037c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = ENOSR; 24047c478bd9Sstevel@tonic-gate goto error; 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate /* 24087c478bd9Sstevel@tonic-gate * Verify address correctness. 24097c478bd9Sstevel@tonic-gate */ 24107c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) { 24117c478bd9Sstevel@tonic-gate ASSERT(bind->PRIM_type == O_T_BIND_REQ); 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate if ((alen != TL_SOUX_ADDRLEN) || 24147c478bd9Sstevel@tonic-gate (aoff < 0) || 24157c478bd9Sstevel@tonic-gate (aoff + alen > msz)) { 24167c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 24177c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 24187c478bd9Sstevel@tonic-gate "tl_bind: invalid socket addr")); 24197c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 24207c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = EINVAL; 24217c478bd9Sstevel@tonic-gate goto error; 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate /* Copy address from message to local buffer. */ 24247c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + aoff, &ux_addr, sizeof (ux_addr)); 24257c478bd9Sstevel@tonic-gate /* 24267c478bd9Sstevel@tonic-gate * Check that we got correct address from sockets 24277c478bd9Sstevel@tonic-gate */ 24287c478bd9Sstevel@tonic-gate if ((ux_addr.soua_magic != SOU_MAGIC_EXPLICIT) && 24297c478bd9Sstevel@tonic-gate (ux_addr.soua_magic != SOU_MAGIC_IMPLICIT)) { 24307c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 24317c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 24327c478bd9Sstevel@tonic-gate "tl_bind: invalid socket magic")); 24337c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 24347c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = EINVAL; 24357c478bd9Sstevel@tonic-gate goto error; 24367c478bd9Sstevel@tonic-gate } 24377c478bd9Sstevel@tonic-gate if ((ux_addr.soua_magic == SOU_MAGIC_IMPLICIT) && 24387c478bd9Sstevel@tonic-gate (ux_addr.soua_vp != NULL)) { 24397c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 24407c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 24417c478bd9Sstevel@tonic-gate "tl_bind: implicit addr non-empty")); 24427c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 24437c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = EINVAL; 24447c478bd9Sstevel@tonic-gate goto error; 24457c478bd9Sstevel@tonic-gate } 24467c478bd9Sstevel@tonic-gate if ((ux_addr.soua_magic == SOU_MAGIC_EXPLICIT) && 24477c478bd9Sstevel@tonic-gate (ux_addr.soua_vp == NULL)) { 24487c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 24497c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 24507c478bd9Sstevel@tonic-gate "tl_bind: explicit addr empty")); 24517c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 24527c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = EINVAL; 24537c478bd9Sstevel@tonic-gate goto error; 24547c478bd9Sstevel@tonic-gate } 24557c478bd9Sstevel@tonic-gate } else { 24567c478bd9Sstevel@tonic-gate if ((alen > 0) && ((aoff < 0) || 24577c478bd9Sstevel@tonic-gate ((ssize_t)(aoff + alen) > msz) || 24587c478bd9Sstevel@tonic-gate ((aoff + alen) < 0))) { 24597c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 24607c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 24617c478bd9Sstevel@tonic-gate "tl_bind: invalid message")); 24627c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 24637c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = EINVAL; 24647c478bd9Sstevel@tonic-gate goto error; 24657c478bd9Sstevel@tonic-gate } 24667c478bd9Sstevel@tonic-gate if ((alen < 0) || (alen > (msz - sizeof (struct T_bind_req)))) { 24677c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 24687c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 24697c478bd9Sstevel@tonic-gate "tl_bind: bad addr in message")); 24707c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 24717c478bd9Sstevel@tonic-gate tli_err = TBADADDR; 24727c478bd9Sstevel@tonic-gate goto error; 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate #ifdef DEBUG 24757c478bd9Sstevel@tonic-gate /* 24767c478bd9Sstevel@tonic-gate * Mild form of ASSERT()ion to detect broken TPI apps. 24777c478bd9Sstevel@tonic-gate * if (! assertion) 24787c478bd9Sstevel@tonic-gate * log warning; 24797c478bd9Sstevel@tonic-gate */ 24807c478bd9Sstevel@tonic-gate if (! ((alen == 0 && aoff == 0) || 24817c478bd9Sstevel@tonic-gate (aoff >= (t_scalar_t)(sizeof (struct T_bind_req))))) { 24827c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 24837c478bd9Sstevel@tonic-gate 3, SL_TRACE|SL_ERROR, 24847c478bd9Sstevel@tonic-gate "tl_bind: addr overlaps TPI message")); 24857c478bd9Sstevel@tonic-gate } 24867c478bd9Sstevel@tonic-gate #endif 24877c478bd9Sstevel@tonic-gate } 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate /* 24907c478bd9Sstevel@tonic-gate * Bind the address provided or allocate one if requested. 24917c478bd9Sstevel@tonic-gate * Allow rebinds with a new qlen value. 24927c478bd9Sstevel@tonic-gate */ 24937c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) { 24947c478bd9Sstevel@tonic-gate /* 24957c478bd9Sstevel@tonic-gate * For anonymous requests the te_ap is already set up properly 24967c478bd9Sstevel@tonic-gate * so use minor number as an address. 24977c478bd9Sstevel@tonic-gate * For explicit requests need to check whether the address is 24987c478bd9Sstevel@tonic-gate * already in use. 24997c478bd9Sstevel@tonic-gate */ 25007c478bd9Sstevel@tonic-gate if (ux_addr.soua_magic == SOU_MAGIC_EXPLICIT) { 25017c478bd9Sstevel@tonic-gate int rc; 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate if (tep->te_flag & TL_ADDRHASHED) { 25047c478bd9Sstevel@tonic-gate ASSERT(IS_COTS(tep) && tep->te_qlen == 0); 25057c478bd9Sstevel@tonic-gate if (tep->te_vp == ux_addr.soua_vp) 25067c478bd9Sstevel@tonic-gate goto skip_addr_bind; 25077c478bd9Sstevel@tonic-gate else /* Rebind to a new address. */ 25087c478bd9Sstevel@tonic-gate tl_addr_unbind(tep); 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate /* 25117c478bd9Sstevel@tonic-gate * Insert address in the hash if it is not already 25127c478bd9Sstevel@tonic-gate * there. Since we use preallocated handle, the insert 25137c478bd9Sstevel@tonic-gate * can fail only if the key is already present. 25147c478bd9Sstevel@tonic-gate */ 25157c478bd9Sstevel@tonic-gate rc = mod_hash_insert_reserve(tep->te_addrhash, 25167c478bd9Sstevel@tonic-gate (mod_hash_key_t)ux_addr.soua_vp, 25177c478bd9Sstevel@tonic-gate (mod_hash_val_t)tep, tep->te_hash_hndl); 25187c478bd9Sstevel@tonic-gate 25197c478bd9Sstevel@tonic-gate if (rc != 0) { 25207c478bd9Sstevel@tonic-gate ASSERT(rc == MH_ERR_DUPLICATE); 25217c478bd9Sstevel@tonic-gate /* 25227c478bd9Sstevel@tonic-gate * Violate O_T_BIND_REQ semantics and fail with 25237c478bd9Sstevel@tonic-gate * TADDRBUSY - sockets will not use any address 25247c478bd9Sstevel@tonic-gate * other than supplied one for explicit binds. 25257c478bd9Sstevel@tonic-gate */ 25267c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 25277c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 25287c478bd9Sstevel@tonic-gate "tl_bind:requested addr %p is busy", 25297c478bd9Sstevel@tonic-gate ux_addr.soua_vp)); 25307c478bd9Sstevel@tonic-gate tli_err = TADDRBUSY; unix_err = 0; 25317c478bd9Sstevel@tonic-gate goto error; 25327c478bd9Sstevel@tonic-gate } 25337c478bd9Sstevel@tonic-gate tep->te_uxaddr = ux_addr; 25347c478bd9Sstevel@tonic-gate tep->te_flag |= TL_ADDRHASHED; 25357c478bd9Sstevel@tonic-gate tep->te_hash_hndl = NULL; 25367c478bd9Sstevel@tonic-gate } 25377c478bd9Sstevel@tonic-gate } else if (alen == 0) { 25387c478bd9Sstevel@tonic-gate /* 25397c478bd9Sstevel@tonic-gate * assign any free address 25407c478bd9Sstevel@tonic-gate */ 25417c478bd9Sstevel@tonic-gate if (! tl_get_any_addr(tep, NULL)) { 25427c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 25437c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 25447c478bd9Sstevel@tonic-gate "tl_bind:failed to get buffer for any " 25457c478bd9Sstevel@tonic-gate "address")); 25467c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = ENOSR; 25477c478bd9Sstevel@tonic-gate goto error; 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate } else { 25507c478bd9Sstevel@tonic-gate addr_req.ta_alen = alen; 25517c478bd9Sstevel@tonic-gate addr_req.ta_abuf = (mp->b_rptr + aoff); 25527c478bd9Sstevel@tonic-gate addr_req.ta_zoneid = tep->te_zoneid; 25537c478bd9Sstevel@tonic-gate 25547c478bd9Sstevel@tonic-gate tep->te_abuf = kmem_zalloc((size_t)alen, KM_NOSLEEP); 25557c478bd9Sstevel@tonic-gate if (tep->te_abuf == NULL) { 25567c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = ENOSR; 25577c478bd9Sstevel@tonic-gate goto error; 25587c478bd9Sstevel@tonic-gate } 25597c478bd9Sstevel@tonic-gate bcopy(addr_req.ta_abuf, tep->te_abuf, addr_req.ta_alen); 25607c478bd9Sstevel@tonic-gate tep->te_alen = alen; 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate if (mod_hash_insert_reserve(tep->te_addrhash, 25637c478bd9Sstevel@tonic-gate (mod_hash_key_t)&tep->te_ap, (mod_hash_val_t)tep, 25647c478bd9Sstevel@tonic-gate tep->te_hash_hndl) != 0) { 25657c478bd9Sstevel@tonic-gate if (save_prim_type == T_BIND_REQ) { 25667c478bd9Sstevel@tonic-gate /* 25677c478bd9Sstevel@tonic-gate * The bind semantics for this primitive 25687c478bd9Sstevel@tonic-gate * require a failure if the exact address 25697c478bd9Sstevel@tonic-gate * requested is busy 25707c478bd9Sstevel@tonic-gate */ 25717c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 25727c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 25737c478bd9Sstevel@tonic-gate "tl_bind:requested addr is busy")); 25747c478bd9Sstevel@tonic-gate tli_err = TADDRBUSY; unix_err = 0; 25757c478bd9Sstevel@tonic-gate goto error; 25767c478bd9Sstevel@tonic-gate } 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate /* 25797c478bd9Sstevel@tonic-gate * O_T_BIND_REQ semantics say if address if requested 25807c478bd9Sstevel@tonic-gate * address is busy, bind to any available free address 25817c478bd9Sstevel@tonic-gate */ 25827c478bd9Sstevel@tonic-gate if (! tl_get_any_addr(tep, &addr_req)) { 25837c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 25847c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 25857c478bd9Sstevel@tonic-gate "tl_bind:unable to get any addr buf")); 25867c478bd9Sstevel@tonic-gate tli_err = TSYSERR; unix_err = ENOMEM; 25877c478bd9Sstevel@tonic-gate goto error; 25887c478bd9Sstevel@tonic-gate } 25897c478bd9Sstevel@tonic-gate } else { 25907c478bd9Sstevel@tonic-gate tep->te_flag |= TL_ADDRHASHED; 25917c478bd9Sstevel@tonic-gate tep->te_hash_hndl = NULL; 25927c478bd9Sstevel@tonic-gate } 25937c478bd9Sstevel@tonic-gate } 25947c478bd9Sstevel@tonic-gate 25957c478bd9Sstevel@tonic-gate ASSERT(tep->te_alen >= 0); 25967c478bd9Sstevel@tonic-gate 25977c478bd9Sstevel@tonic-gate skip_addr_bind: 25987c478bd9Sstevel@tonic-gate /* 25997c478bd9Sstevel@tonic-gate * prepare T_BIND_ACK TPI message 26007c478bd9Sstevel@tonic-gate */ 26017c478bd9Sstevel@tonic-gate basize = sizeof (struct T_bind_ack) + tep->te_alen; 26027c478bd9Sstevel@tonic-gate bamp = reallocb(mp, basize, 0); 26037c478bd9Sstevel@tonic-gate if (bamp == NULL) { 26047c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 26057c478bd9Sstevel@tonic-gate "tl_wput:tl_bind: allocb failed")); 26067c478bd9Sstevel@tonic-gate /* 26077c478bd9Sstevel@tonic-gate * roll back state changes 26087c478bd9Sstevel@tonic-gate */ 26097c478bd9Sstevel@tonic-gate tl_addr_unbind(tep); 26107c478bd9Sstevel@tonic-gate tep->te_state = TS_UNBND; 26117c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, basize); 26127c478bd9Sstevel@tonic-gate return; 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate DB_TYPE(bamp) = M_PCPROTO; 26167c478bd9Sstevel@tonic-gate bamp->b_wptr = bamp->b_rptr + basize; 26177c478bd9Sstevel@tonic-gate b_ack = (struct T_bind_ack *)bamp->b_rptr; 26187c478bd9Sstevel@tonic-gate b_ack->PRIM_type = T_BIND_ACK; 26197c478bd9Sstevel@tonic-gate b_ack->CONIND_number = qlen; 26207c478bd9Sstevel@tonic-gate b_ack->ADDR_length = tep->te_alen; 26217c478bd9Sstevel@tonic-gate b_ack->ADDR_offset = (t_scalar_t)sizeof (struct T_bind_ack); 26227c478bd9Sstevel@tonic-gate addr_startp = bamp->b_rptr + b_ack->ADDR_offset; 26237c478bd9Sstevel@tonic-gate bcopy(tep->te_abuf, addr_startp, tep->te_alen); 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 26267c478bd9Sstevel@tonic-gate tep->te_qlen = qlen; 26277c478bd9Sstevel@tonic-gate if (qlen > 0) 26287c478bd9Sstevel@tonic-gate tep->te_flag |= TL_LISTENER; 26297c478bd9Sstevel@tonic-gate } 26307c478bd9Sstevel@tonic-gate 26317c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_BIND_ACK, tep->te_state); 26327c478bd9Sstevel@tonic-gate /* 26337c478bd9Sstevel@tonic-gate * send T_BIND_ACK message 26347c478bd9Sstevel@tonic-gate */ 26357c478bd9Sstevel@tonic-gate (void) qreply(wq, bamp); 26367c478bd9Sstevel@tonic-gate return; 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate error: 26397c478bd9Sstevel@tonic-gate ackmp = reallocb(mp, sizeof (struct T_error_ack), 0); 26407c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 26417c478bd9Sstevel@tonic-gate /* 26427c478bd9Sstevel@tonic-gate * roll back state changes 26437c478bd9Sstevel@tonic-gate */ 26447c478bd9Sstevel@tonic-gate tep->te_state = save_state; 26457c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, sizeof (struct T_error_ack)); 26467c478bd9Sstevel@tonic-gate return; 26477c478bd9Sstevel@tonic-gate } 26487c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 26497c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, tli_err, unix_err, save_prim_type); 26507c478bd9Sstevel@tonic-gate } 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate /* 26537c478bd9Sstevel@tonic-gate * Process T_UNBIND_REQ. 26547c478bd9Sstevel@tonic-gate * Called from serializer. 26557c478bd9Sstevel@tonic-gate */ 26567c478bd9Sstevel@tonic-gate static void 26577c478bd9Sstevel@tonic-gate tl_unbind(mblk_t *mp, tl_endpt_t *tep) 26587c478bd9Sstevel@tonic-gate { 26597c478bd9Sstevel@tonic-gate queue_t *wq; 26607c478bd9Sstevel@tonic-gate mblk_t *ackmp; 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate if (tep->te_closing) { 26637c478bd9Sstevel@tonic-gate freemsg(mp); 26647c478bd9Sstevel@tonic-gate return; 26657c478bd9Sstevel@tonic-gate } 26667c478bd9Sstevel@tonic-gate 26677c478bd9Sstevel@tonic-gate wq = tep->te_wq; 26687c478bd9Sstevel@tonic-gate 26697c478bd9Sstevel@tonic-gate /* 26707c478bd9Sstevel@tonic-gate * preallocate memory for max of T_OK_ACK and T_ERROR_ACK 26717c478bd9Sstevel@tonic-gate * ==> allocate for T_ERROR_ACK (known max) 26727c478bd9Sstevel@tonic-gate */ 26737c478bd9Sstevel@tonic-gate if ((ackmp = reallocb(mp, sizeof (struct T_error_ack), 0)) == NULL) { 26747c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, sizeof (struct T_error_ack)); 26757c478bd9Sstevel@tonic-gate return; 26767c478bd9Sstevel@tonic-gate } 26777c478bd9Sstevel@tonic-gate /* 26787c478bd9Sstevel@tonic-gate * memory resources committed 26797c478bd9Sstevel@tonic-gate * Note: no message validation. T_UNBIND_REQ message is 26807c478bd9Sstevel@tonic-gate * same size as PRIM_type field so already verified earlier. 26817c478bd9Sstevel@tonic-gate */ 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate /* 26847c478bd9Sstevel@tonic-gate * validate state 26857c478bd9Sstevel@tonic-gate */ 26867c478bd9Sstevel@tonic-gate if (tep->te_state != TS_IDLE) { 26877c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 26887c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 26897c478bd9Sstevel@tonic-gate "tl_wput:T_UNBIND_REQ:out of state, state=%d", 26907c478bd9Sstevel@tonic-gate tep->te_state)); 26917c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TOUTSTATE, 0, T_UNBIND_REQ); 26927c478bd9Sstevel@tonic-gate return; 26937c478bd9Sstevel@tonic-gate } 26947c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_UNBIND_REQ, tep->te_state); 26957c478bd9Sstevel@tonic-gate 26967c478bd9Sstevel@tonic-gate /* 26977c478bd9Sstevel@tonic-gate * TPI says on T_UNBIND_REQ: 26987c478bd9Sstevel@tonic-gate * send up a M_FLUSH to flush both 26997c478bd9Sstevel@tonic-gate * read and write queues 27007c478bd9Sstevel@tonic-gate */ 27017c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_FLUSH, FLUSHRW); 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate if (! IS_SOCKET(tep) || !IS_CLTS(tep) || tep->te_qlen != 0 || 27047c478bd9Sstevel@tonic-gate tep->te_magic != SOU_MAGIC_EXPLICIT) { 27057c478bd9Sstevel@tonic-gate 27067c478bd9Sstevel@tonic-gate /* 27077c478bd9Sstevel@tonic-gate * Sockets use bind with qlen==0 followed by bind() to 27087c478bd9Sstevel@tonic-gate * the same address with qlen > 0 for listeners. 27097c478bd9Sstevel@tonic-gate * We allow rebind with a new qlen value. 27107c478bd9Sstevel@tonic-gate */ 27117c478bd9Sstevel@tonic-gate tl_addr_unbind(tep); 27127c478bd9Sstevel@tonic-gate } 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_OK_ACK1, tep->te_state); 27157c478bd9Sstevel@tonic-gate /* 27167c478bd9Sstevel@tonic-gate * send T_OK_ACK 27177c478bd9Sstevel@tonic-gate */ 27187c478bd9Sstevel@tonic-gate tl_ok_ack(wq, ackmp, T_UNBIND_REQ); 27197c478bd9Sstevel@tonic-gate } 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate /* 27237c478bd9Sstevel@tonic-gate * Option management code from drv/ip is used here 27247c478bd9Sstevel@tonic-gate * Note: TL_PROT_LEVEL/TL_IOC_CREDOPT option is not part of tl_opt_arr 27257c478bd9Sstevel@tonic-gate * database of options. So optcom_req() will fail T_SVR4_OPTMGMT_REQ. 27267c478bd9Sstevel@tonic-gate * However, that is what we want as that option is 'unorthodox' 27277c478bd9Sstevel@tonic-gate * and only valid in T_CONN_IND, T_CONN_CON and T_UNITDATA_IND 27287c478bd9Sstevel@tonic-gate * and not in T_SVR4_OPTMGMT_REQ/ACK 27297c478bd9Sstevel@tonic-gate * Note2: use of optcom_req means this routine is an exception to 27307c478bd9Sstevel@tonic-gate * recovery from allocb() failures. 27317c478bd9Sstevel@tonic-gate */ 27327c478bd9Sstevel@tonic-gate 27337c478bd9Sstevel@tonic-gate static void 27347c478bd9Sstevel@tonic-gate tl_optmgmt(queue_t *wq, mblk_t *mp) 27357c478bd9Sstevel@tonic-gate { 27367c478bd9Sstevel@tonic-gate tl_endpt_t *tep; 27377c478bd9Sstevel@tonic-gate mblk_t *ackmp; 27387c478bd9Sstevel@tonic-gate union T_primitives *prim; 2739de8c4a14SErik Nordmark cred_t *cr; 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate tep = (tl_endpt_t *)wq->q_ptr; 27427c478bd9Sstevel@tonic-gate prim = (union T_primitives *)mp->b_rptr; 27437c478bd9Sstevel@tonic-gate 2744de8c4a14SErik Nordmark /* 2745de8c4a14SErik Nordmark * All Solaris components should pass a db_credp 2746de8c4a14SErik Nordmark * for this TPI message, hence we ASSERT. 2747de8c4a14SErik Nordmark * But in case there is some other M_PROTO that looks 2748de8c4a14SErik Nordmark * like a TPI message sent by some other kernel 2749de8c4a14SErik Nordmark * component, we check and return an error. 2750de8c4a14SErik Nordmark */ 2751de8c4a14SErik Nordmark cr = msg_getcred(mp, NULL); 2752de8c4a14SErik Nordmark ASSERT(cr != NULL); 2753de8c4a14SErik Nordmark if (cr == NULL) { 2754de8c4a14SErik Nordmark tl_error_ack(wq, mp, TSYSERR, EINVAL, prim->type); 2755de8c4a14SErik Nordmark return; 2756de8c4a14SErik Nordmark } 2757de8c4a14SErik Nordmark 27587c478bd9Sstevel@tonic-gate /* all states OK for AF_UNIX options ? */ 27597c478bd9Sstevel@tonic-gate if (!IS_SOCKET(tep) && tep->te_state != TS_IDLE && 27607c478bd9Sstevel@tonic-gate prim->type == T_SVR4_OPTMGMT_REQ) { 27617c478bd9Sstevel@tonic-gate /* 27627c478bd9Sstevel@tonic-gate * Broken TLI semantics that options can only be managed 27637c478bd9Sstevel@tonic-gate * in TS_IDLE state. Needed for Sparc ABI test suite that 27647c478bd9Sstevel@tonic-gate * tests this TLI (mis)feature using this device driver. 27657c478bd9Sstevel@tonic-gate */ 27667c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 27677c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 27687c478bd9Sstevel@tonic-gate "tl_wput:T_SVR4_OPTMGMT_REQ:out of state, state=%d", 27697c478bd9Sstevel@tonic-gate tep->te_state)); 27707c478bd9Sstevel@tonic-gate /* 27717c478bd9Sstevel@tonic-gate * preallocate memory for T_ERROR_ACK 27727c478bd9Sstevel@tonic-gate */ 27737c478bd9Sstevel@tonic-gate ackmp = allocb(sizeof (struct T_error_ack), BPRI_MED); 27747c478bd9Sstevel@tonic-gate if (! ackmp) { 27757c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, sizeof (struct T_error_ack)); 27767c478bd9Sstevel@tonic-gate return; 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TOUTSTATE, 0, T_SVR4_OPTMGMT_REQ); 27807c478bd9Sstevel@tonic-gate freemsg(mp); 27817c478bd9Sstevel@tonic-gate return; 27827c478bd9Sstevel@tonic-gate } 27837c478bd9Sstevel@tonic-gate 27847c478bd9Sstevel@tonic-gate /* 27857c478bd9Sstevel@tonic-gate * call common option management routine from drv/ip 27867c478bd9Sstevel@tonic-gate */ 27877c478bd9Sstevel@tonic-gate if (prim->type == T_SVR4_OPTMGMT_REQ) { 2788bd670b35SErik Nordmark svr4_optcom_req(wq, mp, cr, &tl_opt_obj); 27897c478bd9Sstevel@tonic-gate } else { 27907c478bd9Sstevel@tonic-gate ASSERT(prim->type == T_OPTMGMT_REQ); 2791bd670b35SErik Nordmark tpi_optcom_req(wq, mp, cr, &tl_opt_obj); 27927c478bd9Sstevel@tonic-gate } 27937c478bd9Sstevel@tonic-gate } 27947c478bd9Sstevel@tonic-gate 27957c478bd9Sstevel@tonic-gate /* 27967c478bd9Sstevel@tonic-gate * Handle T_conn_req - the driver part of accept(). 27977c478bd9Sstevel@tonic-gate * If TL_SET[U]CRED generate the credentials options. 27987c478bd9Sstevel@tonic-gate * If this is a socket pass through options unmodified. 27997c478bd9Sstevel@tonic-gate * For sockets generate the T_CONN_CON here instead of 28007c478bd9Sstevel@tonic-gate * waiting for the T_CONN_RES. 28017c478bd9Sstevel@tonic-gate */ 28027c478bd9Sstevel@tonic-gate static void 28037c478bd9Sstevel@tonic-gate tl_conn_req(queue_t *wq, mblk_t *mp) 28047c478bd9Sstevel@tonic-gate { 28057c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)wq->q_ptr; 28067c478bd9Sstevel@tonic-gate struct T_conn_req *creq = (struct T_conn_req *)mp->b_rptr; 28077c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp); 28087c478bd9Sstevel@tonic-gate t_scalar_t alen, aoff, olen, ooff, err = 0; 28097c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = NULL; 28107c478bd9Sstevel@tonic-gate mblk_t *ackmp; 28117c478bd9Sstevel@tonic-gate mblk_t *dimp; 28127c478bd9Sstevel@tonic-gate struct T_discon_ind *di; 28137c478bd9Sstevel@tonic-gate soux_addr_t ux_addr; 28147c478bd9Sstevel@tonic-gate tl_addr_t dst; 28157c478bd9Sstevel@tonic-gate 28167c478bd9Sstevel@tonic-gate ASSERT(IS_COTS(tep)); 28177c478bd9Sstevel@tonic-gate 28187c478bd9Sstevel@tonic-gate if (tep->te_closing) { 28197c478bd9Sstevel@tonic-gate freemsg(mp); 28207c478bd9Sstevel@tonic-gate return; 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate /* 28247c478bd9Sstevel@tonic-gate * preallocate memory for: 28257c478bd9Sstevel@tonic-gate * 1. max of T_ERROR_ACK and T_OK_ACK 28267c478bd9Sstevel@tonic-gate * ==> known max T_ERROR_ACK 28277c478bd9Sstevel@tonic-gate * 2. max of T_DISCON_IND and T_CONN_IND 28287c478bd9Sstevel@tonic-gate */ 28297c478bd9Sstevel@tonic-gate ackmp = allocb(sizeof (struct T_error_ack), BPRI_MED); 28307c478bd9Sstevel@tonic-gate if (! ackmp) { 28317c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, sizeof (struct T_error_ack)); 28327c478bd9Sstevel@tonic-gate return; 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate /* 28357c478bd9Sstevel@tonic-gate * memory committed for T_OK_ACK/T_ERROR_ACK now 28367c478bd9Sstevel@tonic-gate * will be committed for T_DISCON_IND/T_CONN_IND later 28377c478bd9Sstevel@tonic-gate */ 28387c478bd9Sstevel@tonic-gate 28397c478bd9Sstevel@tonic-gate if (tep->te_state != TS_IDLE) { 28407c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 28417c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 28427c478bd9Sstevel@tonic-gate "tl_wput:T_CONN_REQ:out of state, state=%d", 28437c478bd9Sstevel@tonic-gate tep->te_state)); 28447c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TOUTSTATE, 0, T_CONN_REQ); 28457c478bd9Sstevel@tonic-gate freemsg(mp); 28467c478bd9Sstevel@tonic-gate return; 28477c478bd9Sstevel@tonic-gate } 28487c478bd9Sstevel@tonic-gate 28497c478bd9Sstevel@tonic-gate /* 28507c478bd9Sstevel@tonic-gate * validate the message 28517c478bd9Sstevel@tonic-gate * Note: dereference fields in struct inside message only 28527c478bd9Sstevel@tonic-gate * after validating the message length. 28537c478bd9Sstevel@tonic-gate */ 28547c478bd9Sstevel@tonic-gate if (msz < sizeof (struct T_conn_req)) { 28557c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 28567c478bd9Sstevel@tonic-gate "tl_conn_req:invalid message length")); 28577c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TSYSERR, EINVAL, T_CONN_REQ); 28587c478bd9Sstevel@tonic-gate freemsg(mp); 28597c478bd9Sstevel@tonic-gate return; 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate alen = creq->DEST_length; 28627c478bd9Sstevel@tonic-gate aoff = creq->DEST_offset; 28637c478bd9Sstevel@tonic-gate olen = creq->OPT_length; 28647c478bd9Sstevel@tonic-gate ooff = creq->OPT_offset; 28657c478bd9Sstevel@tonic-gate if (olen == 0) 28667c478bd9Sstevel@tonic-gate ooff = 0; 28677c478bd9Sstevel@tonic-gate 28687c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) { 28697c478bd9Sstevel@tonic-gate if ((alen != TL_SOUX_ADDRLEN) || 28707c478bd9Sstevel@tonic-gate (aoff < 0) || 28717c478bd9Sstevel@tonic-gate (aoff + alen > msz) || 28727c478bd9Sstevel@tonic-gate (alen > msz - sizeof (struct T_conn_req))) { 28737c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 28747c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 28757c478bd9Sstevel@tonic-gate "tl_conn_req: invalid socket addr")); 28767c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TSYSERR, EINVAL, T_CONN_REQ); 28777c478bd9Sstevel@tonic-gate freemsg(mp); 28787c478bd9Sstevel@tonic-gate return; 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + aoff, &ux_addr, TL_SOUX_ADDRLEN); 28817c478bd9Sstevel@tonic-gate if ((ux_addr.soua_magic != SOU_MAGIC_IMPLICIT) && 28827c478bd9Sstevel@tonic-gate (ux_addr.soua_magic != SOU_MAGIC_EXPLICIT)) { 28837c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 28847c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 28857c478bd9Sstevel@tonic-gate "tl_conn_req: invalid socket magic")); 28867c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TSYSERR, EINVAL, T_CONN_REQ); 28877c478bd9Sstevel@tonic-gate freemsg(mp); 28887c478bd9Sstevel@tonic-gate return; 28897c478bd9Sstevel@tonic-gate } 28907c478bd9Sstevel@tonic-gate } else { 28917c478bd9Sstevel@tonic-gate if ((alen > 0 && ((aoff + alen) > msz || aoff + alen < 0)) || 28927c478bd9Sstevel@tonic-gate (olen > 0 && ((ssize_t)(ooff + olen) > msz || 28937c478bd9Sstevel@tonic-gate ooff + olen < 0)) || 28947c478bd9Sstevel@tonic-gate olen < 0 || ooff < 0) { 28957c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 28967c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 28977c478bd9Sstevel@tonic-gate "tl_conn_req:invalid message")); 28987c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TSYSERR, EINVAL, T_CONN_REQ); 28997c478bd9Sstevel@tonic-gate freemsg(mp); 29007c478bd9Sstevel@tonic-gate return; 29017c478bd9Sstevel@tonic-gate } 29027c478bd9Sstevel@tonic-gate 29037c478bd9Sstevel@tonic-gate if (alen <= 0 || aoff < 0 || 29047c478bd9Sstevel@tonic-gate (ssize_t)alen > msz - sizeof (struct T_conn_req)) { 29057c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 29067c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 29077c478bd9Sstevel@tonic-gate "tl_conn_req:bad addr in message, " 29087c478bd9Sstevel@tonic-gate "alen=%d, msz=%ld", 29097c478bd9Sstevel@tonic-gate alen, msz)); 29107c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADADDR, 0, T_CONN_REQ); 29117c478bd9Sstevel@tonic-gate freemsg(mp); 29127c478bd9Sstevel@tonic-gate return; 29137c478bd9Sstevel@tonic-gate } 29147c478bd9Sstevel@tonic-gate #ifdef DEBUG 29157c478bd9Sstevel@tonic-gate /* 29167c478bd9Sstevel@tonic-gate * Mild form of ASSERT()ion to detect broken TPI apps. 29177c478bd9Sstevel@tonic-gate * if (! assertion) 29187c478bd9Sstevel@tonic-gate * log warning; 29197c478bd9Sstevel@tonic-gate */ 29207c478bd9Sstevel@tonic-gate if (! (aoff >= (t_scalar_t)sizeof (struct T_conn_req))) { 29217c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 29227c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 29237c478bd9Sstevel@tonic-gate "tl_conn_req: addr overlaps TPI message")); 29247c478bd9Sstevel@tonic-gate } 29257c478bd9Sstevel@tonic-gate #endif 29267c478bd9Sstevel@tonic-gate if (olen) { 29277c478bd9Sstevel@tonic-gate /* 29287c478bd9Sstevel@tonic-gate * no opts in connect req 29297c478bd9Sstevel@tonic-gate * supported in this provider except for sockets. 29307c478bd9Sstevel@tonic-gate */ 29317c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 29327c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 29337c478bd9Sstevel@tonic-gate "tl_conn_req:options not supported " 29347c478bd9Sstevel@tonic-gate "in message")); 29357c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADOPT, 0, T_CONN_REQ); 29367c478bd9Sstevel@tonic-gate freemsg(mp); 29377c478bd9Sstevel@tonic-gate return; 29387c478bd9Sstevel@tonic-gate } 29397c478bd9Sstevel@tonic-gate } 29407c478bd9Sstevel@tonic-gate 29417c478bd9Sstevel@tonic-gate /* 29427c478bd9Sstevel@tonic-gate * Prevent tep from closing on us. 29437c478bd9Sstevel@tonic-gate */ 29447c478bd9Sstevel@tonic-gate if (! tl_noclose(tep)) { 29457c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 29467c478bd9Sstevel@tonic-gate "tl_conn_req:endpoint is closing")); 29477c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TOUTSTATE, 0, T_CONN_REQ); 29487c478bd9Sstevel@tonic-gate freemsg(mp); 29497c478bd9Sstevel@tonic-gate return; 29507c478bd9Sstevel@tonic-gate } 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_CONN_REQ, tep->te_state); 29537c478bd9Sstevel@tonic-gate /* 29547c478bd9Sstevel@tonic-gate * get endpoint to connect to 29557c478bd9Sstevel@tonic-gate * check that peer with DEST addr is bound to addr 29567c478bd9Sstevel@tonic-gate * and has CONIND_number > 0 29577c478bd9Sstevel@tonic-gate */ 29587c478bd9Sstevel@tonic-gate dst.ta_alen = alen; 29597c478bd9Sstevel@tonic-gate dst.ta_abuf = mp->b_rptr + aoff; 29607c478bd9Sstevel@tonic-gate dst.ta_zoneid = tep->te_zoneid; 29617c478bd9Sstevel@tonic-gate 29627c478bd9Sstevel@tonic-gate /* 29637c478bd9Sstevel@tonic-gate * Verify if remote addr is in use 29647c478bd9Sstevel@tonic-gate */ 29657c478bd9Sstevel@tonic-gate peer_tep = (IS_SOCKET(tep) ? 29667c478bd9Sstevel@tonic-gate tl_sock_find_peer(tep, &ux_addr) : 29677c478bd9Sstevel@tonic-gate tl_find_peer(tep, &dst)); 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate if (peer_tep == NULL) { 29707c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 29717c478bd9Sstevel@tonic-gate "tl_conn_req:no one at connect address")); 29727c478bd9Sstevel@tonic-gate err = ECONNREFUSED; 29737c478bd9Sstevel@tonic-gate } else if (peer_tep->te_nicon >= peer_tep->te_qlen) { 29747c478bd9Sstevel@tonic-gate /* 29757c478bd9Sstevel@tonic-gate * validate that number of incoming connection is 29767c478bd9Sstevel@tonic-gate * not to capacity on destination endpoint 29777c478bd9Sstevel@tonic-gate */ 29787c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE, 29797c478bd9Sstevel@tonic-gate "tl_conn_req: qlen overflow connection refused")); 29807c478bd9Sstevel@tonic-gate err = ECONNREFUSED; 29817c478bd9Sstevel@tonic-gate } 29827c478bd9Sstevel@tonic-gate 29837c478bd9Sstevel@tonic-gate /* 2984b6626b4dSakolb * Send T_DISCON_IND in case of error 29857c478bd9Sstevel@tonic-gate */ 29867c478bd9Sstevel@tonic-gate if (err != 0) { 29877c478bd9Sstevel@tonic-gate if (peer_tep != NULL) 29887c478bd9Sstevel@tonic-gate tl_refrele(peer_tep); 29897c478bd9Sstevel@tonic-gate /* We are still expected to send T_OK_ACK */ 29907c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_OK_ACK1, tep->te_state); 29917c478bd9Sstevel@tonic-gate tl_ok_ack(tep->te_wq, ackmp, T_CONN_REQ); 29927c478bd9Sstevel@tonic-gate tl_closeok(tep); 29937c478bd9Sstevel@tonic-gate dimp = tpi_ack_alloc(mp, sizeof (struct T_discon_ind), 29947c478bd9Sstevel@tonic-gate M_PROTO, T_DISCON_IND); 29957c478bd9Sstevel@tonic-gate if (dimp == NULL) { 29967c478bd9Sstevel@tonic-gate tl_merror(wq, NULL, ENOSR); 29977c478bd9Sstevel@tonic-gate return; 29987c478bd9Sstevel@tonic-gate } 29997c478bd9Sstevel@tonic-gate di = (struct T_discon_ind *)dimp->b_rptr; 30007c478bd9Sstevel@tonic-gate di->DISCON_reason = err; 30017c478bd9Sstevel@tonic-gate di->SEQ_number = BADSEQNUM; 30027c478bd9Sstevel@tonic-gate 30037c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 30047c478bd9Sstevel@tonic-gate /* 30057c478bd9Sstevel@tonic-gate * send T_DISCON_IND message 30067c478bd9Sstevel@tonic-gate */ 30077c478bd9Sstevel@tonic-gate putnext(tep->te_rq, dimp); 30087c478bd9Sstevel@tonic-gate return; 30097c478bd9Sstevel@tonic-gate } 30107c478bd9Sstevel@tonic-gate 30117c478bd9Sstevel@tonic-gate ASSERT(IS_COTS(peer_tep)); 30127c478bd9Sstevel@tonic-gate 30137c478bd9Sstevel@tonic-gate /* 30147c478bd9Sstevel@tonic-gate * Found the listener. At this point processing will continue on 30157c478bd9Sstevel@tonic-gate * listener serializer. Close of the endpoint should be blocked while we 30167c478bd9Sstevel@tonic-gate * switch serializers. 30177c478bd9Sstevel@tonic-gate */ 30187c478bd9Sstevel@tonic-gate tl_serializer_refhold(peer_tep->te_ser); 30197c478bd9Sstevel@tonic-gate tl_serializer_refrele(tep->te_ser); 30207c478bd9Sstevel@tonic-gate tep->te_ser = peer_tep->te_ser; 30217c478bd9Sstevel@tonic-gate ASSERT(tep->te_oconp == NULL); 30227c478bd9Sstevel@tonic-gate tep->te_oconp = peer_tep; 30237c478bd9Sstevel@tonic-gate 30247c478bd9Sstevel@tonic-gate /* 30257c478bd9Sstevel@tonic-gate * It is safe to close now. Close may continue on listener serializer. 30267c478bd9Sstevel@tonic-gate */ 30277c478bd9Sstevel@tonic-gate tl_closeok(tep); 30287c478bd9Sstevel@tonic-gate 30297c478bd9Sstevel@tonic-gate /* 30307c478bd9Sstevel@tonic-gate * Pass ackmp to tl_conn_req_ser. Note that mp->b_cont may contain user 30317c478bd9Sstevel@tonic-gate * data, so we link mp to ackmp. 30327c478bd9Sstevel@tonic-gate */ 30337c478bd9Sstevel@tonic-gate ackmp->b_cont = mp; 30347c478bd9Sstevel@tonic-gate mp = ackmp; 30357c478bd9Sstevel@tonic-gate 30367c478bd9Sstevel@tonic-gate tl_refhold(tep); 30377c478bd9Sstevel@tonic-gate tl_serializer_enter(tep, tl_conn_req_ser, mp); 30387c478bd9Sstevel@tonic-gate } 30397c478bd9Sstevel@tonic-gate 30407c478bd9Sstevel@tonic-gate /* 30417c478bd9Sstevel@tonic-gate * Finish T_CONN_REQ processing on listener serializer. 30427c478bd9Sstevel@tonic-gate */ 30437c478bd9Sstevel@tonic-gate static void 30447c478bd9Sstevel@tonic-gate tl_conn_req_ser(mblk_t *mp, tl_endpt_t *tep) 30457c478bd9Sstevel@tonic-gate { 30467c478bd9Sstevel@tonic-gate queue_t *wq; 30477c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = tep->te_oconp; 30487c478bd9Sstevel@tonic-gate mblk_t *confmp, *cimp, *indmp; 30497c478bd9Sstevel@tonic-gate void *opts = NULL; 30507c478bd9Sstevel@tonic-gate mblk_t *ackmp = mp; 30517c478bd9Sstevel@tonic-gate struct T_conn_req *creq = (struct T_conn_req *)mp->b_cont->b_rptr; 30527c478bd9Sstevel@tonic-gate struct T_conn_ind *ci; 30537c478bd9Sstevel@tonic-gate tl_icon_t *tip; 30547c478bd9Sstevel@tonic-gate void *addr_startp; 30557c478bd9Sstevel@tonic-gate t_scalar_t olen = creq->OPT_length; 30567c478bd9Sstevel@tonic-gate t_scalar_t ooff = creq->OPT_offset; 30577c478bd9Sstevel@tonic-gate size_t ci_msz; 30587c478bd9Sstevel@tonic-gate size_t size; 305967dbe2beSCasper H.S. Dik cred_t *cr = NULL; 306067dbe2beSCasper H.S. Dik pid_t cpid; 30617c478bd9Sstevel@tonic-gate 30627c478bd9Sstevel@tonic-gate if (tep->te_closing) { 30637c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 30647c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 30657c478bd9Sstevel@tonic-gate tl_refrele(tep); 30667c478bd9Sstevel@tonic-gate freemsg(mp); 30677c478bd9Sstevel@tonic-gate return; 30687c478bd9Sstevel@tonic-gate } 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate wq = tep->te_wq; 30717c478bd9Sstevel@tonic-gate tep->te_flag |= TL_EAGER; 30727c478bd9Sstevel@tonic-gate 30737c478bd9Sstevel@tonic-gate /* 30747c478bd9Sstevel@tonic-gate * Extract preallocated ackmp from mp. 30757c478bd9Sstevel@tonic-gate */ 30767c478bd9Sstevel@tonic-gate mp = mp->b_cont; 30777c478bd9Sstevel@tonic-gate ackmp->b_cont = NULL; 30787c478bd9Sstevel@tonic-gate 30797c478bd9Sstevel@tonic-gate if (olen == 0) 30807c478bd9Sstevel@tonic-gate ooff = 0; 30817c478bd9Sstevel@tonic-gate 30827c478bd9Sstevel@tonic-gate if (peer_tep->te_closing || 30837c478bd9Sstevel@tonic-gate !((peer_tep->te_state == TS_IDLE) || 30847c478bd9Sstevel@tonic-gate (peer_tep->te_state == TS_WRES_CIND))) { 3085b6626b4dSakolb (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE | SL_ERROR, 3086b6626b4dSakolb "tl_conn_req:peer in bad state (%d)", 3087b6626b4dSakolb peer_tep->te_state)); 30887c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 30897c478bd9Sstevel@tonic-gate tl_error_ack(wq, mp, TSYSERR, ECONNREFUSED, T_CONN_REQ); 30907c478bd9Sstevel@tonic-gate freemsg(ackmp); 30917c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 30927c478bd9Sstevel@tonic-gate tl_refrele(tep); 30937c478bd9Sstevel@tonic-gate return; 30947c478bd9Sstevel@tonic-gate } 30957c478bd9Sstevel@tonic-gate 30967c478bd9Sstevel@tonic-gate /* 30977c478bd9Sstevel@tonic-gate * preallocate now for T_DISCON_IND or T_CONN_IND 30987c478bd9Sstevel@tonic-gate */ 30997c478bd9Sstevel@tonic-gate /* 31007c478bd9Sstevel@tonic-gate * calculate length of T_CONN_IND message 31017c478bd9Sstevel@tonic-gate */ 310267dbe2beSCasper H.S. Dik if (peer_tep->te_flag & (TL_SETCRED|TL_SETUCRED)) { 310367dbe2beSCasper H.S. Dik cr = msg_getcred(mp, &cpid); 310467dbe2beSCasper H.S. Dik ASSERT(cr != NULL); 31057c478bd9Sstevel@tonic-gate if (peer_tep->te_flag & TL_SETCRED) { 31067c478bd9Sstevel@tonic-gate ooff = 0; 31077c478bd9Sstevel@tonic-gate olen = (t_scalar_t) sizeof (struct opthdr) + 31087c478bd9Sstevel@tonic-gate OPTLEN(sizeof (tl_credopt_t)); 31097c478bd9Sstevel@tonic-gate /* 1 option only */ 311067dbe2beSCasper H.S. Dik } else { 31117c478bd9Sstevel@tonic-gate ooff = 0; 31127c478bd9Sstevel@tonic-gate olen = (t_scalar_t)sizeof (struct opthdr) + 311367dbe2beSCasper H.S. Dik OPTLEN(ucredminsize(cr)); 31147c478bd9Sstevel@tonic-gate /* 1 option only */ 31157c478bd9Sstevel@tonic-gate } 311667dbe2beSCasper H.S. Dik } 31177c478bd9Sstevel@tonic-gate ci_msz = sizeof (struct T_conn_ind) + tep->te_alen; 31187c478bd9Sstevel@tonic-gate ci_msz = T_ALIGN(ci_msz) + olen; 31197c478bd9Sstevel@tonic-gate size = max(ci_msz, sizeof (struct T_discon_ind)); 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate /* 31227c478bd9Sstevel@tonic-gate * Save options from mp - we'll need them for T_CONN_IND. 31237c478bd9Sstevel@tonic-gate */ 31247c478bd9Sstevel@tonic-gate if (ooff != 0) { 31257c478bd9Sstevel@tonic-gate opts = kmem_alloc(olen, KM_NOSLEEP); 31267c478bd9Sstevel@tonic-gate if (opts == NULL) { 31277c478bd9Sstevel@tonic-gate /* 31287c478bd9Sstevel@tonic-gate * roll back state changes 31297c478bd9Sstevel@tonic-gate */ 31307c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 31317c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, size); 31327c478bd9Sstevel@tonic-gate freemsg(ackmp); 31337c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 31347c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 31357c478bd9Sstevel@tonic-gate tl_refrele(tep); 31367c478bd9Sstevel@tonic-gate return; 31377c478bd9Sstevel@tonic-gate } 31387c478bd9Sstevel@tonic-gate /* Copy options to a temp buffer */ 31397c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + ooff, opts, olen); 31407c478bd9Sstevel@tonic-gate } 31417c478bd9Sstevel@tonic-gate 31427c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep) && !tl_disable_early_connect) { 31437c478bd9Sstevel@tonic-gate /* 31447c478bd9Sstevel@tonic-gate * Generate a T_CONN_CON that has the identical address 31457c478bd9Sstevel@tonic-gate * (and options) as the T_CONN_REQ. 31467c478bd9Sstevel@tonic-gate * NOTE: assumes that the T_conn_req and T_conn_con structures 31477c478bd9Sstevel@tonic-gate * are isomorphic. 31487c478bd9Sstevel@tonic-gate */ 31497c478bd9Sstevel@tonic-gate confmp = copyb(mp); 31507c478bd9Sstevel@tonic-gate if (! confmp) { 31517c478bd9Sstevel@tonic-gate /* 31527c478bd9Sstevel@tonic-gate * roll back state changes 31537c478bd9Sstevel@tonic-gate */ 31547c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 31557c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, mp->b_wptr - mp->b_rptr); 31567c478bd9Sstevel@tonic-gate freemsg(ackmp); 31577c478bd9Sstevel@tonic-gate if (opts != NULL) 31587c478bd9Sstevel@tonic-gate kmem_free(opts, olen); 31597c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 31607c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 31617c478bd9Sstevel@tonic-gate tl_refrele(tep); 31627c478bd9Sstevel@tonic-gate return; 31637c478bd9Sstevel@tonic-gate } 31647c478bd9Sstevel@tonic-gate ((struct T_conn_con *)(confmp->b_rptr))->PRIM_type = 31657c478bd9Sstevel@tonic-gate T_CONN_CON; 31667c478bd9Sstevel@tonic-gate } else { 31677c478bd9Sstevel@tonic-gate confmp = NULL; 31687c478bd9Sstevel@tonic-gate } 31697c478bd9Sstevel@tonic-gate if ((indmp = reallocb(mp, size, 0)) == NULL) { 31707c478bd9Sstevel@tonic-gate /* 31717c478bd9Sstevel@tonic-gate * roll back state changes 31727c478bd9Sstevel@tonic-gate */ 31737c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 31747c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, size); 31757c478bd9Sstevel@tonic-gate freemsg(ackmp); 31767c478bd9Sstevel@tonic-gate if (opts != NULL) 31777c478bd9Sstevel@tonic-gate kmem_free(opts, olen); 31787c478bd9Sstevel@tonic-gate freemsg(confmp); 31797c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 31807c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 31817c478bd9Sstevel@tonic-gate tl_refrele(tep); 31827c478bd9Sstevel@tonic-gate return; 31837c478bd9Sstevel@tonic-gate } 31847c478bd9Sstevel@tonic-gate 31857c478bd9Sstevel@tonic-gate tip = kmem_zalloc(sizeof (*tip), KM_NOSLEEP); 31867c478bd9Sstevel@tonic-gate if (tip == NULL) { 31877c478bd9Sstevel@tonic-gate /* 31887c478bd9Sstevel@tonic-gate * roll back state changes 31897c478bd9Sstevel@tonic-gate */ 31907c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 31917c478bd9Sstevel@tonic-gate tl_memrecover(wq, indmp, sizeof (*tip)); 31927c478bd9Sstevel@tonic-gate freemsg(ackmp); 31937c478bd9Sstevel@tonic-gate if (opts != NULL) 31947c478bd9Sstevel@tonic-gate kmem_free(opts, olen); 31957c478bd9Sstevel@tonic-gate freemsg(confmp); 31967c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 31977c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 31987c478bd9Sstevel@tonic-gate tl_refrele(tep); 31997c478bd9Sstevel@tonic-gate return; 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate tip->ti_mp = NULL; 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate /* 32047c478bd9Sstevel@tonic-gate * memory is now committed for T_DISCON_IND/T_CONN_IND/T_CONN_CON 32057c478bd9Sstevel@tonic-gate * and tl_icon_t cell. 32067c478bd9Sstevel@tonic-gate */ 32077c478bd9Sstevel@tonic-gate 32087c478bd9Sstevel@tonic-gate /* 32097c478bd9Sstevel@tonic-gate * ack validity of request and send the peer credential in the ACK. 32107c478bd9Sstevel@tonic-gate */ 32117c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_OK_ACK1, tep->te_state); 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate if (peer_tep != NULL && peer_tep->te_credp != NULL && 32147c478bd9Sstevel@tonic-gate confmp != NULL) { 3215de8c4a14SErik Nordmark mblk_setcred(confmp, peer_tep->te_credp, peer_tep->te_cpid); 32167c478bd9Sstevel@tonic-gate } 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate tl_ok_ack(wq, ackmp, T_CONN_REQ); 32197c478bd9Sstevel@tonic-gate 32207c478bd9Sstevel@tonic-gate /* 32217c478bd9Sstevel@tonic-gate * prepare message to send T_CONN_IND 32227c478bd9Sstevel@tonic-gate */ 32237c478bd9Sstevel@tonic-gate /* 32247c478bd9Sstevel@tonic-gate * allocate the message - original data blocks retained 32257c478bd9Sstevel@tonic-gate * in the returned mblk 32267c478bd9Sstevel@tonic-gate */ 32277c478bd9Sstevel@tonic-gate cimp = tl_resizemp(indmp, size); 32287c478bd9Sstevel@tonic-gate if (! cimp) { 32297c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 32307c478bd9Sstevel@tonic-gate "tl_conn_req:con_ind:allocb failure")); 32317c478bd9Sstevel@tonic-gate tl_merror(wq, indmp, ENOMEM); 32327c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 32337c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 32347c478bd9Sstevel@tonic-gate tl_refrele(tep); 32357c478bd9Sstevel@tonic-gate if (opts != NULL) 32367c478bd9Sstevel@tonic-gate kmem_free(opts, olen); 32377c478bd9Sstevel@tonic-gate freemsg(confmp); 32387c478bd9Sstevel@tonic-gate ASSERT(tip->ti_mp == NULL); 32397c478bd9Sstevel@tonic-gate kmem_free(tip, sizeof (*tip)); 32407c478bd9Sstevel@tonic-gate return; 32417c478bd9Sstevel@tonic-gate } 32427c478bd9Sstevel@tonic-gate 32437c478bd9Sstevel@tonic-gate DB_TYPE(cimp) = M_PROTO; 32447c478bd9Sstevel@tonic-gate ci = (struct T_conn_ind *)cimp->b_rptr; 32457c478bd9Sstevel@tonic-gate ci->PRIM_type = T_CONN_IND; 32467c478bd9Sstevel@tonic-gate ci->SRC_offset = (t_scalar_t)sizeof (struct T_conn_ind); 32477c478bd9Sstevel@tonic-gate ci->SRC_length = tep->te_alen; 32487c478bd9Sstevel@tonic-gate ci->SEQ_number = tep->te_seqno; 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate addr_startp = cimp->b_rptr + ci->SRC_offset; 32517c478bd9Sstevel@tonic-gate bcopy(tep->te_abuf, addr_startp, tep->te_alen); 32527c478bd9Sstevel@tonic-gate if (peer_tep->te_flag & (TL_SETCRED|TL_SETUCRED)) { 3253de8c4a14SErik Nordmark 32547c478bd9Sstevel@tonic-gate ci->OPT_offset = (t_scalar_t)T_ALIGN(ci->SRC_offset + 32557c478bd9Sstevel@tonic-gate ci->SRC_length); 32567c478bd9Sstevel@tonic-gate ci->OPT_length = olen; /* because only 1 option */ 32577c478bd9Sstevel@tonic-gate tl_fill_option(cimp->b_rptr + ci->OPT_offset, 3258de8c4a14SErik Nordmark cr, cpid, 325945916cd2Sjpk peer_tep->te_flag, peer_tep->te_credp); 32607c478bd9Sstevel@tonic-gate } else if (ooff != 0) { 32617c478bd9Sstevel@tonic-gate /* Copy option from T_CONN_REQ */ 32627c478bd9Sstevel@tonic-gate ci->OPT_offset = (t_scalar_t)T_ALIGN(ci->SRC_offset + 32637c478bd9Sstevel@tonic-gate ci->SRC_length); 32647c478bd9Sstevel@tonic-gate ci->OPT_length = olen; 32657c478bd9Sstevel@tonic-gate ASSERT(opts != NULL); 32667c478bd9Sstevel@tonic-gate bcopy(opts, (void *)((uintptr_t)ci + ci->OPT_offset), olen); 32677c478bd9Sstevel@tonic-gate } else { 32687c478bd9Sstevel@tonic-gate ci->OPT_offset = 0; 32697c478bd9Sstevel@tonic-gate ci->OPT_length = 0; 32707c478bd9Sstevel@tonic-gate } 32717c478bd9Sstevel@tonic-gate if (opts != NULL) 32727c478bd9Sstevel@tonic-gate kmem_free(opts, olen); 32737c478bd9Sstevel@tonic-gate 32747c478bd9Sstevel@tonic-gate /* 32757c478bd9Sstevel@tonic-gate * register connection request with server peer 32767c478bd9Sstevel@tonic-gate * append to list of incoming connections 32777c478bd9Sstevel@tonic-gate * increment references for both peer_tep and tep: peer_tep is placed on 32787c478bd9Sstevel@tonic-gate * te_oconp and tep is placed on listeners queue. 32797c478bd9Sstevel@tonic-gate */ 32807c478bd9Sstevel@tonic-gate tip->ti_tep = tep; 32817c478bd9Sstevel@tonic-gate tip->ti_seqno = tep->te_seqno; 32827c478bd9Sstevel@tonic-gate list_insert_tail(&peer_tep->te_iconp, tip); 32837c478bd9Sstevel@tonic-gate peer_tep->te_nicon++; 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate peer_tep->te_state = NEXTSTATE(TE_CONN_IND, peer_tep->te_state); 32867c478bd9Sstevel@tonic-gate /* 32877c478bd9Sstevel@tonic-gate * send the T_CONN_IND message 32887c478bd9Sstevel@tonic-gate */ 32897c478bd9Sstevel@tonic-gate putnext(peer_tep->te_rq, cimp); 32907c478bd9Sstevel@tonic-gate 32917c478bd9Sstevel@tonic-gate /* 32927c478bd9Sstevel@tonic-gate * Send a T_CONN_CON message for sockets. 32937c478bd9Sstevel@tonic-gate * Disable the queues until we have reached the correct state! 32947c478bd9Sstevel@tonic-gate */ 32957c478bd9Sstevel@tonic-gate if (confmp != NULL) { 32967c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_CONN_CON, tep->te_state); 32977c478bd9Sstevel@tonic-gate noenable(wq); 32987c478bd9Sstevel@tonic-gate putnext(tep->te_rq, confmp); 32997c478bd9Sstevel@tonic-gate } 33007c478bd9Sstevel@tonic-gate /* 33017c478bd9Sstevel@tonic-gate * Now we need to increment tep reference because tep is referenced by 33027c478bd9Sstevel@tonic-gate * server list of pending connections. We also need to decrement 33037c478bd9Sstevel@tonic-gate * reference before exiting serializer. Two operations void each other 33047c478bd9Sstevel@tonic-gate * so we don't modify reference at all. 33057c478bd9Sstevel@tonic-gate */ 33067c478bd9Sstevel@tonic-gate ASSERT(tep->te_refcnt >= 2); 33077c478bd9Sstevel@tonic-gate ASSERT(peer_tep->te_refcnt >= 2); 33087c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 33097c478bd9Sstevel@tonic-gate } 33107c478bd9Sstevel@tonic-gate 33117c478bd9Sstevel@tonic-gate 33127c478bd9Sstevel@tonic-gate 33137c478bd9Sstevel@tonic-gate /* 33147c478bd9Sstevel@tonic-gate * Handle T_conn_res on listener stream. Called on listener serializer. 33157c478bd9Sstevel@tonic-gate * tl_conn_req has already generated the T_CONN_CON. 33167c478bd9Sstevel@tonic-gate * tl_conn_res is called on listener serializer. 33177c478bd9Sstevel@tonic-gate * No one accesses acceptor at this point, so it is safe to modify acceptor. 33187c478bd9Sstevel@tonic-gate * Switch eager serializer to acceptor's. 33197c478bd9Sstevel@tonic-gate * 33207c478bd9Sstevel@tonic-gate * If TL_SET[U]CRED generate the credentials options. 33217c478bd9Sstevel@tonic-gate * For sockets tl_conn_req has already generated the T_CONN_CON. 33227c478bd9Sstevel@tonic-gate */ 33237c478bd9Sstevel@tonic-gate static void 33247c478bd9Sstevel@tonic-gate tl_conn_res(mblk_t *mp, tl_endpt_t *tep) 33257c478bd9Sstevel@tonic-gate { 33267c478bd9Sstevel@tonic-gate queue_t *wq; 33277c478bd9Sstevel@tonic-gate struct T_conn_res *cres = (struct T_conn_res *)mp->b_rptr; 33287c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp); 33297c478bd9Sstevel@tonic-gate t_scalar_t olen, ooff, err = 0; 33307c478bd9Sstevel@tonic-gate t_scalar_t prim = cres->PRIM_type; 33317c478bd9Sstevel@tonic-gate uchar_t *addr_startp; 33327c478bd9Sstevel@tonic-gate tl_endpt_t *acc_ep = NULL, *cl_ep = NULL; 33337c478bd9Sstevel@tonic-gate tl_icon_t *tip; 33347c478bd9Sstevel@tonic-gate size_t size; 33357c478bd9Sstevel@tonic-gate mblk_t *ackmp, *respmp; 33367c478bd9Sstevel@tonic-gate mblk_t *dimp, *ccmp = NULL; 33377c478bd9Sstevel@tonic-gate struct T_discon_ind *di; 33387c478bd9Sstevel@tonic-gate struct T_conn_con *cc; 33397c478bd9Sstevel@tonic-gate boolean_t client_noclose_set = B_FALSE; 33407c478bd9Sstevel@tonic-gate boolean_t switch_client_serializer = B_TRUE; 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate ASSERT(IS_COTS(tep)); 33437c478bd9Sstevel@tonic-gate 33447c478bd9Sstevel@tonic-gate if (tep->te_closing) { 33457c478bd9Sstevel@tonic-gate freemsg(mp); 33467c478bd9Sstevel@tonic-gate return; 33477c478bd9Sstevel@tonic-gate } 33487c478bd9Sstevel@tonic-gate 33497c478bd9Sstevel@tonic-gate wq = tep->te_wq; 33507c478bd9Sstevel@tonic-gate 33517c478bd9Sstevel@tonic-gate /* 33527c478bd9Sstevel@tonic-gate * preallocate memory for: 33537c478bd9Sstevel@tonic-gate * 1. max of T_ERROR_ACK and T_OK_ACK 33547c478bd9Sstevel@tonic-gate * ==> known max T_ERROR_ACK 33557c478bd9Sstevel@tonic-gate * 2. max of T_DISCON_IND and T_CONN_CON 33567c478bd9Sstevel@tonic-gate */ 33577c478bd9Sstevel@tonic-gate ackmp = allocb(sizeof (struct T_error_ack), BPRI_MED); 33587c478bd9Sstevel@tonic-gate if (! ackmp) { 33597c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, sizeof (struct T_error_ack)); 33607c478bd9Sstevel@tonic-gate return; 33617c478bd9Sstevel@tonic-gate } 33627c478bd9Sstevel@tonic-gate /* 33637c478bd9Sstevel@tonic-gate * memory committed for T_OK_ACK/T_ERROR_ACK now 33647c478bd9Sstevel@tonic-gate * will be committed for T_DISCON_IND/T_CONN_CON later 33657c478bd9Sstevel@tonic-gate */ 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate 33687c478bd9Sstevel@tonic-gate ASSERT(prim == T_CONN_RES || prim == O_T_CONN_RES); 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate /* 33717c478bd9Sstevel@tonic-gate * validate state 33727c478bd9Sstevel@tonic-gate */ 33737c478bd9Sstevel@tonic-gate if (tep->te_state != TS_WRES_CIND) { 33747c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 33757c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 33767c478bd9Sstevel@tonic-gate "tl_wput:T_CONN_RES:out of state, state=%d", 33777c478bd9Sstevel@tonic-gate tep->te_state)); 33787c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TOUTSTATE, 0, prim); 33797c478bd9Sstevel@tonic-gate freemsg(mp); 33807c478bd9Sstevel@tonic-gate return; 33817c478bd9Sstevel@tonic-gate } 33827c478bd9Sstevel@tonic-gate 33837c478bd9Sstevel@tonic-gate /* 33847c478bd9Sstevel@tonic-gate * validate the message 33857c478bd9Sstevel@tonic-gate * Note: dereference fields in struct inside message only 33867c478bd9Sstevel@tonic-gate * after validating the message length. 33877c478bd9Sstevel@tonic-gate */ 33887c478bd9Sstevel@tonic-gate if (msz < sizeof (struct T_conn_res)) { 33897c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 33907c478bd9Sstevel@tonic-gate "tl_conn_res:invalid message length")); 33917c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TSYSERR, EINVAL, prim); 33927c478bd9Sstevel@tonic-gate freemsg(mp); 33937c478bd9Sstevel@tonic-gate return; 33947c478bd9Sstevel@tonic-gate } 33957c478bd9Sstevel@tonic-gate olen = cres->OPT_length; 33967c478bd9Sstevel@tonic-gate ooff = cres->OPT_offset; 33977c478bd9Sstevel@tonic-gate if (((olen > 0) && ((ooff + olen) > msz))) { 33987c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 33997c478bd9Sstevel@tonic-gate "tl_conn_res:invalid message")); 34007c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TSYSERR, EINVAL, prim); 34017c478bd9Sstevel@tonic-gate freemsg(mp); 34027c478bd9Sstevel@tonic-gate return; 34037c478bd9Sstevel@tonic-gate } 34047c478bd9Sstevel@tonic-gate if (olen) { 34057c478bd9Sstevel@tonic-gate /* 34067c478bd9Sstevel@tonic-gate * no opts in connect res 34077c478bd9Sstevel@tonic-gate * supported in this provider 34087c478bd9Sstevel@tonic-gate */ 34097c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 34107c478bd9Sstevel@tonic-gate "tl_conn_res:options not supported in message")); 34117c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADOPT, 0, prim); 34127c478bd9Sstevel@tonic-gate freemsg(mp); 34137c478bd9Sstevel@tonic-gate return; 34147c478bd9Sstevel@tonic-gate } 34157c478bd9Sstevel@tonic-gate 34167c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_CONN_RES, tep->te_state); 34177c478bd9Sstevel@tonic-gate ASSERT(tep->te_state == TS_WACK_CRES); 34187c478bd9Sstevel@tonic-gate 34197c478bd9Sstevel@tonic-gate if (cres->SEQ_number < TL_MINOR_START && 34207c478bd9Sstevel@tonic-gate cres->SEQ_number >= BADSEQNUM) { 34217c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE|SL_ERROR, 34227c478bd9Sstevel@tonic-gate "tl_conn_res:remote endpoint sequence number bad")); 34237c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 34247c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADSEQ, 0, prim); 34257c478bd9Sstevel@tonic-gate freemsg(mp); 34267c478bd9Sstevel@tonic-gate return; 34277c478bd9Sstevel@tonic-gate } 34287c478bd9Sstevel@tonic-gate 34297c478bd9Sstevel@tonic-gate /* 34307c478bd9Sstevel@tonic-gate * find accepting endpoint. Will have extra reference if found. 34317c478bd9Sstevel@tonic-gate */ 34327c478bd9Sstevel@tonic-gate if (mod_hash_find_cb(tep->te_transport->tr_ai_hash, 34337c478bd9Sstevel@tonic-gate (mod_hash_key_t)(uintptr_t)cres->ACCEPTOR_id, 34347c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&acc_ep, tl_find_callback) != 0) { 34357c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE|SL_ERROR, 34367c478bd9Sstevel@tonic-gate "tl_conn_res:bad accepting endpoint")); 34377c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 34387c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADF, 0, prim); 34397c478bd9Sstevel@tonic-gate freemsg(mp); 34407c478bd9Sstevel@tonic-gate return; 34417c478bd9Sstevel@tonic-gate } 34427c478bd9Sstevel@tonic-gate 34437c478bd9Sstevel@tonic-gate /* 34447c478bd9Sstevel@tonic-gate * Prevent acceptor from closing. 34457c478bd9Sstevel@tonic-gate */ 34467c478bd9Sstevel@tonic-gate if (! tl_noclose(acc_ep)) { 34477c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE|SL_ERROR, 34487c478bd9Sstevel@tonic-gate "tl_conn_res:bad accepting endpoint")); 34497c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 34507c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADF, 0, prim); 34517c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 34527c478bd9Sstevel@tonic-gate freemsg(mp); 34537c478bd9Sstevel@tonic-gate return; 34547c478bd9Sstevel@tonic-gate } 34557c478bd9Sstevel@tonic-gate 34567c478bd9Sstevel@tonic-gate acc_ep->te_flag |= TL_ACCEPTOR; 34577c478bd9Sstevel@tonic-gate 34587c478bd9Sstevel@tonic-gate /* 34597c478bd9Sstevel@tonic-gate * validate that accepting endpoint, if different from listening 34607c478bd9Sstevel@tonic-gate * has address bound => state is TS_IDLE 34617c478bd9Sstevel@tonic-gate * TROUBLE in XPG4 !!? 34627c478bd9Sstevel@tonic-gate */ 34637c478bd9Sstevel@tonic-gate if ((tep != acc_ep) && (acc_ep->te_state != TS_IDLE)) { 34647c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE|SL_ERROR, 34657c478bd9Sstevel@tonic-gate "tl_conn_res:accepting endpoint has no address bound," 34667c478bd9Sstevel@tonic-gate "state=%d", acc_ep->te_state)); 34677c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 34687c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TOUTSTATE, 0, prim); 34697c478bd9Sstevel@tonic-gate freemsg(mp); 34707c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 34717c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 34727c478bd9Sstevel@tonic-gate return; 34737c478bd9Sstevel@tonic-gate } 34747c478bd9Sstevel@tonic-gate 34757c478bd9Sstevel@tonic-gate /* 34767c478bd9Sstevel@tonic-gate * validate if accepting endpt same as listening, then 34777c478bd9Sstevel@tonic-gate * no other incoming connection should be on the queue 34787c478bd9Sstevel@tonic-gate */ 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate if ((tep == acc_ep) && (tep->te_nicon > 1)) { 34817c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 34827c478bd9Sstevel@tonic-gate "tl_conn_res: > 1 conn_ind on listener-acceptor")); 34837c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 34847c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADF, 0, prim); 34857c478bd9Sstevel@tonic-gate freemsg(mp); 34867c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 34877c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 34887c478bd9Sstevel@tonic-gate return; 34897c478bd9Sstevel@tonic-gate } 34907c478bd9Sstevel@tonic-gate 34917c478bd9Sstevel@tonic-gate /* 34927c478bd9Sstevel@tonic-gate * Mark for deletion, the entry corresponding to client 34937c478bd9Sstevel@tonic-gate * on list of pending connections made by the listener 34947c478bd9Sstevel@tonic-gate * search list to see if client is one of the 34957c478bd9Sstevel@tonic-gate * recorded as a listener. 34967c478bd9Sstevel@tonic-gate */ 34977c478bd9Sstevel@tonic-gate tip = tl_icon_find(tep, cres->SEQ_number); 34987c478bd9Sstevel@tonic-gate if (tip == NULL) { 34997c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE|SL_ERROR, 35007c478bd9Sstevel@tonic-gate "tl_conn_res:no client in listener list")); 35017c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, tep->te_state); 35027c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADSEQ, 0, prim); 35037c478bd9Sstevel@tonic-gate freemsg(mp); 35047c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 35057c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 35067c478bd9Sstevel@tonic-gate return; 35077c478bd9Sstevel@tonic-gate } 35087c478bd9Sstevel@tonic-gate 35097c478bd9Sstevel@tonic-gate /* 35107c478bd9Sstevel@tonic-gate * If ti_tep is NULL the client has already closed. In this case 35117c478bd9Sstevel@tonic-gate * the code below will avoid any action on the client side 35127c478bd9Sstevel@tonic-gate * but complete the server and acceptor state transitions. 35137c478bd9Sstevel@tonic-gate */ 35147c478bd9Sstevel@tonic-gate ASSERT(tip->ti_tep == NULL || 35157c478bd9Sstevel@tonic-gate tip->ti_tep->te_seqno == cres->SEQ_number); 35167c478bd9Sstevel@tonic-gate cl_ep = tip->ti_tep; 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate /* 35197c478bd9Sstevel@tonic-gate * If the client is present it is switched from listener's to acceptor's 35207c478bd9Sstevel@tonic-gate * serializer. We should block client closes while serializers are 35217c478bd9Sstevel@tonic-gate * being switched. 35227c478bd9Sstevel@tonic-gate * 35237c478bd9Sstevel@tonic-gate * It is possible that the client is present but is currently being 35247c478bd9Sstevel@tonic-gate * closed. There are two possible cases: 35257c478bd9Sstevel@tonic-gate * 35267c478bd9Sstevel@tonic-gate * 1) The client has already entered tl_close_finish_ser() and sent 35277c478bd9Sstevel@tonic-gate * T_ORDREL_IND. In this case we can just ignore the client (but we 35287c478bd9Sstevel@tonic-gate * still need to send all messages from tip->ti_mp to the acceptor). 35297c478bd9Sstevel@tonic-gate * 35307c478bd9Sstevel@tonic-gate * 2) The client started the close but has not entered 35317c478bd9Sstevel@tonic-gate * tl_close_finish_ser() yet. In this case, the client is already 35327c478bd9Sstevel@tonic-gate * proceeding asynchronously on the listener's serializer, so we're 35337c478bd9Sstevel@tonic-gate * forced to change the acceptor to use the listener's serializer to 35347c478bd9Sstevel@tonic-gate * ensure that any operations on the acceptor are serialized with 35357c478bd9Sstevel@tonic-gate * respect to the close that's in-progress. 35367c478bd9Sstevel@tonic-gate */ 35377c478bd9Sstevel@tonic-gate if (cl_ep != NULL) { 35387c478bd9Sstevel@tonic-gate if (tl_noclose(cl_ep)) { 35397c478bd9Sstevel@tonic-gate client_noclose_set = B_TRUE; 35407c478bd9Sstevel@tonic-gate } else { 35417c478bd9Sstevel@tonic-gate /* 35427c478bd9Sstevel@tonic-gate * Client is closing. If it it has sent the 35437c478bd9Sstevel@tonic-gate * T_ORDREL_IND, we can simply ignore it - otherwise, 35447c478bd9Sstevel@tonic-gate * we have to let let the client continue until it is 35457c478bd9Sstevel@tonic-gate * sent. 35467c478bd9Sstevel@tonic-gate * 35477c478bd9Sstevel@tonic-gate * If we do continue using the client, acceptor will 35487c478bd9Sstevel@tonic-gate * switch to client's serializer which is used by client 35497c478bd9Sstevel@tonic-gate * for its close. 35507c478bd9Sstevel@tonic-gate */ 35517c478bd9Sstevel@tonic-gate tl_client_closing_when_accepting++; 35527c478bd9Sstevel@tonic-gate switch_client_serializer = B_FALSE; 35537c478bd9Sstevel@tonic-gate if (!IS_SOCKET(cl_ep) || tl_disable_early_connect || 35547c478bd9Sstevel@tonic-gate cl_ep->te_state == -1) 35557c478bd9Sstevel@tonic-gate cl_ep = NULL; 35567c478bd9Sstevel@tonic-gate } 35577c478bd9Sstevel@tonic-gate } 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate if (cl_ep != NULL) { 35607c478bd9Sstevel@tonic-gate /* 35617c478bd9Sstevel@tonic-gate * validate client state to be TS_WCON_CREQ or TS_DATA_XFER 35627c478bd9Sstevel@tonic-gate * (latter for sockets only) 35637c478bd9Sstevel@tonic-gate */ 35647c478bd9Sstevel@tonic-gate if (cl_ep->te_state != TS_WCON_CREQ && 35657c478bd9Sstevel@tonic-gate (cl_ep->te_state != TS_DATA_XFER && 35667c478bd9Sstevel@tonic-gate IS_SOCKET(cl_ep))) { 35677c478bd9Sstevel@tonic-gate err = ECONNREFUSED; 35687c478bd9Sstevel@tonic-gate /* 35697c478bd9Sstevel@tonic-gate * T_DISCON_IND sent later after committing memory 35707c478bd9Sstevel@tonic-gate * and acking validity of request 35717c478bd9Sstevel@tonic-gate */ 35727c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, SL_TRACE, 35737c478bd9Sstevel@tonic-gate "tl_conn_res:peer in bad state")); 35747c478bd9Sstevel@tonic-gate } 35757c478bd9Sstevel@tonic-gate 35767c478bd9Sstevel@tonic-gate /* 35777c478bd9Sstevel@tonic-gate * preallocate now for T_DISCON_IND or T_CONN_CONN 35787c478bd9Sstevel@tonic-gate * ack validity of request (T_OK_ACK) after memory committed 35797c478bd9Sstevel@tonic-gate */ 35807c478bd9Sstevel@tonic-gate 35817c478bd9Sstevel@tonic-gate if (err) 35827c478bd9Sstevel@tonic-gate size = sizeof (struct T_discon_ind); 35837c478bd9Sstevel@tonic-gate else { 35847c478bd9Sstevel@tonic-gate /* 35857c478bd9Sstevel@tonic-gate * calculate length of T_CONN_CON message 35867c478bd9Sstevel@tonic-gate */ 35877c478bd9Sstevel@tonic-gate olen = 0; 35887c478bd9Sstevel@tonic-gate if (cl_ep->te_flag & TL_SETCRED) { 35897c478bd9Sstevel@tonic-gate olen = (t_scalar_t)sizeof (struct opthdr) + 35907c478bd9Sstevel@tonic-gate OPTLEN(sizeof (tl_credopt_t)); 35917c478bd9Sstevel@tonic-gate } else if (cl_ep->te_flag & TL_SETUCRED) { 35927c478bd9Sstevel@tonic-gate olen = (t_scalar_t)sizeof (struct opthdr) + 359367dbe2beSCasper H.S. Dik OPTLEN(ucredminsize(acc_ep->te_credp)); 35947c478bd9Sstevel@tonic-gate } 35957c478bd9Sstevel@tonic-gate size = T_ALIGN(sizeof (struct T_conn_con) + 35967c478bd9Sstevel@tonic-gate acc_ep->te_alen) + olen; 35977c478bd9Sstevel@tonic-gate } 35987c478bd9Sstevel@tonic-gate if ((respmp = reallocb(mp, size, 0)) == NULL) { 35997c478bd9Sstevel@tonic-gate /* 36007c478bd9Sstevel@tonic-gate * roll back state changes 36017c478bd9Sstevel@tonic-gate */ 36027c478bd9Sstevel@tonic-gate tep->te_state = TS_WRES_CIND; 36037c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, size); 36047c478bd9Sstevel@tonic-gate freemsg(ackmp); 36057c478bd9Sstevel@tonic-gate if (client_noclose_set) 36067c478bd9Sstevel@tonic-gate tl_closeok(cl_ep); 36077c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 36087c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 36097c478bd9Sstevel@tonic-gate return; 36107c478bd9Sstevel@tonic-gate } 36117c478bd9Sstevel@tonic-gate mp = NULL; 36127c478bd9Sstevel@tonic-gate } 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate /* 36157c478bd9Sstevel@tonic-gate * Now ack validity of request 36167c478bd9Sstevel@tonic-gate */ 36177c478bd9Sstevel@tonic-gate if (tep->te_nicon == 1) { 36187c478bd9Sstevel@tonic-gate if (tep == acc_ep) 36197c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_OK_ACK2, tep->te_state); 36207c478bd9Sstevel@tonic-gate else 36217c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_OK_ACK3, tep->te_state); 36227c478bd9Sstevel@tonic-gate } else 36237c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_OK_ACK4, tep->te_state); 36247c478bd9Sstevel@tonic-gate 36257c478bd9Sstevel@tonic-gate /* 36267c478bd9Sstevel@tonic-gate * send T_DISCON_IND now if client state validation failed earlier 36277c478bd9Sstevel@tonic-gate */ 36287c478bd9Sstevel@tonic-gate if (err) { 36297c478bd9Sstevel@tonic-gate tl_ok_ack(wq, ackmp, prim); 36307c478bd9Sstevel@tonic-gate /* 36317c478bd9Sstevel@tonic-gate * flush the queues - why always ? 36327c478bd9Sstevel@tonic-gate */ 36337c478bd9Sstevel@tonic-gate (void) putnextctl1(acc_ep->te_rq, M_FLUSH, FLUSHR); 36347c478bd9Sstevel@tonic-gate 36357c478bd9Sstevel@tonic-gate dimp = tl_resizemp(respmp, size); 36367c478bd9Sstevel@tonic-gate if (! dimp) { 36377c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 36387c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 36397c478bd9Sstevel@tonic-gate "tl_conn_res:con_ind:allocb failure")); 36407c478bd9Sstevel@tonic-gate tl_merror(wq, respmp, ENOMEM); 36417c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 36427c478bd9Sstevel@tonic-gate if (client_noclose_set) 36437c478bd9Sstevel@tonic-gate tl_closeok(cl_ep); 36447c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 36457c478bd9Sstevel@tonic-gate return; 36467c478bd9Sstevel@tonic-gate } 36477c478bd9Sstevel@tonic-gate if (dimp->b_cont) { 36487c478bd9Sstevel@tonic-gate /* no user data in provider generated discon ind */ 36497c478bd9Sstevel@tonic-gate freemsg(dimp->b_cont); 36507c478bd9Sstevel@tonic-gate dimp->b_cont = NULL; 36517c478bd9Sstevel@tonic-gate } 36527c478bd9Sstevel@tonic-gate 36537c478bd9Sstevel@tonic-gate DB_TYPE(dimp) = M_PROTO; 36547c478bd9Sstevel@tonic-gate di = (struct T_discon_ind *)dimp->b_rptr; 36557c478bd9Sstevel@tonic-gate di->PRIM_type = T_DISCON_IND; 36567c478bd9Sstevel@tonic-gate di->DISCON_reason = err; 36577c478bd9Sstevel@tonic-gate di->SEQ_number = BADSEQNUM; 36587c478bd9Sstevel@tonic-gate 36597c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 36607c478bd9Sstevel@tonic-gate /* 36617c478bd9Sstevel@tonic-gate * send T_DISCON_IND message 36627c478bd9Sstevel@tonic-gate */ 36637c478bd9Sstevel@tonic-gate putnext(acc_ep->te_rq, dimp); 36647c478bd9Sstevel@tonic-gate if (client_noclose_set) 36657c478bd9Sstevel@tonic-gate tl_closeok(cl_ep); 36667c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 36677c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 36687c478bd9Sstevel@tonic-gate return; 36697c478bd9Sstevel@tonic-gate } 36707c478bd9Sstevel@tonic-gate 36717c478bd9Sstevel@tonic-gate /* 36727c478bd9Sstevel@tonic-gate * now start connecting the accepting endpoint 36737c478bd9Sstevel@tonic-gate */ 36747c478bd9Sstevel@tonic-gate if (tep != acc_ep) 36757c478bd9Sstevel@tonic-gate acc_ep->te_state = NEXTSTATE(TE_PASS_CONN, acc_ep->te_state); 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate if (cl_ep == NULL) { 36787c478bd9Sstevel@tonic-gate /* 36797c478bd9Sstevel@tonic-gate * The client has already closed. Send up any queued messages 36807c478bd9Sstevel@tonic-gate * and change the state accordingly. 36817c478bd9Sstevel@tonic-gate */ 36827c478bd9Sstevel@tonic-gate tl_ok_ack(wq, ackmp, prim); 36837c478bd9Sstevel@tonic-gate tl_icon_sendmsgs(acc_ep, &tip->ti_mp); 36847c478bd9Sstevel@tonic-gate 36857c478bd9Sstevel@tonic-gate /* 36867c478bd9Sstevel@tonic-gate * remove endpoint from incoming connection 36877c478bd9Sstevel@tonic-gate * delete client from list of incoming connections 36887c478bd9Sstevel@tonic-gate */ 36897c478bd9Sstevel@tonic-gate tl_freetip(tep, tip); 36907c478bd9Sstevel@tonic-gate freemsg(mp); 36917c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 36927c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 36937c478bd9Sstevel@tonic-gate return; 36947c478bd9Sstevel@tonic-gate } else if (tip->ti_mp != NULL) { 36957c478bd9Sstevel@tonic-gate /* 36967c478bd9Sstevel@tonic-gate * The client could have queued a T_DISCON_IND which needs 36977c478bd9Sstevel@tonic-gate * to be sent up. 36987c478bd9Sstevel@tonic-gate * Note that t_discon_req can not operate the same as 36997c478bd9Sstevel@tonic-gate * t_data_req since it is not possible for it to putbq 37007c478bd9Sstevel@tonic-gate * the message and return -1 due to the use of qwriter. 37017c478bd9Sstevel@tonic-gate */ 37027c478bd9Sstevel@tonic-gate tl_icon_sendmsgs(acc_ep, &tip->ti_mp); 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate /* 37067c478bd9Sstevel@tonic-gate * prepare connect confirm T_CONN_CON message 37077c478bd9Sstevel@tonic-gate */ 37087c478bd9Sstevel@tonic-gate 37097c478bd9Sstevel@tonic-gate /* 37107c478bd9Sstevel@tonic-gate * allocate the message - original data blocks 37117c478bd9Sstevel@tonic-gate * retained in the returned mblk 37127c478bd9Sstevel@tonic-gate */ 37137c478bd9Sstevel@tonic-gate if (! IS_SOCKET(cl_ep) || tl_disable_early_connect) { 37147c478bd9Sstevel@tonic-gate ccmp = tl_resizemp(respmp, size); 37157c478bd9Sstevel@tonic-gate if (ccmp == NULL) { 37167c478bd9Sstevel@tonic-gate tl_ok_ack(wq, ackmp, prim); 37177c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 37187c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 37197c478bd9Sstevel@tonic-gate "tl_conn_res:conn_con:allocb failure")); 37207c478bd9Sstevel@tonic-gate tl_merror(wq, respmp, ENOMEM); 37217c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 37227c478bd9Sstevel@tonic-gate if (client_noclose_set) 37237c478bd9Sstevel@tonic-gate tl_closeok(cl_ep); 37247c478bd9Sstevel@tonic-gate tl_refrele(acc_ep); 37257c478bd9Sstevel@tonic-gate return; 37267c478bd9Sstevel@tonic-gate } 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate DB_TYPE(ccmp) = M_PROTO; 37297c478bd9Sstevel@tonic-gate cc = (struct T_conn_con *)ccmp->b_rptr; 37307c478bd9Sstevel@tonic-gate cc->PRIM_type = T_CONN_CON; 37317c478bd9Sstevel@tonic-gate cc->RES_offset = (t_scalar_t)sizeof (struct T_conn_con); 37327c478bd9Sstevel@tonic-gate cc->RES_length = acc_ep->te_alen; 37337c478bd9Sstevel@tonic-gate addr_startp = ccmp->b_rptr + cc->RES_offset; 37347c478bd9Sstevel@tonic-gate bcopy(acc_ep->te_abuf, addr_startp, acc_ep->te_alen); 37357c478bd9Sstevel@tonic-gate if (cl_ep->te_flag & (TL_SETCRED|TL_SETUCRED)) { 37367c478bd9Sstevel@tonic-gate cc->OPT_offset = (t_scalar_t)T_ALIGN(cc->RES_offset + 37377c478bd9Sstevel@tonic-gate cc->RES_length); 37387c478bd9Sstevel@tonic-gate cc->OPT_length = olen; 37397c478bd9Sstevel@tonic-gate tl_fill_option(ccmp->b_rptr + cc->OPT_offset, 374045916cd2Sjpk acc_ep->te_credp, acc_ep->te_cpid, cl_ep->te_flag, 374145916cd2Sjpk cl_ep->te_credp); 37427c478bd9Sstevel@tonic-gate } else { 37437c478bd9Sstevel@tonic-gate cc->OPT_offset = 0; 37447c478bd9Sstevel@tonic-gate cc->OPT_length = 0; 37457c478bd9Sstevel@tonic-gate } 37467c478bd9Sstevel@tonic-gate /* 37477c478bd9Sstevel@tonic-gate * Forward the credential in the packet so it can be picked up 37487c478bd9Sstevel@tonic-gate * at the higher layers for more complete credential processing 37497c478bd9Sstevel@tonic-gate */ 3750de8c4a14SErik Nordmark mblk_setcred(ccmp, acc_ep->te_credp, acc_ep->te_cpid); 37517c478bd9Sstevel@tonic-gate } else { 37527c478bd9Sstevel@tonic-gate freemsg(respmp); 37537c478bd9Sstevel@tonic-gate respmp = NULL; 37547c478bd9Sstevel@tonic-gate } 37557c478bd9Sstevel@tonic-gate 37567c478bd9Sstevel@tonic-gate /* 37577c478bd9Sstevel@tonic-gate * make connection linking 37587c478bd9Sstevel@tonic-gate * accepting and client endpoints 37597c478bd9Sstevel@tonic-gate * No need to increment references: 37607c478bd9Sstevel@tonic-gate * on client: it should already have one from tip->ti_tep linkage. 37617c478bd9Sstevel@tonic-gate * on acceptor is should already have one from the table lookup. 37627c478bd9Sstevel@tonic-gate * 37637c478bd9Sstevel@tonic-gate * At this point both client and acceptor can't close. Set client 37647c478bd9Sstevel@tonic-gate * serializer to acceptor's. 37657c478bd9Sstevel@tonic-gate */ 37667c478bd9Sstevel@tonic-gate ASSERT(cl_ep->te_refcnt >= 2); 37677c478bd9Sstevel@tonic-gate ASSERT(acc_ep->te_refcnt >= 2); 37687c478bd9Sstevel@tonic-gate ASSERT(cl_ep->te_conp == NULL); 37697c478bd9Sstevel@tonic-gate ASSERT(acc_ep->te_conp == NULL); 37707c478bd9Sstevel@tonic-gate cl_ep->te_conp = acc_ep; 37717c478bd9Sstevel@tonic-gate acc_ep->te_conp = cl_ep; 37727c478bd9Sstevel@tonic-gate ASSERT(cl_ep->te_ser == tep->te_ser); 37737c478bd9Sstevel@tonic-gate if (switch_client_serializer) { 37747c478bd9Sstevel@tonic-gate mutex_enter(&cl_ep->te_ser_lock); 37757c478bd9Sstevel@tonic-gate if (cl_ep->te_ser_count > 0) { 37767c478bd9Sstevel@tonic-gate switch_client_serializer = B_FALSE; 37777c478bd9Sstevel@tonic-gate tl_serializer_noswitch++; 37787c478bd9Sstevel@tonic-gate } else { 37797c478bd9Sstevel@tonic-gate /* 37807c478bd9Sstevel@tonic-gate * Move client to the acceptor's serializer. 37817c478bd9Sstevel@tonic-gate */ 37827c478bd9Sstevel@tonic-gate tl_serializer_refhold(acc_ep->te_ser); 37837c478bd9Sstevel@tonic-gate tl_serializer_refrele(cl_ep->te_ser); 37847c478bd9Sstevel@tonic-gate cl_ep->te_ser = acc_ep->te_ser; 37857c478bd9Sstevel@tonic-gate } 37867c478bd9Sstevel@tonic-gate mutex_exit(&cl_ep->te_ser_lock); 37877c478bd9Sstevel@tonic-gate } 37887c478bd9Sstevel@tonic-gate if (!switch_client_serializer) { 37897c478bd9Sstevel@tonic-gate /* 37907c478bd9Sstevel@tonic-gate * It is not possible to switch client to use acceptor's. 37917c478bd9Sstevel@tonic-gate * Move acceptor to client's serializer (which is the same as 37927c478bd9Sstevel@tonic-gate * listener's). 37937c478bd9Sstevel@tonic-gate */ 37947c478bd9Sstevel@tonic-gate tl_serializer_refhold(cl_ep->te_ser); 37957c478bd9Sstevel@tonic-gate tl_serializer_refrele(acc_ep->te_ser); 37967c478bd9Sstevel@tonic-gate acc_ep->te_ser = cl_ep->te_ser; 37977c478bd9Sstevel@tonic-gate } 37987c478bd9Sstevel@tonic-gate 37997c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(cl_ep->te_oconp); 38007c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(acc_ep->te_oconp); 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate /* 38037c478bd9Sstevel@tonic-gate * remove endpoint from incoming connection 38047c478bd9Sstevel@tonic-gate * delete client from list of incoming connections 38057c478bd9Sstevel@tonic-gate */ 38067c478bd9Sstevel@tonic-gate tip->ti_tep = NULL; 38077c478bd9Sstevel@tonic-gate tl_freetip(tep, tip); 38087c478bd9Sstevel@tonic-gate tl_ok_ack(wq, ackmp, prim); 38097c478bd9Sstevel@tonic-gate 38107c478bd9Sstevel@tonic-gate /* 38117c478bd9Sstevel@tonic-gate * data blocks already linked in reallocb() 38127c478bd9Sstevel@tonic-gate */ 38137c478bd9Sstevel@tonic-gate 38147c478bd9Sstevel@tonic-gate /* 38157c478bd9Sstevel@tonic-gate * link queues so that I_SENDFD will work 38167c478bd9Sstevel@tonic-gate */ 38177c478bd9Sstevel@tonic-gate if (! IS_SOCKET(tep)) { 38187c478bd9Sstevel@tonic-gate acc_ep->te_wq->q_next = cl_ep->te_rq; 38197c478bd9Sstevel@tonic-gate cl_ep->te_wq->q_next = acc_ep->te_rq; 38207c478bd9Sstevel@tonic-gate } 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate /* 38237c478bd9Sstevel@tonic-gate * send T_CONN_CON up on client side unless it was already 38247c478bd9Sstevel@tonic-gate * done (for a socket). In cases any data or ordrel req has been 38257c478bd9Sstevel@tonic-gate * queued make sure that the service procedure runs. 38267c478bd9Sstevel@tonic-gate */ 38277c478bd9Sstevel@tonic-gate if (IS_SOCKET(cl_ep) && !tl_disable_early_connect) { 38287c478bd9Sstevel@tonic-gate enableok(cl_ep->te_wq); 38297c478bd9Sstevel@tonic-gate TL_QENABLE(cl_ep); 38307c478bd9Sstevel@tonic-gate if (ccmp != NULL) 38317c478bd9Sstevel@tonic-gate freemsg(ccmp); 38327c478bd9Sstevel@tonic-gate } else { 38337c478bd9Sstevel@tonic-gate /* 38347c478bd9Sstevel@tonic-gate * change client state on TE_CONN_CON event 38357c478bd9Sstevel@tonic-gate */ 38367c478bd9Sstevel@tonic-gate cl_ep->te_state = NEXTSTATE(TE_CONN_CON, cl_ep->te_state); 38377c478bd9Sstevel@tonic-gate putnext(cl_ep->te_rq, ccmp); 38387c478bd9Sstevel@tonic-gate } 38397c478bd9Sstevel@tonic-gate 38407c478bd9Sstevel@tonic-gate /* Mark the both endpoints as accepted */ 38417c478bd9Sstevel@tonic-gate cl_ep->te_flag |= TL_ACCEPTED; 38427c478bd9Sstevel@tonic-gate acc_ep->te_flag |= TL_ACCEPTED; 38437c478bd9Sstevel@tonic-gate 38447c478bd9Sstevel@tonic-gate /* 38457c478bd9Sstevel@tonic-gate * Allow client and acceptor to close. 38467c478bd9Sstevel@tonic-gate */ 38477c478bd9Sstevel@tonic-gate tl_closeok(acc_ep); 38487c478bd9Sstevel@tonic-gate if (client_noclose_set) 38497c478bd9Sstevel@tonic-gate tl_closeok(cl_ep); 38507c478bd9Sstevel@tonic-gate } 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate 38547c478bd9Sstevel@tonic-gate 38557c478bd9Sstevel@tonic-gate static void 38567c478bd9Sstevel@tonic-gate tl_discon_req(mblk_t *mp, tl_endpt_t *tep) 38577c478bd9Sstevel@tonic-gate { 38587c478bd9Sstevel@tonic-gate queue_t *wq; 38597c478bd9Sstevel@tonic-gate struct T_discon_req *dr; 38607c478bd9Sstevel@tonic-gate ssize_t msz; 38617c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = tep->te_conp; 38627c478bd9Sstevel@tonic-gate tl_endpt_t *srv_tep = tep->te_oconp; 38637c478bd9Sstevel@tonic-gate tl_icon_t *tip; 38647c478bd9Sstevel@tonic-gate size_t size; 38657c478bd9Sstevel@tonic-gate mblk_t *ackmp, *dimp, *respmp; 38667c478bd9Sstevel@tonic-gate struct T_discon_ind *di; 38677c478bd9Sstevel@tonic-gate t_scalar_t save_state, new_state; 38687c478bd9Sstevel@tonic-gate 38697c478bd9Sstevel@tonic-gate if (tep->te_closing) { 38707c478bd9Sstevel@tonic-gate freemsg(mp); 38717c478bd9Sstevel@tonic-gate return; 38727c478bd9Sstevel@tonic-gate } 38737c478bd9Sstevel@tonic-gate 38747c478bd9Sstevel@tonic-gate if ((peer_tep != NULL) && peer_tep->te_closing) { 38757c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_conp); 38767c478bd9Sstevel@tonic-gate peer_tep = NULL; 38777c478bd9Sstevel@tonic-gate } 38787c478bd9Sstevel@tonic-gate if ((srv_tep != NULL) && srv_tep->te_closing) { 38797c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 38807c478bd9Sstevel@tonic-gate srv_tep = NULL; 38817c478bd9Sstevel@tonic-gate } 38827c478bd9Sstevel@tonic-gate 38837c478bd9Sstevel@tonic-gate wq = tep->te_wq; 38847c478bd9Sstevel@tonic-gate 38857c478bd9Sstevel@tonic-gate /* 38867c478bd9Sstevel@tonic-gate * preallocate memory for: 38877c478bd9Sstevel@tonic-gate * 1. max of T_ERROR_ACK and T_OK_ACK 38887c478bd9Sstevel@tonic-gate * ==> known max T_ERROR_ACK 38897c478bd9Sstevel@tonic-gate * 2. for T_DISCON_IND 38907c478bd9Sstevel@tonic-gate */ 38917c478bd9Sstevel@tonic-gate ackmp = allocb(sizeof (struct T_error_ack), BPRI_MED); 38927c478bd9Sstevel@tonic-gate if (! ackmp) { 38937c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, sizeof (struct T_error_ack)); 38947c478bd9Sstevel@tonic-gate return; 38957c478bd9Sstevel@tonic-gate } 38967c478bd9Sstevel@tonic-gate /* 38977c478bd9Sstevel@tonic-gate * memory committed for T_OK_ACK/T_ERROR_ACK now 38987c478bd9Sstevel@tonic-gate * will be committed for T_DISCON_IND later 38997c478bd9Sstevel@tonic-gate */ 39007c478bd9Sstevel@tonic-gate 39017c478bd9Sstevel@tonic-gate dr = (struct T_discon_req *)mp->b_rptr; 39027c478bd9Sstevel@tonic-gate msz = MBLKL(mp); 39037c478bd9Sstevel@tonic-gate 39047c478bd9Sstevel@tonic-gate /* 39057c478bd9Sstevel@tonic-gate * validate the state 39067c478bd9Sstevel@tonic-gate */ 39077c478bd9Sstevel@tonic-gate save_state = new_state = tep->te_state; 39087c478bd9Sstevel@tonic-gate if (! (save_state >= TS_WCON_CREQ && save_state <= TS_WRES_CIND) && 39097c478bd9Sstevel@tonic-gate ! (save_state >= TS_DATA_XFER && save_state <= TS_WREQ_ORDREL)) { 39107c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 39117c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 39127c478bd9Sstevel@tonic-gate "tl_wput:T_DISCON_REQ:out of state, state=%d", 39137c478bd9Sstevel@tonic-gate tep->te_state)); 39147c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TOUTSTATE, 0, T_DISCON_REQ); 39157c478bd9Sstevel@tonic-gate freemsg(mp); 39167c478bd9Sstevel@tonic-gate return; 39177c478bd9Sstevel@tonic-gate } 39187c478bd9Sstevel@tonic-gate /* 39197c478bd9Sstevel@tonic-gate * Defer committing the state change until it is determined if 39207c478bd9Sstevel@tonic-gate * the message will be queued with the tl_icon or not. 39217c478bd9Sstevel@tonic-gate */ 39227c478bd9Sstevel@tonic-gate new_state = NEXTSTATE(TE_DISCON_REQ, tep->te_state); 39237c478bd9Sstevel@tonic-gate 39247c478bd9Sstevel@tonic-gate /* validate the message */ 39257c478bd9Sstevel@tonic-gate if (msz < sizeof (struct T_discon_req)) { 39267c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 39277c478bd9Sstevel@tonic-gate "tl_discon_req:invalid message")); 39287c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, new_state); 39297c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TSYSERR, EINVAL, T_DISCON_REQ); 39307c478bd9Sstevel@tonic-gate freemsg(mp); 39317c478bd9Sstevel@tonic-gate return; 39327c478bd9Sstevel@tonic-gate } 39337c478bd9Sstevel@tonic-gate 39347c478bd9Sstevel@tonic-gate /* 39357c478bd9Sstevel@tonic-gate * if server, then validate that client exists 39367c478bd9Sstevel@tonic-gate * by connection sequence number etc. 39377c478bd9Sstevel@tonic-gate */ 39387c478bd9Sstevel@tonic-gate if (tep->te_nicon > 0) { /* server */ 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate /* 39417c478bd9Sstevel@tonic-gate * search server list for disconnect client 39427c478bd9Sstevel@tonic-gate */ 39437c478bd9Sstevel@tonic-gate tip = tl_icon_find(tep, dr->SEQ_number); 39447c478bd9Sstevel@tonic-gate if (tip == NULL) { 39457c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, 39467c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 39477c478bd9Sstevel@tonic-gate "tl_discon_req:no disconnect endpoint")); 39487c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ERROR_ACK, new_state); 39497c478bd9Sstevel@tonic-gate tl_error_ack(wq, ackmp, TBADSEQ, 0, T_DISCON_REQ); 39507c478bd9Sstevel@tonic-gate freemsg(mp); 39517c478bd9Sstevel@tonic-gate return; 39527c478bd9Sstevel@tonic-gate } 39537c478bd9Sstevel@tonic-gate /* 39547c478bd9Sstevel@tonic-gate * If ti_tep is NULL the client has already closed. In this case 39557c478bd9Sstevel@tonic-gate * the code below will avoid any action on the client side. 39567c478bd9Sstevel@tonic-gate */ 39577c478bd9Sstevel@tonic-gate 395856f33205SJonathan Adams IMPLY(tip->ti_tep != NULL, 395956f33205SJonathan Adams tip->ti_tep->te_seqno == dr->SEQ_number); 39607c478bd9Sstevel@tonic-gate peer_tep = tip->ti_tep; 39617c478bd9Sstevel@tonic-gate } 39627c478bd9Sstevel@tonic-gate 39637c478bd9Sstevel@tonic-gate /* 39647c478bd9Sstevel@tonic-gate * preallocate now for T_DISCON_IND 39657c478bd9Sstevel@tonic-gate * ack validity of request (T_OK_ACK) after memory committed 39667c478bd9Sstevel@tonic-gate */ 39677c478bd9Sstevel@tonic-gate size = sizeof (struct T_discon_ind); 39687c478bd9Sstevel@tonic-gate if ((respmp = reallocb(mp, size, 0)) == NULL) { 39697c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, size); 39707c478bd9Sstevel@tonic-gate freemsg(ackmp); 39717c478bd9Sstevel@tonic-gate return; 39727c478bd9Sstevel@tonic-gate } 39737c478bd9Sstevel@tonic-gate 39747c478bd9Sstevel@tonic-gate /* 39757c478bd9Sstevel@tonic-gate * prepare message to ack validity of request 39767c478bd9Sstevel@tonic-gate */ 39777c478bd9Sstevel@tonic-gate if (tep->te_nicon == 0) 39787c478bd9Sstevel@tonic-gate new_state = NEXTSTATE(TE_OK_ACK1, new_state); 39797c478bd9Sstevel@tonic-gate else 39807c478bd9Sstevel@tonic-gate if (tep->te_nicon == 1) 39817c478bd9Sstevel@tonic-gate new_state = NEXTSTATE(TE_OK_ACK2, new_state); 39827c478bd9Sstevel@tonic-gate else 39837c478bd9Sstevel@tonic-gate new_state = NEXTSTATE(TE_OK_ACK4, new_state); 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate /* 39867c478bd9Sstevel@tonic-gate * Flushing queues according to TPI. Using the old state. 39877c478bd9Sstevel@tonic-gate */ 39887c478bd9Sstevel@tonic-gate if ((tep->te_nicon <= 1) && 39897c478bd9Sstevel@tonic-gate ((save_state == TS_DATA_XFER) || 39907c478bd9Sstevel@tonic-gate (save_state == TS_WIND_ORDREL) || 39917c478bd9Sstevel@tonic-gate (save_state == TS_WREQ_ORDREL))) 39927c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(wq), M_FLUSH, FLUSHRW); 39937c478bd9Sstevel@tonic-gate 39947c478bd9Sstevel@tonic-gate /* send T_OK_ACK up */ 39957c478bd9Sstevel@tonic-gate tl_ok_ack(wq, ackmp, T_DISCON_REQ); 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate /* 39987c478bd9Sstevel@tonic-gate * now do disconnect business 39997c478bd9Sstevel@tonic-gate */ 40007c478bd9Sstevel@tonic-gate if (tep->te_nicon > 0) { /* listener */ 40017c478bd9Sstevel@tonic-gate if (peer_tep != NULL && !peer_tep->te_closing) { 40027c478bd9Sstevel@tonic-gate /* 40037c478bd9Sstevel@tonic-gate * disconnect incoming connect request pending to tep 40047c478bd9Sstevel@tonic-gate */ 40057c478bd9Sstevel@tonic-gate if ((dimp = tl_resizemp(respmp, size)) == NULL) { 40067c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, 40077c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 40087c478bd9Sstevel@tonic-gate "tl_discon_req: reallocb failed")); 40097c478bd9Sstevel@tonic-gate tep->te_state = new_state; 40107c478bd9Sstevel@tonic-gate tl_merror(wq, respmp, ENOMEM); 40117c478bd9Sstevel@tonic-gate return; 40127c478bd9Sstevel@tonic-gate } 40137c478bd9Sstevel@tonic-gate di = (struct T_discon_ind *)dimp->b_rptr; 40147c478bd9Sstevel@tonic-gate di->SEQ_number = BADSEQNUM; 40157c478bd9Sstevel@tonic-gate save_state = peer_tep->te_state; 40167c478bd9Sstevel@tonic-gate peer_tep->te_state = TS_IDLE; 40177c478bd9Sstevel@tonic-gate 40187c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(peer_tep->te_oconp); 40197c478bd9Sstevel@tonic-gate enableok(peer_tep->te_wq); 40207c478bd9Sstevel@tonic-gate TL_QENABLE(peer_tep); 40217c478bd9Sstevel@tonic-gate } else { 40227c478bd9Sstevel@tonic-gate freemsg(respmp); 40237c478bd9Sstevel@tonic-gate dimp = NULL; 40247c478bd9Sstevel@tonic-gate } 40257c478bd9Sstevel@tonic-gate 40267c478bd9Sstevel@tonic-gate /* 40277c478bd9Sstevel@tonic-gate * remove endpoint from incoming connection list 40287c478bd9Sstevel@tonic-gate * - remove disconnect client from list on server 40297c478bd9Sstevel@tonic-gate */ 40307c478bd9Sstevel@tonic-gate tl_freetip(tep, tip); 40317c478bd9Sstevel@tonic-gate } else if ((peer_tep = tep->te_oconp) != NULL) { /* client */ 40327c478bd9Sstevel@tonic-gate /* 40337c478bd9Sstevel@tonic-gate * disconnect an outgoing request pending from tep 40347c478bd9Sstevel@tonic-gate */ 40357c478bd9Sstevel@tonic-gate 40367c478bd9Sstevel@tonic-gate if ((dimp = tl_resizemp(respmp, size)) == NULL) { 40377c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, 40387c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 40397c478bd9Sstevel@tonic-gate "tl_discon_req: reallocb failed")); 40407c478bd9Sstevel@tonic-gate tep->te_state = new_state; 40417c478bd9Sstevel@tonic-gate tl_merror(wq, respmp, ENOMEM); 40427c478bd9Sstevel@tonic-gate return; 40437c478bd9Sstevel@tonic-gate } 40447c478bd9Sstevel@tonic-gate di = (struct T_discon_ind *)dimp->b_rptr; 40457c478bd9Sstevel@tonic-gate DB_TYPE(dimp) = M_PROTO; 40467c478bd9Sstevel@tonic-gate di->PRIM_type = T_DISCON_IND; 40477c478bd9Sstevel@tonic-gate di->DISCON_reason = ECONNRESET; 40487c478bd9Sstevel@tonic-gate di->SEQ_number = tep->te_seqno; 40497c478bd9Sstevel@tonic-gate 40507c478bd9Sstevel@tonic-gate /* 40517c478bd9Sstevel@tonic-gate * If this is a socket the T_DISCON_IND is queued with 40527c478bd9Sstevel@tonic-gate * the T_CONN_IND. Otherwise the T_CONN_IND is removed 40537c478bd9Sstevel@tonic-gate * from the list of pending connections. 40547c478bd9Sstevel@tonic-gate * Note that when te_oconp is set the peer better have 40557c478bd9Sstevel@tonic-gate * a t_connind_t for the client. 40567c478bd9Sstevel@tonic-gate */ 40577c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep) && !tl_disable_early_connect) { 40587c478bd9Sstevel@tonic-gate /* 40597c478bd9Sstevel@tonic-gate * No need to check that 40607c478bd9Sstevel@tonic-gate * ti_tep == NULL since the T_DISCON_IND 40617c478bd9Sstevel@tonic-gate * takes precedence over other queued 40627c478bd9Sstevel@tonic-gate * messages. 40637c478bd9Sstevel@tonic-gate */ 40647c478bd9Sstevel@tonic-gate tl_icon_queuemsg(peer_tep, tep->te_seqno, dimp); 40657c478bd9Sstevel@tonic-gate peer_tep = NULL; 40667c478bd9Sstevel@tonic-gate dimp = NULL; 40677c478bd9Sstevel@tonic-gate /* 40687c478bd9Sstevel@tonic-gate * Can't clear te_oconp since tl_co_unconnect needs 40697c478bd9Sstevel@tonic-gate * it as a hint not to free the tep. 40707c478bd9Sstevel@tonic-gate * Keep the state unchanged since tl_conn_res inspects 40717c478bd9Sstevel@tonic-gate * it. 40727c478bd9Sstevel@tonic-gate */ 40737c478bd9Sstevel@tonic-gate new_state = tep->te_state; 40747c478bd9Sstevel@tonic-gate } else { 40757c478bd9Sstevel@tonic-gate /* Found - delete it */ 40767c478bd9Sstevel@tonic-gate tip = tl_icon_find(peer_tep, tep->te_seqno); 40777c478bd9Sstevel@tonic-gate if (tip != NULL) { 40787c478bd9Sstevel@tonic-gate ASSERT(tep == tip->ti_tep); 40797c478bd9Sstevel@tonic-gate save_state = peer_tep->te_state; 40807c478bd9Sstevel@tonic-gate if (peer_tep->te_nicon == 1) 40817c478bd9Sstevel@tonic-gate peer_tep->te_state = 40827c478bd9Sstevel@tonic-gate NEXTSTATE(TE_DISCON_IND2, 40837c478bd9Sstevel@tonic-gate peer_tep->te_state); 40847c478bd9Sstevel@tonic-gate else 40857c478bd9Sstevel@tonic-gate peer_tep->te_state = 40867c478bd9Sstevel@tonic-gate NEXTSTATE(TE_DISCON_IND3, 40877c478bd9Sstevel@tonic-gate peer_tep->te_state); 40887c478bd9Sstevel@tonic-gate tl_freetip(peer_tep, tip); 40897c478bd9Sstevel@tonic-gate } 40907c478bd9Sstevel@tonic-gate ASSERT(tep->te_oconp != NULL); 40917c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 40927c478bd9Sstevel@tonic-gate } 40937c478bd9Sstevel@tonic-gate } else if ((peer_tep = tep->te_conp) != NULL) { /* connected! */ 40947c478bd9Sstevel@tonic-gate if ((dimp = tl_resizemp(respmp, size)) == NULL) { 40957c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, 40967c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 40977c478bd9Sstevel@tonic-gate "tl_discon_req: reallocb failed")); 40987c478bd9Sstevel@tonic-gate tep->te_state = new_state; 40997c478bd9Sstevel@tonic-gate tl_merror(wq, respmp, ENOMEM); 41007c478bd9Sstevel@tonic-gate return; 41017c478bd9Sstevel@tonic-gate } 41027c478bd9Sstevel@tonic-gate di = (struct T_discon_ind *)dimp->b_rptr; 41037c478bd9Sstevel@tonic-gate di->SEQ_number = BADSEQNUM; 41047c478bd9Sstevel@tonic-gate 41057c478bd9Sstevel@tonic-gate save_state = peer_tep->te_state; 41067c478bd9Sstevel@tonic-gate peer_tep->te_state = TS_IDLE; 41077c478bd9Sstevel@tonic-gate } else { 41087c478bd9Sstevel@tonic-gate /* Not connected */ 41097c478bd9Sstevel@tonic-gate tep->te_state = new_state; 41107c478bd9Sstevel@tonic-gate freemsg(respmp); 41117c478bd9Sstevel@tonic-gate return; 41127c478bd9Sstevel@tonic-gate } 41137c478bd9Sstevel@tonic-gate 41147c478bd9Sstevel@tonic-gate /* Commit state changes */ 41157c478bd9Sstevel@tonic-gate tep->te_state = new_state; 41167c478bd9Sstevel@tonic-gate 41177c478bd9Sstevel@tonic-gate if (peer_tep == NULL) { 41187c478bd9Sstevel@tonic-gate ASSERT(dimp == NULL); 41197c478bd9Sstevel@tonic-gate goto done; 41207c478bd9Sstevel@tonic-gate } 41217c478bd9Sstevel@tonic-gate /* 41227c478bd9Sstevel@tonic-gate * Flush queues on peer before sending up 41237c478bd9Sstevel@tonic-gate * T_DISCON_IND according to TPI 41247c478bd9Sstevel@tonic-gate */ 41257c478bd9Sstevel@tonic-gate 41267c478bd9Sstevel@tonic-gate if ((save_state == TS_DATA_XFER) || 41277c478bd9Sstevel@tonic-gate (save_state == TS_WIND_ORDREL) || 41287c478bd9Sstevel@tonic-gate (save_state == TS_WREQ_ORDREL)) 41297c478bd9Sstevel@tonic-gate (void) putnextctl1(peer_tep->te_rq, M_FLUSH, FLUSHRW); 41307c478bd9Sstevel@tonic-gate 41317c478bd9Sstevel@tonic-gate DB_TYPE(dimp) = M_PROTO; 41327c478bd9Sstevel@tonic-gate di->PRIM_type = T_DISCON_IND; 41337c478bd9Sstevel@tonic-gate di->DISCON_reason = ECONNRESET; 41347c478bd9Sstevel@tonic-gate 41357c478bd9Sstevel@tonic-gate /* 41367c478bd9Sstevel@tonic-gate * data blocks already linked into dimp by reallocb() 41377c478bd9Sstevel@tonic-gate */ 41387c478bd9Sstevel@tonic-gate /* 41397c478bd9Sstevel@tonic-gate * send indication message to peer user module 41407c478bd9Sstevel@tonic-gate */ 41417c478bd9Sstevel@tonic-gate ASSERT(dimp != NULL); 41427c478bd9Sstevel@tonic-gate putnext(peer_tep->te_rq, dimp); 41437c478bd9Sstevel@tonic-gate done: 41447c478bd9Sstevel@tonic-gate if (tep->te_conp) { /* disconnect pointers if connected */ 41457c478bd9Sstevel@tonic-gate ASSERT(! peer_tep->te_closing); 41467c478bd9Sstevel@tonic-gate 41477c478bd9Sstevel@tonic-gate /* 41487c478bd9Sstevel@tonic-gate * Messages may be queued on peer's write queue 41497c478bd9Sstevel@tonic-gate * waiting to be processed by its write service 41507c478bd9Sstevel@tonic-gate * procedure. Before the pointer to the peer transport 41517c478bd9Sstevel@tonic-gate * structure is set to NULL, qenable the peer's write 41527c478bd9Sstevel@tonic-gate * queue so that the queued up messages are processed. 41537c478bd9Sstevel@tonic-gate */ 41547c478bd9Sstevel@tonic-gate if ((save_state == TS_DATA_XFER) || 41557c478bd9Sstevel@tonic-gate (save_state == TS_WIND_ORDREL) || 41567c478bd9Sstevel@tonic-gate (save_state == TS_WREQ_ORDREL)) 41577c478bd9Sstevel@tonic-gate TL_QENABLE(peer_tep); 41587c478bd9Sstevel@tonic-gate ASSERT(peer_tep != NULL && peer_tep->te_conp != NULL); 41597c478bd9Sstevel@tonic-gate TL_UNCONNECT(peer_tep->te_conp); 41607c478bd9Sstevel@tonic-gate if (! IS_SOCKET(tep)) { 41617c478bd9Sstevel@tonic-gate /* 41627c478bd9Sstevel@tonic-gate * unlink the streams 41637c478bd9Sstevel@tonic-gate */ 41647c478bd9Sstevel@tonic-gate tep->te_wq->q_next = NULL; 41657c478bd9Sstevel@tonic-gate peer_tep->te_wq->q_next = NULL; 41667c478bd9Sstevel@tonic-gate } 41677c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_conp); 41687c478bd9Sstevel@tonic-gate } 41697c478bd9Sstevel@tonic-gate } 41707c478bd9Sstevel@tonic-gate 4171b2d8fb89SDan Kruchinin static void 4172b2d8fb89SDan Kruchinin tl_addr_req_ser(mblk_t *mp, tl_endpt_t *tep) 4173b2d8fb89SDan Kruchinin { 4174b2d8fb89SDan Kruchinin if (!tep->te_closing) 4175b2d8fb89SDan Kruchinin tl_addr_req(mp, tep); 4176b2d8fb89SDan Kruchinin else 4177b2d8fb89SDan Kruchinin freemsg(mp); 4178b2d8fb89SDan Kruchinin 4179b2d8fb89SDan Kruchinin tl_serializer_exit(tep); 4180b2d8fb89SDan Kruchinin tl_refrele(tep); 4181b2d8fb89SDan Kruchinin } 41827c478bd9Sstevel@tonic-gate 41837c478bd9Sstevel@tonic-gate static void 41847c478bd9Sstevel@tonic-gate tl_addr_req(mblk_t *mp, tl_endpt_t *tep) 41857c478bd9Sstevel@tonic-gate { 41867c478bd9Sstevel@tonic-gate queue_t *wq; 41877c478bd9Sstevel@tonic-gate size_t ack_sz; 41887c478bd9Sstevel@tonic-gate mblk_t *ackmp; 41897c478bd9Sstevel@tonic-gate struct T_addr_ack *taa; 41907c478bd9Sstevel@tonic-gate 41917c478bd9Sstevel@tonic-gate if (tep->te_closing) { 41927c478bd9Sstevel@tonic-gate freemsg(mp); 41937c478bd9Sstevel@tonic-gate return; 41947c478bd9Sstevel@tonic-gate } 41957c478bd9Sstevel@tonic-gate 41967c478bd9Sstevel@tonic-gate wq = tep->te_wq; 41977c478bd9Sstevel@tonic-gate 41987c478bd9Sstevel@tonic-gate /* 41997c478bd9Sstevel@tonic-gate * Note: T_ADDR_REQ message has only PRIM_type field 42007c478bd9Sstevel@tonic-gate * so it is already validated earlier. 42017c478bd9Sstevel@tonic-gate */ 42027c478bd9Sstevel@tonic-gate 42037c478bd9Sstevel@tonic-gate if (IS_CLTS(tep) || 42047c478bd9Sstevel@tonic-gate (tep->te_state > TS_WREQ_ORDREL) || 42057c478bd9Sstevel@tonic-gate (tep->te_state < TS_DATA_XFER)) { 42067c478bd9Sstevel@tonic-gate /* 42077c478bd9Sstevel@tonic-gate * Either connectionless or connection oriented but not 42087c478bd9Sstevel@tonic-gate * in connected data transfer state or half-closed states. 42097c478bd9Sstevel@tonic-gate */ 42107c478bd9Sstevel@tonic-gate ack_sz = sizeof (struct T_addr_ack); 42117c478bd9Sstevel@tonic-gate if (tep->te_state >= TS_IDLE) 42127c478bd9Sstevel@tonic-gate /* is bound */ 42137c478bd9Sstevel@tonic-gate ack_sz += tep->te_alen; 42147c478bd9Sstevel@tonic-gate ackmp = reallocb(mp, ack_sz, 0); 42157c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 42167c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 42177c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 42187c478bd9Sstevel@tonic-gate "tl_addr_req: reallocb failed")); 42197c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, ack_sz); 42207c478bd9Sstevel@tonic-gate return; 42217c478bd9Sstevel@tonic-gate } 42227c478bd9Sstevel@tonic-gate 42237c478bd9Sstevel@tonic-gate taa = (struct T_addr_ack *)ackmp->b_rptr; 42247c478bd9Sstevel@tonic-gate 42257c478bd9Sstevel@tonic-gate bzero(taa, sizeof (struct T_addr_ack)); 42267c478bd9Sstevel@tonic-gate 42277c478bd9Sstevel@tonic-gate taa->PRIM_type = T_ADDR_ACK; 42287c478bd9Sstevel@tonic-gate ackmp->b_datap->db_type = M_PCPROTO; 42297c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&taa[1]; 42307c478bd9Sstevel@tonic-gate 42317c478bd9Sstevel@tonic-gate if (tep->te_state >= TS_IDLE) { 42327c478bd9Sstevel@tonic-gate /* endpoint is bound */ 42337c478bd9Sstevel@tonic-gate taa->LOCADDR_length = tep->te_alen; 42347c478bd9Sstevel@tonic-gate taa->LOCADDR_offset = (t_scalar_t)sizeof (*taa); 42357c478bd9Sstevel@tonic-gate 42367c478bd9Sstevel@tonic-gate bcopy(tep->te_abuf, ackmp->b_wptr, 42377c478bd9Sstevel@tonic-gate tep->te_alen); 42387c478bd9Sstevel@tonic-gate ackmp->b_wptr += tep->te_alen; 42397c478bd9Sstevel@tonic-gate ASSERT(ackmp->b_wptr <= ackmp->b_datap->db_lim); 42407c478bd9Sstevel@tonic-gate } 42417c478bd9Sstevel@tonic-gate 42427c478bd9Sstevel@tonic-gate (void) qreply(wq, ackmp); 42437c478bd9Sstevel@tonic-gate } else { 42447c478bd9Sstevel@tonic-gate ASSERT(tep->te_state == TS_DATA_XFER || 42457c478bd9Sstevel@tonic-gate tep->te_state == TS_WIND_ORDREL || 42467c478bd9Sstevel@tonic-gate tep->te_state == TS_WREQ_ORDREL); 42477c478bd9Sstevel@tonic-gate /* connection oriented in data transfer */ 42487c478bd9Sstevel@tonic-gate tl_connected_cots_addr_req(mp, tep); 42497c478bd9Sstevel@tonic-gate } 42507c478bd9Sstevel@tonic-gate } 42517c478bd9Sstevel@tonic-gate 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate static void 42547c478bd9Sstevel@tonic-gate tl_connected_cots_addr_req(mblk_t *mp, tl_endpt_t *tep) 42557c478bd9Sstevel@tonic-gate { 4256bbaa8b60SDan Kruchinin tl_endpt_t *peer_tep = tep->te_conp; 42577c478bd9Sstevel@tonic-gate size_t ack_sz; 42587c478bd9Sstevel@tonic-gate mblk_t *ackmp; 42597c478bd9Sstevel@tonic-gate struct T_addr_ack *taa; 42607c478bd9Sstevel@tonic-gate uchar_t *addr_startp; 42617c478bd9Sstevel@tonic-gate 42627c478bd9Sstevel@tonic-gate if (tep->te_closing) { 42637c478bd9Sstevel@tonic-gate freemsg(mp); 42647c478bd9Sstevel@tonic-gate return; 42657c478bd9Sstevel@tonic-gate } 42667c478bd9Sstevel@tonic-gate 4267bbaa8b60SDan Kruchinin if (peer_tep == NULL || peer_tep->te_closing) { 4268bbaa8b60SDan Kruchinin tl_error_ack(tep->te_wq, mp, TSYSERR, ECONNRESET, T_ADDR_REQ); 4269bbaa8b60SDan Kruchinin return; 4270bbaa8b60SDan Kruchinin } 4271bbaa8b60SDan Kruchinin 42727c478bd9Sstevel@tonic-gate ASSERT(tep->te_state >= TS_IDLE); 42737c478bd9Sstevel@tonic-gate 42747c478bd9Sstevel@tonic-gate ack_sz = sizeof (struct T_addr_ack); 42757c478bd9Sstevel@tonic-gate ack_sz += T_ALIGN(tep->te_alen); 42767c478bd9Sstevel@tonic-gate ack_sz += peer_tep->te_alen; 42777c478bd9Sstevel@tonic-gate 42787c478bd9Sstevel@tonic-gate ackmp = tpi_ack_alloc(mp, ack_sz, M_PCPROTO, T_ADDR_ACK); 42797c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 42807c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 42817c478bd9Sstevel@tonic-gate "tl_connected_cots_addr_req: reallocb failed")); 42827c478bd9Sstevel@tonic-gate tl_memrecover(tep->te_wq, mp, ack_sz); 42837c478bd9Sstevel@tonic-gate return; 42847c478bd9Sstevel@tonic-gate } 42857c478bd9Sstevel@tonic-gate 42867c478bd9Sstevel@tonic-gate taa = (struct T_addr_ack *)ackmp->b_rptr; 42877c478bd9Sstevel@tonic-gate 42887c478bd9Sstevel@tonic-gate /* endpoint is bound */ 42897c478bd9Sstevel@tonic-gate taa->LOCADDR_length = tep->te_alen; 42907c478bd9Sstevel@tonic-gate taa->LOCADDR_offset = (t_scalar_t)sizeof (*taa); 42917c478bd9Sstevel@tonic-gate 42927c478bd9Sstevel@tonic-gate addr_startp = (uchar_t *)&taa[1]; 42937c478bd9Sstevel@tonic-gate 42947c478bd9Sstevel@tonic-gate bcopy(tep->te_abuf, addr_startp, 42957c478bd9Sstevel@tonic-gate tep->te_alen); 42967c478bd9Sstevel@tonic-gate 42977c478bd9Sstevel@tonic-gate taa->REMADDR_length = peer_tep->te_alen; 42987c478bd9Sstevel@tonic-gate taa->REMADDR_offset = (t_scalar_t)T_ALIGN(taa->LOCADDR_offset + 42997c478bd9Sstevel@tonic-gate taa->LOCADDR_length); 43007c478bd9Sstevel@tonic-gate addr_startp = ackmp->b_rptr + taa->REMADDR_offset; 43017c478bd9Sstevel@tonic-gate bcopy(peer_tep->te_abuf, addr_startp, 43027c478bd9Sstevel@tonic-gate peer_tep->te_alen); 43037c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)ackmp->b_rptr + 43047c478bd9Sstevel@tonic-gate taa->REMADDR_offset + peer_tep->te_alen; 43057c478bd9Sstevel@tonic-gate ASSERT(ackmp->b_wptr <= ackmp->b_datap->db_lim); 43067c478bd9Sstevel@tonic-gate 43077c478bd9Sstevel@tonic-gate putnext(tep->te_rq, ackmp); 43087c478bd9Sstevel@tonic-gate } 43097c478bd9Sstevel@tonic-gate 43107c478bd9Sstevel@tonic-gate static void 43117c478bd9Sstevel@tonic-gate tl_copy_info(struct T_info_ack *ia, tl_endpt_t *tep) 43127c478bd9Sstevel@tonic-gate { 43137c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 43147c478bd9Sstevel@tonic-gate *ia = tl_clts_info_ack; 43157c478bd9Sstevel@tonic-gate ia->TSDU_size = tl_tidusz; /* TSDU and TIDU size are same */ 43167c478bd9Sstevel@tonic-gate } else { 43177c478bd9Sstevel@tonic-gate *ia = tl_cots_info_ack; 43187c478bd9Sstevel@tonic-gate if (IS_COTSORD(tep)) 43197c478bd9Sstevel@tonic-gate ia->SERV_type = T_COTS_ORD; 43207c478bd9Sstevel@tonic-gate } 43217c478bd9Sstevel@tonic-gate ia->TIDU_size = tl_tidusz; 43227c478bd9Sstevel@tonic-gate ia->CURRENT_state = tep->te_state; 43237c478bd9Sstevel@tonic-gate } 43247c478bd9Sstevel@tonic-gate 43257c478bd9Sstevel@tonic-gate /* 43267c478bd9Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 43277c478bd9Sstevel@tonic-gate * tl_wput. 43287c478bd9Sstevel@tonic-gate */ 43297c478bd9Sstevel@tonic-gate static void 43307c478bd9Sstevel@tonic-gate tl_capability_req(mblk_t *mp, tl_endpt_t *tep) 43317c478bd9Sstevel@tonic-gate { 43327c478bd9Sstevel@tonic-gate mblk_t *ackmp; 43337c478bd9Sstevel@tonic-gate t_uscalar_t cap_bits1; 43347c478bd9Sstevel@tonic-gate struct T_capability_ack *tcap; 43357c478bd9Sstevel@tonic-gate 43367c478bd9Sstevel@tonic-gate if (tep->te_closing) { 43377c478bd9Sstevel@tonic-gate freemsg(mp); 43387c478bd9Sstevel@tonic-gate return; 43397c478bd9Sstevel@tonic-gate } 43407c478bd9Sstevel@tonic-gate 43417c478bd9Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate ackmp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 43447c478bd9Sstevel@tonic-gate M_PCPROTO, T_CAPABILITY_ACK); 43457c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 43467c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 43477c478bd9Sstevel@tonic-gate "tl_capability_req: reallocb failed")); 43487c478bd9Sstevel@tonic-gate tl_memrecover(tep->te_wq, mp, 43497c478bd9Sstevel@tonic-gate sizeof (struct T_capability_ack)); 43507c478bd9Sstevel@tonic-gate return; 43517c478bd9Sstevel@tonic-gate } 43527c478bd9Sstevel@tonic-gate 43537c478bd9Sstevel@tonic-gate tcap = (struct T_capability_ack *)ackmp->b_rptr; 43547c478bd9Sstevel@tonic-gate tcap->CAP_bits1 = 0; 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 43577c478bd9Sstevel@tonic-gate tl_copy_info(&tcap->INFO_ack, tep); 43587c478bd9Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 43597c478bd9Sstevel@tonic-gate } 43607c478bd9Sstevel@tonic-gate 43617c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_ACCEPTOR_ID) { 43627c478bd9Sstevel@tonic-gate tcap->ACCEPTOR_id = tep->te_acceptor_id; 43637c478bd9Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_ACCEPTOR_ID; 43647c478bd9Sstevel@tonic-gate } 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate putnext(tep->te_rq, ackmp); 43677c478bd9Sstevel@tonic-gate } 43687c478bd9Sstevel@tonic-gate 43697c478bd9Sstevel@tonic-gate static void 43707c478bd9Sstevel@tonic-gate tl_info_req_ser(mblk_t *mp, tl_endpt_t *tep) 43717c478bd9Sstevel@tonic-gate { 43727c478bd9Sstevel@tonic-gate if (! tep->te_closing) 43737c478bd9Sstevel@tonic-gate tl_info_req(mp, tep); 43747c478bd9Sstevel@tonic-gate else 43757c478bd9Sstevel@tonic-gate freemsg(mp); 43767c478bd9Sstevel@tonic-gate 43777c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 43787c478bd9Sstevel@tonic-gate tl_refrele(tep); 43797c478bd9Sstevel@tonic-gate } 43807c478bd9Sstevel@tonic-gate 43817c478bd9Sstevel@tonic-gate static void 43827c478bd9Sstevel@tonic-gate tl_info_req(mblk_t *mp, tl_endpt_t *tep) 43837c478bd9Sstevel@tonic-gate { 43847c478bd9Sstevel@tonic-gate mblk_t *ackmp; 43857c478bd9Sstevel@tonic-gate 43867c478bd9Sstevel@tonic-gate ackmp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), 43877c478bd9Sstevel@tonic-gate M_PCPROTO, T_INFO_ACK); 43887c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 43897c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 43907c478bd9Sstevel@tonic-gate "tl_info_req: reallocb failed")); 43917c478bd9Sstevel@tonic-gate tl_memrecover(tep->te_wq, mp, sizeof (struct T_info_ack)); 43927c478bd9Sstevel@tonic-gate return; 43937c478bd9Sstevel@tonic-gate } 43947c478bd9Sstevel@tonic-gate 43957c478bd9Sstevel@tonic-gate /* 43967c478bd9Sstevel@tonic-gate * fill in T_INFO_ACK contents 43977c478bd9Sstevel@tonic-gate */ 43987c478bd9Sstevel@tonic-gate tl_copy_info((struct T_info_ack *)ackmp->b_rptr, tep); 43997c478bd9Sstevel@tonic-gate 44007c478bd9Sstevel@tonic-gate /* 44017c478bd9Sstevel@tonic-gate * send ack message 44027c478bd9Sstevel@tonic-gate */ 44037c478bd9Sstevel@tonic-gate putnext(tep->te_rq, ackmp); 44047c478bd9Sstevel@tonic-gate } 44057c478bd9Sstevel@tonic-gate 44067c478bd9Sstevel@tonic-gate /* 44077c478bd9Sstevel@tonic-gate * Handle M_DATA, T_data_req and T_optdata_req. 44087c478bd9Sstevel@tonic-gate * If this is a socket pass through T_optdata_req options unmodified. 44097c478bd9Sstevel@tonic-gate */ 44107c478bd9Sstevel@tonic-gate static void 44117c478bd9Sstevel@tonic-gate tl_data(mblk_t *mp, tl_endpt_t *tep) 44127c478bd9Sstevel@tonic-gate { 44137c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 44147c478bd9Sstevel@tonic-gate union T_primitives *prim = (union T_primitives *)mp->b_rptr; 44157c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp); 44167c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep; 44177c478bd9Sstevel@tonic-gate queue_t *peer_rq; 44187c478bd9Sstevel@tonic-gate boolean_t closing = tep->te_closing; 44197c478bd9Sstevel@tonic-gate 44207c478bd9Sstevel@tonic-gate if (IS_CLTS(tep)) { 44217c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 2, 44227c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 44237c478bd9Sstevel@tonic-gate "tl_wput:clts:unattached M_DATA")); 44247c478bd9Sstevel@tonic-gate if (!closing) { 44257c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 44267c478bd9Sstevel@tonic-gate } else { 44277c478bd9Sstevel@tonic-gate freemsg(mp); 44287c478bd9Sstevel@tonic-gate } 44297c478bd9Sstevel@tonic-gate return; 44307c478bd9Sstevel@tonic-gate } 44317c478bd9Sstevel@tonic-gate 44327c478bd9Sstevel@tonic-gate /* 44337c478bd9Sstevel@tonic-gate * If the endpoint is closing it should still forward any data to the 44347c478bd9Sstevel@tonic-gate * peer (if it has one). If it is not allowed to forward it can just 44357c478bd9Sstevel@tonic-gate * free the message. 44367c478bd9Sstevel@tonic-gate */ 44377c478bd9Sstevel@tonic-gate if (closing && 44387c478bd9Sstevel@tonic-gate (tep->te_state != TS_DATA_XFER) && 44397c478bd9Sstevel@tonic-gate (tep->te_state != TS_WREQ_ORDREL)) { 44407c478bd9Sstevel@tonic-gate freemsg(mp); 44417c478bd9Sstevel@tonic-gate return; 44427c478bd9Sstevel@tonic-gate } 44437c478bd9Sstevel@tonic-gate 44447c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_PROTO) { 44457c478bd9Sstevel@tonic-gate if (prim->type == T_DATA_REQ && 44467c478bd9Sstevel@tonic-gate msz < sizeof (struct T_data_req)) { 44477c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 44487c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 44497c478bd9Sstevel@tonic-gate "tl_data:T_DATA_REQ:invalid message")); 44507c478bd9Sstevel@tonic-gate if (!closing) { 44517c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 44527c478bd9Sstevel@tonic-gate } else { 44537c478bd9Sstevel@tonic-gate freemsg(mp); 44547c478bd9Sstevel@tonic-gate } 44557c478bd9Sstevel@tonic-gate return; 44567c478bd9Sstevel@tonic-gate } else if (prim->type == T_OPTDATA_REQ && 445719397407SSherry Moore (msz < sizeof (struct T_optdata_req) || !IS_SOCKET(tep))) { 44587c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 44597c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 44607c478bd9Sstevel@tonic-gate "tl_data:T_OPTDATA_REQ:invalid message")); 44617c478bd9Sstevel@tonic-gate if (!closing) { 44627c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 44637c478bd9Sstevel@tonic-gate } else { 44647c478bd9Sstevel@tonic-gate freemsg(mp); 44657c478bd9Sstevel@tonic-gate } 44667c478bd9Sstevel@tonic-gate return; 44677c478bd9Sstevel@tonic-gate } 44687c478bd9Sstevel@tonic-gate } 44697c478bd9Sstevel@tonic-gate 44707c478bd9Sstevel@tonic-gate /* 44717c478bd9Sstevel@tonic-gate * connection oriented provider 44727c478bd9Sstevel@tonic-gate */ 44737c478bd9Sstevel@tonic-gate switch (tep->te_state) { 44747c478bd9Sstevel@tonic-gate case TS_IDLE: 44757c478bd9Sstevel@tonic-gate /* 44767c478bd9Sstevel@tonic-gate * Other end not here - do nothing. 44777c478bd9Sstevel@tonic-gate */ 44787c478bd9Sstevel@tonic-gate freemsg(mp); 44797c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 44807c478bd9Sstevel@tonic-gate "tl_data:cots with endpoint idle")); 44817c478bd9Sstevel@tonic-gate return; 44827c478bd9Sstevel@tonic-gate 44837c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 44847c478bd9Sstevel@tonic-gate /* valid states */ 44857c478bd9Sstevel@tonic-gate if (tep->te_conp != NULL) 44867c478bd9Sstevel@tonic-gate break; 44877c478bd9Sstevel@tonic-gate 44887c478bd9Sstevel@tonic-gate if (tep->te_oconp == NULL) { 44897c478bd9Sstevel@tonic-gate if (!closing) { 44907c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 44917c478bd9Sstevel@tonic-gate } else { 44927c478bd9Sstevel@tonic-gate freemsg(mp); 44937c478bd9Sstevel@tonic-gate } 44947c478bd9Sstevel@tonic-gate return; 44957c478bd9Sstevel@tonic-gate } 44967c478bd9Sstevel@tonic-gate /* 44977c478bd9Sstevel@tonic-gate * For a socket the T_CONN_CON is sent early thus 44987c478bd9Sstevel@tonic-gate * the peer might not yet have accepted the connection. 44997c478bd9Sstevel@tonic-gate * If we are closing queue the packet with the T_CONN_IND. 45007c478bd9Sstevel@tonic-gate * Otherwise defer processing the packet until the peer 45017c478bd9Sstevel@tonic-gate * accepts the connection. 45027c478bd9Sstevel@tonic-gate * Note that the queue is noenabled when we go into this 45037c478bd9Sstevel@tonic-gate * state. 45047c478bd9Sstevel@tonic-gate */ 45057c478bd9Sstevel@tonic-gate if (!closing) { 45067c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 45077c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 45087c478bd9Sstevel@tonic-gate "tl_data: ocon")); 45097c478bd9Sstevel@tonic-gate TL_PUTBQ(tep, mp); 45107c478bd9Sstevel@tonic-gate return; 45117c478bd9Sstevel@tonic-gate } 45127c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_PROTO) { 45137c478bd9Sstevel@tonic-gate if (msz < sizeof (t_scalar_t)) { 45147c478bd9Sstevel@tonic-gate freemsg(mp); 45157c478bd9Sstevel@tonic-gate return; 45167c478bd9Sstevel@tonic-gate } 45177c478bd9Sstevel@tonic-gate /* reuse message block - just change REQ to IND */ 45187c478bd9Sstevel@tonic-gate if (prim->type == T_DATA_REQ) 45197c478bd9Sstevel@tonic-gate prim->type = T_DATA_IND; 45207c478bd9Sstevel@tonic-gate else 45217c478bd9Sstevel@tonic-gate prim->type = T_OPTDATA_IND; 45227c478bd9Sstevel@tonic-gate } 45237c478bd9Sstevel@tonic-gate tl_icon_queuemsg(tep->te_oconp, tep->te_seqno, mp); 45247c478bd9Sstevel@tonic-gate return; 45257c478bd9Sstevel@tonic-gate 45267c478bd9Sstevel@tonic-gate case TS_WREQ_ORDREL: 45277c478bd9Sstevel@tonic-gate if (tep->te_conp == NULL) { 45287c478bd9Sstevel@tonic-gate /* 45297c478bd9Sstevel@tonic-gate * Other end closed - generate discon_ind 45307c478bd9Sstevel@tonic-gate * with reason 0 to cause an EPIPE but no 45317c478bd9Sstevel@tonic-gate * read side error on AF_UNIX sockets. 45327c478bd9Sstevel@tonic-gate */ 45337c478bd9Sstevel@tonic-gate freemsg(mp); 45347c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 45357c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 45367c478bd9Sstevel@tonic-gate "tl_data: WREQ_ORDREL and no peer")); 45377c478bd9Sstevel@tonic-gate tl_discon_ind(tep, 0); 45387c478bd9Sstevel@tonic-gate return; 45397c478bd9Sstevel@tonic-gate } 45407c478bd9Sstevel@tonic-gate break; 45417c478bd9Sstevel@tonic-gate 45427c478bd9Sstevel@tonic-gate default: 45437c478bd9Sstevel@tonic-gate /* invalid state for event TE_DATA_REQ */ 45447c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 45457c478bd9Sstevel@tonic-gate "tl_data:cots:out of state")); 45467c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 45477c478bd9Sstevel@tonic-gate return; 45487c478bd9Sstevel@tonic-gate } 45497c478bd9Sstevel@tonic-gate /* 45507c478bd9Sstevel@tonic-gate * tep->te_state = NEXTSTATE(TE_DATA_REQ, tep->te_state); 45517c478bd9Sstevel@tonic-gate * (State stays same on this event) 45527c478bd9Sstevel@tonic-gate */ 45537c478bd9Sstevel@tonic-gate 45547c478bd9Sstevel@tonic-gate /* 45557c478bd9Sstevel@tonic-gate * get connected endpoint 45567c478bd9Sstevel@tonic-gate */ 45577c478bd9Sstevel@tonic-gate if (((peer_tep = tep->te_conp) == NULL) || peer_tep->te_closing) { 45587c478bd9Sstevel@tonic-gate freemsg(mp); 45597c478bd9Sstevel@tonic-gate /* Peer closed */ 45607c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE, 45617c478bd9Sstevel@tonic-gate "tl_data: peer gone")); 45627c478bd9Sstevel@tonic-gate return; 45637c478bd9Sstevel@tonic-gate } 45647c478bd9Sstevel@tonic-gate 45657c478bd9Sstevel@tonic-gate ASSERT(tep->te_serializer == peer_tep->te_serializer); 45667c478bd9Sstevel@tonic-gate peer_rq = peer_tep->te_rq; 45677c478bd9Sstevel@tonic-gate 45687c478bd9Sstevel@tonic-gate /* 45697c478bd9Sstevel@tonic-gate * Put it back if flow controlled 45707c478bd9Sstevel@tonic-gate * Note: Messages already on queue when we are closing is bounded 45717c478bd9Sstevel@tonic-gate * so we can ignore flow control. 45727c478bd9Sstevel@tonic-gate */ 45737c478bd9Sstevel@tonic-gate if (!canputnext(peer_rq) && !closing) { 45747c478bd9Sstevel@tonic-gate TL_PUTBQ(tep, mp); 45757c478bd9Sstevel@tonic-gate return; 45767c478bd9Sstevel@tonic-gate } 45777c478bd9Sstevel@tonic-gate 45787c478bd9Sstevel@tonic-gate /* 45797c478bd9Sstevel@tonic-gate * validate peer state 45807c478bd9Sstevel@tonic-gate */ 45817c478bd9Sstevel@tonic-gate switch (peer_tep->te_state) { 45827c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 45837c478bd9Sstevel@tonic-gate case TS_WIND_ORDREL: 45847c478bd9Sstevel@tonic-gate /* valid states */ 45857c478bd9Sstevel@tonic-gate break; 45867c478bd9Sstevel@tonic-gate default: 45877c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 45887c478bd9Sstevel@tonic-gate "tl_data:rx side:invalid state")); 45897c478bd9Sstevel@tonic-gate tl_merror(peer_tep->te_wq, mp, EPROTO); 45907c478bd9Sstevel@tonic-gate return; 45917c478bd9Sstevel@tonic-gate } 45927c478bd9Sstevel@tonic-gate if (DB_TYPE(mp) == M_PROTO) { 45937c478bd9Sstevel@tonic-gate /* reuse message block - just change REQ to IND */ 45947c478bd9Sstevel@tonic-gate if (prim->type == T_DATA_REQ) 45957c478bd9Sstevel@tonic-gate prim->type = T_DATA_IND; 45967c478bd9Sstevel@tonic-gate else 45977c478bd9Sstevel@tonic-gate prim->type = T_OPTDATA_IND; 45987c478bd9Sstevel@tonic-gate } 45997c478bd9Sstevel@tonic-gate /* 46007c478bd9Sstevel@tonic-gate * peer_tep->te_state = NEXTSTATE(TE_DATA_IND, peer_tep->te_state); 46017c478bd9Sstevel@tonic-gate * (peer state stays same on this event) 46027c478bd9Sstevel@tonic-gate */ 46037c478bd9Sstevel@tonic-gate /* 46047c478bd9Sstevel@tonic-gate * send data to connected peer 46057c478bd9Sstevel@tonic-gate */ 46067c478bd9Sstevel@tonic-gate putnext(peer_rq, mp); 46077c478bd9Sstevel@tonic-gate } 46087c478bd9Sstevel@tonic-gate 46097c478bd9Sstevel@tonic-gate 46107c478bd9Sstevel@tonic-gate 46117c478bd9Sstevel@tonic-gate static void 46127c478bd9Sstevel@tonic-gate tl_exdata(mblk_t *mp, tl_endpt_t *tep) 46137c478bd9Sstevel@tonic-gate { 46147c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 46157c478bd9Sstevel@tonic-gate union T_primitives *prim = (union T_primitives *)mp->b_rptr; 46167c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp); 46177c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep; 46187c478bd9Sstevel@tonic-gate queue_t *peer_rq; 46197c478bd9Sstevel@tonic-gate boolean_t closing = tep->te_closing; 46207c478bd9Sstevel@tonic-gate 46217c478bd9Sstevel@tonic-gate if (msz < sizeof (struct T_exdata_req)) { 46227c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 46237c478bd9Sstevel@tonic-gate "tl_exdata:invalid message")); 46247c478bd9Sstevel@tonic-gate if (!closing) { 46257c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 46267c478bd9Sstevel@tonic-gate } else { 46277c478bd9Sstevel@tonic-gate freemsg(mp); 46287c478bd9Sstevel@tonic-gate } 46297c478bd9Sstevel@tonic-gate return; 46307c478bd9Sstevel@tonic-gate } 46317c478bd9Sstevel@tonic-gate 46327c478bd9Sstevel@tonic-gate /* 46337c478bd9Sstevel@tonic-gate * If the endpoint is closing it should still forward any data to the 46347c478bd9Sstevel@tonic-gate * peer (if it has one). If it is not allowed to forward it can just 46357c478bd9Sstevel@tonic-gate * free the message. 46367c478bd9Sstevel@tonic-gate */ 46377c478bd9Sstevel@tonic-gate if (closing && 46387c478bd9Sstevel@tonic-gate (tep->te_state != TS_DATA_XFER) && 46397c478bd9Sstevel@tonic-gate (tep->te_state != TS_WREQ_ORDREL)) { 46407c478bd9Sstevel@tonic-gate freemsg(mp); 46417c478bd9Sstevel@tonic-gate return; 46427c478bd9Sstevel@tonic-gate } 46437c478bd9Sstevel@tonic-gate 46447c478bd9Sstevel@tonic-gate /* 46457c478bd9Sstevel@tonic-gate * validate state 46467c478bd9Sstevel@tonic-gate */ 46477c478bd9Sstevel@tonic-gate switch (tep->te_state) { 46487c478bd9Sstevel@tonic-gate case TS_IDLE: 46497c478bd9Sstevel@tonic-gate /* 46507c478bd9Sstevel@tonic-gate * Other end not here - do nothing. 46517c478bd9Sstevel@tonic-gate */ 46527c478bd9Sstevel@tonic-gate freemsg(mp); 46537c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 46547c478bd9Sstevel@tonic-gate "tl_exdata:cots with endpoint idle")); 46557c478bd9Sstevel@tonic-gate return; 46567c478bd9Sstevel@tonic-gate 46577c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 46587c478bd9Sstevel@tonic-gate /* valid states */ 46597c478bd9Sstevel@tonic-gate if (tep->te_conp != NULL) 46607c478bd9Sstevel@tonic-gate break; 46617c478bd9Sstevel@tonic-gate 46627c478bd9Sstevel@tonic-gate if (tep->te_oconp == NULL) { 46637c478bd9Sstevel@tonic-gate if (!closing) { 46647c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 46657c478bd9Sstevel@tonic-gate } else { 46667c478bd9Sstevel@tonic-gate freemsg(mp); 46677c478bd9Sstevel@tonic-gate } 46687c478bd9Sstevel@tonic-gate return; 46697c478bd9Sstevel@tonic-gate } 46707c478bd9Sstevel@tonic-gate /* 46717c478bd9Sstevel@tonic-gate * For a socket the T_CONN_CON is sent early thus 46727c478bd9Sstevel@tonic-gate * the peer might not yet have accepted the connection. 46737c478bd9Sstevel@tonic-gate * If we are closing queue the packet with the T_CONN_IND. 46747c478bd9Sstevel@tonic-gate * Otherwise defer processing the packet until the peer 46757c478bd9Sstevel@tonic-gate * accepts the connection. 46767c478bd9Sstevel@tonic-gate * Note that the queue is noenabled when we go into this 46777c478bd9Sstevel@tonic-gate * state. 46787c478bd9Sstevel@tonic-gate */ 46797c478bd9Sstevel@tonic-gate if (!closing) { 46807c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 46817c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 46827c478bd9Sstevel@tonic-gate "tl_exdata: ocon")); 46837c478bd9Sstevel@tonic-gate TL_PUTBQ(tep, mp); 46847c478bd9Sstevel@tonic-gate return; 46857c478bd9Sstevel@tonic-gate } 46867c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 46877c478bd9Sstevel@tonic-gate "tl_exdata: closing socket ocon")); 46887c478bd9Sstevel@tonic-gate prim->type = T_EXDATA_IND; 46897c478bd9Sstevel@tonic-gate tl_icon_queuemsg(tep->te_oconp, tep->te_seqno, mp); 46907c478bd9Sstevel@tonic-gate return; 46917c478bd9Sstevel@tonic-gate 46927c478bd9Sstevel@tonic-gate case TS_WREQ_ORDREL: 46937c478bd9Sstevel@tonic-gate if (tep->te_conp == NULL) { 46947c478bd9Sstevel@tonic-gate /* 46957c478bd9Sstevel@tonic-gate * Other end closed - generate discon_ind 46967c478bd9Sstevel@tonic-gate * with reason 0 to cause an EPIPE but no 46977c478bd9Sstevel@tonic-gate * read side error on AF_UNIX sockets. 46987c478bd9Sstevel@tonic-gate */ 46997c478bd9Sstevel@tonic-gate freemsg(mp); 47007c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 47017c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 47027c478bd9Sstevel@tonic-gate "tl_exdata: WREQ_ORDREL and no peer")); 47037c478bd9Sstevel@tonic-gate tl_discon_ind(tep, 0); 47047c478bd9Sstevel@tonic-gate return; 47057c478bd9Sstevel@tonic-gate } 47067c478bd9Sstevel@tonic-gate break; 47077c478bd9Sstevel@tonic-gate 47087c478bd9Sstevel@tonic-gate default: 47097c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 47107c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 47117c478bd9Sstevel@tonic-gate "tl_wput:T_EXDATA_REQ:out of state, state=%d", 47127c478bd9Sstevel@tonic-gate tep->te_state)); 47137c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 47147c478bd9Sstevel@tonic-gate return; 47157c478bd9Sstevel@tonic-gate } 47167c478bd9Sstevel@tonic-gate /* 47177c478bd9Sstevel@tonic-gate * tep->te_state = NEXTSTATE(TE_EXDATA_REQ, tep->te_state); 47187c478bd9Sstevel@tonic-gate * (state stays same on this event) 47197c478bd9Sstevel@tonic-gate */ 47207c478bd9Sstevel@tonic-gate 47217c478bd9Sstevel@tonic-gate /* 47227c478bd9Sstevel@tonic-gate * get connected endpoint 47237c478bd9Sstevel@tonic-gate */ 47247c478bd9Sstevel@tonic-gate if (((peer_tep = tep->te_conp) == NULL) || peer_tep->te_closing) { 47257c478bd9Sstevel@tonic-gate freemsg(mp); 47267c478bd9Sstevel@tonic-gate /* Peer closed */ 47277c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE, 47287c478bd9Sstevel@tonic-gate "tl_exdata: peer gone")); 47297c478bd9Sstevel@tonic-gate return; 47307c478bd9Sstevel@tonic-gate } 47317c478bd9Sstevel@tonic-gate 47327c478bd9Sstevel@tonic-gate peer_rq = peer_tep->te_rq; 47337c478bd9Sstevel@tonic-gate 47347c478bd9Sstevel@tonic-gate /* 47357c478bd9Sstevel@tonic-gate * Put it back if flow controlled 47367c478bd9Sstevel@tonic-gate * Note: Messages already on queue when we are closing is bounded 47377c478bd9Sstevel@tonic-gate * so we can ignore flow control. 47387c478bd9Sstevel@tonic-gate */ 47397c478bd9Sstevel@tonic-gate if (!canputnext(peer_rq) && !closing) { 47407c478bd9Sstevel@tonic-gate TL_PUTBQ(tep, mp); 47417c478bd9Sstevel@tonic-gate return; 47427c478bd9Sstevel@tonic-gate } 47437c478bd9Sstevel@tonic-gate 47447c478bd9Sstevel@tonic-gate /* 47457c478bd9Sstevel@tonic-gate * validate state on peer 47467c478bd9Sstevel@tonic-gate */ 47477c478bd9Sstevel@tonic-gate switch (peer_tep->te_state) { 47487c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 47497c478bd9Sstevel@tonic-gate case TS_WIND_ORDREL: 47507c478bd9Sstevel@tonic-gate /* valid states */ 47517c478bd9Sstevel@tonic-gate break; 47527c478bd9Sstevel@tonic-gate default: 47537c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 47547c478bd9Sstevel@tonic-gate "tl_exdata:rx side:invalid state")); 47557c478bd9Sstevel@tonic-gate tl_merror(peer_tep->te_wq, mp, EPROTO); 47567c478bd9Sstevel@tonic-gate return; 47577c478bd9Sstevel@tonic-gate } 47587c478bd9Sstevel@tonic-gate /* 47597c478bd9Sstevel@tonic-gate * peer_tep->te_state = NEXTSTATE(TE_DATA_IND, peer_tep->te_state); 47607c478bd9Sstevel@tonic-gate * (peer state stays same on this event) 47617c478bd9Sstevel@tonic-gate */ 47627c478bd9Sstevel@tonic-gate /* 47637c478bd9Sstevel@tonic-gate * reuse message block 47647c478bd9Sstevel@tonic-gate */ 47657c478bd9Sstevel@tonic-gate prim->type = T_EXDATA_IND; 47667c478bd9Sstevel@tonic-gate 47677c478bd9Sstevel@tonic-gate /* 47687c478bd9Sstevel@tonic-gate * send data to connected peer 47697c478bd9Sstevel@tonic-gate */ 47707c478bd9Sstevel@tonic-gate putnext(peer_rq, mp); 47717c478bd9Sstevel@tonic-gate } 47727c478bd9Sstevel@tonic-gate 47737c478bd9Sstevel@tonic-gate 47747c478bd9Sstevel@tonic-gate 47757c478bd9Sstevel@tonic-gate static void 47767c478bd9Sstevel@tonic-gate tl_ordrel(mblk_t *mp, tl_endpt_t *tep) 47777c478bd9Sstevel@tonic-gate { 47787c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 47797c478bd9Sstevel@tonic-gate union T_primitives *prim = (union T_primitives *)mp->b_rptr; 47807c478bd9Sstevel@tonic-gate ssize_t msz = MBLKL(mp); 47817c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep; 47827c478bd9Sstevel@tonic-gate queue_t *peer_rq; 47837c478bd9Sstevel@tonic-gate boolean_t closing = tep->te_closing; 47847c478bd9Sstevel@tonic-gate 47857c478bd9Sstevel@tonic-gate if (msz < sizeof (struct T_ordrel_req)) { 47867c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 47877c478bd9Sstevel@tonic-gate "tl_ordrel:invalid message")); 47887c478bd9Sstevel@tonic-gate if (!closing) { 47897c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 47907c478bd9Sstevel@tonic-gate } else { 47917c478bd9Sstevel@tonic-gate freemsg(mp); 47927c478bd9Sstevel@tonic-gate } 47937c478bd9Sstevel@tonic-gate return; 47947c478bd9Sstevel@tonic-gate } 47957c478bd9Sstevel@tonic-gate 47967c478bd9Sstevel@tonic-gate /* 47977c478bd9Sstevel@tonic-gate * validate state 47987c478bd9Sstevel@tonic-gate */ 47997c478bd9Sstevel@tonic-gate switch (tep->te_state) { 48007c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 48017c478bd9Sstevel@tonic-gate case TS_WREQ_ORDREL: 48027c478bd9Sstevel@tonic-gate /* valid states */ 48037c478bd9Sstevel@tonic-gate if (tep->te_conp != NULL) 48047c478bd9Sstevel@tonic-gate break; 48057c478bd9Sstevel@tonic-gate 48067c478bd9Sstevel@tonic-gate if (tep->te_oconp == NULL) 48077c478bd9Sstevel@tonic-gate break; 48087c478bd9Sstevel@tonic-gate 48097c478bd9Sstevel@tonic-gate /* 48107c478bd9Sstevel@tonic-gate * For a socket the T_CONN_CON is sent early thus 48117c478bd9Sstevel@tonic-gate * the peer might not yet have accepted the connection. 48127c478bd9Sstevel@tonic-gate * If we are closing queue the packet with the T_CONN_IND. 48137c478bd9Sstevel@tonic-gate * Otherwise defer processing the packet until the peer 48147c478bd9Sstevel@tonic-gate * accepts the connection. 48157c478bd9Sstevel@tonic-gate * Note that the queue is noenabled when we go into this 48167c478bd9Sstevel@tonic-gate * state. 48177c478bd9Sstevel@tonic-gate */ 48187c478bd9Sstevel@tonic-gate if (!closing) { 48197c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 48207c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 48217c478bd9Sstevel@tonic-gate "tl_ordlrel: ocon")); 48227c478bd9Sstevel@tonic-gate TL_PUTBQ(tep, mp); 48237c478bd9Sstevel@tonic-gate return; 48247c478bd9Sstevel@tonic-gate } 48257c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 48267c478bd9Sstevel@tonic-gate "tl_ordlrel: closing socket ocon")); 48277c478bd9Sstevel@tonic-gate prim->type = T_ORDREL_IND; 48287c478bd9Sstevel@tonic-gate (void) tl_icon_queuemsg(tep->te_oconp, tep->te_seqno, mp); 48297c478bd9Sstevel@tonic-gate return; 48307c478bd9Sstevel@tonic-gate 48317c478bd9Sstevel@tonic-gate default: 48327c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 48337c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 48347c478bd9Sstevel@tonic-gate "tl_wput:T_ORDREL_REQ:out of state, state=%d", 48357c478bd9Sstevel@tonic-gate tep->te_state)); 48367c478bd9Sstevel@tonic-gate if (!closing) { 48377c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 48387c478bd9Sstevel@tonic-gate } else { 48397c478bd9Sstevel@tonic-gate freemsg(mp); 48407c478bd9Sstevel@tonic-gate } 48417c478bd9Sstevel@tonic-gate return; 48427c478bd9Sstevel@tonic-gate } 48437c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ORDREL_REQ, tep->te_state); 48447c478bd9Sstevel@tonic-gate 48457c478bd9Sstevel@tonic-gate /* 48467c478bd9Sstevel@tonic-gate * get connected endpoint 48477c478bd9Sstevel@tonic-gate */ 48487c478bd9Sstevel@tonic-gate if (((peer_tep = tep->te_conp) == NULL) || peer_tep->te_closing) { 48497c478bd9Sstevel@tonic-gate /* Peer closed */ 48507c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE, 48517c478bd9Sstevel@tonic-gate "tl_ordrel: peer gone")); 48527c478bd9Sstevel@tonic-gate freemsg(mp); 48537c478bd9Sstevel@tonic-gate return; 48547c478bd9Sstevel@tonic-gate } 48557c478bd9Sstevel@tonic-gate 48567c478bd9Sstevel@tonic-gate peer_rq = peer_tep->te_rq; 48577c478bd9Sstevel@tonic-gate 48587c478bd9Sstevel@tonic-gate /* 48597c478bd9Sstevel@tonic-gate * Put it back if flow controlled except when we are closing. 48607c478bd9Sstevel@tonic-gate * Note: Messages already on queue when we are closing is bounded 48617c478bd9Sstevel@tonic-gate * so we can ignore flow control. 48627c478bd9Sstevel@tonic-gate */ 48637c478bd9Sstevel@tonic-gate if (! canputnext(peer_rq) && !closing) { 48647c478bd9Sstevel@tonic-gate TL_PUTBQ(tep, mp); 48657c478bd9Sstevel@tonic-gate return; 48667c478bd9Sstevel@tonic-gate } 48677c478bd9Sstevel@tonic-gate 48687c478bd9Sstevel@tonic-gate /* 48697c478bd9Sstevel@tonic-gate * validate state on peer 48707c478bd9Sstevel@tonic-gate */ 48717c478bd9Sstevel@tonic-gate switch (peer_tep->te_state) { 48727c478bd9Sstevel@tonic-gate case TS_DATA_XFER: 48737c478bd9Sstevel@tonic-gate case TS_WIND_ORDREL: 48747c478bd9Sstevel@tonic-gate /* valid states */ 48757c478bd9Sstevel@tonic-gate break; 48767c478bd9Sstevel@tonic-gate default: 48777c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 48787c478bd9Sstevel@tonic-gate "tl_ordrel:rx side:invalid state")); 48797c478bd9Sstevel@tonic-gate tl_merror(peer_tep->te_wq, mp, EPROTO); 48807c478bd9Sstevel@tonic-gate return; 48817c478bd9Sstevel@tonic-gate } 48827c478bd9Sstevel@tonic-gate peer_tep->te_state = NEXTSTATE(TE_ORDREL_IND, peer_tep->te_state); 48837c478bd9Sstevel@tonic-gate 48847c478bd9Sstevel@tonic-gate /* 48857c478bd9Sstevel@tonic-gate * reuse message block 48867c478bd9Sstevel@tonic-gate */ 48877c478bd9Sstevel@tonic-gate prim->type = T_ORDREL_IND; 48887c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE, 48897c478bd9Sstevel@tonic-gate "tl_ordrel: send ordrel_ind")); 48907c478bd9Sstevel@tonic-gate 48917c478bd9Sstevel@tonic-gate /* 48927c478bd9Sstevel@tonic-gate * send data to connected peer 48937c478bd9Sstevel@tonic-gate */ 48947c478bd9Sstevel@tonic-gate putnext(peer_rq, mp); 48957c478bd9Sstevel@tonic-gate } 48967c478bd9Sstevel@tonic-gate 48977c478bd9Sstevel@tonic-gate 48987c478bd9Sstevel@tonic-gate /* 48997c478bd9Sstevel@tonic-gate * Send T_UDERROR_IND. The error should be from the <sys/errno.h> space. 49007c478bd9Sstevel@tonic-gate */ 49017c478bd9Sstevel@tonic-gate static void 49027c478bd9Sstevel@tonic-gate tl_uderr(queue_t *wq, mblk_t *mp, t_scalar_t err) 49037c478bd9Sstevel@tonic-gate { 49047c478bd9Sstevel@tonic-gate size_t err_sz; 49057c478bd9Sstevel@tonic-gate tl_endpt_t *tep; 49067c478bd9Sstevel@tonic-gate struct T_unitdata_req *udreq; 49077c478bd9Sstevel@tonic-gate mblk_t *err_mp; 49087c478bd9Sstevel@tonic-gate t_scalar_t alen; 49097c478bd9Sstevel@tonic-gate t_scalar_t olen; 49107c478bd9Sstevel@tonic-gate struct T_uderror_ind *uderr; 49117c478bd9Sstevel@tonic-gate uchar_t *addr_startp; 49127c478bd9Sstevel@tonic-gate 49137c478bd9Sstevel@tonic-gate err_sz = sizeof (struct T_uderror_ind); 49147c478bd9Sstevel@tonic-gate tep = (tl_endpt_t *)wq->q_ptr; 49157c478bd9Sstevel@tonic-gate udreq = (struct T_unitdata_req *)mp->b_rptr; 49167c478bd9Sstevel@tonic-gate alen = udreq->DEST_length; 49177c478bd9Sstevel@tonic-gate olen = udreq->OPT_length; 49187c478bd9Sstevel@tonic-gate 49197c478bd9Sstevel@tonic-gate if (alen > 0) 49207c478bd9Sstevel@tonic-gate err_sz = T_ALIGN(err_sz + alen); 49217c478bd9Sstevel@tonic-gate if (olen > 0) 49227c478bd9Sstevel@tonic-gate err_sz += olen; 49237c478bd9Sstevel@tonic-gate 49247c478bd9Sstevel@tonic-gate err_mp = allocb(err_sz, BPRI_MED); 49257c478bd9Sstevel@tonic-gate if (! err_mp) { 49267c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 49277c478bd9Sstevel@tonic-gate "tl_uderr:allocb failure")); 49287c478bd9Sstevel@tonic-gate /* 49297c478bd9Sstevel@tonic-gate * Note: no rollback of state needed as it does 49307c478bd9Sstevel@tonic-gate * not change in connectionless transport 49317c478bd9Sstevel@tonic-gate */ 49327c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, err_sz); 49337c478bd9Sstevel@tonic-gate return; 49347c478bd9Sstevel@tonic-gate } 49357c478bd9Sstevel@tonic-gate 49367c478bd9Sstevel@tonic-gate DB_TYPE(err_mp) = M_PROTO; 49377c478bd9Sstevel@tonic-gate err_mp->b_wptr = err_mp->b_rptr + err_sz; 49387c478bd9Sstevel@tonic-gate uderr = (struct T_uderror_ind *)err_mp->b_rptr; 49397c478bd9Sstevel@tonic-gate uderr->PRIM_type = T_UDERROR_IND; 49407c478bd9Sstevel@tonic-gate uderr->ERROR_type = err; 49417c478bd9Sstevel@tonic-gate uderr->DEST_length = alen; 49427c478bd9Sstevel@tonic-gate uderr->OPT_length = olen; 49437c478bd9Sstevel@tonic-gate if (alen <= 0) { 49447c478bd9Sstevel@tonic-gate uderr->DEST_offset = 0; 49457c478bd9Sstevel@tonic-gate } else { 49467c478bd9Sstevel@tonic-gate uderr->DEST_offset = 49477c478bd9Sstevel@tonic-gate (t_scalar_t)sizeof (struct T_uderror_ind); 49487c478bd9Sstevel@tonic-gate addr_startp = mp->b_rptr + udreq->DEST_offset; 49497c478bd9Sstevel@tonic-gate bcopy(addr_startp, err_mp->b_rptr + uderr->DEST_offset, 49507c478bd9Sstevel@tonic-gate (size_t)alen); 49517c478bd9Sstevel@tonic-gate } 49527c478bd9Sstevel@tonic-gate if (olen <= 0) { 49537c478bd9Sstevel@tonic-gate uderr->OPT_offset = 0; 49547c478bd9Sstevel@tonic-gate } else { 49557c478bd9Sstevel@tonic-gate uderr->OPT_offset = 49567c478bd9Sstevel@tonic-gate (t_scalar_t)T_ALIGN(sizeof (struct T_uderror_ind) + 49577c478bd9Sstevel@tonic-gate uderr->DEST_length); 49587c478bd9Sstevel@tonic-gate addr_startp = mp->b_rptr + udreq->OPT_offset; 49597c478bd9Sstevel@tonic-gate bcopy(addr_startp, err_mp->b_rptr+uderr->OPT_offset, 49607c478bd9Sstevel@tonic-gate (size_t)olen); 49617c478bd9Sstevel@tonic-gate } 49627c478bd9Sstevel@tonic-gate freemsg(mp); 49637c478bd9Sstevel@tonic-gate 49647c478bd9Sstevel@tonic-gate /* 49657c478bd9Sstevel@tonic-gate * send indication message 49667c478bd9Sstevel@tonic-gate */ 49677c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_UDERROR_IND, tep->te_state); 49687c478bd9Sstevel@tonic-gate 49697c478bd9Sstevel@tonic-gate qreply(wq, err_mp); 49707c478bd9Sstevel@tonic-gate } 49717c478bd9Sstevel@tonic-gate 49727c478bd9Sstevel@tonic-gate static void 49737c478bd9Sstevel@tonic-gate tl_unitdata_ser(mblk_t *mp, tl_endpt_t *tep) 49747c478bd9Sstevel@tonic-gate { 49757c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 49767c478bd9Sstevel@tonic-gate 49777c478bd9Sstevel@tonic-gate if (!tep->te_closing && (wq->q_first != NULL)) { 49787c478bd9Sstevel@tonic-gate TL_PUTQ(tep, mp); 49797c478bd9Sstevel@tonic-gate } else if (tep->te_rq != NULL) 49807c478bd9Sstevel@tonic-gate tl_unitdata(mp, tep); 49817c478bd9Sstevel@tonic-gate else 49827c478bd9Sstevel@tonic-gate freemsg(mp); 49837c478bd9Sstevel@tonic-gate 49847c478bd9Sstevel@tonic-gate tl_serializer_exit(tep); 49857c478bd9Sstevel@tonic-gate tl_refrele(tep); 49867c478bd9Sstevel@tonic-gate } 49877c478bd9Sstevel@tonic-gate 49887c478bd9Sstevel@tonic-gate /* 49897c478bd9Sstevel@tonic-gate * Handle T_unitdata_req. 49907c478bd9Sstevel@tonic-gate * If TL_SET[U]CRED or TL_SOCKUCRED generate the credentials options. 49917c478bd9Sstevel@tonic-gate * If this is a socket pass through options unmodified. 49927c478bd9Sstevel@tonic-gate */ 49937c478bd9Sstevel@tonic-gate static void 49947c478bd9Sstevel@tonic-gate tl_unitdata(mblk_t *mp, tl_endpt_t *tep) 49957c478bd9Sstevel@tonic-gate { 49967c478bd9Sstevel@tonic-gate queue_t *wq = tep->te_wq; 49977c478bd9Sstevel@tonic-gate soux_addr_t ux_addr; 49987c478bd9Sstevel@tonic-gate tl_addr_t destaddr; 49997c478bd9Sstevel@tonic-gate uchar_t *addr_startp; 50007c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep; 50017c478bd9Sstevel@tonic-gate struct T_unitdata_ind *udind; 50027c478bd9Sstevel@tonic-gate struct T_unitdata_req *udreq; 50037c478bd9Sstevel@tonic-gate ssize_t msz, ui_sz; 50047c478bd9Sstevel@tonic-gate t_scalar_t alen, aoff, olen, ooff; 50057c478bd9Sstevel@tonic-gate t_scalar_t oldolen = 0; 500667dbe2beSCasper H.S. Dik cred_t *cr = NULL; 500767dbe2beSCasper H.S. Dik pid_t cpid; 50087c478bd9Sstevel@tonic-gate 50097c478bd9Sstevel@tonic-gate udreq = (struct T_unitdata_req *)mp->b_rptr; 50107c478bd9Sstevel@tonic-gate msz = MBLKL(mp); 50117c478bd9Sstevel@tonic-gate 50127c478bd9Sstevel@tonic-gate /* 50137c478bd9Sstevel@tonic-gate * validate the state 50147c478bd9Sstevel@tonic-gate */ 50157c478bd9Sstevel@tonic-gate if (tep->te_state != TS_IDLE) { 50167c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 50177c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 50187c478bd9Sstevel@tonic-gate "tl_wput:T_CONN_REQ:out of state")); 50197c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EPROTO); 50207c478bd9Sstevel@tonic-gate return; 50217c478bd9Sstevel@tonic-gate } 50227c478bd9Sstevel@tonic-gate /* 50237c478bd9Sstevel@tonic-gate * tep->te_state = NEXTSTATE(TE_UNITDATA_REQ, tep->te_state); 50247c478bd9Sstevel@tonic-gate * (state does not change on this event) 50257c478bd9Sstevel@tonic-gate */ 50267c478bd9Sstevel@tonic-gate 50277c478bd9Sstevel@tonic-gate /* 50287c478bd9Sstevel@tonic-gate * validate the message 50297c478bd9Sstevel@tonic-gate * Note: dereference fields in struct inside message only 50307c478bd9Sstevel@tonic-gate * after validating the message length. 50317c478bd9Sstevel@tonic-gate */ 50327c478bd9Sstevel@tonic-gate if (msz < sizeof (struct T_unitdata_req)) { 50337c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 50347c478bd9Sstevel@tonic-gate "tl_unitdata:invalid message length")); 50357c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EINVAL); 50367c478bd9Sstevel@tonic-gate return; 50377c478bd9Sstevel@tonic-gate } 50387c478bd9Sstevel@tonic-gate alen = udreq->DEST_length; 50397c478bd9Sstevel@tonic-gate aoff = udreq->DEST_offset; 50407c478bd9Sstevel@tonic-gate oldolen = olen = udreq->OPT_length; 50417c478bd9Sstevel@tonic-gate ooff = udreq->OPT_offset; 50427c478bd9Sstevel@tonic-gate if (olen == 0) 50437c478bd9Sstevel@tonic-gate ooff = 0; 50447c478bd9Sstevel@tonic-gate 50457c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) { 50467c478bd9Sstevel@tonic-gate if ((alen != TL_SOUX_ADDRLEN) || 50477c478bd9Sstevel@tonic-gate (aoff < 0) || 50487c478bd9Sstevel@tonic-gate (aoff + alen > msz) || 50497c478bd9Sstevel@tonic-gate (olen < 0) || (ooff < 0) || 50507c478bd9Sstevel@tonic-gate ((olen > 0) && ((ooff + olen) > msz))) { 50517c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 50527c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 50537c478bd9Sstevel@tonic-gate "tl_unitdata_req: invalid socket addr " 50547c478bd9Sstevel@tonic-gate "(msz=%d, al=%d, ao=%d, ol=%d, oo = %d)", 50557c478bd9Sstevel@tonic-gate (int)msz, alen, aoff, olen, ooff)); 50567c478bd9Sstevel@tonic-gate tl_error_ack(wq, mp, TSYSERR, EINVAL, T_UNITDATA_REQ); 50577c478bd9Sstevel@tonic-gate return; 50587c478bd9Sstevel@tonic-gate } 50597c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr + aoff, &ux_addr, TL_SOUX_ADDRLEN); 50607c478bd9Sstevel@tonic-gate 50617c478bd9Sstevel@tonic-gate if ((ux_addr.soua_magic != SOU_MAGIC_IMPLICIT) && 50627c478bd9Sstevel@tonic-gate (ux_addr.soua_magic != SOU_MAGIC_EXPLICIT)) { 50637c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 50647c478bd9Sstevel@tonic-gate 1, SL_TRACE|SL_ERROR, 50657c478bd9Sstevel@tonic-gate "tl_conn_req: invalid socket magic")); 50667c478bd9Sstevel@tonic-gate tl_error_ack(wq, mp, TSYSERR, EINVAL, T_UNITDATA_REQ); 50677c478bd9Sstevel@tonic-gate return; 50687c478bd9Sstevel@tonic-gate } 50697c478bd9Sstevel@tonic-gate } else { 50707c478bd9Sstevel@tonic-gate if ((alen < 0) || 50717c478bd9Sstevel@tonic-gate (aoff < 0) || 50727c478bd9Sstevel@tonic-gate ((alen > 0) && ((aoff + alen) > msz)) || 50737c478bd9Sstevel@tonic-gate ((ssize_t)alen > (msz - sizeof (struct T_unitdata_req))) || 50747c478bd9Sstevel@tonic-gate ((aoff + alen) < 0) || 50757c478bd9Sstevel@tonic-gate ((olen > 0) && ((ooff + olen) > msz)) || 50767c478bd9Sstevel@tonic-gate (olen < 0) || 50777c478bd9Sstevel@tonic-gate (ooff < 0) || 50787c478bd9Sstevel@tonic-gate ((ssize_t)olen > (msz - sizeof (struct T_unitdata_req)))) { 50797c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 50807c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 50817c478bd9Sstevel@tonic-gate "tl_unitdata:invalid unit data message")); 50827c478bd9Sstevel@tonic-gate tl_merror(wq, mp, EINVAL); 50837c478bd9Sstevel@tonic-gate return; 50847c478bd9Sstevel@tonic-gate } 50857c478bd9Sstevel@tonic-gate } 50867c478bd9Sstevel@tonic-gate 50877c478bd9Sstevel@tonic-gate /* Options not supported unless it's a socket */ 50887c478bd9Sstevel@tonic-gate if (alen == 0 || (olen != 0 && !IS_SOCKET(tep))) { 50897c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 50907c478bd9Sstevel@tonic-gate "tl_unitdata:option use(unsupported) or zero len addr")); 50917c478bd9Sstevel@tonic-gate tl_uderr(wq, mp, EPROTO); 50927c478bd9Sstevel@tonic-gate return; 50937c478bd9Sstevel@tonic-gate } 50947c478bd9Sstevel@tonic-gate #ifdef DEBUG 50957c478bd9Sstevel@tonic-gate /* 50967c478bd9Sstevel@tonic-gate * Mild form of ASSERT()ion to detect broken TPI apps. 50977c478bd9Sstevel@tonic-gate * if (! assertion) 50987c478bd9Sstevel@tonic-gate * log warning; 50997c478bd9Sstevel@tonic-gate */ 51007c478bd9Sstevel@tonic-gate if (! (aoff >= (t_scalar_t)sizeof (struct T_unitdata_req))) { 51017c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 51027c478bd9Sstevel@tonic-gate "tl_unitdata:addr overlaps TPI message")); 51037c478bd9Sstevel@tonic-gate } 51047c478bd9Sstevel@tonic-gate #endif 51057c478bd9Sstevel@tonic-gate /* 51067c478bd9Sstevel@tonic-gate * get destination endpoint 51077c478bd9Sstevel@tonic-gate */ 51087c478bd9Sstevel@tonic-gate destaddr.ta_alen = alen; 51097c478bd9Sstevel@tonic-gate destaddr.ta_abuf = mp->b_rptr + aoff; 51107c478bd9Sstevel@tonic-gate destaddr.ta_zoneid = tep->te_zoneid; 51117c478bd9Sstevel@tonic-gate 51127c478bd9Sstevel@tonic-gate /* 51137c478bd9Sstevel@tonic-gate * Check whether the destination is the same that was used previously 51147c478bd9Sstevel@tonic-gate * and the destination endpoint is in the right state. If something is 51157c478bd9Sstevel@tonic-gate * wrong, find destination again and cache it. 51167c478bd9Sstevel@tonic-gate */ 51177c478bd9Sstevel@tonic-gate peer_tep = tep->te_lastep; 51187c478bd9Sstevel@tonic-gate 51197c478bd9Sstevel@tonic-gate if ((peer_tep == NULL) || peer_tep->te_closing || 51207c478bd9Sstevel@tonic-gate (peer_tep->te_state != TS_IDLE) || 51217c478bd9Sstevel@tonic-gate !tl_eqaddr(&destaddr, &peer_tep->te_ap)) { 51227c478bd9Sstevel@tonic-gate /* 51237c478bd9Sstevel@tonic-gate * Not the same as cached destination , need to find the right 51247c478bd9Sstevel@tonic-gate * destination. 51257c478bd9Sstevel@tonic-gate */ 51267c478bd9Sstevel@tonic-gate peer_tep = (IS_SOCKET(tep) ? 51277c478bd9Sstevel@tonic-gate tl_sock_find_peer(tep, &ux_addr) : 51287c478bd9Sstevel@tonic-gate tl_find_peer(tep, &destaddr)); 51297c478bd9Sstevel@tonic-gate 51307c478bd9Sstevel@tonic-gate if (peer_tep == NULL) { 51317c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 51327c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 51337c478bd9Sstevel@tonic-gate "tl_unitdata:no one at destination address")); 51347c478bd9Sstevel@tonic-gate tl_uderr(wq, mp, ECONNRESET); 51357c478bd9Sstevel@tonic-gate return; 51367c478bd9Sstevel@tonic-gate } 51377c478bd9Sstevel@tonic-gate 51387c478bd9Sstevel@tonic-gate /* 51397c478bd9Sstevel@tonic-gate * Cache the new peer. 51407c478bd9Sstevel@tonic-gate */ 51417c478bd9Sstevel@tonic-gate if (tep->te_lastep != NULL) 51427c478bd9Sstevel@tonic-gate tl_refrele(tep->te_lastep); 51437c478bd9Sstevel@tonic-gate 51447c478bd9Sstevel@tonic-gate tep->te_lastep = peer_tep; 51457c478bd9Sstevel@tonic-gate } 51467c478bd9Sstevel@tonic-gate 51477c478bd9Sstevel@tonic-gate if (peer_tep->te_state != TS_IDLE) { 51487c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 51497c478bd9Sstevel@tonic-gate "tl_unitdata:provider in invalid state")); 51507c478bd9Sstevel@tonic-gate tl_uderr(wq, mp, EPROTO); 51517c478bd9Sstevel@tonic-gate return; 51527c478bd9Sstevel@tonic-gate } 51537c478bd9Sstevel@tonic-gate 51547c478bd9Sstevel@tonic-gate ASSERT(peer_tep->te_rq != NULL); 51557c478bd9Sstevel@tonic-gate 51567c478bd9Sstevel@tonic-gate /* 51577c478bd9Sstevel@tonic-gate * Put it back if flow controlled except when we are closing. 51587c478bd9Sstevel@tonic-gate * Note: Messages already on queue when we are closing is bounded 51597c478bd9Sstevel@tonic-gate * so we can ignore flow control. 51607c478bd9Sstevel@tonic-gate */ 51617c478bd9Sstevel@tonic-gate if (!canputnext(peer_tep->te_rq) && !(tep->te_closing)) { 51627c478bd9Sstevel@tonic-gate /* record what we are flow controlled on */ 51637c478bd9Sstevel@tonic-gate if (tep->te_flowq != NULL) { 51647c478bd9Sstevel@tonic-gate list_remove(&tep->te_flowq->te_flowlist, tep); 51657c478bd9Sstevel@tonic-gate } 51667c478bd9Sstevel@tonic-gate list_insert_head(&peer_tep->te_flowlist, tep); 51677c478bd9Sstevel@tonic-gate tep->te_flowq = peer_tep; 51687c478bd9Sstevel@tonic-gate TL_PUTBQ(tep, mp); 51697c478bd9Sstevel@tonic-gate return; 51707c478bd9Sstevel@tonic-gate } 51717c478bd9Sstevel@tonic-gate /* 51727c478bd9Sstevel@tonic-gate * prepare indication message 51737c478bd9Sstevel@tonic-gate */ 51747c478bd9Sstevel@tonic-gate 51757c478bd9Sstevel@tonic-gate /* 51767c478bd9Sstevel@tonic-gate * calculate length of message 51777c478bd9Sstevel@tonic-gate */ 517867dbe2beSCasper H.S. Dik if (peer_tep->te_flag & (TL_SETCRED|TL_SETUCRED|TL_SOCKUCRED)) { 517967dbe2beSCasper H.S. Dik cr = msg_getcred(mp, &cpid); 518067dbe2beSCasper H.S. Dik ASSERT(cr != NULL); 518167dbe2beSCasper H.S. Dik 51827c478bd9Sstevel@tonic-gate if (peer_tep->te_flag & TL_SETCRED) { 51837c478bd9Sstevel@tonic-gate ASSERT(olen == 0); 51847c478bd9Sstevel@tonic-gate olen = (t_scalar_t)sizeof (struct opthdr) + 51857c478bd9Sstevel@tonic-gate OPTLEN(sizeof (tl_credopt_t)); 51867c478bd9Sstevel@tonic-gate /* 1 option only */ 51877c478bd9Sstevel@tonic-gate } else if (peer_tep->te_flag & TL_SETUCRED) { 51887c478bd9Sstevel@tonic-gate ASSERT(olen == 0); 518967dbe2beSCasper H.S. Dik olen = (t_scalar_t)sizeof (struct opthdr) + 519067dbe2beSCasper H.S. Dik OPTLEN(ucredminsize(cr)); 51917c478bd9Sstevel@tonic-gate /* 1 option only */ 519267dbe2beSCasper H.S. Dik } else { 51937c478bd9Sstevel@tonic-gate /* Possibly more than one option */ 51947c478bd9Sstevel@tonic-gate olen += (t_scalar_t)sizeof (struct T_opthdr) + 519567dbe2beSCasper H.S. Dik OPTLEN(ucredminsize(cr)); 519667dbe2beSCasper H.S. Dik } 51977c478bd9Sstevel@tonic-gate } 51987c478bd9Sstevel@tonic-gate 51997c478bd9Sstevel@tonic-gate ui_sz = T_ALIGN(sizeof (struct T_unitdata_ind) + tep->te_alen) + 52007c478bd9Sstevel@tonic-gate olen; 52017c478bd9Sstevel@tonic-gate /* 52027c478bd9Sstevel@tonic-gate * If the unitdata_ind fits and we are not adding options 52037c478bd9Sstevel@tonic-gate * reuse the udreq mblk. 52047c478bd9Sstevel@tonic-gate */ 52057c478bd9Sstevel@tonic-gate if (msz >= ui_sz && alen >= tep->te_alen && 52067c478bd9Sstevel@tonic-gate !(peer_tep->te_flag & (TL_SETCRED|TL_SETUCRED|TL_SOCKUCRED))) { 52077c478bd9Sstevel@tonic-gate /* 52087c478bd9Sstevel@tonic-gate * Reuse the original mblk. Leave options in place. 52097c478bd9Sstevel@tonic-gate */ 52107c478bd9Sstevel@tonic-gate udind = (struct T_unitdata_ind *)mp->b_rptr; 52117c478bd9Sstevel@tonic-gate udind->PRIM_type = T_UNITDATA_IND; 52127c478bd9Sstevel@tonic-gate udind->SRC_length = tep->te_alen; 52137c478bd9Sstevel@tonic-gate addr_startp = mp->b_rptr + udind->SRC_offset; 52147c478bd9Sstevel@tonic-gate bcopy(tep->te_abuf, addr_startp, tep->te_alen); 52157c478bd9Sstevel@tonic-gate } else { 52167c478bd9Sstevel@tonic-gate /* Allocate a new T_unidata_ind message */ 52177c478bd9Sstevel@tonic-gate mblk_t *ui_mp; 52187c478bd9Sstevel@tonic-gate 52197c478bd9Sstevel@tonic-gate ui_mp = allocb(ui_sz, BPRI_MED); 52207c478bd9Sstevel@tonic-gate if (! ui_mp) { 52217c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 4, SL_TRACE, 52227c478bd9Sstevel@tonic-gate "tl_unitdata:allocb failure:message queued")); 52237c478bd9Sstevel@tonic-gate tl_memrecover(wq, mp, ui_sz); 52247c478bd9Sstevel@tonic-gate return; 52257c478bd9Sstevel@tonic-gate } 52267c478bd9Sstevel@tonic-gate 52277c478bd9Sstevel@tonic-gate /* 52287c478bd9Sstevel@tonic-gate * fill in T_UNITDATA_IND contents 52297c478bd9Sstevel@tonic-gate */ 52307c478bd9Sstevel@tonic-gate DB_TYPE(ui_mp) = M_PROTO; 52317c478bd9Sstevel@tonic-gate ui_mp->b_wptr = ui_mp->b_rptr + ui_sz; 52327c478bd9Sstevel@tonic-gate udind = (struct T_unitdata_ind *)ui_mp->b_rptr; 52337c478bd9Sstevel@tonic-gate udind->PRIM_type = T_UNITDATA_IND; 52347c478bd9Sstevel@tonic-gate udind->SRC_offset = (t_scalar_t)sizeof (struct T_unitdata_ind); 52357c478bd9Sstevel@tonic-gate udind->SRC_length = tep->te_alen; 52367c478bd9Sstevel@tonic-gate addr_startp = ui_mp->b_rptr + udind->SRC_offset; 52377c478bd9Sstevel@tonic-gate bcopy(tep->te_abuf, addr_startp, tep->te_alen); 52387c478bd9Sstevel@tonic-gate udind->OPT_offset = 52397c478bd9Sstevel@tonic-gate (t_scalar_t)T_ALIGN(udind->SRC_offset + udind->SRC_length); 52407c478bd9Sstevel@tonic-gate udind->OPT_length = olen; 52417c478bd9Sstevel@tonic-gate if (peer_tep->te_flag & (TL_SETCRED|TL_SETUCRED|TL_SOCKUCRED)) { 5242de8c4a14SErik Nordmark 52437c478bd9Sstevel@tonic-gate if (oldolen != 0) { 52447c478bd9Sstevel@tonic-gate bcopy((void *)((uintptr_t)udreq + ooff), 52457c478bd9Sstevel@tonic-gate (void *)((uintptr_t)udind + 52467c478bd9Sstevel@tonic-gate udind->OPT_offset), 52477c478bd9Sstevel@tonic-gate oldolen); 52487c478bd9Sstevel@tonic-gate } 5249de8c4a14SErik Nordmark ASSERT(cr != NULL); 5250de8c4a14SErik Nordmark 52517c478bd9Sstevel@tonic-gate tl_fill_option(ui_mp->b_rptr + udind->OPT_offset + 5252de8c4a14SErik Nordmark oldolen, cr, cpid, 525345916cd2Sjpk peer_tep->te_flag, peer_tep->te_credp); 52547c478bd9Sstevel@tonic-gate } else { 52557c478bd9Sstevel@tonic-gate bcopy((void *)((uintptr_t)udreq + ooff), 52567c478bd9Sstevel@tonic-gate (void *)((uintptr_t)udind + udind->OPT_offset), 52577c478bd9Sstevel@tonic-gate olen); 52587c478bd9Sstevel@tonic-gate } 52597c478bd9Sstevel@tonic-gate 52607c478bd9Sstevel@tonic-gate /* 52617c478bd9Sstevel@tonic-gate * relink data blocks from mp to ui_mp 52627c478bd9Sstevel@tonic-gate */ 52637c478bd9Sstevel@tonic-gate ui_mp->b_cont = mp->b_cont; 52647c478bd9Sstevel@tonic-gate freeb(mp); 52657c478bd9Sstevel@tonic-gate mp = ui_mp; 52667c478bd9Sstevel@tonic-gate } 52677c478bd9Sstevel@tonic-gate /* 52687c478bd9Sstevel@tonic-gate * send indication message 52697c478bd9Sstevel@tonic-gate */ 52707c478bd9Sstevel@tonic-gate peer_tep->te_state = NEXTSTATE(TE_UNITDATA_IND, peer_tep->te_state); 52717c478bd9Sstevel@tonic-gate putnext(peer_tep->te_rq, mp); 52727c478bd9Sstevel@tonic-gate } 52737c478bd9Sstevel@tonic-gate 52747c478bd9Sstevel@tonic-gate 52757c478bd9Sstevel@tonic-gate 52767c478bd9Sstevel@tonic-gate /* 52777c478bd9Sstevel@tonic-gate * Check if a given addr is in use. 52787c478bd9Sstevel@tonic-gate * Endpoint ptr returned or NULL if not found. 52797c478bd9Sstevel@tonic-gate * The name space is separate for each mode. This implies that 52807c478bd9Sstevel@tonic-gate * sockets get their own name space. 52817c478bd9Sstevel@tonic-gate */ 52827c478bd9Sstevel@tonic-gate static tl_endpt_t * 52837c478bd9Sstevel@tonic-gate tl_find_peer(tl_endpt_t *tep, tl_addr_t *ap) 52847c478bd9Sstevel@tonic-gate { 52857c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = NULL; 52867c478bd9Sstevel@tonic-gate int rc = mod_hash_find_cb(tep->te_addrhash, (mod_hash_key_t)ap, 52877c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&peer_tep, tl_find_callback); 52887c478bd9Sstevel@tonic-gate 52897c478bd9Sstevel@tonic-gate ASSERT(! IS_SOCKET(tep)); 52907c478bd9Sstevel@tonic-gate 52917c478bd9Sstevel@tonic-gate ASSERT(ap != NULL && ap->ta_alen > 0); 52927c478bd9Sstevel@tonic-gate ASSERT(ap->ta_zoneid == tep->te_zoneid); 52937c478bd9Sstevel@tonic-gate ASSERT(ap->ta_abuf != NULL); 529456f33205SJonathan Adams EQUIV(rc == 0, peer_tep != NULL); 529556f33205SJonathan Adams IMPLY(rc == 0, 52967c478bd9Sstevel@tonic-gate (tep->te_zoneid == peer_tep->te_zoneid) && 529756f33205SJonathan Adams (tep->te_transport == peer_tep->te_transport)); 52987c478bd9Sstevel@tonic-gate 52997c478bd9Sstevel@tonic-gate if ((rc == 0) && (peer_tep->te_closing)) { 53007c478bd9Sstevel@tonic-gate tl_refrele(peer_tep); 53017c478bd9Sstevel@tonic-gate peer_tep = NULL; 53027c478bd9Sstevel@tonic-gate } 53037c478bd9Sstevel@tonic-gate 53047c478bd9Sstevel@tonic-gate return (peer_tep); 53057c478bd9Sstevel@tonic-gate } 53067c478bd9Sstevel@tonic-gate 53077c478bd9Sstevel@tonic-gate /* 53087c478bd9Sstevel@tonic-gate * Find peer for a socket based on unix domain address. 53097c478bd9Sstevel@tonic-gate * For implicit addresses our peer can be found by minor number in ai hash. For 53109bf9355bSRic Aleshire * explicit binds we look vnode address at addr_hash. 53117c478bd9Sstevel@tonic-gate */ 53127c478bd9Sstevel@tonic-gate static tl_endpt_t * 53137c478bd9Sstevel@tonic-gate tl_sock_find_peer(tl_endpt_t *tep, soux_addr_t *ux_addr) 53147c478bd9Sstevel@tonic-gate { 53157c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = NULL; 53167c478bd9Sstevel@tonic-gate mod_hash_t *hash = ux_addr->soua_magic == SOU_MAGIC_IMPLICIT ? 53177c478bd9Sstevel@tonic-gate tep->te_aihash : tep->te_addrhash; 53187c478bd9Sstevel@tonic-gate int rc = mod_hash_find_cb(hash, (mod_hash_key_t)ux_addr->soua_vp, 53197c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&peer_tep, tl_find_callback); 53207c478bd9Sstevel@tonic-gate 53217c478bd9Sstevel@tonic-gate ASSERT(IS_SOCKET(tep)); 532256f33205SJonathan Adams EQUIV(rc == 0, peer_tep != NULL); 532356f33205SJonathan Adams IMPLY(rc == 0, (tep->te_transport == peer_tep->te_transport)); 53249bf9355bSRic Aleshire 53259bf9355bSRic Aleshire if (peer_tep != NULL) { 53269bf9355bSRic Aleshire /* Don't attempt to use closing peer. */ 53279bf9355bSRic Aleshire if (peer_tep->te_closing) 53289bf9355bSRic Aleshire goto errout; 53299bf9355bSRic Aleshire 53307c478bd9Sstevel@tonic-gate /* 53319bf9355bSRic Aleshire * Cross-zone unix sockets are permitted, but for Trusted 53329bf9355bSRic Aleshire * Extensions only, the "server" for these must be in the 53339bf9355bSRic Aleshire * global zone. 53347c478bd9Sstevel@tonic-gate */ 53359bf9355bSRic Aleshire if ((peer_tep->te_zoneid != tep->te_zoneid) && 53369bf9355bSRic Aleshire is_system_labeled() && 53379bf9355bSRic Aleshire (peer_tep->te_zoneid != GLOBAL_ZONEID)) 53389bf9355bSRic Aleshire goto errout; 53397c478bd9Sstevel@tonic-gate } 53407c478bd9Sstevel@tonic-gate 53417c478bd9Sstevel@tonic-gate return (peer_tep); 53429bf9355bSRic Aleshire 53439bf9355bSRic Aleshire errout: 53449bf9355bSRic Aleshire tl_refrele(peer_tep); 53459bf9355bSRic Aleshire return (NULL); 53467c478bd9Sstevel@tonic-gate } 53477c478bd9Sstevel@tonic-gate 53487c478bd9Sstevel@tonic-gate /* 53497c478bd9Sstevel@tonic-gate * Generate a free addr and return it in struct pointed by ap 53507c478bd9Sstevel@tonic-gate * but allocating space for address buffer. 53517c478bd9Sstevel@tonic-gate * The generated address will be at least 4 bytes long and, if req->ta_alen 53527c478bd9Sstevel@tonic-gate * exceeds 4 bytes, be req->ta_alen bytes long. 53537c478bd9Sstevel@tonic-gate * 53547c478bd9Sstevel@tonic-gate * If address is found it will be inserted in the hash. 53557c478bd9Sstevel@tonic-gate * 53567c478bd9Sstevel@tonic-gate * If req->ta_alen is larger than the default alen (4 bytes) the last 53577c478bd9Sstevel@tonic-gate * alen-4 bytes will always be the same as in req. 53587c478bd9Sstevel@tonic-gate * 53597c478bd9Sstevel@tonic-gate * Return 0 for failure. 53607c478bd9Sstevel@tonic-gate * Return non-zero for success. 53617c478bd9Sstevel@tonic-gate */ 53627c478bd9Sstevel@tonic-gate static boolean_t 53637c478bd9Sstevel@tonic-gate tl_get_any_addr(tl_endpt_t *tep, tl_addr_t *req) 53647c478bd9Sstevel@tonic-gate { 53657c478bd9Sstevel@tonic-gate t_scalar_t alen; 53667c478bd9Sstevel@tonic-gate uint32_t loopcnt; /* Limit loop to 2^32 */ 53677c478bd9Sstevel@tonic-gate 53687c478bd9Sstevel@tonic-gate ASSERT(tep->te_hash_hndl != NULL); 53697c478bd9Sstevel@tonic-gate ASSERT(! IS_SOCKET(tep)); 53707c478bd9Sstevel@tonic-gate 53717c478bd9Sstevel@tonic-gate if (tep->te_hash_hndl == NULL) 53727c478bd9Sstevel@tonic-gate return (B_FALSE); 53737c478bd9Sstevel@tonic-gate 53747c478bd9Sstevel@tonic-gate /* 53757c478bd9Sstevel@tonic-gate * check if default addr is in use 53767c478bd9Sstevel@tonic-gate * if it is - bump it and try again 53777c478bd9Sstevel@tonic-gate */ 53787c478bd9Sstevel@tonic-gate if (req == NULL) { 53797c478bd9Sstevel@tonic-gate alen = sizeof (uint32_t); 53807c478bd9Sstevel@tonic-gate } else { 53817c478bd9Sstevel@tonic-gate alen = max(req->ta_alen, sizeof (uint32_t)); 53827c478bd9Sstevel@tonic-gate ASSERT(tep->te_zoneid == req->ta_zoneid); 53837c478bd9Sstevel@tonic-gate } 53847c478bd9Sstevel@tonic-gate 53857c478bd9Sstevel@tonic-gate if (tep->te_alen < alen) { 53867c478bd9Sstevel@tonic-gate void *abuf = kmem_zalloc((size_t)alen, KM_NOSLEEP); 53877c478bd9Sstevel@tonic-gate 53887c478bd9Sstevel@tonic-gate /* 53897c478bd9Sstevel@tonic-gate * Not enough space in tep->ta_ap to hold the address, 53907c478bd9Sstevel@tonic-gate * allocate a bigger space. 53917c478bd9Sstevel@tonic-gate */ 53927c478bd9Sstevel@tonic-gate if (abuf == NULL) 53937c478bd9Sstevel@tonic-gate return (B_FALSE); 53947c478bd9Sstevel@tonic-gate 53957c478bd9Sstevel@tonic-gate if (tep->te_alen > 0) 53967c478bd9Sstevel@tonic-gate kmem_free(tep->te_abuf, tep->te_alen); 53977c478bd9Sstevel@tonic-gate 53987c478bd9Sstevel@tonic-gate tep->te_alen = alen; 53997c478bd9Sstevel@tonic-gate tep->te_abuf = abuf; 54007c478bd9Sstevel@tonic-gate } 54017c478bd9Sstevel@tonic-gate 54027c478bd9Sstevel@tonic-gate /* Copy in the address in req */ 54037c478bd9Sstevel@tonic-gate if (req != NULL) { 54047c478bd9Sstevel@tonic-gate ASSERT(alen >= req->ta_alen); 54057c478bd9Sstevel@tonic-gate bcopy(req->ta_abuf, tep->te_abuf, (size_t)req->ta_alen); 54067c478bd9Sstevel@tonic-gate } 54077c478bd9Sstevel@tonic-gate 54087c478bd9Sstevel@tonic-gate /* 54097c478bd9Sstevel@tonic-gate * First try minor number then try default addresses. 54107c478bd9Sstevel@tonic-gate */ 54117c478bd9Sstevel@tonic-gate bcopy(&tep->te_minor, tep->te_abuf, sizeof (uint32_t)); 54127c478bd9Sstevel@tonic-gate 54137c478bd9Sstevel@tonic-gate for (loopcnt = 0; loopcnt < UINT32_MAX; loopcnt++) { 54147c478bd9Sstevel@tonic-gate if (mod_hash_insert_reserve(tep->te_addrhash, 54157c478bd9Sstevel@tonic-gate (mod_hash_key_t)&tep->te_ap, (mod_hash_val_t)tep, 54167c478bd9Sstevel@tonic-gate tep->te_hash_hndl) == 0) { 54177c478bd9Sstevel@tonic-gate /* 54187c478bd9Sstevel@tonic-gate * found free address 54197c478bd9Sstevel@tonic-gate */ 54207c478bd9Sstevel@tonic-gate tep->te_flag |= TL_ADDRHASHED; 54217c478bd9Sstevel@tonic-gate tep->te_hash_hndl = NULL; 54227c478bd9Sstevel@tonic-gate 54237c478bd9Sstevel@tonic-gate return (B_TRUE); /* successful return */ 54247c478bd9Sstevel@tonic-gate } 54257c478bd9Sstevel@tonic-gate /* 54267c478bd9Sstevel@tonic-gate * Use default address. 54277c478bd9Sstevel@tonic-gate */ 54287c478bd9Sstevel@tonic-gate bcopy(&tep->te_defaddr, tep->te_abuf, sizeof (uint32_t)); 5429*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&tep->te_defaddr); 54307c478bd9Sstevel@tonic-gate } 54317c478bd9Sstevel@tonic-gate 54327c478bd9Sstevel@tonic-gate /* 54337c478bd9Sstevel@tonic-gate * Failed to find anything. 54347c478bd9Sstevel@tonic-gate */ 54357c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, -1, 1, SL_ERROR, 54367c478bd9Sstevel@tonic-gate "tl_get_any_addr:looped 2^32 times")); 54377c478bd9Sstevel@tonic-gate return (B_FALSE); 54387c478bd9Sstevel@tonic-gate } 54397c478bd9Sstevel@tonic-gate 54407c478bd9Sstevel@tonic-gate /* 54417c478bd9Sstevel@tonic-gate * reallocb + set r/w ptrs to reflect size. 54427c478bd9Sstevel@tonic-gate */ 54437c478bd9Sstevel@tonic-gate static mblk_t * 54447c478bd9Sstevel@tonic-gate tl_resizemp(mblk_t *mp, ssize_t new_size) 54457c478bd9Sstevel@tonic-gate { 54467c478bd9Sstevel@tonic-gate if ((mp = reallocb(mp, new_size, 0)) == NULL) 54477c478bd9Sstevel@tonic-gate return (NULL); 54487c478bd9Sstevel@tonic-gate 54497c478bd9Sstevel@tonic-gate mp->b_rptr = DB_BASE(mp); 54507c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + new_size; 54517c478bd9Sstevel@tonic-gate return (mp); 54527c478bd9Sstevel@tonic-gate } 54537c478bd9Sstevel@tonic-gate 54547c478bd9Sstevel@tonic-gate static void 54557c478bd9Sstevel@tonic-gate tl_cl_backenable(tl_endpt_t *tep) 54567c478bd9Sstevel@tonic-gate { 54577c478bd9Sstevel@tonic-gate list_t *l = &tep->te_flowlist; 54587c478bd9Sstevel@tonic-gate tl_endpt_t *elp; 54597c478bd9Sstevel@tonic-gate 54607c478bd9Sstevel@tonic-gate ASSERT(IS_CLTS(tep)); 54617c478bd9Sstevel@tonic-gate 54627c478bd9Sstevel@tonic-gate for (elp = list_head(l); elp != NULL; elp = list_head(l)) { 54637c478bd9Sstevel@tonic-gate ASSERT(tep->te_ser == elp->te_ser); 54647c478bd9Sstevel@tonic-gate ASSERT(elp->te_flowq == tep); 54657c478bd9Sstevel@tonic-gate if (! elp->te_closing) 54667c478bd9Sstevel@tonic-gate TL_QENABLE(elp); 54677c478bd9Sstevel@tonic-gate elp->te_flowq = NULL; 54687c478bd9Sstevel@tonic-gate list_remove(l, elp); 54697c478bd9Sstevel@tonic-gate } 54707c478bd9Sstevel@tonic-gate } 54717c478bd9Sstevel@tonic-gate 54727c478bd9Sstevel@tonic-gate /* 54737c478bd9Sstevel@tonic-gate * Unconnect endpoints. 54747c478bd9Sstevel@tonic-gate */ 54757c478bd9Sstevel@tonic-gate static void 54767c478bd9Sstevel@tonic-gate tl_co_unconnect(tl_endpt_t *tep) 54777c478bd9Sstevel@tonic-gate { 54787c478bd9Sstevel@tonic-gate tl_endpt_t *peer_tep = tep->te_conp; 54797c478bd9Sstevel@tonic-gate tl_endpt_t *srv_tep = tep->te_oconp; 54807c478bd9Sstevel@tonic-gate list_t *l; 54817c478bd9Sstevel@tonic-gate tl_icon_t *tip; 54827c478bd9Sstevel@tonic-gate tl_endpt_t *cl_tep; 54837c478bd9Sstevel@tonic-gate mblk_t *d_mp; 54847c478bd9Sstevel@tonic-gate 54857c478bd9Sstevel@tonic-gate ASSERT(IS_COTS(tep)); 54867c478bd9Sstevel@tonic-gate /* 54877c478bd9Sstevel@tonic-gate * If our peer is closing, don't use it. 54887c478bd9Sstevel@tonic-gate */ 54897c478bd9Sstevel@tonic-gate if ((peer_tep != NULL) && peer_tep->te_closing) { 54907c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_conp); 54917c478bd9Sstevel@tonic-gate peer_tep = NULL; 54927c478bd9Sstevel@tonic-gate } 54937c478bd9Sstevel@tonic-gate if ((srv_tep != NULL) && srv_tep->te_closing) { 54947c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 54957c478bd9Sstevel@tonic-gate srv_tep = NULL; 54967c478bd9Sstevel@tonic-gate } 54977c478bd9Sstevel@tonic-gate 54987c478bd9Sstevel@tonic-gate if (tep->te_nicon > 0) { 54997c478bd9Sstevel@tonic-gate l = &tep->te_iconp; 55007c478bd9Sstevel@tonic-gate /* 55017c478bd9Sstevel@tonic-gate * If incoming requests pending, change state 55027c478bd9Sstevel@tonic-gate * of clients on disconnect ind event and send 55037c478bd9Sstevel@tonic-gate * discon_ind pdu to modules above them 55047c478bd9Sstevel@tonic-gate * for server: all clients get disconnect 55057c478bd9Sstevel@tonic-gate */ 55067c478bd9Sstevel@tonic-gate 55077c478bd9Sstevel@tonic-gate while (tep->te_nicon > 0) { 55087c478bd9Sstevel@tonic-gate tip = list_head(l); 55097c478bd9Sstevel@tonic-gate cl_tep = tip->ti_tep; 55107c478bd9Sstevel@tonic-gate 55117c478bd9Sstevel@tonic-gate if (cl_tep == NULL) { 55127c478bd9Sstevel@tonic-gate tl_freetip(tep, tip); 55137c478bd9Sstevel@tonic-gate continue; 55147c478bd9Sstevel@tonic-gate } 55157c478bd9Sstevel@tonic-gate 55167c478bd9Sstevel@tonic-gate if (cl_tep->te_oconp != NULL) { 55177c478bd9Sstevel@tonic-gate ASSERT(cl_tep != cl_tep->te_oconp); 55187c478bd9Sstevel@tonic-gate TL_UNCONNECT(cl_tep->te_oconp); 55197c478bd9Sstevel@tonic-gate } 55207c478bd9Sstevel@tonic-gate 55217c478bd9Sstevel@tonic-gate if (cl_tep->te_closing) { 55227c478bd9Sstevel@tonic-gate tl_freetip(tep, tip); 55237c478bd9Sstevel@tonic-gate continue; 55247c478bd9Sstevel@tonic-gate } 55257c478bd9Sstevel@tonic-gate 55267c478bd9Sstevel@tonic-gate enableok(cl_tep->te_wq); 55277c478bd9Sstevel@tonic-gate TL_QENABLE(cl_tep); 55287c478bd9Sstevel@tonic-gate d_mp = tl_discon_ind_alloc(ECONNREFUSED, BADSEQNUM); 55297c478bd9Sstevel@tonic-gate if (d_mp != NULL) { 55307c478bd9Sstevel@tonic-gate cl_tep->te_state = TS_IDLE; 55317c478bd9Sstevel@tonic-gate putnext(cl_tep->te_rq, d_mp); 55327c478bd9Sstevel@tonic-gate } else { 55337c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 55347c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 55357c478bd9Sstevel@tonic-gate "tl_co_unconnect:icmng: " 55367c478bd9Sstevel@tonic-gate "allocb failure")); 55377c478bd9Sstevel@tonic-gate } 55387c478bd9Sstevel@tonic-gate tl_freetip(tep, tip); 55397c478bd9Sstevel@tonic-gate } 55407c478bd9Sstevel@tonic-gate } else if (srv_tep != NULL) { 55417c478bd9Sstevel@tonic-gate /* 55427c478bd9Sstevel@tonic-gate * If outgoing request pending, change state 55437c478bd9Sstevel@tonic-gate * of server on discon ind event 55447c478bd9Sstevel@tonic-gate */ 55457c478bd9Sstevel@tonic-gate 55467c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep) && !tl_disable_early_connect && 55477c478bd9Sstevel@tonic-gate IS_COTSORD(srv_tep) && 55487c478bd9Sstevel@tonic-gate !tl_icon_hasprim(srv_tep, tep->te_seqno, T_ORDREL_IND)) { 55497c478bd9Sstevel@tonic-gate /* 55507c478bd9Sstevel@tonic-gate * Queue ordrel_ind for server to be picked up 55517c478bd9Sstevel@tonic-gate * when the connection is accepted. 55527c478bd9Sstevel@tonic-gate */ 55537c478bd9Sstevel@tonic-gate d_mp = tl_ordrel_ind_alloc(); 55547c478bd9Sstevel@tonic-gate } else { 55557c478bd9Sstevel@tonic-gate /* 55567c478bd9Sstevel@tonic-gate * send discon_ind to server 55577c478bd9Sstevel@tonic-gate */ 55587c478bd9Sstevel@tonic-gate d_mp = tl_discon_ind_alloc(ECONNRESET, tep->te_seqno); 55597c478bd9Sstevel@tonic-gate } 55607c478bd9Sstevel@tonic-gate if (d_mp == NULL) { 55617c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 55627c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 55637c478bd9Sstevel@tonic-gate "tl_co_unconnect:outgoing:allocb failure")); 55647c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 55657c478bd9Sstevel@tonic-gate goto discon_peer; 55667c478bd9Sstevel@tonic-gate } 55677c478bd9Sstevel@tonic-gate 55687c478bd9Sstevel@tonic-gate /* 55697c478bd9Sstevel@tonic-gate * If this is a socket the T_DISCON_IND is queued with 55707c478bd9Sstevel@tonic-gate * the T_CONN_IND. Otherwise the T_CONN_IND is removed 55717c478bd9Sstevel@tonic-gate * from the list of pending connections. 55727c478bd9Sstevel@tonic-gate * Note that when te_oconp is set the peer better have 55737c478bd9Sstevel@tonic-gate * a t_connind_t for the client. 55747c478bd9Sstevel@tonic-gate */ 55757c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep) && !tl_disable_early_connect) { 55767c478bd9Sstevel@tonic-gate /* 55777c478bd9Sstevel@tonic-gate * Queue the disconnection message. 55787c478bd9Sstevel@tonic-gate */ 55797c478bd9Sstevel@tonic-gate tl_icon_queuemsg(srv_tep, tep->te_seqno, d_mp); 55807c478bd9Sstevel@tonic-gate } else { 55817c478bd9Sstevel@tonic-gate tip = tl_icon_find(srv_tep, tep->te_seqno); 55827c478bd9Sstevel@tonic-gate if (tip == NULL) { 55837c478bd9Sstevel@tonic-gate freemsg(d_mp); 55847c478bd9Sstevel@tonic-gate } else { 55857c478bd9Sstevel@tonic-gate ASSERT(tep == tip->ti_tep); 55867c478bd9Sstevel@tonic-gate ASSERT(tep->te_ser == srv_tep->te_ser); 55877c478bd9Sstevel@tonic-gate /* 55887c478bd9Sstevel@tonic-gate * Delete tip from the server list. 55897c478bd9Sstevel@tonic-gate */ 55907c478bd9Sstevel@tonic-gate if (srv_tep->te_nicon == 1) { 55917c478bd9Sstevel@tonic-gate srv_tep->te_state = 55927c478bd9Sstevel@tonic-gate NEXTSTATE(TE_DISCON_IND2, 55937c478bd9Sstevel@tonic-gate srv_tep->te_state); 55947c478bd9Sstevel@tonic-gate } else { 55957c478bd9Sstevel@tonic-gate srv_tep->te_state = 55967c478bd9Sstevel@tonic-gate NEXTSTATE(TE_DISCON_IND3, 55977c478bd9Sstevel@tonic-gate srv_tep->te_state); 55987c478bd9Sstevel@tonic-gate } 55997c478bd9Sstevel@tonic-gate ASSERT(*(uint32_t *)(d_mp->b_rptr) == 56007c478bd9Sstevel@tonic-gate T_DISCON_IND); 56017c478bd9Sstevel@tonic-gate putnext(srv_tep->te_rq, d_mp); 56027c478bd9Sstevel@tonic-gate tl_freetip(srv_tep, tip); 56037c478bd9Sstevel@tonic-gate } 56047c478bd9Sstevel@tonic-gate TL_UNCONNECT(tep->te_oconp); 56057c478bd9Sstevel@tonic-gate srv_tep = NULL; 56067c478bd9Sstevel@tonic-gate } 56077c478bd9Sstevel@tonic-gate } else if (peer_tep != NULL) { 56087c478bd9Sstevel@tonic-gate /* 56097c478bd9Sstevel@tonic-gate * unconnect existing connection 56107c478bd9Sstevel@tonic-gate * If connected, change state of peer on 56117c478bd9Sstevel@tonic-gate * discon ind event and send discon ind pdu 56127c478bd9Sstevel@tonic-gate * to module above it 56137c478bd9Sstevel@tonic-gate */ 56147c478bd9Sstevel@tonic-gate 56157c478bd9Sstevel@tonic-gate ASSERT(tep->te_ser == peer_tep->te_ser); 56167c478bd9Sstevel@tonic-gate if (IS_COTSORD(peer_tep) && 56177c478bd9Sstevel@tonic-gate (peer_tep->te_state == TS_WIND_ORDREL || 56187c478bd9Sstevel@tonic-gate peer_tep->te_state == TS_DATA_XFER)) { 56197c478bd9Sstevel@tonic-gate /* 56207c478bd9Sstevel@tonic-gate * send ordrel ind 56217c478bd9Sstevel@tonic-gate */ 56227c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE, 56237c478bd9Sstevel@tonic-gate "tl_co_unconnect:connected: ordrel_ind state %d->%d", 56247c478bd9Sstevel@tonic-gate peer_tep->te_state, 56257c478bd9Sstevel@tonic-gate NEXTSTATE(TE_ORDREL_IND, peer_tep->te_state))); 56267c478bd9Sstevel@tonic-gate d_mp = tl_ordrel_ind_alloc(); 56277c478bd9Sstevel@tonic-gate if (! d_mp) { 56287c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 56297c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 56307c478bd9Sstevel@tonic-gate "tl_co_unconnect:connected:" 56317c478bd9Sstevel@tonic-gate "allocb failure")); 56327c478bd9Sstevel@tonic-gate /* 56337c478bd9Sstevel@tonic-gate * Continue with cleaning up peer as 56347c478bd9Sstevel@tonic-gate * this side may go away with the close 56357c478bd9Sstevel@tonic-gate */ 56367c478bd9Sstevel@tonic-gate TL_QENABLE(peer_tep); 56377c478bd9Sstevel@tonic-gate goto discon_peer; 56387c478bd9Sstevel@tonic-gate } 56397c478bd9Sstevel@tonic-gate peer_tep->te_state = 56407c478bd9Sstevel@tonic-gate NEXTSTATE(TE_ORDREL_IND, peer_tep->te_state); 56417c478bd9Sstevel@tonic-gate 56427c478bd9Sstevel@tonic-gate putnext(peer_tep->te_rq, d_mp); 56437c478bd9Sstevel@tonic-gate /* 56447c478bd9Sstevel@tonic-gate * Handle flow control case. This will generate 56457c478bd9Sstevel@tonic-gate * a t_discon_ind message with reason 0 if there 56467c478bd9Sstevel@tonic-gate * is data queued on the write side. 56477c478bd9Sstevel@tonic-gate */ 56487c478bd9Sstevel@tonic-gate TL_QENABLE(peer_tep); 56497c478bd9Sstevel@tonic-gate } else if (IS_COTSORD(peer_tep) && 56507c478bd9Sstevel@tonic-gate peer_tep->te_state == TS_WREQ_ORDREL) { 56517c478bd9Sstevel@tonic-gate /* 56527c478bd9Sstevel@tonic-gate * Sent an ordrel_ind. We send a discon with 56537c478bd9Sstevel@tonic-gate * with error 0 to inform that the peer is gone. 56547c478bd9Sstevel@tonic-gate */ 56557c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 56567c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 56577c478bd9Sstevel@tonic-gate "tl_co_unconnect: discon in state %d", 56587c478bd9Sstevel@tonic-gate tep->te_state)); 56597c478bd9Sstevel@tonic-gate tl_discon_ind(peer_tep, 0); 56607c478bd9Sstevel@tonic-gate } else { 56617c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, 56627c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 56637c478bd9Sstevel@tonic-gate "tl_co_unconnect: state %d", tep->te_state)); 56647c478bd9Sstevel@tonic-gate tl_discon_ind(peer_tep, ECONNRESET); 56657c478bd9Sstevel@tonic-gate } 56667c478bd9Sstevel@tonic-gate 56677c478bd9Sstevel@tonic-gate discon_peer: 56687c478bd9Sstevel@tonic-gate /* 56697c478bd9Sstevel@tonic-gate * Disconnect cross-pointers only for close 56707c478bd9Sstevel@tonic-gate */ 56717c478bd9Sstevel@tonic-gate if (tep->te_closing) { 56727c478bd9Sstevel@tonic-gate peer_tep = tep->te_conp; 56737c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(peer_tep->te_conp); 56747c478bd9Sstevel@tonic-gate TL_REMOVE_PEER(tep->te_conp); 56757c478bd9Sstevel@tonic-gate } 56767c478bd9Sstevel@tonic-gate } 56777c478bd9Sstevel@tonic-gate } 56787c478bd9Sstevel@tonic-gate 56797c478bd9Sstevel@tonic-gate /* 56807c478bd9Sstevel@tonic-gate * Note: The following routine does not recover from allocb() 56817c478bd9Sstevel@tonic-gate * failures 56827c478bd9Sstevel@tonic-gate * The reason should be from the <sys/errno.h> space. 56837c478bd9Sstevel@tonic-gate */ 56847c478bd9Sstevel@tonic-gate static void 56857c478bd9Sstevel@tonic-gate tl_discon_ind(tl_endpt_t *tep, uint32_t reason) 56867c478bd9Sstevel@tonic-gate { 56877c478bd9Sstevel@tonic-gate mblk_t *d_mp; 56887c478bd9Sstevel@tonic-gate 56897c478bd9Sstevel@tonic-gate if (tep->te_closing) 56907c478bd9Sstevel@tonic-gate return; 56917c478bd9Sstevel@tonic-gate 56927c478bd9Sstevel@tonic-gate /* 56937c478bd9Sstevel@tonic-gate * flush the queues. 56947c478bd9Sstevel@tonic-gate */ 56957c478bd9Sstevel@tonic-gate flushq(tep->te_rq, FLUSHDATA); 56967c478bd9Sstevel@tonic-gate (void) putnextctl1(tep->te_rq, M_FLUSH, FLUSHRW); 56977c478bd9Sstevel@tonic-gate 56987c478bd9Sstevel@tonic-gate /* 56997c478bd9Sstevel@tonic-gate * send discon ind 57007c478bd9Sstevel@tonic-gate */ 57017c478bd9Sstevel@tonic-gate d_mp = tl_discon_ind_alloc(reason, tep->te_seqno); 57027c478bd9Sstevel@tonic-gate if (! d_mp) { 57037c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 3, SL_TRACE|SL_ERROR, 57047c478bd9Sstevel@tonic-gate "tl_discon_ind:allocb failure")); 57057c478bd9Sstevel@tonic-gate return; 57067c478bd9Sstevel@tonic-gate } 57077c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 57087c478bd9Sstevel@tonic-gate putnext(tep->te_rq, d_mp); 57097c478bd9Sstevel@tonic-gate } 57107c478bd9Sstevel@tonic-gate 57117c478bd9Sstevel@tonic-gate /* 57127c478bd9Sstevel@tonic-gate * Note: The following routine does not recover from allocb() 57137c478bd9Sstevel@tonic-gate * failures 57147c478bd9Sstevel@tonic-gate * The reason should be from the <sys/errno.h> space. 57157c478bd9Sstevel@tonic-gate */ 57167c478bd9Sstevel@tonic-gate static mblk_t * 57177c478bd9Sstevel@tonic-gate tl_discon_ind_alloc(uint32_t reason, t_scalar_t seqnum) 57187c478bd9Sstevel@tonic-gate { 57197c478bd9Sstevel@tonic-gate mblk_t *mp; 57207c478bd9Sstevel@tonic-gate struct T_discon_ind *tdi; 57217c478bd9Sstevel@tonic-gate 57227c478bd9Sstevel@tonic-gate if (mp = allocb(sizeof (struct T_discon_ind), BPRI_MED)) { 57237c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 57247c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct T_discon_ind); 57257c478bd9Sstevel@tonic-gate tdi = (struct T_discon_ind *)mp->b_rptr; 57267c478bd9Sstevel@tonic-gate tdi->PRIM_type = T_DISCON_IND; 57277c478bd9Sstevel@tonic-gate tdi->DISCON_reason = reason; 57287c478bd9Sstevel@tonic-gate tdi->SEQ_number = seqnum; 57297c478bd9Sstevel@tonic-gate } 57307c478bd9Sstevel@tonic-gate return (mp); 57317c478bd9Sstevel@tonic-gate } 57327c478bd9Sstevel@tonic-gate 57337c478bd9Sstevel@tonic-gate 57347c478bd9Sstevel@tonic-gate /* 57357c478bd9Sstevel@tonic-gate * Note: The following routine does not recover from allocb() 57367c478bd9Sstevel@tonic-gate * failures 57377c478bd9Sstevel@tonic-gate */ 57387c478bd9Sstevel@tonic-gate static mblk_t * 57397c478bd9Sstevel@tonic-gate tl_ordrel_ind_alloc(void) 57407c478bd9Sstevel@tonic-gate { 57417c478bd9Sstevel@tonic-gate mblk_t *mp; 57427c478bd9Sstevel@tonic-gate struct T_ordrel_ind *toi; 57437c478bd9Sstevel@tonic-gate 57447c478bd9Sstevel@tonic-gate if (mp = allocb(sizeof (struct T_ordrel_ind), BPRI_MED)) { 57457c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_PROTO; 57467c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct T_ordrel_ind); 57477c478bd9Sstevel@tonic-gate toi = (struct T_ordrel_ind *)mp->b_rptr; 57487c478bd9Sstevel@tonic-gate toi->PRIM_type = T_ORDREL_IND; 57497c478bd9Sstevel@tonic-gate } 57507c478bd9Sstevel@tonic-gate return (mp); 57517c478bd9Sstevel@tonic-gate } 57527c478bd9Sstevel@tonic-gate 57537c478bd9Sstevel@tonic-gate 57547c478bd9Sstevel@tonic-gate /* 57557c478bd9Sstevel@tonic-gate * Lookup the seqno in the list of queued connections. 57567c478bd9Sstevel@tonic-gate */ 57577c478bd9Sstevel@tonic-gate static tl_icon_t * 57587c478bd9Sstevel@tonic-gate tl_icon_find(tl_endpt_t *tep, t_scalar_t seqno) 57597c478bd9Sstevel@tonic-gate { 57607c478bd9Sstevel@tonic-gate list_t *l = &tep->te_iconp; 57617c478bd9Sstevel@tonic-gate tl_icon_t *tip = list_head(l); 57627c478bd9Sstevel@tonic-gate 57637c478bd9Sstevel@tonic-gate ASSERT(seqno != 0); 57647c478bd9Sstevel@tonic-gate 57657c478bd9Sstevel@tonic-gate for (; tip != NULL && (tip->ti_seqno != seqno); tip = list_next(l, tip)) 57667c478bd9Sstevel@tonic-gate ; 57677c478bd9Sstevel@tonic-gate 57687c478bd9Sstevel@tonic-gate return (tip); 57697c478bd9Sstevel@tonic-gate } 57707c478bd9Sstevel@tonic-gate 57717c478bd9Sstevel@tonic-gate /* 57727c478bd9Sstevel@tonic-gate * Queue data for a given T_CONN_IND while verifying that redundant 57737c478bd9Sstevel@tonic-gate * messages, such as a T_ORDREL_IND after a T_DISCON_IND, are not queued. 57747c478bd9Sstevel@tonic-gate * Used when the originator of the connection closes. 57757c478bd9Sstevel@tonic-gate */ 57767c478bd9Sstevel@tonic-gate static void 57777c478bd9Sstevel@tonic-gate tl_icon_queuemsg(tl_endpt_t *tep, t_scalar_t seqno, mblk_t *nmp) 57787c478bd9Sstevel@tonic-gate { 57797c478bd9Sstevel@tonic-gate tl_icon_t *tip; 57807c478bd9Sstevel@tonic-gate mblk_t **mpp, *mp; 57817c478bd9Sstevel@tonic-gate int prim, nprim; 57827c478bd9Sstevel@tonic-gate 57837c478bd9Sstevel@tonic-gate if (nmp->b_datap->db_type == M_PROTO) 57847c478bd9Sstevel@tonic-gate nprim = ((union T_primitives *)nmp->b_rptr)->type; 57857c478bd9Sstevel@tonic-gate else 57867c478bd9Sstevel@tonic-gate nprim = -1; /* M_DATA */ 57877c478bd9Sstevel@tonic-gate 57887c478bd9Sstevel@tonic-gate tip = tl_icon_find(tep, seqno); 57897c478bd9Sstevel@tonic-gate if (tip == NULL) { 57907c478bd9Sstevel@tonic-gate freemsg(nmp); 57917c478bd9Sstevel@tonic-gate return; 57927c478bd9Sstevel@tonic-gate } 57937c478bd9Sstevel@tonic-gate 57947c478bd9Sstevel@tonic-gate ASSERT(tip->ti_seqno != 0); 57957c478bd9Sstevel@tonic-gate mpp = &tip->ti_mp; 57967c478bd9Sstevel@tonic-gate while (*mpp != NULL) { 57977c478bd9Sstevel@tonic-gate mp = *mpp; 57987c478bd9Sstevel@tonic-gate 57997c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_PROTO) 58007c478bd9Sstevel@tonic-gate prim = ((union T_primitives *)mp->b_rptr)->type; 58017c478bd9Sstevel@tonic-gate else 58027c478bd9Sstevel@tonic-gate prim = -1; /* M_DATA */ 58037c478bd9Sstevel@tonic-gate 58047c478bd9Sstevel@tonic-gate /* 58057c478bd9Sstevel@tonic-gate * Allow nothing after a T_DISCON_IND 58067c478bd9Sstevel@tonic-gate */ 58077c478bd9Sstevel@tonic-gate if (prim == T_DISCON_IND) { 58087c478bd9Sstevel@tonic-gate freemsg(nmp); 58097c478bd9Sstevel@tonic-gate return; 58107c478bd9Sstevel@tonic-gate } 58117c478bd9Sstevel@tonic-gate /* 58127c478bd9Sstevel@tonic-gate * Only allow a T_DISCON_IND after an T_ORDREL_IND 58137c478bd9Sstevel@tonic-gate */ 58147c478bd9Sstevel@tonic-gate if (prim == T_ORDREL_IND && nprim != T_DISCON_IND) { 58157c478bd9Sstevel@tonic-gate freemsg(nmp); 58167c478bd9Sstevel@tonic-gate return; 58177c478bd9Sstevel@tonic-gate } 58187c478bd9Sstevel@tonic-gate mpp = &(mp->b_next); 58197c478bd9Sstevel@tonic-gate } 58207c478bd9Sstevel@tonic-gate *mpp = nmp; 58217c478bd9Sstevel@tonic-gate } 58227c478bd9Sstevel@tonic-gate 58237c478bd9Sstevel@tonic-gate /* 58247c478bd9Sstevel@tonic-gate * Verify if a certain TPI primitive exists on the connind queue. 58257c478bd9Sstevel@tonic-gate * Use prim -1 for M_DATA. 58267c478bd9Sstevel@tonic-gate * Return non-zero if found. 58277c478bd9Sstevel@tonic-gate */ 58287c478bd9Sstevel@tonic-gate static boolean_t 58297c478bd9Sstevel@tonic-gate tl_icon_hasprim(tl_endpt_t *tep, t_scalar_t seqno, t_scalar_t prim) 58307c478bd9Sstevel@tonic-gate { 58317c478bd9Sstevel@tonic-gate tl_icon_t *tip = tl_icon_find(tep, seqno); 58327c478bd9Sstevel@tonic-gate boolean_t found = B_FALSE; 58337c478bd9Sstevel@tonic-gate 58347c478bd9Sstevel@tonic-gate if (tip != NULL) { 58357c478bd9Sstevel@tonic-gate mblk_t *mp; 58367c478bd9Sstevel@tonic-gate for (mp = tip->ti_mp; !found && mp != NULL; mp = mp->b_next) { 58377c478bd9Sstevel@tonic-gate found = (DB_TYPE(mp) == M_PROTO && 58387c478bd9Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type == prim); 58397c478bd9Sstevel@tonic-gate } 58407c478bd9Sstevel@tonic-gate } 58417c478bd9Sstevel@tonic-gate return (found); 58427c478bd9Sstevel@tonic-gate } 58437c478bd9Sstevel@tonic-gate 58447c478bd9Sstevel@tonic-gate /* 58457c478bd9Sstevel@tonic-gate * Send the b_next mblk chain that has accumulated before the connection 58467c478bd9Sstevel@tonic-gate * was accepted. Perform the necessary state transitions. 58477c478bd9Sstevel@tonic-gate */ 58487c478bd9Sstevel@tonic-gate static void 58497c478bd9Sstevel@tonic-gate tl_icon_sendmsgs(tl_endpt_t *tep, mblk_t **mpp) 58507c478bd9Sstevel@tonic-gate { 58517c478bd9Sstevel@tonic-gate mblk_t *mp; 58527c478bd9Sstevel@tonic-gate union T_primitives *primp; 58537c478bd9Sstevel@tonic-gate 58547c478bd9Sstevel@tonic-gate if (tep->te_closing) { 58557c478bd9Sstevel@tonic-gate tl_icon_freemsgs(mpp); 58567c478bd9Sstevel@tonic-gate return; 58577c478bd9Sstevel@tonic-gate } 58587c478bd9Sstevel@tonic-gate 58597c478bd9Sstevel@tonic-gate ASSERT(tep->te_state == TS_DATA_XFER); 58607c478bd9Sstevel@tonic-gate ASSERT(tep->te_rq->q_first == NULL); 58617c478bd9Sstevel@tonic-gate 58627c478bd9Sstevel@tonic-gate while ((mp = *mpp) != NULL) { 58637c478bd9Sstevel@tonic-gate *mpp = mp->b_next; 58647c478bd9Sstevel@tonic-gate mp->b_next = NULL; 58657c478bd9Sstevel@tonic-gate 58667c478bd9Sstevel@tonic-gate ASSERT((DB_TYPE(mp) == M_DATA) || (DB_TYPE(mp) == M_PROTO)); 58677c478bd9Sstevel@tonic-gate switch (DB_TYPE(mp)) { 58687c478bd9Sstevel@tonic-gate default: 58697c478bd9Sstevel@tonic-gate freemsg(mp); 58707c478bd9Sstevel@tonic-gate break; 58717c478bd9Sstevel@tonic-gate case M_DATA: 58727c478bd9Sstevel@tonic-gate putnext(tep->te_rq, mp); 58737c478bd9Sstevel@tonic-gate break; 58747c478bd9Sstevel@tonic-gate case M_PROTO: 58757c478bd9Sstevel@tonic-gate primp = (union T_primitives *)mp->b_rptr; 58767c478bd9Sstevel@tonic-gate switch (primp->type) { 58777c478bd9Sstevel@tonic-gate case T_UNITDATA_IND: 58787c478bd9Sstevel@tonic-gate case T_DATA_IND: 58797c478bd9Sstevel@tonic-gate case T_OPTDATA_IND: 58807c478bd9Sstevel@tonic-gate case T_EXDATA_IND: 58817c478bd9Sstevel@tonic-gate putnext(tep->te_rq, mp); 58827c478bd9Sstevel@tonic-gate break; 58837c478bd9Sstevel@tonic-gate case T_ORDREL_IND: 58847c478bd9Sstevel@tonic-gate tep->te_state = NEXTSTATE(TE_ORDREL_IND, 58857c478bd9Sstevel@tonic-gate tep->te_state); 58867c478bd9Sstevel@tonic-gate putnext(tep->te_rq, mp); 58877c478bd9Sstevel@tonic-gate break; 58887c478bd9Sstevel@tonic-gate case T_DISCON_IND: 58897c478bd9Sstevel@tonic-gate tep->te_state = TS_IDLE; 58907c478bd9Sstevel@tonic-gate putnext(tep->te_rq, mp); 58917c478bd9Sstevel@tonic-gate break; 58927c478bd9Sstevel@tonic-gate default: 58937c478bd9Sstevel@tonic-gate #ifdef DEBUG 58947c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, 58957c478bd9Sstevel@tonic-gate "tl_icon_sendmsgs: unknown primitive"); 58967c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 58977c478bd9Sstevel@tonic-gate freemsg(mp); 58987c478bd9Sstevel@tonic-gate break; 58997c478bd9Sstevel@tonic-gate } 59007c478bd9Sstevel@tonic-gate break; 59017c478bd9Sstevel@tonic-gate } 59027c478bd9Sstevel@tonic-gate } 59037c478bd9Sstevel@tonic-gate } 59047c478bd9Sstevel@tonic-gate 59057c478bd9Sstevel@tonic-gate /* 59067c478bd9Sstevel@tonic-gate * Free the b_next mblk chain that has accumulated before the connection 59077c478bd9Sstevel@tonic-gate * was accepted. 59087c478bd9Sstevel@tonic-gate */ 59097c478bd9Sstevel@tonic-gate static void 59107c478bd9Sstevel@tonic-gate tl_icon_freemsgs(mblk_t **mpp) 59117c478bd9Sstevel@tonic-gate { 59127c478bd9Sstevel@tonic-gate mblk_t *mp; 59137c478bd9Sstevel@tonic-gate 59147c478bd9Sstevel@tonic-gate while ((mp = *mpp) != NULL) { 59157c478bd9Sstevel@tonic-gate *mpp = mp->b_next; 59167c478bd9Sstevel@tonic-gate mp->b_next = NULL; 59177c478bd9Sstevel@tonic-gate freemsg(mp); 59187c478bd9Sstevel@tonic-gate } 59197c478bd9Sstevel@tonic-gate } 59207c478bd9Sstevel@tonic-gate 59217c478bd9Sstevel@tonic-gate /* 59227c478bd9Sstevel@tonic-gate * Send M_ERROR 59237c478bd9Sstevel@tonic-gate * Note: assumes caller ensured enough space in mp or enough 59247c478bd9Sstevel@tonic-gate * memory available. Does not attempt recovery from allocb() 59257c478bd9Sstevel@tonic-gate * failures 59267c478bd9Sstevel@tonic-gate */ 59277c478bd9Sstevel@tonic-gate 59287c478bd9Sstevel@tonic-gate static void 59297c478bd9Sstevel@tonic-gate tl_merror(queue_t *wq, mblk_t *mp, int error) 59307c478bd9Sstevel@tonic-gate { 59317c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)wq->q_ptr; 59327c478bd9Sstevel@tonic-gate 59337c478bd9Sstevel@tonic-gate if (tep->te_closing) { 59347c478bd9Sstevel@tonic-gate freemsg(mp); 59357c478bd9Sstevel@tonic-gate return; 59367c478bd9Sstevel@tonic-gate } 59377c478bd9Sstevel@tonic-gate 59387c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 59397c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 5940903a11ebSrh87107 "tl_merror: tep=%p, err=%d", (void *)tep, error)); 59417c478bd9Sstevel@tonic-gate 59427c478bd9Sstevel@tonic-gate /* 59437c478bd9Sstevel@tonic-gate * flush all messages on queue. we are shutting 59447c478bd9Sstevel@tonic-gate * the stream down on fatal error 59457c478bd9Sstevel@tonic-gate */ 59467c478bd9Sstevel@tonic-gate flushq(wq, FLUSHALL); 59477c478bd9Sstevel@tonic-gate if (IS_COTS(tep)) { 59487c478bd9Sstevel@tonic-gate /* connection oriented - unconnect endpoints */ 59497c478bd9Sstevel@tonic-gate tl_co_unconnect(tep); 59507c478bd9Sstevel@tonic-gate } 59517c478bd9Sstevel@tonic-gate if (mp->b_cont) { 59527c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 59537c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 59547c478bd9Sstevel@tonic-gate } 59557c478bd9Sstevel@tonic-gate 59567c478bd9Sstevel@tonic-gate if ((MBLKSIZE(mp) < 1) || (DB_REF(mp) > 1)) { 59577c478bd9Sstevel@tonic-gate freemsg(mp); 59587c478bd9Sstevel@tonic-gate mp = allocb(1, BPRI_HI); 59597c478bd9Sstevel@tonic-gate if (!mp) { 59607c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 59617c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 59627c478bd9Sstevel@tonic-gate "tl_merror:M_PROTO: out of memory")); 59637c478bd9Sstevel@tonic-gate return; 59647c478bd9Sstevel@tonic-gate } 59657c478bd9Sstevel@tonic-gate } 59667c478bd9Sstevel@tonic-gate if (mp) { 59677c478bd9Sstevel@tonic-gate DB_TYPE(mp) = M_ERROR; 59687c478bd9Sstevel@tonic-gate mp->b_rptr = DB_BASE(mp); 59697c478bd9Sstevel@tonic-gate *mp->b_rptr = (char)error; 59707c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (char); 59717c478bd9Sstevel@tonic-gate qreply(wq, mp); 59727c478bd9Sstevel@tonic-gate } else { 59737c478bd9Sstevel@tonic-gate (void) putnextctl1(tep->te_rq, M_ERROR, error); 59747c478bd9Sstevel@tonic-gate } 59757c478bd9Sstevel@tonic-gate } 59767c478bd9Sstevel@tonic-gate 59777c478bd9Sstevel@tonic-gate static void 597845916cd2Sjpk tl_fill_option(uchar_t *buf, cred_t *cr, pid_t cpid, int flag, cred_t *pcr) 59797c478bd9Sstevel@tonic-gate { 5980de8c4a14SErik Nordmark ASSERT(cr != NULL); 5981de8c4a14SErik Nordmark 59827c478bd9Sstevel@tonic-gate if (flag & TL_SETCRED) { 59837c478bd9Sstevel@tonic-gate struct opthdr *opt = (struct opthdr *)buf; 59847c478bd9Sstevel@tonic-gate tl_credopt_t *tlcred; 59857c478bd9Sstevel@tonic-gate 59867c478bd9Sstevel@tonic-gate opt->level = TL_PROT_LEVEL; 59877c478bd9Sstevel@tonic-gate opt->name = TL_OPT_PEER_CRED; 59887c478bd9Sstevel@tonic-gate opt->len = (t_uscalar_t)OPTLEN(sizeof (tl_credopt_t)); 59897c478bd9Sstevel@tonic-gate 59907c478bd9Sstevel@tonic-gate tlcred = (tl_credopt_t *)(opt + 1); 59917c478bd9Sstevel@tonic-gate tlcred->tc_uid = crgetuid(cr); 59927c478bd9Sstevel@tonic-gate tlcred->tc_gid = crgetgid(cr); 59937c478bd9Sstevel@tonic-gate tlcred->tc_ruid = crgetruid(cr); 59947c478bd9Sstevel@tonic-gate tlcred->tc_rgid = crgetrgid(cr); 59957c478bd9Sstevel@tonic-gate tlcred->tc_suid = crgetsuid(cr); 59967c478bd9Sstevel@tonic-gate tlcred->tc_sgid = crgetsgid(cr); 59977c478bd9Sstevel@tonic-gate tlcred->tc_ngroups = crgetngroups(cr); 59987c478bd9Sstevel@tonic-gate } else if (flag & TL_SETUCRED) { 59997c478bd9Sstevel@tonic-gate struct opthdr *opt = (struct opthdr *)buf; 60007c478bd9Sstevel@tonic-gate 60017c478bd9Sstevel@tonic-gate opt->level = TL_PROT_LEVEL; 60027c478bd9Sstevel@tonic-gate opt->name = TL_OPT_PEER_UCRED; 600367dbe2beSCasper H.S. Dik opt->len = (t_uscalar_t)OPTLEN(ucredminsize(cr)); 60047c478bd9Sstevel@tonic-gate 600545916cd2Sjpk (void) cred2ucred(cr, cpid, (void *)(opt + 1), pcr); 60067c478bd9Sstevel@tonic-gate } else { 60077c478bd9Sstevel@tonic-gate struct T_opthdr *topt = (struct T_opthdr *)buf; 60087c478bd9Sstevel@tonic-gate ASSERT(flag & TL_SOCKUCRED); 60097c478bd9Sstevel@tonic-gate 60107c478bd9Sstevel@tonic-gate topt->level = SOL_SOCKET; 60117c478bd9Sstevel@tonic-gate topt->name = SCM_UCRED; 601267dbe2beSCasper H.S. Dik topt->len = ucredminsize(cr) + sizeof (*topt); 60137c478bd9Sstevel@tonic-gate topt->status = 0; 601445916cd2Sjpk (void) cred2ucred(cr, cpid, (void *)(topt + 1), pcr); 60157c478bd9Sstevel@tonic-gate } 60167c478bd9Sstevel@tonic-gate } 60177c478bd9Sstevel@tonic-gate 60187c478bd9Sstevel@tonic-gate /* ARGSUSED */ 60197c478bd9Sstevel@tonic-gate static int 60207c478bd9Sstevel@tonic-gate tl_default_opt(queue_t *wq, int level, int name, uchar_t *ptr) 60217c478bd9Sstevel@tonic-gate { 60227c478bd9Sstevel@tonic-gate /* no default value processed in protocol specific code currently */ 60237c478bd9Sstevel@tonic-gate return (-1); 60247c478bd9Sstevel@tonic-gate } 60257c478bd9Sstevel@tonic-gate 60267c478bd9Sstevel@tonic-gate /* ARGSUSED */ 60277c478bd9Sstevel@tonic-gate static int 60287c478bd9Sstevel@tonic-gate tl_get_opt(queue_t *wq, int level, int name, uchar_t *ptr) 60297c478bd9Sstevel@tonic-gate { 60307c478bd9Sstevel@tonic-gate int len; 60317c478bd9Sstevel@tonic-gate tl_endpt_t *tep; 60327c478bd9Sstevel@tonic-gate int *valp; 60337c478bd9Sstevel@tonic-gate 60347c478bd9Sstevel@tonic-gate tep = (tl_endpt_t *)wq->q_ptr; 60357c478bd9Sstevel@tonic-gate 60367c478bd9Sstevel@tonic-gate len = 0; 60377c478bd9Sstevel@tonic-gate 60387c478bd9Sstevel@tonic-gate /* 60397c478bd9Sstevel@tonic-gate * Assumes: option level and name sanity check done elsewhere 60407c478bd9Sstevel@tonic-gate */ 60417c478bd9Sstevel@tonic-gate 60427c478bd9Sstevel@tonic-gate switch (level) { 60437c478bd9Sstevel@tonic-gate case SOL_SOCKET: 60447c478bd9Sstevel@tonic-gate if (! IS_SOCKET(tep)) 60457c478bd9Sstevel@tonic-gate break; 60467c478bd9Sstevel@tonic-gate switch (name) { 60477c478bd9Sstevel@tonic-gate case SO_RECVUCRED: 60487c478bd9Sstevel@tonic-gate len = sizeof (int); 60497c478bd9Sstevel@tonic-gate valp = (int *)ptr; 60507c478bd9Sstevel@tonic-gate *valp = (tep->te_flag & TL_SOCKUCRED) != 0; 60517c478bd9Sstevel@tonic-gate break; 60527c478bd9Sstevel@tonic-gate default: 60537c478bd9Sstevel@tonic-gate break; 60547c478bd9Sstevel@tonic-gate } 60557c478bd9Sstevel@tonic-gate break; 60567c478bd9Sstevel@tonic-gate case TL_PROT_LEVEL: 60577c478bd9Sstevel@tonic-gate switch (name) { 60587c478bd9Sstevel@tonic-gate case TL_OPT_PEER_CRED: 60597c478bd9Sstevel@tonic-gate case TL_OPT_PEER_UCRED: 60607c478bd9Sstevel@tonic-gate /* 60617c478bd9Sstevel@tonic-gate * option not supposed to retrieved directly 60627c478bd9Sstevel@tonic-gate * Only sent in T_CON_{IND,CON}, T_UNITDATA_IND 60637c478bd9Sstevel@tonic-gate * when some internal flags set by other options 60647c478bd9Sstevel@tonic-gate * Direct retrieval always designed to fail(ignored) 60657c478bd9Sstevel@tonic-gate * for this option. 60667c478bd9Sstevel@tonic-gate */ 60677c478bd9Sstevel@tonic-gate break; 60687c478bd9Sstevel@tonic-gate } 60697c478bd9Sstevel@tonic-gate } 60707c478bd9Sstevel@tonic-gate return (len); 60717c478bd9Sstevel@tonic-gate } 60727c478bd9Sstevel@tonic-gate 60737c478bd9Sstevel@tonic-gate /* ARGSUSED */ 60747c478bd9Sstevel@tonic-gate static int 60757c478bd9Sstevel@tonic-gate tl_set_opt( 60767c478bd9Sstevel@tonic-gate queue_t *wq, 60777c478bd9Sstevel@tonic-gate uint_t mgmt_flags, 60787c478bd9Sstevel@tonic-gate int level, 60797c478bd9Sstevel@tonic-gate int name, 60807c478bd9Sstevel@tonic-gate uint_t inlen, 60817c478bd9Sstevel@tonic-gate uchar_t *invalp, 60827c478bd9Sstevel@tonic-gate uint_t *outlenp, 60837c478bd9Sstevel@tonic-gate uchar_t *outvalp, 60847c478bd9Sstevel@tonic-gate void *thisdg_attrs, 6085bd670b35SErik Nordmark cred_t *cr) 60867c478bd9Sstevel@tonic-gate { 60877c478bd9Sstevel@tonic-gate int error; 60887c478bd9Sstevel@tonic-gate tl_endpt_t *tep; 60897c478bd9Sstevel@tonic-gate 60907c478bd9Sstevel@tonic-gate tep = (tl_endpt_t *)wq->q_ptr; 60917c478bd9Sstevel@tonic-gate 60927c478bd9Sstevel@tonic-gate error = 0; /* NOERROR */ 60937c478bd9Sstevel@tonic-gate 60947c478bd9Sstevel@tonic-gate /* 60957c478bd9Sstevel@tonic-gate * Assumes: option level and name sanity checks done elsewhere 60967c478bd9Sstevel@tonic-gate */ 60977c478bd9Sstevel@tonic-gate 60987c478bd9Sstevel@tonic-gate switch (level) { 60997c478bd9Sstevel@tonic-gate case SOL_SOCKET: 61007c478bd9Sstevel@tonic-gate if (! IS_SOCKET(tep)) { 61017c478bd9Sstevel@tonic-gate error = EINVAL; 61027c478bd9Sstevel@tonic-gate break; 61037c478bd9Sstevel@tonic-gate } 61047c478bd9Sstevel@tonic-gate /* 61057c478bd9Sstevel@tonic-gate * TBD: fill in other AF_UNIX socket options and then stop 61067c478bd9Sstevel@tonic-gate * returning error. 61077c478bd9Sstevel@tonic-gate */ 61087c478bd9Sstevel@tonic-gate switch (name) { 61097c478bd9Sstevel@tonic-gate case SO_RECVUCRED: 61107c478bd9Sstevel@tonic-gate /* 61117c478bd9Sstevel@tonic-gate * We only support this for datagram sockets; 61127c478bd9Sstevel@tonic-gate * getpeerucred handles the connection oriented 61137c478bd9Sstevel@tonic-gate * transports. 61147c478bd9Sstevel@tonic-gate */ 61157c478bd9Sstevel@tonic-gate if (! IS_CLTS(tep)) { 61167c478bd9Sstevel@tonic-gate error = EINVAL; 61177c478bd9Sstevel@tonic-gate break; 61187c478bd9Sstevel@tonic-gate } 61197c478bd9Sstevel@tonic-gate if (*(int *)invalp == 0) 61207c478bd9Sstevel@tonic-gate tep->te_flag &= ~TL_SOCKUCRED; 61217c478bd9Sstevel@tonic-gate else 61227c478bd9Sstevel@tonic-gate tep->te_flag |= TL_SOCKUCRED; 61237c478bd9Sstevel@tonic-gate break; 61247c478bd9Sstevel@tonic-gate default: 61257c478bd9Sstevel@tonic-gate error = EINVAL; 61267c478bd9Sstevel@tonic-gate break; 61277c478bd9Sstevel@tonic-gate } 61287c478bd9Sstevel@tonic-gate break; 61297c478bd9Sstevel@tonic-gate case TL_PROT_LEVEL: 61307c478bd9Sstevel@tonic-gate switch (name) { 61317c478bd9Sstevel@tonic-gate case TL_OPT_PEER_CRED: 61327c478bd9Sstevel@tonic-gate case TL_OPT_PEER_UCRED: 61337c478bd9Sstevel@tonic-gate /* 61347c478bd9Sstevel@tonic-gate * option not supposed to be set directly 61357c478bd9Sstevel@tonic-gate * Its value in initialized for each endpoint at 61367c478bd9Sstevel@tonic-gate * driver open time. 61377c478bd9Sstevel@tonic-gate * Direct setting always designed to fail for this 61387c478bd9Sstevel@tonic-gate * option. 61397c478bd9Sstevel@tonic-gate */ 61407c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, 61417c478bd9Sstevel@tonic-gate SL_TRACE|SL_ERROR, 61427c478bd9Sstevel@tonic-gate "tl_set_opt: option is not supported")); 61437c478bd9Sstevel@tonic-gate error = EPROTO; 61447c478bd9Sstevel@tonic-gate break; 61457c478bd9Sstevel@tonic-gate } 61467c478bd9Sstevel@tonic-gate } 61477c478bd9Sstevel@tonic-gate return (error); 61487c478bd9Sstevel@tonic-gate } 61497c478bd9Sstevel@tonic-gate 61507c478bd9Sstevel@tonic-gate 61517c478bd9Sstevel@tonic-gate static void 61527c478bd9Sstevel@tonic-gate tl_timer(void *arg) 61537c478bd9Sstevel@tonic-gate { 61547c478bd9Sstevel@tonic-gate queue_t *wq = arg; 61557c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)wq->q_ptr; 61567c478bd9Sstevel@tonic-gate 61577c478bd9Sstevel@tonic-gate ASSERT(tep); 61587c478bd9Sstevel@tonic-gate 61597c478bd9Sstevel@tonic-gate tep->te_timoutid = 0; 61607c478bd9Sstevel@tonic-gate 61617c478bd9Sstevel@tonic-gate enableok(wq); 61627c478bd9Sstevel@tonic-gate /* 61637c478bd9Sstevel@tonic-gate * Note: can call wsrv directly here and save context switch 61647c478bd9Sstevel@tonic-gate * Consider change when qtimeout (not timeout) is active 61657c478bd9Sstevel@tonic-gate */ 61667c478bd9Sstevel@tonic-gate qenable(wq); 61677c478bd9Sstevel@tonic-gate } 61687c478bd9Sstevel@tonic-gate 61697c478bd9Sstevel@tonic-gate static void 61707c478bd9Sstevel@tonic-gate tl_buffer(void *arg) 61717c478bd9Sstevel@tonic-gate { 61727c478bd9Sstevel@tonic-gate queue_t *wq = arg; 61737c478bd9Sstevel@tonic-gate tl_endpt_t *tep = (tl_endpt_t *)wq->q_ptr; 61747c478bd9Sstevel@tonic-gate 61757c478bd9Sstevel@tonic-gate ASSERT(tep); 61767c478bd9Sstevel@tonic-gate 61777c478bd9Sstevel@tonic-gate tep->te_bufcid = 0; 61787c478bd9Sstevel@tonic-gate tep->te_nowsrv = B_FALSE; 61797c478bd9Sstevel@tonic-gate 61807c478bd9Sstevel@tonic-gate enableok(wq); 61817c478bd9Sstevel@tonic-gate /* 61827c478bd9Sstevel@tonic-gate * Note: can call wsrv directly here and save context switch 61837c478bd9Sstevel@tonic-gate * Consider change when qbufcall (not bufcall) is active 61847c478bd9Sstevel@tonic-gate */ 61857c478bd9Sstevel@tonic-gate qenable(wq); 61867c478bd9Sstevel@tonic-gate } 61877c478bd9Sstevel@tonic-gate 61887c478bd9Sstevel@tonic-gate static void 61897c478bd9Sstevel@tonic-gate tl_memrecover(queue_t *wq, mblk_t *mp, size_t size) 61907c478bd9Sstevel@tonic-gate { 61917c478bd9Sstevel@tonic-gate tl_endpt_t *tep; 61927c478bd9Sstevel@tonic-gate 61937c478bd9Sstevel@tonic-gate tep = (tl_endpt_t *)wq->q_ptr; 61947c478bd9Sstevel@tonic-gate 61957c478bd9Sstevel@tonic-gate if (tep->te_closing) { 61967c478bd9Sstevel@tonic-gate freemsg(mp); 61977c478bd9Sstevel@tonic-gate return; 61987c478bd9Sstevel@tonic-gate } 61997c478bd9Sstevel@tonic-gate noenable(wq); 62007c478bd9Sstevel@tonic-gate 62017c478bd9Sstevel@tonic-gate (void) insq(wq, wq->q_first, mp); 62027c478bd9Sstevel@tonic-gate 62037c478bd9Sstevel@tonic-gate if (tep->te_bufcid || tep->te_timoutid) { 62047c478bd9Sstevel@tonic-gate (void) (STRLOG(TL_ID, tep->te_minor, 1, SL_TRACE|SL_ERROR, 62057c478bd9Sstevel@tonic-gate "tl_memrecover:recover %p pending", (void *)wq)); 62067c478bd9Sstevel@tonic-gate return; 62077c478bd9Sstevel@tonic-gate } 62087c478bd9Sstevel@tonic-gate 62097c478bd9Sstevel@tonic-gate if (!(tep->te_bufcid = qbufcall(wq, size, BPRI_MED, tl_buffer, wq))) { 62107c478bd9Sstevel@tonic-gate tep->te_timoutid = qtimeout(wq, tl_timer, wq, 62117c478bd9Sstevel@tonic-gate drv_usectohz(TL_BUFWAIT)); 62127c478bd9Sstevel@tonic-gate } 62137c478bd9Sstevel@tonic-gate } 62147c478bd9Sstevel@tonic-gate 62157c478bd9Sstevel@tonic-gate static void 62167c478bd9Sstevel@tonic-gate tl_freetip(tl_endpt_t *tep, tl_icon_t *tip) 62177c478bd9Sstevel@tonic-gate { 62187c478bd9Sstevel@tonic-gate ASSERT(tip->ti_seqno != 0); 62197c478bd9Sstevel@tonic-gate 62207c478bd9Sstevel@tonic-gate if (tip->ti_mp != NULL) { 62217c478bd9Sstevel@tonic-gate tl_icon_freemsgs(&tip->ti_mp); 62227c478bd9Sstevel@tonic-gate tip->ti_mp = NULL; 62237c478bd9Sstevel@tonic-gate } 62247c478bd9Sstevel@tonic-gate if (tip->ti_tep != NULL) { 62257c478bd9Sstevel@tonic-gate tl_refrele(tip->ti_tep); 62267c478bd9Sstevel@tonic-gate tip->ti_tep = NULL; 62277c478bd9Sstevel@tonic-gate } 62287c478bd9Sstevel@tonic-gate list_remove(&tep->te_iconp, tip); 62297c478bd9Sstevel@tonic-gate kmem_free(tip, sizeof (tl_icon_t)); 62307c478bd9Sstevel@tonic-gate tep->te_nicon--; 62317c478bd9Sstevel@tonic-gate } 62327c478bd9Sstevel@tonic-gate 62337c478bd9Sstevel@tonic-gate /* 62347c478bd9Sstevel@tonic-gate * Remove address from address hash. 62357c478bd9Sstevel@tonic-gate */ 62367c478bd9Sstevel@tonic-gate static void 62377c478bd9Sstevel@tonic-gate tl_addr_unbind(tl_endpt_t *tep) 62387c478bd9Sstevel@tonic-gate { 62397c478bd9Sstevel@tonic-gate tl_endpt_t *elp; 62407c478bd9Sstevel@tonic-gate 62417c478bd9Sstevel@tonic-gate if (tep->te_flag & TL_ADDRHASHED) { 62427c478bd9Sstevel@tonic-gate if (IS_SOCKET(tep)) { 62437c478bd9Sstevel@tonic-gate (void) mod_hash_remove(tep->te_addrhash, 62447c478bd9Sstevel@tonic-gate (mod_hash_key_t)tep->te_vp, 62457c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&elp); 62467c478bd9Sstevel@tonic-gate tep->te_vp = (void *)(uintptr_t)tep->te_minor; 62477c478bd9Sstevel@tonic-gate tep->te_magic = SOU_MAGIC_IMPLICIT; 62487c478bd9Sstevel@tonic-gate } else { 62497c478bd9Sstevel@tonic-gate (void) mod_hash_remove(tep->te_addrhash, 62507c478bd9Sstevel@tonic-gate (mod_hash_key_t)&tep->te_ap, 62517c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&elp); 62527c478bd9Sstevel@tonic-gate (void) kmem_free(tep->te_abuf, tep->te_alen); 62537c478bd9Sstevel@tonic-gate tep->te_alen = -1; 62547c478bd9Sstevel@tonic-gate tep->te_abuf = NULL; 62557c478bd9Sstevel@tonic-gate } 62567c478bd9Sstevel@tonic-gate tep->te_flag &= ~TL_ADDRHASHED; 62577c478bd9Sstevel@tonic-gate } 62587c478bd9Sstevel@tonic-gate } 6259