/*
 * nasd_od_srpc.c
 *
 * SRPC module for NASD drive
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>

#if NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_SRPC

#include <nasd/nasd_types.h>
#include <nasd/nasd_itypes.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_control.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_od_rpc.h>
#include <nasd/nasd_timeout.h>
#include <nasd/nasd_freelist.h>
#include <nasd/nasd_pipe.h>
#include <nasd/nasd_srpc_types.h>
#include <nasd/nasd_srpc.h>
#include <nasd/nasd_pdrive.h>
#include <nasd/nasd_pdrive_sstub.h>
#include <nasd/nasd_security.h>
#include <nasd/nasd_security_dr.h>
#include <nasd/nasd_trace_dr.h>
#include <nasd/nasd_keymgmt_dr.h>

/* Don't use __FILE__ here to avoid getting kernel-mangled names */
#define NASD_OD_RPC_NASD_RET out_res.nasd_status
#define NASD_OD_RPC_RETURN(_statval_) { \
  return(_statval_); \
}
#define DOBEGIN(_opname_)  NASD_OD_RPC_DOBEGIN(_opname_,"nasd_od_srpc.c")
#define DORETURN(_opname_) NASD_OD_RPC_DORETURN(_opname_,"nasd_od_srpc.c")

#define NASD_SRPC_SEC_OP_DECL \
  nasd_security_param_t in_sec_param; \
  nasd_capability_t in_capability; \
  nasd_key_t op_key; \
  nasd_key_t integrity_key; \
  nasd_key_t privacy_key; \
  nasd_iv_t icv;

#if NASD_TRACE_DR > 0
#define NASD_SRPC_TRACE_OP_DECL \
  nasd_trace_seq_t trace_seq;
#else /* NASD_TRACE_DR > 0 */
#define NASD_SRPC_TRACE_OP_DECL
#endif /* NASD_TRACE_DR > 0 */

#define NASD_SRPC_OP_DECL \
  NASD_SRPC_SEC_OP_DECL \
  NASD_SRPC_TRACE_OP_DECL \
  NASD_OD_RPC_OP_STATS_DECL

#define NASD_SRPC_NOSEC_OP_DECL \
  NASD_SRPC_TRACE_OP_DECL \
  NASD_OD_RPC_OP_STATS_DECL

nasd_drive_opholder_t nasd_drive_fail_opholder;

/*
 * RPC callbacks
 */

nasd_srpc_status_t
nasd_p_null_dr_server(
  nasd_srpc_listener_t     *listener,
  nasd_srpc_conn_t         *conn,
  nasd_srpc_server_call_t  *call,
  nasd_res_otw_t            out_res_otw)
{
  nasd_res_t out_res;
  NASD_SRPC_NOSEC_OP_DECL

  DOBEGIN(null);
  nasd_dt_noop_args(&trace_seq);

  out_res.nasd_status = NASD_SUCCESS;
  nasd_res_t_marshall(&out_res, out_res_otw);

  nasd_dt_noop_res(trace_seq);
  DORETURN(null);
}

nasd_srpc_status_t
nasd_p_sync_dr_server(
  nasd_srpc_listener_t     *listener,
  nasd_srpc_conn_t         *conn,
  nasd_srpc_server_call_t  *call,
  nasd_res_otw_t            out_res_otw)
{
  nasd_res_t out_res;
  NASD_SRPC_NOSEC_OP_DECL

  DOBEGIN(null);
  nasd_dt_sync_args(&trace_seq);

  out_res.nasd_status = nasd_odc_flush_dirty(1);
  nasd_res_t_marshall(&out_res, out_res_otw);

  nasd_dt_sync_res(trace_seq);
  DORETURN(null);
}

nasd_srpc_status_t
nasd_p_part_creat_otw_dr_server(
  nasd_srpc_listener_t             *listener,
  nasd_srpc_conn_t                 *conn,
  nasd_srpc_server_call_t          *call,
  nasd_security_param_otw_t         in_sec_param_otw,
  nasd_capability_otw_t             in_capability_otw,
  nasd_digest_nonce_otw_t           in_digest_otw,
  nasd_p_part_creat_dr_args_otw_t   in_args_otw,
  nasd_p_part_creat_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t           out_digest_otw)
{
  nasd_p_part_creat_dr_args_t in_args;
  nasd_p_part_creat_dr_res_t out_res;
  nasd_identifier_t nid;
  NASD_SRPC_OP_DECL

  DOBEGIN(part_creat);
  nasd_dt_part_creat_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_part_creat_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_part_creat_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_part_creat;

  NASD_SEC_POLICY_PART_CREAT(in_sec_param, in_capability, in_args,
                             out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_part_creat;

  out_res.nasd_status = nasd_od_create_partition(
    (int)in_args.in_partnum, (nasd_blkcnt_t)in_args.in_blkcnt,
    in_args.in_min_protection, in_args.in_partition_key,
    in_args.in_red_key, in_args.in_black_key, &nid);

 done_part_creat:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_part_creat_dr_res_otw_t),
                out_digest_otw,
                nasd_p_part_creat_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_part_creat_res(out_res_otw, trace_seq);
  DORETURN(part_creat);
}

