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 * 760Sstevel@tonic-gate * Since all we do is reformat the messages between routing socket and 770Sstevel@tonic-gate * ioctl forms, no synchronization is necessary in this module; all 780Sstevel@tonic-gate * the dirty work is done down in ip. 790Sstevel@tonic-gate */ 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages */ 820Sstevel@tonic-gate static struct T_info_ack rts_g_t_info_ack = { 830Sstevel@tonic-gate T_INFO_ACK, 840Sstevel@tonic-gate T_INFINITE, /* TSDU_size. Maximum size messages. */ 850Sstevel@tonic-gate T_INVALID, /* ETSDU_size. No expedited data. */ 860Sstevel@tonic-gate T_INVALID, /* CDATA_size. No connect data. */ 870Sstevel@tonic-gate T_INVALID, /* DDATA_size. No disconnect data. */ 880Sstevel@tonic-gate 0, /* ADDR_size. */ 890Sstevel@tonic-gate 0, /* OPT_size - not initialized here */ 900Sstevel@tonic-gate 64 * 1024, /* TIDU_size. rts allows maximum size messages. */ 910Sstevel@tonic-gate T_COTS, /* SERV_type. rts supports connection oriented. */ 920Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from rts_state. */ 930Sstevel@tonic-gate (XPG4_1) /* PROVIDER_flag */ 940Sstevel@tonic-gate }; 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* 970Sstevel@tonic-gate * Table of ND variables supported by rts. These are loaded into rts_g_nd 980Sstevel@tonic-gate * in rts_open. 990Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 1000Sstevel@tonic-gate */ 1013448Sdh155122 static rtsparam_t lcl_param_arr[] = { 1020Sstevel@tonic-gate /* min max value name */ 1030Sstevel@tonic-gate { 4096, 65536, 8192, "rts_xmit_hiwat"}, 1040Sstevel@tonic-gate { 0, 65536, 1024, "rts_xmit_lowat"}, 1050Sstevel@tonic-gate { 4096, 65536, 8192, "rts_recv_hiwat"}, 1060Sstevel@tonic-gate { 65536, 1024*1024*1024, 256*1024, "rts_max_buf"}, 1070Sstevel@tonic-gate }; 1083448Sdh155122 #define rtss_xmit_hiwat rtss_params[0].rts_param_value 1093448Sdh155122 #define rtss_xmit_lowat rtss_params[1].rts_param_value 1103448Sdh155122 #define rtss_recv_hiwat rtss_params[2].rts_param_value 1115240Snordmark #define rtss_max_buf rtss_params[3].rts_param_value 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate static void rts_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, 1140Sstevel@tonic-gate int sys_error); 115*11042SErik.Nordmark@Sun.COM static void rts_input(void *, mblk_t *, void *, ip_recv_attr_t *); 116*11042SErik.Nordmark@Sun.COM static void rts_icmp_input(void *, mblk_t *, void *, ip_recv_attr_t *); 1178778SErik.Nordmark@Sun.COM static mblk_t *rts_ioctl_alloc(mblk_t *data); 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 * 1628778SErik.Nordmark@Sun.COM rts_ioctl_alloc(mblk_t *data) 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 1698778SErik.Nordmark@Sun.COM mp = allocb_tmpl(sizeof (ipllc_t), data); 1700Sstevel@tonic-gate if (mp == NULL) 1710Sstevel@tonic-gate return (NULL); 1728778SErik.Nordmark@Sun.COM mp1 = allocb_tmpl(sizeof (struct iocblk), data); 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); 214*11042SErik.Nordmark@Sun.COM } 2150Sstevel@tonic-gate 216*11042SErik.Nordmark@Sun.COM /* 217*11042SErik.Nordmark@Sun.COM * Now we are truly single threaded on this stream, and can 218*11042SErik.Nordmark@Sun.COM * delete the things hanging off the connp, and finally the connp. 219*11042SErik.Nordmark@Sun.COM * We removed this connp from the fanout list, it cannot be 220*11042SErik.Nordmark@Sun.COM * accessed thru the fanouts, and we already waited for the 221*11042SErik.Nordmark@Sun.COM * conn_ref to drop to 0. We are already in close, so 222*11042SErik.Nordmark@Sun.COM * there cannot be any other thread from the top. qprocsoff 223*11042SErik.Nordmark@Sun.COM * has completed, and service has completed or won't run in 224*11042SErik.Nordmark@Sun.COM * future. 225*11042SErik.Nordmark@Sun.COM */ 226*11042SErik.Nordmark@Sun.COM ASSERT(connp->conn_ref == 1); 227*11042SErik.Nordmark@Sun.COM 228*11042SErik.Nordmark@Sun.COM if (!IPCL_IS_NONSTR(connp)) { 2298348SEric.Yu@Sun.COM inet_minor_free(connp->conn_minor_arena, connp->conn_dev); 2308348SEric.Yu@Sun.COM } else { 2318477SRao.Shoaib@Sun.COM ip_free_helper_stream(connp); 2328348SEric.Yu@Sun.COM } 2335240Snordmark 2345240Snordmark connp->conn_ref--; 2355240Snordmark ipcl_conn_destroy(connp); 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; 2598348SEric.Yu@Sun.COM rts_t *rts; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* If the stream is already open, return immediately. */ 2620Sstevel@tonic-gate if (q->q_ptr != NULL) 2630Sstevel@tonic-gate return (0); 2640Sstevel@tonic-gate 2655240Snordmark if (sflag == MODOPEN) 2660Sstevel@tonic-gate return (EINVAL); 2670Sstevel@tonic-gate 2688348SEric.Yu@Sun.COM /* 2698348SEric.Yu@Sun.COM * Since RTS is not used so heavily, allocating from the small 2708348SEric.Yu@Sun.COM * arena should be sufficient. 2718348SEric.Yu@Sun.COM */ 2728348SEric.Yu@Sun.COM if ((conn_dev = inet_minor_alloc(ip_minor_arena_sa)) == 0) { 2738348SEric.Yu@Sun.COM return (EBUSY); 2748348SEric.Yu@Sun.COM } 2758348SEric.Yu@Sun.COM 2768348SEric.Yu@Sun.COM connp = rts_open(flag, credp); 2778348SEric.Yu@Sun.COM ASSERT(connp != NULL); 2788348SEric.Yu@Sun.COM 2798348SEric.Yu@Sun.COM *devp = makedevice(getemajor(*devp), (minor_t)conn_dev); 2808348SEric.Yu@Sun.COM 2818348SEric.Yu@Sun.COM rts = connp->conn_rts; 2828348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 2838348SEric.Yu@Sun.COM connp->conn_dev = conn_dev; 2848348SEric.Yu@Sun.COM connp->conn_minor_arena = ip_minor_arena_sa; 2858348SEric.Yu@Sun.COM 2868348SEric.Yu@Sun.COM q->q_ptr = connp; 2878348SEric.Yu@Sun.COM WR(q)->q_ptr = connp; 2888348SEric.Yu@Sun.COM connp->conn_rq = q; 2898348SEric.Yu@Sun.COM connp->conn_wq = WR(q); 2908348SEric.Yu@Sun.COM 291*11042SErik.Nordmark@Sun.COM WR(q)->q_hiwat = connp->conn_sndbuf; 292*11042SErik.Nordmark@Sun.COM WR(q)->q_lowat = connp->conn_sndlowat; 2938348SEric.Yu@Sun.COM 2948348SEric.Yu@Sun.COM mutex_enter(&connp->conn_lock); 2958348SEric.Yu@Sun.COM connp->conn_state_flags &= ~CONN_INCIPIENT; 2968348SEric.Yu@Sun.COM mutex_exit(&connp->conn_lock); 297*11042SErik.Nordmark@Sun.COM rw_exit(&rts->rts_rwlock); 298*11042SErik.Nordmark@Sun.COM 299*11042SErik.Nordmark@Sun.COM /* Indicate to IP that this is a routing socket client */ 300*11042SErik.Nordmark@Sun.COM ip_rts_register(connp); 3018348SEric.Yu@Sun.COM 3028348SEric.Yu@Sun.COM qprocson(q); 3038348SEric.Yu@Sun.COM 3048348SEric.Yu@Sun.COM return (0); 3058348SEric.Yu@Sun.COM } 3068348SEric.Yu@Sun.COM 3078348SEric.Yu@Sun.COM /* ARGSUSED */ 3088348SEric.Yu@Sun.COM static conn_t * 3098348SEric.Yu@Sun.COM rts_open(int flag, cred_t *credp) 3108348SEric.Yu@Sun.COM { 3118348SEric.Yu@Sun.COM netstack_t *ns; 3128348SEric.Yu@Sun.COM rts_stack_t *rtss; 3138348SEric.Yu@Sun.COM rts_t *rts; 3148348SEric.Yu@Sun.COM conn_t *connp; 3158348SEric.Yu@Sun.COM zoneid_t zoneid; 3168348SEric.Yu@Sun.COM 3173448Sdh155122 ns = netstack_find_by_cred(credp); 3183448Sdh155122 ASSERT(ns != NULL); 3193448Sdh155122 rtss = ns->netstack_rts; 3203448Sdh155122 ASSERT(rtss != NULL); 3213448Sdh155122 3225240Snordmark /* 3235240Snordmark * For exclusive stacks we set the zoneid to zero 3245240Snordmark * to make RTS operate as if in the global zone. 3255240Snordmark */ 3265240Snordmark if (ns->netstack_stackid != GLOBAL_NETSTACKID) 3275240Snordmark zoneid = GLOBAL_ZONEID; 3285240Snordmark else 3295240Snordmark zoneid = crgetzoneid(credp); 3305240Snordmark 3315240Snordmark connp = ipcl_conn_create(IPCL_RTSCONN, KM_SLEEP, ns); 3325240Snordmark rts = connp->conn_rts; 3335240Snordmark 3345240Snordmark /* 3355240Snordmark * ipcl_conn_create did a netstack_hold. Undo the hold that was 3365240Snordmark * done by netstack_find_by_cred() 3375240Snordmark */ 3385240Snordmark netstack_rele(ns); 3395240Snordmark 3405240Snordmark rw_enter(&rts->rts_rwlock, RW_WRITER); 3415240Snordmark ASSERT(connp->conn_rts == rts); 3425240Snordmark ASSERT(rts->rts_connp == connp); 3435240Snordmark 344*11042SErik.Nordmark@Sun.COM connp->conn_ixa->ixa_flags |= IXAF_MULTICAST_LOOP | IXAF_SET_ULP_CKSUM; 345*11042SErik.Nordmark@Sun.COM /* conn_allzones can not be set this early, hence no IPCL_ZONEID */ 346*11042SErik.Nordmark@Sun.COM connp->conn_ixa->ixa_zoneid = zoneid; 3475240Snordmark connp->conn_zoneid = zoneid; 3488348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_FALSE; 3495240Snordmark 350*11042SErik.Nordmark@Sun.COM rts->rts_rtss = rtss; 3510Sstevel@tonic-gate 352*11042SErik.Nordmark@Sun.COM connp->conn_rcvbuf = rtss->rtss_recv_hiwat; 353*11042SErik.Nordmark@Sun.COM connp->conn_sndbuf = rtss->rtss_xmit_hiwat; 354*11042SErik.Nordmark@Sun.COM connp->conn_sndlowat = rtss->rtss_xmit_lowat; 355*11042SErik.Nordmark@Sun.COM connp->conn_rcvlowat = rts_mod_info.mi_lowat; 356*11042SErik.Nordmark@Sun.COM 357*11042SErik.Nordmark@Sun.COM connp->conn_family = PF_ROUTE; 358*11042SErik.Nordmark@Sun.COM connp->conn_so_type = SOCK_RAW; 359*11042SErik.Nordmark@Sun.COM /* SO_PROTOTYPE is always sent down by sockfs setting conn_proto */ 3605240Snordmark 3615240Snordmark connp->conn_recv = rts_input; 362*11042SErik.Nordmark@Sun.COM connp->conn_recvicmp = rts_icmp_input; 363*11042SErik.Nordmark@Sun.COM 3645240Snordmark crhold(credp); 3655240Snordmark connp->conn_cred = credp; 366*11042SErik.Nordmark@Sun.COM connp->conn_cpid = curproc->p_pid; 367*11042SErik.Nordmark@Sun.COM /* Cache things in ixa without an extra refhold */ 368*11042SErik.Nordmark@Sun.COM connp->conn_ixa->ixa_cred = connp->conn_cred; 369*11042SErik.Nordmark@Sun.COM connp->conn_ixa->ixa_cpid = connp->conn_cpid; 370*11042SErik.Nordmark@Sun.COM if (is_system_labeled()) 371*11042SErik.Nordmark@Sun.COM connp->conn_ixa->ixa_tsl = crgetlabel(connp->conn_cred); 3725240Snordmark 3738348SEric.Yu@Sun.COM /* 3748348SEric.Yu@Sun.COM * rts sockets start out as bound and connected 3758348SEric.Yu@Sun.COM * For streams based sockets, socket state is set to 3768348SEric.Yu@Sun.COM * SS_ISBOUND | SS_ISCONNECTED in so_strinit. 3778348SEric.Yu@Sun.COM */ 3788348SEric.Yu@Sun.COM rts->rts_state = TS_DATA_XFER; 3795240Snordmark rw_exit(&rts->rts_rwlock); 3805240Snordmark 3818348SEric.Yu@Sun.COM return (connp); 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate /* 3850Sstevel@tonic-gate * This routine creates a T_ERROR_ACK message and passes it upstream. 3860Sstevel@tonic-gate */ 3870Sstevel@tonic-gate static void 3880Sstevel@tonic-gate rts_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error) 3890Sstevel@tonic-gate { 3900Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 3910Sstevel@tonic-gate qreply(q, mp); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * This routine creates a T_OK_ACK message and passes it upstream. 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gate static void 3980Sstevel@tonic-gate rts_ok_ack(queue_t *q, mblk_t *mp) 3990Sstevel@tonic-gate { 4000Sstevel@tonic-gate if ((mp = mi_tpi_ok_ack_alloc(mp)) != NULL) 4010Sstevel@tonic-gate qreply(q, mp); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate /* 4050Sstevel@tonic-gate * This routine is called by rts_wput to handle T_UNBIND_REQ messages. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate static void 4088348SEric.Yu@Sun.COM rts_tpi_unbind(queue_t *q, mblk_t *mp) 4090Sstevel@tonic-gate { 4105240Snordmark conn_t *connp = Q_TO_CONN(q); 4115240Snordmark rts_t *rts = connp->conn_rts; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate /* If a bind has not been done, we can't unbind. */ 4140Sstevel@tonic-gate if (rts->rts_state != TS_IDLE) { 4150Sstevel@tonic-gate rts_err_ack(q, mp, TOUTSTATE, 0); 4160Sstevel@tonic-gate return; 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate rts->rts_state = TS_UNBND; 4190Sstevel@tonic-gate rts_ok_ack(q, mp); 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * This routine is called to handle each 4240Sstevel@tonic-gate * O_T_BIND_REQ/T_BIND_REQ message passed to 4250Sstevel@tonic-gate * rts_wput. Note: This routine works with both 4260Sstevel@tonic-gate * O_T_BIND_REQ and T_BIND_REQ semantics. 4270Sstevel@tonic-gate */ 4280Sstevel@tonic-gate static void 4298348SEric.Yu@Sun.COM rts_tpi_bind(queue_t *q, mblk_t *mp) 4300Sstevel@tonic-gate { 4315240Snordmark conn_t *connp = Q_TO_CONN(q); 4325240Snordmark rts_t *rts = connp->conn_rts; 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 tbr = (struct T_bind_req *)mp->b_rptr; 4480Sstevel@tonic-gate if (tbr->ADDR_length != 0) { 4490Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 4508348SEric.Yu@Sun.COM "rts_tpi_bind: bad ADDR_length %d", tbr->ADDR_length); 4510Sstevel@tonic-gate rts_err_ack(q, mp, TBADADDR, 0); 4520Sstevel@tonic-gate return; 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate /* Generic request */ 4550Sstevel@tonic-gate tbr->ADDR_offset = (t_scalar_t)sizeof (struct T_bind_req); 4560Sstevel@tonic-gate tbr->ADDR_length = 0; 4570Sstevel@tonic-gate tbr->PRIM_type = T_BIND_ACK; 458*11042SErik.Nordmark@Sun.COM mp->b_datap->db_type = M_PCPROTO; 4590Sstevel@tonic-gate rts->rts_state = TS_IDLE; 4600Sstevel@tonic-gate qreply(q, mp); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate static void 4640Sstevel@tonic-gate rts_copy_info(struct T_info_ack *tap, rts_t *rts) 4650Sstevel@tonic-gate { 4660Sstevel@tonic-gate *tap = rts_g_t_info_ack; 4670Sstevel@tonic-gate tap->CURRENT_state = rts->rts_state; 4680Sstevel@tonic-gate tap->OPT_size = rts_max_optsize; 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 4730Sstevel@tonic-gate * rts_wput. Much of the T_CAPABILITY_ACK information is copied from 4740Sstevel@tonic-gate * rts_g_t_info_ack. The current state of the stream is copied from 4750Sstevel@tonic-gate * rts_state. 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate static void 4780Sstevel@tonic-gate rts_capability_req(queue_t *q, mblk_t *mp) 4790Sstevel@tonic-gate { 4805240Snordmark conn_t *connp = Q_TO_CONN(q); 4815240Snordmark rts_t *rts = connp->conn_rts; 4820Sstevel@tonic-gate t_uscalar_t cap_bits1; 4830Sstevel@tonic-gate struct T_capability_ack *tcap; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 4885240Snordmark mp->b_datap->db_type, T_CAPABILITY_ACK); 4890Sstevel@tonic-gate if (mp == NULL) 4900Sstevel@tonic-gate return; 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr; 4930Sstevel@tonic-gate tcap->CAP_bits1 = 0; 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 4960Sstevel@tonic-gate rts_copy_info(&tcap->INFO_ack, rts); 4970Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate qreply(q, mp); 5010Sstevel@tonic-gate } 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate /* 5040Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by rts_wput. 5050Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from rts_g_t_info_ack. 5060Sstevel@tonic-gate * The current state of the stream is copied from rts_state. 5070Sstevel@tonic-gate */ 5080Sstevel@tonic-gate static void 5090Sstevel@tonic-gate rts_info_req(queue_t *q, mblk_t *mp) 5100Sstevel@tonic-gate { 5115240Snordmark conn_t *connp = Q_TO_CONN(q); 5125240Snordmark rts_t *rts = connp->conn_rts; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (rts_g_t_info_ack), M_PCPROTO, 5150Sstevel@tonic-gate T_INFO_ACK); 5160Sstevel@tonic-gate if (mp == NULL) 5170Sstevel@tonic-gate return; 5180Sstevel@tonic-gate rts_copy_info((struct T_info_ack *)mp->b_rptr, rts); 5190Sstevel@tonic-gate qreply(q, mp); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate /* 5230Sstevel@tonic-gate * This routine gets default values of certain options whose default 5240Sstevel@tonic-gate * values are maintained by protcol specific code 5250Sstevel@tonic-gate */ 5260Sstevel@tonic-gate /* ARGSUSED */ 5270Sstevel@tonic-gate int 5280Sstevel@tonic-gate rts_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 5290Sstevel@tonic-gate { 5300Sstevel@tonic-gate /* no default value processed by protocol specific code currently */ 5310Sstevel@tonic-gate return (-1); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5348348SEric.Yu@Sun.COM 5358348SEric.Yu@Sun.COM static int 5368348SEric.Yu@Sun.COM rts_opt_get(conn_t *connp, int level, int name, uchar_t *ptr) 5370Sstevel@tonic-gate { 5388348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 539*11042SErik.Nordmark@Sun.COM conn_opt_arg_t coas; 540*11042SErik.Nordmark@Sun.COM int retval; 5418348SEric.Yu@Sun.COM 5428348SEric.Yu@Sun.COM ASSERT(RW_READ_HELD(&rts->rts_rwlock)); 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate switch (level) { 545*11042SErik.Nordmark@Sun.COM /* do this in conn_opt_get? */ 5468485SPeter.Memishian@Sun.COM case SOL_ROUTE: 5478485SPeter.Memishian@Sun.COM switch (name) { 5488485SPeter.Memishian@Sun.COM case RT_AWARE: 5498485SPeter.Memishian@Sun.COM mutex_enter(&connp->conn_lock); 550*11042SErik.Nordmark@Sun.COM *(int *)ptr = connp->conn_rtaware; 5518485SPeter.Memishian@Sun.COM mutex_exit(&connp->conn_lock); 552*11042SErik.Nordmark@Sun.COM return (0); 5538485SPeter.Memishian@Sun.COM } 5548485SPeter.Memishian@Sun.COM break; 5550Sstevel@tonic-gate } 556*11042SErik.Nordmark@Sun.COM coas.coa_connp = connp; 557*11042SErik.Nordmark@Sun.COM coas.coa_ixa = connp->conn_ixa; 558*11042SErik.Nordmark@Sun.COM coas.coa_ipp = &connp->conn_xmit_ipp; 559*11042SErik.Nordmark@Sun.COM mutex_enter(&connp->conn_lock); 560*11042SErik.Nordmark@Sun.COM retval = conn_opt_get(&coas, level, name, ptr); 561*11042SErik.Nordmark@Sun.COM mutex_exit(&connp->conn_lock); 562*11042SErik.Nordmark@Sun.COM return (retval); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5658348SEric.Yu@Sun.COM /* ARGSUSED */ 5668348SEric.Yu@Sun.COM static int 5678348SEric.Yu@Sun.COM rts_do_opt_set(conn_t *connp, int level, int name, uint_t inlen, 5688348SEric.Yu@Sun.COM uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, cred_t *cr, 5698348SEric.Yu@Sun.COM void *thisdg_attrs, boolean_t checkonly) 5700Sstevel@tonic-gate { 5710Sstevel@tonic-gate int *i1 = (int *)invalp; 5725240Snordmark rts_t *rts = connp->conn_rts; 5733448Sdh155122 rts_stack_t *rtss = rts->rts_rtss; 574*11042SErik.Nordmark@Sun.COM int error; 575*11042SErik.Nordmark@Sun.COM conn_opt_arg_t coas; 576*11042SErik.Nordmark@Sun.COM 577*11042SErik.Nordmark@Sun.COM coas.coa_connp = connp; 578*11042SErik.Nordmark@Sun.COM coas.coa_ixa = connp->conn_ixa; 579*11042SErik.Nordmark@Sun.COM coas.coa_ipp = &connp->conn_xmit_ipp; 5800Sstevel@tonic-gate 5818348SEric.Yu@Sun.COM ASSERT(RW_WRITE_HELD(&rts->rts_rwlock)); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * For rts, we should have no ancillary data sent down 5850Sstevel@tonic-gate * (rts_wput doesn't handle options). 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate ASSERT(thisdg_attrs == NULL); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate /* 5900Sstevel@tonic-gate * For fixed length options, no sanity check 5910Sstevel@tonic-gate * of passed in length is done. It is assumed *_optcom_req() 5920Sstevel@tonic-gate * routines do the right thing. 5930Sstevel@tonic-gate */ 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate switch (level) { 5960Sstevel@tonic-gate case SOL_SOCKET: 5970Sstevel@tonic-gate switch (name) { 5980Sstevel@tonic-gate case SO_PROTOTYPE: 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * Routing socket applications that call socket() with 6010Sstevel@tonic-gate * a third argument can filter which messages will be 6020Sstevel@tonic-gate * sent upstream thanks to sockfs. so_socket() sends 6030Sstevel@tonic-gate * down the SO_PROTOTYPE and rts_queue_input() 6040Sstevel@tonic-gate * implements the filtering. 6050Sstevel@tonic-gate */ 606*11042SErik.Nordmark@Sun.COM if (*i1 != AF_INET && *i1 != AF_INET6) { 607*11042SErik.Nordmark@Sun.COM *outlenp = 0; 6080Sstevel@tonic-gate return (EPROTONOSUPPORT); 609*11042SErik.Nordmark@Sun.COM } 610*11042SErik.Nordmark@Sun.COM if (!checkonly) 6118552SRao.Shoaib@Sun.COM connp->conn_proto = *i1; 612*11042SErik.Nordmark@Sun.COM *outlenp = inlen; 613*11042SErik.Nordmark@Sun.COM return (0); 614*11042SErik.Nordmark@Sun.COM 6150Sstevel@tonic-gate /* 6160Sstevel@tonic-gate * The following two items can be manipulated, 6170Sstevel@tonic-gate * but changing them should do nothing. 6180Sstevel@tonic-gate */ 6190Sstevel@tonic-gate case SO_SNDBUF: 6203448Sdh155122 if (*i1 > rtss->rtss_max_buf) { 6210Sstevel@tonic-gate *outlenp = 0; 6220Sstevel@tonic-gate return (ENOBUFS); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6250Sstevel@tonic-gate case SO_RCVBUF: 6263448Sdh155122 if (*i1 > rtss->rtss_max_buf) { 6270Sstevel@tonic-gate *outlenp = 0; 6280Sstevel@tonic-gate return (ENOBUFS); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate break; 6338485SPeter.Memishian@Sun.COM case SOL_ROUTE: 6348485SPeter.Memishian@Sun.COM switch (name) { 6358485SPeter.Memishian@Sun.COM case RT_AWARE: 6368485SPeter.Memishian@Sun.COM if (!checkonly) { 6378485SPeter.Memishian@Sun.COM mutex_enter(&connp->conn_lock); 6388485SPeter.Memishian@Sun.COM connp->conn_rtaware = *i1; 6398485SPeter.Memishian@Sun.COM mutex_exit(&connp->conn_lock); 6408485SPeter.Memishian@Sun.COM } 641*11042SErik.Nordmark@Sun.COM *outlenp = inlen; 642*11042SErik.Nordmark@Sun.COM return (0); 6438485SPeter.Memishian@Sun.COM } 6448485SPeter.Memishian@Sun.COM break; 645*11042SErik.Nordmark@Sun.COM } 646*11042SErik.Nordmark@Sun.COM /* Serialized setsockopt since we are D_MTQPAIR */ 647*11042SErik.Nordmark@Sun.COM error = conn_opt_set(&coas, level, name, inlen, invalp, 648*11042SErik.Nordmark@Sun.COM checkonly, cr); 649*11042SErik.Nordmark@Sun.COM if (error != 0) { 6500Sstevel@tonic-gate *outlenp = 0; 651*11042SErik.Nordmark@Sun.COM return (error); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate /* 6540Sstevel@tonic-gate * Common case of return from an option that is sizeof (int) 6550Sstevel@tonic-gate */ 6568348SEric.Yu@Sun.COM if (invalp != outvalp) { 6578348SEric.Yu@Sun.COM /* don't trust bcopy for identical src/dst */ 6588348SEric.Yu@Sun.COM (void) bcopy(invalp, outvalp, inlen); 6598348SEric.Yu@Sun.COM } 6600Sstevel@tonic-gate *outlenp = (t_uscalar_t)sizeof (int); 6610Sstevel@tonic-gate return (0); 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 6648348SEric.Yu@Sun.COM static int 6658348SEric.Yu@Sun.COM rts_opt_set(conn_t *connp, uint_t optset_context, int level, int name, 6668348SEric.Yu@Sun.COM uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp, 6678348SEric.Yu@Sun.COM void *thisdg_attrs, cred_t *cr) 6688348SEric.Yu@Sun.COM { 6698348SEric.Yu@Sun.COM boolean_t checkonly = B_FALSE; 6708348SEric.Yu@Sun.COM 6718348SEric.Yu@Sun.COM if (optset_context) { 6728348SEric.Yu@Sun.COM switch (optset_context) { 6738348SEric.Yu@Sun.COM case SETFN_OPTCOM_CHECKONLY: 6748348SEric.Yu@Sun.COM checkonly = B_TRUE; 6758348SEric.Yu@Sun.COM /* 6768348SEric.Yu@Sun.COM * Note: Implies T_CHECK semantics for T_OPTCOM_REQ 6778348SEric.Yu@Sun.COM * inlen != 0 implies value supplied and 6788348SEric.Yu@Sun.COM * we have to "pretend" to set it. 6798348SEric.Yu@Sun.COM * inlen == 0 implies that there is no value part 6808348SEric.Yu@Sun.COM * in T_CHECK request and just validation 6818348SEric.Yu@Sun.COM * done elsewhere should be enough, we just return here. 6828348SEric.Yu@Sun.COM */ 6838348SEric.Yu@Sun.COM if (inlen == 0) { 6848348SEric.Yu@Sun.COM *outlenp = 0; 6858348SEric.Yu@Sun.COM return (0); 6868348SEric.Yu@Sun.COM } 6878348SEric.Yu@Sun.COM break; 6888348SEric.Yu@Sun.COM case SETFN_OPTCOM_NEGOTIATE: 6898348SEric.Yu@Sun.COM checkonly = B_FALSE; 6908348SEric.Yu@Sun.COM break; 6918348SEric.Yu@Sun.COM case SETFN_UD_NEGOTIATE: 6928348SEric.Yu@Sun.COM case SETFN_CONN_NEGOTIATE: 6938348SEric.Yu@Sun.COM checkonly = B_FALSE; 6948348SEric.Yu@Sun.COM /* 6958348SEric.Yu@Sun.COM * Negotiating local and "association-related" options 6968348SEric.Yu@Sun.COM * through T_UNITDATA_REQ or T_CONN_{REQ,CON} 6978348SEric.Yu@Sun.COM * Not allowed in this module. 6988348SEric.Yu@Sun.COM */ 6998348SEric.Yu@Sun.COM return (EINVAL); 7008348SEric.Yu@Sun.COM default: 7018348SEric.Yu@Sun.COM /* 7028348SEric.Yu@Sun.COM * We should never get here 7038348SEric.Yu@Sun.COM */ 7048348SEric.Yu@Sun.COM *outlenp = 0; 7058348SEric.Yu@Sun.COM return (EINVAL); 7068348SEric.Yu@Sun.COM } 7078348SEric.Yu@Sun.COM 7088348SEric.Yu@Sun.COM ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) || 7098348SEric.Yu@Sun.COM (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0)); 7108348SEric.Yu@Sun.COM 7118348SEric.Yu@Sun.COM } 7128348SEric.Yu@Sun.COM return (rts_do_opt_set(connp, level, name, inlen, invalp, outlenp, 7138348SEric.Yu@Sun.COM outvalp, cr, thisdg_attrs, checkonly)); 7148348SEric.Yu@Sun.COM 7158348SEric.Yu@Sun.COM } 7168348SEric.Yu@Sun.COM 7178348SEric.Yu@Sun.COM /* 7188348SEric.Yu@Sun.COM * This routine retrieves the current status of socket options. 7198348SEric.Yu@Sun.COM * It returns the size of the option retrieved. 7208348SEric.Yu@Sun.COM */ 7218348SEric.Yu@Sun.COM int 7228348SEric.Yu@Sun.COM rts_tpi_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 7238348SEric.Yu@Sun.COM { 7248348SEric.Yu@Sun.COM rts_t *rts; 7258348SEric.Yu@Sun.COM int err; 7268348SEric.Yu@Sun.COM 7278348SEric.Yu@Sun.COM rts = Q_TO_RTS(q); 7288348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_READER); 7298348SEric.Yu@Sun.COM err = rts_opt_get(Q_TO_CONN(q), level, name, ptr); 7308348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 7318348SEric.Yu@Sun.COM return (err); 7328348SEric.Yu@Sun.COM } 7338348SEric.Yu@Sun.COM 7348348SEric.Yu@Sun.COM /* 7358348SEric.Yu@Sun.COM * This routine sets socket options. 7368348SEric.Yu@Sun.COM */ 7378348SEric.Yu@Sun.COM /*ARGSUSED*/ 7388348SEric.Yu@Sun.COM int 7398348SEric.Yu@Sun.COM rts_tpi_opt_set(queue_t *q, uint_t optset_context, int level, 7408348SEric.Yu@Sun.COM int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp, 741*11042SErik.Nordmark@Sun.COM uchar_t *outvalp, void *thisdg_attrs, cred_t *cr) 7428348SEric.Yu@Sun.COM { 7438348SEric.Yu@Sun.COM conn_t *connp = Q_TO_CONN(q); 7448348SEric.Yu@Sun.COM int error; 7458348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 7468348SEric.Yu@Sun.COM 7478348SEric.Yu@Sun.COM 7488348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 7498348SEric.Yu@Sun.COM error = rts_opt_set(connp, optset_context, level, name, inlen, invalp, 7508348SEric.Yu@Sun.COM outlenp, outvalp, thisdg_attrs, cr); 7518348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 7528348SEric.Yu@Sun.COM return (error); 7538348SEric.Yu@Sun.COM } 7548348SEric.Yu@Sun.COM 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * This routine retrieves the value of an ND variable in a rtsparam_t 7570Sstevel@tonic-gate * structure. It is called through nd_getset when a user reads the 7580Sstevel@tonic-gate * variable. 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate /* ARGSUSED */ 7610Sstevel@tonic-gate static int 7620Sstevel@tonic-gate rts_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 7630Sstevel@tonic-gate { 7640Sstevel@tonic-gate rtsparam_t *rtspa = (rtsparam_t *)cp; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", rtspa->rts_param_value); 7670Sstevel@tonic-gate return (0); 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate /* 7710Sstevel@tonic-gate * Walk through the param array specified registering each element with the 7720Sstevel@tonic-gate * named dispatch (ND) handler. 7730Sstevel@tonic-gate */ 7740Sstevel@tonic-gate static boolean_t 7753448Sdh155122 rts_param_register(IDP *ndp, rtsparam_t *rtspa, int cnt) 7760Sstevel@tonic-gate { 7770Sstevel@tonic-gate for (; cnt-- > 0; rtspa++) { 7780Sstevel@tonic-gate if (rtspa->rts_param_name != NULL && rtspa->rts_param_name[0]) { 7793448Sdh155122 if (!nd_load(ndp, rtspa->rts_param_name, 7800Sstevel@tonic-gate rts_param_get, rts_param_set, (caddr_t)rtspa)) { 7813448Sdh155122 nd_free(ndp); 7820Sstevel@tonic-gate return (B_FALSE); 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate return (B_TRUE); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate /* This routine sets an ND variable in a rtsparam_t structure. */ 7900Sstevel@tonic-gate /* ARGSUSED */ 7910Sstevel@tonic-gate static int 7920Sstevel@tonic-gate rts_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 7930Sstevel@tonic-gate { 7940Sstevel@tonic-gate ulong_t new_value; 7950Sstevel@tonic-gate rtsparam_t *rtspa = (rtsparam_t *)cp; 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate /* 7980Sstevel@tonic-gate * Fail the request if the new value does not lie within the 7990Sstevel@tonic-gate * required bounds. 8000Sstevel@tonic-gate */ 8010Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 8020Sstevel@tonic-gate new_value < rtspa->rts_param_min || 8030Sstevel@tonic-gate new_value > rtspa->rts_param_max) { 8040Sstevel@tonic-gate return (EINVAL); 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate /* Set the new value */ 8080Sstevel@tonic-gate rtspa->rts_param_value = new_value; 8090Sstevel@tonic-gate return (0); 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate /* 8135240Snordmark * Empty rsrv routine which is used by rts_input to cause a wakeup 8145240Snordmark * of a thread in qwait. 8155240Snordmark */ 8165240Snordmark /*ARGSUSED*/ 8175240Snordmark static void 8185240Snordmark rts_rsrv(queue_t *q) 8195240Snordmark { 8205240Snordmark } 8215240Snordmark 8225240Snordmark /* 8230Sstevel@tonic-gate * This routine handles synchronous messages passed downstream. It either 8240Sstevel@tonic-gate * consumes the message or passes it downstream; it never queues a 8250Sstevel@tonic-gate * a message. The data messages that go down are wrapped in an IOCTL 8260Sstevel@tonic-gate * message. 8270Sstevel@tonic-gate * 8280Sstevel@tonic-gate * Since it is synchronous, it waits for the M_IOCACK/M_IOCNAK so that 8290Sstevel@tonic-gate * it can return an immediate error (such as ENETUNREACH when adding a route). 8300Sstevel@tonic-gate * It uses the RTS_WRW_PENDING to ensure that each rts instance has only 8310Sstevel@tonic-gate * one M_IOCTL outstanding at any given time. 8320Sstevel@tonic-gate */ 8330Sstevel@tonic-gate static int 8340Sstevel@tonic-gate rts_wrw(queue_t *q, struiod_t *dp) 8350Sstevel@tonic-gate { 8360Sstevel@tonic-gate mblk_t *mp = dp->d_mp; 8370Sstevel@tonic-gate mblk_t *mp1; 8380Sstevel@tonic-gate int error; 8390Sstevel@tonic-gate rt_msghdr_t *rtm; 8405240Snordmark conn_t *connp = Q_TO_CONN(q); 8415240Snordmark rts_t *rts = connp->conn_rts; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate while (rts->rts_flag & RTS_WRW_PENDING) { 8440Sstevel@tonic-gate if (qwait_rw(q)) { 8450Sstevel@tonic-gate rts->rts_error = EINTR; 8460Sstevel@tonic-gate goto err_ret; 8470Sstevel@tonic-gate } 8488348SEric.Yu@Sun.COM } 8490Sstevel@tonic-gate rts->rts_flag |= RTS_WRW_PENDING; 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate if (isuioq(q) && (error = struioget(q, mp, dp, 0))) { 8520Sstevel@tonic-gate /* 8530Sstevel@tonic-gate * Uio error of some sort, so just return the error. 8540Sstevel@tonic-gate */ 8550Sstevel@tonic-gate rts->rts_error = error; 8560Sstevel@tonic-gate goto err_ret; 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate /* 8590Sstevel@tonic-gate * Pass the mblk (chain) onto wput(). 8600Sstevel@tonic-gate */ 8610Sstevel@tonic-gate dp->d_mp = 0; 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate switch (mp->b_datap->db_type) { 8640Sstevel@tonic-gate case M_PROTO: 8650Sstevel@tonic-gate case M_PCPROTO: 8660Sstevel@tonic-gate /* Expedite other than T_DATA_REQ to below the switch */ 8670Sstevel@tonic-gate if (((mp->b_wptr - mp->b_rptr) != 8680Sstevel@tonic-gate sizeof (struct T_data_req)) || 8690Sstevel@tonic-gate (((union T_primitives *)mp->b_rptr)->type != T_DATA_REQ)) 8700Sstevel@tonic-gate break; 8710Sstevel@tonic-gate if ((mp1 = mp->b_cont) == NULL) { 8720Sstevel@tonic-gate rts->rts_error = EINVAL; 8738752SPeter.Memishian@Sun.COM freemsg(mp); 8740Sstevel@tonic-gate goto err_ret; 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate freeb(mp); 8770Sstevel@tonic-gate mp = mp1; 8780Sstevel@tonic-gate /* FALLTHRU */ 8790Sstevel@tonic-gate case M_DATA: 8800Sstevel@tonic-gate /* 8810Sstevel@tonic-gate * The semantics of the routing socket is such that the rtm_pid 8820Sstevel@tonic-gate * field is automatically filled in during requests with the 8830Sstevel@tonic-gate * current process' pid. We do this here (where we still have 8840Sstevel@tonic-gate * user context) after checking we have at least a message the 8850Sstevel@tonic-gate * size of a routing message header. 8860Sstevel@tonic-gate */ 8870Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 8880Sstevel@tonic-gate if (!pullupmsg(mp, sizeof (rt_msghdr_t))) { 8890Sstevel@tonic-gate rts->rts_error = EINVAL; 8908752SPeter.Memishian@Sun.COM freemsg(mp); 8910Sstevel@tonic-gate goto err_ret; 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate rtm = (rt_msghdr_t *)mp->b_rptr; 8950Sstevel@tonic-gate rtm->rtm_pid = curproc->p_pid; 8960Sstevel@tonic-gate break; 8970Sstevel@tonic-gate default: 8980Sstevel@tonic-gate break; 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate rts->rts_flag |= RTS_WPUT_PENDING; 9010Sstevel@tonic-gate rts_wput(q, mp); 9020Sstevel@tonic-gate while (rts->rts_flag & RTS_WPUT_PENDING) 9030Sstevel@tonic-gate if (qwait_rw(q)) { 9040Sstevel@tonic-gate /* RTS_WPUT_PENDING will be cleared below */ 9050Sstevel@tonic-gate rts->rts_error = EINTR; 9060Sstevel@tonic-gate break; 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate err_ret: 9090Sstevel@tonic-gate rts->rts_flag &= ~(RTS_WPUT_PENDING | RTS_WRW_PENDING); 9100Sstevel@tonic-gate return (rts->rts_error); 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* 9140Sstevel@tonic-gate * This routine handles all messages passed downstream. It either 9150Sstevel@tonic-gate * consumes the message or passes it downstream; it never queues a 9160Sstevel@tonic-gate * a message. The data messages that go down are wrapped in an IOCTL 9170Sstevel@tonic-gate * message. 9180Sstevel@tonic-gate */ 9190Sstevel@tonic-gate static void 9200Sstevel@tonic-gate rts_wput(queue_t *q, mblk_t *mp) 9210Sstevel@tonic-gate { 9220Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 9230Sstevel@tonic-gate mblk_t *mp1; 9245240Snordmark conn_t *connp = Q_TO_CONN(q); 9255240Snordmark rts_t *rts = connp->conn_rts; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate switch (mp->b_datap->db_type) { 9280Sstevel@tonic-gate case M_DATA: 9290Sstevel@tonic-gate break; 9300Sstevel@tonic-gate case M_PROTO: 9310Sstevel@tonic-gate case M_PCPROTO: 9320Sstevel@tonic-gate if ((mp->b_wptr - rptr) == sizeof (struct T_data_req)) { 9330Sstevel@tonic-gate /* Expedite valid T_DATA_REQ to below the switch */ 9340Sstevel@tonic-gate if (((union T_primitives *)rptr)->type == T_DATA_REQ) { 9350Sstevel@tonic-gate mp1 = mp->b_cont; 9360Sstevel@tonic-gate freeb(mp); 9370Sstevel@tonic-gate if (mp1 == NULL) 9380Sstevel@tonic-gate return; 9390Sstevel@tonic-gate mp = mp1; 9400Sstevel@tonic-gate break; 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate } 9430Sstevel@tonic-gate /* FALLTHRU */ 9440Sstevel@tonic-gate default: 9450Sstevel@tonic-gate rts_wput_other(q, mp); 9460Sstevel@tonic-gate return; 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate 9508778SErik.Nordmark@Sun.COM ASSERT(msg_getcred(mp, NULL) != NULL); 9518778SErik.Nordmark@Sun.COM 9528778SErik.Nordmark@Sun.COM mp1 = rts_ioctl_alloc(mp); 9530Sstevel@tonic-gate if (mp1 == NULL) { 9540Sstevel@tonic-gate ASSERT(rts != NULL); 9550Sstevel@tonic-gate freemsg(mp); 9560Sstevel@tonic-gate if (rts->rts_flag & RTS_WPUT_PENDING) { 9570Sstevel@tonic-gate rts->rts_error = ENOMEM; 9580Sstevel@tonic-gate rts->rts_flag &= ~RTS_WPUT_PENDING; 9590Sstevel@tonic-gate } 9600Sstevel@tonic-gate return; 9610Sstevel@tonic-gate } 962*11042SErik.Nordmark@Sun.COM ip_wput_nondata(q, mp1); 9630Sstevel@tonic-gate } 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate /* 9670Sstevel@tonic-gate * Handles all the control message, if it 9680Sstevel@tonic-gate * can not understand it, it will 9690Sstevel@tonic-gate * pass down stream. 9700Sstevel@tonic-gate */ 9710Sstevel@tonic-gate static void 9720Sstevel@tonic-gate rts_wput_other(queue_t *q, mblk_t *mp) 9730Sstevel@tonic-gate { 9745240Snordmark conn_t *connp = Q_TO_CONN(q); 9755240Snordmark rts_t *rts = connp->conn_rts; 9760Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 9770Sstevel@tonic-gate struct iocblk *iocp; 9780Sstevel@tonic-gate cred_t *cr; 9793448Sdh155122 rts_stack_t *rtss; 9800Sstevel@tonic-gate 9813448Sdh155122 rtss = rts->rts_rtss; 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate switch (mp->b_datap->db_type) { 9840Sstevel@tonic-gate case M_PROTO: 9850Sstevel@tonic-gate case M_PCPROTO: 9860Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (t_scalar_t)) { 9870Sstevel@tonic-gate /* 9880Sstevel@tonic-gate * If the message does not contain a PRIM_type, 9890Sstevel@tonic-gate * throw it away. 9900Sstevel@tonic-gate */ 9910Sstevel@tonic-gate freemsg(mp); 9920Sstevel@tonic-gate return; 9930Sstevel@tonic-gate } 9940Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) { 9950Sstevel@tonic-gate case T_BIND_REQ: 9960Sstevel@tonic-gate case O_T_BIND_REQ: 9978348SEric.Yu@Sun.COM rts_tpi_bind(q, mp); 9980Sstevel@tonic-gate return; 9990Sstevel@tonic-gate case T_UNBIND_REQ: 10008348SEric.Yu@Sun.COM rts_tpi_unbind(q, mp); 10010Sstevel@tonic-gate return; 10020Sstevel@tonic-gate case T_CAPABILITY_REQ: 10030Sstevel@tonic-gate rts_capability_req(q, mp); 10040Sstevel@tonic-gate return; 10050Sstevel@tonic-gate case T_INFO_REQ: 10060Sstevel@tonic-gate rts_info_req(q, mp); 10070Sstevel@tonic-gate return; 10080Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 10090Sstevel@tonic-gate case T_OPTMGMT_REQ: 10108778SErik.Nordmark@Sun.COM /* 10118778SErik.Nordmark@Sun.COM * All Solaris components should pass a db_credp 10128778SErik.Nordmark@Sun.COM * for this TPI message, hence we ASSERT. 10138778SErik.Nordmark@Sun.COM * But in case there is some other M_PROTO that looks 10148778SErik.Nordmark@Sun.COM * like a TPI message sent by some other kernel 10158778SErik.Nordmark@Sun.COM * component, we check and return an error. 10168778SErik.Nordmark@Sun.COM */ 10178778SErik.Nordmark@Sun.COM cr = msg_getcred(mp, NULL); 10188778SErik.Nordmark@Sun.COM ASSERT(cr != NULL); 10198778SErik.Nordmark@Sun.COM if (cr == NULL) { 10208778SErik.Nordmark@Sun.COM rts_err_ack(q, mp, TSYSERR, EINVAL); 10218778SErik.Nordmark@Sun.COM return; 10228778SErik.Nordmark@Sun.COM } 10238778SErik.Nordmark@Sun.COM if (((union T_primitives *)rptr)->type == 10248778SErik.Nordmark@Sun.COM T_SVR4_OPTMGMT_REQ) { 1025*11042SErik.Nordmark@Sun.COM svr4_optcom_req(q, mp, cr, &rts_opt_obj); 10268778SErik.Nordmark@Sun.COM } else { 1027*11042SErik.Nordmark@Sun.COM tpi_optcom_req(q, mp, cr, &rts_opt_obj); 10288778SErik.Nordmark@Sun.COM } 10290Sstevel@tonic-gate return; 10300Sstevel@tonic-gate case O_T_CONN_RES: 10310Sstevel@tonic-gate case T_CONN_RES: 10320Sstevel@tonic-gate case T_DISCON_REQ: 10330Sstevel@tonic-gate /* Not supported by rts. */ 10340Sstevel@tonic-gate rts_err_ack(q, mp, TNOTSUPPORT, 0); 10350Sstevel@tonic-gate return; 10360Sstevel@tonic-gate case T_DATA_REQ: 10370Sstevel@tonic-gate case T_EXDATA_REQ: 10380Sstevel@tonic-gate case T_ORDREL_REQ: 10390Sstevel@tonic-gate /* Illegal for rts. */ 10400Sstevel@tonic-gate freemsg(mp); 10410Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO); 10420Sstevel@tonic-gate return; 10438348SEric.Yu@Sun.COM 10440Sstevel@tonic-gate default: 10450Sstevel@tonic-gate break; 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate break; 10480Sstevel@tonic-gate case M_IOCTL: 10490Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 10500Sstevel@tonic-gate switch (iocp->ioc_cmd) { 10510Sstevel@tonic-gate case ND_SET: 10520Sstevel@tonic-gate case ND_GET: 10533448Sdh155122 if (nd_getset(q, rtss->rtss_g_nd, mp)) { 10540Sstevel@tonic-gate qreply(q, mp); 10550Sstevel@tonic-gate return; 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate break; 10580Sstevel@tonic-gate case TI_GETPEERNAME: 10590Sstevel@tonic-gate mi_copyin(q, mp, NULL, 10600Sstevel@tonic-gate SIZEOF_STRUCT(strbuf, iocp->ioc_flag)); 10610Sstevel@tonic-gate return; 10620Sstevel@tonic-gate default: 10630Sstevel@tonic-gate break; 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate case M_IOCDATA: 10660Sstevel@tonic-gate rts_wput_iocdata(q, mp); 10670Sstevel@tonic-gate return; 10680Sstevel@tonic-gate default: 10690Sstevel@tonic-gate break; 10700Sstevel@tonic-gate } 1071*11042SErik.Nordmark@Sun.COM ip_wput_nondata(q, mp); 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate /* 10750Sstevel@tonic-gate * Called by rts_wput_other to handle all M_IOCDATA messages. 10760Sstevel@tonic-gate */ 10770Sstevel@tonic-gate static void 10780Sstevel@tonic-gate rts_wput_iocdata(queue_t *q, mblk_t *mp) 10790Sstevel@tonic-gate { 10800Sstevel@tonic-gate struct sockaddr *rtsaddr; 10810Sstevel@tonic-gate mblk_t *mp1; 10820Sstevel@tonic-gate STRUCT_HANDLE(strbuf, sb); 10830Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate /* Make sure it is one of ours. */ 10860Sstevel@tonic-gate switch (iocp->ioc_cmd) { 10870Sstevel@tonic-gate case TI_GETPEERNAME: 10880Sstevel@tonic-gate break; 10890Sstevel@tonic-gate default: 1090*11042SErik.Nordmark@Sun.COM ip_wput_nondata(q, mp); 10910Sstevel@tonic-gate return; 10920Sstevel@tonic-gate } 10930Sstevel@tonic-gate switch (mi_copy_state(q, mp, &mp1)) { 10940Sstevel@tonic-gate case -1: 10950Sstevel@tonic-gate return; 10960Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_IN, 1): 10970Sstevel@tonic-gate break; 10980Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 1): 10990Sstevel@tonic-gate /* Copy out the strbuf. */ 11000Sstevel@tonic-gate mi_copyout(q, mp); 11010Sstevel@tonic-gate return; 11020Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 2): 11030Sstevel@tonic-gate /* All done. */ 11040Sstevel@tonic-gate mi_copy_done(q, mp, 0); 11050Sstevel@tonic-gate return; 11060Sstevel@tonic-gate default: 11070Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 11080Sstevel@tonic-gate return; 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate STRUCT_SET_HANDLE(sb, iocp->ioc_flag, (void *)mp1->b_rptr); 11110Sstevel@tonic-gate if (STRUCT_FGET(sb, maxlen) < (int)sizeof (sin_t)) { 11120Sstevel@tonic-gate mi_copy_done(q, mp, EINVAL); 11130Sstevel@tonic-gate return; 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate switch (iocp->ioc_cmd) { 11160Sstevel@tonic-gate case TI_GETPEERNAME: 11170Sstevel@tonic-gate break; 11180Sstevel@tonic-gate default: 11190Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 11200Sstevel@tonic-gate return; 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), sizeof (sin_t), 11230Sstevel@tonic-gate B_TRUE); 11240Sstevel@tonic-gate if (mp1 == NULL) 11250Sstevel@tonic-gate return; 11260Sstevel@tonic-gate STRUCT_FSET(sb, len, (int)sizeof (sin_t)); 11270Sstevel@tonic-gate rtsaddr = (struct sockaddr *)mp1->b_rptr; 11280Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)&rtsaddr[1]; 11290Sstevel@tonic-gate bzero(rtsaddr, sizeof (struct sockaddr)); 11300Sstevel@tonic-gate rtsaddr->sa_family = AF_ROUTE; 11310Sstevel@tonic-gate /* Copy out the address */ 11320Sstevel@tonic-gate mi_copyout(q, mp); 11330Sstevel@tonic-gate } 11340Sstevel@tonic-gate 1135*11042SErik.Nordmark@Sun.COM /* 1136*11042SErik.Nordmark@Sun.COM * IP passes up a NULL ira. 1137*11042SErik.Nordmark@Sun.COM */ 11385240Snordmark /*ARGSUSED2*/ 11390Sstevel@tonic-gate static void 1140*11042SErik.Nordmark@Sun.COM rts_input(void *arg1, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) 11410Sstevel@tonic-gate { 11425240Snordmark conn_t *connp = (conn_t *)arg1; 11435240Snordmark rts_t *rts = connp->conn_rts; 11440Sstevel@tonic-gate struct iocblk *iocp; 11450Sstevel@tonic-gate mblk_t *mp1; 11460Sstevel@tonic-gate struct T_data_ind *tdi; 11478348SEric.Yu@Sun.COM int error; 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate switch (mp->b_datap->db_type) { 11500Sstevel@tonic-gate case M_IOCACK: 11510Sstevel@tonic-gate case M_IOCNAK: 11520Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 1153*11042SErik.Nordmark@Sun.COM ASSERT(!IPCL_IS_NONSTR(connp)); 1154*11042SErik.Nordmark@Sun.COM if (rts->rts_flag & (RTS_WPUT_PENDING)) { 1155*11042SErik.Nordmark@Sun.COM rts->rts_flag &= ~RTS_WPUT_PENDING; 11560Sstevel@tonic-gate rts->rts_error = iocp->ioc_error; 1157*11042SErik.Nordmark@Sun.COM /* 1158*11042SErik.Nordmark@Sun.COM * Tell rts_wvw/qwait that we are done. 1159*11042SErik.Nordmark@Sun.COM * Note: there is no qwait_wakeup() we can use. 1160*11042SErik.Nordmark@Sun.COM */ 1161*11042SErik.Nordmark@Sun.COM qenable(connp->conn_rq); 11620Sstevel@tonic-gate freemsg(mp); 11630Sstevel@tonic-gate return; 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate break; 11660Sstevel@tonic-gate case M_DATA: 11670Sstevel@tonic-gate /* 11680Sstevel@tonic-gate * Prepend T_DATA_IND to prevent the stream head from 11690Sstevel@tonic-gate * consolidating multiple messages together. 11700Sstevel@tonic-gate * If the allocation fails just send up the M_DATA. 11710Sstevel@tonic-gate */ 11720Sstevel@tonic-gate mp1 = allocb(sizeof (*tdi), BPRI_MED); 11730Sstevel@tonic-gate if (mp1 != NULL) { 11740Sstevel@tonic-gate mp1->b_cont = mp; 11750Sstevel@tonic-gate mp = mp1; 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 11780Sstevel@tonic-gate mp->b_wptr += sizeof (*tdi); 11790Sstevel@tonic-gate tdi = (struct T_data_ind *)mp->b_rptr; 11800Sstevel@tonic-gate tdi->PRIM_type = T_DATA_IND; 11810Sstevel@tonic-gate tdi->MORE_flag = 0; 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate break; 11840Sstevel@tonic-gate default: 11850Sstevel@tonic-gate break; 11860Sstevel@tonic-gate } 11878348SEric.Yu@Sun.COM 11888348SEric.Yu@Sun.COM if (IPCL_IS_NONSTR(connp)) { 11898348SEric.Yu@Sun.COM if ((*connp->conn_upcalls->su_recv) 11908348SEric.Yu@Sun.COM (connp->conn_upper_handle, mp, msgdsize(mp), 0, 11918348SEric.Yu@Sun.COM &error, NULL) < 0) { 11928348SEric.Yu@Sun.COM ASSERT(error == ENOSPC); 11938348SEric.Yu@Sun.COM /* 11948348SEric.Yu@Sun.COM * Let's confirm hoding the lock that 11958348SEric.Yu@Sun.COM * we are out of recv space. 11968348SEric.Yu@Sun.COM */ 11978348SEric.Yu@Sun.COM mutex_enter(&rts->rts_recv_mutex); 11988348SEric.Yu@Sun.COM if ((*connp->conn_upcalls->su_recv) 11998348SEric.Yu@Sun.COM (connp->conn_upper_handle, NULL, 0, 0, 12008348SEric.Yu@Sun.COM &error, NULL) < 0) { 12018348SEric.Yu@Sun.COM ASSERT(error == ENOSPC); 12028348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_TRUE; 12038348SEric.Yu@Sun.COM } 12048348SEric.Yu@Sun.COM mutex_exit(&rts->rts_recv_mutex); 12058348SEric.Yu@Sun.COM } 12068348SEric.Yu@Sun.COM } else { 12078348SEric.Yu@Sun.COM putnext(connp->conn_rq, mp); 12088348SEric.Yu@Sun.COM } 12090Sstevel@tonic-gate } 12100Sstevel@tonic-gate 1211*11042SErik.Nordmark@Sun.COM /*ARGSUSED*/ 1212*11042SErik.Nordmark@Sun.COM static void 1213*11042SErik.Nordmark@Sun.COM rts_icmp_input(void *arg1, mblk_t *mp, void *arg2, ip_recv_attr_t *ira) 1214*11042SErik.Nordmark@Sun.COM { 1215*11042SErik.Nordmark@Sun.COM freemsg(mp); 1216*11042SErik.Nordmark@Sun.COM } 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate void 12198348SEric.Yu@Sun.COM rts_ddi_g_init(void) 12200Sstevel@tonic-gate { 12210Sstevel@tonic-gate rts_max_optsize = optcom_max_optsize(rts_opt_obj.odb_opt_des_arr, 12220Sstevel@tonic-gate rts_opt_obj.odb_opt_arr_cnt); 12233448Sdh155122 12243448Sdh155122 /* 12253448Sdh155122 * We want to be informed each time a stack is created or 12263448Sdh155122 * destroyed in the kernel, so we can maintain the 12273448Sdh155122 * set of rts_stack_t's. 12283448Sdh155122 */ 12293448Sdh155122 netstack_register(NS_RTS, rts_stack_init, NULL, rts_stack_fini); 12300Sstevel@tonic-gate } 12313448Sdh155122 12323448Sdh155122 void 12338348SEric.Yu@Sun.COM rts_ddi_g_destroy(void) 12343448Sdh155122 { 12353448Sdh155122 netstack_unregister(NS_RTS); 12363448Sdh155122 } 12373448Sdh155122 12388348SEric.Yu@Sun.COM #define INET_NAME "ip" 12398348SEric.Yu@Sun.COM 12403448Sdh155122 /* 12413448Sdh155122 * Initialize the RTS stack instance. 12423448Sdh155122 */ 12433448Sdh155122 /* ARGSUSED */ 12443448Sdh155122 static void * 12453448Sdh155122 rts_stack_init(netstackid_t stackid, netstack_t *ns) 12463448Sdh155122 { 12473448Sdh155122 rts_stack_t *rtss; 12483448Sdh155122 rtsparam_t *pa; 12498348SEric.Yu@Sun.COM int error = 0; 12508348SEric.Yu@Sun.COM major_t major; 12513448Sdh155122 12523448Sdh155122 rtss = (rts_stack_t *)kmem_zalloc(sizeof (*rtss), KM_SLEEP); 12533448Sdh155122 rtss->rtss_netstack = ns; 12543448Sdh155122 12553448Sdh155122 pa = (rtsparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP); 12563448Sdh155122 rtss->rtss_params = pa; 12573448Sdh155122 bcopy(lcl_param_arr, rtss->rtss_params, sizeof (lcl_param_arr)); 12583448Sdh155122 12593448Sdh155122 (void) rts_param_register(&rtss->rtss_g_nd, 12603448Sdh155122 rtss->rtss_params, A_CNT(lcl_param_arr)); 12618348SEric.Yu@Sun.COM 12628348SEric.Yu@Sun.COM major = mod_name_to_major(INET_NAME); 12638348SEric.Yu@Sun.COM error = ldi_ident_from_major(major, &rtss->rtss_ldi_ident); 12648348SEric.Yu@Sun.COM ASSERT(error == 0); 12653448Sdh155122 return (rtss); 12663448Sdh155122 } 12673448Sdh155122 12683448Sdh155122 /* 12693448Sdh155122 * Free the RTS stack instance. 12703448Sdh155122 */ 12713448Sdh155122 /* ARGSUSED */ 12723448Sdh155122 static void 12733448Sdh155122 rts_stack_fini(netstackid_t stackid, void *arg) 12743448Sdh155122 { 12753448Sdh155122 rts_stack_t *rtss = (rts_stack_t *)arg; 12763448Sdh155122 12775240Snordmark nd_free(&rtss->rtss_g_nd); 12783448Sdh155122 kmem_free(rtss->rtss_params, sizeof (lcl_param_arr)); 12793448Sdh155122 rtss->rtss_params = NULL; 12808348SEric.Yu@Sun.COM ldi_ident_release(rtss->rtss_ldi_ident); 12813448Sdh155122 kmem_free(rtss, sizeof (*rtss)); 12823448Sdh155122 } 12838348SEric.Yu@Sun.COM 12848348SEric.Yu@Sun.COM /* ARGSUSED */ 12858348SEric.Yu@Sun.COM int 12868348SEric.Yu@Sun.COM rts_accept(sock_lower_handle_t lproto_handle, 12878348SEric.Yu@Sun.COM sock_lower_handle_t eproto_handle, sock_upper_handle_t sock_handle, 12888348SEric.Yu@Sun.COM cred_t *cr) 12898348SEric.Yu@Sun.COM { 12908348SEric.Yu@Sun.COM return (EINVAL); 12918348SEric.Yu@Sun.COM } 12928348SEric.Yu@Sun.COM 12938348SEric.Yu@Sun.COM /* ARGSUSED */ 12948348SEric.Yu@Sun.COM static int 12958348SEric.Yu@Sun.COM rts_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa, 12968348SEric.Yu@Sun.COM socklen_t len, cred_t *cr) 12978348SEric.Yu@Sun.COM { 12988348SEric.Yu@Sun.COM /* 12998348SEric.Yu@Sun.COM * rebind not allowed 13008348SEric.Yu@Sun.COM */ 13018348SEric.Yu@Sun.COM return (EINVAL); 13028348SEric.Yu@Sun.COM } 13038348SEric.Yu@Sun.COM 13048348SEric.Yu@Sun.COM /* ARGSUSED */ 13058348SEric.Yu@Sun.COM int 13068348SEric.Yu@Sun.COM rts_listen(sock_lower_handle_t proto_handle, int backlog, cred_t *cr) 13078348SEric.Yu@Sun.COM { 13088348SEric.Yu@Sun.COM return (EINVAL); 13098348SEric.Yu@Sun.COM } 13108348SEric.Yu@Sun.COM 13118348SEric.Yu@Sun.COM /* ARGSUSED */ 13128348SEric.Yu@Sun.COM int 13138348SEric.Yu@Sun.COM rts_connect(sock_lower_handle_t proto_handle, const struct sockaddr *sa, 13148348SEric.Yu@Sun.COM socklen_t len, sock_connid_t *id, cred_t *cr) 13158348SEric.Yu@Sun.COM { 13168348SEric.Yu@Sun.COM /* 13178348SEric.Yu@Sun.COM * rts sockets start out as bound and connected 13188348SEric.Yu@Sun.COM */ 13198348SEric.Yu@Sun.COM *id = 0; 13208348SEric.Yu@Sun.COM return (EISCONN); 13218348SEric.Yu@Sun.COM } 13228348SEric.Yu@Sun.COM 13238348SEric.Yu@Sun.COM /* ARGSUSED */ 13248348SEric.Yu@Sun.COM int 13258348SEric.Yu@Sun.COM rts_getpeername(sock_lower_handle_t proto_handle, struct sockaddr *addr, 13268348SEric.Yu@Sun.COM socklen_t *addrlen, cred_t *cr) 13278348SEric.Yu@Sun.COM { 13288348SEric.Yu@Sun.COM bzero(addr, sizeof (struct sockaddr)); 13298348SEric.Yu@Sun.COM addr->sa_family = AF_ROUTE; 13308348SEric.Yu@Sun.COM *addrlen = sizeof (struct sockaddr); 13318348SEric.Yu@Sun.COM 13328348SEric.Yu@Sun.COM return (0); 13338348SEric.Yu@Sun.COM } 13348348SEric.Yu@Sun.COM 13358348SEric.Yu@Sun.COM /* ARGSUSED */ 13368348SEric.Yu@Sun.COM int 13378348SEric.Yu@Sun.COM rts_getsockname(sock_lower_handle_t proto_handle, struct sockaddr *addr, 13388348SEric.Yu@Sun.COM socklen_t *addrlen, cred_t *cr) 13398348SEric.Yu@Sun.COM { 1340*11042SErik.Nordmark@Sun.COM bzero(addr, sizeof (struct sockaddr)); 1341*11042SErik.Nordmark@Sun.COM addr->sa_family = AF_ROUTE; 1342*11042SErik.Nordmark@Sun.COM *addrlen = sizeof (struct sockaddr); 1343*11042SErik.Nordmark@Sun.COM 1344*11042SErik.Nordmark@Sun.COM return (0); 13458348SEric.Yu@Sun.COM } 13468348SEric.Yu@Sun.COM 13478348SEric.Yu@Sun.COM static int 13488348SEric.Yu@Sun.COM rts_getsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 13498348SEric.Yu@Sun.COM void *optvalp, socklen_t *optlen, cred_t *cr) 13508348SEric.Yu@Sun.COM { 13518348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 13528348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 13538348SEric.Yu@Sun.COM int error; 13548348SEric.Yu@Sun.COM t_uscalar_t max_optbuf_len; 13558348SEric.Yu@Sun.COM void *optvalp_buf; 13568348SEric.Yu@Sun.COM int len; 13578348SEric.Yu@Sun.COM 13588348SEric.Yu@Sun.COM error = proto_opt_check(level, option_name, *optlen, &max_optbuf_len, 13598348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_des_arr, 13608348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_arr_cnt, 13618348SEric.Yu@Sun.COM B_FALSE, B_TRUE, cr); 13628348SEric.Yu@Sun.COM if (error != 0) { 13638348SEric.Yu@Sun.COM if (error < 0) 13648348SEric.Yu@Sun.COM error = proto_tlitosyserr(-error); 13658348SEric.Yu@Sun.COM return (error); 13668348SEric.Yu@Sun.COM } 13678348SEric.Yu@Sun.COM 13688348SEric.Yu@Sun.COM optvalp_buf = kmem_alloc(max_optbuf_len, KM_SLEEP); 13698348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_READER); 13708348SEric.Yu@Sun.COM len = rts_opt_get(connp, level, option_name, optvalp_buf); 13718348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 1372*11042SErik.Nordmark@Sun.COM if (len == -1) { 1373*11042SErik.Nordmark@Sun.COM kmem_free(optvalp_buf, max_optbuf_len); 1374*11042SErik.Nordmark@Sun.COM return (EINVAL); 13758348SEric.Yu@Sun.COM } 13768348SEric.Yu@Sun.COM 1377*11042SErik.Nordmark@Sun.COM /* 1378*11042SErik.Nordmark@Sun.COM * update optlen and copy option value 1379*11042SErik.Nordmark@Sun.COM */ 1380*11042SErik.Nordmark@Sun.COM t_uscalar_t size = MIN(len, *optlen); 1381*11042SErik.Nordmark@Sun.COM 1382*11042SErik.Nordmark@Sun.COM bcopy(optvalp_buf, optvalp, size); 1383*11042SErik.Nordmark@Sun.COM bcopy(&size, optlen, sizeof (size)); 13848348SEric.Yu@Sun.COM kmem_free(optvalp_buf, max_optbuf_len); 1385*11042SErik.Nordmark@Sun.COM return (0); 13868348SEric.Yu@Sun.COM } 13878348SEric.Yu@Sun.COM 13888348SEric.Yu@Sun.COM static int 13898348SEric.Yu@Sun.COM rts_setsockopt(sock_lower_handle_t proto_handle, int level, int option_name, 13908348SEric.Yu@Sun.COM const void *optvalp, socklen_t optlen, cred_t *cr) 13918348SEric.Yu@Sun.COM { 13928348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 13938348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 13948348SEric.Yu@Sun.COM int error; 13958348SEric.Yu@Sun.COM 13968348SEric.Yu@Sun.COM error = proto_opt_check(level, option_name, optlen, NULL, 13978348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_des_arr, 13988348SEric.Yu@Sun.COM rts_opt_obj.odb_opt_arr_cnt, 13998348SEric.Yu@Sun.COM B_TRUE, B_FALSE, cr); 14008348SEric.Yu@Sun.COM 14018348SEric.Yu@Sun.COM if (error != 0) { 14028348SEric.Yu@Sun.COM if (error < 0) 14038348SEric.Yu@Sun.COM error = proto_tlitosyserr(-error); 14048348SEric.Yu@Sun.COM return (error); 14058348SEric.Yu@Sun.COM } 14068348SEric.Yu@Sun.COM 14078348SEric.Yu@Sun.COM rw_enter(&rts->rts_rwlock, RW_WRITER); 14088348SEric.Yu@Sun.COM error = rts_opt_set(connp, SETFN_OPTCOM_NEGOTIATE, level, option_name, 14098348SEric.Yu@Sun.COM optlen, (uchar_t *)optvalp, (uint_t *)&optlen, (uchar_t *)optvalp, 14108348SEric.Yu@Sun.COM NULL, cr); 14118348SEric.Yu@Sun.COM rw_exit(&rts->rts_rwlock); 14128348SEric.Yu@Sun.COM 14138348SEric.Yu@Sun.COM ASSERT(error >= 0); 14148348SEric.Yu@Sun.COM 14158348SEric.Yu@Sun.COM return (error); 14168348SEric.Yu@Sun.COM } 14178348SEric.Yu@Sun.COM 14188348SEric.Yu@Sun.COM /* ARGSUSED */ 14198348SEric.Yu@Sun.COM static int 14208348SEric.Yu@Sun.COM rts_send(sock_lower_handle_t proto_handle, mblk_t *mp, 14218348SEric.Yu@Sun.COM struct nmsghdr *msg, cred_t *cr) 14228348SEric.Yu@Sun.COM { 14238348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14248348SEric.Yu@Sun.COM rt_msghdr_t *rtm; 14258348SEric.Yu@Sun.COM int error; 14268348SEric.Yu@Sun.COM 14278348SEric.Yu@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA); 14288348SEric.Yu@Sun.COM /* 14298348SEric.Yu@Sun.COM * The semantics of the routing socket is such that the rtm_pid 14308348SEric.Yu@Sun.COM * field is automatically filled in during requests with the 14318348SEric.Yu@Sun.COM * current process' pid. We do this here (where we still have 14328348SEric.Yu@Sun.COM * user context) after checking we have at least a message the 14338348SEric.Yu@Sun.COM * size of a routing message header. 14348348SEric.Yu@Sun.COM */ 14358348SEric.Yu@Sun.COM if ((mp->b_wptr - mp->b_rptr) < sizeof (rt_msghdr_t)) { 14368348SEric.Yu@Sun.COM if (!pullupmsg(mp, sizeof (rt_msghdr_t))) { 14378348SEric.Yu@Sun.COM freemsg(mp); 1438*11042SErik.Nordmark@Sun.COM return (EINVAL); 14398348SEric.Yu@Sun.COM } 14408348SEric.Yu@Sun.COM } 14418348SEric.Yu@Sun.COM rtm = (rt_msghdr_t *)mp->b_rptr; 14428348SEric.Yu@Sun.COM rtm->rtm_pid = curproc->p_pid; 14438348SEric.Yu@Sun.COM 14448348SEric.Yu@Sun.COM /* 1445*11042SErik.Nordmark@Sun.COM * We are not constrained by the ioctl interface and 1446*11042SErik.Nordmark@Sun.COM * ip_rts_request_common processing requests synchronously hence 1447*11042SErik.Nordmark@Sun.COM * we can send them down concurrently. 14488348SEric.Yu@Sun.COM */ 1449*11042SErik.Nordmark@Sun.COM error = ip_rts_request_common(mp, connp, cr); 14508348SEric.Yu@Sun.COM return (error); 14518348SEric.Yu@Sun.COM } 14528348SEric.Yu@Sun.COM 14538348SEric.Yu@Sun.COM /* ARGSUSED */ 14548348SEric.Yu@Sun.COM sock_lower_handle_t 14558348SEric.Yu@Sun.COM rts_create(int family, int type, int proto, sock_downcalls_t **sock_downcalls, 14568348SEric.Yu@Sun.COM uint_t *smodep, int *errorp, int flags, cred_t *credp) 14578348SEric.Yu@Sun.COM { 14588348SEric.Yu@Sun.COM conn_t *connp; 14598348SEric.Yu@Sun.COM 14608348SEric.Yu@Sun.COM if (family != AF_ROUTE || type != SOCK_RAW || 14618348SEric.Yu@Sun.COM (proto != 0 && proto != AF_INET && proto != AF_INET6)) { 14628348SEric.Yu@Sun.COM *errorp = EPROTONOSUPPORT; 14638348SEric.Yu@Sun.COM return (NULL); 14648348SEric.Yu@Sun.COM } 14658348SEric.Yu@Sun.COM 14668348SEric.Yu@Sun.COM connp = rts_open(flags, credp); 14678348SEric.Yu@Sun.COM ASSERT(connp != NULL); 14688348SEric.Yu@Sun.COM connp->conn_flags |= IPCL_NONSTR; 14698348SEric.Yu@Sun.COM 1470*11042SErik.Nordmark@Sun.COM connp->conn_proto = proto; 14718348SEric.Yu@Sun.COM 14728348SEric.Yu@Sun.COM mutex_enter(&connp->conn_lock); 14738348SEric.Yu@Sun.COM connp->conn_state_flags &= ~CONN_INCIPIENT; 14748348SEric.Yu@Sun.COM mutex_exit(&connp->conn_lock); 14758348SEric.Yu@Sun.COM 14768348SEric.Yu@Sun.COM *errorp = 0; 14778348SEric.Yu@Sun.COM *smodep = SM_ATOMIC; 14788348SEric.Yu@Sun.COM *sock_downcalls = &sock_rts_downcalls; 14798348SEric.Yu@Sun.COM return ((sock_lower_handle_t)connp); 14808348SEric.Yu@Sun.COM } 14818348SEric.Yu@Sun.COM 14828348SEric.Yu@Sun.COM /* ARGSUSED */ 14838348SEric.Yu@Sun.COM void 14848348SEric.Yu@Sun.COM rts_activate(sock_lower_handle_t proto_handle, sock_upper_handle_t sock_handle, 14858348SEric.Yu@Sun.COM sock_upcalls_t *sock_upcalls, int flags, cred_t *cr) 14868348SEric.Yu@Sun.COM { 14878348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 14888348SEric.Yu@Sun.COM struct sock_proto_props sopp; 14898348SEric.Yu@Sun.COM 14908348SEric.Yu@Sun.COM connp->conn_upcalls = sock_upcalls; 14918348SEric.Yu@Sun.COM connp->conn_upper_handle = sock_handle; 14928348SEric.Yu@Sun.COM 14938348SEric.Yu@Sun.COM sopp.sopp_flags = SOCKOPT_WROFF | SOCKOPT_RCVHIWAT | SOCKOPT_RCVLOWAT | 14948348SEric.Yu@Sun.COM SOCKOPT_MAXBLK | SOCKOPT_MAXPSZ | SOCKOPT_MINPSZ; 14958348SEric.Yu@Sun.COM sopp.sopp_wroff = 0; 1496*11042SErik.Nordmark@Sun.COM sopp.sopp_rxhiwat = connp->conn_rcvbuf; 1497*11042SErik.Nordmark@Sun.COM sopp.sopp_rxlowat = connp->conn_rcvlowat; 14988348SEric.Yu@Sun.COM sopp.sopp_maxblk = INFPSZ; 14998348SEric.Yu@Sun.COM sopp.sopp_maxpsz = rts_mod_info.mi_maxpsz; 15008348SEric.Yu@Sun.COM sopp.sopp_minpsz = (rts_mod_info.mi_minpsz == 1) ? 0 : 15018348SEric.Yu@Sun.COM rts_mod_info.mi_minpsz; 15028348SEric.Yu@Sun.COM 15038348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_set_proto_props) 15048348SEric.Yu@Sun.COM (connp->conn_upper_handle, &sopp); 15058348SEric.Yu@Sun.COM 15068348SEric.Yu@Sun.COM /* 15078348SEric.Yu@Sun.COM * We treat it as already connected for routing socket. 15088348SEric.Yu@Sun.COM */ 15098348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_connected) 15108348SEric.Yu@Sun.COM (connp->conn_upper_handle, 0, NULL, -1); 15118348SEric.Yu@Sun.COM 1512*11042SErik.Nordmark@Sun.COM /* Indicate to IP that this is a routing socket client */ 15138348SEric.Yu@Sun.COM ip_rts_register(connp); 15148348SEric.Yu@Sun.COM } 15158348SEric.Yu@Sun.COM 15168348SEric.Yu@Sun.COM /* ARGSUSED */ 15178348SEric.Yu@Sun.COM int 15188348SEric.Yu@Sun.COM rts_close(sock_lower_handle_t proto_handle, int flags, cred_t *cr) 15198348SEric.Yu@Sun.COM { 15208348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 15218348SEric.Yu@Sun.COM 15228348SEric.Yu@Sun.COM ASSERT(connp != NULL && IPCL_IS_RTS(connp)); 15238348SEric.Yu@Sun.COM return (rts_common_close(NULL, connp)); 15248348SEric.Yu@Sun.COM } 15258348SEric.Yu@Sun.COM 15268348SEric.Yu@Sun.COM /* ARGSUSED */ 15278348SEric.Yu@Sun.COM int 15288348SEric.Yu@Sun.COM rts_shutdown(sock_lower_handle_t proto_handle, int how, cred_t *cr) 15298348SEric.Yu@Sun.COM { 15308348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 15318348SEric.Yu@Sun.COM 15328348SEric.Yu@Sun.COM /* shut down the send side */ 15338348SEric.Yu@Sun.COM if (how != SHUT_RD) 15348348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 15358348SEric.Yu@Sun.COM SOCK_OPCTL_SHUT_SEND, 0); 15368348SEric.Yu@Sun.COM /* shut down the recv side */ 15378348SEric.Yu@Sun.COM if (how != SHUT_WR) 15388348SEric.Yu@Sun.COM (*connp->conn_upcalls->su_opctl)(connp->conn_upper_handle, 15398348SEric.Yu@Sun.COM SOCK_OPCTL_SHUT_RECV, 0); 15408348SEric.Yu@Sun.COM return (0); 15418348SEric.Yu@Sun.COM } 15428348SEric.Yu@Sun.COM 15438348SEric.Yu@Sun.COM void 15448348SEric.Yu@Sun.COM rts_clr_flowctrl(sock_lower_handle_t proto_handle) 15458348SEric.Yu@Sun.COM { 15468348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 15478348SEric.Yu@Sun.COM rts_t *rts = connp->conn_rts; 15488348SEric.Yu@Sun.COM 15498348SEric.Yu@Sun.COM mutex_enter(&rts->rts_recv_mutex); 15508348SEric.Yu@Sun.COM connp->conn_flow_cntrld = B_FALSE; 15518348SEric.Yu@Sun.COM mutex_exit(&rts->rts_recv_mutex); 15528348SEric.Yu@Sun.COM } 15538348SEric.Yu@Sun.COM 15548348SEric.Yu@Sun.COM int 15558348SEric.Yu@Sun.COM rts_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg, 15568348SEric.Yu@Sun.COM int mode, int32_t *rvalp, cred_t *cr) 15578348SEric.Yu@Sun.COM { 15588348SEric.Yu@Sun.COM conn_t *connp = (conn_t *)proto_handle; 15598348SEric.Yu@Sun.COM int error; 15608348SEric.Yu@Sun.COM 1561*11042SErik.Nordmark@Sun.COM /* 1562*11042SErik.Nordmark@Sun.COM * If we don't have a helper stream then create one. 1563*11042SErik.Nordmark@Sun.COM * ip_create_helper_stream takes care of locking the conn_t, 1564*11042SErik.Nordmark@Sun.COM * so this check for NULL is just a performance optimization. 1565*11042SErik.Nordmark@Sun.COM */ 1566*11042SErik.Nordmark@Sun.COM if (connp->conn_helper_info == NULL) { 1567*11042SErik.Nordmark@Sun.COM rts_stack_t *rtss = connp->conn_rts->rts_rtss; 1568*11042SErik.Nordmark@Sun.COM 1569*11042SErik.Nordmark@Sun.COM ASSERT(rtss->rtss_ldi_ident != NULL); 1570*11042SErik.Nordmark@Sun.COM 1571*11042SErik.Nordmark@Sun.COM /* 1572*11042SErik.Nordmark@Sun.COM * Create a helper stream for non-STREAMS socket. 1573*11042SErik.Nordmark@Sun.COM */ 1574*11042SErik.Nordmark@Sun.COM error = ip_create_helper_stream(connp, rtss->rtss_ldi_ident); 1575*11042SErik.Nordmark@Sun.COM if (error != 0) { 1576*11042SErik.Nordmark@Sun.COM ip0dbg(("rts_ioctl: create of IP helper stream " 1577*11042SErik.Nordmark@Sun.COM "failed %d\n", error)); 1578*11042SErik.Nordmark@Sun.COM return (error); 1579*11042SErik.Nordmark@Sun.COM } 1580*11042SErik.Nordmark@Sun.COM } 1581*11042SErik.Nordmark@Sun.COM 15828348SEric.Yu@Sun.COM switch (cmd) { 15838348SEric.Yu@Sun.COM case ND_SET: 15848348SEric.Yu@Sun.COM case ND_GET: 15858348SEric.Yu@Sun.COM case TI_GETPEERNAME: 15868348SEric.Yu@Sun.COM case TI_GETMYNAME: 15878348SEric.Yu@Sun.COM #ifdef DEUG 15888348SEric.Yu@Sun.COM cmn_err(CE_CONT, "rts_ioctl cmd 0x%x on non sreams" 15898348SEric.Yu@Sun.COM " socket", cmd); 15908348SEric.Yu@Sun.COM #endif 15918348SEric.Yu@Sun.COM error = EINVAL; 15928348SEric.Yu@Sun.COM break; 15938348SEric.Yu@Sun.COM default: 15948348SEric.Yu@Sun.COM /* 15958348SEric.Yu@Sun.COM * Pass on to IP using helper stream 15968348SEric.Yu@Sun.COM */ 15978444SRao.Shoaib@Sun.COM error = ldi_ioctl(connp->conn_helper_info->iphs_handle, 15988348SEric.Yu@Sun.COM cmd, arg, mode, cr, rvalp); 15998348SEric.Yu@Sun.COM break; 16008348SEric.Yu@Sun.COM } 16018348SEric.Yu@Sun.COM 16028348SEric.Yu@Sun.COM return (error); 16038348SEric.Yu@Sun.COM } 16048348SEric.Yu@Sun.COM 16058348SEric.Yu@Sun.COM sock_downcalls_t sock_rts_downcalls = { 16068348SEric.Yu@Sun.COM rts_activate, 16078348SEric.Yu@Sun.COM rts_accept, 16088348SEric.Yu@Sun.COM rts_bind, 16098348SEric.Yu@Sun.COM rts_listen, 16108348SEric.Yu@Sun.COM rts_connect, 16118348SEric.Yu@Sun.COM rts_getpeername, 16128348SEric.Yu@Sun.COM rts_getsockname, 16138348SEric.Yu@Sun.COM rts_getsockopt, 16148348SEric.Yu@Sun.COM rts_setsockopt, 16158348SEric.Yu@Sun.COM rts_send, 16168348SEric.Yu@Sun.COM NULL, 16178348SEric.Yu@Sun.COM NULL, 16188348SEric.Yu@Sun.COM NULL, 16198348SEric.Yu@Sun.COM rts_shutdown, 16208348SEric.Yu@Sun.COM rts_clr_flowctrl, 16218348SEric.Yu@Sun.COM rts_ioctl, 16228348SEric.Yu@Sun.COM rts_close 16238348SEric.Yu@Sun.COM }; 1624