17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*45916cd2Sjpk * Common Development and Distribution License (the "License"). 6*45916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*45916cd2Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * This file contains common code for handling Options Management requests. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/stream.h> 357c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 367c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 377c478bd9Sstevel@tonic-gate #include <sys/errno.h> 387c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 397c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 407c478bd9Sstevel@tonic-gate #include <sys/socket.h> 417c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 427c478bd9Sstevel@tonic-gate #include <sys/debug.h> /* for ASSERT */ 437c478bd9Sstevel@tonic-gate #include <sys/policy.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include <inet/common.h> 467c478bd9Sstevel@tonic-gate #include <inet/mi.h> 477c478bd9Sstevel@tonic-gate #include <inet/nd.h> 487c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 497c478bd9Sstevel@tonic-gate #include <inet/ip.h> 507c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 517c478bd9Sstevel@tonic-gate #include <netinet/in.h> 527c478bd9Sstevel@tonic-gate #include "optcom.h" 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * Function prototypes 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate static t_scalar_t process_topthdrs_first_pass(mblk_t *, cred_t *, optdb_obj_t *, 607c478bd9Sstevel@tonic-gate boolean_t *, size_t *); 617c478bd9Sstevel@tonic-gate static t_scalar_t do_options_second_pass(queue_t *q, mblk_t *reqmp, 627c478bd9Sstevel@tonic-gate mblk_t *ack_mp, cred_t *, optdb_obj_t *dbobjp, 637c478bd9Sstevel@tonic-gate mblk_t *first_mp, boolean_t is_restart, boolean_t *queued_statusp); 647c478bd9Sstevel@tonic-gate static t_uscalar_t get_worst_status(t_uscalar_t, t_uscalar_t); 657c478bd9Sstevel@tonic-gate static int do_opt_default(queue_t *, struct T_opthdr *, uchar_t **, 667c478bd9Sstevel@tonic-gate t_uscalar_t *, cred_t *, optdb_obj_t *); 677c478bd9Sstevel@tonic-gate static void do_opt_current(queue_t *, struct T_opthdr *, uchar_t **, 687c478bd9Sstevel@tonic-gate t_uscalar_t *, cred_t *cr, optdb_obj_t *); 697c478bd9Sstevel@tonic-gate static int do_opt_check_or_negotiate(queue_t *q, struct T_opthdr *reqopt, 707c478bd9Sstevel@tonic-gate uint_t optset_context, uchar_t **resptrp, t_uscalar_t *worst_statusp, 717c478bd9Sstevel@tonic-gate cred_t *, optdb_obj_t *dbobjp, mblk_t *first_mp); 727c478bd9Sstevel@tonic-gate static opdes_t *opt_chk_lookup(t_uscalar_t, t_uscalar_t, opdes_t *, uint_t); 737c478bd9Sstevel@tonic-gate static boolean_t opt_level_valid(t_uscalar_t, optlevel_t *, uint_t); 747c478bd9Sstevel@tonic-gate static size_t opt_level_allopts_lengths(t_uscalar_t, opdes_t *, uint_t); 757c478bd9Sstevel@tonic-gate static boolean_t opt_length_ok(opdes_t *, struct T_opthdr *); 767c478bd9Sstevel@tonic-gate static t_uscalar_t optcom_max_optbuf_len(opdes_t *, uint_t); 777c478bd9Sstevel@tonic-gate static boolean_t opt_bloated_maxsize(opdes_t *); 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* Common code for sending back a T_ERROR_ACK. */ 807c478bd9Sstevel@tonic-gate void 817c478bd9Sstevel@tonic-gate optcom_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error) 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 847c478bd9Sstevel@tonic-gate qreply(q, mp); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * The option management routines svr4_optcom_req() and tpi_optcom_req() use 897c478bd9Sstevel@tonic-gate * callback functions as arguments. Here is the expected interfaces 907c478bd9Sstevel@tonic-gate * assumed from the callback functions 917c478bd9Sstevel@tonic-gate * 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * (1) deffn(q, optlevel, optname, optvalp) 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * - Function only called when default value comes from protocol 967c478bd9Sstevel@tonic-gate * specific code and not the option database table (indicated by 977c478bd9Sstevel@tonic-gate * OP_DEF_FN property in option database.) 987c478bd9Sstevel@tonic-gate * - Error return is -1. Valid returns are >=0. 997c478bd9Sstevel@tonic-gate * - When valid, the return value represents the length used for storing 1007c478bd9Sstevel@tonic-gate * the default value of the option. 1017c478bd9Sstevel@tonic-gate * - Error return implies the called routine did not recognize this 1027c478bd9Sstevel@tonic-gate * option. Something downstream could so input is left unchanged 1037c478bd9Sstevel@tonic-gate * in request buffer. 1047c478bd9Sstevel@tonic-gate * 1057c478bd9Sstevel@tonic-gate * (2) getfn(q, optlevel, optname, optvalp) 1067c478bd9Sstevel@tonic-gate * 1077c478bd9Sstevel@tonic-gate * - Error return is -1. Valid returns are >=0. 1087c478bd9Sstevel@tonic-gate * - When valid, the return value represents the length used for storing 1097c478bd9Sstevel@tonic-gate * the actual value of the option. 1107c478bd9Sstevel@tonic-gate * - Error return implies the called routine did not recognize this 1117c478bd9Sstevel@tonic-gate * option. Something downstream could so input is left unchanged 1127c478bd9Sstevel@tonic-gate * in request buffer. 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * (3) setfn(q, optset_context, optlevel, optname, inlen, invalp, 1157c478bd9Sstevel@tonic-gate * outlenp, outvalp, attrp, cr); 1167c478bd9Sstevel@tonic-gate * 1177c478bd9Sstevel@tonic-gate * - OK return is 0, Error code is returned as a non-zero argument. 1187c478bd9Sstevel@tonic-gate * - If negative it is ignored by svr4_optcom_req(). If positive, error 1197c478bd9Sstevel@tonic-gate * is returned. A negative return implies that option, while handled on 1207c478bd9Sstevel@tonic-gate * this stack is not handled at this level and will be handled further 1217c478bd9Sstevel@tonic-gate * downstream. 1227c478bd9Sstevel@tonic-gate * - Both negative and positive errors are treats as errors in an 1237c478bd9Sstevel@tonic-gate * identical manner by tpi_optcom_req(). The errors affect "status" 1247c478bd9Sstevel@tonic-gate * field of each option's T_opthdr. If sucessfull, an appropriate sucess 1257c478bd9Sstevel@tonic-gate * result is carried. If error, it instantiated to "failure" at the 1267c478bd9Sstevel@tonic-gate * topmost level and left unchanged at other levels. (This "failure" can 1277c478bd9Sstevel@tonic-gate * turn to a success at another level). 1287c478bd9Sstevel@tonic-gate * - optset_context passed for tpi_optcom_req(). It is interpreted as: 1297c478bd9Sstevel@tonic-gate * - SETFN_OPTCOM_CHECKONLY 1307c478bd9Sstevel@tonic-gate * semantics are to pretend to set the value and report 1317c478bd9Sstevel@tonic-gate * back if it would be successful. 1327c478bd9Sstevel@tonic-gate * This is used with T_CHECK semantics in XTI 1337c478bd9Sstevel@tonic-gate * - SETFN_OPTCOM_NEGOTIATE 1347c478bd9Sstevel@tonic-gate * set the value. Call from option management primitive 1357c478bd9Sstevel@tonic-gate * T_OPTMGMT_REQ when T_NEGOTIATE flags is used. 1367c478bd9Sstevel@tonic-gate * - SETFN_UD_NEGOTIATE 1377c478bd9Sstevel@tonic-gate * option request came riding on UNITDATA primitive most often 1387c478bd9Sstevel@tonic-gate * has "this datagram" semantics to influence prpoerties 1397c478bd9Sstevel@tonic-gate * affecting an outgoig datagram or associated with recived 1407c478bd9Sstevel@tonic-gate * datagram 1417c478bd9Sstevel@tonic-gate * [ Note: XTI permits this use outside of "this datagram" 1427c478bd9Sstevel@tonic-gate * semantics also and permits setting "management related" 1437c478bd9Sstevel@tonic-gate * options in this context and its test suite enforces it ] 1447c478bd9Sstevel@tonic-gate * - SETFN_CONN_NEGOTATE 1457c478bd9Sstevel@tonic-gate * option request came riding on CONN_REQ/RES primitive and 1467c478bd9Sstevel@tonic-gate * most often has "this connection" (negotiation during 1477c478bd9Sstevel@tonic-gate * "connection estblishment") semantics. 1487c478bd9Sstevel@tonic-gate * [ Note: XTI permits use of these outside of "this connection" 1497c478bd9Sstevel@tonic-gate * semantics and permits "management related" options in this 1507c478bd9Sstevel@tonic-gate * context and its test suite enforces it. ] 1517c478bd9Sstevel@tonic-gate * 1527c478bd9Sstevel@tonic-gate * - inlen, invalp is the option length,value requested to be set. 1537c478bd9Sstevel@tonic-gate * - outlenp, outvalp represent return parameters which contain the 1547c478bd9Sstevel@tonic-gate * value set and it might be different from one passed on input. 1557c478bd9Sstevel@tonic-gate * - attrp points to a data structure that's used by v6 modules to 1567c478bd9Sstevel@tonic-gate * store ancillary data options or sticky options. 1577c478bd9Sstevel@tonic-gate * - cr points to the caller's credentials 1587c478bd9Sstevel@tonic-gate * - the caller might pass same buffers for input and output and the 1597c478bd9Sstevel@tonic-gate * routine should protect against this case by not updating output 1607c478bd9Sstevel@tonic-gate * buffers until it is done referencing input buffers and any other 1617c478bd9Sstevel@tonic-gate * issues (e.g. not use bcopy() if we do not trust what it does). 1627c478bd9Sstevel@tonic-gate * - If option is not known, it returns error. We randomly pick EINVAL. 1637c478bd9Sstevel@tonic-gate * It can however get called with options that are handled downstream 1647c478bd9Sstevel@tonic-gate * opr upstream so for svr4_optcom_req(), it does not return error for 1657c478bd9Sstevel@tonic-gate * negative return values. 1667c478bd9Sstevel@tonic-gate * 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * Upper Level Protocols call this routine when they receive 1717c478bd9Sstevel@tonic-gate * a T_SVR4_OPTMGMT_REQ message. They supply callback functions 1727c478bd9Sstevel@tonic-gate * for setting a new value for a single options, getting the 1737c478bd9Sstevel@tonic-gate * current value for a single option, and checking for support 1747c478bd9Sstevel@tonic-gate * of a single option. svr4_optcom_req validates the option management 1757c478bd9Sstevel@tonic-gate * buffer passed in, and calls the appropriate routines to do the 1767c478bd9Sstevel@tonic-gate * job requested. 1777c478bd9Sstevel@tonic-gate * XXX Code below needs some restructuring after we have some more 1787c478bd9Sstevel@tonic-gate * macros to support 'struct opthdr' in the headers. 1797c478bd9Sstevel@tonic-gate * 1807c478bd9Sstevel@tonic-gate * IP-MT notes: The option management framework functions svr4_optcom_req() and 1817c478bd9Sstevel@tonic-gate * tpi_optcom_req() allocate and prepend an M_CTL mblk to the actual 1827c478bd9Sstevel@tonic-gate * T_optmgmt_req mblk and pass the chain as an additional parameter to the 1837c478bd9Sstevel@tonic-gate * protocol set functions. If a protocol set function (such as ip_opt_set) 1847c478bd9Sstevel@tonic-gate * cannot process the option immediately it can return EINPROGRESS. ip_opt_set 1857c478bd9Sstevel@tonic-gate * enqueues the message in the appropriate sq and returns EINPROGRESS. Later 1867c478bd9Sstevel@tonic-gate * the sq framework arranges to restart this operation and passes control to 1877c478bd9Sstevel@tonic-gate * the restart function ip_restart_optmgmt() which in turn calls 1887c478bd9Sstevel@tonic-gate * svr4_optcom_req() or tpi_optcom_req() to restart the option processing. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate int 1917c478bd9Sstevel@tonic-gate svr4_optcom_req(queue_t *q, mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate pfi_t deffn = dbobjp->odb_deffn; 1947c478bd9Sstevel@tonic-gate pfi_t getfn = dbobjp->odb_getfn; 1957c478bd9Sstevel@tonic-gate opt_set_fn setfn = dbobjp->odb_setfn; 1967c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 1977c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 1987c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 1997c478bd9Sstevel@tonic-gate opt_restart_t *or; 2007c478bd9Sstevel@tonic-gate struct opthdr *restart_opt; 2017c478bd9Sstevel@tonic-gate boolean_t is_restart = B_FALSE; 2027c478bd9Sstevel@tonic-gate mblk_t *first_mp; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate t_uscalar_t max_optbuf_len; 2057c478bd9Sstevel@tonic-gate int len; 2067c478bd9Sstevel@tonic-gate mblk_t *mp1 = NULL; 2077c478bd9Sstevel@tonic-gate struct opthdr *next_opt; 2087c478bd9Sstevel@tonic-gate struct opthdr *opt; 2097c478bd9Sstevel@tonic-gate struct opthdr *opt1; 2107c478bd9Sstevel@tonic-gate struct opthdr *opt_end; 2117c478bd9Sstevel@tonic-gate struct opthdr *opt_start; 2127c478bd9Sstevel@tonic-gate opdes_t *optd; 2137c478bd9Sstevel@tonic-gate boolean_t pass_to_next = B_FALSE; 2147c478bd9Sstevel@tonic-gate boolean_t pass_to_ip = B_FALSE; 215ff550d0eSmasputra boolean_t is_tcp; 2167c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa; 2177c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor; 2187c478bd9Sstevel@tonic-gate 219ff550d0eSmasputra is_tcp = (dbobjp == &tcp_opt_obj); 220ff550d0eSmasputra 2217c478bd9Sstevel@tonic-gate /* 2227c478bd9Sstevel@tonic-gate * Allocate M_CTL and prepend to the packet for restarting this 2237c478bd9Sstevel@tonic-gate * option if needed. IP may need to queue and restart the option 2247c478bd9Sstevel@tonic-gate * if it cannot obtain exclusive conditions immediately. Please see 2257c478bd9Sstevel@tonic-gate * IP-MT notes before the start of svr4_optcom_req 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) { 2287c478bd9Sstevel@tonic-gate is_restart = B_TRUE; 2297c478bd9Sstevel@tonic-gate first_mp = mp; 2307c478bd9Sstevel@tonic-gate mp = mp->b_cont; 2317c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr - mp->b_rptr >= 2327c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_req)); 2337c478bd9Sstevel@tonic-gate tor = (struct T_optmgmt_req *)mp->b_rptr; 2347c478bd9Sstevel@tonic-gate ASSERT(tor->MGMT_flags == T_NEGOTIATE); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 2377c478bd9Sstevel@tonic-gate opt_start = or->or_start; 2387c478bd9Sstevel@tonic-gate opt_end = or->or_end; 2397c478bd9Sstevel@tonic-gate restart_opt = or->or_ropt; 2407c478bd9Sstevel@tonic-gate goto restart; 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate tor = (struct T_optmgmt_req *)mp->b_rptr; 2447c478bd9Sstevel@tonic-gate /* Verify message integrity. */ 2457c478bd9Sstevel@tonic-gate if (mp->b_wptr - mp->b_rptr < sizeof (struct T_optmgmt_req)) 2467c478bd9Sstevel@tonic-gate goto bad_opt; 2477c478bd9Sstevel@tonic-gate /* Verify MGMT_flags legal */ 2487c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 2497c478bd9Sstevel@tonic-gate case T_DEFAULT: 2507c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 2517c478bd9Sstevel@tonic-gate case T_CURRENT: 2527c478bd9Sstevel@tonic-gate case T_CHECK: 2537c478bd9Sstevel@tonic-gate /* OK - legal request flags */ 2547c478bd9Sstevel@tonic-gate break; 2557c478bd9Sstevel@tonic-gate default: 2567c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 2577c478bd9Sstevel@tonic-gate return (0); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_DEFAULT) { 2607c478bd9Sstevel@tonic-gate /* Is it a request for default option settings? */ 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* 2637c478bd9Sstevel@tonic-gate * Note: XXX TLI and TPI specification was unclear about 2647c478bd9Sstevel@tonic-gate * semantics of T_DEFAULT and the following historical note 2657c478bd9Sstevel@tonic-gate * and its interpretation is incorrect (it implies a request 2667c478bd9Sstevel@tonic-gate * for default values of only the identified options not all. 2677c478bd9Sstevel@tonic-gate * The semantics have been explained better in XTI spec.) 2687c478bd9Sstevel@tonic-gate * However, we do not modify (comment or code) here to keep 2697c478bd9Sstevel@tonic-gate * compatibility. 2707c478bd9Sstevel@tonic-gate * We can rethink this if it ever becomes an issue. 2717c478bd9Sstevel@tonic-gate * ----historical comment start------ 2727c478bd9Sstevel@tonic-gate * As we understand it, the input buffer is meaningless 2737c478bd9Sstevel@tonic-gate * so we ditch the message. A T_DEFAULT request is a 2747c478bd9Sstevel@tonic-gate * request to obtain a buffer containing defaults for 2757c478bd9Sstevel@tonic-gate * all supported options, so we allocate a maximum length 2767c478bd9Sstevel@tonic-gate * reply. 2777c478bd9Sstevel@tonic-gate * ----historical comment end ------- 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate /* T_DEFAULT not passed down */ 2807c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider == B_TRUE); 2817c478bd9Sstevel@tonic-gate freemsg(mp); 2827c478bd9Sstevel@tonic-gate max_optbuf_len = optcom_max_optbuf_len(opt_arr, 2837c478bd9Sstevel@tonic-gate opt_arr_cnt); 2847c478bd9Sstevel@tonic-gate mp = allocb(max_optbuf_len, BPRI_MED); 2857c478bd9Sstevel@tonic-gate if (!mp) { 2867c478bd9Sstevel@tonic-gate no_mem:; 2877c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 2887c478bd9Sstevel@tonic-gate return (0); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* Initialize the T_optmgmt_ack header. */ 2927c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)mp->b_rptr; 2937c478bd9Sstevel@tonic-gate bzero((char *)toa, max_optbuf_len); 2947c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_ACK; 2957c478bd9Sstevel@tonic-gate toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack); 2967c478bd9Sstevel@tonic-gate /* TODO: Is T_DEFAULT the right thing to put in MGMT_flags? */ 2977c478bd9Sstevel@tonic-gate toa->MGMT_flags = T_DEFAULT; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* Now walk the table of options passed in */ 3007c478bd9Sstevel@tonic-gate opt = (struct opthdr *)&toa[1]; 3017c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * All the options in the table of options passed 3047c478bd9Sstevel@tonic-gate * in are by definition supported by the protocol 3057c478bd9Sstevel@tonic-gate * calling this function. 3067c478bd9Sstevel@tonic-gate */ 3077c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) 3087c478bd9Sstevel@tonic-gate continue; 3097c478bd9Sstevel@tonic-gate opt->level = optd->opdes_level; 3107c478bd9Sstevel@tonic-gate opt->name = optd->opdes_name; 3117c478bd9Sstevel@tonic-gate if (!(optd->opdes_props & OP_DEF_FN) || 3127c478bd9Sstevel@tonic-gate ((len = (*deffn)(q, opt->level, 3137c478bd9Sstevel@tonic-gate opt->name, (uchar_t *)&opt[1])) < 0)) { 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * Fill length and value from table. 3167c478bd9Sstevel@tonic-gate * 3177c478bd9Sstevel@tonic-gate * Default value not instantiated from function 3187c478bd9Sstevel@tonic-gate * (or the protocol specific function failed it; 3197c478bd9Sstevel@tonic-gate * In this interpretation of T_DEFAULT, this is 3207c478bd9Sstevel@tonic-gate * the best we can do) 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate switch (optd->opdes_size) { 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * Since options are guaranteed aligned only 3257c478bd9Sstevel@tonic-gate * on a 4 byte boundary (t_scalar_t) any 3267c478bd9Sstevel@tonic-gate * option that is greater in size will default 3277c478bd9Sstevel@tonic-gate * to the bcopy below 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate case sizeof (int32_t): 3307c478bd9Sstevel@tonic-gate *(int32_t *)&opt[1] = 3317c478bd9Sstevel@tonic-gate (int32_t)optd->opdes_default; 3327c478bd9Sstevel@tonic-gate break; 3337c478bd9Sstevel@tonic-gate case sizeof (int16_t): 3347c478bd9Sstevel@tonic-gate *(int16_t *)&opt[1] = 3357c478bd9Sstevel@tonic-gate (int16_t)optd->opdes_default; 3367c478bd9Sstevel@tonic-gate break; 3377c478bd9Sstevel@tonic-gate case sizeof (int8_t): 3387c478bd9Sstevel@tonic-gate *(int8_t *)&opt[1] = 3397c478bd9Sstevel@tonic-gate (int8_t)optd->opdes_default; 3407c478bd9Sstevel@tonic-gate break; 3417c478bd9Sstevel@tonic-gate default: 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * other length but still assume 3447c478bd9Sstevel@tonic-gate * fixed - use bcopy 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate bcopy(optd->opdes_defbuf, 3477c478bd9Sstevel@tonic-gate &opt[1], optd->opdes_size); 3487c478bd9Sstevel@tonic-gate break; 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate opt->len = optd->opdes_size; 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate else 3537c478bd9Sstevel@tonic-gate opt->len = (t_uscalar_t)len; 3547c478bd9Sstevel@tonic-gate opt = (struct opthdr *)((char *)&opt[1] + 3557c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* Now record the final length. */ 3597c478bd9Sstevel@tonic-gate toa->OPT_length = (t_scalar_t)((char *)opt - (char *)&toa[1]); 3607c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)opt; 3617c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PCPROTO; 3627c478bd9Sstevel@tonic-gate /* Ship it back. */ 3637c478bd9Sstevel@tonic-gate qreply(q, mp); 3647c478bd9Sstevel@tonic-gate return (0); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate /* T_DEFAULT processing complete - no more T_DEFAULT */ 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * For T_NEGOTIATE, T_CURRENT, and T_CHECK requests, we make a 3707c478bd9Sstevel@tonic-gate * pass through the input buffer validating the details and 3717c478bd9Sstevel@tonic-gate * making sure each option is supported by the protocol. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate if ((opt_start = (struct opthdr *)mi_offset_param(mp, 3747c478bd9Sstevel@tonic-gate tor->OPT_offset, tor->OPT_length)) == NULL) 3757c478bd9Sstevel@tonic-gate goto bad_opt; 3767c478bd9Sstevel@tonic-gate if (!__TPI_OPT_ISALIGNED(opt_start)) 3777c478bd9Sstevel@tonic-gate goto bad_opt; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate opt_end = (struct opthdr *)((uchar_t *)opt_start + 3807c478bd9Sstevel@tonic-gate tor->OPT_length); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate for (opt = opt_start; opt < opt_end; opt = next_opt) { 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Verify we have room to reference the option header 3857c478bd9Sstevel@tonic-gate * fields in the option buffer. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate if ((uchar_t *)opt + sizeof (struct opthdr) > 3887c478bd9Sstevel@tonic-gate (uchar_t *)opt_end) 3897c478bd9Sstevel@tonic-gate goto bad_opt; 3907c478bd9Sstevel@tonic-gate /* 3917c478bd9Sstevel@tonic-gate * We now compute pointer to next option in buffer 'next_opt' 3927c478bd9Sstevel@tonic-gate * The next_opt computation above below 'opt->len' initialized 3937c478bd9Sstevel@tonic-gate * by application which cannot be trusted. The usual value 3947c478bd9Sstevel@tonic-gate * too large will be captured by the loop termination condition 3957c478bd9Sstevel@tonic-gate * above. We check for the following which it will miss. 3967c478bd9Sstevel@tonic-gate * -pointer space wraparound arithmetic overflow 3977c478bd9Sstevel@tonic-gate * -last option in buffer with 'opt->len' being too large 3987c478bd9Sstevel@tonic-gate * (only reason 'next_opt' should equal or exceed 3997c478bd9Sstevel@tonic-gate * 'opt_end' for last option is roundup unless length is 4007c478bd9Sstevel@tonic-gate * too-large/invalid) 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate next_opt = (struct opthdr *)((uchar_t *)&opt[1] + 4037c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate if ((uchar_t *)next_opt < (uchar_t *)&opt[1] || 4067c478bd9Sstevel@tonic-gate ((next_opt >= opt_end) && 4077c478bd9Sstevel@tonic-gate (((uchar_t *)next_opt - (uchar_t *)opt_end) >= 4087c478bd9Sstevel@tonic-gate __TPI_ALIGN_SIZE))) 4097c478bd9Sstevel@tonic-gate goto bad_opt; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* sanity check */ 4127c478bd9Sstevel@tonic-gate if (opt->name == T_ALLOPT) 4137c478bd9Sstevel@tonic-gate goto bad_opt; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* Find the option in the opt_arr. */ 4167c478bd9Sstevel@tonic-gate if ((optd = opt_chk_lookup(opt->level, opt->name, 4177c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt)) == NULL) { 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Not found, that is a bad thing if 4207c478bd9Sstevel@tonic-gate * the caller is a tpi provider 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 4237c478bd9Sstevel@tonic-gate goto bad_opt; 4247c478bd9Sstevel@tonic-gate else 4257c478bd9Sstevel@tonic-gate continue; /* skip unmodified */ 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* Additional checks dependent on operation. */ 4297c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 4307c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 4317c478bd9Sstevel@tonic-gate if (!OA_WRITE_OR_EXECUTE(optd, cr)) { 4327c478bd9Sstevel@tonic-gate /* can't negotiate option */ 4337c478bd9Sstevel@tonic-gate if (!(OA_MATCHED_PRIV(optd, cr)) && 4347c478bd9Sstevel@tonic-gate OA_WX_ANYPRIV(optd)) { 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * not privileged but privilege 4377c478bd9Sstevel@tonic-gate * will help negotiate option. 4387c478bd9Sstevel@tonic-gate */ 4397c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TACCES, 0); 4407c478bd9Sstevel@tonic-gate return (0); 4417c478bd9Sstevel@tonic-gate } else 4427c478bd9Sstevel@tonic-gate goto bad_opt; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * Verify size for options 4467c478bd9Sstevel@tonic-gate * Note: For retaining compatibility with historical 4477c478bd9Sstevel@tonic-gate * behavior, variable lengths options will have their 4487c478bd9Sstevel@tonic-gate * length verified in the setfn() processing. 4497c478bd9Sstevel@tonic-gate * In order to be compatible with SunOS 4.X we return 4507c478bd9Sstevel@tonic-gate * EINVAL errors for bad lengths. 4517c478bd9Sstevel@tonic-gate */ 4527c478bd9Sstevel@tonic-gate if (!(optd->opdes_props & OP_VARLEN)) { 4537c478bd9Sstevel@tonic-gate /* fixed length - size must match */ 4547c478bd9Sstevel@tonic-gate if (opt->len != optd->opdes_size) { 4557c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, EINVAL); 4567c478bd9Sstevel@tonic-gate return (0); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate break; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate case T_CHECK: 4627c478bd9Sstevel@tonic-gate if (!OA_RWX_ANYPRIV(optd)) 4637c478bd9Sstevel@tonic-gate /* any of "rwx" permission but not not none */ 4647c478bd9Sstevel@tonic-gate goto bad_opt; 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * XXX Since T_CURRENT was not there in TLI and the 4677c478bd9Sstevel@tonic-gate * official TLI inspired TPI standard, getsockopt() 4687c478bd9Sstevel@tonic-gate * API uses T_CHECK (for T_CURRENT semantics) 4697c478bd9Sstevel@tonic-gate * The following fallthru makes sense because of its 4707c478bd9Sstevel@tonic-gate * historical use as semantic equivalent to T_CURRENT. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate /* FALLTHRU */ 4737c478bd9Sstevel@tonic-gate case T_CURRENT: 4747c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) { 4757c478bd9Sstevel@tonic-gate /* can't read option value */ 4767c478bd9Sstevel@tonic-gate if (!(OA_MATCHED_PRIV(optd, cr)) && 4777c478bd9Sstevel@tonic-gate OA_R_ANYPRIV(optd)) { 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * not privileged but privilege 4807c478bd9Sstevel@tonic-gate * will help in reading option value. 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TACCES, 0); 4837c478bd9Sstevel@tonic-gate return (0); 4847c478bd9Sstevel@tonic-gate } else 4857c478bd9Sstevel@tonic-gate goto bad_opt; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate break; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate default: 4907c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 4917c478bd9Sstevel@tonic-gate return (0); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate /* We liked it. Keep going. */ 4947c478bd9Sstevel@tonic-gate } /* end for loop scanning option buffer */ 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* Now complete the operation as required. */ 4977c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 4987c478bd9Sstevel@tonic-gate case T_CHECK: 4997c478bd9Sstevel@tonic-gate /* 5007c478bd9Sstevel@tonic-gate * Historically used same as T_CURRENT (which was added to 5017c478bd9Sstevel@tonic-gate * standard later). Code retained for compatibility. 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 5047c478bd9Sstevel@tonic-gate case T_CURRENT: 5057c478bd9Sstevel@tonic-gate /* 5067c478bd9Sstevel@tonic-gate * Allocate a maximum size reply. Perhaps we are supposed to 5077c478bd9Sstevel@tonic-gate * assume that the input buffer includes space for the answers 5087c478bd9Sstevel@tonic-gate * as well as the opthdrs, but we don't know that for sure. 5097c478bd9Sstevel@tonic-gate * So, instead, we create a new output buffer, using the 5107c478bd9Sstevel@tonic-gate * input buffer only as a list of options. 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate max_optbuf_len = optcom_max_optbuf_len(opt_arr, 5137c478bd9Sstevel@tonic-gate opt_arr_cnt); 5147c478bd9Sstevel@tonic-gate mp1 = allocb_cred(max_optbuf_len, cr); 5157c478bd9Sstevel@tonic-gate if (!mp1) 5167c478bd9Sstevel@tonic-gate goto no_mem; 5177c478bd9Sstevel@tonic-gate /* Initialize the header. */ 5187c478bd9Sstevel@tonic-gate mp1->b_datap->db_type = M_PCPROTO; 5197c478bd9Sstevel@tonic-gate mp1->b_wptr = &mp1->b_rptr[sizeof (struct T_optmgmt_ack)]; 5207c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)mp1->b_rptr; 5217c478bd9Sstevel@tonic-gate toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack); 5227c478bd9Sstevel@tonic-gate toa->MGMT_flags = tor->MGMT_flags; 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * Walk through the input buffer again, this time adding 5257c478bd9Sstevel@tonic-gate * entries to the output buffer for each option requested. 5267c478bd9Sstevel@tonic-gate * Note, sanity of option header, last option etc, verified 5277c478bd9Sstevel@tonic-gate * in first pass. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate opt1 = (struct opthdr *)&toa[1]; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate for (opt = opt_start; opt < opt_end; opt = next_opt) { 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate next_opt = (struct opthdr *)((uchar_t *)&opt[1] + 5347c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate opt1->name = opt->name; 5377c478bd9Sstevel@tonic-gate opt1->level = opt->level; 5387c478bd9Sstevel@tonic-gate len = (*getfn)(q, opt->level, 5397c478bd9Sstevel@tonic-gate opt->name, (uchar_t *)&opt1[1]); 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Failure means option is not recognized. Copy input 5427c478bd9Sstevel@tonic-gate * buffer as is 5437c478bd9Sstevel@tonic-gate */ 5447c478bd9Sstevel@tonic-gate if (len < 0) { 5457c478bd9Sstevel@tonic-gate opt1->len = opt->len; 5467c478bd9Sstevel@tonic-gate bcopy(&opt[1], &opt1[1], opt->len); 5477c478bd9Sstevel@tonic-gate /* 548ff550d0eSmasputra * Pass the option down to IP only 549ff550d0eSmasputra * if TCP hasn't processed it. 5507c478bd9Sstevel@tonic-gate */ 551ff550d0eSmasputra if (is_tcp) 5527c478bd9Sstevel@tonic-gate pass_to_ip = B_TRUE; 553ff550d0eSmasputra } else { 5547c478bd9Sstevel@tonic-gate opt1->len = (t_uscalar_t)len; 555ff550d0eSmasputra } 5567c478bd9Sstevel@tonic-gate opt1 = (struct opthdr *)((uchar_t *)&opt1[1] + 5577c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt1->len)); 5587c478bd9Sstevel@tonic-gate } /* end for loop */ 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* Record the final length. */ 5617c478bd9Sstevel@tonic-gate toa->OPT_length = (t_scalar_t)((uchar_t *)opt1 - 5627c478bd9Sstevel@tonic-gate (uchar_t *)&toa[1]); 5637c478bd9Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)opt1; 5647c478bd9Sstevel@tonic-gate /* Ditch the input buffer. */ 5657c478bd9Sstevel@tonic-gate freemsg(mp); 5667c478bd9Sstevel@tonic-gate mp = mp1; 5677c478bd9Sstevel@tonic-gate /* Always let the next module look at the option. */ 5687c478bd9Sstevel@tonic-gate pass_to_next = B_TRUE; 5697c478bd9Sstevel@tonic-gate break; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 5727c478bd9Sstevel@tonic-gate first_mp = allocb(sizeof (opt_restart_t), BPRI_LO); 5737c478bd9Sstevel@tonic-gate if (first_mp == NULL) { 5747c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 5757c478bd9Sstevel@tonic-gate return (0); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate first_mp->b_datap->db_type = M_CTL; 5787c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 5797c478bd9Sstevel@tonic-gate or->or_start = opt_start; 5807c478bd9Sstevel@tonic-gate or->or_end = opt_end; 5817c478bd9Sstevel@tonic-gate or->or_type = T_SVR4_OPTMGMT_REQ; 5827c478bd9Sstevel@tonic-gate or->or_private = 0; 5837c478bd9Sstevel@tonic-gate first_mp->b_cont = mp; 5847c478bd9Sstevel@tonic-gate restart: 5857c478bd9Sstevel@tonic-gate /* 5867c478bd9Sstevel@tonic-gate * Here we are expecting that the response buffer is exactly 5877c478bd9Sstevel@tonic-gate * the same size as the input buffer. We pass each opthdr 5887c478bd9Sstevel@tonic-gate * to the protocol's set function. If the protocol doesn't 5897c478bd9Sstevel@tonic-gate * like it, it can update the value in it return argument. 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * Pass each negotiated option through the protocol set 5937c478bd9Sstevel@tonic-gate * function. 5947c478bd9Sstevel@tonic-gate * Note: sanity check on option header values done in first 5957c478bd9Sstevel@tonic-gate * pass and not repeated here. 5967c478bd9Sstevel@tonic-gate */ 5977c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)tor; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate for (opt = is_restart ? restart_opt: opt_start; opt < opt_end; 6007c478bd9Sstevel@tonic-gate opt = next_opt) { 6017c478bd9Sstevel@tonic-gate int error; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * Point to the current option in or, in case this 6057c478bd9Sstevel@tonic-gate * option has to be restarted later on 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate or->or_ropt = opt; 6087c478bd9Sstevel@tonic-gate next_opt = (struct opthdr *)((uchar_t *)&opt[1] + 6097c478bd9Sstevel@tonic-gate _TPI_ALIGN_OPT(opt->len)); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate error = (*setfn)(q, SETFN_OPTCOM_NEGOTIATE, 6127c478bd9Sstevel@tonic-gate opt->level, opt->name, 6137c478bd9Sstevel@tonic-gate opt->len, (uchar_t *)&opt[1], 6147c478bd9Sstevel@tonic-gate &opt->len, (uchar_t *)&opt[1], NULL, cr, first_mp); 6157c478bd9Sstevel@tonic-gate /* 6167c478bd9Sstevel@tonic-gate * Treat positive "errors" as real. 6177c478bd9Sstevel@tonic-gate * Note: negative errors are to be treated as 6187c478bd9Sstevel@tonic-gate * non-fatal by svr4_optcom_req() and are 6197c478bd9Sstevel@tonic-gate * returned by setfn() when it is passed an 6207c478bd9Sstevel@tonic-gate * option it does not handle. Since the option 6217c478bd9Sstevel@tonic-gate * passed opt_chk_lookup(), it is implied that 6227c478bd9Sstevel@tonic-gate * it is valid but was either handled upstream 6237c478bd9Sstevel@tonic-gate * or will be handled downstream. 6247c478bd9Sstevel@tonic-gate */ 6257c478bd9Sstevel@tonic-gate if (error == EINPROGRESS) { 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate * The message is queued and will be 6287c478bd9Sstevel@tonic-gate * reprocessed later. Typically ip queued 6297c478bd9Sstevel@tonic-gate * the message to get some exclusive conditions 6307c478bd9Sstevel@tonic-gate * and later on calls this func again. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate return (EINPROGRESS); 6337c478bd9Sstevel@tonic-gate } else if (error > 0) { 6347c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, error); 6357c478bd9Sstevel@tonic-gate freeb(first_mp); 6367c478bd9Sstevel@tonic-gate return (0); 637ff550d0eSmasputra } else if (error < 0 && is_tcp) { 6387c478bd9Sstevel@tonic-gate /* 639ff550d0eSmasputra * Pass the option down to IP only 640ff550d0eSmasputra * if TCP hasn't processed it. 6417c478bd9Sstevel@tonic-gate */ 6427c478bd9Sstevel@tonic-gate pass_to_ip = B_TRUE; 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate /* Done with the restart control mp. */ 6467c478bd9Sstevel@tonic-gate freeb(first_mp); 6477c478bd9Sstevel@tonic-gate pass_to_next = B_TRUE; 6487c478bd9Sstevel@tonic-gate break; 6497c478bd9Sstevel@tonic-gate default: 6507c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 6517c478bd9Sstevel@tonic-gate return (0); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate if (pass_to_next && (q->q_next != NULL || pass_to_ip)) { 6557c478bd9Sstevel@tonic-gate /* Send it down to the next module and let it reply */ 6567c478bd9Sstevel@tonic-gate toa->PRIM_type = T_SVR4_OPTMGMT_REQ; /* Changed by IP to ACK */ 6577c478bd9Sstevel@tonic-gate if (q->q_next != NULL) 6587c478bd9Sstevel@tonic-gate putnext(q, mp); 6597c478bd9Sstevel@tonic-gate else 6607c478bd9Sstevel@tonic-gate ip_output(Q_TO_CONN(q), mp, q, IP_WPUT); 6617c478bd9Sstevel@tonic-gate } else { 6627c478bd9Sstevel@tonic-gate /* Set common fields in the header. */ 6637c478bd9Sstevel@tonic-gate toa->MGMT_flags = T_SUCCESS; 6647c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PCPROTO; 6657c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_ACK; 6667c478bd9Sstevel@tonic-gate qreply(q, mp); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate return (0); 6697c478bd9Sstevel@tonic-gate bad_opt:; 6707c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADOPT, 0); 6717c478bd9Sstevel@tonic-gate return (0); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * New optcom_req inspired by TPI/XTI semantics 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate int 6787c478bd9Sstevel@tonic-gate tpi_optcom_req(queue_t *q, mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate t_scalar_t t_error; 6817c478bd9Sstevel@tonic-gate mblk_t *toa_mp; 6827c478bd9Sstevel@tonic-gate boolean_t pass_to_next; 6837c478bd9Sstevel@tonic-gate size_t toa_len; 6847c478bd9Sstevel@tonic-gate struct T_optmgmt_ack *toa; 6857c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = 6867c478bd9Sstevel@tonic-gate (struct T_optmgmt_req *)mp->b_rptr; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate opt_restart_t *or; 6897c478bd9Sstevel@tonic-gate boolean_t is_restart = B_FALSE; 6907c478bd9Sstevel@tonic-gate mblk_t *first_mp = NULL; 6917c478bd9Sstevel@tonic-gate t_uscalar_t worst_status; 6927c478bd9Sstevel@tonic-gate boolean_t queued_status; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate /* 6957c478bd9Sstevel@tonic-gate * Allocate M_CTL and prepend to the packet for restarting this 6967c478bd9Sstevel@tonic-gate * option if needed. IP may need to queue and restart the option 6977c478bd9Sstevel@tonic-gate * if it cannot obtain exclusive conditions immediately. Please see 6987c478bd9Sstevel@tonic-gate * IP-MT notes before the start of svr4_optcom_req 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_CTL) { 7017c478bd9Sstevel@tonic-gate is_restart = B_TRUE; 7027c478bd9Sstevel@tonic-gate first_mp = mp; 7037c478bd9Sstevel@tonic-gate toa_mp = mp->b_cont; 7047c478bd9Sstevel@tonic-gate mp = toa_mp->b_cont; 7057c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr - mp->b_rptr >= 7067c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_req)); 7077c478bd9Sstevel@tonic-gate tor = (struct T_optmgmt_req *)mp->b_rptr; 7087c478bd9Sstevel@tonic-gate ASSERT(tor->MGMT_flags == T_NEGOTIATE); 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 7117c478bd9Sstevel@tonic-gate goto restart; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* Verify message integrity. */ 7157c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_optmgmt_req)) { 7167c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADOPT, 0); 7177c478bd9Sstevel@tonic-gate return (0); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* Verify MGMT_flags legal */ 7217c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 7227c478bd9Sstevel@tonic-gate case T_DEFAULT: 7237c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 7247c478bd9Sstevel@tonic-gate case T_CURRENT: 7257c478bd9Sstevel@tonic-gate case T_CHECK: 7267c478bd9Sstevel@tonic-gate /* OK - legal request flags */ 7277c478bd9Sstevel@tonic-gate break; 7287c478bd9Sstevel@tonic-gate default: 7297c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TBADFLAG, 0); 7307c478bd9Sstevel@tonic-gate return (0); 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate * In this design, there are two passes required on the input buffer 7357c478bd9Sstevel@tonic-gate * mostly to accomodate variable length options and "T_ALLOPT" option 7367c478bd9Sstevel@tonic-gate * which has the semantics "all options of the specified level". 7377c478bd9Sstevel@tonic-gate * 7387c478bd9Sstevel@tonic-gate * For T_DEFAULT, T_NEGOTIATE, T_CURRENT, and T_CHECK requests, we make 7397c478bd9Sstevel@tonic-gate * a pass through the input buffer validating the details and making 7407c478bd9Sstevel@tonic-gate * sure each option is supported by the protocol. We also determine the 7417c478bd9Sstevel@tonic-gate * length of the option buffer to return. (Variable length options and 7427c478bd9Sstevel@tonic-gate * T_ALLOPT mean that length can be different for output buffer). 7437c478bd9Sstevel@tonic-gate */ 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate pass_to_next = B_FALSE; /* initial value */ 7467c478bd9Sstevel@tonic-gate toa_len = 0; /* initial value */ 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate /* 7497c478bd9Sstevel@tonic-gate * First pass, we do the following 7507c478bd9Sstevel@tonic-gate * - estimate cumulative length needed for results 7517c478bd9Sstevel@tonic-gate * - set "status" field based on permissions, option header check 7527c478bd9Sstevel@tonic-gate * etc. 7537c478bd9Sstevel@tonic-gate * - determine "pass_to_next" whether we need to send request to 7547c478bd9Sstevel@tonic-gate * downstream module/driver. 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate if ((t_error = process_topthdrs_first_pass(mp, cr, dbobjp, 7577c478bd9Sstevel@tonic-gate &pass_to_next, &toa_len)) != 0) { 7587c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, t_error, 0); 7597c478bd9Sstevel@tonic-gate return (0); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * A validation phase of the input buffer is done. We have also 7647c478bd9Sstevel@tonic-gate * obtained the length requirement and and other details about the 7657c478bd9Sstevel@tonic-gate * input and we liked input buffer so far. We make another scan 7667c478bd9Sstevel@tonic-gate * through the input now and generate the output necessary to complete 7677c478bd9Sstevel@tonic-gate * the operation. 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate toa_mp = allocb_cred(toa_len, cr); 7717c478bd9Sstevel@tonic-gate if (!toa_mp) { 7727c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 7737c478bd9Sstevel@tonic-gate return (0); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate first_mp = allocb(sizeof (opt_restart_t), BPRI_LO); 7777c478bd9Sstevel@tonic-gate if (first_mp == NULL) { 7787c478bd9Sstevel@tonic-gate freeb(toa_mp); 7797c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, TSYSERR, ENOMEM); 7807c478bd9Sstevel@tonic-gate return (0); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate first_mp->b_datap->db_type = M_CTL; 7837c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 7847c478bd9Sstevel@tonic-gate /* 7857c478bd9Sstevel@tonic-gate * Set initial values for generating output. 7867c478bd9Sstevel@tonic-gate */ 7877c478bd9Sstevel@tonic-gate or->or_worst_status = T_SUCCESS; 7887c478bd9Sstevel@tonic-gate or->or_type = T_OPTMGMT_REQ; 7897c478bd9Sstevel@tonic-gate or->or_private = 0; 7907c478bd9Sstevel@tonic-gate /* remaining fields fileed in do_options_second_pass */ 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate restart: 7937c478bd9Sstevel@tonic-gate /* 7947c478bd9Sstevel@tonic-gate * This routine makes another pass through the option buffer this 7957c478bd9Sstevel@tonic-gate * time acting on the request based on "status" result in the 7967c478bd9Sstevel@tonic-gate * first pass. It also performs "expansion" of T_ALLOPT into 7977c478bd9Sstevel@tonic-gate * all options of a certain level and acts on each for this request. 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate if ((t_error = do_options_second_pass(q, mp, toa_mp, cr, dbobjp, 8007c478bd9Sstevel@tonic-gate first_mp, is_restart, &queued_status)) != 0) { 8017c478bd9Sstevel@tonic-gate freemsg(toa_mp); 8027c478bd9Sstevel@tonic-gate optcom_err_ack(q, mp, t_error, 0); 8037c478bd9Sstevel@tonic-gate return (0); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate if (queued_status) { 8067c478bd9Sstevel@tonic-gate /* Option will be restarted */ 8077c478bd9Sstevel@tonic-gate return (EINPROGRESS); 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate worst_status = or->or_worst_status; 8107c478bd9Sstevel@tonic-gate /* Done with the first mp */ 8117c478bd9Sstevel@tonic-gate freeb(first_mp); 8127c478bd9Sstevel@tonic-gate toa_mp->b_cont = NULL; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * Following code relies on the coincidence that T_optmgmt_req 8167c478bd9Sstevel@tonic-gate * and T_optmgmt_ack are identical in binary representation 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate toa = (struct T_optmgmt_ack *)toa_mp->b_rptr; 8197c478bd9Sstevel@tonic-gate toa->OPT_length = (t_scalar_t)(toa_mp->b_wptr - (toa_mp->b_rptr + 8207c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_ack))); 8217c478bd9Sstevel@tonic-gate toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack); 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate toa->MGMT_flags = tor->MGMT_flags; 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate freemsg(mp); /* free input mblk */ 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate /* 8297c478bd9Sstevel@tonic-gate * If there is atleast one option that requires a downstream 8307c478bd9Sstevel@tonic-gate * forwarding and if it is possible, we forward the message 8317c478bd9Sstevel@tonic-gate * downstream. Else we ack it. 8327c478bd9Sstevel@tonic-gate */ 8337c478bd9Sstevel@tonic-gate if (pass_to_next && (q->q_next != NULL || dbobjp == &tcp_opt_obj)) { 8347c478bd9Sstevel@tonic-gate /* 8357c478bd9Sstevel@tonic-gate * We pass it down as T_OPTMGMT_REQ. This code relies 8367c478bd9Sstevel@tonic-gate * on the happy coincidence that T_optmgmt_req and 8377c478bd9Sstevel@tonic-gate * T_optmgmt_ack are identical data structures 8387c478bd9Sstevel@tonic-gate * at the binary representation level. 8397c478bd9Sstevel@tonic-gate */ 8407c478bd9Sstevel@tonic-gate toa_mp->b_datap->db_type = M_PROTO; 8417c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_REQ; 8427c478bd9Sstevel@tonic-gate if (q->q_next != NULL) 8437c478bd9Sstevel@tonic-gate putnext(q, toa_mp); 8447c478bd9Sstevel@tonic-gate else 8457c478bd9Sstevel@tonic-gate ip_output(Q_TO_CONN(q), toa_mp, q, IP_WPUT); 8467c478bd9Sstevel@tonic-gate } else { 8477c478bd9Sstevel@tonic-gate toa->PRIM_type = T_OPTMGMT_ACK; 8487c478bd9Sstevel@tonic-gate toa_mp->b_datap->db_type = M_PCPROTO; 8497c478bd9Sstevel@tonic-gate toa->MGMT_flags |= worst_status; /* XXX "worst" or "OR" TPI ? */ 8507c478bd9Sstevel@tonic-gate qreply(q, toa_mp); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate return (0); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * Following routine makes a pass through option buffer in mp and performs the 8587c478bd9Sstevel@tonic-gate * following tasks. 8597c478bd9Sstevel@tonic-gate * - estimate cumulative length needed for results 8607c478bd9Sstevel@tonic-gate * - set "status" field based on permissions, option header check 8617c478bd9Sstevel@tonic-gate * etc. 8627c478bd9Sstevel@tonic-gate * - determine "pass_to_next" whether we need to send request to 8637c478bd9Sstevel@tonic-gate * downstream module/driver. 8647c478bd9Sstevel@tonic-gate */ 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate static t_scalar_t 8677c478bd9Sstevel@tonic-gate process_topthdrs_first_pass(mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp, 8687c478bd9Sstevel@tonic-gate boolean_t *pass_to_nextp, size_t *toa_lenp) 8697c478bd9Sstevel@tonic-gate { 8707c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 8717c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 8727c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 8737c478bd9Sstevel@tonic-gate optlevel_t *valid_level_arr = dbobjp->odb_valid_levels_arr; 8747c478bd9Sstevel@tonic-gate uint_t valid_level_arr_cnt = dbobjp->odb_valid_levels_arr_cnt; 8757c478bd9Sstevel@tonic-gate struct T_opthdr *opt; 8767c478bd9Sstevel@tonic-gate struct T_opthdr *opt_start, *opt_end; 8777c478bd9Sstevel@tonic-gate opdes_t *optd; 8787c478bd9Sstevel@tonic-gate size_t allopt_len; 8797c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = 8807c478bd9Sstevel@tonic-gate (struct T_optmgmt_req *)mp->b_rptr; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate *toa_lenp = sizeof (struct T_optmgmt_ack); /* initial value */ 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate if ((opt_start = (struct T_opthdr *) 8857c478bd9Sstevel@tonic-gate mi_offset_param(mp, tor->OPT_offset, tor->OPT_length)) == NULL) { 8867c478bd9Sstevel@tonic-gate return (TBADOPT); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate if (!__TPI_TOPT_ISALIGNED(opt_start)) 8897c478bd9Sstevel@tonic-gate return (TBADOPT); 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)((uchar_t *)opt_start + tor->OPT_length); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate for (opt = opt_start; opt && (opt < opt_end); 8947c478bd9Sstevel@tonic-gate opt = _TPI_TOPT_NEXTHDR(opt_start, tor->OPT_length, opt)) { 8957c478bd9Sstevel@tonic-gate /* 8967c478bd9Sstevel@tonic-gate * Validate the option for length and alignment 8977c478bd9Sstevel@tonic-gate * before accessing anything in it. 8987c478bd9Sstevel@tonic-gate */ 8997c478bd9Sstevel@tonic-gate if (!(_TPI_TOPT_VALID(opt, opt_start, opt_end))) 9007c478bd9Sstevel@tonic-gate return (TBADOPT); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* Find the option in the opt_arr. */ 9037c478bd9Sstevel@tonic-gate if (opt->name != T_ALLOPT) { 9047c478bd9Sstevel@tonic-gate optd = opt_chk_lookup(opt->level, opt->name, 9057c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt); 9067c478bd9Sstevel@tonic-gate if (optd == NULL) { 9077c478bd9Sstevel@tonic-gate /* 9087c478bd9Sstevel@tonic-gate * Option not found 9097c478bd9Sstevel@tonic-gate * 9107c478bd9Sstevel@tonic-gate * Verify if level is "valid" or not. 9117c478bd9Sstevel@tonic-gate * Note: This check is required by XTI 9127c478bd9Sstevel@tonic-gate * 9137c478bd9Sstevel@tonic-gate * TPI provider always initializes 9147c478bd9Sstevel@tonic-gate * the "not supported" (or whatever) status 9157c478bd9Sstevel@tonic-gate * for the options. Other levels leave status 9167c478bd9Sstevel@tonic-gate * unchanged if they do not understand an 9177c478bd9Sstevel@tonic-gate * option. 9187c478bd9Sstevel@tonic-gate */ 9197c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) { 9207c478bd9Sstevel@tonic-gate if (!opt_level_valid(opt->level, 9217c478bd9Sstevel@tonic-gate valid_level_arr, 9227c478bd9Sstevel@tonic-gate valid_level_arr_cnt)) 9237c478bd9Sstevel@tonic-gate return (TBADOPT); 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * level is valid - initialize 9267c478bd9Sstevel@tonic-gate * option as not supported 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 9327c478bd9Sstevel@tonic-gate continue; 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate } else { 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * Handle T_ALLOPT case as a special case. 9377c478bd9Sstevel@tonic-gate * Note: T_ALLOPT does not mean anything 9387c478bd9Sstevel@tonic-gate * for T_CHECK operation. 9397c478bd9Sstevel@tonic-gate */ 9407c478bd9Sstevel@tonic-gate allopt_len = 0; 9417c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_CHECK || 9427c478bd9Sstevel@tonic-gate !topmost_tpiprovider || 9437c478bd9Sstevel@tonic-gate ((allopt_len = opt_level_allopts_lengths(opt->level, 9447c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt)) == 0)) { 9457c478bd9Sstevel@tonic-gate /* 9467c478bd9Sstevel@tonic-gate * This is confusing but correct ! 9477c478bd9Sstevel@tonic-gate * It is not valid to to use T_ALLOPT with 9487c478bd9Sstevel@tonic-gate * T_CHECK flag. 9497c478bd9Sstevel@tonic-gate * 9507c478bd9Sstevel@tonic-gate * T_ALLOPT is assumed "expanded" at the 9517c478bd9Sstevel@tonic-gate * topmost_tpiprovider level so it should not 9527c478bd9Sstevel@tonic-gate * be there as an "option name" if this is not 9537c478bd9Sstevel@tonic-gate * a topmost_tpiprovider call and we fail it. 9547c478bd9Sstevel@tonic-gate * 9557c478bd9Sstevel@tonic-gate * opt_level_allopts_lengths() is used to verify 9567c478bd9Sstevel@tonic-gate * that "level" associated with the T_ALLOPT is 9577c478bd9Sstevel@tonic-gate * supported. 9587c478bd9Sstevel@tonic-gate * 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 9617c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 9627c478bd9Sstevel@tonic-gate continue; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate ASSERT(allopt_len != 0); /* remove ? */ 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate *toa_lenp += allopt_len; 9677c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 9687c478bd9Sstevel@tonic-gate /* XXX - always set T_ALLOPT 'pass_to_next' for now */ 9697c478bd9Sstevel@tonic-gate *pass_to_nextp = B_TRUE; 9707c478bd9Sstevel@tonic-gate continue; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * Check if option wants to flow downstream 9747c478bd9Sstevel@tonic-gate */ 9757c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_PASSNEXT) 9767c478bd9Sstevel@tonic-gate *pass_to_nextp = B_TRUE; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate /* Additional checks dependent on operation. */ 9797c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 9807c478bd9Sstevel@tonic-gate case T_DEFAULT: 9817c478bd9Sstevel@tonic-gate case T_CURRENT: 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate /* 9847c478bd9Sstevel@tonic-gate * The opt_chk_lookup() routine call above approved of 9857c478bd9Sstevel@tonic-gate * this option so we can work on the status for it 9867c478bd9Sstevel@tonic-gate * based on the permissions for the operation. (This 9877c478bd9Sstevel@tonic-gate * can override any status for it set at higher levels) 9887c478bd9Sstevel@tonic-gate * We assume this override is OK since chkfn at this 9897c478bd9Sstevel@tonic-gate * level approved of this option. 9907c478bd9Sstevel@tonic-gate * 9917c478bd9Sstevel@tonic-gate * T_CURRENT semantics: 9927c478bd9Sstevel@tonic-gate * The read access is required. Else option 9937c478bd9Sstevel@tonic-gate * status is T_NOTSUPPORT. 9947c478bd9Sstevel@tonic-gate * 9957c478bd9Sstevel@tonic-gate * T_DEFAULT semantics: 9967c478bd9Sstevel@tonic-gate * Note: specification is not clear on this but we 9977c478bd9Sstevel@tonic-gate * interpret T_DEFAULT semantics such that access to 9987c478bd9Sstevel@tonic-gate * read value is required for access even the default 9997c478bd9Sstevel@tonic-gate * value. Otherwise the option status is T_NOTSUPPORT. 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) { 10027c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 10037c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 10047c478bd9Sstevel@tonic-gate /* skip to next */ 10057c478bd9Sstevel@tonic-gate continue; 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate /* 10097c478bd9Sstevel@tonic-gate * T_DEFAULT/T_CURRENT semantics: 10107c478bd9Sstevel@tonic-gate * We know that read access is set. If no other access 10117c478bd9Sstevel@tonic-gate * is set, then status is T_READONLY. 10127c478bd9Sstevel@tonic-gate */ 10137c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) 10147c478bd9Sstevel@tonic-gate opt->status = T_READONLY; 10157c478bd9Sstevel@tonic-gate else 10167c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 10177c478bd9Sstevel@tonic-gate /* 10187c478bd9Sstevel@tonic-gate * Option passes all checks. Make room for it in the 10197c478bd9Sstevel@tonic-gate * ack. Note: size stored in table does not include 10207c478bd9Sstevel@tonic-gate * space for option header. 10217c478bd9Sstevel@tonic-gate */ 10227c478bd9Sstevel@tonic-gate *toa_lenp += sizeof (struct T_opthdr) + 10237c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(optd->opdes_size); 10247c478bd9Sstevel@tonic-gate break; 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate case T_CHECK: 10277c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate /* 10307c478bd9Sstevel@tonic-gate * T_NEGOTIATE semantics: 10317c478bd9Sstevel@tonic-gate * If for fixed length option value on input is not the 10327c478bd9Sstevel@tonic-gate * same as value supplied, then status is T_FAILURE. 10337c478bd9Sstevel@tonic-gate * 10347c478bd9Sstevel@tonic-gate * T_CHECK semantics: 10357c478bd9Sstevel@tonic-gate * If value is supplied, semantics same as T_NEGOTIATE. 10367c478bd9Sstevel@tonic-gate * It is however ok not to supply a value with T_CHECK. 10377c478bd9Sstevel@tonic-gate */ 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_NEGOTIATE || 10407c478bd9Sstevel@tonic-gate (opt->len != sizeof (struct T_opthdr))) { 10417c478bd9Sstevel@tonic-gate /* 10427c478bd9Sstevel@tonic-gate * Implies "value" is specified in T_CHECK or 10437c478bd9Sstevel@tonic-gate * it is a T_NEGOTIATE request. 10447c478bd9Sstevel@tonic-gate * Verify size. 10457c478bd9Sstevel@tonic-gate * Note: This can override anything about this 10467c478bd9Sstevel@tonic-gate * option request done at a higher level. 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate if (!opt_length_ok(optd, opt)) { 10497c478bd9Sstevel@tonic-gate /* bad size */ 10507c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 10517c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 10527c478bd9Sstevel@tonic-gate continue; 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate /* 10567c478bd9Sstevel@tonic-gate * The opt_chk_lookup() routine above() approved of 10577c478bd9Sstevel@tonic-gate * this option so we can work on the status for it based 10587c478bd9Sstevel@tonic-gate * on the permissions for the operation. (This can 10597c478bd9Sstevel@tonic-gate * override anything set at a higher level). 10607c478bd9Sstevel@tonic-gate * 10617c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE semantics: 10627c478bd9Sstevel@tonic-gate * Set status to T_READONLY if read is the only access 10637c478bd9Sstevel@tonic-gate * permitted 10647c478bd9Sstevel@tonic-gate */ 10657c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 10667c478bd9Sstevel@tonic-gate opt->status = T_READONLY; 10677c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 10687c478bd9Sstevel@tonic-gate /* skip to next */ 10697c478bd9Sstevel@tonic-gate continue; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE semantics: 10747c478bd9Sstevel@tonic-gate * If write (or execute) access is not set, then status 10757c478bd9Sstevel@tonic-gate * is T_NOTSUPPORT. 10767c478bd9Sstevel@tonic-gate */ 10777c478bd9Sstevel@tonic-gate if (!OA_WRITE_OR_EXECUTE(optd, cr)) { 10787c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 10797c478bd9Sstevel@tonic-gate *toa_lenp += _TPI_ALIGN_TOPT(opt->len); 10807c478bd9Sstevel@tonic-gate /* skip to next option */ 10817c478bd9Sstevel@tonic-gate continue; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate /* 10847c478bd9Sstevel@tonic-gate * Option passes all checks. Make room for it in the 10857c478bd9Sstevel@tonic-gate * ack and set success in status. 10867c478bd9Sstevel@tonic-gate * Note: size stored in table does not include header 10877c478bd9Sstevel@tonic-gate * length. 10887c478bd9Sstevel@tonic-gate */ 10897c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 10907c478bd9Sstevel@tonic-gate *toa_lenp += sizeof (struct T_opthdr) + 10917c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(optd->opdes_size); 10927c478bd9Sstevel@tonic-gate break; 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate default: 10957c478bd9Sstevel@tonic-gate return (TBADFLAG); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate } /* for loop scanning input buffer */ 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate return (0); /* OK return */ 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate /* 11037c478bd9Sstevel@tonic-gate * This routine makes another pass through the option buffer this 11047c478bd9Sstevel@tonic-gate * time acting on the request based on "status" result in the 11057c478bd9Sstevel@tonic-gate * first pass. It also performs "expansion" of T_ALLOPT into 11067c478bd9Sstevel@tonic-gate * all options of a certain level and acts on each for this request. 11077c478bd9Sstevel@tonic-gate */ 11087c478bd9Sstevel@tonic-gate static t_scalar_t 11097c478bd9Sstevel@tonic-gate do_options_second_pass(queue_t *q, mblk_t *reqmp, mblk_t *ack_mp, cred_t *cr, 11107c478bd9Sstevel@tonic-gate optdb_obj_t *dbobjp, mblk_t *first_mp, boolean_t is_restart, 11117c478bd9Sstevel@tonic-gate boolean_t *queued_statusp) 11127c478bd9Sstevel@tonic-gate { 11137c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 11147c478bd9Sstevel@tonic-gate int failed_option; 11157c478bd9Sstevel@tonic-gate struct T_opthdr *opt; 11167c478bd9Sstevel@tonic-gate struct T_opthdr *opt_start, *opt_end, *restart_opt; 11177c478bd9Sstevel@tonic-gate uchar_t *optr; 11187c478bd9Sstevel@tonic-gate uint_t optset_context; 11197c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor = (struct T_optmgmt_req *)reqmp->b_rptr; 11207c478bd9Sstevel@tonic-gate opt_restart_t *or; 11217c478bd9Sstevel@tonic-gate t_uscalar_t *worst_statusp; 11227c478bd9Sstevel@tonic-gate int err; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate *queued_statusp = B_FALSE; 11257c478bd9Sstevel@tonic-gate or = (opt_restart_t *)first_mp->b_rptr; 11267c478bd9Sstevel@tonic-gate worst_statusp = &or->or_worst_status; 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate optr = (uchar_t *)ack_mp->b_rptr + 11297c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_ack); /* assumed int32_t aligned */ 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * Set initial values for scanning input 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate if (is_restart) { 11357c478bd9Sstevel@tonic-gate opt_start = (struct T_opthdr *)or->or_start; 11367c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)or->or_end; 11377c478bd9Sstevel@tonic-gate restart_opt = (struct T_opthdr *)or->or_ropt; 11387c478bd9Sstevel@tonic-gate } else { 11397c478bd9Sstevel@tonic-gate opt_start = (struct T_opthdr *)mi_offset_param(reqmp, 11407c478bd9Sstevel@tonic-gate tor->OPT_offset, tor->OPT_length); 11417c478bd9Sstevel@tonic-gate if (opt_start == NULL) 11427c478bd9Sstevel@tonic-gate return (TBADOPT); 11437c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)((uchar_t *)opt_start + 11447c478bd9Sstevel@tonic-gate tor->OPT_length); 11457c478bd9Sstevel@tonic-gate or->or_start = (struct opthdr *)opt_start; 11467c478bd9Sstevel@tonic-gate or->or_end = (struct opthdr *)opt_end; 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * construct the mp chain, in case the setfn needs to 11497c478bd9Sstevel@tonic-gate * queue this and restart option processing later on. 11507c478bd9Sstevel@tonic-gate */ 11517c478bd9Sstevel@tonic-gate first_mp->b_cont = ack_mp; 11527c478bd9Sstevel@tonic-gate ack_mp->b_cont = reqmp; 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate ASSERT(__TPI_TOPT_ISALIGNED(opt_start)); /* verified in first pass */ 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate for (opt = is_restart ? restart_opt : opt_start; 11577c478bd9Sstevel@tonic-gate opt && (opt < opt_end); 11587c478bd9Sstevel@tonic-gate opt = _TPI_TOPT_NEXTHDR(opt_start, tor->OPT_length, opt)) { 11597c478bd9Sstevel@tonic-gate or->or_ropt = (struct opthdr *)opt; 11607c478bd9Sstevel@tonic-gate /* verified in first pass */ 11617c478bd9Sstevel@tonic-gate ASSERT(_TPI_TOPT_VALID(opt, opt_start, opt_end)); 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* 11647c478bd9Sstevel@tonic-gate * If the first pass in process_topthdrs_first_pass() 11657c478bd9Sstevel@tonic-gate * has marked the option as a failure case for the MGMT_flags 11667c478bd9Sstevel@tonic-gate * semantics then there is not much to do. 11677c478bd9Sstevel@tonic-gate * 11687c478bd9Sstevel@tonic-gate * Note: For all practical purposes, T_READONLY status is 11697c478bd9Sstevel@tonic-gate * a "success" for T_DEFAULT/T_CURRENT and "failure" for 11707c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE 11717c478bd9Sstevel@tonic-gate */ 11727c478bd9Sstevel@tonic-gate failed_option = 11737c478bd9Sstevel@tonic-gate (opt->status == T_NOTSUPPORT) || 11747c478bd9Sstevel@tonic-gate (opt->status == T_FAILURE) || 11757c478bd9Sstevel@tonic-gate ((tor->MGMT_flags & (T_NEGOTIATE|T_CHECK)) && 11767c478bd9Sstevel@tonic-gate (opt->status == T_READONLY)); 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate if (failed_option) { 11797c478bd9Sstevel@tonic-gate /* 11807c478bd9Sstevel@tonic-gate * According to T_DEFAULT/T_CURRENT semantics, the 11817c478bd9Sstevel@tonic-gate * input values, even if present, are to be ignored. 11827c478bd9Sstevel@tonic-gate * Note: Specification is not clear on this, but we 11837c478bd9Sstevel@tonic-gate * interpret that even though we ignore the values, we 11847c478bd9Sstevel@tonic-gate * can return them as is. So we process them similar to 11857c478bd9Sstevel@tonic-gate * T_CHECK/T_NEGOTIATE case which has the semantics to 11867c478bd9Sstevel@tonic-gate * return the values as is. XXX If interpretation is 11877c478bd9Sstevel@tonic-gate * ever determined incorrect fill in appropriate code 11887c478bd9Sstevel@tonic-gate * here to treat T_DEFAULT/T_CURRENT differently. 11897c478bd9Sstevel@tonic-gate * 11907c478bd9Sstevel@tonic-gate * According to T_CHECK/T_NEGOTIATE semantics, 11917c478bd9Sstevel@tonic-gate * in the case of T_NOTSUPPORT/T_FAILURE/T_READONLY, 11927c478bd9Sstevel@tonic-gate * the semantics are to return the "value" part of 11937c478bd9Sstevel@tonic-gate * option untouched. So here we copy the option 11947c478bd9Sstevel@tonic-gate * head including value part if any to output. 11957c478bd9Sstevel@tonic-gate */ 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate bcopy(opt, optr, opt->len); 11987c478bd9Sstevel@tonic-gate optr += _TPI_ALIGN_TOPT(opt->len); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(opt->status, 12017c478bd9Sstevel@tonic-gate *worst_statusp); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate /* skip to process next option in buffer */ 12047c478bd9Sstevel@tonic-gate continue; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate } /* end if "failed option" */ 12077c478bd9Sstevel@tonic-gate /* 12087c478bd9Sstevel@tonic-gate * The status is T_SUCCESS or T_READONLY 12097c478bd9Sstevel@tonic-gate * We process the value part here 12107c478bd9Sstevel@tonic-gate */ 12117c478bd9Sstevel@tonic-gate ASSERT(opt->status == T_SUCCESS || opt->status == T_READONLY); 12127c478bd9Sstevel@tonic-gate switch (tor->MGMT_flags) { 12137c478bd9Sstevel@tonic-gate case T_DEFAULT: 12147c478bd9Sstevel@tonic-gate /* 12157c478bd9Sstevel@tonic-gate * We fill default value from table or protocol specific 12167c478bd9Sstevel@tonic-gate * function. If this call fails, we pass input through. 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate if (do_opt_default(q, opt, &optr, worst_statusp, 12197c478bd9Sstevel@tonic-gate cr, dbobjp) < 0) { 12207c478bd9Sstevel@tonic-gate /* fail or pass transparently */ 12217c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 12227c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 12237c478bd9Sstevel@tonic-gate bcopy(opt, optr, opt->len); 12247c478bd9Sstevel@tonic-gate optr += _TPI_ALIGN_TOPT(opt->len); 12257c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(opt->status, 12267c478bd9Sstevel@tonic-gate *worst_statusp); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate break; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate case T_CURRENT: 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate do_opt_current(q, opt, &optr, worst_statusp, cr, 12337c478bd9Sstevel@tonic-gate dbobjp); 12347c478bd9Sstevel@tonic-gate break; 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate case T_CHECK: 12377c478bd9Sstevel@tonic-gate case T_NEGOTIATE: 12387c478bd9Sstevel@tonic-gate if (tor->MGMT_flags == T_CHECK) 12397c478bd9Sstevel@tonic-gate optset_context = SETFN_OPTCOM_CHECKONLY; 12407c478bd9Sstevel@tonic-gate else /* T_NEGOTIATE */ 12417c478bd9Sstevel@tonic-gate optset_context = SETFN_OPTCOM_NEGOTIATE; 12427c478bd9Sstevel@tonic-gate err = do_opt_check_or_negotiate(q, opt, optset_context, 12437c478bd9Sstevel@tonic-gate &optr, worst_statusp, cr, dbobjp, first_mp); 12447c478bd9Sstevel@tonic-gate if (err == EINPROGRESS) { 12457c478bd9Sstevel@tonic-gate *queued_statusp = B_TRUE; 12467c478bd9Sstevel@tonic-gate return (0); 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate break; 12497c478bd9Sstevel@tonic-gate default: 12507c478bd9Sstevel@tonic-gate return (TBADFLAG); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate } /* end for loop scanning option buffer */ 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate ack_mp->b_wptr = optr; 12557c478bd9Sstevel@tonic-gate ASSERT(ack_mp->b_wptr <= ack_mp->b_datap->db_lim); 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate return (0); /* OK return */ 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate static t_uscalar_t 12627c478bd9Sstevel@tonic-gate get_worst_status(t_uscalar_t status, t_uscalar_t current_worst_status) 12637c478bd9Sstevel@tonic-gate { 12647c478bd9Sstevel@tonic-gate /* 12657c478bd9Sstevel@tonic-gate * Return the "worst" among the arguments "status" and 12667c478bd9Sstevel@tonic-gate * "current_worst_status". 12677c478bd9Sstevel@tonic-gate * 12687c478bd9Sstevel@tonic-gate * Note: Tracking "worst_status" can be made a bit simpler 12697c478bd9Sstevel@tonic-gate * if we use the property that status codes are bitwise 12707c478bd9Sstevel@tonic-gate * distinct. 12717c478bd9Sstevel@tonic-gate * 12727c478bd9Sstevel@tonic-gate * The pecking order is 12737c478bd9Sstevel@tonic-gate * 12747c478bd9Sstevel@tonic-gate * T_SUCCESS ..... best 12757c478bd9Sstevel@tonic-gate * T_PARTSUCCESS 12767c478bd9Sstevel@tonic-gate * T_FAILURE 12777c478bd9Sstevel@tonic-gate * T_READONLY 12787c478bd9Sstevel@tonic-gate * T_NOTSUPPORT... worst 12797c478bd9Sstevel@tonic-gate */ 12807c478bd9Sstevel@tonic-gate if (status == current_worst_status) 12817c478bd9Sstevel@tonic-gate return (current_worst_status); 12827c478bd9Sstevel@tonic-gate switch (current_worst_status) { 12837c478bd9Sstevel@tonic-gate case T_SUCCESS: 12847c478bd9Sstevel@tonic-gate if (status == T_PARTSUCCESS) 12857c478bd9Sstevel@tonic-gate return (T_PARTSUCCESS); 12867c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 12877c478bd9Sstevel@tonic-gate case T_PARTSUCCESS: 12887c478bd9Sstevel@tonic-gate if (status == T_FAILURE) 12897c478bd9Sstevel@tonic-gate return (T_FAILURE); 12907c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 12917c478bd9Sstevel@tonic-gate case T_FAILURE: 12927c478bd9Sstevel@tonic-gate if (status == T_READONLY) 12937c478bd9Sstevel@tonic-gate return (T_READONLY); 12947c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 12957c478bd9Sstevel@tonic-gate case T_READONLY: 12967c478bd9Sstevel@tonic-gate if (status == T_NOTSUPPORT) 12977c478bd9Sstevel@tonic-gate return (T_NOTSUPPORT); 12987c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 12997c478bd9Sstevel@tonic-gate case T_NOTSUPPORT: 13007c478bd9Sstevel@tonic-gate default: 13017c478bd9Sstevel@tonic-gate return (current_worst_status); 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate static int 13067c478bd9Sstevel@tonic-gate do_opt_default(queue_t *q, struct T_opthdr *reqopt, uchar_t **resptrp, 13077c478bd9Sstevel@tonic-gate t_uscalar_t *worst_statusp, cred_t *cr, optdb_obj_t *dbobjp) 13087c478bd9Sstevel@tonic-gate { 13097c478bd9Sstevel@tonic-gate pfi_t deffn = dbobjp->odb_deffn; 13107c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 13117c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 13127c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate struct T_opthdr *topth; 13157c478bd9Sstevel@tonic-gate opdes_t *optd; 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate if (reqopt->name != T_ALLOPT) { 13187c478bd9Sstevel@tonic-gate /* 13197c478bd9Sstevel@tonic-gate * lookup the option in the table and fill default value 13207c478bd9Sstevel@tonic-gate */ 13217c478bd9Sstevel@tonic-gate optd = opt_chk_lookup(reqopt->level, reqopt->name, 13227c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt); 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate if (optd == NULL) { 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * not found - fail this one. Should not happen 13277c478bd9Sstevel@tonic-gate * for topmost_tpiprovider as calling routine 13287c478bd9Sstevel@tonic-gate * should have verified it. 13297c478bd9Sstevel@tonic-gate */ 13307c478bd9Sstevel@tonic-gate ASSERT(!topmost_tpiprovider); 13317c478bd9Sstevel@tonic-gate return (-1); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)(*resptrp); 13357c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 13367c478bd9Sstevel@tonic-gate topth->name = reqopt->name; 13377c478bd9Sstevel@tonic-gate topth->status = reqopt->status; 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(reqopt->status, 13407c478bd9Sstevel@tonic-gate *worst_statusp); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_NODEFAULT) { 13437c478bd9Sstevel@tonic-gate /* header only, no default "value" part */ 13447c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 13457c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 13467c478bd9Sstevel@tonic-gate } else { 13477c478bd9Sstevel@tonic-gate int deflen; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_DEF_FN) { 13507c478bd9Sstevel@tonic-gate deflen = (*deffn)(q, reqopt->level, 13517c478bd9Sstevel@tonic-gate reqopt->name, _TPI_TOPT_DATA(topth)); 13527c478bd9Sstevel@tonic-gate if (deflen >= 0) { 13537c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t) 13547c478bd9Sstevel@tonic-gate (sizeof (struct T_opthdr) + deflen); 13557c478bd9Sstevel@tonic-gate } else { 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate * return error, this should 'pass 13587c478bd9Sstevel@tonic-gate * through' the option and maybe some 13597c478bd9Sstevel@tonic-gate * other level will fill it in or 13607c478bd9Sstevel@tonic-gate * already did. 13617c478bd9Sstevel@tonic-gate * (No change in 'resptrp' upto here) 13627c478bd9Sstevel@tonic-gate */ 13637c478bd9Sstevel@tonic-gate return (-1); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate } else { 13667c478bd9Sstevel@tonic-gate /* fill length and value part */ 13677c478bd9Sstevel@tonic-gate switch (optd->opdes_size) { 13687c478bd9Sstevel@tonic-gate /* 13697c478bd9Sstevel@tonic-gate * Since options are guaranteed aligned only 13707c478bd9Sstevel@tonic-gate * on a 4 byte boundary (t_scalar_t) any 13717c478bd9Sstevel@tonic-gate * option that is greater in size will default 13727c478bd9Sstevel@tonic-gate * to the bcopy below 13737c478bd9Sstevel@tonic-gate */ 13747c478bd9Sstevel@tonic-gate case sizeof (int32_t): 13757c478bd9Sstevel@tonic-gate *(int32_t *)_TPI_TOPT_DATA(topth) = 13767c478bd9Sstevel@tonic-gate (int32_t)optd->opdes_default; 13777c478bd9Sstevel@tonic-gate break; 13787c478bd9Sstevel@tonic-gate case sizeof (int16_t): 13797c478bd9Sstevel@tonic-gate *(int16_t *)_TPI_TOPT_DATA(topth) = 13807c478bd9Sstevel@tonic-gate (int16_t)optd->opdes_default; 13817c478bd9Sstevel@tonic-gate break; 13827c478bd9Sstevel@tonic-gate case sizeof (int8_t): 13837c478bd9Sstevel@tonic-gate *(int8_t *)_TPI_TOPT_DATA(topth) = 13847c478bd9Sstevel@tonic-gate (int8_t)optd->opdes_default; 13857c478bd9Sstevel@tonic-gate break; 13867c478bd9Sstevel@tonic-gate default: 13877c478bd9Sstevel@tonic-gate /* 13887c478bd9Sstevel@tonic-gate * other length but still assume 13897c478bd9Sstevel@tonic-gate * fixed - use bcopy 13907c478bd9Sstevel@tonic-gate */ 13917c478bd9Sstevel@tonic-gate bcopy(optd->opdes_defbuf, 13927c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(topth), 13937c478bd9Sstevel@tonic-gate optd->opdes_size); 13947c478bd9Sstevel@tonic-gate break; 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optd->opdes_size + 13977c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(topth->len); 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate return (0); /* OK return */ 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * T_ALLOPT processing 14067c478bd9Sstevel@tonic-gate * 14077c478bd9Sstevel@tonic-gate * lookup and stuff default values of all the options of the 14087c478bd9Sstevel@tonic-gate * level specified 14097c478bd9Sstevel@tonic-gate * Note: This expansion of T_ALLOPT should happen in 14107c478bd9Sstevel@tonic-gate * a topmost_tpiprovider. 14117c478bd9Sstevel@tonic-gate */ 14127c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider); 14137c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 14147c478bd9Sstevel@tonic-gate if (reqopt->level != optd->opdes_level) 14157c478bd9Sstevel@tonic-gate continue; 14167c478bd9Sstevel@tonic-gate /* 14177c478bd9Sstevel@tonic-gate * 14187c478bd9Sstevel@tonic-gate * T_DEFAULT semantics: 14197c478bd9Sstevel@tonic-gate * XXX: we interpret T_DEFAULT semantics such that access to 14207c478bd9Sstevel@tonic-gate * read value is required for access even the default value. 14217c478bd9Sstevel@tonic-gate * Else option is ignored for T_ALLOPT request. 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) 14247c478bd9Sstevel@tonic-gate /* skip this one */ 14257c478bd9Sstevel@tonic-gate continue; 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate /* 14287c478bd9Sstevel@tonic-gate * Found option of same level as T_ALLOPT request 14297c478bd9Sstevel@tonic-gate * that we can return. 14307c478bd9Sstevel@tonic-gate */ 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)(*resptrp); 14337c478bd9Sstevel@tonic-gate topth->level = optd->opdes_level; 14347c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate /* 14377c478bd9Sstevel@tonic-gate * T_DEFAULT semantics: 14387c478bd9Sstevel@tonic-gate * We know that read access is set. If no other access is set, 14397c478bd9Sstevel@tonic-gate * then status is T_READONLY 14407c478bd9Sstevel@tonic-gate */ 14417c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 14427c478bd9Sstevel@tonic-gate topth->status = T_READONLY; 14437c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(T_READONLY, 14447c478bd9Sstevel@tonic-gate *worst_statusp); 14457c478bd9Sstevel@tonic-gate } else { 14467c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * Note: *worst_statusp has to be T_SUCCESS or 14497c478bd9Sstevel@tonic-gate * worse so no need to adjust 14507c478bd9Sstevel@tonic-gate */ 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_NODEFAULT) { 14547c478bd9Sstevel@tonic-gate /* header only, no value part */ 14557c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 14567c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 14577c478bd9Sstevel@tonic-gate } else { 14587c478bd9Sstevel@tonic-gate int deflen; 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_DEF_FN) { 14617c478bd9Sstevel@tonic-gate deflen = (*deffn)(q, reqopt->level, 14627c478bd9Sstevel@tonic-gate reqopt->name, _TPI_TOPT_DATA(topth)); 14637c478bd9Sstevel@tonic-gate if (deflen >= 0) { 14647c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(deflen + 14657c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 14667c478bd9Sstevel@tonic-gate } else { 14677c478bd9Sstevel@tonic-gate /* 14687c478bd9Sstevel@tonic-gate * deffn failed. 14697c478bd9Sstevel@tonic-gate * return just the header as T_ALLOPT 14707c478bd9Sstevel@tonic-gate * expansion. 14717c478bd9Sstevel@tonic-gate * Some other level deffn may 14727c478bd9Sstevel@tonic-gate * supply value part. 14737c478bd9Sstevel@tonic-gate */ 14747c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 14757c478bd9Sstevel@tonic-gate topth->status = T_FAILURE; 14767c478bd9Sstevel@tonic-gate *worst_statusp = 14777c478bd9Sstevel@tonic-gate get_worst_status(T_FAILURE, 14787c478bd9Sstevel@tonic-gate *worst_statusp); 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate } else { 14817c478bd9Sstevel@tonic-gate /* 14827c478bd9Sstevel@tonic-gate * fill length and value part from 14837c478bd9Sstevel@tonic-gate * table 14847c478bd9Sstevel@tonic-gate */ 14857c478bd9Sstevel@tonic-gate switch (optd->opdes_size) { 14867c478bd9Sstevel@tonic-gate /* 14877c478bd9Sstevel@tonic-gate * Since options are guaranteed aligned only 14887c478bd9Sstevel@tonic-gate * on a 4 byte boundary (t_scalar_t) any 14897c478bd9Sstevel@tonic-gate * option that is greater in size will default 14907c478bd9Sstevel@tonic-gate * to the bcopy below 14917c478bd9Sstevel@tonic-gate */ 14927c478bd9Sstevel@tonic-gate case sizeof (int32_t): 14937c478bd9Sstevel@tonic-gate *(int32_t *)_TPI_TOPT_DATA(topth) = 14947c478bd9Sstevel@tonic-gate (int32_t)optd->opdes_default; 14957c478bd9Sstevel@tonic-gate break; 14967c478bd9Sstevel@tonic-gate case sizeof (int16_t): 14977c478bd9Sstevel@tonic-gate *(int16_t *)_TPI_TOPT_DATA(topth) = 14987c478bd9Sstevel@tonic-gate (int16_t)optd->opdes_default; 14997c478bd9Sstevel@tonic-gate break; 15007c478bd9Sstevel@tonic-gate case sizeof (int8_t): 15017c478bd9Sstevel@tonic-gate *(int8_t *)_TPI_TOPT_DATA(topth) = 15027c478bd9Sstevel@tonic-gate (int8_t)optd->opdes_default; 15037c478bd9Sstevel@tonic-gate break; 15047c478bd9Sstevel@tonic-gate default: 15057c478bd9Sstevel@tonic-gate /* 15067c478bd9Sstevel@tonic-gate * other length but still assume 15077c478bd9Sstevel@tonic-gate * fixed - use bcopy 15087c478bd9Sstevel@tonic-gate */ 15097c478bd9Sstevel@tonic-gate bcopy(optd->opdes_defbuf, 15107c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(topth), 15117c478bd9Sstevel@tonic-gate optd->opdes_size); 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optd->opdes_size + 15147c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(topth->len); 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate return (0); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate static void 15237c478bd9Sstevel@tonic-gate do_opt_current(queue_t *q, struct T_opthdr *reqopt, uchar_t **resptrp, 15247c478bd9Sstevel@tonic-gate t_uscalar_t *worst_statusp, cred_t *cr, optdb_obj_t *dbobjp) 15257c478bd9Sstevel@tonic-gate { 15267c478bd9Sstevel@tonic-gate pfi_t getfn = dbobjp->odb_getfn; 15277c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 15287c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 15297c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate struct T_opthdr *topth; 15327c478bd9Sstevel@tonic-gate opdes_t *optd; 15337c478bd9Sstevel@tonic-gate int optlen; 15347c478bd9Sstevel@tonic-gate uchar_t *initptr = *resptrp; 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate /* 15377c478bd9Sstevel@tonic-gate * We call getfn to get the current value of an option. The call may 15387c478bd9Sstevel@tonic-gate * fail in which case we copy the values from the input buffer. Maybe 15397c478bd9Sstevel@tonic-gate * something downstream will fill it in or something upstream did. 15407c478bd9Sstevel@tonic-gate */ 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate if (reqopt->name != T_ALLOPT) { 15437c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 15447c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 15457c478bd9Sstevel@tonic-gate optlen = (*getfn)(q, reqopt->level, reqopt->name, *resptrp); 15467c478bd9Sstevel@tonic-gate if (optlen >= 0) { 15477c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optlen + 15487c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 15497c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 15507c478bd9Sstevel@tonic-gate topth->name = reqopt->name; 15517c478bd9Sstevel@tonic-gate topth->status = reqopt->status; 15527c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 15537c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 15547c478bd9Sstevel@tonic-gate *worst_statusp); 15557c478bd9Sstevel@tonic-gate } else { 15567c478bd9Sstevel@tonic-gate /* failed - reset "*resptrp" pointer */ 15577c478bd9Sstevel@tonic-gate *resptrp -= sizeof (struct T_opthdr); 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate } else { /* T_ALLOPT processing */ 15607c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider == B_TRUE); 15617c478bd9Sstevel@tonic-gate /* scan and get all options */ 15627c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 15637c478bd9Sstevel@tonic-gate /* skip other levels */ 15647c478bd9Sstevel@tonic-gate if (reqopt->level != optd->opdes_level) 15657c478bd9Sstevel@tonic-gate continue; 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate if (!OA_READ_PERMISSION(optd, cr)) 15687c478bd9Sstevel@tonic-gate /* skip this one */ 15697c478bd9Sstevel@tonic-gate continue; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 15727c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* get option of this level */ 15757c478bd9Sstevel@tonic-gate optlen = (*getfn)(q, reqopt->level, optd->opdes_name, 15767c478bd9Sstevel@tonic-gate *resptrp); 15777c478bd9Sstevel@tonic-gate if (optlen >= 0) { 15787c478bd9Sstevel@tonic-gate /* success */ 15797c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optlen + 15807c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 15817c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 15827c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 15837c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) 15847c478bd9Sstevel@tonic-gate topth->status = T_READONLY; 15857c478bd9Sstevel@tonic-gate else 15867c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 15877c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 15887c478bd9Sstevel@tonic-gate } else { 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * failed, return as T_FAILURE and null value 15917c478bd9Sstevel@tonic-gate * part. Maybe something downstream will 15927c478bd9Sstevel@tonic-gate * handle this one and fill in a value. Here 15937c478bd9Sstevel@tonic-gate * it is just part of T_ALLOPT expansion. 15947c478bd9Sstevel@tonic-gate */ 15957c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 15967c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 15977c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 15987c478bd9Sstevel@tonic-gate topth->status = T_FAILURE; 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 16017c478bd9Sstevel@tonic-gate *worst_statusp); 16027c478bd9Sstevel@tonic-gate } /* end for loop */ 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate if (*resptrp == initptr) { 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * getfn failed and does not want to handle this option. Maybe 16077c478bd9Sstevel@tonic-gate * something downstream will or something upstream did. (If 16087c478bd9Sstevel@tonic-gate * topmost_tpiprovider, initialize "status" to failure which 16097c478bd9Sstevel@tonic-gate * can possibly change downstream). Copy the input "as is" from 16107c478bd9Sstevel@tonic-gate * input option buffer if any to maintain transparency. 16117c478bd9Sstevel@tonic-gate */ 16127c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 16137c478bd9Sstevel@tonic-gate reqopt->status = T_FAILURE; 16147c478bd9Sstevel@tonic-gate bcopy(reqopt, *resptrp, reqopt->len); 16157c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(reqopt->len); 16167c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(reqopt->status, 16177c478bd9Sstevel@tonic-gate *worst_statusp); 16187c478bd9Sstevel@tonic-gate } 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate static int 16247c478bd9Sstevel@tonic-gate do_opt_check_or_negotiate(queue_t *q, struct T_opthdr *reqopt, 16257c478bd9Sstevel@tonic-gate uint_t optset_context, uchar_t **resptrp, t_uscalar_t *worst_statusp, 16267c478bd9Sstevel@tonic-gate cred_t *cr, optdb_obj_t *dbobjp, mblk_t *first_mp) 16277c478bd9Sstevel@tonic-gate { 16287c478bd9Sstevel@tonic-gate pfi_t deffn = dbobjp->odb_deffn; 16297c478bd9Sstevel@tonic-gate opt_set_fn setfn = dbobjp->odb_setfn; 16307c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 16317c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 16327c478bd9Sstevel@tonic-gate boolean_t topmost_tpiprovider = dbobjp->odb_topmost_tpiprovider; 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate struct T_opthdr *topth; 16357c478bd9Sstevel@tonic-gate opdes_t *optd; 16367c478bd9Sstevel@tonic-gate int error; 16377c478bd9Sstevel@tonic-gate t_uscalar_t optlen; 16387c478bd9Sstevel@tonic-gate t_scalar_t optsize; 16397c478bd9Sstevel@tonic-gate uchar_t *initptr = *resptrp; 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate ASSERT(reqopt->status == T_SUCCESS); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate if (reqopt->name != T_ALLOPT) { 16447c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 16457c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 16467c478bd9Sstevel@tonic-gate error = (*setfn)(q, optset_context, reqopt->level, reqopt->name, 16477c478bd9Sstevel@tonic-gate reqopt->len - sizeof (struct T_opthdr), 16487c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(reqopt), &optlen, _TPI_TOPT_DATA(topth), 16497c478bd9Sstevel@tonic-gate NULL, cr, first_mp); 16507c478bd9Sstevel@tonic-gate if (error) { 16517c478bd9Sstevel@tonic-gate /* failed - reset "*resptrp" */ 16527c478bd9Sstevel@tonic-gate *resptrp -= sizeof (struct T_opthdr); 16537c478bd9Sstevel@tonic-gate if (error == EINPROGRESS) 16547c478bd9Sstevel@tonic-gate return (error); 16557c478bd9Sstevel@tonic-gate } else { 16567c478bd9Sstevel@tonic-gate /* 16577c478bd9Sstevel@tonic-gate * success - "value" already filled in setfn() 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate topth->len = (t_uscalar_t)(optlen + 16607c478bd9Sstevel@tonic-gate sizeof (struct T_opthdr)); 16617c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 16627c478bd9Sstevel@tonic-gate topth->name = reqopt->name; 16637c478bd9Sstevel@tonic-gate topth->status = reqopt->status; 16647c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 16657c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 16667c478bd9Sstevel@tonic-gate *worst_statusp); 16677c478bd9Sstevel@tonic-gate } 16687c478bd9Sstevel@tonic-gate } else { /* T_ALLOPT processing */ 16697c478bd9Sstevel@tonic-gate /* only for T_NEGOTIATE case */ 16707c478bd9Sstevel@tonic-gate ASSERT(optset_context == SETFN_OPTCOM_NEGOTIATE); 16717c478bd9Sstevel@tonic-gate ASSERT(topmost_tpiprovider == B_TRUE); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate /* scan and set all options to default value */ 16747c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate /* skip other levels */ 16777c478bd9Sstevel@tonic-gate if (reqopt->level != optd->opdes_level) 16787c478bd9Sstevel@tonic-gate continue; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate if (OA_EXECUTE_PERMISSION(optd, cr) || 16817c478bd9Sstevel@tonic-gate OA_NO_PERMISSION(optd, cr)) { 16827c478bd9Sstevel@tonic-gate /* 16837c478bd9Sstevel@tonic-gate * skip this one too. Does not make sense to 16847c478bd9Sstevel@tonic-gate * set anything to default value for "execute" 16857c478bd9Sstevel@tonic-gate * options. 16867c478bd9Sstevel@tonic-gate */ 16877c478bd9Sstevel@tonic-gate continue; 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 16917c478bd9Sstevel@tonic-gate /* 16927c478bd9Sstevel@tonic-gate * Return with T_READONLY status (and no value 16937c478bd9Sstevel@tonic-gate * part). Note: spec is not clear but 16947c478bd9Sstevel@tonic-gate * XTI test suite needs this. 16957c478bd9Sstevel@tonic-gate */ 16967c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 16977c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 16987c478bd9Sstevel@tonic-gate *resptrp += topth->len; 16997c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 17007c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 17017c478bd9Sstevel@tonic-gate topth->status = T_READONLY; 17027c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 17037c478bd9Sstevel@tonic-gate *worst_statusp); 17047c478bd9Sstevel@tonic-gate continue; 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate /* 17087c478bd9Sstevel@tonic-gate * It is not read only or execute type 17097c478bd9Sstevel@tonic-gate * the it must have write permission 17107c478bd9Sstevel@tonic-gate */ 17117c478bd9Sstevel@tonic-gate ASSERT(OA_WRITE_PERMISSION(optd, cr)); 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate topth = (struct T_opthdr *)*resptrp; 17147c478bd9Sstevel@tonic-gate *resptrp += sizeof (struct T_opthdr); 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate topth->len = sizeof (struct T_opthdr); 17177c478bd9Sstevel@tonic-gate topth->level = reqopt->level; 17187c478bd9Sstevel@tonic-gate topth->name = optd->opdes_name; 17197c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_NODEFAULT) { 17207c478bd9Sstevel@tonic-gate /* 17217c478bd9Sstevel@tonic-gate * Option of "no default value" so it does not 17227c478bd9Sstevel@tonic-gate * make sense to try to set it. We just return 17237c478bd9Sstevel@tonic-gate * header with status of T_SUCCESS 17247c478bd9Sstevel@tonic-gate * XXX should this be failure ? 17257c478bd9Sstevel@tonic-gate */ 17267c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 17277c478bd9Sstevel@tonic-gate continue; /* skip setting */ 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_DEF_FN) { 17307c478bd9Sstevel@tonic-gate if ((optd->opdes_props & OP_VARLEN) || 17317c478bd9Sstevel@tonic-gate ((optsize = (*deffn)(q, reqopt->level, 17327c478bd9Sstevel@tonic-gate optd->opdes_name, 17337c478bd9Sstevel@tonic-gate (uchar_t *)optd->opdes_defbuf)) < 0)) { 17347c478bd9Sstevel@tonic-gate /* XXX - skip these too */ 17357c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 17367c478bd9Sstevel@tonic-gate continue; /* skip setting */ 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate } else { 17397c478bd9Sstevel@tonic-gate optsize = optd->opdes_size; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate /* set option of this level */ 17447c478bd9Sstevel@tonic-gate error = (*setfn)(q, SETFN_OPTCOM_NEGOTIATE, 17457c478bd9Sstevel@tonic-gate reqopt->level, optd->opdes_name, optsize, 17467c478bd9Sstevel@tonic-gate (uchar_t *)optd->opdes_defbuf, &optlen, 17477c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(topth), NULL, cr, NULL); 17487c478bd9Sstevel@tonic-gate if (error) { 17497c478bd9Sstevel@tonic-gate /* 17507c478bd9Sstevel@tonic-gate * failed, return as T_FAILURE and null value 17517c478bd9Sstevel@tonic-gate * part. Maybe something downstream will 17527c478bd9Sstevel@tonic-gate * handle this one and fill in a value. Here 17537c478bd9Sstevel@tonic-gate * it is just part of T_ALLOPT expansion. 17547c478bd9Sstevel@tonic-gate */ 17557c478bd9Sstevel@tonic-gate topth->status = T_FAILURE; 17567c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(topth->status, 17577c478bd9Sstevel@tonic-gate *worst_statusp); 17587c478bd9Sstevel@tonic-gate } else { 17597c478bd9Sstevel@tonic-gate /* success */ 17607c478bd9Sstevel@tonic-gate topth->len += optlen; 17617c478bd9Sstevel@tonic-gate topth->status = T_SUCCESS; 17627c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(optlen); 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate } /* end for loop */ 17657c478bd9Sstevel@tonic-gate /* END T_ALLOPT */ 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate if (*resptrp == initptr) { 17697c478bd9Sstevel@tonic-gate /* 17707c478bd9Sstevel@tonic-gate * setfn failed and does not want to handle this option. Maybe 17717c478bd9Sstevel@tonic-gate * something downstream will or something upstream 17727c478bd9Sstevel@tonic-gate * did. Copy the input as is from input option buffer if any to 17737c478bd9Sstevel@tonic-gate * maintain transparency (maybe something at a level above 17747c478bd9Sstevel@tonic-gate * did something. 17757c478bd9Sstevel@tonic-gate */ 17767c478bd9Sstevel@tonic-gate if (topmost_tpiprovider) 17777c478bd9Sstevel@tonic-gate reqopt->status = T_FAILURE; 17787c478bd9Sstevel@tonic-gate bcopy(reqopt, *resptrp, reqopt->len); 17797c478bd9Sstevel@tonic-gate *resptrp += _TPI_ALIGN_TOPT(reqopt->len); 17807c478bd9Sstevel@tonic-gate *worst_statusp = get_worst_status(reqopt->status, 17817c478bd9Sstevel@tonic-gate *worst_statusp); 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate return (0); 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate /* 17877c478bd9Sstevel@tonic-gate * The following routines process options buffer passed with 17887c478bd9Sstevel@tonic-gate * T_CONN_REQ, T_CONN_RES and T_UNITDATA_REQ. 17897c478bd9Sstevel@tonic-gate * This routine does the consistency check applied to the 17907c478bd9Sstevel@tonic-gate * sanity of formatting of multiple options packed in the 17917c478bd9Sstevel@tonic-gate * buffer. 17927c478bd9Sstevel@tonic-gate * 17937c478bd9Sstevel@tonic-gate * XTI brain damage alert: 17947c478bd9Sstevel@tonic-gate * XTI interface adopts the notion of an option being an 17957c478bd9Sstevel@tonic-gate * "absolute requirement" from OSI transport service (but applies 17967c478bd9Sstevel@tonic-gate * it to all transports including Internet transports). 17977c478bd9Sstevel@tonic-gate * The main effect of that is action on failure to "negotiate" a 17987c478bd9Sstevel@tonic-gate * requested option to the exact requested value 17997c478bd9Sstevel@tonic-gate * 18007c478bd9Sstevel@tonic-gate * - if the option is an "absolute requirement", the primitive 18017c478bd9Sstevel@tonic-gate * is aborted (e.g T_DISCON_REQ or T_UDERR generated) 18027c478bd9Sstevel@tonic-gate * - if the option is NOT and "absolute requirement" it can 18037c478bd9Sstevel@tonic-gate * just be ignored. 18047c478bd9Sstevel@tonic-gate * 18057c478bd9Sstevel@tonic-gate * We would not support "negotiating" of options on connection 18067c478bd9Sstevel@tonic-gate * primitives for Internet transports. However just in case we 18077c478bd9Sstevel@tonic-gate * forced to in order to pass strange test suites, the design here 18087c478bd9Sstevel@tonic-gate * tries to support these notions. 18097c478bd9Sstevel@tonic-gate * 18107c478bd9Sstevel@tonic-gate * tpi_optcom_buf(q, mp, opt_lenp, opt_offset, cred, dbobjp, thisdg_attrs, 18117c478bd9Sstevel@tonic-gate * *is_absreq_failurep) 18127c478bd9Sstevel@tonic-gate * 18137c478bd9Sstevel@tonic-gate * - Verify the option buffer, if formatted badly, return error 1 18147c478bd9Sstevel@tonic-gate * 18157c478bd9Sstevel@tonic-gate * - If it is a "permissions" failure (read-only), return error 2 18167c478bd9Sstevel@tonic-gate * 18177c478bd9Sstevel@tonic-gate * - Else, process the option "in place", the following can happen, 18187c478bd9Sstevel@tonic-gate * - if a "privileged" option, mark it as "ignored". 18197c478bd9Sstevel@tonic-gate * - if "not supported", mark "ignored" 18207c478bd9Sstevel@tonic-gate * - if "supported" attempt negotiation and fill result in 18217c478bd9Sstevel@tonic-gate * the outcome 18227c478bd9Sstevel@tonic-gate * - if "absolute requirement", set "*is_absreq_failurep" 18237c478bd9Sstevel@tonic-gate * - if NOT an "absolute requirement", then our 18247c478bd9Sstevel@tonic-gate * interpretation is to mark is at ignored if 18257c478bd9Sstevel@tonic-gate * negotiation fails (Spec allows partial success 18267c478bd9Sstevel@tonic-gate * as in OSI protocols but not failure) 18277c478bd9Sstevel@tonic-gate * 18287c478bd9Sstevel@tonic-gate * Then delete "ignored" options from option buffer and return success. 18297c478bd9Sstevel@tonic-gate * 18307c478bd9Sstevel@tonic-gate */ 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate int 18337c478bd9Sstevel@tonic-gate tpi_optcom_buf(queue_t *q, mblk_t *mp, t_scalar_t *opt_lenp, 18347c478bd9Sstevel@tonic-gate t_scalar_t opt_offset, cred_t *cr, optdb_obj_t *dbobjp, 18357c478bd9Sstevel@tonic-gate void *thisdg_attrs, int *is_absreq_failurep) 18367c478bd9Sstevel@tonic-gate { 18377c478bd9Sstevel@tonic-gate opt_set_fn setfn = dbobjp->odb_setfn; 18387c478bd9Sstevel@tonic-gate opdes_t *opt_arr = dbobjp->odb_opt_des_arr; 18397c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt; 18407c478bd9Sstevel@tonic-gate struct T_opthdr *opt, *opt_start, *opt_end; 18417c478bd9Sstevel@tonic-gate mblk_t *copy_mp_head; 18427c478bd9Sstevel@tonic-gate uchar_t *optr, *init_optr; 18437c478bd9Sstevel@tonic-gate opdes_t *optd; 18447c478bd9Sstevel@tonic-gate uint_t optset_context; 18457c478bd9Sstevel@tonic-gate t_uscalar_t olen; 18467c478bd9Sstevel@tonic-gate int error = 0; 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate ASSERT((uchar_t *)opt_lenp > mp->b_rptr && 18497c478bd9Sstevel@tonic-gate (uchar_t *)opt_lenp < mp->b_wptr); 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate copy_mp_head = NULL; 18527c478bd9Sstevel@tonic-gate *is_absreq_failurep = 0; 18537c478bd9Sstevel@tonic-gate switch (((union T_primitives *)mp->b_rptr)->type) { 18547c478bd9Sstevel@tonic-gate case T_CONN_REQ: 18557c478bd9Sstevel@tonic-gate case T_CONN_RES: 18567c478bd9Sstevel@tonic-gate optset_context = SETFN_CONN_NEGOTIATE; 18577c478bd9Sstevel@tonic-gate break; 18587c478bd9Sstevel@tonic-gate case T_UNITDATA_REQ: 18597c478bd9Sstevel@tonic-gate optset_context = SETFN_UD_NEGOTIATE; 18607c478bd9Sstevel@tonic-gate break; 18617c478bd9Sstevel@tonic-gate default: 18627c478bd9Sstevel@tonic-gate /* 18637c478bd9Sstevel@tonic-gate * should never get here, all possible TPI primitives 18647c478bd9Sstevel@tonic-gate * where this can be called from should be accounted 18657c478bd9Sstevel@tonic-gate * for in the cases above 18667c478bd9Sstevel@tonic-gate */ 18677c478bd9Sstevel@tonic-gate return (EINVAL); 18687c478bd9Sstevel@tonic-gate } 18697c478bd9Sstevel@tonic-gate 18707c478bd9Sstevel@tonic-gate if ((opt_start = (struct T_opthdr *) 18717c478bd9Sstevel@tonic-gate mi_offset_param(mp, opt_offset, *opt_lenp)) == NULL) { 18727c478bd9Sstevel@tonic-gate error = ENOPROTOOPT; 18737c478bd9Sstevel@tonic-gate goto error_ret; 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate if (!__TPI_TOPT_ISALIGNED(opt_start)) { 18767c478bd9Sstevel@tonic-gate error = ENOPROTOOPT; 18777c478bd9Sstevel@tonic-gate goto error_ret; 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate opt_end = (struct T_opthdr *)((uchar_t *)opt_start 18817c478bd9Sstevel@tonic-gate + *opt_lenp); 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate if ((copy_mp_head = copyb(mp)) == (mblk_t *)NULL) { 18847c478bd9Sstevel@tonic-gate error = ENOMEM; 18857c478bd9Sstevel@tonic-gate goto error_ret; 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate init_optr = optr = (uchar_t *)©_mp_head->b_rptr[opt_offset]; 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate for (opt = opt_start; opt && (opt < opt_end); 18917c478bd9Sstevel@tonic-gate opt = _TPI_TOPT_NEXTHDR(opt_start, *opt_lenp, opt)) { 18927c478bd9Sstevel@tonic-gate /* 18937c478bd9Sstevel@tonic-gate * Validate the option for length and alignment 18947c478bd9Sstevel@tonic-gate * before accessing anything in it 18957c478bd9Sstevel@tonic-gate */ 18967c478bd9Sstevel@tonic-gate if (!_TPI_TOPT_VALID(opt, opt_start, opt_end)) { 18977c478bd9Sstevel@tonic-gate error = ENOPROTOOPT; 18987c478bd9Sstevel@tonic-gate goto error_ret; 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* Find the option in the opt_arr. */ 19027c478bd9Sstevel@tonic-gate optd = opt_chk_lookup(opt->level, opt->name, 19037c478bd9Sstevel@tonic-gate opt_arr, opt_arr_cnt); 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate if (optd == NULL) { 19067c478bd9Sstevel@tonic-gate /* 19077c478bd9Sstevel@tonic-gate * Option not found 19087c478bd9Sstevel@tonic-gate */ 19097c478bd9Sstevel@tonic-gate opt->status = T_NOTSUPPORT; 19107c478bd9Sstevel@tonic-gate continue; 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate /* 19147c478bd9Sstevel@tonic-gate * Weird but as in XTI spec. 19157c478bd9Sstevel@tonic-gate * Sec 6.3.6 "Privileged and ReadOnly Options" 19167c478bd9Sstevel@tonic-gate * Permission problems (e.g.readonly) fail with bad access 19177c478bd9Sstevel@tonic-gate * BUT "privileged" option request from those NOT PRIVILEGED 19187c478bd9Sstevel@tonic-gate * are to be merely "ignored". 19197c478bd9Sstevel@tonic-gate * XXX Prevents "probing" of privileged options ? 19207c478bd9Sstevel@tonic-gate */ 19217c478bd9Sstevel@tonic-gate if (OA_READONLY_PERMISSION(optd, cr)) { 19227c478bd9Sstevel@tonic-gate error = EACCES; 19237c478bd9Sstevel@tonic-gate goto error_ret; 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate if (OA_MATCHED_PRIV(optd, cr)) { 19267c478bd9Sstevel@tonic-gate /* 19277c478bd9Sstevel@tonic-gate * For privileged options, we DO perform 19287c478bd9Sstevel@tonic-gate * access checks as is common sense 19297c478bd9Sstevel@tonic-gate */ 19307c478bd9Sstevel@tonic-gate if (!OA_WX_ANYPRIV(optd)) { 19317c478bd9Sstevel@tonic-gate error = EACCES; 19327c478bd9Sstevel@tonic-gate goto error_ret; 19337c478bd9Sstevel@tonic-gate } 19347c478bd9Sstevel@tonic-gate } else { 19357c478bd9Sstevel@tonic-gate /* 19367c478bd9Sstevel@tonic-gate * For non privileged, we fail instead following 19377c478bd9Sstevel@tonic-gate * "ignore" semantics dictated by XTI spec for 19387c478bd9Sstevel@tonic-gate * permissions problems. 19397c478bd9Sstevel@tonic-gate * Sec 6.3.6 "Privileged and ReadOnly Options" 19407c478bd9Sstevel@tonic-gate * XXX Should we do "ignore" semantics ? 19417c478bd9Sstevel@tonic-gate */ 19427c478bd9Sstevel@tonic-gate if (!OA_WX_NOPRIV(optd)) { /* nopriv */ 19437c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 19447c478bd9Sstevel@tonic-gate continue; 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate /* 19487c478bd9Sstevel@tonic-gate * 19497c478bd9Sstevel@tonic-gate * If the negotiation fails, for options that 19507c478bd9Sstevel@tonic-gate * are "absolute requirement", it is a fatal error. 19517c478bd9Sstevel@tonic-gate * For options that are NOT "absolute requirements", 19527c478bd9Sstevel@tonic-gate * and the value fails to negotiate, the XTI spec 19537c478bd9Sstevel@tonic-gate * only considers the possibility of partial success 19547c478bd9Sstevel@tonic-gate * (T_PARTSUCCES - not likely for Internet protocols). 19557c478bd9Sstevel@tonic-gate * The spec is in denial about complete failure 19567c478bd9Sstevel@tonic-gate * (T_FAILURE) to negotiate for options that are 19577c478bd9Sstevel@tonic-gate * carried on T_CONN_REQ/T_CONN_RES/T_UNITDATA 19587c478bd9Sstevel@tonic-gate * We interpret the T_FAILURE to negotiate an option 19597c478bd9Sstevel@tonic-gate * that is NOT an absolute requirement that it is safe 19607c478bd9Sstevel@tonic-gate * to ignore it. 19617c478bd9Sstevel@tonic-gate */ 19627c478bd9Sstevel@tonic-gate 19637c478bd9Sstevel@tonic-gate /* verify length */ 19647c478bd9Sstevel@tonic-gate if (!opt_length_ok(optd, opt)) { 19657c478bd9Sstevel@tonic-gate /* bad size */ 19667c478bd9Sstevel@tonic-gate if ((optd->opdes_props & OP_NOT_ABSREQ) == 0) { 19677c478bd9Sstevel@tonic-gate /* option is absolute requirement */ 19687c478bd9Sstevel@tonic-gate *is_absreq_failurep = 1; 19697c478bd9Sstevel@tonic-gate error = EINVAL; 19707c478bd9Sstevel@tonic-gate goto error_ret; 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 19737c478bd9Sstevel@tonic-gate continue; 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate /* 19777c478bd9Sstevel@tonic-gate * verified generic attributes. Now call set function. 19787c478bd9Sstevel@tonic-gate * Note: We assume the following to simplify code. 19797c478bd9Sstevel@tonic-gate * XXX If this is found not to be valid, this routine 19807c478bd9Sstevel@tonic-gate * will need to be rewritten. At this point it would 19817c478bd9Sstevel@tonic-gate * be premature to introduce more complexity than is 19827c478bd9Sstevel@tonic-gate * needed. 19837c478bd9Sstevel@tonic-gate * Assumption: For variable length options, we assume 19847c478bd9Sstevel@tonic-gate * that the value returned will be same or less length 19857c478bd9Sstevel@tonic-gate * (size does not increase). This makes it OK to pass the 19867c478bd9Sstevel@tonic-gate * same space for output as it is on input. 19877c478bd9Sstevel@tonic-gate */ 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate error = (*setfn)(q, optset_context, opt->level, opt->name, 19907c478bd9Sstevel@tonic-gate opt->len - (t_uscalar_t)sizeof (struct T_opthdr), 19917c478bd9Sstevel@tonic-gate _TPI_TOPT_DATA(opt), &olen, _TPI_TOPT_DATA(opt), 19927c478bd9Sstevel@tonic-gate thisdg_attrs, cr, NULL); 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate if (olen > (int)(opt->len - sizeof (struct T_opthdr))) { 19957c478bd9Sstevel@tonic-gate /* 19967c478bd9Sstevel@tonic-gate * Space on output more than space on input. Should 19977c478bd9Sstevel@tonic-gate * not happen and we consider it a bug/error. 19987c478bd9Sstevel@tonic-gate * More of a restriction than an error in our 19997c478bd9Sstevel@tonic-gate * implementation. Will see if we can live with this 20007c478bd9Sstevel@tonic-gate * otherwise code will get more hairy with multiple 20017c478bd9Sstevel@tonic-gate * passes. 20027c478bd9Sstevel@tonic-gate */ 20037c478bd9Sstevel@tonic-gate error = EINVAL; 20047c478bd9Sstevel@tonic-gate goto error_ret; 20057c478bd9Sstevel@tonic-gate } 20067c478bd9Sstevel@tonic-gate if (error != 0) { 20077c478bd9Sstevel@tonic-gate if ((optd->opdes_props & OP_NOT_ABSREQ) == 0) { 20087c478bd9Sstevel@tonic-gate /* option is absolute requirement. */ 20097c478bd9Sstevel@tonic-gate *is_absreq_failurep = 1; 20107c478bd9Sstevel@tonic-gate goto error_ret; 20117c478bd9Sstevel@tonic-gate } 20127c478bd9Sstevel@tonic-gate /* 20137c478bd9Sstevel@tonic-gate * failed - but option "not an absolute 20147c478bd9Sstevel@tonic-gate * requirement" 20157c478bd9Sstevel@tonic-gate */ 20167c478bd9Sstevel@tonic-gate opt->status = T_FAILURE; 20177c478bd9Sstevel@tonic-gate continue; 20187c478bd9Sstevel@tonic-gate } 20197c478bd9Sstevel@tonic-gate /* 20207c478bd9Sstevel@tonic-gate * Fill in the only possible successful result 20217c478bd9Sstevel@tonic-gate * (Note: TPI allows for T_PARTSUCCESS - partial 20227c478bd9Sstevel@tonic-gate * sucess result code which is relevant in OSI world 20237c478bd9Sstevel@tonic-gate * and not possible in Internet code) 20247c478bd9Sstevel@tonic-gate */ 20257c478bd9Sstevel@tonic-gate opt->status = T_SUCCESS; 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate /* 20287c478bd9Sstevel@tonic-gate * Add T_SUCCESS result code options to the "output" options. 20297c478bd9Sstevel@tonic-gate * No T_FAILURES or T_NOTSUPPORT here as they are to be 20307c478bd9Sstevel@tonic-gate * ignored. 20317c478bd9Sstevel@tonic-gate * This code assumes output option buffer will 20327c478bd9Sstevel@tonic-gate * be <= input option buffer. 20337c478bd9Sstevel@tonic-gate * 20347c478bd9Sstevel@tonic-gate * Copy option header+value 20357c478bd9Sstevel@tonic-gate */ 20367c478bd9Sstevel@tonic-gate bcopy(opt, optr, opt->len); 20377c478bd9Sstevel@tonic-gate optr += _TPI_ALIGN_TOPT(opt->len); 20387c478bd9Sstevel@tonic-gate } 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate * Overwrite the input mblk option buffer now with the output 20417c478bd9Sstevel@tonic-gate * and update length, and contents in original mbl 20427c478bd9Sstevel@tonic-gate * (offset remains unchanged). 20437c478bd9Sstevel@tonic-gate */ 20447c478bd9Sstevel@tonic-gate *opt_lenp = (t_scalar_t)(optr - init_optr); 20457c478bd9Sstevel@tonic-gate if (*opt_lenp > 0) { 20467c478bd9Sstevel@tonic-gate bcopy(init_optr, opt_start, *opt_lenp); 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate error_ret: 20507c478bd9Sstevel@tonic-gate if (copy_mp_head != NULL) 20517c478bd9Sstevel@tonic-gate freeb(copy_mp_head); 20527c478bd9Sstevel@tonic-gate return (error); 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate static opdes_t * 20567c478bd9Sstevel@tonic-gate opt_chk_lookup(t_uscalar_t level, t_uscalar_t name, opdes_t *opt_arr, 20577c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt) 20587c478bd9Sstevel@tonic-gate { 20597c478bd9Sstevel@tonic-gate opdes_t *optd; 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; 20627c478bd9Sstevel@tonic-gate optd++) { 20637c478bd9Sstevel@tonic-gate if (level == (uint_t)optd->opdes_level && 20647c478bd9Sstevel@tonic-gate name == (uint_t)optd->opdes_name) 20657c478bd9Sstevel@tonic-gate return (optd); 20667c478bd9Sstevel@tonic-gate } 20677c478bd9Sstevel@tonic-gate return (NULL); 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate static boolean_t 20717c478bd9Sstevel@tonic-gate opt_level_valid(t_uscalar_t level, optlevel_t *valid_level_arr, 20727c478bd9Sstevel@tonic-gate uint_t valid_level_arr_cnt) 20737c478bd9Sstevel@tonic-gate { 20747c478bd9Sstevel@tonic-gate optlevel_t *olp; 20757c478bd9Sstevel@tonic-gate 20767c478bd9Sstevel@tonic-gate for (olp = valid_level_arr; 20777c478bd9Sstevel@tonic-gate olp < &valid_level_arr[valid_level_arr_cnt]; 20787c478bd9Sstevel@tonic-gate olp++) { 20797c478bd9Sstevel@tonic-gate if (level == (uint_t)(*olp)) 20807c478bd9Sstevel@tonic-gate return (B_TRUE); 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate return (B_FALSE); 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate /* 20877c478bd9Sstevel@tonic-gate * Compute largest possible size for an option buffer containing 20887c478bd9Sstevel@tonic-gate * all options in one buffer. 20897c478bd9Sstevel@tonic-gate * 20907c478bd9Sstevel@tonic-gate * XXX TBD, investigate use of opt_bloated_maxsize() to avoid 20917c478bd9Sstevel@tonic-gate * wastefully large buffer allocation. 20927c478bd9Sstevel@tonic-gate */ 20937c478bd9Sstevel@tonic-gate static size_t 20947c478bd9Sstevel@tonic-gate opt_level_allopts_lengths(t_uscalar_t level, opdes_t *opt_arr, 20957c478bd9Sstevel@tonic-gate uint_t opt_arr_cnt) 20967c478bd9Sstevel@tonic-gate { 20977c478bd9Sstevel@tonic-gate opdes_t *optd; 20987c478bd9Sstevel@tonic-gate size_t allopt_len = 0; /* 0 implies no option at this level */ 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate /* 21017c478bd9Sstevel@tonic-gate * Scan opt_arr computing aggregate length 21027c478bd9Sstevel@tonic-gate * requirement for storing values of all 21037c478bd9Sstevel@tonic-gate * options. 21047c478bd9Sstevel@tonic-gate * Note: we do not filter for permissions 21057c478bd9Sstevel@tonic-gate * etc. This will be >= the real aggregate 21067c478bd9Sstevel@tonic-gate * length required (upper bound). 21077c478bd9Sstevel@tonic-gate */ 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; 21107c478bd9Sstevel@tonic-gate optd++) { 21117c478bd9Sstevel@tonic-gate if (level == optd->opdes_level) { 21127c478bd9Sstevel@tonic-gate allopt_len += sizeof (struct T_opthdr) + 21137c478bd9Sstevel@tonic-gate _TPI_ALIGN_TOPT(optd->opdes_size); 21147c478bd9Sstevel@tonic-gate } 21157c478bd9Sstevel@tonic-gate } 21167c478bd9Sstevel@tonic-gate return (allopt_len); /* 0 implies level not found */ 21177c478bd9Sstevel@tonic-gate } 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate /* 21207c478bd9Sstevel@tonic-gate * Compute largest possible size for an option buffer containing 21217c478bd9Sstevel@tonic-gate * all options in one buffer - a (theoretical?) worst case scenario 21227c478bd9Sstevel@tonic-gate * for certain cases. 21237c478bd9Sstevel@tonic-gate */ 21247c478bd9Sstevel@tonic-gate t_uscalar_t 21257c478bd9Sstevel@tonic-gate optcom_max_optbuf_len(opdes_t *opt_arr, uint_t opt_arr_cnt) 21267c478bd9Sstevel@tonic-gate { 21277c478bd9Sstevel@tonic-gate t_uscalar_t max_optbuf_len = sizeof (struct T_info_ack); 21287c478bd9Sstevel@tonic-gate opdes_t *optd; 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 21317c478bd9Sstevel@tonic-gate max_optbuf_len += (t_uscalar_t)sizeof (struct T_opthdr) + 21327c478bd9Sstevel@tonic-gate (t_uscalar_t)_TPI_ALIGN_TOPT(optd->opdes_size); 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate return (max_optbuf_len); 21357c478bd9Sstevel@tonic-gate } 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate /* 21387c478bd9Sstevel@tonic-gate * Compute largest possible size for OPT_size for a transport. 21397c478bd9Sstevel@tonic-gate * Heuristic used is to add all but certain extremely large 21407c478bd9Sstevel@tonic-gate * size options; this is done by calling opt_bloated_maxsize(). 21417c478bd9Sstevel@tonic-gate * It affects user level allocations in TLI/XTI code using t_alloc() 21427c478bd9Sstevel@tonic-gate * and other TLI/XTI implementation instance strucutures. 21437c478bd9Sstevel@tonic-gate * The large size options excluded are presumed to be 21447c478bd9Sstevel@tonic-gate * never accessed through the (theoretical?) worst case code paths 21457c478bd9Sstevel@tonic-gate * through TLI/XTI as they are currently IPv6 specific options. 21467c478bd9Sstevel@tonic-gate */ 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate t_uscalar_t 21497c478bd9Sstevel@tonic-gate optcom_max_optsize(opdes_t *opt_arr, uint_t opt_arr_cnt) 21507c478bd9Sstevel@tonic-gate { 21517c478bd9Sstevel@tonic-gate t_uscalar_t max_optbuf_len = sizeof (struct T_info_ack); 21527c478bd9Sstevel@tonic-gate opdes_t *optd; 21537c478bd9Sstevel@tonic-gate 21547c478bd9Sstevel@tonic-gate for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) { 21557c478bd9Sstevel@tonic-gate if (!opt_bloated_maxsize(optd)) { 21567c478bd9Sstevel@tonic-gate max_optbuf_len += 21577c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_opthdr) + 21587c478bd9Sstevel@tonic-gate (t_uscalar_t)_TPI_ALIGN_TOPT(optd->opdes_size); 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate } 21617c478bd9Sstevel@tonic-gate return (max_optbuf_len); 21627c478bd9Sstevel@tonic-gate } 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate /* 21657c478bd9Sstevel@tonic-gate * The theoretical model used in optcom_max_optsize() and 21667c478bd9Sstevel@tonic-gate * opt_level_allopts_lengths() accounts for the worst case of all 21677c478bd9Sstevel@tonic-gate * possible options for the theoretical cases and results in wasteful 21687c478bd9Sstevel@tonic-gate * memory allocations for certain theoretically correct usage scenarios. 21697c478bd9Sstevel@tonic-gate * In practice, the "features" they support are rarely, if ever, 21707c478bd9Sstevel@tonic-gate * used and even then only by test suites for those features (VSU, VST). 21717c478bd9Sstevel@tonic-gate * However, they result in large allocations due to the increased transport 21727c478bd9Sstevel@tonic-gate * T_INFO_ACK OPT_size field affecting t_alloc() users and TLI/XTI library 21737c478bd9Sstevel@tonic-gate * instance data structures for applications. 21747c478bd9Sstevel@tonic-gate * 21757c478bd9Sstevel@tonic-gate * The following routine opt_bloated_maxsize() supports a hack that avoids 21767c478bd9Sstevel@tonic-gate * paying the tax for the bloated options by excluding them and pretending 21777c478bd9Sstevel@tonic-gate * they don't exist for certain features without affecting features that 21787c478bd9Sstevel@tonic-gate * do use them. 21797c478bd9Sstevel@tonic-gate * 21807c478bd9Sstevel@tonic-gate * XXX Currently implemented only for optcom_max_optsize() 21817c478bd9Sstevel@tonic-gate * (to reduce risk late in release). 21827c478bd9Sstevel@tonic-gate * TBD for future, investigate use in optcom_level_allopts_lengths() and 21837c478bd9Sstevel@tonic-gate * all the instances of T_ALLOPT processing to exclude "bloated options". 21847c478bd9Sstevel@tonic-gate * Will not affect VSU/VST tests as they do not test with IPPROTO_IPV6 21857c478bd9Sstevel@tonic-gate * level options which are the only ones that fit the "bloated maxsize" 21867c478bd9Sstevel@tonic-gate * option profile now. 21877c478bd9Sstevel@tonic-gate */ 21887c478bd9Sstevel@tonic-gate static boolean_t 21897c478bd9Sstevel@tonic-gate opt_bloated_maxsize(opdes_t *optd) 21907c478bd9Sstevel@tonic-gate { 21917c478bd9Sstevel@tonic-gate if (optd->opdes_level != IPPROTO_IPV6) 21927c478bd9Sstevel@tonic-gate return (B_FALSE); 21937c478bd9Sstevel@tonic-gate switch (optd->opdes_name) { 21947c478bd9Sstevel@tonic-gate case IPV6_HOPOPTS: 21957c478bd9Sstevel@tonic-gate case IPV6_DSTOPTS: 21967c478bd9Sstevel@tonic-gate case IPV6_RTHDRDSTOPTS: 21977c478bd9Sstevel@tonic-gate case IPV6_RTHDR: 21987c478bd9Sstevel@tonic-gate case IPV6_PATHMTU: 21997c478bd9Sstevel@tonic-gate return (B_TRUE); 22007c478bd9Sstevel@tonic-gate default: 22017c478bd9Sstevel@tonic-gate break; 22027c478bd9Sstevel@tonic-gate } 22037c478bd9Sstevel@tonic-gate return (B_FALSE); 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate static boolean_t 22077c478bd9Sstevel@tonic-gate opt_length_ok(opdes_t *optd, struct T_opthdr *opt) 22087c478bd9Sstevel@tonic-gate { 22097c478bd9Sstevel@tonic-gate /* 22107c478bd9Sstevel@tonic-gate * Verify length. 22117c478bd9Sstevel@tonic-gate * Value specified should match length of fixed length option or be 22127c478bd9Sstevel@tonic-gate * less than maxlen of variable length option. 22137c478bd9Sstevel@tonic-gate */ 22147c478bd9Sstevel@tonic-gate if (optd->opdes_props & OP_VARLEN) { 22157c478bd9Sstevel@tonic-gate if (opt->len <= optd->opdes_size + 22167c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_opthdr)) 22177c478bd9Sstevel@tonic-gate return (B_TRUE); 22187c478bd9Sstevel@tonic-gate } else { 22197c478bd9Sstevel@tonic-gate /* fixed length option */ 22207c478bd9Sstevel@tonic-gate if (opt->len == optd->opdes_size + 22217c478bd9Sstevel@tonic-gate (t_uscalar_t)sizeof (struct T_opthdr)) 22227c478bd9Sstevel@tonic-gate return (B_TRUE); 22237c478bd9Sstevel@tonic-gate } 22247c478bd9Sstevel@tonic-gate return (B_FALSE); 22257c478bd9Sstevel@tonic-gate } 2226*45916cd2Sjpk 2227*45916cd2Sjpk /* 2228*45916cd2Sjpk * This routine appends a pssed in hop-by-hop option to the existing 2229*45916cd2Sjpk * option (in this case a cipso label encoded in HOPOPT option). The 2230*45916cd2Sjpk * passed in option is always padded. The 'reservelen' is the 2231*45916cd2Sjpk * length of reserved data (label). New memory will be allocated if 2232*45916cd2Sjpk * the current buffer is not large enough. Return failure if memory 2233*45916cd2Sjpk * can not be allocated. 2234*45916cd2Sjpk */ 2235*45916cd2Sjpk int 2236*45916cd2Sjpk optcom_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky, 2237*45916cd2Sjpk uchar_t **optbufp, uint_t *optlenp, uint_t reservelen) 2238*45916cd2Sjpk { 2239*45916cd2Sjpk uchar_t *optbuf; 2240*45916cd2Sjpk uchar_t *optp; 2241*45916cd2Sjpk 2242*45916cd2Sjpk if (!sticky) { 2243*45916cd2Sjpk *optbufp = invalp; 2244*45916cd2Sjpk *optlenp = inlen; 2245*45916cd2Sjpk return (0); 2246*45916cd2Sjpk } 2247*45916cd2Sjpk 2248*45916cd2Sjpk if (inlen == *optlenp - reservelen) { 2249*45916cd2Sjpk /* Unchanged length - no need to reallocate */ 2250*45916cd2Sjpk optp = *optbufp + reservelen; 2251*45916cd2Sjpk bcopy(invalp, optp, inlen); 2252*45916cd2Sjpk if (reservelen != 0) { 2253*45916cd2Sjpk /* 2254*45916cd2Sjpk * Convert the NextHeader and Length of the 2255*45916cd2Sjpk * passed in hop-by-hop header to pads 2256*45916cd2Sjpk */ 2257*45916cd2Sjpk optp[0] = IP6OPT_PADN; 2258*45916cd2Sjpk optp[1] = 0; 2259*45916cd2Sjpk } 2260*45916cd2Sjpk return (0); 2261*45916cd2Sjpk } 2262*45916cd2Sjpk if (inlen + reservelen > 0) { 2263*45916cd2Sjpk /* Allocate new buffer before free */ 2264*45916cd2Sjpk optbuf = kmem_alloc(inlen + reservelen, KM_NOSLEEP); 2265*45916cd2Sjpk if (optbuf == NULL) 2266*45916cd2Sjpk return (ENOMEM); 2267*45916cd2Sjpk } else { 2268*45916cd2Sjpk optbuf = NULL; 2269*45916cd2Sjpk } 2270*45916cd2Sjpk 2271*45916cd2Sjpk /* Copy out old reserved data (label) */ 2272*45916cd2Sjpk if (reservelen > 0) 2273*45916cd2Sjpk bcopy(*optbufp, optbuf, reservelen); 2274*45916cd2Sjpk 2275*45916cd2Sjpk /* Free old buffer */ 2276*45916cd2Sjpk if (*optlenp != 0) 2277*45916cd2Sjpk kmem_free(*optbufp, *optlenp); 2278*45916cd2Sjpk 2279*45916cd2Sjpk if (inlen > 0) 2280*45916cd2Sjpk bcopy(invalp, optbuf + reservelen, inlen); 2281*45916cd2Sjpk 2282*45916cd2Sjpk if (reservelen != 0) { 2283*45916cd2Sjpk /* 2284*45916cd2Sjpk * Convert the NextHeader and Length of the 2285*45916cd2Sjpk * passed in hop-by-hop header to pads 2286*45916cd2Sjpk */ 2287*45916cd2Sjpk optbuf[reservelen] = IP6OPT_PADN; 2288*45916cd2Sjpk optbuf[reservelen + 1] = 0; 2289*45916cd2Sjpk /* 2290*45916cd2Sjpk * Set the Length of the hop-by-hop header, number of 8 2291*45916cd2Sjpk * byte-words following the 1st 8 bytes 2292*45916cd2Sjpk */ 2293*45916cd2Sjpk optbuf[1] = (reservelen + inlen - 1) >> 3; 2294*45916cd2Sjpk } 2295*45916cd2Sjpk *optbufp = optbuf; 2296*45916cd2Sjpk *optlenp = inlen + reservelen; 2297*45916cd2Sjpk return (0); 2298*45916cd2Sjpk } 2299