[Cryptech-Commits] [sw/libhal] 01/05: Added serial RPC transport and lots more...

git at cryptech.is git at cryptech.is
Tue Mar 22 03:06:36 UTC 2016


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch rpc
in repository sw/libhal.

commit 79559c5041835ce6835a35265a97e291789ec0b0
Author: Paul Selkirk <paul at psgd.org>
AuthorDate: Wed Mar 16 10:15:47 2016 -0400

    Added serial RPC transport and lots more...
    
    Added RPC function to get server version number.
    Substantially reworked GNUMakefile with conditionals.
    Renamed rpc_*() and xdr_*() to hal_*() for consistency.
    Moved hal_io_fmc.c from stm32 repo.
---
 GNUmakefile                                  | 125 ++++++--
 hal.h                                        |  12 +
 hal_internal.h                               |  67 ++--
 hal_io_fmc.c                                 | 207 ++++++++++++
 hash.c                                       |   2 +-
 rpc_api.c                                    |   5 +
 rpc_client.c                                 | 449 ++++++++++++++-------------
 rpc_client_loopback.c                        |   8 +-
 rpc_client_loopback.c => rpc_client_serial.c |  79 +++--
 rpc_hash.c                                   |   3 +-
 rpc_misc.c                                   |   8 +-
 rpc_server.c                                 | 228 +++++++-------
 rpc_server_loopback.c                        |  22 +-
 rpc_client_loopback.c => rpc_server_serial.c |  58 ++--
 slip.c                                       | 141 +++++++++
 rpc_client_loopback.c => slip_internal.h     |  64 +---
 tests/GNUmakefile                            |  18 +-
 tests/test-rpc_hash.c                        |   7 +-
 tests/test-rpc_server.c                      |  10 +-
 rpc_xdr.c => xdr.c                           | 148 +++++----
 rpc_client_loopback.c => xdr_internal.h      |  75 ++---
 21 files changed, 1104 insertions(+), 632 deletions(-)

diff --git a/GNUmakefile b/GNUmakefile
index 0637f76..dc518b3 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2015, NORDUnet A/S
+# Copyright (c) 2015-2016, NORDUnet A/S
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -36,28 +36,98 @@ STATIC_PKEY_STATE_BLOCKS = 6
 
 INC		= hal.h hal_internal.h
 LIB		= libhal.a
-OBJ		= core.o csprng.o hash.o aes_keywrap.o pbkdf2.o \
-		  modexp.o rsa.o ecdsa.o asn1.o errorstrings.o \
-		  ${IO_OBJ} ${RPC_OBJ} ${KS_OBJ}
 
-IO_OBJ_EIM	= hal_io_eim.o novena-eim.o
-IO_OBJ_I2C 	= hal_io_i2c.o
+OBJ		= errorstrings.o ${CORE_OBJ} ${IO_OBJ} ${RPC_OBJ} ${KS_OBJ}
+CORE_OBJ	:= core.o csprng.o hash.o aes_keywrap.o pbkdf2.o \
+		   modexp.o rsa.o ecdsa.o asn1.o
 
-# Default I/O bus is EIM, override this to use I2C instead
-IO_OBJ		= ${IO_OBJ_EIM}
+USAGE = "usage: make [IO_BUS=eim|i2c|fmc] [RPC_CLIENT=local|remote|mixed] [RPC_SERVER=yes] [KS=mmap|volatile|flash]"
 
-RPC_OBJ_COMMON	= rpc_api.o rpc_hash.o rpc_misc.o rpc_pkey.o rpc_xdr.o
-RPC_OBJ_CLIENT	= rpc_client.o rpc_client_loopback.o
-RPC_OBJ_SERVER	= rpc_server.o rpc_server_loopback.o
-
-# Default should be to build the RPC server code. We'll probably end up
-# needing a makefile conditional to handle all this properly.
-RPC_OBJ		= ${RPC_OBJ_COMMON} ${RPC_OBJ_CLIENT} ${RPC_OBJ_SERVER}
-
-KS_OBJ_COMMON	= ks.o
-KS_OBJ_MMAP	= ${KS_OBJ_COMMON} ks_mmap.o
-KS_OBJ_VOLATILE	= ${KS_OBJ_COMMON} ks_volatile.o
-KS_OBJ_FLASH	= ${KS_OBJ_COMMON} ks_flash.o
+# I/O bus to the FPGA
+#
+# IO_BUS = eim | i2c | fmc
+#   eim: EIM bus from Novena
+#   i2c: older I2C bus from Novena
+#   fmc: FMC bus from dev-bridge board
+
+IO_BUS ?= eim
+ifeq (${IO_BUS},eim)
+  IO_OBJ = hal_io_eim.o novena-eim.o
+else ifeq (${IO_BUS},i2c)
+  IO_OBJ = hal_io_i2c.o
+else ifeq (${IO_BUS},fmc)
+  IO_OBJ = hal_io_fmc.o
+endif
+
+# RPC_CLIENT = local | remote | mixed
+#   local: Build for Novena or dev-bridge, access FPGA cores directly.
+#   remote: Build for other host, communicate with RPC server.
+#   mixed: Do hashing locally in software, other functions remotely.
+#
+# RPC_SERVER = yes
+#
+# RPC_TRANSPORT = loopback | serial
+#   loopback: communicate over loopback socket on Novena
+#   serial: communicate over USB in serial pass-through mode
+
+RPC_CORE_OBJ = rpc_api.o rpc_hash.o rpc_misc.o rpc_pkey.o
+
+ifdef RPC_SERVER
+  RPC_SERVER_OBJ = rpc_server.o ${RPC_CORE_OBJ}
+  RPC_TRANSPORT ?= serial
+endif
+
+ifdef RPC_CLIENT
+  RPC_CLIENT_OBJ = rpc_client.o
+  ifeq (${RPC_CLIENT},local)
+    RPC_CLIENT_OBJ += ${RPC_CORE_OBJ}
+  else
+    RPC_TRANSPORT ?= serial
+    ifeq (${RPC_CLIENT},mixed)
+      CFLAGS += -DHAL_ENABLE_SOFTWARE_HASH_CORES
+    endif
+    ifndef RPC_SERVER
+      # If we're only building a remote RPC client lib, don't include
+      # the modules that access the FPGA cores.
+      CORE_OBJ :=
+      IO_OBJ :=
+    endif
+  endif
+endif
+
+ifdef RPC_TRANSPORT
+  RPC_TRANSPORT_OBJ = xdr.o
+  ifeq (${RPC_TRANSPORT},loopback)
+    ifdef RPC_SERVER
+      RPC_TRANSPORT_OBJ += rpc_server_loopback.o
+    endif
+    ifdef RPC_CLIENT
+      RPC_TRANSPORT_OBJ += rpc_client_loopback.o
+    endif
+  else ifeq (${RPC_TRANSPORT},serial)
+    RPC_TRANSPORT_OBJ += slip.o
+    ifdef RPC_SERVER
+      RPC_TRANSPORT_OBJ += rpc_server_serial.o
+    endif
+    ifdef RPC_CLIENT
+      RPC_TRANSPORT_OBJ += rpc_client_serial.o
+    endif
+  endif
+endif
+
+RPC_OBJ = ${RPC_SERVER_OBJ} ${RPC_CLIENT_OBJ} ${RPC_TRANSPORT_OBJ}
+
+# RPC client locality, for rpc_client.c. This has to be kept in sync with
+# hal_internal.h. Yeah, it's ugly, but the C preprocessor can only
+# compare integers, not strings.
+
+ifeq (${RPC_CLIENT},local)
+  RPC_CLIENT_FLAG = 0
+else ifeq (${RPC_CLIENT},remote)
+  RPC_CLIENT_FLAG = 1
+else ifeq (${RPC_CLIENT},mixed)
+  RPC_CLIENT_FLAG = 2
+endif
 
 # The mmap and flash keystore implementations are both server code.
 #
@@ -67,7 +137,15 @@ KS_OBJ_FLASH	= ${KS_OBJ_COMMON} ks_flash.o
 # Default at the moment is mmap, since that should work on the Novena
 # and we haven't yet written the flash code for the bridge board.
 
-KS_OBJ		= ${KS_OBJ_MMAP}
+KS_OBJ = ks.o
+KS ?= mmap
+ifeq (${KS},mmap)
+  KS_OBJ += ks_mmap.o
+else ifeq (${KS},volatile)
+  KS_OBJ += ks_volatile.o
+else ifeq (${KS},flash)
+  KS_OBJ += ks_flash.o
+endif
 
 TFMDIR		:= $(abspath ../thirdparty/libtfm)
 CFLAGS		+= -g3 -Wall -fPIC -std=c99 -I${TFMDIR} -DHAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM=1
@@ -76,10 +154,13 @@ LDFLAGS		:= -g3 -L${TFMDIR} -ltfm
 CFLAGS		+= -DHAL_STATIC_HASH_STATE_BLOCKS=${STATIC_HASH_STATE_BLOCKS}
 CFLAGS		+= -DHAL_STATIC_HMAC_STATE_BLOCKS=${STATIC_HMAC_STATE_BLOCKS}
 CFLAGS		+= -DHAL_STATIC_PKEY_STATE_BLOCKS=${STATIC_PKEY_STATE_BLOCKS}
+CFLAGS		+= -DRPC_CLIENT=${RPC_CLIENT_FLAG}
 
 all: ${LIB}
 	cd tests; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@
+ifneq (${CORE_OBJ},)
 	cd utils; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@
+endif
 
 ${OBJ}: ${INC}
 
@@ -89,8 +170,10 @@ ${LIB}: ${OBJ}
 asn1.o rsa.o ecdsa.o:		asn1_internal.h
 ecdsa.o:			ecdsa_curves.h
 novena-eim.o hal_io_eim.o:	novena-eim.h
+slip.o rpc_client_serial.o rpc_server_serial.o:	slip_internal.h
 
 test: all
+	export RPC_CLIENT RPC_SERVER
 	cd tests; ${MAKE} -k $@
 
 clean:
diff --git a/hal.h b/hal.h
index f3b59ad..1dd996d 100644
--- a/hal.h
+++ b/hal.h
@@ -562,6 +562,12 @@ extern hal_error_t hal_rpc_is_logged_in(const hal_client_handle_t client,
                                         const hal_user_t user);
 
 /*
+ * Get the version number of the remote RPC server.
+ */
+
+extern hal_error_t hal_rpc_get_version(uint32_t *version);
+
+/*
  * Get random bytes.
  */
 
