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
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/errno.h>
43 #include <sys/uio.h>
44 #include <sys/types.h>
45 #include <sys/stream.h>
46 #include <sys/strsun.h>
47 #include <sys/strsubr.h>
48 #include <sys/sunddi.h>
49 #include <sys/cmn_err.h>
50
51 #include <netsmb/smb_osdep.h>
52 #include <netsmb/mchain.h>
53
54 #include <netsmb/smb.h>
55 #include <netsmb/smb_conn.h>
56 #include <netsmb/smb_subr.h>
57
58 /* BEGIN CSTYLED */
59 /*
60 * BSD-style mbufs, vs SysV-style mblks:
61 * One big difference: the mbuf payload is:
62 * m_data ... (m_data + m_len)
63 * In Unix STREAMS, the mblk payload is:
64 * b_rptr ... b_wptr
65 *
66 * Here are some handy conversion notes:
67 *
68 * struct mbuf struct mblk
69 * m->m_next m->b_cont
70 * m->m_nextpkt m->b_next
71 * m->m_data m->b_rptr
72 * m->m_len MBLKL(m)
73 * m->m_dat[] m->b_datap->db_base
74 * &m->m_dat[MLEN] m->b_datap->db_lim
75 * M_TRAILINGSPACE(m) MBLKTAIL(m)
76 * m_freem(m) freemsg(m)
77 *
78 * Note that mbufs chains also have a special "packet" header,
79 * which has the length of the whole message. In STREAMS one
80 * typically just calls msgdsize(m) to get that.
81 */
82 /* END CSTYLED */
83
84
85 /*
86 *
87 * MODULE_VERSION(libmchain, 1);
88 */
89
90 #ifdef __GNUC__
91 #define MBERROR(format, args...) printf("%s(%d): "format, \
92 __FUNCTION__, __LINE__, ## args)
93 #define MBPANIC(format, args...) printf("%s(%d): "format, \
94 __FUNCTION__, __LINE__, ## args)
95 #else
96 #define MBERROR(...) \
97 smb_errmsg(CE_NOTE, __func__, __VA_ARGS__)
98 #define MBPANIC(...) \
99 smb_errmsg(CE_PANIC, __func__, __VA_ARGS__)
100 #endif
101
102 /*
103 * MLEN: The smallest mblk we'll allocate.
104 *
105 * There's more to MLEN than you might think.
106 * Some ethernet drivers may send each mblk as a
107 * separate frame, so we want MLEN at least 1K.
108 * We could have used 1K here, but that might
109 * hurt transports that support larger frames.
110 * 4K fits nicely in 3 Ethernet frames (3 * 1500)
111 * leaving about 500 bytes for protocol headers.
112 *
113 * XXX: Would Ethernet drivers be happier
114 * (more efficient) if we used 1K here?
115 */
116 #define MLEN 4096
117
118
119 /*
120 * Some UIO routines.
121 * Taken from Darwin Sourcecs.
122 */
123
124 /*
125 * uio_isuserspace - non zero value if the address space
126 * flag is for a user address space (could be 32 or 64 bit).
127 */
128 #define uio_isuserspace(uio) (uio->uio_segflg == UIO_USERSPACE)
129
130 /*
131 * uio_curriovbase - return the base address of the current iovec associated
132 * with the given uio_t. May return 0.
133 */
134 caddr_t
uio_curriovbase(uio_t * a_uio)135 uio_curriovbase(uio_t *a_uio)
136 {
137 if (a_uio->uio_iovcnt < 1) {
138 return (0);
139 }
140 return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base));
141 }
142
143 /*
144 * uio_curriovlen - return the length value of the current iovec associated
145 * with the given uio_t.
146 */
147 size_t
uio_curriovlen(uio_t * a_uio)148 uio_curriovlen(uio_t *a_uio)
149 {
150 if (a_uio->uio_iovcnt < 1) {
151 return (0);
152 }
153 return ((size_t)a_uio->uio_iov->iov_len);
154 }
155
156
157 /*
158 * uio_update - update the given uio_t for a_count of completed IO.
159 * This call decrements the current iovec length and residual IO value
160 * and increments the current iovec base address and offset value.
161 * If the current iovec length is 0 then advance to the next
162 * iovec (if any).
163 * If the a_count passed in is 0, than only do the advancement
164 * over any 0 length iovec's.
165 */
166 void
uio_update(uio_t * a_uio,size_t a_count)167 uio_update(uio_t *a_uio, size_t a_count)
168 {
169 if (a_uio->uio_iovcnt < 1) {
170 return;
171 }
172
173 /*
174 * if a_count == 0, then we are asking to skip over
175 * any empty iovs
176 */
177 if (a_count) {
178 if (a_count > a_uio->uio_iov->iov_len) {
179 a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len;
180 a_uio->uio_iov->iov_len = 0;
181 } else {
182 a_uio->uio_iov->iov_base += a_count;
183 a_uio->uio_iov->iov_len -= a_count;
184 }
185 if (a_uio->uio_resid < 0) {
186 a_uio->uio_resid = 0;
187 }
188 if (a_count > (size_t)a_uio->uio_resid) {
189 a_uio->uio_loffset += a_uio->uio_resid;
190 a_uio->uio_resid = 0;
191 } else {
192 a_uio->uio_loffset += a_count;
193 a_uio->uio_resid -= a_count;
194 }
195 }
196 /*
197 * advance to next iovec if current one is totally consumed
198 */
199 while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) {
200 a_uio->uio_iovcnt--;
201 if (a_uio->uio_iovcnt > 0) {
202 a_uio->uio_iov++;
203 }
204 }
205 }
206
207 /*
208 * This is now used only to extend an existing mblk chain,
209 * so don't need to use allocb_cred_wait here.
210 */
211 /*ARGSUSED*/
212 mblk_t *
m_getblk(int size,int type)213 m_getblk(int size, int type)
214 {
215 mblk_t *mblk;
216 int error;
217
218 /* Make size at least MLEN. */
219 if (size < MLEN)
220 size = MLEN;
221 mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error);
222 ASSERT(mblk);
223 return (mblk);
224 }
225
226 void
mb_done(struct mbchain * mbp)227 mb_done(struct mbchain *mbp)
228 {
229 if (mbp->mb_top) {
230 freemsg(mbp->mb_top);
231 mbp->mb_top = NULL;
232 }
233 /* Avoid dangling references */
234 mbp->mb_cur = NULL;
235 }
236
237 unsigned int
m_length(mblk_t * mblk)238 m_length(mblk_t *mblk)
239 {
240 uint64_t diff;
241
242 diff = (uintptr_t)mblk->b_datap->db_lim -
243 (uintptr_t)mblk->b_datap->db_base;
244 ASSERT(diff == (uint64_t)((unsigned int)diff));
245 return ((unsigned int)diff);
246 }
247
248 void
mb_initm(struct mbchain * mbp,mblk_t * m)249 mb_initm(struct mbchain *mbp, mblk_t *m)
250 {
251 bzero(mbp, sizeof (*mbp));
252 mbp->mb_top = mbp->mb_cur = m;
253 }
254
255
256 int
mb_init(struct mbchain * mbp)257 mb_init(struct mbchain *mbp)
258 {
259 cred_t *cr;
260 mblk_t *mblk;
261 int error;
262
263 /*
264 * This message will be the head of a new mblk chain,
265 * so we'd like its db_credp set. If we extend this
266 * chain later, we'll just use allocb_wait()
267 */
268 cr = ddi_get_cred();
269 mblk = allocb_cred_wait(MLEN, STR_NOSIG, &error, cr, NOPID);
270
271 /*
272 * Leave room in this first mblk so we can
273 * prepend a 4-byte NetBIOS header.
274 * See smb_nbst_send()
275 */
276 mblk->b_wptr += 4;
277 mblk->b_rptr = mblk->b_wptr;
278
279 mb_initm(mbp, mblk);
280 return (0);
281 }
282
283
284 /*
285 * mb_detach() function returns the value of mbp->mb_top field
286 * and sets its * value to NULL.
287 */
288
289 mblk_t *
mb_detach(struct mbchain * mbp)290 mb_detach(struct mbchain *mbp)
291 {
292 mblk_t *m;
293
294 m = mbp->mb_top;
295 mbp->mb_top = mbp->mb_cur = NULL;
296 return (m);
297 }
298
299 /*
300 * Returns the length of the mblk_t data.
301 * Should be m_totlen() perhaps?
302 */
303 int
m_fixhdr(mblk_t * m0)304 m_fixhdr(mblk_t *m0)
305 {
306 size_t dsz;
307
308 dsz = msgdsize(m0);
309 return ((int)dsz);
310 }
311
312 /*
313 * BSD code set the message header length here, and
314 * returned the length. We don't have that field, so
315 * just return the message length.
316 */
317 int
mb_fixhdr(struct mbchain * mbp)318 mb_fixhdr(struct mbchain *mbp)
319 {
320 return (m_fixhdr(mbp->mb_top));
321 }
322
323
324 /*
325 * Check if object of size 'size' fit to the current position and
326 * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s).
327 * Return pointer to the object placeholder or NULL if any error occured.
328 * Note: size should be <= MLEN
329 */
330 void *
mb_reserve(struct mbchain * mbp,int size)331 mb_reserve(struct mbchain *mbp, int size)
332 {
333 mblk_t *m, *mn;
334 void *bpos;
335
336 m = mbp->mb_cur;
337 /*
338 * If the requested size is more than the space left.
339 * Allocate and appenad a new mblk.
340 */
341 if (MBLKTAIL(m) < size) {
342 mn = m_getblk(size, 1);
343 if (mn == NULL)
344 return (NULL);
345 mbp->mb_cur = m->b_cont = mn;
346 m = mn;
347 }
348 /*
349 * If 'size' bytes fits into the buffer, then
350 * 1. increment the write pointer to the size.
351 * 2. return the position from where the memory is reserved.
352 */
353 bpos = m->b_wptr;
354 m->b_wptr += size;
355 mbp->mb_count += size;
356 return (bpos);
357 }
358
359 /*
360 * All mb_put_*() functions perform an actual copy of the data into mbuf
361 * chain. Functions which have le or be suffixes will perform conversion to
362 * the little- or big-endian data formats.
363 *
364 * Inline version of mb_put_mem(). Handles the easy case in-line,
365 * and calls mb_put_mem() if crossing mblk boundaries, etc.
366 *
367 * We build with -xspace, which causes these inline functions
368 * to not be inlined. Using macros instead for now.
369 */
370 #ifdef INLINE_WORKS
371
372 static inline int
mb_put_inline(struct mbchain * mbp,void * src,int size)373 mb_put_inline(struct mbchain *mbp, void *src, int size)
374 {
375 mblk_t *m = mbp->mb_cur;
376
377 if (m != NULL && size <= MBLKTAIL(m)) {
378 uchar_t *p = src;
379 int n = size;
380 while (n--)
381 *(m->b_wptr)++ = *p++;
382 mbp->mb_count += size;
383 return (0);
384 }
385 return (mb_put_mem(mbp, src, size, MB_MINLINE));
386 }
387 #define MB_PUT_INLINE(MBP, SRC, SZ) \
388 return (mb_put_inline(MBP, SRC, SZ))
389
390 #else /* INLINE_WORKS */
391
392 #define MB_PUT_INLINE(MBP, SRC, SZ) \
393 mblk_t *m = MBP->mb_cur; \
394 if (m != NULL && SZ <= MBLKTAIL(m)) { \
395 uchar_t *p = (void *) SRC; \
396 int n = SZ; \
397 while (n--) \
398 *(m->b_wptr)++ = *p++; \
399 MBP->mb_count += SZ; \
400 return (0); \
401 } \
402 return (mb_put_mem(MBP, SRC, SZ, MB_MINLINE))
403
404 #endif /* INLINE_WORKS */
405
406 /*
407 * Assumes total data length in previous mblks is EVEN.
408 * Might need to compute the offset from mb_top instead.
409 */
410 int
mb_put_padbyte(struct mbchain * mbp)411 mb_put_padbyte(struct mbchain *mbp)
412 {
413 uintptr_t dst;
414 char v = 0;
415
416 dst = (uintptr_t)mbp->mb_cur->b_wptr;
417 /* only add padding if address is odd */
418 if (dst & 1) {
419 MB_PUT_INLINE(mbp, &v, sizeof (v));
420 }
421
422 return (0);
423 }
424
425 int
mb_put_uint8(struct mbchain * mbp,u_int8_t x)426 mb_put_uint8(struct mbchain *mbp, u_int8_t x)
427 {
428 u_int8_t v = x;
429 MB_PUT_INLINE(mbp, &v, sizeof (v));
430 }
431
432 int
mb_put_uint16be(struct mbchain * mbp,u_int16_t x)433 mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
434 {
435 u_int16_t v = htobes(x);
436 MB_PUT_INLINE(mbp, &v, sizeof (v));
437 }
438
439 int
mb_put_uint16le(struct mbchain * mbp,u_int16_t x)440 mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
441 {
442 u_int16_t v = htoles(x);
443 MB_PUT_INLINE(mbp, &v, sizeof (v));
444 }
445
446 int
mb_put_uint32be(struct mbchain * mbp,u_int32_t x)447 mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
448 {
449 u_int32_t v = htobel(x);
450 MB_PUT_INLINE(mbp, &v, sizeof (v));
451 }
452
453 int
mb_put_uint32le(struct mbchain * mbp,u_int32_t x)454 mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
455 {
456 u_int32_t v = htolel(x);
457 MB_PUT_INLINE(mbp, &v, sizeof (v));
458 }
459
460 int
mb_put_uint64be(struct mbchain * mbp,u_int64_t x)461 mb_put_uint64be(struct mbchain *mbp, u_int64_t x)
462 {
463 u_int64_t v = htobeq(x);
464 MB_PUT_INLINE(mbp, &v, sizeof (v));
465 }
466
467 int
mb_put_uint64le(struct mbchain * mbp,u_int64_t x)468 mb_put_uint64le(struct mbchain *mbp, u_int64_t x)
469 {
470 u_int64_t v = htoleq(x);
471 MB_PUT_INLINE(mbp, &v, sizeof (v));
472 }
473
474 /*
475 * mb_put_mem() function copies size bytes of data specified by the source
476 * argument to an mbuf chain. The type argument specifies the method used
477 * to perform a copy
478 */
479 int
mb_put_mem(struct mbchain * mbp,const void * vsrc,int size,int type)480 mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
481 {
482 mblk_t *n, *m = mbp->mb_cur;
483 c_caddr_t source = vsrc;
484 c_caddr_t src;
485 caddr_t dst;
486 uint64_t diff;
487 int cplen, mleft, count;
488
489 diff = MBLKTAIL(m);
490 ASSERT(diff == (uint64_t)((int)diff));
491 mleft = (int)diff;
492
493 while (size > 0) {
494 if (mleft == 0) {
495 if (m->b_cont == NULL) {
496 /*
497 * Changed m_getm() to m_getblk()
498 * with the requested size, so we
499 * don't need m_getm() anymore.
500 */
501 n = m_getblk(size, 1);
502 if (n == NULL)
503 return (ENOBUFS);
504 m->b_cont = n;
505 }
506 m = m->b_cont;
507 diff = MBLKTAIL(m);
508 ASSERT(diff == (uint64_t)((int)diff));
509 mleft = (int)diff;
510 continue;
511 }
512 cplen = mleft > size ? size : mleft;
513 dst = (caddr_t)m->b_wptr;
514 switch (type) {
515 case MB_MINLINE:
516 for (src = source, count = cplen; count; count--)
517 *dst++ = *src++;
518 break;
519 case MB_MSYSTEM:
520 bcopy(source, dst, cplen);
521 break;
522 case MB_MUSER:
523 if (copyin((void *)source, dst, cplen))
524 return (EFAULT);
525 break;
526 case MB_MZERO:
527 bzero(dst, cplen);
528 break;
529 }
530 size -= cplen;
531 source += cplen;
532 mleft -= cplen;
533 m->b_wptr += cplen;
534 mbp->mb_count += cplen;
535 }
536 mbp->mb_cur = m;
537 return (0);
538 }
539
540 /*
541 * Append an mblk to the chain.
542 */
543 int
mb_put_mbuf(struct mbchain * mbp,mblk_t * m)544 mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
545 {
546 mblk_t *mb;
547
548 /* See: linkb(9f) */
549 for (mb = mbp->mb_cur; mb->b_cont; mb = mb->b_cont)
550 ;
551 mb->b_cont = m;
552 mbp->mb_cur = m;
553 mbp->mb_count += msgdsize(m);
554
555 return (0);
556 }
557
558 /*
559 * copies a uio scatter/gather list to an mbuf chain.
560 */
561 int
mb_put_uio(struct mbchain * mbp,uio_t * uiop,size_t size)562 mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size)
563 {
564 size_t left;
565 int mtype, error;
566
567 mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
568 while (size > 0 && uiop->uio_resid) {
569 if (uiop->uio_iovcnt <= 0 ||
570 uio_curriovbase(uiop) == USER_ADDR_NULL)
571 return (EFBIG);
572 left = uio_curriovlen(uiop);
573 if (left > size)
574 left = size;
575 error = mb_put_mem(mbp, CAST_DOWN(caddr_t,
576 uio_curriovbase(uiop)), left, mtype);
577 if (error)
578 return (error);
579 uio_update(uiop, left);
580 size -= left;
581 }
582 return (0);
583 }
584
585 /*
586 * Routines for fetching data from an mbuf chain
587 */
588
589 void
md_initm(struct mdchain * mdp,mblk_t * m)590 md_initm(struct mdchain *mdp, mblk_t *m)
591 {
592 bzero(mdp, sizeof (*mdp));
593 mdp->md_top = mdp->md_cur = m;
594 mdp->md_pos = m->b_rptr;
595 }
596
597 void
md_done(struct mdchain * mdp)598 md_done(struct mdchain *mdp)
599 {
600 mblk_t *m;
601
602 /*
603 * Deal with the fact that we can error out of
604 * smb_t2_reply or smb_nt_reply without using up
605 * all the "records" added by md_append_record().
606 */
607 while ((m = mdp->md_top) != NULL) {
608 mdp->md_top = m->b_next;
609 m->b_next = NULL;
610 freemsg(m);
611 }
612 /* Avoid dangling references */
613 mdp->md_cur = NULL;
614 mdp->md_pos = NULL;
615 }
616
617 /*
618 * Append a new message (separate mbuf chain).
619 * It is caller responsibility to prevent
620 * multiple calls to fetch/record routines.
621 * Note unusual use of mblk->b_next here.
622 */
623 void
md_append_record(struct mdchain * mdp,mblk_t * top)624 md_append_record(struct mdchain *mdp, mblk_t *top)
625 {
626 mblk_t *m;
627
628 top->b_next = NULL;
629 if (mdp->md_top == NULL) {
630 md_initm(mdp, top);
631 return;
632 }
633 m = mdp->md_top;
634 /* Get to last message (not b_cont chain) */
635 while (m->b_next)
636 m = m->b_next;
637 m->b_next = top;
638 }
639
640 /*
641 * Advance mdp->md_top to the next message.
642 * Note unusual use of mblk->b_next here.
643 */
644 void
md_next_record(struct mdchain * mdp)645 md_next_record(struct mdchain *mdp)
646 {
647 mblk_t *m, *top;
648
649 if ((top = mdp->md_top) == NULL)
650 return;
651
652 /*
653 * Get the next message, if any,
654 * stored by md_append_record.
655 * Note: NOT b_cont chain
656 */
657 m = top->b_next;
658 top->b_next = NULL;
659
660 /* Done with old "top". */
661 md_done(mdp);
662 if (m == NULL)
663 return;
664
665 /* Setup new "top". */
666 md_initm(mdp, m);
667 }
668
669 /*
670 * Inline version of md_get_mem(). Handles the easy case in-line,
671 * and calls md_get_mem() if crossing mblk boundaries, etc.
672 */
673 #ifdef INLINE_WORKS /* see above */
674
675 static inline int
md_get_inline(struct mdchain * mdp,void * dst,int size)676 md_get_inline(struct mdchain *mdp, void *dst, int size)
677 {
678 mblk_t *m = mdp->md_cur;
679
680 if (m != NULL && mdp->md_pos + size <= m->b_wptr) {
681 uchar_t *p = dst;
682 int n = size;
683 while (n--)
684 *p++ = *(mdp->md_pos)++;
685 /* no md_count += size */
686 return (0);
687 }
688 return (md_get_mem(mdp, dst, size, MB_MINLINE));
689 }
690 #define MD_GET_INLINE(MDP, DST, SZ) \
691 error = md_get_inline(MDP, DST, SZ)
692
693 #else /* INLINE_WORKS */
694
695 /* Note, sets variable: error */
696 #define MD_GET_INLINE(MDP, DST, SZ) \
697 mblk_t *m = MDP->md_cur; \
698 if (m != NULL && MDP->md_pos + SZ <= m->b_wptr) { \
699 uchar_t *p = (void *) DST; \
700 int n = SZ; \
701 while (n--) \
702 *p++ = *(mdp->md_pos)++; \
703 /* no md_count += SZ */ \
704 error = 0; \
705 } else \
706 error = md_get_mem(MDP, DST, SZ, MB_MINLINE)
707
708 #endif /* INLINE_WORKS */
709
710
711 int
md_get_uint8(struct mdchain * mdp,u_int8_t * x)712 md_get_uint8(struct mdchain *mdp, u_int8_t *x)
713 {
714 uint8_t v;
715 int error;
716
717 MD_GET_INLINE(mdp, &v, sizeof (v));
718 if (x)
719 *x = v;
720 return (error);
721 }
722
723 int
md_get_uint16be(struct mdchain * mdp,u_int16_t * x)724 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
725 u_int16_t v;
726 int error;
727
728 MD_GET_INLINE(mdp, &v, sizeof (v));
729 if (x)
730 *x = betohs(v);
731 return (error);
732 }
733
734 int
md_get_uint16le(struct mdchain * mdp,u_int16_t * x)735 md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
736 {
737 u_int16_t v;
738 int error;
739
740 MD_GET_INLINE(mdp, &v, sizeof (v));
741 if (x)
742 *x = letohs(v);
743 return (error);
744 }
745
746 int
md_get_uint32be(struct mdchain * mdp,u_int32_t * x)747 md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
748 {
749 u_int32_t v;
750 int error;
751
752 MD_GET_INLINE(mdp, &v, sizeof (v));
753 if (x)
754 *x = betohl(v);
755 return (error);
756 }
757
758 int
md_get_uint32le(struct mdchain * mdp,u_int32_t * x)759 md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
760 {
761 u_int32_t v;
762 int error;
763
764 MD_GET_INLINE(mdp, &v, sizeof (v));
765 if (x)
766 *x = letohl(v);
767 return (error);
768 }
769
770 int
md_get_uint64be(struct mdchain * mdp,u_int64_t * x)771 md_get_uint64be(struct mdchain *mdp, u_int64_t *x)
772 {
773 u_int64_t v;
774 int error;
775
776 MD_GET_INLINE(mdp, &v, sizeof (v));
777 if (x)
778 *x = betohq(v);
779 return (error);
780 }
781
782 int
md_get_uint64le(struct mdchain * mdp,u_int64_t * x)783 md_get_uint64le(struct mdchain *mdp, u_int64_t *x)
784 {
785 u_int64_t v;
786 int error;
787
788 MD_GET_INLINE(mdp, &v, sizeof (v));
789 if (x)
790 *x = letohq(v);
791 return (error);
792 }
793
794 int
md_get_mem(struct mdchain * mdp,void * vdst,int size,int type)795 md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
796 {
797 mblk_t *m = mdp->md_cur;
798 caddr_t target = vdst;
799 unsigned char *s;
800 uint64_t diff;
801 int count;
802
803 while (size > 0) {
804 if (m == NULL) {
805 SMBSDEBUG("incomplete copy\n");
806 return (EBADRPC);
807 }
808
809 /*
810 * Offset in the current MBUF.
811 */
812 s = mdp->md_pos;
813 ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
814
815 /* Data remaining. */
816 diff = (uintptr_t)m->b_wptr - (uintptr_t)s;
817 ASSERT(diff == (uint64_t)((int)diff));
818 count = (int)diff;
819
820 /*
821 * Check if the no. of bytes remaining is less than
822 * the bytes requested.
823 */
824 if (count == 0) {
825 m = m->b_cont;
826 if (m) {
827 mdp->md_cur = m;
828 mdp->md_pos = s = m->b_rptr;
829 }
830 continue;
831 }
832 if (count > size)
833 count = size;
834 size -= count;
835 mdp->md_pos += count;
836 if (target == NULL)
837 continue;
838 switch (type) {
839 case MB_MUSER:
840 if (copyout(s, target, count))
841 return (EFAULT);
842 break;
843 case MB_MSYSTEM:
844 bcopy(s, target, count);
845 break;
846 case MB_MINLINE:
847 while (count--)
848 *target++ = *s++;
849 continue;
850 }
851 target += count;
852 }
853 return (0);
854 }
855
856 /*
857 * Get the next SIZE bytes as a separate mblk.
858 */
859 int
md_get_mbuf(struct mdchain * mdp,int size,mblk_t ** ret)860 md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
861 {
862 mblk_t *m, *rm;
863
864 unsigned char *s;
865 uint64_t diff;
866 int off;
867
868 /*
869 * Offset in the current MBUF.
870 */
871 m = mdp->md_cur;
872 s = mdp->md_pos;
873 ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
874 diff = (uintptr_t)s - (uintptr_t)m->b_rptr;
875 ASSERT(diff == (uint64_t)((int)diff));
876 off = (int)diff;
877
878 rm = m_copym(m, off, size, M_WAITOK);
879 if (rm == NULL)
880 return (EBADRPC);
881
882 *ret = rm;
883 return (0);
884 }
885
886 int
md_get_uio(struct mdchain * mdp,uio_t * uiop,size_t size)887 md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size)
888 {
889 size_t left;
890 int mtype, error;
891
892 mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
893 while (size > 0 && uiop->uio_resid) {
894 if (uiop->uio_iovcnt <= 0 ||
895 uio_curriovbase(uiop) == USER_ADDR_NULL)
896 return (EFBIG);
897 left = uio_curriovlen(uiop);
898 if (left > size)
899 left = size;
900 error = md_get_mem(mdp, CAST_DOWN(caddr_t,
901 uio_curriovbase(uiop)), left, mtype);
902 if (error)
903 return (error);
904 uio_update(uiop, left);
905 size -= left;
906 }
907 return (0);
908 }
909
910 /*
911 * Additions for Solaris
912 */
913
914 /*
915 * concatenate mblk chain n to m.
916 * go till end of data in m.
917 * then add the link of b_cont to n.
918 * See: linkb(9f)
919 */
920
m_cat(mblk_t * m,mblk_t * n)921 void m_cat(
922 mblk_t *m,
923 mblk_t *n)
924 {
925 if (!n)
926 return;
927 while (m->b_cont) {
928 m = m->b_cont;
929 }
930 m->b_cont = n;
931 }
932
933 /*ARGSUSED*/
934 mblk_t *
m_copym(mblk_t * m,int off,int len,int wait)935 m_copym(mblk_t *m, int off, int len, int wait)
936 {
937 mblk_t *n;
938 size_t dsz;
939 ssize_t adj;
940
941 dsz = msgdsize(m);
942 if (len == M_COPYALL) {
943 if (off > dsz)
944 return (0);
945 } else {
946 if ((off + len) > dsz)
947 return (0);
948 }
949
950 if ((n = dupmsg(m)) == NULL)
951 return (0);
952
953 /* trim from head */
954 adj = off;
955 if (!adjmsg(n, adj)) {
956 freemsg(n);
957 return (0);
958 }
959
960 /* trim from tail */
961 if (len != M_COPYALL) {
962 dsz = msgdsize(n);
963 ASSERT(len <= dsz);
964 if (len < dsz) {
965 adj = (ssize_t)len - (ssize_t)dsz;
966 ASSERT(adj < 0);
967 (void) adjmsg(n, adj);
968 }
969 }
970
971 return (n);
972 }
973
974 /*
975 * Get "rqlen" contiguous bytes into the first mblk of a chain.
976 */
977 mblk_t *
m_pullup(mblk_t * m,int rqlen)978 m_pullup(
979 mblk_t *m,
980 int rqlen)
981 {
982 ptrdiff_t diff;
983
984 diff = MBLKL(m);
985 ASSERT(diff == (ptrdiff_t)((int)diff));
986 if ((int)diff < rqlen) {
987 /* This should be rare. */
988 if (!pullupmsg(m, rqlen)) {
989 SMBSDEBUG("pullupmsg failed!\n");
990 freemsg(m);
991 return (NULL);
992 }
993 }
994 return (m);
995 }
996
997
998 /*
999 * m_split : split the mblk from the offset(len0) to the end.
1000 * Partition an mbuf chain in two pieces, returning the tail --
1001 * all but the first len0 bytes. In case of failure, it returns NULL and
1002 * attempts to restore the chain to its original state.
1003 * Similar to dupmsg() + adjmsg() on Solaris.
1004 */
1005 /*ARGSUSED*/
1006 mblk_t *
m_split(mblk_t * m0,int len0,int wait)1007 m_split(
1008 mblk_t *m0,
1009 int len0,
1010 int wait)
1011 {
1012 mblk_t *m, *n;
1013 int mbl, len = len0;
1014 ptrdiff_t diff;
1015
1016 #if 0 /* If life were simple, this would be: */
1017 for (m = m0; m && len > MBLKL(m); m = m->b_cont)
1018 len -= MBLKL(m);
1019 #else /* but with LP64 and picky lint we have: */
1020 for (m = m0; m; m = m->b_cont) {
1021 diff = MBLKL(m);
1022 ASSERT(diff == (ptrdiff_t)((int)diff));
1023 mbl = (int)diff;
1024 if (len <= mbl)
1025 break;
1026 len -= mbl;
1027 }
1028 #endif
1029
1030 if (m == 0)
1031 return (0);
1032
1033 /* This is the one to split (dupb, adjust) */
1034 if ((n = dupb(m)) == 0)
1035 return (0);
1036
1037 ASSERT(len <= MBLKL(m));
1038
1039 m->b_wptr = m->b_rptr + len;
1040 n->b_rptr += len;
1041
1042 /* Move any b_cont (tail) to the new head. */
1043 n->b_cont = m->b_cont;
1044 m->b_cont = NULL;
1045
1046 return (n);
1047 }
1048