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,
|