@@ -599,6 +605,12 @@ extern hal_error_t hal_rpc_hash_update(const hal_hash_handle_t hash,
 extern hal_error_t hal_rpc_hash_finalize(const hal_hash_handle_t hash,
                                          uint8_t *digest, const size_t length);
 
+extern hal_error_t hal_rpc_client_init(void);
+extern hal_error_t hal_rpc_client_close(void);
+extern hal_error_t hal_rpc_server_init(void);
+extern hal_error_t hal_rpc_server_close(void);
+extern void hal_rpc_server_main(void);
+
 /*
  * Public key functions.
  *
diff --git a/hal_internal.h b/hal_internal.h
index 692067e..8c0b0bc 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -102,6 +102,8 @@ typedef struct {
 
   hal_error_t (*get_random)(void *buffer, const size_t length);
 
+  hal_error_t (*get_version)(uint32_t *version);
+
 } hal_rpc_misc_dispatch_t;
 
 
@@ -327,66 +329,29 @@ extern hal_error_t hal_ks_set_pin(const hal_user_t user,
                                   const hal_ks_pin_t * const pin);
 
 /*
- * RPC serialization/deserialization routines, using XDR (RFC 4506) encoding.
- */
-
-hal_error_t rpc_encode_int(uint8_t ** const outbuf,
-                           const uint8_t * const limit,
-                           const uint32_t value);
-
-hal_error_t rpc_decode_int(uint8_t ** const inbuf,
-                           const uint8_t * const limit,
-                           uint32_t * const value);
-
-hal_error_t rpc_encode_buffer(uint8_t ** const outbuf,
-                              const uint8_t * const limit,
-                              const uint8_t * const value,
-                              const uint32_t len);
-
-hal_error_t rpc_decode_buffer_in_place(uint8_t ** const inbuf,
-                                       const uint8_t * const limit,
-                                       uint8_t ** const vptr,
-                                       uint32_t * const len);
-
-hal_error_t rpc_decode_buffer(uint8_t ** const inbuf,
-                              const uint8_t * const limit,
-                              uint8_t * const value,
-                              uint32_t * const len);
-
-/* XXX move to hal.h? */
-typedef enum {
-    RPC_LOCAL,
-    RPC_REMOTE,
-    RPC_MIXED,
-} rpc_locality_t;
-
-/*
  * RPC lowest-level send and receive routines. These are blocking, and
  * transport-specific (sockets, USB).
  */
 
-hal_error_t rpc_send(const uint8_t * const buf, const size_t len);
-hal_error_t rpc_recv(uint8_t * const buf, size_t * const len);
+extern hal_error_t hal_rpc_send(const uint8_t * const buf, const size_t len);
+extern hal_error_t hal_rpc_recv(uint8_t * const buf, size_t * const len);
 
-hal_error_t rpc_client_init(rpc_locality_t locality);
-hal_error_t rpc_client_close(void);
-hal_error_t rpc_client_transport_init(void);
-hal_error_t rpc_client_transport_close(void);
+extern hal_error_t hal_rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque);
+extern hal_error_t hal_rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque);
 
-hal_error_t rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque);
-hal_error_t rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque);
+extern hal_error_t hal_rpc_client_transport_init(void);
+extern hal_error_t hal_rpc_client_transport_close(void);
+
+extern hal_error_t hal_rpc_server_transport_init(void);
+extern hal_error_t hal_rpc_server_transport_close(void);
 
-hal_error_t rpc_server_init(void);
-hal_error_t rpc_server_close(void);
-hal_error_t rpc_server_transport_init(void);
-hal_error_t rpc_server_transport_close(void);
-void rpc_server_main(void);
 
 /*
  * RPC function numbers
  */
 
 typedef enum {
+    RPC_FUNC_GET_VERSION = 0,
     RPC_FUNC_GET_RANDOM,
     RPC_FUNC_SET_PIN,
     RPC_FUNC_LOGIN,
@@ -414,6 +379,14 @@ typedef enum {
     RPC_FUNC_PKEY_LIST,
 } rpc_func_num_t;
 
+#define RPC_VERSION 0x00010000		/* 0.1.0.0 */
+
+/* RPC client locality. These have to be defines rather than an enum,
+ * because they're handled by the preprocessor.
+ */
+#define RPC_CLIENT_LOCAL	0
+#define RPC_CLIENT_REMOTE	1
+#define RPC_CLIENT_MIXED	2
 
 #endif /* _HAL_INTERNAL_H_ */
 
diff --git a/hal_io_fmc.c b/hal_io_fmc.c
new file mode 100644
index 0000000..904b93f
--- /dev/null
+++ b/hal_io_fmc.c
@@ -0,0 +1,207 @@
+/*
+ * hal_io_fmc.c
+ * ------------
+ * This module contains common code to talk to the FPGA over the FMC bus.
+ *
+ * Author: Paul Selkirk
+ * Copyright (c) 2014-2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "stm-fmc.h"
+#include "libhal/hal.h"
+#include "libhal/verilog_constants.h"
+
+static int debug = 0;
+static int inited = 0;
+
+#ifndef FMC_IO_TIMEOUT
+#define FMC_IO_TIMEOUT  100000000
+#endif
+
+/* not available in arm-none-eabi libc */
+#ifdef __ARMEL__    // Little endian
+static inline uint32_t htonl(uint32_t w)
+{
+  return
+    ((w & 0x000000ff) << 24) +
+    ((w & 0x0000ff00) << 8) +
+    ((w & 0x00ff0000) >> 8) +
+    ((w & 0xff000000) >> 24);
+}
+#else               // Big endian
+#define htonl(x) (x)
+#endif
+#define ntohl htonl
+
+static hal_error_t init(void)
+{
+  if (!inited) {
+    fmc_init();
+    inited = 1;
+  }
+  return HAL_OK;
+}
+
+/* Translate cryptech register number to FMC address.
+ *
+ * register number format:
+ * 3 bits segment selector
+ * 5 bits core selector (6 bits in native eim)
+ * 8 bits register selector
+ *
+ * sss ccccc rrrrrrrr => sss 0 ccccc rrrrrrrr 00
+ */
+static hal_addr_t fmc_offset(hal_addr_t offset)
+{
+  return ((offset & ~0x1fff) << 3) + ((offset & 0x1fff) << 2);
+}
+
+void hal_io_set_debug(int onoff)
+{
+  debug = onoff;
+}
+
+static void dump(char *label, const uint8_t *buf, size_t len)
+{
+  if (debug) {
+    size_t i;
+    printf("%s [", label);
+    for (i = 0; i < len; ++i)
+      printf(" %02x", buf[i]);
+    printf(" ]\n");
+  }
+}
+
+hal_error_t hal_io_write(const hal_core_t *core, hal_addr_t offset, const uint8_t *buf, size_t len)
+{
+  hal_error_t err;
+
+  if (core == NULL)
+    return HAL_ERROR_CORE_NOT_FOUND;
+
+  if (len % 4 != 0)
+    return HAL_ERROR_IO_BAD_COUNT;
+
+  if ((err = init()) != HAL_OK)
+    return err;
+
+  dump("write ", buf, len);
+
+  offset = fmc_offset(offset + hal_core_base(core));
+  for (; len > 0; offset += 4, buf += 4, len -= 4) {
+    uint32_t val;
+    val = htonl(*(uint32_t *)buf);
+    fmc_write_32(offset, &val);
+  }
+
+  return HAL_OK;
+}
+
+hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf, size_t len)
+{
+  uint8_t *rbuf = buf;
+  int rlen = len;
+  hal_error_t err;
+
+  if (core == NULL)
+    return HAL_ERROR_CORE_NOT_FOUND;
+
+  if (len % 4 != 0)
+    return HAL_ERROR_IO_BAD_COUNT;
+
+  if ((err = init()) != HAL_OK)
+    return err;
+
+  offset = fmc_offset(offset + hal_core_base(core));
+  for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) {
+    uint32_t val;
+    fmc_read_32(offset, &val);
+    *(uint32_t *)rbuf = ntohl(val);
+  }
+
+  dump("read  ", buf, len);
+
+  return HAL_OK;
+}
+
+hal_error_t hal_io_init(const hal_core_t *core)
+{
+  uint8_t buf[4] = { 0, 0, 0, CTRL_INIT };
+  return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
+}
+
+hal_error_t hal_io_next(const hal_core_t *core)
+{
+  uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT };
+  return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
+}
+
+hal_error_t hal_io_wait(const hal_core_t *core, uint8_t status, int *count)
+{
+  hal_error_t err;
+  uint8_t buf[4];
+  int i;
+
+  for (i = 1; ; ++i) {
+
+    if (count && (*count > 0) && (i >= *count))
+      return HAL_ERROR_IO_TIMEOUT;
+
+    if ((err = hal_io_read(core, ADDR_STATUS, buf, sizeof(buf))) != HAL_OK)
+      return err;
+
+    if ((buf[3] & status) != 0) {
+      if (count)
+        *count = i;
+      return HAL_OK;
+    }
+  }
+}
+
+hal_error_t hal_io_wait_ready(const hal_core_t *core)
+{
+  int limit = FMC_IO_TIMEOUT;
+  return hal_io_wait(core, STATUS_READY, &limit);
+}
+
+hal_error_t hal_io_wait_valid(const hal_core_t *core)
+{
+  int limit = FMC_IO_TIMEOUT;
+  return hal_io_wait(core, STATUS_VALID, &limit);
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-basic-offset: 2
+ * End:
+ */
diff --git a/hash.c b/hash.c
index 3c5f5d7..e2a7f43 100644
--- a/hash.c
+++ b/hash.c
@@ -3,7 +3,7 @@
  * ------
  * HAL interface to Cryptech hash cores.
  *
- * Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein
+ * Authors: Joachim Str�mbergson, Paul Selkirk, Rob Austein
  * Copyright (c) 2014-2016, NORDUnet A/S
  * All rights reserved.
  *
diff --git a/rpc_api.c b/rpc_api.c
index b494ca8..a903f57 100644
--- a/rpc_api.c
+++ b/rpc_api.c
@@ -88,6 +88,11 @@ static inline int check_pkey_type_curve_flags(const hal_key_type_t type,
 }
 
 
+hal_error_t hal_rpc_get_version(uint32_t *version)
+{
+  return hal_rpc_misc_dispatch->get_version(version);
+}
+
 hal_error_t hal_rpc_get_random(void *buffer, const size_t length)
 {
   if (buffer == NULL)
diff --git a/rpc_client.c b/rpc_client.c
index d58cb92..5903895 100644
--- a/rpc_client.c
+++ b/rpc_client.c
@@ -37,6 +37,7 @@
 
 #include "hal.h"
 #include "hal_internal.h"
+#include "xdr_internal.h"
 
 /*
  * RPC calls.
@@ -46,6 +47,27 @@
 
 #define pad(n) (((n) + 3) & ~3)
 
+#if RPC_CLIENT != RPC_CLIENT_LOCAL
+
+static hal_error_t get_version(uint32_t *version)
+{
+  uint8_t outbuf[4], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+  uint8_t inbuf[8], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+  size_t ilen = sizeof(inbuf);
+  hal_error_t ret, rpc_ret;
+
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_GET_VERSION));
+  check(hal_rpc_send(outbuf, optr - outbuf));
+
+  check(hal_rpc_recv(inbuf, &ilen));
+  assert(ilen <= sizeof(inbuf));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+  if (rpc_ret == HAL_OK) {
+    check(hal_xdr_decode_int(&iptr, ilimit, version));
+  }
+  return rpc_ret;
+}
+
 static hal_error_t get_random(void *buffer, const size_t length)
 {
   uint8_t outbuf[8], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
@@ -54,15 +76,15 @@ static hal_error_t get_random(void *buffer, const size_t length)
   uint32_t rcvlen = length;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_GET_RANDOM));
-  check(rpc_encode_int(&optr, olimit, (uint32_t)length));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_GET_RANDOM));
+  check(hal_xdr_encode_int(&optr, olimit, (uint32_t)length));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_buffer(&iptr, ilimit, buffer, &rcvlen));
+    check(hal_xdr_decode_buffer(&iptr, ilimit, buffer, &rcvlen));
     // XXX check rcvlen vs length
   }
   return rpc_ret;
@@ -77,15 +99,15 @@ static hal_error_t set_pin(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_SET_PIN));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, user));
-  check(rpc_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_SET_PIN));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, user));
+  check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -112,15 +134,15 @@ static hal_error_t login(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_LOGIN));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, user));
-  check(rpc_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGIN));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, user));
+  check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -131,13 +153,13 @@ static hal_error_t logout(const hal_client_handle_t client)
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_LOGOUT));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGOUT));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -148,12 +170,12 @@ static hal_error_t logout_all(void)
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_LOGOUT_ALL));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGOUT_ALL));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -165,14 +187,14 @@ static hal_error_t is_logged_in(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_IS_LOGGED_IN));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, user));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_IS_LOGGED_IN));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, user));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -184,15 +206,15 @@ static hal_error_t hash_get_digest_len(const hal_digest_algorithm_t alg, size_t
   uint32_t len32;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN));
-  check(rpc_encode_int(&optr, olimit, alg));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN));
+  check(hal_xdr_encode_int(&optr, olimit, alg));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_int(&iptr, ilimit, &len32));
+    check(hal_xdr_decode_int(&iptr, ilimit, &len32));
     *length = (size_t)len32;
   }
   return rpc_ret;
@@ -207,16 +229,16 @@ static hal_error_t hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg
   uint32_t len32 = len_max;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN));
-  check(rpc_encode_int(&optr, olimit, alg));
-  check(rpc_encode_int(&optr, olimit, len_max));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN));
+  check(hal_xdr_encode_int(&optr, olimit, alg));
+  check(hal_xdr_encode_int(&optr, olimit, len_max));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_buffer(&iptr, ilimit, id, &len32));
+    check(hal_xdr_decode_buffer(&iptr, ilimit, id, &len32));
     *len = len32;
   }
   return rpc_ret;
@@ -230,15 +252,15 @@ static hal_error_t hash_get_algorithm(const hal_hash_handle_t hash, hal_digest_a
   uint32_t alg32;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_ALGORITHM));
-  check(rpc_encode_int(&optr, olimit, hash.handle));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_ALGORITHM));
+  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_int(&iptr, ilimit, &alg32));
+    check(hal_xdr_decode_int(&iptr, ilimit, &alg32));
     *alg = (hal_digest_algorithm_t)alg32;
   }
   return rpc_ret;
@@ -255,18 +277,18 @@ static hal_error_t hash_initialize(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_HASH_INITIALIZE));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, session.handle));
-  check(rpc_encode_int(&optr, olimit, alg));
-  check(rpc_encode_buffer(&optr, olimit, key, key_len));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_INITIALIZE));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, session.handle));
+  check(hal_xdr_encode_int(&optr, olimit, alg));
+  check(hal_xdr_encode_buffer(&optr, olimit, key, key_len));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_int(&iptr, ilimit, &hash->handle));
+    check(hal_xdr_decode_int(&iptr, ilimit, &hash->handle));
   }
   return rpc_ret;
 }
@@ -279,14 +301,14 @@ static hal_error_t hash_update(const hal_hash_handle_t hash,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_HASH_UPDATE));
-  check(rpc_encode_int(&optr, olimit, hash.handle));
-  check(rpc_encode_buffer(&optr, olimit, data, length));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_UPDATE));
+  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
+  check(hal_xdr_encode_buffer(&optr, olimit, data, length));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -299,16 +321,16 @@ static hal_error_t hash_finalize(const hal_hash_handle_t hash,
   uint32_t digest_len = length;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_HASH_FINALIZE));
-  check(rpc_encode_int(&optr, olimit, hash.handle));
-  check(rpc_encode_int(&optr, olimit, length));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_FINALIZE));
+  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
+  check(hal_xdr_encode_int(&optr, olimit, length));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_buffer(&iptr, ilimit, digest, &digest_len));
+    check(hal_xdr_decode_buffer(&iptr, ilimit, digest, &digest_len));
     /* XXX check digest_len vs length */
   }
   return rpc_ret;
@@ -328,21 +350,21 @@ static hal_error_t pkey_load(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, session.handle));
-  check(rpc_encode_int(&optr, olimit, type));
-  check(rpc_encode_int(&optr, olimit, curve));
-  check(rpc_encode_buffer(&optr, olimit, name, name_len));
-  check(rpc_encode_buffer(&optr, olimit, der, der_len));
-  check(rpc_encode_int(&optr, olimit, flags));
-  check(rpc_send(outbuf, optr - outbuf));
-
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, session.handle));
+  check(hal_xdr_encode_int(&optr, olimit, type));
+  check(hal_xdr_encode_int(&optr, olimit, curve));
+  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
+  check(hal_xdr_encode_buffer(&optr, olimit, der, der_len));
+  check(hal_xdr_encode_int(&optr, olimit, flags));
+  check(hal_rpc_send(outbuf, optr - outbuf));
+
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK)
-    check(rpc_decode_int(&iptr, ilimit, &pkey->handle));
+    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
 
   return rpc_ret;
 }
