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 */
49 enum 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 */
62 enum 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 */
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,
78 };
79 
80 /* c.f. IEEE 802.15.4e Table 4e */
81 enum ieee802154e_mlme_long_subie_id {
82  MLME_LONG_IE_TSCH_CHANNEL_HOPPING_SEQUENCE = 0x9,
83 };
84 
86 enum 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 */
98 static void
99 create_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 */
108 static void
109 create_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 */
118 static void
119 create_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 */
128 static void
129 create_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 */
138 int
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) */
161 int
162 frame80215e_create_ie_header_list_termination_1(uint8_t *buf, int len,
163  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) */
176 int
177 frame80215e_create_ie_header_list_termination_2(uint8_t *buf, int len,
178  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 */
190 int
191 frame80215e_create_ie_payload_list_termination(uint8_t *buf, int len,
192  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 */
205 int
206 frame80215e_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 */
219 int
220 frame80215e_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 */
234 int
235 frame80215e_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 */
254 int
255 frame80215e_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) */
291 int
292 frame80215e_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 */
317 int
318 frame80215e_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 */
344 static int
345 frame802154e_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 */
379 static int
380 frame802154e_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 */
442 static int
443 frame802154e_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 */
467 int
468 frame802154e_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 }
IEEE 802.15.4e Information Element (IE) creation and parsing.
static void start(void)
Start measurement.
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.