1177633Sdfr/*- 2177633Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3177633Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4177633Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5177633Sdfr * 6177633Sdfr * Redistribution and use in source and binary forms, with or without 7177633Sdfr * modification, are permitted provided that the following conditions 8177633Sdfr * are met: 9177633Sdfr * 1. Redistributions of source code must retain the above copyright 10177633Sdfr * notice, this list of conditions and the following disclaimer. 11177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12177633Sdfr * notice, this list of conditions and the following disclaimer in the 13177633Sdfr * documentation and/or other materials provided with the distribution. 14177633Sdfr * 15177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25177633Sdfr * SUCH DAMAGE. 26177633Sdfr */ 27177633Sdfr 28177633Sdfr#include <sys/cdefs.h> 29177633Sdfr__FBSDID("$FreeBSD$"); 30177633Sdfr 31177633Sdfr#include <sys/param.h> 32177633Sdfr#include <sys/systm.h> 33177633Sdfr#include <sys/malloc.h> 34177633Sdfr#include <sys/mbuf.h> 35177633Sdfr 36177633Sdfr#include <rpc/types.h> 37177633Sdfr#include <rpc/xdr.h> 38177633Sdfr 39177633Sdfrstatic void xdrmbuf_destroy(XDR *); 40177633Sdfrstatic bool_t xdrmbuf_getlong(XDR *, long *); 41177633Sdfrstatic bool_t xdrmbuf_putlong(XDR *, const long *); 42177633Sdfrstatic bool_t xdrmbuf_getbytes(XDR *, char *, u_int); 43177633Sdfrstatic bool_t xdrmbuf_putbytes(XDR *, const char *, u_int); 44177633Sdfr/* XXX: w/64-bit pointers, u_int not enough! */ 45177633Sdfrstatic u_int xdrmbuf_getpos(XDR *); 46177633Sdfrstatic bool_t xdrmbuf_setpos(XDR *, u_int); 47177633Sdfrstatic int32_t *xdrmbuf_inline(XDR *, u_int); 48177633Sdfr 49177633Sdfrstatic const struct xdr_ops xdrmbuf_ops = { 50177633Sdfr xdrmbuf_getlong, 51177633Sdfr xdrmbuf_putlong, 52177633Sdfr xdrmbuf_getbytes, 53177633Sdfr xdrmbuf_putbytes, 54177633Sdfr xdrmbuf_getpos, 55177633Sdfr xdrmbuf_setpos, 56177633Sdfr xdrmbuf_inline, 57177633Sdfr xdrmbuf_destroy 58177633Sdfr}; 59177633Sdfr 60177633Sdfr/* 61177633Sdfr * The procedure xdrmbuf_create initializes a stream descriptor for a 62177633Sdfr * mbuf. 63177633Sdfr */ 64177633Sdfrvoid 65177633Sdfrxdrmbuf_create(XDR *xdrs, struct mbuf *m, enum xdr_op op) 66177633Sdfr{ 67177633Sdfr 68184921Sdfr KASSERT(m != NULL, ("xdrmbuf_create with NULL mbuf chain")); 69177633Sdfr xdrs->x_op = op; 70177633Sdfr xdrs->x_ops = &xdrmbuf_ops; 71177633Sdfr xdrs->x_base = (char *) m; 72177633Sdfr if (op == XDR_ENCODE) { 73177633Sdfr m = m_last(m); 74177633Sdfr xdrs->x_private = m; 75177633Sdfr xdrs->x_handy = m->m_len; 76177633Sdfr } else { 77177633Sdfr xdrs->x_private = m; 78177633Sdfr xdrs->x_handy = 0; 79177633Sdfr } 80177633Sdfr} 81177633Sdfr 82184588Sdfrvoid 83184588Sdfrxdrmbuf_append(XDR *xdrs, struct mbuf *madd) 84184588Sdfr{ 85184588Sdfr struct mbuf *m; 86184588Sdfr 87184588Sdfr KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_ENCODE, 88184588Sdfr ("xdrmbuf_append: invalid XDR stream")); 89184588Sdfr 90184588Sdfr if (m_length(madd, NULL) == 0) { 91184588Sdfr m_freem(madd); 92184588Sdfr return; 93184588Sdfr } 94184588Sdfr 95184588Sdfr m = (struct mbuf *) xdrs->x_private; 96184588Sdfr m->m_next = madd; 97184588Sdfr 98184588Sdfr m = m_last(madd); 99184588Sdfr xdrs->x_private = m; 100184588Sdfr xdrs->x_handy = m->m_len; 101184588Sdfr} 102184588Sdfr 103184588Sdfrstruct mbuf * 104184588Sdfrxdrmbuf_getall(XDR *xdrs) 105184588Sdfr{ 106184588Sdfr struct mbuf *m0, *m; 107184588Sdfr 108184588Sdfr KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_DECODE, 109184588Sdfr ("xdrmbuf_append: invalid XDR stream")); 110184588Sdfr 111184588Sdfr m0 = (struct mbuf *) xdrs->x_base; 112184588Sdfr m = (struct mbuf *) xdrs->x_private; 113184588Sdfr if (m0 != m) { 114184588Sdfr while (m0->m_next != m) 115184588Sdfr m0 = m0->m_next; 116184588Sdfr m0->m_next = NULL; 117184588Sdfr xdrs->x_private = NULL; 118184588Sdfr } else { 119184588Sdfr xdrs->x_base = NULL; 120184588Sdfr xdrs->x_private = NULL; 121184588Sdfr } 122184588Sdfr 123184692Sdfr if (m) 124184692Sdfr m_adj(m, xdrs->x_handy); 125184692Sdfr else 126248318Sglebius m = m_get(M_WAITOK, MT_DATA); 127184588Sdfr return (m); 128184588Sdfr} 129184588Sdfr 130177633Sdfrstatic void 131177633Sdfrxdrmbuf_destroy(XDR *xdrs) 132177633Sdfr{ 133177633Sdfr 134177633Sdfr if (xdrs->x_op == XDR_DECODE && xdrs->x_base) { 135177633Sdfr m_freem((struct mbuf *) xdrs->x_base); 136177633Sdfr xdrs->x_base = NULL; 137177633Sdfr xdrs->x_private = NULL; 138177633Sdfr } 139177633Sdfr} 140177633Sdfr 141177633Sdfrstatic bool_t 142177633Sdfrxdrmbuf_getlong(XDR *xdrs, long *lp) 143177633Sdfr{ 144184588Sdfr int32_t *p; 145177633Sdfr int32_t t; 146177633Sdfr 147184588Sdfr p = xdrmbuf_inline(xdrs, sizeof(int32_t)); 148184588Sdfr if (p) { 149184588Sdfr t = *p; 150184588Sdfr } else { 151184588Sdfr xdrmbuf_getbytes(xdrs, (char *) &t, sizeof(int32_t)); 152184588Sdfr } 153184588Sdfr 154177633Sdfr *lp = ntohl(t); 155177633Sdfr return (TRUE); 156177633Sdfr} 157177633Sdfr 158177633Sdfrstatic bool_t 159177633Sdfrxdrmbuf_putlong(xdrs, lp) 160177633Sdfr XDR *xdrs; 161177633Sdfr const long *lp; 162177633Sdfr{ 163184588Sdfr int32_t *p; 164177633Sdfr int32_t t = htonl(*lp); 165177633Sdfr 166184588Sdfr p = xdrmbuf_inline(xdrs, sizeof(int32_t)); 167184588Sdfr if (p) { 168184588Sdfr *p = t; 169184588Sdfr return (TRUE); 170184588Sdfr } else { 171184588Sdfr return (xdrmbuf_putbytes(xdrs, (char *) &t, sizeof(int32_t))); 172184588Sdfr } 173177633Sdfr} 174177633Sdfr 175177633Sdfrstatic bool_t 176177633Sdfrxdrmbuf_getbytes(XDR *xdrs, char *addr, u_int len) 177177633Sdfr{ 178177633Sdfr struct mbuf *m = (struct mbuf *) xdrs->x_private; 179177633Sdfr size_t sz; 180177633Sdfr 181177633Sdfr while (len > 0) { 182177633Sdfr /* 183177633Sdfr * Make sure we haven't hit the end. 184177633Sdfr */ 185177633Sdfr if (!m) { 186177633Sdfr return (FALSE); 187177633Sdfr } 188177633Sdfr 189177633Sdfr /* 190177633Sdfr * See how much we can get from this mbuf. 191177633Sdfr */ 192177633Sdfr sz = m->m_len - xdrs->x_handy; 193177633Sdfr if (sz > len) 194177633Sdfr sz = len; 195184588Sdfr bcopy(mtod(m, const char *) + xdrs->x_handy, addr, sz); 196177633Sdfr 197177633Sdfr addr += sz; 198177633Sdfr xdrs->x_handy += sz; 199177633Sdfr len -= sz; 200177633Sdfr 201177633Sdfr if (xdrs->x_handy == m->m_len) { 202177633Sdfr m = m->m_next; 203177633Sdfr xdrs->x_private = (void *) m; 204177633Sdfr xdrs->x_handy = 0; 205177633Sdfr } 206177633Sdfr } 207177633Sdfr 208177633Sdfr return (TRUE); 209177633Sdfr} 210177633Sdfr 211177633Sdfrstatic bool_t 212177633Sdfrxdrmbuf_putbytes(XDR *xdrs, const char *addr, u_int len) 213177633Sdfr{ 214177633Sdfr struct mbuf *m = (struct mbuf *) xdrs->x_private; 215177633Sdfr struct mbuf *n; 216177633Sdfr size_t sz; 217177633Sdfr 218177633Sdfr while (len > 0) { 219177633Sdfr sz = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy); 220177633Sdfr if (sz > len) 221177633Sdfr sz = len; 222184588Sdfr bcopy(addr, mtod(m, char *) + xdrs->x_handy, sz); 223177633Sdfr addr += sz; 224177633Sdfr xdrs->x_handy += sz; 225177633Sdfr if (xdrs->x_handy > m->m_len) 226177633Sdfr m->m_len = xdrs->x_handy; 227177633Sdfr len -= sz; 228177633Sdfr 229177633Sdfr if (xdrs->x_handy == m->m_len && M_TRAILINGSPACE(m) == 0) { 230177633Sdfr if (!m->m_next) { 231184588Sdfr if (m->m_flags & M_EXT) 232248318Sglebius n = m_getcl(M_WAITOK, m->m_type, 0); 233248318Sglebius else 234248318Sglebius n = m_get(M_WAITOK, m->m_type); 235177633Sdfr m->m_next = n; 236177633Sdfr } 237177633Sdfr m = m->m_next; 238177633Sdfr xdrs->x_private = (void *) m; 239177633Sdfr xdrs->x_handy = 0; 240177633Sdfr } 241177633Sdfr } 242177633Sdfr 243177633Sdfr return (TRUE); 244177633Sdfr} 245177633Sdfr 246177633Sdfrstatic u_int 247177633Sdfrxdrmbuf_getpos(XDR *xdrs) 248177633Sdfr{ 249177633Sdfr struct mbuf *m0 = (struct mbuf *) xdrs->x_base; 250177633Sdfr struct mbuf *m = (struct mbuf *) xdrs->x_private; 251177633Sdfr u_int pos = 0; 252177633Sdfr 253177633Sdfr while (m0 && m0 != m) { 254177633Sdfr pos += m0->m_len; 255177633Sdfr m0 = m0->m_next; 256177633Sdfr } 257177633Sdfr KASSERT(m0, ("Corrupted mbuf chain")); 258177633Sdfr 259177633Sdfr return (pos + xdrs->x_handy); 260177633Sdfr} 261177633Sdfr 262177633Sdfrstatic bool_t 263177633Sdfrxdrmbuf_setpos(XDR *xdrs, u_int pos) 264177633Sdfr{ 265177633Sdfr struct mbuf *m = (struct mbuf *) xdrs->x_base; 266177633Sdfr 267177633Sdfr while (m && pos > m->m_len) { 268177633Sdfr pos -= m->m_len; 269177633Sdfr m = m->m_next; 270177633Sdfr } 271177633Sdfr KASSERT(m, ("Corrupted mbuf chain")); 272177633Sdfr 273177633Sdfr xdrs->x_private = (void *) m; 274177633Sdfr xdrs->x_handy = pos; 275177633Sdfr 276177633Sdfr return (TRUE); 277177633Sdfr} 278177633Sdfr 279177633Sdfrstatic int32_t * 280177633Sdfrxdrmbuf_inline(XDR *xdrs, u_int len) 281177633Sdfr{ 282177633Sdfr struct mbuf *m = (struct mbuf *) xdrs->x_private; 283177633Sdfr size_t available; 284177633Sdfr char *p; 285177633Sdfr 286196149Srmacklem if (!m) 287196149Srmacklem return (0); 288177633Sdfr if (xdrs->x_op == XDR_ENCODE) { 289177633Sdfr available = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy); 290177633Sdfr } else { 291177633Sdfr available = m->m_len - xdrs->x_handy; 292177633Sdfr } 293177633Sdfr 294177633Sdfr if (available >= len) { 295177633Sdfr p = mtod(m, char *) + xdrs->x_handy; 296177633Sdfr if (((uintptr_t) p) & (sizeof(int32_t) - 1)) 297177633Sdfr return (0); 298177633Sdfr xdrs->x_handy += len; 299177633Sdfr if (xdrs->x_handy > m->m_len) 300177633Sdfr m->m_len = xdrs->x_handy; 301177633Sdfr return ((int32_t *) p); 302177633Sdfr } 303177633Sdfr 304177633Sdfr return (0); 305177633Sdfr} 306