/*
 * nasd_pdrive_client_srpc.c
 *
 * SRPC wrappers for drive client
 *
 * Authors: Jim Zelenka, Marc Unangst, Howard Gobioff, David Rochberg
 */
/*
 * 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_threadstuff.h>
#include <nasd/nasd_shutdown.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_freelist.h>
#include <nasd/nasd_srpc_types.h>
#include <nasd/nasd_srpc.h>
#include <nasd/nasd_rpcgen_glob_param.h>
#include <nasd/nasd_marshall.h>
#include <nasd/nasd_pdrive_client.h>
#include <nasd/nasd_pdrive_client_srpc.h>
#include <nasd/nasd_pdrive_cstub.h>
#include <nasd/nasd_security.h>
#include <nasd/nasd_security_cl.h>

#define NASD_SRPC_SEC_OP_DECL \
        nasd_security_param_otw_t sec_param_otw; \
        nasd_capability_otw_t capability_otw; \
        nasd_digest_nonce_otw_t args_digest_otw; \
        nasd_digest_nonce_otw_t res_digest_otw; \
        nasd_iv_t icv; \
        nasd_status_t sec_rc;

#define NASD_SRPC_OP_DECL \
        NASD_SRPC_SEC_OP_DECL

void
nasd_cl_p_srpc_shutdown(
  void  *ignored)
{
  nasd_srpc_shutdown();
}

nasd_status_t
nasd_cl_srpc_init(
  nasd_shutdown_list_t  *sl)
{
  nasd_status_t rc;

  rc = nasd_srpc_init();
  if (rc)
    return(rc);
  rc = nasd_shutdown_proc(sl, nasd_cl_p_srpc_shutdown, NULL);
  if (rc) {
    nasd_cl_p_srpc_shutdown(NULL);
    return(rc);
  }

  rc = nasd_cl_pipe_init(sl);
  if (rc)
    return(rc);

  return(NASD_SUCCESS);
}

nasd_status_t
nasd_cl_srpc_bind(
  nasd_drive_handle_t   handle,
  char                 *drive_name,
  char                 *portnum,
  int                   binding_type,
  void                 *binding_param,
  int                   binding_param_len)
{
  nasd_drive_handle_srpc_t *rpch;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  rc = nasd_srpc_bind_to_server(drive_name, portnum, &rpch->h);

  if (rc)
    return(rc);

  return(NASD_SUCCESS);
}

nasd_status_t
nasd_cl_srpc_unbind(
  nasd_drive_handle_t  handle)
{
  nasd_drive_handle_srpc_t *rpch;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  rc = nasd_srpc_unbind_server(&rpch->h);
  if (rc)
    return(rc);

  return(NASD_SUCCESS);
}

void
nasd_cl_srpc_null_dr(
  nasd_drive_handle_t   handle,
  nasd_res_t           *res,
  nasd_rpc_status_t    *status)
{
  nasd_drive_handle_srpc_t *rpch;
  nasd_res_otw_t res_otw;
  nasd_srpc_status_t src;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  src = nasd_p_null_dr_client(rpch->h, res_otw);
  *status = src;
  if (src) {
    res->nasd_status = NASD_RPC_FAILURE;
  }
  else {
    nasd_res_t_unmarshall(res_otw, res);
  }
}

void
nasd_cl_srpc_sync_dr(
  nasd_drive_handle_t   handle,
  nasd_res_t           *res,
  nasd_rpc_status_t    *status)
{
  nasd_drive_handle_srpc_t *rpch;
  nasd_res_otw_t res_otw;
  nasd_srpc_status_t src;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  src = nasd_p_sync_dr_client(rpch->h, res_otw);
  *status = src;
  if (src) {
    res->nasd_status = NASD_RPC_FAILURE;
  }
  else {
    nasd_res_t_unmarshall(res_otw, res);
  }
}

void
nasd_cl_srpc_part_creat_dr(
  nasd_drive_handle_t           handle,
  nasd_key_t                    in_key,
  nasd_security_param_t        *sec_param,
  nasd_capability_t            *capability,
  nasd_p_part_creat_dr_args_t  *args,
  nasd_p_part_creat_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_p_part_creat_dr_args_otw_t args_otw;
  nasd_p_part_creat_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_part_creat_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_part_creat_otw_dr_client(rpch->h, sec_param_otw,
                                            capability_otw, args_digest_otw,
                                            args_otw, res_otw, res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_part_creat_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_create_dr__otw_provided(
  nasd_drive_handle_t       handle,
  nasd_key_t                in_key,
  nasd_security_param_t    *sec_param,
  nasd_capability_t        *capability,
  nasd_p_create_dr_args_t  *args,
  nasd_p_create_dr_res_t   *res,
  nasd_cl_p_otw_buf_t      *otw,
  nasd_rpc_status_t        *status)
{
  nasd_drive_handle_srpc_t *rpch;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 otw->sec_param_otw, otw->capability_otw,
                 otw->args_digest_otw, otw->args_otw,
                 sizeof(nasd_p_create_dr_args_otw_t),
                 nasd_p_create_dr_args_t_marshall,
                 otw->icv, in_key, NULL);

  *status = nasd_p_create_otw_dr_client(rpch->h, otw->sec_param_otw,
                                        otw->capability_otw,
                                        otw->args_digest_otw,
                                        otw->args_otw,
                                        otw->res_otw,
                                        otw->res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    otw->sec_rc = nasd_unpack_res(handle,
                                  sec_param, capability, otw->res_otw,
                                  sizeof(nasd_p_create_dr_res_otw_t),
                                  otw->res_digest_otw, res,
                                  nasd_p_create_dr_res_t_unmarshall,
                                  otw->icv, in_key, NULL);
    if(otw->sec_rc) {
      res->nasd_status = otw->sec_rc;
    }
  }
}

void
nasd_cl_srpc_getattr_dr(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  nasd_p_getattr_dr_args_t  *args,
  nasd_p_getattr_dr_res_t   *res,
  nasd_rpc_status_t         *status)
{
  nasd_p_getattr_dr_args_otw_t args_otw;
  nasd_p_getattr_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_getattr_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_getattr_otw_dr_client(rpch->h, sec_param_otw,
                                         capability_otw, args_digest_otw,
                                         args_otw, res_otw, res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_getattr_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_write_list_alloc(
  void          *state,
  nasd_uint32    bsize,
  nasd_byte_t  **bufp,
  nasd_uint32   *bcount)
{
  nasd_cl_fo_list_state_t *s;

  s = (nasd_cl_fo_list_state_t *)state;

  nasd_pipe_cb_write_alloc_list(s, bsize, bufp, bcount);
}

void
nasd_cl_srpc_write_list_pull(
  void          *state,
  void          *buf,
  nasd_uint32    in_count,
  nasd_uint32   *out_count)
{
  nasd_cl_fo_list_state_t *s;

  s = (nasd_cl_fo_list_state_t *)state;

  nasd_pipe_cb_write_pull_list(s, buf, in_count, out_count);
}

void
nasd_cl_srpc_range_write_dr(
  nasd_drive_handle_t         handle,
  nasd_key_t                  in_key,
  nasd_security_param_t      *sec_param,
  nasd_capability_t          *capability,
  nasd_p_smpl_op_dr_args_t   *args,
  nasd_mem_list_t            *memlist,
  nasd_p_fastwrite_dr_res_t  *res,
  nasd_rpc_status_t          *status)
{
  nasd_p_smpl_op_dr_args_otw_t args_otw;
  nasd_p_fastwrite_dr_res_otw_t res_otw;
  nasd_srpc_client_pull_func_t pull_func;
  void *pull_arg;
  nasd_drive_handle_srpc_t *rpch;
  nasd_cl_fo_list_state_t *statep;
  nasd_srpc_client_pullcb_t pipe;
  nasd_security_context_t *ctx;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;
  statep = NULL;

  if(sec_param->actual_protection != NASD_NO_PROTECTION) {
    /* all this craziness because we need to use a callback-based pipe,
       so we can calculate digests and encrypt data on the fly. */

    NASD_FREELIST_GET(nasd_cl_fo_list_state_freelist, statep, push_cur,
                      (nasd_cl_fo_list_state_t *));
    if (statep == NULL) {
      res->nasd_status = NASD_NO_MEM;
      *status = 0;
      return;
    }

    res->out_datalen = 0;
    statep->dce_bug = 0;
    statep->out_lenp = &res->out_datalen;
    statep->targetlen = args->in_len;
    statep->badstate = 0;
      statep->alloc_cur = statep->push_cur = memlist;
      statep->alloc_buf = statep->push_buf = memlist->addr;
      statep->alloc_len = statep->push_len = memlist->len;
    statep->alloc_elem = statep->push_elem = 0;
    statep->alloc_off = statep->push_off = 0;
    statep->alloc_adj = statep->push_adj = args->in_offset;
    statep->digest_alloc_cur = statep->digest_pull_cur = NULL;
    statep->alloc_digest = statep->pull_digest = 0;
    statep->next_alloc_digest_off = statep->next_pull_digest_off =
      ((args->in_offset/NASD_SEC_HMAC_BLOCKSIZE)+1) * NASD_SEC_HMAC_BLOCKSIZE;
    statep->status = NASD_SUCCESS;

    pipe.state = (void *)statep;
    pipe.alloc_cb = nasd_cl_srpc_write_list_alloc;
    pipe.pull_cb = nasd_cl_srpc_write_list_pull;

    pull_func = nasd_srpc_client_run_serverpull_cb;
    pull_arg = &pipe;

    ctx = &statep->context;
  } else {
    pull_func = nasd_srpc_client_run_serverpull;
    pull_arg = memlist;
    ctx = NULL;
  }

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_smpl_op_dr_args_t_marshall,
                 icv, in_key, ctx);

  *status = nasd_p_write_simple_otw_dr_client(rpch->h, sec_param_otw,
                                              capability_otw, args_digest_otw,
                                              args_otw, pull_func, pull_arg,
                                              res_otw, res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_fastwrite_dr_res_t_unmarshall,
                             icv, in_key, ctx);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }

  if(sec_param->actual_protection != NASD_NO_PROTECTION) {
    if(statep->status || statep->badstate) {
      res->nasd_status = NASD_MEM_LIST_ERR;
    }

    NASD_FREELIST_FREE(nasd_cl_fo_list_state_freelist, statep, push_cur);
  }
}

