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