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