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 
 
 
  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) {
 
 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 
 
 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);
 
 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,
 
 | 
 
 
  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 
 
 
  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) {
 
 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 
 
 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);
 
 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,
 
 |