#define BEACON_TYPE_UNPROVISIONED 0x00
+struct deferred_cmd {
+ uint16_t len;
+ uint8_t cmd[];
+};
+
static const uint8_t pkt_filter = MESH_AD_TYPE_PROVISION;
static const uint8_t bec_filter[] = {MESH_AD_TYPE_BEACON,
BEACON_TYPE_UNPROVISIONED};
-enum acp_state {
- ACP_PROV_IDLE = 0,
- ACP_PROV_CAPS_SENT,
- ACP_PROV_CAPS_ACKED,
- ACP_PROV_KEY_SENT,
- ACP_PROV_KEY_ACKED,
- ACP_PROV_INP_CMPLT_SENT,
- ACP_PROV_INP_CMPLT_ACKED,
- ACP_PROV_CONF_SENT,
- ACP_PROV_CONF_ACKED,
- ACP_PROV_RAND_SENT,
- ACP_PROV_RAND_ACKED,
- ACP_PROV_CMPLT_SENT,
- ACP_PROV_FAIL_SENT,
-};
-
#define MAT_REMOTE_PUBLIC 0x01
#define MAT_LOCAL_PRIVATE 0x02
#define MAT_RAND_AUTH 0x04
struct mesh_prov_acceptor {
mesh_prov_acceptor_complete_func_t cmplt;
prov_trans_tx_t trans_tx;
+ struct l_queue *ob;
void *agent;
void *caller_data;
void *trans_data;
struct l_timeout *timeout;
uint32_t to_secs;
- enum acp_state state;
+ uint8_t out_opcode;
uint8_t transport;
uint8_t material;
uint8_t expected;
return;
l_timeout_remove(prov->timeout);
+ l_queue_destroy(prov->ob, l_free);
mesh_send_cancel(bec_filter, sizeof(bec_filter));
mesh_send_cancel(&pkt_filter, sizeof(pkt_filter));
acceptor_free();
}
+static void prov_send(struct mesh_prov_acceptor *prov, void *cmd, uint16_t len)
+{
+ struct deferred_cmd *defer;
+
+ if (prov->out_opcode == PROV_NONE) {
+ prov->out_opcode = *(uint8_t *) cmd;
+ prov->trans_tx(prov->trans_data, cmd, len);
+ } else {
+ defer = l_malloc(len + sizeof(struct deferred_cmd));
+ defer->len = len;
+ memcpy(defer->cmd, cmd, len);
+ l_queue_push_tail(prov->ob, defer);
+ }
+}
+
static void prov_to(struct l_timeout *timeout, void *user_data)
{
struct mesh_prov_acceptor *rx_prov = user_data;
if (prov->cmplt && prov->trans_tx) {
prov->cmplt(prov->caller_data, PROV_ERR_TIMEOUT, NULL);
prov->cmplt = NULL;
- prov->trans_tx(prov->trans_data, fail_code, 2);
+ prov_send(prov, fail_code, 2);
prov->timeout = l_timeout_create(1, prov_to, prov, NULL);
return;
}
if (err) {
msg.opcode = PROV_FAILED;
msg.reason = PROV_ERR_UNEXPECTED_ERR;
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
return;
}
l_put_be32(number, prov->rand_auth_workspace + 44);
prov->material |= MAT_RAND_AUTH;
msg.opcode = PROV_INP_CMPLT;
- prov->trans_tx(prov->trans_data, &msg.opcode, 1);
+ prov_send(prov, &msg.opcode, 1);
}
static void static_cb(void *user_data, int err, uint8_t *key, uint32_t len)
if (err || !key || len != 16) {
msg.opcode = PROV_FAILED;
msg.reason = PROV_ERR_UNEXPECTED_ERR;
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
return;
}
if (prov->conf_inputs.start.auth_action == PROV_ACTION_IN_ALPHA) {
msg.opcode = PROV_INP_CMPLT;
- prov->trans_tx(prov->trans_data, &msg.opcode, 1);
+ prov_send(prov, &msg.opcode, 1);
}
}
if (err || !key || len != 32) {
msg.opcode = PROV_FAILED;
msg.reason = PROV_ERR_UNEXPECTED_ERR;
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
return;
}
if (!acp_credentials(prov)) {
msg.opcode = PROV_FAILED;
msg.reason = PROV_ERR_UNEXPECTED_ERR;
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
}
}
}
memcpy(&msg.caps, &prov->conf_inputs.caps,
sizeof(prov->conf_inputs.caps));
- prov->state = ACP_PROV_CAPS_SENT;
prov->expected = PROV_START;
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
}
static void send_pub_key(struct mesh_prov_acceptor *prov)
msg.opcode = PROV_PUB_KEY;
memcpy(msg.pub_key, prov->conf_inputs.dev_pub_key, sizeof(msg.pub_key));
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
}
static bool send_conf(struct mesh_prov_acceptor *prov)
if (!memcmp(msg.conf, prov->confirm, sizeof(msg.conf)))
return false;
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
return true;
}
msg.opcode = PROV_RANDOM;
memcpy(msg.rand, prov->rand_auth_workspace, sizeof(msg.rand));
- prov->trans_tx(prov->trans_data, &msg, sizeof(msg));
+ prov_send(prov, &msg, sizeof(msg));
}
static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
if (result) {
prov->rand_auth_workspace[0] = PROV_COMPLETE;
- prov->trans_tx(prov->trans_data,
- prov->rand_auth_workspace, 1);
+ prov_send(prov, prov->rand_auth_workspace, 1);
goto cleanup;
} else {
fail.reason = PROV_ERR_UNEXPECTED_ERR;
failure:
fail.opcode = PROV_FAILED;
- prov->trans_tx(prov->trans_data, &fail, sizeof(fail));
+ prov_send(prov, &fail, sizeof(fail));
if (prov->cmplt)
prov->cmplt(prov->caller_data, fail.reason, NULL);
prov->cmplt = NULL;
static void acp_prov_ack(void *user_data, uint8_t msg_num)
{
- /* TODO: Handle PB-ADV Ack */
+ struct mesh_prov_acceptor *rx_prov = user_data;
+ struct deferred_cmd *deferred;
+
+ if (rx_prov != prov)
+ return;
+
+ if (prov->out_opcode == PROV_NONE)
+ return;
+
+ prov->out_opcode = PROV_NONE;
+
+ deferred = l_queue_pop_head(prov->ob);
+ if (!deferred)
+ return;
+
+ prov_send(prov, deferred->cmd, deferred->len);
+ l_free(deferred);
}
prov->to_secs = timeout;
prov->agent = agent;
prov->cmplt = complete_cb;
+ prov->ob = l_queue_new();
prov->previous = -1;
+ prov->out_opcode = PROV_NONE;
prov->caller_data = caller_data;
caps = mesh_agent_get_caps(agent);