From f41c421482002ee4f395918b88f77d4b50305aee Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Thu, 21 May 2026 14:02:36 +0200 Subject: [PATCH 1/2] kernel/os: Check if CONTAINER_OF is already defined Check if CONTAINER_OF is already defined before defining in the OS. This is quite common macro name and may cause macro redefine error otherwise. --- kernel/os/include/os/util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/os/include/os/util.h b/kernel/os/include/os/util.h index 3e59670c4e..f272a0a342 100644 --- a/kernel/os/include/os/util.h +++ b/kernel/os/include/os/util.h @@ -27,8 +27,10 @@ #define INT_TO_POINTER(u) ((void *) ((intptr_t) (u))) /* Helper to retrieve pointer to "parent" object in structure */ +#ifndef CONTAINER_OF #define CONTAINER_OF(ptr, type, field) \ ((type *)(((char *)(ptr)) - offsetof(type, field))) +#endif /* Helper to calculate number of elements in array */ #ifndef ARRAY_SIZE From a049ac80c1ad64a3af2f09bea845064822ecaf32 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 17 Apr 2026 16:04:28 +0200 Subject: [PATCH 2/2] net/osdp: Update to 3.2.1 and move to external repo This moves removes OSDP library copy and uses latest upstream release as external repository. Also includes use of mbedTLS crypto backend. --- apps/osdp_sample/pkg.yml | 2 - apps/osdp_sample/src/main.c | 174 +-- apps/osdp_sample/syscfg.yml | 1 - net/osdp/include/osdp/osdp.h | 717 --------- net/osdp/include/osdp/osdp_common.h | 416 ------ net/osdp/include/osdp/osdp_config.h | 105 ++ .../osdp/osdp_mynewt.h} | 24 +- net/osdp/include/osdp/osdp_utils.h | 130 -- net/osdp/pkg.yml | 52 +- net/osdp/src/osdp_common.c | 241 --- net/osdp/src/osdp_cp.c | 1305 ----------------- net/osdp/src/{osdp.c => osdp_mynewt.c} | 65 +- .../osdp_hooks.h => src/osdp_mynewt_utils.c} | 19 +- net/osdp/src/osdp_pd.c | 1221 --------------- net/osdp/src/osdp_phy.c | 498 ------- net/osdp/src/osdp_sc.c | 262 ---- net/osdp/src/osdp_utils.c | 126 -- net/osdp/syscfg.yml | 6 +- 18 files changed, 286 insertions(+), 5078 deletions(-) delete mode 100644 net/osdp/include/osdp/osdp.h delete mode 100644 net/osdp/include/osdp/osdp_common.h create mode 100644 net/osdp/include/osdp/osdp_config.h rename net/osdp/{src/osdp_hooks.c => include/osdp/osdp_mynewt.h} (74%) delete mode 100644 net/osdp/include/osdp/osdp_utils.h delete mode 100644 net/osdp/src/osdp_common.c delete mode 100644 net/osdp/src/osdp_cp.c rename net/osdp/src/{osdp.c => osdp_mynewt.c} (80%) rename net/osdp/{include/osdp/osdp_hooks.h => src/osdp_mynewt_utils.c} (67%) delete mode 100644 net/osdp/src/osdp_pd.c delete mode 100644 net/osdp/src/osdp_phy.c delete mode 100644 net/osdp/src/osdp_sc.c delete mode 100644 net/osdp/src/osdp_utils.c diff --git a/apps/osdp_sample/pkg.yml b/apps/osdp_sample/pkg.yml index fb3ffe66c5..05ad12f89a 100644 --- a/apps/osdp_sample/pkg.yml +++ b/apps/osdp_sample/pkg.yml @@ -29,6 +29,4 @@ pkg.deps: - "@apache-mynewt-core/hw/hal" - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/console" - - "@apache-mynewt-core/crypto/tinycrypt" - - "@apache-mynewt-core/hw/drivers/trng" - "@apache-mynewt-core/net/osdp" diff --git a/apps/osdp_sample/src/main.c b/apps/osdp_sample/src/main.c index 490a93a10f..d5288eed70 100644 --- a/apps/osdp_sample/src/main.c +++ b/apps/osdp_sample/src/main.c @@ -26,9 +26,7 @@ #include "bsp/bsp.h" #include "console/console.h" #include "hal/hal_gpio.h" -#include "tinycrypt/aes.h" -#include "osdp/osdp.h" -#include "osdp/osdp_common.h" +#include "osdp/osdp_mynewt.h" #ifdef ARCH_sim #include "mcu/mcu_sim.h" #endif @@ -56,6 +54,8 @@ static int create_cardreader_event(struct osdp_event *event); static int create_mfgreply_event(struct osdp_cmd *oc); static int pd_command_handler(void *arg, struct osdp_cmd *cmd); +static struct osdp_t *ctx; + /* From osdp.h */ static const char *const osdp_cmd_str[] = { "OSDP_CMD_OUTPUT", @@ -85,43 +85,24 @@ pd_command_handler(void *arg, struct osdp_cmd *cmd) break; case OSDP_CMD_BUZZER: LOG(INFO, "\n\trdr: %d,\n\tctrl_code: %d,\n\ton_ct: %d,\n\toff_ct: %d,\n\trep_count: %d\n", - cmd->buzzer.reader, - cmd->buzzer.control_code, - cmd->buzzer.on_count, - cmd->buzzer.off_count, - cmd->buzzer.rep_count - ); + cmd->buzzer.reader, cmd->buzzer.control_code, cmd->buzzer.on_count, + cmd->buzzer.off_count, cmd->buzzer.rep_count); break; case OSDP_CMD_LED: - LOG(INFO, - "\n\trdr: %d,\n\tctrl_code: %d,\n\tled_num: %d,\n\ton_ct: %d,\n\toff_ct: %d,\n\ton_clr: %d,\n\toff_clr: %d,\n\ttmr_ct: %d\n", - cmd->led.reader, - cmd->led.temporary.control_code, - cmd->led.led_number, - cmd->led.temporary.on_count, - cmd->led.temporary.off_count, - cmd->led.temporary.on_color, - cmd->led.temporary.off_color, - cmd->led.temporary.timer_count - ); + LOG(INFO, "\n\trdr: %d,\n\tctrl_code: %d,\n\tled_num: %d,\n\ton_ct: %d,\n\toff_ct: %d,\n\ton_clr: %d,\n\toff_clr: %d,\n\ttmr_ct: %d\n", + cmd->led.reader, cmd->led.temporary.control_code, + cmd->led.led_number, cmd->led.temporary.on_count, + cmd->led.temporary.off_count, cmd->led.temporary.on_color, + cmd->led.temporary.off_color, cmd->led.temporary.timer_count); break; case OSDP_CMD_TEXT: - LOG(INFO, - "\n\trdr: %d,\n\tctrl_code: %d,\n\ttemp_time: %d,\n\toffset_row: %d,\n\toffset_col: %d,\n\tdata: %s\n", - cmd->text.reader, - cmd->text.control_code, - cmd->text.temp_time, - cmd->text.offset_row, - cmd->text.offset_col, - cmd->text.data - ); + LOG(INFO, "\n\trdr: %d,\n\tctrl_code: %d,\n\ttemp_time: %d,\n\toffset_row: %d,\n\toffset_col: %d,\n\tdata: %s\n", + cmd->text.reader, cmd->text.control_code, cmd->text.temp_time, + cmd->text.offset_row, cmd->text.offset_col, cmd->text.data); break; case OSDP_CMD_MFG: - LOG(INFO, "\n\tv_code: 0x%04x,\n\tcmd: %d,\n\tlen: %d,\n\tdata: ", - cmd->mfg.vendor_code, - cmd->mfg.command, - cmd->mfg.length - ); + LOG(INFO, "\n\tv_code: 0x%04x,\n\tlen: %d,\n\tdata: ", cmd->mfg.vendor_code, + cmd->mfg.length); for (int i = 0; i < cmd->mfg.length; ++i) { printf("%02x ", cmd->mfg.data[i]); } @@ -138,23 +119,18 @@ pd_command_handler(void *arg, struct osdp_cmd *cmd) return ret; } -/* - * - */ static int create_mfgreply_event(struct osdp_cmd *oc) { - int i, data_length, vendor_code, mfg_command; + int i, data_length, vendor_code; struct osdp_cmd_mfg *cmd = &oc->mfg; /* Sample reply */ uint8_t data_bytes[] = {"ManufacturerReply"}; data_length = sizeof(data_bytes); vendor_code = 0x00030201; - mfg_command = 14; cmd->vendor_code = (uint32_t)vendor_code; - cmd->command = mfg_command; cmd->length = data_length; for (i = 0; i < cmd->length; i++) { cmd->data[i] = data_bytes[i]; @@ -184,7 +160,7 @@ create_cardreader_event(struct osdp_event *event) len_bytes = data_length; } - if (len_bytes > OSDP_EVENT_MAX_DATALEN) { + if (len_bytes > OSDP_EVENT_CARDREAD_MAX_DATALEN) { return -1; } @@ -227,10 +203,10 @@ static void cmd_handler(struct os_event *ev) { assert(ev != NULL); - struct osdp *ctx = osdp_get_ctx(); static int cmd = 0; + uint8_t sc_active; - uint32_t sc_active = osdp_get_sc_status_mask(ctx); + osdp_get_sc_status_mask(ctx, &sc_active); if (sc_active) { struct osdp_event event; @@ -241,7 +217,7 @@ cmd_handler(struct os_event *ev) LOG(INFO, "Sending Key Press\n"); create_keypress_event(&event); } - osdp_pd_notify_event(ctx, &event); + osdp_pd_submit_event(ctx, &event); cmd++; if (cmd > 1) { cmd = 0; @@ -262,56 +238,68 @@ static int timers_init(void) { /* Configure and reset timer */ - os_callout_init(&cmd_timer, os_eventq_dflt_get(), - cmd_handler, NULL); + os_callout_init(&cmd_timer, os_eventq_dflt_get(), cmd_handler, NULL); os_callout_reset(&cmd_timer, COMMAND_HANDLER_INTERVAL); return 0; } -/* - * Simple test for OSDP encryption routine - */ static int -test_encryption_wrappers(uint8_t *key, uint8_t len) +char2hex(char c, uint8_t *x) { - int rc; - uint8_t plaintext_ref[TC_AES_BLOCK_SIZE] = - {0xff, 0x53, 0x65, 0x13, 0x00, 0x0e, 0x03, 0x11, 0x00, 0x01, 0x76, 0x3b, 0x24, 0xdf, 0x92, 0x5b}; - uint8_t data_buffer[TC_AES_BLOCK_SIZE]; - uint8_t iv_buffer[TC_AES_BLOCK_SIZE]; - - /* Test AES-CBC */ - memcpy(data_buffer, plaintext_ref, TC_AES_BLOCK_SIZE); - osdp_get_rand(iv_buffer, TC_AES_BLOCK_SIZE); /* Create initial vector */ - osdp_encrypt(key, iv_buffer, data_buffer, - TC_AES_BLOCK_SIZE); /* Encrypt using initial vector in CBC mode */ - osdp_decrypt(key, iv_buffer, data_buffer, TC_AES_BLOCK_SIZE); /* Decrypt */ - - rc = memcmp(data_buffer, plaintext_ref, TC_AES_BLOCK_SIZE); - if (rc) { - return rc; + if (c >= '0' && c <= '9') { + *x = c - '0'; + } else if (c >= 'a' && c <= 'f') { + *x = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + *x = c - 'A' + 10; + } else { + return -OS_EINVAL; } - /* Test AES-ECB */ - memcpy(data_buffer, plaintext_ref, TC_AES_BLOCK_SIZE); - osdp_encrypt(key, NULL, data_buffer, - TC_AES_BLOCK_SIZE); /* Encrypt without initial vector, i.e ECB mode */ - osdp_decrypt(key, NULL, data_buffer, TC_AES_BLOCK_SIZE); /* Decrypt */ + return 0; +} + +static size_t +hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen) +{ + uint8_t dec; - rc = memcmp(data_buffer, plaintext_ref, TC_AES_BLOCK_SIZE); - if (rc) { - return rc; + if (buflen < hexlen / 2 + hexlen % 2) { + return 0; } - return rc; + /* if hexlen is uneven, insert leading zero nibble */ + if (hexlen % 2) { + if (char2hex(hex[0], &dec) < 0) { + return 0; + } + buf[0] = dec; + hex++; + buf++; + } + + /* regular hex conversion */ + for (size_t i = 0; i < hexlen / 2; i++) { + if (char2hex(hex[2 * i], &dec) < 0) { + return 0; + } + buf[i] = dec << 4; + + if (char2hex(hex[2 * i + 1], &dec) < 0) { + return 0; + } + buf[i] += dec; + } + + return hexlen / 2 + hexlen % 2; } int mynewt_main(int argc, char **argv) { - int rc, len; + int len; uint8_t key_buf[16]; uint8_t *key = NULL; @@ -346,6 +334,18 @@ mynewt_main(int argc, char **argv) { -1, 0, 0 } }; + /* Validate and assign key */ + if (MYNEWT_VAL(OSDP_SC_ENABLED) && strcmp(OSDP_KEY_STRING, "NONE") != 0) { + + len = strlen(OSDP_KEY_STRING); + assert(len == 32); + + len = hex2bin(OSDP_KEY_STRING, 32, key_buf, 16); + assert(len == 16); + + key = key_buf; + } + osdp_pd_info_t info_pd = { .address = MYNEWT_VAL(OSDP_PD_ADDRESS), .baud_rate = MYNEWT_VAL(OSDP_UART_BAUD_RATE), @@ -362,26 +362,14 @@ mynewt_main(int argc, char **argv) .firmware_version = MYNEWT_VAL(OSDP_PD_ID_FIRMWARE_VERSION), }, .cap = cap, - .pd_cb = pd_command_handler + .scbk = key, }; - /* Validate and assign key */ - if (MYNEWT_VAL(OSDP_SC_ENABLED) && strcmp(OSDP_KEY_STRING, "NONE") != 0) { - - len = strlen(OSDP_KEY_STRING); - assert(len == 32); - - len = hex2bin(OSDP_KEY_STRING, 32, key_buf, 16); - assert(len == 16); - - rc = test_encryption_wrappers(key_buf, 16); - assert(rc == 0); - - key = key_buf; - } - /* Initialize the library module */ - osdp_init(&info_pd, key); + ctx = osdp_init(&info_pd); + assert(ctx); + + osdp_pd_set_command_callback(ctx, pd_command_handler, NULL); timers_init(); diff --git a/apps/osdp_sample/syscfg.yml b/apps/osdp_sample/syscfg.yml index ef52295e6e..150033e7de 100644 --- a/apps/osdp_sample/syscfg.yml +++ b/apps/osdp_sample/syscfg.yml @@ -24,7 +24,6 @@ syscfg.vals: OSDP_MODE_PD: 1 # set in peripheral device mode OSDP_SC_ENABLED: 1 # enable secure channel OSDP_UART_DEV_NAME: '"uart0"' # set uart device for OSDP communication - TRNG: 1 # for SC mode # PD mode config syscfg.vals.OSDP_MODE_PD: diff --git a/net/osdp/include/osdp/osdp.h b/net/osdp/include/osdp/osdp.h deleted file mode 100644 index d61e9fa5cf..0000000000 --- a/net/osdp/include/osdp/osdp.h +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _OSDP_H_ -#define _OSDP_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OSDP_CMD_TEXT_MAX_LEN 32 -#define OSDP_CMD_KEYSET_KEY_MAX_LEN 16 -#define OSDP_CMD_MFG_MAX_DATALEN 64 -#define OSDP_EVENT_MAX_DATALEN 64 - -/** - * @brief OSDP setup flags. See osdp_pd_info_t::flags - */ - -/** - * @brief ENFORCE_SECURE: Make security conscious assumptions (see below) where - * possible. Fail where these assumptions don't hold. - * - Don't allow use of SCBK-D. - * - Assume that a KEYSET was successful at an earlier time. - * - * @note This flag is recommended in production use. - */ -#define OSDP_FLAG_ENFORCE_SECURE 0x00010000 - -/** - * @brief When set, the PD would allow one session of secure channel to be - * setup with SCBK-D. - * - * @note In this mode, the PD is in a vulnerable state, the application is - * responsible for making sure that the device enters this mode only during - * controlled/provisioning-time environments. - */ -#define OSDP_FLAG_INSTALL_MODE 0x00020000 - -/** - * @brief When set, the PD will not set up secure mode capability. - */ -#define OSDP_FLAG_NON_SECURE_MODE 0x00040000 - -/** - * @brief Various PD capability function codes. - */ -enum osdp_pd_cap_function_code_e { - /** - * @brief Dummy. - */ - OSDP_PD_CAP_UNUSED, - - /** - * @brief This function indicates the ability to monitor the status of a - * switch using a two-wire electrical connection between the PD and the - * switch. The on/off position of the switch indicates the state of an - * external device. - * - * The PD may simply resolve all circuit states to an open/closed - * status, or it may implement supervision of the monitoring circuit. - * A supervised circuit is able to indicate circuit fault status in - * addition to open/closed status. - */ - OSDP_PD_CAP_CONTACT_STATUS_MONITORING, - - /** - * @brief This function provides a switched output, typically in the - * form of a relay. The Output has two states: active or inactive. The - * Control Panel (CP) can directly set the Output's state, or, if the PD - * supports timed operations, the CP can specify a time period for the - * activation of the Output. - */ - OSDP_PD_CAP_OUTPUT_CONTROL, - - /** - * @brief This capability indicates the form of the card data is - * presented to the Control Panel. - */ - OSDP_PD_CAP_CARD_DATA_FORMAT, - - /** - * @brief This capability indicates the presence of and type of LEDs. - */ - OSDP_PD_CAP_READER_LED_CONTROL, - - /** - * @brief This capability indicates the presence of and type of an - * Audible Annunciator (buzzer or similar tone generator) - */ - OSDP_PD_CAP_READER_AUDIBLE_OUTPUT, - - /** - * @brief This capability indicates that the PD supports a text display - * emulating character-based display terminals. - */ - OSDP_PD_CAP_READER_TEXT_OUTPUT, - - /** - * @brief This capability indicates that the type of date and time - * awareness or time keeping ability of the PD. - */ - OSDP_PD_CAP_TIME_KEEPING, - - /** - * @brief All PDs must be able to support the checksum mode. This - * capability indicates if the PD is capable of supporting CRC mode. - */ - OSDP_PD_CAP_CHECK_CHARACTER_SUPPORT, - - /** - * @brief This capability indicates the extent to which the PD supports - * communication security (Secure Channel Communication) - */ - OSDP_PD_CAP_COMMUNICATION_SECURITY, - - /** - * @brief This capability indicates the maximum size single message the - * PD can receive. - */ - OSDP_PD_CAP_RECEIVE_BUFFERSIZE, - - /** - * @brief This capability indicates the maximum size multi-part message - * which the PD can handle. - */ - OSDP_PD_CAP_LARGEST_COMBINED_MESSAGE_SIZE, - - /** - * @brief This capability indicates whether the PD supports the - * transparent mode used for communicating directly with a smart card. - */ - OSDP_PD_CAP_SMART_CARD_SUPPORT, - - /** - * @brief This capability indicates the number of credential reader - * devices present. Compliance levels are bit fields to be assigned as - * needed. - */ - OSDP_PD_CAP_READERS, - - /** - * @brief This capability indicates the ability of the reader to handle - * biometric input - */ - OSDP_PD_CAP_BIOMETRICS, - - /** - * @brief Capability Sentinel - */ - OSDP_PD_CAP_SENTINEL -}; - -/** - * @brief PD capability structure. Each PD capability has a 3 byte - * representation. - * - * @param function_code One of enum osdp_pd_cap_function_code_e. - * @param compliance_level A function_code dependent number that indicates what - * the PD can do with this capability. - * @param num_items Number of such capability entities in PD. - */ -struct osdp_pd_cap { - uint8_t function_code; - uint8_t compliance_level; - uint8_t num_items; -}; - -/** - * @brief PD ID information advertised by the PD. - * - * @param version 3-bytes IEEE assigned OUI - * @param model 1-byte Manufacturer's model number - * @param vendor_code 1-Byte Manufacturer's version number - * @param serial_number 4-byte serial number for the PD - * @param firmware_version 3-byte version (major, minor, build) - */ -struct osdp_pd_id { - int version; - int model; - uint32_t vendor_code; - uint32_t serial_number; - uint32_t firmware_version; -}; - -struct osdp_channel { - /** - * @brief pointer to a block of memory that will be passed to the - * send/receive method. This is optional and can be left empty. - */ - void *data; - - /** - * @brief on multi-drop networks, more than one PD can share the same - * channel (read/write/flush pointers). On such networks, the channel_id - * is used to lock a PD to a channel. On multi-drop networks, this `id` - * must non-zero and be unique for each bus. - */ - int id; - - /** - * @brief pointer to function that copies received bytes into buffer - * @param data for use by underlying layers. channel_s::data is passed - * @param buf byte array copy incoming data - * @param len sizeof `buf`. Can copy utmost `len` bytes into `buf` - * - * @retval +ve: number of bytes copied on to `bug`. Must be <= `len` - * @retval -ve on errors - */ - int (*recv)(void *data, uint8_t *buf, int maxlen); - - /** - * @brief pointer to function that sends byte array into some channel - * @param data for use by underlying layers. channel_s::data is passed - * @param buf byte array to be sent - * @param len number of bytes in `buf` - * - * @retval +ve: number of bytes sent. must be <= `len` - * @retval -ve on errors - */ - int (*send)(void *data, uint8_t *buf, int len); - - /** - * @brief pointer to function that drops all bytes in TX/RX fifo - * @param data for use by underlying layers. channel_s::data is passed - */ - void (*flush)(void *data); -}; - -/** - * The keep the OSDP internal data strucutres from polluting the exposed - * headers, they are typedefed to void before sending them to the upper layers. - * This level of abstaction looked reasonable as _technically_ no one should - * attempt to modify it outside fo the LibOSDP and their definition may change - * at any time. - */ -typedef void osdp_t; - -/* ------------------------------- */ -/* OSDP Commands */ -/* ------------------------------- */ - -/** - * @brief Command sent from CP to Control digital output of PD. - * - * @param output_no 0 = First Output, 1 = Second Output, etc. - * @param control_code One of the following: - * 0 - NOP – do not alter this output - * 1 - set the permanent state to OFF, abort timed operation (if any) - * 2 - set the permanent state to ON, abort timed operation (if any) - * 3 - set the permanent state to OFF, allow timed operation to complete - * 4 - set the permanent state to ON, allow timed operation to complete - * 5 - set the temporary state to ON, resume perm state on timeout - * 6 - set the temporary state to OFF, resume permanent state on timeout - * @param timer_count Time in units of 100 ms - */ -struct osdp_cmd_output { - uint8_t output_no; - uint8_t control_code; - uint16_t timer_count; -}; - -/** - * @brief LED Colors as specified in OSDP for the on_color/off_color parameters. - */ -enum osdp_led_color_e { - OSDP_LED_COLOR_NONE, - OSDP_LED_COLOR_RED, - OSDP_LED_COLOR_GREEN, - OSDP_LED_COLOR_AMBER, - OSDP_LED_COLOR_BLUE, - OSDP_LED_COLOR_SENTINEL -}; - -/** - * @brief LED params sub-structure. Part of LED command. See struct osdp_cmd_led - * - * @param control_code One of the following: - * Temporary Control Code: - * 0 - NOP - do not alter this LED's temporary settings - * 1 - Cancel any temporary operation and display this LED's permanent - * state immediately - * 2 - Set the temporary state as given and start timer immediately - * Permanent Control Code: - * 0 - NOP - do not alter this LED's permanent settings - * 1 - Set the permanent state as given - * @param on_count The ON duration of the flash, in units of 100 ms - * @param off_count The OFF duration of the flash, in units of 100 ms - * @param on_color Color to set during the ON timer (enum osdp_led_color_e) - * @param off_color Color to set during the OFF timer (enum osdp_led_color_e) - * @param timer_count Time in units of 100 ms (only for temporary mode) - */ -struct osdp_cmd_led_params { - uint8_t control_code; - uint8_t on_count; - uint8_t off_count; - uint8_t on_color; - uint8_t off_color; - uint16_t timer_count; -}; - -/** - * @brief Sent from CP to PD to control the behaviour of it's on-board LEDs - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param led_number 0 = first LED, 1 = second LED, etc. - * @param temporary ephemeral LED status descriptor - * @param permanent permanent LED status descriptor - */ -struct osdp_cmd_led { - uint8_t reader; - uint8_t led_number; - struct osdp_cmd_led_params temporary; - struct osdp_cmd_led_params permanent; -}; - -/** - * @brief Sent from CP to control the behaviour of a buzzer in the PD. - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param control_code 0: no tone, 1: off, 2: default tone, 3+ is TBD. - * @param on_count The ON duration of the flash, in units of 100 ms - * @param off_count The OFF duration of the flash, in units of 100 ms - * @param rep_count The number of times to repeat the ON/OFF cycle; 0: forever - */ -struct osdp_cmd_buzzer { - uint8_t reader; - uint8_t control_code; - uint8_t on_count; - uint8_t off_count; - uint8_t rep_count; -}; - -/** - * @brief Command to manuplate any display units that the PD supports. - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param control_code One of the following: - * 1 - permanent text, no wrap - * 2 - permanent text, with wrap - * 3 - temp text, no wrap - * 4 - temp text, with wrap - * @param temp_time duration to display temporary text, in seconds - * @param offset_row row to display the first character (1 indexed) - * @param offset_col column to display the first character (1 indexed) - * @param length Number of characters in the string - * @param data The string to display - */ -struct osdp_cmd_text { - uint8_t reader; - uint8_t control_code; - uint8_t temp_time; - uint8_t offset_row; - uint8_t offset_col; - uint8_t length; - uint8_t data[OSDP_CMD_TEXT_MAX_LEN]; -}; - -/** - * @brief Sent in response to a COMSET command. Set communication parameters to - * PD. Must be stored in PD non-volatile memory. - * - * @param address Unit ID to which this PD will respond after the change takes - * effect. - * @param baud_rate baud rate value 9600/38400/115200 - */ -struct osdp_cmd_comset { - uint8_t address; - uint32_t baud_rate; -}; - -/** - * @brief This command transfers an encryption key from the CP to a PD. - * - * @param type Type of keys: - * - 0x00 - Master Key (This is not part of OSDP Spec, see gh-issue:#42) - * - 0x01 – Secure Channel Base Key - * @param length Number of bytes of key data - (Key Length in bits + 7) / 8 - * @param data Key data - */ -struct osdp_cmd_keyset { - uint8_t type; - uint8_t length; - uint8_t data[OSDP_CMD_KEYSET_KEY_MAX_LEN]; -}; - -/** - * @brief Manufacturer Specific Commands - * - * @param vendor_code 3-byte IEEE assigned OUI. Most Significat 8-bits are - * unused. - * @param command 1-byte manufacturer defined osdp command - * @param length Length of command data - * @param data Command data - */ -struct osdp_cmd_mfg { - uint32_t vendor_code; - uint8_t command; - uint8_t length; - uint8_t data[OSDP_CMD_MFG_MAX_DATALEN]; -}; - -/** - * @brief OSDP application exposed commands - */ -enum osdp_cmd_e { - OSDP_CMD_OUTPUT = 1, - OSDP_CMD_LED, - OSDP_CMD_BUZZER, - OSDP_CMD_TEXT, - OSDP_CMD_KEYSET, - OSDP_CMD_COMSET, - OSDP_CMD_MFG, - OSDP_CMD_SENTINEL -}; - -/** - * @brief OSDP Command Structure. This is a wrapper for all individual OSDP - * commands. - * - * @param id used to select specific commands in union. Type: enum osdp_cmd_e - * @param led LED command structure - * @param buzzer buzzer command structure - * @param text text command structure - * @param output output command structure - * @param comset comset command structure - * @param keyset keyset command structure - */ -struct osdp_cmd { - enum osdp_cmd_e id; - union { - struct osdp_cmd_led led; - struct osdp_cmd_buzzer buzzer; - struct osdp_cmd_text text; - struct osdp_cmd_output output; - struct osdp_cmd_comset comset; - struct osdp_cmd_keyset keyset; - struct osdp_cmd_mfg mfg; - }; -}; - -/* ------------------------------- */ -/* OSDP Events */ -/* ------------------------------- */ - -/** - * @brief Various card formats that a PD can support. This is sent to CP - * when a PD must report a card read. - */ -enum osdp_event_cardread_format_e { - OSDP_CARD_FMT_RAW_UNSPECIFIED, - OSDP_CARD_FMT_RAW_WIEGAND, - OSDP_CARD_FMT_ASCII, - OSDP_CARD_FMT_SENTINEL -}; - -/** - * @brief OSDP event cardread - * - * @param reader_no In context of readers attached to current PD, this number - * indicated this number. This is not supported by LibOSDP. - * @param format Format of the card being read. - * see `enum osdp_event_cardread_format_e` - * @param direction Card read direction of PD 0 - Forward; 1 - Backward - * @param length Length of card data in bytes or bits depending on `format` - * (see note). - * @param data Card data of `length` bytes or bits bits depending on `format` - * (see note). - * - * @note When `format` is set to OSDP_CARD_FMT_RAW_UNSPECIFIED or - * OSDP_CARD_FMT_RAW_WIEGAND, the length is expressed in bits. OTOH, when it is - * set to OSDP_CARD_FMT_ASCII, the length is in bytes. The number of bytes to - * read from the `data` field must be interpreted accordingly. - */ -struct osdp_event_cardread { - int reader_no; - enum osdp_event_cardread_format_e format; - int direction; - int length; - uint8_t data[OSDP_EVENT_MAX_DATALEN]; -}; - -/** - * @brief OSDP Event Keypad - * - * @param reader_no In context of readers attached to current PD, this number - * indicated this number. This is not supported by LibOSDP. - * @param length Length of keypress data in bytes - * @param data keypress data of `length` bytes - */ -struct osdp_event_keypress { - int reader_no; - int length; - uint8_t data[OSDP_EVENT_MAX_DATALEN]; -}; - -/** - * @brief OSDP Event Manufacturer Specific Command - * - * @param vendor_code 3-bytes IEEE assigned OUI of manufacturer - * @param length Length of manufacturer data in bytes - * @param data manufacturer data of `length` bytes - */ -struct osdp_event_mfgrep { - uint32_t vendor_code; - int command; - int length; - uint8_t data[OSDP_EVENT_MAX_DATALEN]; -}; - -/** - * @brief OSDP PD Events - */ -enum osdp_event_type { - OSDP_EVENT_CARDREAD, - OSDP_EVENT_KEYPRESS, - OSDP_EVENT_MFGREP, - OSDP_EVENT_SENTINEL -}; - -/** - * @brief OSDP Event structure. - * - * @param id used to select specific event in union. See: enum osdp_event_type - * @param keypress keypress event structure - * @param cardread cardread event structure - * @param mfgrep mfgrep event structure - */ -struct osdp_event { - enum osdp_event_type type; - union { - struct osdp_event_keypress keypress; - struct osdp_event_cardread cardread; - struct osdp_event_mfgrep mfgrep; - }; -}; - -typedef int (*pd_command_callback_t)(void *arg, struct osdp_cmd *c); -typedef int (*cp_event_callback_t)(void *arg, int addr, struct osdp_event *ev); - -/** - * @brief OSDP PD Information. This struct is used to describe a PD to LibOSDP. - * - * @param baud_rate Can be one of 9600/38400/115200 - * @param address 7 bit PD address. the rest of the bits are ignored. The - * special address 0x7F is used for broadcast. So there can be 2^7-1 - * devices on a multi-drop channel - * @param flags Used to modify the way the context is setup. See `OSDP_FLAG_XXX` - * @param id Static information that the PD reports to the CP when it received a - * `CMD_ID`. These information must be populated by a PD appliication. - * @param cap This is a pointer to an array of structures containing the PD' - * capabilities. Use { -1, 0, 0 } to terminate the array. This is used - * only PD mode of operation - * @param channel Communication channel ops structure, containing send/recv - * function pointers. - */ -typedef struct { - int baud_rate; - int address; - int flags; - struct osdp_pd_id id; - struct osdp_pd_cap *cap; - struct osdp_channel channel; - pd_command_callback_t pd_cb; - cp_event_callback_t cp_cb; -} osdp_pd_info_t; - -/** - * @brief Periodic refresh method. Must be called by the application at least - * once every 50ms to meet OSDP timing requirements. - * - * @param ctx OSDP context - */ -void osdp_refresh(osdp_t *ctx); - -/* ------------------------------- */ -/* CP Methods */ -/* ------------------------------- */ - -/** - * @brief Periodic refresh method. Must be called by the application at least - * once every 50ms to meet OSDP timing requirements. - * - * @param ctx OSDP context - */ -void osdp_cp_refresh(osdp_t *ctx); - -/** - * @brief Cleanup all osdp resources. The context pointer is no longer valid - * after this call. - * - * @param ctx OSDP context - */ -void osdp_cp_teardown(osdp_t *ctx); - -/** - * @brief Generic command enqueue API. - * - * @param ctx OSDP context - * @param pd PD offset number as in `pd_info_t *`. - * @param cmd command pointer. Must be filled by application. - * - * @retval 0 on success - * @retval -1 on failure - * - * @note This method only adds the command on to a particular PD's command - * queue. The command itself can fail due to various reasons. - */ -int osdp_cp_send_command(osdp_t *ctx, int pd, struct osdp_cmd *cmd); - -/** - * @brief Set callback method for CP event notification. This callback is - * invoked when the CP receives an event from the PD. - * - * @param ctx OSDP context - * @param cb The callback function's pointer - * @param arg A pointer that will be passed as the first argument of `cb` - */ -void osdp_cp_set_event_callback(osdp_t *ctx, cp_event_callback_t cb, void *arg); - -/* ------------------------------- */ -/* PD Methods */ -/* ------------------------------- */ - -/** - * @brief Periodic refresh method. Must be called by the application at least - * once every 50ms to meet OSDP timing requirements. - * - * @param ctx OSDP context - */ -void osdp_pd_refresh(osdp_t *ctx); - -/** - * @brief Cleanup all osdp resources. The context pointer is no longer valid - * after this call. - * - * @param ctx OSDP context - */ -void osdp_pd_teardown(osdp_t *ctx); - -/** - * @brief Set PD's capabilities - * - * @param ctx OSDP context - * @param cap pointer to array of cap (`struct osdp_pd_cap`) terminated by a - * capability with cap->function_code set to 0. - */ -void osdp_pd_set_capabilities(osdp_t *ctx, struct osdp_pd_cap *cap); - -/** - * @brief Set callback method for PD command notification. This callback is - * invoked when the PD receives a command from the CP. This function must - * return: - * - 0 if LibOSDP must send a `osdp_ACK` response - * - -ve if LibOSDP must send a `osdp_NAK` response - * - +ve and modify the passed `struct osdp_cmd *cmd` if LibOSDP must send a - * specific response. This is useful for sending manufacturer specific reply - * ``osdp_MFGREP``. - * - * @param ctx OSDP context - * @param cb The callback function's pointer - * @param arg A pointer that will be passed as the first argument of `cb` - */ -void osdp_pd_set_command_callback(osdp_t *ctx, pd_command_callback_t cb, - void *arg); - -/** - * @brief API to notify PD events to CP. These events are sent to the CP as an - * alternate response to a POLL command. - * - * @param ctx OSDP context - * @param event pointer to event struct. Must be filled by application. - * - * @retval 0 on success - * @retval -1 on failure - */ -int osdp_pd_notify_event(osdp_t *ctx, struct osdp_event *event); - -/* ------------------------------- */ -/* Common Methods */ -/* ------------------------------- */ - -/** - * @brief Get a bit mask of number of PD that are online currently. - * - * @return Bit-Mask (max 32 PDs) - */ -uint32_t osdp_get_status_mask(osdp_t *ctx); - -/** - * @brief Get a bit mask of number of PD that are online and have an active - * secure channel currently. - * - * @return Bit-Mask (max 32 PDs) - */ -uint32_t osdp_get_sc_status_mask(osdp_t *ctx); - -/** - * @brief Initialize context for OSDP library. - */ -void osdp_init(osdp_pd_info_t *info, uint8_t *scbk); - -/** - * @brief Stop OSDP library. - */ -void osdp_stop(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _OSDP_H_ */ diff --git a/net/osdp/include/osdp/osdp_common.h b/net/osdp/include/osdp/osdp_common.h deleted file mode 100644 index f4a014ad81..0000000000 --- a/net/osdp/include/osdp/osdp_common.h +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _OSDP_COMMON_H_ -#define _OSDP_COMMON_H_ - -#include -#include - -#include "osdp/osdp.h" -#include "osdp/osdp_utils.h" - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#define ARG_UNUSED(x) (void)(x) - -#define ISSET_FLAG(p, f) (((p)->flags & (f)) == (f)) -#define SET_FLAG(p, f) ((p)->flags |= (f)) -#define CLEAR_FLAG(p, f) ((p)->flags &= ~(f)) - -#define BYTE_0(x) (uint8_t)(((x) >> 0) & 0xFF) -#define BYTE_1(x) (uint8_t)(((x) >> 8) & 0xFF) -#define BYTE_2(x) (uint8_t)(((x) >> 16) & 0xFF) -#define BYTE_3(x) (uint8_t)(((x) >> 24) & 0xFF) - -/* casting helpers */ -#define TO_OSDP(p) ((struct osdp *)p) -#define TO_CP(p) (((struct osdp *)(p))->cp) -#define TO_PD(p, i) (((struct osdp *)(p))->pd + i) -#define TO_CTX(p) ((struct osdp *)p->__parent) - -#define GET_CURRENT_PD(p) (TO_CP(p)->current_pd) -#define SET_CURRENT_PD(p, i) \ - do { \ - TO_CP(p)->current_pd = TO_PD(p, i); \ - TO_CP(p)->pd_offset = i; \ - } while (0) -#define PD_MASK(ctx) \ - (uint32_t)((1 << (TO_CP(ctx)->num_pd)) - 1) -#define AES_PAD_LEN(x) ((x + 16 - 1) & (~(16 - 1))) -#define NUM_PD(ctx) (TO_CP(ctx)->num_pd) - -/* Unused type only to estmate ephemeral_data size */ -union osdp_ephemeral_data { - struct osdp_cmd cmd; - struct osdp_event event; -}; -#define OSDP_EPHEMERAL_DATA_MAX_LEN sizeof(union osdp_ephemeral_data) - -/** - * @brief OSDP reserved commands - */ -#define CMD_POLL 0x60 -#define CMD_ID 0x61 -#define CMD_CAP 0x62 -#define CMD_DIAG 0x63 -#define CMD_LSTAT 0x64 -#define CMD_ISTAT 0x65 -#define CMD_OSTAT 0x66 -#define CMD_RSTAT 0x67 -#define CMD_OUT 0x68 -#define CMD_LED 0x69 -#define CMD_BUZ 0x6A -#define CMD_TEXT 0x6B -#define CMD_RMODE 0x6C -#define CMD_TDSET 0x6D -#define CMD_COMSET 0x6E -#define CMD_DATA 0x6F -#define CMD_XMIT 0x70 -#define CMD_PROMPT 0x71 -#define CMD_SPE 0x72 -#define CMD_BIOREAD 0x73 -#define CMD_BIOMATCH 0x74 -#define CMD_KEYSET 0x75 -#define CMD_CHLNG 0x76 -#define CMD_SCRYPT 0x77 -#define CMD_CONT 0x79 -#define CMD_ABORT 0x7A -#define CMD_MAXREPLY 0x7B -#define CMD_MFG 0x80 -#define CMD_SCDONE 0xA0 -#define CMD_XWR 0xA1 - -/** - * @brief OSDP reserved responses - */ -#define REPLY_ACK 0x40 -#define REPLY_NAK 0x41 -#define REPLY_PDID 0x45 -#define REPLY_PDCAP 0x46 -#define REPLY_LSTATR 0x48 -#define REPLY_ISTATR 0x49 -#define REPLY_OSTATR 0x4A -#define REPLY_RSTATR 0x4B -#define REPLY_RAW 0x50 -#define REPLY_FMT 0x51 -#define REPLY_PRES 0x52 -#define REPLY_KEYPPAD 0x53 -#define REPLY_COM 0x54 -#define REPLY_SCREP 0x55 -#define REPLY_SPER 0x56 -#define REPLY_BIOREADR 0x57 -#define REPLY_BIOMATCHR 0x58 -#define REPLY_CCRYPT 0x76 -#define REPLY_RMAC_I 0x78 -#define REPLY_MFGREP 0x90 -#define REPLY_BUSY 0x79 -#define REPLY_XRD 0xB1 - -/** - * @brief secure block types - */ -#define SCS_11 0x11 /* CP -> PD -- CMD_CHLNG */ -#define SCS_12 0x12 /* PD -> CP -- REPLY_CCRYPT */ -#define SCS_13 0x13 /* CP -> PD -- CMD_SCRYPT */ -#define SCS_14 0x14 /* PD -> CP -- REPLY_RMAC_I */ - -#define SCS_15 0x15 /* CP -> PD -- packets w MAC w/o ENC */ -#define SCS_16 0x16 /* PD -> CP -- packets w MAC w/o ENC */ -#define SCS_17 0x17 /* CP -> PD -- packets w MAC w ENC*/ -#define SCS_18 0x18 /* PD -> CP -- packets w MAC w ENC*/ - -/* Global flags */ -#define FLAG_CP_MODE 0x00000001 /* Set when initialized as CP */ -#define FLAG_SC_DISABLED 0x00000002 /* cp_setup with master_key=NULL */ - -/* PD State Flags */ -#define PD_FLAG_MASK 0x0000FFFF /* only 16 bits are for flags */ -#define PD_FLAG_SC_CAPABLE 0x00000001 /* PD secure channel capable */ -#define PD_FLAG_TAMPER 0x00000002 /* local tamper status */ -#define PD_FLAG_POWER 0x00000004 /* local power status */ -#define PD_FLAG_R_TAMPER 0x00000008 /* remote tamper status */ -#define PD_FLAG_AWAIT_RESP 0x00000010 /* set after command is sent */ -#define PD_FLAG_SKIP_SEQ_CHECK 0x00000020 /* disable seq checks (debug) */ -#define PD_FLAG_SC_USE_SCBKD 0x00000040 /* in this SC attempt, use SCBKD */ -#define PD_FLAG_SC_ACTIVE 0x00000080 /* secure channel is active */ -#define PD_FLAG_SC_SCBKD_DONE 0x00000100 /* SCBKD check is done */ -#define PD_FLAG_PD_MODE 0x00000200 /* device is setup as PD */ -#define PD_FLAG_CHN_SHARED 0x00000400 /* PD's channel is shared */ -#define PD_FLAG_PKT_SKIP_MARK 0x00000800 /* CONFIG_OSDP_SKIP_MARK_BYTE */ -#define PD_FLAG_PKT_HAS_MARK 0x00001000 /* Packet has mark byte */ -#define PD_FLAG_CP_POLL_ACTIVE 0x00002000 /* PD is getting polled by CP, for non-secure mode */ - -#define osdp_dump(b, l, f, ...) hexdump(b, l, f, __VA_ARGS__) - -enum osdp_pd_nak_code_e { - /** - * @brief Dummy - */ - OSDP_PD_NAK_NONE, - /** - * @brief Message check character(s) error (bad cksum/crc) - */ - OSDP_PD_NAK_MSG_CHK, - /** - * @brief Command length error - */ - OSDP_PD_NAK_CMD_LEN, - /** - * @brief Unknown Command Code – Command not implemented by PD - */ - OSDP_PD_NAK_CMD_UNKNOWN, - /** - * @brief This PD does not support the security block that was received - */ - OSDP_PD_NAK_SEQ_NUM, - /** - * @brief Secure Channel is not supported by PD - */ - OSDP_PD_NAK_SC_UNSUP, - /** - * @brief unsupported security block or security conditions not met - */ - OSDP_PD_NAK_SC_COND, - /** - * @brief BIO_TYPE not supported - */ - OSDP_PD_NAK_BIO_TYPE, - /** - * @brief BIO_FORMAT not supported - */ - OSDP_PD_NAK_BIO_FMT, - /** - * @brief Unable to process command record - */ - OSDP_PD_NAK_RECORD, - /** - * @brief Dummy - */ - OSDP_PD_NAK_SENTINEL -}; - -enum osdp_pd_state_e { - OSDP_PD_STATE_IDLE, - OSDP_PD_STATE_PROCESS_CMD, - OSDP_PD_STATE_SEND_REPLY, - OSDP_PD_STATE_ERR, -}; - -enum osdp_cp_phy_state_e { - OSDP_CP_PHY_STATE_IDLE, - OSDP_CP_PHY_STATE_SEND_CMD, - OSDP_CP_PHY_STATE_REPLY_WAIT, - OSDP_CP_PHY_STATE_WAIT, - OSDP_CP_PHY_STATE_ERR, -}; - -enum osdp_state_e { - OSDP_CP_STATE_INIT, - OSDP_CP_STATE_IDREQ, - OSDP_CP_STATE_CAPDET, - OSDP_CP_STATE_SC_INIT, - OSDP_CP_STATE_SC_CHLNG, - OSDP_CP_STATE_SC_SCRYPT, - OSDP_CP_STATE_SET_SCBK, - OSDP_CP_STATE_ONLINE, - OSDP_CP_STATE_OFFLINE -}; - -enum osdp_pkt_errors_e { - /* Define the busy error to a +ve value to indicate no error. Also set it - * to 2 which is the value of OSDP_CP_ERR_RETRY_CMD which is the error - * code returned by cp_decode_response() after decoding the busy reply - * packet. This thus allows a busy reply packet to be detected and - * handled without needing the usual additional decoding step. */ - OSDP_ERR_PKT_BUSY = 2, - - OSDP_ERR_PKT_NONE = 0, - OSDP_ERR_PKT_FMT = -1, - OSDP_ERR_PKT_WAIT = -2, - OSDP_ERR_PKT_SKIP = -3, - OSDP_ERR_PKT_CHECK = -4 -}; - -struct osdp_secure_channel { - uint8_t scbk[16]; - uint8_t s_enc[16]; - uint8_t s_mac1[16]; - uint8_t s_mac2[16]; - uint8_t r_mac[16]; - uint8_t c_mac[16]; - uint8_t cp_random[8]; - uint8_t pd_random[8]; - uint8_t pd_client_uid[8]; - uint8_t cp_cryptogram[16]; - uint8_t pd_cryptogram[16]; -}; - -#if MYNEWT_VAL(OSDP_MODE_PD) -struct pd_event_node { - TAILQ_ENTRY(pd_event_node) pd_node; - struct osdp_event object; -}; -typedef TAILQ_HEAD(queue, pd_event_node) queue_t; -#else -struct cp_cmd_node { - TAILQ_ENTRY(cp_cmd_node) cp_node; - struct osdp_cmd object; -}; -typedef TAILQ_HEAD(queue, cp_cmd_node) queue_t; -#endif - -/* Adjust pool size based on CP vs PD mode */ -#if MYNEWT_VAL(OSDP_MODE_PD) -#define POOL_SIZE OS_MEMPOOL_SIZE(MYNEWT_VAL(OSDP_PD_COMMAND_QUEUE_SIZE), sizeof(struct pd_event_node)) -#else -#define POOL_SIZE OS_MEMPOOL_SIZE(MYNEWT_VAL(OSDP_PD_COMMAND_QUEUE_SIZE), sizeof(struct cp_cmd_node)) -#endif - -struct osdp_queue { - queue_t queue; - struct os_mempool pool; - os_membuf_t pool_buf[POOL_SIZE]; -}; - -struct osdp_pd { - void *__parent; - int offset; - uint32_t flags; - - /* OSDP specified data */ - int baud_rate; - int address; - int seq_number; - struct osdp_pd_cap cap[OSDP_PD_CAP_SENTINEL]; - struct osdp_pd_id id; - - /* PD state management */ - int state; - int phy_state; - uint32_t wait_ms; - - int64_t tstamp; - int64_t sc_tstamp; - uint8_t rx_buf[MYNEWT_VAL(OSDP_UART_RX_BUFFER_LENGTH)]; - int rx_buf_len; - int64_t phy_tstamp; - - int cmd_id; - int reply_id; - uint8_t ephemeral_data[OSDP_EPHEMERAL_DATA_MAX_LEN]; - - union { - struct osdp_queue cmd; - struct osdp_queue event; - }; - - struct osdp_channel channel; - struct osdp_secure_channel sc; - void *command_callback_arg; - pd_command_callback_t command_callback; - struct os_mutex lock; /* Manage access to pool + queue */ -}; - -struct osdp_cp { - void *__parent; - int num_pd; - struct osdp_pd *current_pd; /* current operational pd's pointer */ - int pd_offset; /* current pd's offset into ctx->pd */ - int *channel_lock; - void *event_callback_arg; - cp_event_callback_t event_callback; -}; - -struct osdp { - int magic; - uint32_t flags; - struct osdp_cp *cp; - struct osdp_pd *pd; - uint8_t sc_master_key[16]; -}; - -struct osdp_ctx { - struct osdp ctx; - struct osdp_cp cp_ctx; - struct osdp_pd pd_ctx[MYNEWT_VAL(OSDP_NUM_CONNECTED_PD)]; - int ch_locks_ctx[MYNEWT_VAL(OSDP_NUM_CONNECTED_PD)]; -}; - -/* from osdp_phy.c */ -int osdp_phy_packet_init(struct osdp_pd *p, uint8_t *buf, int max_len); -int osdp_phy_packet_finalize(struct osdp_pd *p, uint8_t *buf, - int len, int max_len); -int osdp_phy_check_packet(struct osdp_pd *pd, uint8_t *buf, int len, - int *one_pkt_len); -int osdp_phy_decode_packet(struct osdp_pd *p, uint8_t *buf, int len, - uint8_t **pkt_start); -void osdp_phy_state_reset(struct osdp_pd *pd); -int osdp_phy_packet_get_data_offset(struct osdp_pd *p, const uint8_t *buf); -uint8_t *osdp_phy_packet_get_smb(struct osdp_pd *p, const uint8_t *buf); - -/* from osdp.c */ -struct osdp *osdp_get_ctx(); - -/* from osdp_sc.c */ -void osdp_compute_scbk(struct osdp_pd *pd, uint8_t *master_key, uint8_t *scbk); -void osdp_compute_session_keys(struct osdp *ctx); -void osdp_compute_cp_cryptogram(struct osdp_pd *pd); -int osdp_verify_cp_cryptogram(struct osdp_pd *pd); -void osdp_compute_pd_cryptogram(struct osdp_pd *pd); -int osdp_verify_pd_cryptogram(struct osdp_pd *pd); -void osdp_compute_rmac_i(struct osdp_pd *pd); -int osdp_decrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int len); -int osdp_encrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int len); -int osdp_compute_mac(struct osdp_pd *pd, int is_cmd, - const uint8_t *data, int len); -void osdp_sc_init(struct osdp_pd *pd); - -/* from osdp_common.c */ -__attribute__((weak)) int64_t osdp_millis_now(void); -int64_t osdp_millis_since(int64_t last); -/* void osdp_dump(const char *head, uint8_t *buf, int len); */ -uint16_t osdp_compute_crc16(const uint8_t *buf, size_t len); -__attribute__((weak)) void osdp_encrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len); -__attribute__((weak)) void osdp_decrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len); -__attribute__((weak)) void osdp_get_rand(uint8_t *buf, int len); -int osdp_device_lock(struct os_mutex *lock); -void osdp_device_unlock(struct os_mutex *lock); - -/** - * @brief This method is used to setup a device in PD mode. Application must - * store the returned context poiter and pass it back to all OSDP functions - * intact. - * - * @param info Pointer to iinfo struct populated by application. - * @param scbk 16 byte Secure Channel Base Key. If this field is NULL PD is set - * to "Install Mode". - * - * @return OSDP Context on success - * @return NULL on errors - */ -osdp_t *osdp_pd_setup(struct osdp_ctx *osdp_ctx, osdp_pd_info_t *info, uint8_t *scbk); - -/** - * @brief This method is used to setup a device in CP mode. Application must - * store the returned context poiter and pass it back to all OSDP functions - * intact. - * - * @param num_pd Number of PDs connected to this CP. The `osdp_pd_info_t *` is - * treated as an array of length num_pd. - * @param info Pointer to info struct populated by application. - * @param scbk 16 byte Secure Channel Base Key. If this field is NULL PD is set - * to "Install Mode". - * - * @return OSDP Context on success - * @return NULL on errors - */ -osdp_t *osdp_cp_setup(struct osdp_ctx *osdp_ctx, int num_pd, osdp_pd_info_t *info, - uint8_t *master_key); - -#endif /* _OSDP_COMMON_H_ */ diff --git a/net/osdp/include/osdp/osdp_config.h b/net/osdp/include/osdp/osdp_config.h new file mode 100644 index 0000000000..f9c636d412 --- /dev/null +++ b/net/osdp/include/osdp/osdp_config.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020-2026 Siddharth Chandrasekaran + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _OSDP_CONFIG_H_ +#define _OSDP_CONFIG_H_ + +#include + +/** + * @brief The following macros are defined defined from the variable in cmake + * files. All @XXX@ are replaced by the value of XXX as resolved by cmake. + */ +#define PROJECT_VERSION "3.2.1" +#define PROJECT_NAME "libosdp" +#define GIT_BRANCH "" +#define GIT_REV "" +#define GIT_TAG "" +#define GIT_DIFF "" +#define REPO_ROOT "" + +/** + * @brief OSDP configuration parameters + * + * These values can be overridden by build system (Kconfig for Zephyr, + * CMake options for other platforms). The values below are defaults + * used when not overridden. + */ + +/* Protocol Timings */ +#ifndef OSDP_PD_SC_RETRY_MS +#define OSDP_PD_SC_RETRY_MS (MYNEWT_VAL(OSDP_SC_RETRY_WAIT_SEC) * 1000u) +#endif + +#ifndef OSDP_PD_POLL_TIMEOUT_MS +#define OSDP_PD_POLL_TIMEOUT_MS (1000 / MYNEWT_VAL(OSDP_PD_POLL_RATE)) +#endif + +#ifndef OSDP_PD_SC_TIMEOUT_MS +#define OSDP_PD_SC_TIMEOUT_MS (MYNEWT_VAL(OSDP_PD_SC_TIMEOUT_MS) * 1000u) +#endif + +#ifndef OSDP_PD_ONLINE_TOUT_MS +#define OSDP_PD_ONLINE_TOUT_MS (MYNEWT_VAL(OSDP_PD_IDLE_TIMEOUT_MS)) +#endif + +#ifndef OSDP_RESP_TOUT_MS +#define OSDP_RESP_TOUT_MS (MYNEWT_VAL(OSDP_RESP_TOUT_MS)) +#endif + +#ifndef OSDP_CMD_RETRY_WAIT_MS +#define OSDP_CMD_RETRY_WAIT_MS (MYNEWT_VAL(OSDP_CMD_RETRY_WAIT_SEC) * 1000) +#endif + +#ifndef OSDP_ONLINE_RETRY_WAIT_MAX_MS +#define OSDP_ONLINE_RETRY_WAIT_MAX_MS \ + (MYNEWT_VAL(OSDP_ONLINE_RETRY_WAIT_MAX_SEC) * 1000u) +#endif + +/* Protocol Limits */ +#ifndef OSDP_CMD_MAX_RETRIES +#define OSDP_CMD_MAX_RETRIES (8) +#endif + +#ifndef OSDP_FILE_ERROR_RETRY_MAX +#define OSDP_FILE_ERROR_RETRY_MAX (10) +#endif + +#ifndef OSDP_PD_MAX +#define OSDP_PD_MAX (126) +#endif + +#ifndef OSDP_PD_NAME_MAXLEN +#define OSDP_PD_NAME_MAXLEN (16) +#endif + +/* Memory Configuration */ +#ifndef OSDP_PACKET_BUF_SIZE +#define OSDP_PACKET_BUF_SIZE (256) +#endif + +#ifndef OSDP_MINIMUM_PACKET_SIZE +#define OSDP_MINIMUM_PACKET_SIZE (128) +#endif + +#ifndef OSDP_RX_RB_SIZE +#define OSDP_RX_RB_SIZE (512) +#endif + +#ifndef OSDP_CP_CMD_POOL_SIZE +#define OSDP_CP_CMD_POOL_SIZE (4) +#endif + +/* Internal Constants */ +#ifndef OSDP_CMD_ID_OFFSET +#define OSDP_CMD_ID_OFFSET (MYNEWT_VAL(OSDP_CMD_ID_OFFSET)) +#endif + +#ifndef OSDP_PCAP_LINK_TYPE +#define OSDP_PCAP_LINK_TYPE (162) +#endif + +#endif /* _OSDP_CONFIG_H_ */ diff --git a/net/osdp/src/osdp_hooks.c b/net/osdp/include/osdp/osdp_mynewt.h similarity index 74% rename from net/osdp/src/osdp_hooks.c rename to net/osdp/include/osdp/osdp_mynewt.h index dc445fda3e..941e93b145 100644 --- a/net/osdp/src/osdp_hooks.c +++ b/net/osdp/include/osdp/osdp_mynewt.h @@ -17,17 +17,19 @@ * under the License. */ -#include "osdp/osdp_hooks.h" -#include "modlog/modlog.h" +#ifndef _OSDP_MYNEWT_H_ +#define _OSDP_MYNEWT_H_ -#if MYNEWT_VAL(OSDP_USE_CRYPTO_HOOK) -/* - * Stub function. Needs to be overridden to use correctly +#include + +/** + * @brief Initialize context for OSDP library. + */ +struct osdp_t *osdp_init(osdp_pd_info_t *info); + +/** + * @brief Stop OSDP library. */ -size_t -osdp_hook_crypto_random_bytes(uint8_t *out, size_t out_len) -{ - return 1; -} +void osdp_stop(void); -#endif /* OSDP_USE_CRYPTO_HOOK */ +#endif /* _OSDP_MYNEWT_H_ */ diff --git a/net/osdp/include/osdp/osdp_utils.h b/net/osdp/include/osdp/osdp_utils.h deleted file mode 100644 index b0df7dbe05..0000000000 --- a/net/osdp/include/osdp/osdp_utils.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _OSDP_UTILS_H_ -#define _OSDP_UTILS_H_ - -#include -#include - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#ifndef TRUE -#define TRUE (1) -#endif - -#ifndef FALSE -#define FALSE (0) -#endif - -#define BYTE_0(x) (uint8_t)(((x) >> 0) & 0xFF) -#define BYTE_1(x) (uint8_t)(((x) >> 8) & 0xFF) -#define BYTE_2(x) (uint8_t)(((x) >> 16) & 0xFF) -#define BYTE_3(x) (uint8_t)(((x) >> 24) & 0xFF) - -#define ARG_UNUSED(x) (void)(x) - -#define STR(x) #x -#define XSTR(x) STR(x) - -#define MATH_MOD(a, b) (((a % b) + b) % b) - -#define IS_POW2(n) ((n) & ((n) - 1)) - -#define ARRAY_SIZEOF(x) \ - (sizeof(x) / sizeof(x[0])) - -#define ARRAY_BASE(ptr, type, offset) \ - ((char *)(ptr)) - ((sizeof(type)) * offset) - -#define OFFSET_OF(type, field) (size_t)(&((type *)(0))->field) - -#define OSDP_CONTAINER_OF(ptr, type, field) \ - ((type *)(((char *)(ptr)) - OFFSET_OF(type, field))) - -#define U16_STR_SZ (sizeof("65535")) -/* - #define MAX(a,b) ({ \ - __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; \ - }) - - #define MIN(a,b) ({ \ - __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _b : _a; \ - }) - */ - -/* config_enabled() from the kernel */ -#define __IS_ENABLED1(x) __IS_ENABLED2(__XXXX ## x) -#define __XXXX1 __YYYY, -#define __IS_ENABLED2(y) __IS_ENABLED3(y 1, 0) -#define __IS_ENABLED3(_i, val, ...) val - -#define IS_ENABLED(x) __IS_ENABLED1(x) - -/* gcc attribute shorthands */ -#ifndef __fallthrough -#if __GNUC__ >= 7 -#define __fallthrough __attribute__((fallthrough)) -#else -#define __fallthrough -#endif -#endif - -#ifndef __packed -#define __packed __attribute__((__packed__)) -#endif - -/** - * @brief Dumps an array of bytes in HEX and ASCII formats for debugging. `head` - * is string that is printed before the actual bytes are dumped. - * - * Example: - * int len; - * uint8_t data[MAX_LEN]; - * len = get_data_from_somewhere(data, MAX_LEN); - * hexdump(data, len, "Data From Somewhere"); - */ -void hexdump(const uint8_t *data, size_t len, const char *fmt, ...); - -/** - * @brief Convert a single character into a hexadecimal nibble. - * - * @param c The character to convert - * @param x The address of storage for the converted number. - * - * @return Zero on success or (negative) error code otherwise. - */ -int char2hex(char c, uint8_t *x); - -/** - * @brief Convert a hexadecimal string into a binary array. - * - * @param hex The hexadecimal string to convert - * @param hexlen The length of the hexadecimal string to convert. - * @param buf Address of where to store the binary data - * @param buflen Size of the storage area for binary data - * - * @return The length of the binary array, or 0 if an error occurred. - */ -size_t hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen); - -/** - * @brief Convert unsigned 16bit number to string. - * - * @param num The unsigned 16bit number to convert. - * @param str Input buffer enough for UINT16_MAX including null terminator. - * - * @return Pointer to start of string. - */ -char *u16_to_str(uint16_t num, char *str); - -#endif /* _OSDP_UTILS_H_ */ diff --git a/net/osdp/pkg.yml b/net/osdp/pkg.yml index 5a941089f4..db5fa1b35e 100644 --- a/net/osdp/pkg.yml +++ b/net/osdp/pkg.yml @@ -17,16 +17,52 @@ # pkg.name: net/osdp -pkg.description: > - This package is a mynewt port of libOSDP library - available at https://github.com/goToMain/libosdp - It is currently at par with commit hash - aaba129fe6ad71d61b8526bd8a9b3778b93c9b26 +pkg.description: OSDP (Open Supervised Device Protocol) library pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" +pkg.homepage: "https://github.com/goToMain/libosdp" pkg.keywords: - osdp +pkg.type: sdk + +pkg.include_dirs: + - "include" + - "@osdp/include" + +pkg.private_include_dirs: + - "@osdp/utils/include" + - "include/osdp" + +pkg.source_files: + - "src/osdp_mynewt.c" + - "src/osdp_mynewt_utils.c" + - "@osdp/src/osdp_common.c" + - "@osdp/src/osdp_phy.c" + - "@osdp/src/osdp_sc.c" + - "@osdp/src/osdp_file.c" + - "@osdp/src/crypto/mbedtls.c" + - "@osdp/utils/src/list.c" + - "@osdp/utils/src/queue.c" + - "@osdp/utils/src/utils.c" + - "@osdp/utils/src/disjoint_set.c" + - "@osdp/utils/src/slab.c" + - "@osdp/utils/src/crc16.c" + - "@osdp/utils/src/logger.c" + +pkg.source_files.OSDP_MODE_PD: + - "@osdp/src/osdp_pd.c" + +pkg.source_files.OSDP_MODE_CP: + - "@osdp/src/osdp_cp.c" + pkg.deps: - - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/util/crc" + - "@apache-mynewt-core/crypto/mbedtls" + +# allows to override settings from mbedtls +pkg.subpriority: 1 + +repository.osdp: + type: github + vers: v3.2.1-commit + user: goToMain + repo: libosdp diff --git a/net/osdp/src/osdp_common.c b/net/osdp/src/osdp_common.c deleted file mode 100644 index b5d1b09e18..0000000000 --- a/net/osdp/src/osdp_common.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include "modlog/modlog.h" - -#include - -#include "tinycrypt/cbc_mode.h" -#include "tinycrypt/aes.h" -#include "tinycrypt/constants.h" -#if MYNEWT_VAL(TRNG) && !MYNEWT_VAL(OSDP_USE_CRYPTO_HOOK) -#include "trng/trng.h" -#endif /* MYNEWT_VAL(TRNG) && !MYNEWT_VAL(OSDP_USE_CRYPTO_HOOK) */ - -#include "osdp/osdp_common.h" -#include "osdp/osdp_hooks.h" - -/* - * Set this to size of the max UART buffer length and add block size - * If the entire buffer were to be encrypted, account for the - * the fact that the output buffer comes with IV appended - */ -#define MAX_UART_BUF (max(MYNEWT_VAL(OSDP_UART_TX_BUFFER_LENGTH), \ - MYNEWT_VAL(OSDP_UART_RX_BUFFER_LENGTH))) -#define MAX_SCRATCH_LEN (MAX_UART_BUF + TC_AES_BLOCK_SIZE) -static uint8_t scratch_buf1[MAX_SCRATCH_LEN]; -#if MYNEWT_VAL(TRNG) && !MYNEWT_VAL(OSDP_USE_CRYPTO_HOOK) -static struct trng_dev *trng = NULL; -#endif /* MYNEWT_VAL(TRNG) && !MYNEWT_VAL(OSDP_USE_CRYPTO_HOOK) */ - -#define OSDP_LOCK_TMO \ - (OS_TICKS_PER_SEC * MYNEWT_VAL(OSDP_DEVICE_LOCK_TIMEOUT_MS)/1000 + 1) - -#if 0 -/* see macro in osdp_common.h */ -void -osdp_dump(const char *head, uint8_t *buf, int len) -{ - -} -#endif - -uint16_t -osdp_compute_crc16(const uint8_t *buf, size_t len) -{ - return crc16_ccitt(0x1D0F, buf, len); -} - -int64_t -osdp_millis_now(void) -{ - return (os_get_uptime_usec() / 1000); -} - -int64_t -osdp_millis_since(int64_t last) -{ - return osdp_millis_now() - last; -} - -void -osdp_encrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len) -{ - struct tc_aes_key_sched_struct s; - (void)tc_aes128_set_encrypt_key(&s, key); - - if (iv != NULL) { - /* Check if there is enough space for IV + len */ - assert(len <= MAX_SCRATCH_LEN - TC_AES_BLOCK_SIZE); - if (tc_cbc_mode_encrypt(scratch_buf1, /* out: output buffer */ - len + TC_AES_BLOCK_SIZE, /* outlen: max output size, including size of IV */ - data, /* in: input buffer */ - len, /* inlen: input len */ - iv, /* iv: IV start */ - &s) == TC_CRYPTO_FAIL) { - OSDP_LOG_ERROR("osdp: sc: CBC ENCRYPT - Failed"); - } - - /* copy ciphertext from offset */ - memcpy(data, scratch_buf1 + TC_AES_BLOCK_SIZE, len); - - } else { - if (tc_aes_encrypt(data, data, &s) == TC_CRYPTO_FAIL) { - OSDP_LOG_ERROR("osdp: sc: ECB ENCRYPT - Failed\n"); - } - } -} - -void -osdp_decrypt(uint8_t *key, uint8_t *iv, uint8_t *data, int len) -{ - struct tc_aes_key_sched_struct s; - (void)tc_aes128_set_decrypt_key(&s, key); - - if (iv != NULL) { - /* Check if there is enough space for IV + len */ - assert(len <= MAX_SCRATCH_LEN - TC_AES_BLOCK_SIZE); - /* Create input buffer. IV and cipher text in contiguous buffer per tinycrypt */ - memcpy(scratch_buf1, iv, TC_AES_BLOCK_SIZE); - memcpy(scratch_buf1 + TC_AES_BLOCK_SIZE, data, len); - /* - note commit da923ca upstream(tinycrypt) - Commit message has this nugget:- - When decrypting with CBC mode, the in and out buffers should be the same size. - Even though the IV and ciphertext are contiguous, the in buffer points to the first byte of the ciphertext. - */ - if (tc_cbc_mode_decrypt(scratch_buf1, /* out: output buffer */ - len + TC_AES_BLOCK_SIZE, /* outlen: same as inlen */ - scratch_buf1 + TC_AES_BLOCK_SIZE, /* in: offset to ciphertext in input buffer */ - len + TC_AES_BLOCK_SIZE, /* inlen: total length of input, iv + buffer length */ - scratch_buf1, /* iv: offset to IV in input buffer */ - &s) == TC_CRYPTO_FAIL) { - OSDP_LOG_ERROR("osdp: sc: CBC DECRYPT - Failed\n"); - } - /* Copy decrypted data into output buffer */ - memcpy(data, scratch_buf1, len); - } else { - if (tc_aes_decrypt(data, data, &s) == TC_CRYPTO_FAIL) { - OSDP_LOG_ERROR("osdp: sc: ECB DECRYPT - Failed\n"); - } - } -} - -void -osdp_get_rand(uint8_t *buf, int len) -{ - size_t ret = 0; - -#if MYNEWT_VAL(OSDP_USE_CRYPTO_HOOK) - ret = osdp_hook_crypto_random_bytes(buf, len); -#elif MYNEWT_VAL(TRNG) - trng = (struct trng_dev *) os_dev_open("trng", OS_WAIT_FOREVER, NULL); - if (trng == NULL) { - OSDP_LOG_ERROR("osdp: sc: Could not open TRNG\n"); - buf = NULL; - } - - ret = trng_read(trng, buf, len); - while (ret < len) { - os_sched(NULL); - ret += trng_read(trng, &buf[ret], len - ret); - } - - os_dev_close((struct os_dev *)trng); -#endif - - if (ret == 0) { - buf = NULL; - } -} - -uint32_t -osdp_get_sc_status_mask(osdp_t *ctx) -{ - int i; - uint32_t mask = 0; - struct osdp_pd *pd; - - assert(ctx); - - if (ISSET_FLAG(TO_OSDP(ctx), FLAG_CP_MODE)) { - for (i = 0; i < NUM_PD(ctx); i++) { - pd = TO_PD(ctx, i); - if (pd->state == OSDP_CP_STATE_ONLINE && - ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - mask |= 1 << i; - } - } - } else { - pd = TO_PD(ctx, 0); - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - mask = 1; - } - } - - return mask; -} - -uint32_t -osdp_get_status_mask(osdp_t *ctx) -{ - int i; - uint32_t mask = 0; - struct osdp_pd *pd; - - assert(ctx); - - if (ISSET_FLAG(TO_OSDP(ctx), FLAG_CP_MODE)) { - for (i = 0; i < TO_OSDP(ctx)->cp->num_pd; i++) { - pd = TO_PD(ctx, i); - if (pd->state == OSDP_CP_STATE_ONLINE) { - mask |= 1 << i; - } - } - } else { - /* PD state is either online or offline based on whether it got polled from CP */ - pd = TO_PD(ctx, 0); - if (ISSET_FLAG(pd, PD_FLAG_CP_POLL_ACTIVE)) { - mask = 1; - } - } - - return mask; -} - -/** - * Lock access to event/command resource. Blocks until configured timeout. - * - * @param The peripheral device to lock. - * - * @return 0 on success, non-zero on failure. - */ -int -osdp_device_lock(struct os_mutex *lock) -{ - int rc; - - rc = os_mutex_pend(lock, OSDP_LOCK_TMO); - if (rc == 0 || rc == OS_NOT_STARTED) { - return (0); - } - return (rc); -} - -/** - * Unlock access to the event/command resource. - * - * @param The peripheral device to unlock access to. - */ -void -osdp_device_unlock(struct os_mutex *lock) -{ - os_mutex_release(lock); -} - diff --git a/net/osdp/src/osdp_cp.c b/net/osdp/src/osdp_cp.c deleted file mode 100644 index 52b5e024c0..0000000000 --- a/net/osdp/src/osdp_cp.c +++ /dev/null @@ -1,1305 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include "modlog/modlog.h" - -#include "osdp/osdp_common.h" - -#if MYNEWT_VAL(OSDP_MODE_CP) /* compile flag based on mode */ - -#define TAG "CP: " - -#define OSDP_PD_POLL_TIMEOUT_MS (1000 / MYNEWT_VAL(OSDP_PD_POLL_RATE)) -#define OSDP_CMD_RETRY_WAIT_MS (MYNEWT_VAL(OSDP_CMD_RETRY_WAIT_SEC) * 1000) -#define OSDP_PD_SC_RETRY_MS (MYNEWT_VAL(OSDP_SC_RETRY_WAIT_SEC) * 1000) -#define OSDP_ONLINE_RETRY_WAIT_MAX_MS (MYNEWT_VAL(OSDP_ONLINE_RETRY_WAIT_MAX_SEC) * 1000) - -#define CMD_POLL_LEN 1 -#define CMD_LSTAT_LEN 1 -#define CMD_ISTAT_LEN 1 -#define CMD_OSTAT_LEN 1 -#define CMD_RSTAT_LEN 1 -#define CMD_ID_LEN 2 -#define CMD_CAP_LEN 2 -#define CMD_DIAG_LEN 2 -#define CMD_OUT_LEN 5 -#define CMD_LED_LEN 15 -#define CMD_BUZ_LEN 6 -#define CMD_TEXT_LEN 7 /* variable length command */ -#define CMD_COMSET_LEN 6 -#define CMD_MFG_LEN 4 /* variable length command */ -#define CMD_KEYSET_LEN 19 -#define CMD_CHLNG_LEN 9 -#define CMD_SCRYPT_LEN 17 - -#define REPLY_ACK_DATA_LEN 0 -#define REPLY_PDID_DATA_LEN 12 -#define REPLY_PDCAP_ENTITY_LEN 3 -#define REPLY_LSTATR_DATA_LEN 2 -#define REPLY_RSTATR_DATA_LEN 1 -#define REPLY_COM_DATA_LEN 5 -#define REPLY_NAK_DATA_LEN 1 -#define REPLY_MFGREP_LEN 4 /* variable length command */ -#define REPLY_CCRYPT_DATA_LEN 32 -#define REPLY_RMAC_I_DATA_LEN 16 -#define REPLY_KEYPPAD_DATA_LEN 2 /* variable length command */ -#define REPLY_RAW_DATA_LEN 4 /* variable length command */ -#define REPLY_FMT_DATA_LEN 3 /* variable length command */ -#define REPLY_BUSY_DATA_LEN 0 - -#define OSDP_CP_ERR_NONE 0 -#define OSDP_CP_ERR_GENERIC -1 -#define OSDP_CP_ERR_EMPTY_Q -2 -#define OSDP_CP_ERR_NO_DATA 1 -#define OSDP_CP_ERR_RETRY_CMD 2 -#define OSDP_CP_ERR_CAN_YIELD 3 -#define OSDP_CP_ERR_INPROG 4 - -#define POOL_NAME_COMMON "cp_cmd_pool" - -/* Enough to hold POOL_NAME_COMMON + digits in 16bit number */ -static char pool_names[MYNEWT_VAL(OSDP_PD_COMMAND_QUEUE_SIZE)][sizeof(POOL_NAME_COMMON) + U16_STR_SZ - 1]; - -static int -cp_cmd_queue_init(struct osdp_pd *pd, uint16_t num) -{ - int rc; - char buf[U16_STR_SZ] = {0}; - - char *num_ptr = u16_to_str(num, buf); - memcpy(pool_names[num], POOL_NAME_COMMON, sizeof(POOL_NAME_COMMON)); - strcat(pool_names[num], num_ptr); - - rc = os_mempool_init(&pd->cmd.pool, - MYNEWT_VAL(OSDP_PD_COMMAND_QUEUE_SIZE), - sizeof(struct cp_cmd_node), - pd->cmd.pool_buf, pool_names[num]); - - if (rc != OS_OK) { - OSDP_LOG_ERROR("osdp: cp: Failed to initialize command pool\n"); - return rc; - } - - pd->cmd.queue.tqh_first = NULL; - pd->cmd.queue.tqh_last = &pd->cmd.queue.tqh_first; - - os_mutex_init(&pd->lock); - - return rc; -} - -static struct osdp_cmd * -cp_cmd_alloc(struct osdp_pd *pd) -{ - struct cp_cmd_node *cmd = NULL; - - cmd = os_memblock_get(&pd->cmd.pool); - if (cmd == NULL) { - OSDP_LOG_ERROR("osdp: cp: Command pool allocation failed\n"); - return NULL; - } - - return &cmd->object; -} - -static void -cp_cmd_free(struct osdp_pd *pd, struct osdp_cmd *cmd) -{ - struct cp_cmd_node *node; - - node = CONTAINER_OF(cmd, struct cp_cmd_node, object); - os_memblock_put(&pd->cmd.pool, node); -} - -static void -cp_cmd_enqueue(struct osdp_pd *pd, struct osdp_cmd *cmd) -{ - struct cp_cmd_node *node; - - node = CONTAINER_OF(cmd, struct cp_cmd_node, object); - TAILQ_INSERT_HEAD(&pd->cmd.queue, node, cp_node); -} - -static int -cp_cmd_dequeue(struct osdp_pd *pd, struct osdp_cmd **cmd) -{ - struct cp_cmd_node *node; - - node = TAILQ_LAST(&pd->cmd.queue, queue); - if (node == NULL) { - return OSDP_CP_ERR_EMPTY_Q; - } - TAILQ_REMOVE(&pd->cmd.queue, node, cp_node); - - *cmd = &node->object; - return 0; -} - -static void -cp_flush_command_queue(struct osdp_pd *pd) -{ - struct osdp_cmd *cmd; - - while (cp_cmd_dequeue(pd, &cmd) == 0) { - cp_cmd_free(pd, cmd); - } -} - -static void -cp_cmd_queue_del(struct osdp_pd *pd) -{ - /* Empty the queue and put back blocks */ - cp_flush_command_queue(pd); - - os_mempool_clear(&pd->cmd.pool); - os_mempool_unregister(&pd->cmd.pool); -} - -static int -cp_cmd_get(struct osdp_pd *pd, struct osdp_cmd **cmd, int *ret) -{ - int rc = 0; - - rc = osdp_device_lock(&pd->lock); - if (rc) { - *ret = OSDP_CP_ERR_NONE; /* no error for now, retry later */ - return rc; - } - - rc = cp_cmd_dequeue(pd, cmd); - if (rc) { - *ret = OSDP_CP_ERR_NONE; /* command queue is empty */ - goto err; - } - - pd->cmd_id = (*cmd)->id; - memcpy(pd->ephemeral_data, *cmd, sizeof(struct osdp_cmd)); - cp_cmd_free(pd, *cmd); - -err: - osdp_device_unlock(&pd->lock); - return rc; -} - -static int -cp_cmd_put(struct osdp_pd *pd, struct osdp_cmd *in, int cmd_id) -{ - int rc = 0; - struct osdp_cmd *cmd; - - rc = osdp_device_lock(&pd->lock); - if (rc) { - return rc; - } - - cmd = cp_cmd_alloc(pd); - if (cmd == NULL) { - rc = OS_ENOMEM; - goto err; - } - - memcpy(cmd, in, sizeof(struct osdp_cmd)); - cmd->id = cmd_id; /* translate to internal */ - cp_cmd_enqueue(pd, cmd); - -err: - osdp_device_unlock(&pd->lock); - return rc; -} - - -static int -cp_channel_acquire(struct osdp_pd *pd, int *owner) -{ - int i; - struct osdp *ctx = TO_CTX(pd); - - if (ctx->cp->channel_lock[pd->offset] == pd->channel.id) { - return 0; /* already acquired! by current PD */ - } - assert(ctx->cp->channel_lock[pd->offset] == 0); - for (i = 0; i < NUM_PD(ctx); i++) { - if (ctx->cp->channel_lock[i] == pd->channel.id) { - /* some other PD has locked this channel */ - if (owner != NULL) { - *owner = i; - } - return -1; - } - } - ctx->cp->channel_lock[pd->offset] = pd->channel.id; - - return 0; -} - -static int -cp_channel_release(struct osdp_pd *pd) -{ - struct osdp *ctx = TO_CTX(pd); - - if (ctx->cp->channel_lock[pd->offset] != pd->channel.id) { - OSDP_LOG_ERROR("osdp: cp: Attempt to release another PD's channel lock\n"); - return -1; - } - ctx->cp->channel_lock[pd->offset] = 0; - - return 0; -} - -/** - * Returns: - * +ve: length of command - * -ve: error - */ -static int -cp_build_command(struct osdp_pd *pd, uint8_t *buf, int max_len) -{ - uint8_t *smb; - struct osdp_cmd *cmd = NULL; - int data_off, i, ret = -1, len = 0; - - data_off = osdp_phy_packet_get_data_offset(pd, buf); - smb = osdp_phy_packet_get_smb(pd, buf); - - buf += data_off; - max_len -= data_off; - -#define ASSERT_BUF_LEN(need) \ - if (max_len < need) { \ - OSDP_LOG_ERROR("osdp: cp: OOM at build CMD(%02x) - have:%d, need:%d\n", \ - pd->cmd_id, max_len, need); \ - return OSDP_CP_ERR_GENERIC; \ - } - - switch (pd->cmd_id) { - case CMD_POLL: - ASSERT_BUF_LEN(CMD_POLL_LEN); - buf[len++] = pd->cmd_id; - ret = 0; - break; - case CMD_LSTAT: - ASSERT_BUF_LEN(CMD_LSTAT_LEN); - buf[len++] = pd->cmd_id; - ret = 0; - break; - case CMD_ISTAT: - ASSERT_BUF_LEN(CMD_ISTAT_LEN); - buf[len++] = pd->cmd_id; - ret = 0; - break; - case CMD_OSTAT: - ASSERT_BUF_LEN(CMD_OSTAT_LEN); - buf[len++] = pd->cmd_id; - ret = 0; - break; - case CMD_RSTAT: - ASSERT_BUF_LEN(CMD_RSTAT_LEN); - buf[len++] = pd->cmd_id; - ret = 0; - break; - case CMD_ID: - ASSERT_BUF_LEN(CMD_ID_LEN); - buf[len++] = pd->cmd_id; - buf[len++] = 0x00; - ret = 0; - break; - case CMD_CAP: - ASSERT_BUF_LEN(CMD_CAP_LEN); - buf[len++] = pd->cmd_id; - buf[len++] = 0x00; - ret = 0; - break; - case CMD_DIAG: - ASSERT_BUF_LEN(CMD_DIAG_LEN); - buf[len++] = pd->cmd_id; - buf[len++] = 0x00; - ret = 0; - break; - case CMD_OUT: - ASSERT_BUF_LEN(CMD_OUT_LEN); - cmd = (struct osdp_cmd *)pd->ephemeral_data; - buf[len++] = pd->cmd_id; - buf[len++] = cmd->output.output_no; - buf[len++] = cmd->output.control_code; - buf[len++] = BYTE_0(cmd->output.timer_count); - buf[len++] = BYTE_1(cmd->output.timer_count); - ret = 0; - break; - case CMD_LED: - ASSERT_BUF_LEN(CMD_LED_LEN); - cmd = (struct osdp_cmd *)pd->ephemeral_data; - buf[len++] = pd->cmd_id; - buf[len++] = cmd->led.reader; - buf[len++] = cmd->led.led_number; - - buf[len++] = cmd->led.temporary.control_code; - buf[len++] = cmd->led.temporary.on_count; - buf[len++] = cmd->led.temporary.off_count; - buf[len++] = cmd->led.temporary.on_color; - buf[len++] = cmd->led.temporary.off_color; - buf[len++] = BYTE_0(cmd->led.temporary.timer_count); - buf[len++] = BYTE_1(cmd->led.temporary.timer_count); - - buf[len++] = cmd->led.permanent.control_code; - buf[len++] = cmd->led.permanent.on_count; - buf[len++] = cmd->led.permanent.off_count; - buf[len++] = cmd->led.permanent.on_color; - buf[len++] = cmd->led.permanent.off_color; - ret = 0; - break; - case CMD_BUZ: - ASSERT_BUF_LEN(CMD_BUZ_LEN); - cmd = (struct osdp_cmd *)pd->ephemeral_data; - buf[len++] = pd->cmd_id; - buf[len++] = cmd->buzzer.reader; - buf[len++] = cmd->buzzer.control_code; - buf[len++] = cmd->buzzer.on_count; - buf[len++] = cmd->buzzer.off_count; - buf[len++] = cmd->buzzer.rep_count; - ret = 0; - break; - case CMD_TEXT: - cmd = (struct osdp_cmd *)pd->ephemeral_data; - ASSERT_BUF_LEN(CMD_TEXT_LEN + cmd->text.length); - buf[len++] = pd->cmd_id; - buf[len++] = cmd->text.reader; - buf[len++] = cmd->text.control_code; - buf[len++] = cmd->text.temp_time; - buf[len++] = cmd->text.offset_row; - buf[len++] = cmd->text.offset_col; - buf[len++] = cmd->text.length; - for (i = 0; i < cmd->text.length; i++) { - buf[len++] = cmd->text.data[i]; - } - ret = 0; - break; - case CMD_COMSET: - ASSERT_BUF_LEN(CMD_COMSET_LEN); - cmd = (struct osdp_cmd *)pd->ephemeral_data; - buf[len++] = pd->cmd_id; - buf[len++] = cmd->comset.address; - buf[len++] = BYTE_0(cmd->comset.baud_rate); - buf[len++] = BYTE_1(cmd->comset.baud_rate); - buf[len++] = BYTE_2(cmd->comset.baud_rate); - buf[len++] = BYTE_3(cmd->comset.baud_rate); - ret = 0; - break; - case CMD_MFG: - cmd = (struct osdp_cmd *)pd->ephemeral_data; - ASSERT_BUF_LEN(CMD_MFG_LEN + cmd->mfg.length); - buf[len++] = pd->cmd_id; - buf[len++] = BYTE_0(cmd->mfg.vendor_code); - buf[len++] = BYTE_1(cmd->mfg.vendor_code); - buf[len++] = BYTE_2(cmd->mfg.vendor_code); - buf[len++] = cmd->mfg.command; - for (i = 0; i < cmd->mfg.length; i++) { - buf[len++] = cmd->mfg.data[i]; - } - ret = 0; - break; - case CMD_KEYSET: - if (!ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - OSDP_LOG_ERROR("osdp: cp: Can not perform a KEYSET without SC!\n"); - return -1; - } - cmd = (struct osdp_cmd *)pd->ephemeral_data; - ASSERT_BUF_LEN(CMD_KEYSET_LEN); - buf[len++] = pd->cmd_id; - buf[len++] = 1; /* key type (1: SCBK) */ - buf[len++] = 16; /* key length in bytes */ - osdp_compute_scbk(pd, cmd->keyset.data, buf + len); - len += 16; - ret = 0; - break; - case CMD_CHLNG: - ASSERT_BUF_LEN(CMD_CHLNG_LEN); - if (smb == NULL) { - break; - } - smb[0] = 3; /* length */ - smb[1] = SCS_11; /* type */ - smb[2] = ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD) ? 0 : 1; - buf[len++] = pd->cmd_id; - for (i = 0; i < 8; i++) { - buf[len++] = pd->sc.cp_random[i]; - } - ret = 0; - break; - case CMD_SCRYPT: - ASSERT_BUF_LEN(CMD_SCRYPT_LEN); - if (smb == NULL) { - break; - } - osdp_compute_cp_cryptogram(pd); - smb[0] = 3; /* length */ - smb[1] = SCS_13; /* type */ - smb[2] = ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD) ? 0 : 1; - buf[len++] = pd->cmd_id; - for (i = 0; i < 16; i++) { - buf[len++] = pd->sc.cp_cryptogram[i]; - } - ret = 0; - break; - default: - OSDP_LOG_ERROR("osdp: cp: Unknown/Unsupported CMD(%02x)\n", pd->cmd_id); - return OSDP_CP_ERR_GENERIC; - } - - if (smb && (smb[1] > SCS_14) && ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - /** - * When SC active and current cmd is not a handshake (<= SCS_14) - * then we must set SCS type to 17 if this message has data - * bytes and 15 otherwise. - */ - smb[0] = 2; - smb[1] = (len > 1) ? SCS_17 : SCS_15; - } - - if (ret < 0) { - OSDP_LOG_ERROR("osdp: cp: Unable to build CMD(%02x)\n", pd->cmd_id); - return OSDP_CP_ERR_GENERIC; - } - - return len; -} - -static int -cp_decode_response(struct osdp_pd *pd, uint8_t *buf, int len) -{ - uint32_t temp32; - struct osdp_cp *cp = TO_CTX(pd)->cp; - int i, ret = OSDP_CP_ERR_GENERIC, pos = 0, t1, t2; - struct osdp_event event; - - pd->reply_id = buf[pos++]; - len--; /* consume reply id from the head */ - -#define ASSERT_LENGTH(got, exp) \ - if (got != exp) { \ - OSDP_LOG_ERROR("osdp: cp: REPLY(%02x) length error! Got:%d, Exp:%d\n", \ - pd->reply_id, got, exp); \ - return OSDP_CP_ERR_GENERIC; \ - } - - switch (pd->reply_id) { - case REPLY_ACK: - ASSERT_LENGTH(len, REPLY_ACK_DATA_LEN); - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_NAK: - ASSERT_LENGTH(len, REPLY_NAK_DATA_LEN); - OSDP_LOG_WARN("osdp: cp: PD replied with NAK(%d) for CMD(%02x)", - buf[pos], pd->cmd_id); - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_PDID: - ASSERT_LENGTH(len, REPLY_PDID_DATA_LEN); - pd->id.vendor_code = buf[pos++]; - pd->id.vendor_code |= buf[pos++] << 8; - pd->id.vendor_code |= buf[pos++] << 16; - - pd->id.model = buf[pos++]; - pd->id.version = buf[pos++]; - - pd->id.serial_number = buf[pos++]; - pd->id.serial_number |= buf[pos++] << 8; - pd->id.serial_number |= buf[pos++] << 16; - pd->id.serial_number |= buf[pos++] << 24; - - pd->id.firmware_version = buf[pos++] << 16; - pd->id.firmware_version |= buf[pos++] << 8; - pd->id.firmware_version |= buf[pos++]; - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_PDCAP: - if ((len % REPLY_PDCAP_ENTITY_LEN) != 0) { - OSDP_LOG_ERROR("osdp: cp: PDCAP response length is not a multiple of 3", - buf[pos], pd->cmd_id); - return OSDP_CP_ERR_GENERIC; - } - while (pos < len) { - t1 = buf[pos++]; /* func_code */ - if (t1 > OSDP_PD_CAP_SENTINEL) { - break; - } - pd->cap[t1].function_code = t1; - pd->cap[t1].compliance_level = buf[pos++]; - pd->cap[t1].num_items = buf[pos++]; - } - /* post-capabilities hooks */ - t2 = OSDP_PD_CAP_COMMUNICATION_SECURITY; - if (pd->cap[t2].compliance_level & 0x01) { - SET_FLAG(pd, PD_FLAG_SC_CAPABLE); - } else { - CLEAR_FLAG(pd, PD_FLAG_SC_CAPABLE); - } - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_LSTATR: - ASSERT_LENGTH(len, REPLY_LSTATR_DATA_LEN); - if (buf[pos++]) { - SET_FLAG(pd, PD_FLAG_TAMPER); - } else { - CLEAR_FLAG(pd, PD_FLAG_TAMPER); - } - if (buf[pos++]) { - SET_FLAG(pd, PD_FLAG_POWER); - } else { - CLEAR_FLAG(pd, PD_FLAG_POWER); - } - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_RSTATR: - ASSERT_LENGTH(len, REPLY_RSTATR_DATA_LEN); - if (buf[pos++]) { - SET_FLAG(pd, PD_FLAG_R_TAMPER); - } else { - CLEAR_FLAG(pd, PD_FLAG_R_TAMPER); - } - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_COM: - ASSERT_LENGTH(len, REPLY_COM_DATA_LEN); - t1 = buf[pos++]; - temp32 = buf[pos++]; - temp32 |= buf[pos++] << 8; - temp32 |= buf[pos++] << 16; - temp32 |= buf[pos++] << 24; - OSDP_LOG_WARN("osdp: cp: COMSET responded with ID:%d Baud:%d\n", t1, temp32); - pd->address = t1; - pd->baud_rate = temp32; - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_KEYPPAD: - if (len < REPLY_KEYPPAD_DATA_LEN || !cp->event_callback) { - break; - } - event.type = OSDP_EVENT_KEYPRESS; - event.keypress.reader_no = buf[pos++]; - event.keypress.length = buf[pos++]; /* key length */ - if ((len - REPLY_KEYPPAD_DATA_LEN) != event.keypress.length) { - break; - } - for (i = 0; i < event.keypress.length; i++) { - event.keypress.data[i] = buf[pos + i]; - } - cp->event_callback(cp->event_callback_arg, pd->offset, &event); - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_RAW: - if (len < REPLY_RAW_DATA_LEN || !cp->event_callback) { - break; - } - event.type = OSDP_EVENT_CARDREAD; - event.cardread.reader_no = buf[pos++]; - event.cardread.format = buf[pos++]; - event.cardread.length = buf[pos++]; /* bits LSB */ - event.cardread.length |= buf[pos++] << 8; /* bits MSB */ - event.cardread.direction = 0; /* un-specified */ - t1 = (event.cardread.length + 7) / 8; /* len: bytes */ - if (t1 != (len - REPLY_RAW_DATA_LEN)) { - break; - } - for (i = 0; i < t1; i++) { - event.cardread.data[i] = buf[pos + i]; - } - cp->event_callback(cp->event_callback_arg, pd->offset, &event); - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_FMT: - if (len < REPLY_FMT_DATA_LEN || !cp->event_callback) { - break; - } - event.type = OSDP_EVENT_CARDREAD; - event.cardread.reader_no = buf[pos++]; - event.cardread.direction = buf[pos++]; - event.cardread.length = buf[pos++]; - event.cardread.format = OSDP_CARD_FMT_ASCII; - if (event.cardread.length != (len - REPLY_FMT_DATA_LEN) || - event.cardread.length > OSDP_EVENT_MAX_DATALEN) { - break; - } - for (i = 0; i < event.cardread.length; i++) { - event.cardread.data[i] = buf[pos + i]; - } - cp->event_callback(cp->event_callback_arg, pd->offset, &event); - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_BUSY: - /* PD busy; signal upper layer to retry command */ - ASSERT_LENGTH(len, REPLY_BUSY_DATA_LEN); - ret = OSDP_CP_ERR_RETRY_CMD; - break; - case REPLY_MFGREP: - if (len < REPLY_MFGREP_LEN || !cp->event_callback) { - break; - } - event.type = OSDP_EVENT_MFGREP; - event.mfgrep.vendor_code = buf[pos++]; - event.mfgrep.vendor_code |= buf[pos++] << 8; - event.mfgrep.vendor_code |= buf[pos++] << 16; - event.mfgrep.command = buf[pos++]; - event.mfgrep.length = len - REPLY_MFGREP_LEN; - if (event.mfgrep.length > OSDP_EVENT_MAX_DATALEN) { - break; - } - for (i = 0; i < event.mfgrep.length; i++) { - event.mfgrep.data[i] = buf[pos + i]; - } - cp->event_callback(cp->event_callback_arg, pd->offset, &event); - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_CCRYPT: - ASSERT_LENGTH(len, REPLY_CCRYPT_DATA_LEN); - for (i = 0; i < 8; i++) { - pd->sc.pd_client_uid[i] = buf[pos++]; - } - for (i = 0; i < 8; i++) { - pd->sc.pd_random[i] = buf[pos++]; - } - for (i = 0; i < 16; i++) { - pd->sc.pd_cryptogram[i] = buf[pos++]; - } - osdp_compute_session_keys(TO_CTX(pd)); - if (osdp_verify_pd_cryptogram(pd) != 0) { - OSDP_LOG_ERROR("osdp: cp: Failed to verify PD cryptogram\n"); - return OSDP_CP_ERR_GENERIC; - } - ret = OSDP_CP_ERR_NONE; - break; - case REPLY_RMAC_I: - ASSERT_LENGTH(len, REPLY_RMAC_I_DATA_LEN); - for (i = 0; i < 16; i++) { - pd->sc.r_mac[i] = buf[pos++]; - } - SET_FLAG(pd, PD_FLAG_SC_ACTIVE); - ret = OSDP_CP_ERR_NONE; - break; - default: - OSDP_LOG_DEBUG("osdp: cp: Unexpected REPLY(%02x)\n", pd->reply_id); - return OSDP_CP_ERR_GENERIC; - } - - if (ret == OSDP_CP_ERR_GENERIC) { - OSDP_LOG_ERROR("osdp: cp: Format error in REPLY(%02x) for CMD(%02x)", - pd->reply_id, pd->cmd_id); - return OSDP_CP_ERR_GENERIC; - } - - if (pd->cmd_id != CMD_POLL) { - OSDP_LOG_DEBUG("osdp: cp: CMD(%02x) REPLY(%02x)\n", pd->cmd_id, pd->reply_id); - } - - return ret; -} - -static int -cp_send_command(struct osdp_pd *pd) -{ - int ret, len; - - /* init packet buf with header */ - len = osdp_phy_packet_init(pd, pd->rx_buf, sizeof(pd->rx_buf)); - if (len < 0) { - return OSDP_CP_ERR_GENERIC; - } - - /* fill command data */ - ret = cp_build_command(pd, pd->rx_buf, sizeof(pd->rx_buf)); - if (ret < 0) { - return OSDP_CP_ERR_GENERIC; - } - len += ret; - - /* finalize packet */ - len = osdp_phy_packet_finalize(pd, pd->rx_buf, len, sizeof(pd->rx_buf)); - if (len < 0) { - return OSDP_CP_ERR_GENERIC; - } - - /* flush rx to remove any invalid data. */ - if (pd->channel.flush) { - pd->channel.flush(pd->channel.data); - } - - ret = pd->channel.send(pd->channel.data, pd->rx_buf, len); - if (ret != len) { - OSDP_LOG_ERROR("osdp: cp: Channel send for %d bytes failed! ret: %d\n", len, ret); - return OSDP_CP_ERR_GENERIC; - } - - if (MYNEWT_VAL(OSDP_PACKET_TRACE)) { - if (pd->cmd_id != CMD_POLL) { - osdp_dump(pd->rx_buf, len, - "OSDP: PD[%d]: Sent\n", pd->offset); - } - } - - return OSDP_CP_ERR_NONE; -} - -static int -cp_process_reply(struct osdp_pd *pd) -{ - uint8_t *buf; - int err, len, remaining; - - buf = pd->rx_buf + pd->rx_buf_len; - remaining = sizeof(pd->rx_buf) - pd->rx_buf_len; - - len = pd->channel.recv(pd->channel.data, buf, remaining); - if (len <= 0) { /* No data received */ - return OSDP_CP_ERR_NO_DATA; - } - pd->rx_buf_len += len; - - if (MYNEWT_VAL(OSDP_PACKET_TRACE)) { - if (pd->cmd_id != CMD_POLL) { - osdp_dump(pd->rx_buf, pd->rx_buf_len, - "OSDP: PD[%d]: Received\n", pd->offset); - } - } - - err = osdp_phy_check_packet(pd, pd->rx_buf, pd->rx_buf_len, &len); - if (err == OSDP_ERR_PKT_WAIT) { - /* rx_buf_len < pkt->len; wait for more data */ - return OSDP_CP_ERR_NO_DATA; - } - if (err == OSDP_ERR_PKT_NONE) { - /* Valid OSDP packet in buffer */ - len = osdp_phy_decode_packet(pd, pd->rx_buf, len, &buf); - if (len <= 0) { - return OSDP_CP_ERR_GENERIC; - } - err = cp_decode_response(pd, buf, len); - } - - /* We are done with the packet (error or not). Remove processed bytes */ - remaining = pd->rx_buf_len - len; - if (remaining) { - memmove(pd->rx_buf, pd->rx_buf + len, remaining); - pd->rx_buf_len = remaining; - } - - return err; -} - -static inline void -cp_set_state(struct osdp_pd *pd, enum osdp_state_e state) -{ - pd->state = state; - CLEAR_FLAG(pd, PD_FLAG_AWAIT_RESP); -} - -static inline void -cp_set_online(struct osdp_pd *pd) -{ - cp_set_state(pd, OSDP_CP_STATE_ONLINE); - pd->wait_ms = 0; -} - -static inline void -cp_set_offline(struct osdp_pd *pd) -{ - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - pd->state = OSDP_CP_STATE_OFFLINE; - pd->tstamp = osdp_millis_now(); - if (pd->wait_ms == 0) { - pd->wait_ms = 1000; /* retry after 1 second initially */ - } else { - pd->wait_ms <<= 1; - if (pd->wait_ms > OSDP_ONLINE_RETRY_WAIT_MAX_MS) { - pd->wait_ms = OSDP_ONLINE_RETRY_WAIT_MAX_MS; - } - } -} - -static int -cp_phy_state_update(struct osdp_pd *pd) -{ - int64_t elapsed; - int rc, ret = OSDP_CP_ERR_CAN_YIELD; - struct osdp_cmd *cmd = NULL; - - switch (pd->phy_state) { - case OSDP_CP_PHY_STATE_WAIT: - elapsed = osdp_millis_since(pd->phy_tstamp); - if (elapsed < OSDP_CMD_RETRY_WAIT_MS) { - break; - } - pd->phy_state = OSDP_CP_PHY_STATE_SEND_CMD; - break; - case OSDP_CP_PHY_STATE_ERR: - ret = OSDP_CP_ERR_GENERIC; - break; - case OSDP_CP_PHY_STATE_IDLE: - if (cp_cmd_get(pd, &cmd, &ret)) { - break; - } - /* fall-thru */ - case OSDP_CP_PHY_STATE_SEND_CMD: - if ((cp_send_command(pd)) < 0) { - OSDP_LOG_ERROR("osdp: cp: Failed to send CMD(%d)\n", pd->cmd_id); - pd->phy_state = OSDP_CP_PHY_STATE_ERR; - ret = OSDP_CP_ERR_GENERIC; - break; - } - ret = OSDP_CP_ERR_INPROG; - pd->phy_state = OSDP_CP_PHY_STATE_REPLY_WAIT; - pd->rx_buf_len = 0; /* reset buf_len for next use */ - pd->phy_tstamp = osdp_millis_now(); - break; - case OSDP_CP_PHY_STATE_REPLY_WAIT: - rc = cp_process_reply(pd); - if (rc == OSDP_CP_ERR_NONE) { - pd->phy_state = OSDP_CP_PHY_STATE_IDLE; - break; - } - if (rc == OSDP_CP_ERR_RETRY_CMD) { - OSDP_LOG_INFO("osdp: cp: PD busy; retry last command\n"); - pd->phy_tstamp = osdp_millis_now(); - pd->phy_state = OSDP_CP_PHY_STATE_WAIT; - break; - } - if (rc == OSDP_CP_ERR_GENERIC || - osdp_millis_since(pd->phy_tstamp) > MYNEWT_VAL(OSDP_RESP_TOUT_MS)) { - if (rc != OSDP_CP_ERR_GENERIC) { - OSDP_LOG_ERROR("osdp: cp: Response timeout for CMD(%02x)", - pd->cmd_id); - } - pd->rx_buf_len = 0; - if (pd->channel.flush) { - pd->channel.flush(pd->channel.data); - } - cp_flush_command_queue(pd); - pd->phy_state = OSDP_CP_PHY_STATE_ERR; - ret = OSDP_CP_ERR_GENERIC; - break; - } - ret = OSDP_CP_ERR_INPROG; - break; - } - - return ret; -} - -static int -cp_cmd_dispatcher(struct osdp_pd *pd, int cmd) -{ - int rc; - struct osdp *ctx = TO_CTX(pd); - struct osdp_cmd *c; - - if (ISSET_FLAG(pd, PD_FLAG_AWAIT_RESP)) { - CLEAR_FLAG(pd, PD_FLAG_AWAIT_RESP); - return OSDP_CP_ERR_NONE; /* nothing to be done here */ - } - rc = osdp_device_lock(&pd->lock); - if (rc) { - return rc; - } - - c = cp_cmd_alloc(pd); - if (c == NULL) { - rc = OS_ENOMEM; - goto err; - } - - c->id = cmd; - switch (cmd) { - case CMD_KEYSET: - c->keyset.length = 16; - memcpy(c->keyset.data, ctx->sc_master_key, 16); - break; - } - cp_cmd_enqueue(pd, c); - SET_FLAG(pd, PD_FLAG_AWAIT_RESP); - rc = OSDP_CP_ERR_INPROG; - -err: - osdp_device_unlock(&pd->lock); - return rc; -} - -static int -state_update(struct osdp_pd *pd) -{ - int phy_state, soft_fail; - struct osdp *ctx = TO_CTX(pd); - - phy_state = cp_phy_state_update(pd); - if (phy_state == OSDP_CP_ERR_INPROG || - phy_state == OSDP_CP_ERR_CAN_YIELD) { - return phy_state; - } - - /* Certain states can fail without causing PD offline */ - soft_fail = (pd->state == OSDP_CP_STATE_SC_CHLNG); - - /* phy state error -- cleanup */ - if (pd->state != OSDP_CP_STATE_OFFLINE && - phy_state == OSDP_CP_ERR_GENERIC && soft_fail == 0) { - cp_set_offline(pd); - return OSDP_CP_ERR_CAN_YIELD; - } - - /* command queue is empty and last command was successful */ - - switch (pd->state) { - case OSDP_CP_STATE_ONLINE: - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE) == false && - ISSET_FLAG(pd, PD_FLAG_SC_CAPABLE) == true && - ISSET_FLAG(ctx, FLAG_SC_DISABLED) == false && - osdp_millis_since(pd->sc_tstamp) > OSDP_PD_SC_RETRY_MS) { - OSDP_LOG_INFO("osdp: cp: Retry SC after retry timeout\n"); - cp_set_state(pd, OSDP_CP_STATE_SC_INIT); - break; - } - if (osdp_millis_since(pd->tstamp) < OSDP_PD_POLL_TIMEOUT_MS) { - break; - } - if (cp_cmd_dispatcher(pd, CMD_POLL) == 0) { - pd->tstamp = osdp_millis_now(); - } - break; - case OSDP_CP_STATE_OFFLINE: - if (osdp_millis_since(pd->tstamp) > pd->wait_ms) { - cp_set_state(pd, OSDP_CP_STATE_INIT); - osdp_phy_state_reset(pd); - } - break; - case OSDP_CP_STATE_INIT: - cp_set_state(pd, OSDP_CP_STATE_IDREQ); - __fallthrough; - case OSDP_CP_STATE_IDREQ: - if (cp_cmd_dispatcher(pd, CMD_ID) != 0) { - break; - } - if (pd->reply_id != REPLY_PDID) { - OSDP_LOG_ERROR("osdp: cp: Unexpected REPLY(%02x) for cmd " - STR(CMD_CAP), pd->reply_id); - cp_set_offline(pd); - break; - } - cp_set_state(pd, OSDP_CP_STATE_CAPDET); - __fallthrough; - case OSDP_CP_STATE_CAPDET: - if (cp_cmd_dispatcher(pd, CMD_CAP) != 0) { - break; - } - if (pd->reply_id != REPLY_PDCAP) { - OSDP_LOG_ERROR("osdp: cp: Unexpected REPLY(%02x) for cmd " - STR(CMD_CAP), pd->reply_id); - cp_set_offline(pd); - break; - } - if (ISSET_FLAG(pd, PD_FLAG_SC_CAPABLE) && - !ISSET_FLAG(ctx, FLAG_SC_DISABLED)) { - CLEAR_FLAG(pd, PD_FLAG_SC_SCBKD_DONE); - CLEAR_FLAG(pd, PD_FLAG_SC_USE_SCBKD); - cp_set_state(pd, OSDP_CP_STATE_SC_INIT); - break; - } - if (ISSET_FLAG(pd, OSDP_FLAG_ENFORCE_SECURE)) { - OSDP_LOG_INFO("osdp: cp: SC disabled or not capable. Set PD offline due " - "to ENFORCE_SECURE\n"); - cp_set_offline(pd); - } else { - cp_set_online(pd); - } - break; - case OSDP_CP_STATE_SC_INIT: - osdp_sc_init(pd); - cp_set_state(pd, OSDP_CP_STATE_SC_CHLNG); - __fallthrough; - case OSDP_CP_STATE_SC_CHLNG: - if (cp_cmd_dispatcher(pd, CMD_CHLNG) != 0) { - break; - } - if (phy_state < 0) { - if (ISSET_FLAG(pd, OSDP_FLAG_ENFORCE_SECURE)) { - OSDP_LOG_INFO("osdp: cp: SC Failed. Set PD offline due to " - "ENFORCE_SECURE\n"); - cp_set_offline(pd); - break; - } - if (ISSET_FLAG(pd, PD_FLAG_SC_SCBKD_DONE)) { - OSDP_LOG_INFO("osdp: cp: SC Failed. Online without SC\n"); - pd->sc_tstamp = osdp_millis_now(); - cp_set_online(pd); - break; - } - SET_FLAG(pd, PD_FLAG_SC_USE_SCBKD); - SET_FLAG(pd, PD_FLAG_SC_SCBKD_DONE); - cp_set_state(pd, OSDP_CP_STATE_SC_INIT); - pd->phy_state = 0; /* soft reset phy state */ - OSDP_LOG_WARN("osdp: cp: SC Failed. Retry with SCBK-D\n"); - break; - } - if (pd->reply_id != REPLY_CCRYPT) { - if (ISSET_FLAG(pd, OSDP_FLAG_ENFORCE_SECURE)) { - OSDP_LOG_ERROR("osdp: cp: CHLNG failed. Set PD offline due to " - "ENFORCE_SECURE\n"); - cp_set_offline(pd); - } else { - OSDP_LOG_ERROR("osdp: cp: CHLNG failed. Online without SC\n"); - pd->sc_tstamp = osdp_millis_now(); - osdp_phy_state_reset(pd); - cp_set_online(pd); - } - break; - } - cp_set_state(pd, OSDP_CP_STATE_SC_SCRYPT); - __fallthrough; - case OSDP_CP_STATE_SC_SCRYPT: - if (cp_cmd_dispatcher(pd, CMD_SCRYPT) != 0) { - break; - } - if (pd->reply_id != REPLY_RMAC_I) { - if (ISSET_FLAG(pd, OSDP_FLAG_ENFORCE_SECURE)) { - OSDP_LOG_ERROR("osdp: cp: SCRYPT failed. Set PD offline due to " - "ENFORCE_SECURE\n"); - cp_set_offline(pd); - } else { - OSDP_LOG_ERROR("osdp: cp: SCRYPT failed. Online without SC\n"); - osdp_phy_state_reset(pd); - pd->sc_tstamp = osdp_millis_now(); - cp_set_online(pd); - } - break; - } - if (ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD)) { - OSDP_LOG_WARN("osdp: cp: SC ACtive with SCBK-D. Set SCBK\n"); - cp_set_state(pd, OSDP_CP_STATE_SET_SCBK); - break; - } - OSDP_LOG_INFO("osdp: cp: SC Active\n"); - pd->sc_tstamp = osdp_millis_now(); - cp_set_online(pd); - break; - case OSDP_CP_STATE_SET_SCBK: - if (cp_cmd_dispatcher(pd, CMD_KEYSET) != 0) { - break; - } - if (pd->reply_id == REPLY_NAK) { - if (ISSET_FLAG(pd, OSDP_FLAG_ENFORCE_SECURE)) { - OSDP_LOG_ERROR("osdp: cp: Failed to set SCBK; " - "Set PD offline due to ENFORCE_SECURE\n"); - cp_set_offline(pd); - } else { - OSDP_LOG_WARN("osdp: cp: Failed to set SCBK; " - "Continue with SCBK-D\n"); - cp_set_state(pd, OSDP_CP_STATE_ONLINE); - } - break; - } - OSDP_LOG_INFO("osdp: cp: SCBK set; restarting SC to verify new SCBK\n"); - CLEAR_FLAG(pd, PD_FLAG_SC_USE_SCBKD); - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - cp_set_state(pd, OSDP_CP_STATE_SC_INIT); - pd->seq_number = -1; - break; - default: - break; - } - - return OSDP_CP_ERR_CAN_YIELD; -} - -static int -osdp_cp_send_command_keyset(osdp_t *ctx, struct osdp_cmd_keyset *p) -{ - int i, rc; - struct osdp_pd *pd; - - if (osdp_get_sc_status_mask(ctx) != PD_MASK(ctx)) { - OSDP_LOG_WARN("osdp: cp: CMD_KEYSET can be sent only when all PDs are " - "ONLINE and SC_ACTIVE.\n"); - return 1; - } - - for (i = 0; i < NUM_PD(ctx); i++) { - pd = TO_PD(ctx, i); - struct osdp_cmd *cmd; - cmd = CONTAINER_OF(p, struct osdp_cmd, keyset); - rc = cp_cmd_put(pd, cmd, CMD_KEYSET); - if (rc) { - return rc; - } - } - - return 0; -} - -osdp_t * -osdp_cp_setup(struct osdp_ctx *osdp_ctx, int num_pd, osdp_pd_info_t *info, - uint8_t *master_key) -{ - uint16_t i; - int owner; - struct osdp_pd *pd; - struct osdp_cp *cp; - struct osdp *ctx; - - assert(info); - assert(num_pd > 0); - - ctx = &osdp_ctx->ctx; - ctx->magic = 0xDEADBEAF; - SET_FLAG(ctx, FLAG_CP_MODE); - - if (master_key != NULL) { - memcpy(ctx->sc_master_key, master_key, 16); - } else { - OSDP_LOG_WARN("osdp: cp: Master key not available! SC Disabled.\n"); - SET_FLAG(ctx, FLAG_SC_DISABLED); - } - - ctx->cp = &osdp_ctx->cp_ctx; - cp = TO_CP(ctx); - cp->__parent = ctx; - cp->channel_lock = &osdp_ctx->ch_locks_ctx[0]; - - ctx->pd = &osdp_ctx->pd_ctx[0]; - cp->num_pd = num_pd; - - for (i = 0; i < num_pd; i++) { - osdp_pd_info_t *p = info + i; - pd = TO_PD(ctx, i); - pd->offset = i; - pd->__parent = ctx; - pd->baud_rate = p->baud_rate; - pd->address = p->address; - pd->flags = p->flags; - pd->seq_number = -1; - if (cp_cmd_queue_init(pd, i)) { - goto error; - } - memcpy(&pd->channel, &p->channel, sizeof(struct osdp_channel)); - if (cp_channel_acquire(pd, &owner) == -1) { - SET_FLAG(TO_PD(ctx, owner), PD_FLAG_CHN_SHARED); - SET_FLAG(pd, PD_FLAG_CHN_SHARED); - } - if (IS_ENABLED(CONFIG_OSDP_SKIP_MARK_BYTE)) { - SET_FLAG(pd, PD_FLAG_PKT_SKIP_MARK); - } - osdp_cp_set_event_callback(ctx, p->cp_cb, NULL); - } - memset(cp->channel_lock, 0, sizeof(int) * num_pd); - SET_CURRENT_PD(ctx, 0); - OSDP_LOG_INFO("osdp: cp: CP setup complete\n"); - return (osdp_t *) ctx; - -error: - osdp_cp_teardown((osdp_t *)ctx); - return NULL; -} - -void -osdp_cp_teardown(osdp_t *ctx) -{ - int i; - - if (ctx == NULL || TO_CP(ctx) == NULL) { - return; - } - - for (i = 0; i < NUM_PD(ctx); i++) { - cp_cmd_queue_del(TO_PD(ctx, i)); - } -} - -void -osdp_refresh(osdp_t *ctx) -{ - int i, rc; - struct osdp_pd *pd; - - assert(ctx); - - for (i = 0; i < NUM_PD(ctx); i++) { - SET_CURRENT_PD(ctx, i); - /* - osdp_log_ctx_set(i); - */ - pd = TO_PD(ctx, i); - - if (ISSET_FLAG(pd, PD_FLAG_CHN_SHARED) && - cp_channel_acquire(pd, NULL)) { - /* failed to lock shared channel */ - continue; - } - - rc = state_update(pd); - - if (ISSET_FLAG(pd, PD_FLAG_CHN_SHARED) && - rc == OSDP_CP_ERR_CAN_YIELD) { - cp_channel_release(pd); - } - } -} - -/* --- Exported Methods --- */ - -void -osdp_cp_set_event_callback(osdp_t *ctx, cp_event_callback_t cb, void *arg) -{ - assert(ctx); - - TO_CP(ctx)->event_callback = cb; - TO_CP(ctx)->event_callback_arg = arg; -} - -int -osdp_cp_send_command(osdp_t *ctx, int pd, struct osdp_cmd *p) -{ - assert(ctx); - int cmd_id; - - if (pd < 0 || pd >= NUM_PD(ctx)) { - OSDP_LOG_ERROR("osdp: cp: Invalid PD number\n"); - return -1; - } - if (TO_PD(ctx, pd)->state != OSDP_CP_STATE_ONLINE) { - OSDP_LOG_WARN("osdp: cp: PD not online\n"); - return -1; - } - - switch (p->id) { - case OSDP_CMD_OUTPUT: - cmd_id = CMD_OUT; - break; - case OSDP_CMD_LED: - cmd_id = CMD_LED; - break; - case OSDP_CMD_BUZZER: - cmd_id = CMD_BUZ; - break; - case OSDP_CMD_TEXT: - cmd_id = CMD_TEXT; - break; - case OSDP_CMD_COMSET: - cmd_id = CMD_COMSET; - break; - case OSDP_CMD_MFG: - cmd_id = CMD_MFG; - break; - case OSDP_CMD_KEYSET: - OSDP_LOG_INFO("osdp: cp: Master KEYSET is a global command; " - "all connected PDs will be affected.\n"); - return osdp_cp_send_command_keyset(ctx, &p->keyset); - default: - OSDP_LOG_ERROR("osdp: cp: Invalid CMD_ID:%d\n", p->id); - return -1; - } - - return cp_cmd_put(TO_PD(ctx, pd), p, cmd_id); -} - -#endif /* OSDP_MODE_CP */ diff --git a/net/osdp/src/osdp.c b/net/osdp/src/osdp_mynewt.c similarity index 80% rename from net/osdp/src/osdp.c rename to net/osdp/src/osdp_mynewt.c index b6293fe7a0..de4dd3d322 100644 --- a/net/osdp/src/osdp.c +++ b/net/osdp/src/osdp_mynewt.c @@ -1,14 +1,26 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 * - * SPDX-License-Identifier: Apache-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 "modlog/modlog.h" #include "uart/uart.h" -#include "tinycrypt/aes.h" -#include "osdp/osdp_common.h" +#include "osdp.h" /* Interval in ticks */ #define OSDP_REFRESH_INTERVAL \ @@ -29,7 +41,7 @@ struct osdp_device { struct uart_dev *uart; }; -static struct osdp_ctx osdp_ctx; +static struct osdp_t *ctx; static struct osdp_device osdp_device; static struct os_callout osdp_refresh_timer; @@ -170,23 +182,17 @@ osdp_uart_flush(void *data) od->rx_ring.tail = 0; } -/* - * Get context handle - */ -struct osdp * -osdp_get_ctx() -{ - return &osdp_ctx.ctx; -} - /* * Timer handler */ -void +static void osdp_refresh_handler(struct os_event *ev) { - struct osdp *ctx = osdp_get_ctx(); - osdp_refresh(ctx); +#if MYNEWT_VAL(OSDP_MODE_PD) + osdp_pd_refresh(ctx); +#else + osdp_cp_refresh(ctx); +#endif /* Restart */ os_callout_reset(&osdp_refresh_timer, OSDP_REFRESH_INTERVAL); @@ -199,12 +205,8 @@ void osdp_stop(void) { int rc; - struct osdp *ctx; struct osdp_device *od = &osdp_device; - ctx = osdp_get_ctx(); - assert(ctx); - /* Stop timer */ os_callout_stop(&osdp_refresh_timer); @@ -215,6 +217,9 @@ osdp_stop(void) osdp_cp_teardown(ctx); #endif + /* clear OSDP context */ + ctx = NULL; + /* Stop uart */ assert(od->uart); rc = os_dev_close((struct os_dev *)od->uart); @@ -222,18 +227,14 @@ osdp_stop(void) /* Flush circular buffers */ osdp_uart_flush((void *)od); - - /* Reset OSDP context */ - memset(&osdp_ctx, 0, sizeof(struct osdp_ctx)); } /* * Start OSDP. Called by application */ -void -osdp_init(osdp_pd_info_t *info, uint8_t *scbk) +struct osdp_t * +osdp_init(osdp_pd_info_t *info) { - struct osdp *ctx; struct osdp_device *od = &osdp_device; /* Assign remaining function handlers not managed by the application layer */ @@ -264,18 +265,20 @@ osdp_init(osdp_pd_info_t *info, uint8_t *scbk) /* Setup OSDP */ #if MYNEWT_VAL(OSDP_MODE_PD) - ctx = osdp_pd_setup(&osdp_ctx, info, scbk); + ctx = osdp_pd_setup(info); assert(ctx != NULL); #else - ctx = osdp_cp_setup(&osdp_ctx, MYNEWT_VAL(OSDP_NUM_CONNECTED_PD), info, scbk); + ctx = osdp_cp_setup(MYNEWT_VAL(OSDP_NUM_CONNECTED_PD), info); assert(ctx != NULL); #endif /* Configure and reset timer */ os_callout_init(&osdp_refresh_timer, os_eventq_dflt_get(), - osdp_refresh_handler, NULL); + osdp_refresh_handler, NULL); os_callout_reset(&osdp_refresh_timer, OSDP_REFRESH_INTERVAL); OSDP_LOG_INFO("osdp: init OK\n"); + + return ctx; } diff --git a/net/osdp/include/osdp/osdp_hooks.h b/net/osdp/src/osdp_mynewt_utils.c similarity index 67% rename from net/osdp/include/osdp/osdp_hooks.h rename to net/osdp/src/osdp_mynewt_utils.c index d9192adeee..18957f68b0 100644 --- a/net/osdp/include/osdp/osdp_hooks.h +++ b/net/osdp/src/osdp_mynewt_utils.c @@ -1,4 +1,4 @@ -/** +/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -17,15 +17,10 @@ * under the License. */ -#include -#include +#include "os/os_time.h" -/** - * @brief Hook function to supply random bytes. - * - * @param out Output buffer for random data. - * @param out_len Output buffer length. - * - * @return number of bytes read, could be less than requested based on implementation. - */ -__attribute__((weak)) size_t osdp_hook_crypto_random_bytes(uint8_t *out, size_t out_len); +int64_t +osdp_millis_now(void) +{ + return (os_get_uptime_usec() / 1000); +} diff --git a/net/osdp/src/osdp_pd.c b/net/osdp/src/osdp_pd.c deleted file mode 100644 index 0eab223395..0000000000 --- a/net/osdp/src/osdp_pd.c +++ /dev/null @@ -1,1221 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "modlog/modlog.h" - -#include -#include - -#include "osdp/osdp_common.h" - -#if MYNEWT_VAL(OSDP_MODE_PD) /* compile flag based on mode */ - -#define TAG "PD: " - -#define CMD_POLL_DATA_LEN 0 -#define CMD_LSTAT_DATA_LEN 0 -#define CMD_ISTAT_DATA_LEN 0 -#define CMD_OSTAT_DATA_LEN 0 -#define CMD_RSTAT_DATA_LEN 0 -#define CMD_ID_DATA_LEN 1 -#define CMD_CAP_DATA_LEN 1 -#define CMD_OUT_DATA_LEN 4 -#define CMD_LED_DATA_LEN 14 -#define CMD_BUZ_DATA_LEN 5 -#define CMD_TEXT_DATA_LEN 6 /* variable length command */ -#define CMD_COMSET_DATA_LEN 5 -#define CMD_MFG_DATA_LEN 4 /* variable length command */ -#define CMD_KEYSET_DATA_LEN 18 -#define CMD_CHLNG_DATA_LEN 8 -#define CMD_SCRYPT_DATA_LEN 16 - -#define REPLY_ACK_LEN 1 -#define REPLY_PDID_LEN 13 -#define REPLY_PDCAP_LEN 1 /* variable length command */ -#define REPLY_PDCAP_ENTITY_LEN 3 -#define REPLY_LSTATR_LEN 3 -#define REPLY_RSTATR_LEN 2 -#define REPLY_KEYPAD_LEN 2 -#define REPLY_RAW_LEN 4 -#define REPLY_FMT_LEN 3 -#define REPLY_COM_LEN 6 -#define REPLY_NAK_LEN 2 -#define REPLY_MFGREP_LEN 4 /* variable length command */ -#define REPLY_CCRYPT_LEN 33 -#define REPLY_RMAC_I_LEN 17 - -#define OSDP_PD_ERR_NONE 0 -#define OSDP_PD_ERR_NO_DATA 1 -#define OSDP_PD_ERR_GENERIC -1 -#define OSDP_PD_ERR_REPLY -2 -#define OSDP_PD_ERR_EMPTY_Q -3 -#define OSDP_PD_ERR_IGNORE -4 - -/* Implicit cababilities */ -static struct osdp_pd_cap osdp_pd_cap[] = { - /* Driver Implicit cababilities */ - { - OSDP_PD_CAP_CHECK_CHARACTER_SUPPORT, - 1, /* The PD supports the 16-bit CRC-16 mode */ - 0, /* N/A */ - }, - { -1, 0, 0 } /* Sentinel */ -}; - -static int -pd_event_queue_init(struct osdp_pd *pd) -{ - int rc; - rc = os_mempool_init(&pd->event.pool, - MYNEWT_VAL(OSDP_PD_COMMAND_QUEUE_SIZE), - sizeof(struct pd_event_node), - pd->event.pool_buf, "pd_event_pool"); - - if (rc != OS_OK) { - OSDP_LOG_ERROR("osdp: pd: Failed to initialize command pool\n"); - return rc; - } - - pd->event.queue.tqh_first = NULL; - pd->event.queue.tqh_last = &pd->event.queue.tqh_first; - - os_mutex_init(&pd->lock); - - return rc; -} - -static struct osdp_event * -pd_event_alloc(struct osdp_pd *pd) -{ - struct pd_event_node *event = NULL; - - event = os_memblock_get(&pd->event.pool); - - if (event == NULL) { - OSDP_LOG_ERROR("osdp: pd: Event pool allocation failed\n"); - return NULL; - } - - return &event->object; -} - -static void -pd_event_free(struct osdp_pd *pd, struct osdp_event *event) -{ - struct pd_event_node *node; - - node = CONTAINER_OF(event, struct pd_event_node, object); - os_memblock_put(&pd->event.pool, node); -} - -static void -pd_event_enqueue(struct osdp_pd *pd, struct osdp_event *event) -{ - struct pd_event_node *node; - - node = CONTAINER_OF(event, struct pd_event_node, object); - TAILQ_INSERT_HEAD(&pd->event.queue, node, pd_node); -} - -static int -pd_event_dequeue(struct osdp_pd *pd, struct osdp_event **event) -{ - struct pd_event_node *node; - - node = TAILQ_LAST(&pd->event.queue, queue); - if (node == NULL) { - return OSDP_PD_ERR_EMPTY_Q; - } - TAILQ_REMOVE(&pd->event.queue, node, pd_node); - - *event = &node->object; - return 0; -} - -static void -pd_event_queue_del(struct osdp_pd *pd) -{ - /* Empty the queue and put back blocks */ - struct osdp_event *event; - while (pd_event_dequeue(pd, &event) == 0) { - pd_event_free(pd, event); - } - - os_mempool_clear(&pd->event.pool); - os_mempool_unregister(&pd->event.pool); -} - -static int -pd_translate_event(struct osdp_event *event, uint8_t *data) -{ - int reply_code = 0; - - switch (event->type) { - case OSDP_EVENT_CARDREAD: - if (event->cardread.format == OSDP_CARD_FMT_RAW_UNSPECIFIED || - event->cardread.format == OSDP_CARD_FMT_RAW_WIEGAND) { - reply_code = REPLY_RAW; - } else if (event->cardread.format == OSDP_CARD_FMT_ASCII) { - reply_code = REPLY_FMT; - } else { - OSDP_LOG_ERROR("osdp: pd: Event: cardread; Error: unknown format\n"); - break; - } - break; - case OSDP_EVENT_KEYPRESS: - reply_code = REPLY_KEYPPAD; - break; - default: - OSDP_LOG_ERROR("osdp: pd: Unknown event type %d\n", event->type); - break; - } - if (reply_code == 0) { - /* POLL command cannot fail even when there are errors here */ - return REPLY_ACK; - } - memcpy(data, event, sizeof(struct osdp_event)); - return reply_code; -} - -static int -pd_event_get(struct osdp_pd *pd, struct osdp_event **event, int *ret) -{ - int rc = 0; - - rc = osdp_device_lock(&pd->lock); - if (rc) { - return rc; - } - - rc = pd_event_dequeue(pd, event); - if (rc) { - goto err; - } - - *ret = pd_translate_event(*event, pd->ephemeral_data); - pd_event_free(pd, *event); - -err: - osdp_device_unlock(&pd->lock); - return rc; -} - -static int -pd_event_put(struct osdp_pd *pd, struct osdp_event *event) -{ - int rc = 0; - struct osdp_event *ev; - - rc = osdp_device_lock(&pd->lock); - if (rc) { - return rc; - } - - ev = pd_event_alloc(pd); - if (ev == NULL) { - rc = OS_ENOMEM; - goto err; - } - - memcpy(ev, event, sizeof(struct osdp_event)); - pd_event_enqueue(pd, ev); - -err: - osdp_device_unlock(&pd->lock); - return rc; -} - -static int -pd_cmd_cap_ok(struct osdp_pd *pd, struct osdp_cmd *cmd) -{ - struct osdp_pd_cap *cap = NULL; - - /* Validate the cmd_id against a PD capabilities where applicable */ - switch (pd->cmd_id) { - case CMD_ISTAT: - cap = &pd->cap[OSDP_PD_CAP_CONTACT_STATUS_MONITORING]; - if (cap->num_items == 0 || cap->compliance_level == 0) { - break; - } - return 0; /* Remove this when REPLY_ISTATR is supported */ - case CMD_OSTAT: - cap = &pd->cap[OSDP_PD_CAP_OUTPUT_CONTROL]; - if (cap->num_items == 0 || cap->compliance_level == 0) { - break; - } - return 0; /* Remove this when REPLY_OSTATR is supported */ - case CMD_OUT: - cap = &pd->cap[OSDP_PD_CAP_OUTPUT_CONTROL]; - if (cmd->output.output_no + 1 > cap->num_items) { - OSDP_LOG_DEBUG("osdp: pd: CAP check: output_no(%d) > cap->num_items(%d)\n", - cmd->output.output_no + 1, cap->num_items); - break; - } - if (cap->compliance_level == 0) { - break; - } - return 1; - case CMD_LED: - cap = &pd->cap[OSDP_PD_CAP_READER_LED_CONTROL]; - if (cmd->led.led_number + 1 > cap->num_items) { - OSDP_LOG_DEBUG("osdp: pd: CAP check: LED(%d) > cap->num_items(%d)\n", - cmd->led.led_number + 1, cap->num_items); - break; - } - if (cap->compliance_level == 0) { - break; - } - return 1; - case CMD_BUZ: - cap = &pd->cap[OSDP_PD_CAP_READER_AUDIBLE_OUTPUT]; - if (cap->num_items == 0 || cap->compliance_level == 0) { - break; - } - return 1; - case CMD_TEXT: - cap = &pd->cap[OSDP_PD_CAP_READER_TEXT_OUTPUT]; - if (cap->num_items == 0 || cap->compliance_level == 0) { - break; - } - return 1; - case CMD_CHLNG: - case CMD_SCRYPT: - case CMD_KEYSET: - cap = &pd->cap[OSDP_PD_CAP_COMMUNICATION_SECURITY]; - if (cap->compliance_level == 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SC_UNSUP; - return 0; - } - return 1; - } - - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_CMD_UNKNOWN; - return 0; -} - -static int -pd_decode_command(struct osdp_pd *pd, uint8_t *buf, int len) -{ - int i, ret = OSDP_PD_ERR_GENERIC, pos = 0; - struct osdp_cmd cmd; - struct osdp_event *event; - - pd->reply_id = 0; - pd->cmd_id = cmd.id = buf[pos++]; - len--; - - if (ISSET_FLAG(pd, OSDP_FLAG_ENFORCE_SECURE) && - !ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - /** - * Only CMD_ID, CMD_CAP and SC handshake commands (CMD_CHLNG - * and CMD_SCRYPT) are allowed when SC is inactive and - * ENFORCE_SECURE was requested. - */ - if (pd->cmd_id != CMD_ID && pd->cmd_id != CMD_CAP && - pd->cmd_id != CMD_CHLNG && pd->cmd_id != CMD_SCRYPT) { - OSDP_LOG_ERROR("osdp: pd: CMD(%02x) not allowed due to ENFORCE_SECURE\n", - pd->cmd_id); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - return OSDP_PD_ERR_REPLY; - } - } - - /* helper macro, can be called from switch cases below */ -#define PD_CMD_CAP_CHECK(pd, cmd) \ - if (!pd_cmd_cap_ok(pd, cmd)) { \ - OSDP_LOG_INFO("osdp: pd: PD is not capable of handling CMD(%02x); " \ - "Reply with NAK_CMD_UNKNOWN\n", pd->cmd_id); \ - ret = OSDP_PD_ERR_REPLY; \ - break; \ - } - -#define ASSERT_LENGTH(got, exp) \ - if (got != exp) { \ - OSDP_LOG_ERROR("osdp: pd: CMD(%02x) length error! Got:%d, Exp:%d\n", \ - pd->cmd_id, got, exp); \ - return OSDP_PD_ERR_GENERIC; \ - } - - switch (pd->cmd_id) { - case CMD_POLL: - ASSERT_LENGTH(len, CMD_POLL_DATA_LEN); - /* Check if we have external events in the queue */ - if (pd_event_get(pd, &event, &ret) == 0) { - pd->reply_id = ret; - } else { - pd->reply_id = REPLY_ACK; - } - ret = OSDP_PD_ERR_NONE; - SET_FLAG(pd, PD_FLAG_CP_POLL_ACTIVE); - break; - case CMD_LSTAT: - ASSERT_LENGTH(len, CMD_LSTAT_DATA_LEN); - pd->reply_id = REPLY_LSTATR; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_ISTAT: - ASSERT_LENGTH(len, CMD_ISTAT_DATA_LEN); - PD_CMD_CAP_CHECK(pd, NULL); - pd->reply_id = REPLY_ISTATR; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_OSTAT: - ASSERT_LENGTH(len, CMD_OSTAT_DATA_LEN); - PD_CMD_CAP_CHECK(pd, NULL); - pd->reply_id = REPLY_OSTATR; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_RSTAT: - ASSERT_LENGTH(len, CMD_RSTAT_DATA_LEN); - pd->reply_id = REPLY_RSTATR; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_ID: - ASSERT_LENGTH(len, CMD_ID_DATA_LEN); - pos++; /* Skip reply type info. */ - pd->reply_id = REPLY_PDID; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_CAP: - ASSERT_LENGTH(len, CMD_CAP_DATA_LEN); - pos++; /* Skip reply type info. */ - pd->reply_id = REPLY_PDCAP; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_OUT: - ASSERT_LENGTH(len, CMD_OUT_DATA_LEN); - if (!pd->command_callback) { - break; - } - cmd.id = OSDP_CMD_OUTPUT; - cmd.output.output_no = buf[pos++]; - cmd.output.control_code = buf[pos++]; - cmd.output.timer_count = buf[pos++]; - cmd.output.timer_count |= buf[pos++] << 8; - PD_CMD_CAP_CHECK(pd, &cmd); - ret = pd->command_callback(pd->command_callback_arg, &cmd); - if (ret != 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - ret = OSDP_PD_ERR_REPLY; - break; - } - pd->reply_id = REPLY_ACK; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_LED: - ASSERT_LENGTH(len, CMD_LED_DATA_LEN); - if (!pd->command_callback) { - break; - } - cmd.id = OSDP_CMD_LED; - cmd.led.reader = buf[pos++]; - cmd.led.led_number = buf[pos++]; - - cmd.led.temporary.control_code = buf[pos++]; - cmd.led.temporary.on_count = buf[pos++]; - cmd.led.temporary.off_count = buf[pos++]; - cmd.led.temporary.on_color = buf[pos++]; - cmd.led.temporary.off_color = buf[pos++]; - cmd.led.temporary.timer_count = buf[pos++]; - cmd.led.temporary.timer_count |= buf[pos++] << 8; - - cmd.led.permanent.control_code = buf[pos++]; - cmd.led.permanent.on_count = buf[pos++]; - cmd.led.permanent.off_count = buf[pos++]; - cmd.led.permanent.on_color = buf[pos++]; - cmd.led.permanent.off_color = buf[pos++]; - PD_CMD_CAP_CHECK(pd, &cmd); - ret = pd->command_callback(pd->command_callback_arg, &cmd); - if (ret != 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - ret = OSDP_PD_ERR_REPLY; - break; - } - pd->reply_id = REPLY_ACK; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_BUZ: - ASSERT_LENGTH(len, CMD_BUZ_DATA_LEN); - if (!pd->command_callback) { - break; - } - cmd.id = OSDP_CMD_BUZZER; - cmd.buzzer.reader = buf[pos++]; - cmd.buzzer.control_code = buf[pos++]; - cmd.buzzer.on_count = buf[pos++]; - cmd.buzzer.off_count = buf[pos++]; - cmd.buzzer.rep_count = buf[pos++]; - PD_CMD_CAP_CHECK(pd, &cmd); - ret = pd->command_callback(pd->command_callback_arg, &cmd); - if (ret != 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - ret = OSDP_PD_ERR_REPLY; - break; - } - pd->reply_id = REPLY_ACK; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_TEXT: - if (len < CMD_TEXT_DATA_LEN || !pd->command_callback) { - break; - } - cmd.id = OSDP_CMD_TEXT; - cmd.text.reader = buf[pos++]; - cmd.text.control_code = buf[pos++]; - cmd.text.temp_time = buf[pos++]; - cmd.text.offset_row = buf[pos++]; - cmd.text.offset_col = buf[pos++]; - cmd.text.length = buf[pos++]; - if (cmd.text.length > OSDP_CMD_TEXT_MAX_LEN || - ((len - CMD_TEXT_DATA_LEN) < cmd.text.length) || - cmd.text.length > OSDP_CMD_TEXT_MAX_LEN) { - break; - } - for (i = 0; i < cmd.text.length; i++) { - cmd.text.data[i] = buf[pos++]; - } - PD_CMD_CAP_CHECK(pd, &cmd); - ret = pd->command_callback(pd->command_callback_arg, &cmd); - if (ret != 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - ret = OSDP_PD_ERR_REPLY; - break; - } - pd->reply_id = REPLY_ACK; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_COMSET: - ASSERT_LENGTH(len, CMD_COMSET_DATA_LEN); - if (!pd->command_callback) { - break; - } - cmd.id = OSDP_CMD_COMSET; - cmd.comset.address = buf[pos++]; - cmd.comset.baud_rate = buf[pos++]; - cmd.comset.baud_rate |= buf[pos++] << 8; - cmd.comset.baud_rate |= buf[pos++] << 16; - cmd.comset.baud_rate |= buf[pos++] << 24; - if (cmd.comset.address >= 0x7F || - (cmd.comset.baud_rate != 9600 && - cmd.comset.baud_rate != 14400 && - cmd.comset.baud_rate != 19200 && - cmd.comset.baud_rate != 38400 && - cmd.comset.baud_rate != 57600 && - cmd.comset.baud_rate != 115200)) { - OSDP_LOG_ERROR("osdp: pd: COMSET Failed! command discarded\n"); - cmd.comset.address = pd->address; - cmd.comset.baud_rate = pd->baud_rate; - } - ret = pd->command_callback(pd->command_callback_arg, &cmd); - if (ret != 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - ret = OSDP_PD_ERR_REPLY; - break; - } - memcpy(pd->ephemeral_data, &cmd, sizeof(struct osdp_cmd)); - pd->reply_id = REPLY_COM; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_MFG: - if (len < CMD_MFG_DATA_LEN || !pd->command_callback) { - break; - } - cmd.id = OSDP_CMD_MFG; - cmd.mfg.vendor_code = buf[pos++]; /* vendor_code */ - cmd.mfg.vendor_code |= buf[pos++] << 8; - cmd.mfg.vendor_code |= buf[pos++] << 16; - cmd.mfg.command = buf[pos++]; - cmd.mfg.length = len - CMD_MFG_DATA_LEN; - if (cmd.mfg.length > OSDP_CMD_MFG_MAX_DATALEN) { - OSDP_LOG_ERROR("osdp: pd: cmd length error\n"); - break; - } - for (i = 0; i < cmd.mfg.length; i++) { - cmd.mfg.data[i] = buf[pos++]; - } - ret = pd->command_callback(pd->command_callback_arg, &cmd); - if (ret < 0) { /* Errors */ - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - ret = OSDP_PD_ERR_REPLY; - break; - } - if (ret > 0) { /* App wants to send a REPLY_MFGREP to the CP */ - memcpy(pd->ephemeral_data, &cmd, sizeof(struct osdp_cmd)); - pd->reply_id = REPLY_MFGREP; - } else { - pd->reply_id = REPLY_ACK; - } - ret = OSDP_PD_ERR_NONE; - break; - case CMD_KEYSET: - PD_CMD_CAP_CHECK(pd, &cmd); - ASSERT_LENGTH(len, CMD_KEYSET_DATA_LEN); - /** - * For CMD_KEYSET to be accepted, PD must be - * ONLINE and SC_ACTIVE. - */ - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE) == 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; - OSDP_LOG_ERROR("osdp: pd: Keyset with SC inactive\n"); - break; - } - /* only key_type == 1 (SCBK) and key_len == 16 is supported */ - if (buf[pos] != 1 || buf[pos + 1] != 16) { - OSDP_LOG_ERROR("osdp: pd: Keyset invalid len/type: %d/%d\n", - buf[pos], buf[pos + 1]); - break; - } - cmd.id = OSDP_CMD_KEYSET; - cmd.keyset.type = buf[pos++]; - cmd.keyset.length = buf[pos++]; - memcpy(cmd.keyset.data, buf + pos, 16); - memcpy(pd->sc.scbk, buf + pos, 16); - ret = OSDP_PD_ERR_NONE; - if (pd->command_callback) { - ret = pd->command_callback(pd->command_callback_arg, - &cmd); - } else { - OSDP_LOG_WARN("osdp: pd: Keyset without command callback trigger\n"); - } - if (ret != 0) { - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_RECORD; - ret = OSDP_PD_ERR_REPLY; - break; - } - CLEAR_FLAG(pd, PD_FLAG_SC_USE_SCBKD); - CLEAR_FLAG(pd, OSDP_FLAG_INSTALL_MODE); - pd->reply_id = REPLY_ACK; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_CHLNG: - PD_CMD_CAP_CHECK(pd, &cmd); - ASSERT_LENGTH(len, CMD_CHLNG_DATA_LEN); - osdp_sc_init(pd); - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - for (i = 0; i < CMD_CHLNG_DATA_LEN; i++) { - pd->sc.cp_random[i] = buf[pos++]; - } - pd->reply_id = REPLY_CCRYPT; - ret = OSDP_PD_ERR_NONE; - break; - case CMD_SCRYPT: - PD_CMD_CAP_CHECK(pd, &cmd); - ASSERT_LENGTH(len, CMD_SCRYPT_DATA_LEN); - for (i = 0; i < CMD_SCRYPT_DATA_LEN; i++) { - pd->sc.cp_cryptogram[i] = buf[pos++]; - } - pd->reply_id = REPLY_RMAC_I; - ret = OSDP_PD_ERR_NONE; - break; - default: - OSDP_LOG_ERROR("osdp: pd: Unknown command ID %02x\n", pd->cmd_id); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_CMD_UNKNOWN; - ret = OSDP_PD_ERR_NONE; - break; - } - - if (ret != 0 && ret != OSDP_PD_ERR_REPLY) { - OSDP_LOG_ERROR("osdp: pd: Invalid command structure. CMD: %02x, Len: %d ret: %d\n", - pd->cmd_id, len, ret); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_CMD_LEN; - return OSDP_PD_ERR_REPLY; - } - - if (pd->cmd_id != CMD_POLL) { - OSDP_LOG_DEBUG("osdp: pd: CMD: %02x REPLY: %02x\n", pd->cmd_id, pd->reply_id); - } - - return ret; -} - -/** - * Returns: - * +ve: length of command - * -ve: error - */ -static int -pd_build_reply(struct osdp_pd *pd, uint8_t *buf, int max_len) -{ - int i, data_off, len = 0, ret = -1; - uint8_t t1, *smb; - struct osdp_event *event; - struct osdp_cmd *cmd; - - data_off = osdp_phy_packet_get_data_offset(pd, buf); - smb = osdp_phy_packet_get_smb(pd, buf); - buf += data_off; - max_len -= data_off; - -#define ASSERT_BUF_LEN(need) \ - if (max_len < need) { \ - OSDP_LOG_ERROR("osdp: pd: OOM at build REPLY(%02x) - have:%d, need:%d\n", \ - pd->reply_id, max_len, need); \ - return OSDP_PD_ERR_GENERIC; \ - } - - switch (pd->reply_id) { - case REPLY_ACK: - ASSERT_BUF_LEN(REPLY_ACK_LEN); - buf[len++] = pd->reply_id; - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_PDID: - ASSERT_BUF_LEN(REPLY_PDID_LEN); - buf[len++] = pd->reply_id; - - buf[len++] = BYTE_0(pd->id.vendor_code); - buf[len++] = BYTE_1(pd->id.vendor_code); - buf[len++] = BYTE_2(pd->id.vendor_code); - - buf[len++] = pd->id.model; - buf[len++] = pd->id.version; - - buf[len++] = BYTE_0(pd->id.serial_number); - buf[len++] = BYTE_1(pd->id.serial_number); - buf[len++] = BYTE_2(pd->id.serial_number); - buf[len++] = BYTE_3(pd->id.serial_number); - - buf[len++] = BYTE_3(pd->id.firmware_version); - buf[len++] = BYTE_2(pd->id.firmware_version); - buf[len++] = BYTE_1(pd->id.firmware_version); - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_PDCAP: - ASSERT_BUF_LEN(REPLY_PDCAP_LEN); - buf[len++] = pd->reply_id; - for (i = 1; i < OSDP_PD_CAP_SENTINEL; i++) { - if (pd->cap[i].function_code != i) { - continue; - } - if (max_len < REPLY_PDCAP_ENTITY_LEN) { - OSDP_LOG_ERROR("osdp: pd: Out of buffer space!\n"); - break; - } - buf[len++] = i; - buf[len++] = pd->cap[i].compliance_level; - buf[len++] = pd->cap[i].num_items; - max_len -= REPLY_PDCAP_ENTITY_LEN; - } - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_LSTATR: - ASSERT_BUF_LEN(REPLY_LSTATR_LEN); - buf[len++] = pd->reply_id; - buf[len++] = ISSET_FLAG(pd, PD_FLAG_TAMPER); - buf[len++] = ISSET_FLAG(pd, PD_FLAG_POWER); - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_RSTATR: - ASSERT_BUF_LEN(REPLY_RSTATR_LEN); - buf[len++] = pd->reply_id; - buf[len++] = ISSET_FLAG(pd, PD_FLAG_R_TAMPER); - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_KEYPPAD: - event = (struct osdp_event *)pd->ephemeral_data; - ASSERT_BUF_LEN(REPLY_KEYPAD_LEN + event->keypress.length); - buf[len++] = pd->reply_id; - buf[len++] = (uint8_t)event->keypress.reader_no; - buf[len++] = (uint8_t)event->keypress.length; - for (i = 0; i < event->keypress.length; i++) { - buf[len++] = event->keypress.data[i]; - } - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_RAW: - event = (struct osdp_event *)pd->ephemeral_data; - t1 = (event->cardread.length + 7) / 8; - ASSERT_BUF_LEN(REPLY_RAW_LEN + t1); - buf[len++] = pd->reply_id; - buf[len++] = (uint8_t)event->cardread.reader_no; - buf[len++] = (uint8_t)event->cardread.format; - buf[len++] = BYTE_0(event->cardread.length); - buf[len++] = BYTE_1(event->cardread.length); - for (i = 0; i < t1; i++) { - buf[len++] = event->cardread.data[i]; - } - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_FMT: - event = (struct osdp_event *)pd->ephemeral_data; - ASSERT_BUF_LEN(REPLY_FMT_LEN + event->cardread.length); - buf[len++] = pd->reply_id; - buf[len++] = (uint8_t)event->cardread.reader_no; - buf[len++] = (uint8_t)event->cardread.direction; - buf[len++] = (uint8_t)event->cardread.length; - for (i = 0; i < event->cardread.length; i++) { - buf[len++] = event->cardread.data[i]; - } - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_COM: - ASSERT_BUF_LEN(REPLY_COM_LEN); - /** - * If COMSET succeeds, the PD must reply with the old params and - * then switch to the new params from then then on. We have the - * new params in the commands struct that we just enqueued so - * we can peek at tail of command queue and set that to - * pd->addr/pd->baud_rate. - */ - cmd = (struct osdp_cmd *)pd->ephemeral_data; - buf[len++] = pd->reply_id; - buf[len++] = cmd->comset.address; - buf[len++] = BYTE_0(cmd->comset.baud_rate); - buf[len++] = BYTE_1(cmd->comset.baud_rate); - buf[len++] = BYTE_2(cmd->comset.baud_rate); - buf[len++] = BYTE_3(cmd->comset.baud_rate); - - pd->address = (int)cmd->comset.address; - pd->baud_rate = (int)cmd->comset.baud_rate; - OSDP_LOG_INFO("osdp: pd: COMSET Succeeded! New PD-Addr: %d; Baud: %d\n", - pd->address, pd->baud_rate); - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_NAK: - ASSERT_BUF_LEN(REPLY_NAK_LEN); - buf[len++] = pd->reply_id; - buf[len++] = pd->ephemeral_data[0]; - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_MFGREP: - cmd = (struct osdp_cmd *)pd->ephemeral_data; - ASSERT_BUF_LEN(REPLY_MFGREP_LEN + cmd->mfg.length); - buf[len++] = pd->reply_id; - buf[len++] = BYTE_0(cmd->mfg.vendor_code); - buf[len++] = BYTE_1(cmd->mfg.vendor_code); - buf[len++] = BYTE_2(cmd->mfg.vendor_code); - buf[len++] = cmd->mfg.command; - for (i = 0; i < cmd->mfg.length; i++) { - buf[len++] = cmd->mfg.data[i]; - } - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_CCRYPT: - if (smb == NULL) { - break; - } - ASSERT_BUF_LEN(REPLY_CCRYPT_LEN); - osdp_get_rand(pd->sc.pd_random, 8); - osdp_compute_session_keys(TO_CTX(pd)); - osdp_compute_pd_cryptogram(pd); - buf[len++] = pd->reply_id; - for (i = 0; i < 8; i++) { - buf[len++] = pd->sc.pd_client_uid[i]; - } - for (i = 0; i < 8; i++) { - buf[len++] = pd->sc.pd_random[i]; - } - for (i = 0; i < 16; i++) { - buf[len++] = pd->sc.pd_cryptogram[i]; - } - smb[0] = 3; /* length */ - smb[1] = SCS_12; /* type */ - smb[2] = ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD) ? 0 : 1; - ret = OSDP_PD_ERR_NONE; - break; - case REPLY_RMAC_I: - if (smb == NULL) { - break; - } - ASSERT_BUF_LEN(REPLY_RMAC_I_LEN); - osdp_compute_rmac_i(pd); - buf[len++] = pd->reply_id; - for (i = 0; i < 16; i++) { - buf[len++] = pd->sc.r_mac[i]; - } - smb[0] = 3; /* length */ - smb[1] = SCS_14; /* type */ - if (osdp_verify_cp_cryptogram(pd) == 0) { - smb[2] = 1; /* CP auth succeeded */ - SET_FLAG(pd, PD_FLAG_SC_ACTIVE); - pd->sc_tstamp = osdp_millis_now(); - if (ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD)) { - OSDP_LOG_WARN("osdp: pd: SC Active with SCBK-D\n"); - } else { - OSDP_LOG_INFO("osdp: pd: SC Active\n"); - } - } else { - smb[2] = 0; /* CP auth failed */ - OSDP_LOG_WARN("osdp: pd: failed to verify CP_crypt\n"); - } - ret = OSDP_PD_ERR_NONE; - break; - } - - if (smb && (smb[1] > SCS_14) && ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - smb[0] = 2; /* length */ - smb[1] = (len > 1) ? SCS_18 : SCS_16; - } - - if (ret != 0) { - /* catch all errors and report it as a RECORD error to CP */ - OSDP_LOG_ERROR("osdp: pd: Failed to build REPLY(%02x); Sending NAK instead!\n", - pd->reply_id); - ASSERT_BUF_LEN(REPLY_NAK_LEN); - buf[0] = REPLY_NAK; - buf[1] = OSDP_PD_NAK_RECORD; - len = 2; - } - - return len; -} - -/** - * pd_send_reply - blocking send; doesn't handle partials - * Returns: - * 0 - success - * -1 - failure - */ -static int -pd_send_reply(struct osdp_pd *pd) -{ - int ret, len; - - /* init packet buf with header */ - len = osdp_phy_packet_init(pd, pd->rx_buf, sizeof(pd->rx_buf)); - if (len < 0) { - return OSDP_PD_ERR_GENERIC; - } - - /* fill reply data */ - ret = pd_build_reply(pd, pd->rx_buf, sizeof(pd->rx_buf)); - if (ret <= 0) { - return OSDP_PD_ERR_GENERIC; - } - len += ret; - - /* finalize packet */ - len = osdp_phy_packet_finalize(pd, pd->rx_buf, len, sizeof(pd->rx_buf)); - if (len < 0) { - return OSDP_PD_ERR_GENERIC; - } - - /* flush rx to remove any invalid data. */ - if (pd->channel.flush) { - pd->channel.flush(pd->channel.data); - } - - ret = pd->channel.send(pd->channel.data, pd->rx_buf, len); - if (ret != len) { - OSDP_LOG_ERROR("osdp: pd: Channel send for %d bytes failed! ret: %d\n", len, ret); - return OSDP_PD_ERR_GENERIC; - } - - if (MYNEWT_VAL(OSDP_PACKET_TRACE)) { - if (pd->cmd_id != CMD_POLL) { - osdp_dump(pd->rx_buf, pd->rx_buf_len, - "OSDP: PD[%d]: Sent\n", pd->address); - } - } - - return OSDP_PD_ERR_NONE; -} - -static int -pd_receive_packet(struct osdp_pd *pd) -{ - uint8_t *buf; - int len, err, remaining; - - len = pd->channel.recv(pd->channel.data, pd->rx_buf + pd->rx_buf_len, - sizeof(pd->rx_buf) - pd->rx_buf_len); - if (len > 0) { - pd->rx_buf_len += len; - } - - if (MYNEWT_VAL(OSDP_PACKET_TRACE)) { - /** - * A crude way of identifying and not printing poll messages - * when OSDP_PACKET_TRACE is enabled. This is an early - * print to catch errors so keeping it simple. - * OSDP_CMD_ID_OFFSET + 2 is also checked as the CMD_ID can be - * pushed back by 2 bytes if secure channel block is present in - * header. - */ - if (pd->rx_buf_len > MYNEWT_VAL(OSDP_CMD_ID_OFFSET) + 2 && - pd->rx_buf[MYNEWT_VAL(OSDP_CMD_ID_OFFSET)] != CMD_POLL && - pd->rx_buf[MYNEWT_VAL(OSDP_CMD_ID_OFFSET) + 2] != CMD_POLL) { - osdp_dump(pd->rx_buf, pd->rx_buf_len, - "OSDP: PD[%d]: Received\n", pd->address); - } - } - - err = osdp_phy_check_packet(pd, pd->rx_buf, pd->rx_buf_len, &len); - if (err == OSDP_ERR_PKT_WAIT) { - /* rx_buf_len < pkt->len; wait for more data */ - return OSDP_PD_ERR_NO_DATA; - } - if (err == OSDP_ERR_PKT_FMT) { - return OSDP_PD_ERR_GENERIC; - } - if (err == OSDP_ERR_PKT_SKIP) { - err = OSDP_PD_ERR_IGNORE; - } - if (err == OSDP_ERR_PKT_NONE) { - pd->reply_id = 0; /* reset past reply ID so phy can send NAK */ - pd->ephemeral_data[0] = 0; /* reset past NAK reason */ - len = osdp_phy_decode_packet(pd, pd->rx_buf, len, &buf); - if (len <= 0) { - if (pd->reply_id != 0) { - return OSDP_PD_ERR_REPLY; /* Send a NAK */ - } - return OSDP_PD_ERR_GENERIC; /* fatal errors */ - } - err = pd_decode_command(pd, buf, len); - } - - /* We are done with the packet (error or not). Remove processed bytes */ - remaining = pd->rx_buf_len - len; - if (remaining) { - memmove(pd->rx_buf, pd->rx_buf + len, remaining); - } - /** - * Store remaining length that needs to be processed. - * State machine will be updated accordingly. - */ - pd->rx_buf_len = remaining; - - return err; -} - -static void -osdp_update(struct osdp_pd *pd) -{ - int ret; - - switch (pd->state) { - case OSDP_PD_STATE_IDLE: - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE) && - osdp_millis_since(pd->sc_tstamp) > MYNEWT_VAL(OSDP_PD_SC_TIMEOUT_MS)) { - OSDP_LOG_INFO("osdp: pd: PD SC session timeout!\n"); - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - } - /* When secure mode is inactive check if CP is polling */ - if (ISSET_FLAG(pd, PD_FLAG_CP_POLL_ACTIVE) && - osdp_millis_since(pd->tstamp) > MYNEWT_VAL(OSDP_PD_IDLE_TIMEOUT_MS)) { - OSDP_LOG_INFO("osdp: pd: PD CP-poll timeout!\n"); - CLEAR_FLAG(pd, PD_FLAG_CP_POLL_ACTIVE); - } - ret = pd->channel.recv(pd->channel.data, pd->rx_buf, - sizeof(pd->rx_buf)); - if (ret <= 0) { - break; - } - pd->rx_buf_len = ret; - pd->tstamp = osdp_millis_now(); - pd->state = OSDP_PD_STATE_PROCESS_CMD; - __fallthrough; - case OSDP_PD_STATE_PROCESS_CMD: - ret = pd_receive_packet(pd); - if (ret == OSDP_PD_ERR_NO_DATA && - osdp_millis_since(pd->tstamp) < MYNEWT_VAL(OSDP_RESP_TOUT_MS)) { - break; - } - if (ret == OSDP_PD_ERR_IGNORE) { - /* Process command if non-empty */ - if (pd->rx_buf_len > 0) { - pd->state = OSDP_PD_STATE_PROCESS_CMD; - } else { - pd->state = OSDP_PD_STATE_IDLE; - } - break; - } - if (ret != OSDP_PD_ERR_NONE && ret != OSDP_PD_ERR_REPLY) { - OSDP_LOG_ERROR("osdp: pd: CMD receive error/timeout - err:%d\n", ret); - pd->state = OSDP_PD_STATE_ERR; - break; - } - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE) && - ret == OSDP_PD_ERR_NONE) { - pd->sc_tstamp = osdp_millis_now(); - } - pd->state = OSDP_PD_STATE_SEND_REPLY; - __fallthrough; - case OSDP_PD_STATE_SEND_REPLY: - if (pd_send_reply(pd) == -1) { - pd->state = OSDP_PD_STATE_ERR; - break; - } - pd->rx_buf_len = 0; - pd->state = OSDP_PD_STATE_IDLE; - break; - case OSDP_PD_STATE_ERR: - /** - * PD error state is momentary as it doesn't maintain any state - * between commands. We just clean up secure channel status and - * go back to idle state. - */ - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - if (pd->channel.flush) { - pd->channel.flush(pd->channel.data); - } - pd->state = OSDP_PD_STATE_IDLE; - break; - } -} - -static void -osdp_pd_set_attributes(struct osdp_pd *pd, struct osdp_pd_cap *cap, - struct osdp_pd_id *id) -{ - int fc; - - while (cap && ((fc = cap->function_code) > 0)) { - if (fc >= OSDP_PD_CAP_SENTINEL) { - break; - } - pd->cap[fc].function_code = cap->function_code; - pd->cap[fc].compliance_level = cap->compliance_level; - pd->cap[fc].num_items = cap->num_items; - cap++; - } - if (id != NULL) { - memcpy(&pd->id, id, sizeof(struct osdp_pd_id)); - } -} - -osdp_t * -osdp_pd_setup(struct osdp_ctx *osdp_ctx, osdp_pd_info_t *info, uint8_t *scbk) -{ - struct osdp_pd *pd; - struct osdp_cp *cp; - struct osdp *ctx; - - assert(info); - - /* - osdp_log_ctx_set(info->address); - */ - - ctx = &osdp_ctx->ctx; - ctx->magic = 0xDEADBEAF; - - ctx->cp = &osdp_ctx->cp_ctx; - cp = TO_CP(ctx); - cp->__parent = ctx; - cp->num_pd = 1; - - ctx->pd = &osdp_ctx->pd_ctx[0]; - SET_CURRENT_PD(ctx, 0); - pd = TO_PD(ctx, 0); - - pd->__parent = ctx; - pd->offset = 0; - pd->baud_rate = info->baud_rate; - pd->address = info->address; - pd->flags = info->flags; - pd->seq_number = -1; - memcpy(&pd->channel, &info->channel, sizeof(struct osdp_channel)); - - if (pd_event_queue_init(pd)) { - goto error; - } - - if (scbk == NULL) { - if (ISSET_FLAG(pd, OSDP_FLAG_ENFORCE_SECURE)) { - OSDP_LOG_ERROR("osdp: pd: SCBK must be provided in ENFORCE_SECURE\n"); - goto error; - } - if (!ISSET_FLAG(pd, OSDP_FLAG_NON_SECURE_MODE)) { - OSDP_LOG_WARN("osdp: pd: SCBK not provided. PD is in INSTALL_MODE\n"); - SET_FLAG(pd, OSDP_FLAG_INSTALL_MODE); - } else { - OSDP_LOG_WARN("osdp: pd: Setting up in non-secure mode\n"); - /* Non secure mode */ - } - } else { - memcpy(pd->sc.scbk, scbk, 16); - } - - /* Set secure capability based on non-secure flag */ - if (!ISSET_FLAG(pd, OSDP_FLAG_NON_SECURE_MODE)) { - OSDP_LOG_INFO("osdp: pd: PD is SC capable!\n"); - SET_FLAG(pd, PD_FLAG_SC_CAPABLE); - } - - if (IS_ENABLED(CONFIG_OSDP_SKIP_MARK_BYTE)) { - SET_FLAG(pd, PD_FLAG_PKT_SKIP_MARK); - } - /* Set capabilities based on application */ - osdp_pd_set_attributes(pd, info->cap, &info->id); - /* Set implicit capabilities */ - osdp_pd_set_attributes(pd, osdp_pd_cap, NULL); - - SET_FLAG(pd, PD_FLAG_PD_MODE); /* used in checks in phy */ - - osdp_pd_set_command_callback(ctx, info->pd_cb, NULL); - - OSDP_LOG_INFO("osdp: pd: PD setup complete\n"); - return (osdp_t *) ctx; - -error: - osdp_pd_teardown((osdp_t *) ctx); - return NULL; -} - -/* --- Exported Methods --- */ - -void -osdp_pd_teardown(osdp_t *ctx) -{ - assert(ctx); - - pd_event_queue_del(TO_PD(ctx, 0)); -} - -void -osdp_refresh(osdp_t *ctx) -{ - assert(ctx); - struct osdp_pd *pd = GET_CURRENT_PD(ctx); - - osdp_update(pd); -} - -void -osdp_pd_set_capabilities(osdp_t *ctx, struct osdp_pd_cap *cap) -{ - assert(ctx); - struct osdp_pd *pd = GET_CURRENT_PD(ctx); - - osdp_pd_set_attributes(pd, cap, NULL); -} - -void -osdp_pd_set_command_callback(osdp_t *ctx, pd_command_callback_t cb, - void *arg) -{ - assert(ctx); - struct osdp_pd *pd = GET_CURRENT_PD(ctx); - - pd->command_callback_arg = arg; - pd->command_callback = cb; -} - -int -osdp_pd_notify_event(osdp_t *ctx, struct osdp_event *event) -{ - assert(ctx); - struct osdp_pd *pd = GET_CURRENT_PD(ctx); - - pd_event_put(pd, event); - return 0; -} - -#endif /* OSDP_MODE_PD */ diff --git a/net/osdp/src/osdp_phy.c b/net/osdp/src/osdp_phy.c deleted file mode 100644 index fa94c9aee9..0000000000 --- a/net/osdp/src/osdp_phy.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "modlog/modlog.h" -#include "osdp/osdp_common.h" - -#define LOG_TAG "PHY: " -#define OSDP_PKT_MARK 0xFF -#define OSDP_PKT_SOM 0x53 -#define PKT_CONTROL_SQN 0x03 -#define PKT_CONTROL_CRC 0x04 -#define PKT_CONTROL_SCB 0x08 - -struct osdp_packet_header { - uint8_t som; - uint8_t pd_address; - uint8_t len_lsb; - uint8_t len_msb; - uint8_t control; - uint8_t data[]; -} __packed; - -uint8_t -osdp_compute_checksum(uint8_t *msg, int length) -{ - uint8_t checksum = 0; - int i, whole_checksum; - - whole_checksum = 0; - for (i = 0; i < length; i++) { - whole_checksum += msg[i]; - checksum = ~(0xff & whole_checksum) + 1; - } - return checksum; -} - -static int -osdp_phy_get_seq_number(struct osdp_pd *pd, int do_inc) -{ - /* pd->seq_num is set to -1 to reset phy cmd state */ - if (do_inc) { - pd->seq_number += 1; - if (pd->seq_number > 3) { - pd->seq_number = 1; - } - } - return pd->seq_number & PKT_CONTROL_SQN; -} - -int -osdp_phy_packet_get_data_offset(struct osdp_pd *pd, const uint8_t *buf) -{ - int sb_len = 0, mark_byte_len = 0; - struct osdp_packet_header *pkt; - - ARG_UNUSED(pd); - if (ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK)) { - mark_byte_len = 1; - buf += 1; - } - pkt = (struct osdp_packet_header *)buf; - if (pkt->control & PKT_CONTROL_SCB) { - sb_len = pkt->data[0]; - } - return mark_byte_len + sizeof(struct osdp_packet_header) + sb_len; -} - -uint8_t * -osdp_phy_packet_get_smb(struct osdp_pd *pd, const uint8_t *buf) -{ - struct osdp_packet_header *pkt; - - ARG_UNUSED(pd); - if (ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK)) { - buf += 1; - } - pkt = (struct osdp_packet_header *)buf; - if (pkt->control & PKT_CONTROL_SCB) { - return pkt->data; - } - return NULL; -} - -int -osdp_phy_in_sc_handshake(int is_reply, int id) -{ - if (is_reply) { - return (id == REPLY_CCRYPT || id == REPLY_RMAC_I); - } else { - return (id == CMD_CHLNG || id == CMD_SCRYPT); - } -} - -int -osdp_phy_packet_init(struct osdp_pd *pd, uint8_t *buf, int max_len) -{ - int exp_len, pd_mode, id, scb_len = 0, mark_byte_len = 0; - struct osdp_packet_header *pkt; - - pd_mode = ISSET_FLAG(pd, PD_FLAG_PD_MODE); - exp_len = sizeof(struct osdp_packet_header) + 64; /* 64 is estimated */ - if (max_len < exp_len) { - OSDP_LOG_ERROR("packet_init: out of space! CMD: %02x\n", pd->cmd_id); - return OSDP_ERR_PKT_FMT; - } - - /** - * In PD mode just follow what we received from CP. In CP mode, as we - * initiate the transaction, choose based on CONFIG_OSDP_SKIP_MARK_BYTE. - */ - if ((pd_mode && ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK)) || - (!pd_mode && !ISSET_FLAG(pd, PD_FLAG_PKT_SKIP_MARK))) { - buf[0] = OSDP_PKT_MARK; - buf++; - mark_byte_len = 1; - SET_FLAG(pd, PD_FLAG_PKT_HAS_MARK); - } - - /* Fill packet header */ - pkt = (struct osdp_packet_header *)buf; - pkt->som = OSDP_PKT_SOM; - pkt->pd_address = pd->address & 0x7F; /* Use only the lower 7 bits */ - if (pd_mode) { - /* PD must reply with MSB of it's address set */ - pkt->pd_address |= 0x80; - id = pd->reply_id; - } else { - id = pd->cmd_id; - } - pkt->control = osdp_phy_get_seq_number(pd, !pd_mode); - pkt->control |= PKT_CONTROL_CRC; - - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - pkt->control |= PKT_CONTROL_SCB; - pkt->data[0] = scb_len = 2; - pkt->data[1] = SCS_15; - } else if (osdp_phy_in_sc_handshake(pd_mode, id)) { - pkt->control |= PKT_CONTROL_SCB; - pkt->data[0] = scb_len = 3; - pkt->data[1] = SCS_11; - } - - return mark_byte_len + sizeof(struct osdp_packet_header) + scb_len; -} - -int -osdp_phy_packet_finalize(struct osdp_pd *pd, uint8_t *buf, - int len, int max_len) -{ - uint8_t *data; - uint16_t crc16; - struct osdp_packet_header *pkt; - int i, is_cmd, data_len; - - is_cmd = !ISSET_FLAG(pd, PD_FLAG_PD_MODE); - - /* Do a sanity check only; we expect expect header to be prefilled */ - if ((unsigned long)len <= sizeof(struct osdp_packet_header)) { - OSDP_LOG_ERROR("PKT_F: Invalid header\n"); - return OSDP_ERR_PKT_FMT; - } - - if (ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK)) { - if (buf[0] != OSDP_PKT_MARK) { - OSDP_LOG_ERROR("PKT_F: MARK validation failed! ID: 0x%02x\n", - is_cmd ? pd->cmd_id : pd->reply_id); - return OSDP_ERR_PKT_FMT; - } - /* temporarily get rid of mark byte */ - buf += 1; - len -= 1; - max_len -= 1; - } - pkt = (struct osdp_packet_header *)buf; - if (pkt->som != OSDP_PKT_SOM) { - OSDP_LOG_ERROR("PKT_F: header SOM validation failed! ID: 0x%02x\n", - is_cmd ? pd->cmd_id : pd->reply_id); - return OSDP_ERR_PKT_FMT; - } - - /* len: with 2 byte CRC */ - pkt->len_lsb = BYTE_0(len + 2); - pkt->len_msb = BYTE_1(len + 2); - - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE) && - pkt->control & PKT_CONTROL_SCB && - pkt->data[1] >= SCS_15) { - if (pkt->data[1] == SCS_17 || pkt->data[1] == SCS_18) { - /** - * Only the data portion of message (after id byte) - * is encrypted. While (en/de)crypting, we must skip - * header, security block, and cmd/reply ID byte. - * - * Note: if cmd/reply has no data, we must set type to - * SCS_15/SCS_16 and send them. - */ - data = pkt->data + pkt->data[0] + 1; - data_len = len - (sizeof(struct osdp_packet_header) - + pkt->data[0] + 1); - len -= data_len; - /** - * check if the passed buffer can hold the encrypted - * data where length may be rounded up to the nearest - * 16 byte block bondary. - */ - if (AES_PAD_LEN(data_len + 1) > max_len) { - /* data_len + 1 for OSDP_SC_EOM_MARKER */ - goto out_of_space_error; - } - len += osdp_encrypt_data(pd, is_cmd, data, data_len); - } - /* len: with 4bytes MAC; with 2 byte CRC; without 1 byte mark */ - if (len + 4 > max_len) { - goto out_of_space_error; - } - - /* len: with 2 byte CRC; with 4 byte MAC */ - pkt->len_lsb = BYTE_0(len + 2 + 4); - pkt->len_msb = BYTE_1(len + 2 + 4); - - /* compute and extend the buf with 4 MAC bytes */ - osdp_compute_mac(pd, is_cmd, buf, len); - data = is_cmd ? pd->sc.c_mac : pd->sc.r_mac; - for (i = 0; i < 4; i++) { - buf[len + i] = data[i]; - } - len += 4; - } - - /* fill crc16 */ - if (len + 2 > max_len) { - goto out_of_space_error; - } - crc16 = osdp_compute_crc16(buf, len); - buf[len + 0] = BYTE_0(crc16); - buf[len + 1] = BYTE_1(crc16); - len += 2; - - if (ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK)) { - len += 1; /* put back mark byte */ - } - - return len; - -out_of_space_error: - OSDP_LOG_ERROR("PKT_F: Out of buffer space! CMD(%02x)\n", pd->cmd_id); - return OSDP_ERR_PKT_FMT; -} - -int -osdp_phy_check_packet(struct osdp_pd *pd, uint8_t *buf, int len, - int *one_pkt_len) -{ - uint16_t comp, cur; - int pd_addr, pkt_len; - struct osdp_packet_header *pkt; - - /* wait till we have the header */ - if ((unsigned long)len < sizeof(struct osdp_packet_header)) { - /* incomplete data */ - return OSDP_ERR_PKT_WAIT; - } - - CLEAR_FLAG(pd, PD_FLAG_PKT_HAS_MARK); - if (buf[0] == OSDP_PKT_MARK) { - buf += 1; - len -= 1; - SET_FLAG(pd, PD_FLAG_PKT_HAS_MARK); - } - - pkt = (struct osdp_packet_header *)buf; - - /* validate packet header */ - if (pkt->som != OSDP_PKT_SOM) { - OSDP_LOG_ERROR("Invalid SOM 0x%02x\n", pkt->som); - return OSDP_ERR_PKT_FMT; - } - - if (!ISSET_FLAG(pd, PD_FLAG_PD_MODE) && - !(pkt->pd_address & 0x80)) { - OSDP_LOG_ERROR("Reply without address MSB set 0x%02x!\n", pkt->pd_address); - return OSDP_ERR_PKT_FMT; - } - - /* validate packet length */ - pkt_len = (pkt->len_msb << 8) | pkt->len_lsb; - if (len < pkt_len) { - /* wait for more data? */ - return OSDP_ERR_PKT_WAIT; - } - - *one_pkt_len = pkt_len + (ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK) ? 1 : 0); - - /* validate CRC/checksum */ - if (pkt->control & PKT_CONTROL_CRC) { - pkt_len -= 2; /* consume CRC */ - cur = (buf[pkt_len + 1] << 8) | buf[pkt_len]; - comp = osdp_compute_crc16(buf, pkt_len); - if (comp != cur) { - OSDP_LOG_ERROR("Invalid crc 0x%04x/0x%04x\n", comp, cur); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_MSG_CHK; - return OSDP_ERR_PKT_CHECK; - } - } else { - pkt_len -= 1; /* consume checksum */ - cur = buf[pkt_len]; - comp = osdp_compute_checksum(buf, pkt_len); - if (comp != cur) { - OSDP_LOG_ERROR("Invalid checksum %02x/%02x\n", comp, cur); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_MSG_CHK; - return OSDP_ERR_PKT_CHECK; - } - } - - /* validate PD address */ - pd_addr = pkt->pd_address & 0x7F; - if (pd_addr != pd->address && pd_addr != 0x7F) { - /* not addressed to us and was not broadcasted */ - if (!ISSET_FLAG(pd, PD_FLAG_PD_MODE)) { - OSDP_LOG_ERROR("Invalid pd address %d\n", pd_addr); - return OSDP_ERR_PKT_FMT; - } - return OSDP_ERR_PKT_SKIP; - } - - /* validate sequence number */ - comp = pkt->control & PKT_CONTROL_SQN; - if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) { - if (comp == 0) { - /** - * CP is trying to restart communication by sending a 0. - * The current PD implementation does not hold any state - * between commands so we can just set seq_number to -1 - * (so it gets incremented to 0 with a call to - * phy_get_seq_number()) and invalidate any established - * secure channels. - */ - pd->seq_number = -1; - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - } - if (comp == pd->seq_number) { - /** - * TODO: PD must resend the last response if CP send the - * same sequence number again. - */ - OSDP_LOG_ERROR("seq-repeat/reply-resend not supported!\n"); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SEQ_NUM; - return OSDP_ERR_PKT_FMT; - } - } else { - if (comp == 0) { - /** - * Check for receiving a busy reply from the PD which would - * have a sequence number of 0, come in an unsecured packet - * of minimum length, and have the reply ID REPLY_BUSY. - */ - if ((pkt_len == 6) && (pkt->data[0] == REPLY_BUSY)) { - pd->seq_number -= 1; - return OSDP_ERR_PKT_BUSY; - } - } - } - cur = osdp_phy_get_seq_number(pd, ISSET_FLAG(pd, PD_FLAG_PD_MODE)); - if (cur != comp && !ISSET_FLAG(pd, PD_FLAG_SKIP_SEQ_CHECK)) { - OSDP_LOG_ERROR("packet seq mismatch %d/%d\n", cur, comp); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SEQ_NUM; - return OSDP_ERR_PKT_FMT; - } - - return OSDP_ERR_PKT_NONE; -} - -int -osdp_phy_decode_packet(struct osdp_pd *pd, uint8_t *buf, int len, - uint8_t **pkt_start) -{ - uint8_t *data, *mac; - int mac_offset, is_cmd; - struct osdp_packet_header *pkt; - - if (ISSET_FLAG(pd, PD_FLAG_PKT_HAS_MARK)) { - /* Consume mark byte */ - buf += 1; - len -= 1; - } - - pkt = (struct osdp_packet_header *)buf; - len -= pkt->control & PKT_CONTROL_CRC ? 2 : 1; - mac_offset = len - 4; - data = pkt->data; - len -= sizeof(struct osdp_packet_header); - - if (pkt->control & PKT_CONTROL_SCB) { - if (ISSET_FLAG(pd, PD_FLAG_PD_MODE) && - !ISSET_FLAG(pd, PD_FLAG_SC_CAPABLE)) { - OSDP_LOG_ERROR("PD is not SC capable\n"); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SC_UNSUP; - return OSDP_ERR_PKT_FMT; - } - if (pkt->data[1] < SCS_11 || pkt->data[1] > SCS_18) { - OSDP_LOG_ERROR("Invalid SB Type\n"); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; - return OSDP_ERR_PKT_FMT; - } - if (pkt->data[1] == SCS_11 || pkt->data[1] == SCS_13) { - /** - * CP signals PD to use SCBKD by setting SB data byte - * to 0. In CP, PD_FLAG_SC_USE_SCBKD comes from FSM; on - * PD we extract it from the command itself. But this - * usage of SCBKD is allowed only when the PD is in - * install mode (indicated by OSDP_FLAG_INSTALL_MODE). - */ - if (ISSET_FLAG(pd, OSDP_FLAG_INSTALL_MODE) && - pkt->data[2] == 0) { - SET_FLAG(pd, PD_FLAG_SC_USE_SCBKD); - } - } - data = pkt->data + pkt->data[0]; - len -= pkt->data[0]; /* consume security block */ - } else { - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE)) { - OSDP_LOG_ERROR("Received plain-text message in SC\n"); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; - return OSDP_ERR_PKT_FMT; - } - } - - if (ISSET_FLAG(pd, PD_FLAG_SC_ACTIVE) && - pkt->control & PKT_CONTROL_SCB && - pkt->data[1] >= SCS_15) { - /* validate MAC */ - is_cmd = ISSET_FLAG(pd, PD_FLAG_PD_MODE); - osdp_compute_mac(pd, is_cmd, buf, mac_offset); - mac = is_cmd ? pd->sc.c_mac : pd->sc.r_mac; - if (memcmp(buf + mac_offset, mac, 4) != 0) { - OSDP_LOG_ERROR("Invalid MAC; discarding SC\n"); - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; - return OSDP_ERR_PKT_FMT; - } - len -= 4; /* consume MAC */ - - /* decrypt data block */ - if (pkt->data[1] == SCS_17 || pkt->data[1] == SCS_18) { - /** - * Only the data portion of message (after id byte) - * is encrypted. While (en/de)crypting, we must skip - * header (6), security block (2) and cmd/reply id (1) - * bytes. - * - * At this point, the header and security block is - * already consumed. So we can just skip the cmd/reply - * ID (data[0]) when calling osdp_decrypt_data(). - */ - len = osdp_decrypt_data(pd, is_cmd, data + 1, len - 1); - if (len < 0) { - OSDP_LOG_ERROR("Failed at decrypt; discarding SC\n"); - CLEAR_FLAG(pd, PD_FLAG_SC_ACTIVE); - pd->reply_id = REPLY_NAK; - pd->ephemeral_data[0] = OSDP_PD_NAK_SC_COND; - return OSDP_ERR_PKT_FMT; - } - if (len == 0) { - /** - * If cmd/reply has no data, PD "should" have - * used SCS_15/SCS_16 but we will be tolerant - * towards those faulty implementations. - */ - OSDP_LOG_INFO("Received encrypted data block with 0 " - "length; tolerating non-conformance!\n"); - } - len += 1; /* put back cmd/reply ID */ - } - } - - *pkt_start = data; - return len; -} - -void -osdp_phy_state_reset(struct osdp_pd *pd) -{ - pd->phy_state = 0; - pd->seq_number = -1; - pd->rx_buf_len = 0; -} diff --git a/net/osdp/src/osdp_sc.c b/net/osdp/src/osdp_sc.c deleted file mode 100644 index 4566df6ece..0000000000 --- a/net/osdp/src/osdp_sc.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (c) 2019 Siddharth Chandrasekaran - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "modlog/modlog.h" - -#include -#include "osdp/osdp_common.h" - -#define TAG "SC: " -#define OSDP_SC_EOM_MARKER 0x80 /* End of Message Marker */ - -/* Default key as specified in OSDP specification */ -static const uint8_t osdp_scbk_default[16] = { - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F -}; - -void -osdp_compute_scbk(struct osdp_pd *pd, uint8_t *master_key, uint8_t *scbk) -{ - int i; - - memcpy(scbk, pd->sc.pd_client_uid, 8); - for (i = 8; i < 16; i++) { - scbk[i] = ~scbk[i - 8]; - } - osdp_encrypt(master_key, NULL, scbk, 16); -} - -void -osdp_compute_session_keys(struct osdp *ctx) -{ - int i; - struct osdp_pd *pd = GET_CURRENT_PD(ctx); - - if (ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD)) { - memcpy(pd->sc.scbk, osdp_scbk_default, 16); - } else { - /** - * Compute SCBK only in CP mode. PD mode, expect to already have - * the SCBK (sent from application layer). - */ - if (ISSET_FLAG(pd, PD_FLAG_PD_MODE) == 0) { - osdp_compute_scbk(pd, ctx->sc_master_key, pd->sc.scbk); - } - } - - memset(pd->sc.s_enc, 0, 16); - memset(pd->sc.s_mac1, 0, 16); - memset(pd->sc.s_mac2, 0, 16); - - pd->sc.s_enc[0] = 0x01; - pd->sc.s_enc[1] = 0x82; - pd->sc.s_mac1[0] = 0x01; - pd->sc.s_mac1[1] = 0x01; - pd->sc.s_mac2[0] = 0x01; - pd->sc.s_mac2[1] = 0x02; - - for (i = 2; i < 8; i++) { - pd->sc.s_enc[i] = pd->sc.cp_random[i - 2]; - pd->sc.s_mac1[i] = pd->sc.cp_random[i - 2]; - pd->sc.s_mac2[i] = pd->sc.cp_random[i - 2]; - } - - osdp_encrypt(pd->sc.scbk, NULL, pd->sc.s_enc, 16); - osdp_encrypt(pd->sc.scbk, NULL, pd->sc.s_mac1, 16); - osdp_encrypt(pd->sc.scbk, NULL, pd->sc.s_mac2, 16); -} - -void -osdp_compute_cp_cryptogram(struct osdp_pd *pd) -{ - /* cp_cryptogram = AES-ECB( pd_random[8] || cp_random[8], s_enc ) */ - memcpy(pd->sc.cp_cryptogram + 0, pd->sc.pd_random, 8); - memcpy(pd->sc.cp_cryptogram + 8, pd->sc.cp_random, 8); - osdp_encrypt(pd->sc.s_enc, NULL, pd->sc.cp_cryptogram, 16); -} - -/** - * Like memcmp; but operates at constant time. - * - * Returns 0 if memory pointed to by s1 and and s2 are identical; non-zero - * otherwise. - */ -static int -osdp_ct_compare(const void *s1, const void *s2, size_t len) -{ - size_t i, ret = 0; - const uint8_t *_s1 = s1; - const uint8_t *_s2 = s2; - - for (i = 0; i < len; i++) { - ret |= _s1[i] ^ _s2[i]; - } - return (int)ret; -} - -int -osdp_verify_cp_cryptogram(struct osdp_pd *pd) -{ - uint8_t cp_crypto[16]; - - /* cp_cryptogram = AES-ECB( pd_random[8] || cp_random[8], s_enc ) */ - memcpy(cp_crypto + 0, pd->sc.pd_random, 8); - memcpy(cp_crypto + 8, pd->sc.cp_random, 8); - osdp_encrypt(pd->sc.s_enc, NULL, cp_crypto, 16); - - if (osdp_ct_compare(pd->sc.cp_cryptogram, cp_crypto, 16) != 0) { - return -1; - } - return 0; -} - -void -osdp_compute_pd_cryptogram(struct osdp_pd *pd) -{ - /* pd_cryptogram = AES-ECB( cp_random[8] || pd_random[8], s_enc ) */ - memcpy(pd->sc.pd_cryptogram + 0, pd->sc.cp_random, 8); - memcpy(pd->sc.pd_cryptogram + 8, pd->sc.pd_random, 8); - osdp_encrypt(pd->sc.s_enc, NULL, pd->sc.pd_cryptogram, 16); -} - -int -osdp_verify_pd_cryptogram(struct osdp_pd *pd) -{ - uint8_t pd_crypto[16]; - - /* pd_cryptogram = AES-ECB( cp_random[8] || pd_random[8], s_enc ) */ - memcpy(pd_crypto + 0, pd->sc.cp_random, 8); - memcpy(pd_crypto + 8, pd->sc.pd_random, 8); - osdp_encrypt(pd->sc.s_enc, NULL, pd_crypto, 16); - - if (osdp_ct_compare(pd->sc.pd_cryptogram, pd_crypto, 16) != 0) { - return -1; - } - return 0; -} - -void -osdp_compute_rmac_i(struct osdp_pd *pd) -{ - /* rmac_i = AES-ECB( AES-ECB( cp_cryptogram, s_mac1 ), s_mac2 ) */ - memcpy(pd->sc.r_mac, pd->sc.cp_cryptogram, 16); - osdp_encrypt(pd->sc.s_mac1, NULL, pd->sc.r_mac, 16); - osdp_encrypt(pd->sc.s_mac2, NULL, pd->sc.r_mac, 16); -} - -int -osdp_decrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int length) -{ - int i; - uint8_t iv[16]; - - if (length % 16 != 0) { - OSDP_LOG_ERROR("osdp: sc: decrypt_pkt invalid len:%d\n", length); - return -1; - } - - memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16); - for (i = 0; i < 16; i++) { - iv[i] = ~iv[i]; - } - - osdp_decrypt(pd->sc.s_enc, iv, data, length); - - length--; - while (length && data[length] == 0x00) { - length--; - } - if (data[length] != OSDP_SC_EOM_MARKER) { - return -1; - } - data[length] = 0; - - return length; -} - -int -osdp_encrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int length) -{ - int i, pad_len; - uint8_t iv[16]; - - data[length] = OSDP_SC_EOM_MARKER; /* append EOM marker */ - pad_len = AES_PAD_LEN(length + 1); - if ((pad_len - length - 1) > 0) { - memset(data + length + 1, 0, pad_len - length - 1); - } - memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16); - for (i = 0; i < 16; i++) { - iv[i] = ~iv[i]; - } - - osdp_encrypt(pd->sc.s_enc, iv, data, pad_len); - - return pad_len; -} - -int -osdp_compute_mac(struct osdp_pd *pd, int is_cmd, - const uint8_t *data, int len) -{ - int pad_len; - uint8_t buf[max(MYNEWT_VAL(OSDP_UART_TX_BUFFER_LENGTH), - MYNEWT_VAL(OSDP_UART_RX_BUFFER_LENGTH))] = { 0 }; - uint8_t iv[16]; - - memcpy(buf, data, len); - pad_len = (len % 16 == 0) ? len : AES_PAD_LEN(len); - if (len % 16 != 0) { - buf[len] = 0x80; /* end marker */ - } - /** - * MAC for data blocks B[1] .. B[N] (post padding) is computed as: - * IV1 = R_MAC (or) C_MAC -- depending on is_cmd - * IV2 = B[N-1] after -- AES-CBC ( IV1, B[1] to B[N-1], SMAC-1 ) - * MAC = AES-ECB ( IV2, B[N], SMAC-2 ) - */ - - memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16); - if (pad_len > 16) { - /* N-1 blocks -- encrypted with SMAC-1 */ - osdp_encrypt(pd->sc.s_mac1, iv, buf, pad_len - 16); - /* N-1 th block is the IV for N th block */ - memcpy(iv, buf + pad_len - 32, 16); - } - - /* N-th Block encrypted with SMAC-2 == MAC */ - osdp_encrypt(pd->sc.s_mac2, iv, buf + pad_len - 16, 16); - memcpy(is_cmd ? pd->sc.c_mac : pd->sc.r_mac, buf + pad_len - 16, 16); - - return 0; -} - -void -osdp_sc_init(struct osdp_pd *pd) -{ - uint8_t key[16]; - - if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) { - memcpy(key, pd->sc.scbk, 16); - } - memset(&pd->sc, 0, sizeof(struct osdp_secure_channel)); - if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) { - memcpy(pd->sc.scbk, key, 16); - } - if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) { - pd->sc.pd_client_uid[0] = BYTE_0(pd->id.vendor_code); - pd->sc.pd_client_uid[1] = BYTE_1(pd->id.vendor_code); - pd->sc.pd_client_uid[2] = BYTE_0(pd->id.model); - pd->sc.pd_client_uid[3] = BYTE_1(pd->id.version); - pd->sc.pd_client_uid[4] = BYTE_0(pd->id.serial_number); - pd->sc.pd_client_uid[5] = BYTE_1(pd->id.serial_number); - pd->sc.pd_client_uid[6] = BYTE_2(pd->id.serial_number); - pd->sc.pd_client_uid[7] = BYTE_3(pd->id.serial_number); - } else { - osdp_get_rand(pd->sc.cp_random, 8); - } -} diff --git a/net/osdp/src/osdp_utils.c b/net/osdp/src/osdp_utils.c deleted file mode 100644 index 8db879f791..0000000000 --- a/net/osdp/src/osdp_utils.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2020 Siddharth Chandrasekaran - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include "osdp/osdp_utils.h" - -void -hexdump(const uint8_t *data, size_t len, const char *fmt, ...) -{ - size_t i; - va_list args; - char str[16 + 1] = {0}; - - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - printf(" [%zu] =>\n 0000 %02x ", len, data[0]); - str[0] = isprint(data[0]) ? data[0] : '.'; - for (i = 1; i < len; i++) { - if ((i & 0x0f) == 0) { - printf(" |%16s|", str); - printf("\n %04zu ", i); - } else if ((i & 0x07) == 0) { - printf(" "); - } - printf("%02x ", data[i]); - str[i & 0x0f] = isprint(data[i]) ? data[i] : '.'; - } - if ((i &= 0x0f) != 0) { - if (i <= 8) { - printf(" "); - } - while (i < 16) { - printf(" "); - str[i++] = ' '; - } - printf(" |%16s|", str); - } - printf("\n"); -} - -int -char2hex(char c, uint8_t *x) -{ - if (c >= '0' && c <= '9') { - *x = c - '0'; - } else if (c >= 'a' && c <= 'f') { - *x = c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - *x = c - 'A' + 10; - } else { - return -OS_EINVAL; - } - - return 0; -} - -size_t -hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen) -{ - uint8_t dec; - - if (buflen < hexlen / 2 + hexlen % 2) { - return 0; - } - - /* if hexlen is uneven, insert leading zero nibble */ - if (hexlen % 2) { - if (char2hex(hex[0], &dec) < 0) { - return 0; - } - buf[0] = dec; - hex++; - buf++; - } - - /* regular hex conversion */ - for (size_t i = 0; i < hexlen / 2; i++) { - if (char2hex(hex[2 * i], &dec) < 0) { - return 0; - } - buf[i] = dec << 4; - - if (char2hex(hex[2 * i + 1], &dec) < 0) { - return 0; - } - buf[i] += dec; - } - - return hexlen / 2 + hexlen % 2; -} - -char * -u16_to_str(uint16_t num, char * str) -{ - if (num == 0) { - str[0] = '0'; - str[1] = '\0'; - return str; - } - uint8_t i = 0, len = U16_STR_SZ - 1; - - /** - Start filling characters from the end of the buffer, - after accounting for null terminator - */ - while (num > 0) { - str[len - 1 - i] = (num % 10) + '0'; - num /= 10; - i++; - } - str[U16_STR_SZ - 1] = '\0'; - - /* Return start of converted string in the buffer */ - return &str[U16_STR_SZ - 1 - i]; -} diff --git a/net/osdp/syscfg.yml b/net/osdp/syscfg.yml index 33674a7267..fccede67fc 100644 --- a/net/osdp/syscfg.yml +++ b/net/osdp/syscfg.yml @@ -35,10 +35,6 @@ syscfg.defs: value: 50 description: 'Refresh interval factor for OSDP state update.' - OSDP_USE_CRYPTO_HOOK: - value: 0 - description: 'Override crypto functions.' - OSDP_SC_RETRY_WAIT_SEC: value: 600 description: 'Time in seconds to wait after a secure channel failure, and before @@ -295,3 +291,5 @@ syscfg.logs: level: MYNEWT_VAL(OSDP_LOG_LVL) syscfg.vals: + MBEDTLS_CIPHER_MODE_CBC: 1 + MBEDTLS_CTR_DRBG_C: 1