@@ -358,18 +380,18 @@ static hal_error_t pkey_find(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_FIND));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, session.handle));
-  check(rpc_encode_int(&optr, olimit, type));
-  check(rpc_encode_buffer(&optr, olimit, name, name_len));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_FIND));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, session.handle));
+  check(hal_xdr_encode_int(&optr, olimit, type));
+  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK)
-    check(rpc_decode_int(&iptr, ilimit, &pkey->handle));
+    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
 
   return rpc_ret;
 }
@@ -387,20 +409,20 @@ static hal_error_t pkey_generate_rsa(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_RSA));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, session.handle));
-  check(rpc_encode_buffer(&optr, olimit, name, name_len));
-  check(rpc_encode_int(&optr, olimit, key_len));
-  check(rpc_encode_buffer(&optr, olimit, exp, exp_len));
-  check(rpc_encode_int(&optr, olimit, flags));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_RSA));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, session.handle));
+  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
+  check(hal_xdr_encode_int(&optr, olimit, key_len));
+  check(hal_xdr_encode_buffer(&optr, olimit, exp, exp_len));
+  check(hal_xdr_encode_int(&optr, olimit, flags));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK)
-    check(rpc_decode_int(&iptr, ilimit, &pkey->handle));
+    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
 
   return rpc_ret;
 }
@@ -417,19 +439,19 @@ static hal_error_t pkey_generate_ec(const hal_client_handle_t client,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC));
-  check(rpc_encode_int(&optr, olimit, client.handle));
-  check(rpc_encode_int(&optr, olimit, session.handle));
-  check(rpc_encode_buffer(&optr, olimit, name, name_len));
-  check(rpc_encode_int(&optr, olimit, curve));
-  check(rpc_encode_int(&optr, olimit, flags));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC));
+  check(hal_xdr_encode_int(&optr, olimit, client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, session.handle));
+  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
+  check(hal_xdr_encode_int(&optr, olimit, curve));
+  check(hal_xdr_encode_int(&optr, olimit, flags));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK)
-    check(rpc_decode_int(&iptr, ilimit, &pkey->handle));
+    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
 
   return rpc_ret;
 }
@@ -441,13 +463,13 @@ static hal_error_t pkey_close(const hal_pkey_handle_t pkey)
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_CLOSE));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_CLOSE));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -458,13 +480,13 @@ static hal_error_t pkey_delete(const hal_pkey_handle_t pkey)
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_DELETE));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_DELETE));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
@@ -477,15 +499,15 @@ static hal_error_t pkey_get_key_type(const hal_pkey_handle_t pkey,
   uint32_t type32;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_TYPE));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_TYPE));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_int(&iptr, ilimit, &type32));
+    check(hal_xdr_decode_int(&iptr, ilimit, &type32));
     *type = (hal_key_type_t)type32;
   }
   return rpc_ret;
@@ -500,15 +522,15 @@ static hal_error_t pkey_get_key_flags(const hal_pkey_handle_t pkey,
   uint32_t flags32;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_FLAGS));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_FLAGS));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_int(&iptr, ilimit, &flags32));
+    check(hal_xdr_decode_int(&iptr, ilimit, &flags32));
     *flags = (hal_key_flags_t)flags32;
   }
   return rpc_ret;
@@ -522,15 +544,15 @@ static size_t pkey_get_public_key_len(const hal_pkey_handle_t pkey)
   uint32_t len32;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_int(&iptr, ilimit, &len32));
+    check(hal_xdr_decode_int(&iptr, ilimit, &len32));
     return (size_t)len32;
   }
   else
@@ -546,16 +568,16 @@ static hal_error_t pkey_get_public_key(const hal_pkey_handle_t pkey,
   uint32_t dlen32 = der_max;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_encode_int(&optr, olimit, der_max));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_xdr_encode_int(&optr, olimit, der_max));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_buffer(&iptr, ilimit, der, &dlen32));
+    check(hal_xdr_decode_buffer(&iptr, ilimit, der, &dlen32));
     *der_len = (size_t)dlen32;
   }
   return rpc_ret;
@@ -573,19 +595,19 @@ static hal_error_t pkey_remote_sign(const hal_session_handle_t session,
   uint32_t slen32 = signature_max;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_SIGN));
-  check(rpc_encode_int(&optr, olimit, session.handle));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_encode_int(&optr, olimit, hash.handle));
-  check(rpc_encode_buffer(&optr, olimit, input, input_len));
-  check(rpc_encode_int(&optr, olimit, signature_max));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_SIGN));
+  check(hal_xdr_encode_int(&optr, olimit, session.handle));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
+  check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
+  check(hal_xdr_encode_int(&optr, olimit, signature_max));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    check(rpc_decode_buffer(&iptr, ilimit, signature, &slen32));
+    check(hal_xdr_decode_buffer(&iptr, ilimit, signature, &slen32));
     *signature_len = (size_t)slen32;
   }
   return rpc_ret;
@@ -602,29 +624,29 @@ static hal_error_t pkey_remote_verify(const hal_session_handle_t session,
   size_t ilen = sizeof(inbuf);
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_VERIFY));
-  check(rpc_encode_int(&optr, olimit, session.handle));
-  check(rpc_encode_int(&optr, olimit, pkey.handle));
-  check(rpc_encode_int(&optr, olimit, hash.handle));
-  check(rpc_encode_buffer(&optr, olimit, input, input_len));
-  check(rpc_encode_buffer(&optr, olimit, signature, signature_len));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_VERIFY));
+  check(hal_xdr_encode_int(&optr, olimit, session.handle));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
+  check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
+  check(hal_xdr_encode_buffer(&optr, olimit, signature, signature_len));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   return rpc_ret;
 }
 
-static hal_error_t rpc_decode_pkey_info(uint8_t **iptr, const uint8_t * const ilimit, hal_pkey_info_t *info)
+static hal_error_t hal_xdr_decode_pkey_info(uint8_t **iptr, const uint8_t * const ilimit, hal_pkey_info_t *info)
 {
   uint32_t i32;
   hal_error_t ret;
 
-  check(rpc_decode_int(iptr, ilimit, &i32)); info->type = i32;
-  check(rpc_decode_int(iptr, ilimit, &i32)); info->curve = i32;
-  check(rpc_decode_int(iptr, ilimit, &i32)); info->flags = i32;
-  check(rpc_decode_buffer(iptr, ilimit, (uint8_t *)&info->name[0], &i32)); info->name_len = i32;
+  check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->type = i32;
+  check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->curve = i32;
+  check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->flags = i32;
+  check(hal_xdr_decode_buffer(iptr, ilimit, (uint8_t *)&info->name[0], &i32)); info->name_len = i32;
   return HAL_OK;
 }
 
@@ -638,19 +660,19 @@ static hal_error_t pkey_list(hal_pkey_info_t *result,
   uint32_t len;
   hal_error_t ret, rpc_ret;
 
-  check(rpc_encode_int(&optr, olimit, RPC_FUNC_PKEY_LIST));
-  check(rpc_encode_int(&optr, olimit, result_max));
-  check(rpc_send(outbuf, optr - outbuf));
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LIST));
+  check(hal_xdr_encode_int(&optr, olimit, result_max));
+  check(hal_rpc_send(outbuf, optr - outbuf));
 
-  check(rpc_recv(inbuf, &ilen));
+  check(hal_rpc_recv(inbuf, &ilen));
   assert(ilen <= sizeof(inbuf));
-  check(rpc_decode_int(&iptr, ilimit, &rpc_ret));
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
     int i;
