Contiki-NG
frame802154e-ie.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, SICS Swedish ICT.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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 Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 */
32
33/**
34 * \file
35 * IEEE 802.15.4e Information Element (IE) creation and parsing.
36 * \author
37 * Simon Duquennoy <simonduq@sics.se>
38 */
39
40#include <string.h>
42
43/* Log configuration */
44#include "sys/log.h"
45#define LOG_MODULE "Frame 15.4"
46#define LOG_LEVEL LOG_LEVEL_FRAMER
47
48/* c.f. IEEE 802.15.4e Table 4b */
49enum ieee802154e_header_ie_id {
50 HEADER_IE_LE_CSL = 0x1a,
51 HEADER_IE_LE_RIT,
52 HEADER_IE_DSME_PAN_DESCRIPTOR,
53 HEADER_IE_RZ_TIME,
54 HEADER_IE_ACK_NACK_TIME_CORRECTION,
55 HEADER_IE_GACK,
56 HEADER_IE_LOW_LATENCY_NETWORK_INFO,
57 HEADER_IE_LIST_TERMINATION_1 = 0x7e,
58 HEADER_IE_LIST_TERMINATION_2 = 0x7f,
59};
60
61/* c.f. IEEE 802.15.4e Table 4c */
62enum ieee802154e_payload_ie_id {
63 PAYLOAD_IE_ESDU = 0,
64 PAYLOAD_IE_MLME,
65 PAYLOAD_IE_IETF = 0x5,
66 PAYLOAD_IE_LIST_TERMINATION = 0xf,
67};
68
69/* c.f. IEEE 802.15.4e Table 4d */
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,
78};
79
80/* c.f. IEEE 802.15.4e Table 4e */
81enum ieee802154e_mlme_long_subie_id {
82 MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE = 0x9,
83};
84
86enum ieee802154e_ietf_subie_id {
87 IETF_IE_6TOP = SIXTOP_SUBIE_ID,
88};
89
90#define WRITE16(buf, val) \
91 do { ((uint8_t *)(buf))[0] = (val) & 0xff; \
92 ((uint8_t *)(buf))[1] = ((val) >> 8) & 0xff; } while(0);
93
94#define READ16(buf, var) \
95 (var) = ((uint8_t *)(buf))[0] | ((uint8_t *)(buf))[1] << 8
96
97/* Create a header IE 2-byte descriptor */
98static void
99create_header_ie_descriptor(uint8_t *buf, uint8_t element_id, int ie_len)
100{
101 uint16_t ie_desc;
102 /* Header IE descriptor: b0-6: len, b7-14: element id:, b15: type: 0 */
103 ie_desc = (ie_len & 0x7f) + ((element_id & 0xff) << 7);
104 WRITE16(buf, ie_desc);
105}
106
107/* Create a payload IE 2-byte descriptor */
108static void
109create_payload_ie_descriptor(uint8_t *buf, uint8_t group_id, int ie_len)
110{
111 uint16_t ie_desc;
112 /* MLME Long IE descriptor: b0-10: len, b11-14: group id:, b15: type: 1 */
113 ie_desc = (ie_len & 0x07ff) + ((group_id & 0x0f) << 11) + (1 << 15);
114 WRITE16(buf, ie_desc);
115}
116
117/* Create a MLME short IE 2-byte descriptor */
118static void
119create_mlme_short_ie_descriptor(uint8_t *buf, uint8_t sub_id, int ie_len)
120{
121 uint16_t ie_desc;
122 /* MLME Short IE descriptor: b0-7: len, b8-14: sub id:, b15: type: 0 */
123 ie_desc = (ie_len & 0xff) + ((sub_id & 0x7f) << 8);
124 WRITE16(buf, ie_desc);
125}
126
127/* Create a MLME long IE 2-byte descriptor */
128static void
129create_mlme_long_ie_descriptor(uint8_t *buf, uint8_t sub_id, int ie_len)
130{
131 uint16_t ie_desc;
132 /* MLME Long IE descriptor: b0-10: len, b11-14: sub id:, b15: type: 1 */
133 ie_desc = (ie_len & 0x07ff) + ((sub_id & 0x0f) << 11) + (1 << 15);
134 WRITE16(buf, ie_desc);
135}
136
137/* Header IE. ACK/NACK time correction. Used in enhanced ACKs */
138int
140 struct ieee802154_ies *ies)
141{
142 int ie_len = 2;
143 if(len >= 2 + ie_len && ies != NULL) {
144 int16_t drift_us;
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;
150 }
151 WRITE16(buf+2, time_sync_field);
152 create_header_ie_descriptor(buf, HEADER_IE_ACK_NACK_TIME_CORRECTION, ie_len);
153 return 2 + ie_len;
154 } else {
155 return -1;
156 }
157}
158
159/* Header IE. List termination 1 (Signals the end of the Header IEs when
160 * followed by payload IEs) */
161int
162frame80215e_create_ie_header_list_termination_1(uint8_t *buf, int len,
163 const struct ieee802154_ies *ies)
164{
165 int ie_len = 0;
166 if(len >= 2 + ie_len && ies != NULL) {
167 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_1, 0);
168 return 2 + ie_len;
169 } else {
170 return -1;
171 }
172}
173
174/* Header IE. List termination 2 (Signals the end of the Header IEs when
175 * followed by an unformatted payload) */
176int
177frame80215e_create_ie_header_list_termination_2(uint8_t *buf, int len,
178 const struct ieee802154_ies *ies)
179{
180 int ie_len = 0;
181 if(len >= 2 + ie_len && ies != NULL) {
182 create_header_ie_descriptor(buf, HEADER_IE_LIST_TERMINATION_2, 0);
183 return 2 + ie_len;
184 } else {
185 return -1;
186 }
187}
188
189/* Payload IE. List termination */
190int
191frame80215e_create_ie_payload_list_termination(uint8_t *buf, int len,
192 const struct ieee802154_ies *ies)
193{
194 int ie_len = 0;
195 if(len >= 2 + ie_len && ies != NULL) {
196 create_payload_ie_descriptor(buf, PAYLOAD_IE_LIST_TERMINATION, 0);
197 return 2 + ie_len;
198 } else {
199 return -1;
200 }
201}
202
203#if TSCH_WITH_SIXTOP
204/* Payload IE. 6top. Used to nest sub-IEs */
205int
206frame80215e_create_ie_ietf(uint8_t *buf, int len, struct ieee802154_ies *ies)
207{
208 if(len >= 2 && ies != NULL) {
209 create_payload_ie_descriptor(buf,
210 PAYLOAD_IE_IETF,
211 ies->sixtop_ie_content_len);
212 return 2 + ies->sixtop_ie_content_len;
213 }
214 return -1;
215}
216#endif /* TSCH_WITH_SIXTOP */
217
218/* Payload IE. MLME. Used to nest sub-IEs */
219int
220frame80215e_create_ie_mlme(uint8_t *buf, int len,
221 struct ieee802154_ies *ies)
222{
223 int ie_len = 0;
224 if(len >= 2 + ie_len && ies != NULL) {
225 /* The length of the outer MLME IE is the total length of sub-IEs */
226 create_payload_ie_descriptor(buf, PAYLOAD_IE_MLME, ies->ie_mlme_len);
227 return 2 + ie_len;
228 } else {
229 return -1;
230 }
231}
232
233/* MLME sub-IE. TSCH synchronization. Used in EBs: ASN and join priority */
234int
235frame80215e_create_ie_tsch_synchronization(uint8_t *buf, int len,
236 struct ieee802154_ies *ies)
237{
238 int ie_len = 6;
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);
247 return 2 + ie_len;
248 } else {
249 return -1;
250 }
251}
252
253/* MLME sub-IE. TSCH slotframe and link. Used in EBs: initial schedule */
254int
255frame80215e_create_ie_tsch_slotframe_and_link(uint8_t *buf, int len,
256 struct ieee802154_ies *ies)
257{
258 if(ies != NULL) {
259 int i;
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) {
265 /* We support only 0 or 1 slotframe in this IE and a predefined maximum number of links */
266 return -1;
267 }
268 /* Insert IE */
269 buf[2] = num_slotframes;
270 /* Insert slotframe */
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;
275 /* Loop over links */
276 for(i = 0; i < num_links; i++) {
277 /* Insert links */
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;
281 }
282 }
283 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK, ie_len);
284 return 2 + ie_len;
285 } else {
286 return -1;
287 }
288}
289
290/* MLME sub-IE. TSCH timeslot. Used in EBs: timeslot template (timing) */
291int
292frame80215e_create_ie_tsch_timeslot(uint8_t *buf, int len,
293 struct ieee802154_ies *ies)
294{
295 int ie_len;
296 if(ies == NULL) {
297 return -1;
298 }
299 /* Only ID if ID == 0, else full timing description */
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) {
304 int i;
305 for(i = 0; i < tsch_ts_elements_count; i++) {
306 WRITE16(buf + 3 + 2 * i, ies->ie_tsch_timeslot[i]);
307 }
308 }
309 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_TIMESLOT, ie_len);
310 return 2 + ie_len;
311 } else {
312 return -1;
313 }
314}
315
316/* MLME sub-IE. TSCH channel hopping sequence. Used in EBs: hopping sequence */
317int
318frame80215e_create_ie_tsch_channel_hopping_sequence(uint8_t *buf, int len,
319 struct ieee802154_ies *ies)
320{
321 int ie_len;
322 if(ies == NULL || ies->ie_hopping_sequence_len > sizeof(ies->ie_hopping_sequence_list)) {
323 return -1;
324 }
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;
328 buf[3] = 0; /* channel page */
329 WRITE16(buf + 4, 0); /* number of channels */
330 WRITE16(buf + 6, 0); /* phy configuration */
331 WRITE16(buf + 8, 0);
332 /* Extended bitmap. Size: 0 */
333 WRITE16(buf + 10, ies->ie_hopping_sequence_len); /* sequence len */
334 memcpy(buf + 12, ies->ie_hopping_sequence_list, ies->ie_hopping_sequence_len); /* sequence list */
335 WRITE16(buf + 12 + ies->ie_hopping_sequence_len, 0); /* current hop */
336 create_mlme_long_ie_descriptor(buf, MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE, ie_len);
337 return 2 + ie_len;
338 } else {
339 return -1;
340 }
341}
342
343/* Parse a header IE */
344static int
345frame802154e_parse_header_ie(const uint8_t *buf, int len,
346 uint8_t element_id, struct ieee802154_ies *ies)
347{
348 switch(element_id) {
349 case HEADER_IE_ACK_NACK_TIME_CORRECTION:
350 if(len == 2) {
351 if(ies != NULL) {
352 /* If the originator was a time source neighbor, the receiver adjust
353 * its own clock by incorporating the received drift correction */
354 uint16_t time_sync_field = 0;
355 int16_t drift_us = 0;
356 /* Extract drift correction from Sync-IE, cast from 12 to 16-bit,
357 * and convert it to RTIMER ticks.
358 * See page 88 in IEEE Std 802.15.4e-2012. */
359 READ16(buf, time_sync_field);
360 /* First extract NACK */
361 ies->ie_is_nack = (time_sync_field & (uint16_t)0x8000) ? 1 : 0;
362 /* Then cast from 12 to 16 bit signed */
363 if(time_sync_field & 0x0800) { /* Negative integer */
364 drift_us = time_sync_field | 0xf000;
365 } else { /* Positive integer */
366 drift_us = time_sync_field & 0x0fff;
367 }
368 /* Convert to RTIMER ticks */
369 ies->ie_time_correction = drift_us;
370 }
371 return len;
372 }
373 break;
374 }
375 return -1;
376}
377
378/* Parse a MLME short IE */
379static int
380frame802154e_parse_mlme_short_ie(const uint8_t *buf, int len,
381 uint8_t sub_id, struct ieee802154_ies *ies)
382{
383 switch(sub_id) {
384 case MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK:
385 if(len >= 1) {
386 int i;
387 int num_slotframes = buf[0];
388 int num_links = buf[4];
389 if(num_slotframes == 0) {
390 return len;
391 }
392 if(num_slotframes <= 1 && num_links <= FRAME802154E_IE_MAX_LINKS
393 && len == 1 + num_slotframes * (4 + 5 * num_links)) {
394 if(ies != NULL) {
395 /* We support only 0 or 1 slotframe in this IE and a predefined maximum number of 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];
404 }
405 }
406 return len;
407 }
408 }
409 break;
410 case MLME_SHORT_IE_TSCH_SYNCHRONIZATION:
411 if(len == 6) {
412 if(ies != NULL) {
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];
419 }
420 return len;
421 }
422 break;
423 case MLME_SHORT_IE_TSCH_TIMESLOT:
424 if(len == 1 || len == 25) {
425 if(ies != NULL) {
426 ies->ie_tsch_timeslot_id = buf[0];
427 if(len == 25) {
428 int i;
429 for(i = 0; i < tsch_ts_elements_count; i++) {
430 READ16(buf+1+2*i, ies->ie_tsch_timeslot[i]);
431 }
432 }
433 }
434 return len;
435 }
436 break;
437 }
438 return -1;
439}
440
441/* Parse a MLME long IE */
442static int
443frame802154e_parse_mlme_long_ie(const uint8_t *buf, int len,
444 uint8_t sub_id, struct ieee802154_ies *ies)
445{
446 switch(sub_id) {
447 case MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE:
448 if(len > 0) {
449 if(ies != NULL) {
450 ies->ie_channel_hopping_sequence_id = buf[0];
451 if(len > 1) {
452 READ16(buf+8, ies->ie_hopping_sequence_len); /* 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); /* sequence list */
456 }
457 }
458 }
459 return len;
460 }
461 break;
462 }
463 return -1;
464}
465
466/* Parse all IEEE 802.15.4e Information Elements (IE) from a frame */
467int
468frame802154e_parse_information_elements(const uint8_t *buf, uint8_t buf_size,
469 struct ieee802154_ies *ies)
470{
471 const uint8_t *start = buf;
472 uint16_t ie_desc;
473 uint8_t type;
474 uint8_t id;
475 uint16_t len = 0;
476 int nested_mlme_len = 0;
477 enum {PARSING_HEADER_IE, PARSING_PAYLOAD_IE, PARSING_MLME_SUBIE} parsing_state;
478
479 if(ies == NULL) {
480 return -1;
481 }
482
483 /* Always look for a header IE first (at least "list termination 1") */
484 parsing_state = PARSING_HEADER_IE;
485 ies->ie_payload_ie_offset = 0;
486
487 /* Loop over all IEs */
488 while(buf_size > 0) {
489 if(buf_size < 2) { /* Not enough space for IE descriptor */
490 return -1;
491 }
492 READ16(buf, ie_desc);
493 buf_size -= 2;
494 buf += 2;
495 type = ie_desc & 0x8000 ? 1 : 0; /* b15 */
496 LOG_DBG("ie type %u, current state %u\n", type, parsing_state);
497
498 switch(parsing_state) {
499 case PARSING_HEADER_IE:
500 if(type != 0) {
501 LOG_ERR("header ie: wrong type %04x\n", ie_desc);
502 return -1;
503 }
504 /* Header IE: 2 bytes descriptor, c.f. fig 48n in IEEE 802.15.4e */
505 len = ie_desc & 0x007f; /* b0-b6 */
506 id = (ie_desc & 0x7f80) >> 7; /* b7-b14 */
507 LOG_DBG("header ie: len %u id %x\n", len, id);
508 switch(id) {
509 case HEADER_IE_LIST_TERMINATION_1:
510 if(len == 0) {
511 /* End of payload IE list, now expect payload IEs */
512 parsing_state = PARSING_PAYLOAD_IE;
513 ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
514 LOG_DBG("list termination 1, look for payload IEs\n");
515 } else {
516 LOG_ERR("list termination 1, wrong len %u\n", len);
517 return -1;
518 }
519 break;
520 case HEADER_IE_LIST_TERMINATION_2:
521 /* End of IE parsing */
522 if(len == 0) {
523 ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
524 LOG_DBG("list termination 2\n");
525 return buf + len - start;
526 } else {
527 LOG_ERR("list termination 2, wrong len %u\n", len);
528 return -1;
529 }
530 default:
531 if(len > buf_size || frame802154e_parse_header_ie(buf, len, id, ies) == -1) {
532 LOG_ERR("failed to parse\n");
533 return -1;
534 }
535 break;
536 }
537 break;
538 case PARSING_PAYLOAD_IE:
539 if(type != 1) {
540 LOG_ERR("payload ie: wrong type %04x\n", ie_desc);
541 return -1;
542 }
543 /* Payload IE: 2 bytes descriptor, c.f. fig 48o in IEEE 802.15.4e */
544 len = ie_desc & 0x7ff; /* b0-b10 */
545 id = (ie_desc & 0x7800) >> 11; /* b11-b14 */
546 LOG_DBG("payload ie: len %u id %x\n", len, id);
547 switch(id) {
548 case PAYLOAD_IE_MLME:
549 /* Now expect 'len' bytes of MLME sub-IEs */
550 parsing_state = PARSING_MLME_SUBIE;
551 nested_mlme_len = len;
552 len = 0; /* Reset len as we want to read subIEs and not jump over them */
553 LOG_DBG("entering MLME ie with len %u\n", nested_mlme_len);
554 break;
555#if TSCH_WITH_SIXTOP
556 case PAYLOAD_IE_IETF:
557 switch(*buf) {
558 case IETF_IE_6TOP:
559 /*
560 * buf points to the Sub-ID field, a one-octet field, now;
561 * advance it by one and use the result as the head pointer of
562 * 6top IE Content.
563 */
564 ies->sixtop_ie_content_ptr = buf + 1;
565 /*
566 * Similarly as above, subtract 1 (one octet) from len, which
567 * includes the length of Sub-ID field, and use the result as
568 * the length of 6top IE Content.
569 */
570 ies->sixtop_ie_content_len = len - 1;
571 break;
572 default:
573 LOG_ERR("frame802154e: unsupported IETF sub-IE %u\n", *buf);
574 break;
575 }
576 break;
577#endif /* TSCH_WITH_SIXTOP */
578 case PAYLOAD_IE_LIST_TERMINATION:
579 LOG_DBG("payload ie list termination %u\n", len);
580 return (len == 0) ? buf + len - start : -1;
581 default:
582 LOG_ERR("non-supported payload ie\n");
583 return -1;
584 }
585 break;
586 case PARSING_MLME_SUBIE:
587 /* MLME sub-IE: 2 bytes descriptor, c.f. fig 48q in IEEE 802.15.4e */
588 /* type == 0 means short sub-IE, type == 1 means long sub-IE */
589 if(type == 0) {
590 /* Short sub-IE, c.f. fig 48r in IEEE 802.15.4e */
591 len = ie_desc & 0x00ff; /* b0-b7 */
592 id = (ie_desc & 0x7f00) >> 8; /* b8-b14 */
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");
596 return -1;
597 }
598 } else {
599 /* Long sub-IE, c.f. fig 48s in IEEE 802.15.4e */
600 len = ie_desc & 0x7ff; /* b0-b10 */
601 id = (ie_desc & 0x7800) >> 11; /* b11-b14 */
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");
605 return -1;
606 }
607 }
608 /* Update remaining nested MLME len */
609 nested_mlme_len -= 2 + len;
610 if(nested_mlme_len < 0) {
611 LOG_ERR("found more sub-IEs than initially advertised\n");
612 /* We found more sub-IEs than initially advertised */
613 return -1;
614 }
615 if(nested_mlme_len == 0) {
616 LOG_DBG("end of MLME IE parsing\n");
617 /* End of IE parsing, look for another payload IE */
618 parsing_state = PARSING_PAYLOAD_IE;
619 }
620 break;
621 }
622 buf += len;
623 buf_size -= len;
624 }
625
626 if(parsing_state == PARSING_HEADER_IE) {
627 ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
628 }
629
630 return buf - start;
631}
int frame80215e_create_ie_header_ack_nack_time_correction(uint8_t *buf, int len, 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