45 #define LOG_MODULE "Frame 15.4" 46 #define LOG_LEVEL LOG_LEVEL_FRAMER 49 enum 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,
62 enum ieee802154e_payload_ie_id {
65 PAYLOAD_IE_IETF = 0x5,
66 PAYLOAD_IE_LIST_TERMINATION = 0xf,
70 enum 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,
81 enum ieee802154e_mlme_long_subie_id {
82 MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE = 0x9,
86 enum 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 99 create_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);
109 create_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);
119 create_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);
129 create_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);
140 struct ieee802154_ies *ies)
143 if(len >= 2 + ie_len && ies != NULL) {
145 uint16_t time_sync_field;
146 drift_us = ies->ie_time_correction;
147 time_sync_field = drift_us & 0x0fff;
148 if(ies->ie_is_nack) {
149 time_sync_field |= 0x8000;
151 WRITE16(buf+2, time_sync_field);
152 create_header_ie_descriptor(buf, HEADER_IE_ACK_NACK_TIME_CORRECTION, ie_len);
162 frame80215e_create_ie_header_list_termination_1(uint8_t *buf,
int len,
163 struct ieee802154_ies *ies)
166 if(len >= 2 + ie_len && ies != NULL) {
167 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_1, 0);
177 frame80215e_create_ie_header_list_termination_2(uint8_t *buf,
int len,
178 struct ieee802154_ies *ies)
181 if(len >= 2 + ie_len && ies != NULL) {
182 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_2, 0);
191 frame80215e_create_ie_payload_list_termination(uint8_t *buf,
int len,
192 struct ieee802154_ies *ies)
195 if(len >= 2 + ie_len && ies != NULL) {
196 create_payload_ie_descriptor(buf, PAYLOAD_IE_LIST_TERMINATION, 0);
206 frame80215e_create_ie_ietf(uint8_t *buf,
int len,
struct ieee802154_ies *ies)
208 if(len >= 2 && ies != NULL) {
209 create_payload_ie_descriptor(buf,
211 ies->sixtop_ie_content_len);
212 return 2 + ies->sixtop_ie_content_len;
220 frame80215e_create_ie_mlme(uint8_t *buf,
int len,
221 struct ieee802154_ies *ies)
224 if(len >= 2 + ie_len && ies != NULL) {
226 create_payload_ie_descriptor(buf, PAYLOAD_IE_MLME, ies->ie_mlme_len);
235 frame80215e_create_ie_tsch_synchronization(uint8_t *buf,
int len,
236 struct ieee802154_ies *ies)
239 if(len >= 2 + ie_len && ies != NULL) {
240 buf[2] = ies->ie_asn.ls4b;
241 buf[3] = ies->ie_asn.ls4b >> 8;
242 buf[4] = ies->ie_asn.ls4b >> 16;
243 buf[5] = ies->ie_asn.ls4b >> 24;
244 buf[6] = ies->ie_asn.ms1b;
245 buf[7] = ies->ie_join_priority;
246 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SYNCHRONIZATION, ie_len);
255 frame80215e_create_ie_tsch_slotframe_and_link(uint8_t *buf,
int len,
256 struct ieee802154_ies *ies)
260 int num_slotframes = ies->ie_tsch_slotframe_and_link.num_slotframes;
261 int num_links = ies->ie_tsch_slotframe_and_link.num_links;
262 int ie_len = 1 + num_slotframes * (4 + 5 * num_links);
263 if(num_slotframes > 1 || num_links > FRAME802154E_IE_MAX_LINKS
264 || len < 2 + ie_len) {
269 buf[2] = num_slotframes;
271 if(num_slotframes == 1) {
272 buf[2 + 1] = ies->ie_tsch_slotframe_and_link.slotframe_handle;
273 WRITE16(buf + 2 + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
274 buf[2 + 4] = num_links;
276 for(i = 0; i < num_links; i++) {
278 WRITE16(buf + 2 + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
279 WRITE16(buf + 2 + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
280 buf[2 + 5 + i * 5 + 4] = ies->ie_tsch_slotframe_and_link.links[i].link_options;
283 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK, ie_len);
292 frame80215e_create_ie_tsch_timeslot(uint8_t *buf,
int len,
293 struct ieee802154_ies *ies)
300 ie_len = ies->ie_tsch_timeslot_id == 0 ? 1 : 25;
301 if(len >= 2 + ie_len) {
302 buf[2] = ies->ie_tsch_timeslot_id;
303 if(ies->ie_tsch_timeslot_id != 0) {
305 for(i = 0; i < tsch_ts_elements_count; i++) {
306 WRITE16(buf + 3 + 2 * i, ies->ie_tsch_timeslot[i]);
309 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_TIMESLOT, ie_len);
318 frame80215e_create_ie_tsch_channel_hopping_sequence(uint8_t *buf,
int len,
319 struct ieee802154_ies *ies)
322 if(ies == NULL || ies->ie_hopping_sequence_len >
sizeof(ies->ie_hopping_sequence_list)) {
325 ie_len = ies->ie_channel_hopping_sequence_id == 0 ? 1 : 12 + ies->ie_hopping_sequence_len;
326 if(len >= 2 + ie_len && ies != NULL) {
327 buf[2] = ies->ie_channel_hopping_sequence_id;
333 WRITE16(buf + 10, ies->ie_hopping_sequence_len);
334 memcpy(buf + 12, ies->ie_hopping_sequence_list, ies->ie_hopping_sequence_len);
335 WRITE16(buf + 12 + ies->ie_hopping_sequence_len, 0);
336 create_mlme_long_ie_descriptor(buf, MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE, ie_len);
345 frame802154e_parse_header_ie(
const uint8_t *buf,
int len,
346 uint8_t element_id,
struct ieee802154_ies *ies)
349 case HEADER_IE_ACK_NACK_TIME_CORRECTION:
354 uint16_t time_sync_field = 0;
355 int16_t drift_us = 0;
359 READ16(buf, time_sync_field);
361 ies->ie_is_nack = (time_sync_field & (uint16_t)0x8000) ? 1 : 0;
363 if(time_sync_field & 0x0800) {
364 drift_us = time_sync_field | 0xf000;
366 drift_us = time_sync_field & 0x0fff;
369 ies->ie_time_correction = drift_us;
380 frame802154e_parse_mlme_short_ie(
const uint8_t *buf,
int len,
381 uint8_t sub_id,
struct ieee802154_ies *ies)
384 case MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK:
387 int num_slotframes = buf[0];
388 int num_links = buf[4];
389 if(num_slotframes == 0) {
392 if(num_slotframes <= 1 && num_links <= FRAME802154E_IE_MAX_LINKS
393 && len == 1 + num_slotframes * (4 + 5 * num_links)) {
396 ies->ie_tsch_slotframe_and_link.num_slotframes = buf[0];
397 ies->ie_tsch_slotframe_and_link.slotframe_handle = buf[1];
398 READ16(buf + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
399 ies->ie_tsch_slotframe_and_link.num_links = buf[4];
400 for(i = 0; i < num_links; i++) {
401 READ16(buf + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
402 READ16(buf + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
403 ies->ie_tsch_slotframe_and_link.links[i].link_options = buf[5 + i * 5 + 4];
410 case MLME_SHORT_IE_TSCH_SYNCHRONIZATION:
413 ies->ie_asn.ls4b = (uint32_t)buf[0];
414 ies->ie_asn.ls4b |= (uint32_t)buf[1] << 8;
415 ies->ie_asn.ls4b |= (uint32_t)buf[2] << 16;
416 ies->ie_asn.ls4b |= (uint32_t)buf[3] << 24;
417 ies->ie_asn.ms1b = (uint8_t)buf[4];
418 ies->ie_join_priority = (uint8_t)buf[5];
423 case MLME_SHORT_IE_TSCH_TIMESLOT:
424 if(len == 1 || len == 25) {
426 ies->ie_tsch_timeslot_id = buf[0];
429 for(i = 0; i < tsch_ts_elements_count; i++) {
430 READ16(buf+1+2*i, ies->ie_tsch_timeslot[i]);
443 frame802154e_parse_mlme_long_ie(
const uint8_t *buf,
int len,
444 uint8_t sub_id,
struct ieee802154_ies *ies)
447 case MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE:
450 ies->ie_channel_hopping_sequence_id = buf[0];
452 READ16(buf+8, ies->ie_hopping_sequence_len);
453 if(ies->ie_hopping_sequence_len <=
sizeof(ies->ie_hopping_sequence_list)
454 && len == 12 + ies->ie_hopping_sequence_len) {
455 memcpy(ies->ie_hopping_sequence_list, buf+10, ies->ie_hopping_sequence_len);
468 frame802154e_parse_information_elements(
const uint8_t *buf, uint8_t buf_size,
469 struct ieee802154_ies *ies)
471 const uint8_t *
start = buf;
476 int nested_mlme_len = 0;
477 enum {PARSING_HEADER_IE, PARSING_PAYLOAD_IE, PARSING_MLME_SUBIE} parsing_state;
484 parsing_state = PARSING_HEADER_IE;
485 ies->ie_payload_ie_offset = 0;
488 while(buf_size > 0) {
492 READ16(buf, ie_desc);
495 type = ie_desc & 0x8000 ? 1 : 0;
496 LOG_DBG(
"ie type %u, current state %u\n", type, parsing_state);
498 switch(parsing_state) {
499 case PARSING_HEADER_IE:
501 LOG_ERR(
"header ie: wrong type %04x\n", ie_desc);
505 len = ie_desc & 0x007f;
506 id = (ie_desc & 0x7f80) >> 7;
507 LOG_DBG(
"header ie: len %u id %x\n", len,
id);
509 case HEADER_IE_LIST_TERMINATION_1:
512 parsing_state = PARSING_PAYLOAD_IE;
513 ies->ie_payload_ie_offset = buf -
start;
514 LOG_DBG(
"list termination 1, look for payload IEs\n");
516 LOG_ERR(
"list termination 1, wrong len %u\n", len);
520 case HEADER_IE_LIST_TERMINATION_2:
523 ies->ie_payload_ie_offset = buf -
start;
524 LOG_DBG(
"list termination 2\n");
525 return buf + len -
start;
527 LOG_ERR(
"list termination 2, wrong len %u\n", len);
531 if(len > buf_size || frame802154e_parse_header_ie(buf, len,
id, ies) == -1) {
532 LOG_ERR(
"failed to parse\n");
538 case PARSING_PAYLOAD_IE:
540 LOG_ERR(
"payload ie: wrong type %04x\n", ie_desc);
544 len = ie_desc & 0x7ff;
545 id = (ie_desc & 0x7800) >> 11;
546 LOG_DBG(
"payload ie: len %u id %x\n", len,
id);
548 case PAYLOAD_IE_MLME:
550 parsing_state = PARSING_MLME_SUBIE;
551 nested_mlme_len = len;
553 LOG_DBG(
"entering MLME ie with len %u\n", nested_mlme_len);
556 case PAYLOAD_IE_IETF:
564 ies->sixtop_ie_content_ptr = buf + 1;
570 ies->sixtop_ie_content_len = len - 1;
573 LOG_ERR(
"frame802154e: unsupported IETF sub-IE %u\n", *buf);
578 case PAYLOAD_IE_LIST_TERMINATION:
579 LOG_DBG(
"payload ie list termination %u\n", len);
580 return (len == 0) ? buf + len -
start : -1;
582 LOG_ERR(
"non-supported payload ie\n");
586 case PARSING_MLME_SUBIE:
591 len = ie_desc & 0x00ff;
592 id = (ie_desc & 0x7f00) >> 8;
593 LOG_DBG(
"short mlme ie len %u id %x\n", len,
id);
594 if(len > buf_size || frame802154e_parse_mlme_short_ie(buf, len,
id, ies) == -1) {
595 LOG_ERR(
"failed to parse ie\n");
600 len = ie_desc & 0x7ff;
601 id = (ie_desc & 0x7800) >> 11;
602 LOG_DBG(
"long mlme ie len %u id %x\n", len,
id);
603 if(len > buf_size || frame802154e_parse_mlme_long_ie(buf, len,
id, ies) == -1) {
604 LOG_ERR(
"failed to parse ie\n");
609 nested_mlme_len -= 2 + len;
610 if(nested_mlme_len < 0) {
611 LOG_ERR(
"found more sub-IEs than initially advertised\n");
615 if(nested_mlme_len == 0) {
616 LOG_DBG(
"end of MLME IE parsing\n");
618 parsing_state = PARSING_PAYLOAD_IE;
626 if(parsing_state == PARSING_HEADER_IE) {
627 ies->ie_payload_ie_offset = buf -
start;
static bool start(void)
Start measurement.
IEEE 802.15.4e Information Element (IE) creation and parsing.
6TiSCH Operation Sublayer (6top) APIs
Header file for the logging system
int frame80215e_create_ie_header_ack_nack_time_correction(uint8_t *buf, int len, struct ieee802154_ies *ies)
Insert various Information Elements.