summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/xdr/xdr_mbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/xdr/xdr_mbuf.c')
-rw-r--r--freebsd/sys/xdr/xdr_mbuf.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/freebsd/sys/xdr/xdr_mbuf.c b/freebsd/sys/xdr/xdr_mbuf.c
new file mode 100644
index 00000000..571dfec7
--- /dev/null
+++ b/freebsd/sys/xdr/xdr_mbuf.c
@@ -0,0 +1,307 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr@rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+static void xdrmbuf_destroy(XDR *);
+static bool_t xdrmbuf_getlong(XDR *, long *);
+static bool_t xdrmbuf_putlong(XDR *, const long *);
+static bool_t xdrmbuf_getbytes(XDR *, char *, u_int);
+static bool_t xdrmbuf_putbytes(XDR *, const char *, u_int);
+/* XXX: w/64-bit pointers, u_int not enough! */
+static u_int xdrmbuf_getpos(XDR *);
+static bool_t xdrmbuf_setpos(XDR *, u_int);
+static int32_t *xdrmbuf_inline(XDR *, u_int);
+
+static const struct xdr_ops xdrmbuf_ops = {
+ xdrmbuf_getlong,
+ xdrmbuf_putlong,
+ xdrmbuf_getbytes,
+ xdrmbuf_putbytes,
+ xdrmbuf_getpos,
+ xdrmbuf_setpos,
+ xdrmbuf_inline,
+ xdrmbuf_destroy
+};
+
+/*
+ * The procedure xdrmbuf_create initializes a stream descriptor for a
+ * mbuf.
+ */
+void
+xdrmbuf_create(XDR *xdrs, struct mbuf *m, enum xdr_op op)
+{
+
+ KASSERT(m != NULL, ("xdrmbuf_create with NULL mbuf chain"));
+ xdrs->x_op = op;
+ xdrs->x_ops = &xdrmbuf_ops;
+ xdrs->x_base = (char *) m;
+ if (op == XDR_ENCODE) {
+ m = m_last(m);
+ xdrs->x_private = m;
+ xdrs->x_handy = m->m_len;
+ } else {
+ xdrs->x_private = m;
+ xdrs->x_handy = 0;
+ }
+}
+
+void
+xdrmbuf_append(XDR *xdrs, struct mbuf *madd)
+{
+ struct mbuf *m;
+
+ KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_ENCODE,
+ ("xdrmbuf_append: invalid XDR stream"));
+
+ if (m_length(madd, NULL) == 0) {
+ m_freem(madd);
+ return;
+ }
+
+ m = (struct mbuf *) xdrs->x_private;
+ m->m_next = madd;
+
+ m = m_last(madd);
+ xdrs->x_private = m;
+ xdrs->x_handy = m->m_len;
+}
+
+struct mbuf *
+xdrmbuf_getall(XDR *xdrs)
+{
+ struct mbuf *m0, *m;
+
+ KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_DECODE,
+ ("xdrmbuf_append: invalid XDR stream"));
+
+ m0 = (struct mbuf *) xdrs->x_base;
+ m = (struct mbuf *) xdrs->x_private;
+ if (m0 != m) {
+ while (m0->m_next != m)
+ m0 = m0->m_next;
+ m0->m_next = NULL;
+ xdrs->x_private = NULL;
+ } else {
+ xdrs->x_base = NULL;
+ xdrs->x_private = NULL;
+ }
+
+ if (m)
+ m_adj(m, xdrs->x_handy);
+ else
+ m = m_get(M_WAITOK, MT_DATA);
+ return (m);
+}
+
+static void
+xdrmbuf_destroy(XDR *xdrs)
+{
+
+ if (xdrs->x_op == XDR_DECODE && xdrs->x_base) {
+ m_freem((struct mbuf *) xdrs->x_base);
+ xdrs->x_base = NULL;
+ xdrs->x_private = NULL;
+ }
+}
+
+static bool_t
+xdrmbuf_getlong(XDR *xdrs, long *lp)
+{
+ int32_t *p;
+ int32_t t;
+
+ p = xdrmbuf_inline(xdrs, sizeof(int32_t));
+ if (p) {
+ t = *p;
+ } else {
+ xdrmbuf_getbytes(xdrs, (char *) &t, sizeof(int32_t));
+ }
+
+ *lp = ntohl(t);
+ return (TRUE);
+}
+
+static bool_t
+xdrmbuf_putlong(xdrs, lp)
+ XDR *xdrs;
+ const long *lp;
+{
+ int32_t *p;
+ int32_t t = htonl(*lp);
+
+ p = xdrmbuf_inline(xdrs, sizeof(int32_t));
+ if (p) {
+ *p = t;
+ return (TRUE);
+ } else {
+ return (xdrmbuf_putbytes(xdrs, (char *) &t, sizeof(int32_t)));
+ }
+}
+
+static bool_t
+xdrmbuf_getbytes(XDR *xdrs, char *addr, u_int len)
+{
+ struct mbuf *m = (struct mbuf *) xdrs->x_private;
+ size_t sz;
+
+ while (len > 0) {
+ /*
+ * Make sure we haven't hit the end.
+ */
+ if (!m) {
+ return (FALSE);
+ }
+
+ /*
+ * See how much we can get from this mbuf.
+ */
+ sz = m->m_len - xdrs->x_handy;
+ if (sz > len)
+ sz = len;
+ bcopy(mtod(m, const char *) + xdrs->x_handy, addr, sz);
+
+ addr += sz;
+ xdrs->x_handy += sz;
+ len -= sz;
+
+ if (xdrs->x_handy == m->m_len) {
+ m = m->m_next;
+ xdrs->x_private = (void *) m;
+ xdrs->x_handy = 0;
+ }
+ }
+
+ return (TRUE);
+}
+
+static bool_t
+xdrmbuf_putbytes(XDR *xdrs, const char *addr, u_int len)
+{
+ struct mbuf *m = (struct mbuf *) xdrs->x_private;
+ struct mbuf *n;
+ size_t sz;
+
+ while (len > 0) {
+ sz = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy);
+ if (sz > len)
+ sz = len;
+ bcopy(addr, mtod(m, char *) + xdrs->x_handy, sz);
+ addr += sz;
+ xdrs->x_handy += sz;
+ if (xdrs->x_handy > m->m_len)
+ m->m_len = xdrs->x_handy;
+ len -= sz;
+
+ if (xdrs->x_handy == m->m_len && M_TRAILINGSPACE(m) == 0) {
+ if (!m->m_next) {
+ if (m->m_flags & M_EXT)
+ n = m_getcl(M_WAITOK, m->m_type, 0);
+ else
+ n = m_get(M_WAITOK, m->m_type);
+ m->m_next = n;
+ }
+ m = m->m_next;
+ xdrs->x_private = (void *) m;
+ xdrs->x_handy = 0;
+ }
+ }
+
+ return (TRUE);
+}
+
+static u_int
+xdrmbuf_getpos(XDR *xdrs)
+{
+ struct mbuf *m0 = (struct mbuf *) xdrs->x_base;
+ struct mbuf *m = (struct mbuf *) xdrs->x_private;
+ u_int pos = 0;
+
+ while (m0 && m0 != m) {
+ pos += m0->m_len;
+ m0 = m0->m_next;
+ }
+ KASSERT(m0, ("Corrupted mbuf chain"));
+
+ return (pos + xdrs->x_handy);
+}
+
+static bool_t
+xdrmbuf_setpos(XDR *xdrs, u_int pos)
+{
+ struct mbuf *m = (struct mbuf *) xdrs->x_base;
+
+ while (m && pos > m->m_len) {
+ pos -= m->m_len;
+ m = m->m_next;
+ }
+ KASSERT(m, ("Corrupted mbuf chain"));
+
+ xdrs->x_private = (void *) m;
+ xdrs->x_handy = pos;
+
+ return (TRUE);
+}
+
+static int32_t *
+xdrmbuf_inline(XDR *xdrs, u_int len)
+{
+ struct mbuf *m = (struct mbuf *) xdrs->x_private;
+ size_t available;
+ char *p;
+
+ if (!m)
+ return (0);
+ if (xdrs->x_op == XDR_ENCODE) {
+ available = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy);
+ } else {
+ available = m->m_len - xdrs->x_handy;
+ }
+
+ if (available >= len) {
+ p = mtod(m, char *) + xdrs->x_handy;
+ if (((uintptr_t) p) & (sizeof(int32_t) - 1))
+ return (0);
+ xdrs->x_handy += len;
+ if (xdrs->x_handy > m->m_len)
+ m->m_len = xdrs->x_handy;
+ return ((int32_t *) p);
+ }
+
+ return (0);
+}