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