-    check(rpc_decode_int(&iptr, ilimit, &len));
+    check(hal_xdr_decode_int(&iptr, ilimit, &len));
     *result_len = len;
     for (i = 0; i < len; ++i) {
-      if ((ret = rpc_decode_pkey_info(&iptr, ilimit, &result[i])) != HAL_OK) {
+      if ((ret = hal_xdr_decode_pkey_info(&iptr, ilimit, &result[i])) != HAL_OK) {
         *result_len = 0;
         return ret;
       }
@@ -726,7 +748,7 @@ static hal_error_t pkey_mixed_verify(const hal_session_handle_t session,
  */
 
 const hal_rpc_misc_dispatch_t hal_rpc_remote_misc_dispatch = {
-  set_pin, login, logout, logout_all, is_logged_in, get_random
+  set_pin, login, logout, logout_all, is_logged_in, get_random, get_version
 };
 
 const hal_rpc_hash_dispatch_t hal_rpc_remote_hash_dispatch = {
@@ -748,37 +770,38 @@ const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
   pkey_list
 };
 
-const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch;
-const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch;
-const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch;
-
-hal_error_t rpc_client_init(rpc_locality_t locality)
+#endif
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_local_misc_dispatch;
+const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_local_hash_dispatch;
+const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_local_pkey_dispatch;
+#elif RPC_CLIENT == RPC_CLIENT_REMOTE
+const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch;
+const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_remote_hash_dispatch;
+const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_remote_pkey_dispatch;
+#elif RPC_CLIENT == RPC_CLIENT_MIXED
+const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch;
+const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_remote_hash_dispatch; //mixed?
+const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_mixed_pkey_dispatch;
+#endif
+
+hal_error_t hal_rpc_client_init(void)
 {
-  switch (locality) {
-  case RPC_LOCAL:
-    hal_rpc_misc_dispatch = &hal_rpc_local_misc_dispatch;
-    hal_rpc_hash_dispatch = &hal_rpc_local_hash_dispatch;
-    hal_rpc_pkey_dispatch = &hal_rpc_local_pkey_dispatch;
-    break; 
-  case RPC_REMOTE:
-    hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch;
-    hal_rpc_hash_dispatch = &hal_rpc_remote_hash_dispatch;
-    hal_rpc_pkey_dispatch = &hal_rpc_remote_pkey_dispatch;
-    break;
-  case RPC_MIXED:
-    hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch;
-    hal_rpc_hash_dispatch = &hal_rpc_remote_hash_dispatch;
-    hal_rpc_pkey_dispatch = &hal_rpc_mixed_pkey_dispatch;
-    break;
-  default:
-    return HAL_ERROR_BAD_ARGUMENTS;
-  }
-  return rpc_client_transport_init();
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+  return HAL_OK;
+#else
+  return hal_rpc_client_transport_init();
+#endif
 }
 
-hal_error_t rpc_client_close(void)
+hal_error_t hal_rpc_client_close(void)
 {
-  return rpc_client_transport_close();
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+  return HAL_OK;
+#else
+  return hal_rpc_client_transport_close();
+#endif
 }
 
 
diff --git a/rpc_client_loopback.c b/rpc_client_loopback.c
index a3d7e73..b31bdd2 100644
--- a/rpc_client_loopback.c
+++ b/rpc_client_loopback.c
@@ -43,7 +43,7 @@
 
 static int sock = -1;
 
-hal_error_t rpc_client_transport_init(void)
+hal_error_t hal_rpc_client_transport_init(void)
 {
     struct sockaddr_in sin;
 
@@ -58,7 +58,7 @@ hal_error_t rpc_client_transport_init(void)
     return HAL_OK;
 }
 
-hal_error_t rpc_client_transport_close(void)
+hal_error_t hal_rpc_client_transport_close(void)
 {
     int ret = close(sock);
     sock = -1;
@@ -67,14 +67,14 @@ hal_error_t rpc_client_transport_close(void)
     return HAL_OK;
 }
 
-hal_error_t rpc_send(const uint8_t * const buf, const size_t len)
+hal_error_t hal_rpc_send(const uint8_t * const buf, const size_t len)
 {
     if (send(sock, buf, len, 0) == -1)
         return perror("send"), HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_recv(uint8_t * const buf, size_t * const len)
+hal_error_t hal_rpc_recv(uint8_t * const buf, size_t * const len)
 {
     int ret;
     
diff --git a/rpc_client_loopback.c b/rpc_client_serial.c
similarity index 58%
copy from rpc_client_loopback.c
copy to rpc_client_serial.c
index a3d7e73..d6bda1d 100644
--- a/rpc_client_loopback.c
+++ b/rpc_client_serial.c
@@ -1,7 +1,7 @@
 /*
- * rpc_client_loopback.c
- * ---------------------
- * Remote procedure call transport over loopback socket.
+ * rpc_client_serial.c
+ * -------------------
+ * Remote procedure call transport over serial line with SLIP framing.
  *
  * Copyright (c) 2016, NORDUnet A/S All rights reserved.
  *
@@ -36,50 +36,81 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <unistd.h>     /* close */
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
 
 #include "hal.h"
 #include "hal_internal.h"
+#include "slip_internal.h"
 
-static int sock = -1;
+#define DEVICE "/dev/ttyUSB0"
+#define SPEED B115200
 
-hal_error_t rpc_client_transport_init(void)
+static int fd = -1;
+
+hal_error_t hal_rpc_client_transport_init(void)
 {
-    struct sockaddr_in sin;
-
-    sock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sock == -1)
-        return perror("socket"), HAL_ERROR_RPC_TRANSPORT;
-    sin.sin_family = AF_INET;
-    sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    sin.sin_port = 17425;
-    if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) != 0)
-        return perror("connect"), HAL_ERROR_RPC_TRANSPORT;
+    struct termios tty;
+    
+    fd = open(DEVICE, O_RDWR | O_NOCTTY | O_SYNC);
+    if (fd == -1)
+	return perror("open"), HAL_ERROR_RPC_TRANSPORT;
+
+    if (tcgetattr (fd, &tty) != 0)
+	return perror("tcgetattr"), HAL_ERROR_RPC_TRANSPORT;
+
+    cfsetospeed (&tty, SPEED);
+    cfsetispeed (&tty, SPEED);
+
+    tty.c_cflag &= ~CSIZE;
+    tty.c_cflag |= (CS8 | CLOCAL | CREAD);
+
+    tty.c_iflag = 0;
+    tty.c_oflag = 0;
+    tty.c_lflag = 0;
+
+    tty.c_cc[VMIN] = 1;
+    tty.c_cc[VTIME] = 0;
+
+    if (tcsetattr (fd, TCSANOW, &tty) != 0)
+	return perror("tcsetattr"), HAL_ERROR_RPC_TRANSPORT;
+
     return HAL_OK;
 }
 
-hal_error_t rpc_client_transport_close(void)
+hal_error_t hal_rpc_client_transport_close(void)
 {
-    int ret = close(sock);
-    sock = -1;
+    int ret = close(fd);
+    fd = -1;
     if (ret != 0)
         return perror("close"), HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_send(const uint8_t * const buf, const size_t len)
+hal_error_t hal_rpc_send(const uint8_t * const buf, const size_t len)
 {
-    if (send(sock, buf, len, 0) == -1)
-        return perror("send"), HAL_ERROR_RPC_TRANSPORT;
+    if (hal_slip_send(buf, len) == -1)
+        return HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_recv(uint8_t * const buf, size_t * const len)
+hal_error_t hal_rpc_recv(uint8_t * const buf, size_t * const len)
 {
     int ret;
     
-    if ((ret = recv(sock, buf, *len, 0)) == -1)
+    if ((ret = hal_slip_recv(buf, *len)) == -1)
         return HAL_ERROR_RPC_TRANSPORT;
     *len = ret;
     return HAL_OK;
 }
+
+int hal_slip_send_char(const uint8_t c)
+{
+    return write(fd, &c, 1);
+}
+
+int hal_slip_recv_char(uint8_t * const c)
+{
+    return read(fd, c, 1);
+}
diff --git a/rpc_hash.c b/rpc_hash.c
index 1bce86e..3c4c79b 100644
--- a/rpc_hash.c
+++ b/rpc_hash.c
@@ -143,8 +143,9 @@ static inline handle_slot_t *find_handle(const hal_hash_handle_t handle)
   return NULL;
 }
 
-static inline free_handle(handle_slot_t *slot)
+static inline void free_handle(handle_slot_t *slot)
 {
+  if (slot != NULL)
     /* state is a union, so this this works for hash and hmac */
     slot->state.hash = NULL;
 }
diff --git a/rpc_misc.c b/rpc_misc.c
index bcd1974..c0558da 100644
--- a/rpc_misc.c
+++ b/rpc_misc.c
@@ -38,6 +38,12 @@
 #include "hal.h"
 #include "hal_internal.h"
 
+static hal_error_t get_version(uint32_t *version)
+{
+  *version = RPC_VERSION;
+  return HAL_OK;
+}
+
 static hal_error_t get_random(void *buffer, const size_t length)
 {
   assert(buffer != NULL && length > 0);
@@ -219,7 +225,7 @@ static hal_error_t logout_all(void)
 }
 
 const hal_rpc_misc_dispatch_t hal_rpc_local_misc_dispatch = {
-  set_pin, login, logout, logout_all, is_logged_in, get_random
+  set_pin, login, logout, logout_all, is_logged_in, get_random, get_version
 };
 
 /*
diff --git a/rpc_server.c b/rpc_server.c
index 3447c53..d57fc57 100644
--- a/rpc_server.c
+++ b/rpc_server.c
@@ -34,6 +34,7 @@
 
 #include "hal.h"
 #include "hal_internal.h"
+#include "xdr_internal.h"
 
 /*
  * RPC calls.
@@ -43,20 +44,36 @@
 
 #define pad(n) (((n) + 3) & ~3)
 
+static hal_error_t get_version(uint8_t **iptr, const uint8_t * const ilimit,
+                               uint8_t **optr, const uint8_t * const olimit)
+{
+    uint32_t version;
+    hal_error_t ret;
+
+    check(hal_xdr_encode_int(optr, olimit, RPC_VERSION));
+
+    /* call the local function */
+    ret = hal_rpc_local_misc_dispatch.get_version(&version);
+    if (ret == HAL_OK)
+        check(hal_xdr_encode_int(optr, olimit, version));
+
+    return ret;
+}
+
 static hal_error_t get_random(uint8_t **iptr, const uint8_t * const ilimit,
                               uint8_t **optr, const uint8_t * const olimit)
 {
     uint32_t length;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &length));
+    check(hal_xdr_decode_int(iptr, ilimit, &length));
     /* sanity check length */
     if (length == 0 || length > olimit - *optr - 4)
         return HAL_ERROR_IO_BAD_COUNT;  /* need a better error */
 
     /* call the local function */
     /* get the data directly into the output buffer */
-    check(rpc_encode_int(optr, olimit, length));
+    check(hal_xdr_encode_int(optr, olimit, length));
     ret = hal_rpc_local_misc_dispatch.get_random(*optr, (size_t)length);
     if (ret == HAL_OK)
         *optr += pad(length);
@@ -71,14 +88,14 @@ static hal_error_t set_pin(uint8_t **iptr, const uint8_t * const ilimit,
                            uint8_t **optr, const uint8_t * const olimit)
 {
     hal_client_handle_t client;
-    hal_user_t user;
+    uint32_t user;
     uint8_t *pin;
     uint32_t pin_len;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &user));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &user));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
 
     /* call the local function */
     ret = hal_rpc_local_misc_dispatch.set_pin(client, user, (const char * const)pin, pin_len);
@@ -89,14 +106,14 @@ static hal_error_t login(uint8_t **iptr, const uint8_t * const ilimit,
                          uint8_t **optr, const uint8_t * const olimit)
 {
     hal_client_handle_t client;
-    hal_user_t user;
+    uint32_t user;
     uint8_t *pin;
     uint32_t pin_len;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &user));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &user));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
 
     /* call the local function */
     ret = hal_rpc_local_misc_dispatch.login(client, user, (const char * const)pin, pin_len);
