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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 /* 26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 /* 30 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 31 */ 32 33 #include "mt.h" 34 #include <stdlib.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <unistd.h> 38 #include <errno.h> 39 #include <stropts.h> 40 #include <sys/stream.h> 41 #define _SUN_TPI_VERSION 2 42 #include <sys/tihdr.h> 43 #include <sys/timod.h> 44 #include <sys/stat.h> 45 #include <xti.h> 46 #include <fcntl.h> 47 #include <signal.h> 48 #include <assert.h> 49 #include <syslog.h> 50 #include <limits.h> 51 #include <ucred.h> 52 #include "tx.h" 53 54 #define DEFSIZE 2048 55 56 /* 57 * The following used to be in tiuser.h, but was causing too much namespace 58 * pollution. 59 */ 60 #define ROUNDUP32(X) ((X + 0x03)&~0x03) 61 62 static struct _ti_user *find_tilink(int s); 63 static struct _ti_user *add_tilink(int s); 64 static void _t_free_lookbufs(struct _ti_user *tiptr); 65 static unsigned int _t_setsize(t_scalar_t infosize, boolean_t option); 66 static int _t_cbuf_alloc(struct _ti_user *tiptr, char **retbuf); 67 static int _t_rbuf_alloc(struct _ti_user *tiptr, char **retbuf); 68 static int _t_adjust_state(int fd, int instate); 69 static int _t_alloc_bufs(int fd, struct _ti_user *tiptr, 70 struct T_info_ack *tsap); 71 72 mutex_t _ti_userlock = DEFAULTMUTEX; /* Protects hash_bucket[] */ 73 74 /* 75 * Checkfd - checks validity of file descriptor 76 */ 77 struct _ti_user * 78 _t_checkfd(int fd, int force_sync, int api_semantics) 79 { 80 sigset_t mask; 81 struct _ti_user *tiptr; 82 int retval, timodpushed; 83 84 if (fd < 0) { 85 t_errno = TBADF; 86 return (NULL); 87 } 88 89 if (!force_sync) { 90 sig_mutex_lock(&_ti_userlock); 91 tiptr = find_tilink(fd); 92 sig_mutex_unlock(&_ti_userlock); 93 if (tiptr != NULL) 94 return (tiptr); 95 } 96 97 /* 98 * Not found or a forced sync is required. 99 * check if this is a valid TLI/XTI descriptor. 100 */ 101 timodpushed = 0; 102 do { 103 retval = ioctl(fd, I_FIND, "timod"); 104 } while (retval < 0 && errno == EINTR); 105 106 if (retval < 0 || (retval == 0 && _T_IS_TLI(api_semantics))) { 107 /* 108 * not a stream or a TLI endpoint with no timod 109 * XXX Note: If it is a XTI call, we push "timod" and 110 * try to convert it into a transport endpoint later. 111 * We do not do it for TLI and "retain" the old buggy 112 * behavior because ypbind and a lot of other deamons seem 113 * to use a buggy logic test of the form 114 * "(t_getstate(0) != -1 || t_errno != TBADF)" to see if 115 * they we ever invoked with request on stdin and drop into 116 * untested code. This test is in code generated by rpcgen 117 * which is why it is replicated test in many daemons too. 118 * We will need to fix that test too with "IsaTLIendpoint" 119 * test if we ever fix this for TLI 120 */ 121 t_errno = TBADF; 122 return (NULL); 123 } 124 125 if (retval == 0) { 126 /* 127 * "timod" not already on stream, then push it 128 */ 129 do { 130 /* 131 * Assumes (correctly) that I_PUSH is 132 * atomic w.r.t signals (EINTR error) 133 */ 134 retval = ioctl(fd, I_PUSH, "timod"); 135 } while (retval < 0 && errno == EINTR); 136 137 if (retval < 0) { 138 t_errno = TSYSERR; 139 return (NULL); 140 } 141 timodpushed = 1; 142 } 143 /* 144 * Try to (re)constitute the info at user level from state 145 * in the kernel. This could be information that lost due 146 * to an exec or being instantiated at a new descriptor due 147 * to , open(), dup2() etc. 148 * 149 * _t_create() requires that all signals be blocked. 150 * Note that sig_mutex_lock() only defers signals, it does not 151 * block them, so interruptible syscalls could still get EINTR. 152 */ 153 (void) thr_sigsetmask(SIG_SETMASK, &fillset, &mask); 154 sig_mutex_lock(&_ti_userlock); 155 tiptr = _t_create(fd, NULL, api_semantics, NULL); 156 if (tiptr == NULL) { 157 int sv_errno = errno; 158 sig_mutex_unlock(&_ti_userlock); 159 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 160 /* 161 * restore to stream before timod pushed. It may 162 * not have been a network transport stream. 163 */ 164 if (timodpushed) 165 (void) ioctl(fd, I_POP, 0); 166 errno = sv_errno; 167 return (NULL); 168 } 169 sig_mutex_unlock(&_ti_userlock); 170 (void) thr_sigsetmask(SIG_SETMASK, &mask, NULL); 171 return (tiptr); 172 } 173 174 /* 175 * copy data to output buffer making sure the output buffer is 32 bit 176 * aligned, even though the input buffer may not be. 177 */ 178 int 179 _t_aligned_copy( 180 struct strbuf *strbufp, 181 int len, 182 int init_offset, 183 char *datap, 184 t_scalar_t *rtn_offset) 185 { 186 *rtn_offset = ROUNDUP32(init_offset); 187 if ((*rtn_offset + len) > strbufp->maxlen) { 188 /* 189 * Aligned copy will overflow buffer 190 */ 191 return (-1); 192 } 193 (void) memcpy(strbufp->buf + *rtn_offset, datap, (size_t)len); 194 195 return (0); 196 } 197 198 199 /* 200 * append data and control info in look buffer (list in the MT case) 201 * 202 * The only thing that can be in look buffer is a T_DISCON_IND, 203 * T_ORDREL_IND or a T_UDERROR_IND. 204 * 205 * It also enforces priority of T_DISCONDs over any T_ORDREL_IND 206 * already in the buffer. It assumes no T_ORDREL_IND is appended 207 * when there is already something on the looklist (error case) and 208 * that a T_ORDREL_IND if present will always be the first on the 209 * list. 210 * 211 * This also assumes ti_lock is held via sig_mutex_lock(), 212 * so signals are deferred here. 213 */ 214 int 215 _t_register_lookevent( 216 struct _ti_user *tiptr, 217 caddr_t dptr, 218 int dsize, 219 caddr_t cptr, 220 int csize) 221 { 222 struct _ti_lookbufs *tlbs; 223 int cbuf_size, dbuf_size; 224 225 assert(MUTEX_HELD(&tiptr->ti_lock)); 226 227 cbuf_size = tiptr->ti_ctlsize; 228 dbuf_size = tiptr->ti_rcvsize; 229 230 if ((csize > cbuf_size) || dsize > dbuf_size) { 231 /* can't fit - return error */ 232 return (-1); /* error */ 233 } 234 /* 235 * Enforce priority of T_DISCON_IND over T_ORDREL_IND 236 * queued earlier. 237 * Note: Since there can be only at most one T_ORDREL_IND 238 * queued (more than one is error case), and we look for it 239 * on each append of T_DISCON_IND, it can only be at the 240 * head of the list if it is there. 241 */ 242 if (tiptr->ti_lookcnt > 0) { /* something already on looklist */ 243 if (cptr && csize >= (int)sizeof (struct T_discon_ind) && 244 /* LINTED pointer cast */ 245 *(t_scalar_t *)cptr == T_DISCON_IND) { 246 /* appending discon ind */ 247 assert(tiptr->ti_servtype != T_CLTS); 248 /* LINTED pointer cast */ 249 if (*(t_scalar_t *)tiptr->ti_lookbufs.tl_lookcbuf == 250 T_ORDREL_IND) { /* T_ORDREL_IND is on list */ 251 /* 252 * Blow away T_ORDREL_IND 253 */ 254 _t_free_looklist_head(tiptr); 255 } 256 } 257 } 258 tlbs = &tiptr->ti_lookbufs; 259 if (tiptr->ti_lookcnt > 0) { 260 int listcount = 0; 261 /* 262 * Allocate and append a new lookbuf to the 263 * existing list. (Should only happen in MT case) 264 */ 265 while (tlbs->tl_next != NULL) { 266 listcount++; 267 tlbs = tlbs->tl_next; 268 } 269 assert(tiptr->ti_lookcnt == listcount); 270 271 /* 272 * signals are deferred, calls to malloc() are safe. 273 */ 274 if ((tlbs->tl_next = malloc(sizeof (struct _ti_lookbufs))) == 275 NULL) 276 return (-1); /* error */ 277 tlbs = tlbs->tl_next; 278 /* 279 * Allocate the buffers. The sizes derived from the 280 * sizes of other related buffers. See _t_alloc_bufs() 281 * for details. 282 */ 283 if ((tlbs->tl_lookcbuf = malloc(cbuf_size)) == NULL) { 284 /* giving up - free other memory chunks */ 285 free(tlbs); 286 return (-1); /* error */ 287 } 288 if ((dsize > 0) && 289 ((tlbs->tl_lookdbuf = malloc(dbuf_size)) == NULL)) { 290 /* giving up - free other memory chunks */ 291 free(tlbs->tl_lookcbuf); 292 free(tlbs); 293 return (-1); /* error */ 294 } 295 } 296 297 (void) memcpy(tlbs->tl_lookcbuf, cptr, csize); 298 if (dsize > 0) 299 (void) memcpy(tlbs->tl_lookdbuf, dptr, dsize); 300 tlbs->tl_lookdlen = dsize; 301 tlbs->tl_lookclen = csize; 302 tlbs->tl_next = NULL; 303 tiptr->ti_lookcnt++; 304 return (0); /* ok return */ 305 } 306 307 /* 308 * Is there something that needs attention? 309 * Assumes tiptr->ti_lock held and this threads signals blocked 310 * in MT case. 311 */ 312 int 313 _t_is_event(int fd, struct _ti_user *tiptr) 314 { 315 int size, retval; 316 317 assert(MUTEX_HELD(&tiptr->ti_lock)); 318 if ((retval = ioctl(fd, I_NREAD, &size)) < 0) { 319 t_errno = TSYSERR; 320 return (-1); 321 } 322 323 if ((retval > 0) || (tiptr->ti_lookcnt > 0)) { 324 t_errno = TLOOK; 325 return (-1); 326 } 327 return (0); 328 } 329 330 /* 331 * wait for T_OK_ACK 332 * assumes tiptr->ti_lock held in MT case 333 */ 334 int 335 _t_is_ok(int fd, struct _ti_user *tiptr, t_scalar_t type) 336 { 337 struct strbuf ctlbuf; 338 struct strbuf databuf; 339 union T_primitives *pptr; 340 int retval, cntlflag; 341 int size; 342 int didalloc, didralloc; 343 int flags = 0; 344 345 assert(MUTEX_HELD(&tiptr->ti_lock)); 346 /* 347 * Acquire ctlbuf for use in sending/receiving control part 348 * of the message. 349 */ 350 if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0) 351 return (-1); 352 /* 353 * Acquire databuf for use in sending/receiving data part 354 */ 355 if (_t_acquire_databuf(tiptr, &databuf, &didralloc) < 0) { 356 if (didalloc) 357 free(ctlbuf.buf); 358 else 359 tiptr->ti_ctlbuf = ctlbuf.buf; 360 return (-1); 361 } 362 363 /* 364 * Temporarily convert a non blocking endpoint to a 365 * blocking one and restore status later 366 */ 367 cntlflag = fcntl(fd, F_GETFL, 0); 368 if (cntlflag & (O_NDELAY | O_NONBLOCK)) 369 (void) fcntl(fd, F_SETFL, cntlflag & ~(O_NDELAY | O_NONBLOCK)); 370 371 flags = RS_HIPRI; 372 373 while ((retval = getmsg(fd, &ctlbuf, &databuf, &flags)) < 0) { 374 if (errno == EINTR) 375 continue; 376 if (cntlflag & (O_NDELAY | O_NONBLOCK)) 377 (void) fcntl(fd, F_SETFL, cntlflag); 378 t_errno = TSYSERR; 379 goto err_out; 380 } 381 382 /* did I get entire message */ 383 if (retval > 0) { 384 if (cntlflag & (O_NDELAY | O_NONBLOCK)) 385 (void) fcntl(fd, F_SETFL, cntlflag); 386 t_errno = TSYSERR; 387 errno = EIO; 388 goto err_out; 389 } 390 391 /* 392 * is ctl part large enough to determine type? 393 */ 394 if (ctlbuf.len < (int)sizeof (t_scalar_t)) { 395 if (cntlflag & (O_NDELAY | O_NONBLOCK)) 396 (void) fcntl(fd, F_SETFL, cntlflag); 397 t_errno = TSYSERR; 398 errno = EPROTO; 399 goto err_out; 400 } 401 402 if (cntlflag & (O_NDELAY | O_NONBLOCK)) 403 (void) fcntl(fd, F_SETFL, cntlflag); 404 405 /* LINTED pointer cast */ 406 pptr = (union T_primitives *)ctlbuf.buf; 407 408 switch (pptr->type) { 409 case T_OK_ACK: 410 if ((ctlbuf.len < (int)sizeof (struct T_ok_ack)) || 411 (pptr->ok_ack.CORRECT_prim != type)) { 412 t_errno = TSYSERR; 413 errno = EPROTO; 414 goto err_out; 415 } 416 if (didalloc) 417 free(ctlbuf.buf); 418 else 419 tiptr->ti_ctlbuf = ctlbuf.buf; 420 if (didralloc) 421 free(databuf.buf); 422 else 423 tiptr->ti_rcvbuf = databuf.buf; 424 return (0); 425 426 case T_ERROR_ACK: 427 if ((ctlbuf.len < (int)sizeof (struct T_error_ack)) || 428 (pptr->error_ack.ERROR_prim != type)) { 429 t_errno = TSYSERR; 430 errno = EPROTO; 431 goto err_out; 432 } 433 /* 434 * if error is out of state and there is something 435 * on read queue, then indicate to user that 436 * there is something that needs attention 437 */ 438 if (pptr->error_ack.TLI_error == TOUTSTATE) { 439 if ((retval = ioctl(fd, I_NREAD, &size)) < 0) { 440 t_errno = TSYSERR; 441 goto err_out; 442 } 443 if (retval > 0) 444 t_errno = TLOOK; 445 else 446 t_errno = TOUTSTATE; 447 } else { 448 t_errno = pptr->error_ack.TLI_error; 449 if (t_errno == TSYSERR) 450 errno = pptr->error_ack.UNIX_error; 451 } 452 goto err_out; 453 default: 454 t_errno = TSYSERR; 455 errno = EPROTO; 456 /* fallthru to err_out: */ 457 } 458 err_out: 459 if (didalloc) 460 free(ctlbuf.buf); 461 else 462 tiptr->ti_ctlbuf = ctlbuf.buf; 463 if (didralloc) 464 free(databuf.buf); 465 else 466 tiptr->ti_rcvbuf = databuf.buf; 467 return (-1); 468 } 469 470 /* 471 * timod ioctl 472 */ 473 int 474 _t_do_ioctl(int fd, char *buf, int size, int cmd, int *retlenp) 475 { 476 int retval; 477 struct strioctl strioc; 478 479 strioc.ic_cmd = cmd; 480 strioc.ic_timout = -1; 481 strioc.ic_len = size; 482 strioc.ic_dp = buf; 483 484 if ((retval = ioctl(fd, I_STR, &strioc)) < 0) { 485 t_errno = TSYSERR; 486 return (-1); 487 } 488 489 if (retval > 0) { 490 t_errno = retval & 0xff; 491 if (t_errno == TSYSERR) 492 errno = (retval >> 8) & 0xff; 493 return (-1); 494 } 495 if (retlenp) 496 *retlenp = strioc.ic_len; 497 return (0); 498 } 499 500 /* 501 * alloc scratch buffers and look buffers 502 */ 503 /* ARGSUSED */ 504 static int 505 _t_alloc_bufs(int fd, struct _ti_user *tiptr, struct T_info_ack *tsap) 506 { 507 unsigned int size1, size2; 508 t_scalar_t optsize; 509 unsigned int csize, dsize, asize, osize; 510 char *ctlbuf, *rcvbuf; 511 char *lookdbuf, *lookcbuf; 512 513 csize = _t_setsize(tsap->CDATA_size, B_FALSE); 514 dsize = _t_setsize(tsap->DDATA_size, B_FALSE); 515 516 size1 = _T_MAX(csize, dsize); 517 518 if (size1 != 0) { 519 if ((rcvbuf = malloc(size1)) == NULL) 520 return (-1); 521 if ((lookdbuf = malloc(size1)) == NULL) { 522 free(rcvbuf); 523 return (-1); 524 } 525 } else { 526 rcvbuf = NULL; 527 lookdbuf = NULL; 528 } 529 530 asize = _t_setsize(tsap->ADDR_size, B_FALSE); 531 if (tsap->OPT_size >= 0) 532 /* compensate for XTI level options */ 533 optsize = tsap->OPT_size + TX_XTI_LEVEL_MAX_OPTBUF; 534 else 535 optsize = tsap->OPT_size; 536 osize = _t_setsize(optsize, B_TRUE); 537 538 /* 539 * We compute the largest buffer size needed for this provider by 540 * adding the components. [ An extra sizeof (t_scalar_t) is added to 541 * take care of rounding off for alignment) for each buffer ] 542 * The goal here is compute the size of largest possible buffer that 543 * might be needed to hold a TPI message for the transport provider 544 * on this endpoint. 545 * Note: T_ADDR_ACK contains potentially two address buffers. 546 */ 547 548 size2 = (unsigned int)sizeof (union T_primitives) /* TPI struct */ 549 + asize + (unsigned int)sizeof (t_scalar_t) + 550 /* first addr buffer plus alignment */ 551 asize + (unsigned int)sizeof (t_scalar_t) + 552 /* second addr buffer plus ailignment */ 553 osize + (unsigned int)sizeof (t_scalar_t); 554 /* option buffer plus alignment */ 555 556 if ((ctlbuf = malloc(size2)) == NULL) { 557 if (size1 != 0) { 558 free(rcvbuf); 559 free(lookdbuf); 560 } 561 return (-1); 562 } 563 564 if ((lookcbuf = malloc(size2)) == NULL) { 565 if (size1 != 0) { 566 free(rcvbuf); 567 free(lookdbuf); 568 } 569 free(ctlbuf); 570 return (-1); 571 } 572 573 tiptr->ti_rcvsize = size1; 574 tiptr->ti_rcvbuf = rcvbuf; 575 tiptr->ti_ctlsize = size2; 576 tiptr->ti_ctlbuf = ctlbuf; 577 578 /* 579 * Note: The head of the lookbuffers list (and associated buffers) 580 * is allocated here on initialization. 581 * More allocated on demand. 582 */ 583 tiptr->ti_lookbufs.tl_lookclen = 0; 584 tiptr->ti_lookbufs.tl_lookcbuf = lookcbuf; 585 tiptr->ti_lookbufs.tl_lookdlen = 0; 586 tiptr->ti_lookbufs.tl_lookdbuf = lookdbuf; 587 588 return (0); 589 } 590 591 592 /* 593 * set sizes of buffers 594 */ 595 static unsigned int 596 _t_setsize(t_scalar_t infosize, boolean_t option) 597 { 598 static size_t optinfsize; 599 600 switch (infosize) { 601 case T_INFINITE /* -1 */: 602 if (option) { 603 if (optinfsize == 0) { 604 size_t uc = ucred_size(); 605 if (uc < DEFSIZE/2) 606 optinfsize = DEFSIZE; 607 else 608 optinfsize = ucred_size() + DEFSIZE/2; 609 } 610 return ((unsigned int)optinfsize); 611 } 612 return (DEFSIZE); 613 case T_INVALID /* -2 */: 614 return (0); 615 default: 616 return ((unsigned int) infosize); 617 } 618 } 619 620 static void 621 _t_reinit_tiptr(struct _ti_user *tiptr) 622 { 623 /* 624 * Note: This routine is designed for a "reinitialization" 625 * Following fields are not modified here and preserved. 626 * - ti_fd field 627 * - ti_lock 628 * - ti_next 629 * - ti_prev 630 * The above fields have to be separately initialized if this 631 * is used for a fresh initialization. 632 */ 633 634 tiptr->ti_flags = 0; 635 tiptr->ti_rcvsize = 0; 636 tiptr->ti_rcvbuf = NULL; 637 tiptr->ti_ctlsize = 0; 638 tiptr->ti_ctlbuf = NULL; 639 tiptr->ti_lookbufs.tl_lookdbuf = NULL; 640 tiptr->ti_lookbufs.tl_lookcbuf = NULL; 641 tiptr->ti_lookbufs.tl_lookdlen = 0; 642 tiptr->ti_lookbufs.tl_lookclen = 0; 643 tiptr->ti_lookbufs.tl_next = NULL; 644 tiptr->ti_maxpsz = 0; 645 tiptr->ti_tsdusize = 0; 646 tiptr->ti_etsdusize = 0; 647 tiptr->ti_cdatasize = 0; 648 tiptr->ti_ddatasize = 0; 649 tiptr->ti_servtype = 0; 650 tiptr->ti_lookcnt = 0; 651 tiptr->ti_state = 0; 652 tiptr->ti_ocnt = 0; 653 tiptr->ti_prov_flag = 0; 654 tiptr->ti_qlen = 0; 655 } 656 657 /* 658 * Link manipulation routines. 659 * 660 * NBUCKETS hash buckets are used to give fast 661 * access. The number is derived the file descriptor softlimit 662 * number (64). 663 */ 664 665 #define NBUCKETS 64 666 static struct _ti_user *hash_bucket[NBUCKETS]; 667 668 /* 669 * Allocates a new link and returns a pointer to it. 670 * Assumes that the caller is holding _ti_userlock via sig_mutex_lock(), 671 * so signals are deferred here. 672 */ 673 static struct _ti_user * 674 add_tilink(int s) 675 { 676 struct _ti_user *tiptr; 677 struct _ti_user *prevptr; 678 struct _ti_user *curptr; 679 int x; 680 struct stat stbuf; 681 682 assert(MUTEX_HELD(&_ti_userlock)); 683 684 if (s < 0 || fstat(s, &stbuf) != 0) 685 return (NULL); 686 687 x = s % NBUCKETS; 688 if (hash_bucket[x] != NULL) { 689 /* 690 * Walk along the bucket looking for 691 * duplicate entry or the end. 692 */ 693 for (curptr = hash_bucket[x]; curptr != NULL; 694 curptr = curptr->ti_next) { 695 if (curptr->ti_fd == s) { 696 /* 697 * This can happen when the user has close(2)'ed 698 * a descriptor and then been allocated it again 699 * via t_open(). 700 * 701 * We will re-use the existing _ti_user struct 702 * in this case rather than using the one 703 * we allocated above. If there are buffers 704 * associated with the existing _ti_user 705 * struct, they may not be the correct size, 706 * so we can not use it. We free them 707 * here and re-allocate a new ones 708 * later on. 709 */ 710 if (curptr->ti_rcvbuf != NULL) 711 free(curptr->ti_rcvbuf); 712 free(curptr->ti_ctlbuf); 713 _t_free_lookbufs(curptr); 714 _t_reinit_tiptr(curptr); 715 curptr->ti_rdev = stbuf.st_rdev; 716 curptr->ti_ino = stbuf.st_ino; 717 return (curptr); 718 } 719 prevptr = curptr; 720 } 721 /* 722 * Allocate and link in a new one. 723 */ 724 if ((tiptr = malloc(sizeof (*tiptr))) == NULL) 725 return (NULL); 726 /* 727 * First initialize fields common with reinitialization and 728 * then other fields too 729 */ 730 _t_reinit_tiptr(tiptr); 731 prevptr->ti_next = tiptr; 732 tiptr->ti_prev = prevptr; 733 } else { 734 /* 735 * First entry. 736 */ 737 if ((tiptr = malloc(sizeof (*tiptr))) == NULL) 738 return (NULL); 739 _t_reinit_tiptr(tiptr); 740 hash_bucket[x] = tiptr; 741 tiptr->ti_prev = NULL; 742 } 743 tiptr->ti_next = NULL; 744 tiptr->ti_fd = s; 745 tiptr->ti_rdev = stbuf.st_rdev; 746 tiptr->ti_ino = stbuf.st_ino; 747 (void) mutex_init(&tiptr->ti_lock, USYNC_THREAD, NULL); 748 return (tiptr); 749 } 750 751 /* 752 * Find a link by descriptor 753 * Assumes that the caller is holding _ti_userlock. 754 */ 755 static struct _ti_user * 756 find_tilink(int s) 757 { 758 struct _ti_user *curptr; 759 int x; 760 struct stat stbuf; 761 762 assert(MUTEX_HELD(&_ti_userlock)); 763 764 if (s < 0 || fstat(s, &stbuf) != 0) 765 return (NULL); 766 767 x = s % NBUCKETS; 768 /* 769 * Walk along the bucket looking for the descriptor. 770 */ 771 for (curptr = hash_bucket[x]; curptr; curptr = curptr->ti_next) { 772 if (curptr->ti_fd == s) { 773 if (curptr->ti_rdev == stbuf.st_rdev && 774 curptr->ti_ino == stbuf.st_ino) 775 return (curptr); 776 (void) _t_delete_tilink(s); 777 } 778 } 779 return (NULL); 780 } 781 782 /* 783 * Assumes that the caller is holding _ti_userlock. 784 * Also assumes that all signals are blocked. 785 */ 786 int 787 _t_delete_tilink(int s) 788 { 789 struct _ti_user *curptr; 790 int x; 791 792 /* 793 * Find the link. 794 */ 795 assert(MUTEX_HELD(&_ti_userlock)); 796 if (s < 0) 797 return (-1); 798 x = s % NBUCKETS; 799 /* 800 * Walk along the bucket looking for 801 * the descriptor. 802 */ 803 for (curptr = hash_bucket[x]; curptr; curptr = curptr->ti_next) { 804 if (curptr->ti_fd == s) { 805 struct _ti_user *nextptr; 806 struct _ti_user *prevptr; 807 808 nextptr = curptr->ti_next; 809 prevptr = curptr->ti_prev; 810 if (prevptr) 811 prevptr->ti_next = nextptr; 812 else 813 hash_bucket[x] = nextptr; 814 if (nextptr) 815 nextptr->ti_prev = prevptr; 816 817 /* 818 * free resource associated with the curptr 819 */ 820 if (curptr->ti_rcvbuf != NULL) 821 free(curptr->ti_rcvbuf); 822 free(curptr->ti_ctlbuf); 823 _t_free_lookbufs(curptr); 824 (void) mutex_destroy(&curptr->ti_lock); 825 free(curptr); 826 return (0); 827 } 828 } 829 return (-1); 830 } 831 832 /* 833 * Allocate a TLI state structure and synch it with the kernel 834 * *tiptr is returned 835 * Assumes that the caller is holding the _ti_userlock and has blocked signals. 836 * 837 * This function may fail the first time it is called with given transport if it 838 * doesn't support T_CAPABILITY_REQ TPI message. 839 */ 840 struct _ti_user * 841 _t_create(int fd, struct t_info *info, int api_semantics, int *t_capreq_failed) 842 { 843 /* 844 * Aligned data buffer for ioctl. 845 */ 846 union { 847 struct ti_sync_req ti_req; 848 struct ti_sync_ack ti_ack; 849 union T_primitives t_prim; 850 char pad[128]; 851 } ioctl_data; 852 void *ioctlbuf = &ioctl_data; /* TI_SYNC/GETINFO with room to grow */ 853 /* preferred location first local variable */ 854 /* see note below */ 855 /* 856 * Note: We use "ioctlbuf" allocated on stack above with 857 * room to grow since (struct ti_sync_ack) can grow in size 858 * on future kernels. (We do not use malloc'd "ti_ctlbuf" as that 859 * part of instance structure which may not exist yet) 860 * Its preferred declaration location is first local variable in this 861 * procedure as bugs causing overruns will be detectable on 862 * platforms where procedure calling conventions place return 863 * address on stack (such as x86) instead of causing silent 864 * memory corruption. 865 */ 866 struct ti_sync_req *tsrp = (struct ti_sync_req *)ioctlbuf; 867 struct ti_sync_ack *tsap = (struct ti_sync_ack *)ioctlbuf; 868 struct T_capability_req *tcrp = (struct T_capability_req *)ioctlbuf; 869 struct T_capability_ack *tcap = (struct T_capability_ack *)ioctlbuf; 870 struct T_info_ack *tiap = &tcap->INFO_ack; 871 struct _ti_user *ntiptr; 872 int expected_acksize; 873 int retlen, rstate, sv_errno, rval; 874 875 assert(MUTEX_HELD(&_ti_userlock)); 876 877 /* 878 * Use ioctl required for sync'ing state with kernel. 879 * We use two ioctls. TI_CAPABILITY is used to get TPI information and 880 * TI_SYNC is used to synchronise state with timod. Statically linked 881 * TLI applications will no longer work on older releases where there 882 * are no TI_SYNC and TI_CAPABILITY. 883 */ 884 885 /* 886 * Request info about transport. 887 * Assumes that TC1_INFO should always be implemented. 888 * For TI_CAPABILITY size argument to ioctl specifies maximum buffer 889 * size. 890 */ 891 tcrp->PRIM_type = T_CAPABILITY_REQ; 892 tcrp->CAP_bits1 = TC1_INFO | TC1_ACCEPTOR_ID; 893 rval = _t_do_ioctl(fd, (char *)ioctlbuf, 894 (int)sizeof (struct T_capability_ack), TI_CAPABILITY, &retlen); 895 expected_acksize = (int)sizeof (struct T_capability_ack); 896 897 if (rval < 0) { 898 /* 899 * TI_CAPABILITY may fail when transport provider doesn't 900 * support T_CAPABILITY_REQ message type. In this case file 901 * descriptor may be unusable (when transport provider sent 902 * M_ERROR in response to T_CAPABILITY_REQ). This should only 903 * happen once during system lifetime for given transport 904 * provider since timod will emulate TI_CAPABILITY after it 905 * detected the failure. 906 */ 907 if (t_capreq_failed != NULL) 908 *t_capreq_failed = 1; 909 return (NULL); 910 } 911 912 if (retlen != expected_acksize) { 913 t_errno = TSYSERR; 914 errno = EIO; 915 return (NULL); 916 } 917 918 if ((tcap->CAP_bits1 & TC1_INFO) == 0) { 919 t_errno = TSYSERR; 920 errno = EPROTO; 921 return (NULL); 922 } 923 if (info != NULL) { 924 if (tiap->PRIM_type != T_INFO_ACK) { 925 t_errno = TSYSERR; 926 errno = EPROTO; 927 return (NULL); 928 } 929 info->addr = tiap->ADDR_size; 930 info->options = tiap->OPT_size; 931 info->tsdu = tiap->TSDU_size; 932 info->etsdu = tiap->ETSDU_size; 933 info->connect = tiap->CDATA_size; 934 info->discon = tiap->DDATA_size; 935 info->servtype = tiap->SERV_type; 936 if (_T_IS_XTI(api_semantics)) { 937 /* 938 * XTI ONLY - TLI "struct t_info" does not 939 * have "flags" 940 */ 941 info->flags = 0; 942 if (tiap->PROVIDER_flag & (SENDZERO|OLD_SENDZERO)) 943 info->flags |= T_SENDZERO; 944 /* 945 * Some day there MAY be a NEW bit in T_info_ack 946 * PROVIDER_flag namespace exposed by TPI header 947 * <sys/tihdr.h> which will functionally correspond to 948 * role played by T_ORDRELDATA in info->flags namespace 949 * When that bit exists, we can add a test to see if 950 * it is set and set T_ORDRELDATA. 951 * Note: Currently only mOSI ("minimal OSI") provider 952 * is specified to use T_ORDRELDATA so probability of 953 * needing it is minimal. 954 */ 955 } 956 } 957 958 /* 959 * if first time or no instance (after fork/exec, dup etc, 960 * then create initialize data structure 961 * and allocate buffers 962 */ 963 ntiptr = add_tilink(fd); 964 if (ntiptr == NULL) { 965 t_errno = TSYSERR; 966 errno = ENOMEM; 967 return (NULL); 968 } 969 970 /* 971 * Allocate buffers for the new descriptor 972 */ 973 if (_t_alloc_bufs(fd, ntiptr, tiap) < 0) { 974 sv_errno = errno; 975 (void) _t_delete_tilink(fd); 976 t_errno = TSYSERR; 977 errno = sv_errno; 978 return (NULL); 979 } 980 981 /* Fill instance structure */ 982 983 ntiptr->ti_lookcnt = 0; 984 ntiptr->ti_flags = USED; 985 ntiptr->ti_state = T_UNINIT; 986 ntiptr->ti_ocnt = 0; 987 988 assert(tiap->TIDU_size > 0); 989 ntiptr->ti_maxpsz = tiap->TIDU_size; 990 assert(tiap->TSDU_size >= -2); 991 ntiptr->ti_tsdusize = tiap->TSDU_size; 992 assert(tiap->ETSDU_size >= -2); 993 ntiptr->ti_etsdusize = tiap->ETSDU_size; 994 assert(tiap->CDATA_size >= -2); 995 ntiptr->ti_cdatasize = tiap->CDATA_size; 996 assert(tiap->DDATA_size >= -2); 997 ntiptr->ti_ddatasize = tiap->DDATA_size; 998 ntiptr->ti_servtype = tiap->SERV_type; 999 ntiptr->ti_prov_flag = tiap->PROVIDER_flag; 1000 1001 if ((tcap->CAP_bits1 & TC1_ACCEPTOR_ID) != 0) { 1002 ntiptr->acceptor_id = tcap->ACCEPTOR_id; 1003 ntiptr->ti_flags |= V_ACCEPTOR_ID; 1004 } 1005 else 1006 ntiptr->ti_flags &= ~V_ACCEPTOR_ID; 1007 1008 /* 1009 * Restore state from kernel (caveat some heuristics) 1010 */ 1011 switch (tiap->CURRENT_state) { 1012 1013 case TS_UNBND: 1014 ntiptr->ti_state = T_UNBND; 1015 break; 1016 1017 case TS_IDLE: 1018 if ((rstate = _t_adjust_state(fd, T_IDLE)) < 0) { 1019 sv_errno = errno; 1020 (void) _t_delete_tilink(fd); 1021 errno = sv_errno; 1022 return (NULL); 1023 } 1024 ntiptr->ti_state = rstate; 1025 break; 1026 1027 case TS_WRES_CIND: 1028 ntiptr->ti_state = T_INCON; 1029 break; 1030 1031 case TS_WCON_CREQ: 1032 ntiptr->ti_state = T_OUTCON; 1033 break; 1034 1035 case TS_DATA_XFER: 1036 if ((rstate = _t_adjust_state(fd, T_DATAXFER)) < 0) { 1037 sv_errno = errno; 1038 (void) _t_delete_tilink(fd); 1039 errno = sv_errno; 1040 return (NULL); 1041 } 1042 ntiptr->ti_state = rstate; 1043 break; 1044 1045 case TS_WIND_ORDREL: 1046 ntiptr->ti_state = T_OUTREL; 1047 break; 1048 1049 case TS_WREQ_ORDREL: 1050 if ((rstate = _t_adjust_state(fd, T_INREL)) < 0) { 1051 sv_errno = errno; 1052 (void) _t_delete_tilink(fd); 1053 errno = sv_errno; 1054 return (NULL); 1055 } 1056 ntiptr->ti_state = rstate; 1057 break; 1058 default: 1059 t_errno = TSTATECHNG; 1060 (void) _t_delete_tilink(fd); 1061 return (NULL); 1062 } 1063 1064 /* 1065 * Sync information with timod. 1066 */ 1067 tsrp->tsr_flags = TSRF_QLEN_REQ; 1068 1069 rval = _t_do_ioctl(fd, ioctlbuf, 1070 (int)sizeof (struct ti_sync_req), TI_SYNC, &retlen); 1071 expected_acksize = (int)sizeof (struct ti_sync_ack); 1072 1073 if (rval < 0) { 1074 sv_errno = errno; 1075 (void) _t_delete_tilink(fd); 1076 t_errno = TSYSERR; 1077 errno = sv_errno; 1078 return (NULL); 1079 } 1080 1081 /* 1082 * This is a "less than" check as "struct ti_sync_ack" returned by 1083 * TI_SYNC can grow in size in future kernels. If/when a statically 1084 * linked application is run on a future kernel, it should not fail. 1085 */ 1086 if (retlen < expected_acksize) { 1087 sv_errno = errno; 1088 (void) _t_delete_tilink(fd); 1089 t_errno = TSYSERR; 1090 errno = sv_errno; 1091 return (NULL); 1092 } 1093 1094 if (_T_IS_TLI(api_semantics)) 1095 tsap->tsa_qlen = 0; /* not needed for TLI */ 1096 1097 ntiptr->ti_qlen = tsap->tsa_qlen; 1098 1099 return (ntiptr); 1100 } 1101 1102 1103 static int 1104 _t_adjust_state(int fd, int instate) 1105 { 1106 char ctlbuf[sizeof (t_scalar_t)]; 1107 char databuf[sizeof (int)]; /* size unimportant - anything > 0 */ 1108 struct strpeek arg; 1109 int outstate, retval; 1110 1111 /* 1112 * Peek at message on stream head (if any) 1113 * and see if it is data 1114 */ 1115 arg.ctlbuf.buf = ctlbuf; 1116 arg.ctlbuf.maxlen = (int)sizeof (ctlbuf); 1117 arg.ctlbuf.len = 0; 1118 1119 arg.databuf.buf = databuf; 1120 arg.databuf.maxlen = (int)sizeof (databuf); 1121 arg.databuf.len = 0; 1122 1123 arg.flags = 0; 1124 1125 if ((retval = ioctl(fd, I_PEEK, &arg)) < 0) { 1126 t_errno = TSYSERR; 1127 return (-1); 1128 } 1129 outstate = instate; 1130 /* 1131 * If peek shows something at stream head, then 1132 * Adjust "outstate" based on some heuristics. 1133 */ 1134 if (retval > 0) { 1135 switch (instate) { 1136 case T_IDLE: 1137 /* 1138 * The following heuristic is to handle data 1139 * ahead of T_DISCON_IND indications that might 1140 * be at the stream head waiting to be 1141 * read (T_DATA_IND or M_DATA) 1142 */ 1143 if (((arg.ctlbuf.len == 4) && 1144 /* LINTED pointer cast */ 1145 ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) || 1146 ((arg.ctlbuf.len == 0) && arg.databuf.len)) { 1147 outstate = T_DATAXFER; 1148 } 1149 break; 1150 case T_DATAXFER: 1151 /* 1152 * The following heuristic is to handle 1153 * the case where the connection is established 1154 * and in data transfer state at the provider 1155 * but the T_CONN_CON has not yet been read 1156 * from the stream head. 1157 */ 1158 if ((arg.ctlbuf.len == 4) && 1159 /* LINTED pointer cast */ 1160 ((*(int32_t *)arg.ctlbuf.buf) == T_CONN_CON)) 1161 outstate = T_OUTCON; 1162 break; 1163 case T_INREL: 1164 /* 1165 * The following heuristic is to handle data 1166 * ahead of T_ORDREL_IND indications that might 1167 * be at the stream head waiting to be 1168 * read (T_DATA_IND or M_DATA) 1169 */ 1170 if (((arg.ctlbuf.len == 4) && 1171 /* LINTED pointer cast */ 1172 ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) || 1173 ((arg.ctlbuf.len == 0) && arg.databuf.len)) { 1174 outstate = T_DATAXFER; 1175 } 1176 break; 1177 default: 1178 break; 1179 } 1180 } 1181 return (outstate); 1182 } 1183 1184 /* 1185 * Assumes caller has blocked signals at least in this thread (for safe 1186 * malloc/free operations) 1187 */ 1188 static int 1189 _t_cbuf_alloc(struct _ti_user *tiptr, char **retbuf) 1190 { 1191 unsigned size2; 1192 1193 assert(MUTEX_HELD(&tiptr->ti_lock)); 1194 size2 = tiptr->ti_ctlsize; /* same size as default ctlbuf */ 1195 1196 if ((*retbuf = malloc(size2)) == NULL) { 1197 return (-1); 1198 } 1199 return (size2); 1200 } 1201 1202 1203 /* 1204 * Assumes caller has blocked signals at least in this thread (for safe 1205 * malloc/free operations) 1206 */ 1207 int 1208 _t_rbuf_alloc(struct _ti_user *tiptr, char **retbuf) 1209 { 1210 unsigned size1; 1211 1212 assert(MUTEX_HELD(&tiptr->ti_lock)); 1213 size1 = tiptr->ti_rcvsize; /* same size as default rcvbuf */ 1214 1215 if ((*retbuf = malloc(size1)) == NULL) { 1216 return (-1); 1217 } 1218 return (size1); 1219 } 1220 1221 /* 1222 * Free lookbuffer structures and associated resources 1223 * Assumes ti_lock held for MT case. 1224 */ 1225 static void 1226 _t_free_lookbufs(struct _ti_user *tiptr) 1227 { 1228 struct _ti_lookbufs *tlbs, *prev_tlbs, *head_tlbs; 1229 1230 /* 1231 * Assertion: 1232 * The structure lock should be held or the global list 1233 * manipulation lock. The assumption is that nothing 1234 * else can access the descriptor since global list manipulation 1235 * lock is held so it is OK to manipulate fields without the 1236 * structure lock 1237 */ 1238 assert(MUTEX_HELD(&tiptr->ti_lock) || MUTEX_HELD(&_ti_userlock)); 1239 1240 /* 1241 * Free only the buffers in the first lookbuf 1242 */ 1243 head_tlbs = &tiptr->ti_lookbufs; 1244 if (head_tlbs->tl_lookdbuf != NULL) { 1245 free(head_tlbs->tl_lookdbuf); 1246 head_tlbs->tl_lookdbuf = NULL; 1247 } 1248 free(head_tlbs->tl_lookcbuf); 1249 head_tlbs->tl_lookcbuf = NULL; 1250 /* 1251 * Free the node and the buffers in the rest of the 1252 * list 1253 */ 1254 1255 tlbs = head_tlbs->tl_next; 1256 head_tlbs->tl_next = NULL; 1257 1258 while (tlbs != NULL) { 1259 if (tlbs->tl_lookdbuf != NULL) 1260 free(tlbs->tl_lookdbuf); 1261 free(tlbs->tl_lookcbuf); 1262 prev_tlbs = tlbs; 1263 tlbs = tlbs->tl_next; 1264 free(prev_tlbs); 1265 } 1266 } 1267 1268 /* 1269 * Free lookbuffer event list head. 1270 * Consume current lookbuffer event 1271 * Assumes ti_lock held for MT case. 1272 * Note: The head of this list is part of the instance 1273 * structure so the code is a little unorthodox. 1274 */ 1275 void 1276 _t_free_looklist_head(struct _ti_user *tiptr) 1277 { 1278 struct _ti_lookbufs *tlbs, *next_tlbs; 1279 1280 tlbs = &tiptr->ti_lookbufs; 1281 1282 if (tlbs->tl_next) { 1283 /* 1284 * Free the control and data buffers 1285 */ 1286 if (tlbs->tl_lookdbuf != NULL) 1287 free(tlbs->tl_lookdbuf); 1288 free(tlbs->tl_lookcbuf); 1289 /* 1290 * Replace with next lookbuf event contents 1291 */ 1292 next_tlbs = tlbs->tl_next; 1293 tlbs->tl_next = next_tlbs->tl_next; 1294 tlbs->tl_lookcbuf = next_tlbs->tl_lookcbuf; 1295 tlbs->tl_lookclen = next_tlbs->tl_lookclen; 1296 tlbs->tl_lookdbuf = next_tlbs->tl_lookdbuf; 1297 tlbs->tl_lookdlen = next_tlbs->tl_lookdlen; 1298 free(next_tlbs); 1299 /* 1300 * Decrement the flag - should never get to zero. 1301 * in this path 1302 */ 1303 tiptr->ti_lookcnt--; 1304 assert(tiptr->ti_lookcnt > 0); 1305 } else { 1306 /* 1307 * No more look buffer events - just clear the flag 1308 * and leave the buffers alone 1309 */ 1310 assert(tiptr->ti_lookcnt == 1); 1311 tiptr->ti_lookcnt = 0; 1312 } 1313 } 1314 1315 /* 1316 * Discard lookbuffer events. 1317 * Assumes ti_lock held for MT case. 1318 */ 1319 void 1320 _t_flush_lookevents(struct _ti_user *tiptr) 1321 { 1322 struct _ti_lookbufs *tlbs, *prev_tlbs; 1323 1324 /* 1325 * Leave the first nodes buffers alone (i.e. allocated) 1326 * but reset the flag. 1327 */ 1328 assert(MUTEX_HELD(&tiptr->ti_lock)); 1329 tiptr->ti_lookcnt = 0; 1330 /* 1331 * Blow away the rest of the list 1332 */ 1333 tlbs = tiptr->ti_lookbufs.tl_next; 1334 tiptr->ti_lookbufs.tl_next = NULL; 1335 while (tlbs != NULL) { 1336 if (tlbs->tl_lookdbuf != NULL) 1337 free(tlbs->tl_lookdbuf); 1338 free(tlbs->tl_lookcbuf); 1339 prev_tlbs = tlbs; 1340 tlbs = tlbs->tl_next; 1341 free(prev_tlbs); 1342 } 1343 } 1344 1345 1346 /* 1347 * This routine checks if the receive. buffer in the instance structure 1348 * is available (non-null). If it is, the buffer is acquired and marked busy 1349 * (null). If it is busy (possible in MT programs), it allocates a new 1350 * buffer and sets a flag indicating new memory was allocated and the caller 1351 * has to free it. 1352 */ 1353 int 1354 _t_acquire_ctlbuf( 1355 struct _ti_user *tiptr, 1356 struct strbuf *ctlbufp, 1357 int *didallocp) 1358 { 1359 *didallocp = 0; 1360 1361 ctlbufp->len = 0; 1362 if (tiptr->ti_ctlbuf) { 1363 ctlbufp->buf = tiptr->ti_ctlbuf; 1364 tiptr->ti_ctlbuf = NULL; 1365 ctlbufp->maxlen = tiptr->ti_ctlsize; 1366 } else { 1367 /* 1368 * tiptr->ti_ctlbuf is in use 1369 * allocate new buffer and free after use. 1370 */ 1371 if ((ctlbufp->maxlen = _t_cbuf_alloc(tiptr, 1372 &ctlbufp->buf)) < 0) { 1373 t_errno = TSYSERR; 1374 return (-1); 1375 } 1376 *didallocp = 1; 1377 } 1378 return (0); 1379 } 1380 1381 /* 1382 * This routine checks if the receive buffer in the instance structure 1383 * is available (non-null). If it is, the buffer is acquired and marked busy 1384 * (null). If it is busy (possible in MT programs), it allocates a new 1385 * buffer and sets a flag indicating new memory was allocated and the caller 1386 * has to free it. 1387 * Note: The receive buffer pointer can also be null if the transport 1388 * provider does not support connect/disconnect data, (e.g. TCP) - not 1389 * just when it is "busy". In that case, ti_rcvsize will be 0 and that is 1390 * used to instantiate the databuf which points to a null buffer of 1391 * length 0 which is the right thing to do for that case. 1392 */ 1393 int 1394 _t_acquire_databuf( 1395 struct _ti_user *tiptr, 1396 struct strbuf *databufp, 1397 int *didallocp) 1398 { 1399 *didallocp = 0; 1400 1401 databufp->len = 0; 1402 if (tiptr->ti_rcvbuf) { 1403 assert(tiptr->ti_rcvsize != 0); 1404 databufp->buf = tiptr->ti_rcvbuf; 1405 tiptr->ti_rcvbuf = NULL; 1406 databufp->maxlen = tiptr->ti_rcvsize; 1407 } else if (tiptr->ti_rcvsize == 0) { 1408 databufp->buf = NULL; 1409 databufp->maxlen = 0; 1410 } else { 1411 /* 1412 * tiptr->ti_rcvbuf is in use 1413 * allocate new buffer and free after use. 1414 */ 1415 if ((databufp->maxlen = _t_rbuf_alloc(tiptr, 1416 &databufp->buf)) < 0) { 1417 t_errno = TSYSERR; 1418 return (-1); 1419 } 1420 *didallocp = 1; 1421 } 1422 return (0); 1423 } 1424 1425 /* 1426 * This routine requests timod to look for any expedited data 1427 * queued in the "receive buffers" in the kernel. Used for XTI 1428 * t_look() semantics for transports that send expedited data 1429 * data inline (e.g TCP). 1430 * Returns -1 for failure 1431 * Returns 0 for success 1432 * On a successful return, the location pointed by "expedited_queuedp" 1433 * contains 1434 * 0 if no expedited data is found queued in "receive buffers" 1435 * 1 if expedited data is found queued in "receive buffers" 1436 */ 1437 1438 int 1439 _t_expinline_queued(int fd, int *expedited_queuedp) 1440 { 1441 union { 1442 struct ti_sync_req ti_req; 1443 struct ti_sync_ack ti_ack; 1444 char pad[128]; 1445 } ioctl_data; 1446 void *ioctlbuf = &ioctl_data; /* for TI_SYNC with room to grow */ 1447 /* preferred location first local variable */ 1448 /* see note in _t_create above */ 1449 struct ti_sync_req *tsrp = (struct ti_sync_req *)ioctlbuf; 1450 struct ti_sync_ack *tsap = (struct ti_sync_ack *)ioctlbuf; 1451 int rval, retlen; 1452 1453 *expedited_queuedp = 0; 1454 /* request info on rq expinds */ 1455 tsrp->tsr_flags = TSRF_IS_EXP_IN_RCVBUF; 1456 do { 1457 rval = _t_do_ioctl(fd, ioctlbuf, 1458 (int)sizeof (struct T_info_req), TI_SYNC, &retlen); 1459 } while (rval < 0 && errno == EINTR); 1460 1461 if (rval < 0) 1462 return (-1); 1463 1464 /* 1465 * This is a "less than" check as "struct ti_sync_ack" returned by 1466 * TI_SYNC can grow in size in future kernels. If/when a statically 1467 * linked application is run on a future kernel, it should not fail. 1468 */ 1469 if (retlen < (int)sizeof (struct ti_sync_ack)) { 1470 t_errno = TSYSERR; 1471 errno = EIO; 1472 return (-1); 1473 } 1474 if (tsap->tsa_flags & TSAF_EXP_QUEUED) 1475 *expedited_queuedp = 1; 1476 return (0); 1477 } 1478 1479 /* 1480 * Support functions for use by functions that do scatter/gather 1481 * like t_sndv(), t_rcvv() etc..follow below. 1482 */ 1483 1484 /* 1485 * _t_bytecount_upto_intmax() : 1486 * Sum of the lengths of the individual buffers in 1487 * the t_iovec array. If the sum exceeds INT_MAX 1488 * it is truncated to INT_MAX. 1489 */ 1490 unsigned int 1491 _t_bytecount_upto_intmax(const struct t_iovec *tiov, unsigned int tiovcount) 1492 { 1493 size_t nbytes; 1494 int i; 1495 1496 nbytes = 0; 1497 for (i = 0; i < tiovcount && nbytes < INT_MAX; i++) { 1498 if (tiov[i].iov_len >= INT_MAX) { 1499 nbytes = INT_MAX; 1500 break; 1501 } 1502 nbytes += tiov[i].iov_len; 1503 } 1504 1505 if (nbytes > INT_MAX) 1506 nbytes = INT_MAX; 1507 1508 return ((unsigned int)nbytes); 1509 } 1510 1511 /* 1512 * Gather the data in the t_iovec buffers, into a single linear buffer 1513 * starting at dataptr. Caller must have allocated sufficient space 1514 * starting at dataptr. The total amount of data that is gathered is 1515 * limited to INT_MAX. Any remaining data in the t_iovec buffers is 1516 * not copied. 1517 */ 1518 void 1519 _t_gather(char *dataptr, const struct t_iovec *tiov, unsigned int tiovcount) 1520 { 1521 char *curptr; 1522 unsigned int cur_count; 1523 unsigned int nbytes_remaining; 1524 int i; 1525 1526 curptr = dataptr; 1527 cur_count = 0; 1528 1529 nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount); 1530 for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) { 1531 if (tiov[i].iov_len <= nbytes_remaining) 1532 cur_count = (int)tiov[i].iov_len; 1533 else 1534 cur_count = nbytes_remaining; 1535 (void) memcpy(curptr, tiov[i].iov_base, cur_count); 1536 curptr += cur_count; 1537 nbytes_remaining -= cur_count; 1538 } 1539 } 1540 1541 /* 1542 * Scatter the data from the single linear buffer at pdatabuf->buf into 1543 * the t_iovec buffers. 1544 */ 1545 void 1546 _t_scatter(struct strbuf *pdatabuf, struct t_iovec *tiov, int tiovcount) 1547 { 1548 char *curptr; 1549 unsigned int nbytes_remaining; 1550 unsigned int curlen; 1551 int i; 1552 1553 /* 1554 * There cannot be any uncopied data leftover in pdatabuf 1555 * at the conclusion of this function. (asserted below) 1556 */ 1557 assert(pdatabuf->len <= _t_bytecount_upto_intmax(tiov, tiovcount)); 1558 curptr = pdatabuf->buf; 1559 nbytes_remaining = pdatabuf->len; 1560 for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) { 1561 if (tiov[i].iov_len < nbytes_remaining) 1562 curlen = (unsigned int)tiov[i].iov_len; 1563 else 1564 curlen = nbytes_remaining; 1565 (void) memcpy(tiov[i].iov_base, curptr, curlen); 1566 curptr += curlen; 1567 nbytes_remaining -= curlen; 1568 } 1569 } 1570 1571 /* 1572 * Adjust the iovec array, for subsequent use. Examine each element in the 1573 * iovec array,and zero out the iov_len if the buffer was sent fully. 1574 * otherwise the buffer was only partially sent, so adjust both iov_len and 1575 * iov_base. 1576 * 1577 */ 1578 void 1579 _t_adjust_iov(int bytes_sent, struct iovec *iov, int *iovcountp) 1580 { 1581 1582 int i; 1583 1584 for (i = 0; i < *iovcountp && bytes_sent; i++) { 1585 if (iov[i].iov_len == 0) 1586 continue; 1587 if (bytes_sent < iov[i].iov_len) 1588 break; 1589 else { 1590 bytes_sent -= iov[i].iov_len; 1591 iov[i].iov_len = 0; 1592 } 1593 } 1594 iov[i].iov_len -= bytes_sent; 1595 iov[i].iov_base += bytes_sent; 1596 } 1597 1598 /* 1599 * Copy the t_iovec array to the iovec array while taking care to see 1600 * that the sum of the buffer lengths in the result is not more than 1601 * INT_MAX. This function requires that T_IOV_MAX is no larger than 1602 * IOV_MAX. Otherwise the resulting array is not a suitable input to 1603 * writev(). If the sum of the lengths in t_iovec is zero, so is the 1604 * resulting iovec. 1605 */ 1606 void 1607 _t_copy_tiov_to_iov(const struct t_iovec *tiov, int tiovcount, 1608 struct iovec *iov, int *iovcountp) 1609 { 1610 int i; 1611 unsigned int nbytes_remaining; 1612 1613 nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount); 1614 i = 0; 1615 do { 1616 iov[i].iov_base = tiov[i].iov_base; 1617 if (tiov[i].iov_len > nbytes_remaining) 1618 iov[i].iov_len = nbytes_remaining; 1619 else 1620 iov[i].iov_len = tiov[i].iov_len; 1621 nbytes_remaining -= iov[i].iov_len; 1622 i++; 1623 } while (nbytes_remaining != 0 && i < tiovcount); 1624 1625 *iovcountp = i; 1626 } 1627 1628 /* 1629 * Routine called after connection establishment on transports where 1630 * connection establishment changes certain transport attributes such as 1631 * TIDU_size 1632 */ 1633 int 1634 _t_do_postconn_sync(int fd, struct _ti_user *tiptr) 1635 { 1636 union { 1637 struct T_capability_req tc_req; 1638 struct T_capability_ack tc_ack; 1639 } ioctl_data; 1640 1641 void *ioctlbuf = &ioctl_data; 1642 int expected_acksize; 1643 int retlen, rval; 1644 struct T_capability_req *tc_reqp = (struct T_capability_req *)ioctlbuf; 1645 struct T_capability_ack *tc_ackp = (struct T_capability_ack *)ioctlbuf; 1646 struct T_info_ack *tiap; 1647 1648 /* 1649 * This T_CAPABILITY_REQ should not fail, even if it is unsupported 1650 * by the transport provider. timod will emulate it in that case. 1651 */ 1652 tc_reqp->PRIM_type = T_CAPABILITY_REQ; 1653 tc_reqp->CAP_bits1 = TC1_INFO; 1654 rval = _t_do_ioctl(fd, (char *)ioctlbuf, 1655 (int)sizeof (struct T_capability_ack), TI_CAPABILITY, &retlen); 1656 expected_acksize = (int)sizeof (struct T_capability_ack); 1657 1658 if (rval < 0) 1659 return (-1); 1660 1661 /* 1662 * T_capability TPI messages are extensible and can grow in future. 1663 * However timod will take care of returning no more information 1664 * than what was requested, and truncating the "extended" 1665 * information towards the end of the T_capability_ack, if necessary. 1666 */ 1667 if (retlen != expected_acksize) { 1668 t_errno = TSYSERR; 1669 errno = EIO; 1670 return (-1); 1671 } 1672 1673 /* 1674 * The T_info_ack part of the T_capability_ack is guaranteed to be 1675 * present only if the corresponding TC1_INFO bit is set 1676 */ 1677 if ((tc_ackp->CAP_bits1 & TC1_INFO) == 0) { 1678 t_errno = TSYSERR; 1679 errno = EPROTO; 1680 return (-1); 1681 } 1682 1683 tiap = &tc_ackp->INFO_ack; 1684 if (tiap->PRIM_type != T_INFO_ACK) { 1685 t_errno = TSYSERR; 1686 errno = EPROTO; 1687 return (-1); 1688 } 1689 1690 /* 1691 * Note: Sync with latest information returned in "struct T_info_ack 1692 * but we deliberately not sync the state here as user level state 1693 * construction here is not required, only update of attributes which 1694 * may have changed because of negotations during connection 1695 * establsihment 1696 */ 1697 assert(tiap->TIDU_size > 0); 1698 tiptr->ti_maxpsz = tiap->TIDU_size; 1699 assert(tiap->TSDU_size >= T_INVALID); 1700 tiptr->ti_tsdusize = tiap->TSDU_size; 1701 assert(tiap->ETSDU_size >= T_INVALID); 1702 tiptr->ti_etsdusize = tiap->ETSDU_size; 1703 assert(tiap->CDATA_size >= T_INVALID); 1704 tiptr->ti_cdatasize = tiap->CDATA_size; 1705 assert(tiap->DDATA_size >= T_INVALID); 1706 tiptr->ti_ddatasize = tiap->DDATA_size; 1707 tiptr->ti_prov_flag = tiap->PROVIDER_flag; 1708 1709 return (0); 1710 } 1711