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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1990 Mentat Inc. */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <inet/common.h> /* for various inet/mi.h and inet/nd.h needs */ 31 #include <sys/stream.h> 32 #include <sys/stropts.h> 33 #include <sys/strsun.h> 34 #include <sys/sysmacros.h> 35 #include <inet/nd.h> 36 #include <inet/mi.h> 37 #define _SUN_TPI_VERSION 2 38 #include <sys/tihdr.h> 39 #include <sys/timod.h> 40 #include <sys/vtrace.h> 41 #include <sys/kmem.h> 42 #include <sys/mkdev.h> 43 #include <sys/strlog.h> 44 #include <sys/ddi.h> 45 #include <sys/suntpi.h> 46 #include <sys/cmn_err.h> 47 #include <sys/debug.h> 48 #include <sys/kobj.h> 49 50 #define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') 51 #define ISUPPER(ch) ((ch) >= 'A' && (ch) <= 'Z') 52 #define tolower(ch) ('a' + ((ch) - 'A')) 53 54 #define MI_IS_TRANSPARENT(mp) (mp->b_cont && \ 55 (mp->b_cont->b_rptr != mp->b_cont->b_wptr)) 56 57 /* 58 * NOTE: Whenever anything is allocated by mi_alloc or mi_alloc_sleep (below), 59 * the size of the requested allocation is increased by one word. This extra 60 * word is used to store the size of the object being allocated, and is located 61 * at the beginning of the allocated block. The pointer returned to the caller 62 * is a pointer to the *second* word in the newly-allocated block. The IP 63 * module of mdb is aware of this, and will need to be changed if this 64 * allocation strategy is changed. 65 */ 66 67 typedef struct stroptions *STROPTP; 68 typedef union T_primitives *TPRIMP; 69 70 /* Timer block states. */ 71 #define TB_RUNNING 1 72 #define TB_IDLE 2 73 /* 74 * Could not stop/free before putq 75 */ 76 #define TB_RESCHED 3 /* mtb_time_left contains tick count */ 77 #define TB_CANCELLED 4 78 #define TB_TO_BE_FREED 5 79 80 typedef struct mtb_s { 81 int mtb_state; 82 timeout_id_t mtb_tid; 83 queue_t *mtb_q; 84 MBLKP mtb_mp; 85 clock_t mtb_time_left; 86 } MTB, *MTBP; 87 88 static int mi_timer_fire(MTBP); 89 static int mi_iprintf(char *, va_list, pfi_t, char *); 90 static void mi_tpi_addr_and_opt(MBLKP, char *, t_scalar_t, char *, t_scalar_t); 91 static MBLKP mi_tpi_trailer_alloc(MBLKP, size_t, t_scalar_t); 92 93 /* ARGSUSED1 */ 94 void * 95 mi_alloc(size_t size, uint_t pri) 96 { 97 size_t *ptr; 98 99 size += sizeof (size); 100 if (ptr = kmem_alloc(size, KM_NOSLEEP)) { 101 *ptr = size; 102 return (ptr + 1); 103 } 104 return (NULL); 105 } 106 107 /* ARGSUSED1 */ 108 void * 109 mi_alloc_sleep(size_t size, uint_t pri) 110 { 111 size_t *ptr; 112 113 size += sizeof (size); 114 ptr = kmem_alloc(size, KM_SLEEP); 115 *ptr = size; 116 return (ptr + 1); 117 } 118 119 int 120 mi_close_comm(void **mi_headp, queue_t *q) 121 { 122 IDP ptr; 123 124 ptr = q->q_ptr; 125 mi_close_unlink(mi_headp, ptr); 126 mi_close_free(ptr); 127 q->q_ptr = WR(q)->q_ptr = NULL; 128 return (0); 129 } 130 131 void 132 mi_close_unlink(void **mi_headp, IDP ptr) 133 { 134 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 135 MI_OP mi_o; 136 dev_t dev; 137 138 mi_o = (MI_OP)ptr; 139 if (!mi_o) 140 return; 141 mi_o--; 142 143 if (mi_o->mi_o_next == NULL) { 144 /* Not in list */ 145 ASSERT(mi_o->mi_o_prev == NULL); 146 return; 147 } 148 149 /* Free minor number */ 150 dev = mi_o->mi_o_dev; 151 if ((dev != OPENFAIL) && (dev != 0) && (dev <= MAXMIN)) 152 inet_minor_free(mi_head->mh_arena, dev); 153 154 /* Unlink from list */ 155 ASSERT(mi_o->mi_o_next != NULL); 156 ASSERT(mi_o->mi_o_prev != NULL); 157 ASSERT(mi_o->mi_o_next->mi_o_prev == mi_o); 158 ASSERT(mi_o->mi_o_prev->mi_o_next == mi_o); 159 160 mi_o->mi_o_next->mi_o_prev = mi_o->mi_o_prev; 161 mi_o->mi_o_prev->mi_o_next = mi_o->mi_o_next; 162 mi_o->mi_o_next = mi_o->mi_o_prev = NULL; 163 164 mi_o->mi_o_dev = (dev_t)OPENFAIL; 165 166 /* If list now empty free the list head */ 167 if (mi_head->mh_o.mi_o_next == &mi_head->mh_o) { 168 ASSERT(mi_head->mh_o.mi_o_prev == &mi_head->mh_o); 169 if (mi_head->mh_arena != NULL) 170 inet_minor_destroy(mi_head->mh_arena); 171 mi_free((IDP)mi_head); 172 *mi_headp = NULL; 173 } 174 } 175 176 void 177 mi_close_free(IDP ptr) 178 { 179 MI_OP mi_o; 180 181 mi_o = (MI_OP)ptr; 182 if (!mi_o) 183 return; 184 mi_o--; 185 186 ASSERT(mi_o->mi_o_next == NULL && mi_o->mi_o_prev == NULL); 187 mi_free((IDP)mi_o); 188 } 189 190 /* 191 * mi_copyin - takes care of transparent or non-transparent ioctl for the 192 * calling function so that they have to deal with just M_IOCDATA type 193 * and not worry about M_COPYIN. 194 * 195 * mi_copyin checks to see if the ioctl is transparent or non transparent. 196 * In case of a non_transparent ioctl, it packs the data into a M_IOCDATA 197 * message and puts it back onto the current queue for further processing. 198 * In case of transparent ioctl, it sends a M_COPYIN message up to the 199 * streamhead so that a M_IOCDATA with the information comes back down. 200 */ 201 void 202 mi_copyin(queue_t *q, MBLKP mp, char *uaddr, size_t len) 203 { 204 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 205 struct copyreq *cq = (struct copyreq *)mp->b_rptr; 206 struct copyresp *cp = (struct copyresp *)mp->b_rptr; 207 int err; 208 MBLKP mp1; 209 210 ASSERT(mp->b_datap->db_type == M_IOCTL && !uaddr); 211 212 /* A transparent ioctl. Send a M_COPYIN message to the streamhead. */ 213 if (iocp->ioc_count == TRANSPARENT) { 214 MI_COPY_COUNT(mp) = 1; 215 MI_COPY_DIRECTION(mp) = MI_COPY_IN; 216 cq->cq_private = mp->b_cont; 217 cq->cq_size = len; 218 cq->cq_flag = 0; 219 bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr)); 220 mp->b_cont = NULL; 221 mp->b_datap->db_type = M_COPYIN; 222 qreply(q, mp); 223 return; 224 } 225 226 /* 227 * A non-transparent ioctl. Need to convert into M_IOCDATA message. 228 * 229 * We allocate a 0 byte message block and put its address in 230 * cp_private. It also makes the b_prev field = 1 and b_next 231 * field = MI_COPY_IN for this 0 byte block. This is done to 232 * maintain compatibility with old code in mi_copy_state 233 * (which removes the empty block). 234 */ 235 err = miocpullup(mp, len); 236 if (err != 0) 237 goto err_ret; 238 239 mp1 = allocb(0, BPRI_MED); 240 if (mp1 == NULL) { 241 err = ENOMEM; 242 goto err_ret; 243 } 244 245 /* 246 * Temporarily insert mp1 between the M_IOCTL and M_DATA blocks so 247 * that we can use the MI_COPY_COUNT & MI_COPY_DIRECTION macros. 248 */ 249 mp1->b_cont = mp->b_cont; 250 mp->b_cont = mp1; 251 MI_COPY_COUNT(mp) = 1; 252 MI_COPY_DIRECTION(mp) = MI_COPY_IN; 253 mp->b_cont = mp1->b_cont; 254 mp1->b_cont = NULL; 255 256 /* 257 * Leave a pointer to the 0 byte block in cp_private field for 258 * future use by the mi_copy_* routines. 259 */ 260 mp->b_datap->db_type = M_IOCDATA; 261 cp->cp_private = mp1; 262 cp->cp_rval = NULL; 263 put(q, mp); 264 return; 265 266 err_ret: 267 iocp->ioc_error = err; 268 iocp->ioc_count = 0; 269 if (mp->b_cont) { 270 freemsg(mp->b_cont); 271 mp->b_cont = NULL; 272 } 273 mp->b_datap->db_type = M_IOCACK; 274 qreply(q, mp); 275 } 276 277 /* 278 * Allows transparent IOCTLs to have multiple copyins. This is needed 279 * for some variable-length structures, where the total size is only known 280 * after the first part is copied in. Rather than setting MI_COPY_COUNT to 281 * 1, as in mi_coypin(), it is simply incremented here. This value can 282 * then be checked in the returned IOCBLK. 283 * 284 * As this deals with copyins that follow the initial copyin, the byte 285 * offset into the user buffer from which copying should begin must be 286 * passed in in the offset parameter. 287 * 288 * Unlike mi_coypin(), this function expects to be passed an mblk chain 289 * headed by an M_IOCBLK, as that's the chain that will be in use for 290 * copies after the first one (copies where n != 1). 291 */ 292 void 293 mi_copyin_n(queue_t *q, MBLKP mp, size_t offset, size_t len) 294 { 295 struct copyreq *cq = (struct copyreq *)mp->b_rptr; 296 297 ASSERT(mp->b_datap->db_type == M_IOCDATA); 298 299 MI_COPY_COUNT(mp)++; 300 MI_COPY_DIRECTION(mp) = MI_COPY_IN; 301 cq->cq_private = mp->b_cont; 302 cq->cq_size = len; 303 cq->cq_flag = 0; 304 bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr)); 305 cq->cq_addr += offset; 306 mp->b_cont = NULL; 307 mp->b_datap->db_type = M_COPYIN; 308 qreply(q, mp); 309 } 310 311 void 312 mi_copyout(queue_t *q, MBLKP mp) 313 { 314 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 315 struct copyreq *cq = (struct copyreq *)iocp; 316 struct copyresp *cp = (struct copyresp *)cq; 317 MBLKP mp1; 318 MBLKP mp2; 319 320 if (mp->b_datap->db_type != M_IOCDATA || !mp->b_cont) { 321 mi_copy_done(q, mp, EPROTO); 322 return; 323 } 324 /* Check completion of previous copyout operation. */ 325 mp1 = mp->b_cont; 326 if ((int)(uintptr_t)cp->cp_rval || !mp1->b_cont) { 327 mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval); 328 return; 329 } 330 if (!mp1->b_cont->b_cont && !MI_IS_TRANSPARENT(mp)) { 331 mp1->b_next = NULL; 332 mp1->b_prev = NULL; 333 mp->b_cont = mp1->b_cont; 334 freeb(mp1); 335 mp1 = mp->b_cont; 336 mp1->b_next = NULL; 337 mp1->b_prev = NULL; 338 iocp->ioc_count = mp1->b_wptr - mp1->b_rptr; 339 iocp->ioc_error = 0; 340 mp->b_datap->db_type = M_IOCACK; 341 qreply(q, mp); 342 return; 343 } 344 if (MI_COPY_DIRECTION(mp) == MI_COPY_IN) { 345 /* Set up for first copyout. */ 346 MI_COPY_DIRECTION(mp) = MI_COPY_OUT; 347 MI_COPY_COUNT(mp) = 1; 348 } else { 349 ++MI_COPY_COUNT(mp); 350 } 351 cq->cq_private = mp1; 352 /* Find message preceding last. */ 353 for (mp2 = mp1; mp2->b_cont->b_cont; mp2 = mp2->b_cont) 354 ; 355 if (mp2 == mp1) 356 bcopy((char *)mp1->b_rptr, (char *)&cq->cq_addr, 357 sizeof (cq->cq_addr)); 358 else 359 cq->cq_addr = (char *)mp2->b_cont->b_next; 360 mp1 = mp2->b_cont; 361 mp->b_datap->db_type = M_COPYOUT; 362 mp->b_cont = mp1; 363 mp2->b_cont = NULL; 364 mp1->b_next = NULL; 365 cq->cq_size = mp1->b_wptr - mp1->b_rptr; 366 cq->cq_flag = 0; 367 qreply(q, mp); 368 } 369 370 MBLKP 371 mi_copyout_alloc(queue_t *q, MBLKP mp, char *uaddr, size_t len, 372 boolean_t free_on_error) 373 { 374 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 375 MBLKP mp1; 376 377 if (mp->b_datap->db_type == M_IOCTL) { 378 if (iocp->ioc_count != TRANSPARENT) { 379 mp1 = allocb(0, BPRI_MED); 380 if (mp1 == NULL) { 381 if (free_on_error) { 382 iocp->ioc_error = ENOMEM; 383 iocp->ioc_count = 0; 384 freemsg(mp->b_cont); 385 mp->b_cont = NULL; 386 mp->b_datap->db_type = M_IOCACK; 387 qreply(q, mp); 388 } 389 return (NULL); 390 } 391 mp1->b_cont = mp->b_cont; 392 mp->b_cont = mp1; 393 } 394 MI_COPY_COUNT(mp) = 0; 395 MI_COPY_DIRECTION(mp) = MI_COPY_OUT; 396 /* Make sure it looks clean to mi_copyout. */ 397 mp->b_datap->db_type = M_IOCDATA; 398 ((struct copyresp *)iocp)->cp_rval = NULL; 399 } 400 mp1 = allocb(len, BPRI_MED); 401 if (mp1 == NULL) { 402 if (free_on_error) 403 mi_copy_done(q, mp, ENOMEM); 404 return (NULL); 405 } 406 linkb(mp, mp1); 407 mp1->b_next = (MBLKP)uaddr; 408 return (mp1); 409 } 410 411 void 412 mi_copy_done(queue_t *q, MBLKP mp, int err) 413 { 414 struct iocblk *iocp; 415 MBLKP mp1; 416 417 if (!mp) 418 return; 419 if (!q || (mp->b_wptr - mp->b_rptr) < sizeof (struct iocblk)) { 420 freemsg(mp); 421 return; 422 } 423 iocp = (struct iocblk *)mp->b_rptr; 424 mp->b_datap->db_type = M_IOCACK; 425 iocp->ioc_error = err; 426 427 iocp->ioc_count = 0; 428 if ((mp1 = mp->b_cont) != NULL) { 429 for (; mp1; mp1 = mp1->b_cont) { 430 mp1->b_prev = NULL; 431 mp1->b_next = NULL; 432 } 433 freemsg(mp->b_cont); 434 mp->b_cont = NULL; 435 } 436 qreply(q, mp); 437 } 438 439 int 440 mi_copy_state(queue_t *q, MBLKP mp, MBLKP *mpp) 441 { 442 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 443 struct copyresp *cp = (struct copyresp *)iocp; 444 MBLKP mp1; 445 446 mp1 = mp->b_cont; 447 mp->b_cont = cp->cp_private; 448 if (mp1) { 449 if (mp1->b_cont && !pullupmsg(mp1, -1)) { 450 mi_copy_done(q, mp, ENOMEM); 451 return (-1); 452 } 453 linkb(mp->b_cont, mp1); 454 } 455 if ((int)(uintptr_t)cp->cp_rval) { 456 mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval); 457 return (-1); 458 } 459 if (mpp && MI_COPY_DIRECTION(mp) == MI_COPY_IN) 460 *mpp = mp1; 461 return (MI_COPY_STATE(mp)); 462 } 463 464 void 465 mi_free(void *ptr) 466 { 467 size_t size; 468 469 if (!ptr) 470 return; 471 if ((size = ((size_t *)ptr)[-1]) <= 0) 472 cmn_err(CE_PANIC, "mi_free"); 473 474 kmem_free((void *) ((size_t *)ptr - 1), size); 475 } 476 477 static int 478 mi_iprintf(char *fmt, va_list ap, pfi_t putc_func, char *cookie) 479 { 480 int base; 481 char buf[(sizeof (long) * 3) + 1]; 482 static char hex_val[] = "0123456789abcdef"; 483 int ch; 484 int count; 485 char *cp1; 486 int digits; 487 char *fcp; 488 boolean_t is_long; 489 ulong_t uval; 490 long val; 491 boolean_t zero_filled; 492 493 if (!fmt) 494 return (-1); 495 count = 0; 496 while (*fmt) { 497 if (*fmt != '%' || *++fmt == '%') { 498 count += (*putc_func)(cookie, *fmt++); 499 continue; 500 } 501 if (*fmt == '0') { 502 zero_filled = B_TRUE; 503 fmt++; 504 if (!*fmt) 505 break; 506 } else 507 zero_filled = B_FALSE; 508 base = 0; 509 for (digits = 0; ISDIGIT(*fmt); fmt++) { 510 digits *= 10; 511 digits += (*fmt - '0'); 512 } 513 if (!*fmt) 514 break; 515 is_long = B_FALSE; 516 if (*fmt == 'l') { 517 is_long = B_TRUE; 518 fmt++; 519 } 520 if (!*fmt) 521 break; 522 ch = *fmt++; 523 if (ISUPPER(ch)) { 524 ch = tolower(ch); 525 is_long = B_TRUE; 526 } 527 switch (ch) { 528 case 'c': 529 count += (*putc_func)(cookie, va_arg(ap, int *)); 530 continue; 531 case 'd': 532 base = 10; 533 break; 534 case 'm': /* Print out memory, 2 hex chars per byte */ 535 if (is_long) 536 fcp = va_arg(ap, char *); 537 else { 538 if ((cp1 = va_arg(ap, char *)) != NULL) 539 fcp = (char *)cp1; 540 else 541 fcp = NULL; 542 } 543 if (!fcp) { 544 for (fcp = (char *)"(NULL)"; *fcp; fcp++) 545 count += (*putc_func)(cookie, *fcp); 546 } else { 547 while (digits--) { 548 int u1 = *fcp++ & 0xFF; 549 count += (*putc_func)(cookie, 550 hex_val[(u1>>4)& 0xF]); 551 count += (*putc_func)(cookie, 552 hex_val[u1& 0xF]); 553 } 554 } 555 continue; 556 case 'o': 557 base = 8; 558 break; 559 case 'p': 560 is_long = B_TRUE; 561 /* FALLTHRU */ 562 case 'x': 563 base = 16; 564 break; 565 case 's': 566 if (is_long) 567 fcp = va_arg(ap, char *); 568 else { 569 if ((cp1 = va_arg(ap, char *)) != NULL) 570 fcp = (char *)cp1; 571 else 572 fcp = NULL; 573 } 574 if (!fcp) 575 fcp = (char *)"(NULL)"; 576 while (*fcp) { 577 count += (*putc_func)(cookie, *fcp++); 578 if (digits && --digits == 0) 579 break; 580 } 581 while (digits > 0) { 582 count += (*putc_func)(cookie, ' '); 583 digits--; 584 } 585 continue; 586 case 'u': 587 base = 10; 588 break; 589 default: 590 return (count); 591 } 592 if (is_long) 593 val = va_arg(ap, long); 594 else 595 val = va_arg(ap, int); 596 if (base == 10 && ch != 'u') { 597 if (val < 0) { 598 count += (*putc_func)(cookie, '-'); 599 val = -val; 600 } 601 uval = val; 602 } else { 603 if (is_long) 604 uval = val; 605 else 606 uval = (uint_t)val; 607 } 608 /* Hand overload/restore the register variable 'fmt' */ 609 cp1 = fmt; 610 fmt = A_END(buf); 611 *--fmt = '\0'; 612 do { 613 if (fmt > buf) 614 *--fmt = hex_val[uval % base]; 615 if (digits && --digits == 0) 616 break; 617 } while (uval /= base); 618 if (zero_filled) { 619 while (digits > 0 && fmt > buf) { 620 *--fmt = '0'; 621 digits--; 622 } 623 } 624 while (*fmt) 625 count += (*putc_func)(cookie, *fmt++); 626 fmt = cp1; 627 } 628 return (count); 629 } 630 631 /* PRINTFLIKE2 */ 632 int 633 mi_mpprintf(MBLKP mp, char *fmt, ...) 634 { 635 va_list ap; 636 int count = -1; 637 638 va_start(ap, fmt); 639 if (mp) { 640 count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc, 641 (char *)mp); 642 if (count != -1) 643 (void) mi_mpprintf_putc((char *)mp, '\0'); 644 } 645 va_end(ap); 646 return (count); 647 } 648 649 /* PRINTFLIKE2 */ 650 int 651 mi_mpprintf_nr(MBLKP mp, char *fmt, ...) 652 { 653 va_list ap; 654 int count = -1; 655 656 va_start(ap, fmt); 657 if (mp) { 658 (void) adjmsg(mp, -1); 659 count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc, 660 (char *)mp); 661 if (count != -1) 662 (void) mi_mpprintf_putc((char *)mp, '\0'); 663 } 664 va_end(ap); 665 return (count); 666 } 667 668 int 669 mi_mpprintf_putc(char *cookie, int ch) 670 { 671 MBLKP mp = (MBLKP)cookie; 672 673 while (mp->b_cont) 674 mp = mp->b_cont; 675 if (mp->b_wptr >= mp->b_datap->db_lim) { 676 mp->b_cont = allocb(1024, BPRI_HI); 677 mp = mp->b_cont; 678 if (!mp) 679 return (0); 680 } 681 *mp->b_wptr++ = (unsigned char)ch; 682 return (1); 683 } 684 685 IDP 686 mi_first_ptr(void **mi_headp) 687 { 688 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 689 MI_OP mi_op; 690 691 mi_op = mi_head->mh_o.mi_o_next; 692 if (mi_op && mi_op != &mi_head->mh_o) 693 return ((IDP)&mi_op[1]); 694 return (NULL); 695 } 696 697 /* 698 * Clients can choose to have both module instances and device instances 699 * in the same list. Return the first device instance in the list. 700 */ 701 IDP 702 mi_first_dev_ptr(void **mi_headp) 703 { 704 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 705 MI_OP mi_op; 706 707 mi_op = mi_head->mh_o.mi_o_next; 708 while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) { 709 if (mi_op->mi_o_isdev) 710 return ((IDP)&mi_op[1]); 711 mi_op = mi_op->mi_o_next; 712 } 713 return (NULL); 714 } 715 716 IDP 717 mi_next_ptr(void **mi_headp, IDP ptr) 718 { 719 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 720 MI_OP mi_op = ((MI_OP)ptr) - 1; 721 722 if ((mi_op = mi_op->mi_o_next) != NULL && mi_op != &mi_head->mh_o) 723 return ((IDP)&mi_op[1]); 724 return (NULL); 725 } 726 727 /* 728 * Clients can choose to have both module instances and device instances 729 * in the same list. Return the next device instance in the list. 730 */ 731 IDP 732 mi_next_dev_ptr(void **mi_headp, IDP ptr) 733 { 734 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 735 MI_OP mi_op = ((MI_OP)ptr) - 1; 736 737 mi_op = mi_op->mi_o_next; 738 while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) { 739 if (mi_op->mi_o_isdev) 740 return ((IDP)&mi_op[1]); 741 mi_op = mi_op->mi_o_next; 742 } 743 return (NULL); 744 } 745 746 /* 747 * Self clone the device 748 * XXX - should we still support clone device 749 */ 750 /* ARGSUSED4 */ 751 int 752 mi_open_comm(void **mi_headp, size_t size, queue_t *q, dev_t *devp, 753 int flag, int sflag, cred_t *credp) 754 { 755 int error; 756 IDP ptr; 757 758 if (q->q_ptr != NULL) 759 return (0); 760 761 ptr = mi_open_alloc_sleep(size); 762 q->q_ptr = WR(q)->q_ptr = ptr; 763 error = mi_open_link(mi_headp, ptr, devp, flag, sflag, credp); 764 if (error != 0) { 765 q->q_ptr = WR(q)->q_ptr = NULL; 766 mi_close_free(ptr); 767 } 768 return (error); 769 } 770 771 IDP 772 mi_open_alloc_sleep(size_t size) 773 { 774 MI_OP mi_o; 775 776 if (size > (UINT_MAX - sizeof (MI_O))) 777 return (NULL); 778 779 mi_o = (MI_OP)mi_zalloc_sleep(size + sizeof (MI_O)); 780 mi_o++; 781 return ((IDP)mi_o); 782 } 783 784 IDP 785 mi_open_alloc(size_t size) 786 { 787 MI_OP mi_o; 788 789 if (size > (UINT_MAX - sizeof (MI_O))) 790 return (NULL); 791 792 if ((mi_o = (MI_OP)mi_zalloc(size + sizeof (MI_O))) == NULL) 793 return (NULL); 794 mi_o++; 795 return ((IDP)mi_o); 796 } 797 798 /* 799 * MODOPEN means just link in without respect of mi_o_dev. 800 * A NULL devp can be used to create a detached instance 801 * Otherwise self-clone the device. 802 */ 803 /* ARGSUSED3 */ 804 int 805 mi_open_link(void **mi_headp, IDP ptr, dev_t *devp, int flag, int sflag, 806 cred_t *credp) 807 { 808 mi_head_t *mi_head = *(mi_head_t **)mi_headp; 809 MI_OP insert; 810 MI_OP mi_o; 811 dev_t dev; 812 813 if (mi_head == NULL) { 814 char arena_name[50]; 815 char *head_name; 816 ulong_t offset; 817 818 head_name = kobj_getsymname((uintptr_t)mi_headp, &offset); 819 if (head_name != NULL && offset == 0) { 820 (void) sprintf(arena_name, "%s_", head_name); 821 } else { 822 (void) sprintf(arena_name, "Hex0x%p_", 823 (void *)mi_headp); 824 } 825 (void) sprintf(strchr(arena_name, '_') + 1, "minor"); 826 mi_head = (mi_head_t *)mi_zalloc_sleep(sizeof (mi_head_t)); 827 *mi_headp = (void *)mi_head; 828 /* Setup doubly linked list */ 829 mi_head->mh_o.mi_o_next = &mi_head->mh_o; 830 mi_head->mh_o.mi_o_prev = &mi_head->mh_o; 831 mi_head->mh_o.mi_o_dev = 0; /* For asserts only */ 832 mi_head->mh_arena = (vmem_t *)inet_minor_create(arena_name, 833 INET_MIN_DEV, MAXMIN, KM_SLEEP); 834 } 835 ASSERT(ptr != NULL); 836 mi_o = (MI_OP)ptr; 837 mi_o--; 838 839 if (sflag == MODOPEN) { 840 devp = NULL; 841 /* 842 * Set device number to MAXMIN + incrementing number. 843 */ 844 dev = MAXMIN + ++mi_head->mh_module_dev; 845 /* check for wraparound */ 846 if (dev <= MAXMIN) { 847 dev = MAXMIN + 1; 848 mi_head->mh_module_dev = 1; 849 } 850 } else if (devp == NULL) { 851 /* Detached open */ 852 dev = (dev_t)OPENFAIL; 853 } else if ((dev = inet_minor_alloc(mi_head->mh_arena)) == 0) { 854 return (EBUSY); 855 } 856 857 mi_o->mi_o_dev = dev; 858 insert = (&mi_head->mh_o); 859 mi_o->mi_o_next = insert; 860 insert->mi_o_prev->mi_o_next = mi_o; 861 mi_o->mi_o_prev = insert->mi_o_prev; 862 insert->mi_o_prev = mi_o; 863 864 if (sflag == MODOPEN) 865 mi_o->mi_o_isdev = B_FALSE; 866 else 867 mi_o->mi_o_isdev = B_TRUE; 868 869 if (devp) 870 *devp = makedevice(getemajor(*devp), (minor_t)dev); 871 return (0); 872 } 873 874 uint8_t * 875 mi_offset_param(mblk_t *mp, size_t offset, size_t len) 876 { 877 size_t msg_len; 878 879 if (!mp) 880 return (NULL); 881 msg_len = mp->b_wptr - mp->b_rptr; 882 if (msg_len == 0 || offset > msg_len || len > msg_len || 883 (offset + len) > msg_len || len == 0) 884 return (NULL); 885 return (&mp->b_rptr[offset]); 886 } 887 888 uint8_t * 889 mi_offset_paramc(mblk_t *mp, size_t offset, size_t len) 890 { 891 uint8_t *param; 892 893 for (; mp; mp = mp->b_cont) { 894 int type = mp->b_datap->db_type; 895 if (datamsg(type)) { 896 if (param = mi_offset_param(mp, offset, len)) 897 return (param); 898 if (offset < mp->b_wptr - mp->b_rptr) 899 break; 900 offset -= mp->b_wptr - mp->b_rptr; 901 } 902 } 903 return (NULL); 904 } 905 906 907 boolean_t 908 mi_set_sth_hiwat(queue_t *q, size_t size) 909 { 910 MBLKP mp; 911 STROPTP stropt; 912 913 if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 914 return (B_FALSE); 915 mp->b_datap->db_type = M_SETOPTS; 916 mp->b_wptr += sizeof (*stropt); 917 stropt = (STROPTP)mp->b_rptr; 918 stropt->so_flags = SO_HIWAT; 919 stropt->so_hiwat = size; 920 putnext(q, mp); 921 return (B_TRUE); 922 } 923 924 boolean_t 925 mi_set_sth_lowat(queue_t *q, size_t size) 926 { 927 MBLKP mp; 928 STROPTP stropt; 929 930 if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 931 return (B_FALSE); 932 mp->b_datap->db_type = M_SETOPTS; 933 mp->b_wptr += sizeof (*stropt); 934 stropt = (STROPTP)mp->b_rptr; 935 stropt->so_flags = SO_LOWAT; 936 stropt->so_lowat = size; 937 putnext(q, mp); 938 return (B_TRUE); 939 } 940 941 /* ARGSUSED */ 942 boolean_t 943 mi_set_sth_maxblk(queue_t *q, ssize_t size) 944 { 945 MBLKP mp; 946 STROPTP stropt; 947 948 if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 949 return (B_FALSE); 950 mp->b_datap->db_type = M_SETOPTS; 951 mp->b_wptr += sizeof (*stropt); 952 stropt = (STROPTP)mp->b_rptr; 953 stropt->so_flags = SO_MAXBLK; 954 stropt->so_maxblk = size; 955 putnext(q, mp); 956 return (B_TRUE); 957 } 958 959 boolean_t 960 mi_set_sth_copyopt(queue_t *q, int copyopt) 961 { 962 MBLKP mp; 963 STROPTP stropt; 964 965 if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 966 return (B_FALSE); 967 mp->b_datap->db_type = M_SETOPTS; 968 mp->b_wptr += sizeof (*stropt); 969 stropt = (STROPTP)mp->b_rptr; 970 stropt->so_flags = SO_COPYOPT; 971 stropt->so_copyopt = (ushort_t)copyopt; 972 putnext(q, mp); 973 return (B_TRUE); 974 } 975 976 boolean_t 977 mi_set_sth_wroff(queue_t *q, size_t size) 978 { 979 MBLKP mp; 980 STROPTP stropt; 981 982 if (!(mp = allocb(sizeof (*stropt), BPRI_LO))) 983 return (B_FALSE); 984 mp->b_datap->db_type = M_SETOPTS; 985 mp->b_wptr += sizeof (*stropt); 986 stropt = (STROPTP)mp->b_rptr; 987 stropt->so_flags = SO_WROFF; 988 stropt->so_wroff = (ushort_t)size; 989 putnext(q, mp); 990 return (B_TRUE); 991 } 992 993 int 994 mi_sprintf(char *buf, char *fmt, ...) 995 { 996 va_list ap; 997 int count = -1; 998 va_start(ap, fmt); 999 if (buf) { 1000 count = mi_iprintf(fmt, ap, (pfi_t)mi_sprintf_putc, 1001 (char *)&buf); 1002 if (count != -1) 1003 (void) mi_sprintf_putc((char *)&buf, '\0'); 1004 } 1005 va_end(ap); 1006 return (count); 1007 } 1008 1009 /* Used to count without writing data */ 1010 /* ARGSUSED1 */ 1011 static int 1012 mi_sprintf_noop(char *cookie, int ch) 1013 { 1014 char **cpp = (char **)cookie; 1015 1016 (*cpp)++; 1017 return (1); 1018 } 1019 1020 int 1021 mi_sprintf_putc(char *cookie, int ch) 1022 { 1023 char **cpp = (char **)cookie; 1024 1025 **cpp = (char)ch; 1026 (*cpp)++; 1027 return (1); 1028 } 1029 1030 int 1031 mi_strcmp(const char *cp1, const char *cp2) 1032 { 1033 while (*cp1++ == *cp2++) { 1034 if (!cp2[-1]) 1035 return (0); 1036 } 1037 return ((uint_t)cp2[-1] & 0xFF) - ((uint_t)cp1[-1] &