Contiki 3.x
frame802154.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2008, Swedish Institute of Computer Science
4  * All rights reserved.
5  *
6  * Additional fixes for AVR contributed by:
7  *
8  * Colin O'Flynn coflynn@newae.com
9  * Eric Gnoske egnoske@gmail.com
10  * Blake Leverett bleverett@gmail.com
11  * Mike Vidales mavida404@gmail.com
12  * Kevin Brown kbrown3@uccs.edu
13  * Nate Bohlmann nate@elfwerks.com
14  *
15  * Additional fixes for MSP430 contributed by:
16  * Joakim Eriksson
17  * Niclas Finne
18  * Nicolas Tsiftes
19  *
20  * All rights reserved.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions are met:
24  *
25  * * Redistributions of source code must retain the above copyright
26  * notice, this list of conditions and the following disclaimer.
27  * * Redistributions in binary form must reproduce the above copyright
28  * notice, this list of conditions and the following disclaimer in
29  * the documentation and/or other materials provided with the
30  * distribution.
31  * * Neither the name of the copyright holders nor the names of
32  * contributors may be used to endorse or promote products derived
33  * from this software without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
39  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45  * POSSIBILITY OF SUCH DAMAGE.
46  *
47 */
48 /*
49  * \brief This file is where the main functions that relate to frame
50  * manipulation will reside.
51 */
52 
53 /**
54  * \file
55  * \brief 802.15.4 frame creation and parsing functions
56  *
57  * This file converts to and from a structure to a packed 802.15.4
58  * frame.
59  */
60 
61 /**
62  * \addtogroup frame802154
63  * @{
64 */
65 
66 #include "sys/cc.h"
67 #include "net/mac/frame802154.h"
68 #include "net/llsec/llsec802154.h"
69 #include "net/linkaddr.h"
70 #include <string.h>
71 
72 /**
73  * \brief Structure that contains the lengths of the various addressing and security fields
74  * in the 802.15.4 header. This structure is used in \ref frame802154_create()
75  */
76 typedef struct {
77  uint8_t dest_pid_len; /**< Length (in bytes) of destination PAN ID field */
78  uint8_t dest_addr_len; /**< Length (in bytes) of destination address field */
79  uint8_t src_pid_len; /**< Length (in bytes) of source PAN ID field */
80  uint8_t src_addr_len; /**< Length (in bytes) of source address field */
81  uint8_t aux_sec_len; /**< Length (in bytes) of aux security header field */
82 } field_length_t;
83 
84 /*----------------------------------------------------------------------------*/
85 CC_INLINE static uint8_t
86 addr_len(uint8_t mode)
87 {
88  switch(mode) {
89  case FRAME802154_SHORTADDRMODE: /* 16-bit address */
90  return 2;
91  case FRAME802154_LONGADDRMODE: /* 64-bit address */
92  return 8;
93  default:
94  return 0;
95  }
96 }
97 /*----------------------------------------------------------------------------*/
98 #if LLSEC802154_USES_EXPLICIT_KEYS
99 static uint8_t
100 get_key_id_len(uint8_t key_id_mode)
101 {
102  switch(key_id_mode) {
103  case FRAME802154_1_BYTE_KEY_ID_MODE:
104  return 1;
105  case FRAME802154_5_BYTE_KEY_ID_MODE:
106  return 5;
107  case FRAME802154_9_BYTE_KEY_ID_MODE:
108  return 9;
109  default:
110  return 0;
111  }
112 }
113 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
114 /*----------------------------------------------------------------------------*/
115 static void
116 field_len(frame802154_t *p, field_length_t *flen)
117 {
118  /* init flen to zeros */
119  memset(flen, 0, sizeof(field_length_t));
120 
121  /* Determine lengths of each field based on fcf and other args */
122  if(p->fcf.dest_addr_mode & 3) {
123  flen->dest_pid_len = 2;
124  }
125  if(p->fcf.src_addr_mode & 3) {
126  flen->src_pid_len = 2;
127  }
128 
129  /* Set PAN ID compression bit if src pan id matches dest pan id. */
130  if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
131  p->src_pid == p->dest_pid) {
132  p->fcf.panid_compression = 1;
133 
134  /* compressed header, only do dest pid */
135  flen->src_pid_len = 0;
136  } else {
137  p->fcf.panid_compression = 0;
138  }
139 
140  /* determine address lengths */
141  flen->dest_addr_len = addr_len(p->fcf.dest_addr_mode & 3);
142  flen->src_addr_len = addr_len(p->fcf.src_addr_mode & 3);
143 
144 #if LLSEC802154_SECURITY_LEVEL
145  /* Aux security header */
146  if(p->fcf.security_enabled & 1) {
147  flen->aux_sec_len = 5
148 #if LLSEC802154_USES_EXPLICIT_KEYS
149  + get_key_id_len(p->aux_hdr.security_control.key_id_mode);
150 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
151  ;
152  }
153 #endif /* LLSEC802154_SECURITY_LEVEL */
154 }
155 /*----------------------------------------------------------------------------*/
156 /**
157  * \brief Calculates the length of the frame header. This function is
158  * meant to be called by a higher level function, that interfaces to a MAC.
159  *
160  * \param p Pointer to frame802154_t_t struct, which specifies the
161  * frame to send.
162  *
163  * \return The length of the frame header.
164 */
165 int
167 {
168  field_length_t flen;
169  field_len(p, &flen);
170  return 3 + flen.dest_pid_len + flen.dest_addr_len +
171  flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
172 }
173 /*----------------------------------------------------------------------------*/
174 /**
175  * \brief Creates a frame for transmission over the air. This function is
176  * meant to be called by a higher level function, that interfaces to a MAC.
177  *
178  * \param p Pointer to frame802154_t struct, which specifies the
179  * frame to send.
180  *
181  * \param buf Pointer to the buffer to use for the frame.
182  *
183  * \return The length of the frame header
184 */
185 int
187 {
188  int c;
189  field_length_t flen;
190  uint8_t pos;
191 #if LLSEC802154_USES_EXPLICIT_KEYS
192  uint8_t key_id_mode;
193 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
194 
195  field_len(p, &flen);
196 
197  /* OK, now we have field lengths. Time to actually construct */
198  /* the outgoing frame, and store it in buf */
199  buf[0] = (p->fcf.frame_type & 7) |
200  ((p->fcf.security_enabled & 1) << 3) |
201  ((p->fcf.frame_pending & 1) << 4) |
202  ((p->fcf.ack_required & 1) << 5) |
203  ((p->fcf.panid_compression & 1) << 6);
204  buf[1] = ((p->fcf.dest_addr_mode & 3) << 2) |
205  ((p->fcf.frame_version & 3) << 4) |
206  ((p->fcf.src_addr_mode & 3) << 6);
207 
208  /* sequence number */
209  buf[2] = p->seq;
210  pos = 3;
211 
212  /* Destination PAN ID */
213  if(flen.dest_pid_len == 2) {
214  buf[pos++] = p->dest_pid & 0xff;
215  buf[pos++] = (p->dest_pid >> 8) & 0xff;
216  }
217 
218  /* Destination address */
219  for(c = flen.dest_addr_len; c > 0; c--) {
220  buf[pos++] = p->dest_addr[c - 1];
221  }
222 
223  /* Source PAN ID */
224  if(flen.src_pid_len == 2) {
225  buf[pos++] = p->src_pid & 0xff;
226  buf[pos++] = (p->src_pid >> 8) & 0xff;
227  }
228 
229  /* Source address */
230  for(c = flen.src_addr_len; c > 0; c--) {
231  buf[pos++] = p->src_addr[c - 1];
232  }
233 
234 #if LLSEC802154_SECURITY_LEVEL
235  /* Aux header */
236  if(flen.aux_sec_len) {
237  buf[pos++] = p->aux_hdr.security_control.security_level
238 #if LLSEC802154_USES_EXPLICIT_KEYS
240 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
241  ;
242  memcpy(buf + pos, p->aux_hdr.frame_counter.u8, 4);
243  pos += 4;
244 
245 #if LLSEC802154_USES_EXPLICIT_KEYS
246  key_id_mode = p->aux_hdr.security_control.key_id_mode;
247  if(key_id_mode) {
248  c = (key_id_mode - 1) * 4;
249  memcpy(buf + pos, p->aux_hdr.key_source.u8, c);
250  pos += c;
251  buf[pos++] = p->aux_hdr.key_index;
252  }
253 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
254  }
255 #endif /* LLSEC802154_SECURITY_LEVEL */
256 
257  return (int)pos;
258 }
259 /*----------------------------------------------------------------------------*/
260 /**
261  * \brief Parses an input frame. Scans the input frame to find each
262  * section, and stores the information of each section in a
263  * frame802154_t structure.
264  *
265  * \param data The input data from the radio chip.
266  * \param len The size of the input data
267  * \param pf The frame802154_t struct to store the parsed frame information.
268  */
269 int
270 frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
271 {
272  uint8_t *p;
273  frame802154_fcf_t fcf;
274  int c;
275 #if LLSEC802154_USES_EXPLICIT_KEYS
276  uint8_t key_id_mode;
277 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
278 
279  if(len < 3) {
280  return 0;
281  }
282 
283  p = data;
284 
285  /* decode the FCF */
286  fcf.frame_type = p[0] & 7;
287  fcf.security_enabled = (p[0] >> 3) & 1;
288  fcf.frame_pending = (p[0] >> 4) & 1;
289  fcf.ack_required = (p[0] >> 5) & 1;
290  fcf.panid_compression = (p[0] >> 6) & 1;
291 
292  fcf.dest_addr_mode = (p[1] >> 2) & 3;
293  fcf.frame_version = (p[1] >> 4) & 3;
294  fcf.src_addr_mode = (p[1] >> 6) & 3;
295 
296  /* copy fcf and seqNum */
297  memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
298  pf->seq = p[2];
299  p += 3; /* Skip first three bytes */
300 
301  /* Destination address, if any */
302  if(fcf.dest_addr_mode) {
303  /* Destination PAN */
304  pf->dest_pid = p[0] + (p[1] << 8);
305  p += 2;
306 
307  /* Destination address */
308 /* l = addr_len(fcf.dest_addr_mode); */
309 /* for(c = 0; c < l; c++) { */
310 /* pf->dest_addr.u8[c] = p[l - c - 1]; */
311 /* } */
312 /* p += l; */
313  if(fcf.dest_addr_mode == FRAME802154_SHORTADDRMODE) {
314  linkaddr_copy((linkaddr_t *)&(pf->dest_addr), &linkaddr_null);
315  pf->dest_addr[0] = p[1];
316  pf->dest_addr[1] = p[0];
317  p += 2;
318  } else if(fcf.dest_addr_mode == FRAME802154_LONGADDRMODE) {
319  for(c = 0; c < 8; c++) {
320  pf->dest_addr[c] = p[7 - c];
321  }
322  p += 8;
323  }
324  } else {
325  linkaddr_copy((linkaddr_t *)&(pf->dest_addr), &linkaddr_null);
326  pf->dest_pid = 0;
327  }
328 
329  /* Source address, if any */
330  if(fcf.src_addr_mode) {
331  /* Source PAN */
332  if(!fcf.panid_compression) {
333  pf->src_pid = p[0] + (p[1] << 8);
334  p += 2;
335  } else {
336  pf->src_pid = pf->dest_pid;
337  }
338 
339  /* Source address */
340 /* l = addr_len(fcf.src_addr_mode); */
341 /* for(c = 0; c < l; c++) { */
342 /* pf->src_addr.u8[c] = p[l - c - 1]; */
343 /* } */
344 /* p += l; */
345  if(fcf.src_addr_mode == FRAME802154_SHORTADDRMODE) {
346  linkaddr_copy((linkaddr_t *)&(pf->src_addr), &linkaddr_null);
347  pf->src_addr[0] = p[1];
348  pf->src_addr[1] = p[0];
349  p += 2;
350  } else if(fcf.src_addr_mode == FRAME802154_LONGADDRMODE) {
351  for(c = 0; c < 8; c++) {
352  pf->src_addr[c] = p[7 - c];
353  }
354  p += 8;
355  }
356  } else {
357  linkaddr_copy((linkaddr_t *)&(pf->src_addr), &linkaddr_null);
358  pf->src_pid = 0;
359  }
360 
361 #if LLSEC802154_SECURITY_LEVEL
362  if(fcf.security_enabled) {
363  pf->aux_hdr.security_control.security_level = p[0] & 7;
364 #if LLSEC802154_USES_EXPLICIT_KEYS
365  pf->aux_hdr.security_control.key_id_mode = (p[0] >> 3) & 3;
366 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
367  p += 1;
368 
369  memcpy(pf->aux_hdr.frame_counter.u8, p, 4);
370  p += 4;
371 
372 #if LLSEC802154_USES_EXPLICIT_KEYS
373  key_id_mode = pf->aux_hdr.security_control.key_id_mode;
374  if(key_id_mode) {
375  c = (key_id_mode - 1) * 4;
376  memcpy(pf->aux_hdr.key_source.u8, p, c);
377  p += c;
378  pf->aux_hdr.key_index = p[0];
379  p += 1;
380  }
381 #endif /* LLSEC802154_USES_EXPLICIT_KEYS */
382  }
383 #endif /* LLSEC802154_SECURITY_LEVEL */
384 
385  /* header length */
386  c = p - data;
387  /* payload length */
388  pf->payload_len = (len - c);
389  /* payload */
390  pf->payload = p;
391 
392  /* return header length if successful */
393  return c > len ? 0 : c;
394 }
395 /** \} */
frame802154_frame_counter_t frame_counter
Frame counter, used for security.
Definition: frame802154.h:166
The IEEE 802.15.4 frame has a number of constant/fixed fields that can be counted to make frame const...
Definition: frame802154.h:133
uint8_t * payload
Pointer to 802.15.4 payload.
Definition: frame802154.h:186
802.15.4 frame creation and parsing functions
uint8_t ack_required
1 bit.
Definition: frame802154.h:137
frame802154_key_source_t key_source
Key Source subfield.
Definition: frame802154.h:167
uint8_t frame_version
2 bit.
Definition: frame802154.h:141
const linkaddr_t linkaddr_null
The null Rime address.
uint8_t frame_type
3 bit.
Definition: frame802154.h:134
int frame802154_hdrlen(frame802154_t *p)
Calculates the length of the frame header.
Definition: frame802154.c:166
uint8_t security_enabled
1 bit.
Definition: frame802154.h:135
int frame802154_create(frame802154_t *p, uint8_t *buf)
Creates a frame for transmission over the air.
Definition: frame802154.c:186
uint8_t src_addr_mode
2 bit.
Definition: frame802154.h:142
Default definitions of C compiler quirk work-arounds.
uint8_t panid_compression
1 bit.
Definition: frame802154.h:138
uint8_t key_id_mode
2 bit.
Definition: frame802154.h:148
Parameters used by the frame802154_create() function.
Definition: frame802154.h:175
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
Definition: linkaddr.c:60
uint8_t seq
Sequence number.
Definition: frame802154.h:182
int payload_len
Length of payload field.
Definition: frame802154.h:187
frame802154_scf_t security_control
Security control bitfield.
Definition: frame802154.h:165
uint8_t dest_addr[8]
Destination address.
Definition: frame802154.h:179
uint8_t key_index
Key Index subfield.
Definition: frame802154.h:168
uint16_t dest_pid
Destination PAN ID.
Definition: frame802154.h:183
uint16_t src_pid
Source PAN ID.
Definition: frame802154.h:184
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
Definition: frame802154.c:270
Common functionality of 802.15.4-compliant llsec_drivers.
uint8_t frame_pending
1 bit.
Definition: frame802154.h:136
frame802154_fcf_t fcf
Frame control field.
Definition: frame802154.h:181
uint8_t security_level
3 bit.
Definition: frame802154.h:147
uint8_t src_addr[8]
Source address.
Definition: frame802154.h:180
frame802154_aux_hdr_t aux_hdr
Aux security header.
Definition: frame802154.h:185
uint8_t dest_addr_mode
&lt; 3 bit.
Definition: frame802154.h:140
Header file for the Rime address representation