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