10f1702c5SYu Xiangning /* 20f1702c5SYu Xiangning * CDDL HEADER START 30f1702c5SYu Xiangning * 40f1702c5SYu Xiangning * The contents of this file are subject to the terms of the 50f1702c5SYu Xiangning * Common Development and Distribution License (the "License"). 60f1702c5SYu Xiangning * You may not use this file except in compliance with the License. 70f1702c5SYu Xiangning * 80f1702c5SYu Xiangning * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90f1702c5SYu Xiangning * or http://www.opensolaris.org/os/licensing. 100f1702c5SYu Xiangning * See the License for the specific language governing permissions 110f1702c5SYu Xiangning * and limitations under the License. 120f1702c5SYu Xiangning * 130f1702c5SYu Xiangning * When distributing Covered Code, include this CDDL HEADER in each 140f1702c5SYu Xiangning * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150f1702c5SYu Xiangning * If applicable, add the following below this CDDL HEADER, with the 160f1702c5SYu Xiangning * fields enclosed by brackets "[]" replaced with your own identifying 170f1702c5SYu Xiangning * information: Portions Copyright [yyyy] [name of copyright owner] 180f1702c5SYu Xiangning * 190f1702c5SYu Xiangning * CDDL HEADER END 200f1702c5SYu Xiangning */ 210f1702c5SYu Xiangning /* 22*bd670b35SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230f1702c5SYu Xiangning * Use is subject to license terms. 240f1702c5SYu Xiangning */ 250f1702c5SYu Xiangning 260f1702c5SYu Xiangning #include <sys/types.h> 270f1702c5SYu Xiangning #include <inet/common.h> 280f1702c5SYu Xiangning #include <sys/stream.h> 290f1702c5SYu Xiangning #include <sys/stropts.h> 300f1702c5SYu Xiangning #include <sys/strsun.h> 310f1702c5SYu Xiangning #include <sys/sysmacros.h> 320f1702c5SYu Xiangning #include <sys/stropts.h> 330f1702c5SYu Xiangning #include <sys/strsubr.h> 340f1702c5SYu Xiangning #include <sys/tpicommon.h> 350f1702c5SYu Xiangning #include <sys/socket_proto.h> 360f1702c5SYu Xiangning #include <sys/policy.h> 370f1702c5SYu Xiangning #include <inet/optcom.h> 380f1702c5SYu Xiangning #include <inet/ipclassifier.h> 390f1702c5SYu Xiangning 400f1702c5SYu Xiangning boolean_t 410f1702c5SYu Xiangning proto_set_rx_hiwat(queue_t *q, conn_t *connp, size_t size) 420f1702c5SYu Xiangning { 430f1702c5SYu Xiangning 440f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 450f1702c5SYu Xiangning struct sock_proto_props sopp; 460f1702c5SYu Xiangning 470f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_RCVHIWAT; 480f1702c5SYu Xiangning sopp.sopp_rxhiwat = size; 490f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 500f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 510f1702c5SYu Xiangning } else { 520f1702c5SYu Xiangning MBLKP mp; 530f1702c5SYu Xiangning struct stroptions *stropt; 540f1702c5SYu Xiangning 550f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 560f1702c5SYu Xiangning return (B_FALSE); 570f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 580f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 590f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 600f1702c5SYu Xiangning stropt->so_flags = SO_HIWAT; 610f1702c5SYu Xiangning stropt->so_hiwat = size; 620f1702c5SYu Xiangning putnext(q, mp); 630f1702c5SYu Xiangning } 640f1702c5SYu Xiangning return (B_TRUE); 650f1702c5SYu Xiangning } 660f1702c5SYu Xiangning 670f1702c5SYu Xiangning boolean_t 680f1702c5SYu Xiangning proto_set_rx_lowat(queue_t *q, conn_t *connp, size_t size) 690f1702c5SYu Xiangning { 700f1702c5SYu Xiangning 710f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 720f1702c5SYu Xiangning struct sock_proto_props sopp; 730f1702c5SYu Xiangning 740f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_RCVLOWAT; 750f1702c5SYu Xiangning sopp.sopp_rxlowat = size; 760f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 770f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 780f1702c5SYu Xiangning } else { 790f1702c5SYu Xiangning MBLKP mp; 800f1702c5SYu Xiangning struct stroptions *stropt; 810f1702c5SYu Xiangning 820f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 830f1702c5SYu Xiangning return (B_FALSE); 840f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 850f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 860f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 870f1702c5SYu Xiangning stropt->so_flags = SO_LOWAT; 880f1702c5SYu Xiangning stropt->so_lowat = size; 890f1702c5SYu Xiangning putnext(q, mp); 900f1702c5SYu Xiangning } 910f1702c5SYu Xiangning return (B_TRUE); 920f1702c5SYu Xiangning } 930f1702c5SYu Xiangning 940f1702c5SYu Xiangning /* 950f1702c5SYu Xiangning * Set maximum packet size. This is the maximum amount of data the protocol 960f1702c5SYu Xiangning * wants to be given at any time, Larger data needs to be broken in multiples 970f1702c5SYu Xiangning * of maximum packet size and given to the protocol one at a time. 980f1702c5SYu Xiangning */ 990f1702c5SYu Xiangning boolean_t 1000f1702c5SYu Xiangning proto_set_maxpsz(queue_t *q, conn_t *connp, size_t size) 1010f1702c5SYu Xiangning { 1020f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 1030f1702c5SYu Xiangning struct sock_proto_props sopp; 1040f1702c5SYu Xiangning 1050f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXPSZ; 1060f1702c5SYu Xiangning sopp.sopp_maxpsz = size; 1070f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 1080f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 1090f1702c5SYu Xiangning return (B_TRUE); 1100f1702c5SYu Xiangning } else { 1110f1702c5SYu Xiangning struct stdata *stp; 1120f1702c5SYu Xiangning queue_t *wq; 1130f1702c5SYu Xiangning stp = STREAM(q); 1140f1702c5SYu Xiangning 1150f1702c5SYu Xiangning /* 1160f1702c5SYu Xiangning * At this point change of a queue parameter is not allowed 1170f1702c5SYu Xiangning * when a multiplexor is sitting on top. 1180f1702c5SYu Xiangning */ 1190f1702c5SYu Xiangning if (stp == NULL || stp->sd_flag & STPLEX) 1200f1702c5SYu Xiangning return (B_FALSE); 1210f1702c5SYu Xiangning 1220f1702c5SYu Xiangning claimstr(stp->sd_wrq); 1230f1702c5SYu Xiangning wq = stp->sd_wrq->q_next; 1240f1702c5SYu Xiangning ASSERT(wq != NULL); 1250f1702c5SYu Xiangning (void) strqset(wq, QMAXPSZ, 0, size); 1260f1702c5SYu Xiangning releasestr(stp->sd_wrq); 1270f1702c5SYu Xiangning return (B_TRUE); 1280f1702c5SYu Xiangning } 1290f1702c5SYu Xiangning } 1300f1702c5SYu Xiangning 1310f1702c5SYu Xiangning /* ARGSUSED */ 1320f1702c5SYu Xiangning boolean_t 1330f1702c5SYu Xiangning proto_set_tx_maxblk(queue_t *q, conn_t *connp, ssize_t size) 1340f1702c5SYu Xiangning { 1350f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 1360f1702c5SYu Xiangning struct sock_proto_props sopp; 1370f1702c5SYu Xiangning 1380f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_MAXBLK; 1390f1702c5SYu Xiangning sopp.sopp_maxblk = size; 1400f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 1410f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 1420f1702c5SYu Xiangning } else { 1430f1702c5SYu Xiangning MBLKP mp; 1440f1702c5SYu Xiangning struct stroptions *stropt; 1450f1702c5SYu Xiangning 1460f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 1470f1702c5SYu Xiangning return (B_FALSE); 1480f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 1490f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 1500f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 1510f1702c5SYu Xiangning stropt->so_flags = SO_MAXBLK; 1520f1702c5SYu Xiangning stropt->so_maxblk = size; 1530f1702c5SYu Xiangning putnext(q, mp); 1540f1702c5SYu Xiangning } 1550f1702c5SYu Xiangning return (B_TRUE); 1560f1702c5SYu Xiangning } 1570f1702c5SYu Xiangning 1580f1702c5SYu Xiangning boolean_t 1590f1702c5SYu Xiangning proto_set_tx_copyopt(queue_t *q, conn_t *connp, int copyopt) 1600f1702c5SYu Xiangning { 1610f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 1620f1702c5SYu Xiangning struct sock_proto_props sopp; 1630f1702c5SYu Xiangning 1640f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_ZCOPY; 1650f1702c5SYu Xiangning sopp.sopp_zcopyflag = (ushort_t)copyopt; 1660f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 1670f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 1680f1702c5SYu Xiangning } else { 1690f1702c5SYu Xiangning MBLKP mp; 1700f1702c5SYu Xiangning struct stroptions *stropt; 1710f1702c5SYu Xiangning 1720f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 1730f1702c5SYu Xiangning return (B_FALSE); 1740f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 1750f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 1760f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 1770f1702c5SYu Xiangning stropt->so_flags = SO_COPYOPT; 1780f1702c5SYu Xiangning stropt->so_copyopt = (ushort_t)copyopt; 1790f1702c5SYu Xiangning putnext(q, mp); 1800f1702c5SYu Xiangning } 1810f1702c5SYu Xiangning return (B_TRUE); 1820f1702c5SYu Xiangning } 1830f1702c5SYu Xiangning 1840f1702c5SYu Xiangning boolean_t 1850f1702c5SYu Xiangning proto_set_tx_wroff(queue_t *q, conn_t *connp, size_t size) 1860f1702c5SYu Xiangning { 1870f1702c5SYu Xiangning if (connp != NULL && IPCL_IS_NONSTR(connp)) { 1880f1702c5SYu Xiangning struct sock_proto_props sopp; 1890f1702c5SYu Xiangning 1900f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_WROFF; 1910f1702c5SYu Xiangning sopp.sopp_wroff = size; 1920f1702c5SYu Xiangning 1930f1702c5SYu Xiangning /* XXX workaround for CR6757374 */ 1940f1702c5SYu Xiangning if (connp->conn_upper_handle != NULL) 1950f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 1960f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 1970f1702c5SYu Xiangning } else { 1980f1702c5SYu Xiangning 1990f1702c5SYu Xiangning MBLKP mp; 2000f1702c5SYu Xiangning struct stroptions *stropt; 2010f1702c5SYu Xiangning if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 2020f1702c5SYu Xiangning return (B_FALSE); 2030f1702c5SYu Xiangning mp->b_datap->db_type = M_SETOPTS; 2040f1702c5SYu Xiangning mp->b_wptr += sizeof (*stropt); 2050f1702c5SYu Xiangning stropt = (struct stroptions *)mp->b_rptr; 2060f1702c5SYu Xiangning stropt->so_flags = SO_WROFF; 2070f1702c5SYu Xiangning stropt->so_wroff = (ushort_t)size; 2080f1702c5SYu Xiangning putnext(q, mp); 2090f1702c5SYu Xiangning } 2100f1702c5SYu Xiangning return (B_TRUE); 2110f1702c5SYu Xiangning } 2120f1702c5SYu Xiangning 2130f1702c5SYu Xiangning /* 2140f1702c5SYu Xiangning * set OOBINLINE processing on the socket 2150f1702c5SYu Xiangning */ 2160f1702c5SYu Xiangning void 2170f1702c5SYu Xiangning proto_set_rx_oob_opt(conn_t *connp, boolean_t onoff) 2180f1702c5SYu Xiangning { 2190f1702c5SYu Xiangning struct sock_proto_props sopp; 2200f1702c5SYu Xiangning 2210f1702c5SYu Xiangning ASSERT(IPCL_IS_NONSTR(connp)); 2220f1702c5SYu Xiangning 2230f1702c5SYu Xiangning sopp.sopp_flags = SOCKOPT_OOBINLINE; 2240f1702c5SYu Xiangning sopp.sopp_oobinline = onoff; 2250f1702c5SYu Xiangning (*connp->conn_upcalls->su_set_proto_props) 2260f1702c5SYu Xiangning (connp->conn_upper_handle, &sopp); 2270f1702c5SYu Xiangning } 2280f1702c5SYu Xiangning 2290f1702c5SYu Xiangning /* 2300f1702c5SYu Xiangning * Translate a TLI(/XTI) error into a system error as best we can. 2310f1702c5SYu Xiangning */ 2320f1702c5SYu Xiangning static const int tli_errs[] = { 2330f1702c5SYu Xiangning 0, /* no error */ 2340f1702c5SYu Xiangning EADDRNOTAVAIL, /* TBADADDR */ 2350f1702c5SYu Xiangning ENOPROTOOPT, /* TBADOPT */ 2360f1702c5SYu Xiangning EACCES, /* TACCES */ 2370f1702c5SYu Xiangning EBADF, /* TBADF */ 2380f1702c5SYu Xiangning EADDRNOTAVAIL, /* TNOADDR */ 2390f1702c5SYu Xiangning EPROTO, /* TOUTSTATE */ 2400f1702c5SYu Xiangning ECONNABORTED, /* TBADSEQ */ 2410f1702c5SYu Xiangning 0, /* TSYSERR - will never get */ 2420f1702c5SYu Xiangning EPROTO, /* TLOOK - should never be sent by transport */ 2430f1702c5SYu Xiangning EMSGSIZE, /* TBADDATA */ 2440f1702c5SYu Xiangning EMSGSIZE, /* TBUFOVFLW */ 2450f1702c5SYu Xiangning EPROTO, /* TFLOW */ 2460f1702c5SYu Xiangning EWOULDBLOCK, /* TNODATA */ 2470f1702c5SYu Xiangning EPROTO, /* TNODIS */ 2480f1702c5SYu Xiangning EPROTO, /* TNOUDERR */ 2490f1702c5SYu Xiangning EINVAL, /* TBADFLAG */ 2500f1702c5SYu Xiangning EPROTO, /* TNOREL */ 2510f1702c5SYu Xiangning EOPNOTSUPP, /* TNOTSUPPORT */ 2520f1702c5SYu Xiangning EPROTO, /* TSTATECHNG */ 2530f1702c5SYu Xiangning /* following represent error namespace expansion with XTI */ 2540f1702c5SYu Xiangning EPROTO, /* TNOSTRUCTYPE - never sent by transport */ 2550f1702c5SYu Xiangning EPROTO, /* TBADNAME - never sent by transport */ 2560f1702c5SYu Xiangning EPROTO, /* TBADQLEN - never sent by transport */ 2570f1702c5SYu Xiangning EADDRINUSE, /* TADDRBUSY */ 2580f1702c5SYu Xiangning EBADF, /* TINDOUT */ 2590f1702c5SYu Xiangning EBADF, /* TPROVMISMATCH */ 2600f1702c5SYu Xiangning EBADF, /* TRESQLEN */ 2610f1702c5SYu Xiangning EBADF, /* TRESADDR */ 2620f1702c5SYu Xiangning EPROTO, /* TQFULL - never sent by transport */ 2630f1702c5SYu Xiangning EPROTO, /* TPROTO */ 2640f1702c5SYu Xiangning }; 2650f1702c5SYu Xiangning 2660f1702c5SYu Xiangning int 2670f1702c5SYu Xiangning proto_tlitosyserr(int terr) 2680f1702c5SYu Xiangning { 2690f1702c5SYu Xiangning ASSERT(terr != TSYSERR); 2700f1702c5SYu Xiangning if (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))) 2710f1702c5SYu Xiangning return (EPROTO); 2720f1702c5SYu Xiangning else 2730f1702c5SYu Xiangning return (tli_errs[terr]); 2740f1702c5SYu Xiangning } 2750f1702c5SYu Xiangning 2760f1702c5SYu Xiangning /* 2770f1702c5SYu Xiangning * Verify that address is suitable for connect/sendmsg and is aligned properly 2780f1702c5SYu Xiangning * Since this is a generic function we do not test for port being zero 2790f1702c5SYu Xiangning * as some protocols like icmp do not require a port 2800f1702c5SYu Xiangning */ 2810f1702c5SYu Xiangning int 2820f1702c5SYu Xiangning proto_verify_ip_addr(int family, const struct sockaddr *name, socklen_t namelen) 2830f1702c5SYu Xiangning { 2840f1702c5SYu Xiangning 2850f1702c5SYu Xiangning if (name == NULL || !OK_32PTR((char *)name)) 2860f1702c5SYu Xiangning return (EINVAL); 2870f1702c5SYu Xiangning 2880f1702c5SYu Xiangning switch (family) { 2890f1702c5SYu Xiangning case AF_INET: 2900f1702c5SYu Xiangning if (name->sa_family != AF_INET) { 2910f1702c5SYu Xiangning return (EAFNOSUPPORT); 2920f1702c5SYu Xiangning } 2930f1702c5SYu Xiangning 2940f1702c5SYu Xiangning if (namelen != (socklen_t)sizeof (struct sockaddr_in)) { 2950f1702c5SYu Xiangning return (EINVAL); 2960f1702c5SYu Xiangning } 2970f1702c5SYu Xiangning break; 2980f1702c5SYu Xiangning case AF_INET6: { 2990f1702c5SYu Xiangning #ifdef DEBUG 3000f1702c5SYu Xiangning struct sockaddr_in6 *sin6; 3010f1702c5SYu Xiangning #endif /* DEBUG */ 3020f1702c5SYu Xiangning 3030f1702c5SYu Xiangning if (name->sa_family != AF_INET6) { 3040f1702c5SYu Xiangning return (EAFNOSUPPORT); 3050f1702c5SYu Xiangning } 3060f1702c5SYu Xiangning if (namelen != (socklen_t)sizeof (struct sockaddr_in6)) { 3070f1702c5SYu Xiangning return (EINVAL); 3080f1702c5SYu Xiangning } 3090f1702c5SYu Xiangning #ifdef DEBUG 3100f1702c5SYu Xiangning /* Verify that apps don't forget to clear sin6_scope_id etc */ 3110f1702c5SYu Xiangning sin6 = (struct sockaddr_in6 *)name; 3120f1702c5SYu Xiangning if (sin6->sin6_scope_id != 0 && 3130f1702c5SYu Xiangning !IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { 3140f1702c5SYu Xiangning zcmn_err(getzoneid(), CE_WARN, 3150f1702c5SYu Xiangning "connect/send* with uninitialized sin6_scope_id " 3160f1702c5SYu Xiangning "(%d) on socket. Pid = %d\n", 3170f1702c5SYu Xiangning (int)sin6->sin6_scope_id, (int)curproc->p_pid); 3180f1702c5SYu Xiangning } 3190f1702c5SYu Xiangning #endif /* DEBUG */ 3200f1702c5SYu Xiangning break; 3210f1702c5SYu Xiangning } 3220f1702c5SYu Xiangning default: 3230f1702c5SYu Xiangning return (EINVAL); 3240f1702c5SYu Xiangning } 3250f1702c5SYu Xiangning 3260f1702c5SYu Xiangning return (0); 3270f1702c5SYu Xiangning } 3280f1702c5SYu Xiangning 3290f1702c5SYu Xiangning /* 3300f1702c5SYu Xiangning * Do a lookup of the options in the array. 3310f1702c5SYu Xiangning * Rerurn NULL if there isn't a match. 3320f1702c5SYu Xiangning */ 3330f1702c5SYu Xiangning opdes_t * 3340f1702c5SYu Xiangning proto_opt_lookup(t_uscalar_t level, t_uscalar_t name, opdes_t *opt_arr, 3350f1702c5SYu Xiangning uint_t opt_arr_cnt) 3360f1702c5SYu Xiangning { 3370f1702c5SYu Xiangning opdes_t *optd; 3380f1702c5SYu Xiangning 3390f1702c5SYu Xiangning for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; 3400f1702c5SYu Xiangning optd++) { 3410f1702c5SYu Xiangning if (level == (uint_t)optd->opdes_level && 3420f1702c5SYu Xiangning name == (uint_t)optd->opdes_name) 3430f1702c5SYu Xiangning return (optd); 3440f1702c5SYu Xiangning } 3450f1702c5SYu Xiangning return (NULL); 3460f1702c5SYu Xiangning } 3470f1702c5SYu Xiangning 3480f1702c5SYu Xiangning /* 3490f1702c5SYu Xiangning * Do a lookup of the options in the array and do permission and length checking 3500f1702c5SYu Xiangning * Returns zero if there is no error (note: for non-tpi-providers not being able 351*bd670b35SErik Nordmark * to find the option is not an error). TPI errors are returned as negative 352*bd670b35SErik Nordmark * numbers and errnos as positive numbers. 353*bd670b35SErik Nordmark * If max_len is set we update it based on the max length of the option. 3540f1702c5SYu Xiangning */ 3550f1702c5SYu Xiangning int 3560f1702c5SYu Xiangning proto_opt_check(int level, int name, int len, t_uscalar_t *max_len, 357*bd670b35SErik Nordmark opdes_t *opt_arr, uint_t opt_arr_cnt, boolean_t negotiate, boolean_t check, 358*bd670b35SErik Nordmark cred_t *cr) 3590f1702c5SYu Xiangning { 3600f1702c5SYu Xiangning opdes_t *optd; 3610f1702c5SYu Xiangning 3620f1702c5SYu Xiangning /* Find the option in the opt_arr. */ 363*bd670b35SErik Nordmark optd = proto_opt_lookup(level, name, opt_arr, opt_arr_cnt); 364*bd670b35SErik Nordmark if (optd == NULL) 3650f1702c5SYu Xiangning return (-TBADOPT); 3660f1702c5SYu Xiangning 3670f1702c5SYu Xiangning /* Additional checks dependent on operation. */ 3680f1702c5SYu Xiangning if (negotiate) { 3690f1702c5SYu Xiangning /* Cannot be true at the same time */ 3700f1702c5SYu Xiangning ASSERT(check == B_FALSE); 3710f1702c5SYu Xiangning 3720f1702c5SYu Xiangning if (!OA_WRITE_OR_EXECUTE(optd, cr)) { 3730f1702c5SYu Xiangning /* can't negotiate option */ 3740f1702c5SYu Xiangning if (!(OA_MATCHED_PRIV(optd, cr)) && 3750f1702c5SYu Xiangning OA_WX_ANYPRIV(optd)) { 3760f1702c5SYu Xiangning /* 3770f1702c5SYu Xiangning * not privileged but privilege 3780f1702c5SYu Xiangning * will help negotiate option. 3790f1702c5SYu Xiangning */ 3800f1702c5SYu Xiangning return (-TACCES); 3810f1702c5SYu Xiangning } else { 3820f1702c5SYu Xiangning return (-TBADOPT); 3830f1702c5SYu Xiangning } 3840f1702c5SYu Xiangning } 3850f1702c5SYu Xiangning /* 3860f1702c5SYu Xiangning * Verify size for options 3870f1702c5SYu Xiangning * Note: For retaining compatibility with historical 3880f1702c5SYu Xiangning * behavior, variable lengths options will have their 3890f1702c5SYu Xiangning * length verified in the setfn() processing. 3900f1702c5SYu Xiangning * In order to be compatible with SunOS 4.X we return 3910f1702c5SYu Xiangning * EINVAL errors for bad lengths. 3920f1702c5SYu Xiangning */ 3930f1702c5SYu Xiangning if (!(optd->opdes_props & OP_VARLEN)) { 3940f1702c5SYu Xiangning /* fixed length - size must match */ 3950f1702c5SYu Xiangning if (len != optd->opdes_size) { 3960f1702c5SYu Xiangning return (EINVAL); 3970f1702c5SYu Xiangning } 3980f1702c5SYu Xiangning } 3990f1702c5SYu Xiangning } else { 4000f1702c5SYu Xiangning if (check) { 4010f1702c5SYu Xiangning if (!OA_RWX_ANYPRIV(optd)) 4020f1702c5SYu Xiangning /* any of "rwx" permission but not none */ 4030f1702c5SYu Xiangning return (-TBADOPT); 4040f1702c5SYu Xiangning } 4050f1702c5SYu Xiangning /* 4060f1702c5SYu Xiangning * XXX Since T_CURRENT was not there in TLI and the 4070f1702c5SYu Xiangning * official TLI inspired TPI standard, getsockopt() 4080f1702c5SYu Xiangning * API uses T_CHECK (for T_CURRENT semantics) 409*bd670b35SErik Nordmark * Thus T_CHECK includes the T_CURRENT semantics due to that 410*bd670b35SErik Nordmark * historical use. 4110f1702c5SYu Xiangning */ 4120f1702c5SYu Xiangning if (!OA_READ_PERMISSION(optd, cr)) { 4130f1702c5SYu Xiangning /* can't read option value */ 4140f1702c5SYu Xiangning if (!(OA_MATCHED_PRIV(optd, cr)) && 4150f1702c5SYu Xiangning OA_R_ANYPRIV(optd)) { 4160f1702c5SYu Xiangning /* 4170f1702c5SYu Xiangning * not privileged but privilege 4180f1702c5SYu Xiangning * will help in reading option value. 4190f1702c5SYu Xiangning */ 4200f1702c5SYu Xiangning return (-TACCES); 4210f1702c5SYu Xiangning } else { 4220f1702c5SYu Xiangning return (-TBADOPT); 4230f1702c5SYu Xiangning } 4240f1702c5SYu Xiangning } 4250f1702c5SYu Xiangning } 4260f1702c5SYu Xiangning if (max_len != NULL) 4270f1702c5SYu Xiangning *max_len = optd->opdes_size; 4280f1702c5SYu Xiangning 4290f1702c5SYu Xiangning /* We liked it. Keep going. */ 4300f1702c5SYu Xiangning return (0); 4310f1702c5SYu Xiangning } 432