void
nasd_cl_srpc_read_list_alloc(
  void          *state,
  nasd_uint32    bsize,
  nasd_byte_t  **bufp,
  nasd_uint32   *bcount)
{
  nasd_cl_fo_list_state_t *s;

  s = (nasd_cl_fo_list_state_t *)state;

  nasd_pipe_cb_read_alloc_list(s, bsize, bufp, bcount);
}

void
nasd_cl_srpc_read_list_push(
  void          *state,
  void          *buf,
  nasd_uint32    in_count)
{
  nasd_cl_fo_list_state_t *s;

  s = (nasd_cl_fo_list_state_t *)state;

  nasd_pipe_cb_read_push_list(s, buf, in_count);
}

typedef nasd_srpc_status_t (* nasd_cl_srpc_range_read_fn_t) (
  nasd_srpc_handle_t   handle,
  nasd_security_param_otw_t in_sec_param,
  nasd_capability_otw_t in_capability,
  nasd_digest_nonce_otw_t in_digest,
  nasd_p_smpl_op_dr_args_otw_t in_args,
  nasd_srpc_client_push_func_t byte_pipe_proc,
  void *byte_pipe,
  int *byte_pipe_pushed,
  nasd_p_fastread_dr_res_otw_t out_res,
  nasd_digest_nonce_otw_t out_digest);


