1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * This file contains common code for handling Options Management requests. 32*7c478bd9Sstevel@tonic-gate */ 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 40*7c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 41*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/timod.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> /* for ASSERT */ 47*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #include <inet/common.h> 50*7c478bd9Sstevel@tonic-gate #include <inet/mi.h> 51*7c478bd9Sstevel@tonic-gate #include <inet/nd.h> 52*7c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 53*7c478bd9Sstevel@tonic-gate #include <inet/ip.h> 54*7c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 55*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 56*7c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 57*7c478bd9Sstevel@tonic-gate #include <netinet/ip_mroute.h> 58*7c478bd9Sstevel@tonic-gate #include "optcom.h" 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* 63*7c478bd9Sstevel@tonic-gate * Function prototypes 64*7c478bd9Sstevel@tonic-gate */ 65*7c478bd9Sstevel@tonic-gate static t_scalar_t process_topthdrs_first_pass(mblk_t *, cred_t *, optdb_obj_t *, 66*7c478bd9Sstevel@tonic-gate boolean_t *, size_t *); 67*7c478bd9Sstevel@tonic-gate static t_scalar_t do_options_second_pass(queue_t *q, mblk_t *reqmp, 68*7c478bd9Sstevel@tonic-gate mblk_t *ack_mp, cred_t *, optdb_obj_t *dbobjp, 69*7c478bd9Sstevel@tonic-gate mblk_t *first_mp, boolean_t is_restart, boolean_t *queued_statusp); 70*7c478bd9Sstevel@tonic-gate static t_uscalar_t get_worst_status(t_uscalar_t, t_uscalar_t); 71*7c478bd9Sstevel@tonic-gate static int do_opt_default(queue_t *, struct T_opthdr *, uchar_t **, 72*7c478bd9Sstevel@tonic-gate t_uscalar_t *, cred_t *, optdb_obj_t *); 73*7c478bd9Sstevel@tonic-gate static void do_opt_current(queue_t *, struct T_opthdr *, uchar_t **, 74*7c478bd9Sstevel@tonic-gate t_uscalar_t *, cred_t *cr, optdb_obj_t *); 75*7c478bd9Sstevel@tonic-gate static int do_opt_check_or_negotiate(queue_t *q, struct T_opthdr *reqopt, 76*7c478bd9Sstevel@tonic-gate uint_t optset_context, uchar_t **resptrp, t_uscalar_t *worst_statusp, 77*7c478bd9Sstevel@tonic-gate cred_t *, optdb_obj_t *dbobjp, mblk_t *first_mp); 78*7c478bd9Sstevel@tonic-gate static opdes_t *opt_chk_lookup(t_uscalar_t, t_uscalar_t, opdes_t *, uint_t); 79*7c478bd9Sstevel@tonic-gate static boolean_t opt_level_valid(t_uscalar_t, optlevel_t *, uint_t); 80*7c478bd9Sstevel@tonic-gate static size_t opt_level_allopts_lengths(t_uscalar_t, opdes_t *, uint_t); 81*7c478bd9Sstevel@tonic-gate static boolean_t opt_length_ok(opdes_t *, struct T_opthdr *); 82*7c478bd9Sstevel@tonic-gate static t_uscalar_t optcom_max_optbuf_len(opdes_t *, uint_t); 83*7c478bd9Sstevel@tonic-gate static boolean_t opt_bloated_maxsize(opdes_t *); 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate extern optdb_obj_t tcp_opt_obj; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* Common code for sending back a T_ERROR_ACK. */ 88*7c478bd9Sstevel@tonic-gate void 89*7c478bd9Sstevel@tonic-gate optcom_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error) 90*7c478bd9Sstevel@tonic-gate { 91*7c478bd9Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 92*7c478bd9Sstevel@tonic-gate qreply(q, mp); 93*7c478bd9Sstevel@tonic-gate } 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* 96*7c478bd9Sstevel@tonic-gate * The option management routines svr4_optcom_req() and tpi_optcom_req() use 97*7c478bd9Sstevel@tonic-gate * callback functions as arguments. Here is the expected interfaces 98*7c478bd9Sstevel@tonic-gate * assumed from the callback functions 99*7c478bd9Sstevel@tonic-gate * 100*7c478bd9Sstevel@tonic-gate * 101*7c478bd9Sstevel@tonic-gate * (1) deffn(q, optlevel, optname, optvalp) 102*7c478bd9Sstevel@tonic-gate * 103*7c478bd9Sstevel@tonic-gate * - Function only called when default value comes from protocol 104*7c478bd9Sstevel@tonic-gate * specific code and not the option database table (indicated by 105*7c478bd9Sstevel@tonic-gate * OP_DEF_FN property in option database.) 106*7c478bd9Sstevel@tonic-gate * - Error return is -1. Valid returns are >=0. 107*7c478bd9Sstevel@tonic-gate * - When valid, the return value represents the length used for storing 108*7c478bd9Sstevel@tonic-gate * the default value of the option. 109*7c478bd9Sstevel@tonic-gate * - Error return implies the called routine did not recognize this 110*7c478bd9Sstevel@tonic-gate * option. Something downstream could so input is left unchanged 111*7c478bd9Sstevel@tonic-gate * in request buffer. 112*7c478bd9Sstevel@tonic-gate * 113*7c478bd9Sstevel@tonic-gate * (2) getfn(q, optlevel, optname, optvalp) 114*7c478bd9Sstevel@tonic-gate * 115*7c478bd9Sstevel@tonic-gate * - Error return is -1. Valid returns are >=0. 116*7c478bd9Sstevel@tonic-gate * - When valid, the return value represents the length used for storing 117*7c478bd9Sstevel@tonic-gate * the actual value of the option. 118*7c478bd9Sstevel@tonic-gate * - Error return implies the called routine did not recognize this 119*7c478bd9Sstevel@tonic-gate * option. Something downstream could so input is left unchanged 120*7c478bd9Sstevel@tonic-gate * in request buffer. 121*7c478bd9Sstevel@tonic-gate * 122*7c478bd9Sstevel@tonic-gate * (3) setfn(q, optset_context, optlevel, optname, inlen, invalp, 123*7c478bd9Sstevel@tonic-gate * outlenp, outvalp, attrp, cr); 124*7c478bd9Sstevel@tonic-gate * 125*7c478bd9Sstevel@tonic-gate * - OK return is 0, Error code is returned as a non-zero argument. 126*7c478bd9Sstevel@tonic-gate * - If negative it is ignored by svr4_optcom_req(). If positive, error 127*7c478bd9Sstevel@tonic-gate * is returned. A negative return implies that option, while handled on 128*7c478bd9Sstevel@tonic-gate * this stack is not handled at this level and will be handled further 129*7c478bd9Sstevel@tonic-gate * downstream. 130*7c478bd9Sstevel@tonic-gate * - Both negative and positive errors are treats as errors in an 131*7c478bd9Sstevel@tonic-gate * identical manner by tpi_optcom_req(). The errors affect "status" 132*7c478bd9Sstevel@tonic-gate * field of each option's T_opthdr. If sucessfull, an appropriate sucess 133*7c478bd9Sstevel@tonic-gate * result is carried. If error, it instantiated to "failure" at the 134*7c478bd9Sstevel@tonic-gate * topmost level and left unchanged at other levels. (This "failure" can 135*7c478bd9Sstevel@tonic-gate * turn to a success at another level). 136*7c478bd9Sstevel@tonic-gate * - optset_context passed for tpi_optcom_req(). It is interpreted as: 137*7c478bd9Sstevel@tonic-gate * - SETFN_OPTCOM_CHECKONLY 138*7c478bd9Sstevel@tonic-gate * semantics are to pretend to set the value and report 139*7c478bd9Sstevel@tonic-gate * back if it would be successful. 140*7c478bd9Sstevel@tonic-gate * This is used with T_CHECK semantics in XTI 141*7c478bd9Sstevel@tonic-gate * - SETFN_OPTCOM_NEGOTIATE 142*7c478bd9Sstevel@tonic-gate * set the value. Call from option management primitive 143*7c478bd9Sstevel@tonic-gate * T_OPTMGMT_REQ when T_NEGOTIATE flags is used. 144*7c478bd9Sstevel@tonic-gate * - SETFN_UD_NEGOTIATE 145*7c478bd9Sstevel@tonic-gate * option request came riding on UNITDATA primitive most often 146*7c478bd9Sstevel@tonic-gate * has "this datagram" semantics to influence prpoerties 147*7c478bd9Sstevel@tonic-gate * affecting an outgoig datagram or associated with recived 148*7c478bd9Sstevel@tonic-gate * datagram 149*7c478bd9Sstevel@tonic-gate * [ Note: XTI permits this use outside of "this datagram" 150*7c478bd9Sstevel@tonic-gate * semantics also and permits setting "management related" 151*7c478bd9Sstevel@tonic-gate * options in this context and its test suite enforces it ] 152*7c478bd9Sstevel@tonic-gate * - SETFN_CONN_NEGOTATE 153*7c478bd9Sstevel@tonic-gate * option request came riding on CONN_REQ/RES primitive and 154*7c478bd9Sstevel@tonic-gate * most often has "this connection" (negotiation during 155*7c478bd9Sstevel@tonic-gate * "connection estblishment") semantics. 156*7c478bd9Sstevel@tonic-gate * [ Note: XTI permits use of these outside of "this connection" 157*7c478bd9Sstevel@tonic-gate * semantics and permits "management related" options in this 158*7c478bd9Sstevel@tonic-gate * context and its test suite enforces it. ] 159*7c478bd9Sstevel@tonic-gate * 160*7c478bd9Sstevel@tonic-gate * - inlen, invalp is the option length,value requested to be set. 161*7c478bd9Sstevel@tonic-gate * - outlenp, outvalp represent return parameters which contain the 162*7c478bd9Sstevel@tonic-gate * value set and it might be different from one passed on input. 163*7c478bd9Sstevel@tonic-gate * - attrp points to a data structure that's used by v6 modules to 164*7c478bd9Sstevel@tonic-gate * store ancillary data options or sticky options. 165*7c478bd9Sstevel@tonic-gate * - cr points to the caller's credentials 166*7c478bd9Sstevel@tonic-gate * - the caller might pass same buffers for input and output and the 167*7c478bd9Sstevel@tonic-gate * routine should protect against this case by not updating output 168*7c478bd9Sstevel@tonic-gate * buffers until it is done referencing input buffers and any other 169*7c478bd9Sstevel@tonic-gate * issues (e.g. not use bcopy() if we do not trust what it does). 170*7c478bd9Sstevel@tonic-gate * - If option is not known, it returns error. We randomly pick EINVAL. 171*7c478bd9Sstevel@tonic-gate * It can however get called with options that are handled downstream 172*7c478bd9Sstevel@tonic-gate * opr upstream so for svr4_optcom_req(), it does not return error for 173*7c478bd9Sstevel@tonic-gate * negative return values. 174*7c478bd9Sstevel@tonic-gate * 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate /* 178*7c478bd9Sstevel@tonic-gate * Upper Level Protocols call this routine when they receive 179*7c478bd9Sstevel@tonic-gate * a T_SVR4_OPTMGMT_REQ message. They supply callback functions 180*7c478bd9Sstevel@tonic-gate * for setting a new value for a single options, getting the 181*7c478bd9Sstevel@tonic-gate * current value for a single option, and checking for support 182*7c478bd9Sstevel@tonic-gate * of a single option. svr4_optcom_req validates the option management 183*7c478bd9Sstevel@tonic-gate * buffer passed in, and calls the appropriate routines to do the 184*7c478bd9Sstevel@tonic-gate * job requested. 185*7c478bd9Sstevel@tonic-gate * XXX Code below needs some restructuring after we have some more 186*7c478bd9Sstevel@tonic-gate * macros to support 'struct opthdr' in the headers. 187*7c478bd9Sstevel@tonic-gate * 188*7c478bd9Sstevel@tonic-gate * IP-MT notes: The option management framework functions svr4_optcom_req() and 189*7c478bd9Sstevel@tonic-gate * tpi_optcom_req() allocate and prepend an M_CTL mblk to the actual 190*7c478bd9Sstevel@tonic-gate * T_optmgmt_req mblk and pass the chain as an additional parameter to the 191*7c478bd9Sstevel@tonic-gate * protocol set functions. If a protocol set function (such as ip_opt_set) 192*7c478bd9Sstevel@tonic-gate * cannot process the option immediately it can return EINPROGRESS. ip_opt_set 193*7c478bd9Sstevel@tonic-gate * enqueues the message in the appropriate sq and returns EINPROGRESS. Later 194*7c478bd9Sstevel@tonic-gate * the sq framework arranges to restart this operation and passes control to 195*7c478bd9Sstevel@tonic-gate * the restart function ip_restart_optmgmt() which in turn calls 196*7c478bd9Sstevel@tonic-gate * svr4_optcom_req() or tpi_optcom_req() to restart the option processing. 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate int 199*7c478bd9Sstevel@tonic-gate svr4_optcom_req(queue_t *q, mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp) 200*7c478bd9Sstevel@tonic-gate { 201*7c478bd9Sstevel@tonic-gate pfi_t deffn = dbobjp->odb_deffn; 202*7c478bd9Sstevel@tonic-gate pfi_t getfn = dbobjp->odb_getfn; 203*7c478bd9Sstevel@tonic-gate opt_set_fn setfn = dbobjp->odb_setfn; 204*7c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 205*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 206*7c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 207*7c478bd9Sstevel@tonic-gate opt_restart_t *or; 208*7c478bd9Sstevel@tonic-gate struct opthdr *restart_opt; 209*7c478bd9Sstevel@tonic-gate boolean_t is_restart = B_FALSE; 210*7c478bd9Sstevel@tonic-gate mblk_t *first_mp; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate t_uscalar_t max_optbuf_len; 213*7c478bd9Sstevel@tonic-gate int len; 214*7c478bd9Sstevel@tonic-gate mblk_t *mp1 = NULL; 215*7c478bd9Sstevel@tonic-gate struct opthdr *next_opt; 216*7c478bd9Sstevel@tonic-gate struct opthdr *opt; 217*7c478bd9Sstevel@tonic-gate struct opthdr *opt1; 218*7c478bd9Sstevel@tonic-gate struct opthdr *opt_end; 219*7c478bd9Sstevel@tonic-gate struct opthdr *opt_start; 220*7c478bd9Sstevel@tonic-gate opdes_t *optd; 221*7c478bd9Sstevel@tonic-gate boolean_t pass_to_next = B_FALSE; 222*7c478bd9Sstevel@tonic-gate boolean_t pass_to_ip = B_FALSE; 223*7c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa; 224*7c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * Allocate M_CTL and prepend to the packet for restarting this 228*7c478bd9Sstevel@tonic-gate * option if needed. IP may need to queue and restart the option 229*7c478bd9Sstevel@tonic-gate * if it cannot obtain exclusive conditions immediately. Please see 230*7c478bd9Sstevel@tonic-gate * IP-MT notes before the start of svr4_optcom_req 231*7c478bd9Sstevel@tonic-gate */ 232*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) { 233*7c478bd9Sstevel@tonic-gate is_restart = B_TRUE; 234*7c478bd9Sstevel@tonic-gate first_mp = mp; 235*7c478bd9Sstevel@tonic-gate mp = mp->b_cont; 236*7c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr - mp->b_rptr >= 237*7c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_req)); 238*7c478bd9Sstevel@tonic-gate tor = (struct T_optmgmt_req *)mp->b_rptr; 239*7c478bd9Sstevel@tonic-gate ASSERT(tor->MGMT_flags == T_NEGOTIATE); 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 242*7c478bd9Sstevel@tonic-gate opt_start = or->or_start; 243*7c478bd9Sstevel@tonic-gate opt_end = or->or_end; 244*7c478bd9Sstevel@tonic-gate restart_opt = or->or_ropt; 245*7c478bd9Sstevel@tonic-gate goto restart; 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate tor = (struct T_optmgmt_req *)mp->b_rptr; 249*7c478bd9Sstevel@tonic-gate /* Verify message integrity. */ 250*7c478bd9Sstevel@tonic-gate if (mp->b_wptr - mp->b_rptr < sizeof (struct T_optmgmt_req)) 251*7c478bd9Sstevel@tonic-gate goto bad_opt; 252*7c478bd9Sstevel@tonic-gate /* Verify MGMT_flags legal */ 253*7c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 254*7c478bd9Sstevel@tonic-gate case T_DEFAULT: 255*7c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 256*7c478bd9Sstevel@tonic-gate case T_CURRENT: 257*7c478bd9Sstevel@tonic-gate case T_CHECK: 258*7c478bd9Sstevel@tonic-gate /* OK - legal request flags */ 259*7c478bd9Sstevel@tonic-gate break; 260*7c478bd9Sstevel@tonic-gate default: 261*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 262*7c478bd9Sstevel@tonic-gate return (0); 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_DEFAULT) { 265*7c478bd9Sstevel@tonic-gate /* Is it a request for default option settings? */ 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate /* 268*7c478bd9Sstevel@tonic-gate * Note: XXX TLI and TPI specification was unclear about 269*7c478bd9Sstevel@tonic-gate * semantics of T_DEFAULT and the following historical note 270*7c478bd9Sstevel@tonic-gate * and its interpretation is incorrect (it implies a request 271*7c478bd9Sstevel@tonic-gate * for default values of only the identified options not all. 272*7c478bd9Sstevel@tonic-gate * The semantics have been explained better in XTI spec.) 273*7c478bd9Sstevel@tonic-gate * However, we do not modify (comment or code) here to keep 274*7c478bd9Sstevel@tonic-gate * compatibility. 275*7c478bd9Sstevel@tonic-gate * We can rethink this if it ever becomes an issue. 276*7c478bd9Sstevel@tonic-gate * ----historical comment start------ 277*7c478bd9Sstevel@tonic-gate * As we understand it, the input buffer is meaningless 278*7c478bd9Sstevel@tonic-gate * so we ditch the message. A T_DEFAULT request is a 279*7c478bd9Sstevel@tonic-gate * request to obtain a buffer containing defaults for 280*7c478bd9Sstevel@tonic-gate * all supported options, so we allocate a maximum length 281*7c478bd9Sstevel@tonic-gate * reply. 282*7c478bd9Sstevel@tonic-gate * ----historical comment end ------- 283*7c478bd9Sstevel@tonic-gate */ 284*7c478bd9Sstevel@tonic-gate /* T_DEFAULT not passed down */ 285*7c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider == B_TRUE); 286*7c478bd9Sstevel@tonic-gate freemsg(mp); 287*7c478bd9Sstevel@tonic-gate max_optbuf_len = optcom_max_optbuf_len(opt_arr, 288*7c478bd9Sstevel@tonic-gate opt_arr_cnt); 289*7c478bd9Sstevel@tonic-gate mp = allocb(max_optbuf_len, BPRI_MED); 290*7c478bd9Sstevel@tonic-gate if (!mp) { 291*7c478bd9Sstevel@tonic-gate no_mem:; 292*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 293*7c478bd9Sstevel@tonic-gate return (0); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate /* Initialize the T_optmgmt_ack header. */ 297*7c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)mp->b_rptr; 298*7c478bd9Sstevel@tonic-gate bzero((char *)toa, max_optbuf_len); 299*7c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_ACK; 300*7c478bd9Sstevel@tonic-gate toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack); 301*7c478bd9Sstevel@tonic-gate /* TODO: Is T_DEFAULT the right thing to put in MGMT_flags? */ 302*7c478bd9Sstevel@tonic-gate toa->MGMT_flags = T_DEFAULT; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /* Now walk the table of options passed in */ 305*7c478bd9Sstevel@tonic-gate opt = (struct opthdr *)&toa[1]; 306*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 307*7c478bd9Sstevel@tonic-gate /* 308*7c478bd9Sstevel@tonic-gate * All the options in the table of options passed 309*7c478bd9Sstevel@tonic-gate * in are by definition supported by the protocol 310*7c478bd9Sstevel@tonic-gate * calling this function. 311*7c478bd9Sstevel@tonic-gate */ 312*7c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) 313*7c478bd9Sstevel@tonic-gate continue; 314*7c478bd9Sstevel@tonic-gate opt->level = optd->opdes_level; 315*7c478bd9Sstevel@tonic-gate opt->name = optd->opdes_name; 316*7c478bd9Sstevel@tonic-gate if (!(optd->opdes_props & OP_DEF_FN) || 317*7c478bd9Sstevel@tonic-gate ((len = (*deffn)(q, opt->level, 318*7c478bd9Sstevel@tonic-gate opt->name, (uchar_t *)&opt[1])) < 0)) { 319*7c478bd9Sstevel@tonic-gate /* 320*7c478bd9Sstevel@tonic-gate * Fill length and value from table. 321*7c478bd9Sstevel@tonic-gate * 322*7c478bd9Sstevel@tonic-gate * Default value not instantiated from function 323*7c478bd9Sstevel@tonic-gate * (or the protocol specific function failed it; 324*7c478bd9Sstevel@tonic-gate * In this interpretation of T_DEFAULT, this is 325*7c478bd9Sstevel@tonic-gate * the best we can do) 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate switch (optd->opdes_size) { 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * Since options are guaranteed aligned only 330*7c478bd9Sstevel@tonic-gate * on a 4 byte boundary (t_scalar_t) any 331*7c478bd9Sstevel@tonic-gate * option that is greater in size will default 332*7c478bd9Sstevel@tonic-gate * to the bcopy below 333*7c478bd9Sstevel@tonic-gate */ 334*7c478bd9Sstevel@tonic-gate case sizeof (int32_t): 335*7c478bd9Sstevel@tonic-gate *(int32_t *)&opt[1] = 336*7c478bd9Sstevel@tonic-gate (int32_t)optd->opdes_default; 337*7c478bd9Sstevel@tonic-gate break; 338*7c478bd9Sstevel@tonic-gate case sizeof (int16_t): 339*7c478bd9Sstevel@tonic-gate *(int16_t *)&opt[1] = 340*7c478bd9Sstevel@tonic-gate (int16_t)optd->opdes_default; 341*7c478bd9Sstevel@tonic-gate break; 342*7c478bd9Sstevel@tonic-gate case sizeof (int8_t): 343*7c478bd9Sstevel@tonic-gate *(int8_t *)&opt[1] = 344*7c478bd9Sstevel@tonic-gate (int8_t)optd->opdes_default; 345*7c478bd9Sstevel@tonic-gate break; 346*7c478bd9Sstevel@tonic-gate default: 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * other length but still assume 349*7c478bd9Sstevel@tonic-gate * fixed - use bcopy 350*7c478bd9Sstevel@tonic-gate */ 351*7c478bd9Sstevel@tonic-gate bcopy(optd->opdes_defbuf, 352*7c478bd9Sstevel@tonic-gate &opt[1], optd->opdes_size); 353*7c478bd9Sstevel@tonic-gate break; 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate opt->len = optd->opdes_size; 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate else 358*7c478bd9Sstevel@tonic-gate opt->len = (t_uscalar_t)len; 359*7c478bd9Sstevel@tonic-gate opt = (struct opthdr *)((char *)&opt[1] + 360*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 361*7c478bd9Sstevel@tonic-gate } 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* Now record the final length. */ 364*7c478bd9Sstevel@tonic-gate toa->OPT_length = (t_scalar_t)((char *)opt - (char *)&toa[1]); 365*7c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)opt; 366*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PCPROTO; 367*7c478bd9Sstevel@tonic-gate /* Ship it back. */ 368*7c478bd9Sstevel@tonic-gate qreply(q, mp); 369*7c478bd9Sstevel@tonic-gate return (0); 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate /* T_DEFAULT processing complete - no more T_DEFAULT */ 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* 374*7c478bd9Sstevel@tonic-gate * For T_NEGOTIATE, T_CURRENT, and T_CHECK requests, we make a 375*7c478bd9Sstevel@tonic-gate * pass through the input buffer validating the details and 376*7c478bd9Sstevel@tonic-gate * making sure each option is supported by the protocol. 377*7c478bd9Sstevel@tonic-gate */ 378*7c478bd9Sstevel@tonic-gate if ((opt_start = (struct opthdr *)mi_offset_param(mp, 379*7c478bd9Sstevel@tonic-gate tor->OPT_offset, tor->OPT_length)) == NULL) 380*7c478bd9Sstevel@tonic-gate goto bad_opt; 381*7c478bd9Sstevel@tonic-gate if (!__TPI_OPT_ISALIGNED(opt_start)) 382*7c478bd9Sstevel@tonic-gate goto bad_opt; 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate opt_end = (struct opthdr *)((uchar_t *)opt_start + 385*7c478bd9Sstevel@tonic-gate tor->OPT_length); 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate for (opt = opt_start; opt < opt_end; opt = next_opt) { 388*7c478bd9Sstevel@tonic-gate /* 389*7c478bd9Sstevel@tonic-gate * Verify we have room to reference the option header 390*7c478bd9Sstevel@tonic-gate * fields in the option buffer. 391*7c478bd9Sstevel@tonic-gate */ 392*7c478bd9Sstevel@tonic-gate if ((uchar_t *)opt + sizeof (struct opthdr) > 393*7c478bd9Sstevel@tonic-gate (uchar_t *)opt_end) 394*7c478bd9Sstevel@tonic-gate goto bad_opt; 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * We now compute pointer to next option in buffer 'next_opt' 397*7c478bd9Sstevel@tonic-gate * The next_opt computation above below 'opt->len' initialized 398*7c478bd9Sstevel@tonic-gate * by application which cannot be trusted. The usual value 399*7c478bd9Sstevel@tonic-gate * too large will be captured by the loop termination condition 400*7c478bd9Sstevel@tonic-gate * above. We check for the following which it will miss. 401*7c478bd9Sstevel@tonic-gate * -pointer space wraparound arithmetic overflow 402*7c478bd9Sstevel@tonic-gate * -last option in buffer with 'opt->len' being too large 403*7c478bd9Sstevel@tonic-gate * (only reason 'next_opt' should equal or exceed 404*7c478bd9Sstevel@tonic-gate * 'opt_end' for last option is roundup unless length is 405*7c478bd9Sstevel@tonic-gate * too-large/invalid) 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate next_opt = (struct opthdr *)((uchar_t *)&opt[1] + 408*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate if ((uchar_t *)next_opt < (uchar_t *)&opt[1] || 411*7c478bd9Sstevel@tonic-gate ((next_opt >= opt_end) && 412*7c478bd9Sstevel@tonic-gate (((uchar_t *)next_opt - (uchar_t *)opt_end) >= 413*7c478bd9Sstevel@tonic-gate __TPI_ALIGN_SIZE))) 414*7c478bd9Sstevel@tonic-gate goto bad_opt; 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* sanity check */ 417*7c478bd9Sstevel@tonic-gate if (opt->name == T_ALLOPT) 418*7c478bd9Sstevel@tonic-gate goto bad_opt; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* Find the option in the opt_arr. */ 421*7c478bd9Sstevel@tonic-gate if ((optd = opt_chk_lookup(opt->level, opt->name, 422*7c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt)) == NULL) { 423*7c478bd9Sstevel@tonic-gate /* 424*7c478bd9Sstevel@tonic-gate * Not found, that is a bad thing if 425*7c478bd9Sstevel@tonic-gate * the caller is a tpi provider 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 428*7c478bd9Sstevel@tonic-gate goto bad_opt; 429*7c478bd9Sstevel@tonic-gate else 430*7c478bd9Sstevel@tonic-gate continue; /* skip unmodified */ 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* Additional checks dependent on operation. */ 434*7c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 435*7c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 436*7c478bd9Sstevel@tonic-gate if (!OA_WRITE_OR_EXECUTE(optd, cr)) { 437*7c478bd9Sstevel@tonic-gate /* can't negotiate option */ 438*7c478bd9Sstevel@tonic-gate if (!(OA_MATCHED_PRIV(optd, cr)) && 439*7c478bd9Sstevel@tonic-gate OA_WX_ANYPRIV(optd)) { 440*7c478bd9Sstevel@tonic-gate /* 441*7c478bd9Sstevel@tonic-gate * not privileged but privilege 442*7c478bd9Sstevel@tonic-gate * will help negotiate option. 443*7c478bd9Sstevel@tonic-gate */ 444*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TACCES, 0); 445*7c478bd9Sstevel@tonic-gate return (0); 446*7c478bd9Sstevel@tonic-gate } else 447*7c478bd9Sstevel@tonic-gate goto bad_opt; 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate /* 450*7c478bd9Sstevel@tonic-gate * Verify size for options 451*7c478bd9Sstevel@tonic-gate * Note: For retaining compatibility with historical 452*7c478bd9Sstevel@tonic-gate * behavior, variable lengths options will have their 453*7c478bd9Sstevel@tonic-gate * length verified in the setfn() processing. 454*7c478bd9Sstevel@tonic-gate * In order to be compatible with SunOS 4.X we return 455*7c478bd9Sstevel@tonic-gate * EINVAL errors for bad lengths. 456*7c478bd9Sstevel@tonic-gate */ 457*7c478bd9Sstevel@tonic-gate if (!(optd->opdes_props & OP_VARLEN)) { 458*7c478bd9Sstevel@tonic-gate /* fixed length - size must match */ 459*7c478bd9Sstevel@tonic-gate if (opt->len != optd->opdes_size) { 460*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, EINVAL); 461*7c478bd9Sstevel@tonic-gate return (0); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate break; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate case T_CHECK: 467*7c478bd9Sstevel@tonic-gate if (!OA_RWX_ANYPRIV(optd)) 468*7c478bd9Sstevel@tonic-gate /* any of "rwx" permission but not not none */ 469*7c478bd9Sstevel@tonic-gate goto bad_opt; 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * XXX Since T_CURRENT was not there in TLI and the 472*7c478bd9Sstevel@tonic-gate * official TLI inspired TPI standard, getsockopt() 473*7c478bd9Sstevel@tonic-gate * API uses T_CHECK (for T_CURRENT semantics) 474*7c478bd9Sstevel@tonic-gate * The following fallthru makes sense because of its 475*7c478bd9Sstevel@tonic-gate * historical use as semantic equivalent to T_CURRENT. 476*7c478bd9Sstevel@tonic-gate */ 477*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 478*7c478bd9Sstevel@tonic-gate case T_CURRENT: 479*7c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) { 480*7c478bd9Sstevel@tonic-gate /* can't read option value */ 481*7c478bd9Sstevel@tonic-gate if (!(OA_MATCHED_PRIV(optd, cr)) && 482*7c478bd9Sstevel@tonic-gate OA_R_ANYPRIV(optd)) { 483*7c478bd9Sstevel@tonic-gate /* 484*7c478bd9Sstevel@tonic-gate * not privileged but privilege 485*7c478bd9Sstevel@tonic-gate * will help in reading option value. 486*7c478bd9Sstevel@tonic-gate */ 487*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TACCES, 0); 488*7c478bd9Sstevel@tonic-gate return (0); 489*7c478bd9Sstevel@tonic-gate } else 490*7c478bd9Sstevel@tonic-gate goto bad_opt; 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate break; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate default: 495*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 496*7c478bd9Sstevel@tonic-gate return (0); 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate /* We liked it. Keep going. */ 499*7c478bd9Sstevel@tonic-gate } /* end for loop scanning option buffer */ 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate /* Now complete the operation as required. */ 502*7c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 503*7c478bd9Sstevel@tonic-gate case T_CHECK: 504*7c478bd9Sstevel@tonic-gate /* 505*7c478bd9Sstevel@tonic-gate * Historically used same as T_CURRENT (which was added to 506*7c478bd9Sstevel@tonic-gate * standard later). Code retained for compatibility. 507*7c478bd9Sstevel@tonic-gate */ 508*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 509*7c478bd9Sstevel@tonic-gate case T_CURRENT: 510*7c478bd9Sstevel@tonic-gate /* 511*7c478bd9Sstevel@tonic-gate * Allocate a maximum size reply. Perhaps we are supposed to 512*7c478bd9Sstevel@tonic-gate * assume that the input buffer includes space for the answers 513*7c478bd9Sstevel@tonic-gate * as well as the opthdrs, but we don't know that for sure. 514*7c478bd9Sstevel@tonic-gate * So, instead, we create a new output buffer, using the 515*7c478bd9Sstevel@tonic-gate * input buffer only as a list of options. 516*7c478bd9Sstevel@tonic-gate */ 517*7c478bd9Sstevel@tonic-gate max_optbuf_len = optcom_max_optbuf_len(opt_arr, 518*7c478bd9Sstevel@tonic-gate opt_arr_cnt); 519*7c478bd9Sstevel@tonic-gate mp1 = allocb_cred(max_optbuf_len, cr); 520*7c478bd9Sstevel@tonic-gate if (!mp1) 521*7c478bd9Sstevel@tonic-gate goto no_mem; 522*7c478bd9Sstevel@tonic-gate /* Initialize the header. */ 523*7c478bd9Sstevel@tonic-gate mp1->b_datap->db_type = M_PCPROTO; 524*7c478bd9Sstevel@tonic-gate mp1->b_wptr = &mp1->b_rptr[sizeof (struct T_optmgmt_ack)]; 525*7c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)mp1->b_rptr; 526*7c478bd9Sstevel@tonic-gate toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack); 527*7c478bd9Sstevel@tonic-gate toa->MGMT_flags = tor->MGMT_flags; 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * Walk through the input buffer again, this time adding 530*7c478bd9Sstevel@tonic-gate * entries to the output buffer for each option requested. 531*7c478bd9Sstevel@tonic-gate * Note, sanity of option header, last option etc, verified 532*7c478bd9Sstevel@tonic-gate * in first pass. 533*7c478bd9Sstevel@tonic-gate */ 534*7c478bd9Sstevel@tonic-gate opt1 = (struct opthdr *)&toa[1]; 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate for (opt = opt_start; opt < opt_end; opt = next_opt) { 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate next_opt = (struct opthdr *)((uchar_t *)&opt[1] + 539*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate opt1->name = opt->name; 542*7c478bd9Sstevel@tonic-gate opt1->level = opt->level; 543*7c478bd9Sstevel@tonic-gate len = (*getfn)(q, opt->level, 544*7c478bd9Sstevel@tonic-gate opt->name, (uchar_t *)&opt1[1]); 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * Failure means option is not recognized. Copy input 547*7c478bd9Sstevel@tonic-gate * buffer as is 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate if (len < 0) { 550*7c478bd9Sstevel@tonic-gate opt1->len = opt->len; 551*7c478bd9Sstevel@tonic-gate bcopy(&opt[1], &opt1[1], opt->len); 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * Pass the option down to IP only if 554*7c478bd9Sstevel@tonic-gate * TCP hasn't processed it. 555*7c478bd9Sstevel@tonic-gate */ 556*7c478bd9Sstevel@tonic-gate if (dbobjp == &tcp_opt_obj) 557*7c478bd9Sstevel@tonic-gate pass_to_ip = B_TRUE; 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate else 560*7c478bd9Sstevel@tonic-gate opt1->len = (t_uscalar_t)len; 561*7c478bd9Sstevel@tonic-gate opt1 = (struct opthdr *)((uchar_t *)&opt1[1] + 562*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt1->len)); 563*7c478bd9Sstevel@tonic-gate } /* end for loop */ 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate /* Record the final length. */ 566*7c478bd9Sstevel@tonic-gate toa->OPT_length = (t_scalar_t)((uchar_t *)opt1 - 567*7c478bd9Sstevel@tonic-gate (uchar_t *)&toa[1]); 568*7c478bd9Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)opt1; 569*7c478bd9Sstevel@tonic-gate /* Ditch the input buffer. */ 570*7c478bd9Sstevel@tonic-gate freemsg(mp); 571*7c478bd9Sstevel@tonic-gate mp = mp1; 572*7c478bd9Sstevel@tonic-gate /* Always let the next module look at the option. */ 573*7c478bd9Sstevel@tonic-gate pass_to_next = B_TRUE; 574*7c478bd9Sstevel@tonic-gate break; 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 577*7c478bd9Sstevel@tonic-gate first_mp = allocb(sizeof (opt_restart_t), BPRI_LO); 578*7c478bd9Sstevel@tonic-gate if (first_mp == NULL) { 579*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 580*7c478bd9Sstevel@tonic-gate return (0); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate first_mp->b_datap->db_type = M_CTL; 583*7c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 584*7c478bd9Sstevel@tonic-gate or->or_start = opt_start; 585*7c478bd9Sstevel@tonic-gate or->or_end = opt_end; 586*7c478bd9Sstevel@tonic-gate or->or_type = T_SVR4_OPTMGMT_REQ; 587*7c478bd9Sstevel@tonic-gate or->or_private = 0; 588*7c478bd9Sstevel@tonic-gate first_mp->b_cont = mp; 589*7c478bd9Sstevel@tonic-gate restart: 590*7c478bd9Sstevel@tonic-gate /* 591*7c478bd9Sstevel@tonic-gate * Here we are expecting that the response buffer is exactly 592*7c478bd9Sstevel@tonic-gate * the same size as the input buffer. We pass each opthdr 593*7c478bd9Sstevel@tonic-gate * to the protocol's set function. If the protocol doesn't 594*7c478bd9Sstevel@tonic-gate * like it, it can update the value in it return argument. 595*7c478bd9Sstevel@tonic-gate */ 596*7c478bd9Sstevel@tonic-gate /* 597*7c478bd9Sstevel@tonic-gate * Pass each negotiated option through the protocol set 598*7c478bd9Sstevel@tonic-gate * function. 599*7c478bd9Sstevel@tonic-gate * Note: sanity check on option header values done in first 600*7c478bd9Sstevel@tonic-gate * pass and not repeated here. 601*7c478bd9Sstevel@tonic-gate */ 602*7c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)tor; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate for (opt = is_restart ? restart_opt: opt_start; opt < opt_end; 605*7c478bd9Sstevel@tonic-gate opt = next_opt) { 606*7c478bd9Sstevel@tonic-gate int error; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate /* 609*7c478bd9Sstevel@tonic-gate * Point to the current option in or, in case this 610*7c478bd9Sstevel@tonic-gate * option has to be restarted later on 611*7c478bd9Sstevel@tonic-gate */ 612*7c478bd9Sstevel@tonic-gate or->or_ropt = opt; 613*7c478bd9Sstevel@tonic-gate next_opt = (struct opthdr *)((uchar_t *)&opt[1] + 614*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate error = (*setfn)(q, SETFN_OPTCOM_NEGOTIATE, 617*7c478bd9Sstevel@tonic-gate opt->level, opt->name, 618*7c478bd9Sstevel@tonic-gate opt->len, (uchar_t *)&opt[1], 619*7c478bd9Sstevel@tonic-gate &opt->len, (uchar_t *)&opt[1], NULL, cr, first_mp); 620*7c478bd9Sstevel@tonic-gate /* 621*7c478bd9Sstevel@tonic-gate * Treat positive "errors" as real. 622*7c478bd9Sstevel@tonic-gate * Note: negative errors are to be treated as 623*7c478bd9Sstevel@tonic-gate * non-fatal by svr4_optcom_req() and are 624*7c478bd9Sstevel@tonic-gate * returned by setfn() when it is passed an 625*7c478bd9Sstevel@tonic-gate * option it does not handle. Since the option 626*7c478bd9Sstevel@tonic-gate * passed opt_chk_lookup(), it is implied that 627*7c478bd9Sstevel@tonic-gate * it is valid but was either handled upstream 628*7c478bd9Sstevel@tonic-gate * or will be handled downstream. 629*7c478bd9Sstevel@tonic-gate */ 630*7c478bd9Sstevel@tonic-gate if (error == EINPROGRESS) { 631*7c478bd9Sstevel@tonic-gate /* 632*7c478bd9Sstevel@tonic-gate * The message is queued and will be 633*7c478bd9Sstevel@tonic-gate * reprocessed later. Typically ip queued 634*7c478bd9Sstevel@tonic-gate * the message to get some exclusive conditions 635*7c478bd9Sstevel@tonic-gate * and later on calls this func again. 636*7c478bd9Sstevel@tonic-gate */ 637*7c478bd9Sstevel@tonic-gate return (EINPROGRESS); 638*7c478bd9Sstevel@tonic-gate } else if (error > 0) { 639*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, error); 640*7c478bd9Sstevel@tonic-gate freeb(first_mp); 641*7c478bd9Sstevel@tonic-gate return (0); 642*7c478bd9Sstevel@tonic-gate } else if (error < 0 && dbobjp == &tcp_opt_obj) { 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * Pass the option down to IP only if 645*7c478bd9Sstevel@tonic-gate * TCP hasn't processed it. 646*7c478bd9Sstevel@tonic-gate */ 647*7c478bd9Sstevel@tonic-gate pass_to_ip = B_TRUE; 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate /* Done with the restart control mp. */ 651*7c478bd9Sstevel@tonic-gate freeb(first_mp); 652*7c478bd9Sstevel@tonic-gate pass_to_next = B_TRUE; 653*7c478bd9Sstevel@tonic-gate break; 654*7c478bd9Sstevel@tonic-gate default: 655*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 656*7c478bd9Sstevel@tonic-gate return (0); 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate if (pass_to_next && (q->q_next != NULL || pass_to_ip)) { 660*7c478bd9Sstevel@tonic-gate /* Send it down to the next module and let it reply */ 661*7c478bd9Sstevel@tonic-gate toa->PRIM_type = T_SVR4_OPTMGMT_REQ; /* Changed by IP to ACK */ 662*7c478bd9Sstevel@tonic-gate if (q->q_next != NULL) 663*7c478bd9Sstevel@tonic-gate putnext(q, mp); 664*7c478bd9Sstevel@tonic-gate else 665*7c478bd9Sstevel@tonic-gate ip_output(Q_TO_CONN(q), mp, q, IP_WPUT); 666*7c478bd9Sstevel@tonic-gate } else { 667*7c478bd9Sstevel@tonic-gate /* Set common fields in the header. */ 668*7c478bd9Sstevel@tonic-gate toa->MGMT_flags = T_SUCCESS; 669*7c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PCPROTO; 670*7c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_ACK; 671*7c478bd9Sstevel@tonic-gate qreply(q, mp); 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate return (0); 674*7c478bd9Sstevel@tonic-gate bad_opt:; 675*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADOPT, 0); 676*7c478bd9Sstevel@tonic-gate return (0); 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate /* 680*7c478bd9Sstevel@tonic-gate * New optcom_req inspired by TPI/XTI semantics 681*7c478bd9Sstevel@tonic-gate */ 682*7c478bd9Sstevel@tonic-gate int 683*7c478bd9Sstevel@tonic-gate tpi_optcom_req(queue_t *q, mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp) 684*7c478bd9Sstevel@tonic-gate { 685*7c478bd9Sstevel@tonic-gate t_scalar_t t_error; 686*7c478bd9Sstevel@tonic-gate mblk_t *toa_mp; 687*7c478bd9Sstevel@tonic-gate boolean_t pass_to_next; 688*7c478bd9Sstevel@tonic-gate size_t toa_len; 689*7c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa; 690*7c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = 691*7c478bd9Sstevel@tonic-gate (struct T_optmgmt_req *)mp->b_rptr; 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate opt_restart_t *or; 694*7c478bd9Sstevel@tonic-gate boolean_t is_restart = B_FALSE; 695*7c478bd9Sstevel@tonic-gate mblk_t *first_mp = NULL; 696*7c478bd9Sstevel@tonic-gate t_uscalar_t worst_status; 697*7c478bd9Sstevel@tonic-gate boolean_t queued_status; 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate /* 700*7c478bd9Sstevel@tonic-gate * Allocate M_CTL and prepend to the packet for restarting this 701*7c478bd9Sstevel@tonic-gate * option if needed. IP may need to queue and restart the option 702*7c478bd9Sstevel@tonic-gate * if it cannot obtain exclusive conditions immediately. Please see 703*7c478bd9Sstevel@tonic-gate * IP-MT notes before the start of svr4_optcom_req 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) { 706*7c478bd9Sstevel@tonic-gate is_restart = B_TRUE; 707*7c478bd9Sstevel@tonic-gate first_mp = mp; 708*7c478bd9Sstevel@tonic-gate toa_mp = mp->b_cont; 709*7c478bd9Sstevel@tonic-gate mp = toa_mp->b_cont; 710*7c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr - mp->b_rptr >= 711*7c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_req)); 712*7c478bd9Sstevel@tonic-gate tor = (struct T_optmgmt_req *)mp->b_rptr; 713*7c478bd9Sstevel@tonic-gate ASSERT(tor->MGMT_flags == T_NEGOTIATE); 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 716*7c478bd9Sstevel@tonic-gate goto restart; 717*7c478bd9Sstevel@tonic-gate } 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate /* Verify message integrity. */ 720*7c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_optmgmt_req)) { 721*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADOPT, 0); 722*7c478bd9Sstevel@tonic-gate return (0); 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /* Verify MGMT_flags legal */ 726*7c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 727*7c478bd9Sstevel@tonic-gate case T_DEFAULT: 728*7c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 729*7c478bd9Sstevel@tonic-gate case T_CURRENT: 730*7c478bd9Sstevel@tonic-gate case T_CHECK: 731*7c478bd9Sstevel@tonic-gate /* OK - legal request flags */ 732*7c478bd9Sstevel@tonic-gate break; 733*7c478bd9Sstevel@tonic-gate default: 734*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 735*7c478bd9Sstevel@tonic-gate return (0); 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate /* 739*7c478bd9Sstevel@tonic-gate * In this design, there are two passes required on the input buffer 740*7c478bd9Sstevel@tonic-gate * mostly to accomodate variable length options and "T_ALLOPT" option 741*7c478bd9Sstevel@tonic-gate * which has the semantics "all options of the specified level". 742*7c478bd9Sstevel@tonic-gate * 743*7c478bd9Sstevel@tonic-gate * For T_DEFAULT, T_NEGOTIATE, T_CURRENT, and T_CHECK requests, we make 744*7c478bd9Sstevel@tonic-gate * a pass through the input buffer validating the details and making 745*7c478bd9Sstevel@tonic-gate * sure each option is supported by the protocol. We also determine the 746*7c478bd9Sstevel@tonic-gate * length of the option buffer to return. (Variable length options and 747*7c478bd9Sstevel@tonic-gate * T_ALLOPT mean that length can be different for output buffer). 748*7c478bd9Sstevel@tonic-gate */ 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate pass_to_next = B_FALSE; /* initial value */ 751*7c478bd9Sstevel@tonic-gate toa_len = 0; /* initial value */ 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate /* 754*7c478bd9Sstevel@tonic-gate * First pass, we do the following 755*7c478bd9Sstevel@tonic-gate * - estimate cumulative length needed for results 756*7c478bd9Sstevel@tonic-gate * - set "status" field based on permissions, option header check 757*7c478bd9Sstevel@tonic-gate * etc. 758*7c478bd9Sstevel@tonic-gate * - determine "pass_to_next" whether we need to send request to 759*7c478bd9Sstevel@tonic-gate * downstream module/driver. 760*7c478bd9Sstevel@tonic-gate */ 761*7c478bd9Sstevel@tonic-gate if ((t_error = process_topthdrs_first_pass(mp, cr, dbobjp, 762*7c478bd9Sstevel@tonic-gate &pass_to_next, &toa_len)) != 0) { 763*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, t_error, 0); 764*7c478bd9Sstevel@tonic-gate return (0); 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* 768*7c478bd9Sstevel@tonic-gate * A validation phase of the input buffer is done. We have also 769*7c478bd9Sstevel@tonic-gate * obtained the length requirement and and other details about the 770*7c478bd9Sstevel@tonic-gate * input and we liked input buffer so far. We make another scan 771*7c478bd9Sstevel@tonic-gate * through the input now and generate the output necessary to complete 772*7c478bd9Sstevel@tonic-gate * the operation. 773*7c478bd9Sstevel@tonic-gate */ 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate toa_mp = allocb_cred(toa_len, cr); 776*7c478bd9Sstevel@tonic-gate if (!toa_mp) { 777*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 778*7c478bd9Sstevel@tonic-gate return (0); 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate first_mp = allocb(sizeof (opt_restart_t), BPRI_LO); 782*7c478bd9Sstevel@tonic-gate if (first_mp == NULL) { 783*7c478bd9Sstevel@tonic-gate freeb(toa_mp); 784*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 785*7c478bd9Sstevel@tonic-gate return (0); 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate first_mp->b_datap->db_type = M_CTL; 788*7c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 789*7c478bd9Sstevel@tonic-gate /* 790*7c478bd9Sstevel@tonic-gate * Set initial values for generating output. 791*7c478bd9Sstevel@tonic-gate */ 792*7c478bd9Sstevel@tonic-gate or->or_worst_status = T_SUCCESS; 793*7c478bd9Sstevel@tonic-gate or->or_type = T_OPTMGMT_REQ; 794*7c478bd9Sstevel@tonic-gate or->or_private = 0; 795*7c478bd9Sstevel@tonic-gate /* remaining fields fileed in do_options_second_pass */ 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate restart: 798*7c478bd9Sstevel@tonic-gate /* 799*7c478bd9Sstevel@tonic-gate * This routine makes another pass through the option buffer this 800*7c478bd9Sstevel@tonic-gate * time acting on the request based on "status" result in the 801*7c478bd9Sstevel@tonic-gate * first pass. It also performs "expansion" of T_ALLOPT into 802*7c478bd9Sstevel@tonic-gate * all options of a certain level and acts on each for this request. 803*7c478bd9Sstevel@tonic-gate */ 804*7c478bd9Sstevel@tonic-gate if ((t_error = do_options_second_pass(q, mp, toa_mp, cr, dbobjp, 805*7c478bd9Sstevel@tonic-gate first_mp, is_restart, &queued_status)) != 0) { 806*7c478bd9Sstevel@tonic-gate freemsg(toa_mp); 807*7c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, t_error, 0); 808*7c478bd9Sstevel@tonic-gate return (0); 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate if (queued_status) { 811*7c478bd9Sstevel@tonic-gate /* Option will be restarted */ 812*7c478bd9Sstevel@tonic-gate return (EINPROGRESS); 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate worst_status = or->or_worst_status; 815*7c478bd9Sstevel@tonic-gate /* Done with the first mp */ 816*7c478bd9Sstevel@tonic-gate freeb(first_mp); 817*7c478bd9Sstevel@tonic-gate toa_mp->b_cont = NULL; 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate /* 820*7c478bd9Sstevel@tonic-gate * Following code relies on the coincidence that T_optmgmt_req 821*7c478bd9Sstevel@tonic-gate * and T_optmgmt_ack are identical in binary representation 822*7c478bd9Sstevel@tonic-gate */ 823*7c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)toa_mp->b_rptr; 824*7c478bd9Sstevel@tonic-gate toa->OPT_length = (t_scalar_t)(toa_mp->b_wptr - (toa_mp->b_rptr + 825*7c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_ack))); 826*7c478bd9Sstevel@tonic-gate toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack); 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate toa->MGMT_flags = tor->MGMT_flags; 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate freemsg(mp); /* free input mblk */ 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate /* 834*7c478bd9Sstevel@tonic-gate * If there is atleast one option that requires a downstream 835*7c478bd9Sstevel@tonic-gate * forwarding and if it is possible, we forward the message 836*7c478bd9Sstevel@tonic-gate * downstream. Else we ack it. 837*7c478bd9Sstevel@tonic-gate */ 838*7c478bd9Sstevel@tonic-gate if (pass_to_next && (q->q_next != NULL || dbobjp == &tcp_opt_obj)) { 839*7c478bd9Sstevel@tonic-gate /* 840*7c478bd9Sstevel@tonic-gate * We pass it down as T_OPTMGMT_REQ. This code relies 841*7c478bd9Sstevel@tonic-gate * on the happy coincidence that T_optmgmt_req and 842*7c478bd9Sstevel@tonic-gate * T_optmgmt_ack are identical data structures 843*7c478bd9Sstevel@tonic-gate * at the binary representation level. 844*7c478bd9Sstevel@tonic-gate */ 845*7c478bd9Sstevel@tonic-gate toa_mp->b_datap->db_type = M_PROTO; 846*7c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_REQ; 847*7c478bd9Sstevel@tonic-gate if (q->q_next != NULL) 848*7c478bd9Sstevel@tonic-gate putnext(q, toa_mp); 849*7c478bd9Sstevel@tonic-gate else 850*7c478bd9Sstevel@tonic-gate ip_output(Q_TO_CONN(q), toa_mp, q, IP_WPUT); 851*7c478bd9Sstevel@tonic-gate } else { 852*7c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_ACK; 853*7c478bd9Sstevel@tonic-gate toa_mp->b_datap->db_type = M_PCPROTO; 854*7c478bd9Sstevel@tonic-gate toa->MGMT_flags |= worst_status; /* XXX "worst" or "OR" TPI ? */ 855*7c478bd9Sstevel@tonic-gate qreply(q, toa_mp); 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate return (0); 858*7c478bd9Sstevel@tonic-gate } 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate /* 862*7c478bd9Sstevel@tonic-gate * Following routine makes a pass through option buffer in mp and performs the 863*7c478bd9Sstevel@tonic-gate * following tasks. 864*7c478bd9Sstevel@tonic-gate * - estimate cumulative length needed for results 865*7c478bd9Sstevel@tonic-gate * - set "status" field based on permissions, option header check 866*7c478bd9Sstevel@tonic-gate * etc. 867*7c478bd9Sstevel@tonic-gate * - determine "pass_to_next" whether we need to send request to 868*7c478bd9Sstevel@tonic-gate * downstream module/driver. 869*7c478bd9Sstevel@tonic-gate */ 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate static t_scalar_t 872*7c478bd9Sstevel@tonic-gate process_topthdrs_first_pass(mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp, 873*7c478bd9Sstevel@tonic-gate boolean_t *pass_to_nextp, size_t *toa_lenp) 874*7c478bd9Sstevel@tonic-gate { 875*7c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 876*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 877*7c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 878*7c478bd9Sstevel@tonic-gate optlevel_t *valid_level_arr = dbobjp->odb_valid_levels_arr; 879*7c478bd9Sstevel@tonic-gate uint_t valid_level_arr_cnt = dbobjp->odb_valid_levels_arr_cnt; 880*7c478bd9Sstevel@tonic-gate struct T_opthdr *opt; 881*7c478bd9Sstevel@tonic-gate struct T_opthdr *opt_start, *opt_end; 882*7c478bd9Sstevel@tonic-gate opdes_t *optd; 883*7c478bd9Sstevel@tonic-gate size_t allopt_len; 884*7c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = 885*7c478bd9Sstevel@tonic-gate (struct T_optmgmt_req *)mp->b_rptr; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate *toa_lenp = sizeof (struct T_optmgmt_ack); /* initial value */ 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate if ((opt_start = (struct T_opthdr *) 890*7c478bd9Sstevel@tonic-gate mi_offset_param(mp, tor->OPT_offset, tor->OPT_length)) == NULL) { 891*7c478bd9Sstevel@tonic-gate return (TBADOPT); 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate if (!__TPI_TOPT_ISALIGNED(opt_start)) 894*7c478bd9Sstevel@tonic-gate return (TBADOPT); 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)((uchar_t *)opt_start + tor->OPT_length); 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate for (opt = opt_start; opt && (opt < opt_end); 899*7c478bd9Sstevel@tonic-gate opt = _TPI_TOPT_NEXTHDR(opt_start, tor->OPT_length, opt)) { 900*7c478bd9Sstevel@tonic-gate /* 901*7c478bd9Sstevel@tonic-gate * Validate the option for length and alignment 902*7c478bd9Sstevel@tonic-gate * before accessing anything in it. 903*7c478bd9Sstevel@tonic-gate */ 904*7c478bd9Sstevel@tonic-gate if (!(_TPI_TOPT_VALID(opt, opt_start, opt_end))) 905*7c478bd9Sstevel@tonic-gate return (TBADOPT); 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate /* Find the option in the opt_arr. */ 908*7c478bd9Sstevel@tonic-gate if (opt->name != T_ALLOPT) { 909*7c478bd9Sstevel@tonic-gate optd = opt_chk_lookup(opt->level, opt->name, 910*7c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt); 911*7c478bd9Sstevel@tonic-gate if (optd == NULL) { 912*7c478bd9Sstevel@tonic-gate /* 913*7c478bd9Sstevel@tonic-gate * Option not found 914*7c478bd9Sstevel@tonic-gate * 915*7c478bd9Sstevel@tonic-gate * Verify if level is "valid" or not. 916*7c478bd9Sstevel@tonic-gate * Note: This check is required by XTI 917*7c478bd9Sstevel@tonic-gate * 918*7c478bd9Sstevel@tonic-gate * TPI provider always initializes 919*7c478bd9Sstevel@tonic-gate * the "not supported" (or whatever) status 920*7c478bd9Sstevel@tonic-gate * for the options. Other levels leave status 921*7c478bd9Sstevel@tonic-gate * unchanged if they do not understand an 922*7c478bd9Sstevel@tonic-gate * option. 923*7c478bd9Sstevel@tonic-gate */ 924*7c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) { 925*7c478bd9Sstevel@tonic-gate if (!opt_level_valid(opt->level, 926*7c478bd9Sstevel@tonic-gate valid_level_arr, 927*7c478bd9Sstevel@tonic-gate valid_level_arr_cnt)) 928*7c478bd9Sstevel@tonic-gate return (TBADOPT); 929*7c478bd9Sstevel@tonic-gate /* 930*7c478bd9Sstevel@tonic-gate * level is valid - initialize 931*7c478bd9Sstevel@tonic-gate * option as not supported 932*7c478bd9Sstevel@tonic-gate */ 933*7c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 934*7c478bd9Sstevel@tonic-gate } 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 937*7c478bd9Sstevel@tonic-gate continue; 938*7c478bd9Sstevel@tonic-gate } 939*7c478bd9Sstevel@tonic-gate } else { 940*7c478bd9Sstevel@tonic-gate /* 941*7c478bd9Sstevel@tonic-gate * Handle T_ALLOPT case as a special case. 942*7c478bd9Sstevel@tonic-gate * Note: T_ALLOPT does not mean anything 943*7c478bd9Sstevel@tonic-gate * for T_CHECK operation. 944*7c478bd9Sstevel@tonic-gate */ 945*7c478bd9Sstevel@tonic-gate allopt_len = 0; 946*7c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_CHECK || 947*7c478bd9Sstevel@tonic-gate !topmost_tpiprovider || 948*7c478bd9Sstevel@tonic-gate ((allopt_len = opt_level_allopts_lengths(opt->level, 949*7c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt)) == 0)) { 950*7c478bd9Sstevel@tonic-gate /* 951*7c478bd9Sstevel@tonic-gate * This is confusing but correct ! 952*7c478bd9Sstevel@tonic-gate * It is not valid to to use T_ALLOPT with 953*7c478bd9Sstevel@tonic-gate * T_CHECK flag. 954*7c478bd9Sstevel@tonic-gate * 955*7c478bd9Sstevel@tonic-gate * T_ALLOPT is assumed "expanded" at the 956*7c478bd9Sstevel@tonic-gate * topmost_tpiprovider level so it should not 957*7c478bd9Sstevel@tonic-gate * be there as an "option name" if this is not 958*7c478bd9Sstevel@tonic-gate * a topmost_tpiprovider call and we fail it. 959*7c478bd9Sstevel@tonic-gate * 960*7c478bd9Sstevel@tonic-gate * opt_level_allopts_lengths() is used to verify 961*7c478bd9Sstevel@tonic-gate * that "level" associated with the T_ALLOPT is 962*7c478bd9Sstevel@tonic-gate * supported. 963*7c478bd9Sstevel@tonic-gate * 964*7c478bd9Sstevel@tonic-gate */ 965*7c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 966*7c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 967*7c478bd9Sstevel@tonic-gate continue; 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate ASSERT(allopt_len != 0); /* remove ? */ 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate *toa_lenp += allopt_len; 972*7c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 973*7c478bd9Sstevel@tonic-gate /* XXX - always set T_ALLOPT 'pass_to_next' for now */ 974*7c478bd9Sstevel@tonic-gate *pass_to_nextp = B_TRUE; 975*7c478bd9Sstevel@tonic-gate continue; 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate /* 978*7c478bd9Sstevel@tonic-gate * Check if option wants to flow downstream 979*7c478bd9Sstevel@tonic-gate */ 980*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_PASSNEXT) 981*7c478bd9Sstevel@tonic-gate *pass_to_nextp = B_TRUE; 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate /* Additional checks dependent on operation. */ 984*7c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 985*7c478bd9Sstevel@tonic-gate case T_DEFAULT: 986*7c478bd9Sstevel@tonic-gate case T_CURRENT: 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate /* 989*7c478bd9Sstevel@tonic-gate * The opt_chk_lookup() routine call above approved of 990*7c478bd9Sstevel@tonic-gate * this option so we can work on the status for it 991*7c478bd9Sstevel@tonic-gate * based on the permissions for the operation. (This 992*7c478bd9Sstevel@tonic-gate * can override any status for it set at higher levels) 993*7c478bd9Sstevel@tonic-gate * We assume this override is OK since chkfn at this 994*7c478bd9Sstevel@tonic-gate * level approved of this option. 995*7c478bd9Sstevel@tonic-gate * 996*7c478bd9Sstevel@tonic-gate * T_CURRENT semantics: 997*7c478bd9Sstevel@tonic-gate * The read access is required. Else option 998*7c478bd9Sstevel@tonic-gate * status is T_NOTSUPPORT. 999*7c478bd9Sstevel@tonic-gate * 1000*7c478bd9Sstevel@tonic-gate * T_DEFAULT semantics: 1001*7c478bd9Sstevel@tonic-gate * Note: specification is not clear on this but we 1002*7c478bd9Sstevel@tonic-gate * interpret T_DEFAULT semantics such that access to 1003*7c478bd9Sstevel@tonic-gate * read value is required for access even the default 1004*7c478bd9Sstevel@tonic-gate * value. Otherwise the option status is T_NOTSUPPORT. 1005*7c478bd9Sstevel@tonic-gate */ 1006*7c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) { 1007*7c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 1008*7c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 1009*7c478bd9Sstevel@tonic-gate /* skip to next */ 1010*7c478bd9Sstevel@tonic-gate continue; 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate 1013*7c478bd9Sstevel@tonic-gate /* 1014*7c478bd9Sstevel@tonic-gate * T_DEFAULT/T_CURRENT semantics: 1015*7c478bd9Sstevel@tonic-gate * We know that read access is set. If no other access 1016*7c478bd9Sstevel@tonic-gate * is set, then status is T_READONLY. 1017*7c478bd9Sstevel@tonic-gate */ 1018*7c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) 1019*7c478bd9Sstevel@tonic-gate opt->status = T_READONLY; 1020*7c478bd9Sstevel@tonic-gate else 1021*7c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 1022*7c478bd9Sstevel@tonic-gate /* 1023*7c478bd9Sstevel@tonic-gate * Option passes all checks. Make room for it in the 1024*7c478bd9Sstevel@tonic-gate * ack. Note: size stored in table does not include 1025*7c478bd9Sstevel@tonic-gate * space for option header. 1026*7c478bd9Sstevel@tonic-gate */ 1027*7c478bd9Sstevel@tonic-gate *toa_lenp += sizeof (struct T_opthdr) + 1028*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(optd->opdes_size); 1029*7c478bd9Sstevel@tonic-gate break; 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate case T_CHECK: 1032*7c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate /* 1035*7c478bd9Sstevel@tonic-gate * T_NEGOTIATE semantics: 1036*7c478bd9Sstevel@tonic-gate * If for fixed length option value on input is not the 1037*7c478bd9Sstevel@tonic-gate * same as value supplied, then status is T_FAILURE. 1038*7c478bd9Sstevel@tonic-gate * 1039*7c478bd9Sstevel@tonic-gate * T_CHECK semantics: 1040*7c478bd9Sstevel@tonic-gate * If value is supplied, semantics same as T_NEGOTIATE. 1041*7c478bd9Sstevel@tonic-gate * It is however ok not to supply a value with T_CHECK. 1042*7c478bd9Sstevel@tonic-gate */ 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_NEGOTIATE || 1045*7c478bd9Sstevel@tonic-gate (opt->len != sizeof (struct T_opthdr))) { 1046*7c478bd9Sstevel@tonic-gate /* 1047*7c478bd9Sstevel@tonic-gate * Implies "value" is specified in T_CHECK or 1048*7c478bd9Sstevel@tonic-gate * it is a T_NEGOTIATE request. 1049*7c478bd9Sstevel@tonic-gate * Verify size. 1050*7c478bd9Sstevel@tonic-gate * Note: This can override anything about this 1051*7c478bd9Sstevel@tonic-gate * option request done at a higher level. 1052*7c478bd9Sstevel@tonic-gate */ 1053*7c478bd9Sstevel@tonic-gate if (!opt_length_ok(optd, opt)) { 1054*7c478bd9Sstevel@tonic-gate /* bad size */ 1055*7c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 1056*7c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 1057*7c478bd9Sstevel@tonic-gate continue; 1058*7c478bd9Sstevel@tonic-gate } 1059*7c478bd9Sstevel@tonic-gate } 1060*7c478bd9Sstevel@tonic-gate /* 1061*7c478bd9Sstevel@tonic-gate * The opt_chk_lookup() routine above() approved of 1062*7c478bd9Sstevel@tonic-gate * this option so we can work on the status for it based 1063*7c478bd9Sstevel@tonic-gate * on the permissions for the operation. (This can 1064*7c478bd9Sstevel@tonic-gate * override anything set at a higher level). 1065*7c478bd9Sstevel@tonic-gate * 1066*7c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE semantics: 1067*7c478bd9Sstevel@tonic-gate * Set status to T_READONLY if read is the only access 1068*7c478bd9Sstevel@tonic-gate * permitted 1069*7c478bd9Sstevel@tonic-gate */ 1070*7c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 1071*7c478bd9Sstevel@tonic-gate opt->status = T_READONLY; 1072*7c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 1073*7c478bd9Sstevel@tonic-gate /* skip to next */ 1074*7c478bd9Sstevel@tonic-gate continue; 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate /* 1078*7c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE semantics: 1079*7c478bd9Sstevel@tonic-gate * If write (or execute) access is not set, then status 1080*7c478bd9Sstevel@tonic-gate * is T_NOTSUPPORT. 1081*7c478bd9Sstevel@tonic-gate */ 1082*7c478bd9Sstevel@tonic-gate if (!OA_WRITE_OR_EXECUTE(optd, cr)) { 1083*7c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 1084*7c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 1085*7c478bd9Sstevel@tonic-gate /* skip to next option */ 1086*7c478bd9Sstevel@tonic-gate continue; 1087*7c478bd9Sstevel@tonic-gate } 1088*7c478bd9Sstevel@tonic-gate /* 1089*7c478bd9Sstevel@tonic-gate * Option passes all checks. Make room for it in the 1090*7c478bd9Sstevel@tonic-gate * ack and set success in status. 1091*7c478bd9Sstevel@tonic-gate * Note: size stored in table does not include header 1092*7c478bd9Sstevel@tonic-gate * length. 1093*7c478bd9Sstevel@tonic-gate */ 1094*7c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 1095*7c478bd9Sstevel@tonic-gate *toa_lenp += sizeof (struct T_opthdr) + 1096*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(optd->opdes_size); 1097*7c478bd9Sstevel@tonic-gate break; 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate default: 1100*7c478bd9Sstevel@tonic-gate return (TBADFLAG); 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate } /* for loop scanning input buffer */ 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate return (0); /* OK return */ 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate /* 1108*7c478bd9Sstevel@tonic-gate * This routine makes another pass through the option buffer this 1109*7c478bd9Sstevel@tonic-gate * time acting on the request based on "status" result in the 1110*7c478bd9Sstevel@tonic-gate * first pass. It also performs "expansion" of T_ALLOPT into 1111*7c478bd9Sstevel@tonic-gate * all options of a certain level and acts on each for this request. 1112*7c478bd9Sstevel@tonic-gate */ 1113*7c478bd9Sstevel@tonic-gate static t_scalar_t 1114*7c478bd9Sstevel@tonic-gate do_options_second_pass(queue_t *q, mblk_t *reqmp, mblk_t *ack_mp, cred_t *cr, 1115*7c478bd9Sstevel@tonic-gate optdb_obj_t *dbobjp, mblk_t *first_mp, boolean_t is_restart, 1116*7c478bd9Sstevel@tonic-gate boolean_t *queued_statusp) 1117*7c478bd9Sstevel@tonic-gate { 1118*7c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 1119*7c478bd9Sstevel@tonic-gate int failed_option; 1120*7c478bd9Sstevel@tonic-gate struct T_opthdr *opt; 1121*7c478bd9Sstevel@tonic-gate struct T_opthdr *opt_start, *opt_end, *restart_opt; 1122*7c478bd9Sstevel@tonic-gate uchar_t *optr; 1123*7c478bd9Sstevel@tonic-gate uint_t optset_context; 1124*7c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)reqmp->b_rptr; 1125*7c478bd9Sstevel@tonic-gate opt_restart_t *or; 1126*7c478bd9Sstevel@tonic-gate t_uscalar_t *worst_statusp; 1127*7c478bd9Sstevel@tonic-gate int err; 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate *queued_statusp = B_FALSE; 1130*7c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 1131*7c478bd9Sstevel@tonic-gate worst_statusp = &or->or_worst_status; 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate optr = (uchar_t *)ack_mp->b_rptr + 1134*7c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_ack); /* assumed int32_t aligned */ 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate /* 1137*7c478bd9Sstevel@tonic-gate * Set initial values for scanning input 1138*7c478bd9Sstevel@tonic-gate */ 1139*7c478bd9Sstevel@tonic-gate if (is_restart) { 1140*7c478bd9Sstevel@tonic-gate opt_start = (struct T_opthdr *)or->or_start; 1141*7c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)or->or_end; 1142*7c478bd9Sstevel@tonic-gate restart_opt = (struct T_opthdr *)or->or_ropt; 1143*7c478bd9Sstevel@tonic-gate } else { 1144*7c478bd9Sstevel@tonic-gate opt_start = (struct T_opthdr *)mi_offset_param(reqmp, 1145*7c478bd9Sstevel@tonic-gate tor->OPT_offset, tor->OPT_length); 1146*7c478bd9Sstevel@tonic-gate if (opt_start == NULL) 1147*7c478bd9Sstevel@tonic-gate return (TBADOPT); 1148*7c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)((uchar_t *)opt_start + 1149*7c478bd9Sstevel@tonic-gate tor->OPT_length); 1150*7c478bd9Sstevel@tonic-gate or->or_start = (struct opthdr *)opt_start; 1151*7c478bd9Sstevel@tonic-gate or->or_end = (struct opthdr *)opt_end; 1152*7c478bd9Sstevel@tonic-gate /* 1153*7c478bd9Sstevel@tonic-gate * construct the mp chain, in case the setfn needs to 1154*7c478bd9Sstevel@tonic-gate * queue this and restart option processing later on. 1155*7c478bd9Sstevel@tonic-gate */ 1156*7c478bd9Sstevel@tonic-gate first_mp->b_cont = ack_mp; 1157*7c478bd9Sstevel@tonic-gate ack_mp->b_cont = reqmp; 1158*7c478bd9Sstevel@tonic-gate } 1159*7c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt_start)); /* verified in first pass */ 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate for (opt = is_restart ? restart_opt : opt_start; 1162*7c478bd9Sstevel@tonic-gate opt && (opt < opt_end); 1163*7c478bd9Sstevel@tonic-gate opt = _TPI_TOPT_NEXTHDR(opt_start, tor->OPT_length, opt)) { 1164*7c478bd9Sstevel@tonic-gate or->or_ropt = (struct opthdr *)opt; 1165*7c478bd9Sstevel@tonic-gate /* verified in first pass */ 1166*7c478bd9Sstevel@tonic-gate ASSERT(_TPI_TOPT_VALID(opt, opt_start, opt_end)); 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate /* 1169*7c478bd9Sstevel@tonic-gate * If the first pass in process_topthdrs_first_pass() 1170*7c478bd9Sstevel@tonic-gate * has marked the option as a failure case for the MGMT_flags 1171*7c478bd9Sstevel@tonic-gate * semantics then there is not much to do. 1172*7c478bd9Sstevel@tonic-gate * 1173*7c478bd9Sstevel@tonic-gate * Note: For all practical purposes, T_READONLY status is 1174*7c478bd9Sstevel@tonic-gate * a "success" for T_DEFAULT/T_CURRENT and "failure" for 1175*7c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE 1176*7c478bd9Sstevel@tonic-gate */ 1177*7c478bd9Sstevel@tonic-gate failed_option = 1178*7c478bd9Sstevel@tonic-gate (opt->status == T_NOTSUPPORT) || 1179*7c478bd9Sstevel@tonic-gate (opt->status == T_FAILURE) || 1180*7c478bd9Sstevel@tonic-gate ((tor->MGMT_flags & (T_NEGOTIATE|T_CHECK)) && 1181*7c478bd9Sstevel@tonic-gate (opt->status == T_READONLY)); 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate if (failed_option) { 1184*7c478bd9Sstevel@tonic-gate /* 1185*7c478bd9Sstevel@tonic-gate * According to T_DEFAULT/T_CURRENT semantics, the 1186*7c478bd9Sstevel@tonic-gate * input values, even if present, are to be ignored. 1187*7c478bd9Sstevel@tonic-gate * Note: Specification is not clear on this, but we 1188*7c478bd9Sstevel@tonic-gate * interpret that even though we ignore the values, we 1189*7c478bd9Sstevel@tonic-gate * can return them as is. So we process them similar to 1190*7c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE case which has the semantics to 1191*7c478bd9Sstevel@tonic-gate * return the values as is. XXX If interpretation is 1192*7c478bd9Sstevel@tonic-gate * ever determined incorrect fill in appropriate code 1193*7c478bd9Sstevel@tonic-gate * here to treat T_DEFAULT/T_CURRENT differently. 1194*7c478bd9Sstevel@tonic-gate * 1195*7c478bd9Sstevel@tonic-gate * According to T_CHECK/T_NEGOTIATE semantics, 1196*7c478bd9Sstevel@tonic-gate * in the case of T_NOTSUPPORT/T_FAILURE/T_READONLY, 1197*7c478bd9Sstevel@tonic-gate * the semantics are to return the "value" part of 1198*7c478bd9Sstevel@tonic-gate * option untouched. So here we copy the option 1199*7c478bd9Sstevel@tonic-gate * head including value part if any to output. 1200*7c478bd9Sstevel@tonic-gate */ 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate bcopy(opt, optr, opt->len); 1203*7c478bd9Sstevel@tonic-gate optr += _TPI_ALIGN_TOPT(opt->len); 1204*7c478bd9Sstevel@tonic-gate 1205*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(opt->status, 1206*7c478bd9Sstevel@tonic-gate *worst_statusp); 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate /* skip to process next option in buffer */ 1209*7c478bd9Sstevel@tonic-gate continue; 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate } /* end if "failed option" */ 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * The status is T_SUCCESS or T_READONLY 1214*7c478bd9Sstevel@tonic-gate * We process the value part here 1215*7c478bd9Sstevel@tonic-gate */ 1216*7c478bd9Sstevel@tonic-gate ASSERT(opt->status == T_SUCCESS || opt->status == T_READONLY); 1217*7c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 1218*7c478bd9Sstevel@tonic-gate case T_DEFAULT: 1219*7c478bd9Sstevel@tonic-gate /* 1220*7c478bd9Sstevel@tonic-gate * We fill default value from table or protocol specific 1221*7c478bd9Sstevel@tonic-gate * function. If this call fails, we pass input through. 1222*7c478bd9Sstevel@tonic-gate */ 1223*7c478bd9Sstevel@tonic-gate if (do_opt_default(q, opt, &optr, worst_statusp, 1224*7c478bd9Sstevel@tonic-gate cr, dbobjp) < 0) { 1225*7c478bd9Sstevel@tonic-gate /* fail or pass transparently */ 1226*7c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 1227*7c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 1228*7c478bd9Sstevel@tonic-gate bcopy(opt, optr, opt->len); 1229*7c478bd9Sstevel@tonic-gate optr += _TPI_ALIGN_TOPT(opt->len); 1230*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(opt->status, 1231*7c478bd9Sstevel@tonic-gate *worst_statusp); 1232*7c478bd9Sstevel@tonic-gate } 1233*7c478bd9Sstevel@tonic-gate break; 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate case T_CURRENT: 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate do_opt_current(q, opt, &optr, worst_statusp, cr, 1238*7c478bd9Sstevel@tonic-gate dbobjp); 1239*7c478bd9Sstevel@tonic-gate break; 1240*7c478bd9Sstevel@tonic-gate 1241*7c478bd9Sstevel@tonic-gate case T_CHECK: 1242*7c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 1243*7c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_CHECK) 1244*7c478bd9Sstevel@tonic-gate optset_context = SETFN_OPTCOM_CHECKONLY; 1245*7c478bd9Sstevel@tonic-gate else /* T_NEGOTIATE */ 1246*7c478bd9Sstevel@tonic-gate optset_context = SETFN_OPTCOM_NEGOTIATE; 1247*7c478bd9Sstevel@tonic-gate err = do_opt_check_or_negotiate(q, opt, optset_context, 1248*7c478bd9Sstevel@tonic-gate &optr, worst_statusp, cr, dbobjp, first_mp); 1249*7c478bd9Sstevel@tonic-gate if (err == EINPROGRESS) { 1250*7c478bd9Sstevel@tonic-gate *queued_statusp = B_TRUE; 1251*7c478bd9Sstevel@tonic-gate return (0); 1252*7c478bd9Sstevel@tonic-gate } 1253*7c478bd9Sstevel@tonic-gate break; 1254*7c478bd9Sstevel@tonic-gate default: 1255*7c478bd9Sstevel@tonic-gate return (TBADFLAG); 1256*7c478bd9Sstevel@tonic-gate } 1257*7c478bd9Sstevel@tonic-gate } /* end for loop scanning option buffer */ 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate ack_mp->b_wptr = optr; 1260*7c478bd9Sstevel@tonic-gate ASSERT(ack_mp->b_wptr <= ack_mp->b_datap->db_lim); 1261*7c478bd9Sstevel@tonic-gate 1262*7c478bd9Sstevel@tonic-gate return (0); /* OK return */ 1263*7c478bd9Sstevel@tonic-gate } 1264*7c478bd9Sstevel@tonic-gate 1265*7c478bd9Sstevel@tonic-gate 1266*7c478bd9Sstevel@tonic-gate static t_uscalar_t 1267*7c478bd9Sstevel@tonic-gate get_worst_status(t_uscalar_t status, t_uscalar_t current_worst_status) 1268*7c478bd9Sstevel@tonic-gate { 1269*7c478bd9Sstevel@tonic-gate /* 1270*7c478bd9Sstevel@tonic-gate * Return the "worst" among the arguments "status" and 1271*7c478bd9Sstevel@tonic-gate * "current_worst_status". 1272*7c478bd9Sstevel@tonic-gate * 1273*7c478bd9Sstevel@tonic-gate * Note: Tracking "worst_status" can be made a bit simpler 1274*7c478bd9Sstevel@tonic-gate * if we use the property that status codes are bitwise 1275*7c478bd9Sstevel@tonic-gate * distinct. 1276*7c478bd9Sstevel@tonic-gate * 1277*7c478bd9Sstevel@tonic-gate * The pecking order is 1278*7c478bd9Sstevel@tonic-gate * 1279*7c478bd9Sstevel@tonic-gate * T_SUCCESS ..... best 1280*7c478bd9Sstevel@tonic-gate * T_PARTSUCCESS 1281*7c478bd9Sstevel@tonic-gate * T_FAILURE 1282*7c478bd9Sstevel@tonic-gate * T_READONLY 1283*7c478bd9Sstevel@tonic-gate * T_NOTSUPPORT... worst 1284*7c478bd9Sstevel@tonic-gate */ 1285*7c478bd9Sstevel@tonic-gate if (status == current_worst_status) 1286*7c478bd9Sstevel@tonic-gate return (current_worst_status); 1287*7c478bd9Sstevel@tonic-gate switch (current_worst_status) { 1288*7c478bd9Sstevel@tonic-gate case T_SUCCESS: 1289*7c478bd9Sstevel@tonic-gate if (status == T_PARTSUCCESS) 1290*7c478bd9Sstevel@tonic-gate return (T_PARTSUCCESS); 1291*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1292*7c478bd9Sstevel@tonic-gate case T_PARTSUCCESS: 1293*7c478bd9Sstevel@tonic-gate if (status == T_FAILURE) 1294*7c478bd9Sstevel@tonic-gate return (T_FAILURE); 1295*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1296*7c478bd9Sstevel@tonic-gate case T_FAILURE: 1297*7c478bd9Sstevel@tonic-gate if (status == T_READONLY) 1298*7c478bd9Sstevel@tonic-gate return (T_READONLY); 1299*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1300*7c478bd9Sstevel@tonic-gate case T_READONLY: 1301*7c478bd9Sstevel@tonic-gate if (status == T_NOTSUPPORT) 1302*7c478bd9Sstevel@tonic-gate return (T_NOTSUPPORT); 1303*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1304*7c478bd9Sstevel@tonic-gate case T_NOTSUPPORT: 1305*7c478bd9Sstevel@tonic-gate default: 1306*7c478bd9Sstevel@tonic-gate return (current_worst_status); 1307*7c478bd9Sstevel@tonic-gate } 1308*7c478bd9Sstevel@tonic-gate } 1309*7c478bd9Sstevel@tonic-gate 1310*7c478bd9Sstevel@tonic-gate static int 1311*7c478bd9Sstevel@tonic-gate do_opt_default(queue_t *q, struct T_opthdr *reqopt, uchar_t **resptrp, 1312*7c478bd9Sstevel@tonic-gate t_uscalar_t *worst_statusp, cred_t *cr, optdb_obj_t *dbobjp) 1313*7c478bd9Sstevel@tonic-gate { 1314*7c478bd9Sstevel@tonic-gate pfi_t deffn = dbobjp->odb_deffn; 1315*7c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 1316*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 1317*7c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate struct T_opthdr *topth; 1320*7c478bd9Sstevel@tonic-gate opdes_t *optd; 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate if (reqopt->name != T_ALLOPT) { 1323*7c478bd9Sstevel@tonic-gate /* 1324*7c478bd9Sstevel@tonic-gate * lookup the option in the table and fill default value 1325*7c478bd9Sstevel@tonic-gate */ 1326*7c478bd9Sstevel@tonic-gate optd = opt_chk_lookup(reqopt->level, reqopt->name, 1327*7c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt); 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate if (optd == NULL) { 1330*7c478bd9Sstevel@tonic-gate /* 1331*7c478bd9Sstevel@tonic-gate * not found - fail this one. Should not happen 1332*7c478bd9Sstevel@tonic-gate * for topmost_tpiprovider as calling routine 1333*7c478bd9Sstevel@tonic-gate * should have verified it. 1334*7c478bd9Sstevel@tonic-gate */ 1335*7c478bd9Sstevel@tonic-gate ASSERT(!topmost_tpiprovider); 1336*7c478bd9Sstevel@tonic-gate return (-1); 1337*7c478bd9Sstevel@tonic-gate } 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)(*resptrp); 1340*7c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 1341*7c478bd9Sstevel@tonic-gate topth->name = reqopt->name; 1342*7c478bd9Sstevel@tonic-gate topth->status = reqopt->status; 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(reqopt->status, 1345*7c478bd9Sstevel@tonic-gate *worst_statusp); 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_NODEFAULT) { 1348*7c478bd9Sstevel@tonic-gate /* header only, no default "value" part */ 1349*7c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 1350*7c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 1351*7c478bd9Sstevel@tonic-gate } else { 1352*7c478bd9Sstevel@tonic-gate int deflen; 1353*7c478bd9Sstevel@tonic-gate 1354*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_DEF_FN) { 1355*7c478bd9Sstevel@tonic-gate deflen = (*deffn)(q, reqopt->level, 1356*7c478bd9Sstevel@tonic-gate reqopt->name, _TPI_TOPT_DATA(topth)); 1357*7c478bd9Sstevel@tonic-gate if (deflen >= 0) { 1358*7c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t) 1359*7c478bd9Sstevel@tonic-gate (sizeof (struct T_opthdr) + deflen); 1360*7c478bd9Sstevel@tonic-gate } else { 1361*7c478bd9Sstevel@tonic-gate /* 1362*7c478bd9Sstevel@tonic-gate * return error, this should 'pass 1363*7c478bd9Sstevel@tonic-gate * through' the option and maybe some 1364*7c478bd9Sstevel@tonic-gate * other level will fill it in or 1365*7c478bd9Sstevel@tonic-gate * already did. 1366*7c478bd9Sstevel@tonic-gate * (No change in 'resptrp' upto here) 1367*7c478bd9Sstevel@tonic-gate */ 1368*7c478bd9Sstevel@tonic-gate return (-1); 1369*7c478bd9Sstevel@tonic-gate } 1370*7c478bd9Sstevel@tonic-gate } else { 1371*7c478bd9Sstevel@tonic-gate /* fill length and value part */ 1372*7c478bd9Sstevel@tonic-gate switch (optd->opdes_size) { 1373*7c478bd9Sstevel@tonic-gate /* 1374*7c478bd9Sstevel@tonic-gate * Since options are guaranteed aligned only 1375*7c478bd9Sstevel@tonic-gate * on a 4 byte boundary (t_scalar_t) any 1376*7c478bd9Sstevel@tonic-gate * option that is greater in size will default 1377*7c478bd9Sstevel@tonic-gate * to the bcopy below 1378*7c478bd9Sstevel@tonic-gate */ 1379*7c478bd9Sstevel@tonic-gate case sizeof (int32_t): 1380*7c478bd9Sstevel@tonic-gate *(int32_t *)_TPI_TOPT_DATA(topth) = 1381*7c478bd9Sstevel@tonic-gate (int32_t)optd->opdes_default; 1382*7c478bd9Sstevel@tonic-gate break; 1383*7c478bd9Sstevel@tonic-gate case sizeof (int16_t): 1384*7c478bd9Sstevel@tonic-gate *(int16_t *)_TPI_TOPT_DATA(topth) = 1385*7c478bd9Sstevel@tonic-gate (int16_t)optd->opdes_default; 1386*7c478bd9Sstevel@tonic-gate break; 1387*7c478bd9Sstevel@tonic-gate case sizeof (int8_t): 1388*7c478bd9Sstevel@tonic-gate *(int8_t *)_TPI_TOPT_DATA(topth) = 1389*7c478bd9Sstevel@tonic-gate (int8_t)optd->opdes_default; 1390*7c478bd9Sstevel@tonic-gate break; 1391*7c478bd9Sstevel@tonic-gate default: 1392*7c478bd9Sstevel@tonic-gate /* 1393*7c478bd9Sstevel@tonic-gate * other length but still assume 1394*7c478bd9Sstevel@tonic-gate * fixed - use bcopy 1395*7c478bd9Sstevel@tonic-gate */ 1396*7c478bd9Sstevel@tonic-gate bcopy(optd->opdes_defbuf, 1397*7c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(topth), 1398*7c478bd9Sstevel@tonic-gate optd->opdes_size); 1399*7c478bd9Sstevel@tonic-gate break; 1400*7c478bd9Sstevel@tonic-gate } 1401*7c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optd->opdes_size + 1402*7c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 1403*7c478bd9Sstevel@tonic-gate } 1404*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(topth->len); 1405*7c478bd9Sstevel@tonic-gate } 1406*7c478bd9Sstevel@tonic-gate return (0); /* OK return */ 1407*7c478bd9Sstevel@tonic-gate } 1408*7c478bd9Sstevel@tonic-gate 1409*7c478bd9Sstevel@tonic-gate /* 1410*7c478bd9Sstevel@tonic-gate * T_ALLOPT processing 1411*7c478bd9Sstevel@tonic-gate * 1412*7c478bd9Sstevel@tonic-gate * lookup and stuff default values of all the options of the 1413*7c478bd9Sstevel@tonic-gate * level specified 1414*7c478bd9Sstevel@tonic-gate * Note: This expansion of T_ALLOPT should happen in 1415*7c478bd9Sstevel@tonic-gate * a topmost_tpiprovider. 1416*7c478bd9Sstevel@tonic-gate */ 1417*7c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider); 1418*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 1419*7c478bd9Sstevel@tonic-gate if (reqopt->level != optd->opdes_level) 1420*7c478bd9Sstevel@tonic-gate continue; 1421*7c478bd9Sstevel@tonic-gate /* 1422*7c478bd9Sstevel@tonic-gate * 1423*7c478bd9Sstevel@tonic-gate * T_DEFAULT semantics: 1424*7c478bd9Sstevel@tonic-gate * XXX: we interpret T_DEFAULT semantics such that access to 1425*7c478bd9Sstevel@tonic-gate * read value is required for access even the default value. 1426*7c478bd9Sstevel@tonic-gate * Else option is ignored for T_ALLOPT request. 1427*7c478bd9Sstevel@tonic-gate */ 1428*7c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) 1429*7c478bd9Sstevel@tonic-gate /* skip this one */ 1430*7c478bd9Sstevel@tonic-gate continue; 1431*7c478bd9Sstevel@tonic-gate 1432*7c478bd9Sstevel@tonic-gate /* 1433*7c478bd9Sstevel@tonic-gate * Found option of same level as T_ALLOPT request 1434*7c478bd9Sstevel@tonic-gate * that we can return. 1435*7c478bd9Sstevel@tonic-gate */ 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)(*resptrp); 1438*7c478bd9Sstevel@tonic-gate topth->level = optd->opdes_level; 1439*7c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate /* 1442*7c478bd9Sstevel@tonic-gate * T_DEFAULT semantics: 1443*7c478bd9Sstevel@tonic-gate * We know that read access is set. If no other access is set, 1444*7c478bd9Sstevel@tonic-gate * then status is T_READONLY 1445*7c478bd9Sstevel@tonic-gate */ 1446*7c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 1447*7c478bd9Sstevel@tonic-gate topth->status = T_READONLY; 1448*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(T_READONLY, 1449*7c478bd9Sstevel@tonic-gate *worst_statusp); 1450*7c478bd9Sstevel@tonic-gate } else { 1451*7c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 1452*7c478bd9Sstevel@tonic-gate /* 1453*7c478bd9Sstevel@tonic-gate * Note: *worst_statusp has to be T_SUCCESS or 1454*7c478bd9Sstevel@tonic-gate * worse so no need to adjust 1455*7c478bd9Sstevel@tonic-gate */ 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_NODEFAULT) { 1459*7c478bd9Sstevel@tonic-gate /* header only, no value part */ 1460*7c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 1461*7c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 1462*7c478bd9Sstevel@tonic-gate } else { 1463*7c478bd9Sstevel@tonic-gate int deflen; 1464*7c478bd9Sstevel@tonic-gate 1465*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_DEF_FN) { 1466*7c478bd9Sstevel@tonic-gate deflen = (*deffn)(q, reqopt->level, 1467*7c478bd9Sstevel@tonic-gate reqopt->name, _TPI_TOPT_DATA(topth)); 1468*7c478bd9Sstevel@tonic-gate if (deflen >= 0) { 1469*7c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(deflen + 1470*7c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 1471*7c478bd9Sstevel@tonic-gate } else { 1472*7c478bd9Sstevel@tonic-gate /* 1473*7c478bd9Sstevel@tonic-gate * deffn failed. 1474*7c478bd9Sstevel@tonic-gate * return just the header as T_ALLOPT 1475*7c478bd9Sstevel@tonic-gate * expansion. 1476*7c478bd9Sstevel@tonic-gate * Some other level deffn may 1477*7c478bd9Sstevel@tonic-gate * supply value part. 1478*7c478bd9Sstevel@tonic-gate */ 1479*7c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 1480*7c478bd9Sstevel@tonic-gate topth->status = T_FAILURE; 1481*7c478bd9Sstevel@tonic-gate *worst_statusp = 1482*7c478bd9Sstevel@tonic-gate get_worst_status(T_FAILURE, 1483*7c478bd9Sstevel@tonic-gate *worst_statusp); 1484*7c478bd9Sstevel@tonic-gate } 1485*7c478bd9Sstevel@tonic-gate } else { 1486*7c478bd9Sstevel@tonic-gate /* 1487*7c478bd9Sstevel@tonic-gate * fill length and value part from 1488*7c478bd9Sstevel@tonic-gate * table 1489*7c478bd9Sstevel@tonic-gate */ 1490*7c478bd9Sstevel@tonic-gate switch (optd->opdes_size) { 1491*7c478bd9Sstevel@tonic-gate /* 1492*7c478bd9Sstevel@tonic-gate * Since options are guaranteed aligned only 1493*7c478bd9Sstevel@tonic-gate * on a 4 byte boundary (t_scalar_t) any 1494*7c478bd9Sstevel@tonic-gate * option that is greater in size will default 1495*7c478bd9Sstevel@tonic-gate * to the bcopy below 1496*7c478bd9Sstevel@tonic-gate */ 1497*7c478bd9Sstevel@tonic-gate case sizeof (int32_t): 1498*7c478bd9Sstevel@tonic-gate *(int32_t *)_TPI_TOPT_DATA(topth) = 1499*7c478bd9Sstevel@tonic-gate (int32_t)optd->opdes_default; 1500*7c478bd9Sstevel@tonic-gate break; 1501*7c478bd9Sstevel@tonic-gate case sizeof (int16_t): 1502*7c478bd9Sstevel@tonic-gate *(int16_t *)_TPI_TOPT_DATA(topth) = 1503*7c478bd9Sstevel@tonic-gate (int16_t)optd->opdes_default; 1504*7c478bd9Sstevel@tonic-gate break; 1505*7c478bd9Sstevel@tonic-gate case sizeof (int8_t): 1506*7c478bd9Sstevel@tonic-gate *(int8_t *)_TPI_TOPT_DATA(topth) = 1507*7c478bd9Sstevel@tonic-gate (int8_t)optd->opdes_default; 1508*7c478bd9Sstevel@tonic-gate break; 1509*7c478bd9Sstevel@tonic-gate default: 1510*7c478bd9Sstevel@tonic-gate /* 1511*7c478bd9Sstevel@tonic-gate * other length but still assume 1512*7c478bd9Sstevel@tonic-gate * fixed - use bcopy 1513*7c478bd9Sstevel@tonic-gate */ 1514*7c478bd9Sstevel@tonic-gate bcopy(optd->opdes_defbuf, 1515*7c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(topth), 1516*7c478bd9Sstevel@tonic-gate optd->opdes_size); 1517*7c478bd9Sstevel@tonic-gate } 1518*7c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optd->opdes_size + 1519*7c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(topth->len); 1522*7c478bd9Sstevel@tonic-gate } 1523*7c478bd9Sstevel@tonic-gate } 1524*7c478bd9Sstevel@tonic-gate return (0); 1525*7c478bd9Sstevel@tonic-gate } 1526*7c478bd9Sstevel@tonic-gate 1527*7c478bd9Sstevel@tonic-gate static void 1528*7c478bd9Sstevel@tonic-gate do_opt_current(queue_t *q, struct T_opthdr *reqopt, uchar_t **resptrp, 1529*7c478bd9Sstevel@tonic-gate t_uscalar_t *worst_statusp, cred_t *cr, optdb_obj_t *dbobjp) 1530*7c478bd9Sstevel@tonic-gate { 1531*7c478bd9Sstevel@tonic-gate pfi_t getfn = dbobjp->odb_getfn; 1532*7c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 1533*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 1534*7c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate struct T_opthdr *topth; 1537*7c478bd9Sstevel@tonic-gate opdes_t *optd; 1538*7c478bd9Sstevel@tonic-gate int optlen; 1539*7c478bd9Sstevel@tonic-gate uchar_t *initptr = *resptrp; 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate /* 1542*7c478bd9Sstevel@tonic-gate * We call getfn to get the current value of an option. The call may 1543*7c478bd9Sstevel@tonic-gate * fail in which case we copy the values from the input buffer. Maybe 1544*7c478bd9Sstevel@tonic-gate * something downstream will fill it in or something upstream did. 1545*7c478bd9Sstevel@tonic-gate */ 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate if (reqopt->name != T_ALLOPT) { 1548*7c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 1549*7c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 1550*7c478bd9Sstevel@tonic-gate optlen = (*getfn)(q, reqopt->level, reqopt->name, *resptrp); 1551*7c478bd9Sstevel@tonic-gate if (optlen >= 0) { 1552*7c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optlen + 1553*7c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 1554*7c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 1555*7c478bd9Sstevel@tonic-gate topth->name = reqopt->name; 1556*7c478bd9Sstevel@tonic-gate topth->status = reqopt->status; 1557*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 1558*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 1559*7c478bd9Sstevel@tonic-gate *worst_statusp); 1560*7c478bd9Sstevel@tonic-gate } else { 1561*7c478bd9Sstevel@tonic-gate /* failed - reset "*resptrp" pointer */ 1562*7c478bd9Sstevel@tonic-gate *resptrp -= sizeof (struct T_opthdr); 1563*7c478bd9Sstevel@tonic-gate } 1564*7c478bd9Sstevel@tonic-gate } else { /* T_ALLOPT processing */ 1565*7c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider == B_TRUE); 1566*7c478bd9Sstevel@tonic-gate /* scan and get all options */ 1567*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 1568*7c478bd9Sstevel@tonic-gate /* skip other levels */ 1569*7c478bd9Sstevel@tonic-gate if (reqopt->level != optd->opdes_level) 1570*7c478bd9Sstevel@tonic-gate continue; 1571*7c478bd9Sstevel@tonic-gate 1572*7c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) 1573*7c478bd9Sstevel@tonic-gate /* skip this one */ 1574*7c478bd9Sstevel@tonic-gate continue; 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 1577*7c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate /* get option of this level */ 1580*7c478bd9Sstevel@tonic-gate optlen = (*getfn)(q, reqopt->level, optd->opdes_name, 1581*7c478bd9Sstevel@tonic-gate *resptrp); 1582*7c478bd9Sstevel@tonic-gate if (optlen >= 0) { 1583*7c478bd9Sstevel@tonic-gate /* success */ 1584*7c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optlen + 1585*7c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 1586*7c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 1587*7c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 1588*7c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) 1589*7c478bd9Sstevel@tonic-gate topth->status = T_READONLY; 1590*7c478bd9Sstevel@tonic-gate else 1591*7c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 1592*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 1593*7c478bd9Sstevel@tonic-gate } else { 1594*7c478bd9Sstevel@tonic-gate /* 1595*7c478bd9Sstevel@tonic-gate * failed, return as T_FAILURE and null value 1596*7c478bd9Sstevel@tonic-gate * part. Maybe something downstream will 1597*7c478bd9Sstevel@tonic-gate * handle this one and fill in a value. Here 1598*7c478bd9Sstevel@tonic-gate * it is just part of T_ALLOPT expansion. 1599*7c478bd9Sstevel@tonic-gate */ 1600*7c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 1601*7c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 1602*7c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 1603*7c478bd9Sstevel@tonic-gate topth->status = T_FAILURE; 1604*7c478bd9Sstevel@tonic-gate } 1605*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 1606*7c478bd9Sstevel@tonic-gate *worst_statusp); 1607*7c478bd9Sstevel@tonic-gate } /* end for loop */ 1608*7c478bd9Sstevel@tonic-gate } 1609*7c478bd9Sstevel@tonic-gate if (*resptrp == initptr) { 1610*7c478bd9Sstevel@tonic-gate /* 1611*7c478bd9Sstevel@tonic-gate * getfn failed and does not want to handle this option. Maybe 1612*7c478bd9Sstevel@tonic-gate * something downstream will or something upstream did. (If 1613*7c478bd9Sstevel@tonic-gate * topmost_tpiprovider, initialize "status" to failure which 1614*7c478bd9Sstevel@tonic-gate * can possibly change downstream). Copy the input "as is" from 1615*7c478bd9Sstevel@tonic-gate * input option buffer if any to maintain transparency. 1616*7c478bd9Sstevel@tonic-gate */ 1617*7c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 1618*7c478bd9Sstevel@tonic-gate reqopt->status = T_FAILURE; 1619*7c478bd9Sstevel@tonic-gate bcopy(reqopt, *resptrp, reqopt->len); 1620*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(reqopt->len); 1621*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(reqopt->status, 1622*7c478bd9Sstevel@tonic-gate *worst_statusp); 1623*7c478bd9Sstevel@tonic-gate } 1624*7c478bd9Sstevel@tonic-gate } 1625*7c478bd9Sstevel@tonic-gate 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate 1628*7c478bd9Sstevel@tonic-gate static int 1629*7c478bd9Sstevel@tonic-gate do_opt_check_or_negotiate(queue_t *q, struct T_opthdr *reqopt, 1630*7c478bd9Sstevel@tonic-gate uint_t optset_context, uchar_t **resptrp, t_uscalar_t *worst_statusp, 1631*7c478bd9Sstevel@tonic-gate cred_t *cr, optdb_obj_t *dbobjp, mblk_t *first_mp) 1632*7c478bd9Sstevel@tonic-gate { 1633*7c478bd9Sstevel@tonic-gate pfi_t deffn = dbobjp->odb_deffn; 1634*7c478bd9Sstevel@tonic-gate opt_set_fn setfn = dbobjp->odb_setfn; 1635*7c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 1636*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 1637*7c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 1638*7c478bd9Sstevel@tonic-gate 1639*7c478bd9Sstevel@tonic-gate struct T_opthdr *topth; 1640*7c478bd9Sstevel@tonic-gate opdes_t *optd; 1641*7c478bd9Sstevel@tonic-gate int error; 1642*7c478bd9Sstevel@tonic-gate t_uscalar_t optlen; 1643*7c478bd9Sstevel@tonic-gate t_scalar_t optsize; 1644*7c478bd9Sstevel@tonic-gate uchar_t *initptr = *resptrp; 1645*7c478bd9Sstevel@tonic-gate 1646*7c478bd9Sstevel@tonic-gate ASSERT(reqopt->status == T_SUCCESS); 1647*7c478bd9Sstevel@tonic-gate 1648*7c478bd9Sstevel@tonic-gate if (reqopt->name != T_ALLOPT) { 1649*7c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 1650*7c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 1651*7c478bd9Sstevel@tonic-gate error = (*setfn)(q, optset_context, reqopt->level, reqopt->name, 1652*7c478bd9Sstevel@tonic-gate reqopt->len - sizeof (struct T_opthdr), 1653*7c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(reqopt), &optlen, _TPI_TOPT_DATA(topth), 1654*7c478bd9Sstevel@tonic-gate NULL, cr, first_mp); 1655*7c478bd9Sstevel@tonic-gate if (error) { 1656*7c478bd9Sstevel@tonic-gate /* failed - reset "*resptrp" */ 1657*7c478bd9Sstevel@tonic-gate *resptrp -= sizeof (struct T_opthdr); 1658*7c478bd9Sstevel@tonic-gate if (error == EINPROGRESS) 1659*7c478bd9Sstevel@tonic-gate return (error); 1660*7c478bd9Sstevel@tonic-gate } else { 1661*7c478bd9Sstevel@tonic-gate /* 1662*7c478bd9Sstevel@tonic-gate * success - "value" already filled in setfn() 1663*7c478bd9Sstevel@tonic-gate */ 1664*7c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optlen + 1665*7c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 1666*7c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 1667*7c478bd9Sstevel@tonic-gate topth->name = reqopt->name; 1668*7c478bd9Sstevel@tonic-gate topth->status = reqopt->status; 1669*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 1670*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 1671*7c478bd9Sstevel@tonic-gate *worst_statusp); 1672*7c478bd9Sstevel@tonic-gate } 1673*7c478bd9Sstevel@tonic-gate } else { /* T_ALLOPT processing */ 1674*7c478bd9Sstevel@tonic-gate /* only for T_NEGOTIATE case */ 1675*7c478bd9Sstevel@tonic-gate ASSERT(optset_context == SETFN_OPTCOM_NEGOTIATE); 1676*7c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider == B_TRUE); 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate /* scan and set all options to default value */ 1679*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate /* skip other levels */ 1682*7c478bd9Sstevel@tonic-gate if (reqopt->level != optd->opdes_level) 1683*7c478bd9Sstevel@tonic-gate continue; 1684*7c478bd9Sstevel@tonic-gate 1685*7c478bd9Sstevel@tonic-gate if (OA_EXECUTE_PERMISSION(optd, cr) || 1686*7c478bd9Sstevel@tonic-gate OA_NO_PERMISSION(optd, cr)) { 1687*7c478bd9Sstevel@tonic-gate /* 1688*7c478bd9Sstevel@tonic-gate * skip this one too. Does not make sense to 1689*7c478bd9Sstevel@tonic-gate * set anything to default value for "execute" 1690*7c478bd9Sstevel@tonic-gate * options. 1691*7c478bd9Sstevel@tonic-gate */ 1692*7c478bd9Sstevel@tonic-gate continue; 1693*7c478bd9Sstevel@tonic-gate } 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 1696*7c478bd9Sstevel@tonic-gate /* 1697*7c478bd9Sstevel@tonic-gate * Return with T_READONLY status (and no value 1698*7c478bd9Sstevel@tonic-gate * part). Note: spec is not clear but 1699*7c478bd9Sstevel@tonic-gate * XTI test suite needs this. 1700*7c478bd9Sstevel@tonic-gate */ 1701*7c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 1702*7c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 1703*7c478bd9Sstevel@tonic-gate *resptrp += topth->len; 1704*7c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 1705*7c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 1706*7c478bd9Sstevel@tonic-gate topth->status = T_READONLY; 1707*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 1708*7c478bd9Sstevel@tonic-gate *worst_statusp); 1709*7c478bd9Sstevel@tonic-gate continue; 1710*7c478bd9Sstevel@tonic-gate } 1711*7c478bd9Sstevel@tonic-gate 1712*7c478bd9Sstevel@tonic-gate /* 1713*7c478bd9Sstevel@tonic-gate * It is not read only or execute type 1714*7c478bd9Sstevel@tonic-gate * the it must have write permission 1715*7c478bd9Sstevel@tonic-gate */ 1716*7c478bd9Sstevel@tonic-gate ASSERT(OA_WRITE_PERMISSION(optd, cr)); 1717*7c478bd9Sstevel@tonic-gate 1718*7c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 1719*7c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 1722*7c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 1723*7c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 1724*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_NODEFAULT) { 1725*7c478bd9Sstevel@tonic-gate /* 1726*7c478bd9Sstevel@tonic-gate * Option of "no default value" so it does not 1727*7c478bd9Sstevel@tonic-gate * make sense to try to set it. We just return 1728*7c478bd9Sstevel@tonic-gate * header with status of T_SUCCESS 1729*7c478bd9Sstevel@tonic-gate * XXX should this be failure ? 1730*7c478bd9Sstevel@tonic-gate */ 1731*7c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 1732*7c478bd9Sstevel@tonic-gate continue; /* skip setting */ 1733*7c478bd9Sstevel@tonic-gate } 1734*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_DEF_FN) { 1735*7c478bd9Sstevel@tonic-gate if ((optd->opdes_props & OP_VARLEN) || 1736*7c478bd9Sstevel@tonic-gate ((optsize = (*deffn)(q, reqopt->level, 1737*7c478bd9Sstevel@tonic-gate optd->opdes_name, 1738*7c478bd9Sstevel@tonic-gate (uchar_t *)optd->opdes_defbuf)) < 0)) { 1739*7c478bd9Sstevel@tonic-gate /* XXX - skip these too */ 1740*7c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 1741*7c478bd9Sstevel@tonic-gate continue; /* skip setting */ 1742*7c478bd9Sstevel@tonic-gate } 1743*7c478bd9Sstevel@tonic-gate } else { 1744*7c478bd9Sstevel@tonic-gate optsize = optd->opdes_size; 1745*7c478bd9Sstevel@tonic-gate } 1746*7c478bd9Sstevel@tonic-gate 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate /* set option of this level */ 1749*7c478bd9Sstevel@tonic-gate error = (*setfn)(q, SETFN_OPTCOM_NEGOTIATE, 1750*7c478bd9Sstevel@tonic-gate reqopt->level, optd->opdes_name, optsize, 1751*7c478bd9Sstevel@tonic-gate (uchar_t *)optd->opdes_defbuf, &optlen, 1752*7c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(topth), NULL, cr, NULL); 1753*7c478bd9Sstevel@tonic-gate if (error) { 1754*7c478bd9Sstevel@tonic-gate /* 1755*7c478bd9Sstevel@tonic-gate * failed, return as T_FAILURE and null value 1756*7c478bd9Sstevel@tonic-gate * part. Maybe something downstream will 1757*7c478bd9Sstevel@tonic-gate * handle this one and fill in a value. Here 1758*7c478bd9Sstevel@tonic-gate * it is just part of T_ALLOPT expansion. 1759*7c478bd9Sstevel@tonic-gate */ 1760*7c478bd9Sstevel@tonic-gate topth->status = T_FAILURE; 1761*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 1762*7c478bd9Sstevel@tonic-gate *worst_statusp); 1763*7c478bd9Sstevel@tonic-gate } else { 1764*7c478bd9Sstevel@tonic-gate /* success */ 1765*7c478bd9Sstevel@tonic-gate topth->len += optlen; 1766*7c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 1767*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 1768*7c478bd9Sstevel@tonic-gate } 1769*7c478bd9Sstevel@tonic-gate } /* end for loop */ 1770*7c478bd9Sstevel@tonic-gate /* END T_ALLOPT */ 1771*7c478bd9Sstevel@tonic-gate } 1772*7c478bd9Sstevel@tonic-gate 1773*7c478bd9Sstevel@tonic-gate if (*resptrp == initptr) { 1774*7c478bd9Sstevel@tonic-gate /* 1775*7c478bd9Sstevel@tonic-gate * setfn failed and does not want to handle this option. Maybe 1776*7c478bd9Sstevel@tonic-gate * something downstream will or something upstream 1777*7c478bd9Sstevel@tonic-gate * did. Copy the input as is from input option buffer if any to 1778*7c478bd9Sstevel@tonic-gate * maintain transparency (maybe something at a level above 1779*7c478bd9Sstevel@tonic-gate * did something. 1780*7c478bd9Sstevel@tonic-gate */ 1781*7c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 1782*7c478bd9Sstevel@tonic-gate reqopt->status = T_FAILURE; 1783*7c478bd9Sstevel@tonic-gate bcopy(reqopt, *resptrp, reqopt->len); 1784*7c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(reqopt->len); 1785*7c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(reqopt->status, 1786*7c478bd9Sstevel@tonic-gate *worst_statusp); 1787*7c478bd9Sstevel@tonic-gate } 1788*7c478bd9Sstevel@tonic-gate return (0); 1789*7c478bd9Sstevel@tonic-gate } 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate /* 1792*7c478bd9Sstevel@tonic-gate * The following routines process options buffer passed with 1793*7c478bd9Sstevel@tonic-gate * T_CONN_REQ, T_CONN_RES and T_UNITDATA_REQ. 1794*7c478bd9Sstevel@tonic-gate * This routine does the consistency check applied to the 1795*7c478bd9Sstevel@tonic-gate * sanity of formatting of multiple options packed in the 1796*7c478bd9Sstevel@tonic-gate * buffer. 1797*7c478bd9Sstevel@tonic-gate * 1798*7c478bd9Sstevel@tonic-gate * XTI brain damage alert: 1799*7c478bd9Sstevel@tonic-gate * XTI interface adopts the notion of an option being an 1800*7c478bd9Sstevel@tonic-gate * "absolute requirement" from OSI transport service (but applies 1801*7c478bd9Sstevel@tonic-gate * it to all transports including Internet transports). 1802*7c478bd9Sstevel@tonic-gate * The main effect of that is action on failure to "negotiate" a 1803*7c478bd9Sstevel@tonic-gate * requested option to the exact requested value 1804*7c478bd9Sstevel@tonic-gate * 1805*7c478bd9Sstevel@tonic-gate * - if the option is an "absolute requirement", the primitive 1806*7c478bd9Sstevel@tonic-gate * is aborted (e.g T_DISCON_REQ or T_UDERR generated) 1807*7c478bd9Sstevel@tonic-gate * - if the option is NOT and "absolute requirement" it can 1808*7c478bd9Sstevel@tonic-gate * just be ignored. 1809*7c478bd9Sstevel@tonic-gate * 1810*7c478bd9Sstevel@tonic-gate * We would not support "negotiating" of options on connection 1811*7c478bd9Sstevel@tonic-gate * primitives for Internet transports. However just in case we 1812*7c478bd9Sstevel@tonic-gate * forced to in order to pass strange test suites, the design here 1813*7c478bd9Sstevel@tonic-gate * tries to support these notions. 1814*7c478bd9Sstevel@tonic-gate * 1815*7c478bd9Sstevel@tonic-gate * tpi_optcom_buf(q, mp, opt_lenp, opt_offset, cred, dbobjp, thisdg_attrs, 1816*7c478bd9Sstevel@tonic-gate * *is_absreq_failurep) 1817*7c478bd9Sstevel@tonic-gate * 1818*7c478bd9Sstevel@tonic-gate * - Verify the option buffer, if formatted badly, return error 1 1819*7c478bd9Sstevel@tonic-gate * 1820*7c478bd9Sstevel@tonic-gate * - If it is a "permissions" failure (read-only), return error 2 1821*7c478bd9Sstevel@tonic-gate * 1822*7c478bd9Sstevel@tonic-gate * - Else, process the option "in place", the following can happen, 1823*7c478bd9Sstevel@tonic-gate * - if a "privileged" option, mark it as "ignored". 1824*7c478bd9Sstevel@tonic-gate * - if "not supported", mark "ignored" 1825*7c478bd9Sstevel@tonic-gate * - if "supported" attempt negotiation and fill result in 1826*7c478bd9Sstevel@tonic-gate * the outcome 1827*7c478bd9Sstevel@tonic-gate * - if "absolute requirement", set "*is_absreq_failurep" 1828*7c478bd9Sstevel@tonic-gate * - if NOT an "absolute requirement", then our 1829*7c478bd9Sstevel@tonic-gate * interpretation is to mark is at ignored if 1830*7c478bd9Sstevel@tonic-gate * negotiation fails (Spec allows partial success 1831*7c478bd9Sstevel@tonic-gate * as in OSI protocols but not failure) 1832*7c478bd9Sstevel@tonic-gate * 1833*7c478bd9Sstevel@tonic-gate * Then delete "ignored" options from option buffer and return success. 1834*7c478bd9Sstevel@tonic-gate * 1835*7c478bd9Sstevel@tonic-gate */ 1836*7c478bd9Sstevel@tonic-gate 1837*7c478bd9Sstevel@tonic-gate int 1838*7c478bd9Sstevel@tonic-gate tpi_optcom_buf(queue_t *q, mblk_t *mp, t_scalar_t *opt_lenp, 1839*7c478bd9Sstevel@tonic-gate t_scalar_t opt_offset, cred_t *cr, optdb_obj_t *dbobjp, 1840*7c478bd9Sstevel@tonic-gate void *thisdg_attrs, int *is_absreq_failurep) 1841*7c478bd9Sstevel@tonic-gate { 1842*7c478bd9Sstevel@tonic-gate opt_set_fn setfn = dbobjp->odb_setfn; 1843*7c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 1844*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 1845*7c478bd9Sstevel@tonic-gate struct T_opthdr *opt, *opt_start, *opt_end; 1846*7c478bd9Sstevel@tonic-gate mblk_t *copy_mp_head; 1847*7c478bd9Sstevel@tonic-gate uchar_t *optr, *init_optr; 1848*7c478bd9Sstevel@tonic-gate opdes_t *optd; 1849*7c478bd9Sstevel@tonic-gate uint_t optset_context; 1850*7c478bd9Sstevel@tonic-gate t_uscalar_t olen; 1851*7c478bd9Sstevel@tonic-gate int error = 0; 1852*7c478bd9Sstevel@tonic-gate 1853*7c478bd9Sstevel@tonic-gate ASSERT((uchar_t *)opt_lenp > mp->b_rptr && 1854*7c478bd9Sstevel@tonic-gate (uchar_t *)opt_lenp < mp->b_wptr); 1855*7c478bd9Sstevel@tonic-gate 1856*7c478bd9Sstevel@tonic-gate copy_mp_head = NULL; 1857*7c478bd9Sstevel@tonic-gate *is_absreq_failurep = 0; 1858*7c478bd9Sstevel@tonic-gate switch (((union T_primitives *)mp->b_rptr)->type) { 1859*7c478bd9Sstevel@tonic-gate case T_CONN_REQ: 1860*7c478bd9Sstevel@tonic-gate case T_CONN_RES: 1861*7c478bd9Sstevel@tonic-gate optset_context = SETFN_CONN_NEGOTIATE; 1862*7c478bd9Sstevel@tonic-gate break; 1863*7c478bd9Sstevel@tonic-gate case T_UNITDATA_REQ: 1864*7c478bd9Sstevel@tonic-gate optset_context = SETFN_UD_NEGOTIATE; 1865*7c478bd9Sstevel@tonic-gate break; 1866*7c478bd9Sstevel@tonic-gate default: 1867*7c478bd9Sstevel@tonic-gate /* 1868*7c478bd9Sstevel@tonic-gate * should never get here, all possible TPI primitives 1869*7c478bd9Sstevel@tonic-gate * where this can be called from should be accounted 1870*7c478bd9Sstevel@tonic-gate * for in the cases above 1871*7c478bd9Sstevel@tonic-gate */ 1872*7c478bd9Sstevel@tonic-gate return (EINVAL); 1873*7c478bd9Sstevel@tonic-gate } 1874*7c478bd9Sstevel@tonic-gate 1875*7c478bd9Sstevel@tonic-gate if ((opt_start = (struct T_opthdr *) 1876*7c478bd9Sstevel@tonic-gate mi_offset_param(mp, opt_offset, *opt_lenp)) == NULL) { 1877*7c478bd9Sstevel@tonic-gate error = ENOPROTOOPT; 1878*7c478bd9Sstevel@tonic-gate goto error_ret; 1879*7c478bd9Sstevel@tonic-gate } 1880*7c478bd9Sstevel@tonic-gate if (!__TPI_TOPT_ISALIGNED(opt_start)) { 1881*7c478bd9Sstevel@tonic-gate error = ENOPROTOOPT; 1882*7c478bd9Sstevel@tonic-gate goto error_ret; 1883*7c478bd9Sstevel@tonic-gate } 1884*7c478bd9Sstevel@tonic-gate 1885*7c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)((uchar_t *)opt_start 1886*7c478bd9Sstevel@tonic-gate + *opt_lenp); 1887*7c478bd9Sstevel@tonic-gate 1888*7c478bd9Sstevel@tonic-gate if ((copy_mp_head = copyb(mp)) == (mblk_t *)NULL) { 1889*7c478bd9Sstevel@tonic-gate error = ENOMEM; 1890*7c478bd9Sstevel@tonic-gate goto error_ret; 1891*7c478bd9Sstevel@tonic-gate } 1892*7c478bd9Sstevel@tonic-gate 1893*7c478bd9Sstevel@tonic-gate init_optr = optr = (uchar_t *)©_mp_head->b_rptr[opt_offset]; 1894*7c478bd9Sstevel@tonic-gate 1895*7c478bd9Sstevel@tonic-gate for (opt = opt_start; opt && (opt < opt_end); 1896*7c478bd9Sstevel@tonic-gate opt = _TPI_TOPT_NEXTHDR(opt_start, *opt_lenp, opt)) { 1897*7c478bd9Sstevel@tonic-gate /* 1898*7c478bd9Sstevel@tonic-gate * Validate the option for length and alignment 1899*7c478bd9Sstevel@tonic-gate * before accessing anything in it 1900*7c478bd9Sstevel@tonic-gate */ 1901*7c478bd9Sstevel@tonic-gate if (!_TPI_TOPT_VALID(opt, opt_start, opt_end)) { 1902*7c478bd9Sstevel@tonic-gate error = ENOPROTOOPT; 1903*7c478bd9Sstevel@tonic-gate goto error_ret; 1904*7c478bd9Sstevel@tonic-gate } 1905*7c478bd9Sstevel@tonic-gate 1906*7c478bd9Sstevel@tonic-gate /* Find the option in the opt_arr. */ 1907*7c478bd9Sstevel@tonic-gate optd = opt_chk_lookup(opt->level, opt->name, 1908*7c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt); 1909*7c478bd9Sstevel@tonic-gate 1910*7c478bd9Sstevel@tonic-gate if (optd == NULL) { 1911*7c478bd9Sstevel@tonic-gate /* 1912*7c478bd9Sstevel@tonic-gate * Option not found 1913*7c478bd9Sstevel@tonic-gate */ 1914*7c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 1915*7c478bd9Sstevel@tonic-gate continue; 1916*7c478bd9Sstevel@tonic-gate } 1917*7c478bd9Sstevel@tonic-gate 1918*7c478bd9Sstevel@tonic-gate /* 1919*7c478bd9Sstevel@tonic-gate * Weird but as in XTI spec. 1920*7c478bd9Sstevel@tonic-gate * Sec 6.3.6 "Privileged and ReadOnly Options" 1921*7c478bd9Sstevel@tonic-gate * Permission problems (e.g.readonly) fail with bad access 1922*7c478bd9Sstevel@tonic-gate * BUT "privileged" option request from those NOT PRIVILEGED 1923*7c478bd9Sstevel@tonic-gate * are to be merely "ignored". 1924*7c478bd9Sstevel@tonic-gate * XXX Prevents "probing" of privileged options ? 1925*7c478bd9Sstevel@tonic-gate */ 1926*7c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 1927*7c478bd9Sstevel@tonic-gate error = EACCES; 1928*7c478bd9Sstevel@tonic-gate goto error_ret; 1929*7c478bd9Sstevel@tonic-gate } 1930*7c478bd9Sstevel@tonic-gate if (OA_MATCHED_PRIV(optd, cr)) { 1931*7c478bd9Sstevel@tonic-gate /* 1932*7c478bd9Sstevel@tonic-gate * For privileged options, we DO perform 1933*7c478bd9Sstevel@tonic-gate * access checks as is common sense 1934*7c478bd9Sstevel@tonic-gate */ 1935*7c478bd9Sstevel@tonic-gate if (!OA_WX_ANYPRIV(optd)) { 1936*7c478bd9Sstevel@tonic-gate error = EACCES; 1937*7c478bd9Sstevel@tonic-gate goto error_ret; 1938*7c478bd9Sstevel@tonic-gate } 1939*7c478bd9Sstevel@tonic-gate } else { 1940*7c478bd9Sstevel@tonic-gate /* 1941*7c478bd9Sstevel@tonic-gate * For non privileged, we fail instead following 1942*7c478bd9Sstevel@tonic-gate * "ignore" semantics dictated by XTI spec for 1943*7c478bd9Sstevel@tonic-gate * permissions problems. 1944*7c478bd9Sstevel@tonic-gate * Sec 6.3.6 "Privileged and ReadOnly Options" 1945*7c478bd9Sstevel@tonic-gate * XXX Should we do "ignore" semantics ? 1946*7c478bd9Sstevel@tonic-gate */ 1947*7c478bd9Sstevel@tonic-gate if (!OA_WX_NOPRIV(optd)) { /* nopriv */ 1948*7c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 1949*7c478bd9Sstevel@tonic-gate continue; 1950*7c478bd9Sstevel@tonic-gate } 1951*7c478bd9Sstevel@tonic-gate } 1952*7c478bd9Sstevel@tonic-gate /* 1953*7c478bd9Sstevel@tonic-gate * 1954*7c478bd9Sstevel@tonic-gate * If the negotiation fails, for options that 1955*7c478bd9Sstevel@tonic-gate * are "absolute requirement", it is a fatal error. 1956*7c478bd9Sstevel@tonic-gate * For options that are NOT "absolute requirements", 1957*7c478bd9Sstevel@tonic-gate * and the value fails to negotiate, the XTI spec 1958*7c478bd9Sstevel@tonic-gate * only considers the possibility of partial success 1959*7c478bd9Sstevel@tonic-gate * (T_PARTSUCCES - not likely for Internet protocols). 1960*7c478bd9Sstevel@tonic-gate * The spec is in denial about complete failure 1961*7c478bd9Sstevel@tonic-gate * (T_FAILURE) to negotiate for options that are 1962*7c478bd9Sstevel@tonic-gate * carried on T_CONN_REQ/T_CONN_RES/T_UNITDATA 1963*7c478bd9Sstevel@tonic-gate * We interpret the T_FAILURE to negotiate an option 1964*7c478bd9Sstevel@tonic-gate * that is NOT an absolute requirement that it is safe 1965*7c478bd9Sstevel@tonic-gate * to ignore it. 1966*7c478bd9Sstevel@tonic-gate */ 1967*7c478bd9Sstevel@tonic-gate 1968*7c478bd9Sstevel@tonic-gate /* verify length */ 1969*7c478bd9Sstevel@tonic-gate if (!opt_length_ok(optd, opt)) { 1970*7c478bd9Sstevel@tonic-gate /* bad size */ 1971*7c478bd9Sstevel@tonic-gate if ((optd->opdes_props & OP_NOT_ABSREQ) == 0) { 1972*7c478bd9Sstevel@tonic-gate /* option is absolute requirement */ 1973*7c478bd9Sstevel@tonic-gate *is_absreq_failurep = 1; 1974*7c478bd9Sstevel@tonic-gate error = EINVAL; 1975*7c478bd9Sstevel@tonic-gate goto error_ret; 1976*7c478bd9Sstevel@tonic-gate } 1977*7c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 1978*7c478bd9Sstevel@tonic-gate continue; 1979*7c478bd9Sstevel@tonic-gate } 1980*7c478bd9Sstevel@tonic-gate 1981*7c478bd9Sstevel@tonic-gate /* 1982*7c478bd9Sstevel@tonic-gate * verified generic attributes. Now call set function. 1983*7c478bd9Sstevel@tonic-gate * Note: We assume the following to simplify code. 1984*7c478bd9Sstevel@tonic-gate * XXX If this is found not to be valid, this routine 1985*7c478bd9Sstevel@tonic-gate * will need to be rewritten. At this point it would 1986*7c478bd9Sstevel@tonic-gate * be premature to introduce more complexity than is 1987*7c478bd9Sstevel@tonic-gate * needed. 1988*7c478bd9Sstevel@tonic-gate * Assumption: For variable length options, we assume 1989*7c478bd9Sstevel@tonic-gate * that the value returned will be same or less length 1990*7c478bd9Sstevel@tonic-gate * (size does not increase). This makes it OK to pass the 1991*7c478bd9Sstevel@tonic-gate * same space for output as it is on input. 1992*7c478bd9Sstevel@tonic-gate */ 1993*7c478bd9Sstevel@tonic-gate 1994*7c478bd9Sstevel@tonic-gate error = (*setfn)(q, optset_context, opt->level, opt->name, 1995*7c478bd9Sstevel@tonic-gate opt->len - (t_uscalar_t)sizeof (struct T_opthdr), 1996*7c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(opt), &olen, _TPI_TOPT_DATA(opt), 1997*7c478bd9Sstevel@tonic-gate thisdg_attrs, cr, NULL); 1998*7c478bd9Sstevel@tonic-gate 1999*7c478bd9Sstevel@tonic-gate if (olen > (int)(opt->len - sizeof (struct T_opthdr))) { 2000*7c478bd9Sstevel@tonic-gate /* 2001*7c478bd9Sstevel@tonic-gate * Space on output more than space on input. Should 2002*7c478bd9Sstevel@tonic-gate * not happen and we consider it a bug/error. 2003*7c478bd9Sstevel@tonic-gate * More of a restriction than an error in our 2004*7c478bd9Sstevel@tonic-gate * implementation. Will see if we can live with this 2005*7c478bd9Sstevel@tonic-gate * otherwise code will get more hairy with multiple 2006*7c478bd9Sstevel@tonic-gate * passes. 2007*7c478bd9Sstevel@tonic-gate */ 2008*7c478bd9Sstevel@tonic-gate error = EINVAL; 2009*7c478bd9Sstevel@tonic-gate goto error_ret; 2010*7c478bd9Sstevel@tonic-gate } 2011*7c478bd9Sstevel@tonic-gate if (error != 0) { 2012*7c478bd9Sstevel@tonic-gate if ((optd->opdes_props & OP_NOT_ABSREQ) == 0) { 2013*7c478bd9Sstevel@tonic-gate /* option is absolute requirement. */ 2014*7c478bd9Sstevel@tonic-gate *is_absreq_failurep = 1; 2015*7c478bd9Sstevel@tonic-gate goto error_ret; 2016*7c478bd9Sstevel@tonic-gate } 2017*7c478bd9Sstevel@tonic-gate /* 2018*7c478bd9Sstevel@tonic-gate * failed - but option "not an absolute 2019*7c478bd9Sstevel@tonic-gate * requirement" 2020*7c478bd9Sstevel@tonic-gate */ 2021*7c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 2022*7c478bd9Sstevel@tonic-gate continue; 2023*7c478bd9Sstevel@tonic-gate } 2024*7c478bd9Sstevel@tonic-gate /* 2025*7c478bd9Sstevel@tonic-gate * Fill in the only possible successful result 2026*7c478bd9Sstevel@tonic-gate * (Note: TPI allows for T_PARTSUCCESS - partial 2027*7c478bd9Sstevel@tonic-gate * sucess result code which is relevant in OSI world 2028*7c478bd9Sstevel@tonic-gate * and not possible in Internet code) 2029*7c478bd9Sstevel@tonic-gate */ 2030*7c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 2031*7c478bd9Sstevel@tonic-gate 2032*7c478bd9Sstevel@tonic-gate /* 2033*7c478bd9Sstevel@tonic-gate * Add T_SUCCESS result code options to the "output" options. 2034*7c478bd9Sstevel@tonic-gate * No T_FAILURES or T_NOTSUPPORT here as they are to be 2035*7c478bd9Sstevel@tonic-gate * ignored. 2036*7c478bd9Sstevel@tonic-gate * This code assumes output option buffer will 2037*7c478bd9Sstevel@tonic-gate * be <= input option buffer. 2038*7c478bd9Sstevel@tonic-gate * 2039*7c478bd9Sstevel@tonic-gate * Copy option header+value 2040*7c478bd9Sstevel@tonic-gate */ 2041*7c478bd9Sstevel@tonic-gate bcopy(opt, optr, opt->len); 2042*7c478bd9Sstevel@tonic-gate optr += _TPI_ALIGN_TOPT(opt->len); 2043*7c478bd9Sstevel@tonic-gate } 2044*7c478bd9Sstevel@tonic-gate /* 2045*7c478bd9Sstevel@tonic-gate * Overwrite the input mblk option buffer now with the output 2046*7c478bd9Sstevel@tonic-gate * and update length, and contents in original mbl 2047*7c478bd9Sstevel@tonic-gate * (offset remains unchanged). 2048*7c478bd9Sstevel@tonic-gate */ 2049*7c478bd9Sstevel@tonic-gate *opt_lenp = (t_scalar_t)(optr - init_optr); 2050*7c478bd9Sstevel@tonic-gate if (*opt_lenp > 0) { 2051*7c478bd9Sstevel@tonic-gate bcopy(init_optr, opt_start, *opt_lenp); 2052*7c478bd9Sstevel@tonic-gate } 2053*7c478bd9Sstevel@tonic-gate 2054*7c478bd9Sstevel@tonic-gate error_ret: 2055*7c478bd9Sstevel@tonic-gate if (copy_mp_head != NULL) 2056*7c478bd9Sstevel@tonic-gate freeb(copy_mp_head); 2057*7c478bd9Sstevel@tonic-gate return (error); 2058*7c478bd9Sstevel@tonic-gate } 2059*7c478bd9Sstevel@tonic-gate 2060*7c478bd9Sstevel@tonic-gate static opdes_t * 2061*7c478bd9Sstevel@tonic-gate opt_chk_lookup(t_uscalar_t level, t_uscalar_t name, opdes_t *opt_arr, 2062*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt) 2063*7c478bd9Sstevel@tonic-gate { 2064*7c478bd9Sstevel@tonic-gate opdes_t *optd; 2065*7c478bd9Sstevel@tonic-gate 2066*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; 2067*7c478bd9Sstevel@tonic-gate optd++) { 2068*7c478bd9Sstevel@tonic-gate if (level == (uint_t)optd->opdes_level && 2069*7c478bd9Sstevel@tonic-gate name == (uint_t)optd->opdes_name) 2070*7c478bd9Sstevel@tonic-gate return (optd); 2071*7c478bd9Sstevel@tonic-gate } 2072*7c478bd9Sstevel@tonic-gate return (NULL); 2073*7c478bd9Sstevel@tonic-gate } 2074*7c478bd9Sstevel@tonic-gate 2075*7c478bd9Sstevel@tonic-gate static boolean_t 2076*7c478bd9Sstevel@tonic-gate opt_level_valid(t_uscalar_t level, optlevel_t *valid_level_arr, 2077*7c478bd9Sstevel@tonic-gate uint_t valid_level_arr_cnt) 2078*7c478bd9Sstevel@tonic-gate { 2079*7c478bd9Sstevel@tonic-gate optlevel_t *olp; 2080*7c478bd9Sstevel@tonic-gate 2081*7c478bd9Sstevel@tonic-gate for (olp = valid_level_arr; 2082*7c478bd9Sstevel@tonic-gate olp < &valid_level_arr[valid_level_arr_cnt]; 2083*7c478bd9Sstevel@tonic-gate olp++) { 2084*7c478bd9Sstevel@tonic-gate if (level == (uint_t)(*olp)) 2085*7c478bd9Sstevel@tonic-gate return (B_TRUE); 2086*7c478bd9Sstevel@tonic-gate } 2087*7c478bd9Sstevel@tonic-gate return (B_FALSE); 2088*7c478bd9Sstevel@tonic-gate } 2089*7c478bd9Sstevel@tonic-gate 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate /* 2092*7c478bd9Sstevel@tonic-gate * Compute largest possible size for an option buffer containing 2093*7c478bd9Sstevel@tonic-gate * all options in one buffer. 2094*7c478bd9Sstevel@tonic-gate * 2095*7c478bd9Sstevel@tonic-gate * XXX TBD, investigate use of opt_bloated_maxsize() to avoid 2096*7c478bd9Sstevel@tonic-gate * wastefully large buffer allocation. 2097*7c478bd9Sstevel@tonic-gate */ 2098*7c478bd9Sstevel@tonic-gate static size_t 2099*7c478bd9Sstevel@tonic-gate opt_level_allopts_lengths(t_uscalar_t level, opdes_t *opt_arr, 2100*7c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt) 2101*7c478bd9Sstevel@tonic-gate { 2102*7c478bd9Sstevel@tonic-gate opdes_t *optd; 2103*7c478bd9Sstevel@tonic-gate size_t allopt_len = 0; /* 0 implies no option at this level */ 2104*7c478bd9Sstevel@tonic-gate 2105*7c478bd9Sstevel@tonic-gate /* 2106*7c478bd9Sstevel@tonic-gate * Scan opt_arr computing aggregate length 2107*7c478bd9Sstevel@tonic-gate * requirement for storing values of all 2108*7c478bd9Sstevel@tonic-gate * options. 2109*7c478bd9Sstevel@tonic-gate * Note: we do not filter for permissions 2110*7c478bd9Sstevel@tonic-gate * etc. This will be >= the real aggregate 2111*7c478bd9Sstevel@tonic-gate * length required (upper bound). 2112*7c478bd9Sstevel@tonic-gate */ 2113*7c478bd9Sstevel@tonic-gate 2114*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; 2115*7c478bd9Sstevel@tonic-gate optd++) { 2116*7c478bd9Sstevel@tonic-gate if (level == optd->opdes_level) { 2117*7c478bd9Sstevel@tonic-gate allopt_len += sizeof (struct T_opthdr) + 2118*7c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(optd->opdes_size); 2119*7c478bd9Sstevel@tonic-gate } 2120*7c478bd9Sstevel@tonic-gate } 2121*7c478bd9Sstevel@tonic-gate return (allopt_len); /* 0 implies level not found */ 2122*7c478bd9Sstevel@tonic-gate } 2123*7c478bd9Sstevel@tonic-gate 2124*7c478bd9Sstevel@tonic-gate /* 2125*7c478bd9Sstevel@tonic-gate * Compute largest possible size for an option buffer containing 2126*7c478bd9Sstevel@tonic-gate * all options in one buffer - a (theoretical?) worst case scenario 2127*7c478bd9Sstevel@tonic-gate * for certain cases. 2128*7c478bd9Sstevel@tonic-gate */ 2129*7c478bd9Sstevel@tonic-gate t_uscalar_t 2130*7c478bd9Sstevel@tonic-gate optcom_max_optbuf_len(opdes_t *opt_arr, uint_t opt_arr_cnt) 2131*7c478bd9Sstevel@tonic-gate { 2132*7c478bd9Sstevel@tonic-gate t_uscalar_t max_optbuf_len = sizeof (struct T_info_ack); 2133*7c478bd9Sstevel@tonic-gate opdes_t *optd; 2134*7c478bd9Sstevel@tonic-gate 2135*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 2136*7c478bd9Sstevel@tonic-gate max_optbuf_len += (t_uscalar_t)sizeof (struct T_opthdr) + 2137*7c478bd9Sstevel@tonic-gate (t_uscalar_t)_TPI_ALIGN_TOPT(optd->opdes_size); 2138*7c478bd9Sstevel@tonic-gate } 2139*7c478bd9Sstevel@tonic-gate return (max_optbuf_len); 2140*7c478bd9Sstevel@tonic-gate } 2141*7c478bd9Sstevel@tonic-gate 2142*7c478bd9Sstevel@tonic-gate /* 2143*7c478bd9Sstevel@tonic-gate * Compute largest possible size for OPT_size for a transport. 2144*7c478bd9Sstevel@tonic-gate * Heuristic used is to add all but certain extremely large 2145*7c478bd9Sstevel@tonic-gate * size options; this is done by calling opt_bloated_maxsize(). 2146*7c478bd9Sstevel@tonic-gate * It affects user level allocations in TLI/XTI code using t_alloc() 2147*7c478bd9Sstevel@tonic-gate * and other TLI/XTI implementation instance strucutures. 2148*7c478bd9Sstevel@tonic-gate * The large size options excluded are presumed to be 2149*7c478bd9Sstevel@tonic-gate * never accessed through the (theoretical?) worst case code paths 2150*7c478bd9Sstevel@tonic-gate * through TLI/XTI as they are currently IPv6 specific options. 2151*7c478bd9Sstevel@tonic-gate */ 2152*7c478bd9Sstevel@tonic-gate 2153*7c478bd9Sstevel@tonic-gate t_uscalar_t 2154*7c478bd9Sstevel@tonic-gate optcom_max_optsize(opdes_t *opt_arr, uint_t opt_arr_cnt) 2155*7c478bd9Sstevel@tonic-gate { 2156*7c478bd9Sstevel@tonic-gate t_uscalar_t max_optbuf_len = sizeof (struct T_info_ack); 2157*7c478bd9Sstevel@tonic-gate opdes_t *optd; 2158*7c478bd9Sstevel@tonic-gate 2159*7c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 2160*7c478bd9Sstevel@tonic-gate if (!opt_bloated_maxsize(optd)) { 2161*7c478bd9Sstevel@tonic-gate max_optbuf_len += 2162*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_opthdr) + 2163*7c478bd9Sstevel@tonic-gate (t_uscalar_t)_TPI_ALIGN_TOPT(optd->opdes_size); 2164*7c478bd9Sstevel@tonic-gate } 2165*7c478bd9Sstevel@tonic-gate } 2166*7c478bd9Sstevel@tonic-gate return (max_optbuf_len); 2167*7c478bd9Sstevel@tonic-gate } 2168*7c478bd9Sstevel@tonic-gate 2169*7c478bd9Sstevel@tonic-gate /* 2170*7c478bd9Sstevel@tonic-gate * The theoretical model used in optcom_max_optsize() and 2171*7c478bd9Sstevel@tonic-gate * opt_level_allopts_lengths() accounts for the worst case of all 2172*7c478bd9Sstevel@tonic-gate * possible options for the theoretical cases and results in wasteful 2173*7c478bd9Sstevel@tonic-gate * memory allocations for certain theoretically correct usage scenarios. 2174*7c478bd9Sstevel@tonic-gate * In practice, the "features" they support are rarely, if ever, 2175*7c478bd9Sstevel@tonic-gate * used and even then only by test suites for those features (VSU, VST). 2176*7c478bd9Sstevel@tonic-gate * However, they result in large allocations due to the increased transport 2177*7c478bd9Sstevel@tonic-gate * T_INFO_ACK OPT_size field affecting t_alloc() users and TLI/XTI library 2178*7c478bd9Sstevel@tonic-gate * instance data structures for applications. 2179*7c478bd9Sstevel@tonic-gate * 2180*7c478bd9Sstevel@tonic-gate * The following routine opt_bloated_maxsize() supports a hack that avoids 2181*7c478bd9Sstevel@tonic-gate * paying the tax for the bloated options by excluding them and pretending 2182*7c478bd9Sstevel@tonic-gate * they don't exist for certain features without affecting features that 2183*7c478bd9Sstevel@tonic-gate * do use them. 2184*7c478bd9Sstevel@tonic-gate * 2185*7c478bd9Sstevel@tonic-gate * XXX Currently implemented only for optcom_max_optsize() 2186*7c478bd9Sstevel@tonic-gate * (to reduce risk late in release). 2187*7c478bd9Sstevel@tonic-gate * TBD for future, investigate use in optcom_level_allopts_lengths() and 2188*7c478bd9Sstevel@tonic-gate * all the instances of T_ALLOPT processing to exclude "bloated options". 2189*7c478bd9Sstevel@tonic-gate * Will not affect VSU/VST tests as they do not test with IPPROTO_IPV6 2190*7c478bd9Sstevel@tonic-gate * level options which are the only ones that fit the "bloated maxsize" 2191*7c478bd9Sstevel@tonic-gate * option profile now. 2192*7c478bd9Sstevel@tonic-gate */ 2193*7c478bd9Sstevel@tonic-gate static boolean_t 2194*7c478bd9Sstevel@tonic-gate opt_bloated_maxsize(opdes_t *optd) 2195*7c478bd9Sstevel@tonic-gate { 2196*7c478bd9Sstevel@tonic-gate if (optd->opdes_level != IPPROTO_IPV6) 2197*7c478bd9Sstevel@tonic-gate return (B_FALSE); 2198*7c478bd9Sstevel@tonic-gate switch (optd->opdes_name) { 2199*7c478bd9Sstevel@tonic-gate case IPV6_HOPOPTS: 2200*7c478bd9Sstevel@tonic-gate case IPV6_DSTOPTS: 2201*7c478bd9Sstevel@tonic-gate case IPV6_RTHDRDSTOPTS: 2202*7c478bd9Sstevel@tonic-gate case IPV6_RTHDR: 2203*7c478bd9Sstevel@tonic-gate case IPV6_PATHMTU: 2204*7c478bd9Sstevel@tonic-gate return (B_TRUE); 2205*7c478bd9Sstevel@tonic-gate default: 2206*7c478bd9Sstevel@tonic-gate break; 2207*7c478bd9Sstevel@tonic-gate } 2208*7c478bd9Sstevel@tonic-gate return (B_FALSE); 2209*7c478bd9Sstevel@tonic-gate } 2210*7c478bd9Sstevel@tonic-gate 2211*7c478bd9Sstevel@tonic-gate static boolean_t 2212*7c478bd9Sstevel@tonic-gate opt_length_ok(opdes_t *optd, struct T_opthdr *opt) 2213*7c478bd9Sstevel@tonic-gate { 2214*7c478bd9Sstevel@tonic-gate /* 2215*7c478bd9Sstevel@tonic-gate * Verify length. 2216*7c478bd9Sstevel@tonic-gate * Value specified should match length of fixed length option or be 2217*7c478bd9Sstevel@tonic-gate * less than maxlen of variable length option. 2218*7c478bd9Sstevel@tonic-gate */ 2219*7c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_VARLEN) { 2220*7c478bd9Sstevel@tonic-gate if (opt->len <= optd->opdes_size + 2221*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_opthdr)) 2222*7c478bd9Sstevel@tonic-gate return (B_TRUE); 2223*7c478bd9Sstevel@tonic-gate } else { 2224*7c478bd9Sstevel@tonic-gate /* fixed length option */ 2225*7c478bd9Sstevel@tonic-gate if (opt->len == optd->opdes_size + 2226*7c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_opthdr)) 2227*7c478bd9Sstevel@tonic-gate return (B_TRUE); 2228*7c478bd9Sstevel@tonic-gate } 2229*7c478bd9Sstevel@tonic-gate return (B_FALSE); 2230*7c478bd9Sstevel@tonic-gate } 2231