@@ -109,7 +126,7 @@ static hal_error_t logout(uint8_t **iptr, const uint8_t * const ilimit,
     hal_client_handle_t client;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
 
     /* call the local function */
     ret = hal_rpc_local_misc_dispatch.logout(client);
@@ -130,11 +147,11 @@ static hal_error_t is_logged_in(uint8_t **iptr, const uint8_t * const ilimit,
                                 uint8_t **optr, const uint8_t * const olimit)
 {
     hal_client_handle_t client;
-    hal_user_t user;
+    uint32_t user;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &user));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &user));
 
     /* call the local function */
     ret = hal_rpc_local_misc_dispatch.is_logged_in(client, user);
@@ -144,30 +161,30 @@ static hal_error_t is_logged_in(uint8_t **iptr, const uint8_t * const ilimit,
 static hal_error_t hash_get_digest_len(uint8_t **iptr, const uint8_t * const ilimit,
                                        uint8_t **optr, const uint8_t * const olimit)
 {
-    hal_digest_algorithm_t alg;
+    uint32_t alg;
     size_t length;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &alg));
+    check(hal_xdr_decode_int(iptr, ilimit, &alg));
 
     /* call the local function */
     ret = hal_rpc_local_hash_dispatch.get_digest_length(alg, &length);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, length));
+        check(hal_xdr_encode_int(optr, olimit, length));
     return ret;
 }
 
 static hal_error_t hash_get_digest_algorithm_id(uint8_t **iptr, const uint8_t * const ilimit,
                                                 uint8_t **optr, const uint8_t * const olimit)
 {
-    hal_digest_algorithm_t alg;
+    uint32_t alg;
     size_t len;
     uint32_t len_max;
     uint8_t *optr_orig = *optr;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &alg));
-    check(rpc_decode_int(iptr, ilimit, &len_max));
+    check(hal_xdr_decode_int(iptr, ilimit, &alg));
+    check(hal_xdr_decode_int(iptr, ilimit, &len_max));
     /* sanity check len_max */
     if (len_max > olimit - *optr - 4)
         return HAL_ERROR_IO_BAD_COUNT;  /* need a better error */
@@ -178,7 +195,7 @@ static hal_error_t hash_get_digest_algorithm_id(uint8_t **iptr, const uint8_t *
     ret = hal_rpc_local_hash_dispatch.get_digest_algorithm_id(alg, *optr, &len, (size_t)len_max);
     if (ret == HAL_OK) {
         *optr = optr_orig;
-        check(rpc_encode_int(optr, olimit, len));
+        check(hal_xdr_encode_int(optr, olimit, len));
         *optr += pad(len);
     }
     else {
@@ -195,12 +212,12 @@ static hal_error_t hash_get_algorithm(uint8_t **iptr, const uint8_t * const ilim
     hal_digest_algorithm_t alg;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &hash.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
 
     /* call the local function */
     ret = hal_rpc_local_hash_dispatch.get_algorithm(hash, &alg);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, alg));
+        check(hal_xdr_encode_int(optr, olimit, alg));
     return ret;
 }
 
@@ -215,15 +232,15 @@ static hal_error_t hash_initialize(uint8_t **iptr, const uint8_t * const ilimit,
     uint32_t key_len;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &session.handle));
-    check(rpc_decode_int(iptr, ilimit, &alg));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &key, &key_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &alg));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &key, &key_len));
 
     /* call the local function */
     ret = hal_rpc_local_hash_dispatch.initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, hash.handle));
+        check(hal_xdr_encode_int(optr, olimit, hash.handle));
     return ret;
 }
 
@@ -235,8 +252,8 @@ static hal_error_t hash_update(uint8_t **iptr, const uint8_t * const ilimit,
     uint32_t length;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &hash.handle));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &data, &length));
+    check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &data, &length));
 
     /* call the local function */
     ret = hal_rpc_local_hash_dispatch.update(hash, data, (size_t)length);
@@ -250,15 +267,15 @@ static hal_error_t hash_finalize(uint8_t **iptr, const uint8_t * const ilimit,
     uint32_t length;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &hash.handle));
-    check(rpc_decode_int(iptr, ilimit, &length));
+    check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &length));
     /* sanity check length */
     if (length == 0 || length > olimit - *optr - 4)
         return HAL_ERROR_IO_BAD_COUNT;  /* need a better error */
 
     /* call the local function */
     /* get the data directly into the output buffer */
-    check(rpc_encode_int(optr, olimit, length));
+    check(hal_xdr_encode_int(optr, olimit, length));
     ret = hal_rpc_local_hash_dispatch.finalize(hash, *optr, (size_t)length);
     if (ret == HAL_OK)
         *optr += pad(length);
@@ -274,25 +291,25 @@ static hal_error_t pkey_load(uint8_t **iptr, const uint8_t * const ilimit,
     hal_client_handle_t client;
     hal_session_handle_t session;
     hal_pkey_handle_t pkey;
-    hal_key_type_t type;
-    hal_curve_name_t curve;
+    uint32_t type;
+    uint32_t curve;
     uint8_t *name, *der;
     uint32_t name_len, der_len;
     hal_key_flags_t flags;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &session.handle));
-    check(rpc_decode_int(iptr, ilimit, &type));
-    check(rpc_decode_int(iptr, ilimit, &curve));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &der, &der_len));
-    check(rpc_decode_int(iptr, ilimit, &flags));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &type));
+    check(hal_xdr_decode_int(iptr, ilimit, &curve));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &der, &der_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &flags));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.load(client, session, &pkey, type, curve, name, name_len, der, der_len, flags);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, pkey.handle));
+        check(hal_xdr_encode_int(optr, olimit, pkey.handle));
     return ret;
 }
 
@@ -302,20 +319,20 @@ static hal_error_t pkey_find(uint8_t **iptr, const uint8_t * const ilimit,
     hal_client_handle_t client;
     hal_session_handle_t session;
     hal_pkey_handle_t pkey;
-    hal_key_type_t type;
+    uint32_t type;
     uint8_t *name;
     uint32_t name_len;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &session.handle));
-    check(rpc_decode_int(iptr, ilimit, &type));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &type));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.find(client, session, &pkey, type, name, name_len);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, pkey.handle));
+        check(hal_xdr_encode_int(optr, olimit, pkey.handle));
     return ret;
 }
 
@@ -327,23 +344,23 @@ static hal_error_t pkey_generate_rsa(uint8_t **iptr, const uint8_t * const ilimi
     hal_pkey_handle_t pkey;
     uint8_t *name;
     uint32_t name_len;
-    unsigned key_len;
+    uint32_t key_len;
     uint8_t *exp;
     uint32_t exp_len;
     hal_key_flags_t flags;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &session.handle));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
-    check(rpc_decode_int(iptr, ilimit, &key_len));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &exp, &exp_len));
-    check(rpc_decode_int(iptr, ilimit, &flags));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &key_len));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &exp, &exp_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &flags));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.generate_rsa(client, session, &pkey, name, name_len, key_len, exp, exp_len, flags);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, pkey.handle));
+        check(hal_xdr_encode_int(optr, olimit, pkey.handle));
     return ret;
 }
 
@@ -355,20 +372,20 @@ static hal_error_t pkey_generate_ec(uint8_t **iptr, const uint8_t * const ilimit
     hal_pkey_handle_t pkey;
     uint8_t *name;
     uint32_t name_len;
-    hal_curve_name_t curve;
+    uint32_t curve;
     hal_key_flags_t flags;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &client.handle));
-    check(rpc_decode_int(iptr, ilimit, &session.handle));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
-    check(rpc_decode_int(iptr, ilimit, &curve));
-    check(rpc_decode_int(iptr, ilimit, &flags));
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &curve));
+    check(hal_xdr_decode_int(iptr, ilimit, &flags));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.generate_ec(client, session, &pkey, name, name_len, curve, flags);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, pkey.handle));
+        check(hal_xdr_encode_int(optr, olimit, pkey.handle));
     return ret;
 }
 
@@ -378,7 +395,7 @@ static hal_error_t pkey_close(uint8_t **iptr, const uint8_t * const ilimit,
     hal_pkey_handle_t pkey;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.close(pkey);
@@ -391,7 +408,7 @@ static hal_error_t pkey_delete(uint8_t **iptr, const uint8_t * const ilimit,
     hal_pkey_handle_t pkey;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.delete(pkey);
@@ -405,12 +422,12 @@ static hal_error_t pkey_get_key_type(uint8_t **iptr, const uint8_t * const ilimi
     hal_key_type_t type;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.get_key_type(pkey, &type);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, type));
+        check(hal_xdr_encode_int(optr, olimit, type));
     return ret;
 }
 
@@ -421,12 +438,12 @@ static hal_error_t pkey_get_key_flags(uint8_t **iptr, const uint8_t * const ilim
     hal_key_flags_t flags;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.get_key_flags(pkey, &flags);
     if (ret == HAL_OK)
-        check(rpc_encode_int(optr, olimit, flags));
+        check(hal_xdr_encode_int(optr, olimit, flags));
     return ret;
 }
 
@@ -437,11 +454,11 @@ static hal_error_t pkey_get_public_key_len(uint8_t **iptr, const uint8_t * const
     size_t len;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
 
     /* call the local function */
     len = hal_rpc_local_pkey_dispatch.get_public_key_len(pkey);
-    check(rpc_encode_int(optr, olimit, len));
+    check(hal_xdr_encode_int(optr, olimit, len));
     return HAL_OK;
 }
 
@@ -454,8 +471,8 @@ static hal_error_t pkey_get_public_key(uint8_t **iptr, const uint8_t * const ili
     uint8_t *optr_orig = *optr;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
-    check(rpc_decode_int(iptr, ilimit, &len_max));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &len_max));
     /* sanity check len_max */
     if (len_max > olimit - *optr - 4)
         return HAL_ERROR_IO_BAD_COUNT;  /* need a better error */
@@ -466,7 +483,7 @@ static hal_error_t pkey_get_public_key(uint8_t **iptr, const uint8_t * const ili
     ret = hal_rpc_local_pkey_dispatch.get_public_key(pkey, *optr, &len, len_max);
     if (ret == HAL_OK) {
         *optr = optr_orig;
-        check(rpc_encode_int(optr, olimit, len));
+        check(hal_xdr_encode_int(optr, olimit, len));
         *optr += pad(len);
     }
     else {
@@ -489,11 +506,11 @@ static hal_error_t pkey_remote_sign(uint8_t **iptr, const uint8_t * const ilimit
     uint8_t *optr_orig = *optr;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &session.handle));
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
-    check(rpc_decode_int(iptr, ilimit, &hash.handle));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &input, &input_len));
-    check(rpc_decode_int(iptr, ilimit, &sig_max));
+    check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &input, &input_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &sig_max));
     /* sanity check sig_max */
     if (sig_max > olimit - *optr - 4)
         return HAL_ERROR_IO_BAD_COUNT;  /* need a better error */
@@ -504,7 +521,7 @@ static hal_error_t pkey_remote_sign(uint8_t **iptr, const uint8_t * const ilimit
     ret = hal_rpc_local_pkey_dispatch.sign(session, pkey, hash, input, input_len, *optr, &sig_len, sig_max);
     *optr = optr_orig;
     if (ret == HAL_OK) {
-        check(rpc_encode_int(optr, olimit, sig_len));
+        check(hal_xdr_encode_int(optr, olimit, sig_len));
         *optr += pad(sig_len);
     }
     return ret;
@@ -522,26 +539,26 @@ static hal_error_t pkey_remote_verify(uint8_t **iptr, const uint8_t * const ilim
     uint32_t sig_len;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &session.handle));