nasd_srpc_status_t
nasd_p_create_otw_dr_server(
  nasd_srpc_listener_t         *listener,
  nasd_srpc_conn_t             *conn,
  nasd_srpc_server_call_t      *call,
  nasd_security_param_otw_t     in_sec_param_otw,
  nasd_capability_otw_t         in_capability_otw,
  nasd_digest_nonce_otw_t       in_digest_otw,
  nasd_p_create_dr_args_otw_t   in_args_otw,
  nasd_p_create_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t       out_digest_otw)
{
  nasd_drive_opholder_t *cr_opholder;
  nasd_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(create);
  nasd_dt_create_args(in_args_otw, &trace_seq);

  NASD_DRIVE_GET_OPHOLDER(cr_opholder);
  if (cr_opholder == NULL) {
    /* we don't care about the status of nasd_unpack_args here; all we
       really want is the security information so we can send a
       properly-encrypted/digested NASD_NO_MEM.  if there's an error,
       the client is screwed (and, really, so are we).  oh well. */
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_create_dr_args_otw_t),
                     &in_sec_param, &in_capability,
                     &nasd_drive_fail_opholder.opholder_create.in_args,
                     nasd_p_create_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
    goto done_create;
  }

  out_res.nasd_status =
    cr_opholder->opholder_create.out_res.nasd_status
    = nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                       in_args_otw, sizeof(nasd_p_create_dr_args_otw_t),
                       &in_sec_param, &in_capability,
                       &cr_opholder->opholder_create.in_args,
                       nasd_p_create_dr_args_t_unmarshall,
                       icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_create;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_CREATE(in_sec_param, in_capability,
                         cr_opholder->opholder_create.in_args,
                         out_res.nasd_status);
  if(out_res.nasd_status) {
    cr_opholder->opholder_create.out_res.nasd_status = out_res.nasd_status;
    goto done_create;
  }

  out_res.nasd_status = 
    cr_opholder->opholder_create.out_res.nasd_status
    = nasd_obj_create(
            (int)cr_opholder->opholder_create.in_args.in_partnum,
            &cr_opholder->opholder_create.in_args.in_attribute,
            cr_opholder->opholder_create.in_args.in_fieldmask,
            &cr_opholder->opholder_create.out_res.out_identifier,
            &cr_opholder->opholder_create.out_res.out_attribute, 0);

done_create:
  if (cr_opholder) {
    nasd_pack_res(&in_sec_param, &cr_opholder->opholder_create.out_res,
                  out_res_otw,
                  sizeof(nasd_p_create_dr_res_otw_t),
                  out_digest_otw,
                  nasd_p_create_dr_res_t_marshall, icv, op_key,
                  integrity_key, privacy_key, NULL);
  }
  else {
    nasd_pack_res(&in_sec_param,
                  &nasd_drive_fail_opholder.opholder_create.out_res,
                  out_res_otw,
                  sizeof(nasd_p_create_dr_res_otw_t), out_digest_otw,
                  nasd_p_create_dr_res_t_marshall, icv, op_key,
                  integrity_key, privacy_key, NULL);
  }

  if (cr_opholder) {
    NASD_DRIVE_FREE_OPHOLDER(cr_opholder);
  }

  nasd_dt_create_res(out_res_otw, trace_seq);
  DORETURN(create);
}

nasd_srpc_status_t
nasd_p_getattr_otw_dr_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_security_param_otw_t      in_sec_param_otw,
  nasd_capability_otw_t          in_capability_otw,
  nasd_digest_nonce_otw_t        in_digest_otw,
  nasd_p_getattr_dr_args_otw_t   in_args_otw,
  nasd_p_getattr_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t        out_digest_otw)
{
  nasd_p_getattr_dr_args_t in_args;
  nasd_p_getattr_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(getattr);
  nasd_dt_getattr_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_getattr_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_getattr_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_getattr;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_GETATTR(in_sec_param, in_capability, in_args,
                          out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_getattr;

  out_res.nasd_status = nasd_obj_getattr((int)in_args.in_partnum,
                                         in_args.in_identifier,
                                         &out_res.out_attribute);

 done_getattr:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_getattr_dr_res_otw_t),
                out_digest_otw,
                nasd_p_getattr_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_getattr_res(out_res_otw, trace_seq);
  DORETURN(getattr);
}

/*
 * Read single byterange in object - internal
 * function (does read and read2, which are only
 * different for stats-gathering).
 */