void
nasd_cl_srpc_range_read_generic_dr(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  nasd_cl_srpc_range_read_fn_t function, /* read,read2,invoke */
  nasd_p_smpl_op_dr_args_t  *args,
  nasd_mem_list_t           *memlist,
  nasd_p_fastread_dr_res_t  *res,
  nasd_rpc_status_t         *status)
{
  nasd_p_smpl_op_dr_args_otw_t args_otw;
  nasd_p_fastread_dr_res_otw_t res_otw;
  nasd_srpc_client_push_func_t push_func;
  void *push_arg;
  nasd_drive_handle_srpc_t *rpch;
  nasd_cl_fo_list_state_t *statep;
  nasd_srpc_client_pushcb_t pipe;
  nasd_len_t out_len;
  nasd_len_t pipe_out_len;
  nasd_security_context_t *ctx;
  NASD_SRPC_OP_DECL
  
  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;
  statep = NULL;

  if(sec_param->actual_protection != NASD_NO_PROTECTION) {
    /* all this craziness because we need to use a callback-based pipe,
       so we can calculate digests and encrypt data on the fly. */

    NASD_FREELIST_GET(nasd_cl_fo_list_state_freelist, statep, push_cur,
                      (nasd_cl_fo_list_state_t *));
    if (statep == NULL) {
      res->nasd_status = NASD_NO_MEM;
      *status = 0;
      return;
    }

    pipe_out_len = 0;
    res->out_datalen = 0;
    statep->dce_bug = 0;
    statep->out_lenp = &pipe_out_len;
    statep->targetlen = args->in_len;
    statep->badstate = 0;
    statep->alloc_buf = statep->push_buf = memlist->addr;
    statep->alloc_len = statep->push_len = memlist->len;
    statep->alloc_cur = statep->push_cur = memlist;
    statep->alloc_elem = statep->push_elem = 0;
    statep->alloc_off = statep->push_off = 0;
    statep->push_adj = args->in_offset;
    statep->status = NASD_SUCCESS;

    pipe.state = (void *)statep;
    pipe.alloc_cb = nasd_cl_srpc_read_list_alloc;
    pipe.push_cb = nasd_cl_srpc_read_list_push;

    push_func = nasd_srpc_client_run_serverpush_cb;
    push_arg = &pipe;

    ctx = &statep->context;
  } else {
    push_func = nasd_srpc_client_run_serverpush;
    push_arg = memlist;
    ctx = NULL;
  }

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_smpl_op_dr_args_t_marshall,
                 icv, in_key, ctx);

  *status = function(rpch->h, sec_param_otw,
                     capability_otw, args_digest_otw,
                     args_otw, push_func, push_arg,
                     &out_len, res_otw, res_digest_otw);
  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_fastread_dr_res_t_unmarshall,
                             icv, in_key, ctx);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }

  if(sec_param->actual_protection != NASD_NO_PROTECTION) {
    if(statep->status || statep->badstate) {
      if(statep->status)
        res->nasd_status = statep->status;
      else
        res->nasd_status = NASD_MEM_LIST_ERR;
    }

    NASD_FREELIST_FREE(nasd_cl_fo_list_state_freelist, statep, push_cur);
  }
}

