Skip to content

Commit

Permalink
file: Add support various flow control flags
Browse files Browse the repository at this point in the history
The FSTAT response indicate some flags about what the PD can accept
during a file transfer. LibOSDP was ignoring these so and that caused
PD to fail during file transfer. This patch adds support for those
flags.

Related-to: #192
Signed-off-by: Siddharth Chandrasekaran <[email protected]>
  • Loading branch information
sidcha committed Aug 15, 2024
1 parent f265072 commit 4225650
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 53 deletions.
4 changes: 3 additions & 1 deletion include/osdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,9 @@ void osdp_get_sc_status_mask(const osdp_t *ctx, uint8_t *bitmask);
* @param arg Opaque pointer that was provided in @ref osdp_file_ops when the
* ops struct was registered.
* @param file_id File ID of pre-agreed file between this CP and PD
* @param size Size of the file that was opened (filled by application)
* @param size Size of the file that was opened (to be populated by sender). In
* case of receiver, this value is just just input to indicate the incoming file
* size.
*
* @retval 0 on success
* @retval -1 on errors
Expand Down
2 changes: 1 addition & 1 deletion python/osdp/key_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def gen_key(key_len=16):
return bytes(key)

def _store_key(self, key):
with open(self.key_file(name), "w") as f:
with open(self.key_file(key), "w") as f:
f.write(key.hex())

def get_key(self, name):
Expand Down
12 changes: 9 additions & 3 deletions src/osdp_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@
#define LOG_NOT(...) __logger_log(&pd->logger, LOG_NOTICE, __FILE__, __LINE__, __VA_ARGS__)
#define LOG_DBG(...) __logger_log(&pd->logger, LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)

#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 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 SET_FLAG_V(p, f, v) if ((v)) SET_FLAG(p, f); else CLEAR_FLAG(p, f);

