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