void
nasd_sp_read_generic_otw_dr_internal(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_security_param_otw_t      in_sec_param_otw,
  nasd_capability_otw_t          in_capability_otw,
  nasd_digest_nonce_otw_t        in_digest_otw,
  nasd_p_smpl_op_dr_args_otw_t   in_args_otw,
  nasd_p_fastread_dr_res_otw_t   out_res_otw,
  nasd_digest_nonce_otw_t        out_digest_otw,
  nasd_uint64                   *in_bms_targp,
  int                            is_read2,
  int                            is_remote,
  nasd_srpc_server_pipestate_t  *byte_pipe,
  nasd_od_rpc_basic_t           *out_res_basic_p)
{
  nasd_security_context_t security_context;
  nasd_procpipe_t procpipe;
  nasd_net_pipe_state_t pipe_state;
  nasd_p_fastread_dr_res_t out_res;
  nasd_p_smpl_op_dr_args_t in_args;
  nasd_len_t out_len;
  NASD_SRPC_SEC_OP_DECL;

  NASD_ASSERT(!(is_read2&&is_remote));
    
  bzero(&security_context, sizeof(security_context));    

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_smpl_op_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_smpl_op_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key,
                     &security_context);
  if(out_res.nasd_status)
    goto done_smpl_op;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_READ_SIMPLE(in_sec_param, in_capability, in_args,
                             out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_smpl_op;

  security_context.cur_off = in_args.in_offset;
  security_context.remain = in_args.in_len;

  pipe_state.rpc_state = byte_pipe;
  pipe_state.push = nasd_srpc_server_pipe_push;
  pipe_state.pull = NULL;
  pipe_state.context = &security_context;
  procpipe.state = &pipe_state;
  procpipe.push = nasd_pipe_push;
  procpipe.pull = NULL;

  if (!is_remote) {
    out_res.nasd_status = nasd_obj_read_simple(in_args.in_partnum,
                                               in_args.in_identifier,
                                               in_args.in_offset,
                                               in_args.in_len, NULL,
                                               is_read2,0, &procpipe,
                                               &out_len,
                                               &security_context);
  } else {
    out_res.nasd_status = nasd_obj_remote_invoke(in_args.in_partnum,
                                                 in_args.in_identifier,
                                                 in_args.in_offset,
                                                 in_args.in_len, 
                                                 &procpipe,
                                                 &out_len,
                                                 &security_context);
  }
  NASD_ASSERT(in_args.in_len >= out_len); /* XXX need this always be true for all active/remote stuff? */
  out_res.out_datalen = out_len;
  /*
   * This most likely means we failed shipping data on the pipe inside
   * nasd_obj_read_simple(). Trying to fix things up for the client
   * at this point will most likely lead to more hosage. Screw the client.
   */
done_smpl_op:
  if (out_res.nasd_status != NASD_RPC_TRAP) {
    nasd_srpc_server_pipe_push(byte_pipe, (nasd_byte_t *)nasd_odc_zeroblk, 0);
  }

  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_fastread_dr_res_otw_t),
                out_digest_otw,
                nasd_p_fastread_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, &security_context);
  out_res_basic_p->nasd_status = out_res.nasd_status;

  return;
}

nasd_srpc_status_t
nasd_p_read_simple_otw_dr_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_security_param_otw_t      in_sec_param_otw,
  nasd_capability_otw_t          in_capability_otw,
  nasd_digest_nonce_otw_t        in_digest_otw,
  nasd_p_smpl_op_dr_args_otw_t   in_args_otw,
  nasd_p_fastread_dr_res_otw_t   out_res_otw,
  nasd_digest_nonce_otw_t        out_digest_otw,
  nasd_srpc_server_pipestate_t  *byte_pipe)
{
  nasd_od_rpc_basic_t out_res;
  NASD_SRPC_NOSEC_OP_DECL

  DOBEGIN(read_simple);
  nasd_dt_read_simple_args(in_args_otw, &trace_seq);
  nasd_sp_read_generic_otw_dr_internal(listener, conn, call,
    in_sec_param_otw, in_capability_otw, in_digest_otw,
    in_args_otw, out_res_otw, out_digest_otw, NULL, 0, 0, byte_pipe, &out_res);
  nasd_dt_read_simple_res(out_res_otw, trace_seq);
  DORETURN(read_simple);
}

nasd_srpc_status_t
nasd_p_read2_simple_otw_dr_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_security_param_otw_t      in_sec_param_otw,
  nasd_capability_otw_t          in_capability_otw,
  nasd_digest_nonce_otw_t        in_digest_otw,
  nasd_p_smpl_op_dr_args_otw_t   in_args_otw,
  nasd_p_fastread_dr_res_otw_t   out_res_otw,
  nasd_digest_nonce_otw_t        out_digest_otw,
  nasd_srpc_server_pipestate_t  *byte_pipe)
{
  nasd_od_rpc_basic_t out_res;
  NASD_SRPC_NOSEC_OP_DECL

  DOBEGIN(read2_simple);
  nasd_dt_read2_simple_args(in_args_otw, &trace_seq);
  nasd_sp_read_generic_otw_dr_internal(listener, conn, call,
    in_sec_param_otw, in_capability_otw, in_digest_otw,
    in_args_otw, out_res_otw, out_digest_otw, NULL, 1, 0, byte_pipe, &out_res);
  nasd_dt_read2_simple_res(out_res_otw, trace_seq);
  DORETURN(read2_simple);
}

