1 /* 2 * Copyright (c) 2000, 2001 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: src/sys/kern/subr_mchain.c,v 1.1 2001/02/24 15:44:29 bp Exp $ 33 */ 34 /* 35 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 36 * Use is subject to license terms. 37 */ 38 39 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/errno.h> 44 #include <sys/uio.h> 45 #include <sys/types.h> 46 #include <sys/stream.h> 47 #include <sys/strsun.h> 48 #include <sys/strsubr.h> 49 #include <sys/cmn_err.h> 50 51 #ifdef APPLE 52 #include <sys/smb_apple.h> 53 #else 54 #include <netsmb/smb_osdep.h> 55 #endif 56 57 #include <netsmb/mchain.h> 58 59 #include <netsmb/smb.h> 60 #include <netsmb/smb_conn.h> 61 #include <netsmb/smb_subr.h> 62 63 /* BEGIN CSTYLED */ 64 /* 65 * BSD-style mbufs, vs SysV-style mblks: 66 * One big difference: the mbuf payload is: 67 * m_data ... (m_data + m_len) 68 * In Unix STREAMS, the mblk payload is: 69 * b_rptr ... b_wptr 70 * 71 * Here are some handy conversion notes: 72 * 73 * struct mbuf struct mblk 74 * m->m_next m->b_cont 75 * m->m_nextpkt m->b_next 76 * m->m_data m->b_rptr 77 * m->m_len MBLKL(m) 78 * m->m_dat[] m->b_datap->db_base 79 * &m->m_dat[MLEN] m->b_datap->db_lim 80 * M_TRAILINGSPACE(m) MBLKTAIL(m) 81 * m_freem(m) freemsg(m) 82 * 83 * Note that mbufs chains also have a special "packet" header, 84 * which has the length of the whole message. In STREAMS one 85 * typically just calls msgdsize(m) to get that. 86 */ 87 /* END CSTYLED */ 88 89 90 /* 91 * 92 * MODULE_VERSION(libmchain, 1); 93 */ 94 95 #ifdef __GNUC__ 96 #define MBERROR(format, args...) printf("%s(%d): "format, \ 97 __FUNCTION__, __LINE__, ## args) 98 #define MBPANIC(format, args...) printf("%s(%d): "format, \ 99 __FUNCTION__, __LINE__, ## args) 100 #else 101 #define MBERROR(...) \ 102 smb_errmsg(CE_NOTE, __func__, __VA_ARGS__) 103 #define MBPANIC(...) \ 104 smb_errmsg(CE_PANIC, __func__, __VA_ARGS__) 105 #endif 106 107 /* 108 * MLEN: The smallest mblk we'll allocate. 109 * 110 * There's more to MLEN than you might think. 111 * Some ethernet drivers may send each mblk as a 112 * separate frame, so we want MLEN at least 1K. 113 * We could have used 1K here, but that might 114 * hurt transports that support larger frames. 115 * 4K fits nicely in 3 Ethernet frames (3 * 1500) 116 * leaving about 500 bytes for protocol headers. 117 * 118 * XXX: Would Ethernet drivers be happier 119 * (more efficient) if we used 1K here? 120 */ 121 #define MLEN 4096 122 123 124 /* 125 * Some UIO routines. 126 * Taken from Darwin Sourcecs. 127 */ 128 129 /* 130 * uio_isuserspace - return non zero value if the address space 131 * flag is for a user address space (could be 32 or 64 bit). 132 */ 133 int 134 uio_isuserspace(uio_t *a_uio) 135 { 136 if (a_uio->uio_segflg == UIO_USERSPACE) { 137 return (1); 138 } 139 return (0); 140 } 141 142 /* 143 * uio_curriovbase - return the base address of the current iovec associated 144 * with the given uio_t. May return 0. 145 */ 146 caddr_t 147 uio_curriovbase(uio_t *a_uio) 148 { 149 if (a_uio->uio_iovcnt < 1) { 150 return (0); 151 } 152 return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base)); 153 } 154 155 /* 156 * uio_curriovlen - return the length value of the current iovec associated 157 * with the given uio_t. 158 */ 159 size_t 160 uio_curriovlen(uio_t *a_uio) 161 { 162 if (a_uio->uio_iovcnt < 1) { 163 return (0); 164 } 165 return ((size_t)a_uio->uio_iov->iov_len); 166 } 167 168 169 /* 170 * uio_update - update the given uio_t for a_count of completed IO. 171 * This call decrements the current iovec length and residual IO value 172 * and increments the current iovec base address and offset value. 173 * If the current iovec length is 0 then advance to the next 174 * iovec (if any). 175 * If the a_count passed in is 0, than only do the advancement 176 * over any 0 length iovec's. 177 */ 178 void 179 uio_update(uio_t *a_uio, size_t a_count) 180 { 181 if (a_uio->uio_iovcnt < 1) { 182 return; 183 } 184 185 /* 186 * if a_count == 0, then we are asking to skip over 187 * any empty iovs 188 */ 189 if (a_count) { 190 if (a_count > a_uio->uio_iov->iov_len) { 191 a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len; 192 a_uio->uio_iov->iov_len = 0; 193 } else { 194 a_uio->uio_iov->iov_base += a_count; 195 a_uio->uio_iov->iov_len -= a_count; 196 } 197 if (a_uio->uio_resid < 0) { 198 a_uio->uio_resid = 0; 199 } 200 if (a_count > (size_t)a_uio->uio_resid) { 201 a_uio->uio_offset += a_uio->uio_resid; 202 a_uio->uio_resid = 0; 203 } else { 204 a_uio->uio_offset += a_count; 205 a_uio->uio_resid -= a_count; 206 } 207 } 208 /* 209 * advance to next iovec if current one is totally consumed 210 */ 211 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) { 212 a_uio->uio_iovcnt--; 213 if (a_uio->uio_iovcnt > 0) { 214 a_uio->uio_iov++; 215 } 216 } 217 } 218 219 220 /*ARGSUSED*/ 221 mblk_t * 222 m_getblk(int size, int type) 223 { 224 mblk_t *mblk; 225 int error; 226 227 /* Make size at least MLEN. */ 228 if (size < MLEN) 229 size = MLEN; 230 mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error); 231 ASSERT(mblk); 232 return (mblk); 233 } 234 235 void 236 mb_done(struct mbchain *mbp) 237 { 238 if (mbp->mb_top) { 239 freemsg(mbp->mb_top); 240 mbp->mb_top = NULL; 241 } 242 /* Avoid dangling references */ 243 mbp->mb_cur = NULL; 244 } 245 246 unsigned int 247 m_length(mblk_t *mblk) 248 { 249 uint64_t diff; 250 251 diff = (uintptr_t)mblk->b_datap->db_lim - 252 (uintptr_t)mblk->b_datap->db_base; 253 ASSERT(diff == (uint64_t)((unsigned int)diff)); 254 return ((unsigned int)diff); 255 } 256 257 void 258 mb_initm(struct mbchain *mbp, mblk_t *m) 259 { 260 bzero(mbp, sizeof (*mbp)); 261 mbp->mb_top = mbp->mb_cur = m; 262 } 263 264 265 int 266 mb_init(struct mbchain *mbp) 267 { 268 mblk_t *mblk; 269 270 mblk = m_getblk(MLEN, 1); 271 if (mblk == NULL) { 272 return (ENOSR); 273 } 274 275 /* 276 * Leave room in this first mblk so we can 277 * prepend a 4-byte NetBIOS header. 278 * See smb_nbst_send() 279 */ 280 mblk->b_wptr += 4; 281 mblk->b_rptr = mblk->b_wptr; 282 283 mb_initm(mbp, mblk); 284 return (0); 285 } 286 287 288 /* 289 * mb_detach() function returns the value of mbp->mb_top field 290 * and sets its * value to NULL. 291 */ 292 293 mblk_t * 294 mb_detach(struct mbchain *mbp) 295 { 296 mblk_t *m; 297 298 m = mbp->mb_top; 299 mbp->mb_top = mbp->mb_cur = NULL; 300 return (m); 301 } 302 303 /* 304 * Returns the length of the mblk_t data. 305 * 306 */ 307 int 308 m_fixhdr(mblk_t *m0) 309 { 310 size_t dsz; 311 312 dsz = msgdsize(m0); 313 return ((int)dsz); 314 } 315 316 /* 317 * BSD code set the message header length here, and 318 * returned the length. We don't have that field, so 319 * just return the message length. 320 */ 321 int 322 mb_fixhdr(struct mbchain *mbp) 323 { 324 return (m_fixhdr(mbp->mb_top)); 325 } 326 327 328 /* 329 * Check if object of size 'size' fit to the current position and 330 * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s). 331 * Return pointer to the object placeholder or NULL if any error occured. 332 * Note: size should be <= MLEN 333 */ 334 void * 335 mb_reserve(struct mbchain *mbp, int size) 336 { 337 mblk_t *m, *mn; 338 void *bpos; 339 340 m = mbp->mb_cur; 341 /* 342 * If the requested size is more than the space left. 343 * Allocate and appenad a new mblk. 344 */ 345 /*LINTED*/ 346 if (MBLKTAIL(m) < size) { 347 mn = m_getblk(size, 1); 348 if (mn == NULL) 349 return (NULL); 350 mbp->mb_cur = m->b_cont = mn; 351 m = mn; 352 } 353 /* 354 * If 'size' bytes fits into the buffer, then 355 * 1. increment the write pointer to the size. 356 * 2. return the position from where the memory is reserved. 357 */ 358 bpos = m->b_wptr; 359 m->b_wptr += size; 360 mbp->mb_count += size; 361 return (bpos); 362 } 363 364 /* 365 * All mb_put_*() functions perform an actual copy of the data into mbuf 366 * chain. Functions which have le or be suffixes will perform conversion to 367 * the little- or big-endian data formats. 368 * XXX: Assumes total data length in previous mblks is EVEN. 369 * XXX: Might need to compute the offset from mb_top instead. 370 */ 371 int 372 mb_put_padbyte(struct mbchain *mbp) 373 { 374 caddr_t dst; 375 char x = 0; 376 377 dst = (caddr_t)mbp->mb_cur->b_wptr; 378 379 /* only add padding if address is odd */ 380 if ((long)dst & 1) 381 return (mb_put_mem(mbp, (caddr_t)&x, 1, MB_MSYSTEM)); 382 else 383 return (0); 384 } 385 386 int 387 mb_put_uint8(struct mbchain *mbp, u_int8_t x) 388 { 389 return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); 390 } 391 392 int 393 mb_put_uint16be(struct mbchain *mbp, u_int16_t x) 394 { 395 x = htobes(x); 396 return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); 397 } 398 399 int 400 mb_put_uint16le(struct mbchain *mbp, u_int16_t x) 401 { 402 x = htoles(x); 403 return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); 404 } 405 406 int 407 mb_put_uint32be(struct mbchain *mbp, u_int32_t x) 408 { 409 x = htobel(x); 410 return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); 411 } 412 413 int 414 mb_put_uint32le(struct mbchain *mbp, u_int32_t x) 415 { 416 x = htolel(x); 417 return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); 418 } 419 420 int 421 mb_put_uint64be(struct mbchain *mbp, u_int64_t x) 422 { 423 x = htobeq(x); 424 return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); 425 } 426 427 int 428 mb_put_uint64le(struct mbchain *mbp, u_int64_t x) 429 { 430 x = htoleq(x); 431 return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM)); 432 } 433 434 /* 435 * mb_put_mem() function copies size bytes of data specified by the source 436 * argument to an mbuf chain. The type argument specifies the method used 437 * to perform a copy 438 */ 439 int 440 mb_put_mem(struct mbchain *mbp, c_caddr_t source, int size, int type) 441 { 442 mblk_t *m, *n; 443 caddr_t dst; 444 c_caddr_t src; 445 int cplen, error, mleft, count; 446 uint64_t diff; 447 448 m = mbp->mb_cur; 449 450 /*LINTED*/ 451 diff = MBLKTAIL(m); 452 ASSERT(diff == (uint64_t)((int)diff)); 453 mleft = (int)diff; 454 455 while (size > 0) { 456 if (mleft == 0) { 457 if (m->b_cont == NULL) { 458 /* 459 * Changed m_getm() to m_getblk() 460 * with the requested size, so we 461 * don't need m_getm() anymore. 462 */ 463 n = m_getblk(size, 1); 464 if (n == NULL) 465 return (ENOBUFS); 466 m->b_cont = n; 467 } 468 m = m->b_cont; 469 /*LINTED*/ 470 diff = MBLKTAIL(m); 471 ASSERT(diff == (uint64_t)((int)diff)); 472 mleft = (int)diff; 473 continue; 474 } 475 cplen = mleft > size ? size : mleft; 476 dst = (caddr_t)m->b_wptr; 477 switch (type) { 478 case MB_MINLINE: 479 for (src = source, count = cplen; count; count--) 480 *dst++ = *src++; 481 break; 482 case MB_MSYSTEM: 483 /* 484 * Try copying the raw bytes instead of using bcopy() 485 */ 486 bcopy(source, dst, cplen); 487 break; 488 case MB_MUSER: 489 error = copyin((void *)source, dst, cplen); 490 if (error) 491 return (error); 492 break; 493 case MB_MZERO: 494 bzero(dst, cplen); 495 break; 496 } 497 size -= cplen; 498 source += cplen; 499 mleft -= cplen; 500 m->b_wptr += cplen; 501 mbp->mb_count += cplen; 502 } 503 mbp->mb_cur = m; 504 return (0); 505 } 506 507 /* 508 * Append an mblk to the chain. 509 */ 510 int 511 mb_put_mbuf(struct mbchain *mbp, mblk_t *m) 512 { 513 mblk_t *mb; 514 515 /* See: linkb(9f) */ 516 for (mb = mbp->mb_cur; mb->b_cont; mb = mb->b_cont) 517 ; 518 mb->b_cont = m; 519 mbp->mb_cur = m; 520 mbp->mb_count += msgdsize(m); 521 522 return (0); 523 } 524 525 /* 526 * copies a uio scatter/gather list to an mbuf chain. 527 */ 528 int 529 mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size) 530 { 531 int left; 532 int mtype, error; 533 534 mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM); 535 536 while (size > 0 && uiop->uio_resid) { 537 if (uiop->uio_iovcnt <= 0 || uio_curriovbase(uiop) == 538 USER_ADDR_NULL) 539 return (EFBIG); 540 left = uio_curriovlen(uiop); 541 if (left > size) 542 left = size; 543 error = mb_put_mem(mbp, CAST_DOWN(caddr_t, 544 uio_curriovbase(uiop)), left, mtype); 545 if (error) 546 return (error); 547 uio_update(uiop, left); 548 size -= left; 549 } 550 return (0); 551 } 552 553 /* 554 * Routines for fetching data from an mbuf chain 555 */ 556 int 557 md_init(struct mdchain *mdp) 558 { 559 mblk_t *m; 560 561 m = m_getblk(MLEN, 1); 562 if (m == NULL) 563 return (ENOBUFS); 564 md_initm(mdp, m); 565 return (0); 566 } 567 568 void 569 md_initm(struct mdchain *mdp, mblk_t *m) 570 { 571 bzero(mdp, sizeof (*mdp)); 572 mdp->md_top = mdp->md_cur = m; 573 mdp->md_pos = m->b_rptr; 574 } 575 576 void 577 md_done(struct mdchain *mdp) 578 { 579 mblk_t *m; 580 581 /* 582 * Deal with the fact that we can error out of 583 * smb_t2_reply or smb_nt_reply without using up 584 * all the "records" added by md_append_record(). 585 */ 586 while ((m = mdp->md_top) != NULL) { 587 mdp->md_top = m->b_next; 588 m->b_next = NULL; 589 freemsg(m); 590 } 591 /* Avoid dangling references */ 592 mdp->md_cur = NULL; 593 mdp->md_pos = NULL; 594 } 595 596 /* 597 * Append a new message (separate mbuf chain). 598 * It is caller responsibility to prevent 599 * multiple calls to fetch/record routines. 600 * XXX: Note (mis)use of mblk->b_next here. 601 */ 602 void 603 md_append_record(struct mdchain *mdp, mblk_t *top) 604 { 605 mblk_t *m; 606 607 top->b_next = NULL; 608 if (mdp->md_top == NULL) { 609 md_initm(mdp, top); 610 return; 611 } 612 m = mdp->md_top; 613 /* Get to last message (not b_cont chain) */ 614 while (m->b_next) 615 m = m->b_next; 616 m->b_next = top; 617 } 618 619 /* 620 * Advance mdp->md_top to the next message. 621 * XXX: Note (mis)use of mblk->b_next here. 622 */ 623 int 624 md_next_record(struct mdchain *mdp) 625 { 626 mblk_t *m; 627 628 if (mdp->md_top == NULL) 629 return (ENOENT); 630 /* Get to next message (not b_cont chain) */ 631 m = mdp->md_top->b_next; 632 mdp->md_top->b_next = NULL; 633 md_done(mdp); 634 if (m == NULL) 635 return (ENOENT); 636 md_initm(mdp, m); 637 return (0); 638 } 639 640 int 641 md_get_uint8(struct mdchain *mdp, u_int8_t *x) 642 { 643 return (md_get_mem(mdp, (char *)x, 1, MB_MINLINE)); 644 } 645 646 int 647 md_get_uint16(struct mdchain *mdp, u_int16_t *x) 648 { 649 return (md_get_mem(mdp, (char *)x, 2, MB_MINLINE)); 650 } 651 652 int 653 md_get_uint16le(struct mdchain *mdp, u_int16_t *x) 654 { 655 u_int16_t v; 656 int error = md_get_uint16(mdp, &v); 657 658 if (x) 659 *x = letohs(v); 660 return (error); 661 } 662 663 int 664 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) { 665 u_int16_t v; 666 int error = md_get_uint16(mdp, &v); 667 668 if (x) 669 *x = betohs(v); 670 return (error); 671 } 672 673 int 674 md_get_uint32(struct mdchain *mdp, u_int32_t *x) 675 { 676 return (md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE)); 677 } 678 679 int 680 md_get_uint32be(struct mdchain *mdp, u_int32_t *x) 681 { 682 u_int32_t v; 683 int error; 684 685 error = md_get_uint32(mdp, &v); 686 if (x) 687 *x = betohl(v); 688 return (error); 689 } 690 691 int 692 md_get_uint32le(struct mdchain *mdp, u_int32_t *x) 693 { 694 u_int32_t v; 695 int error; 696 697 error = md_get_uint32(mdp, &v); 698 if (x) 699 *x = letohl(v); 700 return (error); 701 } 702 703 int 704 md_get_uint64(struct mdchain *mdp, u_int64_t *x) 705 { 706 return (md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE)); 707 } 708 709 int 710 md_get_uint64be(struct mdchain *mdp, u_int64_t *x) 711 { 712 u_int64_t v; 713 int error; 714 715 error = md_get_uint64(mdp, &v); 716 if (x) 717 *x = betohq(v); 718 return (error); 719 } 720 721 int 722 md_get_uint64le(struct mdchain *mdp, u_int64_t *x) 723 { 724 u_int64_t v; 725 int error; 726 727 error = md_get_uint64(mdp, &v); 728 if (x) 729 *x = letohq(v); 730 return (error); 731 } 732 733 int 734 md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type) 735 { 736 mblk_t *m = mdp->md_cur; 737 int error; 738 int count; 739 unsigned char *s; 740 uint64_t diff; 741 742 while (size > 0) { 743 if (m == NULL) { 744 SMBSDEBUG("incomplete copy\n"); 745 return (EBADRPC); 746 } 747 748 /* 749 * Offset in the current MBUF. 750 */ 751 s = mdp->md_pos; 752 ASSERT((m->b_rptr <= s) && (s <= m->b_wptr)); 753 754 /* Data remaining. */ 755 diff = (uintptr_t)m->b_wptr - (uintptr_t)s; 756 ASSERT(diff == (uint64_t)((int)diff)); 757 count = (int)diff; 758 759 /* 760 * Check if the no. of bytes remaining is less than 761 * the bytes requested. 762 */ 763 if (count == 0) { 764 m = m->b_cont; 765 if (m) { 766 mdp->md_cur = m; 767 mdp->md_pos = s = m->b_rptr; 768 } 769 continue; 770 } 771 if (count > size) 772 count = size; 773 size -= count; 774 mdp->md_pos += count; 775 if (target == NULL) 776 continue; 777 switch (type) { 778 case MB_MUSER: 779 error = copyout(s, (void *)target, count); 780 if (error) 781 return (error); 782 break; 783 case MB_MSYSTEM: 784 bcopy(s, target, count); 785 break; 786 case MB_MINLINE: 787 while (count--) 788 *target++ = *s++; 789 continue; 790 } 791 target += count; 792 } 793 return (0); 794 } 795 796 /* 797 * Get the next SIZE bytes as a separate mblk. 798 */ 799 int 800 md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret) 801 { 802 mblk_t *m, *rm; 803 804 unsigned char *s; 805 uint64_t diff; 806 int off; 807 808 /* 809 * Offset in the current MBUF. 810 */ 811 m = mdp->md_cur; 812 s = mdp->md_pos; 813 ASSERT((m->b_rptr <= s) && (s <= m->b_wptr)); 814 diff = (uintptr_t)s - (uintptr_t)m->b_rptr; 815 ASSERT(diff == (uint64_t)((int)diff)); 816 off = (int)diff; 817 818 rm = m_copym(m, off, size, M_WAITOK); 819 if (rm == NULL) 820 return (EBADRPC); 821 822 *ret = rm; 823 return (0); 824 } 825 826 int 827 md_get_uio(struct mdchain *mdp, uio_t *uiop, int size) 828 { 829 size_t left; 830 int mtype, error; 831 832 mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM); 833 while (size > 0 && uiop->uio_resid) { 834 if (uiop->uio_iovcnt <= 0 || 835 uio_curriovbase(uiop) == USER_ADDR_NULL) 836 return (EFBIG); 837 left = uio_curriovlen(uiop); 838 if (left > size) 839 left = size; 840 error = md_get_mem(mdp, CAST_DOWN(caddr_t, 841 uio_curriovbase(uiop)), left, mtype); 842 if (error) 843 return (error); 844 uio_update(uiop, left); 845 size -= left; 846 } 847 return (0); 848 } 849 850 /* 851 * Additions for Solaris 852 */ 853 854 /* 855 * concatenate mblk chain n to m. 856 * go till end of data in m. 857 * then add the link of b_cont to n. 858 * See: linkb(9f) 859 */ 860 861 void m_cat( 862 mblk_t *m, 863 mblk_t *n) 864 { 865 if (!n) 866 return; 867 while (m->b_cont) { 868 m = m->b_cont; 869 } 870 m->b_cont = n; 871 } 872 873 /*ARGSUSED*/ 874 mblk_t * 875 m_copym(mblk_t *m, int off, int len, int wait) 876 { 877 mblk_t *n; 878 size_t dsz; 879 ssize_t adj; 880 881 dsz = msgdsize(m); 882 if (len == M_COPYALL) { 883 if (off > dsz) 884 return (0); 885 } else { 886 if ((off + len) > dsz) 887 return (0); 888 } 889 890 if ((n = dupmsg(m)) == NULL) 891 return (0); 892 893 /* trim from head */ 894 adj = off; 895 if (!adjmsg(n, adj)) { 896 freemsg(n); 897 return (0); 898 } 899 900 /* trim from tail */ 901 if (len != M_COPYALL) { 902 dsz = msgdsize(n); 903 ASSERT(len <= dsz); 904 if (len < dsz) { 905 adj = (ssize_t)len - (ssize_t)dsz; 906 ASSERT(adj < 0); 907 adjmsg(n, adj); 908 } 909 } 910 911 return (n); 912 } 913 914 /* 915 * Get "rqlen" contiguous bytes into the first mblk of a chain. 916 */ 917 mblk_t * 918 m_pullup( 919 mblk_t *m, 920 int rqlen) 921 { 922 ptrdiff_t diff; 923 924 /*LINTED*/ 925 diff = MBLKL(m); 926 ASSERT(diff == (ptrdiff_t)((int)diff)); 927 if ((int)diff < rqlen) { 928 /* This should be rare. */ 929 if (!pullupmsg(m, rqlen)) { 930 SMBSDEBUG("pullupmsg failed!\n"); 931 freemsg(m); 932 return (NULL); 933 } 934 } 935 return (m); 936 } 937 938 939 /* 940 * m_split : split the mblk from the offset(len0) to the end. 941 * Partition an mbuf chain in two pieces, returning the tail -- 942 * all but the first len0 bytes. In case of failure, it returns NULL and 943 * attempts to restore the chain to its original state. 944 * Similar to dupmsg() + adjmsg() on Solaris. 945 */ 946 /*ARGSUSED*/ 947 mblk_t * 948 m_split( 949 mblk_t *m0, 950 int len0, 951 int wait) 952 { 953 mblk_t *m, *n; 954 int mbl, len = len0; 955 ptrdiff_t diff; 956 957 #if 0 /* If life were simple, this would be: */ 958 for (m = m0; m && len > MBLKL(m); m = m->b_cont) 959 len -= MBLKL(m); 960 #else /* but with LP64 and picky lint we have: */ 961 for (m = m0; m; m = m->b_cont) { 962 /*LINTED*/ 963 diff = MBLKL(m); 964 ASSERT(diff == (ptrdiff_t)((int)diff)); 965 mbl = (int)diff; 966 if (len <= mbl) 967 break; 968 len -= mbl; 969 } 970 #endif 971 972 if (m == 0) 973 return (0); 974 975 /* This is the one to split (dupb, adjust) */ 976 if ((n = dupb(m)) == 0) 977 return (0); 978 979 /*LINTED*/ 980 ASSERT(len <= MBLKL(m)); 981 982 m->b_wptr = m->b_rptr + len; 983 n->b_rptr += len; 984 985 /* Move any b_cont (tail) to the new head. */ 986 n->b_cont = m->b_cont; 987 m->b_cont = NULL; 988 989 return (n); 990 } 991