Contiki-NG
Loading...
Searching...
No Matches
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 const 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,
207 const struct ieee802154_ies *ies)
208{
209 if(len >= 2 && ies != NULL) {
210 create_payload_ie_descriptor(buf,
211 PAYLOAD_IE_IETF,
212 ies->sixtop_ie_content_len);
213 return 2 + ies->sixtop_ie_content_len;
214 }
215 return -1;
216}
217#endif /* TSCH_WITH_SIXTOP */
218
219/* Payload IE. MLME. Used to nest sub-IEs */
220int
221frame80215e_create_ie_mlme(uint8_t *buf, int len,
222 const struct ieee802154_ies *ies)
223{
224 int ie_len = 0;
225 if(len >= 2 + ie_len && ies != NULL) {
226 /* The length of the outer MLME IE is the total length of sub-IEs */
227 create_payload_ie_descriptor(buf, PAYLOAD_IE_MLME, ies->ie_mlme_len);
228 return 2 + ie_len;
229 } else {
230 return -1;
231 }
232}
233
234/* MLME sub-IE. TSCH synchronization. Used in EBs: ASN and join priority */
235int
236frame80215e_create_ie_tsch_synchronization(uint8_t *buf, int len,
237 const struct ieee802154_ies *ies)
238{
239 int ie_len = 6;
240 if(len >= 2 + ie_len && ies != NULL) {
241 buf[2] = ies->ie_asn.ls4b;
242 buf[3] = ies->ie_asn.ls4b >> 8;
243 buf[4] = ies->ie_asn.ls4b >> 16;
244 buf[5] = ies->ie_asn.ls4b >> 24;
245 buf[6] = ies->ie_asn.ms1b;
246 buf[7] = ies->ie_join_priority;
247 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SYNCHRONIZATION, ie_len);
248 return 2 + ie_len;
249 } else {
250 return -1;
251 }
252}
253
254/* MLME sub-IE. TSCH slotframe and link. Used in EBs: initial schedule */
255int
256frame80215e_create_ie_tsch_slotframe_and_link(uint8_t *buf, int len,
257 const struct ieee802154_ies *ies)
258{
259 if(ies != NULL) {
260 int i;
261 int num_slotframes = ies->ie_tsch_slotframe_and_link.num_slotframes;
262 int num_links = ies->ie_tsch_slotframe_and_link.num_links;
263 int ie_len = 1 + num_slotframes * (4 + 5 * num_links);
264 if(num_slotframes > 1 || num_links > FRAME802154E_IE_MAX_LINKS
265 || len < 2 + ie_len) {
266 /* We support only 0 or 1 slotframe in this IE and a predefined maximum number of links */
267 return -1;
268 }
269 /* Insert IE */
270 buf[2] = num_slotframes;
271 /* Insert slotframe */
272 if(num_slotframes == 1) {
273 buf[2 + 1] = ies->ie_tsch_slotframe_and_link.slotframe_handle;
274 WRITE16(buf + 2 + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
275 buf[2 + 4] = num_links;
276 /* Loop over links */
277 for(i = 0; i < num_links; i++) {
278 /* Insert links */
279 WRITE16(buf + 2 + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
280 WRITE16(buf + 2 + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
281 buf[2 + 5 + i * 5 + 4] = ies->ie_tsch_slotframe_and_link.links[i].link_options;
282 }
283 }
284 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK, ie_len);
285 return 2 + ie_len;
286 } else {
287 return -1;
288 }
289}
290
291/* MLME sub-IE. TSCH timeslot. Used in EBs: timeslot template (timing) */
292int
293frame80215e_create_ie_tsch_timeslot(uint8_t *buf, int len,
294 const struct ieee802154_ies *ies)
295{
296 int ie_len;
297 if(ies == NULL) {
298 return -1;
299 }
300 /* Only ID if ID == 0, else full timing description */
301 ie_len = ies->ie_tsch_timeslot_id == 0 ? 1 : 25;
302 if(len >= 2 + ie_len) {
303 buf[2] = ies->ie_tsch_timeslot_id;
304 if(ies->ie_tsch_timeslot_id != 0) {
305 int i;
306 for(i = 0; i < tsch_ts_elements_count; i++) {
307 WRITE16(buf + 3 + 2 * i, ies->ie_tsch_timeslot[i]);
308 }
309 }
310 create_mlme_short_ie_descriptor(buf, MLME_SHORT_IE_TSCH_TIMESLOT, ie_len);
311 return 2 + ie_len;
312 } else {
313 return -1;
314 }
315}
316
317/* MLME sub-IE. TSCH channel hopping sequence. Used in EBs: hopping sequence */
318int
319frame80215e_create_ie_tsch_channel_hopping_sequence(uint8_t *buf, int len,
320 const struct ieee802154_ies *ies)
321{
322 int ie_len;
323 if(ies == NULL || ies->ie_hopping_sequence_len > sizeof(ies->ie_hopping_sequence_list)) {
324 return -1;
325 }
326 ie_len = ies->ie_channel_hopping_sequence_id == 0 ? 1 : 12 + ies->ie_hopping_sequence_len;
327 if(len >= 2 + ie_len && ies != NULL) {
328 buf[2] = ies->ie_channel_hopping_sequence_id;
329 buf[3] = 0; /* channel page */
330 WRITE16(buf + 4, 0); /* number of channels */
331 WRITE16(buf + 6, 0); /* phy configuration */
332 WRITE16(buf + 8, 0);
333 /* Extended bitmap. Size: 0 */
334 WRITE16(buf + 10, ies->ie_hopping_sequence_len); /* sequence len */
335 memcpy(buf + 12, ies->ie_hopping_sequence_list, ies->ie_hopping_sequence_len); /* sequence list */
336 WRITE16(buf + 12 + ies->ie_hopping_sequence_len, 0); /* current hop */
337 create_mlme_long_ie_descriptor(buf, MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE, ie_len);
338 return 2 + ie_len;
339 } else {
340 return -1;
341 }
342}
343
344/* Parse a header IE */
345static int
346frame802154e_parse_header_ie(const uint8_t *buf, int len,
347 uint8_t element_id, struct ieee802154_ies *ies)
348{
349 switch(element_id) {
350 case HEADER_IE_ACK_NACK_TIME_CORRECTION:
351 if(len == 2) {
352 if(ies != NULL) {
353 /* If the originator was a time source neighbor, the receiver adjust
354 * its own clock by incorporating the received drift correction */
355 uint16_t time_sync_field = 0;
356 int16_t drift_us = 0;
357 /* Extract drift correction from Sync-IE, cast from 12 to 16-bit,
358 * and convert it to RTIMER ticks.
359 * See page 88 in IEEE Std 802.15.4e-2012. */
360 READ16(buf, time_sync_field);
361 /* First extract NACK */
362 ies->ie_is_nack = (time_sync_field & (uint16_t)0x8000) ? 1 : 0;
363 /* Then cast from 12 to 16 bit signed */
364 if(time_sync_field & 0x0800) { /* Negative integer */
365 drift_us = time_sync_field | 0xf000;
366 } else { /* Positive integer */
367 drift_us = time_sync_field & 0x0fff;
368 }
369 /* Convert to RTIMER ticks */
370 ies->ie_time_correction = drift_us;
371 }
372 return len;
373 }
374 break;
375 }
376 return -1;
377}
378
379/* Parse a MLME short IE */
380static int
381frame802154e_parse_mlme_short_ie(const uint8_t *buf, int len,
382 uint8_t sub_id, struct ieee802154_ies *ies)
383{
384 switch(sub_id) {
385 case MLME_SHORT_IE_TSCH_SLOFTRAME_AND_LINK:
386 if(len >= 1) {
387 int i;
388 int num_slotframes = buf[0];
389 int num_links = buf[4];
390 if(num_slotframes == 0) {
391 return len;
392 }
393 if(num_slotframes <= 1 && num_links <= FRAME802154E_IE_MAX_LINKS
394 && len == 1 + num_slotframes * (4 + 5 * num_links)) {
395 if(ies != NULL) {
396 /* We support only 0 or 1 slotframe in this IE and a predefined maximum number of links */
397 ies->ie_tsch_slotframe_and_link.num_slotframes = buf[0];
398 ies->ie_tsch_slotframe_and_link.slotframe_handle = buf[1];
399 READ16(buf + 2, ies->ie_tsch_slotframe_and_link.slotframe_size);
400 ies->ie_tsch_slotframe_and_link.num_links = buf[4];
401 for(i = 0; i < num_links; i++) {
402 READ16(buf + 5 + i * 5, ies->ie_tsch_slotframe_and_link.links[i].timeslot);
403 READ16(buf + 5 + i * 5 + 2, ies->ie_tsch_slotframe_and_link.links[i].channel_offset);
404 ies->ie_tsch_slotframe_and_link.links[i].link_options = buf[5 + i * 5 + 4];
405 }
406 }
407 return len;
408 }
409 }
410 break;
411 case MLME_SHORT_IE_TSCH_SYNCHRONIZATION:
412 if(len == 6) {
413 if(ies != NULL) {
414 ies->ie_asn.ls4b = (uint32_t)buf[0];
415 ies->ie_asn.ls4b |= (uint32_t)buf[1] << 8;
416 ies->ie_asn.ls4b |= (uint32_t)buf[2] << 16;
417 ies->ie_asn.ls4b |= (uint32_t)buf[3] << 24;
418 ies->ie_asn.ms1b = (uint8_t)buf[4];
419 ies->ie_join_priority = (uint8_t)buf[5];
420 }
421 return len;
422 }
423 break;
424 case MLME_SHORT_IE_TSCH_TIMESLOT:
425 if(len == 1 || len == 25) {
426 if(ies != NULL) {
427 ies->ie_tsch_timeslot_id = buf[0];
428 if(len == 25) {
429 int i;
430 for(i = 0; i < tsch_ts_elements_count; i++) {
431 READ16(buf+1+2*i, ies->ie_tsch_timeslot[i]);
432 }
433 }
434 }
435 return len;
436 }
437 break;
438 }
439 return -1;
440}
441
442/* Parse a MLME long IE */
443static int
444frame802154e_parse_mlme_long_ie(const uint8_t *buf, int len,
445 uint8_t sub_id, struct ieee802154_ies *ies)
446{
447 switch(sub_id) {
448 case MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE:
449 if(len > 0) {
450 if(ies != NULL) {
451 ies->ie_channel_hopping_sequence_id = buf[0];
452 if(len > 1) {
453 READ16(buf+8, ies->ie_hopping_sequence_len); /* sequence len */
454 if(ies->ie_hopping_sequence_len <= sizeof(ies->ie_hopping_sequence_list)
455 && len == 12 + ies->ie_hopping_sequence_len) {
456 memcpy(ies->ie_hopping_sequence_list, buf+10, ies->ie_hopping_sequence_len); /* sequence list */
457 }
458 }
459 }
460 return len;
461 }
462 break;
463 }
464 return -1;
465}
466
467/* Parse all IEEE 802.15.4e Information Elements (IE) from a frame */
468int
469frame802154e_parse_information_elements(const uint8_t *buf, uint8_t buf_size,
470 struct ieee802154_ies *ies)
471{
472 const uint8_t *start = buf;
473 uint16_t ie_desc;
474 uint8_t type;
475 uint8_t id;
476 uint16_t len = 0;
477 int nested_mlme_len = 0;
478 enum {PARSING_HEADER_IE, PARSING_PAYLOAD_IE, PARSING_MLME_SUBIE} parsing_state;
479
480 if(ies == NULL) {
481 return -1;
482 }
483
484 /* Always look for a header IE first (at least "list termination 1") */
485 parsing_state = PARSING_HEADER_IE;
486 ies->ie_payload_ie_offset = 0;
487
488 /* Loop over all IEs */
489 while(buf_size > 0) {
490 if(buf_size < 2) { /* Not enough space for IE descriptor */
491 return -1;
492 }
493 READ16(buf, ie_desc);
494 buf_size -= 2;
495 buf += 2;
496 type = ie_desc & 0x8000 ? 1 : 0; /* b15 */
497 LOG_DBG("ie type %u, current state %u\n", type, parsing_state);
498
499 switch(parsing_state) {
500 case PARSING_HEADER_IE:
501 if(type != 0) {
502 LOG_ERR("header ie: wrong type %04x\n", ie_desc);
503 return -1;
504 }
505 /* Header IE: 2 bytes descriptor, c.f. fig 48n in IEEE 802.15.4e */
506 len = ie_desc & 0x007f; /* b0-b6 */
507 id = (ie_desc & 0x7f80) >> 7; /* b7-b14 */
508 LOG_DBG("header ie: len %u id %x\n", len, id);
509 switch(id) {
510 case HEADER_IE_LIST_TERMINATION_1:
511 if(len == 0) {
512 /* End of payload IE list, now expect payload IEs */
513 parsing_state = PARSING_PAYLOAD_IE;
514 ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
515 LOG_DBG("list termination 1, look for payload IEs\n");
516 } else {
517 LOG_ERR("list termination 1, wrong len %u\n", len);
518 return -1;
519 }
520 break;
521 case HEADER_IE_LIST_TERMINATION_2:
522 /* End of IE parsing */
523 if(len == 0) {
524 ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
525 LOG_DBG("list termination 2\n");
526 return buf + len - start;
527 } else {
528 LOG_ERR("list termination 2, wrong len %u\n", len);
529 return -1;
530 }
531 default:
532 if(len > buf_size || frame802154e_parse_header_ie(buf, len, id, ies) == -1) {
533 LOG_ERR("failed to parse\n");
534 return -1;
535 }
536 break;
537 }
538 break;
539 case PARSING_PAYLOAD_IE:
540 if(type != 1) {
541 LOG_ERR("payload ie: wrong type %04x\n", ie_desc);
542 return -1;
543 }
544 /* Payload IE: 2 bytes descriptor, c.f. fig 48o in IEEE 802.15.4e */
545 len = ie_desc & 0x7ff; /* b0-b10 */
546 id = (ie_desc & 0x7800) >> 11; /* b11-b14 */
547 LOG_DBG("payload ie: len %u id %x\n", len, id);
548 switch(id) {
549 case PAYLOAD_IE_MLME:
550 /* Now expect 'len' bytes of MLME sub-IEs */
551 parsing_state = PARSING_MLME_SUBIE;
552 nested_mlme_len = len;
553 len = 0; /* Reset len as we want to read subIEs and not jump over them */
554 LOG_DBG("entering MLME ie with len %u\n", nested_mlme_len);
555 break;
556#if TSCH_WITH_SIXTOP
557 case PAYLOAD_IE_IETF:
558 switch(*buf) {
559 case IETF_IE_6TOP:
560 /*
561 * buf points to the Sub-ID field, a one-octet field, now;
562 * advance it by one and use the result as the head pointer of
563 * 6top IE Content.
564 */
565 ies->sixtop_ie_content_ptr = buf + 1;
566 /*
567 * Similarly as above, subtract 1 (one octet) from len, which
568 * includes the length of Sub-ID field, and use the result as
569 * the length of 6top IE Content.
570 */
571 ies->sixtop_ie_content_len = len - 1;
572 break;
573 default:
574 LOG_ERR("frame802154e: unsupported IETF sub-IE %u\n", *buf);
575 break;
576 }
577 break;
578#endif /* TSCH_WITH_SIXTOP */
579 case PAYLOAD_IE_LIST_TERMINATION:
580 LOG_DBG("payload ie list termination %u\n", len);
581 return (len == 0) ? buf + len - start : -1;
582 default:
583 LOG_ERR("non-supported payload ie\n");
584 return -1;
585 }
586 break;
587 case PARSING_MLME_SUBIE:
588 /* MLME sub-IE: 2 bytes descriptor, c.f. fig 48q in IEEE 802.15.4e */
589 /* type == 0 means short sub-IE, type == 1 means long sub-IE */
590 if(type == 0) {
591 /* Short sub-IE, c.f. fig 48r in IEEE 802.15.4e */
592 len = ie_desc & 0x00ff; /* b0-b7 */
593 id = (ie_desc & 0x7f00) >> 8; /* b8-b14 */
594 LOG_DBG("short mlme ie len %u id %x\n", len, id);
595 if(len > buf_size || frame802154e_parse_mlme_short_ie(buf, len, id, ies) == -1) {
596 LOG_ERR("failed to parse ie\n");
597 return -1;
598 }
599 } else {
600 /* Long sub-IE, c.f. fig 48s in IEEE 802.15.4e */
601 len = ie_desc & 0x7ff; /* b0-b10 */
602 id = (ie_desc & 0x7800) >> 11; /* b11-b14 */
603 LOG_DBG("long mlme ie len %u id %x\n", len, id);
604 if(len > buf_size || frame802154e_parse_mlme_long_ie(buf, len, id, ies) == -1) {
605 LOG_ERR("failed to parse ie\n");
606 return -1;
607 }
608 }
609 /* Update remaining nested MLME len */
610 nested_mlme_len -= 2 + len;
611 if(nested_mlme_len < 0) {
612 LOG_ERR("found more sub-IEs than initially advertised\n");
613 /* We found more sub-IEs than initially advertised */
614 return -1;
615 }
616 if(nested_mlme_len == 0) {
617 LOG_DBG("end of MLME IE parsing\n");
618 /* End of IE parsing, look for another payload IE */
619 parsing_state = PARSING_PAYLOAD_IE;
620 }
621 break;
622 }
623 buf += len;
624 buf_size -= len;
625 }
626
627 if(parsing_state == PARSING_HEADER_IE) {
628 ies->ie_payload_ie_offset = buf - start; /* Save IE header len */
629 }
630
631 return buf - start;
632}
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