nasd_srpc_status_t
nasd_p_tread_simple_otw_dr_server(
  nasd_srpc_listener_t           *listener,
  nasd_srpc_conn_t               *conn,
  nasd_srpc_server_call_t        *call,
  nasd_security_param_otw_t       in_sec_param_otw,
  nasd_capability_otw_t           in_capability_otw,
  nasd_digest_nonce_otw_t         in_digest_otw,
  nasd_p_thrtl_op_dr_args_otw_t   in_args_otw,
  nasd_p_fastread_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t         out_digest_otw,
  nasd_srpc_server_pipestate_t   *byte_pipe)
{
  nasd_security_context_t security_context;
  nasd_procpipe_t procpipe;
  nasd_net_pipe_state_t pipe_state;
  nasd_p_thrtl_op_dr_args_t in_args;
  nasd_p_fastread_dr_res_t out_res;
  nasd_len_t out_len;
  NASD_SRPC_OP_DECL

  DOBEGIN(tread_simple);
  nasd_dt_tread_simple_args(in_args_otw, &trace_seq);

  bzero(&security_context, sizeof(security_context));    

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_thrtl_op_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_thrtl_op_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key,
                     &security_context);
  if(out_res.nasd_status)
    goto done_thrtl_op;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_READ_SIMPLE(in_sec_param, in_capability, in_args,
                             out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_thrtl_op;

  security_context.cur_off = in_args.in_offset;
  security_context.remain = in_args.in_len;

  pipe_state.rpc_state = byte_pipe;
  pipe_state.push = nasd_srpc_server_pipe_push;
  pipe_state.pull = NULL;
  pipe_state.context = &security_context;
  procpipe.state = &pipe_state;
  procpipe.push = nasd_pipe_push;
  procpipe.pull = NULL;

  out_res.nasd_status = nasd_obj_read_simple(in_args.in_partnum,
                                             in_args.in_identifier,
                                             in_args.in_offset,
                                             in_args.in_len,
                                             &in_args.in_bms_targ,
                                             0, 0,&procpipe, &out_len,
                                             &security_context);
  NASD_ASSERT(in_args.in_len >= out_len);
  out_res.out_datalen = out_len;

  /*
   * This most likely means we failed shipping data on the pipe inside
   * nasd_obj_read_simple(). Trying to fix things up for the client
   * at this point will most likely lead to more hosage. Screw the client.
   */
  if (out_res.nasd_status != NASD_RPC_TRAP) {
    nasd_srpc_server_pipe_push(byte_pipe, (nasd_byte_t *)nasd_odc_zeroblk, 0);
  }

 done_thrtl_op:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_fastread_dr_res_otw_t),
                out_digest_otw,
                nasd_p_fastread_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, &security_context);

  nasd_dt_tread_simple_res(out_res_otw, trace_seq);
  DORETURN(tread_simple);
}

nasd_srpc_status_t
nasd_p_write_simple_otw_dr_server(
  nasd_srpc_listener_t           *listener,
  nasd_srpc_conn_t               *conn,
  nasd_srpc_server_call_t        *call,
  nasd_security_param_otw_t       in_sec_param_otw,
  nasd_capability_otw_t           in_capability_otw,
  nasd_digest_nonce_otw_t         in_digest_otw,
  nasd_p_smpl_op_dr_args_otw_t    in_args_otw,
  nasd_p_fastwrite_dr_res_otw_t   out_res_otw,
  nasd_digest_nonce_otw_t         out_digest_otw,
  nasd_srpc_server_pipestate_t   *byte_pipe)
{
  nasd_security_context_t security_context;
  nasd_procpipe_t procpipe;
  nasd_net_pipe_state_t pipe_state;
  nasd_p_fastwrite_dr_res_t out_res;
  nasd_p_smpl_op_dr_args_t in_args;
  nasd_status_t rc;
  nasd_len_t tcount;
  NASD_SRPC_OP_DECL

  DOBEGIN(write_simple);
  nasd_dt_write_simple_args(in_args_otw, &trace_seq);

  bzero(&security_context, sizeof(nasd_security_context_t));

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_smpl_op_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_smpl_op_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key,
                     &security_context);
  if(out_res.nasd_status)
    goto done_write_simple;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_WRITE_SIMPLE(in_sec_param, in_capability, in_args,
                               out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_write_simple;

  security_context.cur_off = in_args.in_offset;
  security_context.remain = in_args.in_len;
  security_context.last_commit_off = in_args.in_offset;

  out_res.out_datalen = 0;
  pipe_state.rpc_state = byte_pipe;
  pipe_state.push = NULL;
  pipe_state.pull = nasd_srpc_server_pipe_pull;
  pipe_state.context = &security_context;
  procpipe.state = &pipe_state;
  procpipe.push = NULL;
  procpipe.pull = nasd_pipe_pull;
  rc = nasd_obj_write_simple(in_args.in_partnum, in_args.in_identifier,
                             in_args.in_offset, in_args.in_len, &procpipe,
                             &security_context, &out_res.out_datalen);
  out_res.nasd_status = rc;
  NASD_ASSERT(in_args.in_len >= out_res.out_datalen);

 done_write_simple:
  /* terminate the pipe */
  rc = nasd_srpc_server_pipe_pull(byte_pipe,
                                   (nasd_byte_t *)nasd_odc_bitbucket,
                                   0, &tcount);
  if (rc) {
    if (out_res.nasd_status == NASD_SUCCESS) {
      out_res.nasd_status = NASD_RPC_TRAP;
    }
  }

  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_fastwrite_dr_res_otw_t),
                out_digest_otw,
                nasd_p_fastwrite_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, &security_context);

  nasd_dt_write_simple_res(out_res_otw, trace_seq);
  DORETURN(write_simple);
}

