45#define LOG_MODULE "Frame 15.4"
46#define LOG_LEVEL LOG_LEVEL_FRAMER
49enum ieee802154e_header_ie_id {
50 HEADER_IE_LE_CSL = 0x1a,
52 HEADER_IE_DSME_PAN_DESCRIPTOR,
54 HEADER_IE_ACK_NACK_TIME_CORRECTION,
56 HEADER_IE_LOW_LATENCY_NETWORK_INFO,
57 HEADER_IE_LIST_TERMINATION_1 = 0x7e,
58 HEADER_IE_LIST_TERMINATION_2 = 0x7f,
62enum ieee802154e_payload_ie_id {
65 PAYLOAD_IE_IETF = 0x5,
66 PAYLOAD_IE_LIST_TERMINATION = 0xf,
70enum ieee802154e_mlme_short_subie_id {
71 MLME_SHORT_IE_TSCH_SYNCHRONIZATION = 0x1a,
72 MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK,
73 MLME_SHORT_IE_TSCH_TIMESLOT,
74 MLME_SHORT_IE_TSCH_HOPPING_TIMING,
75 MLME_SHORT_IE_TSCH_EB_FILTER,
76 MLME_SHORT_IE_TSCH_MAC_METRICS_1,
77 MLME_SHORT_IE_TSCH_MAC_METRICS_2,
81enum ieee802154e_mlme_long_subie_id {
82 MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE = 0x9,
86enum ieee802154e_ietf_subie_id {
87 IETF_IE_6TOP = SIXTOP_SUBIE_ID,
90#define WRITE16(buf, val) \
91 do { ((uint8_t *)(buf))[0] = (val) & 0xff; \
92 ((uint8_t *)(buf))[1] = ((val) >> 8) & 0xff; } while(0)
94#define READ16(buf, var) \
95 (var) = ((uint8_t *)(buf))[0] | ((uint8_t *)(buf))[1] << 8
99create_header_ie_descriptor(uint8_t *buf, uint8_t element_id,
int ie_len)
103 ie_desc = (ie_len & 0x7f) + ((element_id & 0xff) << 7);
104 WRITE16(buf, ie_desc);
109create_payload_ie_descriptor(uint8_t *buf, uint8_t group_id,
int ie_len)
113 ie_desc = (ie_len & 0x07ff) + ((group_id & 0x0f) << 11) + (1 << 15);
114 WRITE16(buf, ie_desc);
119create_mlme_short_ie_descriptor(uint8_t *buf, uint8_t sub_id,
int ie_len)
123 ie_desc = (ie_len & 0xff) + ((sub_id & 0x7f) << 8);
124 WRITE16(buf, ie_desc);
129create_mlme_long_ie_descriptor(uint8_t *buf, uint8_t sub_id,
int ie_len)
133 ie_desc = (ie_len & 0x07ff) + ((sub_id & 0x0f) << 11) + (1 << 15);
134 WRITE16(buf, ie_desc);
139frame802154e_create_ie_rendezvous_time(uint8_t *buf,
int len,
140 const struct ieee802154_ies *ies)
142 if(!ies || (len < 4)) {
146 WRITE16(buf + 2, ies->rendezvous_time);
147 create_header_ie_descriptor(buf, HEADER_IE_RZ_TIME, 2);
152frame802154e_create_ie_csl(uint8_t *buf,
int len,
153 const struct ieee802154_ies *ies)
155 if(!ies || (len < 6)) {
159 WRITE16(buf + 2, ies->csl_phase);
160 WRITE16(buf + 4, ies->csl_period);
161 create_header_ie_descriptor(buf, HEADER_IE_LE_CSL, 4);
169 const struct ieee802154_ies *ies)
172 if(len >= 2 + ie_len && ies != NULL) {
174 uint16_t time_sync_field;
175 drift_us = ies->ie_time_correction;
176 time_sync_field = drift_us & 0x0fff;
177 if(ies->ie_is_nack) {
178 time_sync_field |= 0x8000;
180 WRITE16(buf+2, time_sync_field);
181 create_header_ie_descriptor(buf, HEADER_IE_ACK_NACK_TIME_CORRECTION, ie_len);
191frame80215e_create_ie_header_list_termination_1(uint8_t *buf,
int len,
192 const struct ieee802154_ies *ies)
195 if(len >= 2 + ie_len && ies != NULL) {
196 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_1, 0);
206frame80215e_create_ie_header_list_termination_2(uint8_t *buf,
int len,
207 const struct ieee802154_ies *ies)
210 if(len >= 2 + ie_len && ies != NULL) {
211 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_2, 0);
220frame80215e_create_ie_payload_list_termination(uint8_t *buf,
int len,
221 const struct ieee802154_ies *ies)
224 if(len >= 2 + ie_len && ies != NULL) {
225 create_payload_ie_descriptor(buf, PAYLOAD_IE_LIST_TERMINATION, 0);
235frame80215e_create_ie_ietf(uint8_t *buf,
int len,
236 const struct ieee802154_ies *ies)
238 if(len >= 2 && ies != NULL) {
239 create_payload_ie_descriptor(buf,
241 ies->sixtop_ie_content_len);
242 return 2 + ies->sixtop_ie_content_len;
250frame80215e_create_ie_mlme(uint8_t *buf,
int len,
251 const struct ieee802154_ies *ies)
254 if(len >= 2 + ie_len && ies != NULL) {
256 create_payload_ie_descriptor(buf, PAYLOAD_IE_MLME, ies->ie_mlme_len);
265frame80215e_create_ie_tsch_synchronization(uint8_t *buf,
int len,
266 const struct ieee802154_ies *ies)
269 if(len >= 2 + ie_len && ies != NULL) {
270 buf[2] = ies->ie_asn.ls4b;
271 buf[3] = ies->ie_asn.ls4b >> 8;
272 buf[4] = ies->ie_asn.ls4b >> 16;
273 buf[5] = ies->ie_asn.ls4b >> 24;
274 buf[6] = ies->ie_asn.ms1b;
275 buf[7] = ies->ie_join_priority;
276 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SYNCHRONIZATION, ie_len);
285frame80215e_create_ie_tsch_slotframe_and_link(uint8_t *buf,
int len,
286 const struct ieee802154_ies *ies)
290 int num_slotframes = ies->ie_tsch_slotframe_and_link.num_slotframes;
291 int num_links = ies->ie_tsch_slotframe_and_link.num_links;
292 int ie_len = 1 + num_slotframes * (4 + 5 * num_links);
293 if(num_slotframes > 1 || num_links > FRAME802154E_IE_MAX_LINKS
294 || len < 2 + ie_len) {
299 buf[2] = num_slotframes;
301 if(num_slotframes == 1) {
302 buf[2 + 1] = ies->ie_tsch_slotframe_and_link.slotframe_handle;
303 WRITE16(buf + 2 + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
304 buf[2 + 4] = num_links;
306 for(i = 0; i < num_links; i++) {
308 WRITE16(buf + 2 + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
309 WRITE16(buf + 2 + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
310 buf[2 + 5 + i * 5 + 4] = ies->ie_tsch_slotframe_and_link.links[i].link_options;
313 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK, ie_len);
322frame80215e_create_ie_tsch_timeslot(uint8_t *buf,
int len,
323 const struct ieee802154_ies *ies)
330 ie_len = ies->ie_tsch_timeslot_id == 0 ? 1 : 25;
331 if(len >= 2 + ie_len) {
332 buf[2] = ies->ie_tsch_timeslot_id;
333 if(ies->ie_tsch_timeslot_id != 0) {
335 for(i = 0; i < tsch_ts_elements_count; i++) {
336 WRITE16(buf + 3 + 2 * i, ies->ie_tsch_timeslot[i]);
339 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_TIMESLOT, ie_len);
348frame80215e_create_ie_tsch_channel_hopping_sequence(uint8_t *buf,
int len,
349 const struct ieee802154_ies *ies)
352 if(ies == NULL || ies->ie_hopping_sequence_len >
sizeof(ies->ie_hopping_sequence_list)) {
355 ie_len = ies->ie_channel_hopping_sequence_id == 0 ? 1 : 12 + ies->ie_hopping_sequence_len;
356 if(len >= 2 + ie_len && ies != NULL) {
357 buf[2] = ies->ie_channel_hopping_sequence_id;
363 WRITE16(buf + 10, ies->ie_hopping_sequence_len);
364 memcpy(buf + 12, ies->ie_hopping_sequence_list, ies->ie_hopping_sequence_len);
365 WRITE16(buf + 12 + ies->ie_hopping_sequence_len, 0);
366 create_mlme_long_ie_descriptor(buf, MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE, ie_len);
375frame802154e_parse_header_ie(
const uint8_t *buf,
int len,
376 uint8_t element_id,
struct ieee802154_ies *ies)
379 case HEADER_IE_ACK_NACK_TIME_CORRECTION:
384 uint16_t time_sync_field = 0;
385 int16_t drift_us = 0;
389 READ16(buf, time_sync_field);
391 ies->ie_is_nack = (time_sync_field & (uint16_t)0x8000) ? 1 : 0;
393 if(time_sync_field & 0x0800) {
394 drift_us = time_sync_field | 0xf000;
396 drift_us = time_sync_field & 0x0fff;
399 ies->ie_time_correction = drift_us;
405 case HEADER_IE_RZ_TIME:
406 if((len == 2) && ies) {
407 READ16(buf, ies->rendezvous_time);
411 case HEADER_IE_LE_CSL:
412 if(ies && (len == 4)) {
413 READ16(buf, ies->csl_phase);
414 READ16(buf + 2, ies->csl_period);
425frame802154e_parse_mlme_short_ie(
const uint8_t *buf,
int len,
426 uint8_t sub_id,
struct ieee802154_ies *ies)
429 case MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK:
432 int num_slotframes = buf[0];
433 int num_links = buf[4];
434 if(num_slotframes == 0) {
437 if(num_slotframes <= 1 && num_links <= FRAME802154E_IE_MAX_LINKS
438 && len == 1 + num_slotframes * (4 + 5 * num_links)) {
441 ies->ie_tsch_slotframe_and_link.num_slotframes = buf[0];
442 ies->ie_tsch_slotframe_and_link.slotframe_handle = buf[1];
443 READ16(buf + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
444 ies->ie_tsch_slotframe_and_link.num_links = buf[4];
445 for(i = 0; i < num_links; i++) {
446 READ16(buf + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
447 READ16(buf + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
448 ies->ie_tsch_slotframe_and_link.links[i].link_options = buf[5 + i * 5 + 4];
455 case MLME_SHORT_IE_TSCH_SYNCHRONIZATION:
458 ies->ie_asn.ls4b = (uint32_t)buf[0];
459 ies->ie_asn.ls4b |= (uint32_t)buf[1] << 8;
460 ies->ie_asn.ls4b |= (uint32_t)buf[2] << 16;
461 ies->ie_asn.ls4b |= (uint32_t)buf[3] << 24;
462 ies->ie_asn.ms1b = (uint8_t)buf[4];
463 ies->ie_join_priority = (uint8_t)buf[5];
468 case MLME_SHORT_IE_TSCH_TIMESLOT:
469 if(len == 1 || len == 25) {
471 ies->ie_tsch_timeslot_id = buf[0];
474 for(i = 0; i < tsch_ts_elements_count; i++) {
475 READ16(buf+1+2*i, ies->ie_tsch_timeslot[i]);
488frame802154e_parse_mlme_long_ie(
const uint8_t *buf,
int len,
489 uint8_t sub_id,
struct ieee802154_ies *ies)
492 case MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE:
504 ies->ie_channel_hopping_sequence_id = buf[0];
510 READ16(buf + 8, seq_len);
511 if(seq_len <=
sizeof(ies->ie_hopping_sequence_list)
512 && len == 12 + seq_len) {
514 ies->ie_channel_hopping_sequence_id = buf[0];
515 ies->ie_hopping_sequence_len = seq_len;
516 memcpy(ies->ie_hopping_sequence_list, buf + 10, seq_len);
528frame802154e_parse_information_elements(
const uint8_t *buf, uint8_t buf_size,
529 struct ieee802154_ies *ies)
531 const uint8_t *
start = buf;
536 int nested_mlme_len = 0;
537 enum {PARSING_HEADER_IE, PARSING_PAYLOAD_IE, PARSING_MLME_SUBIE} parsing_state;
544 parsing_state = PARSING_HEADER_IE;
545 ies->ie_payload_ie_offset = 0;
548 while(buf_size > 0) {
552 READ16(buf, ie_desc);
555 type = ie_desc & 0x8000 ? 1 : 0;
556 LOG_DBG(
"ie type %u, current state %u\n", type, parsing_state);
558 switch(parsing_state) {
559 case PARSING_HEADER_IE:
561 LOG_ERR(
"header ie: wrong type %04x\n", ie_desc);
565 len = ie_desc & 0x007f;
566 id = (ie_desc & 0x7f80) >> 7;
567 LOG_DBG(
"header ie: len %u id %x\n", len,
id);
569 case HEADER_IE_LIST_TERMINATION_1:
572 parsing_state = PARSING_PAYLOAD_IE;
573 ies->ie_payload_ie_offset = buf -
start;
574 LOG_DBG(
"list termination 1, look for payload IEs\n");
576 LOG_ERR(
"list termination 1, wrong len %u\n", len);
580 case HEADER_IE_LIST_TERMINATION_2:
583 ies->ie_payload_ie_offset = buf -
start;
584 LOG_DBG(
"list termination 2\n");
585 return buf + len -
start;
587 LOG_ERR(
"list termination 2, wrong len %u\n", len);
591 if(len > buf_size || frame802154e_parse_header_ie(buf, len,
id, ies) == -1) {
592 LOG_ERR(
"failed to parse\n");
598 case PARSING_PAYLOAD_IE:
600 LOG_ERR(
"payload ie: wrong type %04x\n", ie_desc);
604 len = ie_desc & 0x7ff;
605 id = (ie_desc & 0x7800) >> 11;
606 LOG_DBG(
"payload ie: len %u id %x\n", len,
id);
608 case PAYLOAD_IE_MLME:
610 parsing_state = PARSING_MLME_SUBIE;
611 nested_mlme_len = len;
613 LOG_DBG(
"entering MLME ie with len %u\n", nested_mlme_len);
616 case PAYLOAD_IE_IETF:
624 if(len < 1 || len > buf_size) {
625 LOG_ERR(
"frame802154e: invalid IETF IE len %u (remaining %u)\n",
636 ies->sixtop_ie_content_ptr = buf + 1;
642 ies->sixtop_ie_content_len = len - 1;
645 LOG_ERR(
"frame802154e: unsupported IETF sub-IE %u\n", *buf);
650 case PAYLOAD_IE_LIST_TERMINATION:
651 LOG_DBG(
"payload ie list termination %u\n", len);
652 return (len == 0) ? buf + len -
start : -1;
654 LOG_ERR(
"non-supported payload ie\n");
658 case PARSING_MLME_SUBIE:
663 len = ie_desc & 0x00ff;
664 id = (ie_desc & 0x7f00) >> 8;
665 LOG_DBG(
"short mlme ie len %u id %x\n", len,
id);
666 if(len > buf_size || frame802154e_parse_mlme_short_ie(buf, len,
id, ies) == -1) {
667 LOG_ERR(
"failed to parse ie\n");
672 len = ie_desc & 0x7ff;
673 id = (ie_desc & 0x7800) >> 11;
674 LOG_DBG(
"long mlme ie len %u id %x\n", len,
id);
675 if(len > buf_size || frame802154e_parse_mlme_long_ie(buf, len,
id, ies) == -1) {
676 LOG_ERR(
"failed to parse ie\n");
681 nested_mlme_len -= 2 + len;
682 if(nested_mlme_len < 0) {
683 LOG_ERR(
"found more sub-IEs than initially advertised\n");
687 if(nested_mlme_len == 0) {
688 LOG_DBG(
"end of MLME IE parsing\n");
690 parsing_state = PARSING_PAYLOAD_IE;
701 LOG_ERR(
"frame802154e: IE len %u exceeds remaining %u\n", len, buf_size);
708 if(parsing_state == PARSING_HEADER_IE) {
709 ies->ie_payload_ie_offset = buf -
start;
int frame80215e_create_ie_header_ack_nack_time_correction(uint8_t *buf, int len, const struct ieee802154_ies *ies)
Insert various Information Elements.
IEEE 802.15.4e Information Element (IE) creation and parsing.
static void start(void)
Start measurement.
Header file for the logging system.
6TiSCH Operation Sublayer (6top) APIs