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; 5998485SPeter.Memishian@Sun.COM case SOL_ROUTE: 6008485SPeter.Memishian@Sun.COM switch (name) { 6018485SPeter.Memishian@Sun.COM case RT_AWARE: 6028485SPeter.Memishian@Sun.COM mutex_enter(&connp->conn_lock); 6038485SPeter.Memishian@Sun.COM *i1 = connp->conn_rtaware; 6048485SPeter.Memishian@Sun.COM mutex_exit(&connp->conn_lock); 6058485SPeter.Memishian@Sun.COM break; 6068485SPeter.Memishian@Sun.COM } 6078485SPeter.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: 642*8552SRao.Shoaib@Sun.COM if (!checkonly) { 643*8552SRao.Shoaib@Sun.COM rts->rts_reuseaddr = *i1 ? 1 : 0; 644*8552SRao.Shoaib@Sun.COM connp->conn_reuseaddr = *i1 ? 1 : 0; 645*8552SRao.Shoaib@Sun.COM } 6460Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6470Sstevel@tonic-gate case SO_DEBUG: 6480Sstevel@tonic-gate if (!checkonly) 649*8552SRao.Shoaib@Sun.COM rts->rts_debug = *i1 ? 1 : 0; 6500Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * The following three items are available here, 6530Sstevel@tonic-gate * but are only meaningful to IP. 6540Sstevel@tonic-gate */ 6550Sstevel@tonic-gate case SO_DONTROUTE: 656*8552SRao.Shoaib@Sun.COM if (!checkonly) { 657*8552SRao.Shoaib@Sun.COM rts->rts_dontroute = *i1 ? 1 : 0; 658*8552SRao.Shoaib@Sun.COM connp->conn_dontroute = *i1 ? 1 : 0; 659*8552SRao.Shoaib@Sun.COM } 6600Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6610Sstevel@tonic-gate case SO_USELOOPBACK: 662*8552SRao.Shoaib@Sun.COM if (!checkonly) { 663*8552SRao.Shoaib@Sun.COM rts->rts_useloopback = *i1 ? 1 : 0; 664*8552SRao.Shoaib@Sun.COM connp->conn_loopback = *i1 ? 1 : 0; 665*8552SRao.Shoaib@Sun.COM } 6660Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6670Sstevel@tonic-gate case SO_BROADCAST: 668*8552SRao.Shoaib@Sun.COM if (!checkonly) { 669*8552SRao.Shoaib@Sun.COM rts->rts_broadcast = *i1 ? 1 : 0; 670*8552SRao.Shoaib@Sun.COM connp->conn_broadcast = *i1 ? 1 : 0; 671*8552SRao.Shoaib@Sun.COM } 6720Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6730Sstevel@tonic-gate case SO_PROTOTYPE: 6740Sstevel@tonic-gate /* 6750Sstevel@tonic-gate * Routing socket applications that call socket() with 6760Sstevel@tonic-gate * a third argument can filter which messages will be 6770Sstevel@tonic-gate * sent upstream thanks to sockfs. so_socket() sends 6780Sstevel@tonic-gate * down the SO_PROTOTYPE and rts_queue_input() 6790Sstevel@tonic-gate * implements the filtering. 6800Sstevel@tonic-gate */ 6810Sstevel@tonic-gate if (*i1 != AF_INET && *i1 != AF_INET6) 6820Sstevel@tonic-gate return (EPROTONOSUPPORT); 683*8552SRao.Shoaib@Sun.COM if (!checkonly) { 6840Sstevel@tonic-gate rts->rts_proto = *i1; 685*8552SRao.Shoaib@Sun.COM connp->conn_proto = *i1; 686*8552SRao.Shoaib@Sun.COM } 6870Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * The following two items can be manipulated, 6900Sstevel@tonic-gate * but changing them should do nothing. 6910Sstevel@tonic-gate */ 6920Sstevel@tonic-gate case SO_SNDBUF: 6933448Sdh155122 if (*i1 > rtss->rtss_max_buf) { 6940Sstevel@tonic-gate *outlenp = 0; 6950Sstevel@tonic-gate return (ENOBUFS); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate if (!checkonly) { 6988348SEric.Yu@Sun.COM rts->rts_xmit_hiwat = *i1; 6998348SEric.Yu@Sun.COM if (!IPCL_IS_NONSTR(connp)) 7008348SEric.Yu@Sun.COM connp->conn_wq->q_hiwat = *i1; 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 7030Sstevel@tonic-gate case SO_RCVBUF: 7043448Sdh155122 if (*i1 > rtss->rtss_max_buf) { 7050Sstevel@tonic-gate *outlenp = 0; 7060Sstevel@tonic-gate return (ENOBUFS); 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate if (!checkonly) { 7098348SEric.Yu@Sun.COM rts->rts_recv_hiwat = *i1; 7108348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 7118348SEric.Yu@Sun.COM (void) proto_set_rx_hiwat(connp->conn_rq, connp, 7128348SEric.Yu@Sun.COM *i1); 7138348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 7140Sstevel@tonic-gate } 7158348SEric.Yu@Sun.COM 7160Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 7170Sstevel@tonic-gate default: 7180Sstevel@tonic-gate *outlenp = 0; 7190Sstevel@tonic-gate return (EINVAL); 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate break; 7228485SPeter.Memishian@Sun.COM case SOL_ROUTE: 7238485SPeter.Memishian@Sun.COM switch (name) { 7248485SPeter.Memishian@Sun.COM case RT_AWARE: 7258485SPeter.Memishian@Sun.COM if (!checkonly) { 7268485SPeter.Memishian@Sun.COM mutex_enter(&connp->conn_lock); 7278485SPeter.Memishian@Sun.COM connp->conn_rtaware = *i1; 7288485SPeter.Memishian@Sun.COM mutex_exit(&connp->conn_lock); 7298485SPeter.Memishian@Sun.COM } 7308485SPeter.Memishian@Sun.COM break; /* goto sizeof (int) option return */ 7318485SPeter.Memishian@Sun.COM default: 7328485SPeter.Memishian@Sun.COM *outlenp = 0; 7338485SPeter.Memishian@Sun.COM return (EINVAL); 7348485SPeter.Memishian@Sun.COM } 7358485SPeter.Memishian@Sun.COM break; 7360Sstevel@tonic-gate default: 7370Sstevel@tonic-gate *outlenp = 0; 7380Sstevel@tonic-gate return (EINVAL); 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate /* 7410Sstevel@tonic-gate * Common case of return from an option that is sizeof (int) 7420Sstevel@tonic-gate */ 7438348SEric.Yu@Sun.COM if (invalp != outvalp) { 7448348SEric.Yu@Sun.COM /* don't trust bcopy for identical src/dst */ 7458348SEric.Yu@Sun.COM (void) bcopy(invalp, outvalp, inlen); 7468348SEric.Yu@Sun.COM } 7470Sstevel@tonic-gate *outlenp = (t_uscalar_t)sizeof (int); 7480Sstevel@tonic-gate return (0); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7518348SEric.Yu@Sun.COM static int 7528348SEric.Yu@Sun.COM rts_opt_set(conn_t *connp, uint_t optset_context, int level, int name, 7538348SEric.Yu@Sun.COM uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 7548348SEric.Yu@Sun.COM void *thisdg_attrs, cred_t *cr) 7558348SEric.Yu@Sun.COM { 7568348SEric.Yu@Sun.COM boolean_t checkonly = B_FALSE; 7578348SEric.Yu@Sun.COM 7588348SEric.Yu@Sun.COM if (optset_context) { 7598348SEric.Yu@Sun.COM switch (optset_context) { 7608348SEric.Yu@Sun.COM case SETFN_OPTCOM_CHECKONLY: 7618348SEric.Yu@Sun.COM checkonly = B_TRUE; 7628348SEric.Yu@Sun.COM /* 7638348SEric.Yu@Sun.COM * Note: Implies T_CHECK semantics for T_OPTCOM_REQ 7648348SEric.Yu@Sun.COM * inlen != 0 implies value supplied and 7658348SEric.Yu@Sun.COM * we have to "pretend" to set it. 7668348SEric.Yu@Sun.COM * inlen == 0 implies that there is no value part 7678348SEric.Yu@Sun.COM * in T_CHECK request and just validation 7688348SEric.Yu@Sun.COM * done elsewhere should be enough, we just return here. 7698348SEric.Yu@Sun.COM */ 7708348SEric.Yu@Sun.COM if (inlen == 0) { 7718348SEric.Yu@Sun.COM *outlenp = 0; 7728348SEric.Yu@Sun.COM return (0); 7738348SEric.Yu@Sun.COM } 7748348SEric.Yu@Sun.COM break; 7758348SEric.Yu@Sun.COM case SETFN_OPTCOM_NEGOTIATE: 7768348SEric.Yu@Sun.COM checkonly = B_FALSE; 7778348SEric.Yu@Sun.COM break; 7788348SEric.Yu@Sun.COM case SETFN_UD_NEGOTIATE: 7798348SEric.Yu@Sun.COM case SETFN_CONN_NEGOTIATE: 7808348SEric.Yu@Sun.COM checkonly = B_FALSE; 7818348SEric.Yu@Sun.COM /* 7828348SEric.Yu@Sun.COM * Negotiating local and "association-related" options 7838348SEric.Yu@Sun.COM * through T_UNITDATA_REQ or T_CONN_{REQ,CON} 7848348SEric.Yu@Sun.COM * Not allowed in this module. 7858348SEric.Yu@Sun.COM */ 7868348SEric.Yu@Sun.COM return (EINVAL); 7878348SEric.Yu@Sun.COM default: 7888348SEric.Yu@Sun.COM /* 7898348SEric.Yu@Sun.COM * We should never get here 7908348SEric.Yu@Sun.COM */ 7918348SEric.Yu@Sun.COM *outlenp = 0; 7928348SEric.Yu@Sun.COM return (EINVAL); 7938348SEric.Yu@Sun.COM } 7948348SEric.Yu@Sun.COM 7958348SEric.Yu@Sun.COM ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) || 7968348SEric.Yu@Sun.COM (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0)); 7978348SEric.Yu@Sun.COM 7988348SEric.Yu@Sun.COM } 7998348SEric.Yu@Sun.COM return (rts_do_opt_set(connp, level, name, inlen, invalp, outlenp, 8008348SEric.Yu@Sun.COM outvalp, cr, thisdg_attrs, checkonly)); 8018348SEric.Yu@Sun.COM 8028348SEric.Yu@Sun.COM } 8038348SEric.Yu@Sun.COM 8048348SEric.Yu@Sun.COM /* 8058348SEric.Yu@Sun.COM * This routine retrieves the current status of socket options. 8068348SEric.Yu@Sun.COM * It returns the size of the option retrieved. 8078348SEric.Yu@Sun.COM */ 8088348SEric.Yu@Sun.COM int 8098348SEric.Yu@Sun.COM rts_tpi_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 8108348SEric.Yu@Sun.COM { 8118348SEric.Yu@Sun.COM rts_t *rts; 8128348SEric.Yu@Sun.COM int err; 8138348SEric.Yu@Sun.COM 8148348SEric.Yu@Sun.COM rts = Q_TO_RTS(q); 8158348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_READER); 8168348SEric.Yu@Sun.COM err = rts_opt_get(Q_TO_CONN(q), level, name, ptr); 8178348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 8188348SEric.Yu@Sun.COM return (err); 8198348SEric.Yu@Sun.COM } 8208348SEric.Yu@Sun.COM 8218348SEric.Yu@Sun.COM /* 8228348SEric.Yu@Sun.COM * This routine sets socket options. 8238348SEric.Yu@Sun.COM */ 8248348SEric.Yu@Sun.COM /*ARGSUSED*/ 8258348SEric.Yu@Sun.COM int 8268348SEric.Yu@Sun.COM rts_tpi_opt_set(queue_t *q, uint_t optset_context, int level, 8278348SEric.Yu@Sun.COM int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp, 8288348SEric.Yu@Sun.COM uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk) 8298348SEric.Yu@Sun.COM { 8308348SEric.Yu@Sun.COM conn_t *connp = Q_TO_CONN(q); 8318348SEric.Yu@Sun.COM int error; 8328348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 8338348SEric.Yu@Sun.COM 8348348SEric.Yu@Sun.COM 8358348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 8368348SEric.Yu@Sun.COM error = rts_opt_set(connp, optset_context, level, name, inlen, invalp, 8378348SEric.Yu@Sun.COM outlenp, outvalp, thisdg_attrs, cr); 8388348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 8398348SEric.Yu@Sun.COM return (error); 8408348SEric.Yu@Sun.COM } 8418348SEric.Yu@Sun.COM 8420Sstevel@tonic-gate /* 8430Sstevel@tonic-gate * This routine retrieves the value of an ND variable in a rtsparam_t 8440Sstevel@tonic-gate * structure. It is called through nd_getset when a user reads the 8450Sstevel@tonic-gate * variable. 8460Sstevel@tonic-gate */ 8470Sstevel@tonic-gate /* ARGSUSED */ 8480Sstevel@tonic-gate static int 8490Sstevel@tonic-gate rts_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 8500Sstevel@tonic-gate { 8510Sstevel@tonic-gate rtsparam_t *rtspa = (rtsparam_t *)cp; 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", rtspa->rts_param_value); 8540Sstevel@tonic-gate return (0); 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate /* 8580Sstevel@tonic-gate * Walk through the param array specified registering each element with the 8590Sstevel@tonic-gate * named dispatch (ND) handler. 8600Sstevel@tonic-gate */ 8610Sstevel@tonic-gate static boolean_t 8623448Sdh155122 rts_param_register(IDP *ndp, rtsparam_t *rtspa, int cnt) 8630Sstevel@tonic-gate { 8640Sstevel@tonic-gate for (; cnt-- > 0; rtspa++) { 8650Sstevel@tonic-gate if (rtspa->rts_param_name != NULL && rtspa->rts_param_name[0]) { 8663448Sdh155122 if (!nd_load(ndp, rtspa->rts_param_name, 8670Sstevel@tonic-gate rts_param_get, rts_param_set, (caddr_t)rtspa)) { 8683448Sdh155122 nd_free(ndp); 8690Sstevel@tonic-gate return (B_FALSE); 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate } 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate return (B_TRUE); 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate /* This routine sets an ND variable in a rtsparam_t structure. */ 8770Sstevel@tonic-gate /* ARGSUSED */ 8780Sstevel@tonic-gate static int 8790Sstevel@tonic-gate rts_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 8800Sstevel@tonic-gate { 8810Sstevel@tonic-gate ulong_t new_value; 8820Sstevel@tonic-gate rtsparam_t *rtspa = (rtsparam_t *)cp; 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate /* 8850Sstevel@tonic-gate * Fail the request if the new value does not lie within the 8860Sstevel@tonic-gate * required bounds. 8870Sstevel@tonic-gate */ 8880Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 8890Sstevel@tonic-gate new_value < rtspa->rts_param_min || 8900Sstevel@tonic-gate new_value > rtspa->rts_param_max) { 8910Sstevel@tonic-gate return (EINVAL); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* Set the new value */ 8950Sstevel@tonic-gate rtspa->rts_param_value = new_value; 8960Sstevel@tonic-gate return (0); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate /* 9005240Snordmark * Empty rsrv routine which is used by rts_input to cause a wakeup 9015240Snordmark * of a thread in qwait. 9025240Snordmark */ 9035240Snordmark /*ARGSUSED*/ 9045240Snordmark static void 9055240Snordmark rts_rsrv(queue_t *q) 9065240Snordmark { 9075240Snordmark } 9085240Snordmark 9095240Snordmark /* 9100Sstevel@tonic-gate * This routine handles synchronous messages passed downstream. It either 9110Sstevel@tonic-gate * consumes the message or passes it downstream; it never queues a 9120Sstevel@tonic-gate * a message. The data messages that go down are wrapped in an IOCTL 9130Sstevel@tonic-gate * message. 9140Sstevel@tonic-gate * 9150Sstevel@tonic-gate * Since it is synchronous, it waits for the M_IOCACK/M_IOCNAK so that 9160Sstevel@tonic-gate * it can return an immediate error (such as ENETUNREACH when adding a route). 9170Sstevel@tonic-gate * It uses the RTS_WRW_PENDING to ensure that each rts instance has only 9180Sstevel@tonic-gate * one M_IOCTL outstanding at any given time. 9190Sstevel@tonic-gate */ 9200Sstevel@tonic-gate static int 9210Sstevel@tonic-gate rts_wrw(queue_t *q, struiod_t *dp) 9220Sstevel@tonic-gate { 9230Sstevel@tonic-gate mblk_t *mp = dp->d_mp; 9240Sstevel@tonic-gate mblk_t *mp1; 9250Sstevel@tonic-gate int error; 9260Sstevel@tonic-gate rt_msghdr_t *rtm; 9275240Snordmark conn_t *connp = Q_TO_CONN(q); 9285240Snordmark rts_t *rts = connp->conn_rts; 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate while (rts->rts_flag & RTS_WRW_PENDING) { 9310Sstevel@tonic-gate if (qwait_rw(q)) { 9320Sstevel@tonic-gate rts->rts_error = EINTR; 9330Sstevel@tonic-gate goto err_ret; 9340Sstevel@tonic-gate } 9358348SEric.Yu@Sun.COM } 9360Sstevel@tonic-gate rts->rts_flag |= RTS_WRW_PENDING; 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate if (isuioq(q) && (error = struioget(q, mp, dp, 0))) { 9390Sstevel@tonic-gate /* 9400Sstevel@tonic-gate * Uio error of some sort, so just return the error. 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate rts->rts_error = error; 9430Sstevel@tonic-gate goto err_ret; 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate /* 9460Sstevel@tonic-gate * Pass the mblk (chain) onto wput(). 9470Sstevel@tonic-gate */ 9480Sstevel@tonic-gate dp->d_mp = 0; 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate switch (mp->b_datap->db_type) { 9510Sstevel@tonic-gate case M_PROTO: 9520Sstevel@tonic-gate case M_PCPROTO: 9530Sstevel@tonic-gate /* Expedite other than T_DATA_REQ to below the switch */ 9540Sstevel@tonic-gate if (((mp->b_wptr - mp->b_rptr) != 9550Sstevel@tonic-gate sizeof (struct T_data_req)) || 9560Sstevel@tonic-gate (((union T_primitives *)mp->b_rptr)->type != T_DATA_REQ)) 9570Sstevel@tonic-gate break; 9580Sstevel@tonic-gate if ((mp1 = mp->b_cont) == NULL) { 9590Sstevel@tonic-gate rts->rts_error = EINVAL; 9600Sstevel@tonic-gate goto err_ret; 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate freeb(mp); 9630Sstevel@tonic-gate mp = mp1; 9640Sstevel@tonic-gate /* FALLTHRU */ 9650Sstevel@tonic-gate case M_DATA: 9660Sstevel@tonic-gate /* 9670Sstevel@tonic-gate * The semantics of the routing socket is such that the rtm_pid 9680Sstevel@tonic-gate * field is automatically filled in during requests with the 9690Sstevel@tonic-gate * current process' pid. We do this here (where we still have 9700Sstevel@tonic-gate * user context) after checking we have at least a message the 9710Sstevel@tonic-gate * size of a routing message header. 9720Sstevel@tonic-gate */ 9730Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 9740Sstevel@tonic-gate if (!pullupmsg(mp, sizeof (rt_msghdr_t))) { 9750Sstevel@tonic-gate rts->rts_error = EINVAL; 9760Sstevel@tonic-gate goto err_ret; 9770Sstevel@tonic-gate } 9780Sstevel@tonic-gate } 9790Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 9800Sstevel@tonic-gate rtm->rtm_pid = curproc->p_pid; 9810Sstevel@tonic-gate break; 9820Sstevel@tonic-gate default: 9830Sstevel@tonic-gate break; 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate rts->rts_flag |= RTS_WPUT_PENDING; 9860Sstevel@tonic-gate rts_wput(q, mp); 9870Sstevel@tonic-gate while (rts->rts_flag & RTS_WPUT_PENDING) 9880Sstevel@tonic-gate if (qwait_rw(q)) { 9890Sstevel@tonic-gate /* RTS_WPUT_PENDING will be cleared below */ 9900Sstevel@tonic-gate rts->rts_error = EINTR; 9910Sstevel@tonic-gate break; 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate err_ret: 9940Sstevel@tonic-gate rts->rts_flag &= ~(RTS_WPUT_PENDING | RTS_WRW_PENDING); 9950Sstevel@tonic-gate return (rts->rts_error); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate /* 9990Sstevel@tonic-gate * This routine handles all messages passed downstream. It either 10000Sstevel@tonic-gate * consumes the message or passes it downstream; it never queues a 10010Sstevel@tonic-gate * a message. The data messages that go down are wrapped in an IOCTL 10020Sstevel@tonic-gate * message. 10035240Snordmark * 10045240Snordmark * FIXME? Should we call IP rts_request directly? Could punt on returning 10055240Snordmark * errno in the case when it defers processing due to 10065240Snordmark * IPIF_CHANGING/ILL_CHANGING??? 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate static void 10090Sstevel@tonic-gate rts_wput(queue_t *q, mblk_t *mp) 10100Sstevel@tonic-gate { 10110Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 10120Sstevel@tonic-gate mblk_t *mp1; 10135240Snordmark conn_t *connp = Q_TO_CONN(q); 10145240Snordmark rts_t *rts = connp->conn_rts; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate switch (mp->b_datap->db_type) { 10170Sstevel@tonic-gate case M_DATA: 10180Sstevel@tonic-gate break; 10190Sstevel@tonic-gate case M_PROTO: 10200Sstevel@tonic-gate case M_PCPROTO: 10210Sstevel@tonic-gate if ((mp->b_wptr - rptr) == sizeof (struct T_data_req)) { 10220Sstevel@tonic-gate /* Expedite valid T_DATA_REQ to below the switch */ 10230Sstevel@tonic-gate if (((union T_primitives *)rptr)->type == T_DATA_REQ) { 10240Sstevel@tonic-gate mp1 = mp->b_cont; 10250Sstevel@tonic-gate freeb(mp); 10260Sstevel@tonic-gate if (mp1 == NULL) 10270Sstevel@tonic-gate return; 10280Sstevel@tonic-gate mp = mp1; 10290Sstevel@tonic-gate break; 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate /* FALLTHRU */ 10330Sstevel@tonic-gate default: 10340Sstevel@tonic-gate rts_wput_other(q, mp); 10350Sstevel@tonic-gate return; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate mp1 = rts_ioctl_alloc(mp, DB_CRED(mp)); 10400Sstevel@tonic-gate if (mp1 == NULL) { 10410Sstevel@tonic-gate ASSERT(rts != NULL); 10420Sstevel@tonic-gate freemsg(mp); 10430Sstevel@tonic-gate if (rts->rts_flag & RTS_WPUT_PENDING) { 10440Sstevel@tonic-gate rts->rts_error = ENOMEM; 10450Sstevel@tonic-gate rts->rts_flag &= ~RTS_WPUT_PENDING; 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate return; 10480Sstevel@tonic-gate } 10495240Snordmark ip_output(connp, mp1, q, IP_WPUT); 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate /* 10540Sstevel@tonic-gate * Handles all the control message, if it 10550Sstevel@tonic-gate * can not understand it, it will 10560Sstevel@tonic-gate * pass down stream. 10570Sstevel@tonic-gate */ 10580Sstevel@tonic-gate static void 10590Sstevel@tonic-gate rts_wput_other(queue_t *q, mblk_t *mp) 10600Sstevel@tonic-gate { 10615240Snordmark conn_t *connp = Q_TO_CONN(q); 10625240Snordmark rts_t *rts = connp->conn_rts; 10630Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 10640Sstevel@tonic-gate struct iocblk *iocp; 10650Sstevel@tonic-gate cred_t *cr; 10663448Sdh155122 rts_stack_t *rtss; 10670Sstevel@tonic-gate 10683448Sdh155122 rtss = rts->rts_rtss; 10690Sstevel@tonic-gate 10705240Snordmark cr = DB_CREDDEF(mp, connp->conn_cred); 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate switch (mp->b_datap->db_type) { 10730Sstevel@tonic-gate case M_PROTO: 10740Sstevel@tonic-gate case M_PCPROTO: 10750Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (t_scalar_t)) { 10760Sstevel@tonic-gate /* 10770Sstevel@tonic-gate * If the message does not contain a PRIM_type, 10780Sstevel@tonic-gate * throw it away. 10790Sstevel@tonic-gate */ 10800Sstevel@tonic-gate freemsg(mp); 10810Sstevel@tonic-gate return; 10820Sstevel@tonic-gate } 10830Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) { 10840Sstevel@tonic-gate case T_BIND_REQ: 10850Sstevel@tonic-gate case O_T_BIND_REQ: 10868348SEric.Yu@Sun.COM rts_tpi_bind(q, mp); 10870Sstevel@tonic-gate return; 10880Sstevel@tonic-gate case T_UNBIND_REQ: 10898348SEric.Yu@Sun.COM rts_tpi_unbind(q, mp); 10900Sstevel@tonic-gate return; 10910Sstevel@tonic-gate case T_CAPABILITY_REQ: 10920Sstevel@tonic-gate rts_capability_req(q, mp); 10930Sstevel@tonic-gate return; 10940Sstevel@tonic-gate case T_INFO_REQ: 10950Sstevel@tonic-gate rts_info_req(q, mp); 10960Sstevel@tonic-gate return; 10970Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 10985240Snordmark (void) svr4_optcom_req(q, mp, cr, &rts_opt_obj, 10995277Snordmark B_TRUE); 11000Sstevel@tonic-gate return; 11010Sstevel@tonic-gate case T_OPTMGMT_REQ: 11025277Snordmark (void) tpi_optcom_req(q, mp, cr, &rts_opt_obj, B_TRUE); 11030Sstevel@tonic-gate return; 11040Sstevel@tonic-gate case O_T_CONN_RES: 11050Sstevel@tonic-gate case T_CONN_RES: 11060Sstevel@tonic-gate case T_DISCON_REQ: 11070Sstevel@tonic-gate /* Not supported by rts. */ 11080Sstevel@tonic-gate rts_err_ack(q, mp, TNOTSUPPORT, 0); 11090Sstevel@tonic-gate return; 11100Sstevel@tonic-gate case T_DATA_REQ: 11110Sstevel@tonic-gate case T_EXDATA_REQ: 11120Sstevel@tonic-gate case T_ORDREL_REQ: 11130Sstevel@tonic-gate /* Illegal for rts. */ 11140Sstevel@tonic-gate freemsg(mp); 11150Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO); 11160Sstevel@tonic-gate return; 11178348SEric.Yu@Sun.COM 11180Sstevel@tonic-gate default: 11190Sstevel@tonic-gate break; 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate break; 11220Sstevel@tonic-gate case M_IOCTL: 11230Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 11240Sstevel@tonic-gate switch (iocp->ioc_cmd) { 11250Sstevel@tonic-gate case ND_SET: 11260Sstevel@tonic-gate case ND_GET: 11273448Sdh155122 if (nd_getset(q, rtss->rtss_g_nd, mp)) { 11280Sstevel@tonic-gate qreply(q, mp); 11290Sstevel@tonic-gate return; 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate break; 11320Sstevel@tonic-gate case TI_GETPEERNAME: 11330Sstevel@tonic-gate mi_copyin(q, mp, NULL, 11340Sstevel@tonic-gate SIZEOF_STRUCT(strbuf, iocp->ioc_flag)); 11350Sstevel@tonic-gate return; 11360Sstevel@tonic-gate default: 11370Sstevel@tonic-gate break; 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate case M_IOCDATA: 11400Sstevel@tonic-gate rts_wput_iocdata(q, mp); 11410Sstevel@tonic-gate return; 11420Sstevel@tonic-gate default: 11430Sstevel@tonic-gate break; 11440Sstevel@tonic-gate } 11455240Snordmark ip_output(connp, mp, q, IP_WPUT); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate /* 11490Sstevel@tonic-gate * Called by rts_wput_other to handle all M_IOCDATA messages. 11500Sstevel@tonic-gate */ 11510Sstevel@tonic-gate static void 11520Sstevel@tonic-gate rts_wput_iocdata(queue_t *q, mblk_t *mp) 11530Sstevel@tonic-gate { 11545240Snordmark conn_t *connp = Q_TO_CONN(q); 11550Sstevel@tonic-gate struct sockaddr *rtsaddr; 11560Sstevel@tonic-gate mblk_t *mp1; 11570Sstevel@tonic-gate STRUCT_HANDLE(strbuf, sb); 11580Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* Make sure it is one of ours. */ 11610Sstevel@tonic-gate switch (iocp->ioc_cmd) { 11620Sstevel@tonic-gate case TI_GETPEERNAME: 11630Sstevel@tonic-gate break; 11640Sstevel@tonic-gate default: 11655240Snordmark ip_output(connp, mp, q, IP_WPUT); 11660Sstevel@tonic-gate return; 11670Sstevel@tonic-gate } 11680Sstevel@tonic-gate switch (mi_copy_state(q, mp, &mp1)) { 11690Sstevel@tonic-gate case -1: 11700Sstevel@tonic-gate return; 11710Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_IN, 1): 11720Sstevel@tonic-gate break; 11730Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 1): 11740Sstevel@tonic-gate /* Copy out the strbuf. */ 11750Sstevel@tonic-gate mi_copyout(q, mp); 11760Sstevel@tonic-gate return; 11770Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 2): 11780Sstevel@tonic-gate /* All done. */ 11790Sstevel@tonic-gate mi_copy_done(q, mp, 0); 11800Sstevel@tonic-gate return; 11810Sstevel@tonic-gate default: 11820Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 11830Sstevel@tonic-gate return; 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate STRUCT_SET_HANDLE(sb, iocp->ioc_flag, (void *)mp1->b_rptr); 11860Sstevel@tonic-gate if (STRUCT_FGET(sb, maxlen) < (int)sizeof (sin_t)) { 11870Sstevel@tonic-gate mi_copy_done(q, mp, EINVAL); 11880Sstevel@tonic-gate return; 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate switch (iocp->ioc_cmd) { 11910Sstevel@tonic-gate case TI_GETPEERNAME: 11920Sstevel@tonic-gate break; 11930Sstevel@tonic-gate default: 11940Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 11950Sstevel@tonic-gate return; 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), sizeof (sin_t), 11980Sstevel@tonic-gate B_TRUE); 11990Sstevel@tonic-gate if (mp1 == NULL) 12000Sstevel@tonic-gate return; 12010Sstevel@tonic-gate STRUCT_FSET(sb, len, (int)sizeof (sin_t)); 12020Sstevel@tonic-gate rtsaddr = (struct sockaddr *)mp1->b_rptr; 12030Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)&rtsaddr[1]; 12040Sstevel@tonic-gate bzero(rtsaddr, sizeof (struct sockaddr)); 12050Sstevel@tonic-gate rtsaddr->sa_family = AF_ROUTE; 12060Sstevel@tonic-gate /* Copy out the address */ 12070Sstevel@tonic-gate mi_copyout(q, mp); 12080Sstevel@tonic-gate } 12090Sstevel@tonic-gate 12105240Snordmark /*ARGSUSED2*/ 12110Sstevel@tonic-gate static void 12125240Snordmark rts_input(void *arg1, mblk_t *mp, void *arg2) 12130Sstevel@tonic-gate { 12145240Snordmark conn_t *connp = (conn_t *)arg1; 12155240Snordmark rts_t *rts = connp->conn_rts; 12160Sstevel@tonic-gate struct iocblk *iocp; 12170Sstevel@tonic-gate mblk_t *mp1; 12180Sstevel@tonic-gate struct T_data_ind *tdi; 12198348SEric.Yu@Sun.COM int error; 12200Sstevel@tonic-gate 12210Sstevel@tonic-gate switch (mp->b_datap->db_type) { 12220Sstevel@tonic-gate case M_IOCACK: 12230Sstevel@tonic-gate case M_IOCNAK: 12240Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 12258348SEric.Yu@Sun.COM if (IPCL_IS_NONSTR(connp)) { 12268348SEric.Yu@Sun.COM ASSERT(rts->rts_flag & (RTS_REQ_PENDING)); 12278348SEric.Yu@Sun.COM mutex_enter(&rts->rts_send_mutex); 12288348SEric.Yu@Sun.COM rts->rts_flag &= ~RTS_REQ_INPROG; 12290Sstevel@tonic-gate rts->rts_error = iocp->ioc_error; 12308348SEric.Yu@Sun.COM cv_signal(&rts->rts_io_cv); 12318348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 12320Sstevel@tonic-gate freemsg(mp); 12330Sstevel@tonic-gate return; 12348348SEric.Yu@Sun.COM } else { 12358348SEric.Yu@Sun.COM if (rts->rts_flag & (RTS_WPUT_PENDING)) { 12368348SEric.Yu@Sun.COM rts->rts_flag &= ~RTS_WPUT_PENDING; 12378348SEric.Yu@Sun.COM rts->rts_error = iocp->ioc_error; 12388348SEric.Yu@Sun.COM /* 12398348SEric.Yu@Sun.COM * Tell rts_wvw/qwait that we are done. 12408348SEric.Yu@Sun.COM * Note: there is no qwait_wakeup() we can use. 12418348SEric.Yu@Sun.COM */ 12428348SEric.Yu@Sun.COM qenable(connp->conn_rq); 12438348SEric.Yu@Sun.COM freemsg(mp); 12448348SEric.Yu@Sun.COM return; 12458348SEric.Yu@Sun.COM } 12460Sstevel@tonic-gate } 12470Sstevel@tonic-gate break; 12480Sstevel@tonic-gate case M_DATA: 12490Sstevel@tonic-gate /* 12500Sstevel@tonic-gate * Prepend T_DATA_IND to prevent the stream head from 12510Sstevel@tonic-gate * consolidating multiple messages together. 12520Sstevel@tonic-gate * If the allocation fails just send up the M_DATA. 12530Sstevel@tonic-gate */ 12540Sstevel@tonic-gate mp1 = allocb(sizeof (*tdi), BPRI_MED); 12550Sstevel@tonic-gate if (mp1 != NULL) { 12560Sstevel@tonic-gate mp1->b_cont = mp; 12570Sstevel@tonic-gate mp = mp1; 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 12600Sstevel@tonic-gate mp->b_wptr += sizeof (*tdi); 12610Sstevel@tonic-gate tdi = (struct T_data_ind *)mp->b_rptr; 12620Sstevel@tonic-gate tdi->PRIM_type = T_DATA_IND; 12630Sstevel@tonic-gate tdi->MORE_flag = 0; 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate break; 12660Sstevel@tonic-gate default: 12670Sstevel@tonic-gate break; 12680Sstevel@tonic-gate } 12698348SEric.Yu@Sun.COM 12708348SEric.Yu@Sun.COM if (IPCL_IS_NONSTR(connp)) { 12718348SEric.Yu@Sun.COM if ((*connp->conn_upcalls->su_recv) 12728348SEric.Yu@Sun.COM (connp->conn_upper_handle, mp, msgdsize(mp), 0, 12738348SEric.Yu@Sun.COM &error, NULL) < 0) { 12748348SEric.Yu@Sun.COM ASSERT(error == ENOSPC); 12758348SEric.Yu@Sun.COM /* 12768348SEric.Yu@Sun.COM * Let's confirm hoding the lock that 12778348SEric.Yu@Sun.COM * we are out of recv space. 12788348SEric.Yu@Sun.COM */ 12798348SEric.Yu@Sun.COM mutex_enter(&rts->rts_recv_mutex); 12808348SEric.Yu@Sun.COM if ((*connp->conn_upcalls->su_recv) 12818348SEric.Yu@Sun.COM (connp->conn_upper_handle, NULL, 0, 0, 12828348SEric.Yu@Sun.COM &error, NULL) < 0) { 12838348SEric.Yu@Sun.COM ASSERT(error == ENOSPC); 12848348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_TRUE; 12858348SEric.Yu@Sun.COM } 12868348SEric.Yu@Sun.COM mutex_exit(&rts->rts_recv_mutex); 12878348SEric.Yu@Sun.COM } 12888348SEric.Yu@Sun.COM } else { 12898348SEric.Yu@Sun.COM putnext(connp->conn_rq, mp); 12908348SEric.Yu@Sun.COM } 12910Sstevel@tonic-gate } 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate 12940Sstevel@tonic-gate void 12958348SEric.Yu@Sun.COM rts_ddi_g_init(void) 12960Sstevel@tonic-gate { 12970Sstevel@tonic-gate rts_max_optsize = optcom_max_optsize(rts_opt_obj.odb_opt_des_arr, 12980Sstevel@tonic-gate rts_opt_obj.odb_opt_arr_cnt); 12993448Sdh155122 13003448Sdh155122 /* 13013448Sdh155122 * We want to be informed each time a stack is created or 13023448Sdh155122 * destroyed in the kernel, so we can maintain the 13033448Sdh155122 * set of rts_stack_t's. 13043448Sdh155122 */ 13053448Sdh155122 netstack_register(NS_RTS, rts_stack_init, NULL, rts_stack_fini); 13060Sstevel@tonic-gate } 13073448Sdh155122 13083448Sdh155122 void 13098348SEric.Yu@Sun.COM rts_ddi_g_destroy(void) 13103448Sdh155122 { 13113448Sdh155122 netstack_unregister(NS_RTS); 13123448Sdh155122 } 13133448Sdh155122 13148348SEric.Yu@Sun.COM #define INET_NAME "ip" 13158348SEric.Yu@Sun.COM 13163448Sdh155122 /* 13173448Sdh155122 * Initialize the RTS stack instance. 13183448Sdh155122 */ 13193448Sdh155122 /* ARGSUSED */ 13203448Sdh155122 static void * 13213448Sdh155122 rts_stack_init(netstackid_t stackid, netstack_t *ns) 13223448Sdh155122 { 13233448Sdh155122 rts_stack_t *rtss; 13243448Sdh155122 rtsparam_t *pa; 13258348SEric.Yu@Sun.COM int error = 0; 13268348SEric.Yu@Sun.COM major_t major; 13273448Sdh155122 13283448Sdh155122 rtss = (rts_stack_t *)kmem_zalloc(sizeof (*rtss), KM_SLEEP); 13293448Sdh155122 rtss->rtss_netstack = ns; 13303448Sdh155122 13313448Sdh155122 pa = (rtsparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP); 13323448Sdh155122 rtss->rtss_params = pa; 13333448Sdh155122 bcopy(lcl_param_arr, rtss->rtss_params, sizeof (lcl_param_arr)); 13343448Sdh155122 13353448Sdh155122 (void) rts_param_register(&rtss->rtss_g_nd, 13363448Sdh155122 rtss->rtss_params, A_CNT(lcl_param_arr)); 13378348SEric.Yu@Sun.COM 13388348SEric.Yu@Sun.COM major = mod_name_to_major(INET_NAME); 13398348SEric.Yu@Sun.COM error = ldi_ident_from_major(major, &rtss->rtss_ldi_ident); 13408348SEric.Yu@Sun.COM ASSERT(error == 0); 13413448Sdh155122 return (rtss); 13423448Sdh155122 } 13433448Sdh155122 13443448Sdh155122 /* 13453448Sdh155122 * Free the RTS stack instance. 13463448Sdh155122 */ 13473448Sdh155122 /* ARGSUSED */ 13483448Sdh155122 static void 13493448Sdh155122 rts_stack_fini(netstackid_t stackid, void *arg) 13503448Sdh155122 { 13513448Sdh155122 rts_stack_t *rtss = (rts_stack_t *)arg; 13523448Sdh155122 13535240Snordmark nd_free(&rtss->rtss_g_nd); 13543448Sdh155122 kmem_free(rtss->rtss_params, sizeof (lcl_param_arr)); 13553448Sdh155122 rtss->rtss_params = NULL; 13568348SEric.Yu@Sun.COM ldi_ident_release(rtss->rtss_ldi_ident); 13573448Sdh155122 kmem_free(rtss, sizeof (*rtss)); 13583448Sdh155122 } 13598348SEric.Yu@Sun.COM 13608348SEric.Yu@Sun.COM /* ARGSUSED */ 13618348SEric.Yu@Sun.COM int 13628348SEric.Yu@Sun.COM rts_accept(sock_lower_handle_t lproto_handle, 13638348SEric.Yu@Sun.COM sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle, 13648348SEric.Yu@Sun.COM cred_t *cr) 13658348SEric.Yu@Sun.COM { 13668348SEric.Yu@Sun.COM return (EINVAL); 13678348SEric.Yu@Sun.COM } 13688348SEric.Yu@Sun.COM 13698348SEric.Yu@Sun.COM /* ARGSUSED */ 13708348SEric.Yu@Sun.COM static int 13718348SEric.Yu@Sun.COM rts_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 13728348SEric.Yu@Sun.COM socklen_t len, cred_t *cr) 13738348SEric.Yu@Sun.COM { 13748348SEric.Yu@Sun.COM /* 13758348SEric.Yu@Sun.COM * rebind not allowed 13768348SEric.Yu@Sun.COM */ 13778348SEric.Yu@Sun.COM return (EINVAL); 13788348SEric.Yu@Sun.COM } 13798348SEric.Yu@Sun.COM 13808348SEric.Yu@Sun.COM /* ARGSUSED */ 13818348SEric.Yu@Sun.COM int 13828348SEric.Yu@Sun.COM rts_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr) 13838348SEric.Yu@Sun.COM { 13848348SEric.Yu@Sun.COM return (EINVAL); 13858348SEric.Yu@Sun.COM } 13868348SEric.Yu@Sun.COM 13878348SEric.Yu@Sun.COM /* ARGSUSED */ 13888348SEric.Yu@Sun.COM int 13898348SEric.Yu@Sun.COM rts_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa, 13908348SEric.Yu@Sun.COM socklen_t len, sock_connid_t *id, cred_t *cr) 13918348SEric.Yu@Sun.COM { 13928348SEric.Yu@Sun.COM /* 13938348SEric.Yu@Sun.COM * rts sockets start out as bound and connected 13948348SEric.Yu@Sun.COM */ 13958348SEric.Yu@Sun.COM *id = 0; 13968348SEric.Yu@Sun.COM return (EISCONN); 13978348SEric.Yu@Sun.COM } 13988348SEric.Yu@Sun.COM 13998348SEric.Yu@Sun.COM /* ARGSUSED */ 14008348SEric.Yu@Sun.COM int 14018348SEric.Yu@Sun.COM rts_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr, 14028348SEric.Yu@Sun.COM socklen_t *addrlen, cred_t *cr) 14038348SEric.Yu@Sun.COM { 14048348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14058348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 14068348SEric.Yu@Sun.COM 14078348SEric.Yu@Sun.COM ASSERT(rts != NULL); 14088348SEric.Yu@Sun.COM 14098348SEric.Yu@Sun.COM bzero(addr, sizeof (struct sockaddr)); 14108348SEric.Yu@Sun.COM addr->sa_family = AF_ROUTE; 14118348SEric.Yu@Sun.COM *addrlen = sizeof (struct sockaddr); 14128348SEric.Yu@Sun.COM 14138348SEric.Yu@Sun.COM return (0); 14148348SEric.Yu@Sun.COM } 14158348SEric.Yu@Sun.COM 14168348SEric.Yu@Sun.COM /* ARGSUSED */ 14178348SEric.Yu@Sun.COM int 14188348SEric.Yu@Sun.COM rts_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr, 14198348SEric.Yu@Sun.COM socklen_t *addrlen, cred_t *cr) 14208348SEric.Yu@Sun.COM { 14218348SEric.Yu@Sun.COM return (EOPNOTSUPP); 14228348SEric.Yu@Sun.COM } 14238348SEric.Yu@Sun.COM 14248348SEric.Yu@Sun.COM static int 14258348SEric.Yu@Sun.COM rts_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 14268348SEric.Yu@Sun.COM void *optvalp, socklen_t *optlen, cred_t *cr) 14278348SEric.Yu@Sun.COM { 14288348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14298348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 14308348SEric.Yu@Sun.COM int error; 14318348SEric.Yu@Sun.COM t_uscalar_t max_optbuf_len; 14328348SEric.Yu@Sun.COM void *optvalp_buf; 14338348SEric.Yu@Sun.COM int len; 14348348SEric.Yu@Sun.COM 14358348SEric.Yu@Sun.COM error = proto_opt_check(level, option_name, *optlen, &max_optbuf_len, 14368348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_des_arr, 14378348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_arr_cnt, 14388348SEric.Yu@Sun.COM rts_opt_obj.odb_topmost_tpiprovider, 14398348SEric.Yu@Sun.COM B_FALSE, B_TRUE, cr); 14408348SEric.Yu@Sun.COM if (error != 0) { 14418348SEric.Yu@Sun.COM if (error < 0) 14428348SEric.Yu@Sun.COM error = proto_tlitosyserr(-error); 14438348SEric.Yu@Sun.COM return (error); 14448348SEric.Yu@Sun.COM } 14458348SEric.Yu@Sun.COM 14468348SEric.Yu@Sun.COM optvalp_buf = kmem_alloc(max_optbuf_len, KM_SLEEP); 14478348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_READER); 14488348SEric.Yu@Sun.COM len = rts_opt_get(connp, level, option_name, optvalp_buf); 14498348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 14508348SEric.Yu@Sun.COM 14518348SEric.Yu@Sun.COM if (len < 0) { 14528348SEric.Yu@Sun.COM /* 14538348SEric.Yu@Sun.COM * Pass on to IP 14548348SEric.Yu@Sun.COM */ 14558348SEric.Yu@Sun.COM error = ip_get_options(connp, level, option_name, 14568348SEric.Yu@Sun.COM optvalp, optlen, cr); 14578348SEric.Yu@Sun.COM } else { 14588348SEric.Yu@Sun.COM /* 14598348SEric.Yu@Sun.COM * update optlen and copy option value 14608348SEric.Yu@Sun.COM */ 14618348SEric.Yu@Sun.COM t_uscalar_t size = MIN(len, *optlen); 14628348SEric.Yu@Sun.COM bcopy(optvalp_buf, optvalp, size); 14638348SEric.Yu@Sun.COM bcopy(&size, optlen, sizeof (size)); 14648348SEric.Yu@Sun.COM error = 0; 14658348SEric.Yu@Sun.COM } 14668348SEric.Yu@Sun.COM 14678348SEric.Yu@Sun.COM kmem_free(optvalp_buf, max_optbuf_len); 14688348SEric.Yu@Sun.COM return (error); 14698348SEric.Yu@Sun.COM } 14708348SEric.Yu@Sun.COM 14718348SEric.Yu@Sun.COM static int 14728348SEric.Yu@Sun.COM rts_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 14738348SEric.Yu@Sun.COM const void *optvalp, socklen_t optlen, cred_t *cr) 14748348SEric.Yu@Sun.COM { 14758348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14768348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 14778348SEric.Yu@Sun.COM int error; 14788348SEric.Yu@Sun.COM 14798348SEric.Yu@Sun.COM error = proto_opt_check(level, option_name, optlen, NULL, 14808348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_des_arr, 14818348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_arr_cnt, 14828348SEric.Yu@Sun.COM rts_opt_obj.odb_topmost_tpiprovider, 14838348SEric.Yu@Sun.COM B_TRUE, B_FALSE, cr); 14848348SEric.Yu@Sun.COM 14858348SEric.Yu@Sun.COM if (error != 0) { 14868348SEric.Yu@Sun.COM if (error < 0) 14878348SEric.Yu@Sun.COM error = proto_tlitosyserr(-error); 14888348SEric.Yu@Sun.COM return (error); 14898348SEric.Yu@Sun.COM } 14908348SEric.Yu@Sun.COM 14918348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 14928348SEric.Yu@Sun.COM error = rts_opt_set(connp, SETFN_OPTCOM_NEGOTIATE, level, option_name, 14938348SEric.Yu@Sun.COM optlen, (uchar_t *)optvalp, (uint_t *)&optlen, (uchar_t *)optvalp, 14948348SEric.Yu@Sun.COM NULL, cr); 14958348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 14968348SEric.Yu@Sun.COM 14978348SEric.Yu@Sun.COM ASSERT(error >= 0); 14988348SEric.Yu@Sun.COM 14998348SEric.Yu@Sun.COM return (error); 15008348SEric.Yu@Sun.COM } 15018348SEric.Yu@Sun.COM 15028348SEric.Yu@Sun.COM /* ARGSUSED */ 15038348SEric.Yu@Sun.COM static int 15048348SEric.Yu@Sun.COM rts_send(sock_lower_handle_t proto_handle, mblk_t *mp, 15058348SEric.Yu@Sun.COM struct nmsghdr *msg, cred_t *cr) 15068348SEric.Yu@Sun.COM { 15078348SEric.Yu@Sun.COM mblk_t *mp1; 15088348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 15098348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 15108348SEric.Yu@Sun.COM rt_msghdr_t *rtm; 15118348SEric.Yu@Sun.COM int error; 15128348SEric.Yu@Sun.COM 15138348SEric.Yu@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA); 15148348SEric.Yu@Sun.COM /* 15158348SEric.Yu@Sun.COM * The semantics of the routing socket is such that the rtm_pid 15168348SEric.Yu@Sun.COM * field is automatically filled in during requests with the 15178348SEric.Yu@Sun.COM * current process' pid. We do this here (where we still have 15188348SEric.Yu@Sun.COM * user context) after checking we have at least a message the 15198348SEric.Yu@Sun.COM * size of a routing message header. 15208348SEric.Yu@Sun.COM */ 15218348SEric.Yu@Sun.COM if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 15228348SEric.Yu@Sun.COM if (!pullupmsg(mp, sizeof (rt_msghdr_t))) { 15238348SEric.Yu@Sun.COM rts->rts_error = EINVAL; 15248348SEric.Yu@Sun.COM freemsg(mp); 15258348SEric.Yu@Sun.COM return (rts->rts_error); 15268348SEric.Yu@Sun.COM } 15278348SEric.Yu@Sun.COM } 15288348SEric.Yu@Sun.COM rtm = (rt_msghdr_t *)mp->b_rptr; 15298348SEric.Yu@Sun.COM rtm->rtm_pid = curproc->p_pid; 15308348SEric.Yu@Sun.COM 15318348SEric.Yu@Sun.COM mp1 = rts_ioctl_alloc(mp, DB_CRED(mp)); 15328348SEric.Yu@Sun.COM if (mp1 == NULL) { 15338348SEric.Yu@Sun.COM ASSERT(rts != NULL); 15348348SEric.Yu@Sun.COM freemsg(mp); 15358348SEric.Yu@Sun.COM return (ENOMEM); 15368348SEric.Yu@Sun.COM } 15378348SEric.Yu@Sun.COM 15388348SEric.Yu@Sun.COM /* 15398348SEric.Yu@Sun.COM * Allow only one outstanding request(ioctl) at any given time 15408348SEric.Yu@Sun.COM */ 15418348SEric.Yu@Sun.COM mutex_enter(&rts->rts_send_mutex); 15428348SEric.Yu@Sun.COM while (rts->rts_flag & RTS_REQ_PENDING) { 15438348SEric.Yu@Sun.COM int ret; 15448348SEric.Yu@Sun.COM 15458348SEric.Yu@Sun.COM ret = cv_wait_sig(&rts->rts_send_cv, &rts->rts_send_mutex); 15468348SEric.Yu@Sun.COM if (ret <= 0) { 15478348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 15488348SEric.Yu@Sun.COM freemsg(mp); 15498348SEric.Yu@Sun.COM return (EINTR); 15508348SEric.Yu@Sun.COM } 15518348SEric.Yu@Sun.COM } 15528348SEric.Yu@Sun.COM 15538348SEric.Yu@Sun.COM rts->rts_flag |= RTS_REQ_PENDING; 15548348SEric.Yu@Sun.COM 15558348SEric.Yu@Sun.COM rts->rts_flag |= RTS_REQ_INPROG; 15568348SEric.Yu@Sun.COM 15578348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 15588348SEric.Yu@Sun.COM 15598348SEric.Yu@Sun.COM CONN_INC_REF(connp); 15608348SEric.Yu@Sun.COM 15618348SEric.Yu@Sun.COM error = ip_rts_request_common(rts->rts_connp->conn_wq, mp1, connp, 15628348SEric.Yu@Sun.COM DB_CREDDEF(mp, connp->conn_cred)); 15638348SEric.Yu@Sun.COM 15648348SEric.Yu@Sun.COM mutex_enter(&rts->rts_send_mutex); 15658348SEric.Yu@Sun.COM if (error == EINPROGRESS) { 15668348SEric.Yu@Sun.COM ASSERT(rts->rts_flag & RTS_REQ_INPROG); 15678348SEric.Yu@Sun.COM if (rts->rts_flag & RTS_REQ_INPROG) { 15688348SEric.Yu@Sun.COM /* 15698348SEric.Yu@Sun.COM * Once the request has been issued we wait for 15708348SEric.Yu@Sun.COM * completion 15718348SEric.Yu@Sun.COM */ 15728348SEric.Yu@Sun.COM cv_wait(&rts->rts_io_cv, &rts->rts_send_mutex); 15738348SEric.Yu@Sun.COM error = rts->rts_error; 15748348SEric.Yu@Sun.COM } 15758348SEric.Yu@Sun.COM } 15768348SEric.Yu@Sun.COM 15778348SEric.Yu@Sun.COM ASSERT((error != 0) || !(rts->rts_flag & RTS_REQ_INPROG)); 15788348SEric.Yu@Sun.COM ASSERT(MUTEX_HELD(&rts->rts_send_mutex)); 15798348SEric.Yu@Sun.COM 15808348SEric.Yu@Sun.COM rts->rts_flag &= ~(RTS_REQ_PENDING | RTS_REQ_INPROG); 15818348SEric.Yu@Sun.COM cv_signal(&rts->rts_send_cv); 15828348SEric.Yu@Sun.COM mutex_exit(&rts->rts_send_mutex); 15838348SEric.Yu@Sun.COM return (error); 15848348SEric.Yu@Sun.COM } 15858348SEric.Yu@Sun.COM 15868348SEric.Yu@Sun.COM /* ARGSUSED */ 15878348SEric.Yu@Sun.COM sock_lower_handle_t 15888348SEric.Yu@Sun.COM rts_create(int family, int type, int proto, sock_downcalls_t **sock_downcalls, 15898348SEric.Yu@Sun.COM uint_t *smodep, int *errorp, int flags, cred_t *credp) 15908348SEric.Yu@Sun.COM { 15918348SEric.Yu@Sun.COM conn_t *connp; 15928348SEric.Yu@Sun.COM rts_t *rts; 15938348SEric.Yu@Sun.COM rts_stack_t *rtss; 15948348SEric.Yu@Sun.COM 15958348SEric.Yu@Sun.COM if (family != AF_ROUTE || type != SOCK_RAW || 15968348SEric.Yu@Sun.COM (proto != 0 && proto != AF_INET && proto != AF_INET6)) { 15978348SEric.Yu@Sun.COM *errorp = EPROTONOSUPPORT; 15988348SEric.Yu@Sun.COM return (NULL); 15998348SEric.Yu@Sun.COM } 16008348SEric.Yu@Sun.COM 16018348SEric.Yu@Sun.COM connp = rts_open(flags, credp); 16028348SEric.Yu@Sun.COM ASSERT(connp != NULL); 16038348SEric.Yu@Sun.COM connp->conn_flags |= IPCL_NONSTR; 16048348SEric.Yu@Sun.COM 16058348SEric.Yu@Sun.COM rts = connp->conn_rts; 16068348SEric.Yu@Sun.COM rtss = rts->rts_rtss; 16078348SEric.Yu@Sun.COM 16088348SEric.Yu@Sun.COM rts->rts_xmit_hiwat = rtss->rtss_xmit_hiwat; 16098348SEric.Yu@Sun.COM rts->rts_xmit_lowat = rtss->rtss_xmit_lowat; 16108348SEric.Yu@Sun.COM rts->rts_recv_hiwat = rtss->rtss_recv_hiwat; 16118348SEric.Yu@Sun.COM rts->rts_recv_lowat = rts_mod_info.mi_lowat; 16128348SEric.Yu@Sun.COM 16138348SEric.Yu@Sun.COM ASSERT(rtss->rtss_ldi_ident != NULL); 16148348SEric.Yu@Sun.COM 16158348SEric.Yu@Sun.COM *errorp = ip_create_helper_stream(connp, rtss->rtss_ldi_ident); 16168348SEric.Yu@Sun.COM if (*errorp != 0) { 16178348SEric.Yu@Sun.COM #ifdef DEBUG 16188348SEric.Yu@Sun.COM cmn_err(CE_CONT, "rts_create: create of IP helper stream" 16198348SEric.Yu@Sun.COM " failed\n"); 16208348SEric.Yu@Sun.COM #endif 16218348SEric.Yu@Sun.COM (void) rts_close((sock_lower_handle_t)connp, 0, credp); 16228348SEric.Yu@Sun.COM return (NULL); 16238348SEric.Yu@Sun.COM } 16248348SEric.Yu@Sun.COM 16258348SEric.Yu@Sun.COM mutex_enter(&connp->conn_lock); 16268348SEric.Yu@Sun.COM connp->conn_state_flags &= ~CONN_INCIPIENT; 16278348SEric.Yu@Sun.COM mutex_exit(&connp->conn_lock); 16288348SEric.Yu@Sun.COM 16298348SEric.Yu@Sun.COM *errorp = 0; 16308348SEric.Yu@Sun.COM *smodep = SM_ATOMIC; 16318348SEric.Yu@Sun.COM *sock_downcalls = &sock_rts_downcalls; 16328348SEric.Yu@Sun.COM return ((sock_lower_handle_t)connp); 16338348SEric.Yu@Sun.COM } 16348348SEric.Yu@Sun.COM 16358348SEric.Yu@Sun.COM /* ARGSUSED */ 16368348SEric.Yu@Sun.COM void 16378348SEric.Yu@Sun.COM rts_activate(sock_lower_handle_t proto_handle, sock_upper_handle_t sock_handle, 16388348SEric.Yu@Sun.COM sock_upcalls_t *sock_upcalls, int flags, cred_t *cr) 16398348SEric.Yu@Sun.COM { 16408348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 16418348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 16428348SEric.Yu@Sun.COM rts_stack_t *rtss = rts->rts_rtss; 16438348SEric.Yu@Sun.COM struct sock_proto_props sopp; 16448348SEric.Yu@Sun.COM 16458348SEric.Yu@Sun.COM connp->conn_upcalls = sock_upcalls; 16468348SEric.Yu@Sun.COM connp->conn_upper_handle = sock_handle; 16478348SEric.Yu@Sun.COM 16488348SEric.Yu@Sun.COM sopp.sopp_flags = SOCKOPT_WROFF | SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | 16498348SEric.Yu@Sun.COM SOCKOPT_MAXBLK | SOCKOPT_MAXPSZ | SOCKOPT_MINPSZ; 16508348SEric.Yu@Sun.COM sopp.sopp_wroff = 0; 16518348SEric.Yu@Sun.COM sopp.sopp_rxhiwat = rtss->rtss_recv_hiwat; 16528348SEric.Yu@Sun.COM sopp.sopp_rxlowat = rts_mod_info.mi_lowat; 16538348SEric.Yu@Sun.COM sopp.sopp_maxblk = INFPSZ; 16548348SEric.Yu@Sun.COM sopp.sopp_maxpsz = rts_mod_info.mi_maxpsz; 16558348SEric.Yu@Sun.COM sopp.sopp_minpsz = (rts_mod_info.mi_minpsz == 1) ? 0 : 16568348SEric.Yu@Sun.COM rts_mod_info.mi_minpsz; 16578348SEric.Yu@Sun.COM 16588348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_set_proto_props) 16598348SEric.Yu@Sun.COM (connp->conn_upper_handle, &sopp); 16608348SEric.Yu@Sun.COM 16618348SEric.Yu@Sun.COM /* 16628348SEric.Yu@Sun.COM * We treat it as already connected for routing socket. 16638348SEric.Yu@Sun.COM */ 16648348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_connected) 16658348SEric.Yu@Sun.COM (connp->conn_upper_handle, 0, NULL, -1); 16668348SEric.Yu@Sun.COM 16678348SEric.Yu@Sun.COM /* 16688348SEric.Yu@Sun.COM * Indicate the down IP module that this is a routing socket 16698348SEric.Yu@Sun.COM * client by sending an RTS IOCTL without any user data. Although 16708348SEric.Yu@Sun.COM * this is just a notification message (without any real routing 16718348SEric.Yu@Sun.COM * request), we pass in any credential for correctness sake. 16728348SEric.Yu@Sun.COM */ 16738348SEric.Yu@Sun.COM ip_rts_register(connp); 16748348SEric.Yu@Sun.COM } 16758348SEric.Yu@Sun.COM 16768348SEric.Yu@Sun.COM /* ARGSUSED */ 16778348SEric.Yu@Sun.COM int 16788348SEric.Yu@Sun.COM rts_close(sock_lower_handle_t proto_handle, int flags, 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 ASSERT(connp != NULL && IPCL_IS_RTS(connp)); 16838348SEric.Yu@Sun.COM return (rts_common_close(NULL, connp)); 16848348SEric.Yu@Sun.COM } 16858348SEric.Yu@Sun.COM 16868348SEric.Yu@Sun.COM /* ARGSUSED */ 16878348SEric.Yu@Sun.COM int 16888348SEric.Yu@Sun.COM rts_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr) 16898348SEric.Yu@Sun.COM { 16908348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 16918348SEric.Yu@Sun.COM 16928348SEric.Yu@Sun.COM /* shut down the send side */ 16938348SEric.Yu@Sun.COM if (how != SHUT_RD) 16948348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 16958348SEric.Yu@Sun.COM SOCK_OPCTL_SHUT_SEND, 0); 16968348SEric.Yu@Sun.COM /* shut down the recv side */ 16978348SEric.Yu@Sun.COM if (how != SHUT_WR) 16988348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 16998348SEric.Yu@Sun.COM SOCK_OPCTL_SHUT_RECV, 0); 17008348SEric.Yu@Sun.COM return (0); 17018348SEric.Yu@Sun.COM } 17028348SEric.Yu@Sun.COM 17038348SEric.Yu@Sun.COM void 17048348SEric.Yu@Sun.COM rts_clr_flowctrl(sock_lower_handle_t proto_handle) 17058348SEric.Yu@Sun.COM { 17068348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 17078348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 17088348SEric.Yu@Sun.COM 17098348SEric.Yu@Sun.COM mutex_enter(&rts->rts_recv_mutex); 17108348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_FALSE; 17118348SEric.Yu@Sun.COM mutex_exit(&rts->rts_recv_mutex); 17128348SEric.Yu@Sun.COM } 17138348SEric.Yu@Sun.COM 17148348SEric.Yu@Sun.COM int 17158348SEric.Yu@Sun.COM rts_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg, 17168348SEric.Yu@Sun.COM int mode, int32_t *rvalp, cred_t *cr) 17178348SEric.Yu@Sun.COM { 17188348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 17198348SEric.Yu@Sun.COM int error; 17208348SEric.Yu@Sun.COM 17218348SEric.Yu@Sun.COM switch (cmd) { 17228348SEric.Yu@Sun.COM case ND_SET: 17238348SEric.Yu@Sun.COM case ND_GET: 17248348SEric.Yu@Sun.COM case TI_GETPEERNAME: 17258348SEric.Yu@Sun.COM case TI_GETMYNAME: 17268348SEric.Yu@Sun.COM #ifdef DEUG 17278348SEric.Yu@Sun.COM cmn_err(CE_CONT, "rts_ioctl cmd 0x%x on non sreams" 17288348SEric.Yu@Sun.COM " socket", cmd); 17298348SEric.Yu@Sun.COM #endif 17308348SEric.Yu@Sun.COM error = EINVAL; 17318348SEric.Yu@Sun.COM break; 17328348SEric.Yu@Sun.COM default: 17338348SEric.Yu@Sun.COM /* 17348348SEric.Yu@Sun.COM * Pass on to IP using helper stream 17358348SEric.Yu@Sun.COM */ 17368444SRao.Shoaib@Sun.COM error = ldi_ioctl(connp->conn_helper_info->iphs_handle, 17378348SEric.Yu@Sun.COM cmd, arg, mode, cr, rvalp); 17388348SEric.Yu@Sun.COM break; 17398348SEric.Yu@Sun.COM } 17408348SEric.Yu@Sun.COM 17418348SEric.Yu@Sun.COM return (error); 17428348SEric.Yu@Sun.COM } 17438348SEric.Yu@Sun.COM 17448348SEric.Yu@Sun.COM sock_downcalls_t sock_rts_downcalls = { 17458348SEric.Yu@Sun.COM rts_activate, 17468348SEric.Yu@Sun.COM rts_accept, 17478348SEric.Yu@Sun.COM rts_bind, 17488348SEric.Yu@Sun.COM rts_listen, 17498348SEric.Yu@Sun.COM rts_connect, 17508348SEric.Yu@Sun.COM rts_getpeername, 17518348SEric.Yu@Sun.COM rts_getsockname, 17528348SEric.Yu@Sun.COM rts_getsockopt, 17538348SEric.Yu@Sun.COM rts_setsockopt, 17548348SEric.Yu@Sun.COM rts_send, 17558348SEric.Yu@Sun.COM NULL, 17568348SEric.Yu@Sun.COM NULL, 17578348SEric.Yu@Sun.COM NULL, 17588348SEric.Yu@Sun.COM rts_shutdown, 17598348SEric.Yu@Sun.COM rts_clr_flowctrl, 17608348SEric.Yu@Sun.COM rts_ioctl, 17618348SEric.Yu@Sun.COM rts_close 17628348SEric.Yu@Sun.COM }; 1763