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