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 * 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
60 /* BEGIN CSTYLED */
61 /*
62 * BSD-style mbufs, vs SysV-style mblks:
63 * One big difference: the mbuf payload is:
64 * m_data ... (m_data + m_len)
65 * In Unix STREAMS, the mblk payload is:
66 * b_rptr ... b_wptr
67 *
68 * Here are some handy conversion notes:
69 *
70 * struct mbuf struct mblk
71 * m->m_next m->b_cont
72 * m->m_nextpkt m->b_next
73 * m->m_data m->b_rptr
74 * m->m_len MBLKL(m)
75 * m->m_dat[] m->b_datap->db_base
76 * &m->m_dat[MLEN] m->b_datap->db_lim
77 * M_TRAILINGSPACE(m) MBLKTAIL(m)
78 * m_freem(m) freemsg(m)
79 *
80 * Note that mbufs chains also have a special "packet" header,
81 * which has the length of the whole message. In STREAMS one
82 * typically just calls msgdsize(m) to get that.
83 */
84 /* END CSTYLED */
85
86
87 /*
88 *
89 * MODULE_VERSION(libmchain, 1);
90 */
91
92 #ifdef __GNUC__
93 #define MBERROR(format, args...) printf("%s(%d): "format, \
94 __FUNCTION__, __LINE__, ## args)
95 #define MBPANIC(format, args...) printf("%s(%d): "format, \
96 __FUNCTION__, __LINE__, ## args)
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
uio_curriovbase(uio_t * a_uio)137 uio_curriovbase(uio_t *a_uio)
138 {
139 if (a_uio->uio_iovcnt < 1) {
140 return (0);
141 }
142 return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base));
143 }
144
145 /*
146 * uio_curriovlen - return the length value of the current iovec associated
147 * with the given uio_t.
148 */
149 size_t
uio_curriovlen(uio_t * a_uio)150 uio_curriovlen(uio_t *a_uio)
151 {
152 if (a_uio->uio_iovcnt < 1) {
153 return (0);
154 }
155 return ((size_t)a_uio->uio_iov->iov_len);
156 }
157
158
159 /*
160 * uio_update - update the given uio_t for a_count of completed IO.
161 * This call decrements the current iovec length and residual IO value
162 * and increments the current iovec base address and offset value.
163 * If the current iovec length is 0 then advance to the next
164 * iovec (if any).
165 * If the a_count passed in is 0, than only do the advancement
166 * over any 0 length iovec's.
167 */
168 void
uio_update(uio_t * a_uio,size_t a_count)169 uio_update(uio_t *a_uio, size_t a_count)
170 {
171 if (a_uio->uio_iovcnt < 1) {
172 return;
173 }
174
175 /*
176 * if a_count == 0, then we are asking to skip over
177 * any empty iovs
178 */
179 if (a_count) {
180 if (a_count > a_uio->uio_iov->iov_len) {
181 a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len;
182 a_uio->uio_iov->iov_len = 0;
183 } else {
184 a_uio->uio_iov->iov_base += a_count;
185 a_uio->uio_iov->iov_len -= a_count;
186 }
187 if (a_uio->uio_resid < 0) {
188 a_uio->uio_resid = 0;
189 }
190 if (a_count > (size_t)a_uio->uio_resid) {
191 a_uio->uio_loffset += a_uio->uio_resid;
192 a_uio->uio_resid = 0;
193 } else {
194 a_uio->uio_loffset += a_count;
195 a_uio->uio_resid -= a_count;
196 }
197 }
198 /*
199 * advance to next iovec if current one is totally consumed
200 */
201 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) {
202 a_uio->uio_iovcnt--;
203 if (a_uio->uio_iovcnt > 0) {
204 a_uio->uio_iov++;
205 }
206 }
207 }
208
209 /*
210 * This is now used only to extend an existing mblk chain,
211 * so don't need to use allocb_cred_wait here.
212 */
213 /*ARGSUSED*/
214 mblk_t *
m_getblk(int size,int type)215 m_getblk(int size, int type)
216 {
217 mblk_t *mblk;
218 int error;
219
220 /* Make size at least MLEN. */
221 if (size < MLEN)
222 size = MLEN;
223 mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error);
224 ASSERT(mblk);
225 return (mblk);
226 }
227
228 void
mb_done(struct mbchain * mbp)229 mb_done(struct mbchain *mbp)
230 {
231 if (mbp->mb_top) {
232 freemsg(mbp->mb_top);
233 mbp->mb_top = NULL;
234 }
235 /* Avoid dangling references */
236 mbp->mb_cur = NULL;
237 }
238
239 unsigned int
m_length(mblk_t * mblk)240 m_length(mblk_t *mblk)
241 {
242 uint64_t diff;
243
244 diff = (uintptr_t)mblk->b_datap->db_lim -
245 (uintptr_t)mblk->b_datap->db_base;
246 ASSERT(diff == (uint64_t)((unsigned int)diff));
247 return ((unsigned int)diff);
248 }
249
250 void
mb_initm(struct mbchain * mbp,mblk_t * m)251 mb_initm(struct mbchain *mbp, mblk_t *m)
252 {
253 bzero(mbp, sizeof (*mbp));
254 mbp->mb_top = mbp->mb_cur = m;
255 }
256
257
258 int
mb_init(struct mbchain * mbp)259 mb_init(struct mbchain *mbp)
260 {
261 cred_t *cr;
262 mblk_t *mblk;
263 int error;
264
265 /*
266 * This message will be the head of a new mblk chain,
267 * so we'd like its db_credp set. If we extend this
268 * chain later, we'll just use allocb_wait()
269 */
270 cr = ddi_get_cred();
271 mblk = allocb_cred_wait(MLEN, STR_NOSIG, &error, cr, NOPID);
272
273 /*
274 * Leave room in this first mblk so we can
275 * prepend a 4-byte NetBIOS header.
276 * See smb_nbst_send()
277 */
278 mblk->b_wptr += 4;
279 mblk->b_rptr = mblk->b_wptr;
280
281 mb_initm(mbp, mblk);
282 return (0);
283 }
284
285
286 /*
287 * mb_detach() function returns the value of mbp->mb_top field
288 * and sets its * value to NULL.
289 */
290
291 mblk_t *
mb_detach(struct mbchain * mbp)292 mb_detach(struct mbchain *mbp)
293 {
294 mblk_t *m;
295
296 m = mbp->mb_top;
297 mbp->mb_top = mbp->mb_cur = NULL;
298 return (m);
299 }
300
301 /*
302 * Returns the length of the mblk_t data.
303 * Should be m_totlen() perhaps?
304 */
305 int
m_fixhdr(mblk_t * m0)306 m_fixhdr(mblk_t *m0)
307 {
308 size_t dsz;
309
310 dsz = msgdsize(m0);
311 return ((int)dsz);
312 }
313
314 /*
315 * BSD code set the message header length here, and
316 * returned the length. We don't have that field, so
317 * just return the message length.
318 */
319 int
mb_fixhdr(struct mbchain * mbp)320 mb_fixhdr(struct mbchain *mbp)
321 {
322 return (m_fixhdr(mbp->mb_top));
323 }
324
325
326 /*
327 * Check if object of size 'size' fit to the current position and
328 * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s).
329 * Return pointer to the object placeholder or NULL if any error occured.
330 * Note: size should be <= MLEN
331 */
332 void *
mb_reserve(struct mbchain * mbp,int size)333 mb_reserve(struct mbchain *mbp, int size)
334 {
335 mblk_t *m, *mn;
336 void *bpos;
337
338 m = mbp->mb_cur;
339 /*
340 * If the requested size is more than the space left.
341 * Allocate and appenad a new mblk.
342 */
343 if (MBLKTAIL(m) < size) {
344 mn = m_getblk(size, 1);
345 if (mn == NULL)
346 return (NULL);
347 mbp->mb_cur = m->b_cont = mn;
348 m = mn;
349 }
350 /*
351 * If 'size' bytes fits into the buffer, then
352 * 1. increment the write pointer to the size.
353 * 2. return the position from where the memory is reserved.
354 */
355 bpos = m->b_wptr;
356 m->b_wptr += size;
357 mbp->mb_count += size;
358 return (bpos);
359 }
360
361 /*
362 * All mb_put_*() functions perform an actual copy of the data into mbuf
363 * chain. Functions which have le or be suffixes will perform conversion to
364 * the little- or big-endian data formats.
365 *
366 * Inline version of mb_put_mem(). Handles the easy case in-line,
367 * and calls mb_put_mem() if crossing mblk boundaries, etc.
368 *
369 * We build with -xspace, which causes these inline functions
370 * to not be inlined. Using macros instead for now.
371 */
372 #ifdef INLINE_WORKS
373
374 static inline int
mb_put_inline(struct mbchain * mbp,void * src,int size)375 mb_put_inline(struct mbchain *mbp, void *src, int size)
376 {
377 mblk_t *m = mbp->mb_cur;
378
379 if (m != NULL && size <= MBLKTAIL(m)) {
380 uchar_t *p = src;
381 int n = size;
382 while (n--)
383 *(m->b_wptr)++ = *p++;
384 mbp->mb_count += size;
385 return (0);
386 }
387 return (mb_put_mem(mbp, src, size, MB_MINLINE));
388 }
389 #define MB_PUT_INLINE(MBP, SRC, SZ) \
390 return (mb_put_inline(MBP, SRC, SZ))
391
392 #else /* INLINE_WORKS */
393
394 #define MB_PUT_INLINE(MBP, SRC, SZ) \
395 mblk_t *m = MBP->mb_cur; \
396 if (m != NULL && SZ <= MBLKTAIL(m)) { \
397 uchar_t *p = (void *) SRC; \
398 int n = SZ; \
399 while (n--) \
400 *(m->b_wptr)++ = *p++; \
401 MBP->mb_count += SZ; \
402 return (0); \
403 } \
404 return (mb_put_mem(MBP, SRC, SZ, MB_MINLINE))
405
406 #endif /* INLINE_WORKS */
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
mb_put_padbyte(struct mbchain * mbp)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
mb_put_align8(struct mbchain * mbp)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
mb_put_uint8(struct mbchain * mbp,u_int8_t x)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
mb_put_uint16be(struct mbchain * mbp,u_int16_t x)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
mb_put_uint16le(struct mbchain * mbp,u_int16_t x)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
464 int
mb_put_uint32be(struct mbchain * mbp,u_int32_t x)465 mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
466 {
467 u_int32_t v = htobel(x);
468 MB_PUT_INLINE(mbp, &v, sizeof (v));
469 }
470
471 int
mb_put_uint32le(struct mbchain * mbp,u_int32_t x)472 mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
473 {
474 u_int32_t v = htolel(x);
475 MB_PUT_INLINE(mbp, &v, sizeof (v));
476 }
477
478 int
mb_put_uint64be(struct mbchain * mbp,u_int64_t x)479 mb_put_uint64be(struct mbchain *mbp, u_int64_t x)
480 {
481 u_int64_t v = htobeq(x);
482 MB_PUT_INLINE(mbp, &v, sizeof (v));
483 }
484
485 int
mb_put_uint64le(struct mbchain * mbp,u_int64_t x)486 mb_put_uint64le(struct mbchain *mbp, u_int64_t x)
487 {
488 u_int64_t v = htoleq(x);
489 MB_PUT_INLINE(mbp, &v, sizeof (v));
490 }
491
492 /*
493 * mb_put_mem() function copies size bytes of data specified by the source
494 * argument to an mbuf chain. The type argument specifies the method used
495 * to perform a copy
496 */
497 int
mb_put_mem(struct mbchain * mbp,const void * vsrc,int size,int type)498 mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
499 {
500 mblk_t *n, *m = mbp->mb_cur;
501 c_caddr_t source = vsrc;
502 c_caddr_t src;
503 caddr_t dst;
504 uint64_t diff;
505 int cplen, mleft, count;
506
507 diff = MBLKTAIL(m);
508 ASSERT(diff == (uint64_t)((int)diff));
509 mleft = (int)diff;
510
511 while (size > 0) {
512 if (mleft == 0) {
513 if (m->b_cont == NULL) {
514 /*
515 * Changed m_getm() to m_getblk()
516 * with the requested size, so we
517 * don't need m_getm() anymore.
518 */
519 n = m_getblk(size, 1);
520 if (n == NULL)
521 return (ENOBUFS);
522 m->b_cont = n;
523 }
524 m = m->b_cont;
525 diff = MBLKTAIL(m);
526 ASSERT(diff == (uint64_t)((int)diff));
527 mleft = (int)diff;
528 continue;
529 }
530 cplen = mleft > size ? size : mleft;
531 dst = (caddr_t)m->b_wptr;
532 switch (type) {
533 case MB_MINLINE:
534 for (src = source, count = cplen; count; count--)
535 *dst++ = *src++;
536 break;
537 case MB_MSYSTEM:
538 bcopy(source, dst, cplen);
539 break;
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
mb_put_mbuf(struct mbchain * mbp,mblk_t * m)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
mb_put_mbchain(struct mbchain * mbp,struct mbchain * sub_mbp)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
mb_put_uio(struct mbchain * mbp,uio_t * uiop,size_t size)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);
643 uio_update(uiop, left);
644 size -= left;
645 }
646 return (0);
647 }
648
649 /*
650 * Routines for fetching data from an mbuf chain
651 */
652
653 void
md_initm(struct mdchain * mdp,mblk_t * m)654 md_initm(struct mdchain *mdp, mblk_t *m)
655 {
656 bzero(mdp, sizeof (*mdp));
657 mdp->md_top = mdp->md_cur = m;
658 mdp->md_pos = m->b_rptr;
659 }
660
661 void
md_done(struct mdchain * mdp)662 md_done(struct mdchain *mdp)
663 {
664 mblk_t *m;
665
666 /*
667 * Deal with the fact that we can error out of
668 * smb_t2_reply or smb_nt_reply without using up
669 * all the "records" added by md_append_record().
670 */
671 while ((m = mdp->md_top) != NULL) {
672 mdp->md_top = m->b_next;
673 m->b_next = NULL;
674 freemsg(m);
675 }
676 /* Avoid dangling references */
677 mdp->md_cur = NULL;
678 mdp->md_pos = NULL;
679 }
680
681 /*
682 * Append a new message (separate mbuf chain).
683 * It is caller responsibility to prevent
684 * multiple calls to fetch/record routines.
685 * Note unusual use of mblk->b_next here.
686 */
687 void
md_append_record(struct mdchain * mdp,mblk_t * top)688 md_append_record(struct mdchain *mdp, mblk_t *top)
689 {
690 mblk_t *m;
691
692 top->b_next = NULL;
693 if (mdp->md_top == NULL) {
694 md_initm(mdp, top);
695 return;
696 }
697 m = mdp->md_top;
698 /* Get to last message (not b_cont chain) */
699 while (m->b_next)
700 m = m->b_next;
701 m->b_next = top;
702 }
703
704 /*
705 * Advance mdp->md_top to the next message.
706 * Note unusual use of mblk->b_next here.
707 */
708 void
md_next_record(struct mdchain * mdp)709 md_next_record(struct mdchain *mdp)
710 {
711 mblk_t *m, *top;
712
713 if ((top = mdp->md_top) == NULL)
714 return;
715
716 /*
717 * Get the next message, if any,
718 * stored by md_append_record.
719 * Note: NOT b_cont chain
720 */
721 m = top->b_next;
722 top->b_next = NULL;
723
724 /* Done with old "top". */
725 md_done(mdp);
726 if (m == NULL)
727 return;
728
729 /* Setup new "top". */
730 md_initm(mdp, m);
731 }
732
733 /*
734 * Inline version of md_get_mem(). Handles the easy case in-line,
735 * and calls md_get_mem() if crossing mblk boundaries, etc.
736 */
737 #ifdef INLINE_WORKS /* see above */
738
739 static inline int
md_get_inline(struct mdchain * mdp,void * dst,int size)740 md_get_inline(struct mdchain *mdp, void *dst, int size)
741 {
742 mblk_t *m = mdp->md_cur;
743
744 if (m != NULL && mdp->md_pos + size <= m->b_wptr) {
745 uchar_t *p = dst;
746 int n = size;
747 while (n--)
748 *p++ = *(mdp->md_pos)++;
749 /* no md_count += size */
750 return (0);
751 }
752 return (md_get_mem(mdp, dst, size, MB_MINLINE));
753 }
754 #define MD_GET_INLINE(MDP, DST, SZ) \
755 error = md_get_inline(MDP, DST, SZ)
756
757 #else /* INLINE_WORKS */
758
759 /* Note, sets variable: error */
760 #define MD_GET_INLINE(MDP, DST, SZ) \
761 mblk_t *m = MDP->md_cur; \
762 if (m != NULL && MDP->md_pos + SZ <= m->b_wptr) { \
763 uchar_t *p = (void *) DST; \
764 int n = SZ; \
765 while (n--) \
766 *p++ = *(mdp->md_pos)++; \
767 /* no md_count += SZ */ \
768 error = 0; \
769 } else \
770 error = md_get_mem(MDP, DST, SZ, MB_MINLINE)
771
772 #endif /* INLINE_WORKS */
773
774
775 int
md_get_uint8(struct mdchain * mdp,u_int8_t * x)776 md_get_uint8(struct mdchain *mdp, u_int8_t *x)
777 {
778 uint8_t v;
779 int error;
780
781 MD_GET_INLINE(mdp, &v, sizeof (v));
782 if (x)
783 *x = v;
784 return (error);
785 }
786
787 int
md_get_uint16be(struct mdchain * mdp,u_int16_t * x)788 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
789 u_int16_t v;
790 int error;
791
792 MD_GET_INLINE(mdp, &v, sizeof (v));
793 if (x)
794 *x = betohs(v);
795 return (error);
796 }
797
798 int
md_get_uint16le(struct mdchain * mdp,u_int16_t * x)799 md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
800 {
801 u_int16_t v;
802 int error;
803
804 MD_GET_INLINE(mdp, &v, sizeof (v));
805 if (x)
806 *x = letohs(v);
807 return (error);
808 }
809
810 int
md_get_uint32be(struct mdchain * mdp,u_int32_t * x)811 md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
812 {
813 u_int32_t v;
814 int error;
815
816 MD_GET_INLINE(mdp, &v, sizeof (v));
817 if (x)
818 *x = betohl(v);
819 return (error);
820 }
821
822 int
md_get_uint32le(struct mdchain * mdp,u_int32_t * x)823 md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
824 {
825 u_int32_t v;
826 int error;
827
828 MD_GET_INLINE(mdp, &v, sizeof (v));
829 if (x)
830 *x = letohl(v);
831 return (error);
832 }
833
834 int
md_get_uint64be(struct mdchain * mdp,u_int64_t * x)835 md_get_uint64be(struct mdchain *mdp, u_int64_t *x)
836 {
837 u_int64_t v;
838 int error;
839
840 MD_GET_INLINE(mdp, &v, sizeof (v));
841 if (x)
842 *x = betohq(v);
843 return (error);
844 }
845
846 int
md_get_uint64le(struct mdchain * mdp,u_int64_t * x)847 md_get_uint64le(struct mdchain *mdp, u_int64_t *x)
848 {
849 u_int64_t v;
850 int error;
851
852 MD_GET_INLINE(mdp, &v, sizeof (v));
853 if (x)
854 *x = letohq(v);
855 return (error);
856 }
857
858 int
md_get_mem(struct mdchain * mdp,void * vdst,int size,int type)859 md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
860 {
861 mblk_t *m = mdp->md_cur;
862 caddr_t target = vdst;
863 unsigned char *s;
864 uint64_t diff;
865 int count;
866
867 while (size > 0) {
868 if (m == NULL) {
869 SMBSDEBUG("incomplete copy\n");
870 return (EBADRPC);
871 }
872
873 /*
874 * Offset in the current MBUF.
875 */
876 s = mdp->md_pos;
877 ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
878
879 /* Data remaining. */
880 diff = (uintptr_t)m->b_wptr - (uintptr_t)s;
881 ASSERT(diff == (uint64_t)((int)diff));
882 count = (int)diff;
883
884 /*
885 * Check if the no. of bytes remaining is less than
886 * the bytes requested.
887 */
888 if (count == 0) {
889 m = m->b_cont;
890 if (m) {
891 mdp->md_cur = m;
892 mdp->md_pos = s = m->b_rptr;
893 }
894 continue;
895 }
896 if (count > size)
897 count = size;
898 size -= count;
899 mdp->md_pos += count;
900 if (target == NULL)
901 continue;
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
md_get_mbuf(struct mdchain * mdp,int size,mblk_t ** ret)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
md_get_uio(struct mdchain * mdp,uio_t * uiop,size_t size)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,
967 uio_curriovbase(uiop)), left, mtype);
968 if (error)
969 return (error);
970 uio_update(uiop, left);
971 size -= left;
972 }
973 return (0);
974 }
975
976 /*
977 * Additions for Solaris
978 */
979
980 /*
981 * concatenate mblk chain n to m.
982 * go till end of data in m.
983 * then add the link of b_cont to n.
984 * See: linkb(9f)
985 */
986
m_cat(mblk_t * m,mblk_t * n)987 void m_cat(
988 mblk_t *m,
989 mblk_t *n)
990 {
991 if (!n)
992 return;
993 while (m->b_cont) {
994 m = m->b_cont;
995 }
996 m->b_cont = n;
997 }
998
999 /*ARGSUSED*/
1000 mblk_t *
m_copym(mblk_t * m,int off,int len,int wait)1001 m_copym(mblk_t *m, int off, int len, int wait)
1002 {
1003 mblk_t *n;
1004 size_t dsz;
1005 ssize_t adj;
1006
1007 dsz = msgdsize(m);
1008 if (len == M_COPYALL) {
1009 if (off > dsz)
1010 return (0);
1011 } else {
1012 if ((off + len) > dsz)
1013 return (0);
1014 }
1015
1016 if ((n = dupmsg(m)) == NULL)
1017 return (0);
1018
1019 /* trim from head */
1020 adj = off;
1021 if (!adjmsg(n, adj)) {
1022 freemsg(n);
1023 return (0);
1024 }
1025
1026 /* trim from tail */
1027 if (len != M_COPYALL) {
1028 dsz = msgdsize(n);
1029 ASSERT(len <= dsz);
1030 if (len < dsz) {
1031 adj = (ssize_t)len - (ssize_t)dsz;
1032 ASSERT(adj < 0);
1033 (void) adjmsg(n, adj);
1034 }
1035 }
1036
1037 return (n);
1038 }
1039
1040 /*
1041 * Get "rqlen" contiguous bytes into the first mblk of a chain.
1042 */
1043 mblk_t *
m_pullup(mblk_t * m,int rqlen)1044 m_pullup(
1045 mblk_t *m,
1046 int rqlen)
1047 {
1048 ptrdiff_t diff;
1049
1050 diff = MBLKL(m);
1051 ASSERT(diff == (ptrdiff_t)((int)diff));
1052 if ((int)diff < rqlen) {
1053 /* This should be rare. */
1054 if (!pullupmsg(m, rqlen)) {
1055 SMBSDEBUG("pullupmsg failed!\n");
1056 freemsg(m);
1057 return (NULL);
1058 }
1059 }
1060 return (m);
1061 }
1062
1063
1064 /*
1065 * m_split : split the mblk from the offset(len0) to the end.
1066 * Partition an mbuf chain in two pieces, returning the tail --
1067 * all but the first len0 bytes. In case of failure, it returns NULL and
1068 * attempts to restore the chain to its original state.
1069 * Similar to dupmsg() + adjmsg() on Solaris.
1070 */
1071 /*ARGSUSED*/
1072 mblk_t *
m_split(mblk_t * m0,int len0,int wait)1073 m_split(
1074 mblk_t *m0,
1075 int len0,
1076 int wait)
1077 {
1078 mblk_t *m, *n;
1079 int mbl, len = len0;
1080 ptrdiff_t diff;
1081
1082 #if 0 /* If life were simple, this would be: */
1083 for (m = m0; m && len > MBLKL(m); m = m->b_cont)
1084 len -= MBLKL(m);
1085 #else /* but with LP64 and picky lint we have: */
1086 for (m = m0; m; m = m->b_cont) {
1087 diff = MBLKL(m);
1088 ASSERT(diff == (ptrdiff_t)((int)diff));
1089 mbl = (int)diff;
1090 if (len <= mbl)
1091 break;
1092 len -= mbl;
1093 }
1094 #endif
1095
1096 if (m == 0)
1097 return (0);
1098
1099 /* This is the one to split (dupb, adjust) */
1100 if ((n = dupb(m)) == 0)
1101 return (0);
1102
1103 ASSERT(len <= MBLKL(m));
1104
1105 m->b_wptr = m->b_rptr + len;
1106 n->b_rptr += len;
1107
1108 /* Move any b_cont (tail) to the new head. */
1109 n->b_cont = m->b_cont;
1110 m->b_cont = NULL;
1111
1112 return (n);
1113 }
1114