@@ -67,7 +67,7 @@ static void send_pub_status(struct mesh_node *node, uint16_t net_idx,
}
mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
- msg, n);
+ false, msg, n);
}
static bool config_pub_get(struct mesh_node *node, uint16_t net_idx,
@@ -211,8 +211,8 @@ static void send_sub_status(struct mesh_node *node, uint16_t net_idx,
n += 2;
}
- mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx,
- DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
+ false, msg, n);
}
static bool config_sub_get(struct mesh_node *node, uint16_t net_idx,
@@ -272,7 +272,7 @@ static bool config_sub_get(struct mesh_node *node, uint16_t net_idx,
*msg_status = (uint8_t) status;
mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
- msg, n);
+ false, msg, n);
return true;
}
@@ -450,7 +450,7 @@ static void send_model_app_status(struct mesh_node *node, uint16_t net_idx,
n += 2;
mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
- msg, n);
+ false, msg, n);
}
static void model_app_list(struct mesh_node *node, uint16_t net_idx,
@@ -505,7 +505,7 @@ static void model_app_list(struct mesh_node *node, uint16_t net_idx,
if (result >= 0) {
*status = result;
mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx,
- DEFAULT_TTL, msg, n);
+ DEFAULT_TTL, false, msg, n);
}
l_free(msg);
@@ -1234,7 +1234,7 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx,
if (n)
mesh_model_send(node, dst, src,
- APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL,
+ APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, false,
long_msg ? long_msg : msg, n);
l_free(long_msg);
@@ -540,7 +540,7 @@ static void cmplt(uint16_t remote, uint8_t status,
static bool msg_send(struct mesh_node *node, bool credential, uint16_t src,
uint32_t dst, uint16_t app_idx, uint16_t net_idx,
- uint8_t *label, uint8_t ttl,
+ uint8_t *label, uint8_t ttl, bool segmented,
const void *msg, uint16_t msg_len)
{
uint8_t dev_key[16];
@@ -597,8 +597,8 @@ static bool msg_send(struct mesh_node *node, bool credential, uint16_t src,
/* print_packet("Encrypted with", key, 16); */
ret = mesh_net_app_send(net, credential, src, dst, key_aid, net_idx,
- ttl, seq_num, iv_index, szmic, out,
- out_len, cmplt, NULL);
+ ttl, seq_num, iv_index, segmented,
+ szmic, out, out_len, cmplt, NULL);
done:
l_free(out);
return ret;
@@ -1098,14 +1098,14 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
result = msg_send(node, mod->pub->credential != 0, src,
mod->pub->addr, mod->pub->idx, net_idx,
- label, ttl, msg, msg_len);
+ label, ttl, false, msg, msg_len);
return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED;
}
bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
uint16_t app_idx, uint16_t net_idx,
- uint8_t ttl,
+ uint8_t ttl, bool segmented,
const void *msg, uint16_t msg_len)
{
/* print_packet("Mod Tx", msg, msg_len); */
@@ -1120,7 +1120,7 @@ bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
return false;
return msg_send(node, false, src, dst, app_idx, net_idx,
- NULL, ttl, msg, msg_len);
+ NULL, ttl, segmented, msg, msg_len);
}
int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
@@ -95,7 +95,7 @@ int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id,
uint16_t mesh_model_cfg_blk(uint8_t *pkt);
bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst,
uint16_t app_idx, uint16_t net_idx,
- uint8_t ttl,
+ uint8_t ttl, bool segmented,
const void *msg, uint16_t msg_len);
int mesh_model_publish(struct mesh_node *node, uint32_t mod_id, uint16_t src,
uint8_t ttl, const void *msg, uint16_t msg_len);
@@ -139,6 +139,7 @@ struct mesh_net {
struct l_queue *replay_cache;
struct l_queue *sar_in;
struct l_queue *sar_out;
+ struct l_queue *sar_queue;
struct l_queue *frnd_msgs;
struct l_queue *friends;
struct l_queue *negotiations;
@@ -182,6 +183,7 @@ struct mesh_sar {
uint16_t remote;
uint16_t len;
bool szmic;
+ bool segmented;
bool frnd;
bool frnd_cred;
uint8_t ttl;
@@ -662,6 +664,7 @@ struct mesh_net *mesh_net_new(struct mesh_node *node)
net->msg_cache = l_queue_new();
net->sar_in = l_queue_new();
net->sar_out = l_queue_new();
+ net->sar_queue = l_queue_new();
net->frnd_msgs = l_queue_new();
net->destinations = l_queue_new();
net->app_keys = l_queue_new();
@@ -687,6 +690,7 @@ void mesh_net_free(struct mesh_net *net)
l_queue_destroy(net->replay_cache, l_free);
l_queue_destroy(net->sar_in, mesh_sar_free);
l_queue_destroy(net->sar_out, mesh_sar_free);
+ l_queue_destroy(net->sar_queue, mesh_sar_free);
l_queue_destroy(net->frnd_msgs, l_free);
l_queue_destroy(net->friends, mesh_friend_free);
l_queue_destroy(net->negotiations, mesh_friend_free);
@@ -1657,6 +1661,22 @@ static void outmsg_to(struct l_timeout *msg_timeout, void *user_data)
}
static void outseg_to(struct l_timeout *seg_timeout, void *user_data);
+
+static void send_queued_sar(struct mesh_net *net, uint16_t dst)
+{
+ struct mesh_sar *sar = l_queue_remove_if(net->sar_queue,
+ match_sar_remote, L_UINT_TO_PTR(dst));
+
+ if (!sar)
+ return;
+
+ /* Out to current outgoing, and immediate expire Seg TO */
+ l_queue_push_head(net->sar_out, sar);
+ sar->seg_timeout = NULL;
+ sar->msg_timeout = l_timeout_create(MSG_TO, outmsg_to, net, NULL);
+ outseg_to(NULL, net);
+}
+
static void ack_received(struct mesh_net *net, bool timeout,
uint16_t src, uint16_t dst,
uint16_t seq0, uint32_t ack_flag)
@@ -1692,6 +1712,7 @@ static void ack_received(struct mesh_net *net, bool timeout,
outgoing->len - 4, outgoing->user_data);
l_queue_remove(net->sar_out, outgoing);
+ send_queued_sar(net, outgoing->remote);
mesh_sar_free(outgoing);
return;
@@ -1701,10 +1722,10 @@ static void ack_received(struct mesh_net *net, bool timeout,
ack_copy &= outgoing->flags;
- for (i = 0; i <= SEG_MAX(outgoing->len); i++, seg_flag <<= 1) {
+ for (i = 0; i <= SEG_MAX(true, outgoing->len); i++, seg_flag <<= 1) {
if (seg_flag & ack_flag) {
l_debug("Skipping Seg %d of %d",
- i, SEG_MAX(outgoing->len));
+ i, SEG_MAX(true, outgoing->len));
continue;
}
@@ -1741,7 +1762,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index,
uint8_t ttl, uint32_t seq,
uint16_t net_idx,
uint16_t src, uint16_t dst,
- uint8_t key_aid,
+ uint8_t key_aid, bool segmented,
bool szmic, uint16_t seqZero,
const uint8_t *data, uint16_t size)
{
@@ -1768,7 +1789,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index,
hdr |= true << SEG_HDR_SHIFT;
hdr |= szmic << SZMIC_HDR_SHIFT;
hdr |= (seqZero & SEQ_ZERO_MASK) << SEQ_ZERO_HDR_SHIFT;
- hdr |= SEG_MAX(size) << SEGN_HDR_SHIFT;
+ hdr |= SEG_MAX(true, size) << SEGN_HDR_SHIFT;
}
if (friend_packet_queue(net, iv_index, false, frnd_ttl,
@@ -1967,7 +1988,7 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index,
l_info("RXed (old: %04x %06x size:%d) %d of %d",
seqZero, seq, size, segO, segN);
/* Sanity Check--> certain things must match */
- if (SEG_MAX(sar_in->len) != segN ||
+ if (SEG_MAX(true, sar_in->len) != segN ||
sar_in->key_aid != key_aid)
return false;
@@ -2022,8 +2043,8 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index,
msg_rxed(net, frnd, iv_index, ttl, seq, net_idx,
sar_in->remote, dst,
- key_aid,
- szmic, sar_in->seqZero,
+ key_aid, true, szmic,
+ sar_in->seqZero,
sar_in->buf, sar_in->len);
/* Kill Inter-Seg timeout */
@@ -2426,7 +2447,8 @@ static enum _relay_advice packet_received(void *user_data,
net_idx,
net_src, net_dst,
net_key_id,
- false, net_seq & SEQ_ZERO_MASK,
+ false, false,
+ net_seq & SEQ_ZERO_MASK,
msg, app_msg_len);
}
@@ -2539,7 +2561,8 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
switch (net->iv_upd_state) {
case IV_UPD_UPDATING:
- if (l_queue_length(net->sar_out)) {
+ if (l_queue_length(net->sar_out) ||
+ l_queue_length(net->sar_queue)) {
l_info("don't leave IV Update until sar_out empty");
l_timeout_modify(net->iv_update_timeout, 10);
break;
@@ -3043,12 +3066,12 @@ static bool send_seg(struct mesh_net *net, struct mesh_sar *msg, uint8_t segO)
uint8_t gatt_data[30];
uint8_t *packet = gatt_data;
uint8_t packet_len;
- uint8_t segN = SEG_MAX(msg->len);
+ uint8_t segN = SEG_MAX(msg->segmented, msg->len);
uint16_t seg_off = SEG_OFF(segO);
uint32_t key_id = 0;
uint32_t seq_num;
- if (segN) {
+ if (msg->segmented) {
/* Send each segment on unique seq_num */
seq_num = mesh_net_next_seq_num(net);
@@ -3075,7 +3098,7 @@ static bool send_seg(struct mesh_net *net, struct mesh_sar *msg, uint8_t segO)
seq_num,
msg->src, msg->remote,
0,
- segN ? true : false, msg->key_aid,
+ msg->segmented, msg->key_aid,
msg->szmic, false, msg->seqZero,
segO, segN,
msg->buf + seg_off, seg_len,
@@ -3169,7 +3192,8 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id,
bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
uint16_t dst, uint8_t key_aid, uint16_t net_idx,
uint8_t ttl, uint32_t seq, uint32_t iv_index,
- bool szmic, const void *msg, uint16_t msg_len,
+ bool segmented, bool szmic,
+ const void *msg, uint16_t msg_len,
mesh_net_status_func_t status_func,
void *user_data)
{
@@ -3189,14 +3213,17 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
if (ttl == DEFAULT_TTL)
ttl = net->default_ttl;
- seg_max = SEG_MAX(msg_len);
+ /* Long and sizmic messages *require* segmenting */
+ segmented |= szmic;
+ seg_max = SEG_MAX(segmented, msg_len);
+ segmented |= !!(seg_max);
/* First enqueue to any Friends and internal models */
result = msg_rxed(net, false, iv_index, ttl,
seq,
net_idx,
src, dst,
- key_aid,
+ key_aid, segmented,
szmic, seq & SEQ_ZERO_MASK,
msg, msg_len);
@@ -3207,13 +3234,6 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
(dst >= net->src_addr && dst <= net->last_addr))
return true;
- /* If Segmented, Cancel any OB segmented message to same DST */
- if (seg_max) {
- payload = l_queue_remove_if(net->sar_out, match_sar_remote,
- L_UINT_TO_PTR(dst));
- mesh_sar_free(payload);
- }
-
/* Setup OTA Network send */
payload = mesh_sar_new(msg_len);
memcpy(payload->buf, msg, msg_len);
@@ -3224,16 +3244,30 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
payload->szmic = szmic;
payload->frnd_cred = frnd_cred;
payload->key_aid = key_aid;
- if (seg_max) {
+ payload->iv_index = mesh_net_get_iv_index(net);
+ payload->seqAuth = seq;
+ payload->segmented = segmented;
+ if (segmented) {
payload->flags = 0xffffffff >> (31 - seg_max);
payload->seqZero = seq & SEQ_ZERO_MASK;
- }
+ payload->status_func = status_func;
+ payload->user_data = user_data;
+ payload->id = ++net->sar_id_next;
- payload->iv_index = mesh_net_get_iv_index(net);
- payload->seqAuth = seq;
+ /* Single thread SAR messages to same Unicast DST */
+ if (NULL != l_queue_find(net->sar_out, match_sar_remote,
+ L_UINT_TO_PTR(dst))) {
+ /* Delay sending Outbound SAR unless prior
+ * SAR to same DST has completed */
+
+ l_info("OB-Queued SeqZero: %4.4x", payload->seqZero);
+ l_queue_push_tail(net->sar_queue, payload);
+ return true;
+ }
+ }
result = true;
- if (!IS_UNICAST(dst) && seg_max) {
+ if (!IS_UNICAST(dst) && segmented) {
int i;
for (i = 0; i < 4; i++) {
@@ -3246,7 +3280,7 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
}
/* Reliable: Cache; Unreliable: Flush*/
- if (result && seg_max && IS_UNICAST(dst)) {
+ if (result && segmented && IS_UNICAST(dst)) {
l_queue_push_head(net->sar_out, payload);
payload->seg_timeout =
l_timeout_create(SEG_TO, outseg_to, net, NULL);
@@ -40,8 +40,9 @@ struct mesh_node;
#define MAX_UNSEG_LEN 15 /* msg_len == 11 + sizeof(MIC) */
#define MAX_SEG_LEN 12 /* UnSeg length - 3 octets overhead */
-#define SEG_MAX(len) (((len) <= MAX_UNSEG_LEN) ? 0 : \
+#define SEG_MAX(seg, len) ((!seg && len <= MAX_UNSEG_LEN) ? 0 : \
(((len) - 1) / MAX_SEG_LEN))
+
#define SEG_OFF(seg) ((seg) * MAX_SEG_LEN)
#define MAX_SEG_TO_LEN(seg) ((seg) ? SEG_OFF((seg) + 1) : MAX_UNSEG_LEN)
@@ -311,7 +312,8 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id,
bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
uint16_t dst, uint8_t key_id, uint16_t net_idx,
uint8_t ttl, uint32_t seq, uint32_t iv_index,
- bool szmic, const void *msg, uint16_t msg_len,
+ bool segmented, bool szmic,
+ const void *msg, uint16_t msg_len,
mesh_net_status_func_t status_func,
void *user_data);
void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id,
@@ -1830,7 +1830,7 @@ static struct l_dbus_message *send_call(struct l_dbus *dbus,
return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
"Invalid key_index");
- if (!mesh_model_send(node, src, dst, app_idx, 0, DEFAULT_TTL,
+ if (!mesh_model_send(node, src, dst, app_idx, 0, DEFAULT_TTL, false,
data, len))
return dbus_error(msg, MESH_ERROR_FAILED, NULL);
@@ -1879,7 +1879,7 @@ static struct l_dbus_message *dev_key_send_call(struct l_dbus *dbus,
app_idx = remote ? APP_IDX_DEV_REMOTE : APP_IDX_DEV_LOCAL;
if (!mesh_model_send(node, src, dst, app_idx, net_idx, DEFAULT_TTL,
- data, len))
+ false, data, len))
return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL);
return l_dbus_message_new_method_return(msg);
@@ -1937,7 +1937,7 @@ static struct l_dbus_message *add_netkey_call(struct l_dbus *dbus,
l_put_le16(sub_idx, &data[2]);
if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE, net_idx,
- DEFAULT_TTL, data, 20))
+ DEFAULT_TTL, false, data, 20))
return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL);
return l_dbus_message_new_method_return(msg);
@@ -2003,7 +2003,7 @@ static struct l_dbus_message *add_appkey_call(struct l_dbus *dbus,
data[3] = app_idx >> 4;
if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE, net_idx,
- DEFAULT_TTL, data, 20))
+ DEFAULT_TTL, false, data, 20))
return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL);
return l_dbus_message_new_method_return(msg);
@@ -1017,7 +1017,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
app_msg = l_util_from_hexstring(keys->app_msg, &app_msg_len);
if (keys->szmic) {
- seg_max = SEG_MAX(app_msg_len + 8);
+ seg_max = SEG_MAX(keys->segmented, app_msg_len + 8);
enc_msg = l_malloc(app_msg_len + 8);
mesh_crypto_application_encrypt(key_aid, keys->app_seq,
keys->net_src, keys->net_dst,
@@ -1028,7 +1028,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys)
enc_msg, &app_mic64, sizeof(app_mic64));
l_put_be64(app_mic64, enc_msg + app_msg_len);
} else {
- seg_max = SEG_MAX(app_msg_len + 4);
+ seg_max = SEG_MAX(keys->segmented, app_msg_len + 4);
enc_msg = l_malloc(app_msg_len + 4);
mesh_crypto_application_encrypt(key_aid, keys->app_seq,
keys->net_src, keys->net_dst,