nasd_srpc_status_t
nasd_p_setattr_otw_dr_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_security_param_otw_t      in_sec_param_otw,
  nasd_capability_otw_t          in_capability_otw,
  nasd_digest_nonce_otw_t        in_digest_otw,
  nasd_p_setattr_dr_args_otw_t   in_args_otw,
  nasd_p_setattr_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t        out_digest_otw)
{
  nasd_p_setattr_dr_args_t in_args;
  nasd_p_setattr_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(setattr);
  nasd_dt_setattr_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_setattr_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_setattr_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_setattr;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_SETATTR(in_sec_param, in_capability, in_args,
                          out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_setattr;

  out_res.nasd_status = nasd_obj_setattr((int)in_args.in_partnum,
                                         in_args.in_identifier,
                                         &in_args.in_attribute,
                                         in_args.in_fieldmask,
                                         &out_res.out_attribute);

 done_setattr:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_setattr_dr_res_otw_t),
                out_digest_otw,
                nasd_p_setattr_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_setattr_res(out_res_otw, trace_seq);
  DORETURN(setattr);
}

nasd_srpc_status_t
nasd_p_flush_obj_otw_dr_server(
  nasd_srpc_listener_t            *listener,
  nasd_srpc_conn_t                *conn,
  nasd_srpc_server_call_t         *call,
  nasd_security_param_otw_t        in_sec_param_otw,
  nasd_capability_otw_t            in_capability_otw,
  nasd_digest_nonce_otw_t          in_digest_otw,
  nasd_p_flush_obj_dr_args_otw_t   in_args_otw,
  nasd_p_flush_obj_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t          out_digest_otw)
{
  nasd_p_flush_obj_dr_args_t in_args;
  nasd_p_flush_obj_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(flush_obj);
  nasd_dt_flush_obj_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_flush_obj_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_flush_obj_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_flush_obj;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_FLUSH_OBJ(in_sec_param, in_capability, in_args,
                            out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_flush_obj;

  out_res.nasd_status = nasd_obj_flush((int)in_args.in_partnum,
                                       in_args.in_identifier);

 done_flush_obj:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_flush_obj_dr_res_otw_t),
                out_digest_otw,
                nasd_p_flush_obj_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_flush_obj_res(out_res_otw, trace_seq);
  DORETURN(flush_obj);
}

nasd_srpc_status_t
nasd_p_remove_otw_dr_server(
  nasd_srpc_listener_t         *listener,
  nasd_srpc_conn_t             *conn,
  nasd_srpc_server_call_t      *call,
  nasd_security_param_otw_t     in_sec_param_otw,
  nasd_capability_otw_t         in_capability_otw,
  nasd_digest_nonce_otw_t       in_digest_otw,
  nasd_p_remove_dr_args_otw_t   in_args_otw,
  nasd_p_remove_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t       out_digest_otw)
{
  nasd_p_remove_dr_args_t in_args;
  nasd_p_remove_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(remove);
  nasd_dt_remove_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_remove_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_remove_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_remove;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_REMOVE(in_sec_param, in_capability, in_args,
                         out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_remove;

  out_res.nasd_status = nasd_obj_remove((int)in_args.in_partnum,
                                        in_args.in_identifier);

 done_remove:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_remove_dr_res_otw_t),
                out_digest_otw,
                nasd_p_remove_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_remove_res(out_res_otw, trace_seq);
  DORETURN(remove);
}

nasd_srpc_status_t
nasd_p_initialize_otw_dr_server(
  nasd_srpc_listener_t             *listener,
  nasd_srpc_conn_t                 *conn,
  nasd_srpc_server_call_t          *call,
  nasd_p_initialize_dr_args_otw_t   in_args_otw,
  nasd_p_initialize_dr_res_otw_t    out_res_otw)
{
  nasd_p_initialize_dr_args_t in_args;
  nasd_p_initialize_dr_res_t out_res;
  NASD_OD_RPC_OP_STATS_DECL

  DOBEGIN(initialize);

  /* INITIALIZE is special; it cannot be encrypted/digested because
     it's used to set the keys that the security scheme is based on.
     There is also no security policy check, because the caller
     is assumed to be trusted. */

  nasd_p_initialize_dr_args_t_unmarshall(in_args_otw, &in_args);

  out_res.nasd_status = nasd_sec_initialize_drive(
    in_args.in_master_key, in_args.in_drive_key);

  nasd_p_initialize_dr_res_t_marshall(&out_res, out_res_otw);

  DORETURN(initialize);
}

nasd_srpc_status_t
nasd_p_change_key_otw_dr_server(
  nasd_srpc_listener_t             *listener,
  nasd_srpc_conn_t                 *conn,
  nasd_srpc_server_call_t          *call,
  nasd_security_param_otw_t         in_sec_param_otw,
  nasd_capability_otw_t             in_capability_otw,
  nasd_digest_nonce_otw_t           in_digest_otw,
  nasd_p_change_key_dr_args_otw_t   in_args_otw,
  nasd_p_change_key_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t           out_digest_otw)
{
  nasd_p_change_key_dr_args_t in_args;
  nasd_p_change_key_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(change_key);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_change_key_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_change_key_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_change_key;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_CHANGE_KEY(in_sec_param, in_capability, in_args,
                             out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_change_key;

  out_res.nasd_status = nasd_sec_setkey(in_args.in_partnum,
                                        in_args.in_type,
                                        in_args.in_new_key);

 done_change_key:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_change_key_dr_res_otw_t),
                out_digest_otw,
                nasd_p_change_key_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  DORETURN(change_key);
}

