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 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 * 39 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/errno.h> 45 #include <sys/uio.h> 46 #include <sys/types.h> 47 #include <sys/stream.h> 48 #include <sys/strsun.h> 49 #include <sys/strsubr.h> 50 #include <sys/sunddi.h> 51 #include <sys/cmn_err.h> 52 53 #include <netsmb/smb_osdep.h> 54 #include <netsmb/mchain.h> 55 56 #include <netsmb/smb.h> 57 #include <netsmb/smb_conn.h> 58 #include <netsmb/smb_subr.h> 59 60 /* BEGIN CSTYLED */ 61 /* 62 * BSD-style mbufs, vs SysV-style mblks: 63 * One big difference: the mbuf payload is: 64 * m_data ... (m_data + m_len) 65 * In Unix STREAMS, the mblk payload is: 66 * b_rptr ... b_wptr 67 * 68 * Here are some handy conversion notes: 69 * 70 * struct mbuf struct mblk 71 * m->m_next m->b_cont 72 * m->m_nextpkt m->b_next 73 * m->m_data m->b_rptr 74 * m->m_len MBLKL(m) 75 * m->m_dat[] m->b_datap->db_base 76 * &m->m_dat[MLEN] m->b_datap->db_lim 77 * M_TRAILINGSPACE(m) MBLKTAIL(m) 78 * m_freem(m) freemsg(m) 79 * 80 * Note that mbufs chains also have a special "packet" header, 81 * which has the length of the whole message. In STREAMS one 82 * typically just calls msgdsize(m) to get that. 83 */ 84 /* END CSTYLED */ 85 86 87 /* 88 * 89 * MODULE_VERSION(libmchain, 1); 90 */ 91 92 #ifdef __GNUC__ 93 #define MBERROR(format, args...) printf("%s(%d): "format, \ 94 __FUNCTION__, __LINE__, ## args) 95 #define MBPANIC(format, args...) printf("%s(%d): "format, \ 96 __FUNCTION__, __LINE__, ## args) 97 #else 98 #define MBERROR(...) \ 99 smb_errmsg(CE_NOTE, __func__, __VA_ARGS__) 100 #define MBPANIC(...) \ 101 smb_errmsg(CE_PANIC, __func__, __VA_ARGS__) 102 #endif 103 104 /* 105 * MLEN: The smallest mblk we'll allocate. 106 * 107 * There's more to MLEN than you might think. 108 * Some ethernet drivers may send each mblk as a 109 * separate frame, so we want MLEN at least 1K. 110 * We could have used 1K here, but that might 111 * hurt transports that support larger frames. 112 * 4K fits nicely in 3 Ethernet frames (3 * 1500) 113 * leaving about 500 bytes for protocol headers. 114 */ 115 #define MLEN 4096 116 117 #if (MLEN < SMB2_HDRLEN) 118 #error "MLEN can't fit a contiguous SMB2 header" 119 #endif 120 121 /* 122 * Some UIO routines. 123 * Taken from Darwin Sourcecs. 124 */ 125 126 /* 127 * uio_isuserspace - non zero value if the address space 128 * flag is for a user address space (could be 32 or 64 bit). 129 */ 130 #define uio_isuserspace(uio) (uio->uio_segflg == UIO_USERSPACE) 131 132 /* 133 * uio_curriovbase - return the base address of the current iovec associated 134 * with the given uio_t. May return 0. 135 */ 136 caddr_t 137 uio_curriovbase(uio_t *a_uio) 138 { 139 if (a_uio->uio_iovcnt < 1) { 140 return (0); 141 } 142 return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base)); 143 } 144 145 /* 146 * uio_curriovlen - return the length value of the current iovec associated 147 * with the given uio_t. 148 */ 149 size_t 150 uio_curriovlen(uio_t *a_uio) 151 { 152 if (a_uio->uio_iovcnt < 1) { 153 return (0); 154 } 155 return ((size_t)a_uio->uio_iov->iov_len); 156 } 157 158 159 /* 160 * uio_update - update the given uio_t for a_count of completed IO. 161 * This call decrements the current iovec length and residual IO value 162 * and increments the current iovec base address and offset value. 163 * If the current iovec length is 0 then advance to the next 164 * iovec (if any). 165 * If the a_count passed in is 0, than only do the advancement 166 * over any 0 length iovec's. 167 */ 168 void 169 uio_update(uio_t *a_uio, size_t a_count) 170 { 171 if (a_uio->uio_iovcnt < 1) { 172 return; 173 } 174 175 /* 176 * if a_count == 0, then we are asking to skip over 177 * any empty iovs 178 */ 179 if (a_count) { 180 if (a_count > a_uio->uio_iov->iov_len) { 181 a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len; 182 a_uio->uio_iov->iov_len = 0; 183 } else { 184 a_uio->uio_iov->iov_base += a_count; 185 a_uio->uio_iov->iov_len -= a_count; 186 } 187 if (a_uio->uio_resid < 0) { 188 a_uio->uio_resid = 0; 189 } 190 if (a_count > (size_t)a_uio->uio_resid) { 191 a_uio->uio_loffset += a_uio->uio_resid; 192 a_uio->uio_resid = 0; 193 } else { 194 a_uio->uio_loffset += a_count; 195 a_uio->uio_resid -= a_count; 196 } 197 } 198 /* 199 * advance to next iovec if current one is totally consumed 200 */ 201 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) { 202 a_uio->uio_iovcnt--; 203 if (a_uio->uio_iovcnt > 0) { 204 a_uio->uio_iov++; 205 } 206 } 207 } 208 209 /* 210 * This is now used only to extend an existing mblk chain, 211 * so don't need to use allocb_cred_wait here. 212 */ 213 /*ARGSUSED*/ 214 mblk_t * 215 m_getblk(int size, int type) 216 { 217 mblk_t *mblk; 218 int error; 219 220 /* Make size at least MLEN. */ 221 if (size < MLEN) 222 size = MLEN; 223 mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error); 224 ASSERT(mblk); 225 return (mblk); 226 } 227 228 void 229 mb_done(struct mbchain *mbp) 230 { 231 if (mbp->mb_top) { 232 freemsg(mbp->mb_top); 233 mbp->mb_top = NULL; 234 } 235 /* Avoid dangling references */ 236 mbp->mb_cur = NULL; 237 } 238 239 unsigned int 240 m_length(mblk_t *mblk) 241 { 242 uint64_t diff; 243 244 diff = (uintptr_t)mblk->b_datap->db_lim - 245 (uintptr_t)mblk->b_datap->db_base; 246 ASSERT(diff == (uint64_t)((unsigned int)diff)); 247 return ((unsigned int)diff); 248 } 249 250 void 251 mb_initm(struct mbchain *mbp, mblk_t *m) 252 { 253 bzero(mbp, sizeof (*mbp)); 254 mbp->mb_top = mbp->mb_cur = m; 255 } 256 257 258 int 259 mb_init(struct mbchain *mbp) 260 { 261 cred_t *cr; 262 mblk_t *mblk; 263 int error; 264 265 /* 266 * This message will be the head of a new mblk chain, 267 * so we'd like its db_credp set. If we extend this 268 * chain later, we'll just use allocb_wait() 269 */ 270 cr = ddi_get_cred(); 271 mblk = allocb_cred_wait(MLEN, STR_NOSIG, &error, cr, NOPID); 272 273 /* 274 * Leave room in this first mblk so we can 275 * prepend a 4-byte NetBIOS header. 276 * See smb_nbst_send() 277 */ 278 mblk->b_wptr += 4; 279 mblk->b_rptr = mblk->b_wptr; 280 281 mb_initm(mbp, mblk); 282 return (0); 283 } 284 285 286 /* 287 * mb_detach() function returns the value of mbp->mb_top field 288 * and sets its * value to NULL. 289 */ 290 291 mblk_t * 292 mb_detach(struct mbchain *mbp) 293 { 294 mblk_t *m; 295 296 m = mbp->mb_top; 297 mbp->mb_top = mbp->mb_cur = NULL; 298 return (m); 299 } 300 301 /* 302 * Returns the length of the mblk_t data. 303 * Should be m_totlen() perhaps? 304 */ 305 int 306 m_fixhdr(mblk_t *m0) 307 { 308 size_t dsz; 309 310 dsz = msgdsize(m0); 311 return ((int)dsz); 312 } 313 314 /* 315 * BSD code set the message header length here, and 316 * returned the length. We don't have that field, so 317 * just return the message length. 318 */ 319 int 320 mb_fixhdr(struct mbchain *mbp) 321 { 322 return (m_fixhdr(mbp->mb_top)); 323 } 324 325 326 /* 327 * Check if object of size 'size' fit to the current position and 328 * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s). 329 * Return pointer to the object placeholder or NULL if any error occured. 330 * Note: size should be <= MLEN 331 */ 332 void * 333 mb_reserve(struct mbchain *mbp, int size) 334 { 335 mblk_t *m, *mn; 336 void *bpos; 337 338 m = mbp->mb_cur; 339 /* 340 * If the requested size is more than the space left. 341 * Allocate and appenad a new mblk. 342 */ 343 if (MBLKTAIL(m) < size) { 344 mn = m_getblk(size, 1); 345 if (mn == NULL) 346 return (NULL); 347 mbp->mb_cur = m->b_cont = mn; 348 m = mn; 349 } 350 /* 351 * If 'size' bytes fits into the buffer, then 352 * 1. increment the write pointer to the size. 353 * 2. return the position from where the memory is reserved. 354 */ 355 bpos = m->b_wptr; 356 m->b_wptr += size; 357 mbp->mb_count += size; 358 return (bpos); 359 } 360 361 /* 362 * All mb_put_*() functions perform an actual copy of the data into mbuf 363 * chain. Functions which have le or be suffixes will perform conversion to 364 * the little- or big-endian data formats. 365 * 366 * Inline version of mb_put_mem(). Handles the easy case in-line, 367 * and calls mb_put_mem() if crossing mblk boundaries, etc. 368 * 369 * We build with -xspace, which causes these inline functions 370 * to not be inlined. Using macros instead for now. 371 */ 372 #ifdef INLINE_WORKS 373 374 static inline int 375 mb_put_inline(struct mbchain *mbp, void *src, int size) 376 { 377 mblk_t *m = mbp->mb_cur; 378 379 if (m != NULL && size <= MBLKTAIL(m)) { 380 uchar_t *p = src; 381 int n = size; 382 while (n--) 383 *(m->b_wptr)++ = *p++; 384 mbp->mb_count += size; 385 return (0); 386 } 387 return (mb_put_mem(mbp, src, size, MB_MINLINE)); 388 } 389 #define MB_PUT_INLINE(MBP, SRC, SZ) \ 390 return (mb_put_inline(MBP, SRC, SZ)) 391 392 #else /* INLINE_WORKS */ 393 394 #define MB_PUT_INLINE(MBP, SRC, SZ) \ 395 mblk_t *m = MBP->mb_cur; \ 396 if (m != NULL && SZ <= MBLKTAIL(m)) { \ 397 uchar_t *p = (void *) SRC; \ 398 int n = SZ; \ 399 while (n--) \ 400 *(m->b_wptr)++ = *p++; \ 401 MBP->mb_count += SZ; \ 402 return (0); \ 403 } \ 404 return (mb_put_mem(MBP, SRC, SZ, MB_MINLINE)) 405 406 #endif /* INLINE_WORKS */ 407 408 /* 409 * Assumes total data length in previous mblks is EVEN. 410 * Might need to compute the offset from mb_top instead. 411 */ 412 int 413 mb_put_padbyte(struct mbchain *mbp) 414 { 415 uintptr_t dst; 416 char v = 0; 417 418 dst = (uintptr_t)mbp->mb_cur->b_wptr; 419 /* only add padding if address is odd */ 420 if (dst & 1) { 421 MB_PUT_INLINE(mbp, &v, sizeof (v)); 422 } 423 424 return (0); 425 } 426 427 /* 428 * Adds padding to 8 byte boundary 429 */ 430 int 431 mb_put_align8(struct mbchain *mbp) 432 { 433 static const char zeros[8] = { 0 }; 434 int pad_len = 0; 435 436 if ((mbp->mb_count % 8) != 0) { 437 pad_len = 8 - (mbp->mb_count % 8); 438 MB_PUT_INLINE(mbp, zeros, pad_len); 439 } 440 return (0); 441 } 442 443 int 444 mb_put_uint8(struct mbchain *mbp, u_int8_t x) 445 { 446 u_int8_t v = x; 447 MB_PUT_INLINE(mbp, &v, sizeof (v)); 448 } 449 450 int 451 mb_put_uint16be(struct mbchain *mbp, u_int16_t x) 452 { 453 u_int16_t v = htobes(x); 454 MB_PUT_INLINE(mbp, &v, sizeof (v)); 455 } 456 457 int 458 mb_put_uint16le(struct mbchain *mbp, u_int16_t x) 459 { 460 u_int16_t v = htoles(x); 461 MB_PUT_INLINE(mbp, &v, sizeof (v)); 462 } 463 464 int 465 mb_put_uint32be(struct mbchain *mbp, u_int32_t x) 466 { 467 u_int32_t v = htobel(x); 468 MB_PUT_INLINE(mbp, &v, sizeof (v)); 469 } 470 471 int 472 mb_put_uint32le(struct mbchain *mbp, u_int32_t x) 473 { 474 u_int32_t v = htolel(x); 475 MB_PUT_INLINE(mbp, &v, sizeof (v)); 476 } 477 478 int 479 mb_put_uint64be(struct mbchain *mbp, u_int64_t x) 480 { 481 u_int64_t v = htobeq(x); 482 MB_PUT_INLINE(mbp, &v, sizeof (v)); 483 } 484 485 int 486 mb_put_uint64le(struct mbchain *mbp, u_int64_t x) 487 { 488 u_int64_t v = htoleq(x); 489 MB_PUT_INLINE(mbp, &v, sizeof (v)); 490 } 491 492 /* 493 * mb_put_mem() function copies size bytes of data specified by the source 494 * argument to an mbuf chain. The type argument specifies the method used 495 * to perform a copy 496 */ 497 int 498 mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type) 499 { 500 mblk_t *n, *m = mbp->mb_cur; 501 c_caddr_t source = vsrc; 502 c_caddr_t src; 503 caddr_t dst; 504 uint64_t diff; 505 int cplen, mleft, count; 506 507 diff = MBLKTAIL(m); 508 ASSERT(diff == (uint64_t)((int)diff)); 509 mleft = (int)diff; 510 511 while (size > 0) { 512 if (mleft == 0) { 513 if (m->b_cont == NULL) { 514 /* 515 * Changed m_getm() to m_getblk() 516 * with the requested size, so we 517 * don't need m_getm() anymore. 518 */ 519 n = m_getblk(size, 1); 520 if (n == NULL) 521 return (ENOBUFS); 522 m->b_cont = n; 523 } 524 m = m->b_cont; 525 diff = MBLKTAIL(m); 526 ASSERT(diff == (uint64_t)((int)diff)); 527 mleft = (int)diff; 528 continue; 529 } 530 cplen = mleft > size ? size : mleft; 531 dst = (caddr_t)m->b_wptr; 532 switch (type) { 533 case MB_MINLINE: 534 for (src = source, count = cplen; count; count--) 535 *dst++ = *src++; 536 break; 537 case MB_MSYSTEM: 538 bcopy(source, dst, cplen); 539 break; 540 case MB_MUSER: 541 if (copyin((void *)source, dst, cplen)) 542 return (EFAULT); 543 break; 544 case MB_MZERO: 545 bzero(dst, cplen); 546 break; 547 } 548 size -= cplen; 549 source += cplen; 550 mleft -= cplen; 551 m->b_wptr += cplen; 552 mbp->mb_count += cplen; 553 } 554 mbp->mb_cur = m; 555 return (0); 556 } 557 558 /* 559 * Append an mblk to the chain. 560 * Note: The mblk_t *m is consumed. 561 */ 562 int 563 mb_put_mbuf(struct mbchain *mbp, mblk_t *m) 564 { 565 mblk_t *nm, *tail_mb; 566 size_t size; 567 568 /* See: linkb(9f) */ 569 tail_mb = mbp->mb_cur; 570 while (tail_mb->b_cont != NULL) 571 tail_mb = tail_mb->b_cont; 572 573 /* 574 * Avoid small frags: Only link if the size of the 575 * new mbuf is larger than the space left in the last 576 * mblk of the chain (tail), otherwise just copy. 577 */ 578 while (m != NULL) { 579 size = MBLKL(m); 580 if (size > MBLKTAIL(tail_mb)) { 581 /* Link */ 582 tail_mb->b_cont = m; 583 mbp->mb_cur = m; 584 mbp->mb_count += msgdsize(m); 585 return (0); 586 } 587 /* Copy */ 588 bcopy(m->b_rptr, tail_mb->b_wptr, size); 589 tail_mb->b_wptr += size; 590 mbp->mb_count += size; 591 nm = unlinkb(m); 592 freeb(m); 593 m = nm; 594 } 595 596 return (0); 597 } 598 599 /* 600 * Put an mbchain into another mbchain 601 * Leave sub_mbp untouched. 602 */ 603 int 604 mb_put_mbchain(struct mbchain *mbp, struct mbchain *sub_mbp) 605 { 606 mblk_t *m; 607 608 if (sub_mbp == NULL) 609 return (0); 610 611 m = sub_mbp->mb_top; 612 if (m == NULL) 613 return (0); 614 615 m = dupmsg(m); 616 if (m == NULL) 617 return (ENOSR); 618 619 return (mb_put_mbuf(mbp, m)); 620 } 621 622 /* 623 * copies a uio scatter/gather list to an mbuf chain. 624 */ 625 int 626 mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size) 627 { 628 size_t left; 629 int mtype, error; 630 631 mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM); 632 while (size > 0 && uiop->uio_resid) { 633 if (uiop->uio_iovcnt <= 0 || 634 uio_curriovbase(uiop) == USER_ADDR_NULL) 635 return (EFBIG); 636 left = uio_curriovlen(uiop); 637 if (left > size) 638 left = size; 639 error = mb_put_mem(mbp, CAST_DOWN(caddr_t, 640 uio_curriovbase(uiop)), left, mtype); 641 if (error) 642 return (error); 643 uio_update(uiop, left); 644 size -= left; 645 } 646 return (0); 647 } 648 649 /* 650 * Routines for fetching data from an mbuf chain 651 */ 652 653 void 654 md_initm(struct mdchain *mdp, mblk_t *m) 655 { 656 bzero(mdp, sizeof (*mdp)); 657 mdp->md_top = mdp->md_cur = m; 658 mdp->md_pos = m->b_rptr; 659 } 660 661 void 662 md_done(struct mdchain *mdp) 663 { 664 mblk_t *m; 665 666 /* 667 * Deal with the fact that we can error out of 668 * smb_t2_reply or smb_nt_reply without using up 669 * all the "records" added by md_append_record(). 670 */ 671 while ((m = mdp->md_top) != NULL) { 672 mdp->md_top = m->b_next; 673 m->b_next = NULL; 674 freemsg(m); 675 } 676 /* Avoid dangling references */ 677 mdp->md_cur = NULL; 678 mdp->md_pos = NULL; 679 } 680 681 /* 682 * Append a new message (separate mbuf chain). 683 * It is caller responsibility to prevent 684 * multiple calls to fetch/record routines. 685 * Note unusual use of mblk->b_next here. 686 */ 687 void 688 md_append_record(struct mdchain *mdp, mblk_t *top) 689 { 690 mblk_t *m; 691 692 top->b_next = NULL; 693 if (mdp->md_top == NULL) { 694 md_initm(mdp, top); 695 return; 696 } 697 m = mdp->md_top; 698 /* Get to last message (not b_cont chain) */ 699 while (m->b_next) 700 m = m->b_next; 701 m->b_next = top; 702 } 703 704 /* 705 * Advance mdp->md_top to the next message. 706 * Note unusual use of mblk->b_next here. 707 */ 708 void 709 md_next_record(struct mdchain *mdp) 710 { 711 mblk_t *m, *top; 712 713 if ((top = mdp->md_top) == NULL) 714 return; 715 716 /* 717 * Get the next message, if any, 718 * stored by md_append_record. 719 * Note: NOT b_cont chain 720 */ 721 m = top->b_next; 722 top->b_next = NULL; 723 724 /* Done with old "top". */ 725 md_done(mdp); 726 if (m == NULL) 727 return; 728 729 /* Setup new "top". */ 730 md_initm(mdp, m); 731 } 732 733 /* 734 * Inline version of md_get_mem(). Handles the easy case in-line, 735 * and calls md_get_mem() if crossing mblk boundaries, etc. 736 */ 737 #ifdef INLINE_WORKS /* see above */ 738 739 static inline int 740 md_get_inline(struct mdchain *mdp, void *dst, int size) 741 { 742 mblk_t *m = mdp->md_cur; 743 744 if (m != NULL && mdp->md_pos + size <= m->b_wptr) { 745 uchar_t *p = dst; 746 int n = size; 747 while (n--) 748 *p++ = *(mdp->md_pos)++; 749 /* no md_count += size */ 750 return (0); 751 } 752 return (md_get_mem(mdp, dst, size, MB_MINLINE)); 753 } 754 #define MD_GET_INLINE(MDP, DST, SZ) \ 755 error = md_get_inline(MDP, DST, SZ) 756 757 #else /* INLINE_WORKS */ 758 759 /* Note, sets variable: error */ 760 #define MD_GET_INLINE(MDP, DST, SZ) \ 761 mblk_t *m = MDP->md_cur; \ 762 if (m != NULL && MDP->md_pos + SZ <= m->b_wptr) { \ 763 uchar_t *p = (void *) DST; \ 764 int n = SZ; \ 765 while (n--) \ 766 *p++ = *(mdp->md_pos)++; \ 767 /* no md_count += SZ */ \ 768 error = 0; \ 769 } else \ 770 error = md_get_mem(MDP, DST, SZ, MB_MINLINE) 771 772 #endif /* INLINE_WORKS */ 773 774 775 int 776 md_get_uint8(struct mdchain *mdp, u_int8_t *x) 777 { 778 uint8_t v; 779 int error; 780 781 MD_GET_INLINE(mdp, &v, sizeof (v)); 782 if (x) 783 *x = v; 784 return (error); 785 } 786 787 int 788 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) { 789 u_int16_t v; 790 int error; 791 792 MD_GET_INLINE(mdp, &v, sizeof (v)); 793 if (x) 794 *x = betohs(v); 795 return (error); 796 } 797 798 int 799 md_get_uint16le(struct mdchain *mdp, u_int16_t *x) 800 { 801 u_int16_t v; 802 int error; 803 804 MD_GET_INLINE(mdp, &v, sizeof (v)); 805 if (x) 806 *x = letohs(v); 807 return (error); 808 } 809 810 int 811 md_get_uint32be(struct mdchain *mdp, u_int32_t *x) 812 { 813 u_int32_t v; 814 int error; 815 816 MD_GET_INLINE(mdp, &v, sizeof (v)); 817 if (x) 818 *x = betohl(v); 819 return (error); 820 } 821 822 int 823 md_get_uint32le(struct mdchain *mdp, u_int32_t *x) 824 { 825 u_int32_t v; 826 int error; 827 828 MD_GET_INLINE(mdp, &v, sizeof (v)); 829 if (x) 830 *x = letohl(v); 831 return (error); 832 } 833 834 int 835 md_get_uint64be(struct mdchain *mdp, u_int64_t *x) 836 { 837 u_int64_t v; 838 int error; 839 840 MD_GET_INLINE(mdp, &v, sizeof (v)); 841 if (x) 842 *x = betohq(v); 843 return (error); 844 } 845 846 int 847 md_get_uint64le(struct mdchain *mdp, u_int64_t *x) 848 { 849 u_int64_t v; 850 int error; 851 852 MD_GET_INLINE(mdp, &v, sizeof (v)); 853 if (x) 854 *x = letohq(v); 855 return (error); 856 } 857 858 int 859 md_get_mem(struct mdchain *mdp, void *vdst, int size, int type) 860 { 861 mblk_t *m = mdp->md_cur; 862 caddr_t target = vdst; 863 unsigned char *s; 864 uint64_t diff; 865 int count; 866 867 while (size > 0) { 868 if (m == NULL) { 869 SMBSDEBUG("incomplete copy\n"); 870 return (EBADRPC); 871 } 872 873 /* 874 * Offset in the current MBUF. 875 */ 876 s = mdp->md_pos; 877 ASSERT((m->b_rptr <= s) && (s <= m->b_wptr)); 878 879 /* Data remaining. */ 880 diff = (uintptr_t)m->b_wptr - (uintptr_t)s; 881 ASSERT(diff == (uint64_t)((int)diff)); 882 count = (int)diff; 883 884 /* 885 * Check if the no. of bytes remaining is less than 886 * the bytes requested. 887 */ 888 if (count == 0) { 889 m = m->b_cont; 890 if (m) { 891 mdp->md_cur = m; 892 mdp->md_pos = s = m->b_rptr; 893 } 894 continue; 895 } 896 if (count > size) 897 count = size; 898 size -= count; 899 mdp->md_pos += count; 900 if (target == NULL) 901 continue; 902 switch (type) { 903 case MB_MUSER: 904 if (copyout(s, target, count)) 905 return (EFAULT); 906 break; 907 case MB_MSYSTEM: 908 bcopy(s, target, count); 909 break; 910 case MB_MINLINE: 911 while (count--) 912 *target++ = *s++; 913 continue; 914 } 915 target += count; 916 } 917 return (0); 918 } 919 920 /* 921 * Get the next SIZE bytes as a separate mblk. 922 * Advances position in mdp by SIZE. 923 */ 924 int 925 md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret) 926 { 927 mblk_t *m, *rm; 928 929 unsigned char *s; 930 uint64_t diff; 931 int off; 932 933 /* 934 * Offset in the current MBUF. 935 */ 936 m = mdp->md_cur; 937 s = mdp->md_pos; 938 ASSERT((m->b_rptr <= s) && (s <= m->b_wptr)); 939 diff = (uintptr_t)s - (uintptr_t)m->b_rptr; 940 ASSERT(diff == (uint64_t)((int)diff)); 941 off = (int)diff; 942 943 rm = m_copym(m, off, size, M_WAITOK); 944 if (rm == NULL) 945 return (EBADRPC); 946 (void) md_get_mem(mdp, NULL, size, MB_MSYSTEM); 947 948 *ret = rm; 949 return (0); 950 } 951 952 int 953 md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size) 954 { 955 size_t left; 956 int mtype, error; 957 958 mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM); 959 while (size > 0 && uiop->uio_resid) { 960 if (uiop->uio_iovcnt <= 0 || 961 uio_curriovbase(uiop) == USER_ADDR_NULL) 962 return (EFBIG); 963 left = uio_curriovlen(uiop); 964 if (left > size) 965 left = size; 966 error = md_get_mem(mdp, CAST_DOWN(caddr_t, 967 uio_curriovbase(uiop)), left, mtype); 968 if (error) 969 return (error); 970 uio_update(uiop, left); 971 size -= left; 972 } 973 return (0); 974 } 975 976 /* 977 * Additions for Solaris 978 */ 979 980 /* 981 * concatenate mblk chain n to m. 982 * go till end of data in m. 983 * then add the link of b_cont to n. 984 * See: linkb(9f) 985 */ 986 987 void m_cat( 988 mblk_t *m, 989 mblk_t *n) 990 { 991 if (!n) 992 return; 993 while (m->b_cont) { 994 m = m->b_cont; 995 } 996 m->b_cont = n; 997 } 998 999 /*ARGSUSED*/ 1000 mblk_t * 1001 m_copym(mblk_t *m, int off, int len, int wait) 1002 { 1003 mblk_t *n; 1004 size_t dsz; 1005 ssize_t adj; 1006 1007 dsz = msgdsize(m); 1008 if (len == M_COPYALL) { 1009 if (off > dsz) 1010 return (0); 1011 } else { 1012 if ((off + len) > dsz) 1013 return (0); 1014 } 1015 1016 if ((n = dupmsg(m)) == NULL) 1017 return (0); 1018 1019 /* trim from head */ 1020 adj = off; 1021 if (!adjmsg(n, adj)) { 1022 freemsg(n); 1023 return (0); 1024 } 1025 1026 /* trim from tail */ 1027 if (len != M_COPYALL) { 1028 dsz = msgdsize(n); 1029 ASSERT(len <= dsz); 1030 if (len < dsz) { 1031 adj = (ssize_t)len - (ssize_t)dsz; 1032 ASSERT(adj < 0); 1033 (void) adjmsg(n, adj); 1034 } 1035 } 1036 1037 return (n); 1038 } 1039 1040 /* 1041 * Get "rqlen" contiguous bytes into the first mblk of a chain. 1042 */ 1043 mblk_t * 1044 m_pullup( 1045 mblk_t *m, 1046 int rqlen) 1047 { 1048 ptrdiff_t diff; 1049 1050 diff = MBLKL(m); 1051 ASSERT(diff == (ptrdiff_t)((int)diff)); 1052 if ((int)diff < rqlen) { 1053 /* This should be rare. */ 1054 if (!pullupmsg(m, rqlen)) { 1055 SMBSDEBUG("pullupmsg failed!\n"); 1056 freemsg(m); 1057 return (NULL); 1058 } 1059 } 1060 return (m); 1061 } 1062 1063 1064 /* 1065 * m_split : split the mblk from the offset(len0) to the end. 1066 * Partition an mbuf chain in two pieces, returning the tail -- 1067 * all but the first len0 bytes. In case of failure, it returns NULL and 1068 * attempts to restore the chain to its original state. 1069 * Similar to dupmsg() + adjmsg() on Solaris. 1070 */ 1071 /*ARGSUSED*/ 1072 mblk_t * 1073 m_split( 1074 mblk_t *m0, 1075 int len0, 1076 int wait) 1077 { 1078 mblk_t *m, *n; 1079 int mbl, len = len0; 1080 ptrdiff_t diff; 1081 1082 #if 0 /* If life were simple, this would be: */ 1083 for (m = m0; m && len > MBLKL(m); m = m->b_cont) 1084 len -= MBLKL(m); 1085 #else /* but with LP64 and picky lint we have: */ 1086 for (m = m0; m; m = m->b_cont) { 1087 diff = MBLKL(m); 1088 ASSERT(diff == (ptrdiff_t)((int)diff)); 1089 mbl = (int)diff; 1090 if (len <= mbl) 1091 break; 1092 len -= mbl; 1093 } 1094 #endif 1095 1096 if (m == 0) 1097 return (0); 1098 1099 /* This is the one to split (dupb, adjust) */ 1100 if ((n = dupb(m)) == 0) 1101 return (0); 1102 1103 ASSERT(len <= MBLKL(m)); 1104 1105 m->b_wptr = m->b_rptr + len; 1106 n->b_rptr += len; 1107 1108 /* Move any b_cont (tail) to the new head. */ 1109 n->b_cont = m->b_cont; 1110 m->b_cont = NULL; 1111 1112 return (n); 1113 } 1114