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