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