nasd_srpc_status_t
nasd_p_eject_obj_otw_dr_server(
  nasd_srpc_listener_t            *listener,
  nasd_srpc_conn_t                *conn,
  nasd_srpc_server_call_t         *call,
  nasd_security_param_otw_t        in_sec_param_otw,
  nasd_capability_otw_t            in_capability_otw,
  nasd_digest_nonce_otw_t          in_digest_otw,
  nasd_p_eject_obj_dr_args_otw_t   in_args_otw,
  nasd_p_eject_obj_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t          out_digest_otw)
{
  nasd_p_eject_obj_dr_args_t in_args;
  nasd_p_eject_obj_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(eject_obj);
  nasd_dt_eject_obj_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_eject_obj_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_eject_obj_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_eject_obj;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_EJECT_OBJ(in_sec_param, in_capability, in_args,
                            out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_eject_obj;

  out_res.nasd_status = nasd_obj_eject((int)in_args.in_partnum,
                                       in_args.in_identifier);

 done_eject_obj:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_eject_obj_dr_res_otw_t),
                out_digest_otw,
                nasd_p_eject_obj_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_eject_obj_res(out_res_otw, trace_seq);
  DORETURN(eject_obj);
}

nasd_srpc_status_t
nasd_p_strt_iread_otw_dr_server(
  nasd_srpc_listener_t             *listener,
  nasd_srpc_conn_t                 *conn,
  nasd_srpc_server_call_t          *call,
  nasd_security_param_otw_t         in_sec_param_otw,
  nasd_capability_otw_t             in_capability_otw,
  nasd_digest_nonce_otw_t           in_digest_otw,
  nasd_p_strt_iread_dr_args_otw_t   in_args_otw,
  nasd_p_strt_iread_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t           out_digest_otw)
{
  nasd_p_strt_iread_dr_args_t in_args;
  nasd_p_strt_iread_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(strt_iread);
  nasd_dt_strt_iread_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_strt_iread_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_strt_iread_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_strt_iread;

#ifdef KERNEL
  out_res.nasd_status = NASD_OP_NOT_SUPPORTED;
#else /* KERNEL */

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_STRT_IREAD(in_sec_param, in_capability, in_args,
                             out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_strt_iread;

  out_res.nasd_status = nasd_obj_start_iread(in_args.in_partnum,
                                             in_args.in_index_identifier,
                                             in_args.in_data_identifier,
                                             in_args.in_interval,
                                             in_args.in_offset,
                                             in_args.in_flownum,
                                             in_args.in_earliest_start,
                                             in_args.in_latest_start,
                                             in_args.in_client_addr,
                                             &out_res.out_stream_id);
#endif /* KERNEL */

 done_strt_iread:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_strt_iread_dr_res_otw_t),
                out_digest_otw,
                nasd_p_strt_iread_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_strt_iread_res(out_res_otw, trace_seq);
  DORETURN(strt_iread);
}

nasd_srpc_status_t
nasd_p_stop_iread_otw_dr_server(
  nasd_srpc_listener_t             *listener,
  nasd_srpc_conn_t                 *conn,
  nasd_srpc_server_call_t          *call,
  nasd_security_param_otw_t         in_sec_param_otw,
  nasd_capability_otw_t             in_capability_otw,
  nasd_digest_nonce_otw_t           in_digest_otw,
  nasd_p_stop_iread_dr_args_otw_t   in_args_otw,
  nasd_p_stop_iread_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t           out_digest_otw)
{
  nasd_p_stop_iread_dr_args_t in_args;
  nasd_p_stop_iread_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(stop_iread);
  nasd_dt_stop_iread_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_stop_iread_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_stop_iread_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_stop_iread;

#ifdef KERNEL
  out_res.nasd_status = NASD_OP_NOT_SUPPORTED;
#else /* KERNEL */
  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_STOP_IREAD(in_sec_param, in_capability, in_args,
                             out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_stop_iread;

 out_res.nasd_status = nasd_obj_stop_iread(in_args.in_stream_id);
#endif /* KERNEL */

 done_stop_iread:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_stop_iread_dr_res_otw_t),
                out_digest_otw,
                nasd_p_stop_iread_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_stop_iread_res(out_res_otw, trace_seq);
  DORETURN(stop_iread);
}

nasd_srpc_status_t
nasd_p_rshutdown_otw_dr_server(
  nasd_srpc_listener_t            *listener,
  nasd_srpc_conn_t                *conn,
  nasd_srpc_server_call_t         *call,
  nasd_security_param_otw_t        in_sec_param_otw,
  nasd_capability_otw_t            in_capability_otw,
  nasd_digest_nonce_otw_t          in_digest_otw,
  nasd_p_rshutdown_dr_args_otw_t   in_args_otw,
  nasd_p_rshutdown_dr_res_otw_t    out_res_otw,
  nasd_digest_nonce_otw_t          out_digest_otw)
{
  nasd_p_rshutdown_dr_args_t in_args;
  nasd_p_rshutdown_dr_res_t out_res;
  NASD_SRPC_OP_DECL

  DOBEGIN(rshutdown);
  nasd_dt_rshutdown_args(in_args_otw, &trace_seq);

  out_res.nasd_status =
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_rshutdown_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_rshutdown_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if(out_res.nasd_status)
    goto done_rshutdown;

  out_res.nasd_status = NASD_SUCCESS;
  NASD_SEC_POLICY_RSHUTDOWN(in_sec_param, in_capability, in_args,
                            out_res.nasd_status);
  if(out_res.nasd_status)
    goto done_rshutdown;

  out_res.nasd_status = nasd_drive_rshutdown(in_args.in_flags);

 done_rshutdown:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_rshutdown_dr_res_otw_t),
                out_digest_otw,
                nasd_p_rshutdown_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);

  nasd_dt_rshutdown_res(out_res_otw, trace_seq);
  DORETURN(rshutdown);
}

