2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3 * Authors: Doug Rabson <dfr@rabson.org>
4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
36 #include <rpc/types.h>
39 static void xdrmbuf_destroy(XDR
*);
40 static bool_t
xdrmbuf_getlong(XDR
*, long *);
41 static bool_t
xdrmbuf_putlong(XDR
*, const long *);
42 static bool_t
xdrmbuf_getbytes(XDR
*, char *, u_int
);
43 static bool_t
xdrmbuf_putbytes(XDR
*, const char *, u_int
);
44 /* XXX: w/64-bit pointers, u_int not enough! */
45 static u_int
xdrmbuf_getpos(XDR
*);
46 static bool_t
xdrmbuf_setpos(XDR
*, u_int
);
47 static int32_t *xdrmbuf_inline(XDR
*, u_int
);
49 static const struct xdr_ops xdrmbuf_ops
= {
61 * The procedure xdrmbuf_create initializes a stream descriptor for a
65 xdrmbuf_create(XDR
*xdrs
, struct mbuf
*m
, enum xdr_op op
)
68 KASSERT(m
!= NULL
, ("xdrmbuf_create with NULL mbuf chain"));
70 xdrs
->x_ops
= &xdrmbuf_ops
;
71 xdrs
->x_base
= (char *) m
;
72 if (op
== XDR_ENCODE
) {
75 xdrs
->x_handy
= m
->m_len
;
83 xdrmbuf_append(XDR
*xdrs
, struct mbuf
*madd
)
87 KASSERT(xdrs
->x_ops
== &xdrmbuf_ops
&& xdrs
->x_op
== XDR_ENCODE
,
88 ("xdrmbuf_append: invalid XDR stream"));
90 if (m_length(madd
, NULL
) == 0) {
95 m
= (struct mbuf
*) xdrs
->x_private
;
100 xdrs
->x_handy
= m
->m_len
;
104 xdrmbuf_getall(XDR
*xdrs
)
108 KASSERT(xdrs
->x_ops
== &xdrmbuf_ops
&& xdrs
->x_op
== XDR_DECODE
,
109 ("xdrmbuf_append: invalid XDR stream"));
111 m0
= (struct mbuf
*) xdrs
->x_base
;
112 m
= (struct mbuf
*) xdrs
->x_private
;
114 while (m0
->m_next
!= m
)
117 xdrs
->x_private
= NULL
;
120 xdrs
->x_private
= NULL
;
124 m_adj(m
, xdrs
->x_handy
);
126 m
= m_get(M_WAITOK
, MT_DATA
);
131 xdrmbuf_destroy(XDR
*xdrs
)
134 if (xdrs
->x_op
== XDR_DECODE
&& xdrs
->x_base
) {
135 m_freem((struct mbuf
*) xdrs
->x_base
);
137 xdrs
->x_private
= NULL
;
142 xdrmbuf_getlong(XDR
*xdrs
, long *lp
)
147 p
= xdrmbuf_inline(xdrs
, sizeof(int32_t));
151 xdrmbuf_getbytes(xdrs
, (char *) &t
, sizeof(int32_t));
159 xdrmbuf_putlong(xdrs
, lp
)
164 int32_t t
= htonl(*lp
);
166 p
= xdrmbuf_inline(xdrs
, sizeof(int32_t));
171 return (xdrmbuf_putbytes(xdrs
, (char *) &t
, sizeof(int32_t)));
176 xdrmbuf_getbytes(XDR
*xdrs
, char *addr
, u_int len
)
178 struct mbuf
*m
= (struct mbuf
*) xdrs
->x_private
;
183 * Make sure we haven't hit the end.
190 * See how much we can get from this mbuf.
192 sz
= m
->m_len
- xdrs
->x_handy
;
195 bcopy(mtod(m
, const char *) + xdrs
->x_handy
, addr
, sz
);
201 if (xdrs
->x_handy
== m
->m_len
) {
203 xdrs
->x_private
= (void *) m
;
212 xdrmbuf_putbytes(XDR
*xdrs
, const char *addr
, u_int len
)
214 struct mbuf
*m
= (struct mbuf
*) xdrs
->x_private
;
219 sz
= M_TRAILINGSPACE(m
) + (m
->m_len
- xdrs
->x_handy
);
222 bcopy(addr
, mtod(m
, char *) + xdrs
->x_handy
, sz
);
225 if (xdrs
->x_handy
> m
->m_len
)
226 m
->m_len
= xdrs
->x_handy
;
229 if (xdrs
->x_handy
== m
->m_len
&& M_TRAILINGSPACE(m
) == 0) {
231 if (m
->m_flags
& M_EXT
)
232 n
= m_getcl(M_WAITOK
, m
->m_type
, 0);
234 n
= m_get(M_WAITOK
, m
->m_type
);
238 xdrs
->x_private
= (void *) m
;
247 xdrmbuf_getpos(XDR
*xdrs
)
249 struct mbuf
*m0
= (struct mbuf
*) xdrs
->x_base
;
250 struct mbuf
*m
= (struct mbuf
*) xdrs
->x_private
;
253 while (m0
&& m0
!= m
) {
257 KASSERT(m0
, ("Corrupted mbuf chain"));
259 return (pos
+ xdrs
->x_handy
);
263 xdrmbuf_setpos(XDR
*xdrs
, u_int pos
)
265 struct mbuf
*m
= (struct mbuf
*) xdrs
->x_base
;
267 while (m
&& pos
> m
->m_len
) {
271 KASSERT(m
, ("Corrupted mbuf chain"));
273 xdrs
->x_private
= (void *) m
;
280 xdrmbuf_inline(XDR
*xdrs
, u_int len
)
282 struct mbuf
*m
= (struct mbuf
*) xdrs
->x_private
;
288 if (xdrs
->x_op
== XDR_ENCODE
) {
289 available
= M_TRAILINGSPACE(m
) + (m
->m_len
- xdrs
->x_handy
);
291 available
= m
->m_len
- xdrs
->x_handy
;
294 if (available
>= len
) {
295 p
= mtod(m
, char *) + xdrs
->x_handy
;
296 if (((uintptr_t) p
) & (sizeof(int32_t) - 1))
298 xdrs
->x_handy
+= len
;
299 if (xdrs
->x_handy
> m
->m_len
)
300 m
->m_len
= xdrs
->x_handy
;
301 return ((int32_t *) p
);