mesh: use only segments in mesh_upper_transport_pdu_t, use mesh_upper_transport_pdu for unsegmented access

This commit is contained in:
Matthias Ringwald 2020-03-25 14:49:45 +01:00
parent 242605fa4f
commit 1b51af657a
3 changed files with 89 additions and 45 deletions

View File

@ -221,10 +221,7 @@ typedef struct {
uint16_t flags;
// payload, single segmented or list of them
uint16_t len;
union {
btstack_linked_list_t segments;
struct mesh_network_pdu * segment;
} payload;
// access acknowledged message
uint16_t retransmit_count;

View File

@ -92,7 +92,8 @@ static mesh_control_pdu_t * incoming_control_pdu;
static mesh_segmented_pdu_t outgoing_segmented_message_singleton;
static mesh_access_pdu_t * outgoing_segmented_access_pdu;
static mesh_unsegmented_pdu_t outgoing_unsegmented_pdu;
static mesh_unsegmented_pdu_t outgoing_unsegmented_pdu_singleton;
static mesh_upper_transport_pdu_t * outgoing_upper_transport_pdu;
static uint8_t application_nonce[13];
static btstack_crypto_ccm_t ccm;
@ -118,6 +119,7 @@ void mesh_upper_transport_send_access_pdu(mesh_pdu_t *pdu){
case MESH_PDU_TYPE_UNSEGMENTED:
case MESH_PDU_TYPE_ACCESS:
case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
break;
default:
btstack_assert(false);
@ -238,7 +240,7 @@ static void mesh_segmented_pdu_flatten(btstack_linked_list_t * segments, uint8_t
static uint16_t mesh_upper_pdu_flatten(mesh_upper_transport_pdu_t * upper_pdu, uint8_t * buffer, uint16_t buffer_len) {
// assemble payload
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &upper_pdu->payload.segments);
btstack_linked_list_iterator_init(&it, &upper_pdu->segments);
uint16_t offset = 0;
while (btstack_linked_list_iterator_has_next(&it)) {
mesh_network_pdu_t *segment = (mesh_network_pdu_t *) btstack_linked_list_iterator_next(&it);
@ -338,6 +340,7 @@ static void transport_segmented_setup_nonce(uint8_t * nonce, const mesh_pdu_t *
big_endian_store_32(nonce, 9, iv_index_for_ivi_nid(access_pdu->network_header[0]));
break;
case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
upper_pdu = (mesh_upper_transport_pdu_t *) pdu;
nonce[1] = upper_pdu->transmic_len == 8 ? 0x80 : 0x00;
// 'network header'
@ -717,7 +720,7 @@ static uint8_t mesh_upper_transport_setup_segmented_access_pdu_header(mesh_acces
return 0;
}
static uint8_t mesh_upper_transport_setup_upper_segmented_access_pdu_header(mesh_upper_transport_pdu_t * upper_pdu, uint16_t netkey_index,
static uint8_t mesh_upper_transport_setup_upper_access_pdu_header(mesh_upper_transport_pdu_t * upper_pdu, uint16_t netkey_index,
uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest, uint8_t szmic){
// get app or device key
@ -762,14 +765,15 @@ static uint8_t mesh_upper_transport_setup_segmented_access_pdu(mesh_access_pdu_t
return 0;
}
static uint8_t mesh_upper_transport_setup_upper_segmented_access_pdu(mesh_upper_transport_pdu_t * upper_pdu, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest,
static uint8_t mesh_upper_transport_setup_upper_access_pdu(mesh_upper_transport_pdu_t * upper_pdu, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl, uint16_t src, uint16_t dest,
uint8_t szmic, const uint8_t * access_pdu_data, uint8_t access_pdu_len){
int status = mesh_upper_transport_setup_upper_segmented_access_pdu_header(upper_pdu, netkey_index, appkey_index, ttl, src, dest, szmic);
int status = mesh_upper_transport_setup_upper_access_pdu_header(upper_pdu, netkey_index, appkey_index, ttl, src,
dest, szmic);
if (status) return status;
// store in transport pdu
uint16_t offset = 0;
mesh_segmented_append_payload(access_pdu_data, access_pdu_len, &upper_pdu->payload.segments);
mesh_segmented_append_payload(access_pdu_data, access_pdu_len, &upper_pdu->segments);
upper_pdu->len = access_pdu_len;
return 0;
}
@ -797,7 +801,10 @@ uint8_t mesh_upper_transport_setup_access_pdu(mesh_pdu_t * pdu, uint16_t netkey_
case MESH_PDU_TYPE_ACCESS:
return mesh_upper_transport_setup_segmented_access_pdu((mesh_access_pdu_t *) pdu, netkey_index, appkey_index, ttl, src, dest, szmic, access_pdu_data, access_pdu_len);
case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
return mesh_upper_transport_setup_upper_segmented_access_pdu((mesh_upper_transport_pdu_t *) pdu, netkey_index, appkey_index, ttl, src, dest, szmic, access_pdu_data, access_pdu_len);
case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
return mesh_upper_transport_setup_upper_access_pdu((mesh_upper_transport_pdu_t *) pdu, netkey_index,
appkey_index, ttl, src, dest, szmic, access_pdu_data,
access_pdu_len);
default:
btstack_assert(false);
return 1;
@ -977,7 +984,7 @@ static void mesh_upper_transport_send_segmented_access_pdu(mesh_access_pdu_t * a
static void mesh_upper_transport_send_upper_segmented_pdu(mesh_upper_transport_pdu_t * upper_pdu){
// TODO: store upper pdu in outgoing pdus active or similar
// outgoing_segmented_access_pdu = upper_pdu;
outgoing_upper_transport_pdu = upper_pdu;
mesh_segmented_pdu_t * message_pdu = &outgoing_segmented_message_singleton;
message_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_SEGMENTED;
@ -1004,6 +1011,37 @@ static void mesh_upper_transport_send_upper_segmented_pdu(mesh_upper_transport_p
mesh_lower_transport_send_pdu((mesh_pdu_t*) message_pdu);
}
static void mesh_upper_transport_send_upper_unsegmented_pdu(mesh_upper_transport_pdu_t * upper_pdu){
// TODO: store upper pdu in outgoing pdus active or similar
outgoing_upper_transport_pdu = upper_pdu;
mesh_unsegmented_pdu_t * unsegmented_pdu = &outgoing_unsegmented_pdu_singleton;
unsegmented_pdu->pdu_header.pdu_type = MESH_PDU_TYPE_UNSEGMENTED;
// provide segment
mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
btstack_assert(network_pdu);
unsegmented_pdu->segment = network_pdu;
// setup network pdu
network_pdu->data[0] = upper_pdu->ivi_nid;
network_pdu->data[1] = upper_pdu->ctl_ttl;
big_endian_store_24(network_pdu->data, 2, upper_pdu->seq);
big_endian_store_16(network_pdu->data, 5, upper_pdu->src);
big_endian_store_16(network_pdu->data, 7, upper_pdu->dst);
network_pdu->netkey_index = upper_pdu->netkey_index;
// setup acess message
network_pdu->data[9] = upper_pdu->akf_aid_control;
btstack_assert(upper_pdu->len < 15);
(void)memcpy(&network_pdu->data[10], crypto_buffer, upper_pdu->len);
network_pdu->len = 10 + upper_pdu->len;
network_pdu->flags = 0;
mesh_lower_transport_send_pdu((mesh_pdu_t*) unsegmented_pdu);
}
static void mesh_upper_transport_send_upper_segmented_access_pdu_ccm(void * arg){
crypto_active = 0;
@ -1014,7 +1052,16 @@ static void mesh_upper_transport_send_upper_segmented_access_pdu_ccm(void * arg)
mesh_print_hex("TransMIC", &crypto_buffer[upper_pdu->len], upper_pdu->transmic_len);
upper_pdu->len += upper_pdu->transmic_len;
mesh_print_hex("UpperTransportPDU", crypto_buffer, upper_pdu->len);
switch (upper_pdu->pdu_header.pdu_type){
case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
mesh_upper_transport_send_upper_unsegmented_pdu(upper_pdu);
break;
case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
mesh_upper_transport_send_upper_segmented_pdu(upper_pdu);
break;
default:
btstack_assert(false);
}
}
static void mesh_upper_transport_send_upper_segmented_access_pdu_digest(void *arg){
@ -1066,7 +1113,7 @@ static void mesh_upper_transport_send_upper_segmented_access_pdu(mesh_upper_tran
btstack_assert(payload_len == upper_pdu->len);
// Dump PDU
printf("[+] Upper transport, send upper segmented Access PDU - dest %04x, seq %06x\n", upper_pdu->dst, upper_pdu->seq);
printf("[+] Upper transport, send upper (un)segmented Access PDU - dest %04x, seq %06x\n", upper_pdu->dst, upper_pdu->seq);
mesh_print_hex("Access Payload", crypto_buffer, upper_pdu->len);
// setup nonce - uses dst, so after pseudo address translation
@ -1102,12 +1149,12 @@ static void mesh_upper_transport_send_unsegmented_control_pdu(mesh_network_pdu_t
printf("[+] Upper transport, send unsegmented Control PDU %p - seq %06x opcode %02x\n", network_pdu, seq, opcode);
mesh_print_hex("Access Payload", &network_pdu->data[10], network_pdu->len - 10);
// wrap into mesh-unsegmented-pdu
outgoing_unsegmented_pdu.pdu_header.pdu_type = MESH_PDU_TYPE_UNSEGMENTED;
outgoing_unsegmented_pdu.segment = network_pdu;
outgoing_unsegmented_pdu.flags = MESH_TRANSPORT_FLAG_CONTROL;
outgoing_unsegmented_pdu_singleton.pdu_header.pdu_type = MESH_PDU_TYPE_UNSEGMENTED;
outgoing_unsegmented_pdu_singleton.segment = network_pdu;
outgoing_unsegmented_pdu_singleton.flags = MESH_TRANSPORT_FLAG_CONTROL;
// send
mesh_lower_transport_send_pdu((mesh_pdu_t *) &outgoing_unsegmented_pdu);
mesh_lower_transport_send_pdu((mesh_pdu_t *) &outgoing_unsegmented_pdu_singleton);
}
#if 0
@ -1285,6 +1332,7 @@ static void mesh_upper_transport_run(void){
}
break;
case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
mesh_upper_transport_send_upper_segmented_access_pdu((mesh_upper_transport_pdu_t *) pdu);
break;
default:
@ -1322,12 +1370,20 @@ static void mesh_upper_transport_pdu_handler(mesh_transport_callback_type_t call
break;
case MESH_PDU_TYPE_UNSEGMENTED:
unsegmented_pdu = (mesh_unsegmented_pdu_t *) pdu;
if (unsegmented_pdu == &outgoing_unsegmented_pdu){
if (unsegmented_pdu == &outgoing_unsegmented_pdu_singleton){
if ((unsegmented_pdu->flags & MESH_TRANSPORT_FLAG_CONTROL) == 0){
// notify upper layer but use network pdu (control pdu)
btstack_assert((unsegmented_pdu->flags & MESH_TRANSPORT_FLAG_CONTROL) != 0);
mesh_network_pdu_t * network_pdu = outgoing_unsegmented_pdu.segment;
outgoing_unsegmented_pdu.segment = NULL;
mesh_network_pdu_t * network_pdu = outgoing_unsegmented_pdu_singleton.segment;
outgoing_unsegmented_pdu_singleton.segment = NULL;
mesh_control_message_handler(callback_type, status, (mesh_pdu_t *) network_pdu);
} else {
// notify upper layer but use upper access pdu
mesh_network_pdu_t * network_pdu = outgoing_unsegmented_pdu_singleton.segment;
outgoing_unsegmented_pdu_singleton.segment = NULL;
mesh_network_pdu_free(network_pdu);
pdu_to_report = (mesh_pdu_t *) outgoing_upper_transport_pdu;
mesh_access_message_handler(callback_type, status, pdu_to_report);
}
} else {
btstack_assert((unsegmented_pdu->flags & MESH_TRANSPORT_FLAG_CONTROL) == 0);
mesh_access_message_handler(callback_type, status, pdu);

View File

@ -112,6 +112,7 @@ uint16_t mesh_pdu_dst(mesh_pdu_t * pdu){
case MESH_PDU_TYPE_ACCESS:
return mesh_access_dst((mesh_access_pdu_t *) pdu);
case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS:
case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS:
return ((mesh_upper_transport_pdu_t *) pdu)->dst;
default:
btstack_assert(false);
@ -442,21 +443,16 @@ void test_send_access_message(uint16_t netkey_index, uint16_t appkey_index, uin
transport_pdu_len = strlen(control_pdu) / 2;
btstack_parse_hex(control_pdu, transport_pdu_len, transport_pdu_data);
mesh_pdu_t * pdu;
static mesh_unsegmented_pdu_t unsegmented_pdu = { 0 };
static mesh_upper_transport_pdu_t segmented_access_pdu = { 0 };
static mesh_upper_transport_pdu_t upper_pdu = { 0 };
upper_pdu.flags = 0;
mesh_pdu_t * pdu = (mesh_pdu_t *) &upper_pdu;
if (count == 1 ){
// send as unsegmented access pdu
unsegmented_pdu.pdu_header.pdu_type = MESH_PDU_TYPE_UNSEGMENTED;
mesh_network_pdu_t * segment = mesh_network_pdu_get();
unsegmented_pdu.segment = segment;
unsegmented_pdu.flags = 0;
pdu = (mesh_pdu_t*) &unsegmented_pdu;
upper_pdu.pdu_header.pdu_type = MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS;
} else {
// send as segmented access pdu
segmented_access_pdu.pdu_header.pdu_type = MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS;
segmented_access_pdu.flags = 0;
pdu = (mesh_pdu_t *) &segmented_access_pdu;
upper_pdu.pdu_header.pdu_type = MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS;
}
mesh_upper_transport_setup_access_pdu(pdu, netkey_index, appkey_index, ttl, src, dest, szmic, transport_pdu_data, transport_pdu_len);
mesh_upper_transport_send_access_pdu(pdu);
@ -477,15 +473,10 @@ void test_send_access_message(uint16_t netkey_index, uint16_t appkey_index, uin
#endif
}
// free segments
if (count == 1){
mesh_network_pdu_free(unsegmented_pdu.segment);
unsegmented_pdu.segment = NULL;
} else {
while (btstack_linked_list_empty(&segmented_access_pdu.payload.segments) == false){
mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&segmented_access_pdu.payload.segments);
while (btstack_linked_list_empty(&upper_pdu.segments) == false){
mesh_network_pdu_t * network_pdu = (mesh_network_pdu_t *) btstack_linked_list_pop(&upper_pdu.segments);
mesh_network_pdu_free(network_pdu);
}
}
}
void test_send_control_message(uint16_t netkey_index, uint8_t ttl, uint16_t src, uint16_t dest, char * control_pdu, int count, char ** lower_transport_pdus, char ** network_pdus){