nasd_srpc_status_t
nasd_p_getinfo_otw_dr_server(
  nasd_srpc_listener_t            *listener,
  nasd_srpc_conn_t                *conn,
  nasd_srpc_server_call_t         *call,
  nasd_p_getinfo_dr_res_otw_t      out_res_otw)
{
  nasd_p_getinfo_dr_res_t out_res;
  NASD_OD_RPC_OP_STATS_DECL

  DOBEGIN(getinfo);

  /*
   * GETINFO is special; we do no security on this because it is
   * used to retrieve the drive's current time so clients can
   * synchronize their nonces to it. Any information that should
   * be protected belongs in a control object, not here.
   */

  out_res.nasd_status = nasd_drive_getinfo(&out_res.info);

  nasd_p_getinfo_dr_res_t_marshall(&out_res, out_res_otw);

  DORETURN(getinfo);
}



nasd_srpc_status_t
nasd_p_remote_attach_otw_dr_server(
  nasd_srpc_listener_t     *listener,
  nasd_srpc_conn_t         *conn,
  nasd_srpc_server_call_t  *call,
  nasd_security_param_otw_t in_sec_param_otw,
  nasd_capability_otw_t in_capability_otw,
  nasd_digest_nonce_otw_t in_digest_otw,
  nasd_p_remote_attach_dr_args_otw_t in_args_otw,
  nasd_p_remote_attach_dr_res_otw_t out_res_otw,
  nasd_digest_nonce_otw_t          out_digest_otw,
  nasd_srpc_server_pipestate_t *byte_pipe
  )
{
  nasd_security_context_t security_context;
  nasd_procpipe_t procpipe;
  nasd_net_pipe_state_t pipe_state;
  nasd_p_remote_attach_dr_args_t in_args;
  nasd_p_remote_attach_dr_res_t out_res;
  nasd_status_t rc;
  nasd_len_t tcount;
  NASD_SRPC_OP_DECL

  DOBEGIN(remote_attach);
  bzero(&security_context, sizeof(security_context));    

  nasd_dt_remote_attach_args(in_args_otw,&trace_seq);

  out_res.nasd_status = 
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_remote_attach_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_remote_attach_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, &security_context);

  if(out_res.nasd_status)
    goto done_remote_attach;

  /* XXX NOTE: a production NASD drive server would perform a security check here */
  out_res.nasd_status = NASD_SUCCESS;

  /* XXX If this smells rotten, it's 'cause it is.  This code not
     written with an in-depth understanding of its function */
  security_context.cur_off = 0;
  security_context.remain = in_args.in_args_len;
  security_context.last_commit_off = 0;
  
  pipe_state.rpc_state = byte_pipe;
  pipe_state.push = NULL;
  pipe_state.pull = nasd_srpc_server_pipe_pull;
  pipe_state.context = &security_context;
  procpipe.state = &pipe_state;
  procpipe.push = NULL;
  procpipe.pull = nasd_pipe_pull;
  rc = nasd_obj_remote_attach(in_args.in_partnum, in_args.in_identifier,
                              in_args.in_name,in_args.in_args_len,
                              &procpipe, &security_context);
  out_res.nasd_status = rc;
  
 done_remote_attach:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_remote_attach_dr_res_otw_t),
                out_digest_otw,
                nasd_p_remote_attach_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, &security_context);
  nasd_dt_remote_attach_res(out_res_otw,trace_seq);
  DORETURN(remote_attach);
}


nasd_srpc_status_t
nasd_p_remote_detach_otw_dr_server(
  nasd_srpc_listener_t                  *listener,
  nasd_srpc_conn_t                      *conn,
  nasd_srpc_server_call_t               *call,
  nasd_security_param_otw_t             in_sec_param_otw,
  nasd_capability_otw_t                 in_capability_otw,
  nasd_digest_nonce_otw_t               in_digest_otw,
  nasd_p_remote_detach_dr_args_otw_t    in_args_otw,
  nasd_res_otw_t                        out_res_otw,
  nasd_digest_nonce_otw_t               out_digest_otw)
{
  nasd_p_remote_attach_dr_args_t        in_args;
  nasd_p_remote_attach_dr_res_t         out_res;

  NASD_SRPC_OP_DECL;
  DOBEGIN(remote_detach);
  nasd_dt_remote_detach_args(in_args_otw,trace_seq);
  
  out_res.nasd_status = 
    nasd_unpack_args(in_sec_param_otw, in_capability_otw, in_digest_otw,
                     in_args_otw, sizeof(nasd_p_getattr_dr_args_otw_t),
                     &in_sec_param, &in_capability, &in_args,
                     nasd_p_remote_attach_dr_args_t_unmarshall,
                     icv, op_key, integrity_key, privacy_key, NULL);
  if (out_res.nasd_status) 
    goto done_remote_detach;
  
  /*  XXX no security checks*/
  out_res.nasd_status = nasd_obj_remote_detach((int)in_args.in_partnum,
                                 in_args.in_identifier);

 done_remote_detach:
  nasd_pack_res(&in_sec_param, &out_res, out_res_otw,
                sizeof(nasd_p_getattr_dr_res_otw_t),
                out_digest_otw,
                nasd_p_remote_attach_dr_res_t_marshall,
                icv, op_key, integrity_key, privacy_key, NULL);
  nasd_dt_remote_detach_res(out_res_otw,trace_seq);
  DORETURN(remote_detach);
}  

