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 sig_mutex_lock(&ntiptr->ti_lock); 970 971 /* 972 * Allocate buffers for the new descriptor 973 */ 974 if (_t_alloc_bufs(fd, ntiptr, tiap) < 0) { 975 sv_errno = errno; 976 (void) _t_delete_tilink(fd); 977 t_errno = TSYSERR; 978 sig_mutex_unlock(&ntiptr->ti_lock); 979 errno = sv_errno; 980 return (NULL); 981 } 982 983 /* Fill instance structure */ 984 985 ntiptr->ti_lookcnt = 0; 986 ntiptr->ti_flags = USED; 987 ntiptr->ti_state = T_UNINIT; 988 ntiptr->ti_ocnt = 0; 989 990 assert(tiap->TIDU_size > 0); 991 ntiptr->ti_maxpsz = tiap->TIDU_size; 992 assert(tiap->TSDU_size >= -2); 993 ntiptr->ti_tsdusize = tiap->TSDU_size; 994 assert(tiap->ETSDU_size >= -2); 995 ntiptr->ti_etsdusize = tiap->ETSDU_size; 996 assert(tiap->CDATA_size >= -2); 997 ntiptr->ti_cdatasize = tiap->CDATA_size; 998 assert(tiap->DDATA_size >= -2); 999 ntiptr->ti_ddatasize = tiap->DDATA_size; 1000 ntiptr->ti_servtype = tiap->SERV_type; 1001 ntiptr->ti_prov_flag = tiap->PROVIDER_flag; 1002 1003 if ((tcap->CAP_bits1 & TC1_ACCEPTOR_ID) != 0) { 1004 ntiptr->acceptor_id = tcap->ACCEPTOR_id; 1005 ntiptr->ti_flags |= V_ACCEPTOR_ID; 1006 } 1007 else 1008 ntiptr->ti_flags &= ~V_ACCEPTOR_ID; 1009 1010 /* 1011 * Restore state from kernel (caveat some heuristics) 1012 */ 1013 switch (tiap->CURRENT_state) { 1014 1015 case TS_UNBND: 1016 ntiptr->ti_state = T_UNBND; 1017 break; 1018 1019 case TS_IDLE: 1020 if ((rstate = _t_adjust_state(fd, T_IDLE)) < 0) { 1021 sv_errno = errno; 1022 (void) _t_delete_tilink(fd); 1023 sig_mutex_unlock(&ntiptr->ti_lock); 1024 errno = sv_errno; 1025 return (NULL); 1026 } 1027 ntiptr->ti_state = rstate; 1028 break; 1029 1030 case TS_WRES_CIND: 1031 ntiptr->ti_state = T_INCON; 1032 break; 1033 1034 case TS_WCON_CREQ: 1035 ntiptr->ti_state = T_OUTCON; 1036 break; 1037 1038 case TS_DATA_XFER: 1039 if ((rstate = _t_adjust_state(fd, T_DATAXFER)) < 0) { 1040 sv_errno = errno; 1041 (void) _t_delete_tilink(fd); 1042 sig_mutex_unlock(&ntiptr->ti_lock); 1043 errno = sv_errno; 1044 return (NULL); 1045 } 1046 ntiptr->ti_state = rstate; 1047 break; 1048 1049 case TS_WIND_ORDREL: 1050 ntiptr->ti_state = T_OUTREL; 1051 break; 1052 1053 case TS_WREQ_ORDREL: 1054 if ((rstate = _t_adjust_state(fd, T_INREL)) < 0) { 1055 sv_errno = errno; 1056 (void) _t_delete_tilink(fd); 1057 sig_mutex_unlock(&ntiptr->ti_lock); 1058 errno = sv_errno; 1059 return (NULL); 1060 } 1061 ntiptr->ti_state = rstate; 1062 break; 1063 default: 1064 t_errno = TSTATECHNG; 1065 (void) _t_delete_tilink(fd); 1066 sig_mutex_unlock(&ntiptr->ti_lock); 1067 return (NULL); 1068 } 1069 1070 /* 1071 * Sync information with timod. 1072 */ 1073 tsrp->tsr_flags = TSRF_QLEN_REQ; 1074 1075 rval = _t_do_ioctl(fd, ioctlbuf, 1076 (int)sizeof (struct ti_sync_req), TI_SYNC, &retlen); 1077 expected_acksize = (int)sizeof (struct ti_sync_ack); 1078 1079 if (rval < 0) { 1080 sv_errno = errno; 1081 (void) _t_delete_tilink(fd); 1082 t_errno = TSYSERR; 1083 sig_mutex_unlock(&ntiptr->ti_lock); 1084 errno = sv_errno; 1085 return (NULL); 1086 } 1087 1088 /* 1089 * This is a "less than" check as "struct ti_sync_ack" returned by 1090 * TI_SYNC can grow in size in future kernels. If/when a statically 1091 * linked application is run on a future kernel, it should not fail. 1092 */ 1093 if (retlen < expected_acksize) { 1094 sv_errno = errno; 1095 (void) _t_delete_tilink(fd); 1096 t_errno = TSYSERR; 1097 sig_mutex_unlock(&ntiptr->ti_lock); 1098 errno = sv_errno; 1099 return (NULL); 1100 } 1101 1102 if (_T_IS_TLI(api_semantics)) 1103 tsap->tsa_qlen = 0; /* not needed for TLI */ 1104 1105 ntiptr->ti_qlen = tsap->tsa_qlen; 1106 sig_mutex_unlock(&ntiptr->ti_lock); 1107 return (ntiptr); 1108 } 1109 1110 1111 static int 1112 _t_adjust_state(int fd, int instate) 1113 { 1114 char ctlbuf[sizeof (t_scalar_t)]; 1115 char databuf[sizeof (int)]; /* size unimportant - anything > 0 */ 1116 struct strpeek arg; 1117 int outstate, retval; 1118 1119 /* 1120 * Peek at message on stream head (if any) 1121 * and see if it is data 1122 */ 1123 arg.ctlbuf.buf = ctlbuf; 1124 arg.ctlbuf.maxlen = (int)sizeof (ctlbuf); 1125 arg.ctlbuf.len = 0; 1126 1127 arg.databuf.buf = databuf; 1128 arg.databuf.maxlen = (int)sizeof (databuf); 1129 arg.databuf.len = 0; 1130 1131 arg.flags = 0; 1132 1133 if ((retval = ioctl(fd, I_PEEK, &arg)) < 0) { 1134 t_errno = TSYSERR; 1135 return (-1); 1136 } 1137 outstate = instate; 1138 /* 1139 * If peek shows something at stream head, then 1140 * Adjust "outstate" based on some heuristics. 1141 */ 1142 if (retval > 0) { 1143 switch (instate) { 1144 case T_IDLE: 1145 /* 1146 * The following heuristic is to handle data 1147 * ahead of T_DISCON_IND indications that might 1148 * be at the stream head waiting to be 1149 * read (T_DATA_IND or M_DATA) 1150 */ 1151 if (((arg.ctlbuf.len == 4) && 1152 /* LINTED pointer cast */ 1153 ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) || 1154 ((arg.ctlbuf.len == 0) && arg.databuf.len)) { 1155 outstate = T_DATAXFER; 1156 } 1157 break; 1158 case T_DATAXFER: 1159 /* 1160 * The following heuristic is to handle 1161 * the case where the connection is established 1162 * and in data transfer state at the provider 1163 * but the T_CONN_CON has not yet been read 1164 * from the stream head. 1165 */ 1166 if ((arg.ctlbuf.len == 4) && 1167 /* LINTED pointer cast */ 1168 ((*(int32_t *)arg.ctlbuf.buf) == T_CONN_CON)) 1169 outstate = T_OUTCON; 1170 break; 1171 case T_INREL: 1172 /* 1173 * The following heuristic is to handle data 1174 * ahead of T_ORDREL_IND indications that might 1175 * be at the stream head waiting to be 1176 * read (T_DATA_IND or M_DATA) 1177 */ 1178 if (((arg.ctlbuf.len == 4) && 1179 /* LINTED pointer cast */ 1180 ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) || 1181 ((arg.ctlbuf.len == 0) && arg.databuf.len)) { 1182 outstate = T_DATAXFER; 1183 } 1184 break; 1185 default: 1186 break; 1187 } 1188 } 1189 return (outstate); 1190 } 1191 1192 /* 1193 * Assumes caller has blocked signals at least in this thread (for safe 1194 * malloc/free operations) 1195 */ 1196 static int 1197 _t_cbuf_alloc(struct _ti_user *tiptr, char **retbuf) 1198 { 1199 unsigned size2; 1200 1201 assert(MUTEX_HELD(&tiptr->ti_lock)); 1202 size2 = tiptr->ti_ctlsize; /* same size as default ctlbuf */ 1203 1204 if ((*retbuf = malloc(size2)) == NULL) { 1205 return (-1); 1206 } 1207 return (size2); 1208 } 1209 1210 1211 /* 1212 * Assumes caller has blocked signals at least in this thread (for safe 1213 * malloc/free operations) 1214 */ 1215 int 1216 _t_rbuf_alloc(struct _ti_user *tiptr, char **retbuf) 1217 { 1218 unsigned size1; 1219 1220 assert(MUTEX_HELD(&tiptr->ti_lock)); 1221 size1 = tiptr->ti_rcvsize; /* same size as default rcvbuf */ 1222 1223 if ((*retbuf = malloc(size1)) == NULL) { 1224 return (-1); 1225 } 1226 return (size1); 1227 } 1228 1229 /* 1230 * Free lookbuffer structures and associated resources 1231 * Assumes ti_lock held for MT case. 1232 */ 1233 static void 1234 _t_free_lookbufs(struct _ti_user *tiptr) 1235 { 1236 struct _ti_lookbufs *tlbs, *prev_tlbs, *head_tlbs; 1237 1238 /* 1239 * Assertion: 1240 * The structure lock should be held or the global list 1241 * manipulation lock. The assumption is that nothing 1242 * else can access the descriptor since global list manipulation 1243 * lock is held so it is OK to manipulate fields without the 1244 * structure lock 1245 */ 1246 assert(MUTEX_HELD(&tiptr->ti_lock) || MUTEX_HELD(&_ti_userlock)); 1247 1248 /* 1249 * Free only the buffers in the first lookbuf 1250 */ 1251 head_tlbs = &tiptr->ti_lookbufs; 1252 if (head_tlbs->tl_lookdbuf != NULL) { 1253 free(head_tlbs->tl_lookdbuf); 1254 head_tlbs->tl_lookdbuf = NULL; 1255 } 1256 free(head_tlbs->tl_lookcbuf); 1257 head_tlbs->tl_lookcbuf = NULL; 1258 /* 1259 * Free the node and the buffers in the rest of the 1260 * list 1261 */ 1262 1263 tlbs = head_tlbs->tl_next; 1264 head_tlbs->tl_next = NULL; 1265 1266 while (tlbs != NULL) { 1267 if (tlbs->tl_lookdbuf != NULL) 1268 free(tlbs->tl_lookdbuf); 1269 free(tlbs->tl_lookcbuf); 1270 prev_tlbs = tlbs; 1271 tlbs = tlbs->tl_next; 1272 free(prev_tlbs); 1273 } 1274 } 1275 1276 /* 1277 * Free lookbuffer event list head. 1278 * Consume current lookbuffer event 1279 * Assumes ti_lock held for MT case. 1280 * Note: The head of this list is part of the instance 1281 * structure so the code is a little unorthodox. 1282 */ 1283 void 1284 _t_free_looklist_head(struct _ti_user *tiptr) 1285 { 1286 struct _ti_lookbufs *tlbs, *next_tlbs; 1287 1288 tlbs = &tiptr->ti_lookbufs; 1289 1290 if (tlbs->tl_next) { 1291 /* 1292 * Free the control and data buffers 1293 */ 1294 if (tlbs->tl_lookdbuf != NULL) 1295 free(tlbs->tl_lookdbuf); 1296 free(tlbs->tl_lookcbuf); 1297 /* 1298 * Replace with next lookbuf event contents 1299 */ 1300 next_tlbs = tlbs->tl_next; 1301 tlbs->tl_next = next_tlbs->tl_next; 1302 tlbs->tl_lookcbuf = next_tlbs->tl_lookcbuf; 1303 tlbs->tl_lookclen = next_tlbs->tl_lookclen; 1304 tlbs->tl_lookdbuf = next_tlbs->tl_lookdbuf; 1305 tlbs->tl_lookdlen = next_tlbs->tl_lookdlen; 1306 free(next_tlbs); 1307 /* 1308 * Decrement the flag - should never get to zero. 1309 * in this path 1310 */ 1311 tiptr->ti_lookcnt--; 1312 assert(tiptr->ti_lookcnt > 0); 1313 } else { 1314 /* 1315 * No more look buffer events - just clear the flag 1316 * and leave the buffers alone 1317 */ 1318 assert(tiptr->ti_lookcnt == 1); 1319 tiptr->ti_lookcnt = 0; 1320 } 1321 } 1322 1323 /* 1324 * Discard lookbuffer events. 1325 * Assumes ti_lock held for MT case. 1326 */ 1327 void 1328 _t_flush_lookevents(struct _ti_user *tiptr) 1329 { 1330 struct _ti_lookbufs *tlbs, *prev_tlbs; 1331 1332 /* 1333 * Leave the first nodes buffers alone (i.e. allocated) 1334 * but reset the flag. 1335 */ 1336 assert(MUTEX_HELD(&tiptr->ti_lock)); 1337 tiptr->ti_lookcnt = 0; 1338 /* 1339 * Blow away the rest of the list 1340 */ 1341 tlbs = tiptr->ti_lookbufs.tl_next; 1342 tiptr->ti_lookbufs.tl_next = NULL; 1343 while (tlbs != NULL) { 1344 if (tlbs->tl_lookdbuf != NULL) 1345 free(tlbs->tl_lookdbuf); 1346 free(tlbs->tl_lookcbuf); 1347 prev_tlbs = tlbs; 1348 tlbs = tlbs->tl_next; 1349 free(prev_tlbs); 1350 } 1351 } 1352 1353 1354 /* 1355 * This routine checks if the receive. buffer in the instance structure 1356 * is available (non-null). If it is, the buffer is acquired and marked busy 1357 * (null). If it is busy (possible in MT programs), it allocates a new 1358 * buffer and sets a flag indicating new memory was allocated and the caller 1359 * has to free it. 1360 */ 1361 int 1362 _t_acquire_ctlbuf( 1363 struct _ti_user *tiptr, 1364 struct strbuf *ctlbufp, 1365 int *didallocp) 1366 { 1367 *didallocp = 0; 1368 1369 ctlbufp->len = 0; 1370 if (tiptr->ti_ctlbuf) { 1371 ctlbufp->buf = tiptr->ti_ctlbuf; 1372 tiptr->ti_ctlbuf = NULL; 1373 ctlbufp->maxlen = tiptr->ti_ctlsize; 1374 } else { 1375 /* 1376 * tiptr->ti_ctlbuf is in use 1377 * allocate new buffer and free after use. 1378 */ 1379 if ((ctlbufp->maxlen = _t_cbuf_alloc(tiptr, 1380 &ctlbufp->buf)) < 0) { 1381 t_errno = TSYSERR; 1382 return (-1); 1383 } 1384 *didallocp = 1; 1385 } 1386 return (0); 1387 } 1388 1389 /* 1390 * This routine checks if the receive buffer in the instance structure 1391 * is available (non-null). If it is, the buffer is acquired and marked busy 1392 * (null). If it is busy (possible in MT programs), it allocates a new 1393 * buffer and sets a flag indicating new memory was allocated and the caller 1394 * has to free it. 1395 * Note: The receive buffer pointer can also be null if the transport 1396 * provider does not support connect/disconnect data, (e.g. TCP) - not 1397 * just when it is "busy". In that case, ti_rcvsize will be 0 and that is 1398 * used to instantiate the databuf which points to a null buffer of 1399 * length 0 which is the right thing to do for that case. 1400 */ 1401 int 1402 _t_acquire_databuf( 1403 struct _ti_user *tiptr, 1404 struct strbuf *databufp, 1405 int *didallocp) 1406 { 1407 *didallocp = 0; 1408 1409 databufp->len = 0; 1410 if (tiptr->ti_rcvbuf) { 1411 assert(tiptr->ti_rcvsize != 0); 1412 databufp->buf = tiptr->ti_rcvbuf; 1413 tiptr->ti_rcvbuf = NULL; 1414 databufp->maxlen = tiptr->ti_rcvsize; 1415 } else if (tiptr->ti_rcvsize == 0) { 1416 databufp->buf = NULL; 1417 databufp->maxlen = 0; 1418 } else { 1419 /* 1420 * tiptr->ti_rcvbuf is in use 1421 * allocate new buffer and free after use. 1422 */ 1423 if ((databufp->maxlen = _t_rbuf_alloc(tiptr, 1424 &databufp->buf)) < 0) { 1425 t_errno = TSYSERR; 1426 return (-1); 1427 } 1428 *didallocp = 1; 1429 } 1430 return (0); 1431 } 1432 1433 /* 1434 * This routine requests timod to look for any expedited data 1435 * queued in the "receive buffers" in the kernel. Used for XTI 1436 * t_look() semantics for transports that send expedited data 1437 * data inline (e.g TCP). 1438 * Returns -1 for failure 1439 * Returns 0 for success 1440 * On a successful return, the location pointed by "expedited_queuedp" 1441 * contains 1442 * 0 if no expedited data is found queued in "receive buffers" 1443 * 1 if expedited data is found queued in "receive buffers" 1444 */ 1445 1446 int 1447 _t_expinline_queued(int fd, int *expedited_queuedp) 1448 { 1449 union { 1450 struct ti_sync_req ti_req; 1451 struct ti_sync_ack ti_ack; 1452 char pad[128]; 1453 } ioctl_data; 1454 void *ioctlbuf = &ioctl_data; /* for TI_SYNC with room to grow */ 1455 /* preferred location first local variable */ 1456 /* see note in _t_create above */ 1457 struct ti_sync_req *tsrp = (struct ti_sync_req *)ioctlbuf; 1458 struct ti_sync_ack *tsap = (struct ti_sync_ack *)ioctlbuf; 1459 int rval, retlen; 1460 1461 *expedited_queuedp = 0; 1462 /* request info on rq expinds */ 1463 tsrp->tsr_flags = TSRF_IS_EXP_IN_RCVBUF; 1464 do { 1465 rval = _t_do_ioctl(fd, ioctlbuf, 1466 (int)sizeof (struct T_info_req), TI_SYNC, &retlen); 1467 } while (rval < 0 && errno == EINTR); 1468 1469 if (rval < 0) 1470 return (-1); 1471 1472 /* 1473 * This is a "less than" check as "struct ti_sync_ack" returned by 1474 * TI_SYNC can grow in size in future kernels. If/when a statically 1475 * linked application is run on a future kernel, it should not fail. 1476 */ 1477 if (retlen < (int)sizeof (struct ti_sync_ack)) { 1478 t_errno = TSYSERR; 1479 errno = EIO; 1480 return (-1); 1481 } 1482 if (tsap->tsa_flags & TSAF_EXP_QUEUED) 1483 *expedited_queuedp = 1; 1484 return (0); 1485 } 1486 1487 /* 1488 * Support functions for use by functions that do scatter/gather 1489 * like t_sndv(), t_rcvv() etc..follow below. 1490 */ 1491 1492 /* 1493 * _t_bytecount_upto_intmax() : 1494 * Sum of the lengths of the individual buffers in 1495 * the t_iovec array. If the sum exceeds INT_MAX 1496 * it is truncated to INT_MAX. 1497 */ 1498 unsigned int 1499 _t_bytecount_upto_intmax(const struct t_iovec *tiov, unsigned int tiovcount) 1500 { 1501 size_t nbytes; 1502 int i; 1503 1504 nbytes = 0; 1505 for (i = 0; i < tiovcount && nbytes < INT_MAX; i++) { 1506 if (tiov[i].iov_len >= INT_MAX) { 1507 nbytes = INT_MAX; 1508 break; 1509 } 1510 nbytes += tiov[i].iov_len; 1511 } 1512 1513 if (nbytes > INT_MAX) 1514 nbytes = INT_MAX; 1515 1516 return ((unsigned int)nbytes); 1517 } 1518 1519 /* 1520 * Gather the data in the t_iovec buffers, into a single linear buffer 1521 * starting at dataptr. Caller must have allocated sufficient space 1522 * starting at dataptr. The total amount of data that is gathered is 1523 * limited to INT_MAX. Any remaining data in the t_iovec buffers is 1524 * not copied. 1525 */ 1526 void 1527 _t_gather(char *dataptr, const struct t_iovec *tiov, unsigned int tiovcount) 1528 { 1529 char *curptr; 1530 unsigned int cur_count; 1531 unsigned int nbytes_remaining; 1532 int i; 1533 1534 curptr = dataptr; 1535 cur_count = 0; 1536 1537 nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount); 1538 for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) { 1539 if (tiov[i].iov_len <= nbytes_remaining) 1540 cur_count = (int)tiov[i].iov_len; 1541 else 1542 cur_count = nbytes_remaining; 1543 (void) memcpy(curptr, tiov[i].iov_base, cur_count); 1544 curptr += cur_count; 1545 nbytes_remaining -= cur_count; 1546 } 1547 } 1548 1549 /* 1550 * Scatter the data from the single linear buffer at pdatabuf->buf into 1551 * the t_iovec buffers. 1552 */ 1553 void 1554 _t_scatter(struct strbuf *pdatabuf, struct t_iovec *tiov, int tiovcount) 1555 { 1556 char *curptr; 1557 unsigned int nbytes_remaining; 1558 unsigned int curlen; 1559 int i; 1560 1561 /* 1562 * There cannot be any uncopied data leftover in pdatabuf 1563 * at the conclusion of this function. (asserted below) 1564 */ 1565 assert(pdatabuf->len <= _t_bytecount_upto_intmax(tiov, tiovcount)); 1566 curptr = pdatabuf->buf; 1567 nbytes_remaining = pdatabuf->len; 1568 for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) { 1569 if (tiov[i].iov_len < nbytes_remaining) 1570 curlen = (unsigned int)tiov[i].iov_len; 1571 else 1572 curlen = nbytes_remaining; 1573 (void) memcpy(tiov[i].iov_base, curptr, curlen); 1574 curptr += curlen; 1575 nbytes_remaining -= curlen; 1576 } 1577 } 1578 1579 /* 1580 * Adjust the iovec array, for subsequent use. Examine each element in the 1581 * iovec array,and zero out the iov_len if the buffer was sent fully. 1582 * otherwise the buffer was only partially sent, so adjust both iov_len and 1583 * iov_base. 1584 * 1585 */ 1586 void 1587 _t_adjust_iov(int bytes_sent, struct iovec *iov, int *iovcountp) 1588 { 1589 1590 int i; 1591 1592 for (i = 0; i < *iovcountp && bytes_sent; i++) { 1593 if (iov[i].iov_len == 0) 1594 continue; 1595 if (bytes_sent < iov[i].iov_len) 1596 break; 1597 else { 1598 bytes_sent -= iov[i].iov_len; 1599 iov[i].iov_len = 0; 1600 } 1601 } 1602 iov[i].iov_len -= bytes_sent; 1603 iov[i].iov_base += bytes_sent; 1604 } 1605 1606 /* 1607 * Copy the t_iovec array to the iovec array while taking care to see 1608 * that the sum of the buffer lengths in the result is not more than 1609 * INT_MAX. This function requires that T_IOV_MAX is no larger than 1610 * IOV_MAX. Otherwise the resulting array is not a suitable input to 1611 * writev(). If the sum of the lengths in t_iovec is zero, so is the 1612 * resulting iovec. 1613 */ 1614 void 1615 _t_copy_tiov_to_iov(const struct t_iovec *tiov, int tiovcount, 1616 struct iovec *iov, int *iovcountp) 1617 { 1618 int i; 1619 unsigned int nbytes_remaining; 1620 1621 nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount); 1622 i = 0; 1623 do { 1624 iov[i].iov_base = tiov[i].iov_base; 1625 if (tiov[i].iov_len > nbytes_remaining) 1626 iov[i].iov_len = nbytes_remaining; 1627 else 1628 iov[i].iov_len = tiov[i].iov_len; 1629 nbytes_remaining -= iov[i].iov_len; 1630 i++; 1631 } while (nbytes_remaining != 0 && i < tiovcount); 1632 1633 *iovcountp = i; 1634 } 1635 1636 /* 1637 * Routine called after connection establishment on transports where 1638 * connection establishment changes certain transport attributes such as 1639 * TIDU_size 1640 */ 1641 int 1642 _t_do_postconn_sync(int fd, struct _ti_user *tiptr) 1643 { 1644 union { 1645 struct T_capability_req tc_req; 1646 struct T_capability_ack tc_ack; 1647 } ioctl_data; 1648 1649 void *ioctlbuf = &ioctl_data; 1650 int expected_acksize; 1651 int retlen, rval; 1652 struct T_capability_req *tc_reqp = (struct T_capability_req *)ioctlbuf; 1653 struct T_capability_ack *tc_ackp = (struct T_capability_ack *)ioctlbuf; 1654 struct T_info_ack *tiap; 1655 1656 /* 1657 * This T_CAPABILITY_REQ should not fail, even if it is unsupported 1658 * by the transport provider. timod will emulate it in that case. 1659 */ 1660 tc_reqp->PRIM_type = T_CAPABILITY_REQ; 1661 tc_reqp->CAP_bits1 = TC1_INFO; 1662 rval = _t_do_ioctl(fd, (char *)ioctlbuf, 1663 (int)sizeof (struct T_capability_ack), TI_CAPABILITY, &retlen); 1664 expected_acksize = (int)sizeof (struct T_capability_ack); 1665 1666 if (rval < 0) 1667 return (-1); 1668 1669 /* 1670 * T_capability TPI messages are extensible and can grow in future. 1671 * However timod will take care of returning no more information 1672 * than what was requested, and truncating the "extended" 1673 * information towards the end of the T_capability_ack, if necessary. 1674 */ 1675 if (retlen != expected_acksize) { 1676 t_errno = TSYSERR; 1677 errno = EIO; 1678 return (-1); 1679 } 1680 1681 /* 1682 * The T_info_ack part of the T_capability_ack is guaranteed to be 1683 * present only if the corresponding TC1_INFO bit is set 1684 */ 1685 if ((tc_ackp->CAP_bits1 & TC1_INFO) == 0) { 1686 t_errno = TSYSERR; 1687 errno = EPROTO; 1688 return (-1); 1689 } 1690 1691 tiap = &tc_ackp->INFO_ack; 1692 if (tiap->PRIM_type != T_INFO_ACK) { 1693 t_errno = TSYSERR; 1694 errno = EPROTO; 1695 return (-1); 1696 } 1697 1698 /* 1699 * Note: Sync with latest information returned in "struct T_info_ack 1700 * but we deliberately not sync the state here as user level state 1701 * construction here is not required, only update of attributes which 1702 * may have changed because of negotations during connection 1703 * establsihment 1704 */ 1705 assert(tiap->TIDU_size > 0); 1706 tiptr->ti_maxpsz = tiap->TIDU_size; 1707 assert(tiap->TSDU_size >= T_INVALID); 1708 tiptr->ti_tsdusize = tiap->TSDU_size; 1709 assert(tiap->ETSDU_size >= T_INVALID); 1710 tiptr->ti_etsdusize = tiap->ETSDU_size; 1711 assert(tiap->CDATA_size >= T_INVALID); 1712 tiptr->ti_cdatasize = tiap->CDATA_size; 1713 assert(tiap->DDATA_size >= T_INVALID); 1714 tiptr->ti_ddatasize = tiap->DDATA_size; 1715 tiptr->ti_prov_flag = tiap->PROVIDER_flag; 1716 1717 return (0); 1718 } 1719