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