#define BYTE_0(x) (uint8_t)(((x) >> 0) & 0xFF)
#define BYTE_1(x) (uint8_t)(((x) >> 8) & 0xFF)
Expand Down Expand Up @@ -266,6 +267,11 @@ union osdp_ephemeral_data {
#define PD_FLAG_SC_DISABLED BIT(13) /* master_key=NULL && scbk=NULL */
#define PD_FLAG_PKT_BROADCAST BIT(14) /* this packet was addressed to 0x7F */

/* CP event requests; used with make_request() and check_request() */
#define CP_REQ_RESTART_SC 0x00000001
#define CP_REQ_EVENT_SEND 0x00000002
#define CP_REQ_OFFLINE 0x00000001

enum osdp_cp_phy_state_e {
OSDP_CP_PHY_STATE_IDLE,
OSDP_CP_PHY_STATE_SEND_CMD,
Expand Down
37 changes: 18 additions & 19 deletions src/osdp_cp.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@
#define REPLY_BUSY_DATA_LEN 0
#define REPLY_MFGREP_LEN 4 /* variable length command */

/* CP event requests */
#define CP_REQ_RESTART_SC 0x00000001
#define CP_REQ_EVENT_SEND 0x00000002

enum osdp_cp_error_e {
OSDP_CP_ERR_NONE = 0,
OSDP_CP_ERR_GENERIC = -1,
Expand Down Expand Up @@ -939,22 +935,22 @@ static const char *state_get_name(enum osdp_cp_state_e state)
static int cp_get_online_command(struct osdp_pd *pd)
{
struct osdp_cmd *cmd;
int ret;

if (cp_cmd_dequeue(pd, &cmd) == 0) {
return cp_translate_cmd(pd, cmd);
}

ret = osdp_file_tx_get_command(pd);
if (ret != 0) {
return ret;
}

if (osdp_millis_since(pd->tstamp) > OSDP_PD_POLL_TIMEOUT_MS) {
pd->tstamp = osdp_millis_now();
return CMD_POLL;
}

switch(osdp_get_file_tx_state(pd)) {
case OSDP_FILE_TX_STATE_PENDING: return CMD_FILETRANSFER;
case OSDP_FILE_TX_STATE_ERROR: return CMD_ABORT;
default: break;
}

return -1;
}

Expand Down Expand Up @@ -1194,12 +1190,6 @@ static enum osdp_cp_state_e get_next_err_state(struct osdp_pd *pd)

static inline enum osdp_cp_state_e get_next_state(struct osdp_pd *pd, int err)
{
if (pd->state == OSDP_CP_STATE_ONLINE &&
check_request(pd, CP_REQ_RESTART_SC)) {
osdp_phy_state_reset(pd, true);
return OSDP_CP_STATE_SC_CHLNG;
}

return (err == 0) ? get_next_ok_state(pd) : get_next_err_state(pd);
}

Expand Down Expand Up @@ -1318,9 +1308,18 @@ static int state_update(struct osdp_pd *pd)

next = get_next_state(pd, err);

if (next == OSDP_CP_STATE_ONLINE &&
check_request(pd, CP_REQ_EVENT_SEND)) {
do_event_callback(pd);
if (pd->state == OSDP_CP_STATE_ONLINE || next == OSDP_CP_STATE_ONLINE) {
if (check_request(pd, CP_REQ_RESTART_SC)) {
osdp_phy_state_reset(pd, true);
next = OSDP_CP_STATE_SC_CHLNG;
}
if (check_request(pd, CP_REQ_OFFLINE)) {
LOG_INF("Going offline due to request");
next = OSDP_CP_STATE_OFFLINE;
}
if (check_request(pd, CP_REQ_EVENT_SEND)) {
do_event_callback(pd);
}
}

if (cur != next) {
Expand Down
90 changes: 62 additions & 28 deletions src/osdp_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#define OSDP_FILE_TX_STATUS_ERR_UNKNOWN -2
#define OSDP_FILE_TX_STATUS_ERR_INVALID -3

#define OSDP_FILE_TX_FLAG_EXCLUSIVE 0x01000000
#define OSDP_FILE_TX_FLAG_PLAIN_TEXT 0x02000000
#define OSDP_FILE_TX_FLAG_POLL_RESP 0x04000000

static inline void file_state_reset(struct osdp_file *f)
{
f->flags = 0;
Expand Down Expand Up @@ -70,6 +74,10 @@ int osdp_file_cmd_tx_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
goto reply_abort;
}

if (ISSET_FLAG(f, OSDP_FILE_TX_FLAG_PLAIN_TEXT)) {
LOG_WRN("TX_Build: Ignoring plaintext file transfer request");
}

if (f->state == OSDP_FILE_KEEP_ALIVE) {
LOG_DBG("TX_Build: keep-alive");
write_file_tx_header(f, buf);
Expand Down Expand Up @@ -132,28 +140,26 @@ int osdp_file_cmd_stat_decode(struct osdp_pd *pd, uint8_t *buf, int len)
return -1;
}

/* Collect struct osdp_cmd_file_stat */
BYTES_TO_U8_LE(buf, pos, stat.control);
BYTES_TO_U16_LE(buf, pos, stat.delay);
BYTES_TO_U16_LE(buf, pos, stat.status);
BYTES_TO_U16_LE(buf, pos, stat.rx_size);
assert(pos == len);
assert(f->offset + f->length <= f->size);

if (stat.status != OSDP_FILE_TX_STATUS_ACK &&
stat.status != OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED &&
stat.status != OSDP_FILE_TX_STATUS_PD_RESET &&
stat.status != OSDP_FILE_TX_STATUS_KEEP_ALIVE) {
LOG_ERR("Stat_Decode: File transfer error; "
"status:%d offset:%d", stat.status, f->offset);
return -1;
}
/* Collect control flags */
SET_FLAG_V(f, OSDP_FILE_TX_FLAG_EXCLUSIVE, stat.control & 0x01)
SET_FLAG_V(f, OSDP_FILE_TX_FLAG_PLAIN_TEXT, stat.control & 0x02)
SET_FLAG_V(f, OSDP_FILE_TX_FLAG_POLL_RESP, stat.control & 0x04)

f->offset += f->length;
do_close = f->length && (f->offset == f->size);
f->wait_time_ms = stat.delay;
f->tstamp = osdp_millis_now();
f->length = 0;
f->errors = 0;

if (f->offset != f->size) {
/* Transfer is in progress */
return 0;
Expand All @@ -165,14 +171,24 @@ int osdp_file_cmd_stat_decode(struct osdp_pd *pd, uint8_t *buf, int len)
LOG_ERR("Stat_Decode: Close failed! ... continuing");
}

if (stat.status == OSDP_FILE_TX_STATUS_KEEP_ALIVE) {
switch (stat.status) {
case OSDP_FILE_TX_STATUS_KEEP_ALIVE:
f->state = OSDP_FILE_KEEP_ALIVE;
LOG_INF("Stat_Decode: File transfer done; keep alive");
} else {
return 0;
case OSDP_FILE_TX_STATUS_PD_RESET:
make_request(pd, CP_REQ_OFFLINE);
__fallthrough;
case OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED:
f->state = OSDP_FILE_DONE;
LOG_INF("Stat_Decode: File transfer complete");
return 0;
default:
LOG_ERR("Stat_Decode: File transfer error; "
"status:%d offset:%d", stat.status, f->offset);
f->errors++;
return -1;
}
return 0;
}

/* --- Receiver CMD/RESP Handler --- */
Expand Down Expand Up @@ -225,10 +241,10 @@ int osdp_file_cmd_tx_decode(struct osdp_pd *pd, uint8_t *buf, int len)
return -1;
}

LOG_INF("TX_Decode: Starting file transfer");
LOG_INF("TX_Decode: Starting file transfer of size: %d", xfer.size);
file_state_reset(f);
f->file_id = xfer.type;
f->size = size;
f->size = xfer.size;
f->state = OSDP_FILE_INPROG;
}

Expand All @@ -250,8 +266,12 @@ int osdp_file_cmd_tx_decode(struct osdp_pd *pd, uint8_t *buf, int len)

int osdp_file_cmd_stat_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
{
int len = 0, status = 0;
int len = 0;
struct osdp_file *f = TO_FILE(pd);
struct osdp_cmd_file_stat stat = {
.status = OSDP_FILE_TX_STATUS_ACK,
.control = 0x01, /* interleaving, secure channel, no activity */
};

if (f == NULL) {
LOG_ERR("Stat_Build: File ops not registered!");
Expand All @@ -272,26 +292,27 @@ int osdp_file_cmd_stat_build(struct osdp_pd *pd, uint8_t *buf, int max_len)
if (f->length > 0) {
f->offset += f->length;
} else {
status = -1;
stat.status = OSDP_FILE_TX_STATUS_ERR_INVALID;
}
LOG_DBG("length: %d offset: %d size: %d", f->length, f->offset, f->size);
f->length = 0;

assert(f->offset <= f->size);
if (f->offset == f->size) { /* EOF */
if (f->ops.close(f->ops.arg) < 0) {
LOG_ERR("Stat_Build: Close failed!");
return -1;
}
f->state = OSDP_FILE_DONE;
stat.status = OSDP_FILE_TX_STATUS_CONTENTS_PROCESSED;
LOG_INF("TX_Decode: File receive complete");
}

/* fill the packet buffer (layout: struct osdp_cmd_file_stat) */

U8_TO_BYTES_LE(0, buf, len); /* control */
U16_TO_BYTES_LE(0, buf, len); /* delay */
U16_TO_BYTES_LE(status, buf, len);
U16_TO_BYTES_LE(0, buf, len); /* rx_size */
U8_TO_BYTES_LE(stat.control, buf, len);
U16_TO_BYTES_LE(stat.delay, buf, len);
U16_TO_BYTES_LE(stat.status, buf, len);
U16_TO_BYTES_LE(stat.rx_size, buf, len);
assert(len == FILE_TRANSFER_STAT_SIZE);

return len;
Expand All @@ -309,25 +330,38 @@ void osdp_file_tx_abort(struct osdp_pd *pd)
}
}

int osdp_get_file_tx_state(struct osdp_pd *pd)
/**
* @brief Return the next command that the CP should send to the PD.
*
* @param pd PD context
* @retval +ve - Send this OSDP command
* @retval -1 - don't send any command, wait for me
* @retval 0 - nothing to send; let some other module decide
*/
int osdp_file_tx_get_command(struct osdp_pd *pd)
{
struct osdp_file *f = TO_FILE(pd);

if (!f || f->state == OSDP_FILE_IDLE || f->state == OSDP_FILE_DONE) {
return OSDP_FILE_TX_STATE_IDLE;
}

if (osdp_millis_since(f->tstamp) < f->wait_time_ms) {
return OSDP_FILE_TX_STATE_WAIT;
return 0;
}

if (f->errors > OSDP_FILE_ERROR_RETRY_MAX || f->cancel_req) {
LOG_ERR("Aborting transfer of file fd:%d", f->file_id);
osdp_file_tx_abort(pd);
return OSDP_FILE_TX_STATE_ERROR;
return CMD_ABORT;
}

if (f->wait_time_ms &&
osdp_millis_since(f->tstamp) < f->wait_time_ms) {
return ISSET_FLAG(f, OSDP_FILE_TX_FLAG_EXCLUSIVE) ? -1 : 0;
}

if (ISSET_FLAG(f, OSDP_FILE_TX_FLAG_POLL_RESP)) {
return CMD_POLL;
}

return OSDP_FILE_TX_STATE_PENDING;
return CMD_FILETRANSFER;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/osdp_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ int osdp_file_cmd_tx_decode(struct osdp_pd *pd, uint8_t *buf, int len);
int osdp_file_cmd_stat_decode(struct osdp_pd *pd, uint8_t *buf, int len);
int osdp_file_cmd_stat_build(struct osdp_pd *pd, uint8_t *buf, int max_len);
int osdp_file_tx_command(struct osdp_pd *pd, int file_id, uint32_t flags);
int osdp_get_file_tx_state(struct osdp_pd *pd);
int osdp_file_tx_get_command(struct osdp_pd *pd);
void osdp_file_tx_abort(struct osdp_pd *pd);

#endif /* _OSDP_FILE_H_ */

0 comments on commit 4225650

Please sign in to comment.