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