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 /* 228477SRao.Shoaib@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/types.h> 270Sstevel@tonic-gate #include <sys/stream.h> 280Sstevel@tonic-gate #include <sys/strsubr.h> 290Sstevel@tonic-gate #include <sys/stropts.h> 300Sstevel@tonic-gate #include <sys/strsun.h> 310Sstevel@tonic-gate #include <sys/strlog.h> 320Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 330Sstevel@tonic-gate #include <sys/tihdr.h> 340Sstevel@tonic-gate #include <sys/timod.h> 350Sstevel@tonic-gate #include <sys/ddi.h> 360Sstevel@tonic-gate #include <sys/sunddi.h> 370Sstevel@tonic-gate #include <sys/cmn_err.h> 380Sstevel@tonic-gate #include <sys/proc.h> 390Sstevel@tonic-gate #include <sys/suntpi.h> 400Sstevel@tonic-gate #include <sys/policy.h> 413448Sdh155122 #include <sys/zone.h> 428348SEric.Yu@Sun.COM #include <sys/disp.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include <sys/socket.h> 458348SEric.Yu@Sun.COM #include <sys/socketvar.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> 515240Snordmark #include <inet/ipclassifier.h> 528348SEric.Yu@Sun.COM #include <inet/proto_set.h> 530Sstevel@tonic-gate #include <inet/nd.h> 540Sstevel@tonic-gate #include <inet/optcom.h> 550Sstevel@tonic-gate #include <netinet/ip_mroute.h> 560Sstevel@tonic-gate #include <sys/isa_defs.h> 570Sstevel@tonic-gate #include <net/route.h> 580Sstevel@tonic-gate 595240Snordmark #include <inet/rts_impl.h> 605240Snordmark #include <inet/ip_rts.h> 615240Snordmark 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * This is a transport provider for routing sockets. Downstream messages are 640Sstevel@tonic-gate * wrapped with a IP_IOCTL header, and ip_wput_ioctl calls the appropriate entry 650Sstevel@tonic-gate * in the ip_ioctl_ftbl callout table to pass the routing socket data into IP. 660Sstevel@tonic-gate * Upstream messages are generated for listeners of the routing socket as well 670Sstevel@tonic-gate * as the message sender (unless they have turned off their end using 680Sstevel@tonic-gate * SO_USELOOPBACK or shutdown(3n)). Upstream messages may also be generated 690Sstevel@tonic-gate * asynchronously when: 700Sstevel@tonic-gate * 710Sstevel@tonic-gate * Interfaces are brought up or down. 720Sstevel@tonic-gate * Addresses are assigned to interfaces. 734365Snordmark * ICMP redirects are processed and a IRE_HOST/RTF_DYNAMIC is installed. 740Sstevel@tonic-gate * No route is found while sending a packet. 750Sstevel@tonic-gate * When TCP requests IP to remove an IRE_CACHE of a troubled destination. 760Sstevel@tonic-gate * 770Sstevel@tonic-gate * Since all we do is reformat the messages between routing socket and 780Sstevel@tonic-gate * ioctl forms, no synchronization is necessary in this module; all 790Sstevel@tonic-gate * the dirty work is done down in ip. 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages */ 830Sstevel@tonic-gate static struct T_info_ack rts_g_t_info_ack = { 840Sstevel@tonic-gate T_INFO_ACK, 850Sstevel@tonic-gate T_INFINITE, /* TSDU_size. Maximum size messages. */ 860Sstevel@tonic-gate T_INVALID, /* ETSDU_size. No expedited data. */ 870Sstevel@tonic-gate T_INVALID, /* CDATA_size. No connect data. */ 880Sstevel@tonic-gate T_INVALID, /* DDATA_size. No disconnect data. */ 890Sstevel@tonic-gate 0, /* ADDR_size. */ 900Sstevel@tonic-gate 0, /* OPT_size - not initialized here */ 910Sstevel@tonic-gate 64 * 1024, /* TIDU_size. rts allows maximum size messages. */ 920Sstevel@tonic-gate T_COTS, /* SERV_type. rts supports connection oriented. */ 930Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from rts_state. */ 940Sstevel@tonic-gate (XPG4_1) /* PROVIDER_flag */ 950Sstevel@tonic-gate }; 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * Table of ND variables supported by rts. These are loaded into rts_g_nd 990Sstevel@tonic-gate * in rts_open. 1000Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 1010Sstevel@tonic-gate */ 1023448Sdh155122 static rtsparam_t lcl_param_arr[] = { 1030Sstevel@tonic-gate /* min max value name */ 1040Sstevel@tonic-gate { 4096, 65536, 8192, "rts_xmit_hiwat"}, 1050Sstevel@tonic-gate { 0, 65536, 1024, "rts_xmit_lowat"}, 1060Sstevel@tonic-gate { 4096, 65536, 8192, "rts_recv_hiwat"}, 1070Sstevel@tonic-gate { 65536, 1024*1024*1024, 256*1024, "rts_max_buf"}, 1080Sstevel@tonic-gate }; 1093448Sdh155122 #define rtss_xmit_hiwat rtss_params[0].rts_param_value 1103448Sdh155122 #define rtss_xmit_lowat rtss_params[1].rts_param_value 1113448Sdh155122 #define rtss_recv_hiwat rtss_params[2].rts_param_value 1125240Snordmark #define rtss_max_buf rtss_params[3].rts_param_value 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate static void rts_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, 1150Sstevel@tonic-gate int sys_error); 1165240Snordmark static void rts_input(void *, mblk_t *, void *); 1170Sstevel@tonic-gate static mblk_t *rts_ioctl_alloc(mblk_t *data, cred_t *cr); 1180Sstevel@tonic-gate static int rts_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr); 1193448Sdh155122 static boolean_t rts_param_register(IDP *ndp, rtsparam_t *rtspa, int cnt); 1200Sstevel@tonic-gate static int rts_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 1210Sstevel@tonic-gate cred_t *cr); 1225240Snordmark static void rts_rsrv(queue_t *q); 1233448Sdh155122 static void *rts_stack_init(netstackid_t stackid, netstack_t *ns); 1243448Sdh155122 static void rts_stack_fini(netstackid_t stackid, void *arg); 1250Sstevel@tonic-gate static void rts_wput(queue_t *q, mblk_t *mp); 1260Sstevel@tonic-gate static void rts_wput_iocdata(queue_t *q, mblk_t *mp); 1270Sstevel@tonic-gate static void rts_wput_other(queue_t *q, mblk_t *mp); 1280Sstevel@tonic-gate static int rts_wrw(queue_t *q, struiod_t *dp); 1290Sstevel@tonic-gate 1308348SEric.Yu@Sun.COM static int rts_stream_open(queue_t *q, dev_t *devp, int flag, int sflag, 1318348SEric.Yu@Sun.COM cred_t *credp); 1328348SEric.Yu@Sun.COM static conn_t *rts_open(int flag, cred_t *credp); 1338348SEric.Yu@Sun.COM 1348348SEric.Yu@Sun.COM static int rts_stream_close(queue_t *q); 1358348SEric.Yu@Sun.COM static int rts_close(sock_lower_handle_t proto_handle, int flags, 1368348SEric.Yu@Sun.COM cred_t *cr); 1378348SEric.Yu@Sun.COM 1385240Snordmark static struct module_info rts_mod_info = { 1390Sstevel@tonic-gate 129, "rts", 1, INFPSZ, 512, 128 1400Sstevel@tonic-gate }; 1410Sstevel@tonic-gate 1425240Snordmark static struct qinit rtsrinit = { 1438348SEric.Yu@Sun.COM NULL, (pfi_t)rts_rsrv, rts_stream_open, rts_stream_close, NULL, 1448348SEric.Yu@Sun.COM &rts_mod_info 1450Sstevel@tonic-gate }; 1460Sstevel@tonic-gate 1475240Snordmark static struct qinit rtswinit = { 1485240Snordmark (pfi_t)rts_wput, NULL, NULL, NULL, NULL, &rts_mod_info, 1490Sstevel@tonic-gate NULL, (pfi_t)rts_wrw, NULL, STRUIOT_STANDARD 1500Sstevel@tonic-gate }; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate struct streamtab rtsinfo = { 1535240Snordmark &rtsrinit, &rtswinit 1540Sstevel@tonic-gate }; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate /* 1570Sstevel@tonic-gate * This routine allocates the necessary 1580Sstevel@tonic-gate * message blocks for IOCTL wrapping the 1590Sstevel@tonic-gate * user data. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate static mblk_t * 1620Sstevel@tonic-gate rts_ioctl_alloc(mblk_t *data, cred_t *cr) 1630Sstevel@tonic-gate { 1640Sstevel@tonic-gate mblk_t *mp = NULL; 1650Sstevel@tonic-gate mblk_t *mp1 = NULL; 1660Sstevel@tonic-gate ipllc_t *ipllc; 1670Sstevel@tonic-gate struct iocblk *ioc; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate mp = allocb_cred(sizeof (ipllc_t), cr); 1700Sstevel@tonic-gate if (mp == NULL) 1710Sstevel@tonic-gate return (NULL); 1720Sstevel@tonic-gate mp1 = allocb_cred(sizeof (struct iocblk), cr); 1730Sstevel@tonic-gate if (mp1 == NULL) { 1740Sstevel@tonic-gate freeb(mp); 1750Sstevel@tonic-gate return (NULL); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate ipllc = (ipllc_t *)mp->b_rptr; 1790Sstevel@tonic-gate ipllc->ipllc_cmd = IP_IOC_RTS_REQUEST; 1800Sstevel@tonic-gate ipllc->ipllc_name_offset = 0; 1810Sstevel@tonic-gate ipllc->ipllc_name_length = 0; 1820Sstevel@tonic-gate mp->b_wptr += sizeof (ipllc_t); 1830Sstevel@tonic-gate mp->b_cont = data; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate ioc = (struct iocblk *)mp1->b_rptr; 1860Sstevel@tonic-gate ioc->ioc_cmd = IP_IOCTL; 1870Sstevel@tonic-gate ioc->ioc_error = 0; 1880Sstevel@tonic-gate ioc->ioc_cr = NULL; 1890Sstevel@tonic-gate ioc->ioc_count = msgdsize(mp); 1900Sstevel@tonic-gate mp1->b_wptr += sizeof (struct iocblk); 1910Sstevel@tonic-gate mp1->b_datap->db_type = M_IOCTL; 1920Sstevel@tonic-gate mp1->b_cont = mp; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate return (mp1); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate /* 1980Sstevel@tonic-gate * This routine closes rts stream, by disabling 1990Sstevel@tonic-gate * put/srv routines and freeing the this module 2000Sstevel@tonic-gate * internal datastructure. 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate static int 2038348SEric.Yu@Sun.COM rts_common_close(queue_t *q, conn_t *connp) 2040Sstevel@tonic-gate { 2055240Snordmark 2065240Snordmark ASSERT(connp != NULL && IPCL_IS_RTS(connp)); 2075240Snordmark 2085240Snordmark ip_rts_unregister(connp); 2095240Snordmark 2105240Snordmark ip_quiesce_conn(connp); 2113448Sdh155122 2128348SEric.Yu@Sun.COM if (!IPCL_IS_NONSTR(connp)) { 2138348SEric.Yu@Sun.COM qprocsoff(q); 2140Sstevel@tonic-gate 2158348SEric.Yu@Sun.COM /* 2168348SEric.Yu@Sun.COM * Now we are truly single threaded on this stream, and can 2178348SEric.Yu@Sun.COM * delete the things hanging off the connp, and finally the 2188348SEric.Yu@Sun.COM * connp. 2198348SEric.Yu@Sun.COM * We removed this connp from the fanout list, it cannot be 2208348SEric.Yu@Sun.COM * accessed thru the fanouts, and we already waited for the 2218348SEric.Yu@Sun.COM * conn_ref to drop to 0. We are already in close, so 2228348SEric.Yu@Sun.COM * there cannot be any other thread from the top. qprocsoff 2238348SEric.Yu@Sun.COM * has completed, and service has completed or won't run in 2248348SEric.Yu@Sun.COM * future. 2258348SEric.Yu@Sun.COM */ 2268348SEric.Yu@Sun.COM inet_minor_free(connp->conn_minor_arena, connp->conn_dev); 2278348SEric.Yu@Sun.COM } else { 2288477SRao.Shoaib@Sun.COM ip_free_helper_stream(connp); 2298348SEric.Yu@Sun.COM } 2305240Snordmark ASSERT(connp->conn_ref == 1); 2310Sstevel@tonic-gate 2325240Snordmark 2335240Snordmark connp->conn_ref--; 2345240Snordmark ipcl_conn_destroy(connp); 2355240Snordmark 2368348SEric.Yu@Sun.COM return (0); 2378348SEric.Yu@Sun.COM } 2388348SEric.Yu@Sun.COM 2398348SEric.Yu@Sun.COM static int 2408348SEric.Yu@Sun.COM rts_stream_close(queue_t *q) 2418348SEric.Yu@Sun.COM { 2428348SEric.Yu@Sun.COM conn_t *connp = Q_TO_CONN(q); 2438348SEric.Yu@Sun.COM 2448348SEric.Yu@Sun.COM (void) rts_common_close(q, connp); 2455240Snordmark q->q_ptr = WR(q)->q_ptr = NULL; 2460Sstevel@tonic-gate return (0); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* 2500Sstevel@tonic-gate * This is the open routine for routing socket. It allocates 2515240Snordmark * rts_t structure for the stream and tells IP that it is a routing socket. 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate /* ARGSUSED */ 2540Sstevel@tonic-gate static int 2558348SEric.Yu@Sun.COM rts_stream_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 2560Sstevel@tonic-gate { 2575240Snordmark conn_t *connp; 2585240Snordmark dev_t conn_dev; 2593448Sdh155122 rts_stack_t *rtss; 2608348SEric.Yu@Sun.COM rts_t *rts; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* If the stream is already open, return immediately. */ 2630Sstevel@tonic-gate if (q->q_ptr != NULL) 2640Sstevel@tonic-gate return (0); 2650Sstevel@tonic-gate 2665240Snordmark if (sflag == MODOPEN) 2670Sstevel@tonic-gate return (EINVAL); 2680Sstevel@tonic-gate 2698348SEric.Yu@Sun.COM 2708348SEric.Yu@Sun.COM /* 2718348SEric.Yu@Sun.COM * Since RTS is not used so heavily, allocating from the small 2728348SEric.Yu@Sun.COM * arena should be sufficient. 2738348SEric.Yu@Sun.COM */ 2748348SEric.Yu@Sun.COM if ((conn_dev = inet_minor_alloc(ip_minor_arena_sa)) == 0) { 2758348SEric.Yu@Sun.COM return (EBUSY); 2768348SEric.Yu@Sun.COM } 2778348SEric.Yu@Sun.COM 2788348SEric.Yu@Sun.COM connp = rts_open(flag, credp); 2798348SEric.Yu@Sun.COM ASSERT(connp != NULL); 2808348SEric.Yu@Sun.COM 2818348SEric.Yu@Sun.COM 2828348SEric.Yu@Sun.COM *devp = makedevice(getemajor(*devp), (minor_t)conn_dev); 2838348SEric.Yu@Sun.COM 2848348SEric.Yu@Sun.COM rts = connp->conn_rts; 2858348SEric.Yu@Sun.COM 2868348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 2878348SEric.Yu@Sun.COM connp->conn_dev = conn_dev; 2888348SEric.Yu@Sun.COM connp->conn_minor_arena = ip_minor_arena_sa; 2898348SEric.Yu@Sun.COM 2908348SEric.Yu@Sun.COM /* 2918348SEric.Yu@Sun.COM * Initialize the rts_t structure for this stream. 2928348SEric.Yu@Sun.COM */ 2938348SEric.Yu@Sun.COM q->q_ptr = connp; 2948348SEric.Yu@Sun.COM WR(q)->q_ptr = connp; 2958348SEric.Yu@Sun.COM connp->conn_rq = q; 2968348SEric.Yu@Sun.COM connp->conn_wq = WR(q); 2978348SEric.Yu@Sun.COM 2988348SEric.Yu@Sun.COM rtss = rts->rts_rtss; 2998348SEric.Yu@Sun.COM q->q_hiwat = rtss->rtss_recv_hiwat; 3008348SEric.Yu@Sun.COM WR(q)->q_hiwat = rtss->rtss_xmit_hiwat; 3018348SEric.Yu@Sun.COM WR(q)->q_lowat = rtss->rtss_xmit_lowat; 3028348SEric.Yu@Sun.COM 3038348SEric.Yu@Sun.COM 3048348SEric.Yu@Sun.COM 3058348SEric.Yu@Sun.COM mutex_enter(&connp->conn_lock); 3068348SEric.Yu@Sun.COM connp->conn_state_flags &= ~CONN_INCIPIENT; 3078348SEric.Yu@Sun.COM mutex_exit(&connp->conn_lock); 3088348SEric.Yu@Sun.COM 3098348SEric.Yu@Sun.COM qprocson(q); 3108348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 3118348SEric.Yu@Sun.COM /* 3128348SEric.Yu@Sun.COM * Indicate the down IP module that this is a routing socket 3138348SEric.Yu@Sun.COM * client by sending an RTS IOCTL without any user data. Although 3148348SEric.Yu@Sun.COM * this is just a notification message (without any real routing 3158348SEric.Yu@Sun.COM * request), we pass in any credential for correctness sake. 3168348SEric.Yu@Sun.COM */ 3178348SEric.Yu@Sun.COM ip_rts_register(connp); 3188348SEric.Yu@Sun.COM 3198348SEric.Yu@Sun.COM return (0); 3208348SEric.Yu@Sun.COM } 3218348SEric.Yu@Sun.COM 3228348SEric.Yu@Sun.COM /* ARGSUSED */ 3238348SEric.Yu@Sun.COM static conn_t * 3248348SEric.Yu@Sun.COM rts_open(int flag, cred_t *credp) 3258348SEric.Yu@Sun.COM { 3268348SEric.Yu@Sun.COM netstack_t *ns; 3278348SEric.Yu@Sun.COM rts_stack_t *rtss; 3288348SEric.Yu@Sun.COM rts_t *rts; 3298348SEric.Yu@Sun.COM conn_t *connp; 3308348SEric.Yu@Sun.COM zoneid_t zoneid; 3318348SEric.Yu@Sun.COM 3323448Sdh155122 ns = netstack_find_by_cred(credp); 3333448Sdh155122 ASSERT(ns != NULL); 3343448Sdh155122 rtss = ns->netstack_rts; 3353448Sdh155122 ASSERT(rtss != NULL); 3363448Sdh155122 3375240Snordmark /* 3385240Snordmark * For exclusive stacks we set the zoneid to zero 3395240Snordmark * to make RTS operate as if in the global zone. 3405240Snordmark */ 3415240Snordmark if (ns->netstack_stackid != GLOBAL_NETSTACKID) 3425240Snordmark zoneid = GLOBAL_ZONEID; 3435240Snordmark else 3445240Snordmark zoneid = crgetzoneid(credp); 3455240Snordmark 3465240Snordmark connp = ipcl_conn_create(IPCL_RTSCONN, KM_SLEEP, ns); 3475240Snordmark rts = connp->conn_rts; 3485240Snordmark 3495240Snordmark /* 3505240Snordmark * ipcl_conn_create did a netstack_hold. Undo the hold that was 3515240Snordmark * done by netstack_find_by_cred() 3525240Snordmark */ 3535240Snordmark netstack_rele(ns); 3545240Snordmark 3555240Snordmark 3565240Snordmark rw_enter(&rts->rts_rwlock, RW_WRITER); 3575240Snordmark ASSERT(connp->conn_rts == rts); 3585240Snordmark ASSERT(rts->rts_connp == connp); 3595240Snordmark 3605240Snordmark connp->conn_zoneid = zoneid; 3618348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_FALSE; 3625240Snordmark 3635240Snordmark connp->conn_ulp_labeled = is_system_labeled(); 3640Sstevel@tonic-gate 3653448Sdh155122 rts->rts_rtss = rtss; 3668348SEric.Yu@Sun.COM rts->rts_xmit_hiwat = rtss->rtss_xmit_hiwat; 3675240Snordmark 3685240Snordmark connp->conn_recv = rts_input; 3695240Snordmark crhold(credp); 3705240Snordmark connp->conn_cred = credp; 3715240Snordmark 3728348SEric.Yu@Sun.COM /* 3738348SEric.Yu@Sun.COM * rts sockets start out as bound and connected 3748348SEric.Yu@Sun.COM * For streams based sockets, socket state is set to 3758348SEric.Yu@Sun.COM * SS_ISBOUND | SS_ISCONNECTED in so_strinit. 3768348SEric.Yu@Sun.COM */ 3778348SEric.Yu@Sun.COM rts->rts_state = TS_DATA_XFER; 3785240Snordmark rw_exit(&rts->rts_rwlock); 3795240Snordmark 3808348SEric.Yu@Sun.COM return (connp); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * This routine creates a T_ERROR_ACK message and passes it upstream. 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate static void 3870Sstevel@tonic-gate rts_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error) 3880Sstevel@tonic-gate { 3890Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 3900Sstevel@tonic-gate qreply(q, mp); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * This routine creates a T_OK_ACK message and passes it upstream. 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate static void 3970Sstevel@tonic-gate rts_ok_ack(queue_t *q, mblk_t *mp) 3980Sstevel@tonic-gate { 3990Sstevel@tonic-gate if ((mp = mi_tpi_ok_ack_alloc(mp)) != NULL) 4000Sstevel@tonic-gate qreply(q, mp); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * This routine is called by rts_wput to handle T_UNBIND_REQ messages. 4050Sstevel@tonic-gate */ 4060Sstevel@tonic-gate static void 4078348SEric.Yu@Sun.COM rts_tpi_unbind(queue_t *q, mblk_t *mp) 4080Sstevel@tonic-gate { 4095240Snordmark conn_t *connp = Q_TO_CONN(q); 4105240Snordmark rts_t *rts = connp->conn_rts; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* If a bind has not been done, we can't unbind. */ 4130Sstevel@tonic-gate if (rts->rts_state != TS_IDLE) { 4140Sstevel@tonic-gate rts_err_ack(q, mp, TOUTSTATE, 0); 4150Sstevel@tonic-gate return; 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate rts->rts_state = TS_UNBND; 4180Sstevel@tonic-gate rts_ok_ack(q, mp); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * This routine is called to handle each 4230Sstevel@tonic-gate * O_T_BIND_REQ/T_BIND_REQ message passed to 4240Sstevel@tonic-gate * rts_wput. Note: This routine works with both 4250Sstevel@tonic-gate * O_T_BIND_REQ and T_BIND_REQ semantics. 4260Sstevel@tonic-gate */ 4270Sstevel@tonic-gate static void 4288348SEric.Yu@Sun.COM rts_tpi_bind(queue_t *q, mblk_t *mp) 4290Sstevel@tonic-gate { 4305240Snordmark conn_t *connp = Q_TO_CONN(q); 4315240Snordmark rts_t *rts = connp->conn_rts; 4320Sstevel@tonic-gate mblk_t *mp1; 4330Sstevel@tonic-gate struct T_bind_req *tbr; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (*tbr)) { 4360Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 4378348SEric.Yu@Sun.COM "rts_tpi_bind: bad data, %d", rts->rts_state); 4380Sstevel@tonic-gate rts_err_ack(q, mp, TBADADDR, 0); 4390Sstevel@tonic-gate return; 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate if (rts->rts_state != TS_UNBND) { 4420Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 4438348SEric.Yu@Sun.COM "rts_tpi_bind: bad state, %d", rts->rts_state); 4440Sstevel@tonic-gate rts_err_ack(q, mp, TOUTSTATE, 0); 4450Sstevel@tonic-gate return; 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * Reallocate the message to make sure we have enough room for an 4490Sstevel@tonic-gate * address and the protocol type. 4500Sstevel@tonic-gate */ 4510Sstevel@tonic-gate mp1 = reallocb(mp, sizeof (struct T_bind_ack) + sizeof (sin_t), 1); 4520Sstevel@tonic-gate if (mp1 == NULL) { 4530Sstevel@tonic-gate rts_err_ack(q, mp, TSYSERR, ENOMEM); 4540Sstevel@tonic-gate return; 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate mp = mp1; 4570Sstevel@tonic-gate tbr = (struct T_bind_req *)mp->b_rptr; 4580Sstevel@tonic-gate if (tbr->ADDR_length != 0) { 4590Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 4608348SEric.Yu@Sun.COM "rts_tpi_bind: bad ADDR_length %d", tbr->ADDR_length); 4610Sstevel@tonic-gate rts_err_ack(q, mp, TBADADDR, 0); 4620Sstevel@tonic-gate return; 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate /* Generic request */ 4650Sstevel@tonic-gate tbr->ADDR_offset = (t_scalar_t)sizeof (struct T_bind_req); 4660Sstevel@tonic-gate tbr->ADDR_length = 0; 4670Sstevel@tonic-gate tbr->PRIM_type = T_BIND_ACK; 4680Sstevel@tonic-gate rts->rts_state = TS_IDLE; 4690Sstevel@tonic-gate qreply(q, mp); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate static void 4730Sstevel@tonic-gate rts_copy_info(struct T_info_ack *tap, rts_t *rts) 4740Sstevel@tonic-gate { 4750Sstevel@tonic-gate *tap = rts_g_t_info_ack; 4760Sstevel@tonic-gate tap->CURRENT_state = rts->rts_state; 4770Sstevel@tonic-gate tap->OPT_size = rts_max_optsize; 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 4820Sstevel@tonic-gate * rts_wput. Much of the T_CAPABILITY_ACK information is copied from 4830Sstevel@tonic-gate * rts_g_t_info_ack. The current state of the stream is copied from 4840Sstevel@tonic-gate * rts_state. 4850Sstevel@tonic-gate */ 4860Sstevel@tonic-gate static void 4870Sstevel@tonic-gate rts_capability_req(queue_t *q, mblk_t *mp) 4880Sstevel@tonic-gate { 4895240Snordmark conn_t *connp = Q_TO_CONN(q); 4905240Snordmark rts_t *rts = connp->conn_rts; 4910Sstevel@tonic-gate t_uscalar_t cap_bits1; 4920Sstevel@tonic-gate struct T_capability_ack *tcap; 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 4975240Snordmark mp->b_datap->db_type, T_CAPABILITY_ACK); 4980Sstevel@tonic-gate if (mp == NULL) 4990Sstevel@tonic-gate return; 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr; 5020Sstevel@tonic-gate tcap->CAP_bits1 = 0; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 5050Sstevel@tonic-gate rts_copy_info(&tcap->INFO_ack, rts); 5060Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate qreply(q, mp); 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate /* 5130Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by rts_wput. 5140Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from rts_g_t_info_ack. 5150Sstevel@tonic-gate * The current state of the stream is copied from rts_state. 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate static void 5180Sstevel@tonic-gate rts_info_req(queue_t *q, mblk_t *mp) 5190Sstevel@tonic-gate { 5205240Snordmark conn_t *connp = Q_TO_CONN(q); 5215240Snordmark rts_t *rts = connp->conn_rts; 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (rts_g_t_info_ack), M_PCPROTO, 5240Sstevel@tonic-gate T_INFO_ACK); 5250Sstevel@tonic-gate if (mp == NULL) 5260Sstevel@tonic-gate return; 5270Sstevel@tonic-gate rts_copy_info((struct T_info_ack *)mp->b_rptr, rts); 5280Sstevel@tonic-gate qreply(q, mp); 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate /* 5320Sstevel@tonic-gate * This routine gets default values of certain options whose default 5330Sstevel@tonic-gate * values are maintained by protcol specific code 5340Sstevel@tonic-gate */ 5350Sstevel@tonic-gate /* ARGSUSED */ 5360Sstevel@tonic-gate int 5370Sstevel@tonic-gate rts_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 5380Sstevel@tonic-gate { 5390Sstevel@tonic-gate /* no default value processed by protocol specific code currently */ 5400Sstevel@tonic-gate return (-1); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5438348SEric.Yu@Sun.COM 5448348SEric.Yu@Sun.COM static int 5458348SEric.Yu@Sun.COM rts_opt_get(conn_t *connp, int level, int name, uchar_t *ptr) 5460Sstevel@tonic-gate { 5478348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 5480Sstevel@tonic-gate int *i1 = (int *)ptr; 5498348SEric.Yu@Sun.COM 5508348SEric.Yu@Sun.COM ASSERT(RW_READ_HELD(&rts->rts_rwlock)); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate switch (level) { 5530Sstevel@tonic-gate case SOL_SOCKET: 5540Sstevel@tonic-gate switch (name) { 5550Sstevel@tonic-gate case SO_DEBUG: 5560Sstevel@tonic-gate *i1 = rts->rts_debug; 5570Sstevel@tonic-gate break; 5580Sstevel@tonic-gate case SO_REUSEADDR: 5590Sstevel@tonic-gate *i1 = rts->rts_reuseaddr; 5600Sstevel@tonic-gate break; 5610Sstevel@tonic-gate case SO_TYPE: 5620Sstevel@tonic-gate *i1 = SOCK_RAW; 5630Sstevel@tonic-gate break; 5640Sstevel@tonic-gate /* 5650Sstevel@tonic-gate * The following three items are available here, 5660Sstevel@tonic-gate * but are only meaningful to IP. 5670Sstevel@tonic-gate */ 5680Sstevel@tonic-gate case SO_DONTROUTE: 5690Sstevel@tonic-gate *i1 = rts->rts_dontroute; 5700Sstevel@tonic-gate break; 5710Sstevel@tonic-gate case SO_USELOOPBACK: 5720Sstevel@tonic-gate *i1 = rts->rts_useloopback; 5730Sstevel@tonic-gate break; 5740Sstevel@tonic-gate case SO_BROADCAST: 5750Sstevel@tonic-gate *i1 = rts->rts_broadcast; 5760Sstevel@tonic-gate break; 5770Sstevel@tonic-gate case SO_PROTOTYPE: 5780Sstevel@tonic-gate *i1 = rts->rts_proto; 5790Sstevel@tonic-gate break; 5800Sstevel@tonic-gate /* 5810Sstevel@tonic-gate * The following two items can be manipulated, 5820Sstevel@tonic-gate * but changing them should do nothing. 5830Sstevel@tonic-gate */ 5840Sstevel@tonic-gate case SO_SNDBUF: 5858348SEric.Yu@Sun.COM ASSERT(rts->rts_xmit_hiwat <= INT_MAX); 5868348SEric.Yu@Sun.COM *i1 = (int)(rts->rts_xmit_hiwat); 5870Sstevel@tonic-gate break; 5880Sstevel@tonic-gate case SO_RCVBUF: 5898348SEric.Yu@Sun.COM ASSERT(rts->rts_recv_hiwat <= INT_MAX); 5908348SEric.Yu@Sun.COM *i1 = (int)(rts->rts_recv_hiwat); 5910Sstevel@tonic-gate break; 5923388Skcpoon case SO_DOMAIN: 5933388Skcpoon *i1 = PF_ROUTE; 5943388Skcpoon break; 5950Sstevel@tonic-gate default: 5960Sstevel@tonic-gate return (-1); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate break; 599*8485SPeter.Memishian@Sun.COM case SOL_ROUTE: 600*8485SPeter.Memishian@Sun.COM switch (name) { 601*8485SPeter.Memishian@Sun.COM case RT_AWARE: 602*8485SPeter.Memishian@Sun.COM mutex_enter(&connp->conn_lock); 603*8485SPeter.Memishian@Sun.COM *i1 = connp->conn_rtaware; 604*8485SPeter.Memishian@Sun.COM mutex_exit(&connp->conn_lock); 605*8485SPeter.Memishian@Sun.COM break; 606*8485SPeter.Memishian@Sun.COM } 607*8485SPeter.Memishian@Sun.COM break; 6080Sstevel@tonic-gate default: 6090Sstevel@tonic-gate return (-1); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate return ((int)sizeof (int)); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6148348SEric.Yu@Sun.COM /* ARGSUSED */ 6158348SEric.Yu@Sun.COM static int 6168348SEric.Yu@Sun.COM rts_do_opt_set(conn_t *connp, int level, int name, uint_t inlen, 6178348SEric.Yu@Sun.COM uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, cred_t *cr, 6188348SEric.Yu@Sun.COM void *thisdg_attrs, boolean_t checkonly) 6190Sstevel@tonic-gate { 6200Sstevel@tonic-gate int *i1 = (int *)invalp; 6215240Snordmark rts_t *rts = connp->conn_rts; 6223448Sdh155122 rts_stack_t *rtss = rts->rts_rtss; 6230Sstevel@tonic-gate 6248348SEric.Yu@Sun.COM ASSERT(RW_WRITE_HELD(&rts->rts_rwlock)); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * For rts, we should have no ancillary data sent down 6280Sstevel@tonic-gate * (rts_wput doesn't handle options). 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate ASSERT(thisdg_attrs == NULL); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate /* 6330Sstevel@tonic-gate * For fixed length options, no sanity check 6340Sstevel@tonic-gate * of passed in length is done. It is assumed *_optcom_req() 6350Sstevel@tonic-gate * routines do the right thing. 6360Sstevel@tonic-gate */ 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate switch (level) { 6390Sstevel@tonic-gate case SOL_SOCKET: 6400Sstevel@tonic-gate switch (name) { 6410Sstevel@tonic-gate case SO_REUSEADDR: 6420Sstevel@tonic-gate if (!checkonly) 6430Sstevel@tonic-gate rts->rts_reuseaddr = *i1; 6440Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6450Sstevel@tonic-gate case SO_DEBUG: 6460Sstevel@tonic-gate if (!checkonly) 6470Sstevel@tonic-gate rts->rts_debug = *i1; 6480Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * The following three items are available here, 6510Sstevel@tonic-gate * but are only meaningful to IP. 6520Sstevel@tonic-gate */ 6530Sstevel@tonic-gate case SO_DONTROUTE: 6540Sstevel@tonic-gate if (!checkonly) 6550Sstevel@tonic-gate rts->rts_dontroute = *i1; 6560Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6570Sstevel@tonic-gate case SO_USELOOPBACK: 6580Sstevel@tonic-gate if (!checkonly) 6590Sstevel@tonic-gate rts->rts_useloopback = *i1; 6600Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6610Sstevel@tonic-gate case SO_BROADCAST: 6620Sstevel@tonic-gate if (!checkonly) 6630Sstevel@tonic-gate rts->rts_broadcast = *i1; 6640Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6650Sstevel@tonic-gate case SO_PROTOTYPE: 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * Routing socket applications that call socket() with 6680Sstevel@tonic-gate * a third argument can filter which messages will be 6690Sstevel@tonic-gate * sent upstream thanks to sockfs. so_socket() sends 6700Sstevel@tonic-gate * down the SO_PROTOTYPE and rts_queue_input() 6710Sstevel@tonic-gate * implements the filtering. 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate if (*i1 != AF_INET && *i1 != AF_INET6) 6740Sstevel@tonic-gate return (EPROTONOSUPPORT); 6750Sstevel@tonic-gate if (!checkonly) 6760Sstevel@tonic-gate rts->rts_proto = *i1; 6770Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6780Sstevel@tonic-gate /* 6790Sstevel@tonic-gate * The following two items can be manipulated, 6800Sstevel@tonic-gate * but changing them should do nothing. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate case SO_SNDBUF: 6833448Sdh155122 if (*i1 > rtss->rtss_max_buf) { 6840Sstevel@tonic-gate *outlenp = 0; 6850Sstevel@tonic-gate return (ENOBUFS); 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate if (!checkonly) { 6888348SEric.Yu@Sun.COM rts->rts_xmit_hiwat = *i1; 6898348SEric.Yu@Sun.COM if (!IPCL_IS_NONSTR(connp)) 6908348SEric.Yu@Sun.COM connp->conn_wq->q_hiwat = *i1; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6930Sstevel@tonic-gate case SO_RCVBUF: 6943448Sdh155122 if (*i1 > rtss->rtss_max_buf) { 6950Sstevel@tonic-gate *outlenp = 0; 6960Sstevel@tonic-gate return (ENOBUFS); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate if (!checkonly) { 6998348SEric.Yu@Sun.COM rts->rts_recv_hiwat = *i1; 7008348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 7018348SEric.Yu@Sun.COM (void) proto_set_rx_hiwat(connp->conn_rq, connp, 7028348SEric.Yu@Sun.COM *i1); 7038348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 7040Sstevel@tonic-gate } 7058348SEric.Yu@Sun.COM 7060Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 7070Sstevel@tonic-gate default: 7080Sstevel@tonic-gate *outlenp = 0; 7090Sstevel@tonic-gate return (EINVAL); 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate break; 712*8485SPeter.Memishian@Sun.COM case SOL_ROUTE: 713*8485SPeter.Memishian@Sun.COM switch (name) { 714*8485SPeter.Memishian@Sun.COM case RT_AWARE: 715*8485SPeter.Memishian@Sun.COM if (!checkonly) { 716*8485SPeter.Memishian@Sun.COM mutex_enter(&connp->conn_lock); 717*8485SPeter.Memishian@Sun.COM connp->conn_rtaware = *i1; 718*8485SPeter.Memishian@Sun.COM mutex_exit(&connp->conn_lock); 719*8485SPeter.Memishian@Sun.COM } 720*8485SPeter.Memishian@Sun.COM break; /* goto sizeof (int) option return */ 721*8485SPeter.Memishian@Sun.COM default: 722*8485SPeter.Memishian@Sun.COM *outlenp = 0; 723*8485SPeter.Memishian@Sun.COM return (EINVAL); 724*8485SPeter.Memishian@Sun.COM } 725*8485SPeter.Memishian@Sun.COM break; 7260Sstevel@tonic-gate default: 7270Sstevel@tonic-gate *outlenp = 0; 7280Sstevel@tonic-gate return (EINVAL); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate /* 7310Sstevel@tonic-gate * Common case of return from an option that is sizeof (int) 7320Sstevel@tonic-gate */ 7338348SEric.Yu@Sun.COM if (invalp != outvalp) { 7348348SEric.Yu@Sun.COM /* don't trust bcopy for identical src/dst */ 7358348SEric.Yu@Sun.COM (void) bcopy(invalp, outvalp, inlen); 7368348SEric.Yu@Sun.COM } 7370Sstevel@tonic-gate *outlenp = (t_uscalar_t)sizeof (int); 7380Sstevel@tonic-gate return (0); 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate 7418348SEric.Yu@Sun.COM static int 7428348SEric.Yu@Sun.COM rts_opt_set(conn_t *connp, uint_t optset_context, int level, int name, 7438348SEric.Yu@Sun.COM uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 7448348SEric.Yu@Sun.COM void *thisdg_attrs, cred_t *cr) 7458348SEric.Yu@Sun.COM { 7468348SEric.Yu@Sun.COM boolean_t checkonly = B_FALSE; 7478348SEric.Yu@Sun.COM 7488348SEric.Yu@Sun.COM if (optset_context) { 7498348SEric.Yu@Sun.COM switch (optset_context) { 7508348SEric.Yu@Sun.COM case SETFN_OPTCOM_CHECKONLY: 7518348SEric.Yu@Sun.COM checkonly = B_TRUE; 7528348SEric.Yu@Sun.COM /* 7538348SEric.Yu@Sun.COM * Note: Implies T_CHECK semantics for T_OPTCOM_REQ 7548348SEric.Yu@Sun.COM * inlen != 0 implies value supplied and 7558348SEric.Yu@Sun.COM * we have to "pretend" to set it. 7568348SEric.Yu@Sun.COM * inlen == 0 implies that there is no value part 7578348SEric.Yu@Sun.COM * in T_CHECK request and just validation 7588348SEric.Yu@Sun.COM * done elsewhere should be enough, we just return here. 7598348SEric.Yu@Sun.COM */ 7608348SEric.Yu@Sun.COM if (inlen == 0) { 7618348SEric.Yu@Sun.COM *outlenp = 0; 7628348SEric.Yu@Sun.COM return (0); 7638348SEric.Yu@Sun.COM } 7648348SEric.Yu@Sun.COM break; 7658348SEric.Yu@Sun.COM case SETFN_OPTCOM_NEGOTIATE: 7668348SEric.Yu@Sun.COM checkonly = B_FALSE; 7678348SEric.Yu@Sun.COM break; 7688348SEric.Yu@Sun.COM case SETFN_UD_NEGOTIATE: 7698348SEric.Yu@Sun.COM case SETFN_CONN_NEGOTIATE: 7708348SEric.Yu@Sun.COM checkonly = B_FALSE; 7718348SEric.Yu@Sun.COM /* 7728348SEric.Yu@Sun.COM * Negotiating local and "association-related" options 7738348SEric.Yu@Sun.COM * through T_UNITDATA_REQ or T_CONN_{REQ,CON} 7748348SEric.Yu@Sun.COM * Not allowed in this module. 7758348SEric.Yu@Sun.COM */ 7768348SEric.Yu@Sun.COM return (EINVAL); 7778348SEric.Yu@Sun.COM default: 7788348SEric.Yu@Sun.COM /* 7798348SEric.Yu@Sun.COM * We should never get here 7808348SEric.Yu@Sun.COM */ 7818348SEric.Yu@Sun.COM *outlenp = 0; 7828348SEric.Yu@Sun.COM return (EINVAL); 7838348SEric.Yu@Sun.COM } 7848348SEric.Yu@Sun.COM 7858348SEric.Yu@Sun.COM ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) || 7868348SEric.Yu@Sun.COM (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0)); 7878348SEric.Yu@Sun.COM 7888348SEric.Yu@Sun.COM } 7898348SEric.Yu@Sun.COM return (rts_do_opt_set(connp, level, name, inlen, invalp, outlenp, 7908348SEric.Yu@Sun.COM outvalp, cr, thisdg_attrs, checkonly)); 7918348SEric.Yu@Sun.COM 7928348SEric.Yu@Sun.COM } 7938348SEric.Yu@Sun.COM 7948348SEric.Yu@Sun.COM /* 7958348SEric.Yu@Sun.COM * This routine retrieves the current status of socket options. 7968348SEric.Yu@Sun.COM * It returns the size of the option retrieved. 7978348SEric.Yu@Sun.COM */ 7988348SEric.Yu@Sun.COM int 7998348SEric.Yu@Sun.COM rts_tpi_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 8008348SEric.Yu@Sun.COM { 8018348SEric.Yu@Sun.COM rts_t *rts; 8028348SEric.Yu@Sun.COM int err; 8038348SEric.Yu@Sun.COM 8048348SEric.Yu@Sun.COM rts = Q_TO_RTS(q); 8058348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_READER); 8068348SEric.Yu@Sun.COM err = rts_opt_get(Q_TO_CONN(q), level, name, ptr); 8078348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 8088348SEric.Yu@Sun.COM return (err); 8098348SEric.Yu@Sun.COM } 8108348SEric.Yu@Sun.COM 8118348SEric.Yu@Sun.COM /* 8128348SEric.Yu@Sun.COM * This routine sets socket options. 8138348SEric.Yu@Sun.COM */ 8148348SEric.Yu@Sun.COM /*ARGSUSED*/ 8158348SEric.Yu@Sun.COM int 8168348SEric.Yu@Sun.COM rts_tpi_opt_set(queue_t *q, uint_t optset_context, int level, 8178348SEric.Yu@Sun.COM int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp, 8188348SEric.Yu@Sun.COM uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk) 8198348SEric.Yu@Sun.COM { 8208348SEric.Yu@Sun.COM conn_t *connp = Q_TO_CONN(q); 8218348SEric.Yu@Sun.COM int error; 8228348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 8238348SEric.Yu@Sun.COM 8248348SEric.Yu@Sun.COM 8258348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 8268348SEric.Yu@Sun.COM error = rts_opt_set(connp, optset_context, level, name, inlen, invalp, 8278348SEric.Yu@Sun.COM outlenp, outvalp, thisdg_attrs, cr); 8288348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 8298348SEric.Yu@Sun.COM return (error); 8308348SEric.Yu@Sun.COM } 8318348SEric.Yu@Sun.COM 8320Sstevel@tonic-gate /* 8330Sstevel@tonic-gate * This routine retrieves the value of an ND variable in a rtsparam_t 8340Sstevel@tonic-gate * structure. It is called through nd_getset when a user reads the 8350Sstevel@tonic-gate * variable. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate /* ARGSUSED */ 8380Sstevel@tonic-gate static int 8390Sstevel@tonic-gate rts_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 8400Sstevel@tonic-gate { 8410Sstevel@tonic-gate rtsparam_t *rtspa = (rtsparam_t *)cp; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", rtspa->rts_param_value); 8440Sstevel@tonic-gate return (0); 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate /* 8480Sstevel@tonic-gate * Walk through the param array specified registering each element with the 8490Sstevel@tonic-gate * named dispatch (ND) handler. 8500Sstevel@tonic-gate */ 8510Sstevel@tonic-gate static boolean_t 8523448Sdh155122 rts_param_register(IDP *ndp, rtsparam_t *rtspa, int cnt) 8530Sstevel@tonic-gate { 8540Sstevel@tonic-gate for (; cnt-- > 0; rtspa++) { 8550Sstevel@tonic-gate if (rtspa->rts_param_name != NULL && rtspa->rts_param_name[0]) { 8563448Sdh155122 if (!nd_load(ndp, rtspa->rts_param_name, 8570Sstevel@tonic-gate rts_param_get, rts_param_set, (caddr_t)rtspa)) { 8583448Sdh155122 nd_free(ndp); 8590Sstevel@tonic-gate return (B_FALSE); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate return (B_TRUE); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* This routine sets an ND variable in a rtsparam_t structure. */ 8670Sstevel@tonic-gate /* ARGSUSED */ 8680Sstevel@tonic-gate static int 8690Sstevel@tonic-gate rts_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 8700Sstevel@tonic-gate { 8710Sstevel@tonic-gate ulong_t new_value; 8720Sstevel@tonic-gate rtsparam_t *rtspa = (rtsparam_t *)cp; 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate /* 8750Sstevel@tonic-gate * Fail the request if the new value does not lie within the 8760Sstevel@tonic-gate * required bounds. 8770Sstevel@tonic-gate */ 8780Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 8790Sstevel@tonic-gate new_value < rtspa->rts_param_min || 8800Sstevel@tonic-gate new_value > rtspa->rts_param_max) { 8810Sstevel@tonic-gate return (EINVAL); 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate /* Set the new value */ 8850Sstevel@tonic-gate rtspa->rts_param_value = new_value; 8860Sstevel@tonic-gate return (0); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate /* 8905240Snordmark * Empty rsrv routine which is used by rts_input to cause a wakeup 8915240Snordmark * of a thread in qwait. 8925240Snordmark */ 8935240Snordmark /*ARGSUSED*/ 8945240Snordmark static void 8955240Snordmark rts_rsrv(queue_t *q) 8965240Snordmark { 8975240Snordmark } 8985240Snordmark 8995240Snordmark /* 9000Sstevel@tonic-gate * This routine handles synchronous messages passed downstream. It either 9010Sstevel@tonic-gate * consumes the message or passes it downstream; it never queues a 9020Sstevel@tonic-gate * a message. The data messages that go down are wrapped in an IOCTL 9030Sstevel@tonic-gate * message. 9040Sstevel@tonic-gate * 9050Sstevel@tonic-gate * Since it is synchronous, it waits for the M_IOCACK/M_IOCNAK so that 9060Sstevel@tonic-gate * it can return an immediate error (such as ENETUNREACH when adding a route). 9070Sstevel@tonic-gate * It uses the RTS_WRW_PENDING to ensure that each rts instance has only 9080Sstevel@tonic-gate * one M_IOCTL outstanding at any given time. 9090Sstevel@tonic-gate */ 9100Sstevel@tonic-gate static int 9110Sstevel@tonic-gate rts_wrw(queue_t *q, struiod_t *dp) 9120Sstevel@tonic-gate { 9130Sstevel@tonic-gate mblk_t *mp = dp->d_mp; 9140Sstevel@tonic-gate mblk_t *mp1; 9150Sstevel@tonic-gate int error; 9160Sstevel@tonic-gate rt_msghdr_t *rtm; 9175240Snordmark conn_t *connp = Q_TO_CONN(q); 9185240Snordmark rts_t *rts = connp->conn_rts; 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate while (rts->rts_flag & RTS_WRW_PENDING) { 9210Sstevel@tonic-gate if (qwait_rw(q)) { 9220Sstevel@tonic-gate rts->rts_error = EINTR; 9230Sstevel@tonic-gate goto err_ret; 9240Sstevel@tonic-gate } 9258348SEric.Yu@Sun.COM } 9260Sstevel@tonic-gate rts->rts_flag |= RTS_WRW_PENDING; 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate if (isuioq(q) && (error = struioget(q, mp, dp, 0))) { 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * Uio error of some sort, so just return the error. 9310Sstevel@tonic-gate */ 9320Sstevel@tonic-gate rts->rts_error = error; 9330Sstevel@tonic-gate goto err_ret; 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate /* 9360Sstevel@tonic-gate * Pass the mblk (chain) onto wput(). 9370Sstevel@tonic-gate */ 9380Sstevel@tonic-gate dp->d_mp = 0; 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 /* Expedite other than T_DATA_REQ to below the switch */ 9440Sstevel@tonic-gate if (((mp->b_wptr - mp->b_rptr) != 9450Sstevel@tonic-gate sizeof (struct T_data_req)) || 9460Sstevel@tonic-gate (((union T_primitives *)mp->b_rptr)->type != T_DATA_REQ)) 9470Sstevel@tonic-gate break; 9480Sstevel@tonic-gate if ((mp1 = mp->b_cont) == NULL) { 9490Sstevel@tonic-gate rts->rts_error = EINVAL; 9500Sstevel@tonic-gate goto err_ret; 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate freeb(mp); 9530Sstevel@tonic-gate mp = mp1; 9540Sstevel@tonic-gate /* FALLTHRU */ 9550Sstevel@tonic-gate case M_DATA: 9560Sstevel@tonic-gate /* 9570Sstevel@tonic-gate * The semantics of the routing socket is such that the rtm_pid 9580Sstevel@tonic-gate * field is automatically filled in during requests with the 9590Sstevel@tonic-gate * current process' pid. We do this here (where we still have 9600Sstevel@tonic-gate * user context) after checking we have at least a message the 9610Sstevel@tonic-gate * size of a routing message header. 9620Sstevel@tonic-gate */ 9630Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 9640Sstevel@tonic-gate if (!pullupmsg(mp, sizeof (rt_msghdr_t))) { 9650Sstevel@tonic-gate rts->rts_error = EINVAL; 9660Sstevel@tonic-gate goto err_ret; 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 9700Sstevel@tonic-gate rtm->rtm_pid = curproc->p_pid; 9710Sstevel@tonic-gate break; 9720Sstevel@tonic-gate default: 9730Sstevel@tonic-gate break; 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate rts->rts_flag |= RTS_WPUT_PENDING; 9760Sstevel@tonic-gate rts_wput(q, mp); 9770Sstevel@tonic-gate while (rts->rts_flag & RTS_WPUT_PENDING) 9780Sstevel@tonic-gate if (qwait_rw(q)) { 9790Sstevel@tonic-gate /* RTS_WPUT_PENDING will be cleared below */ 9800Sstevel@tonic-gate rts->rts_error = EINTR; 9810Sstevel@tonic-gate break; 9820Sstevel@tonic-gate } 9830Sstevel@tonic-gate err_ret: 9840Sstevel@tonic-gate rts->rts_flag &= ~(RTS_WPUT_PENDING | RTS_WRW_PENDING); 9850Sstevel@tonic-gate return (rts->rts_error); 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate /* 9890Sstevel@tonic-gate * This routine handles all messages passed downstream. It either 9900Sstevel@tonic-gate * consumes the message or passes it downstream; it never queues a 9910Sstevel@tonic-gate * a message. The data messages that go down are wrapped in an IOCTL 9920Sstevel@tonic-gate * message. 9935240Snordmark * 9945240Snordmark * FIXME? Should we call IP rts_request directly? Could punt on returning 9955240Snordmark * errno in the case when it defers processing due to 9965240Snordmark * IPIF_CHANGING/ILL_CHANGING??? 9970Sstevel@tonic-gate */ 9980Sstevel@tonic-gate static void 9990Sstevel@tonic-gate rts_wput(queue_t *q, mblk_t *mp) 10000Sstevel@tonic-gate { 10010Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 10020Sstevel@tonic-gate mblk_t *mp1; 10035240Snordmark conn_t *connp = Q_TO_CONN(q); 10045240Snordmark rts_t *rts = connp->conn_rts; 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate switch (mp->b_datap->db_type) { 10070Sstevel@tonic-gate case M_DATA: 10080Sstevel@tonic-gate break; 10090Sstevel@tonic-gate case M_PROTO: 10100Sstevel@tonic-gate case M_PCPROTO: 10110Sstevel@tonic-gate if ((mp->b_wptr - rptr) == sizeof (struct T_data_req)) { 10120Sstevel@tonic-gate /* Expedite valid T_DATA_REQ to below the switch */ 10130Sstevel@tonic-gate if (((union T_primitives *)rptr)->type == T_DATA_REQ) { 10140Sstevel@tonic-gate mp1 = mp->b_cont; 10150Sstevel@tonic-gate freeb(mp); 10160Sstevel@tonic-gate if (mp1 == NULL) 10170Sstevel@tonic-gate return; 10180Sstevel@tonic-gate mp = mp1; 10190Sstevel@tonic-gate break; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate /* FALLTHRU */ 10230Sstevel@tonic-gate default: 10240Sstevel@tonic-gate rts_wput_other(q, mp); 10250Sstevel@tonic-gate return; 10260Sstevel@tonic-gate } 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate mp1 = rts_ioctl_alloc(mp, DB_CRED(mp)); 10300Sstevel@tonic-gate if (mp1 == NULL) { 10310Sstevel@tonic-gate ASSERT(rts != NULL); 10320Sstevel@tonic-gate freemsg(mp); 10330Sstevel@tonic-gate if (rts->rts_flag & RTS_WPUT_PENDING) { 10340Sstevel@tonic-gate rts->rts_error = ENOMEM; 10350Sstevel@tonic-gate rts->rts_flag &= ~RTS_WPUT_PENDING; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate return; 10380Sstevel@tonic-gate } 10395240Snordmark ip_output(connp, mp1, q, IP_WPUT); 10400Sstevel@tonic-gate } 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate /* 10440Sstevel@tonic-gate * Handles all the control message, if it 10450Sstevel@tonic-gate * can not understand it, it will 10460Sstevel@tonic-gate * pass down stream. 10470Sstevel@tonic-gate */ 10480Sstevel@tonic-gate static void 10490Sstevel@tonic-gate rts_wput_other(queue_t *q, mblk_t *mp) 10500Sstevel@tonic-gate { 10515240Snordmark conn_t *connp = Q_TO_CONN(q); 10525240Snordmark rts_t *rts = connp->conn_rts; 10530Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 10540Sstevel@tonic-gate struct iocblk *iocp; 10550Sstevel@tonic-gate cred_t *cr; 10563448Sdh155122 rts_stack_t *rtss; 10570Sstevel@tonic-gate 10583448Sdh155122 rtss = rts->rts_rtss; 10590Sstevel@tonic-gate 10605240Snordmark cr = DB_CREDDEF(mp, connp->conn_cred); 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate switch (mp->b_datap->db_type) { 10630Sstevel@tonic-gate case M_PROTO: 10640Sstevel@tonic-gate case M_PCPROTO: 10650Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (t_scalar_t)) { 10660Sstevel@tonic-gate /* 10670Sstevel@tonic-gate * If the message does not contain a PRIM_type, 10680Sstevel@tonic-gate * throw it away. 10690Sstevel@tonic-gate */ 10700Sstevel@tonic-gate freemsg(mp); 10710Sstevel@tonic-gate return; 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) { 10740Sstevel@tonic-gate case T_BIND_REQ: 10750Sstevel@tonic-gate case O_T_BIND_REQ: 10768348SEric.Yu@Sun.COM rts_tpi_bind(q, mp); 10770Sstevel@tonic-gate return; 10780Sstevel@tonic-gate case T_UNBIND_REQ: 10798348SEric.Yu@Sun.COM rts_tpi_unbind(q, mp); 10800Sstevel@tonic-gate return; 10810Sstevel@tonic-gate case T_CAPABILITY_REQ: 10820Sstevel@tonic-gate rts_capability_req(q, mp); 10830Sstevel@tonic-gate return; 10840Sstevel@tonic-gate case T_INFO_REQ: 10850Sstevel@tonic-gate rts_info_req(q, mp); 10860Sstevel@tonic-gate return; 10870Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 10885240Snordmark (void) svr4_optcom_req(q, mp, cr, &rts_opt_obj, 10895277Snordmark B_TRUE); 10900Sstevel@tonic-gate return; 10910Sstevel@tonic-gate case T_OPTMGMT_REQ: 10925277Snordmark (void) tpi_optcom_req(q, mp, cr, &rts_opt_obj, B_TRUE); 10930Sstevel@tonic-gate return; 10940Sstevel@tonic-gate case O_T_CONN_RES: 10950Sstevel@tonic-gate case T_CONN_RES: 10960Sstevel@tonic-gate case T_DISCON_REQ: 10970Sstevel@tonic-gate /* Not supported by rts. */ 10980Sstevel@tonic-gate rts_err_ack(q, mp, TNOTSUPPORT, 0); 10990Sstevel@tonic-gate return; 11000Sstevel@tonic-gate case T_DATA_REQ: 11010Sstevel@tonic-gate case T_EXDATA_REQ: 11020Sstevel@tonic-gate case T_ORDREL_REQ: 11030Sstevel@tonic-gate /* Illegal for rts. */ 11040Sstevel@tonic-gate freemsg(mp); 11050Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO); 11060Sstevel@tonic-gate return; 11078348SEric.Yu@Sun.COM 11080Sstevel@tonic-gate default: 11090Sstevel@tonic-gate break; 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate break; 11120Sstevel@tonic-gate case M_IOCTL: 11130Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 11140Sstevel@tonic-gate switch (iocp->ioc_cmd) { 11150Sstevel@tonic-gate case ND_SET: 11160Sstevel@tonic-gate case ND_GET: 11173448Sdh155122 if (nd_getset(q, rtss->rtss_g_nd, mp)) { 11180Sstevel@tonic-gate qreply(q, mp); 11190Sstevel@tonic-gate return; 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate break; 11220Sstevel@tonic-gate case TI_GETPEERNAME: 11230Sstevel@tonic-gate mi_copyin(q, mp, NULL, 11240Sstevel@tonic-gate SIZEOF_STRUCT(strbuf, iocp->ioc_flag)); 11250Sstevel@tonic-gate return; 11260Sstevel@tonic-gate default: 11270Sstevel@tonic-gate break; 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate case M_IOCDATA: 11300Sstevel@tonic-gate rts_wput_iocdata(q, mp); 11310Sstevel@tonic-gate return; 11320Sstevel@tonic-gate default: 11330Sstevel@tonic-gate break; 11340Sstevel@tonic-gate } 11355240Snordmark ip_output(connp, mp, q, IP_WPUT); 11360Sstevel@tonic-gate } 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate /* 11390Sstevel@tonic-gate * Called by rts_wput_other to handle all M_IOCDATA messages. 11400Sstevel@tonic-gate */ 11410Sstevel@tonic-gate static void 11420Sstevel@tonic-gate rts_wput_iocdata(queue_t *q, mblk_t *mp) 11430Sstevel@tonic-gate { 11445240Snordmark conn_t *connp = Q_TO_CONN(q); 11450Sstevel@tonic-gate struct sockaddr *rtsaddr; 11460Sstevel@tonic-gate mblk_t *mp1; 11470Sstevel@tonic-gate STRUCT_HANDLE(strbuf, sb); 11480Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate /* Make sure it is one of ours. */ 11510Sstevel@tonic-gate switch (iocp->ioc_cmd) { 11520Sstevel@tonic-gate case TI_GETPEERNAME: 11530Sstevel@tonic-gate break; 11540Sstevel@tonic-gate default: 11555240Snordmark ip_output(connp, mp, q, IP_WPUT); 11560Sstevel@tonic-gate return; 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate switch (mi_copy_state(q, mp, &mp1)) { 11590Sstevel@tonic-gate case -1: 11600Sstevel@tonic-gate return; 11610Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_IN, 1): 11620Sstevel@tonic-gate break; 11630Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 1): 11640Sstevel@tonic-gate /* Copy out the strbuf. */ 11650Sstevel@tonic-gate mi_copyout(q, mp); 11660Sstevel@tonic-gate return; 11670Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 2): 11680Sstevel@tonic-gate /* All done. */ 11690Sstevel@tonic-gate mi_copy_done(q, mp, 0); 11700Sstevel@tonic-gate return; 11710Sstevel@tonic-gate default: 11720Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 11730Sstevel@tonic-gate return; 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate STRUCT_SET_HANDLE(sb, iocp->ioc_flag, (void *)mp1->b_rptr); 11760Sstevel@tonic-gate if (STRUCT_FGET(sb, maxlen) < (int)sizeof (sin_t)) { 11770Sstevel@tonic-gate mi_copy_done(q, mp, EINVAL); 11780Sstevel@tonic-gate return; 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate switch (iocp->ioc_cmd) { 11810Sstevel@tonic-gate case TI_GETPEERNAME: 11820Sstevel@tonic-gate break; 11830Sstevel@tonic-gate default: 11840Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 11850Sstevel@tonic-gate return; 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), sizeof (sin_t), 11880Sstevel@tonic-gate B_TRUE); 11890Sstevel@tonic-gate if (mp1 == NULL) 11900Sstevel@tonic-gate return; 11910Sstevel@tonic-gate STRUCT_FSET(sb, len, (int)sizeof (sin_t)); 11920Sstevel@tonic-gate rtsaddr = (struct sockaddr *)mp1->b_rptr; 11930Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)&rtsaddr[1]; 11940Sstevel@tonic-gate bzero(rtsaddr, sizeof (struct sockaddr)); 11950Sstevel@tonic-gate rtsaddr->sa_family = AF_ROUTE; 11960Sstevel@tonic-gate /* Copy out the address */ 11970Sstevel@tonic-gate mi_copyout(q, mp); 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12005240Snordmark /*ARGSUSED2*/ 12010Sstevel@tonic-gate static void 12025240Snordmark rts_input(void *arg1, mblk_t *mp, void *arg2) 12030Sstevel@tonic-gate { 12045240Snordmark conn_t *connp = (conn_t *)arg1; 12055240Snordmark rts_t *rts = connp->conn_rts; 12060Sstevel@tonic-gate struct iocblk *iocp; 12070Sstevel@tonic-gate mblk_t *mp1; 12080Sstevel@tonic-gate struct T_data_ind *tdi; 12098348SEric.Yu@Sun.COM int error; 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate switch (mp->b_datap->db_type) { 12120Sstevel@tonic-gate case M_IOCACK: 12130Sstevel@tonic-gate case M_IOCNAK: 12140Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 12158348SEric.Yu@Sun.COM if (IPCL_IS_NONSTR(connp)) { 12168348SEric.Yu@Sun.COM ASSERT(rts->rts_flag & (RTS_REQ_PENDING)); 12178348SEric.Yu@Sun.COM mutex_enter(&rts->rts_send_mutex); 12188348SEric.Yu@Sun.COM rts->rts_flag &= ~RTS_REQ_INPROG; 12190Sstevel@tonic-gate rts->rts_error = iocp->ioc_error; 12208348SEric.Yu@Sun.COM cv_signal(&rts->rts_io_cv); 12218348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 12220Sstevel@tonic-gate freemsg(mp); 12230Sstevel@tonic-gate return; 12248348SEric.Yu@Sun.COM } else { 12258348SEric.Yu@Sun.COM if (rts->rts_flag & (RTS_WPUT_PENDING)) { 12268348SEric.Yu@Sun.COM rts->rts_flag &= ~RTS_WPUT_PENDING; 12278348SEric.Yu@Sun.COM rts->rts_error = iocp->ioc_error; 12288348SEric.Yu@Sun.COM /* 12298348SEric.Yu@Sun.COM * Tell rts_wvw/qwait that we are done. 12308348SEric.Yu@Sun.COM * Note: there is no qwait_wakeup() we can use. 12318348SEric.Yu@Sun.COM */ 12328348SEric.Yu@Sun.COM qenable(connp->conn_rq); 12338348SEric.Yu@Sun.COM freemsg(mp); 12348348SEric.Yu@Sun.COM return; 12358348SEric.Yu@Sun.COM } 12360Sstevel@tonic-gate } 12370Sstevel@tonic-gate break; 12380Sstevel@tonic-gate case M_DATA: 12390Sstevel@tonic-gate /* 12400Sstevel@tonic-gate * Prepend T_DATA_IND to prevent the stream head from 12410Sstevel@tonic-gate * consolidating multiple messages together. 12420Sstevel@tonic-gate * If the allocation fails just send up the M_DATA. 12430Sstevel@tonic-gate */ 12440Sstevel@tonic-gate mp1 = allocb(sizeof (*tdi), BPRI_MED); 12450Sstevel@tonic-gate if (mp1 != NULL) { 12460Sstevel@tonic-gate mp1->b_cont = mp; 12470Sstevel@tonic-gate mp = mp1; 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 12500Sstevel@tonic-gate mp->b_wptr += sizeof (*tdi); 12510Sstevel@tonic-gate tdi = (struct T_data_ind *)mp->b_rptr; 12520Sstevel@tonic-gate tdi->PRIM_type = T_DATA_IND; 12530Sstevel@tonic-gate tdi->MORE_flag = 0; 12540Sstevel@tonic-gate } 12550Sstevel@tonic-gate break; 12560Sstevel@tonic-gate default: 12570Sstevel@tonic-gate break; 12580Sstevel@tonic-gate } 12598348SEric.Yu@Sun.COM 12608348SEric.Yu@Sun.COM if (IPCL_IS_NONSTR(connp)) { 12618348SEric.Yu@Sun.COM if ((*connp->conn_upcalls->su_recv) 12628348SEric.Yu@Sun.COM (connp->conn_upper_handle, mp, msgdsize(mp), 0, 12638348SEric.Yu@Sun.COM &error, NULL) < 0) { 12648348SEric.Yu@Sun.COM ASSERT(error == ENOSPC); 12658348SEric.Yu@Sun.COM /* 12668348SEric.Yu@Sun.COM * Let's confirm hoding the lock that 12678348SEric.Yu@Sun.COM * we are out of recv space. 12688348SEric.Yu@Sun.COM */ 12698348SEric.Yu@Sun.COM mutex_enter(&rts->rts_recv_mutex); 12708348SEric.Yu@Sun.COM if ((*connp->conn_upcalls->su_recv) 12718348SEric.Yu@Sun.COM (connp->conn_upper_handle, NULL, 0, 0, 12728348SEric.Yu@Sun.COM &error, NULL) < 0) { 12738348SEric.Yu@Sun.COM ASSERT(error == ENOSPC); 12748348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_TRUE; 12758348SEric.Yu@Sun.COM } 12768348SEric.Yu@Sun.COM mutex_exit(&rts->rts_recv_mutex); 12778348SEric.Yu@Sun.COM } 12788348SEric.Yu@Sun.COM } else { 12798348SEric.Yu@Sun.COM putnext(connp->conn_rq, mp); 12808348SEric.Yu@Sun.COM } 12810Sstevel@tonic-gate } 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate void 12858348SEric.Yu@Sun.COM rts_ddi_g_init(void) 12860Sstevel@tonic-gate { 12870Sstevel@tonic-gate rts_max_optsize = optcom_max_optsize(rts_opt_obj.odb_opt_des_arr, 12880Sstevel@tonic-gate rts_opt_obj.odb_opt_arr_cnt); 12893448Sdh155122 12903448Sdh155122 /* 12913448Sdh155122 * We want to be informed each time a stack is created or 12923448Sdh155122 * destroyed in the kernel, so we can maintain the 12933448Sdh155122 * set of rts_stack_t's. 12943448Sdh155122 */ 12953448Sdh155122 netstack_register(NS_RTS, rts_stack_init, NULL, rts_stack_fini); 12960Sstevel@tonic-gate } 12973448Sdh155122 12983448Sdh155122 void 12998348SEric.Yu@Sun.COM rts_ddi_g_destroy(void) 13003448Sdh155122 { 13013448Sdh155122 netstack_unregister(NS_RTS); 13023448Sdh155122 } 13033448Sdh155122 13048348SEric.Yu@Sun.COM #define INET_NAME "ip" 13058348SEric.Yu@Sun.COM 13063448Sdh155122 /* 13073448Sdh155122 * Initialize the RTS stack instance. 13083448Sdh155122 */ 13093448Sdh155122 /* ARGSUSED */ 13103448Sdh155122 static void * 13113448Sdh155122 rts_stack_init(netstackid_t stackid, netstack_t *ns) 13123448Sdh155122 { 13133448Sdh155122 rts_stack_t *rtss; 13143448Sdh155122 rtsparam_t *pa; 13158348SEric.Yu@Sun.COM int error = 0; 13168348SEric.Yu@Sun.COM major_t major; 13173448Sdh155122 13183448Sdh155122 rtss = (rts_stack_t *)kmem_zalloc(sizeof (*rtss), KM_SLEEP); 13193448Sdh155122 rtss->rtss_netstack = ns; 13203448Sdh155122 13213448Sdh155122 pa = (rtsparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP); 13223448Sdh155122 rtss->rtss_params = pa; 13233448Sdh155122 bcopy(lcl_param_arr, rtss->rtss_params, sizeof (lcl_param_arr)); 13243448Sdh155122 13253448Sdh155122 (void) rts_param_register(&rtss->rtss_g_nd, 13263448Sdh155122 rtss->rtss_params, A_CNT(lcl_param_arr)); 13278348SEric.Yu@Sun.COM 13288348SEric.Yu@Sun.COM major = mod_name_to_major(INET_NAME); 13298348SEric.Yu@Sun.COM error = ldi_ident_from_major(major, &rtss->rtss_ldi_ident); 13308348SEric.Yu@Sun.COM ASSERT(error == 0); 13313448Sdh155122 return (rtss); 13323448Sdh155122 } 13333448Sdh155122 13343448Sdh155122 /* 13353448Sdh155122 * Free the RTS stack instance. 13363448Sdh155122 */ 13373448Sdh155122 /* ARGSUSED */ 13383448Sdh155122 static void 13393448Sdh155122 rts_stack_fini(netstackid_t stackid, void *arg) 13403448Sdh155122 { 13413448Sdh155122 rts_stack_t *rtss = (rts_stack_t *)arg; 13423448Sdh155122 13435240Snordmark nd_free(&rtss->rtss_g_nd); 13443448Sdh155122 kmem_free(rtss->rtss_params, sizeof (lcl_param_arr)); 13453448Sdh155122 rtss->rtss_params = NULL; 13468348SEric.Yu@Sun.COM ldi_ident_release(rtss->rtss_ldi_ident); 13473448Sdh155122 kmem_free(rtss, sizeof (*rtss)); 13483448Sdh155122 } 13498348SEric.Yu@Sun.COM 13508348SEric.Yu@Sun.COM /* ARGSUSED */ 13518348SEric.Yu@Sun.COM int 13528348SEric.Yu@Sun.COM rts_accept(sock_lower_handle_t lproto_handle, 13538348SEric.Yu@Sun.COM sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle, 13548348SEric.Yu@Sun.COM cred_t *cr) 13558348SEric.Yu@Sun.COM { 13568348SEric.Yu@Sun.COM return (EINVAL); 13578348SEric.Yu@Sun.COM } 13588348SEric.Yu@Sun.COM 13598348SEric.Yu@Sun.COM /* ARGSUSED */ 13608348SEric.Yu@Sun.COM static int 13618348SEric.Yu@Sun.COM rts_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 13628348SEric.Yu@Sun.COM socklen_t len, cred_t *cr) 13638348SEric.Yu@Sun.COM { 13648348SEric.Yu@Sun.COM /* 13658348SEric.Yu@Sun.COM * rebind not allowed 13668348SEric.Yu@Sun.COM */ 13678348SEric.Yu@Sun.COM return (EINVAL); 13688348SEric.Yu@Sun.COM } 13698348SEric.Yu@Sun.COM 13708348SEric.Yu@Sun.COM /* ARGSUSED */ 13718348SEric.Yu@Sun.COM int 13728348SEric.Yu@Sun.COM rts_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr) 13738348SEric.Yu@Sun.COM { 13748348SEric.Yu@Sun.COM return (EINVAL); 13758348SEric.Yu@Sun.COM } 13768348SEric.Yu@Sun.COM 13778348SEric.Yu@Sun.COM /* ARGSUSED */ 13788348SEric.Yu@Sun.COM int 13798348SEric.Yu@Sun.COM rts_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa, 13808348SEric.Yu@Sun.COM socklen_t len, sock_connid_t *id, cred_t *cr) 13818348SEric.Yu@Sun.COM { 13828348SEric.Yu@Sun.COM /* 13838348SEric.Yu@Sun.COM * rts sockets start out as bound and connected 13848348SEric.Yu@Sun.COM */ 13858348SEric.Yu@Sun.COM *id = 0; 13868348SEric.Yu@Sun.COM return (EISCONN); 13878348SEric.Yu@Sun.COM } 13888348SEric.Yu@Sun.COM 13898348SEric.Yu@Sun.COM /* ARGSUSED */ 13908348SEric.Yu@Sun.COM int 13918348SEric.Yu@Sun.COM rts_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr, 13928348SEric.Yu@Sun.COM socklen_t *addrlen, cred_t *cr) 13938348SEric.Yu@Sun.COM { 13948348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 13958348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 13968348SEric.Yu@Sun.COM 13978348SEric.Yu@Sun.COM ASSERT(rts != NULL); 13988348SEric.Yu@Sun.COM 13998348SEric.Yu@Sun.COM bzero(addr, sizeof (struct sockaddr)); 14008348SEric.Yu@Sun.COM addr->sa_family = AF_ROUTE; 14018348SEric.Yu@Sun.COM *addrlen = sizeof (struct sockaddr); 14028348SEric.Yu@Sun.COM 14038348SEric.Yu@Sun.COM return (0); 14048348SEric.Yu@Sun.COM } 14058348SEric.Yu@Sun.COM 14068348SEric.Yu@Sun.COM /* ARGSUSED */ 14078348SEric.Yu@Sun.COM int 14088348SEric.Yu@Sun.COM rts_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr, 14098348SEric.Yu@Sun.COM socklen_t *addrlen, cred_t *cr) 14108348SEric.Yu@Sun.COM { 14118348SEric.Yu@Sun.COM return (EOPNOTSUPP); 14128348SEric.Yu@Sun.COM } 14138348SEric.Yu@Sun.COM 14148348SEric.Yu@Sun.COM static int 14158348SEric.Yu@Sun.COM rts_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 14168348SEric.Yu@Sun.COM void *optvalp, socklen_t *optlen, cred_t *cr) 14178348SEric.Yu@Sun.COM { 14188348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14198348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 14208348SEric.Yu@Sun.COM int error; 14218348SEric.Yu@Sun.COM t_uscalar_t max_optbuf_len; 14228348SEric.Yu@Sun.COM void *optvalp_buf; 14238348SEric.Yu@Sun.COM int len; 14248348SEric.Yu@Sun.COM 14258348SEric.Yu@Sun.COM error = proto_opt_check(level, option_name, *optlen, &max_optbuf_len, 14268348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_des_arr, 14278348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_arr_cnt, 14288348SEric.Yu@Sun.COM rts_opt_obj.odb_topmost_tpiprovider, 14298348SEric.Yu@Sun.COM B_FALSE, B_TRUE, cr); 14308348SEric.Yu@Sun.COM if (error != 0) { 14318348SEric.Yu@Sun.COM if (error < 0) 14328348SEric.Yu@Sun.COM error = proto_tlitosyserr(-error); 14338348SEric.Yu@Sun.COM return (error); 14348348SEric.Yu@Sun.COM } 14358348SEric.Yu@Sun.COM 14368348SEric.Yu@Sun.COM optvalp_buf = kmem_alloc(max_optbuf_len, KM_SLEEP); 14378348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_READER); 14388348SEric.Yu@Sun.COM len = rts_opt_get(connp, level, option_name, optvalp_buf); 14398348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 14408348SEric.Yu@Sun.COM 14418348SEric.Yu@Sun.COM if (len < 0) { 14428348SEric.Yu@Sun.COM /* 14438348SEric.Yu@Sun.COM * Pass on to IP 14448348SEric.Yu@Sun.COM */ 14458348SEric.Yu@Sun.COM error = ip_get_options(connp, level, option_name, 14468348SEric.Yu@Sun.COM optvalp, optlen, cr); 14478348SEric.Yu@Sun.COM } else { 14488348SEric.Yu@Sun.COM /* 14498348SEric.Yu@Sun.COM * update optlen and copy option value 14508348SEric.Yu@Sun.COM */ 14518348SEric.Yu@Sun.COM t_uscalar_t size = MIN(len, *optlen); 14528348SEric.Yu@Sun.COM bcopy(optvalp_buf, optvalp, size); 14538348SEric.Yu@Sun.COM bcopy(&size, optlen, sizeof (size)); 14548348SEric.Yu@Sun.COM error = 0; 14558348SEric.Yu@Sun.COM } 14568348SEric.Yu@Sun.COM 14578348SEric.Yu@Sun.COM kmem_free(optvalp_buf, max_optbuf_len); 14588348SEric.Yu@Sun.COM return (error); 14598348SEric.Yu@Sun.COM } 14608348SEric.Yu@Sun.COM 14618348SEric.Yu@Sun.COM static int 14628348SEric.Yu@Sun.COM rts_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 14638348SEric.Yu@Sun.COM const void *optvalp, socklen_t optlen, cred_t *cr) 14648348SEric.Yu@Sun.COM { 14658348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14668348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 14678348SEric.Yu@Sun.COM int error; 14688348SEric.Yu@Sun.COM 14698348SEric.Yu@Sun.COM error = proto_opt_check(level, option_name, optlen, NULL, 14708348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_des_arr, 14718348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_arr_cnt, 14728348SEric.Yu@Sun.COM rts_opt_obj.odb_topmost_tpiprovider, 14738348SEric.Yu@Sun.COM B_TRUE, B_FALSE, cr); 14748348SEric.Yu@Sun.COM 14758348SEric.Yu@Sun.COM if (error != 0) { 14768348SEric.Yu@Sun.COM if (error < 0) 14778348SEric.Yu@Sun.COM error = proto_tlitosyserr(-error); 14788348SEric.Yu@Sun.COM return (error); 14798348SEric.Yu@Sun.COM } 14808348SEric.Yu@Sun.COM 14818348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 14828348SEric.Yu@Sun.COM error = rts_opt_set(connp, SETFN_OPTCOM_NEGOTIATE, level, option_name, 14838348SEric.Yu@Sun.COM optlen, (uchar_t *)optvalp, (uint_t *)&optlen, (uchar_t *)optvalp, 14848348SEric.Yu@Sun.COM NULL, cr); 14858348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 14868348SEric.Yu@Sun.COM 14878348SEric.Yu@Sun.COM ASSERT(error >= 0); 14888348SEric.Yu@Sun.COM 14898348SEric.Yu@Sun.COM return (error); 14908348SEric.Yu@Sun.COM } 14918348SEric.Yu@Sun.COM 14928348SEric.Yu@Sun.COM /* ARGSUSED */ 14938348SEric.Yu@Sun.COM static int 14948348SEric.Yu@Sun.COM rts_send(sock_lower_handle_t proto_handle, mblk_t *mp, 14958348SEric.Yu@Sun.COM struct nmsghdr *msg, cred_t *cr) 14968348SEric.Yu@Sun.COM { 14978348SEric.Yu@Sun.COM mblk_t *mp1; 14988348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14998348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 15008348SEric.Yu@Sun.COM rt_msghdr_t *rtm; 15018348SEric.Yu@Sun.COM int error; 15028348SEric.Yu@Sun.COM 15038348SEric.Yu@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA); 15048348SEric.Yu@Sun.COM /* 15058348SEric.Yu@Sun.COM * The semantics of the routing socket is such that the rtm_pid 15068348SEric.Yu@Sun.COM * field is automatically filled in during requests with the 15078348SEric.Yu@Sun.COM * current process' pid. We do this here (where we still have 15088348SEric.Yu@Sun.COM * user context) after checking we have at least a message the 15098348SEric.Yu@Sun.COM * size of a routing message header. 15108348SEric.Yu@Sun.COM */ 15118348SEric.Yu@Sun.COM if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 15128348SEric.Yu@Sun.COM if (!pullupmsg(mp, sizeof (rt_msghdr_t))) { 15138348SEric.Yu@Sun.COM rts->rts_error = EINVAL; 15148348SEric.Yu@Sun.COM freemsg(mp); 15158348SEric.Yu@Sun.COM return (rts->rts_error); 15168348SEric.Yu@Sun.COM } 15178348SEric.Yu@Sun.COM } 15188348SEric.Yu@Sun.COM rtm = (rt_msghdr_t *)mp->b_rptr; 15198348SEric.Yu@Sun.COM rtm->rtm_pid = curproc->p_pid; 15208348SEric.Yu@Sun.COM 15218348SEric.Yu@Sun.COM mp1 = rts_ioctl_alloc(mp, DB_CRED(mp)); 15228348SEric.Yu@Sun.COM if (mp1 == NULL) { 15238348SEric.Yu@Sun.COM ASSERT(rts != NULL); 15248348SEric.Yu@Sun.COM freemsg(mp); 15258348SEric.Yu@Sun.COM return (ENOMEM); 15268348SEric.Yu@Sun.COM } 15278348SEric.Yu@Sun.COM 15288348SEric.Yu@Sun.COM /* 15298348SEric.Yu@Sun.COM * Allow only one outstanding request(ioctl) at any given time 15308348SEric.Yu@Sun.COM */ 15318348SEric.Yu@Sun.COM mutex_enter(&rts->rts_send_mutex); 15328348SEric.Yu@Sun.COM while (rts->rts_flag & RTS_REQ_PENDING) { 15338348SEric.Yu@Sun.COM int ret; 15348348SEric.Yu@Sun.COM 15358348SEric.Yu@Sun.COM ret = cv_wait_sig(&rts->rts_send_cv, &rts->rts_send_mutex); 15368348SEric.Yu@Sun.COM if (ret <= 0) { 15378348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 15388348SEric.Yu@Sun.COM freemsg(mp); 15398348SEric.Yu@Sun.COM return (EINTR); 15408348SEric.Yu@Sun.COM } 15418348SEric.Yu@Sun.COM } 15428348SEric.Yu@Sun.COM 15438348SEric.Yu@Sun.COM rts->rts_flag |= RTS_REQ_PENDING; 15448348SEric.Yu@Sun.COM 15458348SEric.Yu@Sun.COM rts->rts_flag |= RTS_REQ_INPROG; 15468348SEric.Yu@Sun.COM 15478348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 15488348SEric.Yu@Sun.COM 15498348SEric.Yu@Sun.COM CONN_INC_REF(connp); 15508348SEric.Yu@Sun.COM 15518348SEric.Yu@Sun.COM error = ip_rts_request_common(rts->rts_connp->conn_wq, mp1, connp, 15528348SEric.Yu@Sun.COM DB_CREDDEF(mp, connp->conn_cred)); 15538348SEric.Yu@Sun.COM 15548348SEric.Yu@Sun.COM mutex_enter(&rts->rts_send_mutex); 15558348SEric.Yu@Sun.COM if (error == EINPROGRESS) { 15568348SEric.Yu@Sun.COM ASSERT(rts->rts_flag & RTS_REQ_INPROG); 15578348SEric.Yu@Sun.COM if (rts->rts_flag & RTS_REQ_INPROG) { 15588348SEric.Yu@Sun.COM /* 15598348SEric.Yu@Sun.COM * Once the request has been issued we wait for 15608348SEric.Yu@Sun.COM * completion 15618348SEric.Yu@Sun.COM */ 15628348SEric.Yu@Sun.COM cv_wait(&rts->rts_io_cv, &rts->rts_send_mutex); 15638348SEric.Yu@Sun.COM error = rts->rts_error; 15648348SEric.Yu@Sun.COM } 15658348SEric.Yu@Sun.COM } 15668348SEric.Yu@Sun.COM 15678348SEric.Yu@Sun.COM ASSERT((error != 0) || !(rts->rts_flag & RTS_REQ_INPROG)); 15688348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(&rts->rts_send_mutex)); 15698348SEric.Yu@Sun.COM 15708348SEric.Yu@Sun.COM rts->rts_flag &= ~(RTS_REQ_PENDING | RTS_REQ_INPROG); 15718348SEric.Yu@Sun.COM cv_signal(&rts->rts_send_cv); 15728348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 15738348SEric.Yu@Sun.COM return (error); 15748348SEric.Yu@Sun.COM } 15758348SEric.Yu@Sun.COM 15768348SEric.Yu@Sun.COM /* ARGSUSED */ 15778348SEric.Yu@Sun.COM sock_lower_handle_t 15788348SEric.Yu@Sun.COM rts_create(int family, int type, int proto, sock_downcalls_t **sock_downcalls, 15798348SEric.Yu@Sun.COM uint_t *smodep, int *errorp, int flags, cred_t *credp) 15808348SEric.Yu@Sun.COM { 15818348SEric.Yu@Sun.COM conn_t *connp; 15828348SEric.Yu@Sun.COM rts_t *rts; 15838348SEric.Yu@Sun.COM rts_stack_t *rtss; 15848348SEric.Yu@Sun.COM 15858348SEric.Yu@Sun.COM if (family != AF_ROUTE || type != SOCK_RAW || 15868348SEric.Yu@Sun.COM (proto != 0 && proto != AF_INET && proto != AF_INET6)) { 15878348SEric.Yu@Sun.COM *errorp = EPROTONOSUPPORT; 15888348SEric.Yu@Sun.COM return (NULL); 15898348SEric.Yu@Sun.COM } 15908348SEric.Yu@Sun.COM 15918348SEric.Yu@Sun.COM connp = rts_open(flags, credp); 15928348SEric.Yu@Sun.COM ASSERT(connp != NULL); 15938348SEric.Yu@Sun.COM connp->conn_flags |= IPCL_NONSTR; 15948348SEric.Yu@Sun.COM 15958348SEric.Yu@Sun.COM rts = connp->conn_rts; 15968348SEric.Yu@Sun.COM rtss = rts->rts_rtss; 15978348SEric.Yu@Sun.COM 15988348SEric.Yu@Sun.COM rts->rts_xmit_hiwat = rtss->rtss_xmit_hiwat; 15998348SEric.Yu@Sun.COM rts->rts_xmit_lowat = rtss->rtss_xmit_lowat; 16008348SEric.Yu@Sun.COM rts->rts_recv_hiwat = rtss->rtss_recv_hiwat; 16018348SEric.Yu@Sun.COM rts->rts_recv_lowat = rts_mod_info.mi_lowat; 16028348SEric.Yu@Sun.COM 16038348SEric.Yu@Sun.COM ASSERT(rtss->rtss_ldi_ident != NULL); 16048348SEric.Yu@Sun.COM 16058348SEric.Yu@Sun.COM *errorp = ip_create_helper_stream(connp, rtss->rtss_ldi_ident); 16068348SEric.Yu@Sun.COM if (*errorp != 0) { 16078348SEric.Yu@Sun.COM #ifdef DEBUG 16088348SEric.Yu@Sun.COM cmn_err(CE_CONT, "rts_create: create of IP helper stream" 16098348SEric.Yu@Sun.COM " failed\n"); 16108348SEric.Yu@Sun.COM #endif 16118348SEric.Yu@Sun.COM (void) rts_close((sock_lower_handle_t)connp, 0, credp); 16128348SEric.Yu@Sun.COM return (NULL); 16138348SEric.Yu@Sun.COM } 16148348SEric.Yu@Sun.COM 16158348SEric.Yu@Sun.COM mutex_enter(&connp->conn_lock); 16168348SEric.Yu@Sun.COM connp->conn_state_flags &= ~CONN_INCIPIENT; 16178348SEric.Yu@Sun.COM mutex_exit(&connp->conn_lock); 16188348SEric.Yu@Sun.COM 16198348SEric.Yu@Sun.COM *errorp = 0; 16208348SEric.Yu@Sun.COM *smodep = SM_ATOMIC; 16218348SEric.Yu@Sun.COM *sock_downcalls = &sock_rts_downcalls; 16228348SEric.Yu@Sun.COM return ((sock_lower_handle_t)connp); 16238348SEric.Yu@Sun.COM } 16248348SEric.Yu@Sun.COM 16258348SEric.Yu@Sun.COM /* ARGSUSED */ 16268348SEric.Yu@Sun.COM void 16278348SEric.Yu@Sun.COM rts_activate(sock_lower_handle_t proto_handle, sock_upper_handle_t sock_handle, 16288348SEric.Yu@Sun.COM sock_upcalls_t *sock_upcalls, int flags, cred_t *cr) 16298348SEric.Yu@Sun.COM { 16308348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 16318348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 16328348SEric.Yu@Sun.COM rts_stack_t *rtss = rts->rts_rtss; 16338348SEric.Yu@Sun.COM struct sock_proto_props sopp; 16348348SEric.Yu@Sun.COM 16358348SEric.Yu@Sun.COM connp->conn_upcalls = sock_upcalls; 16368348SEric.Yu@Sun.COM connp->conn_upper_handle = sock_handle; 16378348SEric.Yu@Sun.COM 16388348SEric.Yu@Sun.COM sopp.sopp_flags = SOCKOPT_WROFF | SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | 16398348SEric.Yu@Sun.COM SOCKOPT_MAXBLK | SOCKOPT_MAXPSZ | SOCKOPT_MINPSZ; 16408348SEric.Yu@Sun.COM sopp.sopp_wroff = 0; 16418348SEric.Yu@Sun.COM sopp.sopp_rxhiwat = rtss->rtss_recv_hiwat; 16428348SEric.Yu@Sun.COM sopp.sopp_rxlowat = rts_mod_info.mi_lowat; 16438348SEric.Yu@Sun.COM sopp.sopp_maxblk = INFPSZ; 16448348SEric.Yu@Sun.COM sopp.sopp_maxpsz = rts_mod_info.mi_maxpsz; 16458348SEric.Yu@Sun.COM sopp.sopp_minpsz = (rts_mod_info.mi_minpsz == 1) ? 0 : 16468348SEric.Yu@Sun.COM rts_mod_info.mi_minpsz; 16478348SEric.Yu@Sun.COM 16488348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_set_proto_props) 16498348SEric.Yu@Sun.COM (connp->conn_upper_handle, &sopp); 16508348SEric.Yu@Sun.COM 16518348SEric.Yu@Sun.COM /* 16528348SEric.Yu@Sun.COM * We treat it as already connected for routing socket. 16538348SEric.Yu@Sun.COM */ 16548348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_connected) 16558348SEric.Yu@Sun.COM (connp->conn_upper_handle, 0, NULL, -1); 16568348SEric.Yu@Sun.COM 16578348SEric.Yu@Sun.COM /* 16588348SEric.Yu@Sun.COM * Indicate the down IP module that this is a routing socket 16598348SEric.Yu@Sun.COM * client by sending an RTS IOCTL without any user data. Although 16608348SEric.Yu@Sun.COM * this is just a notification message (without any real routing 16618348SEric.Yu@Sun.COM * request), we pass in any credential for correctness sake. 16628348SEric.Yu@Sun.COM */ 16638348SEric.Yu@Sun.COM ip_rts_register(connp); 16648348SEric.Yu@Sun.COM } 16658348SEric.Yu@Sun.COM 16668348SEric.Yu@Sun.COM /* ARGSUSED */ 16678348SEric.Yu@Sun.COM int 16688348SEric.Yu@Sun.COM rts_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr) 16698348SEric.Yu@Sun.COM { 16708348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 16718348SEric.Yu@Sun.COM 16728348SEric.Yu@Sun.COM ASSERT(connp != NULL && IPCL_IS_RTS(connp)); 16738348SEric.Yu@Sun.COM return (rts_common_close(NULL, connp)); 16748348SEric.Yu@Sun.COM } 16758348SEric.Yu@Sun.COM 16768348SEric.Yu@Sun.COM /* ARGSUSED */ 16778348SEric.Yu@Sun.COM int 16788348SEric.Yu@Sun.COM rts_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr) 16798348SEric.Yu@Sun.COM { 16808348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 16818348SEric.Yu@Sun.COM 16828348SEric.Yu@Sun.COM /* shut down the send side */ 16838348SEric.Yu@Sun.COM if (how != SHUT_RD) 16848348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 16858348SEric.Yu@Sun.COM SOCK_OPCTL_SHUT_SEND, 0); 16868348SEric.Yu@Sun.COM /* shut down the recv side */ 16878348SEric.Yu@Sun.COM if (how != SHUT_WR) 16888348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 16898348SEric.Yu@Sun.COM SOCK_OPCTL_SHUT_RECV, 0); 16908348SEric.Yu@Sun.COM return (0); 16918348SEric.Yu@Sun.COM } 16928348SEric.Yu@Sun.COM 16938348SEric.Yu@Sun.COM void 16948348SEric.Yu@Sun.COM rts_clr_flowctrl(sock_lower_handle_t proto_handle) 16958348SEric.Yu@Sun.COM { 16968348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 16978348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 16988348SEric.Yu@Sun.COM 16998348SEric.Yu@Sun.COM mutex_enter(&rts->rts_recv_mutex); 17008348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_FALSE; 17018348SEric.Yu@Sun.COM mutex_exit(&rts->rts_recv_mutex); 17028348SEric.Yu@Sun.COM } 17038348SEric.Yu@Sun.COM 17048348SEric.Yu@Sun.COM int 17058348SEric.Yu@Sun.COM rts_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg, 17068348SEric.Yu@Sun.COM int mode, int32_t *rvalp, cred_t *cr) 17078348SEric.Yu@Sun.COM { 17088348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 17098348SEric.Yu@Sun.COM int error; 17108348SEric.Yu@Sun.COM 17118348SEric.Yu@Sun.COM switch (cmd) { 17128348SEric.Yu@Sun.COM case ND_SET: 17138348SEric.Yu@Sun.COM case ND_GET: 17148348SEric.Yu@Sun.COM case TI_GETPEERNAME: 17158348SEric.Yu@Sun.COM case TI_GETMYNAME: 17168348SEric.Yu@Sun.COM #ifdef DEUG 17178348SEric.Yu@Sun.COM cmn_err(CE_CONT, "rts_ioctl cmd 0x%x on non sreams" 17188348SEric.Yu@Sun.COM " socket", cmd); 17198348SEric.Yu@Sun.COM #endif 17208348SEric.Yu@Sun.COM error = EINVAL; 17218348SEric.Yu@Sun.COM break; 17228348SEric.Yu@Sun.COM default: 17238348SEric.Yu@Sun.COM /* 17248348SEric.Yu@Sun.COM * Pass on to IP using helper stream 17258348SEric.Yu@Sun.COM */ 17268444SRao.Shoaib@Sun.COM error = ldi_ioctl(connp->conn_helper_info->iphs_handle, 17278348SEric.Yu@Sun.COM cmd, arg, mode, cr, rvalp); 17288348SEric.Yu@Sun.COM break; 17298348SEric.Yu@Sun.COM } 17308348SEric.Yu@Sun.COM 17318348SEric.Yu@Sun.COM return (error); 17328348SEric.Yu@Sun.COM } 17338348SEric.Yu@Sun.COM 17348348SEric.Yu@Sun.COM sock_downcalls_t sock_rts_downcalls = { 17358348SEric.Yu@Sun.COM rts_activate, 17368348SEric.Yu@Sun.COM rts_accept, 17378348SEric.Yu@Sun.COM rts_bind, 17388348SEric.Yu@Sun.COM rts_listen, 17398348SEric.Yu@Sun.COM rts_connect, 17408348SEric.Yu@Sun.COM rts_getpeername, 17418348SEric.Yu@Sun.COM rts_getsockname, 17428348SEric.Yu@Sun.COM rts_getsockopt, 17438348SEric.Yu@Sun.COM rts_setsockopt, 17448348SEric.Yu@Sun.COM rts_send, 17458348SEric.Yu@Sun.COM NULL, 17468348SEric.Yu@Sun.COM NULL, 17478348SEric.Yu@Sun.COM NULL, 17488348SEric.Yu@Sun.COM rts_shutdown, 17498348SEric.Yu@Sun.COM rts_clr_flowctrl, 17508348SEric.Yu@Sun.COM rts_ioctl, 17518348SEric.Yu@Sun.COM rts_close 17528348SEric.Yu@Sun.COM }; 1753