Revert "Support message CRCs in the transport protocol."

This reverts commit 8cec2e5d378b530dcf3de66ac2d5b52602aec6e7.

We need fastboot support first

Change-Id: I67251eb7ccb8f3416218c96aa3eb9de2f5e74193
Signed-off-by: Bill Richardson <wfrichar@google.com>
diff --git a/libnos_transport/Android.bp b/libnos_transport/Android.bp
index bb8dd4f..9e4703e 100644
--- a/libnos_transport/Android.bp
+++ b/libnos_transport/Android.bp
@@ -18,7 +18,6 @@
     name: "libnos_transport",
     srcs: [
         "transport.c",
-        "crc16.c",
     ],
     defaults: ["nos_cc_host_supported_defaults"],
     cflags: [
diff --git a/libnos_transport/BUILD b/libnos_transport/BUILD
index f101166..79e253d 100644
--- a/libnos_transport/BUILD
+++ b/libnos_transport/BUILD
@@ -2,8 +2,6 @@
     name = "libnos_transport",
     srcs = [
         "transport.c",
-        "crc16.c",
-        "crc16.h",
     ],
     hdrs = [
         "include/nos/transport.h",
diff --git a/libnos_transport/crc16.c b/libnos_transport/crc16.c
deleted file mode 100644
index a6c3c5a..0000000
--- a/libnos_transport/crc16.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "crc16.h"
-
-static const uint16_t crc16_table[256] = {
-  0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
-  0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
-  0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
-  0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
-  0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
-  0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
-  0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
-  0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
-  0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
-  0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
-  0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
-  0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
-  0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
-  0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
-  0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
-  0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
-  0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
-  0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
-  0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
-  0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
-  0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
-  0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
-  0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
-  0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
-  0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
-  0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
-  0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
-  0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
-  0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
-  0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
-  0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
-  0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-};
-
-uint16_t crc16_update(const void *buf, uint32_t len, uint16_t crc) {
-  uint32_t i;
-  const uint8_t *bytes = buf;
-  for (i = 0; i < len; ++i) {
-    crc = crc16_table[((crc >> 8) ^ *bytes++) & 0xFF] ^ (crc << 8);
-  }
-  return crc;
-}
-
-uint16_t crc16(const void *buf, uint32_t len) {
-  return crc16_update(buf, len, 0);
-}
diff --git a/libnos_transport/crc16.h b/libnos_transport/crc16.h
deleted file mode 100644
index 5b9838b..0000000
--- a/libnos_transport/crc16.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef NOS_TRANSPORT_CRC16_H
-#define NOS_TRANSPORT_CRC16_H
-
-#include <stdint.h>
-
-/**
- * Calculate the CRC-16 of the data.
- *
- * This uses the CRC-16-IBM variant: 0x8005 (x^16 + x^15 + x^2 + 1)
- */
-uint16_t crc16(const void *buf, uint32_t len);
-
-/**
- * Calculates the CRC-16 of the data to extend the given crc.
- *
- * CRC is a linear function so crc16( x | y ) == crc16(x, crc16(y)).
- *
- * This uses the CRC-16-IBM variant: 0x8005 (x^16 + x^15 + x^2 + 1)
- */
-uint16_t crc16_update(const void *buf, uint32_t len, uint16_t crc);
-
-#endif /* NOS_TRANSPORT_CRC16_H */
diff --git a/libnos_transport/transport.c b/libnos_transport/transport.c
index 289b1a6..6f09be0 100644
--- a/libnos_transport/transport.c
+++ b/libnos_transport/transport.c
@@ -18,7 +18,6 @@
 
 #include <errno.h>
 #include <stdarg.h>
-#include <stdbool.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,8 +25,6 @@
 
 #include <application.h>
 
-#include "crc16.h"
-
 /* Note: evaluates expressions multiple times */
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
 
@@ -63,24 +60,8 @@
 #define RETRY_COUNT 25
 #define RETRY_WAIT_TIME_US 5000
 
-/* In case of CRC error, try to retransmit */
-#define CRC_RETRY_COUNT 3
-
-struct transport_context {
-  const struct nos_device *dev;
-  uint8_t app_id;
-  uint16_t params;
-  const uint8_t *args;
-  uint32_t arg_len;
-  uint8_t *reply;
-  uint32_t *reply_len;
-};
-
-/*
- * Read a datagram from the device, correctly handling retries.
- */
 static int nos_device_read(const struct nos_device *dev, uint32_t command,
-                           void *buf, uint32_t len) {
+                           uint8_t *buf, uint32_t len) {
   int retries = RETRY_COUNT;
   while (retries--) {
     int err = dev->ops.read(dev->ctx, command, buf, len);
@@ -102,11 +83,8 @@
   return ETIMEDOUT;
 }
 
-/*
- * Write a datagram to the device, correctly handling retries.
- */
 static int nos_device_write(const struct nos_device *dev, uint32_t command,
-                            const void *buf, uint32_t len) {
+                            uint8_t *buf, uint32_t len) {
   int retries = RETRY_COUNT;
   while (retries--) {
     int err = dev->ops.write(dev->ctx, command, buf, len);
@@ -128,316 +106,174 @@
   return ETIMEDOUT;
 }
 
-#define GET_STATUS_OK              0
-#define GET_STATUS_ERROR_IO       -1
-#define GET_STATUS_ERROR_PROTOCOL -2
+/* status is non-zero on error */
+static int get_status(const struct nos_device *dev,
+                      uint8_t app_id, uint32_t *status, uint16_t *ulen)
+{
+  uint8_t buf[6];
+  uint32_t command = CMD_ID(app_id) | CMD_IS_READ | CMD_TRANSPORT;
 
-/*
- * Get the status regardless of protocol version. This means some fields might
- * not be set meaningfully so the caller must check the version before accessing
- * them.
- *
- * Returns non-zero on error.
- */
-static int get_status(const struct transport_context *ctx,
-                      struct transport_status *out) {
-  int retries = CRC_RETRY_COUNT;
-  while (retries--) {
-    /* Get the status from the device */
-    union {
-      struct transport_legacy_status legacy;
-      struct transport_status current;
-    } status;
-    const uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_READ | CMD_TRANSPORT;
-    if (0 != nos_device_read(ctx->dev, command, &status, sizeof(status))) {
-      NLOGE("Failed to read device status");
-      return GET_STATUS_ERROR_IO;
-    }
-
-    /*
-     * Identify the legacy protocol. This could have been caused by a bit error
-     * but which would result in the wrong status and reply_len being used. If
-     * it is the legacy protocol, transform it to V1.
-     */
-    const bool is_legacy = (status.current.magic != TRANSPORT_STATUS_MAGIC);
-    /* TODO: deprecate the legacy protocol when it is safe to do so */
-    if (is_legacy) {
-      out->version = TRANSPORT_LEGACY;
-      out->status = status.legacy.status;
-      out->reply_len = status.legacy.reply_len;
-      return GET_STATUS_OK;
-    }
-
-    /* Check the CRC, if it fails we will retry */
-    const uint16_t their_crc = status.current.crc;
-    status.current.crc = 0;
-    const uint16_t our_crc = crc16(&status, sizeof(status));
-    if (their_crc != our_crc) {
-      NLOGE("Status CRC mismatch: theirs=%04x ours=%04x", their_crc, our_crc);
-      continue;
-    }
-
-    /* Check this is a version we recognise */
-    if (status.current.version != TRANSPORT_V1) {
-      NLOGE("Don't recognise transport version: %d", status.current.version);
-      return GET_STATUS_ERROR_PROTOCOL;
-    }
-
-    /* It all looks good */
-    *out = status.current;
-    return GET_STATUS_OK;
-  }
-
-  NLOGE("Unable to get valid checksum on status");
-  return GET_STATUS_ERROR_PROTOCOL;
-}
-
-static int clear_status(const struct transport_context *ctx) {
-  const uint32_t command = CMD_ID(ctx->app_id) | CMD_TRANSPORT;
-  if (nos_device_write(ctx->dev, command, 0, 0) != 0) {
-    NLOGE("Failed to clear device status");
+  if (0 != nos_device_read(dev, command, buf, sizeof(buf))) {
+    NLOGE("Failed to read device status");
     return -1;
   }
+
+  /* The read operation is successful */
+  *status = *(uint32_t *)buf;
+  *ulen = *(uint16_t *)(buf + 4);
   return 0;
 }
 
-/*
- * Ensure that the app is in an idle state ready to handle the transaction.
- */
-static uint32_t make_ready(const struct transport_context *ctx) {
-  struct transport_status status;
-  int ret = get_status(ctx, &status);
+static int clear_status(const struct nos_device *dev, uint8_t app_id)
+{
+  uint32_t command = CMD_ID(app_id) | CMD_TRANSPORT;
 
-  if (ret == GET_STATUS_OK) {
-    NLOGD("Inspection status=0x%08x reply_len=%d protocol=%s",
-          status.status, status.reply_len,
-          status.version == TRANSPORT_LEGACY ? "legacy" : "current");
-    /* If it's already idle then we're ready to proceed */
-    if (status.status == APP_STATUS_IDLE) {
-      return APP_SUCCESS;
-    }
-    /* Continue to try again after clearing state */
-  } else if (ret != GET_STATUS_ERROR_PROTOCOL) {
-    NLOGE("Failed to inspect device");
-    return APP_ERROR_IO;
+  if (0 != nos_device_write(dev, command, 0, 0)) {
+    NLOGE("Failed to clear device status");
+    return -1;
   }
 
-  /* Try clearing the status */
-  NLOGD("Clearing previous status");
-  if (clear_status(ctx) != 0) {
-    NLOGD("Failed to force idle status");
-    return APP_ERROR_IO;
-  }
-
-  /* Check again */
-  if (get_status(ctx, &status) != GET_STATUS_OK) {
-    NLOGE("Failed to get cleared status");
-    return APP_ERROR_IO;
-  }
-  NLOGD("Cleared status=0x%08x reply_len=%d", status.status, status.reply_len);
-
-  /* It's ignoring us and is still not ready, so it's broken */
-  if (status.status != APP_STATUS_IDLE) {
-    NLOGE("Device is not responding");
-    return APP_ERROR_IO;
-  }
-
-  return APP_SUCCESS;
+  return 0;
 }
 
-/*
- * Split request into datagrams and send command to have app process it.
- */
-static uint32_t send_command(const struct transport_context *ctx) {
-  const uint8_t *args = ctx->args;
-  uint16_t arg_len = ctx->arg_len;
-
-  NLOGV("Send command data (%d bytes)", arg_len);
-  uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_DATA | CMD_TRANSPORT;
-  /* TODO: don't need to send empty packet in non-legacy protocol */
-  do {
-    /*
-     * We can't send more per datagram than the device can accept. For Citadel
-     * using the TPM Wait protocol on SPS, this is a constant. For other buses
-     * it may not be, but this is what we support here. Due to peculiarities of
-     * Citadel's SPS hardware, our protocol requires that we specify the length
-     * of what we're about to send in the params field of each Write.
-     */
-    const uint16_t ulen = MIN(arg_len, MAX_DEVICE_TRANSFER);
-    CMD_SET_PARAM(command, ulen);
-
-    NLOGD("Write command 0x%08x, bytes %d", command, ulen);
-    if (nos_device_write(ctx->dev, command, args, ulen) != 0) {
-      NLOGE("Failed to send datagram to device");
-      return APP_ERROR_IO;
-    }
-
-    /* Any further Writes needed to send all the args must set the MORE bit */
-    command |= CMD_MORE_TO_COME;
-    args += ulen;
-    arg_len -= ulen;
-  } while (arg_len);
-
-  /* Finally, send the "go" command */
-  command = CMD_ID(ctx->app_id) | CMD_PARAM(ctx->params);
-
-  /*
-   * The outgoing crc covers:
-   *
-   *   1. the (16-bit) length of args
-   *   2. the args buffer (if any)
-   *   3. the (16-bit) reply_len_hint
-   *   4. the (32-bit) "go" command
-   */
-  struct transport_command_info command_info = {
-    .version = TRANSPORT_V1,
-    .reply_len_hint = *ctx->reply_len,
-  };
-  arg_len = ctx->arg_len;
-  command_info.crc = crc16(&arg_len, sizeof(arg_len));
-  command_info.crc = crc16_update(ctx->args, ctx->arg_len, command_info.crc);
-  command_info.crc = crc16_update(&command_info.reply_len_hint,
-                                  sizeof(command_info.reply_len_hint),
-                                  command_info.crc);
-  command_info.crc = crc16_update(&command, sizeof(command), command_info.crc);
-
-  /* Tell the app to handle the request while also sending the command_info
-   * which will be ignored by the legacy protocol. */
-  NLOGD("Write command 0x%08x, crc %04x...", command, command_info.crc);
-  if (0 != nos_device_write(ctx->dev, command, &command_info, sizeof(command_info))) {
-    NLOGE("Failed to send command datagram to device");
-    return APP_ERROR_IO;
-  }
-
-  return APP_SUCCESS;
-}
-
-/*
- * Keep polling until the app says it is done.
- */
-uint32_t poll_until_done(const struct transport_context *ctx,
-                         struct transport_status *status) {
-  uint32_t poll_count = 0;
-  NLOGV("Poll the app status until it's done");
-  do {
-    if (get_status(ctx, status) != GET_STATUS_OK) {
-      return APP_ERROR_IO;
-    }
-    poll_count++;
-    NLOGD("%d:  poll=%d status=0x%08x reply_len=%d", __LINE__,
-          poll_count, status->status, status->reply_len);
-  } while (!(status->status & APP_STATUS_DONE));
-
-  NLOGV("status=0x%08x reply_len=%d...", status->status, status->reply_len);
-  return APP_STATUS_CODE(status->status);
-}
-
-/*
- * Reconstruct the reply data from datagram stream.
- */
-uint32_t receive_reply(const struct transport_context *ctx,
-                       const struct transport_status *status) {
-  int retries = CRC_RETRY_COUNT;
-  while (retries--) {
-    NLOGV("Read the reply data (%d bytes)", status->reply_len);
-
-    uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_READ | CMD_TRANSPORT | CMD_IS_DATA;
-    uint8_t *reply = ctx->reply;
-    uint16_t left = MIN(*ctx->reply_len, status->reply_len);
-    uint16_t got = 0;
-    uint16_t crc = 0;
-    while (left) {
-      /* We can't read more per datagram than the device can send */
-      const uint16_t gimme = MIN(left, MAX_DEVICE_TRANSFER);
-      NLOGD("Read command=0x%08x, bytes=%d", command, gimme);
-      if (nos_device_read(ctx->dev, command, reply, gimme) != 0) {
-        NLOGE("Failed to receive datagram from device");
-        return APP_ERROR_IO;
-      }
-
-      /* Any further Reads should set the MORE bit. This only works if Nugget
-       * OS sends back CRCs, but that's the only time we'd retry anyway. */
-      command |= CMD_MORE_TO_COME;
-
-      crc = crc16_update(reply, gimme, crc);
-      reply += gimme;
-      left -= gimme;
-      got += gimme;
-    }
-    /* got it all */
-    *ctx->reply_len = got;
-
-    /* Legacy protocol doesn't support CRC so hopefully it's ok */
-    if (status->version == TRANSPORT_LEGACY) return APP_SUCCESS;
-
-    if (crc == status->reply_crc) return APP_SUCCESS;
-    NLOGE("Reply CRC mismatch: theirs=%04x ours=%04x", status->reply_crc, crc);
-  }
-
-  NLOGE("Unable to get valid checksum on reply data");
-  return APP_ERROR_IO;
-}
-
-/*
- * Driver for the master of the transport protocol.
- */
 uint32_t nos_call_application(const struct nos_device *dev,
                               uint8_t app_id, uint16_t params,
                               const uint8_t *args, uint32_t arg_len,
                               uint8_t *reply, uint32_t *reply_len)
 {
-  uint32_t res;
-  const struct transport_context ctx = {
-    .dev = dev,
-    .app_id = app_id,
-    .params = params,
-    .args = args,
-    .arg_len = arg_len,
-    .reply = reply,
-    .reply_len = reply_len,
-  };
+  uint32_t command;
+  uint8_t buf[MAX_DEVICE_TRANSFER];
+  uint32_t status;
+  uint16_t ulen;
+  uint32_t poll_count = 0;
 
-  if ((ctx.arg_len && !ctx.args) ||
-      (!ctx.reply_len) ||
-      (*ctx.reply_len && !ctx.reply)) {
-    NLOGE("Invalid args to %s()", __func__);
+  if (get_status(dev, app_id, &status, &ulen) != 0) {
+    return APP_ERROR_IO;
+  }
+  NLOGV("%d: query status 0x%08x  ulen 0x%04x", __LINE__, status, ulen);
+
+  /* It's not idle, but we're the only ones telling it what to do, so it
+   * should be. */
+  if (status != APP_STATUS_IDLE) {
+
+    /* Try clearing the status */
+    NLOGV("clearing previous status");
+    if (clear_status(dev, app_id) != 0) {
+      return APP_ERROR_IO;
+    }
+
+    /* Check again */
+    if (get_status(dev, app_id, &status, &ulen) != 0) {
+      return APP_ERROR_IO;
+    }
+    NLOGV("%d: query status 0x%08x  ulen 0x%04x",__LINE__, status, ulen);
+
+    /* It's ignoring us and is still not ready, so it's broken */
+    if (status != APP_STATUS_IDLE) {
+      NLOGE("Device is not responding");
+      return APP_ERROR_IO;
+    }
+  }
+
+  /* Send args data */
+  command = CMD_ID(app_id) | CMD_TRANSPORT | CMD_IS_DATA;
+  do {
+    /*
+     * We can't send more than the device can take. For
+     * Citadel using the TPM Wait protocol on SPS, this is
+     * a constant. For other buses, it may not be.
+     *
+     * For each Write, Citadel requires that we send the length of
+     * what we're about to send in the params field.
+     */
+    ulen = MIN(arg_len, MAX_DEVICE_TRANSFER);
+    CMD_SET_PARAM(command, ulen);
+    if (args && ulen)
+      memcpy(buf, args, ulen);
+
+    NLOGV("Write command 0x%08x, bytes 0x%x", command, ulen);
+
+    if (0 != nos_device_write(dev, command, buf, ulen)) {
+      NLOGE("Failed to send datagram to device");
+      return APP_ERROR_IO;
+    }
+
+    /* Additional data needs the additional flag set */
+    command |= CMD_MORE_TO_COME;
+
+    if (args)
+      args += ulen;
+    if (arg_len)
+      arg_len -= ulen;
+  } while (arg_len);
+
+  /* See if we had any errors while sending the args */
+  if (get_status(dev, app_id, &status, &ulen) != 0) {
+    return APP_ERROR_IO;
+  }
+  NLOGV("%d: query status 0x%08x  ulen 0x%04x", __LINE__, status, ulen);
+  if (status & APP_STATUS_DONE)
+    /* Yep, problems. It should still be idle. */
+    goto reply;
+
+  /* Now tell the app to do whatever */
+  command = CMD_ID(app_id) | CMD_PARAM(params);
+  NLOGV("Write command 0x%08x", command);
+  if (0 != nos_device_write(dev, command, 0, 0)) {
+      NLOGE("Failed to send command datagram to device");
+      return APP_ERROR_IO;
+  }
+
+  /* Poll the app status until it's done */
+  do {
+    if (get_status(dev, app_id, &status, &ulen) != 0) {
+      return APP_ERROR_IO;
+    }
+    NLOGD("%d:  poll status 0x%08x  ulen 0x%04x", __LINE__, status, ulen);
+    poll_count++;
+  } while (!(status & APP_STATUS_DONE));
+  NLOGV("polled %d times, status 0x%08x  ulen 0x%04x", poll_count,
+        status, ulen);
+
+reply:
+  /* Read any result only if there's a place with room to put it */
+  if (reply && reply_len && *reply_len) {
+    uint16_t left = MIN(*reply_len, ulen);
+    uint16_t gimme, got;
+
+    command = CMD_ID(app_id) | CMD_IS_READ |
+      CMD_TRANSPORT | CMD_IS_DATA;
+
+    got = 0 ;
+    while (left) {
+
+      /*
+       * We can't read more than the device can send. For
+       * Citadel using the TPM Wait protocol on SPS, this is
+       * a constant. For other buses, it may not be.
+       */
+      gimme = MIN(left, MAX_DEVICE_TRANSFER);
+      NLOGV("Read command 0x%08x, bytes 0x%x", command, gimme);
+      if (0 != nos_device_read(dev, command, buf, gimme)) {
+        NLOGE("Failed to receive datagram from device");
+        return APP_ERROR_IO;
+      }
+
+      memcpy(reply, buf, gimme);
+      reply += gimme;
+      left -= gimme;
+      got += gimme;
+    }
+    /* got it all */
+    *reply_len = got;
+  }
+
+  /* Clear the reply manually for the next caller */
+  command = CMD_ID(app_id) | CMD_TRANSPORT;
+  if (0 != nos_device_write(dev, command, 0, 0)) {
+    NLOGE("Failed to clear the reply");
     return APP_ERROR_IO;
   }
 
-  NLOGV("Calling app %d with params 0x%04x", app_id, params);
-
-  struct transport_status status;
-  int retries = CRC_RETRY_COUNT;
-  do {
-    /* Wake up and wait for Citadel to be ready */
-    res = make_ready(&ctx);
-    if (res) return res;
-
-    /* Tell the app what to do */
-    res = send_command(&ctx);
-    if (res) return res;
-
-    /* Wait until the app has finished */
-    res = poll_until_done(&ctx, &status);
-    if (res == APP_SUCCESS) break;
-    if (res != APP_ERROR_CHECKSUM) return res;
-    NLOGD("Request checksum error: %d", retries);
-  } while (--retries);
-  if (retries == 0) return APP_ERROR_IO;
-
-  /* Get the reply, but only if the app produced data and the caller wants it */
-  if (ctx.reply && ctx.reply_len && *ctx.reply_len && status.reply_len) {
-    res = receive_reply(&ctx, &status);
-    if (res) return res;
-  } else {
-    *reply_len = 0;
-  }
-
-  NLOGV("Clear the reply manually for the next caller");
-  /* This should work, but isn't completely fatal if it doesn't because the
-   * next call will try again. */
-  (void)clear_status(&ctx);
-
-  NLOGV("%s returning 0x%x", __func__, APP_STATUS_CODE(status.status));
-  return APP_STATUS_CODE(status.status);
+  return APP_STATUS_CODE(status);
 }
diff --git a/nugget/include/application.h b/nugget/include/application.h
index d36ca99..45824b3 100644
--- a/nugget/include/application.h
+++ b/nugget/include/application.h
@@ -199,70 +199,20 @@
  * then performs the requested operation and transititions to a "done" state.
  * The Master will retrieve the application status and any reply data from
  * Nugget OS, after which the application is ready to handle the next command.
- */
-
-/*
- * The master can detect whether the slave uses the legacy protocol by
- * inspecting the status response which will be exactly 6-bytes. The new
- * protocol has a larger status and the magic value will be incorrect if
- * it is a legacy status.
- */
-
-#define TRANSPORT_LEGACY    0x00000000
-#define TRANSPORT_V1        0x00000001
-
-/* Command information for the transport protocol. */
-struct transport_command_info {
-  uint32_t version;          /* version of the protocol */
-  /* Version specific fields may follow */
-  uint16_t reply_len_hint;   /* max that the master will read */
-  uint16_t crc;              /* CRC of some command field */
-} __packed;
-
-/* Status response from the legacy transport protocol. It can be detected by
- * its length as newer version of the protocol adds more information. */
-struct transport_legacy_status {
-  uint32_t status;         /* status of the app */
-  uint16_t reply_len;      /* length of available response data */
-} __packed;
-
-/* The magic straddles the end of the legacy status so the last 2 bytes cannot
- * equal 0xDFDF as that is what will be returned when there is no data. */
-#define TRANSPORT_STATUS_MAGIC 0x157A7051
-
-struct transport_status {
-  uint32_t version;        /* version of the protocol */
-  uint32_t magic;          /* differentiate from the legacy protocol */
-  /* Version specific fields may follow */
-  uint32_t status;         /* status of the app */
-  uint16_t reply_len;      /* length of available response data */
-  uint16_t reply_crc;      /* CRC of the reply data */
-  uint16_t crc;            /* CRC of this struct with crc set to 0 */
-} __packed;
-
-/* Pre-calculated CRCs for different status responses set by in the interrupt
- * context where the CRC would otherwise not be calculated. */
-#define STATUS_CRC_FOR_IDLE              0xd780
-#define STATUS_CRC_FOR_ERROR_IO          0x5d80
-#define STATUS_CRC_FOR_ERROR_TOO_MUCH    0x5680
-
-/*
+ *
  * Applications that wish to use this transport API will need to declare a
  * private struct app_transport which Nugget OS can use to maintain the state:
  */
+
 struct app_transport {
-  void (*done_fn)(struct app_transport *);    /* optional cleanup function */
-  /* Note: Any done_fn() is called in interrupt context. Be quick. */
+  uint32_t command;                           /* from master */
+  volatile uint32_t status;                   /* current application status */
   uint8_t *request, *response;                /* input/output data buffer */
   uint16_t max_request_len, max_response_len; /* data buffer sizes */
-  /* The following are used for the incoming command. */
-  uint32_t command;                           /* from master */
-  struct transport_command_info command_info; /* info about the command */
-  uint16_t request_len;                       /* command data buffer size */
-  uint16_t request_idx;                       /* current index into request */
-  uint16_t response_idx;                      /* current index into response */
-  struct transport_status status[2];          /* current transport_status */
-  volatile uint8_t status_idx;                /* index of active status */
+  uint16_t request_len, response_len;         /* current buffer count */
+  uint16_t request_idx, response_idx;         /* used internally */
+  void (*done_fn)(struct app_transport *);    /* optional cleanup function */
+  /* Note: Any done_fn() is called in interrupt context. Be quick. */
 };
 
 /*
@@ -274,24 +224,18 @@
  */
 #define __TRANSPORT_ALIGNED__ __attribute__((aligned(8)))
 
+/* For debugging if needed */
+extern void dump_transport_state(const struct app_transport *s);
+
 /*
  * The application will need to provide a write_to_app_fn_t function that will
  * be invoked when a new request is ready to be processed. All command and data
  * parameters will already be present in the app's struct app_transport, so it
  * just needs to awaken the application task to do the work.
  *
- * When awakened, the application task must check that there were no errors in
- * the transmission of the request by calling this function. If it returns
- * true, the task should go back to sleep until the next request arrives.
- */
-int request_is_invalid(struct app_transport *s);
-/*
  * When processing is finished, the app should call the app_reply() function to
- * return its status code and specify the length of any data it has placed into
- * the response buffer, and then it can go back to sleep until its next
- * invocation. CAUTION: The Master polls for app completion independently, so
- * it may immediately begin retrieving the results as soon as this function
- * is called *without* waiting for the Nugget OS app to go to sleep.
+ * return its status code and specify length of any data it has placed into the
+ * response buffer, and then it can go back to sleep until its next invocation.
  */
 void app_reply(struct app_transport *st, uint32_t status, uint16_t reply_len);
 
@@ -304,7 +248,6 @@
   APP_ERROR_TOO_MUCH,        /* caller sent too much data */
   APP_ERROR_IO,              /* problem sending or receiving data */
   APP_ERROR_RPC,             /* problem during RPC communication */
-  APP_ERROR_CHECKSUM,        /* checksum failed, only used within protocol */
   /* more? */
 
   APP_SPECIFIC_ERROR = 0x20, /* "should be enough for anybody" */
@@ -371,7 +314,6 @@
 
 /* Command flags used internally by Transport API messages */
 #define CMD_TRANSPORT       0x40000000    /* 1=Transport API message */
-/* When CMD_TRANSPORT is set, the following bits have meaning */
 #define CMD_IS_DATA         0x20000000    /* 1=data msg 0=status msg */
 #define CMD_MORE_TO_COME    0x10000000    /* 1=continued 0=new */