Merge commit '7e934d3acc051b7ee3ef0d11571fd1225800a607'
[unleashed.git] / kernel / net / optcom.c
blob3e62659224c103003bed3d8133dbb214c0dc5041
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 /* Copyright (c) 1990 Mentat Inc. */
28 * This file contains common code for handling Options Management requests.
31 #include <sys/types.h>
32 #include <sys/stream.h>
33 #include <sys/stropts.h>
34 #include <sys/strsubr.h>
35 #include <sys/errno.h>
36 #define _SUN_TPI_VERSION 2
37 #include <sys/tihdr.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 #include <sys/ddi.h>
41 #include <sys/debug.h> /* for ASSERT */
42 #include <sys/policy.h>
44 #include <inet/common.h>
45 #include <inet/mi.h>
46 #include <inet/nd.h>
47 #include <netinet/ip6.h>
48 #include <inet/ip.h>
49 #include <inet/mib2.h>
50 #include <netinet/in.h>
51 #include <inet/optcom.h>
53 #include <inet/optcom.h>
54 #include <inet/ipclassifier.h>
55 #include <inet/proto_set.h>
58 * Function prototypes
60 static t_scalar_t process_topthdrs_first_pass(mblk_t *, cred_t *, optdb_obj_t *,
61 size_t *);
62 static t_scalar_t do_options_second_pass(queue_t *q, mblk_t *reqmp,
63 mblk_t *ack_mp, cred_t *, optdb_obj_t *dbobjp,
64 t_uscalar_t *worst_statusp);
65 static t_uscalar_t get_worst_status(t_uscalar_t, t_uscalar_t);
66 static int do_opt_default(queue_t *, struct T_opthdr *, uchar_t **,
67 t_uscalar_t *, cred_t *, optdb_obj_t *);
68 static void do_opt_current(queue_t *, struct T_opthdr *, uchar_t **,
69 t_uscalar_t *, cred_t *cr, optdb_obj_t *);
70 static void do_opt_check_or_negotiate(queue_t *q, struct T_opthdr *reqopt,
71 uint_t optset_context, uchar_t **resptrp, t_uscalar_t *worst_statusp,
72 cred_t *, optdb_obj_t *dbobjp);
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 *, t_uscalar_t optlen);
76 static t_uscalar_t optcom_max_optbuf_len(opdes_t *, uint_t);
77 static boolean_t opt_bloated_maxsize(opdes_t *);
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)
83 if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL)
84 qreply(q, mp);
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
93 * (1) deffn(q, optlevel, optname, optvalp)
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.
105 * (2) getfn(q, optlevel, optname, optvalp)
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.
114 * (3) setfn(q, optset_context, optlevel, optname, inlen, invalp,
115 * outlenp, outvalp, attrp, cr);
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. ]
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.
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.
180 void
181 svr4_optcom_req(queue_t *q, mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp)
183 pfi_t deffn = dbobjp->odb_deffn;
184 pfi_t getfn = dbobjp->odb_getfn;
185 opt_set_fn setfn = dbobjp->odb_setfn;
186 opdes_t *opt_arr = dbobjp->odb_opt_des_arr;
187 uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt;
188 t_uscalar_t max_optbuf_len;
189 int len;
190 mblk_t *mp1 = NULL;
191 struct opthdr *next_opt;
192 struct opthdr *opt;
193 struct opthdr *opt1;
194 struct opthdr *opt_end;
195 struct opthdr *opt_start;
196 opdes_t *optd;
197 struct T_optmgmt_ack *toa;
198 struct T_optmgmt_req *tor;
199 int error;
201 tor = (struct T_optmgmt_req *)mp->b_rptr;
202 /* Verify message integrity. */
203 if (mp->b_wptr - mp->b_rptr < sizeof (struct T_optmgmt_req))
204 goto bad_opt;
205 /* Verify MGMT_flags legal */
206 switch (tor->MGMT_flags) {
207 case T_DEFAULT:
208 case T_NEGOTIATE:
209 case T_CURRENT:
210 case T_CHECK:
211 /* OK - legal request flags */
212 break;
213 default:
214 optcom_err_ack(q, mp, TBADFLAG, 0);
215 return;
217 if (tor->MGMT_flags == T_DEFAULT) {
218 /* Is it a request for default option settings? */
221 * Note: XXX TLI and TPI specification was unclear about
222 * semantics of T_DEFAULT and the following historical note
223 * and its interpretation is incorrect (it implies a request
224 * for default values of only the identified options not all.
225 * The semantics have been explained better in XTI spec.)
226 * However, we do not modify (comment or code) here to keep
227 * compatibility.
228 * We can rethink this if it ever becomes an issue.
229 * ----historical comment start------
230 * As we understand it, the input buffer is meaningless
231 * so we ditch the message. A T_DEFAULT request is a
232 * request to obtain a buffer containing defaults for
233 * all supported options, so we allocate a maximum length
234 * reply.
235 * ----historical comment end -------
237 /* T_DEFAULT not passed down */
238 freemsg(mp);
239 max_optbuf_len = optcom_max_optbuf_len(opt_arr,
240 opt_arr_cnt);
241 mp = allocb(max_optbuf_len, BPRI_MED);
242 if (!mp) {
243 no_mem:;
244 optcom_err_ack(q, mp, TSYSERR, ENOMEM);
245 return;
248 /* Initialize the T_optmgmt_ack header. */
249 toa = (struct T_optmgmt_ack *)mp->b_rptr;
250 bzero((char *)toa, max_optbuf_len);
251 toa->PRIM_type = T_OPTMGMT_ACK;
252 toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack);
253 /* TODO: Is T_DEFAULT the right thing to put in MGMT_flags? */
254 toa->MGMT_flags = T_DEFAULT;
256 /* Now walk the table of options passed in */
257 opt = (struct opthdr *)&toa[1];
258 for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) {
260 * All the options in the table of options passed
261 * in are by definition supported by the protocol
262 * calling this function.
264 if (!OA_READ_PERMISSION(optd, cr))
265 continue;
266 opt->level = optd->opdes_level;
267 opt->name = optd->opdes_name;
268 if (!(optd->opdes_props & OP_DEF_FN) ||
269 ((len = (*deffn)(q, opt->level,
270 opt->name, (uchar_t *)&opt[1])) < 0)) {
272 * Fill length and value from table.
274 * Default value not instantiated from function
275 * (or the protocol specific function failed it;
276 * In this interpretation of T_DEFAULT, this is
277 * the best we can do)
279 switch (optd->opdes_size) {
281 * Since options are guaranteed aligned only
282 * on a 4 byte boundary (t_scalar_t) any
283 * option that is greater in size will default
284 * to the bcopy below
286 case sizeof (int32_t):
287 *(int32_t *)&opt[1] =
288 (int32_t)optd->opdes_default;
289 break;
290 case sizeof (int16_t):
291 *(int16_t *)&opt[1] =
292 (int16_t)optd->opdes_default;
293 break;
294 case sizeof (int8_t):
295 *(int8_t *)&opt[1] =
296 (int8_t)optd->opdes_default;
297 break;
298 default:
300 * other length but still assume
301 * fixed - use bcopy
303 bcopy(optd->opdes_defbuf,
304 &opt[1], optd->opdes_size);
305 break;
307 opt->len = optd->opdes_size;
309 else
310 opt->len = (t_uscalar_t)len;
311 opt = (struct opthdr *)((char *)&opt[1] +
312 _TPI_ALIGN_OPT(opt->len));
315 /* Now record the final length. */
316 toa->OPT_length = (t_scalar_t)((char *)opt - (char *)&toa[1]);
317 mp->b_wptr = (uchar_t *)opt;
318 mp->b_datap->db_type = M_PCPROTO;
319 /* Ship it back. */
320 qreply(q, mp);
321 return;
323 /* T_DEFAULT processing complete - no more T_DEFAULT */
326 * For T_NEGOTIATE, T_CURRENT, and T_CHECK requests, we make a
327 * pass through the input buffer validating the details and
328 * making sure each option is supported by the protocol.
330 if ((opt_start = (struct opthdr *)mi_offset_param(mp,
331 tor->OPT_offset, tor->OPT_length)) == NULL)
332 goto bad_opt;
333 if (!__TPI_OPT_ISALIGNED(opt_start))
334 goto bad_opt;
336 opt_end = (struct opthdr *)((uchar_t *)opt_start +
337 tor->OPT_length);
339 for (opt = opt_start; opt < opt_end; opt = next_opt) {
341 * Verify we have room to reference the option header
342 * fields in the option buffer.
344 if ((uchar_t *)opt + sizeof (struct opthdr) >
345 (uchar_t *)opt_end)
346 goto bad_opt;
348 * We now compute pointer to next option in buffer 'next_opt'
349 * The next_opt computation above below 'opt->len' initialized
350 * by application which cannot be trusted. The usual value
351 * too large will be captured by the loop termination condition
352 * above. We check for the following which it will miss.
353 * -pointer space wraparound arithmetic overflow
354 * -last option in buffer with 'opt->len' being too large
355 * (only reason 'next_opt' should equal or exceed
356 * 'opt_end' for last option is roundup unless length is
357 * too-large/invalid)
359 next_opt = (struct opthdr *)((uchar_t *)&opt[1] +
360 _TPI_ALIGN_OPT(opt->len));
362 if ((uchar_t *)next_opt < (uchar_t *)&opt[1] ||
363 ((next_opt >= opt_end) &&
364 (((uchar_t *)next_opt - (uchar_t *)opt_end) >=
365 __TPI_ALIGN_SIZE)))
366 goto bad_opt;
368 /* sanity check */
369 if (opt->name == T_ALLOPT)
370 goto bad_opt;
372 error = proto_opt_check(opt->level, opt->name, opt->len, NULL,
373 opt_arr, opt_arr_cnt,
374 tor->MGMT_flags == T_NEGOTIATE, tor->MGMT_flags == T_CHECK,
375 cr);
376 if (error < 0) {
377 optcom_err_ack(q, mp, -error, 0);
378 return;
379 } else if (error > 0) {
380 optcom_err_ack(q, mp, TSYSERR, error);
381 return;
383 } /* end for loop scanning option buffer */
385 /* Now complete the operation as required. */
386 switch (tor->MGMT_flags) {
387 case T_CHECK:
389 * Historically used same as T_CURRENT (which was added to
390 * standard later). Code retained for compatibility.
392 /* FALLTHROUGH */
393 case T_CURRENT:
395 * Allocate a maximum size reply. Perhaps we are supposed to
396 * assume that the input buffer includes space for the answers
397 * as well as the opthdrs, but we don't know that for sure.
398 * So, instead, we create a new output buffer, using the
399 * input buffer only as a list of options.
401 max_optbuf_len = optcom_max_optbuf_len(opt_arr,
402 opt_arr_cnt);
403 mp1 = allocb_tmpl(max_optbuf_len, mp);
404 if (!mp1)
405 goto no_mem;
406 /* Initialize the header. */
407 mp1->b_datap->db_type = M_PCPROTO;
408 mp1->b_wptr = &mp1->b_rptr[sizeof (struct T_optmgmt_ack)];
409 toa = (struct T_optmgmt_ack *)mp1->b_rptr;
410 toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack);
411 toa->MGMT_flags = tor->MGMT_flags;
413 * Walk through the input buffer again, this time adding
414 * entries to the output buffer for each option requested.
415 * Note, sanity of option header, last option etc, verified
416 * in first pass.
418 opt1 = (struct opthdr *)&toa[1];
420 for (opt = opt_start; opt < opt_end; opt = next_opt) {
422 next_opt = (struct opthdr *)((uchar_t *)&opt[1] +
423 _TPI_ALIGN_OPT(opt->len));
425 opt1->name = opt->name;
426 opt1->level = opt->level;
427 len = (*getfn)(q, opt->level,
428 opt->name, (uchar_t *)&opt1[1]);
430 * Failure means option is not recognized. Copy input
431 * buffer as is
433 if (len < 0) {
434 opt1->len = opt->len;
435 bcopy(&opt[1], &opt1[1], opt->len);
436 } else {
437 opt1->len = (t_uscalar_t)len;
439 opt1 = (struct opthdr *)((uchar_t *)&opt1[1] +
440 _TPI_ALIGN_OPT(opt1->len));
441 } /* end for loop */
443 /* Record the final length. */
444 toa->OPT_length = (t_scalar_t)((uchar_t *)opt1 -
445 (uchar_t *)&toa[1]);
446 mp1->b_wptr = (uchar_t *)opt1;
447 /* Ditch the input buffer. */
448 freemsg(mp);
449 mp = mp1;
450 break;
452 case T_NEGOTIATE:
454 * Here we are expecting that the response buffer is exactly
455 * the same size as the input buffer. We pass each opthdr
456 * to the protocol's set function. If the protocol doesn't
457 * like it, it can update the value in it return argument.
460 * Pass each negotiated option through the protocol set
461 * function.
462 * Note: sanity check on option header values done in first
463 * pass and not repeated here.
465 toa = (struct T_optmgmt_ack *)tor;
467 for (opt = opt_start; opt < opt_end; opt = next_opt) {
468 int error;
470 next_opt = (struct opthdr *)((uchar_t *)&opt[1] +
471 _TPI_ALIGN_OPT(opt->len));
473 error = (*setfn)(q, SETFN_OPTCOM_NEGOTIATE,
474 opt->level, opt->name,
475 opt->len, (uchar_t *)&opt[1],
476 &opt->len, (uchar_t *)&opt[1], NULL, cr);
478 * Treat positive "errors" as real.
479 * Note: negative errors are to be treated as
480 * non-fatal by svr4_optcom_req() and are
481 * returned by setfn() when it is passed an
482 * option it does not handle. Since the option
483 * passed proto_opt_lookup(), it is implied that
484 * it is valid but was either handled upstream
485 * or will be handled downstream.
487 if (error > 0) {
488 optcom_err_ack(q, mp, TSYSERR, error);
489 return;
492 * error < 0 means option is not recognized.
495 break;
496 default:
497 optcom_err_ack(q, mp, TBADFLAG, 0);
498 return;
501 /* Set common fields in the header. */
502 toa->MGMT_flags = T_SUCCESS;
503 mp->b_datap->db_type = M_PCPROTO;
504 toa->PRIM_type = T_OPTMGMT_ACK;
505 qreply(q, mp);
506 return;
507 bad_opt:;
508 optcom_err_ack(q, mp, TBADOPT, 0);
512 * New optcom_req inspired by TPI/XTI semantics
514 void
515 tpi_optcom_req(queue_t *q, mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp)
517 t_scalar_t t_error;
518 mblk_t *toa_mp;
519 size_t toa_len;
520 struct T_optmgmt_ack *toa;
521 struct T_optmgmt_req *tor =
522 (struct T_optmgmt_req *)mp->b_rptr;
523 t_uscalar_t worst_status;
525 /* Verify message integrity. */
526 if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_optmgmt_req)) {
527 optcom_err_ack(q, mp, TBADOPT, 0);
528 return;
531 /* Verify MGMT_flags legal */
532 switch (tor->MGMT_flags) {
533 case T_DEFAULT:
534 case T_NEGOTIATE:
535 case T_CURRENT:
536 case T_CHECK:
537 /* OK - legal request flags */
538 break;
539 default:
540 optcom_err_ack(q, mp, TBADFLAG, 0);
541 return;
545 * In this design, there are two passes required on the input buffer
546 * mostly to accomodate variable length options and "T_ALLOPT" option
547 * which has the semantics "all options of the specified level".
549 * For T_DEFAULT, T_NEGOTIATE, T_CURRENT, and T_CHECK requests, we make
550 * a pass through the input buffer validating the details and making
551 * sure each option is supported by the protocol. We also determine the
552 * length of the option buffer to return. (Variable length options and
553 * T_ALLOPT mean that length can be different for output buffer).
556 toa_len = 0; /* initial value */
559 * First pass, we do the following
560 * - estimate cumulative length needed for results
561 * - set "status" field based on permissions, option header check
562 * etc.
564 if ((t_error = process_topthdrs_first_pass(mp, cr, dbobjp,
565 &toa_len)) != 0) {
566 optcom_err_ack(q, mp, t_error, 0);
567 return;
571 * A validation phase of the input buffer is done. We have also
572 * obtained the length requirement and and other details about the
573 * input and we liked input buffer so far. We make another scan
574 * through the input now and generate the output necessary to complete
575 * the operation.
578 toa_mp = allocb_tmpl(toa_len, mp);
579 if (!toa_mp) {
580 optcom_err_ack(q, mp, TSYSERR, ENOMEM);
581 return;
585 * Set initial values for generating output.
587 worst_status = T_SUCCESS; /* initial value */
590 * This routine makes another pass through the option buffer this
591 * time acting on the request based on "status" result in the
592 * first pass. It also performs "expansion" of T_ALLOPT into
593 * all options of a certain level and acts on each for this request.
595 if ((t_error = do_options_second_pass(q, mp, toa_mp, cr, dbobjp,
596 &worst_status)) != 0) {
597 freemsg(toa_mp);
598 optcom_err_ack(q, mp, t_error, 0);
599 return;
603 * Following code relies on the coincidence that T_optmgmt_req
604 * and T_optmgmt_ack are identical in binary representation
606 toa = (struct T_optmgmt_ack *)toa_mp->b_rptr;
607 toa->OPT_length = (t_scalar_t)(toa_mp->b_wptr - (toa_mp->b_rptr +
608 sizeof (struct T_optmgmt_ack)));
609 toa->OPT_offset = (t_scalar_t)sizeof (struct T_optmgmt_ack);
611 toa->MGMT_flags = tor->MGMT_flags;
613 freemsg(mp); /* free input mblk */
615 toa->PRIM_type = T_OPTMGMT_ACK;
616 toa_mp->b_datap->db_type = M_PCPROTO;
617 toa->MGMT_flags |= worst_status; /* XXX "worst" or "OR" TPI ? */
618 qreply(q, toa_mp);
623 * Following routine makes a pass through option buffer in mp and performs the
624 * following tasks.
625 * - estimate cumulative length needed for results
626 * - set "status" field based on permissions, option header check
627 * etc.
630 static t_scalar_t
631 process_topthdrs_first_pass(mblk_t *mp, cred_t *cr, optdb_obj_t *dbobjp,
632 size_t *toa_lenp)
634 opdes_t *opt_arr = dbobjp->odb_opt_des_arr;
635 uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt;
636 optlevel_t *valid_level_arr = dbobjp->odb_valid_levels_arr;
637 uint_t valid_level_arr_cnt = dbobjp->odb_valid_levels_arr_cnt;
638 struct T_opthdr *opt;
639 struct T_opthdr *opt_start, *opt_end;
640 opdes_t *optd;
641 size_t allopt_len;
642 struct T_optmgmt_req *tor =
643 (struct T_optmgmt_req *)mp->b_rptr;
645 *toa_lenp = sizeof (struct T_optmgmt_ack); /* initial value */
647 if ((opt_start = (struct T_opthdr *)
648 mi_offset_param(mp, tor->OPT_offset, tor->OPT_length)) == NULL) {
649 return (TBADOPT);
651 if (!__TPI_TOPT_ISALIGNED(opt_start))
652 return (TBADOPT);
654 opt_end = (struct T_opthdr *)((uchar_t *)opt_start + tor->OPT_length);
656 for (opt = opt_start; opt && (opt < opt_end);
657 opt = _TPI_TOPT_NEXTHDR(opt_start, tor->OPT_length, opt)) {
659 * Validate the option for length and alignment
660 * before accessing anything in it.
662 if (!(_TPI_TOPT_VALID(opt, opt_start, opt_end)))
663 return (TBADOPT);
665 /* Find the option in the opt_arr. */
666 if (opt->name != T_ALLOPT) {
667 optd = proto_opt_lookup(opt->level, opt->name,
668 opt_arr, opt_arr_cnt);
669 if (optd == NULL) {
671 * Option not found
673 * Verify if level is "valid" or not.
674 * Note: This check is required by XTI
676 * TPI provider always initializes
677 * the "not supported" (or whatever) status
678 * for the options. Other levels leave status
679 * unchanged if they do not understand an
680 * option.
682 if (!opt_level_valid(opt->level,
683 valid_level_arr, valid_level_arr_cnt))
684 return (TBADOPT);
686 * level is valid - initialize
687 * option as not supported
689 opt->status = T_NOTSUPPORT;
690 *toa_lenp += _TPI_ALIGN_TOPT(opt->len);
691 continue;
693 } else {
695 * Handle T_ALLOPT case as a special case.
696 * Note: T_ALLOPT does not mean anything
697 * for T_CHECK operation.
699 allopt_len = 0;
700 if (tor->MGMT_flags == T_CHECK ||
701 ((allopt_len = opt_level_allopts_lengths(opt->level,
702 opt_arr, opt_arr_cnt)) == 0)) {
704 * This is confusing but correct !
705 * It is not valid to to use T_ALLOPT with
706 * T_CHECK flag.
708 * opt_level_allopts_lengths() is used to verify
709 * that "level" associated with the T_ALLOPT is
710 * supported.
713 opt->status = T_FAILURE;
714 *toa_lenp += _TPI_ALIGN_TOPT(opt->len);
715 continue;
717 ASSERT(allopt_len != 0); /* remove ? */
719 *toa_lenp += allopt_len;
720 opt->status = T_SUCCESS;
721 continue;
724 /* Additional checks dependent on operation. */
725 switch (tor->MGMT_flags) {
726 case T_DEFAULT:
727 case T_CURRENT:
730 * The proto_opt_lookup() routine call above approved of
731 * this option so we can work on the status for it
732 * based on the permissions for the operation. (This
733 * can override any status for it set at higher levels)
734 * We assume this override is OK since chkfn at this
735 * level approved of this option.
737 * T_CURRENT semantics:
738 * The read access is required. Else option
739 * status is T_NOTSUPPORT.
741 * T_DEFAULT semantics:
742 * Note: specification is not clear on this but we
743 * interpret T_DEFAULT semantics such that access to
744 * read value is required for access even the default
745 * value. Otherwise the option status is T_NOTSUPPORT.
747 if (!OA_READ_PERMISSION(optd, cr)) {
748 opt->status = T_NOTSUPPORT;
749 *toa_lenp += _TPI_ALIGN_TOPT(opt->len);
750 /* skip to next */
751 continue;
755 * T_DEFAULT/T_CURRENT semantics:
756 * We know that read access is set. If no other access
757 * is set, then status is T_READONLY.
759 if (OA_READONLY_PERMISSION(optd, cr))
760 opt->status = T_READONLY;
761 else
762 opt->status = T_SUCCESS;
764 * Option passes all checks. Make room for it in the
765 * ack. Note: size stored in table does not include
766 * space for option header.
768 *toa_lenp += sizeof (struct T_opthdr) +
769 _TPI_ALIGN_TOPT(optd->opdes_size);
770 break;
772 case T_CHECK:
773 case T_NEGOTIATE:
776 * T_NEGOTIATE semantics:
777 * If for fixed length option value on input is not the
778 * same as value supplied, then status is T_FAILURE.
780 * T_CHECK semantics:
781 * If value is supplied, semantics same as T_NEGOTIATE.
782 * It is however ok not to supply a value with T_CHECK.
785 if (tor->MGMT_flags == T_NEGOTIATE ||
786 (opt->len != sizeof (struct T_opthdr))) {
788 * Implies "value" is specified in T_CHECK or
789 * it is a T_NEGOTIATE request.
790 * Verify size.
791 * Note: This can override anything about this
792 * option request done at a higher level.
794 if (opt->len < sizeof (struct T_opthdr) ||
795 !opt_length_ok(optd,
796 opt->len - sizeof (struct T_opthdr))) {
797 /* bad size */
798 *toa_lenp += _TPI_ALIGN_TOPT(opt->len);
799 opt->status = T_FAILURE;
800 continue;
804 * The proto_opt_lookup() routine above() approved of
805 * this option so we can work on the status for it based
806 * on the permissions for the operation. (This can
807 * override anything set at a higher level).
809 * T_CHECK/T_NEGOTIATE semantics:
810 * Set status to T_READONLY if read is the only access
811 * permitted
813 if (OA_READONLY_PERMISSION(optd, cr)) {
814 opt->status = T_READONLY;
815 *toa_lenp += _TPI_ALIGN_TOPT(opt->len);
816 /* skip to next */
817 continue;
821 * T_CHECK/T_NEGOTIATE semantics:
822 * If write (or execute) access is not set, then status
823 * is T_NOTSUPPORT.
825 if (!OA_WRITE_OR_EXECUTE(optd, cr)) {
826 opt->status = T_NOTSUPPORT;
827 *toa_lenp += _TPI_ALIGN_TOPT(opt->len);
828 /* skip to next option */
829 continue;
832 * Option passes all checks. Make room for it in the
833 * ack and set success in status.
834 * Note: size stored in table does not include header
835 * length.
837 opt->status = T_SUCCESS;
838 *toa_lenp += sizeof (struct T_opthdr) +
839 _TPI_ALIGN_TOPT(optd->opdes_size);
840 break;
842 default:
843 return (TBADFLAG);
845 } /* for loop scanning input buffer */
847 return (0); /* OK return */
851 * This routine makes another pass through the option buffer this
852 * time acting on the request based on "status" result in the
853 * first pass. It also performs "expansion" of T_ALLOPT into
854 * all options of a certain level and acts on each for this request.
856 static t_scalar_t
857 do_options_second_pass(queue_t *q, mblk_t *reqmp, mblk_t *ack_mp, cred_t *cr,
858 optdb_obj_t *dbobjp, t_uscalar_t *worst_statusp)
860 int failed_option;
861 struct T_opthdr *opt;
862 struct T_opthdr *opt_start, *opt_end;
863 uchar_t *optr;
864 uint_t optset_context;
865 struct T_optmgmt_req *tor = (struct T_optmgmt_req *)reqmp->b_rptr;
867 optr = (uchar_t *)ack_mp->b_rptr +
868 sizeof (struct T_optmgmt_ack); /* assumed int32_t aligned */
871 * Set initial values for scanning input
873 opt_start = (struct T_opthdr *)mi_offset_param(reqmp,
874 tor->OPT_offset, tor->OPT_length);
875 if (opt_start == NULL)
876 return (TBADOPT);
877 opt_end = (struct T_opthdr *)((uchar_t *)opt_start + tor->OPT_length);
878 ASSERT(__TPI_TOPT_ISALIGNED(opt_start)); /* verified in first pass */
880 for (opt = opt_start; opt && (opt < opt_end);
881 opt = _TPI_TOPT_NEXTHDR(opt_start, tor->OPT_length, opt)) {
883 /* verified in first pass */
884 ASSERT(_TPI_TOPT_VALID(opt, opt_start, opt_end));
887 * If the first pass in process_topthdrs_first_pass()
888 * has marked the option as a failure case for the MGMT_flags
889 * semantics then there is not much to do.
891 * Note: For all practical purposes, T_READONLY status is
892 * a "success" for T_DEFAULT/T_CURRENT and "failure" for
893 * T_CHECK/T_NEGOTIATE
895 failed_option =
896 (opt->status == T_NOTSUPPORT) ||
897 (opt->status == T_FAILURE) ||
898 ((tor->MGMT_flags & (T_NEGOTIATE|T_CHECK)) &&
899 (opt->status == T_READONLY));
901 if (failed_option) {
903 * According to T_DEFAULT/T_CURRENT semantics, the
904 * input values, even if present, are to be ignored.
905 * Note: Specification is not clear on this, but we
906 * interpret that even though we ignore the values, we
907 * can return them as is. So we process them similar to
908 * T_CHECK/T_NEGOTIATE case which has the semantics to
909 * return the values as is. XXX If interpretation is
910 * ever determined incorrect fill in appropriate code
911 * here to treat T_DEFAULT/T_CURRENT differently.
913 * According to T_CHECK/T_NEGOTIATE semantics,
914 * in the case of T_NOTSUPPORT/T_FAILURE/T_READONLY,
915 * the semantics are to return the "value" part of
916 * option untouched. So here we copy the option
917 * head including value part if any to output.
920 bcopy(opt, optr, opt->len);
921 optr += _TPI_ALIGN_TOPT(opt->len);
923 *worst_statusp = get_worst_status(opt->status,
924 *worst_statusp);
926 /* skip to process next option in buffer */
927 continue;
929 } /* end if "failed option" */
931 * The status is T_SUCCESS or T_READONLY
932 * We process the value part here
934 ASSERT(opt->status == T_SUCCESS || opt->status == T_READONLY);
935 switch (tor->MGMT_flags) {
936 case T_DEFAULT:
938 * We fill default value from table or protocol specific
939 * function. If this call fails, we pass input through.
941 if (do_opt_default(q, opt, &optr, worst_statusp,
942 cr, dbobjp) < 0) {
943 opt->status = T_FAILURE;
944 bcopy(opt, optr, opt->len);
945 optr += _TPI_ALIGN_TOPT(opt->len);
946 *worst_statusp = get_worst_status(opt->status,
947 *worst_statusp);
949 break;
951 case T_CURRENT:
953 do_opt_current(q, opt, &optr, worst_statusp, cr,
954 dbobjp);
955 break;
957 case T_CHECK:
958 case T_NEGOTIATE:
959 if (tor->MGMT_flags == T_CHECK)
960 optset_context = SETFN_OPTCOM_CHECKONLY;
961 else /* T_NEGOTIATE */
962 optset_context = SETFN_OPTCOM_NEGOTIATE;
963 do_opt_check_or_negotiate(q, opt, optset_context,
964 &optr, worst_statusp, cr, dbobjp);
965 break;
966 default:
967 return (TBADFLAG);
969 } /* end for loop scanning option buffer */
971 ack_mp->b_wptr = optr;
972 ASSERT(ack_mp->b_wptr <= ack_mp->b_datap->db_lim);
974 return (0); /* OK return */
978 static t_uscalar_t
979 get_worst_status(t_uscalar_t status, t_uscalar_t current_worst_status)
982 * Return the "worst" among the arguments "status" and
983 * "current_worst_status".
985 * Note: Tracking "worst_status" can be made a bit simpler
986 * if we use the property that status codes are bitwise
987 * distinct.
989 * The pecking order is
991 * T_SUCCESS ..... best
992 * T_PARTSUCCESS
993 * T_FAILURE
994 * T_READONLY
995 * T_NOTSUPPORT... worst
997 if (status == current_worst_status)
998 return (current_worst_status);
999 switch (current_worst_status) {
1000 case T_SUCCESS:
1001 if (status == T_PARTSUCCESS)
1002 return (T_PARTSUCCESS);
1003 /* FALLTHROUGH */
1004 case T_PARTSUCCESS:
1005 if (status == T_FAILURE)
1006 return (T_FAILURE);
1007 /* FALLTHROUGH */
1008 case T_FAILURE:
1009 if (status == T_READONLY)
1010 return (T_READONLY);
1011 /* FALLTHROUGH */
1012 case T_READONLY:
1013 if (status == T_NOTSUPPORT)
1014 return (T_NOTSUPPORT);
1015 /* FALLTHROUGH */
1016 case T_NOTSUPPORT:
1017 default:
1018 return (current_worst_status);
1022 static int
1023 do_opt_default(queue_t *q, struct T_opthdr *reqopt, uchar_t **resptrp,
1024 t_uscalar_t *worst_statusp, cred_t *cr, optdb_obj_t *dbobjp)
1026 pfi_t deffn = dbobjp->odb_deffn;
1027 opdes_t *opt_arr = dbobjp->odb_opt_des_arr;
1028 uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt;
1030 struct T_opthdr *topth;
1031 opdes_t *optd;
1033 if (reqopt->name != T_ALLOPT) {
1035 * lookup the option in the table and fill default value
1037 optd = proto_opt_lookup(reqopt->level, reqopt->name,
1038 opt_arr, opt_arr_cnt);
1040 /* Calling routine should have verified it it exists */
1041 ASSERT(optd != NULL);
1043 topth = (struct T_opthdr *)(*resptrp);
1044 topth->level = reqopt->level;
1045 topth->name = reqopt->name;
1046 topth->status = reqopt->status;
1048 *worst_statusp = get_worst_status(reqopt->status,
1049 *worst_statusp);
1051 if (optd->opdes_props & OP_NODEFAULT) {
1052 /* header only, no default "value" part */
1053 topth->len = sizeof (struct T_opthdr);
1054 *resptrp += sizeof (struct T_opthdr);
1055 } else {
1056 int deflen;
1058 if (optd->opdes_props & OP_DEF_FN) {
1059 deflen = (*deffn)(q, reqopt->level,
1060 reqopt->name, _TPI_TOPT_DATA(topth));
1061 if (deflen >= 0) {
1062 topth->len = (t_uscalar_t)
1063 (sizeof (struct T_opthdr) + deflen);
1064 } else {
1066 * return error, this should 'pass
1067 * through' the option and maybe some
1068 * other level will fill it in or
1069 * already did.
1070 * (No change in 'resptrp' upto here)
1072 return (-1);
1074 } else {
1075 /* fill length and value part */
1076 switch (optd->opdes_size) {
1078 * Since options are guaranteed aligned only
1079 * on a 4 byte boundary (t_scalar_t) any
1080 * option that is greater in size will default
1081 * to the bcopy below
1083 case sizeof (int32_t):
1084 *(int32_t *)_TPI_TOPT_DATA(topth) =
1085 (int32_t)optd->opdes_default;
1086 break;
1087 case sizeof (int16_t):
1088 *(int16_t *)_TPI_TOPT_DATA(topth) =
1089 (int16_t)optd->opdes_default;
1090 break;
1091 case sizeof (int8_t):
1092 *(int8_t *)_TPI_TOPT_DATA(topth) =
1093 (int8_t)optd->opdes_default;
1094 break;
1095 default:
1097 * other length but still assume
1098 * fixed - use bcopy
1100 bcopy(optd->opdes_defbuf,
1101 _TPI_TOPT_DATA(topth),
1102 optd->opdes_size);
1103 break;
1105 topth->len = (t_uscalar_t)(optd->opdes_size +
1106 sizeof (struct T_opthdr));
1108 *resptrp += _TPI_ALIGN_TOPT(topth->len);
1110 return (0); /* OK return */
1114 * T_ALLOPT processing
1116 * lookup and stuff default values of all the options of the
1117 * level specified
1119 for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) {
1120 if (reqopt->level != optd->opdes_level)
1121 continue;
1124 * T_DEFAULT semantics:
1125 * XXX: we interpret T_DEFAULT semantics such that access to
1126 * read value is required for access even the default value.
1127 * Else option is ignored for T_ALLOPT request.
1129 if (!OA_READ_PERMISSION(optd, cr))
1130 /* skip this one */
1131 continue;
1134 * Found option of same level as T_ALLOPT request
1135 * that we can return.
1138 topth = (struct T_opthdr *)(*resptrp);
1139 topth->level = optd->opdes_level;
1140 topth->name = optd->opdes_name;
1143 * T_DEFAULT semantics:
1144 * We know that read access is set. If no other access is set,
1145 * then status is T_READONLY
1147 if (OA_READONLY_PERMISSION(optd, cr)) {
1148 topth->status = T_READONLY;
1149 *worst_statusp = get_worst_status(T_READONLY,
1150 *worst_statusp);
1151 } else {
1152 topth->status = T_SUCCESS;
1154 * Note: *worst_statusp has to be T_SUCCESS or
1155 * worse so no need to adjust
1159 if (optd->opdes_props & OP_NODEFAULT) {
1160 /* header only, no value part */
1161 topth->len = sizeof (struct T_opthdr);
1162 *resptrp += sizeof (struct T_opthdr);
1163 } else {
1164 int deflen;
1166 if (optd->opdes_props & OP_DEF_FN) {
1167 deflen = (*deffn)(q, reqopt->level,
1168 reqopt->name, _TPI_TOPT_DATA(topth));
1169 if (deflen >= 0) {
1170 topth->len = (t_uscalar_t)(deflen +
1171 sizeof (struct T_opthdr));
1172 } else {
1174 * deffn failed.
1175 * return just the header as T_ALLOPT
1176 * expansion.
1177 * Some other level deffn may
1178 * supply value part.
1180 topth->len = sizeof (struct T_opthdr);
1181 topth->status = T_FAILURE;
1182 *worst_statusp =
1183 get_worst_status(T_FAILURE,
1184 *worst_statusp);
1186 } else {
1188 * fill length and value part from
1189 * table
1191 switch (optd->opdes_size) {
1193 * Since options are guaranteed aligned only
1194 * on a 4 byte boundary (t_scalar_t) any
1195 * option that is greater in size will default
1196 * to the bcopy below
1198 case sizeof (int32_t):
1199 *(int32_t *)_TPI_TOPT_DATA(topth) =
1200 (int32_t)optd->opdes_default;
1201 break;
1202 case sizeof (int16_t):
1203 *(int16_t *)_TPI_TOPT_DATA(topth) =
1204 (int16_t)optd->opdes_default;
1205 break;
1206 case sizeof (int8_t):
1207 *(int8_t *)_TPI_TOPT_DATA(topth) =
1208 (int8_t)optd->opdes_default;
1209 break;
1210 default:
1212 * other length but still assume
1213 * fixed - use bcopy
1215 bcopy(optd->opdes_defbuf,
1216 _TPI_TOPT_DATA(topth),
1217 optd->opdes_size);
1219 topth->len = (t_uscalar_t)(optd->opdes_size +
1220 sizeof (struct T_opthdr));
1222 *resptrp += _TPI_ALIGN_TOPT(topth->len);
1225 return (0);
1228 static void
1229 do_opt_current(queue_t *q, struct T_opthdr *reqopt, uchar_t **resptrp,
1230 t_uscalar_t *worst_statusp, cred_t *cr, optdb_obj_t *dbobjp)
1232 pfi_t getfn = dbobjp->odb_getfn;
1233 opdes_t *opt_arr = dbobjp->odb_opt_des_arr;
1234 uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt;
1235 struct T_opthdr *topth;
1236 opdes_t *optd;
1237 int optlen;
1238 uchar_t *initptr = *resptrp;
1241 * We call getfn to get the current value of an option. The call may
1242 * fail in which case we copy the values from the input buffer. Maybe
1243 * something downstream will fill it in or something upstream did.
1246 if (reqopt->name != T_ALLOPT) {
1247 topth = (struct T_opthdr *)*resptrp;
1248 *resptrp += sizeof (struct T_opthdr);
1249 optlen = (*getfn)(q, reqopt->level, reqopt->name, *resptrp);
1250 if (optlen >= 0) {
1251 topth->len = (t_uscalar_t)(optlen +
1252 sizeof (struct T_opthdr));
1253 topth->level = reqopt->level;
1254 topth->name = reqopt->name;
1255 topth->status = reqopt->status;
1256 *resptrp += _TPI_ALIGN_TOPT(optlen);
1257 *worst_statusp = get_worst_status(topth->status,
1258 *worst_statusp);
1259 } else {
1260 /* failed - reset "*resptrp" pointer */
1261 *resptrp -= sizeof (struct T_opthdr);
1263 } else { /* T_ALLOPT processing */
1264 /* scan and get all options */
1265 for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) {
1266 /* skip other levels */
1267 if (reqopt->level != optd->opdes_level)
1268 continue;
1270 if (!OA_READ_PERMISSION(optd, cr))
1271 /* skip this one */
1272 continue;
1274 topth = (struct T_opthdr *)*resptrp;
1275 *resptrp += sizeof (struct T_opthdr);
1277 /* get option of this level */
1278 optlen = (*getfn)(q, reqopt->level, optd->opdes_name,
1279 *resptrp);
1280 if (optlen >= 0) {
1281 /* success */
1282 topth->len = (t_uscalar_t)(optlen +
1283 sizeof (struct T_opthdr));
1284 topth->level = reqopt->level;
1285 topth->name = optd->opdes_name;
1286 if (OA_READONLY_PERMISSION(optd, cr))
1287 topth->status = T_READONLY;
1288 else
1289 topth->status = T_SUCCESS;
1290 *resptrp += _TPI_ALIGN_TOPT(optlen);
1291 } else {
1293 * failed, return as T_FAILURE and null value
1294 * part. Maybe something downstream will
1295 * handle this one and fill in a value. Here
1296 * it is just part of T_ALLOPT expansion.
1298 topth->len = sizeof (struct T_opthdr);
1299 topth->level = reqopt->level;
1300 topth->name = optd->opdes_name;
1301 topth->status = T_FAILURE;
1303 *worst_statusp = get_worst_status(topth->status,
1304 *worst_statusp);
1305 } /* end for loop */
1307 if (*resptrp == initptr) {
1309 * getfn failed and does not want to handle this option.
1311 reqopt->status = T_FAILURE;
1312 bcopy(reqopt, *resptrp, reqopt->len);
1313 *resptrp += _TPI_ALIGN_TOPT(reqopt->len);
1314 *worst_statusp = get_worst_status(reqopt->status,
1315 *worst_statusp);
1319 static void
1320 do_opt_check_or_negotiate(queue_t *q, struct T_opthdr *reqopt,
1321 uint_t optset_context, uchar_t **resptrp, t_uscalar_t *worst_statusp,
1322 cred_t *cr, optdb_obj_t *dbobjp)
1324 pfi_t deffn = dbobjp->odb_deffn;
1325 opt_set_fn setfn = dbobjp->odb_setfn;
1326 opdes_t *opt_arr = dbobjp->odb_opt_des_arr;
1327 uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt;
1328 struct T_opthdr *topth;
1329 opdes_t *optd;
1330 int error;
1331 t_uscalar_t optlen;
1332 t_scalar_t optsize;
1333 uchar_t *initptr = *resptrp;
1335 ASSERT(reqopt->status == T_SUCCESS);
1337 if (reqopt->name != T_ALLOPT) {
1338 topth = (struct T_opthdr *)*resptrp;
1339 *resptrp += sizeof (struct T_opthdr);
1340 error = (*setfn)(q, optset_context, reqopt->level, reqopt->name,
1341 reqopt->len - sizeof (struct T_opthdr),
1342 _TPI_TOPT_DATA(reqopt), &optlen, _TPI_TOPT_DATA(topth),
1343 NULL, cr);
1344 if (error) {
1345 /* failed - reset "*resptrp" */
1346 *resptrp -= sizeof (struct T_opthdr);
1347 } else {
1349 * success - "value" already filled in setfn()
1351 topth->len = (t_uscalar_t)(optlen +
1352 sizeof (struct T_opthdr));
1353 topth->level = reqopt->level;
1354 topth->name = reqopt->name;
1355 topth->status = reqopt->status;
1356 *resptrp += _TPI_ALIGN_TOPT(optlen);
1357 *worst_statusp = get_worst_status(topth->status,
1358 *worst_statusp);
1360 } else { /* T_ALLOPT processing */
1361 /* only for T_NEGOTIATE case */
1362 ASSERT(optset_context == SETFN_OPTCOM_NEGOTIATE);
1364 /* scan and set all options to default value */
1365 for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) {
1367 /* skip other levels */
1368 if (reqopt->level != optd->opdes_level)
1369 continue;
1371 if (OA_EXECUTE_PERMISSION(optd, cr) ||
1372 OA_NO_PERMISSION(optd, cr)) {
1374 * skip this one too. Does not make sense to
1375 * set anything to default value for "execute"
1376 * options.
1378 continue;
1381 if (OA_READONLY_PERMISSION(optd, cr)) {
1383 * Return with T_READONLY status (and no value
1384 * part). Note: spec is not clear but
1385 * XTI test suite needs this.
1387 topth = (struct T_opthdr *)*resptrp;
1388 topth->len = sizeof (struct T_opthdr);
1389 *resptrp += topth->len;
1390 topth->level = reqopt->level;
1391 topth->name = optd->opdes_name;
1392 topth->status = T_READONLY;
1393 *worst_statusp = get_worst_status(topth->status,
1394 *worst_statusp);
1395 continue;
1399 * It is not read only or execute type
1400 * the it must have write permission
1402 ASSERT(OA_WRITE_PERMISSION(optd, cr));
1404 topth = (struct T_opthdr *)*resptrp;
1405 *resptrp += sizeof (struct T_opthdr);
1407 topth->len = sizeof (struct T_opthdr);
1408 topth->level = reqopt->level;
1409 topth->name = optd->opdes_name;
1410 if (optd->opdes_props & OP_NODEFAULT) {
1412 * Option of "no default value" so it does not
1413 * make sense to try to set it. We just return
1414 * header with status of T_SUCCESS
1415 * XXX should this be failure ?
1417 topth->status = T_SUCCESS;
1418 continue; /* skip setting */
1420 if (optd->opdes_props & OP_DEF_FN) {
1421 if ((optd->opdes_props & OP_VARLEN) ||
1422 ((optsize = (*deffn)(q, reqopt->level,
1423 optd->opdes_name,
1424 (uchar_t *)optd->opdes_defbuf)) < 0)) {
1425 /* XXX - skip these too */
1426 topth->status = T_SUCCESS;
1427 continue; /* skip setting */
1429 } else {
1430 optsize = optd->opdes_size;
1434 /* set option of this level */
1435 error = (*setfn)(q, SETFN_OPTCOM_NEGOTIATE,
1436 reqopt->level, optd->opdes_name, optsize,
1437 (uchar_t *)optd->opdes_defbuf, &optlen,
1438 _TPI_TOPT_DATA(topth), NULL, cr);
1439 if (error) {
1441 * failed, return as T_FAILURE and null value
1442 * part. Maybe something downstream will
1443 * handle this one and fill in a value. Here
1444 * it is just part of T_ALLOPT expansion.
1446 topth->status = T_FAILURE;
1447 *worst_statusp = get_worst_status(topth->status,
1448 *worst_statusp);
1449 } else {
1450 /* success */
1451 topth->len += optlen;
1452 topth->status = T_SUCCESS;
1453 *resptrp += _TPI_ALIGN_TOPT(optlen);
1455 } /* end for loop */
1456 /* END T_ALLOPT */
1459 if (*resptrp == initptr) {
1461 * setfn failed and does not want to handle this option.
1463 reqopt->status = T_FAILURE;
1464 bcopy(reqopt, *resptrp, reqopt->len);
1465 *resptrp += _TPI_ALIGN_TOPT(reqopt->len);
1466 *worst_statusp = get_worst_status(reqopt->status,
1467 *worst_statusp);
1472 * The following routines process options buffer passed with
1473 * T_CONN_REQ, T_CONN_RES and T_UNITDATA_REQ.
1474 * This routine does the consistency check applied to the
1475 * sanity of formatting of multiple options packed in the
1476 * buffer.
1478 * XTI brain damage alert:
1479 * XTI interface adopts the notion of an option being an
1480 * "absolute requirement" from OSI transport service (but applies
1481 * it to all transports including Internet transports).
1482 * The main effect of that is action on failure to "negotiate" a
1483 * requested option to the exact requested value
1485 * - if the option is an "absolute requirement", the primitive
1486 * is aborted (e.g T_DISCON_REQ or T_UDERR generated)
1487 * - if the option is NOT and "absolute requirement" it can
1488 * just be ignored.
1490 * We would not support "negotiating" of options on connection
1491 * primitives for Internet transports. However just in case we
1492 * forced to in order to pass strange test suites, the design here
1493 * tries to support these notions.
1495 * tpi_optcom_buf(q, mp, opt_lenp, opt_offset, cred, dbobjp, thisdg_attrs,
1496 * *is_absreq_failurep)
1498 * - Verify the option buffer, if formatted badly, return error 1
1500 * - If it is a "permissions" failure (read-only), return error 2
1502 * - Else, process the option "in place", the following can happen,
1503 * - if a "privileged" option, mark it as "ignored".
1504 * - if "not supported", mark "ignored"
1505 * - if "supported" attempt negotiation and fill result in
1506 * the outcome
1507 * - if "absolute requirement", set "*is_absreq_failurep"
1508 * - if NOT an "absolute requirement", then our
1509 * interpretation is to mark is at ignored if
1510 * negotiation fails (Spec allows partial success
1511 * as in OSI protocols but not failure)
1513 * Then delete "ignored" options from option buffer and return success.
1517 tpi_optcom_buf(queue_t *q, mblk_t *mp, t_scalar_t *opt_lenp,
1518 t_scalar_t opt_offset, cred_t *cr, optdb_obj_t *dbobjp,
1519 void *thisdg_attrs, int *is_absreq_failurep)
1521 opt_set_fn setfn = dbobjp->odb_setfn;
1522 opdes_t *opt_arr = dbobjp->odb_opt_des_arr;
1523 uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt;
1524 struct T_opthdr *opt, *opt_start, *opt_end;
1525 mblk_t *copy_mp_head;
1526 uchar_t *optr, *init_optr;
1527 opdes_t *optd;
1528 uint_t optset_context;
1529 t_uscalar_t olen;
1530 int error = 0;
1532 ASSERT((uchar_t *)opt_lenp > mp->b_rptr &&
1533 (uchar_t *)opt_lenp < mp->b_wptr);
1535 copy_mp_head = NULL;
1536 *is_absreq_failurep = 0;
1537 switch (((union T_primitives *)mp->b_rptr)->type) {
1538 case T_CONN_REQ:
1539 case T_CONN_RES:
1540 optset_context = SETFN_CONN_NEGOTIATE;
1541 break;
1542 case T_UNITDATA_REQ:
1543 optset_context = SETFN_UD_NEGOTIATE;
1544 break;
1545 default:
1547 * should never get here, all possible TPI primitives
1548 * where this can be called from should be accounted
1549 * for in the cases above
1551 return (EINVAL);
1554 if ((opt_start = (struct T_opthdr *)
1555 mi_offset_param(mp, opt_offset, *opt_lenp)) == NULL) {
1556 error = ENOPROTOOPT;
1557 goto error_ret;
1559 if (!__TPI_TOPT_ISALIGNED(opt_start)) {
1560 error = ENOPROTOOPT;
1561 goto error_ret;
1564 opt_end = (struct T_opthdr *)((uchar_t *)opt_start
1565 + *opt_lenp);
1567 if ((copy_mp_head = copyb(mp)) == NULL) {
1568 error = ENOMEM;
1569 goto error_ret;
1572 init_optr = optr = (uchar_t *)&copy_mp_head->b_rptr[opt_offset];
1574 for (opt = opt_start; opt && (opt < opt_end);
1575 opt = _TPI_TOPT_NEXTHDR(opt_start, *opt_lenp, opt)) {
1577 * Validate the option for length and alignment
1578 * before accessing anything in it
1580 if (!_TPI_TOPT_VALID(opt, opt_start, opt_end)) {
1581 error = ENOPROTOOPT;
1582 goto error_ret;
1585 /* Find the option in the opt_arr. */
1586 optd = proto_opt_lookup(opt->level, opt->name,
1587 opt_arr, opt_arr_cnt);
1589 if (optd == NULL) {
1591 * Option not found
1593 opt->status = T_NOTSUPPORT;
1594 continue;
1598 * Weird but as in XTI spec.
1599 * Sec 6.3.6 "Privileged and ReadOnly Options"
1600 * Permission problems (e.g.readonly) fail with bad access
1601 * BUT "privileged" option request from those NOT PRIVILEGED
1602 * are to be merely "ignored".
1603 * XXX Prevents "probing" of privileged options ?
1605 if (OA_READONLY_PERMISSION(optd, cr)) {
1606 error = EACCES;
1607 goto error_ret;
1609 if (OA_MATCHED_PRIV(optd, cr)) {
1611 * For privileged options, we DO perform
1612 * access checks as is common sense
1614 if (!OA_WX_ANYPRIV(optd)) {
1615 error = EACCES;
1616 goto error_ret;
1618 } else {
1620 * For non privileged, we fail instead following
1621 * "ignore" semantics dictated by XTI spec for
1622 * permissions problems.
1623 * Sec 6.3.6 "Privileged and ReadOnly Options"
1624 * XXX Should we do "ignore" semantics ?
1626 if (!OA_WX_NOPRIV(optd)) { /* nopriv */
1627 opt->status = T_FAILURE;
1628 continue;
1633 * If the negotiation fails, for options that
1634 * are "absolute requirement", it is a fatal error.
1635 * For options that are NOT "absolute requirements",
1636 * and the value fails to negotiate, the XTI spec
1637 * only considers the possibility of partial success
1638 * (T_PARTSUCCES - not likely for Internet protocols).
1639 * The spec is in denial about complete failure
1640 * (T_FAILURE) to negotiate for options that are
1641 * carried on T_CONN_REQ/T_CONN_RES/T_UNITDATA
1642 * We interpret the T_FAILURE to negotiate an option
1643 * that is NOT an absolute requirement that it is safe
1644 * to ignore it.
1647 /* verify length */
1648 if (opt->len < (t_uscalar_t)sizeof (struct T_opthdr) ||
1649 !opt_length_ok(optd, opt->len - sizeof (struct T_opthdr))) {
1650 /* bad size */
1651 if ((optd->opdes_props & OP_NOT_ABSREQ) == 0) {
1652 /* option is absolute requirement */
1653 *is_absreq_failurep = 1;
1654 error = EINVAL;
1655 goto error_ret;
1657 opt->status = T_FAILURE;
1658 continue;
1662 * verified generic attributes. Now call set function.
1663 * Note: We assume the following to simplify code.
1664 * XXX If this is found not to be valid, this routine
1665 * will need to be rewritten. At this point it would
1666 * be premature to introduce more complexity than is
1667 * needed.
1668 * Assumption: For variable length options, we assume
1669 * that the value returned will be same or less length
1670 * (size does not increase). This makes it OK to pass the
1671 * same space for output as it is on input.
1674 error = (*setfn)(q, optset_context, opt->level, opt->name,
1675 opt->len - (t_uscalar_t)sizeof (struct T_opthdr),
1676 _TPI_TOPT_DATA(opt), &olen, _TPI_TOPT_DATA(opt),
1677 thisdg_attrs, cr);
1679 if (olen > (int)(opt->len - sizeof (struct T_opthdr))) {
1681 * Space on output more than space on input. Should
1682 * not happen and we consider it a bug/error.
1683 * More of a restriction than an error in our
1684 * implementation. Will see if we can live with this
1685 * otherwise code will get more hairy with multiple
1686 * passes.
1688 error = EINVAL;
1689 goto error_ret;
1691 if (error != 0) {
1692 if ((optd->opdes_props & OP_NOT_ABSREQ) == 0) {
1693 /* option is absolute requirement. */
1694 *is_absreq_failurep = 1;
1695 goto error_ret;
1698 * failed - but option "not an absolute
1699 * requirement"
1701 opt->status = T_FAILURE;
1702 continue;
1705 * Fill in the only possible successful result
1706 * (Note: TPI allows for T_PARTSUCCESS - partial
1707 * sucess result code which is relevant in OSI world
1708 * and not possible in Internet code)
1710 opt->status = T_SUCCESS;
1713 * Add T_SUCCESS result code options to the "output" options.
1714 * No T_FAILURES or T_NOTSUPPORT here as they are to be
1715 * ignored.
1716 * This code assumes output option buffer will
1717 * be <= input option buffer.
1719 * Copy option header+value
1721 bcopy(opt, optr, opt->len);
1722 optr += _TPI_ALIGN_TOPT(opt->len);
1725 * Overwrite the input mblk option buffer now with the output
1726 * and update length, and contents in original mbl
1727 * (offset remains unchanged).
1729 *opt_lenp = (t_scalar_t)(optr - init_optr);
1730 if (*opt_lenp > 0) {
1731 bcopy(init_optr, opt_start, *opt_lenp);
1734 error_ret:
1735 if (copy_mp_head != NULL)
1736 freeb(copy_mp_head);
1737 return (error);
1740 static boolean_t
1741 opt_level_valid(t_uscalar_t level, optlevel_t *valid_level_arr,
1742 uint_t valid_level_arr_cnt)
1744 optlevel_t *olp;
1746 for (olp = valid_level_arr;
1747 olp < &valid_level_arr[valid_level_arr_cnt];
1748 olp++) {
1749 if (level == (uint_t)(*olp))
1750 return (B_TRUE);
1752 return (B_FALSE);
1757 * Compute largest possible size for an option buffer containing
1758 * all options in one buffer.
1760 * XXX TBD, investigate use of opt_bloated_maxsize() to avoid
1761 * wastefully large buffer allocation.
1763 static size_t
1764 opt_level_allopts_lengths(t_uscalar_t level, opdes_t *opt_arr,
1765 uint_t opt_arr_cnt)
1767 opdes_t *optd;
1768 size_t allopt_len = 0; /* 0 implies no option at this level */
1771 * Scan opt_arr computing aggregate length
1772 * requirement for storing values of all
1773 * options.
1774 * Note: we do not filter for permissions
1775 * etc. This will be >= the real aggregate
1776 * length required (upper bound).
1779 for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt];
1780 optd++) {
1781 if (level == optd->opdes_level) {
1782 allopt_len += sizeof (struct T_opthdr) +
1783 _TPI_ALIGN_TOPT(optd->opdes_size);
1786 return (allopt_len); /* 0 implies level not found */
1790 * Compute largest possible size for an option buffer containing
1791 * all options in one buffer - a (theoretical?) worst case scenario
1792 * for certain cases.
1794 t_uscalar_t
1795 optcom_max_optbuf_len(opdes_t *opt_arr, uint_t opt_arr_cnt)
1797 t_uscalar_t max_optbuf_len = sizeof (struct T_info_ack);
1798 opdes_t *optd;
1800 for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) {
1801 max_optbuf_len += (t_uscalar_t)sizeof (struct T_opthdr) +
1802 (t_uscalar_t)_TPI_ALIGN_TOPT(optd->opdes_size);
1804 return (max_optbuf_len);
1808 * Compute largest possible size for OPT_size for a transport.
1809 * Heuristic used is to add all but certain extremely large
1810 * size options; this is done by calling opt_bloated_maxsize().
1811 * It affects user level allocations in TLI/XTI code using t_alloc()
1812 * and other TLI/XTI implementation instance strucutures.
1813 * The large size options excluded are presumed to be
1814 * never accessed through the (theoretical?) worst case code paths
1815 * through TLI/XTI as they are currently IPv6 specific options.
1818 t_uscalar_t
1819 optcom_max_optsize(opdes_t *opt_arr, uint_t opt_arr_cnt)
1821 t_uscalar_t max_optbuf_len = sizeof (struct T_info_ack);
1822 opdes_t *optd;
1824 for (optd = opt_arr; optd < &opt_arr[opt_arr_cnt]; optd++) {
1825 if (!opt_bloated_maxsize(optd)) {
1826 max_optbuf_len +=
1827 (t_uscalar_t)sizeof (struct T_opthdr) +
1828 (t_uscalar_t)_TPI_ALIGN_TOPT(optd->opdes_size);
1831 return (max_optbuf_len);
1835 * The theoretical model used in optcom_max_optsize() and
1836 * opt_level_allopts_lengths() accounts for the worst case of all
1837 * possible options for the theoretical cases and results in wasteful
1838 * memory allocations for certain theoretically correct usage scenarios.
1839 * In practice, the "features" they support are rarely, if ever,
1840 * used and even then only by test suites for those features (VSU, VST).
1841 * However, they result in large allocations due to the increased transport
1842 * T_INFO_ACK OPT_size field affecting t_alloc() users and TLI/XTI library
1843 * instance data structures for applications.
1845 * The following routine opt_bloated_maxsize() supports a hack that avoids
1846 * paying the tax for the bloated options by excluding them and pretending
1847 * they don't exist for certain features without affecting features that
1848 * do use them.
1850 * XXX Currently implemented only for optcom_max_optsize()
1851 * (to reduce risk late in release).
1852 * TBD for future, investigate use in optcom_level_allopts_lengths() and
1853 * all the instances of T_ALLOPT processing to exclude "bloated options".
1854 * Will not affect VSU/VST tests as they do not test with IPPROTO_IPV6
1855 * level options which are the only ones that fit the "bloated maxsize"
1856 * option profile now.
1858 static boolean_t
1859 opt_bloated_maxsize(opdes_t *optd)
1861 if (optd->opdes_level != IPPROTO_IPV6)
1862 return (B_FALSE);
1863 switch (optd->opdes_name) {
1864 case IPV6_HOPOPTS:
1865 case IPV6_DSTOPTS:
1866 case IPV6_RTHDRDSTOPTS:
1867 case IPV6_RTHDR:
1868 case IPV6_PATHMTU:
1869 return (B_TRUE);
1870 default:
1871 break;
1873 return (B_FALSE);
1877 * optlen is the length of the option content
1878 * Caller should check the optlen is at least sizeof (struct T_opthdr)
1880 static boolean_t
1881 opt_length_ok(opdes_t *optd, t_uscalar_t optlen)
1884 * Verify length.
1885 * Value specified should match length of fixed length option or be
1886 * less than maxlen of variable length option.
1888 if (optd->opdes_props & OP_VARLEN) {
1889 if (optlen <= optd->opdes_size)
1890 return (B_TRUE);
1891 } else {
1892 /* fixed length option */
1893 if (optlen == optd->opdes_size)
1894 return (B_TRUE);
1896 return (B_FALSE);
1900 * This routine manages the allocation and free of the space for
1901 * an extension header or option. Returns failure if memory
1902 * can not be allocated.
1905 optcom_pkt_set(uchar_t *invalp, uint_t inlen,
1906 uchar_t **optbufp, uint_t *optlenp)
1908 uchar_t *optbuf;
1909 uchar_t *optp;
1911 if (inlen == *optlenp) {
1912 /* Unchanged length - no need to reallocate */
1913 optp = *optbufp;
1914 bcopy(invalp, optp, inlen);
1915 return (0);
1917 if (inlen > 0) {
1918 /* Allocate new buffer before free */
1919 optbuf = kmem_alloc(inlen, KM_NOSLEEP);
1920 if (optbuf == NULL)
1921 return (ENOMEM);
1922 } else {
1923 optbuf = NULL;
1926 /* Free old buffer */
1927 if (*optlenp != 0)
1928 kmem_free(*optbufp, *optlenp);
1930 if (inlen > 0)
1931 bcopy(invalp, optbuf, inlen);
1933 *optbufp = optbuf;
1934 *optlenp = inlen;
1935 return (0);
1939 process_auxiliary_options(conn_t *connp, void *control, t_uscalar_t controllen,
1940 void *optbuf, optdb_obj_t *dbobjp, int (*opt_set_fn)(conn_t *,
1941 uint_t, int, int, uint_t, uchar_t *, uint_t *, uchar_t *, void *, cred_t *),
1942 cred_t *cr)
1944 struct cmsghdr *cmsg;
1945 opdes_t *optd;
1946 t_uscalar_t outlen;
1947 int error = EOPNOTSUPP;
1948 t_uscalar_t len;
1949 uint_t opt_arr_cnt = dbobjp->odb_opt_arr_cnt;
1950 opdes_t *opt_arr = dbobjp->odb_opt_des_arr;
1952 for (cmsg = (struct cmsghdr *)control;
1953 CMSG_VALID(cmsg, control, (uintptr_t)control + controllen);
1954 cmsg = CMSG_NEXT(cmsg)) {
1956 len = (t_uscalar_t)CMSG_CONTENTLEN(cmsg);
1957 /* Find the option in the opt_arr. */
1958 optd = proto_opt_lookup(cmsg->cmsg_level, cmsg->cmsg_type,
1959 opt_arr, opt_arr_cnt);
1960 if (optd == NULL) {
1961 return (EINVAL);
1963 if (OA_READONLY_PERMISSION(optd, cr)) {
1964 return (EACCES);
1966 if (OA_MATCHED_PRIV(optd, cr)) {
1968 * For privileged options, we DO perform
1969 * access checks as is common sense
1971 if (!OA_WX_ANYPRIV(optd)) {
1972 return (EACCES);
1974 } else {
1976 * For non privileged, we fail instead following
1977 * "ignore" semantics dictated by XTI spec for
1978 * permissions problems.
1980 if (!OA_WX_NOPRIV(optd)) { /* nopriv */
1981 return (EACCES);
1984 error = opt_set_fn(connp, SETFN_UD_NEGOTIATE, optd->opdes_level,
1985 optd->opdes_name, len, (uchar_t *)CMSG_CONTENT(cmsg),
1986 &outlen, (uchar_t *)CMSG_CONTENT(cmsg), optbuf, cr);
1987 if (error > 0) {
1988 return (error);
1989 } else if (outlen > len) {
1990 return (EINVAL);
1991 } else {
1993 * error can be -ve if the protocol wants to
1994 * pass the option to IP. We donot pass auxiliary
1995 * options to IP.
1997 error = 0;
2000 return (error);