2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/socket.h>
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <assert.h>
2N/A
2N/A#include <rad/adr_typeset.h>
2N/A
2N/A#include "radproto_util.h"
2N/A#include "radproto_adr.h"
2N/A#include "protocol.h"
2N/A
2N/A#define zalloc(x) calloc(1, x)
2N/A
2N/A/*
2N/A * XDR-like routines for reading and writing ADR data and types.
2N/A * There are two major differences between these and "normal" XDR
2N/A * routines:
2N/A * a) Some take more than two arguments. This is because the
2N/A * routines aren't dealing with fixed data structures and
2N/A * require additional inputs to perform their processing.
2N/A * This is a contributing factor to...
2N/A * b) They aren't symmetric. i.e. there are separate routines
2N/A * for reading (or sizing) and writing. The only substantial
2N/A * effect of merging reading and writing into a single function
2N/A * would be to create functions which are large and difficult
2N/A * to maintain.
2N/A */
2N/A
2N/A/*
2N/A * Marshal type definitions.
2N/A */
2N/A
2N/Astatic bool_t
2N/Atypeset_emit_type(XDR *xdrs, adr_typeset_t *typeset, adr_type_t *type)
2N/A{
2N/A assert(xdrs->x_op != XDR_DECODE);
2N/A
2N/A switch (type->t_type) {
2N/A case DT_ARRAY:
2N/A if (!xdr_int(xdrs, (int *)&type->t_type) ||
2N/A !xdr_typeref_t(xdrs, typeset, type->t_aux.t_array))
2N/A return (FALSE);
2N/A break;
2N/A case DT_STRUCT: {
2N/A if (!xdr_int(xdrs, (int *)&type->t_type) ||
2N/A !xdr_string(xdrs, (char **)&type->adr_t_name, -1) ||
2N/A !xdr_u_int(xdrs, &type->t_size))
2N/A return (FALSE);
2N/A for (int i = 0; i < type->t_size; i++) {
2N/A adr_structfield_t *field = &type->t_aux.t_fields[i];
2N/A if (!xdr_string(xdrs, (char **)&field->sf_name, -1) ||
2N/A !xdr_bool(xdrs, (int *)&field->sf_nullable) ||
2N/A !xdr_typeref_t(xdrs, typeset, field->sf_type))
2N/A return (FALSE);
2N/A }
2N/A break;
2N/A }
2N/A case DT_UNION: {
2N/A adr_unionarm_t *dfltarm = &type->t_aux.t_union.arms[0];
2N/A bool_t dflt = dfltarm->ua_type != NULL;
2N/A
2N/A if (!xdr_int(xdrs, (int *)&type->t_type) ||
2N/A !xdr_string(xdrs, (char **)&type->adr_t_name, -1) ||
2N/A !xdr_typeref_t(xdrs, typeset, type->t_aux.t_union.type) ||
2N/A !xdr_bool(xdrs, &dflt) ||
2N/A (dflt &&
2N/A (!xdr_bool(xdrs, (int *)&dfltarm->ua_nullable) ||
2N/A !xdr_typeref_t(xdrs, typeset, dfltarm->ua_type))) ||
2N/A !xdr_u_int(xdrs, &type->t_size))
2N/A return (FALSE);
2N/A
2N/A for (int i = 0; i < type->t_size; i++) {
2N/A adr_unionarm_t *ua = &type->t_aux.t_union.arms[i + 1];
2N/A if (!xdr_data_t(xdrs, ua->ua_value) ||
2N/A !xdr_bool(xdrs, (int *)&ua->ua_nullable) ||
2N/A !xdr_typeref_t(xdrs, typeset, ua->ua_type))
2N/A return (FALSE);
2N/A }
2N/A break;
2N/A }
2N/A case DT_ENUM: {
2N/A const char *fbname = type->t_aux.t_enum[0].ev_name;
2N/A bool_t fallback = fbname != NULL;
2N/A
2N/A if (!xdr_int(xdrs, (int *)&type->t_type) ||
2N/A !xdr_string(xdrs, (char **)&type->adr_t_name, -1) ||
2N/A !xdr_bool(xdrs, &fallback) ||
2N/A (fallback && !xdr_string(xdrs, (char **)&fbname, -1)) ||
2N/A !xdr_u_int(xdrs, &type->t_size))
2N/A return (FALSE);
2N/A
2N/A for (int i = 1; i < type->t_size + 1; i++) {
2N/A adr_enumval_t *ev = &type->t_aux.t_enum[i];
2N/A if (!xdr_string(xdrs, (char **)&ev->ev_name, -1) ||
2N/A !xdr_int(xdrs, &ev->ev_value))
2N/A return (FALSE);
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A
2N/A return (TRUE);
2N/A}
2N/A
2N/Astatic bool_t
2N/Atypeset_read_type(XDR *xdrs, adr_typeset_t *typeset)
2N/A{
2N/A assert(xdrs->x_op == XDR_DECODE);
2N/A
2N/A int ttype;
2N/A if (!xdr_int(xdrs, &ttype))
2N/A return (FALSE);
2N/A
2N/A if (!ADR_DT_DERIVED(ttype))
2N/A return (FALSE);
2N/A
2N/A adr_type_t *result = zalloc(sizeof (adr_type_t));
2N/A if (result == NULL)
2N/A return (FALSE);
2N/A result->t_type = ttype;
2N/A result->adr_t_name = NULL;
2N/A result->t_size = 0;
2N/A result->t_dynamic = B_TRUE;
2N/A
2N/A switch (ttype) {
2N/A case DT_ARRAY: {
2N/A adr_type_t *atype;
2N/A if (!xdr_r_typeref_t(xdrs, typeset, &atype))
2N/A goto error;
2N/A result->t_aux.t_array = atype;
2N/A break;
2N/A }
2N/A case DT_STRUCT: {
2N/A char *name = NULL;
2N/A
2N/A if (!xdr_string(xdrs, &name, -1))
2N/A goto error;
2N/A result->adr_t_name = name;
2N/A
2N/A if (!xdr_u_int(xdrs, &result->t_size) ||
2N/A (result->t_aux.t_fields = zalloc(result->t_size *
2N/A sizeof (adr_structfield_t))) == NULL)
2N/A goto error;
2N/A for (int i = 0; i < result->t_size; i++) {
2N/A adr_structfield_t *f = &result->t_aux.t_fields[i];
2N/A bool_t fopt;
2N/A if (!xdr_string(xdrs, (char **)&f->sf_name, -1) ||
2N/A !xdr_bool(xdrs, &fopt) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &f->sf_type))
2N/A goto error;
2N/A f->sf_nullable = fopt;
2N/A }
2N/A
2N/A break;
2N/A }
2N/A case DT_UNION: {
2N/A char *name = NULL;
2N/A bool_t dflt, dfltopt;
2N/A adr_type_t *dflttype = NULL, *utype;
2N/A
2N/A if (!xdr_string(xdrs, &name, -1) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &utype))
2N/A goto error;
2N/A result->adr_t_name = name;
2N/A result->t_aux.t_union.type = utype;
2N/A
2N/A if (!xdr_bool(xdrs, &dflt) ||
2N/A (dflt && (
2N/A !xdr_bool(xdrs, &dfltopt) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &dflttype))))
2N/A goto error;
2N/A
2N/A if (!xdr_u_int(xdrs, &result->t_size) ||
2N/A (result->t_aux.t_union.arms =
2N/A zalloc((result->t_size + 1) * sizeof (adr_unionarm_t))) ==
2N/A NULL)
2N/A goto error;
2N/A
2N/A if (dflt) {
2N/A result->t_aux.t_union.arms[0].ua_nullable = dfltopt;
2N/A result->t_aux.t_union.arms[0].ua_type = dflttype;
2N/A }
2N/A
2N/A for (int i = 0; i < result->t_size; i++) {
2N/A adr_unionarm_t *ua = &result->t_aux.t_union.arms[i + 1];
2N/A if (!xdr_r_data_t(xdrs, &ua->ua_value, utype, NULL) ||
2N/A !xdr_bool(xdrs, (int *)&ua->ua_nullable) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &ua->ua_type))
2N/A return (FALSE);
2N/A }
2N/A
2N/A break;
2N/A }
2N/A case DT_ENUM: {
2N/A char *name = NULL, *fbname = NULL;
2N/A bool_t fallback;
2N/A
2N/A if (!xdr_string(xdrs, &name, -1))
2N/A goto error;
2N/A result->adr_t_name = name;
2N/A
2N/A if (!xdr_bool(xdrs, &fallback) ||
2N/A (fallback && !xdr_string(xdrs, &fbname, -1)))
2N/A goto error;
2N/A
2N/A if (!xdr_u_int(xdrs, &result->t_size) ||
2N/A (result->t_aux.t_enum = zalloc((result->t_size + 1) *
2N/A sizeof (adr_enumval_t))) == NULL) {
2N/A free(fbname);
2N/A goto error;
2N/A }
2N/A
2N/A result->t_aux.t_enum[0].ev_name = fbname;
2N/A for (int i = 1; i < result->t_size + 1; i++) {
2N/A adr_enumval_t *e = &result->t_aux.t_enum[i];
2N/A int eval;
2N/A if (!xdr_string(xdrs, (char **)&e->ev_name, -1) ||
2N/A !xdr_int(xdrs, &eval))
2N/A goto error;
2N/A e->ev_value = eval;
2N/A e->ev_data = adr_data_new_enum_index(result, 0);
2N/A if (e->ev_data == NULL)
2N/A goto error;
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A
2N/A (void) adr_typeset_insert(typeset, result);
2N/A return (TRUE);
2N/A
2N/Aerror:
2N/A adr_type_free(result);
2N/A return (FALSE);
2N/A}
2N/A
2N/A
2N/Abool_t
2N/Axdr_typeref_t(XDR *xdrs, adr_typeset_t *typeset, adr_type_t *type)
2N/A{
2N/A if (!xdr_int(xdrs, (int *)&type->t_type))
2N/A return (FALSE);
2N/A
2N/A if (!ADR_DT_DERIVED(type->t_type))
2N/A return (TRUE);
2N/A
2N/A int tnum = adr_typeset_find(typeset, type);
2N/A assert(tnum >= 0);
2N/A
2N/A if (!xdr_int(xdrs, &tnum))
2N/A return (FALSE);
2N/A
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_r_typeref_t(XDR *xdrs, adr_typeset_t *typeset, adr_type_t **typep)
2N/A{
2N/A int ttype, tnum;
2N/A if (!xdr_int(xdrs, &ttype) || !ADR_DT_VALID(ttype))
2N/A return (FALSE);
2N/A
2N/A if (!ADR_DT_DERIVED(ttype)) {
2N/A *typep = adr_basetype(ttype);
2N/A return (TRUE);
2N/A }
2N/A
2N/A adr_type_t *type;
2N/A if (!xdr_int(xdrs, &tnum) ||
2N/A (type = adr_typeset_id(typeset, tnum)) == NULL)
2N/A return (FALSE);
2N/A
2N/A *typep = type;
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_typeset_t(XDR *xdrs, adr_typeset_t *typeset)
2N/A{
2N/A if (!xdr_int(xdrs, &typeset->TS_USED))
2N/A return (FALSE);
2N/A for (int i = 0; i < typeset->TS_USED; i++) {
2N/A adr_type_t *type = typeset->TS_TYPES[i].TR_TYPE;
2N/A if (!typeset_emit_type(xdrs, typeset, type))
2N/A return (FALSE);
2N/A }
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_r_typeset_t(XDR *xdrs, adr_typeset_t **typesetp)
2N/A{
2N/A adr_typeset_t *result;
2N/A int ntypes;
2N/A if (!xdr_int(xdrs, &ntypes))
2N/A return (FALSE);
2N/A
2N/A if ((result = adr_typeset_create(ntypes)) == NULL)
2N/A return (FALSE);
2N/A
2N/A for (int i = 0; i < ntypes; i++)
2N/A if (!typeset_read_type(xdrs, result)) {
2N/A adr_typeset_free(result);
2N/A return (FALSE);
2N/A }
2N/A
2N/A *typesetp = result;
2N/A return (TRUE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Normally the absence of a type is represented by void. Attribute/
2N/A * method error payload types require additional information: it is
2N/A * desirable to distinguish between an operation that doesn't return
2N/A * error payload data, and an operation that doesn't return errors.
2N/A * We effectively treat an error payload type as "optional data".
2N/A *
2N/A * Note that we don't use this when serializing standard error types
2N/A * at protocol negotiation time.
2N/A */
2N/Abool_t
2N/Axdr_errortype_t(XDR *xdrs, adr_typeset_t *typeset, adr_type_t *type)
2N/A{
2N/A assert(xdrs->x_op != XDR_DECODE);
2N/A
2N/A bool_t b = type != NULL;
2N/A if (!xdr_bool(xdrs, &b))
2N/A return (FALSE);
2N/A if (b)
2N/A return (xdr_typeref_t(xdrs, typeset, type));
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_r_errortype_t(XDR *xdrs, adr_typeset_t *typeset, adr_type_t **type)
2N/A{
2N/A assert(xdrs->x_op == XDR_DECODE);
2N/A
2N/A bool_t b;
2N/A if (!xdr_bool(xdrs, &b))
2N/A return (FALSE);
2N/A if (b)
2N/A return (xdr_r_typeref_t(xdrs, typeset, type));
2N/A *type = NULL;
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_stability_t(XDR *xdrs, adr_stability_t *stability)
2N/A{
2N/A if (!xdr_enum(xdrs, (int *)stability))
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_version_t(XDR *xdrs, adr_version_t *version)
2N/A{
2N/A if (!xdr_stability_t(xdrs, &version->av_stability) ||
2N/A !xdr_int(xdrs, &version->av_major) ||
2N/A !xdr_int(xdrs, &version->av_minor))
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Marshal/unmarshall an interface/version tuple.
2N/A *
2N/A * nparents indicates how many parent Interfaces should be processed when
2N/A * decoding. It isn't used when encoding.
2N/A */
2N/Abool_t
2N/Axdr_iface_t(XDR *xdrs, adr_object_t **objp, int nparents)
2N/A{
2N/A adr_object_t *obj = *objp;
2N/A int i;
2N/A
2N/A if (xdrs->x_op == XDR_DECODE) {
2N/A if (obj == NULL) {
2N/A obj = zalloc(sizeof (adr_object_t));
2N/A if ((*objp = obj) == NULL)
2N/A return (FALSE);
2N/A }
2N/A assert(obj->ao_parents == NULL);
2N/A if (nparents > 0) {
2N/A obj->ao_parents =
2N/A zalloc(nparents * sizeof (adr_object_t *));
2N/A if (obj->ao_parents == NULL)
2N/A return (FALSE);
2N/A obj->ao_nparents = nparents;
2N/A }
2N/A }
2N/A
2N/A /* Depth first; primary interface should be last listed */
2N/A for (i = 0; i < obj->ao_nparents; i++)
2N/A if (!xdr_iface_t(xdrs, &obj->ao_parents[i], 0))
2N/A return (FALSE);
2N/A if (!xdr_string(xdrs, (char **)&obj->ao_ifname, -1))
2N/A return (FALSE);
2N/A for (i = 0; i < NSTABILITY; i++)
2N/A if (!xdr_version_t(xdrs, &obj->ao_versions[i]))
2N/A return (FALSE);
2N/A return (TRUE);
2N/A}
2N/A
2N/Astatic int
2N/Acount_parents(adr_object_t *obj)
2N/A{
2N/A int n = 0;
2N/A for (int i = 0; i < obj->ao_nparents; i++)
2N/A n += count_parents(obj->ao_parents[i]);
2N/A return (n + 1);
2N/A}
2N/A
2N/A/*
2N/A * Marshal an interface definition.
2N/A */
2N/Abool_t
2N/Axdr_object_t(XDR *xdrs, adr_typeset_t *typeset, adr_object_t *obj)
2N/A{
2N/A int i, j;
2N/A
2N/A assert(xdrs->x_op != XDR_DECODE);
2N/A
2N/A /*
2N/A * Compatible interfaces and their versions
2N/A */
2N/A int n = count_parents(obj);
2N/A if (!xdr_string(xdrs, (char **)&obj->ao_aname, -1) ||
2N/A !xdr_int(xdrs, &n) ||
2N/A !xdr_iface_t(xdrs, &obj, 0))
2N/A return (FALSE);
2N/A
2N/A /*
2N/A * Type definitions
2N/A */
2N/A
2N/A if (!xdr_typeset_t(xdrs, typeset))
2N/A return (FALSE);
2N/A
2N/A /*
2N/A * Attributes
2N/A */
2N/A if (!xdr_int(xdrs, &obj->ao_nattributes))
2N/A return (FALSE);
2N/A for (i = 0; i < obj->ao_nattributes; i++) {
2N/A adr_attribute_t *a = obj->ao_attributes[i];
2N/A bool_t br = a->aa_readable ? TRUE : FALSE;
2N/A bool_t bw = a->aa_writeable ? TRUE : FALSE;
2N/A if (!xdr_string(xdrs, (char **)&a->aa_name, -1) ||
2N/A !xdr_stability_t(xdrs, &a->aa_stability) ||
2N/A !xdr_bool(xdrs, &br) ||
2N/A !xdr_bool(xdrs, &bw) ||
2N/A !xdr_bool(xdrs, (int *)&a->aa_nullable) ||
2N/A !xdr_typeref_t(xdrs, typeset, a->aa_type) ||
2N/A !xdr_errortype_t(xdrs, typeset, a->aa_read_error) ||
2N/A !xdr_errortype_t(xdrs, typeset, a->aa_write_error))
2N/A return (FALSE);
2N/A }
2N/A
2N/A /*
2N/A * Methods
2N/A */
2N/A if (!xdr_int(xdrs, &obj->ao_nmethods))
2N/A return (FALSE);
2N/A for (i = 0; i < obj->ao_nmethods; i++) {
2N/A adr_method_t *m = obj->ao_methods[i];
2N/A if (!xdr_string(xdrs, (char **)&m->am_name, -1) ||
2N/A !xdr_stability_t(xdrs, &m->am_stability) ||
2N/A !xdr_bool(xdrs, (int *)&m->am_nullable) ||
2N/A !xdr_typeref_t(xdrs, typeset, m->am_result) ||
2N/A !xdr_errortype_t(xdrs, typeset, m->am_error) ||
2N/A !xdr_int(xdrs, &m->am_nargs))
2N/A return (FALSE);
2N/A
2N/A for (j = 0; j < m->am_nargs; j++) {
2N/A adr_parameter_t *p = &m->am_args[j];
2N/A if (!xdr_string(xdrs, (char **)&p->ap_name, -1) ||
2N/A !xdr_bool(xdrs, (int *)&p->ap_nullable) ||
2N/A !xdr_typeref_t(xdrs, typeset, p->ap_type))
2N/A return (FALSE);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Events
2N/A */
2N/A if (!xdr_int(xdrs, &obj->ao_nevents))
2N/A return (FALSE);
2N/A for (i = 0; i < obj->ao_nevents; i++) {
2N/A adr_event_t *e = &obj->ao_events[i];
2N/A if (!xdr_string(xdrs, (char **)&e->ae_name, -1) ||
2N/A !xdr_stability_t(xdrs, &e->ae_stability) ||
2N/A !xdr_typeref_t(xdrs, typeset, e->ae_type))
2N/A return (FALSE);
2N/A }
2N/A
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Unmarshal an interface definition.
2N/A */
2N/Abool_t
2N/Axdr_r_object_t(XDR *xdrs, adr_object_t **obj)
2N/A{
2N/A assert(xdrs->x_op == XDR_DECODE);
2N/A
2N/A adr_typeset_t *typeset = NULL;
2N/A adr_object_t *result = zalloc(sizeof (adr_object_t));
2N/A if (result == NULL)
2N/A return (FALSE);
2N/A
2N/A /*
2N/A * Versions
2N/A */
2N/A int n;
2N/A if (!xdr_string(xdrs, (char **)&result->ao_aname, -1) ||
2N/A !xdr_int(xdrs, &n) ||
2N/A !xdr_iface_t(xdrs, &result, n))
2N/A goto error;
2N/A
2N/A if (!xdr_r_typeset_t(xdrs, &typeset))
2N/A goto error;
2N/A
2N/A /*
2N/A * Attributes
2N/A */
2N/A if (!xdr_int(xdrs, &n))
2N/A goto error;
2N/A result->ao_attributes = zalloc(n * sizeof (adr_attribute_t *));
2N/A if (result->ao_attributes == NULL)
2N/A goto error;
2N/A result->ao_nattributes = n;
2N/A for (int i = 0; i < result->ao_nattributes; i++) {
2N/A adr_attribute_t *attr = zalloc(sizeof (adr_attribute_t));
2N/A if (attr == NULL)
2N/A goto error;
2N/A result->ao_attributes[i] = attr;
2N/A attr->aa_name = NULL;
2N/A if (!xdr_string(xdrs, (char **)&attr->aa_name, -1) ||
2N/A !xdr_stability_t(xdrs, &attr->aa_stability) ||
2N/A !xdr_bool(xdrs, (bool_t *)&attr->aa_readable) ||
2N/A !xdr_bool(xdrs, (bool_t *)&attr->aa_writeable) ||
2N/A !xdr_bool(xdrs, (bool_t *)&attr->aa_nullable) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &attr->aa_type) ||
2N/A !xdr_r_errortype_t(xdrs, typeset, &attr->aa_read_error) ||
2N/A !xdr_r_errortype_t(xdrs, typeset, &attr->aa_write_error))
2N/A goto error;
2N/A }
2N/A
2N/A /*
2N/A * Methods
2N/A */
2N/A if (!xdr_int(xdrs, &n))
2N/A goto error;
2N/A result->ao_methods = zalloc(n * sizeof (adr_method_t *));
2N/A if (result->ao_methods == NULL)
2N/A goto error;
2N/A result->ao_nmethods = n;
2N/A for (int i = 0; i < result->ao_nmethods; i++) {
2N/A adr_method_t *method = zalloc(sizeof (adr_method_t));
2N/A if (method == NULL)
2N/A goto error;
2N/A result->ao_methods[i] = method;
2N/A method->am_name = NULL;
2N/A if (!xdr_string(xdrs, (char **)&method->am_name, -1) ||
2N/A !xdr_stability_t(xdrs, &method->am_stability) ||
2N/A !xdr_bool(xdrs, (bool_t *)&method->am_nullable) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &method->am_result) ||
2N/A !xdr_r_errortype_t(xdrs, typeset, &method->am_error) ||
2N/A !xdr_int(xdrs, &n))
2N/A goto error;
2N/A
2N/A method->am_args = zalloc(n * sizeof (adr_parameter_t));
2N/A if (method->am_args == NULL)
2N/A goto error;
2N/A method->am_nargs = n;
2N/A for (int j = 0; j < method->am_nargs; j++) {
2N/A adr_parameter_t *p = &method->am_args[j];
2N/A p->ap_name = NULL;
2N/A if (!xdr_string(xdrs, (char **)&p->ap_name, -1) ||
2N/A !xdr_bool(xdrs, (bool_t *)&p->ap_nullable) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &p->ap_type))
2N/A goto error;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Events
2N/A */
2N/A if (!xdr_int(xdrs, &n))
2N/A goto error;
2N/A result->ao_events = zalloc(result->ao_nevents * sizeof (adr_event_t));
2N/A if (result->ao_events == NULL)
2N/A goto error;
2N/A result->ao_nevents = n;
2N/A for (int i = 0; i < result->ao_nevents; i++) {
2N/A adr_event_t *e = &result->ao_events[i];
2N/A e->ae_name = NULL;
2N/A if (!xdr_string(xdrs, (char **)&e->ae_name, -1) ||
2N/A !xdr_stability_t(xdrs, &e->ae_stability) ||
2N/A !xdr_r_typeref_t(xdrs, typeset, &e->ae_type))
2N/A goto error;
2N/A }
2N/A
2N/A *obj = result;
2N/A adr_typeset_free(typeset);
2N/A return (TRUE);
2N/A
2N/Aerror:
2N/A adr_typeset_free(typeset);
2N/A adr_free(result);
2N/A return (FALSE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Marshal (typed) data.
2N/A */
2N/Abool_t
2N/Axdr_data_t(XDR *xdrs, adr_data_t *data)
2N/A{
2N/A int i;
2N/A
2N/A assert(xdrs->x_op != XDR_DECODE);
2N/A
2N/A switch (adr_data_basetype(data)) {
2N/A case DT_BOOLEAN:
2N/A if (!xdr_bool(xdrs, (int *)&data->d_data.boolean))
2N/A return (FALSE);
2N/A break;
2N/A case DT_INT:
2N/A if (!xdr_int(xdrs, &data->d_data.integer))
2N/A return (FALSE);
2N/A break;
2N/A case DT_LONG:
2N/A if (!xdr_hyper(xdrs, &data->d_data.longint))
2N/A return (FALSE);
2N/A break;
2N/A case DT_UINT:
2N/A if (!xdr_u_int(xdrs, &data->d_data.uinteger))
2N/A return (FALSE);
2N/A break;
2N/A case DT_ULONG:
2N/A if (!xdr_u_hyper(xdrs, &data->d_data.ulongint))
2N/A return (FALSE);
2N/A break;
2N/A case DT_FLOAT:
2N/A if (!xdr_float(xdrs, &data->d_data.afloat))
2N/A return (FALSE);
2N/A break;
2N/A case DT_DOUBLE:
2N/A if (!xdr_double(xdrs, &data->d_data.adouble))
2N/A return (FALSE);
2N/A break;
2N/A case DT_TIME: {
2N/A wiretime tv = {
2N/A data->d_data.time.seconds,
2N/A data->d_data.time.nanos
2N/A };
2N/A if (!xdr_wiretime(xdrs, &tv))
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_STRING:
2N/A if (!xdr_string(xdrs, (char **)&data->d_data.string, -1))
2N/A return (FALSE);
2N/A break;
2N/A case DT_SECRET:
2N/A if (!xdr_string(xdrs, (char **)&data->d_data.string, -1))
2N/A return (FALSE);
2N/A break;
2N/A case DT_NAME: {
2N/A char *tmp = adr_name_tostr(data->d_data.name);
2N/A if (tmp == NULL)
2N/A return (FALSE);
2N/A if (!xdr_string(xdrs, &tmp, -1)) {
2N/A free(tmp);
2N/A return (FALSE);
2N/A }
2N/A free(tmp);
2N/A break;
2N/A }
2N/A case DT_ARRAY:
2N/A if (!xdr_u_int(xdrs, &data->d_rsize))
2N/A return (FALSE);
2N/A for (i = 0; i < data->d_rsize; i++) {
2N/A assert(adr_array_get(data, i) != NULL);
2N/A if (!xdr_data_t(xdrs, adr_array_get(data, i)))
2N/A return (FALSE);
2N/A }
2N/A break;
2N/A case DT_STRUCT:
2N/A for (i = 0; i < data->d_size; i++) {
2N/A adr_structfield_t *sf =
2N/A &data->d_type->t_aux.t_fields[i];
2N/A if (sf->sf_nullable) {
2N/A if (!xdr_optdata_t(xdrs, data->d_data.array[i]))
2N/A return (FALSE);
2N/A } else {
2N/A if (!xdr_data_t(xdrs, data->d_data.array[i]))
2N/A return (FALSE);
2N/A }
2N/A }
2N/A break;
2N/A case DT_ENUM: {
2N/A /* Communicated as an index */
2N/A if (!xdr_int(xdrs, &data->d_data.integer))
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_OPAQUE:
2N/A if (!xdr_bytes(xdrs, (char **)&data->d_data.opaque,
2N/A (uint_t *)&data->d_size, -1))
2N/A return (FALSE);
2N/A break;
2N/A case DT_UNION: {
2N/A adr_unionarm_t *ua = &data->d_type->t_aux.t_union.arms[
2N/A data->d_rsize];
2N/A
2N/A /* Write arm index, discriminant value */
2N/A if (!xdr_u_int(xdrs, &data->d_rsize) ||
2N/A (data->d_rsize == 0 &&
2N/A !xdr_data_t(xdrs, data->d_data.aunion.value)))
2N/A return (FALSE);
2N/A
2N/A /* Write data, if any */
2N/A if (ua->ua_type->t_type != DT_VOID && (ua->ua_nullable ?
2N/A !xdr_optdata_t(xdrs, data->d_data.aunion.data) :
2N/A !xdr_data_t(xdrs, data->d_data.aunion.data)))
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Unmarshal data of the specified type
2N/A */
2N/Abool_t
2N/Axdr_r_data_t(XDR *xdrs, adr_data_t **data, adr_type_t *type, char *buf)
2N/A{
2N/A assert(xdrs->x_op == XDR_DECODE);
2N/A
2N/A switch (type->t_type) {
2N/A case DT_BOOLEAN: {
2N/A bool_t b;
2N/A if (!xdr_bool(xdrs, &b) ||
2N/A (*data = adr_data_new_boolean(b)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_INT: {
2N/A int i;
2N/A if (!xdr_int(xdrs, &i) ||
2N/A (*data = adr_data_new_integer(i)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_LONG: {
2N/A long long l;
2N/A if (!xdr_hyper(xdrs, &l) ||
2N/A (*data = adr_data_new_long(l)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_UINT: {
2N/A unsigned int ui;
2N/A if (!xdr_u_int(xdrs, &ui) ||
2N/A (*data = adr_data_new_uinteger(ui)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_ULONG: {
2N/A unsigned long long ul;
2N/A if (!xdr_u_hyper(xdrs, &ul) ||
2N/A (*data = adr_data_new_ulong(ul)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_FLOAT: {
2N/A float f;
2N/A if (!xdr_float(xdrs, &f) ||
2N/A (*data = adr_data_new_float(f)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_DOUBLE: {
2N/A double d;
2N/A if (!xdr_double(xdrs, &d) ||
2N/A (*data = adr_data_new_double(d)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_TIME: {
2N/A struct wiretime tv;
2N/A if (!xdr_wiretime(xdrs, &tv) ||
2N/A tv.seconds < 0 || tv.nanos < 0 || tv.nanos >= NANOSEC ||
2N/A (*data = adr_data_new_time(tv.seconds, tv.nanos)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_NAME: {
2N/A char *c = NULL;
2N/A if (!xdr_string(xdrs, &c, -1))
2N/A return (FALSE);
2N/A if ((*data = adr_data_new_name(adr_name_fromstr(c))) == NULL) {
2N/A free(c);
2N/A return (FALSE);
2N/A }
2N/A free(c);
2N/A break;
2N/A }
2N/A case DT_STRING: {
2N/A char *c = NULL;
2N/A if (!xdr_string(xdrs, &c, -1) ||
2N/A (*data = adr_data_new_string(c, LT_FREE)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A
2N/A case DT_SECRET: {
2N/A char *c = NULL;
2N/A if (!xdr_string(xdrs, &c, -1) ||
2N/A (*data = adr_data_new_secret(c)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A
2N/A case DT_ARRAY: {
2N/A int i, count;
2N/A xdr_bytesrec bytes;
2N/A
2N/A if (!xdr_int(xdrs, &count))
2N/A return (FALSE);
2N/A
2N/A /* Check size; only works for xdrmem */
2N/A if (!xdr_control(xdrs, XDR_GET_BYTES_AVAIL, &bytes) ||
2N/A count > bytes.xc_num_avail / 4) {
2N/A if (buf != NULL)
2N/A (void) sprintf(buf, "bogus array size: %d",
2N/A count);
2N/A return (FALSE);
2N/A }
2N/A
2N/A if ((*data = adr_data_new_array(type, count)) == NULL)
2N/A return (FALSE);
2N/A for (i = 0; i < count; i++)
2N/A if (!xdr_r_data_t(xdrs, &(*data)->d_data.array[i],
2N/A type->t_aux.t_array, buf))
2N/A break;
2N/A (*data)->d_rsize = i;
2N/A
2N/A if (i < count) {
2N/A adr_data_free(*data);
2N/A *data = NULL;
2N/A return (FALSE);
2N/A }
2N/A break;
2N/A }
2N/A case DT_STRUCT: {
2N/A int i;
2N/A extern void adr_struct_set_internal(adr_data_t *,
2N/A adr_structfield_t *, adr_data_t *);
2N/A
2N/A if ((*data = adr_data_new_struct(type)) == NULL)
2N/A return (FALSE);
2N/A for (i = 0; i < type->t_size; i++) {
2N/A adr_structfield_t *sf = &type->t_aux.t_fields[i];
2N/A adr_data_t *d;
2N/A if (sf->sf_nullable) {
2N/A if (!xdr_r_optdata_t(xdrs, &d, sf->sf_type))
2N/A break;
2N/A } else {
2N/A if (!xdr_r_data_t(xdrs, &d, sf->sf_type, buf))
2N/A break;
2N/A }
2N/A adr_struct_set_internal(*data, sf, d);
2N/A }
2N/A if (i < type->t_size) {
2N/A adr_data_free(*data);
2N/A *data = NULL;
2N/A return (FALSE);
2N/A }
2N/A break;
2N/A }
2N/A case DT_OPAQUE: {
2N/A char *c = NULL;
2N/A xdr_bytesrec bytes;
2N/A uint_t len;
2N/A
2N/A if (!xdr_u_int(xdrs, &len))
2N/A return (FALSE);
2N/A
2N/A /* Check size; only works for xdrmem */
2N/A if (!xdr_control(xdrs, XDR_GET_BYTES_AVAIL, &bytes) ||
2N/A len > bytes.xc_num_avail) {
2N/A if (buf != NULL)
2N/A (void) sprintf(buf, "bogus opaque size: %d",
2N/A len);
2N/A return (FALSE);
2N/A }
2N/A if ((c = malloc(len)) == NULL)
2N/A return (FALSE);
2N/A if (!xdr_opaque(xdrs, c, len)) {
2N/A free(c);
2N/A return (FALSE);
2N/A }
2N/A if ((*data = adr_data_new_opaque(c, len, LT_FREE)) == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A case DT_ENUM: {
2N/A int index;
2N/A if (!xdr_int(xdrs, &index) || index > type->t_size || index < 0)
2N/A return (FALSE);
2N/A
2N/A if (type->t_aux.t_enum[index].ev_name == NULL) {
2N/A assert(index == 0);
2N/A return (FALSE);
2N/A }
2N/A
2N/A *data = adr_data_ref(type->t_aux.t_enum[index].ev_data);
2N/A break;
2N/A }
2N/A case DT_UNION: {
2N/A adr_data_t *arm, *value = NULL;
2N/A unsigned int index;
2N/A
2N/A /* Read arm index */
2N/A if (!xdr_u_int(xdrs, &index) || index > type->t_size)
2N/A return (FALSE);
2N/A adr_unionarm_t *ua = &type->t_aux.t_union.arms[index];
2N/A
2N/A /* Find/read discriminant value */
2N/A if (index > 0) {
2N/A arm = adr_data_ref(ua->ua_value);
2N/A } else {
2N/A if (!xdr_r_data_t(xdrs, &arm, type->t_aux.t_union.type,
2N/A buf))
2N/A return (FALSE);
2N/A
2N/A /* Ensure that discriminant maps to default/none */
2N/A if (ua != adr_union_arm_type(type, arm)) {
2N/A adr_data_free(arm);
2N/A return (FALSE);
2N/A }
2N/A }
2N/A
2N/A if (ua->ua_type == NULL)
2N/A return (FALSE);
2N/A
2N/A /* Read data, if any */
2N/A if (ua->ua_type->t_type != DT_VOID && (ua->ua_nullable ?
2N/A !xdr_r_optdata_t(xdrs, &value, ua->ua_type) :
2N/A !xdr_r_data_t(xdrs, &value, ua->ua_type, buf))) {
2N/A adr_data_free(arm);
2N/A return (FALSE);
2N/A }
2N/A
2N/A if ((*data =
2N/A adr_data_new_union_indexed(type, index, arm, value))
2N/A == NULL)
2N/A return (FALSE);
2N/A break;
2N/A }
2N/A default:
2N/A if (buf != NULL)
2N/A (void) sprintf(buf,
2N/A "Invalid deserialized data type (%d)",
2N/A type->t_type);
2N/A return (FALSE);
2N/A }
2N/A
2N/A return (TRUE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Marshal a piece of optional data.
2N/A */
2N/Abool_t
2N/Axdr_optdata_t(XDR *xdrs, adr_data_t *data)
2N/A{
2N/A assert(xdrs->x_op != XDR_DECODE);
2N/A
2N/A bool_t b = data != NULL;
2N/A if (!xdr_bool(xdrs, &b))
2N/A return (FALSE);
2N/A if (b)
2N/A return (xdr_data_t(xdrs, data));
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*
2N/A * Unmarshal a piece of typed optional data.
2N/A */
2N/Abool_t
2N/Axdr_r_optdata_t(XDR *xdrs, adr_data_t **data, adr_type_t *type)
2N/A{
2N/A assert(xdrs->x_op == XDR_DECODE);
2N/A
2N/A bool_t b;
2N/A if (!xdr_bool(xdrs, &b))
2N/A return (FALSE);
2N/A if (b)
2N/A return (xdr_r_data_t(xdrs, data, type, NULL));
2N/A else
2N/A *data = NULL;
2N/A return (TRUE);
2N/A}
2N/A
2N/Abool_t
2N/Axdr_unembed_optdata(adr_data_t **data, adr_type_t *t, uint_t len, char *val)
2N/A{
2N/A XDR mxdr;
2N/A mxdr.x_ops = NULL;
2N/A xdrmem_create(&mxdr, val, len, XDR_DECODE);
2N/A if (mxdr.x_ops == NULL)
2N/A return (FALSE);
2N/A if (!xdr_r_optdata_t(&mxdr, data, t)) {
2N/A xdr_destroy(&mxdr);
2N/A return (FALSE);
2N/A }
2N/A xdr_destroy(&mxdr);
2N/A return (TRUE);
2N/A}