1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1990 Mentat Inc. */ 26 27 #include <sys/types.h> 28 #include <inet/common.h> /* for various inet/mi.h and inet/nd.h needs */ 29 #include <sys/stream.h> 30 #include <sys/stropts.h> 31 #include <sys/strsun.h> 32 #include <sys/sysmacros.h> 33 #include <inet/nd.h> 34 #include <inet/mi.h> 35 #define _SUN_TPI_VERSION 2 36 #include <sys/tihdr.h> 37 #include <sys/timod.h> 38 #include <sys/vtrace.h> 39 #include <sys/kmem.h> 40 #include <sys/mkdev.h> 41 #include <sys/strlog.h> 42 #include <sys/ddi.h> 43 #include <sys/suntpi.h> 44 #include <sys/cmn_err.h> 45 #include <sys/debug.h> 46 #include <sys/kobj.h> 47 #include <sys/stropts.h> 48 #include <sys/strsubr.h> 49 #include <inet/proto_set.h> 50 51 #define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') 52 #define ISUPPER(ch) ((ch) >= 'A' && (ch) <= 'Z') 53 #define tolower(ch) ('a' + ((ch) - 'A')) 54 55 #define MI_IS_TRANSPARENT(mp) (mp->b_cont && \ 56 (mp->b_cont->b_rptr != mp->b_cont->b_wptr)) 57 58 /* 59 * NOTE: Whenever anything is allocated by mi_alloc or mi_alloc_sleep (below), 60 * the size of the requested allocation is increased by one word. This extra 61 * word is used to store the size of the object being allocated, and is located 62 * at the beginning of the allocated block. The pointer returned to the caller 63 * is a pointer to the *second* word in the newly-allocated block. The IP 64 * module of mdb is aware of this, and will need to be changed if this 65 * allocation strategy is changed. 66 */ 67 68 typedef struct stroptions *STROPTP; 69 typedef union T_primitives *TPRIMP; 70 71 /* Timer block states. */ 72 #define TB_RUNNING 1 73 #define TB_IDLE 2 74 /* 75 * Could not stop/free before putq 76 */ 77 #define TB_RESCHED 3 /* mtb_time_left contains tick count */ 78 #define TB_CANCELLED 4 79 #define TB_TO_BE_FREED 5 80 81 typedef struct mtb_s { 82 int mtb_state; 83 timeout_id_t mtb_tid; 84 queue_t *mtb_q; 85 MBLKP mtb_mp; 86 clock_t mtb_time_left; 87 } MTB, *MTBP; 88 89 static int mi_timer_fire(MTBP); 90 static int mi_iprintf(char *, va_list, pfi_t, char *); 91 static void mi_tpi_addr_and_opt(MBLKP, char *, t_scalar_t, char *, t_scalar_t); 92 static MBLKP mi_tpi_trailer_alloc(MBLKP, size_t, t_scalar_t); 93 94 /* ARGSUSED1 */ 95 void * 96 mi_alloc(size_t size, uint_t pri) 97 { 98 size_t *ptr; 99 100 size += sizeof (size); 101 if (ptr = kmem_alloc(size, KM_NOSLEEP)) { 102 *ptr = size; 103 return (ptr + 1); 104 } 105 return (NULL); 106 } 107 108 /* ARGSUSED1 */ 109 void * 110 mi_alloc_sleep(size_t size, uint_t pri) 111 { 112 size_t *ptr; 113 114 size += sizeof (size); 115 ptr = kmem_alloc(size, KM_SLEEP); 116 *ptr = size; 117 return (ptr + 1); 118 } 119 120 int 121 mi_close_comm(void **mi_headp, queue_t *q) 122 { 123 IDP ptr; 124 125 ptr = q->q_ptr; 126 mi_close_unlink(mi_headp, ptr); 127 mi_close_free(ptr); 128 q->q_ptr = WR(q)->q_ptr = NULL; 129 return (0); 130 } 131 132 void 133 mi_close_unlink(void **mi_headp, IDP ptr) 134 { 135 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 136 MI_OP mi_o; 137 dev_t dev; 138 139 mi_o = (MI_OP)ptr; 140 if (!mi_o) 141 return; 142 mi_o--; 143 144 if (mi_o->mi_o_next == NULL) { 145 /* Not in list */ 146 ASSERT(mi_o->mi_o_prev == NULL); 147 return; 148 } 149 150 /* Free minor number */ 151 dev = mi_o->mi_o_dev; 152 if ((dev != OPENFAIL) && (dev != 0) && (dev <= MAXMIN)) 153 inet_minor_free(mi_head->mh_arena, dev); 154 155 /* Unlink from list */ 156 ASSERT(mi_o->mi_o_next != NULL); 157 ASSERT(mi_o->mi_o_prev != NULL); 158 ASSERT(mi_o->mi_o_next->mi_o_prev == mi_o); 159 ASSERT(mi_o->mi_o_prev->mi_o_next == mi_o); 160 161 mi_o->mi_o_next->mi_o_prev = mi_o->mi_o_prev; 162 mi_o->mi_o_prev->mi_o_next = mi_o->mi_o_next; 163 mi_o->mi_o_next = mi_o->mi_o_prev = NULL; 164 165 mi_o->mi_o_dev = (dev_t)OPENFAIL; 166 167 /* If list now empty free the list head */ 168 if (mi_head->mh_o.mi_o_next == &mi_head->mh_o) { 169 ASSERT(mi_head->mh_o.mi_o_prev == &mi_head->mh_o); 170 if (mi_head->mh_arena != NULL) 171 inet_minor_destroy(mi_head->mh_arena); 172 mi_free((IDP)mi_head); 173 *mi_headp = NULL; 174 } 175 } 176 177 void 178 mi_close_free(IDP ptr) 179 { 180 MI_OP mi_o; 181 182 mi_o = (MI_OP)ptr; 183 if (!mi_o) 184 return; 185 mi_o--; 186 187 ASSERT(mi_o->mi_o_next == NULL && mi_o->mi_o_prev == NULL); 188 mi_free((IDP)mi_o); 189 } 190 191 /* 192 * mi_copyin - takes care of transparent or non-transparent ioctl for the 193 * calling function so that they have to deal with just M_IOCDATA type 194 * and not worry about M_COPYIN. 195 * 196 * mi_copyin checks to see if the ioctl is transparent or non transparent. 197 * In case of a non_transparent ioctl, it packs the data into a M_IOCDATA 198 * message and puts it back onto the current queue for further processing. 199 * In case of transparent ioctl, it sends a M_COPYIN message up to the 200 * streamhead so that a M_IOCDATA with the information comes back down. 201 */ 202 void 203 mi_copyin(queue_t *q, MBLKP mp, char *uaddr, size_t len) 204 { 205 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 206 struct copyreq *cq = (struct copyreq *)mp->b_rptr; 207 struct copyresp *cp = (struct copyresp *)mp->b_rptr; 208 int err; 209 MBLKP mp1; 210 211 ASSERT(mp->b_datap->db_type == M_IOCTL && !uaddr); 212 213 /* A transparent ioctl. Send a M_COPYIN message to the streamhead. */ 214 if (iocp->ioc_count == TRANSPARENT) { 215 MI_COPY_COUNT(mp) = 1; 216 MI_COPY_DIRECTION(mp) = MI_COPY_IN; 217 cq->cq_private = mp->b_cont; 218 cq->cq_size = len; 219 cq->cq_flag = 0; 220 bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr)); 221 mp->b_cont = NULL; 222 mp->b_datap->db_type = M_COPYIN; 223 qreply(q, mp); 224 return; 225 } 226 227 /* 228 * A non-transparent ioctl. Need to convert into M_IOCDATA message. 229 * 230 * We allocate a 0 byte message block and put its address in 231 * cp_private. It also makes the b_prev field = 1 and b_next 232 * field = MI_COPY_IN for this 0 byte block. This is done to 233 * maintain compatibility with old code in mi_copy_state 234 * (which removes the empty block). 235 */ 236 err = miocpullup(mp, len); 237 if (err != 0) 238 goto err_ret; 239 240 mp1 = allocb(0, BPRI_MED); 241 if (mp1 == NULL) { 242 err = ENOMEM; 243 goto err_ret; 244 } 245 246 /* 247 * Temporarily insert mp1 between the M_IOCTL and M_DATA blocks so 248 * that we can use the MI_COPY_COUNT & MI_COPY_DIRECTION macros. 249 */ 250 mp1->b_cont = mp->b_cont; 251 mp->b_cont = mp1; 252 MI_COPY_COUNT(mp) = 1; 253 MI_COPY_DIRECTION(mp) = MI_COPY_IN; 254 mp->b_cont = mp1->b_cont; 255 mp1->b_cont = NULL; 256 257 /* 258 * Leave a pointer to the 0 byte block in cp_private field for 259 * future use by the mi_copy_* routines. 260 */ 261 mp->b_datap->db_type = M_IOCDATA; 262 cp->cp_private = mp1; 263 cp->cp_rval = NULL; 264 put(q, mp); 265 return; 266 267 err_ret: 268 iocp->ioc_error = err; 269 iocp->ioc_count = 0; 270 if (mp->b_cont) { 271 freemsg(mp->b_cont); 272 mp->b_cont = NULL; 273 } 274 mp->b_datap->db_type = M_IOCACK; 275 qreply(q, mp); 276 } 277 278 /* 279 * Allows transparent IOCTLs to have multiple copyins. This is needed 280 * for some variable-length structures, where the total size is only known 281 * after the first part is copied in. Rather than setting MI_COPY_COUNT to 282 * 1, as in mi_coypin(), it is simply incremented here. This value can 283 * then be checked in the returned IOCBLK. 284 * 285 * As this deals with copyins that follow the initial copyin, the byte 286 * offset into the user buffer from which copying should begin must be 287 * passed in in the offset parameter. 288 * 289 * Unlike mi_coypin(), this function expects to be passed an mblk chain 290 * headed by an M_IOCBLK, as that's the chain that will be in use for 291 * copies after the first one (copies where n != 1). 292 */ 293 void 294 mi_copyin_n(queue_t *q, MBLKP mp, size_t offset, size_t len) 295 { 296 struct copyreq *cq = (struct copyreq *)mp->b_rptr; 297 298 ASSERT(mp->b_datap->db_type == M_IOCDATA); 299 300 MI_COPY_COUNT(mp)++; 301 MI_COPY_DIRECTION(mp) = MI_COPY_IN; 302 cq->cq_private = mp->b_cont; 303 cq->cq_size = len; 304 cq->cq_flag = 0; 305 bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr)); 306 cq->cq_addr += offset; 307 mp->b_cont = NULL; 308 mp->b_datap->db_type = M_COPYIN; 309 qreply(q, mp); 310 } 311 312 void 313 mi_copyout(queue_t *q, MBLKP mp) 314 { 315 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 316 struct copyreq *cq = (struct copyreq *)iocp; 317 struct copyresp *cp = (struct copyresp *)cq; 318 MBLKP mp1; 319 MBLKP mp2; 320 321 if (mp->b_datap->db_type != M_IOCDATA || !mp->b_cont) { 322 mi_copy_done(q, mp, EPROTO); 323 return; 324 } 325 /* Check completion of previous copyout operation. */ 326 mp1 = mp->b_cont; 327 if ((int)(uintptr_t)cp->cp_rval || !mp1->b_cont) { 328 mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval); 329 return; 330 } 331 if (!mp1->b_cont->b_cont && !MI_IS_TRANSPARENT(mp)) { 332 mp1->b_next = NULL; 333 mp1->b_prev = NULL; 334 mp->b_cont = mp1->b_cont; 335 freeb(mp1); 336 mp1 = mp->b_cont; 337 mp1->b_next = NULL; 338 mp1->b_prev = NULL; 339 iocp->ioc_count = mp1->b_wptr - mp1->b_rptr; 340 iocp->ioc_error = 0; 341 mp->b_datap->db_type = M_IOCACK; 342 qreply(q, mp); 343 return; 344 } 345 if (MI_COPY_DIRECTION(mp) == MI_COPY_IN) { 346 /* Set up for first copyout. */ 347 MI_COPY_DIRECTION(mp) = MI_COPY_OUT; 348 MI_COPY_COUNT(mp) = 1; 349 } else { 350 ++MI_COPY_COUNT(mp); 351 } 352 cq->cq_private = mp1; 353 /* Find message preceding last. */ 354 for (mp2 = mp1; mp2->b_cont->b_cont; mp2 = mp2->b_cont) 355 ; 356 if (mp2 == mp1) 357 bcopy((char *)mp1->b_rptr, (char *)&cq->cq_addr, 358 sizeof (cq->cq_addr)); 359 else 360 cq->cq_addr = (char *)mp2->b_cont->b_next; 361 mp1 = mp2->b_cont; 362 mp->b_datap->db_type = M_COPYOUT; 363 mp->b_cont = mp1; 364 mp2->b_cont = NULL; 365 mp1->b_next = NULL; 366 cq->cq_size = mp1->b_wptr - mp1->b_rptr; 367 cq->cq_flag = 0; 368 qreply(q, mp); 369 } 370 371 MBLKP 372 mi_copyout_alloc(queue_t *q, MBLKP mp, char *uaddr, size_t len, 373 boolean_t free_on_error) 374 { 375 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 376 MBLKP mp1; 377 378 if (mp->b_datap->db_type == M_IOCTL) { 379 if (iocp->ioc_count != TRANSPARENT) { 380 mp1 = allocb(0, BPRI_MED); 381 if (mp1 == NULL) { 382 if (free_on_error) { 383 iocp->ioc_error = ENOMEM; 384 iocp->ioc_count = 0; 385 freemsg(mp->b_cont); 386 mp->b_cont = NULL; 387 mp->b_datap->db_type = M_IOCACK; 388 qreply(q, mp); 389 } 390 return (NULL); 391 } 392 mp1->b_cont = mp->b_cont; 393 mp->b_cont = mp1; 394 } 395 MI_COPY_COUNT(mp) = 0; 396 MI_COPY_DIRECTION(mp) = MI_COPY_OUT; 397 /* Make sure it looks clean to mi_copyout. */ 398 mp->b_datap->db_type = M_IOCDATA; 399 ((struct copyresp *)iocp)->cp_rval = NULL; 400 } 401 mp1 = allocb(len, BPRI_MED); 402 if (mp1 == NULL) { 403 if (free_on_error) 404 mi_copy_done(q, mp, ENOMEM); 405 return (NULL); 406 } 407 linkb(mp, mp1); 408 mp1->b_next = (MBLKP)uaddr; 409 return (mp1); 410 } 411 412 void 413 mi_copy_done(queue_t *q, MBLKP mp, int err) 414 { 415 struct iocblk *iocp; 416 MBLKP mp1; 417 418 if (!mp) 419 return; 420 if (!q || (mp->b_wptr - mp->b_rptr) < sizeof (struct iocblk)) { 421 freemsg(mp); 422 return; 423 } 424 iocp = (struct iocblk *)mp->b_rptr; 425 mp->b_datap->db_type = M_IOCACK; 426 iocp->ioc_error = err; 427 428 iocp->ioc_count = 0; 429 if ((mp1 = mp->b_cont) != NULL) { 430 for (; mp1; mp1 = mp1->b_cont) { 431 mp1->b_prev = NULL; 432 mp1->b_next = NULL; 433 } 434 freemsg(mp->b_cont); 435 mp->b_cont = NULL; 436 } 437 qreply(q, mp); 438 } 439 440 int 441 mi_copy_state(queue_t *q, MBLKP mp, MBLKP *mpp) 442 { 443 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 444 struct copyresp *cp = (struct copyresp *)iocp; 445 MBLKP mp1; 446 447 mp1 = mp->b_cont; 448 mp->b_cont = cp->cp_private; 449 if (mp1) { 450 if (mp1->b_cont && !pullupmsg(mp1, -1)) { 451 mi_copy_done(q, mp, ENOMEM); 452 return (-1); 453 } 454 linkb(mp->b_cont, mp1); 455 } 456 if ((int)(uintptr_t)cp->cp_rval) { 457 mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval); 458 return (-1); 459 } 460 if (mpp && MI_COPY_DIRECTION(mp) == MI_COPY_IN) 461 *mpp = mp1; 462 return (MI_COPY_STATE(mp)); 463 } 464 465 void 466 mi_free(void *ptr) 467 { 468 size_t size; 469 470 if (!ptr) 471 return; 472 if ((size = ((size_t *)ptr)[-1]) <= 0) 473 cmn_err(CE_PANIC, "mi_free"); 474 475 kmem_free((void *) ((size_t *)ptr - 1), size); 476 } 477 478 static int 479 mi_iprintf(char *fmt, va_list ap, pfi_t putc_func, char *cookie) 480 { 481 int base; 482 char buf[(sizeof (long) * 3) + 1]; 483 static char hex_val[] = "0123456789abcdef"; 484 int ch; 485 int count; 486 char *cp1; 487 int digits; 488 char *fcp; 489 boolean_t is_long; 490 ulong_t uval; 491 long val; 492 boolean_t zero_filled; 493 494 if (!fmt) 495 return (-1); 496 count = 0; 497 while (*fmt) { 498 if (*fmt != '%' || *++fmt == '%') { 499 count += (*putc_func)(cookie, *fmt++); 500 continue; 501 } 502 if (*fmt == '0') { 503 zero_filled = B_TRUE; 504 fmt++; 505 if (!*fmt) 506 break; 507 } else 508 zero_filled = B_FALSE; 509 base = 0; 510 for (digits = 0; ISDIGIT(*fmt); fmt++) { 511 digits *= 10; 512 digits += (*fmt - '0'); 513 } 514 if (!*fmt) 515 break; 516 is_long = B_FALSE; 517 if (*fmt == 'l') { 518 is_long = B_TRUE; 519 fmt++; 520 } 521 if (!*fmt) 522 break; 523 ch = *fmt++; 524 if (ISUPPER(ch)) { 525 ch = tolower(ch); 526 is_long = B_TRUE; 527 } 528 switch (ch) { 529 case 'c': 530 count += (*putc_func)(cookie, va_arg(ap, int *)); 531 continue; 532 case 'd': 533 base = 10; 534 break; 535 case 'm': /* Print out memory, 2 hex chars per byte */ 536 if (is_long) 537 fcp = va_arg(ap, char *); 538 else { 539 if ((cp1 = va_arg(ap, char *)) != NULL) 540 fcp = (char *)cp1; 541 else 542 fcp = NULL; 543 } 544 if (!fcp) { 545 for (fcp = (char *)"(NULL)"; *fcp; fcp++) 546 count += (*putc_func)(cookie, *fcp); 547 } else { 548 while (digits--) { 549 int u1 = *fcp++ & 0xFF; 550 count += (*putc_func)(cookie, 551 hex_val[(u1>>4)& 0xF]); 552 count += (*putc_func)(cookie, 553 hex_val[u1& 0xF]); 554 } 555 } 556 continue; 557 case 'o': 558 base = 8; 559 break; 560 case 'p': 561 is_long = B_TRUE; 562 /* FALLTHRU */ 563 case 'x': 564 base = 16; 565 break; 566 case 's': 567 if (is_long) 568 fcp = va_arg(ap, char *); 569 else { 570 if ((cp1 = va_arg(ap, char *)) != NULL) 571 fcp = (char *)cp1; 572 else 573 fcp = NULL; 574 } 575 if (!fcp) 576 fcp = (char *)"(NULL)"; 577 while (*fcp) { 578 count += (*putc_func)(cookie, *fcp++); 579 if (digits && --digits == 0) 580 break; 581 } 582 while (digits > 0) { 583 count += (*putc_func)(cookie, ' '); 584 digits--; 585 } 586 continue; 587 case 'u': 588 base = 10; 589 break; 590 default: 591 return (count); 592 } 593 if (is_long) 594 val = va_arg(ap, long); 595 else 596 val = va_arg(ap, int); 597 if (base == 10 && ch != 'u') { 598 if (val < 0) { 599 count += (*putc_func)(cookie, '-'); 600 val = -val; 601 } 602 uval = val; 603 } else { 604 if (is_long) 605 uval = val; 606 else 607 uval = (uint_t)val; 608 } 609 /* Hand overload/restore the register variable 'fmt' */ 610 cp1 = fmt; 611 fmt = A_END(buf); 612 *--fmt = '\0'; 613 do { 614 if (fmt > buf) 615 *--fmt = hex_val[uval % base]; 616 if (digits && --digits == 0) 617 break; 618 } while (uval /= base); 619 if (zero_filled) { 620 while (digits > 0 && fmt > buf) { 621 *--fmt = '0'; 622 digits--; 623 } 624 } 625 while (*fmt) 626 count += (*putc_func)(cookie, *fmt++); 627 fmt = cp1; 628 } 629 return (count); 630 } 631 632 /* PRINTFLIKE2 */ 633 int 634 mi_mpprintf(MBLKP mp, char *fmt, ...) 635 { 636 va_list ap; 637 int count = -1; 638 639 va_start(ap, fmt); 640 if (mp) { 641 count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc, 642 (char *)mp); 643 if (count != -1) 644 (void) mi_mpprintf_putc((char *)mp, '\0'); 645 } 646 va_end(ap); 647 return (count); 648 } 649 650 /* PRINTFLIKE2 */ 651 int 652 mi_mpprintf_nr(MBLKP mp, char *fmt, ...) 653 { 654 va_list ap; 655 int count = -1; 656 657 va_start(ap, fmt); 658 if (mp) { 659 (void) adjmsg(mp, -1); 660 count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc, 661 (char *)mp); 662 if (count != -1) 663 (void) mi_mpprintf_putc((char *)mp, '\0'); 664 } 665 va_end(ap); 666 return (count); 667 } 668 669 int 670 mi_mpprintf_putc(char *cookie, int ch) 671 { 672 MBLKP mp = (MBLKP)cookie; 673 674 while (mp->b_cont) 675 mp = mp->b_cont; 676 if (mp->b_wptr >= mp->b_datap->db_lim) { 677 mp->b_cont = allocb(1024, BPRI_HI); 678 mp = mp->b_cont; 679 if (!mp) 680 return (0); 681 } 682 *mp->b_wptr++ = (unsigned char)ch; 683 return (1); 684 } 685 686 IDP 687 mi_first_ptr(void **mi_headp) 688 { 689 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 690 MI_OP mi_op; 691 692 mi_op = mi_head->mh_o.mi_o_next; 693 if (mi_op && mi_op != &mi_head->mh_o) 694 return ((IDP)&mi_op[1]); 695 return (NULL); 696 } 697 698 /* 699 * Clients can choose to have both module instances and device instances 700 * in the same list. Return the first device instance in the list. 701 */ 702 IDP 703 mi_first_dev_ptr(void **mi_headp) 704 { 705 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 706 MI_OP mi_op; 707 708 mi_op = mi_head->mh_o.mi_o_next; 709 while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) { 710 if (mi_op->mi_o_isdev) 711 return ((IDP)&mi_op[1]); 712 mi_op = mi_op->mi_o_next; 713 } 714 return (NULL); 715 } 716 717 IDP 718 mi_next_ptr(void **mi_headp, IDP ptr) 719 { 720 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 721 MI_OP mi_op = ((MI_OP)ptr) - 1; 722 723 if ((mi_op = mi_op->mi_o_next) != NULL && mi_op != &mi_head->mh_o) 724 return ((IDP)&mi_op[1]); 725 return (NULL); 726 } 727 728 /* 729 * Clients can choose to have both module instances and device instances 730 * in the same list. Return the next device instance in the list. 731 */ 732 IDP 733 mi_next_dev_ptr(void **mi_headp, IDP ptr) 734 { 735 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 736 MI_OP mi_op = ((MI_OP)ptr) - 1; 737 738 mi_op = mi_op->mi_o_next; 739 while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) { 740 if (mi_op->mi_o_isdev) 741 return ((IDP)&mi_op[1]); 742 mi_op = mi_op->mi_o_next; 743 } 744 return (NULL); 745 } 746 747 /* 748 * Self clone the device 749 * XXX - should we still support clone device 750 */ 751 /* ARGSUSED4 */ 752 int 753 mi_open_comm(void **mi_headp, size_t size, queue_t *q, dev_t *devp, 754 int flag, int sflag, cred_t *credp) 755 { 756 int error; 757 IDP ptr; 758 759 if (q->q_ptr != NULL) 760 return (0); 761 762 ptr = mi_open_alloc_sleep(size); 763 q->q_ptr = WR(q)->q_ptr = ptr; 764 error = mi_open_link(mi_headp, ptr, devp, flag, sflag, credp); 765 if (error != 0) { 766 q->q_ptr = WR(q)->q_ptr = NULL; 767 mi_close_free(ptr); 768 } 769 return (error); 770 } 771 772 IDP 773 mi_open_alloc_sleep(size_t size) 774 { 775 MI_OP mi_o; 776 777 if (size > (UINT_MAX - sizeof (MI_O))) 778 return (NULL); 779 780 mi_o = (MI_OP)mi_zalloc_sleep(size + sizeof (MI_O)); 781 mi_o++; 782 return ((IDP)mi_o); 783 } 784 785 IDP 786 mi_open_alloc(size_t size) 787 { 788 MI_OP mi_o; 789 790 if (size > (UINT_MAX - sizeof (MI_O))) 791 return (NULL); 792 793 if ((mi_o = (MI_OP)mi_zalloc(size + sizeof (MI_O))) == NULL) 794 return (NULL); 795 mi_o++; 796 return ((IDP)mi_o); 797 } 798 799 /* 800 * MODOPEN means just link in without respect of mi_o_dev. 801 * A NULL devp can be used to create a detached instance 802 * Otherwise self-clone the device. 803 */ 804 /* ARGSUSED3 */ 805 int 806 mi_open_link(void **mi_headp, IDP ptr, dev_t *devp, int flag, int sflag, 807 cred_t *credp) 808 { 809 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 810 MI_OP insert; 811 MI_OP mi_o; 812 dev_t dev; 813 814 if (mi_head == NULL) { 815 char arena_name[50]; 816 char *head_name; 817 ulong_t offset; 818 819 head_name = kobj_getsymname((uintptr_t)mi_headp, &offset); 820 if (head_name != NULL && offset == 0) { 821 (void) sprintf(arena_name, "%s_", head_name); 822 } else { 823 (void) sprintf(arena_name, "Hex0x%p_", 824 (void *)mi_headp); 825 } 826 (void) sprintf(strchr(arena_name, '_') + 1, "minor"); 827 mi_head = (mi_head_t *)mi_zalloc_sleep(sizeof (mi_head_t)); 828 *mi_headp = (void *)mi_head; 829 /* Setup doubly linked list */ 830 mi_head->mh_o.mi_o_next = &mi_head->mh_o; 831 mi_head->mh_o.mi_o_prev = &mi_head->mh_o; 832 mi_head->mh_o.mi_o_dev = 0; /* For asserts only */ 833 mi_head->mh_arena = (vmem_t *)inet_minor_create(arena_name, 834 INET_MIN_DEV, MAXMIN, KM_SLEEP); 835 } 836 ASSERT(ptr != NULL); 837 mi_o = (MI_OP)ptr; 838 mi_o--; 839 840 if (sflag == MODOPEN) { 841 devp = NULL; 842 /* 843 * Set device number to MAXMIN + incrementing number. 844 */ 845 dev = MAXMIN + ++mi_head->mh_module_dev; 846 /* check for wraparound */ 847 if (dev <= MAXMIN) { 848 dev = MAXMIN + 1; 849 mi_head->mh_module_dev = 1; 850 } 851 } else if (devp == NULL) { 852 /* Detached open */ 853 dev = (dev_t)OPENFAIL; 854 } else if ((dev = inet_minor_alloc(mi_head->mh_arena)) == 0) { 855 return (EBUSY); 856 } 857 858 mi_o->mi_o_dev = dev; 859 insert = (&mi_head->mh_o); 860 mi_o->mi_o_next = insert; 861 insert->mi_o_prev->mi_o_next = mi_o; 862 mi_o->mi_o_prev = insert->mi_o_prev; 863 insert->mi_o_prev = mi_o; 864 865 if (sflag == MODOPEN) 866 mi_o->mi_o_isdev = B_FALSE; 867 else 868 mi_o->mi_o_isdev = B_TRUE; 869 870 if (devp) 871 *devp = makedevice(getemajor(*devp), (minor_t)dev); 872 return (0); 873 } 874 875 uint8_t * 876 mi_offset_param(mblk_t *mp, size_t offset, size_t len) 877 { 878 size_t msg_len; 879 880 if (!mp) 881 return (NULL); 882 msg_len = mp->b_wptr - mp->b_rptr; 883 if (msg_len == 0 || offset > msg_len || len > msg_len || 884 (offset + len) > msg_len || len == 0) 885 return (NULL); 886 return (&mp->b_rptr[offset]); 887 } 888 889 uint8_t * 890 mi_offset_paramc(mblk_t *mp, size_t offset, size_t len) 891 { 892 uint8_t *param; 893 894 for (; mp; mp = mp->b_cont) { 895 int type = mp->b_datap->db_type; 896 if (datamsg(type)) { 897 if (param = mi_offset_param(mp, offset, len)) 898 return (param); 899 if (offset < mp->b_wptr - mp->b_rptr) 900 break; 901 offset -= mp->b_wptr - mp->b_rptr; 902 } 903 } 904 return (NULL); 905 } 906 907 int 908 mi_sprintf(char *buf, char *fmt, ...) 909 { 910 va_list ap; 911 int count = -1; 912 va_start(ap, fmt); 913 if (buf) { 914 count = mi_iprintf(fmt, ap, (pfi_t)mi_sprintf_putc, 915 (char *)&buf); 916 if (count != -1) 917 (void) mi_sprintf_putc((char *)&buf, '\0'); 918 } 919 va_end(ap); 920 return (count); 921 } 922 923 /* Used to count without writing data */ 924 /* ARGSUSED1 */ 925 static int 926 mi_sprintf_noop(char *cookie, int ch) 927 { 928 char **cpp = (char **)cookie; 929 930 (*cpp)++; 931 return (1); 932 } 933 934 int 935 mi_sprintf_putc(char *cookie, int ch) 936 { 937 char **cpp = (char **)cookie; 938 939 **cpp = (char)ch; 940 (*cpp)++; 941 return (1); 942 } 943 944 int 945 mi_strcmp(const char *cp1, const char *cp2) 946 { 947 while (*cp1++ == *cp2++) { 948 if (!cp2[-1]) 949 return (0); 950 } 951 return ((uint_t)cp2[-1] & 0xFF) - ((uint_t)cp1[-1] & 0xFF); 952 } 953 954 size_t 955 mi_strlen(const char *str) 956 { 957 const char *cp = str; 958 959 while (*cp != '\0') 960 cp++; 961 return ((int)(cp - str)); 962 } 963 964 int 965 mi_strlog(queue_t *q, char level, ushort_t flags, char *fmt, ...) 966 { 967 va_list ap; 968 char buf[200]; 969 char *alloc_buf = buf; 970 int count = -1; 971 char *cp; 972 short mid; 973 int ret; 974 short sid; 975 976 sid = 0; 977 mid = 0; 978 if (q != NULL) { 979 mid = q->q_qinfo->qi_minfo->mi_idnum; 980 } 981 982 /* Find out how many bytes we need and allocate if necesary */ 983 va_start(ap, fmt); 984 cp = buf; 985 count = mi_iprintf(fmt, ap, mi_sprintf_noop, (char *)&cp); 986 if (count > sizeof (buf) && 987 !(alloc_buf = mi_alloc((uint_t)count + 2, BPRI_MED))) { 988 va_end(ap); 989 return (-1); 990 } 991 va_end(ap); 992 993 va_start(ap, fmt); 994 cp = alloc_buf; 995 count = mi_iprintf(fmt, ap, mi_sprintf_putc, (char *)&cp); 996 if (count != -1) 997 (void) mi_sprintf_putc((char *)&cp, '\0'); 998 else 999 alloc_buf[0] = '\0'; 1000 va_end(ap); 1001 1002 ret = strlog(mid, sid, level, flags, alloc_buf); 1003 if (alloc_buf != buf) 1004 mi_free(alloc_buf); 1005 return (ret); 1006 } 1007 1008 long 1009 mi_strtol(const char *str, char **ptr, int base) 1010 { 1011 const char *cp; 1012 int digits; 1013 long value; 1014 boolean_t is_negative; 1015 1016 cp = str; 1017 while (*cp == ' ' || *cp == '\t' || *cp == '\n') 1018 cp++; 1019 is_negative = (*cp == '-'); 1020 if (is_negative) 1021 cp++; 1022 if (base == 0) { 1023 base = 10; 1024 if (*cp == '0') { 1025 base = 8; 1026 cp++; 1027 if (*cp == 'x' || *cp == 'X') { 1028 base = 16; 1029 cp++; 1030 } 1031 } 1032 } 1033 value = 0; 1034 for (; *cp != '\0'; cp++) { 1035 if (*cp >= '0' && *cp <= '9') 1036 digits = *cp - '0'; 1037 else if (*cp >= 'a' && *cp <= 'f') 1038 digits = *cp - 'a' + 10; 1039 else if (*cp >= 'A' && *cp <= 'F') 1040 digits = *cp - 'A' + 10; 1041 else 1042 break; 1043 if (digits >= base) 1044 break; 1045 value = (value * base) + digits; 1046 } 1047 /* Note: we cast away const here deliberately */ 1048 if (ptr != NULL) 1049 *ptr = (char *)cp; 1050 if (is_negative) 1051 value = -value; 1052 return (value); 1053 } 1054 1055 /* 1056 * mi_timer mechanism. 1057 * 1058 * Each timer is represented by a timer mblk and a (streams) queue. When the 1059 * timer fires the timer mblk will be put on the associated streams queue 1060 * so that the streams module can process the timer even in its service 1061 * procedure. 1062 * 1063 * The interface consists of 4 entry points: 1064 * mi_timer_alloc - create a timer mblk 1065 * mi_timer_free - free a timer mblk 1066 * mi_timer - start, restart, stop, or move the 1067 * timer to a different queue 1068 * mi_timer_valid - called by streams module to verify that 1069 * the timer did indeed fire. 1070 */ 1071 1072 1073 1074 1075 /* 1076 * Start, restart, stop, or move the timer to a new queue. 1077 * If "tim" is -2 the timer is moved to a different queue. 1078 * If "tim" is -1 the timer is stopped. 1079 * Otherwise, the timer is stopped if it is already running, and 1080 * set to fire tim milliseconds from now. 1081 */ 1082 1083 void 1084 mi_timer(queue_t *q, MBLKP mp, clock_t tim) 1085 { 1086 MTBP mtb; 1087 int state; 1088 1089 ASSERT(tim >= -2); 1090 if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB)) 1091 return; 1092 mtb = (MTBP)mp->b_datap->db_base; 1093 ASSERT(mp->b_datap->db_type == M_PCSIG); 1094 if (tim >= 0) { 1095 mtb->mtb_q = q; 1096 state = mtb->mtb_state; 1097 tim = MSEC_TO_TICK(tim); 1098 if (state == TB_RUNNING) { 1099 if (untimeout(mtb->mtb_tid) < 0) { 1100 /* Message has already been putq */ 1101 ASSERT(mtb->mtb_q->q_first == mp || 1102 mp->b_prev || mp->b_next); 1103 mtb->mtb_state = TB_RESCHED; 1104 mtb->mtb_time_left = tim; 1105 /* mi_timer_valid will start timer */ 1106 return; 1107 } 1108 } else if (state != TB_IDLE) { 1109 ASSERT(state != TB_TO_BE_FREED); 1110 if (state == TB_CANCELLED) { 1111 ASSERT(mtb->mtb_q->q_first == mp || 1112 mp->b_prev || mp->b_next); 1113 mtb->mtb_state = TB_RESCHED; 1114 mtb->mtb_time_left = tim; 1115 /* mi_timer_valid will start timer */ 1116 return; 1117 } 1118 if (state == TB_RESCHED) { 1119 ASSERT(mtb->mtb_q->q_first == mp || 1120 mp->b_prev || mp->b_next); 1121 mtb->mtb_time_left = tim; 1122 /* mi_timer_valid will start timer */ 1123 return; 1124 } 1125 } 1126 mtb->mtb_state = TB_RUNNING; 1127 mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim); 1128 return; 1129 } 1130 switch (tim) { 1131 case -1: 1132 mi_timer_stop(mp); 1133 break; 1134 case -2: 1135 mi_timer_move(q, mp); 1136 break; 1137 } 1138 } 1139 1140 /* 1141 * Allocate an M_PCSIG timer message. The space between db_base and 1142 * b_rptr is used by the mi_timer mechanism, and after b_rptr there are 1143 * "size" bytes that the caller can use for its own purposes. 1144 * 1145 * Note that db_type has to be a priority message since otherwise 1146 * the putq will not cause the service procedure to run when 1147 * there is flow control. 1148 */ 1149 MBLKP 1150 mi_timer_alloc(size_t size) 1151 { 1152 MBLKP mp; 1153 MTBP mtb; 1154 1155 if ((mp = allocb(size + sizeof (MTB), BPRI_HI)) != NULL) { 1156 mp->b_datap->db_type = M_PCSIG; 1157 mtb = (MTBP)mp->b_datap->db_base; 1158 mp->b_rptr = (uchar_t *)&mtb[1]; 1159 mp->b_wptr = mp->b_rptr + size; 1160 mtb->mtb_state = TB_IDLE; 1161 mtb->mtb_mp = mp; 1162 mtb->mtb_q = NULL; 1163 return (mp); 1164 } 1165 return (NULL); 1166 } 1167 1168 /* 1169 * timeout() callback function. 1170 * Put the message on the current queue. 1171 * If the timer is stopped or moved to a different queue after 1172 * it has fired then mi_timer() and mi_timer_valid() will clean 1173 * things up. 1174 */ 1175 static int 1176 mi_timer_fire(MTBP mtb) 1177 { 1178 ASSERT(mtb == (MTBP)mtb->mtb_mp->b_datap->db_base); 1179 ASSERT(mtb->mtb_mp->b_datap->db_type == M_PCSIG); 1180 return (putq(mtb->mtb_q, mtb->mtb_mp)); 1181 } 1182 1183 /* 1184 * Logically free a timer mblk (that might have a pending timeout().) 1185 * If the timer has fired and the mblk has been put on the queue then 1186 * mi_timer_valid will free the mblk. 1187 */ 1188 1189 void 1190 mi_timer_free(MBLKP mp) 1191 { 1192 MTBP mtb; 1193 int state; 1194 1195 if (!mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB)) 1196 return; 1197 mtb = (MTBP)mp->b_datap->db_base; 1198 state = mtb->mtb_state; 1199 if (state == TB_RUNNING) { 1200 if (untimeout(mtb->mtb_tid) < 0) { 1201 /* Message has already been putq */ 1202 ASSERT(mtb->mtb_q->q_first == mp || 1203 mp->b_prev || mp->b_next); 1204 mtb->mtb_state = TB_TO_BE_FREED; 1205 /* mi_timer_valid will free the mblk */ 1206 return; 1207 } 1208 } else if (state != TB_IDLE) { 1209 /* Message has already been putq */ 1210 ASSERT(mtb->mtb_q->q_first == mp || 1211 mp->b_prev || mp->b_next); 1212 ASSERT(state != TB_TO_BE_FREED); 1213 mtb->mtb_state = TB_TO_BE_FREED; 1214 /* mi_timer_valid will free the mblk */ 1215 return; 1216 } 1217 ASSERT(mtb->mtb_q == NULL || mtb->mtb_q->q_first != mp); 1218 freemsg(mp); 1219 } 1220 1221 /* 1222 * Called from mi_timer(,,-2) 1223 */ 1224 void 1225 mi_timer_move(queue_t *q, MBLKP mp) 1226 { 1227 MTBP mtb; 1228 clock_t tim; 1229 1230 if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB)) 1231 return; 1232 1233 mtb = (MTBP)mp->b_datap->db_base; 1234 /* 1235 * Need to untimeout and restart to make 1236 * sure that the mblk is not about to be putq on the old queue 1237 * by mi_timer_fire. 1238 */ 1239 if (mtb->mtb_state == TB_RUNNING) { 1240 if ((tim = untimeout(mtb->mtb_tid)) < 0) { 1241 /* 1242 * Message has already been putq. Move from old queue 1243 * to new queue. 1244 */ 1245 ASSERT(mtb->mtb_q->q_first == mp || 1246 mp->b_prev || mp->b_next); 1247 rmvq(mtb->mtb_q, mp); 1248 ASSERT(mtb->mtb_q->q_first != mp && 1249 mp->b_prev == NULL && mp->b_next == NULL); 1250 mtb->mtb_q = q; 1251 (void) putq(mtb->mtb_q, mp); 1252 return; 1253 } 1254 mtb->mtb_q = q; 1255 mtb->mtb_state = TB_RUNNING; 1256 mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim); 1257 } else if (mtb->mtb_state != TB_IDLE) { 1258 ASSERT(mtb->mtb_state != TB_TO_BE_FREED); 1259 /* 1260 * Message is already sitting on queue. Move to new queue. 1261 */ 1262 ASSERT(mtb->mtb_q->q_first == mp || 1263 mp->b_prev || mp->b_next); 1264 rmvq(mtb->mtb_q, mp); 1265 ASSERT(mtb->mtb_q->q_first != mp && 1266 mp->b_prev == NULL && mp->b_next == NULL); 1267 mtb->mtb_q = q; 1268 (void) putq(mtb->mtb_q, mp); 1269 } else 1270 mtb->mtb_q = q; 1271 } 1272 1273 /* 1274 * Called from mi_timer(,,-1) 1275 */ 1276 void 1277 mi_timer_stop(MBLKP mp) 1278 { 1279 MTBP mtb; 1280 int state; 1281 1282 if (!mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB)) 1283 return; 1284 1285 mtb = (MTBP)mp->b_datap->db_base; 1286 state = mtb->mtb_state; 1287 if (state == TB_RUNNING) { 1288 if (untimeout(mtb->mtb_tid) < 0) { 1289 /* Message has already been putq */ 1290 ASSERT(mtb->mtb_q->q_first == mp || 1291 mp->b_prev || mp->b_next); 1292 mtb->mtb_state = TB_CANCELLED; 1293 } else { 1294 mtb->mtb_state = TB_IDLE; 1295 } 1296 } else if (state == TB_RESCHED) { 1297 ASSERT(mtb->mtb_q->q_first == mp || 1298 mp->b_prev || mp->b_next); 1299 mtb->mtb_state = TB_CANCELLED; 1300 } 1301 } 1302 1303 /* 1304 * The user of the mi_timer mechanism is required to call mi_timer_valid() for 1305 * each M_PCSIG message processed in the service procedures. 1306 * mi_timer_valid will return "true" if the timer actually did fire. 1307 */ 1308 1309 boolean_t 1310 mi_timer_valid(MBLKP mp) 1311 { 1312 MTBP mtb; 1313 int state; 1314 1315 if (!mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB) || 1316 mp->b_datap->db_type != M_PCSIG) 1317 return (B_FALSE); 1318 mtb = (MTBP)mp->b_datap->db_base; 1319 state = mtb->mtb_state; 1320 if (state != TB_RUNNING) { 1321 ASSERT(state != TB_IDLE); 1322 if (state == TB_TO_BE_FREED) { 1323 /* 1324 * mi_timer_free was called after the message 1325 * was putq'ed. 1326 */ 1327 freemsg(mp); 1328 return (B_FALSE); 1329 } 1330 if (state == TB_CANCELLED) { 1331 /* The timer was stopped after the mblk was putq'ed */ 1332 mtb->mtb_state = TB_IDLE; 1333 return (B_FALSE); 1334 } 1335 if (state == TB_RESCHED) { 1336 /* 1337 * The timer was stopped and then restarted after 1338 * the mblk was putq'ed. 1339 * mtb_time_left contains the number of ticks that 1340 * the timer was restarted with. 1341 */ 1342 mtb->mtb_state = TB_RUNNING; 1343 mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, 1344 mtb, mtb->mtb_time_left); 1345 return (B_FALSE); 1346 } 1347 } 1348 mtb->mtb_state = TB_IDLE; 1349 return (B_TRUE); 1350 } 1351 1352 static void 1353 mi_tpi_addr_and_opt(MBLKP mp, char *addr, t_scalar_t addr_length, 1354 char *opt, t_scalar_t opt_length) 1355 { 1356 struct T_unitdata_ind *tudi; 1357 1358 /* 1359 * This code is used more than just for unitdata ind 1360 * (also for T_CONN_IND and T_CONN_CON) and 1361 * relies on correct functioning on the happy 1362 * coincidence that the address and option buffers 1363 * represented by length/offset in all these primitives 1364 * are isomorphic in terms of offset from start of data 1365 * structure 1366 */ 1367 tudi = (struct T_unitdata_ind *)mp->b_rptr; 1368 tudi->SRC_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr); 1369 tudi->SRC_length = addr_length; 1370 if (addr_length > 0) { 1371 bcopy(addr, (char *)mp->b_wptr, addr_length); 1372 mp->b_wptr += addr_length; 1373 } 1374 tudi->OPT_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr); 1375 tudi->OPT_length = opt_length; 1376 if (opt_length > 0) { 1377 bcopy(opt, (char *)mp->b_wptr, opt_length); 1378 mp->b_wptr += opt_length; 1379 } 1380 } 1381 1382 MBLKP 1383 mi_tpi_conn_con(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt, 1384 t_scalar_t opt_length) 1385 { 1386 size_t len; 1387 MBLKP mp; 1388 1389 len = sizeof (struct T_conn_con) + src_length + opt_length; 1390 if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_CON)) != NULL) { 1391 mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_con)]; 1392 mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length); 1393 } 1394 return (mp); 1395 } 1396 1397 MBLKP 1398 mi_tpi_conn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt, 1399 t_scalar_t opt_length, t_scalar_t seqnum) 1400 { 1401 size_t len; 1402 MBLKP mp; 1403 1404 len = sizeof (struct T_conn_ind) + src_length + opt_length; 1405 if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_IND)) != NULL) { 1406 mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_ind)]; 1407 mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length); 1408 ((struct T_conn_ind *)mp->b_rptr)->SEQ_number = seqnum; 1409 mp->b_datap->db_type = M_PROTO; 1410 } 1411 return (mp); 1412 } 1413 1414 MBLKP 1415 mi_tpi_extconn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length, 1416 char *opt, t_scalar_t opt_length, char *dst, t_scalar_t dst_length, 1417 t_scalar_t seqnum) 1418 { 1419 size_t len; 1420 MBLKP mp; 1421 1422 len = sizeof (struct T_extconn_ind) + src_length + opt_length + 1423 dst_length; 1424 if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_EXTCONN_IND)) != 1425 NULL) { 1426 mp->b_wptr = &mp->b_rptr[sizeof (struct T_extconn_ind)]; 1427 mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length); 1428 ((struct T_extconn_ind *)mp->b_rptr)->DEST_length = dst_length; 1429 ((struct T_extconn_ind *)mp->b_rptr)->DEST_offset = 1430 (t_scalar_t)(mp->b_wptr - mp->b_rptr); 1431 if (dst_length > 0) { 1432 bcopy(dst, (char *)mp->b_wptr, dst_length); 1433 mp->b_wptr += dst_length; 1434 } 1435 ((struct T_extconn_ind *)mp->b_rptr)->SEQ_number = seqnum; 1436 mp->b_datap->db_type = M_PROTO; 1437 } 1438 return (mp); 1439 } 1440 1441 MBLKP 1442 mi_tpi_discon_ind(MBLKP trailer_mp, t_scalar_t reason, t_scalar_t seqnum) 1443 { 1444 MBLKP mp; 1445 struct T_discon_ind *tdi; 1446 1447 if ((mp = mi_tpi_trailer_alloc(trailer_mp, 1448 sizeof (struct T_discon_ind), T_DISCON_IND)) != NULL) { 1449 tdi = (struct T_discon_ind *)mp->b_rptr; 1450 tdi->DISCON_reason = reason; 1451 tdi->SEQ_number = seqnum; 1452 } 1453 return (mp); 1454 } 1455 1456 /* 1457 * Allocate and fill in a TPI err ack packet using the 'mp' passed in 1458 * for the 'error_prim' context as well as sacrifice. 1459 */ 1460 MBLKP 1461 mi_tpi_err_ack_alloc(MBLKP mp, t_scalar_t tlierr, int unixerr) 1462 { 1463 struct T_error_ack *teackp; 1464 t_scalar_t error_prim; 1465 1466 if (!mp) 1467 return (NULL); 1468 error_prim = ((TPRIMP)mp->b_rptr)->type; 1469 if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack), 1470 M_PCPROTO, T_ERROR_ACK)) != NULL) { 1471 teackp = (struct T_error_ack *)mp->b_rptr; 1472 teackp->ERROR_prim = error_prim; 1473 teackp->TLI_error = tlierr; 1474 teackp->UNIX_error = unixerr; 1475 } 1476 return (mp); 1477 } 1478 1479 MBLKP 1480 mi_tpi_ok_ack_alloc_extra(MBLKP mp, int extra) 1481 { 1482 t_scalar_t correct_prim; 1483 1484 if (!mp) 1485 return (NULL); 1486 correct_prim = ((TPRIMP)mp->b_rptr)->type; 1487 if ((mp = tpi_ack_alloc(mp, sizeof (struct T_ok_ack) + extra, 1488 M_PCPROTO, T_OK_ACK)) != NULL) { 1489 ((struct T_ok_ack *)mp->b_rptr)->CORRECT_prim = correct_prim; 1490 mp->b_wptr -= extra; 1491 } 1492 return (mp); 1493 } 1494 1495 MBLKP 1496 mi_tpi_ok_ack_alloc(MBLKP mp) 1497 { 1498 return (mi_tpi_ok_ack_alloc_extra(mp, 0)); 1499 } 1500 1501 MBLKP 1502 mi_tpi_ordrel_ind(void) 1503 { 1504 MBLKP mp; 1505 1506 if ((mp = allocb(sizeof (struct T_ordrel_ind), BPRI_HI)) != NULL) { 1507 mp->b_datap->db_type = M_PROTO; 1508 ((struct T_ordrel_ind *)mp->b_rptr)->PRIM_type = T_ORDREL_IND; 1509 mp->b_wptr += sizeof (struct T_ordrel_ind); 1510 } 1511 return (mp); 1512 } 1513 1514 static MBLKP 1515 mi_tpi_trailer_alloc(MBLKP trailer_mp, size_t size, t_scalar_t type) 1516 { 1517 MBLKP mp; 1518 1519 if ((mp = allocb(size, BPRI_MED)) != NULL) { 1520 mp->b_cont = trailer_mp; 1521 mp->b_datap->db_type = M_PROTO; 1522 ((union T_primitives *)mp->b_rptr)->type = type; 1523 mp->b_wptr += size; 1524 } 1525 return (mp); 1526 } 1527 1528 MBLKP 1529 mi_tpi_uderror_ind(char *dest, t_scalar_t dest_length, char *opt, 1530 t_scalar_t opt_length, t_scalar_t error) 1531 { 1532 size_t len; 1533 MBLKP mp; 1534 struct T_uderror_ind *tudei; 1535 1536 len = sizeof (struct T_uderror_ind) + dest_length + opt_length; 1537 if ((mp = allocb(len, BPRI_HI)) != NULL) { 1538 mp->b_datap->db_type = M_PROTO; 1539 tudei = (struct T_uderror_ind *)mp->b_rptr; 1540 tudei->PRIM_type = T_UDERROR_IND; 1541 tudei->ERROR_type = error; 1542 mp->b_wptr = &mp->b_rptr[sizeof (struct T_uderror_ind)]; 1543 mi_tpi_addr_and_opt(mp, dest, dest_length, opt, opt_length); 1544 } 1545 return (mp); 1546 } 1547 1548 IDP 1549 mi_zalloc(size_t size) 1550 { 1551 IDP ptr; 1552 1553 if (ptr = mi_alloc(size, BPRI_LO)) 1554 bzero(ptr, size); 1555 return (ptr); 1556 } 1557 1558 IDP 1559 mi_zalloc_sleep(size_t size) 1560 { 1561 IDP ptr; 1562 1563 if (ptr = mi_alloc_sleep(size, BPRI_LO)) 1564 bzero(ptr, size); 1565 return (ptr); 1566 } 1567