void
nasd_cl_srpc_range_read_dr(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  int                        is_read2,
  nasd_p_smpl_op_dr_args_t  *args,
  nasd_mem_list_t           *memlist,
  nasd_p_fastread_dr_res_t  *res,
  nasd_rpc_status_t         *status)

{
  nasd_cl_srpc_range_read_fn_t f;
  if (is_read2) {
    f = nasd_p_read2_simple_otw_dr_client;
  } else {
    f = nasd_p_read_simple_otw_dr_client;
  }
  
  nasd_cl_srpc_range_read_generic_dr(handle,
                                     in_key,
                                     sec_param,
                                     capability,
                                     f,
                                     args,
                                     memlist,
                                     res,
                                     status);
}




void
nasd_cl_srpc_range_tread_dr(
  nasd_drive_handle_t         handle,
  nasd_key_t                  in_key,
  nasd_security_param_t      *sec_param,
  nasd_capability_t          *capability,
  int                         is_read2,
  nasd_p_thrtl_op_dr_args_t  *args,
  nasd_mem_list_t            *memlist,
  nasd_p_fastread_dr_res_t   *res,
  nasd_rpc_status_t          *status)
{
  nasd_p_thrtl_op_dr_args_otw_t args_otw;
  nasd_p_fastread_dr_res_otw_t res_otw;
  nasd_srpc_client_push_func_t push_func;
  void *push_arg;
  nasd_drive_handle_srpc_t *rpch;
  nasd_cl_fo_list_state_t *statep;
  nasd_srpc_client_pushcb_t pipe;
  nasd_len_t out_len;
  nasd_len_t pipe_out_len;
  nasd_security_context_t *ctx;
  NASD_SRPC_OP_DECL
  
  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;
  statep = NULL;

  if(sec_param->actual_protection != NASD_NO_PROTECTION) {
    /* all this craziness because we need to use a callback-based pipe,
       so we can calculate digests and encrypt data on the fly. */

    NASD_FREELIST_GET(nasd_cl_fo_list_state_freelist, statep, push_cur,
                      (nasd_cl_fo_list_state_t *));
    if (statep == NULL) {
      res->nasd_status = NASD_NO_MEM;
      *status = 0;
      return;
    }

    pipe_out_len = 0;
    res->out_datalen = 0;
    statep->dce_bug = 0;
    statep->out_lenp = &pipe_out_len;
    statep->targetlen = args->in_len;
    statep->badstate = 0;
    statep->alloc_buf = statep->push_buf = memlist->addr;
    statep->alloc_len = statep->push_len = memlist->len;
    statep->alloc_cur = statep->push_cur = memlist;
    statep->alloc_elem = statep->push_elem = 0;
    statep->alloc_off = statep->push_off = 0;
    statep->push_adj = args->in_offset;
    statep->status = NASD_SUCCESS;

    pipe.state = (void *)statep;
    pipe.alloc_cb = nasd_cl_srpc_read_list_alloc;
    pipe.push_cb = nasd_cl_srpc_read_list_push;

    push_func = nasd_srpc_client_run_serverpush_cb;
    push_arg = &pipe;

    ctx = &statep->context;
  } else {
    push_func = nasd_srpc_client_run_serverpush;
    push_arg = memlist;
    ctx = NULL;
  }

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_thrtl_op_dr_args_t_marshall,
                 icv, in_key, ctx);

  if (is_read2) {
    *status = NASD_SRPC_S_CALL_NOIMPL;
  }
  else {
    *status =
      nasd_p_tread_simple_otw_dr_client(rpch->h, sec_param_otw,
                                       capability_otw, args_digest_otw,
                                       args_otw, push_func, push_arg,
                                       &out_len, res_otw, res_digest_otw);
  }

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_fastread_dr_res_t_unmarshall,
                             icv, in_key, ctx);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }

  if(sec_param->actual_protection != NASD_NO_PROTECTION) {
    if(statep->status || statep->badstate) {
      if(statep->status)
        res->nasd_status = statep->status;
      else
        res->nasd_status = NASD_MEM_LIST_ERR;
    }

    NASD_FREELIST_FREE(nasd_cl_fo_list_state_freelist, statep, push_cur);
  }
}

