diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/device_proto.h | 423 | 
1 files changed, 214 insertions, 209 deletions
| diff --git a/include/device_proto.h b/include/device_proto.h index 4044cdc..ebe31df 100644 --- a/include/device_proto.h +++ b/include/device_proto.h @@ -1,5 +1,6 @@  #ifndef DEVICE_PROTO_H  #define DEVICE_PROTO_H +  #include <utility>  #include <thread>  #include <type_traits> @@ -31,7 +32,7 @@  #define PWS_SEND_CR 3  namespace nitrokey { -namespace proto { +    namespace proto {  /*   *	POD types for HID proto commands   *	Instances are meant to be __packed. @@ -42,45 +43,45 @@ namespace proto {  /*   *	Every packet is a USB HID report (check USB spec)   */ -template <CommandID cmd_id, typename Payload> -struct HIDReport { -  uint8_t _zero; -  CommandID command_id;  // uint8_t -  union { -    uint8_t _padding[HID_REPORT_SIZE - 6]; -    Payload payload; -  } __packed; -  uint32_t crc; - -  // POD types can't have non-default constructors -  // used in Transaction<>::run() -  void initialize() { -    bzero(this, sizeof *this); -    command_id = cmd_id; -  } - -  uint32_t calculate_CRC() const { -    // w/o leading zero, a part of each HID packet -    // w/o 4-byte crc -    return misc::stm_crc32((const uint8_t *)(this) + 1, -                           (size_t)(HID_REPORT_SIZE - 5)); -  } - -  void update_CRC() { crc = calculate_CRC(); } - -  bool isCRCcorrect() const { return crc == calculate_CRC(); } - -  bool isValid() const { -    return true; -    //		return !_zero && payload.isValid() && isCRCcorrect(); -  } - -  operator std::string() const { -    // Packet type is known upfront in normal operation. -    // Can't be used to dissect random packets. -    return QueryDissector<cmd_id, decltype(*this)>::dissect(*this); -  } -} __packed; +        template<CommandID cmd_id, typename Payload> +        struct HIDReport { +            uint8_t _zero; +            CommandID command_id;  // uint8_t +            union { +                uint8_t _padding[HID_REPORT_SIZE - 6]; +                Payload payload; +            } __packed; +            uint32_t crc; + +            // POD types can't have non-default constructors +            // used in Transaction<>::run() +            void initialize() { +              bzero(this, sizeof *this); +              command_id = cmd_id; +            } + +            uint32_t calculate_CRC() const { +              // w/o leading zero, a part of each HID packet +              // w/o 4-byte crc +              return misc::stm_crc32((const uint8_t *) (this) + 1, +                                     (size_t) (HID_REPORT_SIZE - 5)); +            } + +            void update_CRC() { crc = calculate_CRC(); } + +            bool isCRCcorrect() const { return crc == calculate_CRC(); } + +            bool isValid() const { +              return true; +              //		return !_zero && payload.isValid() && isCRCcorrect(); +            } + +            operator std::string() const { +              // Packet type is known upfront in normal operation. +              // Can't be used to dissect random packets. +              return QueryDissector<cmd_id, decltype(*this)>::dissect(*this); +            } +        } __packed;  /*   *	Response payload (the parametrized type inside struct HIDReport) @@ -88,175 +89,179 @@ struct HIDReport {   *	command_id member in incoming HIDReport structure carries the command   *	type last used.   */ -template <CommandID cmd_id, typename ResponsePayload> -struct DeviceResponse { -  uint8_t _zero; -  uint8_t device_status; -  uint8_t command_id;  // originally last_command_type -  uint32_t last_command_crc; -  uint8_t last_command_status; -  union { -    uint8_t _padding[HID_REPORT_SIZE - 12]; -    ResponsePayload payload; -  } __packed; -  uint32_t crc; - -  void initialize() { bzero(this, sizeof *this); } - -  uint32_t calculate_CRC() const { -    // w/o leading zero, a part of each HID packet -    // w/o 4-byte crc -    return misc::stm_crc32((const uint8_t *)(this) + 1, -                           (size_t)(HID_REPORT_SIZE - 5)); -  } - -  void update_CRC() { crc = calculate_CRC(); } - -  bool isCRCcorrect() const { return crc == calculate_CRC(); } - -  bool isValid() const { -    //		return !_zero && payload.isValid() && isCRCcorrect() && -    //				command_id == (uint8_t)(cmd_id); -    return true; -  } - -  operator std::string() const { -    return ResponseDissector<cmd_id, decltype(*this)>::dissect(*this); -  } -} __packed; - -struct EmptyPayload { -  uint8_t _data[]; - -  bool isValid() const { return true; } - -  std::string dissect() const { return std::string("Empty Payload."); } -} __packed; - -template <typename command_packet, typename response_payload> -class ClearingProxy{ -public: -    ClearingProxy(command_packet &p){ -        packet = p; -        bzero(&p, sizeof(p)); -    } -    ~ClearingProxy(){ -        bzero(&packet, sizeof(packet)); -    } - -    response_payload & data() { -        return packet.payload; +        template<CommandID cmd_id, typename ResponsePayload> +        struct DeviceResponse { +            uint8_t _zero; +            uint8_t device_status; +            uint8_t command_id;  // originally last_command_type +            uint32_t last_command_crc; +            uint8_t last_command_status; +            union { +                uint8_t _padding[HID_REPORT_SIZE - 12]; +                ResponsePayload payload; +            } __packed; +            uint32_t crc; + +            void initialize() { bzero(this, sizeof *this); } + +            uint32_t calculate_CRC() const { +              // w/o leading zero, a part of each HID packet +              // w/o 4-byte crc +              return misc::stm_crc32((const uint8_t *) (this) + 1, +                                     (size_t) (HID_REPORT_SIZE - 5)); +            } + +            void update_CRC() { crc = calculate_CRC(); } + +            bool isCRCcorrect() const { return crc == calculate_CRC(); } + +            bool isValid() const { +              //		return !_zero && payload.isValid() && isCRCcorrect() && +              //				command_id == (uint8_t)(cmd_id); +              return true; +            } + +            operator std::string() const { +              return ResponseDissector<cmd_id, decltype(*this)>::dissect(*this); +            } +        } __packed; + +        struct EmptyPayload { +            uint8_t _data[]; + +            bool isValid() const { return true; } + +            std::string dissect() const { return std::string("Empty Payload."); } +        } __packed; + +        template<typename command_packet, typename response_payload> +        class ClearingProxy { +        public: +            ClearingProxy(command_packet &p) { +              packet = p; +              bzero(&p, sizeof(p)); +            } + +            ~ClearingProxy() { +              bzero(&packet, sizeof(packet)); +            } + +            response_payload &data() { +              return packet.payload; +            } + +            command_packet packet; +        }; + +        template<CommandID cmd_id, typename command_payload, typename response_payload> +        class Transaction : semantics::non_constructible { +        public: +            // Types declared in command class scope can't be reached from there. +            typedef command_payload CommandPayload; +            typedef response_payload ResponsePayload; + +            typedef struct HIDReport<cmd_id, CommandPayload> OutgoingPacket; +            typedef struct DeviceResponse<cmd_id, ResponsePayload> ResponsePacket; + +            static_assert(std::is_pod<OutgoingPacket>::value, +                          "outgoingpacket must be a pod type"); +            static_assert(std::is_pod<ResponsePacket>::value, +                          "ResponsePacket must be a POD type"); +            static_assert(sizeof(OutgoingPacket) == HID_REPORT_SIZE, +                          "OutgoingPacket type is not the right size"); +            static_assert(sizeof(ResponsePacket) == HID_REPORT_SIZE, +                          "ResponsePacket type is not the right size"); + +            static uint32_t getCRC( +                const command_payload &payload) { +              OutgoingPacket outp; +              outp.initialize(); +              outp.payload = payload; +              outp.update_CRC(); +              return outp.crc; +            } + +            template<typename T> +            static void clear_packet(T &st) { +              bzero(&st, sizeof(st)); +            } + + +            static ClearingProxy<ResponsePacket, response_payload> run(device::Device &dev, +                                                                       const command_payload &payload) { +              using namespace ::nitrokey::device; +              using namespace ::nitrokey::log; +              using namespace std::chrono_literals; + +              Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); + +              int status; +              OutgoingPacket outp; +              ResponsePacket resp; + +              // POD types can't have non-default constructors +              outp.initialize(); +              resp.initialize(); + +              outp.payload = payload; +              outp.update_CRC(); + +              Log::instance()("Outgoing HID packet:", Loglevel::DEBUG); +              Log::instance()((std::string) (outp), Loglevel::DEBUG); + +              if (!outp.isValid()) throw std::runtime_error("Invalid outgoing packet"); + +              status = dev.send(&outp); +              if (status <= 0) +                throw std::runtime_error( +                    std::string("Device error while sending command ") + +                    std::to_string((int) (status))); + +              std::this_thread::sleep_for(dev.get_send_receive_delay()); + +              // FIXME make checks done in device:recv here +              int retry = dev.get_retry_count(); +              while (retry-- > 0) { +                status = dev.recv(&resp); + +                dev.set_last_command_status(resp.last_command_status); // FIXME should be handled on device.recv + +                if (resp.device_status == 0 && resp.last_command_crc == outp.crc) break; +                Log::instance()( +                    "Device is not ready or received packet's last CRC is not equal to sent CRC packet, retrying...", +                    Loglevel::DEBUG); +                Log::instance()("Invalid incoming HID packet:", Loglevel::DEBUG_L2); +                Log::instance()((std::string) (resp), Loglevel::DEBUG_L2); +                std::this_thread::sleep_for(dev.get_retry_timeout()); +                continue; +              } +              clear_packet(outp); + +              if (status <= 0) +                throw std::runtime_error( +                    std::string("Device error while executing command ") + +                    std::to_string(status)); + +              Log::instance()("Incoming HID packet:", Loglevel::DEBUG); +              Log::instance()((std::string) (resp), Loglevel::DEBUG); +              Log::instance()(std::string("Retry count: ") + std::to_string(retry), Loglevel::DEBUG); + +              if (!resp.isValid()) throw std::runtime_error("Invalid incoming packet"); +              if (retry <= 0) +                throw std::runtime_error("Maximum retry count reached for receiving response from the device!"); +              if (resp.last_command_status != 0) +                throw CommandFailedException(resp.command_id, resp.last_command_status); + + +              // See: DeviceResponse +              return resp; +            } + +            static ClearingProxy<ResponsePacket, response_payload> run(device::Device &dev) { +              command_payload empty_payload; +              return run(dev, empty_payload); +            } +        };      } - -    command_packet packet; -}; - -template <CommandID cmd_id, typename command_payload, typename response_payload> -class Transaction : semantics::non_constructible { - public: -  // Types declared in command class scope can't be reached from there. -  typedef command_payload CommandPayload; -  typedef response_payload ResponsePayload; - -  typedef struct HIDReport<cmd_id, CommandPayload> OutgoingPacket; -  typedef struct DeviceResponse<cmd_id, ResponsePayload> ResponsePacket; - -  static_assert(std::is_pod<OutgoingPacket>::value, -                "outgoingpacket must be a pod type"); -  static_assert(std::is_pod<ResponsePacket>::value, -                "ResponsePacket must be a POD type"); -  static_assert(sizeof(OutgoingPacket) == HID_REPORT_SIZE, -                "OutgoingPacket type is not the right size"); -  static_assert(sizeof(ResponsePacket) == HID_REPORT_SIZE, -                "ResponsePacket type is not the right size"); - -  static uint32_t getCRC( -          const command_payload &payload) { -    OutgoingPacket outp; -    outp.initialize(); -    outp.payload = payload; -    outp.update_CRC(); -    return outp.crc; -  } - -    template <typename T> -    static void clear_packet(T &st){ -        bzero(&st, sizeof(st)); -    } - - -    static ClearingProxy<ResponsePacket, response_payload> run(device::Device &dev, -                              const command_payload &payload) { -    using namespace ::nitrokey::device; -    using namespace ::nitrokey::log; -     using namespace std::chrono_literals; - -    Log::instance()(__PRETTY_FUNCTION__, Loglevel::DEBUG_L2); - -    int status; -    OutgoingPacket outp; -    ResponsePacket resp; - -    // POD types can't have non-default constructors -    outp.initialize(); -    resp.initialize(); - -    outp.payload = payload; -    outp.update_CRC(); - -    Log::instance()("Outgoing HID packet:", Loglevel::DEBUG); -    Log::instance()((std::string)(outp), Loglevel::DEBUG); - -    if (!outp.isValid()) throw std::runtime_error("Invalid outgoing packet"); - -    status = dev.send(&outp); -    if (status <= 0) -      throw std::runtime_error( -          std::string("Device error while sending command ") + -          std::to_string((int)(status))); - -      std::this_thread::sleep_for(dev.get_send_receive_delay()); - -      // FIXME make checks done in device:recv here -    int retry = dev.get_retry_count(); -    while (retry-- > 0) { -      status = dev.recv(&resp); - -      dev.set_last_command_status(resp.last_command_status); // FIXME should be handled on device.recv - -      if (resp.device_status == 0 && resp.last_command_crc == outp.crc) break; -      Log::instance()("Device is not ready or received packet's last CRC is not equal to sent CRC packet, retrying...", -                      Loglevel::DEBUG); -      Log::instance()("Invalid incoming HID packet:", Loglevel::DEBUG_L2); -      Log::instance()((std::string)(resp), Loglevel::DEBUG_L2); -      std::this_thread::sleep_for(dev.get_retry_timeout()); -      continue; -    } -    clear_packet(outp); - -    if (status <= 0) -      throw std::runtime_error( -          std::string("Device error while executing command ") + -          std::to_string(status)); - -    Log::instance()("Incoming HID packet:", Loglevel::DEBUG); -    Log::instance()((std::string)(resp), Loglevel::DEBUG); -    Log::instance()(std::string("Retry count: ") + std::to_string(retry), Loglevel::DEBUG); - -    if (!resp.isValid()) throw std::runtime_error("Invalid incoming packet"); -    if (retry <= 0) throw std::runtime_error("Maximum retry count reached for receiving response from the device!"); -    if (resp.last_command_status!=0) throw CommandFailedException(resp.command_id, resp.last_command_status); - - -      // See: DeviceResponse -    return resp; -  } - -  static ClearingProxy<ResponsePacket, response_payload> run(device::Device &dev) { -    command_payload empty_payload; -    return run(dev, empty_payload); -  } -}; -}  }  #endif | 
