xref: /onnv-gate/usr/src/uts/common/inet/ip/rts.c (revision 4365:81df93c194d3)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53388Skcpoon  * Common Development and Distribution License (the "License").
63388Skcpoon  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223388Skcpoon  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/stream.h>
300Sstevel@tonic-gate #include <sys/strsubr.h>
310Sstevel@tonic-gate #include <sys/stropts.h>
320Sstevel@tonic-gate #include <sys/strsun.h>
330Sstevel@tonic-gate #include <sys/strlog.h>
340Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
350Sstevel@tonic-gate #include <sys/tihdr.h>
360Sstevel@tonic-gate #include <sys/timod.h>
370Sstevel@tonic-gate #include <sys/ddi.h>
380Sstevel@tonic-gate #include <sys/sunddi.h>
390Sstevel@tonic-gate #include <sys/cmn_err.h>
400Sstevel@tonic-gate #include <sys/proc.h>
410Sstevel@tonic-gate #include <sys/suntpi.h>
420Sstevel@tonic-gate #include <sys/policy.h>
433448Sdh155122 #include <sys/zone.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <sys/socket.h>
460Sstevel@tonic-gate #include <netinet/in.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <inet/common.h>
490Sstevel@tonic-gate #include <netinet/ip6.h>
500Sstevel@tonic-gate #include <inet/ip.h>
510Sstevel@tonic-gate #include <inet/mi.h>
520Sstevel@tonic-gate #include <inet/nd.h>
530Sstevel@tonic-gate #include <inet/optcom.h>
540Sstevel@tonic-gate #include <netinet/ip_mroute.h>
550Sstevel@tonic-gate #include <sys/isa_defs.h>
560Sstevel@tonic-gate #include <net/route.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * This is a transport provider for routing sockets.  Downstream messages are
600Sstevel@tonic-gate  * wrapped with a IP_IOCTL header, and ip_wput_ioctl calls the appropriate entry
610Sstevel@tonic-gate  * in the ip_ioctl_ftbl callout table to pass the routing socket data into IP.
620Sstevel@tonic-gate  * Upstream messages are generated for listeners of the routing socket as well
630Sstevel@tonic-gate  * as the message sender (unless they have turned off their end using
640Sstevel@tonic-gate  * SO_USELOOPBACK or shutdown(3n)).  Upstream messages may also be generated
650Sstevel@tonic-gate  * asynchronously when:
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  *	Interfaces are brought up or down.
680Sstevel@tonic-gate  *	Addresses are assigned to interfaces.
69*4365Snordmark  *	ICMP redirects are processed and a IRE_HOST/RTF_DYNAMIC is installed.
700Sstevel@tonic-gate  *	No route is found while sending a packet.
710Sstevel@tonic-gate  *	When TCP requests IP to remove an IRE_CACHE of a troubled destination.
720Sstevel@tonic-gate  *
730Sstevel@tonic-gate  * Since all we do is reformat the messages between routing socket and
740Sstevel@tonic-gate  * ioctl forms, no synchronization is necessary in this module; all
750Sstevel@tonic-gate  * the dirty work is done down in ip.
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
793448Sdh155122  * RTS stack instances
803448Sdh155122  */
813448Sdh155122 struct rts_stack {
823448Sdh155122 	netstack_t		*rtss_netstack;	/* Common netstack */
833448Sdh155122 
843448Sdh155122 	caddr_t			rtss_g_nd;
853448Sdh155122 	struct rtsparam_s	*rtss_params;
863448Sdh155122 };
873448Sdh155122 typedef struct rts_stack rts_stack_t;
883448Sdh155122 
893448Sdh155122 /*
900Sstevel@tonic-gate  * Object to represent database of options to search passed to
910Sstevel@tonic-gate  * {sock,tpi}optcom_req() interface routine to take care of option
920Sstevel@tonic-gate  * management and associated methods.
930Sstevel@tonic-gate  * XXX. These and other externs should really move to a rts header.
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate extern optdb_obj_t	rts_opt_obj;
960Sstevel@tonic-gate extern uint_t		rts_max_optsize;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /* Internal routing socket stream control structure, one per open stream */
990Sstevel@tonic-gate typedef	struct rts_s {
1000Sstevel@tonic-gate 	cred_t	*rts_credp;		/* Opener's credentials */
1010Sstevel@tonic-gate 	uint_t	rts_state;		/* Provider interface state */
1020Sstevel@tonic-gate 	uint_t	rts_error;		/* Routing socket error code */
1030Sstevel@tonic-gate 	uint_t	rts_flag;		/* Pending I/O state */
1040Sstevel@tonic-gate 	uint_t	rts_proto;		/* SO_PROTOTYPE "socket" option. */
1050Sstevel@tonic-gate 	uint_t	rts_debug : 1,		/* SO_DEBUG "socket" option. */
1060Sstevel@tonic-gate 		rts_dontroute : 1,	/* SO_DONTROUTE "socket" option. */
1070Sstevel@tonic-gate 		rts_broadcast : 1,	/* SO_BROADCAST "socket" option. */
1080Sstevel@tonic-gate 		rts_reuseaddr : 1,	/* SO_REUSEADDR "socket" option. */
1090Sstevel@tonic-gate 		rts_useloopback : 1,	/* SO_USELOOPBACK "socket" option. */
1100Sstevel@tonic-gate 		rts_multicast_loop : 1,	/* IP_MULTICAST_LOOP option */
1110Sstevel@tonic-gate 		rts_hdrincl : 1,	/* IP_HDRINCL option + RAW and IGMP */
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 		: 0;
1143448Sdh155122 	rts_stack_t	*rts_rtss;
1150Sstevel@tonic-gate } rts_t;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate #define	RTS_WPUT_PENDING	0x1	/* Waiting for write-side to complete */
1180Sstevel@tonic-gate #define	RTS_WRW_PENDING		0x2	/* Routing socket write in progress */
1190Sstevel@tonic-gate #define	RTS_OPEN_PENDING	0x4	/* Routing socket open in progress */
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages */
1220Sstevel@tonic-gate static struct T_info_ack rts_g_t_info_ack = {
1230Sstevel@tonic-gate 	T_INFO_ACK,
1240Sstevel@tonic-gate 	T_INFINITE,	/* TSDU_size. Maximum size messages. */
1250Sstevel@tonic-gate 	T_INVALID,	/* ETSDU_size. No expedited data. */
1260Sstevel@tonic-gate 	T_INVALID,	/* CDATA_size. No connect data. */
1270Sstevel@tonic-gate 	T_INVALID,	/* DDATA_size. No disconnect data. */
1280Sstevel@tonic-gate 	0,		/* ADDR_size. */
1290Sstevel@tonic-gate 	0,		/* OPT_size - not initialized here */
1300Sstevel@tonic-gate 	64 * 1024,	/* TIDU_size. rts allows maximum size messages. */
1310Sstevel@tonic-gate 	T_COTS,		/* SERV_type. rts supports connection oriented. */
1320Sstevel@tonic-gate 	TS_UNBND,	/* CURRENT_state. This is set from rts_state. */
1330Sstevel@tonic-gate 	(XPG4_1)	/* PROVIDER_flag */
1340Sstevel@tonic-gate };
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */
1373448Sdh155122 typedef struct rtsparam_s {
1380Sstevel@tonic-gate 	uint_t	rts_param_min;
1390Sstevel@tonic-gate 	uint_t	rts_param_max;
1400Sstevel@tonic-gate 	uint_t	rts_param_value;
1410Sstevel@tonic-gate 	char	*rts_param_name;
1420Sstevel@tonic-gate } rtsparam_t;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate  * Table of ND variables supported by rts. These are loaded into rts_g_nd
1460Sstevel@tonic-gate  * in rts_open.
1470Sstevel@tonic-gate  * All of these are alterable, within the min/max values given, at run time.
1480Sstevel@tonic-gate  */
1493448Sdh155122 static rtsparam_t	lcl_param_arr[] = {
1500Sstevel@tonic-gate 	/* min		max		value		name */
1510Sstevel@tonic-gate 	{ 4096,		65536,		8192,		"rts_xmit_hiwat"},
1520Sstevel@tonic-gate 	{ 0,		65536,		1024,		"rts_xmit_lowat"},
1530Sstevel@tonic-gate 	{ 4096,		65536,		8192,		"rts_recv_hiwat"},
1540Sstevel@tonic-gate 	{ 65536,	1024*1024*1024, 256*1024,	"rts_max_buf"},
1550Sstevel@tonic-gate };
1563448Sdh155122 #define	rtss_xmit_hiwat		rtss_params[0].rts_param_value
1573448Sdh155122 #define	rtss_xmit_lowat		rtss_params[1].rts_param_value
1583448Sdh155122 #define	rtss_recv_hiwat		rtss_params[2].rts_param_value
1593448Sdh155122 #define	rtss_max_buf			rtss_params[3].rts_param_value
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static int	rts_close(queue_t *q);
1620Sstevel@tonic-gate static void 	rts_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error,
1630Sstevel@tonic-gate     int sys_error);
1640Sstevel@tonic-gate static mblk_t	*rts_ioctl_alloc(mblk_t *data, cred_t *cr);
1650Sstevel@tonic-gate static int	rts_open(queue_t *q, dev_t *devp, int flag, int sflag,
1660Sstevel@tonic-gate     cred_t *credp);
1670Sstevel@tonic-gate int		rts_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name,
1680Sstevel@tonic-gate     uchar_t *ptr);
1690Sstevel@tonic-gate int		rts_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name,
1700Sstevel@tonic-gate     uchar_t *ptr);
1710Sstevel@tonic-gate int		rts_opt_set(queue_t *q, uint_t optset_context, int level,
1720Sstevel@tonic-gate     int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
1730Sstevel@tonic-gate     uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk);
1743448Sdh155122 static void	rts_param_cleanup(IDP *ndp);
1750Sstevel@tonic-gate static int	rts_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
1763448Sdh155122 static boolean_t rts_param_register(IDP *ndp, rtsparam_t *rtspa, int cnt);
1770Sstevel@tonic-gate static int	rts_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
1780Sstevel@tonic-gate     cred_t *cr);
1790Sstevel@tonic-gate static void	rts_rput(queue_t *q, mblk_t *mp);
1803448Sdh155122 static void	*rts_stack_init(netstackid_t stackid, netstack_t *ns);
1813448Sdh155122 static void	rts_stack_fini(netstackid_t stackid, void *arg);
1820Sstevel@tonic-gate static void	rts_wput(queue_t *q, mblk_t *mp);
1830Sstevel@tonic-gate static void	rts_wput_iocdata(queue_t *q, mblk_t *mp);
1840Sstevel@tonic-gate static void 	rts_wput_other(queue_t *q, mblk_t *mp);
1850Sstevel@tonic-gate static int	rts_wrw(queue_t *q, struiod_t *dp);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate static struct module_info info = {
1880Sstevel@tonic-gate 	129, "rts", 1, INFPSZ, 512, 128
1890Sstevel@tonic-gate };
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate static struct qinit rinit = {
1920Sstevel@tonic-gate 	(pfi_t)rts_rput, NULL, rts_open, rts_close, NULL, &info
1930Sstevel@tonic-gate };
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate static struct qinit winit = {
1960Sstevel@tonic-gate 	(pfi_t)rts_wput, NULL, NULL, NULL, NULL, &info,
1970Sstevel@tonic-gate 	NULL, (pfi_t)rts_wrw, NULL, STRUIOT_STANDARD
1980Sstevel@tonic-gate };
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate struct streamtab rtsinfo = {
2010Sstevel@tonic-gate 	&rinit, &winit
2020Sstevel@tonic-gate };
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate /*
2050Sstevel@tonic-gate  * This routine allocates the necessary
2060Sstevel@tonic-gate  * message blocks for IOCTL wrapping the
2070Sstevel@tonic-gate  * user data.
2080Sstevel@tonic-gate  */
2090Sstevel@tonic-gate static mblk_t *
2100Sstevel@tonic-gate rts_ioctl_alloc(mblk_t *data, cred_t *cr)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	mblk_t	*mp = NULL;
2130Sstevel@tonic-gate 	mblk_t	*mp1 = NULL;
2140Sstevel@tonic-gate 	ipllc_t	*ipllc;
2150Sstevel@tonic-gate 	struct iocblk	*ioc;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	mp = allocb_cred(sizeof (ipllc_t), cr);
2180Sstevel@tonic-gate 	if (mp == NULL)
2190Sstevel@tonic-gate 		return (NULL);
2200Sstevel@tonic-gate 	mp1 = allocb_cred(sizeof (struct iocblk), cr);
2210Sstevel@tonic-gate 	if (mp1 == NULL) {
2220Sstevel@tonic-gate 		freeb(mp);
2230Sstevel@tonic-gate 		return (NULL);
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	ipllc = (ipllc_t *)mp->b_rptr;
2270Sstevel@tonic-gate 	ipllc->ipllc_cmd = IP_IOC_RTS_REQUEST;
2280Sstevel@tonic-gate 	ipllc->ipllc_name_offset = 0;
2290Sstevel@tonic-gate 	ipllc->ipllc_name_length = 0;
2300Sstevel@tonic-gate 	mp->b_wptr += sizeof (ipllc_t);
2310Sstevel@tonic-gate 	mp->b_cont = data;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	ioc = (struct iocblk *)mp1->b_rptr;
2340Sstevel@tonic-gate 	ioc->ioc_cmd = IP_IOCTL;
2350Sstevel@tonic-gate 	ioc->ioc_error = 0;
2360Sstevel@tonic-gate 	ioc->ioc_cr = NULL;
2370Sstevel@tonic-gate 	ioc->ioc_count = msgdsize(mp);
2380Sstevel@tonic-gate 	mp1->b_wptr += sizeof (struct iocblk);
2390Sstevel@tonic-gate 	mp1->b_datap->db_type = M_IOCTL;
2400Sstevel@tonic-gate 	mp1->b_cont = mp;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	return (mp1);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate /*
2460Sstevel@tonic-gate  * This routine closes rts stream, by disabling
2470Sstevel@tonic-gate  * put/srv routines and freeing the this module
2480Sstevel@tonic-gate  * internal datastructure.
2490Sstevel@tonic-gate  */
2500Sstevel@tonic-gate static int
2510Sstevel@tonic-gate rts_close(queue_t *q)
2520Sstevel@tonic-gate {
2533448Sdh155122 	rts_t *rts = (rts_t *)q->q_ptr;
2543448Sdh155122 
2550Sstevel@tonic-gate 	qprocsoff(q);
2560Sstevel@tonic-gate 
2573448Sdh155122 	crfree(rts->rts_credp);
2583448Sdh155122 	netstack_rele(rts->rts_rtss->rtss_netstack);
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	mi_free(q->q_ptr);
2610Sstevel@tonic-gate 	return (0);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate  * This is the open routine for routing socket. It allocates
2660Sstevel@tonic-gate  * rts_t structure for the stream and sends an IOCTL to
2670Sstevel@tonic-gate  * the down module to indicate that it is a routing socket
2680Sstevel@tonic-gate  * stream.
2690Sstevel@tonic-gate  */
2700Sstevel@tonic-gate /* ARGSUSED */
2710Sstevel@tonic-gate static int
2720Sstevel@tonic-gate rts_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	mblk_t	*mp = NULL;
2750Sstevel@tonic-gate 	rts_t	*rts;
2763448Sdh155122 	netstack_t *ns;
2773448Sdh155122 	rts_stack_t *rtss;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	/* If the stream is already open, return immediately. */
2800Sstevel@tonic-gate 	if (q->q_ptr != NULL)
2810Sstevel@tonic-gate 		return (0);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/* If this is not a push of rts as a module, fail. */
2840Sstevel@tonic-gate 	if (sflag != MODOPEN)
2850Sstevel@tonic-gate 		return (EINVAL);
2860Sstevel@tonic-gate 
2873448Sdh155122 	ns = netstack_find_by_cred(credp);
2883448Sdh155122 	ASSERT(ns != NULL);
2893448Sdh155122 	rtss = ns->netstack_rts;
2903448Sdh155122 	ASSERT(rtss != NULL);
2913448Sdh155122 
2920Sstevel@tonic-gate 	q->q_ptr = mi_zalloc_sleep(sizeof (rts_t));
2930Sstevel@tonic-gate 	WR(q)->q_ptr = q->q_ptr;
2940Sstevel@tonic-gate 	rts = (rts_t *)q->q_ptr;
2950Sstevel@tonic-gate 
2963448Sdh155122 	rts->rts_rtss = rtss;
2973448Sdh155122 
2980Sstevel@tonic-gate 	rts->rts_credp = credp;
2990Sstevel@tonic-gate 	crhold(credp);
3000Sstevel@tonic-gate 	/*
3010Sstevel@tonic-gate 	 * The receive hiwat is only looked at on the stream head queue.
3020Sstevel@tonic-gate 	 * Store in q_hiwat in order to return on SO_RCVBUF getsockopts.
3030Sstevel@tonic-gate 	 */
3043448Sdh155122 	q->q_hiwat = rtss->rtss_recv_hiwat;
3050Sstevel@tonic-gate 	/*
3060Sstevel@tonic-gate 	 * The transmit hiwat/lowat is only looked at on IP's queue.
3070Sstevel@tonic-gate 	 * Store in q_hiwat/q_lowat in order to return on SO_SNDBUF/SO_SNDLOWAT
3080Sstevel@tonic-gate 	 * getsockopts.
3090Sstevel@tonic-gate 	 */
3103448Sdh155122 	WR(q)->q_hiwat = rtss->rtss_xmit_hiwat;
3113448Sdh155122 	WR(q)->q_lowat = rtss->rtss_xmit_lowat;
3120Sstevel@tonic-gate 	qprocson(q);
3130Sstevel@tonic-gate 	/*
3140Sstevel@tonic-gate 	 * Indicate the down IP module that this is a routing socket
3150Sstevel@tonic-gate 	 * client by sending an RTS IOCTL without any user data. Although
3160Sstevel@tonic-gate 	 * this is just a notification message (without any real routing
3170Sstevel@tonic-gate 	 * request), we pass in any credential for correctness sake.
3180Sstevel@tonic-gate 	 */
3190Sstevel@tonic-gate 	mp = rts_ioctl_alloc(NULL, credp);
3200Sstevel@tonic-gate 	if (mp == NULL) {
3210Sstevel@tonic-gate 		qprocsoff(q);
3220Sstevel@tonic-gate 		ASSERT(q->q_ptr != NULL);
3233448Sdh155122 		netstack_rele(rtss->rtss_netstack);
3240Sstevel@tonic-gate 		mi_free(q->q_ptr);
3250Sstevel@tonic-gate 		crfree(credp);
3260Sstevel@tonic-gate 		return (ENOMEM);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 	rts->rts_flag |= RTS_OPEN_PENDING;
3290Sstevel@tonic-gate 	putnext(WR(q), mp);
3300Sstevel@tonic-gate 	while (rts->rts_flag & RTS_OPEN_PENDING) {
3310Sstevel@tonic-gate 		if (!qwait_sig(q)) {
3320Sstevel@tonic-gate 			(void) rts_close(q);
3330Sstevel@tonic-gate 			return (EINTR);
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 	if (rts->rts_error != 0) {
3370Sstevel@tonic-gate 		(void) rts_close(q);
3380Sstevel@tonic-gate 		return (ENOTSUP);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 	rts->rts_state = TS_UNBND;
3410Sstevel@tonic-gate 	return (0);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate  * This routine creates a T_ERROR_ACK message and passes it upstream.
3460Sstevel@tonic-gate  */
3470Sstevel@tonic-gate static void
3480Sstevel@tonic-gate rts_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL)
3510Sstevel@tonic-gate 		qreply(q, mp);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate  * This routine creates a T_OK_ACK message and passes it upstream.
3560Sstevel@tonic-gate  */
3570Sstevel@tonic-gate static void
3580Sstevel@tonic-gate rts_ok_ack(queue_t *q, mblk_t *mp)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate 	if ((mp = mi_tpi_ok_ack_alloc(mp)) != NULL)
3610Sstevel@tonic-gate 		qreply(q, mp);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate /*
3650Sstevel@tonic-gate  * This routine is called by rts_wput to handle T_UNBIND_REQ messages.
3660Sstevel@tonic-gate  * After some error checking, the message is passed downstream to ip.
3670Sstevel@tonic-gate  */
3680Sstevel@tonic-gate static void
3690Sstevel@tonic-gate rts_unbind(queue_t *q, mblk_t *mp)
3700Sstevel@tonic-gate {
3710Sstevel@tonic-gate 	rts_t	*rts;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	rts = (rts_t *)q->q_ptr;
3740Sstevel@tonic-gate 	/* If a bind has not been done, we can't unbind. */
3750Sstevel@tonic-gate 	if (rts->rts_state != TS_IDLE) {
3760Sstevel@tonic-gate 		rts_err_ack(q, mp, TOUTSTATE, 0);
3770Sstevel@tonic-gate 		return;
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	rts->rts_state = TS_UNBND;
3800Sstevel@tonic-gate 	rts_ok_ack(q, mp);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate  * This routine is called to handle each
3850Sstevel@tonic-gate  * O_T_BIND_REQ/T_BIND_REQ message passed to
3860Sstevel@tonic-gate  * rts_wput. Note: This routine works with both
3870Sstevel@tonic-gate  * O_T_BIND_REQ and T_BIND_REQ semantics.
3880Sstevel@tonic-gate  */
3890Sstevel@tonic-gate static void
3900Sstevel@tonic-gate rts_bind(queue_t *q, mblk_t *mp)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	mblk_t	*mp1;
3930Sstevel@tonic-gate 	struct T_bind_req *tbr;
3940Sstevel@tonic-gate 	rts_t	*rts;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	rts = (rts_t *)q->q_ptr;
3970Sstevel@tonic-gate 	if ((mp->b_wptr - mp->b_rptr) < sizeof (*tbr)) {
3980Sstevel@tonic-gate 		(void) mi_strlog(q, 1, SL_ERROR|SL_TRACE,
3990Sstevel@tonic-gate 		    "rts_bind: bad data, %d", rts->rts_state);
4000Sstevel@tonic-gate 		rts_err_ack(q, mp, TBADADDR, 0);
4010Sstevel@tonic-gate 		return;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	if (rts->rts_state != TS_UNBND) {
4040Sstevel@tonic-gate 		(void) mi_strlog(q, 1, SL_ERROR|SL_TRACE,
4050Sstevel@tonic-gate 		    "rts_bind: bad state, %d", rts->rts_state);
4060Sstevel@tonic-gate 		rts_err_ack(q, mp, TOUTSTATE, 0);
4070Sstevel@tonic-gate 		return;
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 	/*
4100Sstevel@tonic-gate 	 * Reallocate the message to make sure we have enough room for an
4110Sstevel@tonic-gate 	 * address and the protocol type.
4120Sstevel@tonic-gate 	 */
4130Sstevel@tonic-gate 	mp1 = reallocb(mp, sizeof (struct T_bind_ack) + sizeof (sin_t), 1);
4140Sstevel@tonic-gate 	if (mp1 == NULL) {
4150Sstevel@tonic-gate 		rts_err_ack(q, mp, TSYSERR, ENOMEM);
4160Sstevel@tonic-gate 		return;
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 	mp = mp1;
4190Sstevel@tonic-gate 	tbr = (struct T_bind_req *)mp->b_rptr;
4200Sstevel@tonic-gate 	if (tbr->ADDR_length != 0) {
4210Sstevel@tonic-gate 		(void) mi_strlog(q, 1, SL_ERROR|SL_TRACE,
4220Sstevel@tonic-gate 		    "rts_bind: bad ADDR_length %d", tbr->ADDR_length);
4230Sstevel@tonic-gate 		rts_err_ack(q, mp, TBADADDR, 0);
4240Sstevel@tonic-gate 		return;
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 	/* Generic request */
4270Sstevel@tonic-gate 	tbr->ADDR_offset = (t_scalar_t)sizeof (struct T_bind_req);
4280Sstevel@tonic-gate 	tbr->ADDR_length = 0;
4290Sstevel@tonic-gate 	tbr->PRIM_type = T_BIND_ACK;
4300Sstevel@tonic-gate 	rts->rts_state = TS_IDLE;
4310Sstevel@tonic-gate 	qreply(q, mp);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate static void
4350Sstevel@tonic-gate rts_copy_info(struct T_info_ack *tap, rts_t *rts)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate 	*tap = rts_g_t_info_ack;
4380Sstevel@tonic-gate 	tap->CURRENT_state = rts->rts_state;
4390Sstevel@tonic-gate 	tap->OPT_size = rts_max_optsize;
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate  * This routine responds to T_CAPABILITY_REQ messages.  It is called by
4440Sstevel@tonic-gate  * rts_wput.  Much of the T_CAPABILITY_ACK information is copied from
4450Sstevel@tonic-gate  * rts_g_t_info_ack.  The current state of the stream is copied from
4460Sstevel@tonic-gate  * rts_state.
4470Sstevel@tonic-gate  */
4480Sstevel@tonic-gate static void
4490Sstevel@tonic-gate rts_capability_req(queue_t *q, mblk_t *mp)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	rts_t			*rts = (rts_t *)q->q_ptr;
4520Sstevel@tonic-gate 	t_uscalar_t		cap_bits1;
4530Sstevel@tonic-gate 	struct T_capability_ack	*tcap;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
4580Sstevel@tonic-gate 		mp->b_datap->db_type, T_CAPABILITY_ACK);
4590Sstevel@tonic-gate 	if (mp == NULL)
4600Sstevel@tonic-gate 		return;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	tcap = (struct T_capability_ack *)mp->b_rptr;
4630Sstevel@tonic-gate 	tcap->CAP_bits1 = 0;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	if (cap_bits1 & TC1_INFO) {
4660Sstevel@tonic-gate 		rts_copy_info(&tcap->INFO_ack, rts);
4670Sstevel@tonic-gate 		tcap->CAP_bits1 |= TC1_INFO;
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	qreply(q, mp);
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate  * This routine responds to T_INFO_REQ messages.  It is called by rts_wput.
4750Sstevel@tonic-gate  * Most of the T_INFO_ACK information is copied from rts_g_t_info_ack.
4760Sstevel@tonic-gate  * The current state of the stream is copied from rts_state.
4770Sstevel@tonic-gate  */
4780Sstevel@tonic-gate static void
4790Sstevel@tonic-gate rts_info_req(queue_t *q, mblk_t *mp)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	rts_t	*rts = (rts_t *)q->q_ptr;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	mp = tpi_ack_alloc(mp, sizeof (rts_g_t_info_ack), M_PCPROTO,
4840Sstevel@tonic-gate 	    T_INFO_ACK);
4850Sstevel@tonic-gate 	if (mp == NULL)
4860Sstevel@tonic-gate 		return;
4870Sstevel@tonic-gate 	rts_copy_info((struct T_info_ack *)mp->b_rptr, rts);
4880Sstevel@tonic-gate 	qreply(q, mp);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate /*
4920Sstevel@tonic-gate  * This routine gets default values of certain options whose default
4930Sstevel@tonic-gate  * values are maintained by protcol specific code
4940Sstevel@tonic-gate  */
4950Sstevel@tonic-gate /* ARGSUSED */
4960Sstevel@tonic-gate int
4970Sstevel@tonic-gate rts_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	/* no default value processed by protocol specific code currently */
5000Sstevel@tonic-gate 	return (-1);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate /*
5040Sstevel@tonic-gate  * This routine retrieves the current status of socket options.
5050Sstevel@tonic-gate  * It returns the size of the option retrieved.
5060Sstevel@tonic-gate  */
5070Sstevel@tonic-gate int
5080Sstevel@tonic-gate rts_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
5090Sstevel@tonic-gate {
5100Sstevel@tonic-gate 	int	*i1 = (int *)ptr;
5110Sstevel@tonic-gate 	rts_t	*rts = (rts_t *)q->q_ptr;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	switch (level) {
5140Sstevel@tonic-gate 	case SOL_SOCKET:
5150Sstevel@tonic-gate 		switch (name) {
5160Sstevel@tonic-gate 		case SO_DEBUG:
5170Sstevel@tonic-gate 			*i1 = rts->rts_debug;
5180Sstevel@tonic-gate 			break;
5190Sstevel@tonic-gate 		case SO_REUSEADDR:
5200Sstevel@tonic-gate 			*i1 = rts->rts_reuseaddr;
5210Sstevel@tonic-gate 			break;
5220Sstevel@tonic-gate 		case SO_TYPE:
5230Sstevel@tonic-gate 			*i1 = SOCK_RAW;
5240Sstevel@tonic-gate 			break;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		/*
5270Sstevel@tonic-gate 		 * The following three items are available here,
5280Sstevel@tonic-gate 		 * but are only meaningful to IP.
5290Sstevel@tonic-gate 		 */
5300Sstevel@tonic-gate 		case SO_DONTROUTE:
5310Sstevel@tonic-gate 			*i1 = rts->rts_dontroute;
5320Sstevel@tonic-gate 			break;
5330Sstevel@tonic-gate 		case SO_USELOOPBACK:
5340Sstevel@tonic-gate 			*i1 = rts->rts_useloopback;
5350Sstevel@tonic-gate 			break;
5360Sstevel@tonic-gate 		case SO_BROADCAST:
5370Sstevel@tonic-gate 			*i1 = rts->rts_broadcast;
5380Sstevel@tonic-gate 			break;
5390Sstevel@tonic-gate 		case SO_PROTOTYPE:
5400Sstevel@tonic-gate 			*i1 = rts->rts_proto;
5410Sstevel@tonic-gate 			break;
5420Sstevel@tonic-gate 		/*
5430Sstevel@tonic-gate 		 * The following two items can be manipulated,
5440Sstevel@tonic-gate 		 * but changing them should do nothing.
5450Sstevel@tonic-gate 		 */
5460Sstevel@tonic-gate 		case SO_SNDBUF:
5470Sstevel@tonic-gate 			ASSERT(q->q_hiwat <= INT_MAX);
5480Sstevel@tonic-gate 			*i1 = (int)(q->q_hiwat);
5490Sstevel@tonic-gate 			break;
5500Sstevel@tonic-gate 		case SO_RCVBUF:
5510Sstevel@tonic-gate 			ASSERT(q->q_hiwat <= INT_MAX);
5520Sstevel@tonic-gate 			*i1 = (int)(RD(q)->q_hiwat);
5530Sstevel@tonic-gate 			break;
5543388Skcpoon 		case SO_DOMAIN:
5553388Skcpoon 			*i1 = PF_ROUTE;
5563388Skcpoon 			break;
5570Sstevel@tonic-gate 		default:
5580Sstevel@tonic-gate 			return (-1);
5590Sstevel@tonic-gate 		}
5600Sstevel@tonic-gate 		break;
5610Sstevel@tonic-gate 	default:
5620Sstevel@tonic-gate 		return (-1);
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 	return ((int)sizeof (int));
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate  * This routine sets socket options.
5700Sstevel@tonic-gate  */
5710Sstevel@tonic-gate /*ARGSUSED*/
5720Sstevel@tonic-gate int
5730Sstevel@tonic-gate rts_opt_set(queue_t *q, uint_t optset_context, int level,
5740Sstevel@tonic-gate     int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
5750Sstevel@tonic-gate     uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk)
5760Sstevel@tonic-gate {
5770Sstevel@tonic-gate 	int	*i1 = (int *)invalp;
5780Sstevel@tonic-gate 	rts_t	*rts = (rts_t *)q->q_ptr;
5790Sstevel@tonic-gate 	boolean_t checkonly;
5803448Sdh155122 	rts_stack_t	*rtss = rts->rts_rtss;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	switch (optset_context) {
5830Sstevel@tonic-gate 	case SETFN_OPTCOM_CHECKONLY:
5840Sstevel@tonic-gate 		checkonly = B_TRUE;
5850Sstevel@tonic-gate 		/*
5860Sstevel@tonic-gate 		 * Note: Implies T_CHECK semantics for T_OPTCOM_REQ
5870Sstevel@tonic-gate 		 * inlen != 0 implies value supplied and
5880Sstevel@tonic-gate 		 * 	we have to "pretend" to set it.
5890Sstevel@tonic-gate 		 * inlen == 0 implies that there is no
5900Sstevel@tonic-gate 		 * 	value part in T_CHECK request and just validation
5910Sstevel@tonic-gate 		 * done elsewhere should be enough, we just return here.
5920Sstevel@tonic-gate 		 */
5930Sstevel@tonic-gate 		if (inlen == 0) {
5940Sstevel@tonic-gate 			*outlenp = 0;
5950Sstevel@tonic-gate 			return (0);
5960Sstevel@tonic-gate 		}
5970Sstevel@tonic-gate 		break;
5980Sstevel@tonic-gate 	case SETFN_OPTCOM_NEGOTIATE:
5990Sstevel@tonic-gate 		checkonly = B_FALSE;
6000Sstevel@tonic-gate 		break;
6010Sstevel@tonic-gate 	case SETFN_UD_NEGOTIATE:
6020Sstevel@tonic-gate 	case SETFN_CONN_NEGOTIATE:
6030Sstevel@tonic-gate 		checkonly = B_FALSE;
6040Sstevel@tonic-gate 		/*
6050Sstevel@tonic-gate 		 * Negotiating local and "association-related" options
6060Sstevel@tonic-gate 		 * through T_UNITDATA_REQ or T_CONN_{REQ,CON}
6070Sstevel@tonic-gate 		 * Not allowed in this module.
6080Sstevel@tonic-gate 		 */
6090Sstevel@tonic-gate 		return (EINVAL);
6100Sstevel@tonic-gate 	default:
6110Sstevel@tonic-gate 		/*
6120Sstevel@tonic-gate 		 * We should never get here
6130Sstevel@tonic-gate 		 */
6140Sstevel@tonic-gate 		*outlenp = 0;
6150Sstevel@tonic-gate 		return (EINVAL);
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) ||
6190Sstevel@tonic-gate 	    (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0));
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	/*
6220Sstevel@tonic-gate 	 * For rts, we should have no ancillary data sent down
6230Sstevel@tonic-gate 	 * (rts_wput doesn't handle options).
6240Sstevel@tonic-gate 	 */
6250Sstevel@tonic-gate 	ASSERT(thisdg_attrs == NULL);
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	/*
6280Sstevel@tonic-gate 	 * For fixed length options, no sanity check
6290Sstevel@tonic-gate 	 * of passed in length is done. It is assumed *_optcom_req()
6300Sstevel@tonic-gate 	 * routines do the right thing.
6310Sstevel@tonic-gate 	 */
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	switch (level) {
6340Sstevel@tonic-gate 	case SOL_SOCKET:
6350Sstevel@tonic-gate 		switch (name) {
6360Sstevel@tonic-gate 		case SO_REUSEADDR:
6370Sstevel@tonic-gate 			if (!checkonly)
6380Sstevel@tonic-gate 				rts->rts_reuseaddr = *i1;
6390Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6400Sstevel@tonic-gate 		case SO_DEBUG:
6410Sstevel@tonic-gate 			if (!checkonly)
6420Sstevel@tonic-gate 				rts->rts_debug = *i1;
6430Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6440Sstevel@tonic-gate 		/*
6450Sstevel@tonic-gate 		 * The following three items are available here,
6460Sstevel@tonic-gate 		 * but are only meaningful to IP.
6470Sstevel@tonic-gate 		 */
6480Sstevel@tonic-gate 		case SO_DONTROUTE:
6490Sstevel@tonic-gate 			if (!checkonly)
6500Sstevel@tonic-gate 				rts->rts_dontroute = *i1;
6510Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6520Sstevel@tonic-gate 		case SO_USELOOPBACK:
6530Sstevel@tonic-gate 			if (!checkonly)
6540Sstevel@tonic-gate 				rts->rts_useloopback = *i1;
6550Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6560Sstevel@tonic-gate 		case SO_BROADCAST:
6570Sstevel@tonic-gate 			if (!checkonly)
6580Sstevel@tonic-gate 				rts->rts_broadcast = *i1;
6590Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6600Sstevel@tonic-gate 		case SO_PROTOTYPE:
6610Sstevel@tonic-gate 			/*
6620Sstevel@tonic-gate 			 * Routing socket applications that call socket() with
6630Sstevel@tonic-gate 			 * a third argument can filter which messages will be
6640Sstevel@tonic-gate 			 * sent upstream thanks to sockfs.  so_socket() sends
6650Sstevel@tonic-gate 			 * down the SO_PROTOTYPE and rts_queue_input()
6660Sstevel@tonic-gate 			 * implements the filtering.
6670Sstevel@tonic-gate 			 */
6680Sstevel@tonic-gate 			if (*i1 != AF_INET && *i1 != AF_INET6)
6690Sstevel@tonic-gate 				return (EPROTONOSUPPORT);
6700Sstevel@tonic-gate 			if (!checkonly)
6710Sstevel@tonic-gate 				rts->rts_proto = *i1;
6720Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6730Sstevel@tonic-gate 		/*
6740Sstevel@tonic-gate 		 * The following two items can be manipulated,
6750Sstevel@tonic-gate 		 * but changing them should do nothing.
6760Sstevel@tonic-gate 		 */
6770Sstevel@tonic-gate 		case SO_SNDBUF:
6783448Sdh155122 			if (*i1 > rtss->rtss_max_buf) {
6790Sstevel@tonic-gate 				*outlenp = 0;
6800Sstevel@tonic-gate 				return (ENOBUFS);
6810Sstevel@tonic-gate 			}
6820Sstevel@tonic-gate 			if (!checkonly) {
6830Sstevel@tonic-gate 				q->q_hiwat = *i1;
6840Sstevel@tonic-gate 				q->q_next->q_hiwat = *i1;
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6870Sstevel@tonic-gate 		case SO_RCVBUF:
6883448Sdh155122 			if (*i1 > rtss->rtss_max_buf) {
6890Sstevel@tonic-gate 				*outlenp = 0;
6900Sstevel@tonic-gate 				return (ENOBUFS);
6910Sstevel@tonic-gate 			}
6920Sstevel@tonic-gate 			if (!checkonly) {
6930Sstevel@tonic-gate 				RD(q)->q_hiwat = *i1;
6940Sstevel@tonic-gate 				(void) mi_set_sth_hiwat(RD(q), *i1);
6950Sstevel@tonic-gate 			}
6960Sstevel@tonic-gate 			break;	/* goto sizeof (int) option return */
6970Sstevel@tonic-gate 		default:
6980Sstevel@tonic-gate 			*outlenp = 0;
6990Sstevel@tonic-gate 			return (EINVAL);
7000Sstevel@tonic-gate 		}
7010Sstevel@tonic-gate 		break;
7020Sstevel@tonic-gate 	default:
7030Sstevel@tonic-gate 		*outlenp = 0;
7040Sstevel@tonic-gate 		return (EINVAL);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * Common case of return from an option that is sizeof (int)
7080Sstevel@tonic-gate 	 */
7090Sstevel@tonic-gate 	*(int *)outvalp = *i1;
7100Sstevel@tonic-gate 	*outlenp = (t_uscalar_t)sizeof (int);
7110Sstevel@tonic-gate 	return (0);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate /*
7150Sstevel@tonic-gate  * This routine frees the ND table if all streams have been closed.
7160Sstevel@tonic-gate  * It is called by rts_close and rts_open.
7170Sstevel@tonic-gate  */
7180Sstevel@tonic-gate static void
7193448Sdh155122 rts_param_cleanup(IDP *ndp)
7200Sstevel@tonic-gate {
7213448Sdh155122 	nd_free(ndp);
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate /*
7250Sstevel@tonic-gate  * This routine retrieves the value of an ND variable in a rtsparam_t
7260Sstevel@tonic-gate  * structure. It is called through nd_getset when a user reads the
7270Sstevel@tonic-gate  * variable.
7280Sstevel@tonic-gate  */
7290Sstevel@tonic-gate /* ARGSUSED */
7300Sstevel@tonic-gate static int
7310Sstevel@tonic-gate rts_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
7320Sstevel@tonic-gate {
7330Sstevel@tonic-gate 	rtsparam_t	*rtspa = (rtsparam_t *)cp;
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	(void) mi_mpprintf(mp, "%u", rtspa->rts_param_value);
7360Sstevel@tonic-gate 	return (0);
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate  * Walk through the param array specified registering each element with the
7410Sstevel@tonic-gate  * named dispatch (ND) handler.
7420Sstevel@tonic-gate  */
7430Sstevel@tonic-gate static boolean_t
7443448Sdh155122 rts_param_register(IDP *ndp, rtsparam_t *rtspa, int cnt)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate 	for (; cnt-- > 0; rtspa++) {
7470Sstevel@tonic-gate 		if (rtspa->rts_param_name != NULL && rtspa->rts_param_name[0]) {
7483448Sdh155122 			if (!nd_load(ndp, rtspa->rts_param_name,
7490Sstevel@tonic-gate 			    rts_param_get, rts_param_set, (caddr_t)rtspa)) {
7503448Sdh155122 				nd_free(ndp);
7510Sstevel@tonic-gate 				return (B_FALSE);
7520Sstevel@tonic-gate 			}
7530Sstevel@tonic-gate 		}
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 	return (B_TRUE);
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate /* This routine sets an ND variable in a rtsparam_t structure. */
7590Sstevel@tonic-gate /* ARGSUSED */
7600Sstevel@tonic-gate static int
7610Sstevel@tonic-gate rts_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr)
7620Sstevel@tonic-gate {
7630Sstevel@tonic-gate 	ulong_t	new_value;
7640Sstevel@tonic-gate 	rtsparam_t	*rtspa = (rtsparam_t *)cp;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	/*
7670Sstevel@tonic-gate 	 * Fail the request if the new value does not lie within the
7680Sstevel@tonic-gate 	 * required bounds.
7690Sstevel@tonic-gate 	 */
7700Sstevel@tonic-gate 	if (ddi_strtoul(value, NULL, 10, &new_value) != 0 ||
7710Sstevel@tonic-gate 	    new_value < rtspa->rts_param_min ||
7720Sstevel@tonic-gate 	    new_value > rtspa->rts_param_max) {
7730Sstevel@tonic-gate 		return (EINVAL);
7740Sstevel@tonic-gate 	}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/* Set the new value */
7770Sstevel@tonic-gate 	rtspa->rts_param_value = new_value;
7780Sstevel@tonic-gate 	return (0);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate  * This routine handles synchronous messages passed downstream. It either
7830Sstevel@tonic-gate  * consumes the message or passes it downstream; it never queues a
7840Sstevel@tonic-gate  * a message. The data messages that go down are wrapped in an IOCTL
7850Sstevel@tonic-gate  * message.
7860Sstevel@tonic-gate  *
7870Sstevel@tonic-gate  * Since it is synchronous, it waits for the M_IOCACK/M_IOCNAK so that
7880Sstevel@tonic-gate  * it can return an immediate error (such as ENETUNREACH when adding a route).
7890Sstevel@tonic-gate  * It uses the RTS_WRW_PENDING to ensure that each rts instance has only
7900Sstevel@tonic-gate  * one M_IOCTL outstanding at any given time.
7910Sstevel@tonic-gate  */
7920Sstevel@tonic-gate static int
7930Sstevel@tonic-gate rts_wrw(queue_t *q, struiod_t *dp)
7940Sstevel@tonic-gate {
7950Sstevel@tonic-gate 	mblk_t	*mp = dp->d_mp;
7960Sstevel@tonic-gate 	mblk_t	*mp1;
7970Sstevel@tonic-gate 	int	error;
7980Sstevel@tonic-gate 	rt_msghdr_t	*rtm;
7990Sstevel@tonic-gate 	rts_t	*rts;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	rts = (rts_t *)q->q_ptr;
8020Sstevel@tonic-gate 	while (rts->rts_flag & RTS_WRW_PENDING) {
8030Sstevel@tonic-gate 		if (qwait_rw(q)) {
8040Sstevel@tonic-gate 			rts->rts_error = EINTR;
8050Sstevel@tonic-gate 			goto err_ret;
8060Sstevel@tonic-gate 		}
8073448Sdh155122 		}
8080Sstevel@tonic-gate 	rts->rts_flag |= RTS_WRW_PENDING;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	if (isuioq(q) && (error = struioget(q, mp, dp, 0))) {
8110Sstevel@tonic-gate 		/*
8120Sstevel@tonic-gate 		 * Uio error of some sort, so just return the error.
8130Sstevel@tonic-gate 		 */
8140Sstevel@tonic-gate 		rts->rts_error = error;
8150Sstevel@tonic-gate 		goto err_ret;
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 	/*
8180Sstevel@tonic-gate 	 * Pass the mblk (chain) onto wput().
8190Sstevel@tonic-gate 	 */
8200Sstevel@tonic-gate 	dp->d_mp = 0;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
8230Sstevel@tonic-gate 	case M_PROTO:
8240Sstevel@tonic-gate 	case M_PCPROTO:
8250Sstevel@tonic-gate 		/* Expedite other than T_DATA_REQ to below the switch */
8260Sstevel@tonic-gate 		if (((mp->b_wptr - mp->b_rptr) !=
8270Sstevel@tonic-gate 		    sizeof (struct T_data_req)) ||
8280Sstevel@tonic-gate 		    (((union T_primitives *)mp->b_rptr)->type != T_DATA_REQ))
8290Sstevel@tonic-gate 			break;
8300Sstevel@tonic-gate 		if ((mp1 = mp->b_cont) == NULL) {
8310Sstevel@tonic-gate 			rts->rts_error = EINVAL;
8320Sstevel@tonic-gate 			goto err_ret;
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 		freeb(mp);
8350Sstevel@tonic-gate 		mp = mp1;
8360Sstevel@tonic-gate 		/* FALLTHRU */
8370Sstevel@tonic-gate 	case M_DATA:
8380Sstevel@tonic-gate 		/*
8390Sstevel@tonic-gate 		 * The semantics of the routing socket is such that the rtm_pid
8400Sstevel@tonic-gate 		 * field is automatically filled in during requests with the
8410Sstevel@tonic-gate 		 * current process' pid.  We do this here (where we still have
8420Sstevel@tonic-gate 		 * user context) after checking we have at least a message the
8430Sstevel@tonic-gate 		 * size of a routing message header.
8440Sstevel@tonic-gate 		 */
8450Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) {
8460Sstevel@tonic-gate 			if (!pullupmsg(mp, sizeof (rt_msghdr_t))) {
8470Sstevel@tonic-gate 				rts->rts_error = EINVAL;
8480Sstevel@tonic-gate 				goto err_ret;
8490Sstevel@tonic-gate 			}
8500Sstevel@tonic-gate 		}
8510Sstevel@tonic-gate 		rtm = (rt_msghdr_t *)mp->b_rptr;
8520Sstevel@tonic-gate 		rtm->rtm_pid = curproc->p_pid;
8530Sstevel@tonic-gate 		break;
8540Sstevel@tonic-gate 	default:
8550Sstevel@tonic-gate 		break;
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 	rts->rts_flag |= RTS_WPUT_PENDING;
8580Sstevel@tonic-gate 	rts_wput(q, mp);
8590Sstevel@tonic-gate 	while (rts->rts_flag & RTS_WPUT_PENDING)
8600Sstevel@tonic-gate 		if (qwait_rw(q)) {
8610Sstevel@tonic-gate 			/* RTS_WPUT_PENDING will be cleared below */
8620Sstevel@tonic-gate 			rts->rts_error = EINTR;
8630Sstevel@tonic-gate 			break;
8640Sstevel@tonic-gate 		}
8650Sstevel@tonic-gate err_ret:
8660Sstevel@tonic-gate 	rts->rts_flag &= ~(RTS_WPUT_PENDING | RTS_WRW_PENDING);
8670Sstevel@tonic-gate 	return (rts->rts_error);
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate /*
8710Sstevel@tonic-gate  * This routine handles all messages passed downstream. It either
8720Sstevel@tonic-gate  * consumes the message or passes it downstream; it never queues a
8730Sstevel@tonic-gate  * a message. The data messages that go down are wrapped in an IOCTL
8740Sstevel@tonic-gate  * message.
8750Sstevel@tonic-gate  */
8760Sstevel@tonic-gate static void
8770Sstevel@tonic-gate rts_wput(queue_t *q, mblk_t *mp)
8780Sstevel@tonic-gate {
8790Sstevel@tonic-gate 	uchar_t	*rptr = mp->b_rptr;
8800Sstevel@tonic-gate 	mblk_t	*mp1;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
8830Sstevel@tonic-gate 	case M_DATA:
8840Sstevel@tonic-gate 		break;
8850Sstevel@tonic-gate 	case M_PROTO:
8860Sstevel@tonic-gate 	case M_PCPROTO:
8870Sstevel@tonic-gate 		if ((mp->b_wptr - rptr) == sizeof (struct T_data_req)) {
8880Sstevel@tonic-gate 			/* Expedite valid T_DATA_REQ to below the switch */
8890Sstevel@tonic-gate 			if (((union T_primitives *)rptr)->type == T_DATA_REQ) {
8900Sstevel@tonic-gate 				mp1 = mp->b_cont;
8910Sstevel@tonic-gate 				freeb(mp);
8920Sstevel@tonic-gate 				if (mp1 == NULL)
8930Sstevel@tonic-gate 					return;
8940Sstevel@tonic-gate 				mp = mp1;
8950Sstevel@tonic-gate 				break;
8960Sstevel@tonic-gate 			}
8970Sstevel@tonic-gate 		}
8980Sstevel@tonic-gate 		/* FALLTHRU */
8990Sstevel@tonic-gate 	default:
9000Sstevel@tonic-gate 		rts_wput_other(q, mp);
9010Sstevel@tonic-gate 		return;
9020Sstevel@tonic-gate 	}
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	mp1 = rts_ioctl_alloc(mp, DB_CRED(mp));
9060Sstevel@tonic-gate 	if (mp1 == NULL) {
9070Sstevel@tonic-gate 		rts_t	*rts = (rts_t *)q->q_ptr;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 		ASSERT(rts != NULL);
9100Sstevel@tonic-gate 		freemsg(mp);
9110Sstevel@tonic-gate 		if (rts->rts_flag & RTS_WPUT_PENDING) {
9120Sstevel@tonic-gate 			rts->rts_error = ENOMEM;
9130Sstevel@tonic-gate 			rts->rts_flag &= ~RTS_WPUT_PENDING;
9140Sstevel@tonic-gate 		}
9150Sstevel@tonic-gate 		return;
9160Sstevel@tonic-gate 	}
9170Sstevel@tonic-gate 	putnext(q, mp1);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate /*
9220Sstevel@tonic-gate  * Handles all the control message, if it
9230Sstevel@tonic-gate  * can not understand it, it will
9240Sstevel@tonic-gate  * pass down stream.
9250Sstevel@tonic-gate  */
9260Sstevel@tonic-gate static void
9270Sstevel@tonic-gate rts_wput_other(queue_t *q, mblk_t *mp)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	uchar_t	*rptr = mp->b_rptr;
9300Sstevel@tonic-gate 	rts_t	*rts;
9310Sstevel@tonic-gate 	struct iocblk	*iocp;
9320Sstevel@tonic-gate 	cred_t	*cr;
9333448Sdh155122 	rts_stack_t	*rtss;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	rts = (rts_t *)q->q_ptr;
9363448Sdh155122 	rtss = rts->rts_rtss;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	cr = DB_CREDDEF(mp, rts->rts_credp);
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
9410Sstevel@tonic-gate 	case M_PROTO:
9420Sstevel@tonic-gate 	case M_PCPROTO:
9430Sstevel@tonic-gate 		if ((mp->b_wptr - rptr) < sizeof (t_scalar_t)) {
9440Sstevel@tonic-gate 			/*
9450Sstevel@tonic-gate 			 * If the message does not contain a PRIM_type,
9460Sstevel@tonic-gate 			 * throw it away.
9470Sstevel@tonic-gate 			 */
9480Sstevel@tonic-gate 			freemsg(mp);
9490Sstevel@tonic-gate 			return;
9500Sstevel@tonic-gate 		}
9510Sstevel@tonic-gate 		switch (((union T_primitives *)rptr)->type) {
9520Sstevel@tonic-gate 		case T_BIND_REQ:
9530Sstevel@tonic-gate 		case O_T_BIND_REQ:
9540Sstevel@tonic-gate 			rts_bind(q, mp);
9550Sstevel@tonic-gate 			return;
9560Sstevel@tonic-gate 		case T_UNBIND_REQ:
9570Sstevel@tonic-gate 			rts_unbind(q, mp);
9580Sstevel@tonic-gate 			return;
9590Sstevel@tonic-gate 		case T_CAPABILITY_REQ:
9600Sstevel@tonic-gate 			rts_capability_req(q, mp);
9610Sstevel@tonic-gate 			return;
9620Sstevel@tonic-gate 		case T_INFO_REQ:
9630Sstevel@tonic-gate 			rts_info_req(q, mp);
9640Sstevel@tonic-gate 			return;
9650Sstevel@tonic-gate 		case T_SVR4_OPTMGMT_REQ:
9660Sstevel@tonic-gate 			(void) svr4_optcom_req(q, mp, cr, &rts_opt_obj);
9670Sstevel@tonic-gate 			return;
9680Sstevel@tonic-gate 		case T_OPTMGMT_REQ:
9690Sstevel@tonic-gate 			(void) tpi_optcom_req(q, mp, cr, &rts_opt_obj);
9700Sstevel@tonic-gate 			return;
9710Sstevel@tonic-gate 		case O_T_CONN_RES:
9720Sstevel@tonic-gate 		case T_CONN_RES:
9730Sstevel@tonic-gate 		case T_DISCON_REQ:
9740Sstevel@tonic-gate 			/* Not supported by rts. */
9750Sstevel@tonic-gate 			rts_err_ack(q, mp, TNOTSUPPORT, 0);
9760Sstevel@tonic-gate 			return;
9770Sstevel@tonic-gate 		case T_DATA_REQ:
9780Sstevel@tonic-gate 		case T_EXDATA_REQ:
9790Sstevel@tonic-gate 		case T_ORDREL_REQ:
9800Sstevel@tonic-gate 			/* Illegal for rts. */
9810Sstevel@tonic-gate 			freemsg(mp);
9820Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_ERROR, EPROTO);
9830Sstevel@tonic-gate 			return;
9840Sstevel@tonic-gate 		default:
9850Sstevel@tonic-gate 			break;
9860Sstevel@tonic-gate 		}
9870Sstevel@tonic-gate 		break;
9880Sstevel@tonic-gate 	case M_IOCTL:
9890Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
9900Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
9910Sstevel@tonic-gate 		case ND_SET:
9920Sstevel@tonic-gate 		case ND_GET:
9933448Sdh155122 			if (nd_getset(q, rtss->rtss_g_nd, mp)) {
9940Sstevel@tonic-gate 				qreply(q, mp);
9950Sstevel@tonic-gate 				return;
9960Sstevel@tonic-gate 			}
9970Sstevel@tonic-gate 			break;
9980Sstevel@tonic-gate 		case TI_GETPEERNAME:
9990Sstevel@tonic-gate 			mi_copyin(q, mp, NULL,
10000Sstevel@tonic-gate 			    SIZEOF_STRUCT(strbuf, iocp->ioc_flag));
10010Sstevel@tonic-gate 			return;
10020Sstevel@tonic-gate 		default:
10030Sstevel@tonic-gate 			break;
10040Sstevel@tonic-gate 		}
10050Sstevel@tonic-gate 	case M_IOCDATA:
10060Sstevel@tonic-gate 		rts_wput_iocdata(q, mp);
10070Sstevel@tonic-gate 		return;
10080Sstevel@tonic-gate 	default:
10090Sstevel@tonic-gate 		break;
10100Sstevel@tonic-gate 	}
10110Sstevel@tonic-gate 	putnext(q, mp);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate /*
10150Sstevel@tonic-gate  * Called by rts_wput_other to handle all M_IOCDATA messages.
10160Sstevel@tonic-gate  */
10170Sstevel@tonic-gate static void
10180Sstevel@tonic-gate rts_wput_iocdata(queue_t *q, mblk_t *mp)
10190Sstevel@tonic-gate {
10200Sstevel@tonic-gate 	struct sockaddr	*rtsaddr;
10210Sstevel@tonic-gate 	mblk_t	*mp1;
10220Sstevel@tonic-gate 	STRUCT_HANDLE(strbuf, sb);
10230Sstevel@tonic-gate 	struct iocblk	*iocp	= (struct iocblk *)mp->b_rptr;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	/* Make sure it is one of ours. */
10260Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
10270Sstevel@tonic-gate 	case TI_GETPEERNAME:
10280Sstevel@tonic-gate 		break;
10290Sstevel@tonic-gate 	default:
10300Sstevel@tonic-gate 		putnext(q, mp);
10310Sstevel@tonic-gate 		return;
10320Sstevel@tonic-gate 	}
10330Sstevel@tonic-gate 	switch (mi_copy_state(q, mp, &mp1)) {
10340Sstevel@tonic-gate 	case -1:
10350Sstevel@tonic-gate 		return;
10360Sstevel@tonic-gate 	case MI_COPY_CASE(MI_COPY_IN, 1):
10370Sstevel@tonic-gate 		break;
10380Sstevel@tonic-gate 	case MI_COPY_CASE(MI_COPY_OUT, 1):
10390Sstevel@tonic-gate 		/* Copy out the strbuf. */
10400Sstevel@tonic-gate 		mi_copyout(q, mp);
10410Sstevel@tonic-gate 		return;
10420Sstevel@tonic-gate 	case MI_COPY_CASE(MI_COPY_OUT, 2):
10430Sstevel@tonic-gate 		/* All done. */
10440Sstevel@tonic-gate 		mi_copy_done(q, mp, 0);
10450Sstevel@tonic-gate 		return;
10460Sstevel@tonic-gate 	default:
10470Sstevel@tonic-gate 		mi_copy_done(q, mp, EPROTO);
10480Sstevel@tonic-gate 		return;
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 	STRUCT_SET_HANDLE(sb, iocp->ioc_flag, (void *)mp1->b_rptr);
10510Sstevel@tonic-gate 	if (STRUCT_FGET(sb, maxlen) < (int)sizeof (sin_t)) {
10520Sstevel@tonic-gate 		mi_copy_done(q, mp, EINVAL);
10530Sstevel@tonic-gate 		return;
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
10560Sstevel@tonic-gate 	case TI_GETPEERNAME:
10570Sstevel@tonic-gate 		break;
10580Sstevel@tonic-gate 	default:
10590Sstevel@tonic-gate 		mi_copy_done(q, mp, EPROTO);
10600Sstevel@tonic-gate 		return;
10610Sstevel@tonic-gate 	}
10620Sstevel@tonic-gate 	mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), sizeof (sin_t),
10630Sstevel@tonic-gate 	    B_TRUE);
10640Sstevel@tonic-gate 	if (mp1 == NULL)
10650Sstevel@tonic-gate 		return;
10660Sstevel@tonic-gate 	STRUCT_FSET(sb, len, (int)sizeof (sin_t));
10670Sstevel@tonic-gate 	rtsaddr = (struct sockaddr *)mp1->b_rptr;
10680Sstevel@tonic-gate 	mp1->b_wptr = (uchar_t *)&rtsaddr[1];
10690Sstevel@tonic-gate 	bzero(rtsaddr, sizeof (struct sockaddr));
10700Sstevel@tonic-gate 	rtsaddr->sa_family = AF_ROUTE;
10710Sstevel@tonic-gate 	/* Copy out the address */
10720Sstevel@tonic-gate 	mi_copyout(q, mp);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate static void
10760Sstevel@tonic-gate rts_rput(queue_t *q, mblk_t *mp)
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate 	rts_t	*rts;
10790Sstevel@tonic-gate 	struct iocblk	*iocp;
10800Sstevel@tonic-gate 	mblk_t *mp1;
10810Sstevel@tonic-gate 	struct T_data_ind *tdi;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	rts = (rts_t *)q->q_ptr;
10840Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
10850Sstevel@tonic-gate 	case M_IOCACK:
10860Sstevel@tonic-gate 	case M_IOCNAK:
10870Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
10880Sstevel@tonic-gate 		if (rts->rts_flag & (RTS_WPUT_PENDING|RTS_OPEN_PENDING)) {
10890Sstevel@tonic-gate 			if (rts->rts_flag & RTS_WPUT_PENDING)
10900Sstevel@tonic-gate 				rts->rts_flag &= ~RTS_WPUT_PENDING;
10910Sstevel@tonic-gate 			else
10920Sstevel@tonic-gate 				rts->rts_flag &= ~RTS_OPEN_PENDING;
10930Sstevel@tonic-gate 			rts->rts_error = iocp->ioc_error;
10940Sstevel@tonic-gate 			freemsg(mp);
10950Sstevel@tonic-gate 			return;
10960Sstevel@tonic-gate 		}
10970Sstevel@tonic-gate 		break;
10980Sstevel@tonic-gate 	case M_DATA:
10990Sstevel@tonic-gate 		/*
11000Sstevel@tonic-gate 		 * Prepend T_DATA_IND to prevent the stream head from
11010Sstevel@tonic-gate 		 * consolidating multiple messages together.
11020Sstevel@tonic-gate 		 * If the allocation fails just send up the M_DATA.
11030Sstevel@tonic-gate 		 */
11040Sstevel@tonic-gate 		mp1 = allocb(sizeof (*tdi), BPRI_MED);
11050Sstevel@tonic-gate 		if (mp1 != NULL) {
11060Sstevel@tonic-gate 			mp1->b_cont = mp;
11070Sstevel@tonic-gate 			mp = mp1;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 			mp->b_datap->db_type = M_PROTO;
11100Sstevel@tonic-gate 			mp->b_wptr += sizeof (*tdi);
11110Sstevel@tonic-gate 			tdi = (struct T_data_ind *)mp->b_rptr;
11120Sstevel@tonic-gate 			tdi->PRIM_type = T_DATA_IND;
11130Sstevel@tonic-gate 			tdi->MORE_flag = 0;
11140Sstevel@tonic-gate 		}
11150Sstevel@tonic-gate 		break;
11160Sstevel@tonic-gate 	default:
11170Sstevel@tonic-gate 		break;
11180Sstevel@tonic-gate 	}
11190Sstevel@tonic-gate 	putnext(q, mp);
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate void
11240Sstevel@tonic-gate rts_ddi_init(void)
11250Sstevel@tonic-gate {
11260Sstevel@tonic-gate 	rts_max_optsize = optcom_max_optsize(rts_opt_obj.odb_opt_des_arr,
11270Sstevel@tonic-gate 	    rts_opt_obj.odb_opt_arr_cnt);
11283448Sdh155122 
11293448Sdh155122 	/*
11303448Sdh155122 	 * We want to be informed each time a stack is created or
11313448Sdh155122 	 * destroyed in the kernel, so we can maintain the
11323448Sdh155122 	 * set of rts_stack_t's.
11333448Sdh155122 	 */
11343448Sdh155122 	netstack_register(NS_RTS, rts_stack_init, NULL, rts_stack_fini);
11350Sstevel@tonic-gate }
11363448Sdh155122 
11373448Sdh155122 void
11383448Sdh155122 rts_ddi_destroy(void)
11393448Sdh155122 {
11403448Sdh155122 	netstack_unregister(NS_RTS);
11413448Sdh155122 }
11423448Sdh155122 
11433448Sdh155122 /*
11443448Sdh155122  * Initialize the RTS stack instance.
11453448Sdh155122  */
11463448Sdh155122 /* ARGSUSED */
11473448Sdh155122 static void *
11483448Sdh155122 rts_stack_init(netstackid_t stackid, netstack_t *ns)
11493448Sdh155122 {
11503448Sdh155122 	rts_stack_t	*rtss;
11513448Sdh155122 	rtsparam_t	*pa;
11523448Sdh155122 
11533448Sdh155122 	rtss = (rts_stack_t *)kmem_zalloc(sizeof (*rtss), KM_SLEEP);
11543448Sdh155122 	rtss->rtss_netstack = ns;
11553448Sdh155122 
11563448Sdh155122 	pa = (rtsparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
11573448Sdh155122 	rtss->rtss_params = pa;
11583448Sdh155122 	bcopy(lcl_param_arr, rtss->rtss_params, sizeof (lcl_param_arr));
11593448Sdh155122 
11603448Sdh155122 	(void) rts_param_register(&rtss->rtss_g_nd,
11613448Sdh155122 	    rtss->rtss_params, A_CNT(lcl_param_arr));
11623448Sdh155122 	return (rtss);
11633448Sdh155122 }
11643448Sdh155122 
11653448Sdh155122 /*
11663448Sdh155122  * Free the RTS stack instance.
11673448Sdh155122  */
11683448Sdh155122 /* ARGSUSED */
11693448Sdh155122 static void
11703448Sdh155122 rts_stack_fini(netstackid_t stackid, void *arg)
11713448Sdh155122 {
11723448Sdh155122 	rts_stack_t *rtss = (rts_stack_t *)arg;
11733448Sdh155122 
11743448Sdh155122 	rts_param_cleanup(&rtss->rtss_g_nd);
11753448Sdh155122 	kmem_free(rtss->rtss_params, sizeof (lcl_param_arr));
11763448Sdh155122 	rtss->rtss_params = NULL;
11773448Sdh155122 	kmem_free(rtss, sizeof (*rtss));
11783448Sdh155122 }
1179