43 #define DEBUG DEBUG_NONE
47 enum ieee802154e_header_ie_id {
48 HEADER_IE_LE_CSL = 0x1a,
50 HEADER_IE_DSME_PAN_DESCRIPTOR,
52 HEADER_IE_ACK_NACK_TIME_CORRECTION,
54 HEADER_IE_LOW_LATENCY_NETWORK_INFO,
55 HEADER_IE_LIST_TERMINATION_1 = 0x7e,
56 HEADER_IE_LIST_TERMINATION_2 = 0x7f,
60 enum ieee802154e_payload_ie_id {
63 PAYLOAD_IE_LIST_TERMINATION = 0xf,
67 enum ieee802154e_mlme_short_subie_id {
68 MLME_SHORT_IE_TSCH_SYNCHRONIZATION = 0x1a,
69 MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK,
70 MLME_SHORT_IE_TSCH_TIMESLOT,
71 MLME_SHORT_IE_TSCH_HOPPING_TIMING,
72 MLME_SHORT_IE_TSCH_EB_FILTER,
73 MLME_SHORT_IE_TSCH_MAC_METRICS_1,
74 MLME_SHORT_IE_TSCH_MAC_METRICS_2,
78 enum ieee802154e_mlme_long_subie_id {
79 MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE = 0x9,
82 #define WRITE16(buf, val) \
83 do { ((uint8_t *)(buf))[0] = (val) & 0xff; \
84 ((uint8_t *)(buf))[1] = ((val) >> 8) & 0xff; } while(0);
86 #define READ16(buf, var) \
87 (var) = ((uint8_t *)(buf))[0] | ((uint8_t *)(buf))[1] << 8
91 create_header_ie_descriptor(uint8_t *buf, uint8_t element_id,
int ie_len)
95 ie_desc = (ie_len & 0x7f) + ((element_id & 0xff) << 7);
96 WRITE16(buf, ie_desc);
101 create_payload_ie_descriptor(uint8_t *buf, uint8_t group_id,
int ie_len)
105 ie_desc = (ie_len & 0x07ff) + ((group_id & 0x0f) << 11) + (1 << 15);
106 WRITE16(buf, ie_desc);
111 create_mlme_short_ie_descriptor(uint8_t *buf, uint8_t sub_id,
int ie_len)
115 ie_desc = (ie_len & 0xff) + ((sub_id & 0x7f) << 8);
116 WRITE16(buf, ie_desc);
121 create_mlme_long_ie_descriptor(uint8_t *buf, uint8_t sub_id,
int ie_len)
125 ie_desc = (ie_len & 0x07ff) + ((sub_id & 0x0f) << 11) + (1 << 15);
126 WRITE16(buf, ie_desc);
132 struct ieee802154_ies *ies)
135 if(len >= 2 + ie_len && ies !=
NULL) {
137 uint16_t time_sync_field;
138 drift_us = ies->ie_time_correction;
139 time_sync_field = drift_us & 0x0fff;
140 if(ies->ie_is_nack) {
141 time_sync_field |= 0x8000;
143 WRITE16(buf+2, time_sync_field);
144 create_header_ie_descriptor(buf, HEADER_IE_ACK_NACK_TIME_CORRECTION, ie_len);
154 frame80215e_create_ie_header_list_termination_1(uint8_t *buf,
int len,
155 struct ieee802154_ies *ies)
158 if(len >= 2 + ie_len && ies !=
NULL) {
159 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_1, 0);
169 frame80215e_create_ie_header_list_termination_2(uint8_t *buf,
int len,
170 struct ieee802154_ies *ies)
173 if(len >= 2 + ie_len && ies !=
NULL) {
174 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_2, 0);
183 frame80215e_create_ie_payload_list_termination(uint8_t *buf,
int len,
184 struct ieee802154_ies *ies)
187 if(len >= 2 + ie_len && ies !=
NULL) {
188 create_payload_ie_descriptor(buf, PAYLOAD_IE_LIST_TERMINATION, 0);
197 frame80215e_create_ie_mlme(uint8_t *buf,
int len,
198 struct ieee802154_ies *ies)
201 if(len >= 2 + ie_len && ies !=
NULL) {
203 create_payload_ie_descriptor(buf, PAYLOAD_IE_MLME, ies->ie_mlme_len);
212 frame80215e_create_ie_tsch_synchronization(uint8_t *buf,
int len,
213 struct ieee802154_ies *ies)
216 if(len >= 2 + ie_len && ies !=
NULL) {
217 buf[2] = ies->ie_asn.ls4b;
218 buf[3] = ies->ie_asn.ls4b >> 8;
219 buf[4] = ies->ie_asn.ls4b >> 16;
220 buf[5] = ies->ie_asn.ls4b >> 24;
221 buf[6] = ies->ie_asn.ms1b;
222 buf[7] = ies->ie_join_priority;
223 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SYNCHRONIZATION, ie_len);
232 frame80215e_create_ie_tsch_slotframe_and_link(uint8_t *buf,
int len,
233 struct ieee802154_ies *ies)
237 int num_slotframes = ies->ie_tsch_slotframe_and_link.num_slotframes;
238 int num_links = ies->ie_tsch_slotframe_and_link.num_links;
239 int ie_len = 1 + num_slotframes * (4 + 5 * num_links);
240 if(num_slotframes > 1 || num_links > FRAME802154E_IE_MAX_LINKS
241 || len < 2 + ie_len) {
246 buf[2] = num_slotframes;
248 if(num_slotframes == 1) {
249 buf[2 + 1] = ies->ie_tsch_slotframe_and_link.slotframe_handle;
250 WRITE16(buf + 2 + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
251 buf[2 + 4] = num_links;
253 for(i = 0; i < num_links; i++) {
255 WRITE16(buf + 2 + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
256 WRITE16(buf + 2 + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
257 buf[2 + 5 + i * 5 + 4] = ies->ie_tsch_slotframe_and_link.links[i].link_options;
260 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK, ie_len);
269 frame80215e_create_ie_tsch_timeslot(uint8_t *buf,
int len,
270 struct ieee802154_ies *ies)
277 ie_len = ies->ie_tsch_timeslot_id == 0 ? 1 : 25;
278 if(len >= 2 + ie_len) {
279 buf[2] = ies->ie_tsch_timeslot_id;
280 if(ies->ie_tsch_timeslot_id != 0) {
282 for(i = 0; i < tsch_ts_elements_count; i++) {
283 WRITE16(buf + 3 + 2 * i, ies->ie_tsch_timeslot[i]);
286 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_TIMESLOT, ie_len);
295 frame80215e_create_ie_tsch_channel_hopping_sequence(uint8_t *buf,
int len,
296 struct ieee802154_ies *ies)
299 if(ies ==
NULL || ies->ie_hopping_sequence_len >
sizeof(ies->ie_hopping_sequence_list)) {
302 ie_len = ies->ie_channel_hopping_sequence_id == 0 ? 1 : 12 + ies->ie_hopping_sequence_len;
303 if(len >= 2 + ie_len && ies !=
NULL) {
304 buf[2] = ies->ie_channel_hopping_sequence_id;
310 WRITE16(buf + 10, ies->ie_hopping_sequence_len);
311 memcpy(buf + 12, ies->ie_hopping_sequence_list, ies->ie_hopping_sequence_len);
312 WRITE16(buf + 12 + ies->ie_hopping_sequence_len, 0);
313 create_mlme_long_ie_descriptor(buf, MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE, ie_len);
322 frame802154e_parse_header_ie(
const uint8_t *buf,
int len,
323 uint8_t element_id,
struct ieee802154_ies *ies)
326 case HEADER_IE_ACK_NACK_TIME_CORRECTION:
331 uint16_t time_sync_field = 0;
332 int16_t drift_us = 0;
336 READ16(buf, time_sync_field);
338 ies->ie_is_nack = (time_sync_field & (uint16_t)0x8000) ? 1 : 0;
340 if(time_sync_field & 0x0800) {
341 drift_us = time_sync_field | 0xf000;
343 drift_us = time_sync_field & 0x0fff;
346 ies->ie_time_correction = drift_us;
357 frame802154e_parse_mlme_short_ie(
const uint8_t *buf,
int len,
358 uint8_t sub_id,
struct ieee802154_ies *ies)
361 case MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK:
364 int num_slotframes = buf[0];
365 int num_links = buf[4];
366 if(num_slotframes == 0) {
369 if(num_slotframes <= 1 && num_links <= FRAME802154E_IE_MAX_LINKS
370 && len == 1 + num_slotframes * (4 + 5 * num_links)) {
373 ies->ie_tsch_slotframe_and_link.num_slotframes = buf[0];
374 ies->ie_tsch_slotframe_and_link.slotframe_handle = buf[1];
375 READ16(buf + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
376 ies->ie_tsch_slotframe_and_link.num_links = buf[4];
377 for(i = 0; i < num_links; i++) {
378 READ16(buf + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
379 READ16(buf + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
380 ies->ie_tsch_slotframe_and_link.links[i].link_options = buf[5 + i * 5 + 4];
387 case MLME_SHORT_IE_TSCH_SYNCHRONIZATION:
390 ies->ie_asn.ls4b = (uint32_t)buf[0];
391 ies->ie_asn.ls4b |= (uint32_t)buf[1] << 8;
392 ies->ie_asn.ls4b |= (uint32_t)buf[2] << 16;
393 ies->ie_asn.ls4b |= (uint32_t)buf[3] << 24;
394 ies->ie_asn.ms1b = (uint8_t)buf[4];
395 ies->ie_join_priority = (uint8_t)buf[5];
400 case MLME_SHORT_IE_TSCH_TIMESLOT:
401 if(len == 1 || len == 25) {
403 ies->ie_tsch_timeslot_id = buf[0];
406 for(i = 0; i < tsch_ts_elements_count; i++) {
407 READ16(buf+1+2*i, ies->ie_tsch_timeslot[i]);
420 frame802154e_parse_mlme_long_ie(
const uint8_t *buf,
int len,
421 uint8_t sub_id,
struct ieee802154_ies *ies)
424 case MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE:
427 ies->ie_channel_hopping_sequence_id = buf[0];
429 READ16(buf+8, ies->ie_hopping_sequence_len);
430 if(ies->ie_hopping_sequence_len <=
sizeof(ies->ie_hopping_sequence_list)
431 && len == 12 + ies->ie_hopping_sequence_len) {
432 memcpy(ies->ie_hopping_sequence_list, buf+10, ies->ie_hopping_sequence_len);
445 frame802154e_parse_information_elements(
const uint8_t *buf, uint8_t buf_size,
446 struct ieee802154_ies *ies)
448 const uint8_t *
start = buf;
453 int nested_mlme_len = 0;
454 enum {PARSING_HEADER_IE, PARSING_PAYLOAD_IE, PARSING_MLME_SUBIE} parsing_state;
461 parsing_state = PARSING_HEADER_IE;
462 ies->ie_payload_ie_offset = 0;
465 while(buf_size > 0) {
469 READ16(buf, ie_desc);
472 type = ie_desc & 0x8000 ? 1 : 0;
473 PRINTF(
"frame802154e: ie type %u, current state %u\n", type, parsing_state);
475 switch(parsing_state) {
476 case PARSING_HEADER_IE:
478 PRINTF(
"frame802154e: wrong type %04x\n", ie_desc);
482 len = ie_desc & 0x007f;
483 id = (ie_desc & 0x7f80) >> 7;
484 PRINTF(
"frame802154e: header ie len %u id %x\n", len,
id);
486 case HEADER_IE_LIST_TERMINATION_1:
489 parsing_state = PARSING_PAYLOAD_IE;
490 ies->ie_payload_ie_offset = buf -
start;
491 PRINTF(
"frame802154e: list termination 1, look for payload IEs\n");
493 PRINTF(
"frame802154e: list termination 1, wrong len %u\n", len);
497 case HEADER_IE_LIST_TERMINATION_2:
500 ies->ie_payload_ie_offset = buf -
start;
501 PRINTF(
"frame802154e: list termination 2\n");
502 return buf + len -
start;
504 PRINTF(
"frame802154e: list termination 2, wrong len %u\n", len);
508 if(len > buf_size || frame802154e_parse_header_ie(buf, len,
id, ies) == -1) {
509 PRINTF(
"frame802154e: failed to parse\n");
515 case PARSING_PAYLOAD_IE:
517 PRINTF(
"frame802154e: wrong type %04x\n", ie_desc);
521 len = ie_desc & 0x7ff;
522 id = (ie_desc & 0x7800) >> 11;
523 PRINTF(
"frame802154e: payload ie len %u id %x\n", len,
id);
525 case PAYLOAD_IE_MLME:
527 parsing_state = PARSING_MLME_SUBIE;
528 nested_mlme_len = len;
530 PRINTF(
"frame802154e: entering MLME ie with len %u\n", nested_mlme_len);
532 case PAYLOAD_IE_LIST_TERMINATION:
533 PRINTF(
"frame802154e: payload ie list termination %u\n", len);
534 return (len == 0) ? buf + len - start : -1;
536 PRINTF(
"frame802154e: non-supported payload ie\n");
540 case PARSING_MLME_SUBIE:
545 len = ie_desc & 0x00ff;
546 id = (ie_desc & 0x7f00) >> 8;
547 PRINTF(
"frame802154e: short mlme ie len %u id %x\n", len,
id);
548 if(len > buf_size || frame802154e_parse_mlme_short_ie(buf, len,
id, ies) == -1) {
549 PRINTF(
"frame802154e: failed to parse ie\n");
554 len = ie_desc & 0x7ff;
555 id = (ie_desc & 0x7800) >> 11;
556 PRINTF(
"frame802154e: long mlme ie len %u id %x\n", len,
id);
557 if(len > buf_size || frame802154e_parse_mlme_long_ie(buf, len,
id, ies) == -1) {
558 PRINTF(
"frame802154e: failed to parse ie\n");
563 nested_mlme_len -= 2 + len;
564 if(nested_mlme_len < 0) {
565 PRINTF(
"frame802154e: found more sub-IEs than initially advertised\n");
569 if(nested_mlme_len == 0) {
570 PRINTF(
"frame802154e: end of MLME IE parsing\n");
572 parsing_state = PARSING_PAYLOAD_IE;
580 if(parsing_state == PARSING_HEADER_IE) {
581 ies->ie_payload_ie_offset = buf -
start;
static void start(void)
Start measurement.
int frame80215e_create_ie_header_ack_nack_time_correction(uint8_t *buf, int len, struct ieee802154_ies *ies)
Insert various Information Elements.
A set of debugging macros for the netstack
#define NULL
The null pointer.
IEEE 802.15.4e Information Element (IE) creation and parsing.