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