-    check(rpc_decode_int(iptr, ilimit, &pkey.handle));
-    check(rpc_decode_int(iptr, ilimit, &hash.handle));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &input, &input_len));
-    check(rpc_decode_buffer_in_place(iptr, ilimit, &sig, &sig_len));
+    check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &input, &input_len));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &sig, &sig_len));
 
     /* call the local function */
     ret = hal_rpc_local_pkey_dispatch.verify(session, pkey, hash, input, input_len, sig, sig_len);
     return ret;
 }
 
-static hal_error_t rpc_encode_pkey_info(uint8_t **optr, const uint8_t * const olimit, const hal_pkey_info_t *info)
+static hal_error_t hal_xdr_encode_pkey_info(uint8_t **optr, const uint8_t * const olimit, const hal_pkey_info_t *info)
 {
     uint8_t *optr_orig = *optr;
     hal_error_t ret;
     
-    if ((ret = rpc_encode_int(optr, olimit, info->type)) != HAL_OK ||
-        (ret = rpc_encode_int(optr, olimit, info->curve)) != HAL_OK ||
-        (ret = rpc_encode_int(optr, olimit, info->flags)) != HAL_OK ||
-        (ret = rpc_encode_buffer(optr, olimit, (uint8_t *)&info->name[0], info->name_len)) != HAL_OK)
+    if ((ret = hal_xdr_encode_int(optr, olimit, info->type)) != HAL_OK ||
+        (ret = hal_xdr_encode_int(optr, olimit, info->curve)) != HAL_OK ||
+        (ret = hal_xdr_encode_int(optr, olimit, info->flags)) != HAL_OK ||
+        (ret = hal_xdr_encode_buffer(optr, olimit, (uint8_t *)&info->name[0], info->name_len)) != HAL_OK)
         *optr = optr_orig;
     return ret;
 }
@@ -554,7 +571,7 @@ static hal_error_t pkey_list(uint8_t **iptr, const uint8_t * const ilimit,
     uint32_t result_max;
     hal_error_t ret;
 
-    check(rpc_decode_int(iptr, ilimit, &result_max));
+    check(hal_xdr_decode_int(iptr, ilimit, &result_max));
 
     hal_pkey_info_t result[result_max];
     unsigned result_len;
@@ -563,9 +580,9 @@ static hal_error_t pkey_list(uint8_t **iptr, const uint8_t * const ilimit,
     ret = hal_rpc_local_pkey_dispatch.list(result, &result_len, result_max);
     if (ret == HAL_OK) {
         int i;
-        check(rpc_encode_int(optr, olimit, result_len));
+        check(hal_xdr_encode_int(optr, olimit, result_len));
         for (i = 0; i < result_len; ++i) {
-            if ((ret = rpc_encode_pkey_info(optr, olimit, &result[i])) != HAL_OK) {
+            if ((ret = hal_xdr_encode_pkey_info(optr, olimit, &result[i])) != HAL_OK) {
                 *optr = optr_orig;
                 break;
             }
@@ -577,24 +594,27 @@ static hal_error_t pkey_list(uint8_t **iptr, const uint8_t * const ilimit,
 #define MAX_PKT_SIZE 1024
 #define interrupt 0
 
-void rpc_server_main(void)
+void hal_rpc_server_main(void)
 {
     uint8_t inbuf[MAX_PKT_SIZE], outbuf[MAX_PKT_SIZE];
     uint8_t *iptr, *ilimit, *optr, *olimit;
     size_t ilen, olen;
-    rpc_func_num_t rpc_func_num;
+    uint32_t rpc_func_num;
     void *opaque;
     hal_error_t ret;
     
     while (!interrupt) {
         ilen = sizeof(inbuf);
-        if (rpc_recvfrom(inbuf, &ilen, &opaque) == HAL_OK) {
+        if (hal_rpc_recvfrom(inbuf, &ilen, &opaque) == HAL_OK) {
             iptr = inbuf;
             ilimit = inbuf + ilen;
             optr = outbuf + 4;  /* reserve 4 bytes for return code */
             olimit = outbuf + sizeof(outbuf);
-            rpc_decode_int(&iptr, ilimit, &rpc_func_num);
+            hal_xdr_decode_int(&iptr, ilimit, &rpc_func_num);
             switch (rpc_func_num) {
+            case RPC_FUNC_GET_VERSION:
+                ret = get_version(&iptr, ilimit, &optr, olimit);
+                break;
             case RPC_FUNC_GET_RANDOM:
                 ret = get_random(&iptr, ilimit, &optr, olimit);
                 break;
@@ -677,8 +697,8 @@ void rpc_server_main(void)
             /* encode the return code at the beginning of the payload */
             olen = optr - outbuf;
             optr = outbuf;
-            rpc_encode_int(&optr, olimit, ret);
-            rpc_sendto(outbuf, olen, opaque);
+            hal_xdr_encode_int(&optr, olimit, ret);
+            hal_rpc_sendto(outbuf, olen, opaque);
         }
     }
 }
@@ -691,14 +711,14 @@ const hal_rpc_misc_dispatch_t *hal_rpc_misc_dispatch = &hal_rpc_local_misc_dispa
 const hal_rpc_hash_dispatch_t *hal_rpc_hash_dispatch = &hal_rpc_local_hash_dispatch;
 const hal_rpc_pkey_dispatch_t *hal_rpc_pkey_dispatch = &hal_rpc_local_pkey_dispatch;
 
-hal_error_t rpc_server_init(void)
+hal_error_t hal_rpc_server_init(void)
 {
-    return rpc_server_transport_init();
+    return hal_rpc_server_transport_init();
 }
 
-hal_error_t rpc_server_close(void)
+hal_error_t hal_rpc_server_close(void)
 {
-    return rpc_server_transport_close();
+    return hal_rpc_server_transport_close();
 }
 
 
diff --git a/rpc_server_loopback.c b/rpc_server_loopback.c
index a39e12b..4ca7467 100644
--- a/rpc_server_loopback.c
+++ b/rpc_server_loopback.c
@@ -41,47 +41,47 @@
 #include "hal.h"
 #include "hal_internal.h"
 
-static int sock;
+static int fd;
 
-hal_error_t rpc_server_transport_init(void)
+hal_error_t hal_rpc_server_transport_init(void)
 {
     struct sockaddr_in sin;
 
-    sock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sock == -1)
+    fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (fd == -1)
 	return perror("socket"), HAL_ERROR_RPC_TRANSPORT;
     sin.sin_family = AF_INET;
     sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
     sin.sin_port = 17425;
-    if (bind(sock, (const struct sockaddr *)&sin, sizeof(sin)) != 0)
+    if (bind(fd, (const struct sockaddr *)&sin, sizeof(sin)) != 0)
 	return perror("bind"), HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_server_transport_close(void)
+hal_error_t hal_rpc_server_transport_close(void)
 {
-    if (close(sock) != 0)
+    if (close(fd) != 0)
 	return perror("close"), HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque)
+hal_error_t hal_rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque)
 {
     struct sockaddr_in *sin = (struct sockaddr_in *)opaque;
     int ret;
 
-    if ((ret = sendto(sock, buf, len, 0, (struct sockaddr *)sin, sizeof(*sin))) == -1)
+    if ((ret = sendto(fd, buf, len, 0, (struct sockaddr *)sin, sizeof(*sin))) == -1)
 	return perror("sendto"), HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque)
+hal_error_t hal_rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque)
 {
     static struct sockaddr_in sin;
     socklen_t sin_len = sizeof(sin);
     int ret;
     
-    if ((ret = recvfrom(sock, buf, *len, 0, (struct sockaddr *)&sin, &sin_len)) == -1)
+    if ((ret = recvfrom(fd, buf, *len, 0, (struct sockaddr *)&sin, &sin_len)) == -1)
 	return HAL_ERROR_RPC_TRANSPORT;
     *opaque = (void *)&sin;
     *len = ret;
diff --git a/rpc_client_loopback.c b/rpc_server_serial.c
similarity index 60%
copy from rpc_client_loopback.c
copy to rpc_server_serial.c
index a3d7e73..d896700 100644
--- a/rpc_client_loopback.c
+++ b/rpc_server_serial.c
@@ -1,7 +1,7 @@
 /*
- * rpc_client_loopback.c
- * ---------------------
- * Remote procedure call transport over loopback socket.
+ * rpc_server_serial.c
+ * -------------------
+ * Remote procedure call transport over serial line with SLIP framing.
  *
  * Copyright (c) 2016, NORDUnet A/S All rights reserved.
  *
@@ -32,54 +32,48 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <unistd.h>     /* close */
-
 #include "hal.h"
 #include "hal_internal.h"
+#include "slip_internal.h"
 
-static int sock = -1;
+/* Don't include stm-uart.h to avoid conflicting definitions of HAL_OK.
+ */
+extern int uart_send_char(uint8_t ch);
+extern int uart_recv_char(uint8_t *cp);
 
-hal_error_t rpc_client_transport_init(void)
+hal_error_t hal_rpc_server_transport_init(void)
 {
-    struct sockaddr_in sin;
-
-    sock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sock == -1)
-        return perror("socket"), HAL_ERROR_RPC_TRANSPORT;
-    sin.sin_family = AF_INET;
-    sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    sin.sin_port = 17425;
-    if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) != 0)
-        return perror("connect"), HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_client_transport_close(void)
+hal_error_t hal_rpc_server_transport_close(void)
 {
-    int ret = close(sock);
-    sock = -1;
-    if (ret != 0)
-        return perror("close"), HAL_ERROR_RPC_TRANSPORT;
     return HAL_OK;
 }
 
-hal_error_t rpc_send(const uint8_t * const buf, const size_t len)
+hal_error_t hal_rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque)
 {
-    if (send(sock, buf, len, 0) == -1)
-        return perror("send"), HAL_ERROR_RPC_TRANSPORT;
-    return HAL_OK;
+    if (hal_slip_send(buf, len) == -1)
+        return HAL_ERROR_RPC_TRANSPORT;
+    return HAL_OK; 
 }
 
-hal_error_t rpc_recv(uint8_t * const buf, size_t * const len)
+hal_error_t hal_rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque)
 {
     int ret;
     
-    if ((ret = recv(sock, buf, *len, 0)) == -1)
+    if ((ret = hal_slip_recv(buf, *len)) == -1)
         return HAL_ERROR_RPC_TRANSPORT;
     *len = ret;
     return HAL_OK;
 }
+
+int hal_slip_send_char(uint8_t c)
+{
+    return (uart_send_char(c) == 0) ? 0 : -1;
+}
+
+int hal_slip_recv_char(uint8_t *c)
+{
+    return (uart_recv_char(c) == 0) ? 0 : -1;
+}
diff --git a/slip.c b/slip.c
new file mode 100644
index 0000000..3b448f4
--- /dev/null
+++ b/slip.c
@@ -0,0 +1,141 @@
+/* SLIP send/recv code, from RFC 1055 */
+
+#include <stdio.h>      /* perror */
+
+#include "slip_internal.h"
+
+/* SLIP special character codes
+ */
+#define END             0300    /* indicates end of packet */
+#define ESC             0333    /* indicates byte stuffing */
+#define ESC_END         0334    /* ESC ESC_END means END data byte */
+#define ESC_ESC         0335    /* ESC ESC_ESC means ESC data byte */
+
+/* SLIP_SEND: sends a packet of length "len", starting at
+ * location "p".
+ */
+int hal_slip_send(const uint8_t * const ptr, const size_t len)
+{
+    int i;
+    uint8_t *p = (uint8_t *)ptr;
+
+#define check_send_char(c) if (hal_slip_send_char(c) == -1) return perror("write"), -1;
+
+    /* send an initial END character to flush out any data that may
+     * have accumulated in the receiver due to line noise
+     */
+    check_send_char(END);
+
+    /* for each byte in the packet, send the appropriate character
+     * sequence
+     */
+    for (i = 0; i < len; ++i) {
+        switch (*p) {
+            /* if it's the same code as an END character, we send a
+             * special two character code so as not to make the
+             * receiver think we sent an END
+             */
+        case END:
+            check_send_char(ESC);
+            check_send_char(ESC_END);
+            break;
+
+            /* if it's the same code as an ESC character,
+             * we send a special two character code so as not
+             * to make the receiver think we sent an ESC
+             */
+        case ESC:
+            check_send_char(ESC);
+            check_send_char(ESC_ESC);
+            break;
+
+            /* otherwise, we just send the character
+             */
+        default:
+            check_send_char(*p);
+        }
+
+        p++;
+    }
+
+    /* tell the receiver that we're done sending the packet
+     */
+    check_send_char(END);
+
+    return 0;
+#undef check_send_char
+}
+
+/* SLIP_RECV: receives a packet into the buffer located at "p".
+ *      If more than len bytes are received, the packet will
+ *      be truncated.
+ *      Returns the number of bytes stored in the buffer.
+ */
+int hal_slip_recv(uint8_t * const p, const size_t len)
+{
+    uint8_t c;
+    size_t received = 0;
+
+#define check_recv_char(c) if (hal_slip_recv_char(&c) == -1) return perror("read"), -1;
+
+    /* sit in a loop reading bytes until we put together
+     * a whole packet.
+     * Make sure not to copy them into the packet if we
+     * run out of room.
+     */
+    while (1) {
+        /* get a character to process
+         */
+        check_recv_char(c);
+
+        /* handle bytestuffing if necessary
+         */
+        switch (c) {
+
+            /* if it's an END character then we're done with
+             * the packet
+             */
+        case END:
+            /* a minor optimization: if there is no
+             * data in the packet, ignore it. This is
+             * meant to avoid bothering IP with all
+             * the empty packets generated by the
+             * duplicate END characters which are in
+             * turn sent to try to detect line noise.
+             */
+            if (received)
+                return received;
+            else
+                break;
+
+            /* if it's the same code as an ESC character, wait
+             * and get another character and then figure out
+             * what to store in the packet based on that.
+             */
+        case ESC:
+            check_recv_char(c);
+
+            /* if "c" is not one of these two, then we
+             * have a protocol violation.  The best bet
+             * seems to be to leave the byte alone and
+             * just stuff it into the packet
+             */
+            switch(c) {
+            case ESC_END:
+                c = END;
+                break;
+            case ESC_ESC:
+                c = ESC;
+                break;
+            }
+
+            /* here we fall into the default handler and let
+             * it store the character for us
+             */
+        default:
+            if (received < len)
+                p[received++] = c;
+        }
+    }
+#undef check_recv_char
+}
diff --git a/rpc_client_loopback.c b/slip_internal.h
similarity index 55%
copy from rpc_client_loopback.c
copy to slip_internal.h
index a3d7e73..103f72d 100644
--- a/rpc_client_loopback.c
+++ b/slip_internal.h
@@ -1,7 +1,7 @@
 /*
- * rpc_client_loopback.c
- * ---------------------
- * Remote procedure call transport over loopback socket.
+ * slip_internal.h
+ * ---------------
+ * Send/recv data over a serial connection with SLIP framing
  *
  * Copyright (c) 2016, NORDUnet A/S All rights reserved.
  *
@@ -32,54 +32,20 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <unistd.h>     /* close */
+#ifndef _HAL_SLIP_INTERNAL_H
+#define _HAL_SLIP_INTERNAL_H
 
-#include "hal.h"
 #include "hal_internal.h"
 
-static int sock = -1;
-
-hal_error_t rpc_client_transport_init(void)
-{
-    struct sockaddr_in sin;
-
-    sock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sock == -1)
-        return perror("socket"), HAL_ERROR_RPC_TRANSPORT;
-    sin.sin_family = AF_INET;
-    sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    sin.sin_port = 17425;
-    if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) != 0)
-        return perror("connect"), HAL_ERROR_RPC_TRANSPORT;
-    return HAL_OK;
-}
-
-hal_error_t rpc_client_transport_close(void)
-{
-    int ret = close(sock);
-    sock = -1;
-    if (ret != 0)
-        return perror("close"), HAL_ERROR_RPC_TRANSPORT;
-    return HAL_OK;
-}
+/* Defined in slip.c - send/recv a block of data with SLIP framing.
+ */
+extern int hal_slip_send(const uint8_t * const p, const size_t len);
+extern int hal_slip_recv(uint8_t * const p, const size_t len);
 
