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