void
nasd_cl_srpc_setattr_dr__otw_provided(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  nasd_p_setattr_dr_args_t  *args,
  nasd_p_setattr_dr_res_t   *res,
  nasd_cl_p_otw_buf_t       *otw,
  nasd_rpc_status_t         *status)
{
  nasd_drive_handle_srpc_t *rpch;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 otw->sec_param_otw, otw->capability_otw,
                 otw->args_digest_otw, otw->args_otw,
                 sizeof(nasd_p_setattr_dr_args_otw_t),
                 nasd_p_setattr_dr_args_t_marshall,
                 otw->icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_setattr_otw_dr_client(rpch->h, otw->sec_param_otw,
                                         otw->capability_otw,
                                         otw->args_digest_otw,
                                         otw->args_otw, otw->res_otw,
                                         otw->res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    otw->sec_rc = nasd_unpack_res(handle,
                                  sec_param, capability, otw->res_otw,
                                  sizeof(nasd_p_setattr_dr_res_otw_t),
                                  otw->res_digest_otw, res,
                                  nasd_p_setattr_dr_res_t_unmarshall,
                                  otw->icv, in_key, NULL);
    if(otw->sec_rc) {
      res->nasd_status = otw->sec_rc;
    }
  }
}

void
nasd_cl_srpc_flush_obj_dr(
  nasd_drive_handle_t          handle,
  nasd_key_t                   in_key,
  nasd_security_param_t       *sec_param,
  nasd_capability_t           *capability,
  nasd_p_flush_obj_dr_args_t  *args,
  nasd_p_flush_obj_dr_res_t   *res,
  nasd_rpc_status_t           *status)
{
  nasd_p_flush_obj_dr_args_otw_t args_otw;
  nasd_p_flush_obj_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_flush_obj_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_flush_obj_otw_dr_client(rpch->h, sec_param_otw,
                                           capability_otw, args_digest_otw,
                                           args_otw, res_otw,
                                           res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_flush_obj_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_eject_obj_dr(
  nasd_drive_handle_t          handle,
  nasd_key_t                   in_key,
  nasd_security_param_t       *sec_param,
  nasd_capability_t           *capability,
  nasd_p_eject_obj_dr_args_t  *args,
  nasd_p_eject_obj_dr_res_t   *res,
  nasd_rpc_status_t           *status)
{
  nasd_p_eject_obj_dr_args_otw_t args_otw;
  nasd_p_eject_obj_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_eject_obj_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_eject_obj_otw_dr_client(rpch->h, sec_param_otw,
                                           capability_otw, args_digest_otw,
                                           args_otw, res_otw,
                                           res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_eject_obj_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_remove_dr(
  nasd_drive_handle_t       handle,
  nasd_key_t                in_key,
  nasd_security_param_t        *sec_param,
  nasd_capability_t            *capability,
  nasd_p_remove_dr_args_t  *args,
  nasd_p_remove_dr_res_t   *res,
  nasd_rpc_status_t        *status)
{
  nasd_p_remove_dr_args_otw_t args_otw;
  nasd_p_remove_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_remove_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_remove_otw_dr_client(rpch->h, sec_param_otw,
                                        capability_otw, args_digest_otw,
                                        args_otw, res_otw,
                                        res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_remove_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_initialize_dr(
  nasd_drive_handle_t           handle,
  nasd_p_initialize_dr_args_t  *args,
  nasd_p_initialize_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_p_initialize_dr_args_otw_t args_otw;
  nasd_p_initialize_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_p_initialize_dr_args_t_marshall(args, args_otw);

  *status = nasd_p_initialize_otw_dr_client(rpch->h, args_otw, res_otw);

  if (*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  }
  else {
    nasd_p_initialize_dr_res_t_unmarshall(res_otw, res);
  }
}

void
nasd_cl_srpc_strt_iread_dr(
  nasd_drive_handle_t           handle,
  nasd_key_t                    in_key,
  nasd_security_param_t        *sec_param,
  nasd_capability_t            *capability,
  nasd_p_strt_iread_dr_args_t  *args,
  nasd_p_strt_iread_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_p_strt_iread_dr_args_otw_t args_otw;
  nasd_p_strt_iread_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_strt_iread_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_strt_iread_otw_dr_client(rpch->h, sec_param_otw,
                                            capability_otw, args_digest_otw,
                                            args_otw, res_otw,
                                            res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_strt_iread_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_stop_iread_dr(
  nasd_drive_handle_t           handle,
  nasd_key_t                    in_key,
  nasd_security_param_t        *sec_param,
  nasd_capability_t            *capability,
  nasd_p_stop_iread_dr_args_t  *args,
  nasd_p_stop_iread_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_p_stop_iread_dr_args_otw_t args_otw;
  nasd_p_stop_iread_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_stop_iread_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_stop_iread_otw_dr_client(rpch->h, sec_param_otw,
                                            capability_otw, args_digest_otw,
                                            args_otw, res_otw,
                                            res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_stop_iread_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_rshutdown_dr(
  nasd_drive_handle_t          handle,
  nasd_key_t                   in_key,
  nasd_security_param_t       *sec_param,
  nasd_capability_t           *capability,
  nasd_p_rshutdown_dr_args_t  *args,
  nasd_p_rshutdown_dr_res_t   *res,
  nasd_rpc_status_t           *status)
{
  nasd_p_rshutdown_dr_args_otw_t args_otw;
  nasd_p_rshutdown_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_rshutdown_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *status = nasd_p_rshutdown_otw_dr_client(rpch->h, sec_param_otw,
                                           capability_otw, args_digest_otw,
                                           args_otw, res_otw,
                                           res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_rshutdown_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}

void
nasd_cl_srpc_getinfo_dr(
  nasd_drive_handle_t       handle,
  nasd_p_getinfo_dr_res_t  *res,
  nasd_rpc_status_t        *status)
{
  nasd_p_getinfo_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  *status = nasd_p_getinfo_otw_dr_client(rpch->h, res_otw);

  if (*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  }
  else {
    nasd_p_getinfo_dr_res_t_unmarshall(res_otw, res);
  }
}


void
nasd_cl_srpc_remote_attach_dr(
  nasd_drive_handle_t             handle,
  nasd_key_t                      in_key,
  nasd_security_param_t          *sec_param,
  nasd_capability_t              *capability,
  nasd_p_remote_attach_dr_args_t *args,
  void                           *buf,
  nasd_p_remote_attach_dr_res_t  *res,
  nasd_rpc_status_t              *status)
{
  nasd_p_remote_attach_dr_args_otw_t    args_otw;
  nasd_p_remote_attach_dr_res_otw_t     res_otw;
  nasd_srpc_client_pull_func_t          pull_func;
  void                                  *pull_arg;
  nasd_drive_handle_srpc_t              *rpch;
  nasd_cl_fo_list_state_t               *statep;
  nasd_srpc_client_pullcb_t             pipe;
  nasd_security_context_t               *ctx;
  nasd_len_t                            datalen=0;
  nasd_mem_list_t                       mem_list;
  

  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;
  statep = NULL;

  mem_list.addr = buf;
  mem_list.len = args->in_args_len;
  mem_list.stride = 0;
  mem_list.nelem = 1;
  mem_list.next = NULL;
  
  if(sec_param->actual_protection != NASD_NO_PROTECTION) {
    nasd_printf("Security is not enabled for this.  To enable security, you would want to:\n"
        "1.  Factor out the code to set up a secure pipe write from nasd_cl_srpc_range_write_dr\n"
        "2.  put a call to that factored-out code here.\n"
        "3.  put appropriate cleanup code at the end of this function\n");
    NASD_ASSERT(0);
  } else {
    pull_func = nasd_srpc_client_run_serverpull;
    pull_arg = &mem_list;
    ctx = NULL;
  }

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_remote_attach_dr_args_t_marshall,
                 icv, in_key, ctx);


  *status = nasd_p_remote_attach_otw_dr_client(rpch->h,sec_param_otw,
                                               capability_otw, args_digest_otw,
                                               args_otw,pull_func, pull_arg,res_otw, res_digest_otw);

  if(*status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_remote_attach_dr_res_t_unmarshall,
                             icv, in_key, ctx);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}


void
nasd_cl_srpc_remote_detach_dr(
  nasd_drive_handle_t             handle,
  nasd_key_t                      in_key,
  nasd_security_param_t          *sec_param,
  nasd_capability_t              *capability,
  nasd_p_remote_detach_dr_args_t *args,
  nasd_p_remote_detach_dr_res_t  *res,
  nasd_rpc_status_t              *rpc_status)
{
  nasd_p_remote_detach_dr_args_otw_t args_otw;
  nasd_p_remote_detach_dr_res_otw_t res_otw;
  nasd_drive_handle_srpc_t *rpch;
  NASD_SRPC_OP_DECL

  rpch = (nasd_drive_handle_srpc_t *)handle->rpc_specific_handle;

  nasd_pack_args(handle, sec_param, capability, args,
                 sec_param_otw, capability_otw,
                 args_digest_otw, args_otw, sizeof(args_otw),
                 nasd_p_remote_detach_dr_args_t_marshall,
                 icv, in_key, NULL);

  /* really do our rpc here */
  *rpc_status = nasd_p_remote_detach_otw_dr_client(rpch->h, sec_param_otw,
                                        capability_otw, args_digest_otw,
                                        args_otw, res_otw,
                                        res_digest_otw);

  if(*rpc_status) {
    res->nasd_status = NASD_RPC_FAILURE;
  } else {
    sec_rc = nasd_unpack_res(handle,
                             sec_param, capability, res_otw, sizeof(res_otw),
                             res_digest_otw, res,
                             nasd_p_remote_detach_dr_res_t_unmarshall,
                             icv, in_key, NULL);
    if(sec_rc) {
      res->nasd_status = sec_rc;
    }
  }
}


void
nasd_cl_srpc_remote_invoke_dr(
  nasd_drive_handle_t             handle,
  nasd_key_t                      in_key,
  nasd_security_param_t          *sec_param,
  nasd_capability_t              *capability,
  nasd_p_smpl_op_dr_args_t       *args,
  void                           *buf,
  nasd_p_fastread_dr_res_t       *res,
  nasd_rpc_status_t              *rpc_status)
{
  nasd_mem_list_t               list_elem;


  list_elem.addr = buf;
  list_elem.len = args->in_len;
  list_elem.stride = 0;
  list_elem.nelem = 1;
  list_elem.next = NULL;
  
  nasd_cl_srpc_range_read_generic_dr(handle,
                                     in_key,
                                     sec_param,
                                     capability,
                                     nasd_p_remote_invoke_otw_dr_client,
                                     args,
                                     &list_elem,
                                     res,
                                     &res->nasd_status);
}




/* srpc-generic functions start here */
void
nasd_cl_srpc_error_string(
  nasd_drive_handle_t   handle,
  nasd_rpc_status_t     status,
  nasd_error_string_t   str,
  char                 *file,
  int                   line)
{
  nasd_srpc_error_string((nasd_srpc_status_t)status,
    str, sizeof(str), file, line);
}

nasd_cl_p_rpcmod_tab_t nasd_cl_srpc_mod = {
  nasd_cl_srpc_init,
  NASD_RPCMOD_INIT_FAIL,

  nasd_cl_srpc_bind,
  nasd_cl_srpc_unbind,

  nasd_cl_srpc_null_dr,
  nasd_cl_srpc_sync_dr,
  nasd_cl_srpc_part_creat_dr,
  nasd_cl_srpc_getattr_dr,
  NULL, /* write_simple */
  nasd_cl_srpc_range_write_dr,
  NULL, /* read simple */
  nasd_cl_srpc_range_read_dr,
  NULL, /* tread simple */
  nasd_cl_srpc_range_tread_dr,
  nasd_cl_srpc_flush_obj_dr,
  nasd_cl_srpc_eject_obj_dr,
  nasd_cl_srpc_remove_dr,
  nasd_cl_srpc_initialize_dr,
  nasd_cl_srpc_strt_iread_dr,
  nasd_cl_srpc_stop_iread_dr,
  nasd_cl_srpc_rshutdown_dr,
  nasd_cl_srpc_getinfo_dr,
  nasd_cl_srpc_remote_attach_dr,
  nasd_cl_srpc_remote_detach_dr,
  nasd_cl_srpc_remote_invoke_dr,

  nasd_cl_srpc_create_dr__otw_provided,
  nasd_cl_srpc_setattr_dr__otw_provided,

  nasd_cl_srpc_error_string,

  NASD_BIND_SRPC,
  "SRPC",
  sizeof(nasd_drive_handle_srpc_t),

  NULL
};

void
nasd_cl_p_srpc_register(
  int  counter_lock_held)
{
  nasd_cl_p_mod_register(&nasd_cl_srpc_mod, counter_lock_held);
}

#endif /* NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_SRPC */

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