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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 24 /* All Rights Reserved */ 25 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #include "mt.h" 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <sys/stream.h> 37 #define _SUN_TPI_VERSION 2 38 #include <sys/tihdr.h> 39 #include <sys/timod.h> 40 #include <xti.h> 41 #include <signal.h> 42 #include <syslog.h> 43 #include <stropts.h> 44 #include "tx.h" 45 46 /* 47 * The following is based on XTI standard. 48 */ 49 #define ALIGN_XTI_opthdr_size (sizeof (t_uscalar_t)) 50 51 #define ROUNDUP_XTI_opthdr(p) (((p) +\ 52 (ALIGN_XTI_opthdr_size-1)) & ~(ALIGN_XTI_opthdr_size-1)) 53 #define ISALIGNED_XTI_opthdr(p) \ 54 (((ulong_t)(p) & (ALIGN_XTI_opthdr_size - 1)) == 0) 55 56 int 57 _tx_optmgmt( 58 int fd, 59 const struct t_optmgmt *req, 60 struct t_optmgmt *ret, 61 int api_semantics 62 ) 63 { 64 int size, sv_errno; 65 struct strbuf ctlbuf; 66 struct T_optmgmt_req *optreq; 67 struct T_optmgmt_ack *optack; 68 struct _ti_user *tiptr; 69 sigset_t mask; 70 int didalloc, retlen; 71 struct t_opthdr *opt, *next_opt; 72 struct t_opthdr *opt_start, *opt_end; 73 t_uscalar_t first_opt_level; 74 t_scalar_t optlen; 75 76 if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL) 77 return (-1); 78 79 /* 80 * We block all signals during the TI_OPTMGMT operation 81 * as option change being done could potentially be a 82 * non-idempotent operation. 83 * Note that sig_mutex_lock() only defers signals, it does not 84 * block them, so interruptible syscalls could still get EINTR. 85 */ 86 (void) thr_sigsetmask(SIG_SETMASK, &fillset, &mask); 87 sig_mutex_lock(&tiptr->ti_lock); 88 89 /* 90 * Acquire buf for use in sending/receiving of the message. 91 * Note: assumes (correctly) that ti_ctlsize is large enough 92 * to hold sizeof (struct T_bind_req) 93 */ 94 if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) { 95 sv_errno = errno; 96 sig_mutex_unlock(&tiptr->ti_lock); 97 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 98 errno = sv_errno; 99 return (-1); 100 } 101 102 /* 103 * effective option length in local variable "optlen" 104 * Note: can change for XTI for T_ALLOPT. XTI spec states 105 * that options after the T_ALLOPT option are to be ignored 106 * therefore we trncate the option buffer there and modify 107 * the effective length accordingly later. 108 */ 109 optlen = req->opt.len; 110 111 if (_T_IS_XTI(api_semantics) && (optlen > 0)) { 112 /* 113 * Verify integrity of option buffer according to 114 * XTI t_optmgmt() semantics. 115 */ 116 117 if (req->opt.buf == NULL || 118 optlen < (t_scalar_t)sizeof (struct t_opthdr)) { 119 /* option buffer should atleast have an t_opthdr */ 120 t_errno = TBADOPT; 121 goto err_out; 122 } 123 124 /* LINTED pointer cast */ 125 opt_start = (struct t_opthdr *)req->opt.buf; 126 127 /* 128 * XXX We interpret that an option has to start on an 129 * aligned buffer boundary. This is not very explcit in 130 * XTI spec in text but the picture in Section 6.2 shows 131 * "opt.buf" at start of buffer and in combination with 132 * text can be construed to be restricting it to start 133 * on an aligned boundary. [Whether similar restriction 134 * applies to output buffer "ret->opt.buf" is an "interesting 135 * question" but we ignore it for now as that is the problem 136 * for the application not our implementation which will 137 * does not enforce any alignment requirement.] 138 * 139 * If start of buffer is not aligned, we signal an error. 140 */ 141 if (!(ISALIGNED_XTI_opthdr(opt_start))) { 142 t_errno = TBADOPT; 143 goto err_out; 144 } 145 146 /* LINTED pointer cast */ 147 opt_end = (struct t_opthdr *)((char *)opt_start + 148 optlen); 149 150 /* 151 * Make sure we have enough in the message to dereference 152 * the option header. 153 */ 154 if ((uchar_t *)opt_start + sizeof (struct t_opthdr) 155 > (uchar_t *)opt_end) { 156 t_errno = TBADOPT; 157 goto err_out; 158 } 159 /* 160 * If there are multiple options, they all have to be 161 * the same level (so says XTI semantics). 162 */ 163 first_opt_level = opt_start->level; 164 165 for (opt = opt_start; opt < opt_end; opt = next_opt) { 166 /* 167 * Make sure we have enough in the message to 168 * dereference the option header. 169 */ 170 if ((uchar_t *)opt_start + sizeof (struct t_opthdr) 171 > (uchar_t *)opt_end) { 172 t_errno = TBADOPT; 173 goto err_out; 174 } 175 /* 176 * We now compute pointer to next option in buffer 177 * 'next_opt' the next_opt computation above below 178 * 'opt->len' initialized by application which cannot 179 * be trusted. The usual value too large will be 180 * captured by the loop termination condition above. 181 * We check for the following which it will miss. 182 * (1)pointer space wraparound arithmetic overflow 183 * (2)last option in buffer with 'opt->len' being 184 * too large 185 * (only reason 'next_opt' should equal or exceed 186 * 'opt_end' for last option is roundup unless 187 * length is too-large/invalid) 188 * (3) we also enforce the XTI restriction that 189 * all options in the buffer have to be the 190 * same level. 191 */ 192 /* LINTED pointer cast */ 193 next_opt = (struct t_opthdr *)((uchar_t *)opt + 194 ROUNDUP_XTI_opthdr(opt->len)); 195 196 if ((uchar_t *)next_opt < (uchar_t *)opt || /* (1) */ 197 ((next_opt >= opt_end) && 198 (((uchar_t *)next_opt - (uchar_t *)opt_end) >= 199 ALIGN_XTI_opthdr_size)) || /* (2) */ 200 (opt->level != first_opt_level)) { /* (3) */ 201 t_errno = TBADOPT; 202 goto err_out; 203 } 204 205 /* 206 * XTI semantics: options in the buffer after 207 * the T_ALLOPT option can be ignored 208 */ 209 if (opt->name == T_ALLOPT) { 210 if (next_opt < opt_end) { 211 /* 212 * there are options following, ignore 213 * them and truncate input 214 */ 215 optlen = (t_scalar_t)((uchar_t *) 216 next_opt - (uchar_t *)opt_start); 217 opt_end = next_opt; 218 } 219 } 220 } 221 } 222 223 /* LINTED pointer cast */ 224 optreq = (struct T_optmgmt_req *)ctlbuf.buf; 225 if (_T_IS_XTI(api_semantics)) 226 optreq->PRIM_type = T_OPTMGMT_REQ; 227 else 228 optreq->PRIM_type = T_SVR4_OPTMGMT_REQ; 229 230 optreq->OPT_length = optlen; 231 optreq->OPT_offset = 0; 232 optreq->MGMT_flags = req->flags; 233 size = (int)sizeof (struct T_optmgmt_req); 234 235 if (optlen) { 236 if (_t_aligned_copy(&ctlbuf, optlen, size, 237 req->opt.buf, &optreq->OPT_offset) < 0) { 238 /* 239 * Aligned copy will overflow buffer allocated 240 * based on maximum transport option size information 241 */ 242 t_errno = TBADOPT; 243 goto err_out; 244 } 245 size = optreq->OPT_offset + optreq->OPT_length; 246 } 247 248 if (_t_do_ioctl(fd, ctlbuf.buf, size, TI_OPTMGMT, &retlen) < 0) 249 goto err_out; 250 251 if (retlen < (int)sizeof (struct T_optmgmt_ack)) { 252 t_errno = TSYSERR; 253 errno = EIO; 254 goto err_out; 255 } 256 257 /* LINTED pointer cast */ 258 optack = (struct T_optmgmt_ack *)ctlbuf.buf; 259 260 if (_T_IS_TLI(api_semantics) || ret->opt.maxlen > 0) { 261 if (TLEN_GT_NLEN(optack->OPT_length, ret->opt.maxlen)) { 262 t_errno = TBUFOVFLW; 263 goto err_out; 264 } 265 (void) memcpy(ret->opt.buf, 266 (char *)(ctlbuf.buf + optack->OPT_offset), 267 (unsigned int) optack->OPT_length); 268 ret->opt.len = optack->OPT_length; 269 } 270 271 /* 272 * Note: TPI is not clear about what really is carries in the 273 * T_OPTMGMT_ACK MGMT_flags fields. For T_OPTMGMT_ACK in response 274 * to T_SVR4_OPTMGMT_REQ, the Internet protocols in Solaris 2.X return 275 * the result code only (T_SUCCESS). For T_OPTMGMT_ACK in response 276 * to T_OPTMGMT_REQ, currently "worst status" code required for 277 * XTI is carried from the set of options OR'd with request flag. 278 * (This can change in future and "worst status" computation done 279 * with a scan in this routine. 280 * 281 * Note: Even for T_OPTMGMT_ACK is response to T_SVR4_OPTMGMT_REQ, 282 * removing request flag should be OK though it will not be set. 283 */ 284 ret->flags = optack->MGMT_flags & ~req->flags; 285 286 /* 287 * NOTE: 288 * There is no real change of state in state table for option 289 * management. The state change macro is used below only for its 290 * debugging and logging capabilities. 291 * The TLI "(mis)feature" (option management only in T_IDLE state) 292 * has been deprecated in XTI and our state table reflect updated for 293 * both TLI and XTI to reflect that. 294 * TLI semantics can be enforced by the transport providers that 295 * desire it at TPI level. 296 * There is no need to enforce this in the library since 297 * sane transport providers that do allow it (e.g TCP and it *needs* 298 * to allow it) should be allowed to work fine. 299 * The only transport providers that return TOUTSTATE for TLI 300 * t_optmgmt() are the drivers used for conformance testing to the 301 * broken TLI standard. 302 * These are /dev/{ticots,ticotsord,ticlts} used by the Sparc ABI test 303 * suite. Others are /dev/{tivc,tidg} used by the SVVS test suite. 304 */ 305 306 _T_TX_NEXTSTATE(T_OPTMGMT, tiptr, 307 "t_optmgmt: invalid state event T_OPTMGMT"); 308 309 if (didalloc) 310 free(ctlbuf.buf); 311 else 312 tiptr->ti_ctlbuf = ctlbuf.buf; 313 sig_mutex_unlock(&tiptr->ti_lock); 314 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 315 return (0); 316 /* NOTREACHED */ 317 318 err_out: 319 sv_errno = errno; 320 if (didalloc) 321 free(ctlbuf.buf); 322 else 323 tiptr->ti_ctlbuf = ctlbuf.buf; 324 sig_mutex_unlock(&tiptr->ti_lock); 325 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 326 errno = sv_errno; 327 return (-1); 328 } 329