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