1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 24 /* All Rights Reserved */ 25 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 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 "tx.h" 52 53 #define DEFSIZE 2048 54 55 /* 56 * The following used to be in tiuser.h, but was causing too much namespace 57 * pollution. 58 */ 59 #define ROUNDUP32(X) ((X + 0x03)&~0x03) 60 61 static struct _ti_user *find_tilink(int s); 62 static struct _ti_user *add_tilink(int s); 63 static void _t_free_lookbufs(struct _ti_user *tiptr); 64 static unsigned int _t_setsize(t_scalar_t infosize); 65 static int _t_cbuf_alloc(struct _ti_user *tiptr, char **retbuf); 66 static int _t_rbuf_alloc(struct _ti_user *tiptr, char **retbuf); 67 static int _t_adjust_state(int fd, int instate); 68 static int _t_alloc_bufs(int fd, struct _ti_user *tiptr, 69 struct T_info_ack *tsap); 70 71 mutex_t _ti_userlock = DEFAULTMUTEX; /* Protects hash_bucket[] */ 72 73 /* 74 * Checkfd - checks validity of file descriptor 75 */ 76 struct _ti_user * 77 _t_checkfd(int fd, int force_sync, int api_semantics) 78 { 79 sigset_t mask; 80 struct _ti_user *tiptr; 81 int retval, timodpushed; 82 83 if (fd < 0) { 84 t_errno = TBADF; 85 return (NULL); 86 } 87 tiptr = NULL; 88 sig_mutex_lock(&_ti_userlock); 89 if ((tiptr = find_tilink(fd)) != NULL) { 90 if (!force_sync) { 91 sig_mutex_unlock(&_ti_userlock); 92 return (tiptr); 93 } 94 } 95 sig_mutex_unlock(&_ti_userlock); 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); 514 dsize = _t_setsize(tsap->DDATA_size); 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); 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); 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) 597 { 598 switch (infosize) { 599 case T_INFINITE /* -1 */: 600 return (DEFSIZE); 601 case T_INVALID /* -2 */: 602 return (0); 603 default: 604 return ((unsigned int) infosize); 605 } 606 } 607 608 static void 609 _t_reinit_tiptr(struct _ti_user *tiptr) 610 { 611 /* 612 * Note: This routine is designed for a "reinitialization" 613 * Following fields are not modified here and preserved. 614 * - ti_fd field 615 * - ti_lock 616 * - ti_next 617 * - ti_prev 618 * The above fields have to be separately initialized if this 619 * is used for a fresh initialization. 620 */ 621 622 tiptr->ti_flags = 0; 623 tiptr->ti_rcvsize = 0; 624 tiptr->ti_rcvbuf = NULL; 625 tiptr->ti_ctlsize = 0; 626 tiptr->ti_ctlbuf = NULL; 627 tiptr->ti_lookbufs.tl_lookdbuf = NULL; 628 tiptr->ti_lookbufs.tl_lookcbuf = NULL; 629 tiptr->ti_lookbufs.tl_lookdlen = 0; 630 tiptr->ti_lookbufs.tl_lookclen = 0; 631 tiptr->ti_lookbufs.tl_next = NULL; 632 tiptr->ti_maxpsz = 0; 633 tiptr->ti_tsdusize = 0; 634 tiptr->ti_etsdusize = 0; 635 tiptr->ti_cdatasize = 0; 636 tiptr->ti_ddatasize = 0; 637 tiptr->ti_servtype = 0; 638 tiptr->ti_lookcnt = 0; 639 tiptr->ti_state = 0; 640 tiptr->ti_ocnt = 0; 641 tiptr->ti_prov_flag = 0; 642 tiptr->ti_qlen = 0; 643 } 644 645 /* 646 * Link manipulation routines. 647 * 648 * NBUCKETS hash buckets are used to give fast 649 * access. The number is derived the file descriptor softlimit 650 * number (64). 651 */ 652 653 #define NBUCKETS 64 654 static struct _ti_user *hash_bucket[NBUCKETS]; 655 656 /* 657 * Allocates a new link and returns a pointer to it. 658 * Assumes that the caller is holding _ti_userlock via sig_mutex_lock(), 659 * so signals are deferred here. 660 */ 661 static struct _ti_user * 662 add_tilink(int s) 663 { 664 struct _ti_user *tiptr; 665 struct _ti_user *prevptr; 666 struct _ti_user *curptr; 667 int x; 668 struct stat stbuf; 669 670 assert(MUTEX_HELD(&_ti_userlock)); 671 672 if (s < 0 || fstat(s, &stbuf) != 0) 673 return (NULL); 674 675 x = s % NBUCKETS; 676 if (hash_bucket[x] != NULL) { 677 /* 678 * Walk along the bucket looking for 679 * duplicate entry or the end. 680 */ 681 for (curptr = hash_bucket[x]; curptr != NULL; 682 curptr = curptr->ti_next) { 683 if (curptr->ti_fd == s) { 684 /* 685 * This can happen when the user has close(2)'ed 686 * a descriptor and then been allocated it again 687 * via t_open(). 688 * 689 * We will re-use the existing _ti_user struct 690 * in this case rather than using the one 691 * we allocated above. If there are buffers 692 * associated with the existing _ti_user 693 * struct, they may not be the correct size, 694 * so we can not use it. We free them 695 * here and re-allocate a new ones 696 * later on. 697 */ 698 if (curptr->ti_rcvbuf != NULL) 699 free(curptr->ti_rcvbuf); 700 free(curptr->ti_ctlbuf); 701 _t_free_lookbufs(curptr); 702 _t_reinit_tiptr(curptr); 703 curptr->ti_rdev = stbuf.st_rdev; 704 curptr->ti_ino = stbuf.st_ino; 705 return (curptr); 706 } 707 prevptr = curptr; 708 } 709 /* 710 * Allocate and link in a new one. 711 */ 712 if ((tiptr = malloc(sizeof (*tiptr))) == NULL) 713 return (NULL); 714 /* 715 * First initialize fields common with reinitialization and 716 * then other fields too 717 */ 718 _t_reinit_tiptr(tiptr); 719 prevptr->ti_next = tiptr; 720 tiptr->ti_prev = prevptr; 721 } else { 722 /* 723 * First entry. 724 */ 725 if ((tiptr = malloc(sizeof (*tiptr))) == NULL) 726 return (NULL); 727 _t_reinit_tiptr(tiptr); 728 hash_bucket[x] = tiptr; 729 tiptr->ti_prev = NULL; 730 } 731 tiptr->ti_next = NULL; 732 tiptr->ti_fd = s; 733 tiptr->ti_rdev = stbuf.st_rdev; 734 tiptr->ti_ino = stbuf.st_ino; 735 (void) mutex_init(&tiptr->ti_lock, USYNC_THREAD, NULL); 736 return (tiptr); 737 } 738 739 /* 740 * Find a link by descriptor 741 * Assumes that the caller is holding _ti_userlock. 742 */ 743 static struct _ti_user * 744 find_tilink(int s) 745 { 746 struct _ti_user *curptr; 747 int x; 748 struct stat stbuf; 749 750 assert(MUTEX_HELD(&_ti_userlock)); 751 752 if (s < 0 || fstat(s, &stbuf) != 0) 753 return (NULL); 754 755 x = s % NBUCKETS; 756 /* 757 * Walk along the bucket looking for the descriptor. 758 */ 759 for (curptr = hash_bucket[x]; curptr; curptr = curptr->ti_next) { 760 if (curptr->ti_fd == s) { 761 if (curptr->ti_rdev == stbuf.st_rdev && 762 curptr->ti_ino == stbuf.st_ino) 763 return (curptr); 764 (void) _t_delete_tilink(s); 765 } 766 } 767 return (NULL); 768 } 769 770 /* 771 * Assumes that the caller is holding _ti_userlock. 772 * Also assumes that all signals are blocked. 773 */ 774 int 775 _t_delete_tilink(int s) 776 { 777 struct _ti_user *curptr; 778 int x; 779 780 /* 781 * Find the link. 782 */ 783 assert(MUTEX_HELD(&_ti_userlock)); 784 if (s < 0) 785 return (-1); 786 x = s % NBUCKETS; 787 /* 788 * Walk along the bucket looking for 789 * the descriptor. 790 */ 791 for (curptr = hash_bucket[x]; curptr; curptr = curptr->ti_next) { 792 if (curptr->ti_fd == s) { 793 struct _ti_user *nextptr; 794 struct _ti_user *prevptr; 795 796 nextptr = curptr->ti_next; 797 prevptr = curptr->ti_prev; 798 if (prevptr) 799 prevptr->ti_next = nextptr; 800 else 801 hash_bucket[x] = nextptr; 802 if (nextptr) 803 nextptr->ti_prev = prevptr; 804 805 /* 806 * free resource associated with the curptr 807 */ 808 if (curptr->ti_rcvbuf != NULL) 809 free(curptr->ti_rcvbuf); 810 free(curptr->ti_ctlbuf); 811 _t_free_lookbufs(curptr); 812 (void) mutex_destroy(&curptr->ti_lock); 813 free(curptr); 814 return (0); 815 } 816 } 817 return (-1); 818 } 819 820 /* 821 * Allocate a TLI state structure and synch it with the kernel 822 * *tiptr is returned 823 * Assumes that the caller is holding the _ti_userlock and has blocked signals. 824 * 825 * This function may fail the first time it is called with given transport if it 826 * doesn't support T_CAPABILITY_REQ TPI message. 827 */ 828 struct _ti_user * 829 _t_create(int fd, struct t_info *info, int api_semantics, int *t_capreq_failed) 830 { 831 /* 832 * Aligned data buffer for ioctl. 833 */ 834 union { 835 struct ti_sync_req ti_req; 836 struct ti_sync_ack ti_ack; 837 union T_primitives t_prim; 838 char pad[128]; 839 } ioctl_data; 840 void *ioctlbuf = &ioctl_data; /* TI_SYNC/GETINFO with room to grow */ 841 /* preferred location first local variable */ 842 /* see note below */ 843 /* 844 * Note: We use "ioctlbuf" allocated on stack above with 845 * room to grow since (struct ti_sync_ack) can grow in size 846 * on future kernels. (We do not use malloc'd "ti_ctlbuf" as that 847 * part of instance structure which may not exist yet) 848 * Its preferred declaration location is first local variable in this 849 * procedure as bugs causing overruns will be detectable on 850 * platforms where procedure calling conventions place return 851 * address on stack (such as x86) instead of causing silent 852 * memory corruption. 853 */ 854 struct ti_sync_req *tsrp = (struct ti_sync_req *)ioctlbuf; 855 struct ti_sync_ack *tsap = (struct ti_sync_ack *)ioctlbuf; 856 struct T_capability_req *tcrp = (struct T_capability_req *)ioctlbuf; 857 struct T_capability_ack *tcap = (struct T_capability_ack *)ioctlbuf; 858 struct T_info_ack *tiap = &tcap->INFO_ack; 859 struct _ti_user *ntiptr; 860 int expected_acksize; 861 int retlen, rstate, sv_errno, rval; 862 863 assert(MUTEX_HELD(&_ti_userlock)); 864 865 /* 866 * Use ioctl required for sync'ing state with kernel. 867 * We use two ioctls. TI_CAPABILITY is used to get TPI information and 868 * TI_SYNC is used to synchronise state with timod. Statically linked 869 * TLI applications will no longer work on older releases where there 870 * are no TI_SYNC and TI_CAPABILITY. 871 */ 872 873 /* 874 * Request info about transport. 875 * Assumes that TC1_INFO should always be implemented. 876 * For TI_CAPABILITY size argument to ioctl specifies maximum buffer 877 * size. 878 */ 879 tcrp->PRIM_type = T_CAPABILITY_REQ; 880 tcrp->CAP_bits1 = TC1_INFO | TC1_ACCEPTOR_ID; 881 rval = _t_do_ioctl(fd, (char *)ioctlbuf, 882 (int)sizeof (struct T_capability_ack), TI_CAPABILITY, &retlen); 883 expected_acksize = (int)sizeof (struct T_capability_ack); 884 885 if (rval < 0) { 886 /* 887 * TI_CAPABILITY may fail when transport provider doesn't 888 * support T_CAPABILITY_REQ message type. In this case file 889 * descriptor may be unusable (when transport provider sent 890 * M_ERROR in response to T_CAPABILITY_REQ). This should only 891 * happen once during system lifetime for given transport 892 * provider since timod will emulate TI_CAPABILITY after it 893 * detected the failure. 894 */ 895 if (t_capreq_failed != NULL) 896 *t_capreq_failed = 1; 897 return (NULL); 898 } 899 900 if (retlen != expected_acksize) { 901 t_errno = TSYSERR; 902 errno = EIO; 903 return (NULL); 904 } 905 906 if ((tcap->CAP_bits1 & TC1_INFO) == 0) { 907 t_errno = TSYSERR; 908 errno = EPROTO; 909 return (NULL); 910 } 911 if (info != NULL) { 912 if (tiap->PRIM_type != T_INFO_ACK) { 913 t_errno = TSYSERR; 914 errno = EPROTO; 915 return (NULL); 916 } 917 info->addr = tiap->ADDR_size; 918 info->options = tiap->OPT_size; 919 info->tsdu = tiap->TSDU_size; 920 info->etsdu = tiap->ETSDU_size; 921 info->connect = tiap->CDATA_size; 922 info->discon = tiap->DDATA_size; 923 info->servtype = tiap->SERV_type; 924 if (_T_IS_XTI(api_semantics)) { 925 /* 926 * XTI ONLY - TLI "struct t_info" does not 927 * have "flags" 928 */ 929 info->flags = 0; 930 if (tiap->PROVIDER_flag & (SENDZERO|OLD_SENDZERO)) 931 info->flags |= T_SENDZERO; 932 /* 933 * Some day there MAY be a NEW bit in T_info_ack 934 * PROVIDER_flag namespace exposed by TPI header 935 * <sys/tihdr.h> which will functionally correspond to 936 * role played by T_ORDRELDATA in info->flags namespace 937 * When that bit exists, we can add a test to see if 938 * it is set and set T_ORDRELDATA. 939 * Note: Currently only mOSI ("minimal OSI") provider 940 * is specified to use T_ORDRELDATA so probability of 941 * needing it is minimal. 942 */ 943 } 944 } 945 946 /* 947 * if first time or no instance (after fork/exec, dup etc, 948 * then create initialize data structure 949 * and allocate buffers 950 */ 951 ntiptr = add_tilink(fd); 952 if (ntiptr == NULL) { 953 t_errno = TSYSERR; 954 errno = ENOMEM; 955 return (NULL); 956 } 957 sig_mutex_lock(&ntiptr->ti_lock); 958 959 /* 960 * Allocate buffers for the new descriptor 961 */ 962 if (_t_alloc_bufs(fd, ntiptr, tiap) < 0) { 963 sv_errno = errno; 964 (void) _t_delete_tilink(fd); 965 t_errno = TSYSERR; 966 sig_mutex_unlock(&ntiptr->ti_lock); 967 errno = sv_errno; 968 return (NULL); 969 } 970 971 /* Fill instance structure */ 972 973 ntiptr->ti_lookcnt = 0; 974 ntiptr->ti_flags = USED; 975 ntiptr->ti_state = T_UNINIT; 976 ntiptr->ti_ocnt = 0; 977 978 assert(tiap->TIDU_size > 0); 979 ntiptr->ti_maxpsz = tiap->TIDU_size; 980 assert(tiap->TSDU_size >= -2); 981 ntiptr->ti_tsdusize = tiap->TSDU_size; 982 assert(tiap->ETSDU_size >= -2); 983 ntiptr->ti_etsdusize = tiap->ETSDU_size; 984 assert(tiap->CDATA_size >= -2); 985 ntiptr->ti_cdatasize = tiap->CDATA_size; 986 assert(tiap->DDATA_size >= -2); 987 ntiptr->ti_ddatasize = tiap->DDATA_size; 988 ntiptr->ti_servtype = tiap->SERV_type; 989 ntiptr->ti_prov_flag = tiap->PROVIDER_flag; 990 991 if ((tcap->CAP_bits1 & TC1_ACCEPTOR_ID) != 0) { 992 ntiptr->acceptor_id = tcap->ACCEPTOR_id; 993 ntiptr->ti_flags |= V_ACCEPTOR_ID; 994 } 995 else 996 ntiptr->ti_flags &= ~V_ACCEPTOR_ID; 997 998 /* 999 * Restore state from kernel (caveat some heuristics) 1000 */ 1001 switch (tiap->CURRENT_state) { 1002 1003 case TS_UNBND: 1004 ntiptr->ti_state = T_UNBND; 1005 break; 1006 1007 case TS_IDLE: 1008 if ((rstate = _t_adjust_state(fd, T_IDLE)) < 0) { 1009 sv_errno = errno; 1010 (void) _t_delete_tilink(fd); 1011 sig_mutex_unlock(&ntiptr->ti_lock); 1012 errno = sv_errno; 1013 return (NULL); 1014 } 1015 ntiptr->ti_state = rstate; 1016 break; 1017 1018 case TS_WRES_CIND: 1019 ntiptr->ti_state = T_INCON; 1020 break; 1021 1022 case TS_WCON_CREQ: 1023 ntiptr->ti_state = T_OUTCON; 1024 break; 1025 1026 case TS_DATA_XFER: 1027 if ((rstate = _t_adjust_state(fd, T_DATAXFER)) < 0) { 1028 sv_errno = errno; 1029 (void) _t_delete_tilink(fd); 1030 sig_mutex_unlock(&ntiptr->ti_lock); 1031 errno = sv_errno; 1032 return (NULL); 1033 } 1034 ntiptr->ti_state = rstate; 1035 break; 1036 1037 case TS_WIND_ORDREL: 1038 ntiptr->ti_state = T_OUTREL; 1039 break; 1040 1041 case TS_WREQ_ORDREL: 1042 if ((rstate = _t_adjust_state(fd, T_INREL)) < 0) { 1043 sv_errno = errno; 1044 (void) _t_delete_tilink(fd); 1045 sig_mutex_unlock(&ntiptr->ti_lock); 1046 errno = sv_errno; 1047 return (NULL); 1048 } 1049 ntiptr->ti_state = rstate; 1050 break; 1051 default: 1052 t_errno = TSTATECHNG; 1053 (void) _t_delete_tilink(fd); 1054 sig_mutex_unlock(&ntiptr->ti_lock); 1055 return (NULL); 1056 } 1057 1058 /* 1059 * Sync information with timod. 1060 */ 1061 tsrp->tsr_flags = TSRF_QLEN_REQ; 1062 1063 rval = _t_do_ioctl(fd, ioctlbuf, 1064 (int)sizeof (struct ti_sync_req), TI_SYNC, &retlen); 1065 expected_acksize = (int)sizeof (struct ti_sync_ack); 1066 1067 if (rval < 0) { 1068 sv_errno = errno; 1069 (void) _t_delete_tilink(fd); 1070 t_errno = TSYSERR; 1071 sig_mutex_unlock(&ntiptr->ti_lock); 1072 errno = sv_errno; 1073 return (NULL); 1074 } 1075 1076 /* 1077 * This is a "less than" check as "struct ti_sync_ack" returned by 1078 * TI_SYNC can grow in size in future kernels. If/when a statically 1079 * linked application is run on a future kernel, it should not fail. 1080 */ 1081 if (retlen < expected_acksize) { 1082 sv_errno = errno; 1083 (void) _t_delete_tilink(fd); 1084 t_errno = TSYSERR; 1085 sig_mutex_unlock(&ntiptr->ti_lock); 1086 errno = sv_errno; 1087 return (NULL); 1088 } 1089 1090 if (_T_IS_TLI(api_semantics)) 1091 tsap->tsa_qlen = 0; /* not needed for TLI */ 1092 1093 ntiptr->ti_qlen = tsap->tsa_qlen; 1094 sig_mutex_unlock(&ntiptr->ti_lock); 1095 return (ntiptr); 1096 } 1097 1098 1099 static int 1100 _t_adjust_state(int fd, int instate) 1101 { 1102 char ctlbuf[sizeof (t_scalar_t)]; 1103 char databuf[sizeof (int)]; /* size unimportant - anything > 0 */ 1104 struct strpeek arg; 1105 int outstate, retval; 1106 1107 /* 1108 * Peek at message on stream head (if any) 1109 * and see if it is data 1110 */ 1111 arg.ctlbuf.buf = ctlbuf; 1112 arg.ctlbuf.maxlen = (int)sizeof (ctlbuf); 1113 arg.ctlbuf.len = 0; 1114 1115 arg.databuf.buf = databuf; 1116 arg.databuf.maxlen = (int)sizeof (databuf); 1117 arg.databuf.len = 0; 1118 1119 arg.flags = 0; 1120 1121 if ((retval = _ioctl(fd, I_PEEK, &arg)) < 0) { 1122 t_errno = TSYSERR; 1123 return (-1); 1124 } 1125 outstate = instate; 1126 /* 1127 * If peek shows something at stream head, then 1128 * Adjust "outstate" based on some heuristics. 1129 */ 1130 if (retval > 0) { 1131 switch (instate) { 1132 case T_IDLE: 1133 /* 1134 * The following heuristic is to handle data 1135 * ahead of T_DISCON_IND indications that might 1136 * be at the stream head waiting to be 1137 * read (T_DATA_IND or M_DATA) 1138 */ 1139 if (((arg.ctlbuf.len == 4) && 1140 /* LINTED pointer cast */ 1141 ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) || 1142 ((arg.ctlbuf.len == 0) && arg.databuf.len)) { 1143 outstate = T_DATAXFER; 1144 } 1145 break; 1146 case T_DATAXFER: 1147 /* 1148 * The following heuristic is to handle 1149 * the case where the connection is established 1150 * and in data transfer state at the provider 1151 * but the T_CONN_CON has not yet been read 1152 * from the stream head. 1153 */ 1154 if ((arg.ctlbuf.len == 4) && 1155 /* LINTED pointer cast */ 1156 ((*(int32_t *)arg.ctlbuf.buf) == T_CONN_CON)) 1157 outstate = T_OUTCON; 1158 break; 1159 case T_INREL: 1160 /* 1161 * The following heuristic is to handle data 1162 * ahead of T_ORDREL_IND indications that might 1163 * be at the stream head waiting to be 1164 * read (T_DATA_IND or M_DATA) 1165 */ 1166 if (((arg.ctlbuf.len == 4) && 1167 /* LINTED pointer cast */ 1168 ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) || 1169 ((arg.ctlbuf.len == 0) && arg.databuf.len)) { 1170 outstate = T_DATAXFER; 1171 } 1172 break; 1173 default: 1174 break; 1175 } 1176 } 1177 return (outstate); 1178 } 1179 1180 /* 1181 * Assumes caller has blocked signals at least in this thread (for safe 1182 * malloc/free operations) 1183 */ 1184 static int 1185 _t_cbuf_alloc(struct _ti_user *tiptr, char **retbuf) 1186 { 1187 unsigned size2; 1188 1189 assert(MUTEX_HELD(&tiptr->ti_lock)); 1190 size2 = tiptr->ti_ctlsize; /* same size as default ctlbuf */ 1191 1192 if ((*retbuf = malloc(size2)) == NULL) { 1193 return (-1); 1194 } 1195 return (size2); 1196 } 1197 1198 1199 /* 1200 * Assumes caller has blocked signals at least in this thread (for safe 1201 * malloc/free operations) 1202 */ 1203 int 1204 _t_rbuf_alloc(struct _ti_user *tiptr, char **retbuf) 1205 { 1206 unsigned size1; 1207 1208 assert(MUTEX_HELD(&tiptr->ti_lock)); 1209 size1 = tiptr->ti_rcvsize; /* same size as default rcvbuf */ 1210 1211 if ((*retbuf = malloc(size1)) == NULL) { 1212 return (-1); 1213 } 1214 return (size1); 1215 } 1216 1217 /* 1218 * Free lookbuffer structures and associated resources 1219 * Assumes ti_lock held for MT case. 1220 */ 1221 static void 1222 _t_free_lookbufs(struct _ti_user *tiptr) 1223 { 1224 struct _ti_lookbufs *tlbs, *prev_tlbs, *head_tlbs; 1225 1226 /* 1227 * Assertion: 1228 * The structure lock should be held or the global list 1229 * manipulation lock. The assumption is that nothing 1230 * else can access the descriptor since global list manipulation 1231 * lock is held so it is OK to manipulate fields without the 1232 * structure lock 1233 */ 1234 assert(MUTEX_HELD(&tiptr->ti_lock) || MUTEX_HELD(&_ti_userlock)); 1235 1236 /* 1237 * Free only the buffers in the first lookbuf 1238 */ 1239 head_tlbs = &tiptr->ti_lookbufs; 1240 if (head_tlbs->tl_lookdbuf != NULL) { 1241 free(head_tlbs->tl_lookdbuf); 1242 head_tlbs->tl_lookdbuf = NULL; 1243 } 1244 free(head_tlbs->tl_lookcbuf); 1245 head_tlbs->tl_lookcbuf = NULL; 1246 /* 1247 * Free the node and the buffers in the rest of the 1248 * list 1249 */ 1250 1251 tlbs = head_tlbs->tl_next; 1252 head_tlbs->tl_next = NULL; 1253 1254 while (tlbs != NULL) { 1255 if (tlbs->tl_lookdbuf != NULL) 1256 free(tlbs->tl_lookdbuf); 1257 free(tlbs->tl_lookcbuf); 1258 prev_tlbs = tlbs; 1259 tlbs = tlbs->tl_next; 1260 free(prev_tlbs); 1261 } 1262 } 1263 1264 /* 1265 * Free lookbuffer event list head. 1266 * Consume current lookbuffer event 1267 * Assumes ti_lock held for MT case. 1268 * Note: The head of this list is part of the instance 1269 * structure so the code is a little unorthodox. 1270 */ 1271 void 1272 _t_free_looklist_head(struct _ti_user *tiptr) 1273 { 1274 struct _ti_lookbufs *tlbs, *next_tlbs; 1275 1276 tlbs = &tiptr->ti_lookbufs; 1277 1278 if (tlbs->tl_next) { 1279 /* 1280 * Free the control and data buffers 1281 */ 1282 if (tlbs->tl_lookdbuf != NULL) 1283 free(tlbs->tl_lookdbuf); 1284 free(tlbs->tl_lookcbuf); 1285 /* 1286 * Replace with next lookbuf event contents 1287 */ 1288 next_tlbs = tlbs->tl_next; 1289 tlbs->tl_next = next_tlbs->tl_next; 1290 tlbs->tl_lookcbuf = next_tlbs->tl_lookcbuf; 1291 tlbs->tl_lookclen = next_tlbs->tl_lookclen; 1292 tlbs->tl_lookdbuf = next_tlbs->tl_lookdbuf; 1293 tlbs->tl_lookdlen = next_tlbs->tl_lookdlen; 1294 free(next_tlbs); 1295 /* 1296 * Decrement the flag - should never get to zero. 1297 * in this path 1298 */ 1299 tiptr->ti_lookcnt--; 1300 assert(tiptr->ti_lookcnt > 0); 1301 } else { 1302 /* 1303 * No more look buffer events - just clear the flag 1304 * and leave the buffers alone 1305 */ 1306 assert(tiptr->ti_lookcnt == 1); 1307 tiptr->ti_lookcnt = 0; 1308 } 1309 } 1310 1311 /* 1312 * Discard lookbuffer events. 1313 * Assumes ti_lock held for MT case. 1314 */ 1315 void 1316 _t_flush_lookevents(struct _ti_user *tiptr) 1317 { 1318 struct _ti_lookbufs *tlbs, *prev_tlbs; 1319 1320 /* 1321 * Leave the first nodes buffers alone (i.e. allocated) 1322 * but reset the flag. 1323 */ 1324 assert(MUTEX_HELD(&tiptr->ti_lock)); 1325 tiptr->ti_lookcnt = 0; 1326 /* 1327 * Blow away the rest of the list 1328 */ 1329 tlbs = tiptr->ti_lookbufs.tl_next; 1330 tiptr->ti_lookbufs.tl_next = NULL; 1331 while (tlbs != NULL) { 1332 if (tlbs->tl_lookdbuf != NULL) 1333 free(tlbs->tl_lookdbuf); 1334 free(tlbs->tl_lookcbuf); 1335 prev_tlbs = tlbs; 1336 tlbs = tlbs->tl_next; 1337 free(prev_tlbs); 1338 } 1339 } 1340 1341 1342 /* 1343 * This routine checks if the receive. buffer in the instance structure 1344 * is available (non-null). If it is, the buffer is acquired and marked busy 1345 * (null). If it is busy (possible in MT programs), it allocates a new 1346 * buffer and sets a flag indicating new memory was allocated and the caller 1347 * has to free it. 1348 */ 1349 int 1350 _t_acquire_ctlbuf( 1351 struct _ti_user *tiptr, 1352 struct strbuf *ctlbufp, 1353 int *didallocp) 1354 { 1355 *didallocp = 0; 1356 1357 ctlbufp->len = 0; 1358 if (tiptr->ti_ctlbuf) { 1359 ctlbufp->buf = tiptr->ti_ctlbuf; 1360 tiptr->ti_ctlbuf = NULL; 1361 ctlbufp->maxlen = tiptr->ti_ctlsize; 1362 } else { 1363 /* 1364 * tiptr->ti_ctlbuf is in use 1365 * allocate new buffer and free after use. 1366 */ 1367 if ((ctlbufp->maxlen = _t_cbuf_alloc(tiptr, 1368 &ctlbufp->buf)) < 0) { 1369 t_errno = TSYSERR; 1370 return (-1); 1371 } 1372 *didallocp = 1; 1373 } 1374 return (0); 1375 } 1376 1377 /* 1378 * This routine checks if the receive buffer in the instance structure 1379 * is available (non-null). If it is, the buffer is acquired and marked busy 1380 * (null). If it is busy (possible in MT programs), it allocates a new 1381 * buffer and sets a flag indicating new memory was allocated and the caller 1382 * has to free it. 1383 * Note: The receive buffer pointer can also be null if the transport 1384 * provider does not support connect/disconnect data, (e.g. TCP) - not 1385 * just when it is "busy". In that case, ti_rcvsize will be 0 and that is 1386 * used to instantiate the databuf which points to a null buffer of 1387 * length 0 which is the right thing to do for that case. 1388 */ 1389 int 1390 _t_acquire_databuf( 1391 struct _ti_user *tiptr, 1392 struct strbuf *databufp, 1393 int *didallocp) 1394 { 1395 *didallocp = 0; 1396 1397 databufp->len = 0; 1398 if (tiptr->ti_rcvbuf) { 1399 assert(tiptr->ti_rcvsize != 0); 1400 databufp->buf = tiptr->ti_rcvbuf; 1401 tiptr->ti_rcvbuf = NULL; 1402 databufp->maxlen = tiptr->ti_rcvsize; 1403 } else if (tiptr->ti_rcvsize == 0) { 1404 databufp->buf = NULL; 1405 databufp->maxlen = 0; 1406 } else { 1407 /* 1408 * tiptr->ti_rcvbuf is in use 1409 * allocate new buffer and free after use. 1410 */ 1411 if ((databufp->maxlen = _t_rbuf_alloc(tiptr, 1412 &databufp->buf)) < 0) { 1413 t_errno = TSYSERR; 1414 return (-1); 1415 } 1416 *didallocp = 1; 1417 } 1418 return (0); 1419 } 1420 1421 /* 1422 * This routine requests timod to look for any expedited data 1423 * queued in the "receive buffers" in the kernel. Used for XTI 1424 * t_look() semantics for transports that send expedited data 1425 * data inline (e.g TCP). 1426 * Returns -1 for failure 1427 * Returns 0 for success 1428 * On a successful return, the location pointed by "expedited_queuedp" 1429 * contains 1430 * 0 if no expedited data is found queued in "receive buffers" 1431 * 1 if expedited data is found queued in "receive buffers" 1432 */ 1433 1434 int 1435 _t_expinline_queued(int fd, int *expedited_queuedp) 1436 { 1437 union { 1438 struct ti_sync_req ti_req; 1439 struct ti_sync_ack ti_ack; 1440 char pad[128]; 1441 } ioctl_data; 1442 void *ioctlbuf = &ioctl_data; /* for TI_SYNC with room to grow */ 1443 /* preferred location first local variable */ 1444 /* see note in _t_create above */ 1445 struct ti_sync_req *tsrp = (struct ti_sync_req *)ioctlbuf; 1446 struct ti_sync_ack *tsap = (struct ti_sync_ack *)ioctlbuf; 1447 int rval, retlen; 1448 1449 *expedited_queuedp = 0; 1450 /* request info on rq expinds */ 1451 tsrp->tsr_flags = TSRF_IS_EXP_IN_RCVBUF; 1452 do { 1453 rval = _t_do_ioctl(fd, ioctlbuf, 1454 (int)sizeof (struct T_info_req), TI_SYNC, &retlen); 1455 } while (rval < 0 && errno == EINTR); 1456 1457 if (rval < 0) 1458 return (-1); 1459 1460 /* 1461 * This is a "less than" check as "struct ti_sync_ack" returned by 1462 * TI_SYNC can grow in size in future kernels. If/when a statically 1463 * linked application is run on a future kernel, it should not fail. 1464 */ 1465 if (retlen < (int)sizeof (struct ti_sync_ack)) { 1466 t_errno = TSYSERR; 1467 errno = EIO; 1468 return (-1); 1469 } 1470 if (tsap->tsa_flags & TSAF_EXP_QUEUED) 1471 *expedited_queuedp = 1; 1472 return (0); 1473 } 1474 1475 /* 1476 * Support functions for use by functions that do scatter/gather 1477 * like t_sndv(), t_rcvv() etc..follow below. 1478 */ 1479 1480 /* 1481 * _t_bytecount_upto_intmax() : 1482 * Sum of the lengths of the individual buffers in 1483 * the t_iovec array. If the sum exceeds INT_MAX 1484 * it is truncated to INT_MAX. 1485 */ 1486 unsigned int 1487 _t_bytecount_upto_intmax(const struct t_iovec *tiov, unsigned int tiovcount) 1488 { 1489 size_t nbytes; 1490 int i; 1491 1492 nbytes = 0; 1493 for (i = 0; i < tiovcount && nbytes < INT_MAX; i++) { 1494 if (tiov[i].iov_len >= INT_MAX) { 1495 nbytes = INT_MAX; 1496 break; 1497 } 1498 nbytes += tiov[i].iov_len; 1499 } 1500 1501 if (nbytes > INT_MAX) 1502 nbytes = INT_MAX; 1503 1504 return ((unsigned int)nbytes); 1505 } 1506 1507 /* 1508 * Gather the data in the t_iovec buffers, into a single linear buffer 1509 * starting at dataptr. Caller must have allocated sufficient space 1510 * starting at dataptr. The total amount of data that is gathered is 1511 * limited to INT_MAX. Any remaining data in the t_iovec buffers is 1512 * not copied. 1513 */ 1514 void 1515 _t_gather(char *dataptr, const struct t_iovec *tiov, unsigned int tiovcount) 1516 { 1517 char *curptr; 1518 unsigned int cur_count; 1519 unsigned int nbytes_remaining; 1520 int i; 1521 1522 curptr = dataptr; 1523 cur_count = 0; 1524 1525 nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount); 1526 for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) { 1527 if (tiov[i].iov_len <= nbytes_remaining) 1528 cur_count = (int)tiov[i].iov_len; 1529 else 1530 cur_count = nbytes_remaining; 1531 (void) memcpy(curptr, tiov[i].iov_base, cur_count); 1532 curptr += cur_count; 1533 nbytes_remaining -= cur_count; 1534 } 1535 } 1536 1537 /* 1538 * Scatter the data from the single linear buffer at pdatabuf->buf into 1539 * the t_iovec buffers. 1540 */ 1541 void 1542 _t_scatter(struct strbuf *pdatabuf, struct t_iovec *tiov, int tiovcount) 1543 { 1544 char *curptr; 1545 unsigned int nbytes_remaining; 1546 unsigned int curlen; 1547 int i; 1548 1549 /* 1550 * There cannot be any uncopied data leftover in pdatabuf 1551 * at the conclusion of this function. (asserted below) 1552 */ 1553 assert(pdatabuf->len <= _t_bytecount_upto_intmax(tiov, tiovcount)); 1554 curptr = pdatabuf->buf; 1555 nbytes_remaining = pdatabuf->len; 1556 for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) { 1557 if (tiov[i].iov_len < nbytes_remaining) 1558 curlen = (unsigned int)tiov[i].iov_len; 1559 else 1560 curlen = nbytes_remaining; 1561 (void) memcpy(tiov[i].iov_base, curptr, curlen); 1562 curptr += curlen; 1563 nbytes_remaining -= curlen; 1564 } 1565 } 1566 1567 /* 1568 * Adjust the iovec array, for subsequent use. Examine each element in the 1569 * iovec array,and zero out the iov_len if the buffer was sent fully. 1570 * otherwise the buffer was only partially sent, so adjust both iov_len and 1571 * iov_base. 1572 * 1573 */ 1574 void 1575 _t_adjust_iov(int bytes_sent, struct iovec *iov, int *iovcountp) 1576 { 1577 1578 int i; 1579 1580 for (i = 0; i < *iovcountp && bytes_sent; i++) { 1581 if (iov[i].iov_len == 0) 1582 continue; 1583 if (bytes_sent < iov[i].iov_len) 1584 break; 1585 else { 1586 bytes_sent -= iov[i].iov_len; 1587 iov[i].iov_len = 0; 1588 } 1589 } 1590 iov[i].iov_len -= bytes_sent; 1591 iov[i].iov_base += bytes_sent; 1592 } 1593 1594 /* 1595 * Copy the t_iovec array to the iovec array while taking care to see 1596 * that the sum of the buffer lengths in the result is not more than 1597 * INT_MAX. This function requires that T_IOV_MAX is no larger than 1598 * IOV_MAX. Otherwise the resulting array is not a suitable input to 1599 * writev(). If the sum of the lengths in t_iovec is zero, so is the 1600 * resulting iovec. 1601 */ 1602 void 1603 _t_copy_tiov_to_iov(const struct t_iovec *tiov, int tiovcount, 1604 struct iovec *iov, int *iovcountp) 1605 { 1606 int i; 1607 unsigned int nbytes_remaining; 1608 1609 nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount); 1610 i = 0; 1611 do { 1612 iov[i].iov_base = tiov[i].iov_base; 1613 if (tiov[i].iov_len > nbytes_remaining) 1614 iov[i].iov_len = nbytes_remaining; 1615 else 1616 iov[i].iov_len = tiov[i].iov_len; 1617 nbytes_remaining -= iov[i].iov_len; 1618 i++; 1619 } while (nbytes_remaining != 0 && i < tiovcount); 1620 1621 *iovcountp = i; 1622 } 1623 1624 /* 1625 * Routine called after connection establishment on transports where 1626 * connection establishment changes certain transport attributes such as 1627 * TIDU_size 1628 */ 1629 int 1630 _t_do_postconn_sync(int fd, struct _ti_user *tiptr) 1631 { 1632 union { 1633 struct T_capability_req tc_req; 1634 struct T_capability_ack tc_ack; 1635 } ioctl_data; 1636 1637 void *ioctlbuf = &ioctl_data; 1638 int expected_acksize; 1639 int retlen, rval; 1640 struct T_capability_req *tc_reqp = (struct T_capability_req *)ioctlbuf; 1641 struct T_capability_ack *tc_ackp = (struct T_capability_ack *)ioctlbuf; 1642 struct T_info_ack *tiap; 1643 1644 /* 1645 * This T_CAPABILITY_REQ should not fail, even if it is unsupported 1646 * by the transport provider. timod will emulate it in that case. 1647 */ 1648 tc_reqp->PRIM_type = T_CAPABILITY_REQ; 1649 tc_reqp->CAP_bits1 = TC1_INFO; 1650 rval = _t_do_ioctl(fd, (char *)ioctlbuf, 1651 (int)sizeof (struct T_capability_ack), TI_CAPABILITY, &retlen); 1652 expected_acksize = (int)sizeof (struct T_capability_ack); 1653 1654 if (rval < 0) 1655 return (-1); 1656 1657 /* 1658 * T_capability TPI messages are extensible and can grow in future. 1659 * However timod will take care of returning no more information 1660 * than what was requested, and truncating the "extended" 1661 * information towards the end of the T_capability_ack, if necessary. 1662 */ 1663 if (retlen != expected_acksize) { 1664 t_errno = TSYSERR; 1665 errno = EIO; 1666 return (-1); 1667 } 1668 1669 /* 1670 * The T_info_ack part of the T_capability_ack is guaranteed to be 1671 * present only if the corresponding TC1_INFO bit is set 1672 */ 1673 if ((tc_ackp->CAP_bits1 & TC1_INFO) == 0) { 1674 t_errno = TSYSERR; 1675 errno = EPROTO; 1676 return (-1); 1677 } 1678 1679 tiap = &tc_ackp->INFO_ack; 1680 if (tiap->PRIM_type != T_INFO_ACK) { 1681 t_errno = TSYSERR; 1682 errno = EPROTO; 1683 return (-1); 1684 } 1685 1686 /* 1687 * Note: Sync with latest information returned in "struct T_info_ack 1688 * but we deliberately not sync the state here as user level state 1689 * construction here is not required, only update of attributes which 1690 * may have changed because of negotations during connection 1691 * establsihment 1692 */ 1693 assert(tiap->TIDU_size > 0); 1694 tiptr->ti_maxpsz = tiap->TIDU_size; 1695 assert(tiap->TSDU_size >= T_INVALID); 1696 tiptr->ti_tsdusize = tiap->TSDU_size; 1697 assert(tiap->ETSDU_size >= T_INVALID); 1698 tiptr->ti_etsdusize = tiap->ETSDU_size; 1699 assert(tiap->CDATA_size >= T_INVALID); 1700 tiptr->ti_cdatasize = tiap->CDATA_size; 1701 assert(tiap->DDATA_size >= T_INVALID); 1702 tiptr->ti_ddatasize = tiap->DDATA_size; 1703 tiptr->ti_prov_flag = tiap->PROVIDER_flag; 1704 1705 return (0); 1706 } 1707