-hal_error_t rpc_send(const uint8_t * const buf, const size_t len)
-{
-    if (send(sock, buf, len, 0) == -1)
-        return perror("send"), HAL_ERROR_RPC_TRANSPORT;
-    return HAL_OK;
-}
+/* Defined in rpc_[client|server]_serial.c - send/recv one byte over a
+ * serial connection.
+ */
+extern int hal_slip_send_char(const uint8_t c);
+extern int hal_slip_recv_char(uint8_t * const c);
 
-hal_error_t rpc_recv(uint8_t * const buf, size_t * const len)
-{
-    int ret;
-    
-    if ((ret = recv(sock, buf, *len, 0)) == -1)
-        return HAL_ERROR_RPC_TRANSPORT;
-    *len = ret;
-    return HAL_OK;
-}
+#endif /* _HAL_SLIP_INTERNAL_H */
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
index 2f026a1..b4d006d 100644
--- a/tests/GNUmakefile
+++ b/tests/GNUmakefile
@@ -29,8 +29,22 @@
 
 INC	= ../hal.h
 LIB	= ../libhal.a
-BIN	= test-aes-key-wrap test-hash test-pbkdf2 test-ecdsa test-bus test-trng test-rsa
-BIN	+= test-rpc_hash test-rpc_server
+BIN	:= test-aes-key-wrap test-hash test-pbkdf2 test-ecdsa test-bus test-trng test-rsa
+ifndef RPC_SERVER
+  ifdef RPC_CLIENT
+    ifneq (${RPC_CLIENT},local)
+      # If we're only building a remote RPC client lib, don't include
+      # tests that access the FPGA cores.
+      BIN :=
+    endif
+  endif
+endif
+ifdef RPC_CLIENT
+  BIN	+= test-rpc_hash
+endif
+ifdef RPC_SERVER
+  BIN	+= test-rpc_server
+endif
 
 CFLAGS	= -g3 -Wall -fPIC -std=c99 -I..
 
diff --git a/tests/test-rpc_hash.c b/tests/test-rpc_hash.c
index d59e341..38bb793 100644
--- a/tests/test-rpc_hash.c
+++ b/tests/test-rpc_hash.c
@@ -636,11 +636,10 @@ static int _test_hmac(const hal_digest_algorithm_t alg,
 
 int main (int argc, char *argv[])
 {
-//  rpc_client_init(RPC_LOCAL);
-  rpc_client_init(RPC_REMOTE);
-
   int ok = 1;
 
+  ok &= hal_rpc_client_init();
+
   ok &= test_hash(hal_digest_algorithm_sha1,   nist_512_single, sha1_single_digest, "SHA-1 single block");
   ok &= test_hash(hal_digest_algorithm_sha1,   nist_512_double, sha1_double_digest, "SHA-1 double block");
 
@@ -688,6 +687,8 @@ int main (int argc, char *argv[])
   ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha512, "HMAC-SHA-512 test case 6");
   ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha512, "HMAC-SHA-512 test case 7");
 
+  ok &= hal_rpc_client_close();
+
   return !ok;
 }
 
diff --git a/tests/test-rpc_server.c b/tests/test-rpc_server.c
index 6eff755..eb11f6d 100644
--- a/tests/test-rpc_server.c
+++ b/tests/test-rpc_server.c
@@ -1,16 +1,10 @@
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
-
 #include <hal.h>
-#include <hal_internal.h>
 
 int main (int argc, char *argv[])
 {
-    if (rpc_server_init() != HAL_OK)
+    if (hal_rpc_server_init() != HAL_OK)
 	return 1;
 
-    rpc_server_main();
+    hal_rpc_server_main();
     return 0;
 }
diff --git a/rpc_xdr.c b/xdr.c
similarity index 59%
rename from rpc_xdr.c
rename to xdr.c
index 69b8482..2741752 100644
--- a/rpc_xdr.c
+++ b/xdr.c
@@ -1,6 +1,6 @@
 /*
- * rpc_xdr.c
- * ---------
+ * xdr.c
+ * -----
  * Serialization/deserialization routines, using XDR (RFC 4506) encoding.
  *
  * Copyright (c) 2016, NORDUnet A/S All rights reserved.
@@ -34,41 +34,59 @@
 
 #include <stdio.h>
 #include <stdint.h>
-#include <string.h>		/* memcpy */
-#include <strings.h>		/* bzero */
-#include <arpa/inet.h>		/* htonl/ntohl */
+#include <string.h>             /* memcpy, memset */
+
+#ifndef STM32F4XX
+#include <arpa/inet.h>          /* htonl/ntohl */
+#else
+/* htonl is not available in arm-none-eabi headers or libc */
+#ifdef __ARMEL__                /* little endian */
+static inline uint32_t htonl(uint32_t w)
+{
+  return
+    ((w & 0x000000ff) << 24) +
+    ((w & 0x0000ff00) << 8) +
+    ((w & 0x00ff0000) >> 8) +
+    ((w & 0xff000000) >> 24);
+}
+#else
+#define htonl(x) (x)
+#endif
+#define ntohl htonl
+#endif
 
 #include "hal.h"
+#include "xdr_internal.h"
 
 /* encode/decode_int. This covers int, unsigned int, enum, and bool types,
  * which are all encoded as 32-bit big-endian fields. Signed integers are
  * defined to use two's complement, but that's universal these days, yes?
  */
 
-hal_error_t rpc_encode_int(uint8_t ** const outbuf, const uint8_t * const limit, const uint32_t value)
+hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf, const uint8_t * const limit, const uint32_t value)
 {
     /* arg checks */
     if (outbuf == NULL || *outbuf == NULL || limit == NULL)
-	return HAL_ERROR_BAD_ARGUMENTS;
+        return HAL_ERROR_BAD_ARGUMENTS;
 
     /* buffer overflow check */
     if (limit - *outbuf < sizeof(value))
-	return HAL_ERROR_IO_BAD_COUNT;
+        return HAL_ERROR_IO_BAD_COUNT;
 
     **(uint32_t **)outbuf = htonl(value);
     *outbuf += sizeof(value);
     return HAL_OK;
 }
 
-hal_error_t rpc_decode_int(uint8_t **inbuf, const uint8_t * const limit, uint32_t *value)
+hal_error_t hal_xdr_decode_int(uint8_t **inbuf, const uint8_t * const limit, uint32_t *value)
 {
     /* arg checks */
     if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL)
-	return HAL_ERROR_BAD_ARGUMENTS;
+        return HAL_ERROR_BAD_ARGUMENTS;
 
     /* buffer overflow check */
     if (limit - *inbuf < sizeof(*value))
-	return HAL_ERROR_IO_BAD_COUNT;
+        return HAL_ERROR_IO_BAD_COUNT;
 
     *value = ntohl(**(uint32_t **)inbuf);
     *inbuf += sizeof(*value);
