2 * Copyright (c) 2000, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * $Id: mbuf.c,v 1.3 2004/12/13 00:25:22 lindak Exp $
36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
39 #include <sys/types.h>
49 #include <netsmb/smb_lib.h>
50 #include <netsmb/mchain.h>
56 * Note: Leaving a little space (8 bytes) between the
57 * mbuf header and the start of the data so we can
58 * prepend a NetBIOS header in that space.
60 #define M_ALIGNFACTOR (sizeof (long))
61 #define M_ALIGN(len) (((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1))
62 #define M_BASESIZE (sizeof (struct mbuf) + 8)
63 #define M_MINSIZE (1024 - M_BASESIZE)
64 #define M_TOP(m) ((char *)(m) + M_BASESIZE)
65 #define M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len)
68 m_get(int len
, struct mbuf
**mpp
)
72 assert(len
< 0x100000); /* sanity */
77 m
= malloc(M_BASESIZE
+ len
);
80 bzero(m
, M_BASESIZE
+ len
);
88 m_free(struct mbuf
*m
)
94 m_freem(struct mbuf
*m0
)
106 m_totlen(struct mbuf
*m0
)
119 m_lineup(struct mbuf
*m0
, struct mbuf
**mpp
)
126 if (m0
->m_next
== NULL
) {
130 totlen
= m_totlen(m0
);
131 if ((error
= m_get(totlen
, &nm
)) != 0)
133 dp
= mtod(nm
, char *);
136 bcopy(m0
->m_data
, dp
, len
);
148 mb_init(struct mbdata
*mbp
)
150 return (mb_init_sz(mbp
, M_MINSIZE
));
154 mb_init_sz(struct mbdata
*mbp
, int size
)
159 if ((error
= m_get(size
, &m
)) != 0)
166 mb_initm(struct mbdata
*mbp
, struct mbuf
*m
)
168 bzero(mbp
, sizeof (*mbp
));
169 mbp
->mb_top
= mbp
->mb_cur
= m
;
170 mbp
->mb_pos
= mtod(m
, char *);
174 mb_done(struct mbdata
*mbp
)
177 m_freem(mbp
->mb_top
);
183 m_getm(struct mbuf
*top
, int len
, struct mbuf
**mpp
)
188 for (mp
= top
; ; mp
= mp
->m_next
) {
189 ts
= M_TRAILINGSPACE(mp
);
193 if (mp
->m_next
== NULL
)
198 if ((error
= m_get(len
, &m
)) != 0)
208 * Routines to put data in a buffer
212 mb_reserve(mbchain_t
*mbp
, int size
)
216 if (mb_fit(mbp
, size
, &p
) != 0)
223 * Check if object of size 'size' fit to the current position and
224 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
225 * Return pointer to the object placeholder or NULL if any error occured.
228 mb_fit(mbchain_t
*mbp
, int size
, char **pp
)
234 if (M_TRAILINGSPACE(m
) < (int)size
) {
235 if ((error
= m_get(size
, &mn
)) != 0)
237 mbp
->mb_pos
= mtod(mn
, char *);
238 mbp
->mb_cur
= m
->m_next
= mn
;
244 mbp
->mb_count
+= size
;
249 mb_put_uint8(mbchain_t
*mbp
, uint8_t x
)
252 return (mb_put_mem(mbp
, &y
, sizeof (y
), MB_MINLINE
));
256 mb_put_uint16be(mbchain_t
*mbp
, uint16_t x
)
258 uint16_t y
= htobes(x
);
259 return (mb_put_mem(mbp
, &y
, sizeof (y
), MB_MINLINE
));
263 mb_put_uint16le(mbchain_t
*mbp
, uint16_t x
)
265 uint16_t y
= htoles(x
);
266 return (mb_put_mem(mbp
, &y
, sizeof (y
), MB_MINLINE
));
270 mb_put_uint32be(mbchain_t
*mbp
, uint32_t x
)
272 uint32_t y
= htobel(x
);
273 return (mb_put_mem(mbp
, &y
, sizeof (y
), MB_MINLINE
));
277 mb_put_uint32le(mbchain_t
*mbp
, uint32_t x
)
279 uint32_t y
= htolel(x
);
280 return (mb_put_mem(mbp
, &y
, sizeof (y
), MB_MINLINE
));
284 mb_put_uint64be(mbchain_t
*mbp
, uint64_t x
)
286 uint64_t y
= htobeq(x
);
287 return (mb_put_mem(mbp
, &y
, sizeof (y
), MB_MINLINE
));
291 mb_put_uint64le(mbchain_t
*mbp
, uint64_t x
)
293 uint64_t y
= htoleq(x
);
294 return (mb_put_mem(mbp
, &y
, sizeof (y
), MB_MINLINE
));
299 mb_put_mem(mbchain_t
*mbp
, const void *vmem
, int size
, int type
)
312 if ((error
= m_getm(m
, size
, &m
)) != 0)
315 cplen
= M_TRAILINGSPACE(m
);
322 dst
= mtod(m
, char *) + m
->m_len
;
324 bcopy(src
, dst
, cplen
);
330 mbp
->mb_count
+= cplen
;
332 mbp
->mb_pos
= mtod(m
, char *) + m
->m_len
;
338 * Append another mbuf to the mbuf chain.
339 * If what we're appending is smaller than
340 * the current trailing space, just copy.
341 * This always consumes the passed mbuf.
344 mb_put_mbuf(mbchain_t
*mbp
, struct mbuf
*m
)
346 struct mbuf
*cm
= mbp
->mb_cur
;
347 int ts
= M_TRAILINGSPACE(cm
);
349 if (m
->m_next
== NULL
&& m
->m_len
<= ts
) {
351 mb_put_mem(mbp
, m
->m_data
, m
->m_len
, MB_MSYSTEM
);
358 mbp
->mb_count
+= m
->m_len
;
359 if (m
->m_next
== NULL
)
363 mbp
->mb_pos
= mtod(m
, char *) + m
->m_len
;
369 * Convenience function to put an OEM or Unicode string,
370 * null terminated, and aligned if necessary.
373 mb_put_string(mbchain_t
*mbp
, const char *s
, int uc
)
378 /* Put Unicode. align(2) first. */
379 if (mbp
->mb_count
& 1)
380 mb_put_uint8(mbp
, 0);
381 err
= mb_put_ustring(mbp
, s
);
383 /* Put ASCII (really OEM) */
384 err
= mb_put_astring(mbp
, s
);
391 * Put an ASCII string (really OEM), given a UTF-8 string.
394 mb_put_astring(mbchain_t
*mbp
, const char *s
)
399 abuf
= convert_utf8_to_wincs(s
);
402 len
= strlen(abuf
) + 1;
403 err
= mb_put_mem(mbp
, abuf
, len
, MB_MSYSTEM
);
409 * Put UCS-2LE, given a UTF-8 string.
412 mb_put_ustring(mbchain_t
*mbp
, const char *s
)
417 ubuf
= convert_utf8_to_leunicode(s
);
420 len
= 2 * (unicode_strlen(ubuf
) + 1);
421 err
= mb_put_mem(mbp
, ubuf
, len
, MB_MSYSTEM
);
427 * Routines for fetching data from an mbuf chain
429 #define mb_left(m, p) (mtod(m, char *) + (m)->m_len - (p))
432 md_get_uint8(mdchain_t
*mbp
, uint8_t *x
)
434 return (md_get_mem(mbp
, x
, 1, MB_MINLINE
));
438 md_get_uint16le(mdchain_t
*mbp
, uint16_t *x
)
443 if ((err
= md_get_mem(mbp
, &v
, sizeof (v
), MB_MINLINE
)) != 0)
451 md_get_uint16be(mdchain_t
*mbp
, uint16_t *x
) {
455 if ((err
= md_get_mem(mbp
, &v
, sizeof (v
), MB_MINLINE
)) != 0)
463 md_get_uint32be(mdchain_t
*mbp
, uint32_t *x
)
468 if ((err
= md_get_mem(mbp
, &v
, sizeof (v
), MB_MINLINE
)) != 0)
476 md_get_uint32le(mdchain_t
*mbp
, uint32_t *x
)
481 if ((err
= md_get_mem(mbp
, &v
, sizeof (v
), MB_MINLINE
)) != 0)
489 md_get_uint64be(mdchain_t
*mbp
, uint64_t *x
)
494 if ((err
= md_get_mem(mbp
, &v
, sizeof (v
), MB_MINLINE
)) != 0)
502 md_get_uint64le(mdchain_t
*mbp
, uint64_t *x
)
507 if ((err
= md_get_mem(mbp
, &v
, sizeof (v
), MB_MINLINE
)) != 0)
516 md_get_mem(mdchain_t
*mbp
, void *vmem
, int size
, int type
)
518 struct mbuf
*m
= mbp
->mb_cur
;
524 /* DPRINT("incomplete copy"); */
527 count
= mb_left(m
, mbp
->mb_pos
);
529 mbp
->mb_cur
= m
= m
->m_next
;
531 mbp
->mb_pos
= mtod(m
, char *);
539 *dst
++ = *mbp
->mb_pos
;
541 bcopy(mbp
->mb_pos
, dst
, count
);
545 mbp
->mb_pos
+= count
;
551 * Get the next SIZE bytes as a separate mblk.
552 * Nothing fancy here - just copy.
555 md_get_mbuf(mdchain_t
*mbp
, int size
, mbuf_t
**ret
)
560 err
= m_get(size
, &m
);
564 err
= md_get_mem(mbp
, m
->m_data
, size
, MB_MSYSTEM
);
576 * Get a string from the mbuf chain,
577 * either Unicode or OEM chars.
580 md_get_string(mdchain_t
*mbp
, char **str_pp
, int uc
)
585 err
= md_get_ustring(mbp
, str_pp
);
587 err
= md_get_astring(mbp
, str_pp
);
592 * Get an ASCII (really OEM) string from the mbuf chain
593 * and convert it to UTF-8
595 * Similar to md_get_ustring below.
598 md_get_astring(mdchain_t
*real_mbp
, char **str_pp
)
600 mdchain_t tmp_mb
, *mbp
;
606 * First, figure out the string length.
607 * Use a copy of the real_mbp so we don't
608 * actually consume it here, then search for
609 * the null (or end of data).
611 bcopy(real_mbp
, &tmp_mb
, sizeof (tmp_mb
));
615 err
= md_get_uint8(mbp
, &ch
);
624 * Now read the (OEM) string for real.
625 * No need to re-check errors.
627 tstr
= malloc(slen
+ 1);
631 for (i
= 0; i
< slen
; i
++) {
632 md_get_uint8(mbp
, &ch
);
636 md_get_uint8(mbp
, NULL
);
639 * Convert OEM to UTF-8
641 ostr
= convert_wincs_to_utf8(tstr
);
651 * Get a UCS-2LE string from the mbuf chain, and
652 * convert it to UTF-8.
654 * Similar to md_get_astring above.
657 md_get_ustring(mdchain_t
*real_mbp
, char **str_pp
)
659 mdchain_t tmp_mb
, *mbp
;
666 * First, align(2) on the real_mbp
668 if (((uintptr_t)real_mbp
->mb_pos
) & 1)
669 md_get_uint8(real_mbp
, NULL
);
672 * Next, figure out the string length.
673 * Use a copy of the real_mbp so we don't
674 * actually consume it here, then search for
675 * the null (or end of data).
677 bcopy(real_mbp
, &tmp_mb
, sizeof (tmp_mb
));
681 err
= md_get_uint16le(mbp
, &ch
);
690 * Now read the (UCS-2) string for real.
691 * No need to re-check errors. Note:
692 * This puts the UCS-2 in NATIVE order!
694 tstr
= calloc(slen
+ 1, 2);
698 for (i
= 0; i
< slen
; i
++) {
699 md_get_uint16le(mbp
, &ch
);
703 md_get_uint16le(mbp
, NULL
);
706 * Convert UCS-2 (native!) to UTF-8
708 ostr
= convert_unicode_to_utf8(tstr
);