xref: /btstack/src/mesh/mesh_access.c (revision 8ef657c601a354afb4ebba286c8f8d307aa81d4b)
1 /*
2  * Copyright (C) 2019 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define __BTSTACK_FILE__ "mesh_access.c"
39 
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdarg.h>
43 
44 #include "mesh/mesh_access.h"
45 
46 #include "btstack_debug.h"
47 #include "btstack_memory.h"
48 #include "btstack_tlv.h"
49 
50 #include "mesh/beacon.h"
51 #include "mesh/mesh_foundation.h"
52 #include "mesh/mesh_iv_index_seq_number.h"
53 #include "mesh/mesh_node.h"
54 #include "mesh/mesh_proxy.h"
55 #include "mesh/mesh_upper_transport.h"
56 
57 #define MEST_TRANSACTION_TIMEOUT_MS  6000
58 
59 static void mesh_access_message_process_handler(mesh_pdu_t * pdu);
60 static void mesh_access_secure_network_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size);
61 static void mesh_access_upper_transport_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu);
62 static const mesh_operation_t * mesh_model_lookup_operation_by_opcode(mesh_model_t * model, uint32_t opcode);
63 static void mesh_persist_iv_index_and_sequence_number(void);
64 
65 // acknowledged messages
66 static btstack_linked_list_t  mesh_access_acknowledged_messages;
67 static btstack_timer_source_t mesh_access_acknowledged_timer;
68 
69 static uint16_t mid_counter;
70 
71 static const btstack_tlv_t * btstack_tlv_singleton_impl;
72 static void *                btstack_tlv_singleton_context;
73 
74 // Transitions
75 static btstack_linked_list_t  transitions;
76 static btstack_timer_source_t transitions_timer;
77 static uint32_t transition_step_min_ms;
78 static uint8_t mesh_transaction_id_counter = 0;
79 
80 static void mesh_access_setup_tlv(void){
81     if (btstack_tlv_singleton_impl) return;
82     btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context);
83 }
84 
85 void mesh_access_init(void){
86     // register with upper transport
87     mesh_upper_transport_register_access_message_handler(&mesh_access_message_process_handler);
88     mesh_upper_transport_set_higher_layer_handler(&mesh_access_upper_transport_handler);
89 
90     // register for secure network beacons
91     beacon_register_for_secure_network_beacons(&mesh_access_secure_network_beacon_handler);
92 
93     // register for seq number updates
94     mesh_sequence_number_set_update_callback(&mesh_persist_iv_index_and_sequence_number);
95 }
96 
97 void mesh_access_emit_state_update_bool(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
98     model_state_id_t state_identifier, model_state_update_reason_t reason, uint8_t value){
99     if (event_handler == NULL) return;
100     uint8_t event[14] = {HCI_EVENT_MESH_META, 12, MESH_SUBEVENT_STATE_UPDATE_BOOL};
101     int pos = 3;
102     event[pos++] = element_index;
103     little_endian_store_32(event, pos, model_identifier);
104     pos += 4;
105     little_endian_store_32(event, pos, (uint32_t)state_identifier);
106     pos += 4;
107     event[pos++] = (uint8_t)reason;
108     event[pos++] = value;
109     (*event_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
110 }
111 
112 void mesh_access_emit_state_update_int16(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
113     model_state_id_t state_identifier, model_state_update_reason_t reason, int16_t value){
114     if (event_handler == NULL) return;
115     uint8_t event[15] = {HCI_EVENT_MESH_META, 13, MESH_SUBEVENT_STATE_UPDATE_BOOL};
116     int pos = 3;
117     event[pos++] = element_index;
118     little_endian_store_32(event, pos, model_identifier);
119     pos += 4;
120     little_endian_store_32(event, pos, (uint32_t)state_identifier);
121     pos += 4;
122     event[pos++] = (uint8_t)reason;
123     little_endian_store_16(event, pos, (uint16_t) value);
124     pos += 2;
125     (*event_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
126 }
127 
128 uint8_t mesh_access_acknowledged_message_retransmissions(void){
129     return 3;
130 }
131 
132 uint32_t mesh_access_acknowledged_message_timeout_ms(void){
133     return 30000;
134 }
135 
136 #define MESH_ACCESS_OPCODE_INVALID 0xFFFFFFFFu
137 
138 void mesh_access_send_unacknowledged_pdu(mesh_pdu_t * pdu){
139     pdu->ack_opcode = MESH_ACCESS_OPCODE_INVALID;;
140     mesh_upper_transport_send_access_pdu(pdu);
141 }
142 
143 void mesh_access_send_acknowledged_pdu(mesh_pdu_t * pdu, uint8_t retransmissions, uint32_t ack_opcode){
144     pdu->retransmit_count = retransmissions;
145     pdu->ack_opcode = ack_opcode;
146 
147     mesh_upper_transport_send_access_pdu(pdu);
148 }
149 
150 #define MESH_SUBEVENT_MESSAGE_NOT_ACKNOWLEDGED                                        0x30
151 
152 static void mesh_access_acknowledged_run(btstack_timer_source_t * ts){
153     UNUSED(ts);
154 
155     uint32_t now = btstack_run_loop_get_time_ms();
156 
157     // handle timeouts
158     btstack_linked_list_iterator_t ack_it;
159     btstack_linked_list_iterator_init(&ack_it, &mesh_access_acknowledged_messages);
160     while (btstack_linked_list_iterator_has_next(&ack_it)){
161         mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&ack_it);
162         if (btstack_time_delta(now, pdu->retransmit_timeout_ms) >= 0) {
163             // remove from list
164             btstack_linked_list_remove(&mesh_access_acknowledged_messages, (btstack_linked_item_t*) pdu);
165             // retransmit or report failure
166             if (pdu->retransmit_count){
167                 pdu->retransmit_count--;
168                 mesh_upper_transport_send_access_pdu(pdu);
169             } else {
170                 // find correct model and emit error
171                 uint16_t src = mesh_pdu_src(pdu);
172                 uint16_t dst = mesh_pdu_dst(pdu);
173                 mesh_element_t * element = mesh_node_element_for_unicast_address(src);
174                 if (element){
175                     // find
176                     mesh_model_iterator_t model_it;
177                     mesh_model_iterator_init(&model_it, element);
178                     while (mesh_model_iterator_has_next(&model_it)){
179                         mesh_model_t * model = mesh_model_iterator_next(&model_it);
180                         // find opcode in table
181                         const mesh_operation_t * operation = mesh_model_lookup_operation_by_opcode(model, pdu->ack_opcode);
182                         if (operation == NULL) continue;
183                         if (model->model_packet_handler == NULL) continue;
184                         // emit event
185                         uint8_t event[13];
186                         event[0] = HCI_EVENT_MESH_META;
187                         event[1] = sizeof(event) - 2;
188                         event[2] = element->element_index;
189                         little_endian_store_32(event, 3, model->model_identifier);
190                         little_endian_store_32(event, 7, pdu->ack_opcode);
191                         little_endian_store_16(event, 11, dst);
192                         (*model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
193                     }
194                 }
195 
196                 // free
197                 mesh_upper_transport_pdu_free(pdu);
198             }
199         }
200     }
201 
202     // find earliest timeout and set timer
203     btstack_linked_list_iterator_init(&ack_it, &mesh_access_acknowledged_messages);
204     int32_t next_timeout_ms = 0;
205     while (btstack_linked_list_iterator_has_next(&ack_it)){
206         mesh_pdu_t * pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&ack_it);
207         int32_t timeout_delta_ms = btstack_time_delta(pdu->retransmit_timeout_ms, now);
208         if (next_timeout_ms == 0 || timeout_delta_ms < next_timeout_ms){
209             next_timeout_ms = timeout_delta_ms;
210         }
211     }
212 
213     // set timer
214     if (next_timeout_ms == 0) return;
215 
216     btstack_run_loop_set_timer(&mesh_access_acknowledged_timer, next_timeout_ms);
217     btstack_run_loop_set_timer_handler(&mesh_access_acknowledged_timer, mesh_access_acknowledged_run);
218     btstack_run_loop_add_timer(&mesh_access_acknowledged_timer);
219 }
220 
221 static void mesh_access_acknowledged_received(uint16_t rx_src, uint32_t opcode){
222     // check if received src matches our dest
223     // free acknowledged messages if we were waiting for this message
224 
225     btstack_linked_list_iterator_t ack_it;
226     btstack_linked_list_iterator_init(&ack_it, &mesh_access_acknowledged_messages);
227     while (btstack_linked_list_iterator_has_next(&ack_it)){
228         mesh_pdu_t * tx_pdu = (mesh_pdu_t *) btstack_linked_list_iterator_next(&ack_it);
229         uint16_t tx_dest = mesh_pdu_dst(tx_pdu);
230         if (tx_dest != rx_src) continue;
231         if (tx_pdu->ack_opcode != opcode) continue;
232         // got expected response from dest, remove from outgoing messages
233         mesh_upper_transport_pdu_free(tx_pdu);
234         return;
235     }
236 }
237 
238 static void mesh_access_upper_transport_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu){
239     switch (callback_type){
240         case MESH_TRANSPORT_PDU_SENT:
241             // unacknowledged -> free
242             if (pdu->ack_opcode == MESH_ACCESS_OPCODE_INVALID){
243                 mesh_upper_transport_pdu_free(pdu);
244                 break;
245             }
246             // setup timeout
247             pdu->retransmit_timeout_ms = btstack_run_loop_get_time_ms() + mesh_access_acknowledged_message_timeout_ms();
248             // add to mesh_access_acknowledged_messages
249             btstack_linked_list_add(&mesh_access_acknowledged_messages, (btstack_linked_item_t *) pdu);
250             // update timer
251             mesh_access_acknowledged_run(NULL);
252             break;
253         default:
254             break;
255     }
256 }
257 
258 // Mesh Model Transitions
259 
260 void mesh_access_transitions_setup_transaction(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
261     transition->transaction_timestamp_ms = btstack_run_loop_get_time_ms();
262     transition->transaction_identifier = transaction_identifier;
263     transition->src_address = src_address;
264     transition->dst_address = dst_address;
265 }
266 
267 void mesh_access_transitions_abort_transaction(mesh_transition_t * transition){
268     mesh_access_transitions_remove(transition);
269 }
270 
271 
272 static int mesh_access_transitions_transaction_is_expired(mesh_transition_t * transition){
273     return (btstack_run_loop_get_time_ms() - transition->transaction_timestamp_ms) > MEST_TRANSACTION_TIMEOUT_MS;
274 }
275 
276 mesh_transaction_status_t mesh_access_transitions_transaction_status(mesh_transition_t * transition, uint8_t transaction_identifier, uint16_t src_address, uint16_t dst_address){
277     if (transition->src_address != src_address || transition->dst_address != dst_address) return MESH_TRANSACTION_STATUS_DIFFERENT_DST_OR_SRC;
278 
279     if (transition->transaction_identifier == transaction_identifier && !mesh_access_transitions_transaction_is_expired(transition)){
280             return MESH_TRANSACTION_STATUS_RETRANSMISSION;
281     }
282     return MESH_TRANSACTION_STATUS_NEW;
283 }
284 
285 uint8_t mesh_access_transitions_num_steps_from_gdtt(uint8_t time_gdtt){
286     return time_gdtt >> 2;
287 }
288 
289 static uint32_t mesh_access_transitions_step_ms_from_gdtt(uint8_t time_gdtt){
290     mesh_default_transition_step_resolution_t step_resolution = (mesh_default_transition_step_resolution_t) (time_gdtt & 0x03u);
291     switch (step_resolution){
292         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_100ms:
293             return 100;
294         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_1s:
295             return 1000;
296         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_10s:
297             return 10000;
298         case MESH_DEFAULT_TRANSITION_STEP_RESOLUTION_10min:
299             return 600000;
300         default:
301             return 0;
302     }
303 }
304 
305 uint32_t mesh_access_time_gdtt2ms(uint8_t time_gdtt){
306     uint8_t num_steps  = mesh_access_transitions_num_steps_from_gdtt(time_gdtt);
307     if (num_steps > 0x3E) return 0;
308 
309     return mesh_access_transitions_step_ms_from_gdtt(time_gdtt) * num_steps;
310 }
311 
312 static void mesh_access_transitions_timeout_handler(btstack_timer_source_t * timer){
313     btstack_linked_list_iterator_t it;
314     btstack_linked_list_iterator_init(&it, &transitions);
315     while (btstack_linked_list_iterator_has_next(&it)){
316         mesh_transition_t * transition = (mesh_transition_t *)btstack_linked_list_iterator_next(&it);
317         (transition->transition_callback)(transition, TRANSITION_UPDATE, btstack_run_loop_get_time_ms());
318     }
319     if (btstack_linked_list_empty(&transitions)) return;
320 
321     btstack_run_loop_set_timer(timer, transition_step_min_ms);
322     btstack_run_loop_add_timer(timer);
323 }
324 
325 static void mesh_access_transitions_timer_start(void){
326     btstack_run_loop_remove_timer(&transitions_timer);
327     btstack_run_loop_set_timer_handler(&transitions_timer, mesh_access_transitions_timeout_handler);
328     btstack_run_loop_set_timer(&transitions_timer, transition_step_min_ms);
329     btstack_run_loop_add_timer(&transitions_timer);
330 }
331 
332 static void mesh_access_transitions_timer_stop(void){
333     btstack_run_loop_remove_timer(&transitions_timer);
334 }
335 
336 static uint32_t mesh_access_transitions_get_step_min_ms(void){
337     uint32_t min_timeout_ms = 0;
338 
339     btstack_linked_list_iterator_t it;
340     btstack_linked_list_iterator_init(&it, &transitions);
341     while (btstack_linked_list_iterator_has_next(&it)){
342         mesh_transition_t * transition = (mesh_transition_t *)btstack_linked_list_iterator_next(&it);
343         if (min_timeout_ms == 0 || transition->step_duration_ms < min_timeout_ms){
344             min_timeout_ms = transition->step_duration_ms;
345         }
346     }
347     return min_timeout_ms;
348 }
349 
350 void mesh_access_transitions_setup(mesh_transition_t * transition, mesh_model_t * mesh_model,
351     uint8_t transition_time_gdtt, uint8_t delay_gdtt,
352     void (* transition_callback)(struct mesh_transition * transition, transition_event_t event, uint32_t current_timestamp)){
353 
354     //  Only values of 0x00 through 0x3E shall be used to specify the value of the Transition Number of Steps field
355     uint8_t num_steps  = mesh_access_transitions_num_steps_from_gdtt(transition_time_gdtt);
356     if (num_steps > 0x3E) return;
357 
358     transition->state = MESH_TRANSITION_STATE_IDLE;
359     transition->phase_start_ms = 0;
360 
361     transition->mesh_model = mesh_model;
362     transition->transition_callback = transition_callback;
363     transition->step_duration_ms = mesh_access_transitions_step_ms_from_gdtt(transition_time_gdtt);
364     transition->remaining_delay_time_ms = delay_gdtt * 5;
365     transition->remaining_transition_time_ms = num_steps * transition->step_duration_ms;
366 }
367 
368 void mesh_access_transitions_add(mesh_transition_t * transition){
369     if (transition->step_duration_ms == 0) return;
370 
371     if (btstack_linked_list_empty(&transitions) || transition->step_duration_ms < transition_step_min_ms){
372         transition_step_min_ms = transition->step_duration_ms;
373     }
374     mesh_access_transitions_timer_start();
375     btstack_linked_list_add(&transitions, (btstack_linked_item_t *) transition);
376     (transition->transition_callback)(transition, TRANSITION_START, btstack_run_loop_get_time_ms());
377 }
378 
379 void mesh_access_transitions_remove(mesh_transition_t * transition){
380     mesh_access_transitions_setup(transition, NULL, 0, 0, NULL);
381     btstack_linked_list_remove(&transitions, (btstack_linked_item_t *) transition);
382 
383     if (btstack_linked_list_empty(&transitions)){
384         mesh_access_transitions_timer_stop();
385     } else {
386         transition_step_min_ms = mesh_access_transitions_get_step_min_ms();
387     }
388 }
389 
390 uint8_t mesh_access_transactions_get_next_transaction_id(void){
391     mesh_transaction_id_counter++;
392     if (mesh_transaction_id_counter == 0){
393         mesh_transaction_id_counter = 1;
394     }
395     return mesh_transaction_id_counter;
396 }
397 
398 // Mesh Node Element functions
399 uint8_t mesh_access_get_element_index(mesh_model_t * mesh_model){
400     return mesh_model->element->element_index;
401 }
402 
403 uint16_t mesh_access_get_element_address(mesh_model_t * mesh_model){
404     return mesh_node_get_primary_element_address() + mesh_model->element->element_index;
405 }
406 
407 // Model Identifier utilities
408 
409 uint32_t mesh_model_get_model_identifier(uint16_t vendor_id, uint16_t model_id){
410     return (vendor_id << 16) | model_id;
411 }
412 
413 uint32_t mesh_model_get_model_identifier_bluetooth_sig(uint16_t model_id){
414     return (BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC << 16) | model_id;
415 }
416 
417 uint16_t mesh_model_get_model_id(uint32_t model_identifier){
418     return model_identifier & 0xFFFFu;
419 }
420 
421 uint16_t mesh_model_get_vendor_id(uint32_t model_identifier){
422     return model_identifier >> 16;
423 }
424 
425 int mesh_model_is_bluetooth_sig(uint32_t model_identifier){
426     return mesh_model_get_vendor_id(model_identifier) == BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC;
427 }
428 
429 mesh_model_t * mesh_model_get_configuration_server(void){
430     return mesh_model_get_by_identifier(mesh_node_get_primary_element(), mesh_model_get_model_identifier_bluetooth_sig(MESH_SIG_MODEL_ID_CONFIGURATION_SERVER));
431 }
432 
433 void mesh_element_add_model(mesh_element_t * element, mesh_model_t * mesh_model){
434     if (mesh_model_is_bluetooth_sig(mesh_model->model_identifier)){
435         element->models_count_sig++;
436     } else {
437         element->models_count_vendor++;
438     }
439     mesh_model->mid = mid_counter++;
440     mesh_model->element = element;
441     btstack_linked_list_add_tail(&element->models, (btstack_linked_item_t *) mesh_model);
442 }
443 
444 void mesh_model_iterator_init(mesh_model_iterator_t * iterator, mesh_element_t * element){
445     btstack_linked_list_iterator_init(&iterator->it, &element->models);
446 }
447 
448 int mesh_model_iterator_has_next(mesh_model_iterator_t * iterator){
449     return btstack_linked_list_iterator_has_next(&iterator->it);
450 }
451 
452 mesh_model_t * mesh_model_iterator_next(mesh_model_iterator_t * iterator){
453     return (mesh_model_t *) btstack_linked_list_iterator_next(&iterator->it);
454 }
455 
456 mesh_model_t * mesh_model_get_by_identifier(mesh_element_t * element, uint32_t model_identifier){
457     mesh_model_iterator_t it;
458     mesh_model_iterator_init(&it, element);
459     while (mesh_model_iterator_has_next(&it)){
460         mesh_model_t * model = mesh_model_iterator_next(&it);
461         if (model->model_identifier != model_identifier) continue;
462         return model;
463     }
464     return NULL;
465 }
466 
467 mesh_model_t * mesh_access_model_for_address_and_model_identifier(uint16_t element_address, uint32_t model_identifier, uint8_t * status){
468     mesh_element_t * element = mesh_node_element_for_unicast_address(element_address);
469     if (element == NULL){
470         *status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
471         return NULL;
472     }
473     mesh_model_t * model = mesh_model_get_by_identifier(element, model_identifier);
474     if (model == NULL) {
475         *status = MESH_FOUNDATION_STATUS_INVALID_MODEL;
476     } else {
477         *status = MESH_FOUNDATION_STATUS_SUCCESS;
478     }
479     return model;
480 }
481 
482 uint16_t mesh_pdu_src(mesh_pdu_t * pdu){
483     switch (pdu->pdu_type){
484         case MESH_PDU_TYPE_TRANSPORT:
485             return mesh_transport_src((mesh_transport_pdu_t*) pdu);
486         case MESH_PDU_TYPE_NETWORK:
487             return mesh_network_src((mesh_network_pdu_t *) pdu);
488         default:
489             return MESH_ADDRESS_UNSASSIGNED;
490     }
491 }
492 
493 uint16_t mesh_pdu_dst(mesh_pdu_t * pdu){
494     switch (pdu->pdu_type){
495         case MESH_PDU_TYPE_TRANSPORT:
496             return mesh_transport_dst((mesh_transport_pdu_t*) pdu);
497         case MESH_PDU_TYPE_NETWORK:
498             return mesh_network_dst((mesh_network_pdu_t *) pdu);
499         default:
500             return MESH_ADDRESS_UNSASSIGNED;
501     }
502 }
503 
504 uint16_t mesh_pdu_netkey_index(mesh_pdu_t * pdu){
505     switch (pdu->pdu_type){
506         case MESH_PDU_TYPE_TRANSPORT:
507             return ((mesh_transport_pdu_t*) pdu)->netkey_index;
508         case MESH_PDU_TYPE_NETWORK:
509             return ((mesh_network_pdu_t *) pdu)->netkey_index;
510         default:
511             return 0;
512     }
513 }
514 
515 uint16_t mesh_pdu_appkey_index(mesh_pdu_t * pdu){
516     switch (pdu->pdu_type){
517         case MESH_PDU_TYPE_TRANSPORT:
518             return ((mesh_transport_pdu_t*) pdu)->appkey_index;
519         case MESH_PDU_TYPE_NETWORK:
520             return ((mesh_network_pdu_t *) pdu)->appkey_index;
521         default:
522             return 0;
523     }
524 }
525 
526 uint16_t mesh_pdu_len(mesh_pdu_t * pdu){
527     switch (pdu->pdu_type){
528         case MESH_PDU_TYPE_TRANSPORT:
529             return ((mesh_transport_pdu_t*) pdu)->len;
530         case MESH_PDU_TYPE_NETWORK:
531             return ((mesh_network_pdu_t *) pdu)->len - 10;
532         default:
533             return 0;
534     }
535 }
536 
537 uint8_t * mesh_pdu_data(mesh_pdu_t * pdu){
538     switch (pdu->pdu_type){
539         case MESH_PDU_TYPE_TRANSPORT:
540             return ((mesh_transport_pdu_t*) pdu)->data;
541         case MESH_PDU_TYPE_NETWORK:
542             return &((mesh_network_pdu_t *) pdu)->data[10];
543         default:
544             return NULL;
545     }
546 }
547 
548 // message parser
549 
550 static int mesh_access_get_opcode(uint8_t * buffer, uint16_t buffer_size, uint32_t * opcode, uint16_t * opcode_size){
551     switch (buffer[0] >> 6){
552         case 0:
553         case 1:
554             if (buffer[0] == 0x7f) return 0;
555             *opcode = buffer[0];
556             *opcode_size = 1;
557             return 1;
558         case 2:
559             if (buffer_size < 2) return 0;
560             *opcode = big_endian_read_16(buffer, 0);
561             *opcode_size = 2;
562             return 1;
563         case 3:
564             if (buffer_size < 3) return 0;
565             *opcode = (buffer[0] << 16) | little_endian_read_16(buffer, 1);
566             *opcode_size = 3;
567             return 1;
568         default:
569             return 0;
570     }
571 }
572 
573 static int mesh_access_transport_get_opcode(mesh_transport_pdu_t * transport_pdu, uint32_t * opcode, uint16_t * opcode_size){
574     return mesh_access_get_opcode(transport_pdu->data, transport_pdu->len, opcode, opcode_size);
575 }
576 
577 static int mesh_access_network_get_opcode(mesh_network_pdu_t * network_pdu, uint32_t * opcode, uint16_t * opcode_size){
578     // TransMIC already removed by mesh_upper_transport_validate_unsegmented_message_ccm
579     return mesh_access_get_opcode(&network_pdu->data[10], network_pdu->len - 10, opcode, opcode_size);
580 }
581 
582 int mesh_access_pdu_get_opcode(mesh_pdu_t * pdu, uint32_t * opcode, uint16_t * opcode_size){
583     switch (pdu->pdu_type){
584         case MESH_PDU_TYPE_TRANSPORT:
585             return mesh_access_transport_get_opcode((mesh_transport_pdu_t*) pdu, opcode, opcode_size);
586         case MESH_PDU_TYPE_NETWORK:
587             return mesh_access_network_get_opcode((mesh_network_pdu_t *) pdu, opcode, opcode_size);
588         default:
589             return 0;
590     }
591 }
592 
593 void mesh_access_parser_skip(mesh_access_parser_state_t * state, uint16_t bytes_to_skip){
594     state->data += bytes_to_skip;
595     state->len  -= bytes_to_skip;
596 }
597 
598 int mesh_access_parser_init(mesh_access_parser_state_t * state, mesh_pdu_t * pdu){
599     state->data = mesh_pdu_data(pdu);
600     state->len  = mesh_pdu_len(pdu);
601 
602     uint16_t opcode_size = 0;
603     int ok = mesh_access_get_opcode(state->data, state->len, &state->opcode, &opcode_size);
604     if (ok){
605         mesh_access_parser_skip(state, opcode_size);
606     }
607     return ok;
608 }
609 
610 uint16_t mesh_access_parser_available(mesh_access_parser_state_t * state){
611     return state->len;
612 }
613 
614 uint8_t mesh_access_parser_get_u8(mesh_access_parser_state_t * state){
615     uint8_t value = *state->data;
616     mesh_access_parser_skip(state, 1);
617     return value;
618 }
619 
620 uint16_t mesh_access_parser_get_u16(mesh_access_parser_state_t * state){
621     uint16_t value = little_endian_read_16(state->data, 0);
622     mesh_access_parser_skip(state, 2);
623     return value;
624 }
625 
626 uint32_t mesh_access_parser_get_u24(mesh_access_parser_state_t * state){
627     uint32_t value = little_endian_read_24(state->data, 0);
628     mesh_access_parser_skip(state, 3);
629     return value;
630 }
631 
632 uint32_t mesh_access_parser_get_u32(mesh_access_parser_state_t * state){
633     uint32_t value = little_endian_read_24(state->data, 0);
634     mesh_access_parser_skip(state, 4);
635     return value;
636 }
637 
638 void mesh_access_parser_get_u128(mesh_access_parser_state_t * state, uint8_t * dest){
639     reverse_128( state->data, dest);
640     mesh_access_parser_skip(state, 16);
641 }
642 
643 void mesh_access_parser_get_label_uuid(mesh_access_parser_state_t * state, uint8_t * dest){
644     memcpy( dest, state->data, 16);
645     mesh_access_parser_skip(state, 16);
646 }
647 
648 void mesh_access_parser_get_key(mesh_access_parser_state_t * state, uint8_t * dest){
649     memcpy( dest, state->data, 16);
650     mesh_access_parser_skip(state, 16);
651 }
652 
653 uint32_t mesh_access_parser_get_model_identifier(mesh_access_parser_state_t * parser){
654     if (mesh_access_parser_available(parser) == 4){
655         return mesh_access_parser_get_u32(parser);
656     } else {
657         return (BLUETOOTH_COMPANY_ID_BLUETOOTH_SIG_INC << 16) | mesh_access_parser_get_u16(parser);
658     }
659 }
660 
661 // Mesh Access Message Builder
662 
663 // message builder
664 
665 static int mesh_access_setup_opcode(uint8_t * buffer, uint32_t opcode){
666     if (opcode < 0x100){
667         buffer[0] = opcode;
668         return 1;
669     }
670     if (opcode < 0x10000){
671         big_endian_store_16(buffer, 0, opcode);
672         return 2;
673     }
674     buffer[0] = opcode >> 16;
675     little_endian_store_16(buffer, 1, opcode & 0xffff);
676     return 3;
677 }
678 
679 mesh_transport_pdu_t * mesh_access_transport_init(uint32_t opcode){
680     mesh_transport_pdu_t * pdu = mesh_transport_pdu_get();
681     if (!pdu) return NULL;
682 
683     pdu->len  = mesh_access_setup_opcode(pdu->data, opcode);
684     return pdu;
685 }
686 
687 void mesh_access_transport_add_uint8(mesh_transport_pdu_t * pdu, uint8_t value){
688     pdu->data[pdu->len++] = value;
689 }
690 
691 void mesh_access_transport_add_uint16(mesh_transport_pdu_t * pdu, uint16_t value){
692     little_endian_store_16(pdu->data, pdu->len, value);
693     pdu->len += 2;
694 }
695 
696 void mesh_access_transport_add_uint24(mesh_transport_pdu_t * pdu, uint32_t value){
697     little_endian_store_24(pdu->data, pdu->len, value);
698     pdu->len += 3;
699 }
700 
701 void mesh_access_transport_add_uint32(mesh_transport_pdu_t * pdu, uint32_t value){
702     little_endian_store_32(pdu->data, pdu->len, value);
703     pdu->len += 4;
704 }
705 void mesh_access_transport_add_model_identifier(mesh_transport_pdu_t * pdu, uint32_t model_identifier){
706     if (mesh_model_is_bluetooth_sig(model_identifier)){
707         mesh_access_transport_add_uint16( pdu, mesh_model_get_model_id(model_identifier) );
708     } else {
709         mesh_access_transport_add_uint32( pdu, model_identifier );
710     }
711 }
712 
713 mesh_network_pdu_t * mesh_access_network_init(uint32_t opcode){
714     mesh_network_pdu_t * pdu = mesh_network_pdu_get();
715     if (!pdu) return NULL;
716 
717     pdu->len  = mesh_access_setup_opcode(&pdu->data[10], opcode) + 10;
718     return pdu;
719 }
720 
721 void mesh_access_network_add_uint8(mesh_network_pdu_t * pdu, uint8_t value){
722     pdu->data[pdu->len++] = value;
723 }
724 
725 void mesh_access_network_add_uint16(mesh_network_pdu_t * pdu, uint16_t value){
726     little_endian_store_16(pdu->data, pdu->len, value);
727     pdu->len += 2;
728 }
729 
730 void mesh_access_network_add_uint24(mesh_network_pdu_t * pdu, uint16_t value){
731     little_endian_store_24(pdu->data, pdu->len, value);
732     pdu->len += 3;
733 }
734 
735 void mesh_access_network_add_uint32(mesh_network_pdu_t * pdu, uint16_t value){
736     little_endian_store_32(pdu->data, pdu->len, value);
737     pdu->len += 4;
738 }
739 
740 void mesh_access_network_add_model_identifier(mesh_network_pdu_t * pdu, uint32_t model_identifier){
741     if (mesh_model_is_bluetooth_sig(model_identifier)){
742         mesh_access_network_add_uint16( pdu, mesh_model_get_model_id(model_identifier) );
743     } else {
744         mesh_access_network_add_uint32( pdu, model_identifier );
745     }
746 }
747 
748 // access message template
749 
750 mesh_network_pdu_t * mesh_access_setup_unsegmented_message(const mesh_access_message_t *template, ...){
751     mesh_network_pdu_t * network_pdu = mesh_access_network_init(template->opcode);
752     if (!network_pdu) return NULL;
753 
754     va_list argptr;
755     va_start(argptr, template);
756 
757     // add params
758     const char * format = template->format;
759     uint16_t word;
760     uint32_t longword;
761     while (*format){
762         switch (*format){
763             case '1':
764                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
765                 mesh_access_network_add_uint8( network_pdu, word);
766                 break;
767             case '2':
768                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
769                 mesh_access_network_add_uint16( network_pdu, word);
770                 break;
771             case '3':
772                 longword = va_arg(argptr, uint32_t);
773                 mesh_access_network_add_uint24( network_pdu, longword);
774                 break;
775             case '4':
776                 longword = va_arg(argptr, uint32_t);
777                 mesh_access_network_add_uint32( network_pdu, longword);
778                 break;
779             case 'm':
780                 longword = va_arg(argptr, uint32_t);
781                 mesh_access_network_add_model_identifier( network_pdu, longword);
782                 break;
783             default:
784                 log_error("Unsupported mesh message format specifier '%c", *format);
785                 break;
786         }
787         format++;
788     }
789 
790     va_end(argptr);
791 
792     return network_pdu;
793 }
794 
795 mesh_transport_pdu_t * mesh_access_setup_segmented_message(const mesh_access_message_t *template, ...){
796     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(template->opcode);
797     if (!transport_pdu) return NULL;
798 
799     va_list argptr;
800     va_start(argptr, template);
801 
802     // add params
803     const char * format = template->format;
804     uint16_t word;
805     uint32_t longword;
806     while (*format){
807         switch (*format++){
808             case '1':
809                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
810                 mesh_access_transport_add_uint8( transport_pdu, word);
811                 break;
812             case '2':
813                 word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
814                 mesh_access_transport_add_uint16( transport_pdu, word);
815                 break;
816             case '3':
817                 longword = va_arg(argptr, uint32_t);
818                 mesh_access_transport_add_uint24( transport_pdu, longword);
819                 break;
820             case '4':
821                 longword = va_arg(argptr, uint32_t);
822                 mesh_access_transport_add_uint32( transport_pdu, longword);
823                 break;
824             case 'm':
825                 longword = va_arg(argptr, uint32_t);
826                 mesh_access_transport_add_model_identifier( transport_pdu, longword);
827                 break;
828             default:
829                 break;
830         }
831     }
832 
833     va_end(argptr);
834 
835     return transport_pdu;
836 }
837 
838 static const mesh_operation_t * mesh_model_lookup_operation_by_opcode(mesh_model_t * model, uint32_t opcode){
839     // find opcode in table
840     const mesh_operation_t * operation = model->operations;
841     if (operation == NULL) return NULL;
842     for ( ; operation->handler != NULL ; operation++){
843         if (operation->opcode != opcode) continue;
844         return operation;
845     }
846     return NULL;
847 }
848 
849 static const mesh_operation_t * mesh_model_lookup_operation(mesh_model_t * model, mesh_pdu_t * pdu){
850 
851     uint32_t opcode = 0;
852     uint16_t opcode_size = 0;
853     int ok = mesh_access_pdu_get_opcode( pdu, &opcode, &opcode_size);
854     if (!ok) return NULL;
855 
856     uint16_t len = mesh_pdu_len(pdu);
857 
858     // find opcode in table
859     const mesh_operation_t * operation = model->operations;
860     if (operation == NULL) return NULL;
861     for ( ; operation->handler != NULL ; operation++){
862         if (operation->opcode != opcode) continue;
863         if ((opcode_size + operation->minimum_length) > len) continue;
864         return operation;
865     }
866     return NULL;
867 }
868 
869 static int mesh_access_validate_appkey_index(mesh_model_t * model, uint16_t appkey_index){
870     // DeviceKey is valid for all models
871     if (appkey_index == MESH_DEVICE_KEY_INDEX) return 1;
872     // check if AppKey that is bound to this particular model
873     return mesh_model_contains_appkey(model, appkey_index);
874 }
875 
876 static void mesh_access_message_process_handler(mesh_pdu_t * pdu){
877     // get opcode and size
878     uint32_t opcode = 0;
879     uint16_t opcode_size = 0;
880 
881 
882     int ok = mesh_access_pdu_get_opcode( pdu, &opcode, &opcode_size);
883     if (!ok) {
884         mesh_access_message_processed(pdu);
885         return;
886     }
887 
888     uint16_t len = mesh_pdu_len(pdu);
889     printf("MESH Access Message, Opcode = %x: ", opcode);
890     printf_hexdump(mesh_pdu_data(pdu), len);
891 
892     uint16_t src = mesh_pdu_src(pdu);
893     uint16_t dst = mesh_pdu_dst(pdu);
894     uint16_t appkey_index = mesh_pdu_appkey_index(pdu);
895     if (mesh_network_address_unicast(dst)){
896         // loookup element by unicast address
897         mesh_element_t * element = mesh_node_element_for_unicast_address(dst);
898         if (element != NULL){
899             // iterate over models, look for operation
900             mesh_model_iterator_t model_it;
901             mesh_model_iterator_init(&model_it, element);
902             while (mesh_model_iterator_has_next(&model_it)){
903                 mesh_model_t * model = mesh_model_iterator_next(&model_it);
904                 // find opcode in table
905                 const mesh_operation_t * operation = mesh_model_lookup_operation(model, pdu);
906                 if (operation == NULL) continue;
907                 if (mesh_access_validate_appkey_index(model, appkey_index) == 0) continue;
908                 mesh_access_acknowledged_received(src, opcode);
909                 operation->handler(model, pdu);
910                 return;
911             }
912         }
913     }
914     else if (mesh_network_address_group(dst)){
915 
916         // handle fixed group address
917         if (dst >= 0xff00){
918             int deliver_to_primary_element = 1;
919             switch (dst){
920                 case MESH_ADDRESS_ALL_PROXIES:
921                     if (mesh_foundation_gatt_proxy_get() == 1){
922                         deliver_to_primary_element = 1;
923                     }
924                     break;
925                 case MESH_ADDRESS_ALL_FRIENDS:
926                     // TODO: not implemented
927                     break;
928                 case MESH_ADDRESS_ALL_RELAYS:
929                     if (mesh_foundation_relay_get() == 1){
930                         deliver_to_primary_element =1;
931                     }
932                     break;
933                 case MESH_ADDRESS_ALL_NODES:
934                     deliver_to_primary_element = 1;
935                     break;
936                 default:
937                     break;
938             }
939             if (deliver_to_primary_element){
940                 mesh_model_iterator_t model_it;
941                 mesh_model_iterator_init(&model_it, mesh_node_get_primary_element());
942                 while (mesh_model_iterator_has_next(&model_it)){
943                     mesh_model_t * model = mesh_model_iterator_next(&model_it);
944                     // find opcode in table
945                     const mesh_operation_t * operation = mesh_model_lookup_operation(model, pdu);
946                     if (operation == NULL) continue;
947                     if (mesh_access_validate_appkey_index(model, appkey_index) == 0) continue;
948                     mesh_access_acknowledged_received(src, opcode);
949                     operation->handler(model, pdu);
950                     return;
951                 }
952             }
953         }
954         else {
955             // iterate over all elements / models, check subscription list
956             mesh_element_iterator_t it;
957             mesh_element_iterator_init(&it);
958             while (mesh_element_iterator_has_next(&it)){
959                 mesh_element_t * element = (mesh_element_t *) mesh_element_iterator_next(&it);
960                 mesh_model_iterator_t model_it;
961                 mesh_model_iterator_init(&model_it, element);
962                 while (mesh_model_iterator_has_next(&model_it)){
963                     mesh_model_t * model = mesh_model_iterator_next(&model_it);
964                     if (mesh_model_contains_subscription(model, dst)){
965                         // find opcode in table
966                         const mesh_operation_t * operation = mesh_model_lookup_operation(model, pdu);
967                         if (operation == NULL) continue;
968                         if (mesh_access_validate_appkey_index(model, appkey_index) == 0) continue;
969                         mesh_access_acknowledged_received(src, opcode);
970                         operation->handler(model, pdu);
971                         return;
972                     }
973                 }
974             }
975         }
976     }
977 
978     // operation not found -> done
979     printf("Message not handled\n");
980     mesh_access_message_processed(pdu);
981 }
982 
983 void mesh_access_message_processed(mesh_pdu_t * pdu){
984     mesh_upper_transport_message_processed_by_higher_layer(pdu);
985 }
986 
987 int mesh_model_contains_subscription(mesh_model_t * mesh_model, uint16_t address){
988     uint16_t i;
989     for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
990         if (mesh_model->subscriptions[i] == address) return 1;
991     }
992     return 0;
993 }
994 
995 static uint32_t mesh_network_key_tag_for_internal_index(uint16_t internal_index){
996     return ((uint32_t) 'M' << 24) | ((uint32_t) 'N' << 16) | ((uint32_t) internal_index);
997 }
998 
999 // Foundation state
1000 
1001 static const uint32_t mesh_foundation_state_tag = ((uint32_t) 'M' << 24) | ((uint32_t) 'F' << 16)  | ((uint32_t) 'N' << 8) | ((uint32_t) 'D' << 8);
1002 
1003 typedef struct {
1004     uint8_t gatt_proxy;
1005     uint8_t beacon;
1006     uint8_t default_ttl;
1007     uint8_t network_transmit;
1008     uint8_t relay;
1009     uint8_t relay_retransmit;
1010     uint8_t friend;
1011 } mesh_persistent_foundation_t;
1012 
1013 void mesh_foundation_state_load(void){
1014     mesh_access_setup_tlv();
1015     mesh_persistent_foundation_t data;
1016 
1017     int app_key_len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, mesh_foundation_state_tag, (uint8_t *) &data, sizeof(data));
1018     if (app_key_len == 0) return;
1019 
1020     mesh_foundation_gatt_proxy_set(data.gatt_proxy);
1021     mesh_foundation_beacon_set(data.gatt_proxy);
1022     mesh_foundation_default_ttl_set(data.default_ttl);
1023     mesh_foundation_friend_set(data.friend);
1024     mesh_foundation_network_transmit_set(data.network_transmit);
1025     mesh_foundation_relay_set(data.relay);
1026     mesh_foundation_relay_retransmit_set(data.relay_retransmit);
1027 }
1028 
1029 void mesh_foundation_state_store(void){
1030     mesh_access_setup_tlv();
1031     mesh_persistent_foundation_t data;
1032     data.gatt_proxy       = mesh_foundation_gatt_proxy_get();
1033     data.gatt_proxy       = mesh_foundation_beacon_get();
1034     data.default_ttl      = mesh_foundation_default_ttl_get();
1035     data.friend           = mesh_foundation_friend_get();
1036     data.network_transmit = mesh_foundation_network_transmit_get();
1037     data.relay            = mesh_foundation_relay_get();
1038     data.relay_retransmit = mesh_foundation_relay_retransmit_get();
1039     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, mesh_foundation_state_tag, (uint8_t *) &data, sizeof(data));
1040 }
1041 
1042 // Mesh Network Keys
1043 typedef struct {
1044     uint16_t netkey_index;
1045 
1046     uint8_t  version;
1047 
1048     // net_key from provisioner or Config Model Client
1049     uint8_t net_key[16];
1050 
1051     // derived data
1052 
1053     // k1
1054     uint8_t identity_key[16];
1055     uint8_t beacon_key[16];
1056 
1057     // k3
1058     uint8_t network_id[8];
1059 
1060     // k2
1061     uint8_t nid;
1062     uint8_t encryption_key[16];
1063     uint8_t privacy_key[16];
1064 } mesh_persistent_net_key_t;
1065 
1066 void mesh_store_network_key(mesh_network_key_t * network_key){
1067     mesh_access_setup_tlv();
1068     mesh_persistent_net_key_t data;
1069     printf("Store NetKey: internal index 0x%x, NetKey Index 0x%06x, NID %02x: ", network_key->internal_index, network_key->netkey_index, network_key->nid);
1070     printf_hexdump(network_key->net_key, 16);
1071     uint32_t tag = mesh_network_key_tag_for_internal_index(network_key->internal_index);
1072     data.netkey_index = network_key->netkey_index;
1073     memcpy(data.net_key, network_key->net_key, 16);
1074     memcpy(data.identity_key, network_key->identity_key, 16);
1075     memcpy(data.beacon_key, network_key->beacon_key, 16);
1076     memcpy(data.network_id, network_key->network_id, 8);
1077     data.nid = network_key->nid;
1078     data.version = network_key->version;
1079     memcpy(data.encryption_key, network_key->encryption_key, 16);
1080     memcpy(data.privacy_key, network_key->privacy_key, 16);
1081     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(mesh_persistent_net_key_t));
1082 }
1083 
1084 void mesh_delete_network_key(uint16_t internal_index){
1085     mesh_access_setup_tlv();
1086     uint32_t tag = mesh_network_key_tag_for_internal_index(internal_index);
1087     btstack_tlv_singleton_impl->delete_tag(btstack_tlv_singleton_context, tag);
1088 }
1089 
1090 
1091 void mesh_load_network_keys(void){
1092     mesh_access_setup_tlv();
1093     printf("Load Network Keys\n");
1094     uint16_t internal_index;
1095     for (internal_index = 0; internal_index < MAX_NR_MESH_NETWORK_KEYS; internal_index++){
1096         mesh_persistent_net_key_t data;
1097         uint32_t tag = mesh_network_key_tag_for_internal_index(internal_index);
1098         int netkey_len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
1099         if (netkey_len != sizeof(mesh_persistent_net_key_t)) continue;
1100 
1101         mesh_network_key_t * network_key = btstack_memory_mesh_network_key_get();
1102         if (network_key == NULL) return;
1103 
1104         network_key->netkey_index = data.netkey_index;
1105         memcpy(network_key->net_key, data.net_key, 16);
1106         memcpy(network_key->identity_key, data.identity_key, 16);
1107         memcpy(network_key->beacon_key, data.beacon_key, 16);
1108         memcpy(network_key->network_id, data.network_id, 8);
1109         network_key->nid = data.nid;
1110         network_key->version = data.version;
1111         memcpy(network_key->encryption_key, data.encryption_key, 16);
1112         memcpy(network_key->privacy_key, data.privacy_key, 16);
1113 
1114 #ifdef ENABLE_GATT_BEARER
1115         // setup advertisement with network id
1116         network_key->advertisement_with_network_id.adv_length = mesh_proxy_setup_advertising_with_network_id(network_key->advertisement_with_network_id.adv_data, network_key->network_id);
1117 #endif
1118 
1119         mesh_network_key_add(network_key);
1120 
1121         mesh_subnet_setup_for_netkey_index(network_key->netkey_index);
1122 
1123         printf("- internal index 0x%x, NetKey Index 0x%06x, NID %02x: ", network_key->internal_index, network_key->netkey_index, network_key->nid);
1124         printf_hexdump(network_key->net_key, 16);
1125     }
1126 }
1127 
1128 void mesh_delete_network_keys(void){
1129     printf("Delete Network Keys\n");
1130 
1131     uint16_t internal_index;
1132     for (internal_index = 0; internal_index < MAX_NR_MESH_NETWORK_KEYS; internal_index++){
1133         mesh_delete_network_key(internal_index);
1134     }
1135 }
1136 
1137 
1138 // Mesh App Keys
1139 
1140 typedef struct {
1141     uint16_t netkey_index;
1142     uint16_t appkey_index;
1143     uint8_t  aid;
1144     uint8_t  version;
1145     uint8_t  key[16];
1146 } mesh_persistent_app_key_t;
1147 
1148 static uint32_t mesh_transport_key_tag_for_internal_index(uint16_t internal_index){
1149     return ((uint32_t) 'M' << 24) | ((uint32_t) 'A' << 16) | ((uint32_t) internal_index);
1150 }
1151 
1152 void mesh_store_app_key(mesh_transport_key_t * app_key){
1153     mesh_access_setup_tlv();
1154 
1155     mesh_persistent_app_key_t data;
1156     printf("Store AppKey: internal index 0x%x, AppKey Index 0x%06x, AID %02x: ", app_key->internal_index, app_key->appkey_index, app_key->aid);
1157     printf_hexdump(app_key->key, 16);
1158     uint32_t tag = mesh_transport_key_tag_for_internal_index(app_key->internal_index);
1159     data.netkey_index = app_key->netkey_index;
1160     data.appkey_index = app_key->appkey_index;
1161     data.aid = app_key->aid;
1162     data.version = app_key->version;
1163     memcpy(data.key, app_key->key, 16);
1164     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
1165 }
1166 
1167 void mesh_delete_app_key(uint16_t internal_index){
1168     mesh_access_setup_tlv();
1169 
1170     uint32_t tag = mesh_transport_key_tag_for_internal_index(internal_index);
1171     btstack_tlv_singleton_impl->delete_tag(btstack_tlv_singleton_context, tag);
1172 }
1173 
1174 void mesh_load_app_keys(void){
1175     mesh_access_setup_tlv();
1176     printf("Load App Keys\n");
1177     uint16_t internal_index;
1178     for (internal_index = 0; internal_index < MAX_NR_MESH_TRANSPORT_KEYS; internal_index++){
1179         mesh_persistent_app_key_t data;
1180         uint32_t tag = mesh_transport_key_tag_for_internal_index(internal_index);
1181         int app_key_len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
1182         if (app_key_len == 0) continue;
1183 
1184         mesh_transport_key_t * key = btstack_memory_mesh_transport_key_get();
1185         if (key == NULL) return;
1186 
1187         key->internal_index = internal_index;
1188         key->appkey_index = data.appkey_index;
1189         key->netkey_index = data.netkey_index;
1190         key->aid          = data.aid;
1191         key->akf          = 1;
1192         key->version      = data.version;
1193         memcpy(key->key, data.key, 16);
1194         mesh_transport_key_add(key);
1195         printf("- internal index 0x%x, AppKey Index 0x%06x, AID %02x: ", key->internal_index, key->appkey_index, key->aid);
1196         printf_hexdump(key->key, 16);
1197     }
1198 }
1199 
1200 void mesh_delete_app_keys(void){
1201     printf("Delete App Keys\n");
1202 
1203     uint16_t internal_index;
1204     for (internal_index = 0; internal_index < MAX_NR_MESH_TRANSPORT_KEYS; internal_index++){
1205         mesh_delete_app_key(internal_index);
1206     }
1207 }
1208 
1209 
1210 // Model to Appkey List
1211 
1212 static uint32_t mesh_model_tag_for_index(uint16_t internal_model_id){
1213     return ((uint32_t) 'M' << 24) | ((uint32_t) 'B' << 16) | ((uint32_t) internal_model_id);
1214 }
1215 
1216 static void mesh_load_appkey_list(mesh_model_t * model){
1217     mesh_access_setup_tlv();
1218     uint32_t tag = mesh_model_tag_for_index(model->mid);
1219     btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &model->appkey_indices, sizeof(model->appkey_indices));
1220 }
1221 
1222 static void mesh_store_appkey_list(mesh_model_t * model){
1223     mesh_access_setup_tlv();
1224     uint32_t tag = mesh_model_tag_for_index(model->mid);
1225     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &model->appkey_indices, sizeof(model->appkey_indices));
1226 }
1227 
1228 static void mesh_delete_appkey_list(mesh_model_t * model){
1229     mesh_access_setup_tlv();
1230     uint32_t tag = mesh_model_tag_for_index(model->mid);
1231     btstack_tlv_singleton_impl->delete_tag(btstack_tlv_singleton_context, tag);
1232 }
1233 
1234 void mesh_load_appkey_lists(void){
1235     printf("Load Appkey Lists\n");
1236     // iterate over elements and models
1237     mesh_element_iterator_t element_it;
1238     mesh_element_iterator_init(&element_it);
1239     while (mesh_element_iterator_has_next(&element_it)){
1240         mesh_element_t * element = mesh_element_iterator_next(&element_it);
1241         mesh_model_iterator_t model_it;
1242         mesh_model_iterator_init(&model_it, element);
1243         while (mesh_model_iterator_has_next(&model_it)){
1244             mesh_model_t * model = mesh_model_iterator_next(&model_it);
1245             mesh_load_appkey_list(model);
1246         }
1247     }
1248 }
1249 
1250 void mesh_delete_appkey_lists(void){
1251     printf("Delete Appkey Lists\n");
1252     mesh_access_setup_tlv();
1253     // iterate over elements and models
1254     mesh_element_iterator_t element_it;
1255     mesh_element_iterator_init(&element_it);
1256     while (mesh_element_iterator_has_next(&element_it)){
1257         mesh_element_t * element = mesh_element_iterator_next(&element_it);
1258         mesh_model_iterator_t model_it;
1259         mesh_model_iterator_init(&model_it, element);
1260         while (mesh_model_iterator_has_next(&model_it)){
1261             mesh_model_t * model = mesh_model_iterator_next(&model_it);
1262             mesh_delete_appkey_list(model);
1263         }
1264     }
1265 }
1266 
1267 void mesh_model_reset_appkeys(mesh_model_t * mesh_model){
1268     uint16_t i;
1269     for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1270         mesh_model->appkey_indices[i] = MESH_APPKEY_INVALID;
1271     }
1272 }
1273 
1274 uint8_t mesh_model_bind_appkey(mesh_model_t * mesh_model, uint16_t appkey_index){
1275     uint16_t i;
1276     for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1277         if (mesh_model->appkey_indices[i] == appkey_index) return MESH_FOUNDATION_STATUS_SUCCESS;
1278     }
1279     for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1280         if (mesh_model->appkey_indices[i] == MESH_APPKEY_INVALID) {
1281             mesh_model->appkey_indices[i] = appkey_index;
1282             mesh_store_appkey_list(mesh_model);
1283             return MESH_FOUNDATION_STATUS_SUCCESS;
1284         }
1285     }
1286     return MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1287 }
1288 
1289 void mesh_model_unbind_appkey(mesh_model_t * mesh_model, uint16_t appkey_index){
1290     uint16_t i;
1291     for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1292         if (mesh_model->appkey_indices[i] == appkey_index) {
1293             mesh_model->appkey_indices[i] = MESH_APPKEY_INVALID;
1294             mesh_store_appkey_list(mesh_model);
1295         }
1296     }
1297 }
1298 
1299 int mesh_model_contains_appkey(mesh_model_t * mesh_model, uint16_t appkey_index){
1300     uint16_t i;
1301     for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1302         if (mesh_model->appkey_indices[i] == appkey_index) return 1;
1303     }
1304     return 0;
1305 
1306 }
1307 
1308 // Mesh IV Index
1309 static uint32_t mesh_tag_for_iv_index_and_seq_number(void){
1310     return ((uint32_t) 'M' << 24) | ((uint32_t) 'F' << 16) | ((uint32_t) 'I' << 9) | ((uint32_t) 'S');
1311 }
1312 
1313 typedef struct {
1314     uint32_t iv_index;
1315     uint32_t seq_number;
1316 } iv_index_and_sequence_number_t;
1317 
1318 static uint32_t sequence_number_last_stored;
1319 static uint32_t sequence_number_storage_trigger;
1320 
1321 void mesh_store_iv_index_after_provisioning(uint32_t iv_index){
1322     iv_index_and_sequence_number_t data;
1323     mesh_access_setup_tlv();
1324     uint32_t tag = mesh_tag_for_iv_index_and_seq_number();
1325     data.iv_index   = iv_index;
1326     data.seq_number = 0;
1327     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
1328 
1329     sequence_number_last_stored = data.seq_number;
1330     sequence_number_storage_trigger = sequence_number_last_stored + MESH_SEQUENCE_NUMBER_STORAGE_INTERVAL;
1331 }
1332 
1333 void mesh_store_iv_index_and_sequence_number(void){
1334     iv_index_and_sequence_number_t data;
1335     mesh_access_setup_tlv();
1336     uint32_t tag = mesh_tag_for_iv_index_and_seq_number();
1337     data.iv_index   = mesh_get_iv_index();
1338     data.seq_number = mesh_sequence_number_peek();
1339     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
1340 
1341     sequence_number_last_stored = data.seq_number;
1342     sequence_number_storage_trigger = sequence_number_last_stored + MESH_SEQUENCE_NUMBER_STORAGE_INTERVAL;
1343 }
1344 
1345 int mesh_load_iv_index_and_sequence_number(uint32_t * iv_index, uint32_t * sequence_number){
1346     iv_index_and_sequence_number_t data;
1347     mesh_access_setup_tlv();
1348     uint32_t tag = mesh_tag_for_iv_index_and_seq_number();
1349     uint32_t len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
1350     if (len == sizeof(iv_index_and_sequence_number_t)){
1351         *iv_index = data.iv_index;
1352         *sequence_number = data.seq_number;
1353         return 1;
1354     }
1355     return 0;
1356 }
1357 
1358 // higher layer
1359 static void mesh_persist_iv_index_and_sequence_number(void){
1360     if (mesh_sequence_number_peek() >= sequence_number_storage_trigger){
1361         mesh_store_iv_index_and_sequence_number();
1362     }
1363 }
1364 
1365 
1366 // Mesh Model Publication
1367 static btstack_timer_source_t mesh_access_publication_timer;
1368 
1369 static uint32_t mesh_model_publication_retransmit_count(uint8_t retransmit){
1370     return retransmit & 0x07u;
1371 }
1372 
1373 static uint32_t mesh_model_publication_retransmission_period_ms(uint8_t retransmit){
1374     return ((uint32_t)((retransmit >> 3) + 1)) * 50;
1375 }
1376 
1377 static void mesh_model_publication_setup_publication(mesh_publication_model_t * publication_model, uint32_t now){
1378 
1379     // set retransmit counter
1380     publication_model->retransmit_count = mesh_model_publication_retransmit_count(publication_model->retransmit);
1381 
1382     // schedule next publication or retransmission
1383     uint32_t publication_period_ms = mesh_access_transitions_step_ms_from_gdtt(publication_model->period);
1384 
1385     // set next publication
1386     if (publication_period_ms != 0){
1387         publication_model->next_publication_ms = now + publication_period_ms;
1388         publication_model->state = MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS;
1389     }
1390 }
1391 
1392 static void mesh_model_publication_setup_retransmission(mesh_publication_model_t * publication_model, uint32_t now){
1393     uint8_t num_retransmits = mesh_model_publication_retransmit_count(publication_model->retransmit);
1394     if (num_retransmits == 0) return;
1395 
1396     // calc next retransmit time
1397     uint32_t retransmission_ms = now + mesh_model_publication_retransmission_period_ms(publication_model->retransmit);
1398 
1399     // ignore if retransmission would be after next publication timeout
1400     if (publication_model->state == MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS){
1401         if (btstack_time_delta(retransmission_ms, publication_model->next_publication_ms) > 0) return;
1402     }
1403 
1404     // schedule next retransmission
1405     publication_model->next_retransmit_ms = retransmission_ms;
1406     publication_model->state = MESH_MODEL_PUBLICATION_STATE_W4_RETRANSMIT_MS;
1407 }
1408 
1409 static void mesh_model_publication_publish_now_model(mesh_model_t * mesh_model){
1410     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1411     if (publication_model == NULL) return;
1412     if (publication_model->publish_state_fn == NULL) return;
1413     uint16_t dest = publication_model->address;
1414     if (dest == MESH_ADDRESS_UNSASSIGNED) return;
1415     uint16_t appkey_index = publication_model->appkey_index;
1416     mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1417     if (app_key == NULL) return;
1418 
1419     // compose message
1420     mesh_pdu_t * pdu = (*publication_model->publish_state_fn)(mesh_model);
1421     if (pdu == NULL) return;
1422 
1423     mesh_upper_transport_setup_access_pdu_header(pdu, app_key->netkey_index, appkey_index, publication_model->ttl, mesh_access_get_element_address(mesh_model), dest, 0);
1424     mesh_upper_transport_send_access_pdu(pdu);
1425 }
1426 
1427 static void mesh_model_publication_run(btstack_timer_source_t * ts){
1428     UNUSED(ts);
1429 
1430     uint32_t now = btstack_run_loop_get_time_ms();
1431 
1432     // iterate over elements and models and handle time-based transitions
1433     mesh_element_iterator_t element_it;
1434     mesh_element_iterator_init(&element_it);
1435     while (mesh_element_iterator_has_next(&element_it)){
1436         mesh_element_t * element = mesh_element_iterator_next(&element_it);
1437         mesh_model_iterator_t model_it;
1438         mesh_model_iterator_init(&model_it, element);
1439         while (mesh_model_iterator_has_next(&model_it)){
1440             mesh_model_t * mesh_model = mesh_model_iterator_next(&model_it);
1441             mesh_publication_model_t * publication_model = mesh_model->publication_model;
1442             if (publication_model == NULL) continue;
1443 
1444             // schedule next
1445             switch (publication_model->state){
1446                 case MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS:
1447                     if (btstack_time_delta(publication_model->next_publication_ms, now) > 0) break;
1448                     // timeout
1449                     publication_model->publish_now = 1;
1450                     // schedule next publication and retransmission
1451                     mesh_model_publication_setup_publication(publication_model, now);
1452                     mesh_model_publication_setup_retransmission(publication_model, now);
1453                     break;
1454                 case MESH_MODEL_PUBLICATION_STATE_W4_RETRANSMIT_MS:
1455                     if (btstack_time_delta(publication_model->next_retransmit_ms, now) > 0) break;
1456                     // timeout
1457                     publication_model->publish_now = 1;
1458                     publication_model->retransmit_count--;
1459                     // schedule next retransmission
1460                     mesh_model_publication_setup_retransmission(publication_model, now);
1461                     break;
1462                 default:
1463                     break;
1464             }
1465 
1466             if (publication_model->publish_now == 0) continue;
1467 
1468             publication_model->publish_now = 0;
1469             mesh_model_publication_publish_now_model(mesh_model);
1470         }
1471     }
1472 
1473     int32_t next_timeout_ms = 0;
1474     mesh_element_iterator_init(&element_it);
1475     while (mesh_element_iterator_has_next(&element_it)){
1476         mesh_element_t * element = mesh_element_iterator_next(&element_it);
1477         mesh_model_iterator_t model_it;
1478         mesh_model_iterator_init(&model_it, element);
1479         while (mesh_model_iterator_has_next(&model_it)){
1480             mesh_model_t * mesh_model = mesh_model_iterator_next(&model_it);
1481             mesh_publication_model_t * publication_model = mesh_model->publication_model;
1482             if (publication_model == NULL) continue;
1483 
1484             // schedule next
1485             int32_t timeout_delta_ms;
1486             switch (publication_model->state){
1487                 case MESH_MODEL_PUBLICATION_STATE_W4_PUBLICATION_MS:
1488                     timeout_delta_ms = btstack_time_delta(publication_model->next_publication_ms, now);
1489                     if (next_timeout_ms == 0 || timeout_delta_ms < next_timeout_ms){
1490                         next_timeout_ms = timeout_delta_ms;
1491                     }
1492                     break;
1493                 case MESH_MODEL_PUBLICATION_STATE_W4_RETRANSMIT_MS:
1494                     timeout_delta_ms = btstack_time_delta(publication_model->next_retransmit_ms, now);
1495                     if (next_timeout_ms == 0 || timeout_delta_ms < next_timeout_ms){
1496                         next_timeout_ms = timeout_delta_ms;
1497                     }
1498                     break;
1499                 default:
1500                     break;
1501             }
1502         }
1503     }
1504 
1505     // set timer
1506     if (next_timeout_ms == 0) return;
1507 
1508     btstack_run_loop_set_timer(&mesh_access_publication_timer, next_timeout_ms);
1509     btstack_run_loop_set_timer_handler(&mesh_access_publication_timer, mesh_model_publication_run);
1510     btstack_run_loop_add_timer(&mesh_access_publication_timer);
1511 }
1512 
1513 void mesh_model_publication_start(mesh_model_t * mesh_model){
1514     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1515     if (publication_model == NULL) return;
1516 
1517     // reset state
1518     publication_model->state = MESH_MODEL_PUBLICATION_STATE_IDLE;
1519 
1520     // publish right away
1521     publication_model->publish_now = 1;
1522 
1523     // setup next publication and retransmission
1524     uint32_t now = btstack_run_loop_get_time_ms();
1525     mesh_model_publication_setup_publication(publication_model, now);
1526     mesh_model_publication_setup_retransmission(publication_model, now);
1527 
1528     mesh_model_publication_run(NULL);
1529 }
1530 
1531 void mesh_model_publication_stop(mesh_model_t * mesh_model){
1532     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1533     if (publication_model == NULL) return;
1534 
1535     // reset state
1536     publication_model->state = MESH_MODEL_PUBLICATION_STATE_IDLE;
1537 }
1538 
1539 void mesh_access_state_changed(mesh_model_t * mesh_model){
1540     mesh_publication_model_t * publication_model = mesh_model->publication_model;
1541     if (publication_model == NULL) return;
1542     publication_model->publish_now = 1;
1543     mesh_model_publication_run(NULL);
1544 }
1545 
1546 void mesh_access_netkey_finalize(mesh_network_key_t * network_key){
1547     mesh_network_key_remove(network_key);
1548     mesh_delete_network_key(network_key->internal_index);
1549     btstack_memory_mesh_network_key_free(network_key);
1550 }
1551 
1552 void mesh_access_appkey_finalize(mesh_transport_key_t * transport_key){
1553     mesh_transport_key_remove(transport_key);
1554     mesh_delete_app_key(transport_key->appkey_index);
1555     btstack_memory_mesh_transport_key_free(transport_key);
1556 }
1557 
1558 void mesh_access_key_refresh_revoke_keys(mesh_subnet_t * subnet){
1559     // delete old netkey index
1560     mesh_access_netkey_finalize(subnet->old_key);
1561     subnet->old_key = subnet->new_key;
1562     subnet->new_key = NULL;
1563 
1564     // delete old appkeys, if any
1565     mesh_transport_key_iterator_t it;
1566     mesh_transport_key_iterator_init(&it, subnet->netkey_index);
1567     while (mesh_transport_key_iterator_has_more(&it)){
1568         mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
1569         if (transport_key->old_key == 0) continue;
1570         mesh_access_appkey_finalize(transport_key);
1571     }
1572 }
1573 
1574 static void mesh_access_secure_network_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){
1575     UNUSED(channel);
1576     UNUSED(size);
1577 
1578     if (packet_type != MESH_BEACON_PACKET) return;
1579 
1580     // lookup subnet and netkey by network id
1581     uint8_t * beacon_network_id = &packet[2];
1582     mesh_subnet_iterator_t it;
1583     mesh_subnet_iterator_init(&it);
1584     mesh_subnet_t * subnet = NULL;
1585     uint8_t new_key = 0;
1586     while (mesh_subnet_iterator_has_more(&it)){
1587         mesh_subnet_t * item = mesh_subnet_iterator_get_next(&it);
1588         if (memcmp(item->old_key->network_id, beacon_network_id, 8) == 0 ) {
1589             subnet = item;
1590         }
1591         if (item->new_key != NULL && memcmp(item->new_key->network_id, beacon_network_id, 8) == 0 ) {
1592             subnet = item;
1593             new_key = 1;
1594         }
1595         break;
1596     }
1597     if (subnet == NULL) return;
1598 
1599     uint8_t flags = packet[1];
1600 
1601     // Key refresh via secure network beacons that are authenticated with new netkey
1602     if (new_key){
1603         // either first or second phase (in phase 0, new key is not set)
1604         int key_refresh_flag = flags & 1;
1605         if (key_refresh_flag){
1606             //  transition to phase 3 from either phase 1 or 2
1607             switch (subnet->key_refresh){
1608                 case MESH_KEY_REFRESH_FIRST_PHASE:
1609                 case MESH_KEY_REFRESH_SECOND_PHASE:
1610                     mesh_access_key_refresh_revoke_keys(subnet);
1611                     subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
1612                     break;
1613                 default:
1614                     break;
1615             }
1616         } else {
1617             //  transition to phase 2 from either phase 1
1618             switch (subnet->key_refresh){
1619                 case MESH_KEY_REFRESH_FIRST_PHASE:
1620                     // -- update state
1621                     subnet->key_refresh = MESH_KEY_REFRESH_SECOND_PHASE;
1622                     break;
1623                 default:
1624                     break;
1625             }
1626         }
1627     }
1628 
1629     // IV Update
1630 
1631     int     beacon_iv_update_active = flags & 2;
1632     int     local_iv_update_active = mesh_iv_update_active();
1633     uint32_t beacon_iv_index = big_endian_read_32(packet, 10);
1634     uint32_t local_iv_index = mesh_get_iv_index();
1635 
1636     int32_t iv_index_delta = (int32_t)(beacon_iv_index - local_iv_index);
1637 
1638     // "If a node in Normal Operation receives a Secure Network beacon with an IV index less than the last known IV Index or greater than
1639     //  the last known IV Index + 42, the Secure Network beacon shall be ignored."
1640     if (iv_index_delta < 0 || iv_index_delta > 42){
1641         return;
1642     }
1643 
1644     // "If a node in Normal Operation receives a Secure Network beacon with an IV index equal to the last known IV index+1 and
1645     //  the IV Update Flag set to 0, the node may update its IV without going to the IV Update in Progress state, or it may initiate
1646     //  an IV Index Recovery procedure (Section 3.10.6), or it may ignore the Secure Network beacon. The node makes the choice depending
1647     //  on the time since last IV update and the likelihood that the node has missed the Secure Network beacons with the IV update Flag set to 1.""
1648     if (local_iv_update_active == 0 && beacon_iv_update_active == 0 && iv_index_delta == 1){
1649         // instant iv update
1650         mesh_set_iv_index( beacon_iv_index );
1651         // store updated iv index
1652         mesh_store_iv_index_and_sequence_number();
1653         return;
1654     }
1655 
1656     // "If this node is a member of a primary subnet and receives a Secure Network beacon on a secondary subnet with an IV Index greater than
1657     //  the last known IV Index of the primary subnet, the Secure Network beacon shall be ignored."
1658     int member_of_primary_subnet = mesh_subnet_get_by_netkey_index(0) != NULL;
1659     int beacon_on_secondary_subnet = subnet->netkey_index != 0;
1660     if (member_of_primary_subnet && beacon_on_secondary_subnet && iv_index_delta > 0){
1661         return;
1662     }
1663 
1664     // "If a node in Normal Operation receives a Secure Network beacon with an IV index greater than the last known IV Index + 1..."
1665     // "... it may initiate an IV Index Recovery procedure, see Section 3.10.6."
1666     if (local_iv_update_active == 0 && iv_index_delta > 1){
1667         // "Upon receiving and successfully authenticating a Secure Network beacon for a primary subnet... "
1668         int beacon_on_primary_subnet = subnet->netkey_index == 0;
1669         if (!beacon_on_primary_subnet) return;
1670         // "... whose IV Index is 1 or more higher than the current known IV Index, the node shall "
1671         // " set its current IV Index and its current IV Update procedure state from the values in this Secure Network beacon."
1672         mesh_iv_index_recovered(beacon_iv_update_active, beacon_iv_index);
1673         // store updated iv index if in normal mode
1674         if (beacon_iv_update_active == 0){
1675             mesh_store_iv_index_and_sequence_number();
1676         }
1677         return;
1678     }
1679 
1680     if (local_iv_update_active == 0){
1681         if (beacon_iv_update_active){
1682             mesh_trigger_iv_update();
1683         }
1684     } else {
1685         if (beacon_iv_update_active == 0){
1686             // " At the point of transition, the node shall reset the sequence number to 0x000000."
1687             mesh_sequence_number_set(0);
1688             mesh_iv_update_completed();
1689             // store updated iv index
1690             mesh_store_iv_index_and_sequence_number();
1691         }
1692     }
1693 }
1694