Contiki-NG
Loading...
Searching...
No Matches
tsch-packet.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014, 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 * TSCH packet format management
36 * \author
37 * Simon Duquennoy <simonduq@sics.se>
38 * Beshr Al Nahas <beshr@sics.se>
39 */
40
41/**
42 * \addtogroup tsch
43 * @{
44*/
45
46#include "contiki.h"
47#include "net/packetbuf.h"
48#include "net/mac/tsch/tsch.h"
51#include "net/netstack.h"
52#include "lib/ccm-star.h"
53#include "lib/aes-128.h"
54
55/* Log configuration */
56#include "sys/log.h"
57#define LOG_MODULE "TSCH Pkt"
58#define LOG_LEVEL LOG_LEVEL_MAC
59
60/*
61 * We use a local packetbuf_attr array to collect necessary frame settings to
62 * create an EACK because EACK is generated in the interrupt context where
63 * packetbuf and packetbuf_attrs[] may be in use for another purpose.
64 *
65 * We have accessors of eackbuf_attrs: tsch_packet_eackbuf_set_attr() and
66 * tsch_packet_eackbuf_attr(). For some platform, they might need to be
67 * implemented as inline functions. However, for now, we don't provide the
68 * inline option. Such an optimization is left to the compiler for a target
69 * platform.
70 */
71static struct packetbuf_attr eackbuf_attrs[PACKETBUF_NUM_ATTRS];
72
73/* The offset of the frame pending bit flag within the first byte of FCF */
74#define IEEE802154_FRAME_PENDING_BIT_OFFSET 4
75
76/*---------------------------------------------------------------------------*/
77void
78tsch_packet_eackbuf_set_attr(uint8_t type, const packetbuf_attr_t val)
79{
80 eackbuf_attrs[type].val = val;
81 return;
82}
83/*---------------------------------------------------------------------------*/
84/* Return the value of a specified attribute */
85packetbuf_attr_t
87{
88 return eackbuf_attrs[type].val;
89}
90/*---------------------------------------------------------------------------*/
91/* Construct enhanced ACK packet and return ACK length */
92int
93tsch_packet_create_eack(uint8_t *buf, uint16_t buf_len,
94 const linkaddr_t *dest_addr, uint8_t seqno,
95 int16_t drift, int nack)
96{
97 frame802154_t params;
98 struct ieee802154_ies ies;
99 int hdr_len;
100 int ack_len;
101
102 if(buf == NULL) {
103 return -1;
104 }
105
106 /* Init to zeros, like framer-802154 does before setting up params.
107 framer_802154_setup_params() deliberately does not zero the struct
108 and leaves some fields unset; with LLSEC enabled, residual stack
109 garbage in aux_hdr.security_control ends up determining the
110 auxiliary security header layout of the enhanced ACK. */
111 memset(&params, 0, sizeof(params));
112 memset(eackbuf_attrs, 0, sizeof(eackbuf_attrs));
113
114 tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_ACKFRAME);
115 tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_MAC_METADATA, 1);
116 tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno);
117
118 tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_MAC_NO_DEST_ADDR, 1);
119#if TSCH_PACKET_EACK_WITH_DEST_ADDR
120 if(dest_addr != NULL) {
121 tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_MAC_NO_DEST_ADDR, 0);
122 linkaddr_copy((linkaddr_t *)&params.dest_addr, dest_addr);
123 }
124#endif
125
126 tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_MAC_NO_SRC_ADDR, 1);
127#if TSCH_PACKET_EACK_WITH_SRC_ADDR
128 tsch_packet_eackbuf_set_attr(PACKETBUF_ATTR_MAC_NO_SRC_ADDR, 0);
129 linkaddr_copy((linkaddr_t *)&params.src_addr, &linkaddr_node_addr);
130#endif
131
132#if LLSEC802154_ENABLED
133 tsch_security_set_packetbuf_attr(FRAME802154_ACKFRAME);
134#endif /* LLSEC802154_ENABLED */
135
136 framer_802154_setup_params(tsch_packet_eackbuf_attr, 0, &params);
137 hdr_len = frame802154_hdrlen(&params);
138
139 memset(buf, 0, buf_len);
140
141 /* Setup IE timesync */
142 memset(&ies, 0, sizeof(ies));
143 ies.ie_time_correction = drift;
144 ies.ie_is_nack = nack;
145
146 ack_len =
148 buf_len - hdr_len, &ies);
149 if(ack_len < 0) {
150 return -1;
151 }
152 ack_len += hdr_len;
153
154 frame802154_create(&params, buf);
155
156 return ack_len;
157}
158/*---------------------------------------------------------------------------*/
159/* Parse enhanced ACK packet, extract drift and nack */
160int
161tsch_packet_parse_eack(const uint8_t *buf, int buf_size,
162 uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len)
163{
164 uint8_t curr_len = 0;
165 int ret;
166 linkaddr_t dest;
167
168 if(frame == NULL || buf_size < 0) {
169 return 0;
170 }
171 /* Parse 802.15.4-2006 frame, i.e. all fields before Information Elements */
172 if((ret = frame802154_parse((uint8_t *)buf, buf_size, frame)) < 3) {
173 return 0;
174 }
175 if(hdr_len != NULL) {
176 *hdr_len = ret;
177 }
178 curr_len += ret;
179
180 /* Check seqno */
181 if(seqno != frame->seq) {
182 return 0;
183 }
184
185 /* Check destination PAN ID */
186 if(frame802154_check_dest_panid(frame) == 0) {
187 return 0;
188 }
189
190 /* Check destination address (if any) */
191 if(frame802154_extract_linkaddr(frame, NULL, &dest) == 0 ||
193 && !linkaddr_cmp(&dest, &linkaddr_null))) {
194 return 0;
195 }
196
197 if(ies != NULL) {
198 memset(ies, 0, sizeof(struct ieee802154_ies));
199 }
200
201 if(frame->fcf.ie_list_present) {
202 int mic_len = 0;
203#if LLSEC802154_ENABLED
204 /* Check if there is space for the security MIC (if any) */
205 mic_len = tsch_security_mic_len(frame);
206 if(buf_size < curr_len + mic_len) {
207 return 0;
208 }
209#endif /* LLSEC802154_ENABLED */
210 /* Parse information elements. We need to substract the MIC length, as the exact payload len is needed while parsing */
211 if((ret = frame802154e_parse_information_elements(buf + curr_len, buf_size - curr_len - mic_len, ies)) == -1) {
212 return 0;
213 }
214 curr_len += ret;
215 }
216
217 if(hdr_len != NULL) {
218 *hdr_len += ies->ie_payload_ie_offset;
219 }
220
221 return curr_len;
222}
223/*---------------------------------------------------------------------------*/
224/* Create an EB packet */
225int
226tsch_packet_create_eb(uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset)
227{
228 struct ieee802154_ies ies;
229 uint8_t *p;
230 int ie_len;
231 const uint16_t payload_ie_hdr_len = 2;
232
234
235 /* Prepare Information Elements for inclusion in the EB */
236 memset(&ies, 0, sizeof(ies));
237
238 /* Add TSCH timeslot timing IE. */
239#if TSCH_PACKET_EB_WITH_TIMESLOT_TIMING
240 {
241 int i;
242 ies.ie_tsch_timeslot_id = 1;
243 for(i = 0; i < tsch_ts_elements_count; i++) {
244 ies.ie_tsch_timeslot[i] = RTIMERTICKS_TO_US(tsch_timing[i]);
245 }
246 }
247#endif /* TSCH_PACKET_EB_WITH_TIMESLOT_TIMING */
248
249 /* Add TSCH hopping sequence IE */
250#if TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE
251 if(tsch_hopping_sequence_length.val <= sizeof(ies.ie_hopping_sequence_list)) {
252 ies.ie_channel_hopping_sequence_id = 1;
253 ies.ie_hopping_sequence_len = tsch_hopping_sequence_length.val;
254 memcpy(ies.ie_hopping_sequence_list, tsch_hopping_sequence,
255 ies.ie_hopping_sequence_len);
256 }
257#endif /* TSCH_PACKET_EB_WITH_HOPPING_SEQUENCE */
258
259 /* Add Slotframe and Link IE */
260#if TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK
261 {
262 /* Send slotframe 0 with link at timeslot 0 and channel offset 0 */
264 struct tsch_link *link0 = tsch_schedule_get_link_by_offsets(sf0, 0, 0);
265 if(sf0 && link0) {
266 ies.ie_tsch_slotframe_and_link.num_slotframes = 1;
267 ies.ie_tsch_slotframe_and_link.slotframe_handle = sf0->handle;
268 ies.ie_tsch_slotframe_and_link.slotframe_size = sf0->size.val;
269 ies.ie_tsch_slotframe_and_link.num_links = 1;
270 ies.ie_tsch_slotframe_and_link.links[0].timeslot = link0->timeslot;
271 ies.ie_tsch_slotframe_and_link.links[0].channel_offset =
272 link0->channel_offset;
273 ies.ie_tsch_slotframe_and_link.links[0].link_options =
274 link0->link_options;
275 }
276 }
277#endif /* TSCH_PACKET_EB_WITH_SLOTFRAME_AND_LINK */
278
279 p = packetbuf_dataptr();
280
281 ie_len = frame80215e_create_ie_tsch_synchronization(p,
283 &ies);
284 if(ie_len < 0) {
285 return -1;
286 }
287 p += ie_len;
289
290 ie_len = frame80215e_create_ie_tsch_timeslot(p,
292 &ies);
293 if(ie_len < 0) {
294 return -1;
295 }
296 p += ie_len;
298
299 ie_len = frame80215e_create_ie_tsch_channel_hopping_sequence(p,
301 &ies);
302 if(ie_len < 0) {
303 return -1;
304 }
305 p += ie_len;
307
308 ie_len = frame80215e_create_ie_tsch_slotframe_and_link(p,
310 &ies);
311 if(ie_len < 0) {
312 return -1;
313 }
314 p += ie_len;
316
317#if 0
318 /* Payload IE list termination: optional */
319 ie_len = frame80215e_create_ie_payload_list_termination(p,
321 &ies);
322 if(ie_len < 0) {
323 return -1;
324 }
325 p += ie_len;
327#endif
328
329 ies.ie_mlme_len = packetbuf_datalen();
330
331 /* make room for Payload IE header */
332 memmove((uint8_t *)packetbuf_dataptr() + payload_ie_hdr_len,
334 packetbuf_set_datalen(packetbuf_datalen() + payload_ie_hdr_len);
335 ie_len = frame80215e_create_ie_mlme(packetbuf_dataptr(),
337 &ies);
338 if(ie_len < 0) {
339 return -1;
340 }
341
342 /* allocate space for Header Termination IE, the size of which is 2 octets */
344 ie_len = frame80215e_create_ie_header_list_termination_1(packetbuf_hdrptr(),
346 &ies);
347 if(ie_len < 0) {
348 return -1;
349 }
350
351 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_BEACONFRAME);
352 packetbuf_set_attr(PACKETBUF_ATTR_MAC_METADATA, 1);
353
354 packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
355 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &tsch_eb_address);
356
357#if LLSEC802154_ENABLED
358 tsch_security_set_packetbuf_attr(FRAME802154_BEACONFRAME);
359#endif /* LLSEC802154_ENABLED */
360
361 if(NETSTACK_FRAMER.create() < 0) {
362 return -1;
363 }
364
365 if(hdr_len != NULL) {
366 *hdr_len = packetbuf_hdrlen();
367 }
368
369 /*
370 * Save the offset of the TSCH Synchronization IE, which is expected to be
371 * located just after the Payload IE header, needed to update ASN and join
372 * priority before sending.
373 */
374 if(tsch_sync_ie_offset != NULL) {
375 *tsch_sync_ie_offset = packetbuf_hdrlen() + payload_ie_hdr_len;
376 }
377
378 return packetbuf_totlen();
379}
380/*---------------------------------------------------------------------------*/
381/* Update ASN in EB packet */
382int
383tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset)
384{
385 struct ieee802154_ies ies;
386 ies.ie_asn = tsch_current_asn;
387 ies.ie_join_priority = tsch_join_priority;
388 return frame80215e_create_ie_tsch_synchronization(buf+tsch_sync_ie_offset, buf_size-tsch_sync_ie_offset, &ies) != -1;
389}
390/*---------------------------------------------------------------------------*/
391/* Parse a IEEE 802.15.4e TSCH Enhanced Beacon (EB) */
392int
393tsch_packet_parse_eb(const uint8_t *buf, int buf_size,
394 frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len, int frame_without_mic)
395{
396 uint8_t curr_len = 0;
397 int ret;
398
399 if(frame == NULL || buf_size < 0) {
400 return 0;
401 }
402
403 /* Parse 802.15.4-2006 frame, i.e. all fields before Information Elements */
404 if((ret = frame802154_parse((uint8_t *)buf, buf_size, frame)) == 0) {
405 LOG_ERR("! parse_eb: failed to parse frame\n");
406 return 0;
407 }
408
409 if(frame->fcf.frame_version < FRAME802154_IEEE802154_2015
410 || frame->fcf.frame_type != FRAME802154_BEACONFRAME) {
411 LOG_INFO("! parse_eb: frame is not a TSCH beacon." \
412 " Frame version %u, type %u, FCF %02x %02x\n",
413 frame->fcf.frame_version, frame->fcf.frame_type, buf[0], buf[1]);
414 LOG_INFO("! parse_eb: frame was from 0x%x/", frame->src_pid);
415 LOG_INFO_LLADDR((const linkaddr_t *)&frame->src_addr);
416 LOG_INFO_(" to 0x%x/", frame->dest_pid);
417 LOG_INFO_LLADDR((const linkaddr_t *)&frame->dest_addr);
418 LOG_INFO_("\n");
419 return 0;
420 }
421
422 if(hdr_len != NULL) {
423 *hdr_len = ret;
424 }
425 curr_len += ret;
426
427 if(ies != NULL) {
428 memset(ies, 0, sizeof(struct ieee802154_ies));
429 ies->ie_join_priority = 0xff; /* Use max value in case the Beacon does not include a join priority */
430 }
431 if(frame->fcf.ie_list_present) {
432 /* Calculate space needed for the security MIC, if any, before attempting to parse IEs */
433 int mic_len = 0;
434#if LLSEC802154_ENABLED
435 if(!frame_without_mic) {
436 mic_len = tsch_security_mic_len(frame);
437 if(buf_size < curr_len + mic_len) {
438 return 0;
439 }
440 }
441#endif /* LLSEC802154_ENABLED */
442
443 /* Parse information elements. We need to substract the MIC length, as the exact payload len is needed while parsing */
444 if((ret = frame802154e_parse_information_elements(buf + curr_len, buf_size - curr_len - mic_len, ies)) == -1) {
445 LOG_ERR("! parse_eb: failed to parse IEs\n");
446 return 0;
447 }
448 curr_len += ret;
449 }
450
451 if(hdr_len != NULL) {
452 *hdr_len += ies->ie_payload_ie_offset;
453 }
454
455 return curr_len;
456}
457/*---------------------------------------------------------------------------*/
458/* Set frame pending bit in a packet (whose header was already build) */
459void
460tsch_packet_set_frame_pending(uint8_t *buf, int buf_size)
461{
462 buf[0] |= (1 << IEEE802154_FRAME_PENDING_BIT_OFFSET);
463}
464/*---------------------------------------------------------------------------*/
465/* Get frame pending bit from a packet */
466int
467tsch_packet_get_frame_pending(uint8_t *buf, int buf_size)
468{
469 return (buf[0] >> IEEE802154_FRAME_PENDING_BIT_OFFSET) & 1;
470}
471/*---------------------------------------------------------------------------*/
472/** @} */
AES-128.
CCM* header file.
802.15.4 frame creation and parsing functions
int frame80215e_create_ie_header_ack_nack_time_correction(uint8_t *buf, int len, const struct ieee802154_ies *ies)
Insert various Information Elements.
A MAC framer for IEEE 802.15.4.
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
int frame802154_create(frame802154_t *p, uint8_t *buf)
Creates a frame for transmission over the air.
int frame802154_hdrlen(frame802154_t *p)
Calculates the length of the frame header.
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition linkaddr.c:48
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition linkaddr.c:63
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition linkaddr.c:69
const linkaddr_t linkaddr_null
The null link-layer address.
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition packetbuf.c:136
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition packetbuf.c:143
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition packetbuf.c:167
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition packetbuf.c:155
uint8_t packetbuf_hdrlen(void)
Get the length of the header in the packetbuf.
Definition packetbuf.c:161
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition packetbuf.c:149
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition packetbuf.c:75
int packetbuf_hdralloc(int size)
Extend the header of the packetbuf, for outbound packets.
Definition packetbuf.c:107
uint16_t packetbuf_remaininglen(void)
Get the total length of the remaining space in the packetbuf.
Definition packetbuf.c:173
int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset)
Update ASN in EB packet.
struct tsch_slotframe * tsch_schedule_get_slotframe_by_handle(uint16_t handle)
Looks up a slotframe by handle.
int tsch_packet_parse_eb(const uint8_t *buf, int buf_size, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len, int frame_without_mic)
Parse EB.
void tsch_security_set_packetbuf_attr(uint8_t frame_type)
Set packetbuf (or eackbuf) attributes depending on a given frame type.
int tsch_packet_parse_eack(const uint8_t *buf, int buf_size, uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len)
Parse enhanced ACK packet.
int tsch_packet_create_eack(uint8_t *buf, uint16_t buf_len, const linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack)
Construct Enhanced ACK packet.
Definition tsch-packet.c:93
packetbuf_attr_t tsch_packet_eackbuf_attr(uint8_t type)
Return the value of a specified attribute.
Definition tsch-packet.c:86
int tsch_packet_get_frame_pending(uint8_t *buf, int buf_size)
Get frame pending bit from a packet.
unsigned int tsch_security_mic_len(const frame802154_t *frame)
Return MIC length.
struct tsch_link * tsch_schedule_get_link_by_offsets(struct tsch_slotframe *slotframe, uint16_t timeslot, uint16_t channel_offset)
Looks within a slotframe for a link with a given timeslot and channel offset.
int tsch_packet_create_eb(uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset)
Create an EB packet directly in packetbuf.
void tsch_packet_eackbuf_set_attr(uint8_t type, const packetbuf_attr_t val)
Set a packet attribute for the current eack.
Definition tsch-packet.c:78
void tsch_packet_set_frame_pending(uint8_t *buf, int buf_size)
Set frame pending bit in a packet (whose header was already build).
Header file for the logging system.
Include file for the Contiki low-layer network stack (NETSTACK).
Header file for the Packet buffer (packetbuf) management.
uint8_t frame_type
3 bit.
uint8_t frame_version
2 bit.
uint8_t ie_list_present
1 bit.
Parameters used by the frame802154_create() function.
uint8_t seq
Sequence number.
uint8_t dest_addr[8]
Destination address.
uint8_t src_addr[8]
Source address.
uint16_t src_pid
Source PAN ID.
frame802154_fcf_t fcf
Frame control field.
uint16_t dest_pid
Destination PAN ID.
802.15.4e slotframe (contains links)
Definition tsch-types.h:84
Main API declarations for TSCH.