nasd_srpc_status_t
nasd_p_remote_invoke_otw_dr_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_security_param_otw_t     in_sec_param_otw,
  nasd_capability_otw_t         in_capability_otw,
  nasd_digest_nonce_otw_t       in_digest_otw,
  nasd_p_smpl_op_dr_args_otw_t  in_args_otw,
  nasd_p_fastread_dr_res_otw_t  out_res_otw,
  nasd_digest_nonce_otw_t       out_digest_otw,
  nasd_srpc_server_pipestate_t  *byte_pipe)
{
  nasd_od_rpc_basic_t out_res;
  NASD_SRPC_NOSEC_OP_DECL
  DOBEGIN(remote_invoke);
  nasd_dt_remote_invoke_args(in_args_otw, &trace_seq);
  nasd_sp_read_generic_otw_dr_internal(listener, conn, call,
                                       in_sec_param_otw, in_capability_otw, in_digest_otw,
                                       in_args_otw, out_res_otw, out_digest_otw, NULL, 0, 1, byte_pipe, &out_res);
  nasd_dt_remote_invoke_res(out_res_otw, trace_seq);
  DORETURN(remote_invoke);
}

/*
 * RPC mechanism
 */

nasd_srpc_listener_t *nasd_drive_listener;
int nasd_drive_srpc_started = 0;
nasd_threadgroup_t nasd_drive_listening_group;

void
nasd_od_srpc_kill_listener_group(
  void  *ignored)
{
  nasd_status_t rc;

  rc = nasd_destroy_threadgroup(&nasd_drive_listening_group);
  if (rc) {
    nasd_printf("WARNING: got 0x%x (%s) destroying drive_listening_group\n",
      rc, nasd_error_string(rc));
  }
}

nasd_status_t
nasd_drive_rpc_specific_init()
{
  nasd_status_t rc;

  rc = nasd_init_threadgroup(&nasd_drive_listening_group);
  if (rc)
    return(rc);
  rc = nasd_shutdown_proc(nasd_odc_shutdown,
    nasd_od_srpc_kill_listener_group, NULL);
  if (rc) {
    nasd_od_srpc_kill_listener_group(NULL);
    return(rc);
  }

  bzero((char *)&nasd_drive_fail_opholder, sizeof(nasd_drive_fail_opholder));
  nasd_drive_fail_opholder.opholder_create.out_res.nasd_status = NASD_NO_MEM;

  nasd_drive_listener = NULL;
  rc = nasd_srpc_init();

  if (rc == NASD_SUCCESS) {
    nasd_drive_srpc_started = 1;
  }

  return(rc);
}

nasd_status_t
nasd_drive_rpc_specific_startup()
{
  return(NASD_SUCCESS);
}

void
nasd_drive_rpc_specific_stop()
{
  nasd_status_t rc;

  if (nasd_drive_listener) {
    rc = nasd_srpc_listener_destroy(nasd_drive_listener);
    if (rc) {
      nasd_printf("DRIVE ERROR: got 0x%x (%s) from nasd_srpc_listener_destroy()\n",
        rc, nasd_error_string(rc));
    }
    nasd_drive_listener = NULL;
  }

  if (nasd_drive_srpc_started) {
    /* Go go gadget linux */
    NASD_THREADGROUP_WAIT_START(&nasd_drive_listening_group);
    NASD_THREADGROUP_WAIT_STOP(&nasd_drive_listening_group);
    nasd_drive_srpc_started = 0;
    nasd_srpc_shutdown();
  }

}

nasd_status_t
nasd_drive_rpc_specific_listen(
  int          service_threads,
  nasd_uint16  ipport)
{
  nasd_status_t rc;

  rc = nasd_srpc_listener_start(&nasd_drive_listener, service_threads, ipport,
    nasd_pdrive_demux);
  if (rc)
    return(rc);

  /*
   * Subtle race condition: if we shut down asynchronously between the start
   * and this wait, we lose the memory. If this seems like a problem, we
   * could resolve it by having _start() hand the serial number to us,
   * and waiting only on the serial number.
   */

  NASD_THREADGROUP_STARTED(&nasd_drive_listening_group);
  NASD_THREADGROUP_RUNNING(&nasd_drive_listening_group);

  rc = nasd_srpc_listener_wait(nasd_drive_listener);

  NASD_THREADGROUP_DONE(&nasd_drive_listening_group);

  return(rc);
}

nasd_status_t
nasd_drive_rpc_specific_set_stacksize(
  int  stacksize)
{
  return(NASD_OP_NOT_SUPPORTED);
}

#endif /* NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_SRPC */

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