@@ -80,22 +98,22 @@ hal_error_t rpc_decode_int(uint8_t **inbuf, const uint8_t * const limit, uint32_
  * to a multiple of 4 bytes as necessary.
  */
 
-hal_error_t rpc_encode_buffer(uint8_t **outbuf, const uint8_t * const limit, const uint8_t *value, const uint32_t len)
+hal_error_t hal_xdr_encode_buffer(uint8_t **outbuf, const uint8_t * const limit, const uint8_t *value, const uint32_t len)
 {
     hal_error_t ret;
 
     /* arg checks */
     if (outbuf == NULL || *outbuf == NULL || limit == NULL || 
-	(value == NULL && len != 0))
-	return HAL_ERROR_BAD_ARGUMENTS;
+        (value == NULL && len != 0))
+        return HAL_ERROR_BAD_ARGUMENTS;
 
     /* buffer overflow check */
     if ((limit - *outbuf) < (((len + 3) & ~3) + sizeof(len)))
-	return HAL_ERROR_IO_BAD_COUNT;
+        return HAL_ERROR_IO_BAD_COUNT;
 
     /* encode length */
-    if ((ret = rpc_encode_int(outbuf, limit, len)) != HAL_OK)
-	return ret;
+    if ((ret = hal_xdr_encode_int(outbuf, limit, len)) != HAL_OK)
+        return ret;
 
     /* write the string or opaque data */
     memcpy(*outbuf, value, len);
@@ -103,9 +121,9 @@ hal_error_t rpc_encode_buffer(uint8_t **outbuf, const uint8_t * const limit, con
 
     /* pad if necessary */
     if (len & 3) {
-	size_t n = 4 - (len & 3);
-	bzero(*outbuf, n);
-	*outbuf += n;
+        size_t n = 4 - (len & 3);
+        memset(*outbuf, 0, n);
+        *outbuf += n;
     }
 
     return HAL_OK;
@@ -114,7 +132,7 @@ hal_error_t rpc_encode_buffer(uint8_t **outbuf, const uint8_t * const limit, con
 /* This version returns a pointer to the data in the input buffer.
  * It is used in the rpc server.
  */
-hal_error_t rpc_decode_buffer_in_place(uint8_t **inbuf, const uint8_t * const limit, uint8_t ** const value, uint32_t * const len)
+hal_error_t hal_xdr_decode_buffer_in_place(uint8_t **inbuf, const uint8_t * const limit, uint8_t ** const value, uint32_t * const len)
 {
     hal_error_t ret;
     uint32_t xdr_len;
@@ -122,11 +140,11 @@ hal_error_t rpc_decode_buffer_in_place(uint8_t **inbuf, const uint8_t * const li
 
     /* arg checks */
     if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL || len == NULL)
-	return HAL_ERROR_BAD_ARGUMENTS;
+        return HAL_ERROR_BAD_ARGUMENTS;
 
     /* decode the length */
-    if ((ret = rpc_decode_int(inbuf, limit, &xdr_len)) != HAL_OK)
-	return ret;
+    if ((ret = hal_xdr_decode_int(inbuf, limit, &xdr_len)) != HAL_OK)
+        return ret;
 
     /* input and output buffer overflow checks vs decoded length */
 
@@ -134,18 +152,18 @@ hal_error_t rpc_decode_buffer_in_place(uint8_t **inbuf, const uint8_t * const li
      * we're probably out of sync, but nothing we can do now
      */
     if (limit - *inbuf < xdr_len) {
-	/* undo read of length */
-	*inbuf = orig_inbuf;
-	return HAL_ERROR_IO_BAD_COUNT;
+        /* undo read of length */
+        *inbuf = orig_inbuf;
+        return HAL_ERROR_IO_BAD_COUNT;
     }
 
     /* user buffer is too small, update *len
      */
     if (*len < xdr_len) {
-	*len = xdr_len;
-	/* undo read of length */
-	*inbuf = orig_inbuf;
-	return HAL_ERROR_IO_BAD_COUNT;
+        *len = xdr_len;
+        /* undo read of length */
+        *inbuf = orig_inbuf;
+        return HAL_ERROR_IO_BAD_COUNT;
     }
 
     /* return a pointer to the string or opaque data */
@@ -161,29 +179,31 @@ hal_error_t rpc_decode_buffer_in_place(uint8_t **inbuf, const uint8_t * const li
 /* This version copies the data to the user-supplied buffer.
  * It is used in the rpc client.
  */
-hal_error_t rpc_decode_buffer(uint8_t **inbuf, const uint8_t * const limit, uint8_t * const value, uint32_t * const len)
+hal_error_t hal_xdr_decode_buffer(uint8_t **inbuf, const uint8_t * const limit, uint8_t * const value, uint32_t * const len)
 {
     hal_error_t ret;
     uint8_t *vptr;
 
-    if ((ret = rpc_decode_buffer_in_place(inbuf, limit, &vptr, len)) == HAL_OK)
-	memcpy(value, vptr, *len);
+    if ((ret = hal_xdr_decode_buffer_in_place(inbuf, limit, &vptr, len)) == HAL_OK)
+        memcpy(value, vptr, *len);
     return ret;
 }
 
+/* ---------------------------------------------------------------- */
+
 #ifdef TEST
 void hexdump(uint8_t *buf, uint32_t len)
 {
     int i;
 
     for (i = 0; i < len; ++i) {
-	uint8_t c = buf[i];
-	printf("%02x ", c);
-	if ((i & 0x07) == 0x07)
-	    printf("\n");
+        uint8_t c = buf[i];
+        printf("%02x ", c);
+        if ((i & 0x07) == 0x07)
+            printf("\n");
     }
     if ((len & 0x07) != 0)
-	printf("\n");
+        printf("\n");
 }
 
 int main(int argc, char *argv[])
@@ -196,48 +216,48 @@ int main(int argc, char *argv[])
     uint8_t alphabet[] = "abcdefghijklmnopqrstuvwxyz";
     uint8_t readbuf[64] = {0};
 
-    printf("rpc_encode_int: work to failure\n");
+    printf("hal_xdr_encode_int: work to failure\n");
     for (i = 1; i < 100; ++i) {
-	if ((ret = rpc_encode_int(&bufptr, limit, i)) != HAL_OK) {
-	    printf("%d: %s\n", i, hal_error_string(ret));
-	    break;
-	}
+        if ((ret = hal_xdr_encode_int(&bufptr, limit, i)) != HAL_OK) {
+            printf("%d: %s\n", i, hal_error_string(ret));
+            break;
+        }
     }
     hexdump(buf, ((uint8_t *)bufptr - buf));
 
-    printf("\nrpc_decode_int:\n");
+    printf("\nhal_xdr_decode_int:\n");
     readptr = buf;
     while (readptr < bufptr) {
-	if ((ret = rpc_decode_int(&readptr, limit, &i)) != HAL_OK) {
-	    printf("%s\n", hal_error_string(ret));
-	    break;
-	}
-	printf("%u ", i);
+        if ((ret = hal_xdr_decode_int(&readptr, limit, &i)) != HAL_OK) {
+            printf("%s\n", hal_error_string(ret));
+            break;
+        }
+        printf("%u ", i);
     }
     printf("\n");
 
-    printf("\nrpc_encode_buffer: work to failure\n");
-    bzero(buf, sizeof(buf));
+    printf("\nhal_xdr_encode_buffer: work to failure\n");
+    memset(buf, 0, sizeof(buf));
     bufptr = buf;
      for (i = 1; i < 10; ++i) {
-	if ((ret = rpc_encode_buffer(&bufptr, limit, alphabet, i)) != HAL_OK) {
-	    printf("%d: %s\n", i, hal_error_string(ret));
-	    break;
-	}
+        if ((ret = hal_xdr_encode_buffer(&bufptr, limit, alphabet, i)) != HAL_OK) {
+            printf("%d: %s\n", i, hal_error_string(ret));
+            break;
+        }
     }
     hexdump(buf, ((uint8_t *)bufptr - buf));
 
-    printf("\nrpc_decode_buffer:\n");
+    printf("\nhal_xdr_decode_buffer:\n");
     readptr = buf;
     i = sizeof(readbuf);
     while (readptr < bufptr) {
-	if ((ret = rpc_decode_buffer(&readptr, limit, readbuf, &i)) != HAL_OK) {
-	    printf("%s\n", hal_error_string(ret));
-	    break;
-	}
-	printf("%u: ", i); for (int j = 0; j < i; ++j) putchar(readbuf[j]); putchar('\n');
-	i = sizeof(readbuf);
-	bzero(readbuf, sizeof(readbuf));
+        if ((ret = hal_xdr_decode_buffer(&readptr, limit, readbuf, &i)) != HAL_OK) {
+            printf("%s\n", hal_error_string(ret));
+            break;
+        }
+        printf("%u: ", i); for (int j = 0; j < i; ++j) putchar(readbuf[j]); putchar('\n');
+        i = sizeof(readbuf);
+        memset(readbuf, 0, sizeof(readbuf));
     }
 
     return 0;
diff --git a/rpc_client_loopback.c b/xdr_internal.h
similarity index 53%
copy from rpc_client_loopback.c
copy to xdr_internal.h
index a3d7e73..00793b0 100644
--- a/rpc_client_loopback.c
+++ b/xdr_internal.h
@@ -1,7 +1,7 @@
 /*
- * rpc_client_loopback.c
- * ---------------------
- * Remote procedure call transport over loopback socket.
+ * xdr_internal.h
+ * --------------
+ * Serialization/deserialization routines, using XDR (RFC 4506) encoding.
  *
  * Copyright (c) 2016, NORDUnet A/S All rights reserved.
  *
@@ -32,54 +32,35 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <unistd.h>     /* close */
+#ifndef _XDR_INTERNAL_H
+#define _XDR_INTERNAL_H
 
-#include "hal.h"
-#include "hal_internal.h"
+ /*
+ * RPC serialization/deserialization routines, using XDR (RFC 4506) encoding.
+ */
+
+hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf,
+                               const uint8_t * const limit,
+                               const uint32_t value);
 
-static int sock = -1;
+hal_error_t hal_xdr_decode_int(uint8_t ** const inbuf,
+                               const uint8_t * const limit,
+                               uint32_t * const value);
 
-hal_error_t rpc_client_transport_init(void)
-{
-    struct sockaddr_in sin;
+hal_error_t hal_xdr_encode_buffer(uint8_t ** const outbuf,
+                                  const uint8_t * const limit,
+                                  const uint8_t * const value,
+                                  const uint32_t len);
 
-    sock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sock == -1)
-        return perror("socket"), HAL_ERROR_RPC_TRANSPORT;
-    sin.sin_family = AF_INET;
-    sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-    sin.sin_port = 17425;
-    if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) != 0)
-        return perror("connect"), HAL_ERROR_RPC_TRANSPORT;
-    return HAL_OK;
-}
+hal_error_t hal_xdr_decode_buffer_in_place(uint8_t ** const inbuf,
+                                           const uint8_t * const limit,
+                                           uint8_t ** const vptr,
+                                           uint32_t * const len);
 
-hal_error_t rpc_client_transport_close(void)
-{
-    int ret = close(sock);
-    sock = -1;
-    if (ret != 0)
-        return perror("close"), HAL_ERROR_RPC_TRANSPORT;
-    return HAL_OK;
-}
+hal_error_t hal_xdr_decode_buffer(uint8_t ** const inbuf,
+                                  const uint8_t * const limit,
+                                  uint8_t * const value,
+                                  uint32_t * const len);
 
-hal_error_t rpc_send(const uint8_t * const buf, const size_t len)
-{
-    if (send(sock, buf, len, 0) == -1)
-        return perror("send"), HAL_ERROR_RPC_TRANSPORT;
-    return HAL_OK;
-}
 
-hal_error_t rpc_recv(uint8_t * const buf, size_t * const len)
-{
-    int ret;
-    
-    if ((ret = recv(sock, buf, *len, 0)) == -1)
-        return HAL_ERROR_RPC_TRANSPORT;
-    *len = ret;
-    return HAL_OK;
-}
+#endif /* _XDR_INTERNAL_H*/



More information about the Commits mailing list