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