Contiki 2.5
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  * $Id: frame802154.c,v 1.4 2010/02/18 21:00:28 adamdunkels Exp $
48 */
49 /*
50  * \brief This file is where the main functions that relate to frame
51  * manipulation will reside.
52 */
53 /**
54  * \addtogroup frame802154
55  * @{
56 */
57 /**
58  * \file
59  * \brief 802.15.4 frame creation and parsing functions
60  *
61  * This file converts to and from a structure to a packed 802.15.4
62  * frame.
63  */
64 
65 #include "sys/cc.h"
66 #include "net/mac/frame802154.h"
67 #include <string.h>
68 
69 /**
70  * \brief Structure that contains the lengths of the various addressing and security fields
71  * in the 802.15.4 header. This structure is used in \ref frame802154_create()
72  */
73 typedef struct {
74  uint8_t dest_pid_len; /**< Length (in bytes) of destination PAN ID field */
75  uint8_t dest_addr_len; /**< Length (in bytes) of destination address field */
76  uint8_t src_pid_len; /**< Length (in bytes) of source PAN ID field */
77  uint8_t src_addr_len; /**< Length (in bytes) of source address field */
78  uint8_t aux_sec_len; /**< Length (in bytes) of aux security header field */
79 } field_length_t;
80 
81 /*----------------------------------------------------------------------------*/
82 CC_INLINE static uint8_t
83 addr_len(uint8_t mode)
84 {
85  switch(mode) {
86  case FRAME802154_SHORTADDRMODE: /* 16-bit address */
87  return 2;
88  case FRAME802154_LONGADDRMODE: /* 64-bit address */
89  return 8;
90  default:
91  return 0;
92  }
93 }
94 /*----------------------------------------------------------------------------*/
95 static void
96 field_len(frame802154_t *p, field_length_t *flen)
97 {
98  /* init flen to zeros */
99  memset(flen, 0, sizeof(field_length_t));
100 
101  /* Determine lengths of each field based on fcf and other args */
102  if(p->fcf.dest_addr_mode & 3) {
103  flen->dest_pid_len = 2;
104  }
105  if(p->fcf.src_addr_mode & 3) {
106  flen->src_pid_len = 2;
107  }
108 
109  /* Set PAN ID compression bit if src pan id matches dest pan id. */
110  if(p->fcf.dest_addr_mode & 3 && p->fcf.src_addr_mode & 3 &&
111  p->src_pid == p->dest_pid) {
112  p->fcf.panid_compression = 1;
113 
114  /* compressed header, only do dest pid */
115  flen->src_pid_len = 0;
116  } else {
117  p->fcf.panid_compression = 0;
118  }
119 
120  /* determine address lengths */
121  flen->dest_addr_len = addr_len(p->fcf.dest_addr_mode & 3);
122  flen->src_addr_len = addr_len(p->fcf.src_addr_mode & 3);
123 
124  /* Aux security header */
125  if(p->fcf.security_enabled & 1) {
126  /* TODO Aux security header not yet implemented */
127 #if 0
129  case 0:
130  flen->aux_sec_len = 5; /* minimum value */
131  break;
132  case 1:
133  flen->aux_sec_len = 6;
134  break;
135  case 2:
136  flen->aux_sec_len = 10;
137  break;
138  case 3:
139  flen->aux_sec_len = 14;
140  break;
141  default:
142  break;
143  }
144 #endif
145  }
146 }
147 /*----------------------------------------------------------------------------*/
148 /**
149  * \brief Calculates the length of the frame header. This function is
150  * meant to be called by a higher level function, that interfaces to a MAC.
151  *
152  * \param p Pointer to frame802154_t_t struct, which specifies the
153  * frame to send.
154  *
155  * \return The length of the frame header.
156 */
157 uint8_t
159 {
160  field_length_t flen;
161  field_len(p, &flen);
162  return 3 + flen.dest_pid_len + flen.dest_addr_len +
163  flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len;
164 }
165 /*----------------------------------------------------------------------------*/
166 /**
167  * \brief Creates a frame for transmission over the air. This function is
168  * meant to be called by a higher level function, that interfaces to a MAC.
169  *
170  * \param p Pointer to frame802154_t struct, which specifies the
171  * frame to send.
172  *
173  * \param buf Pointer to the buffer to use for the frame.
174  *
175  * \param buf_len The length of the buffer to use for the frame.
176  *
177  * \return The length of the frame header or 0 if there was
178  * insufficient space in the buffer for the frame headers.
179 */
180 uint8_t
181 frame802154_create(frame802154_t *p, uint8_t *buf, uint8_t buf_len)
182 {
183  int c;
184  field_length_t flen;
185  uint8_t *tx_frame_buffer;
186  uint8_t pos;
187 
188  field_len(p, &flen);
189 
190  if(3 + flen.dest_pid_len + flen.dest_addr_len +
191  flen.src_pid_len + flen.src_addr_len + flen.aux_sec_len > buf_len) {
192  /* Too little space for headers. */
193  return 0;
194  }
195 
196  /* OK, now we have field lengths. Time to actually construct */
197  /* the outgoing frame, and store it in tx_frame_buffer */
198  tx_frame_buffer = buf;
199  tx_frame_buffer[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  tx_frame_buffer[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  tx_frame_buffer[2] = p->seq;
210  pos = 3;
211 
212  /* Destination PAN ID */
213  if(flen.dest_pid_len == 2) {
214  tx_frame_buffer[pos++] = p->dest_pid & 0xff;
215  tx_frame_buffer[pos++] = (p->dest_pid >> 8) & 0xff;
216  }
217 
218  /* Destination address */
219  for(c = flen.dest_addr_len; c > 0; c--) {
220  tx_frame_buffer[pos++] = p->dest_addr[c - 1];
221  }
222 
223  /* Source PAN ID */
224  if(flen.src_pid_len == 2) {
225  tx_frame_buffer[pos++] = p->src_pid & 0xff;
226  tx_frame_buffer[pos++] = (p->src_pid >> 8) & 0xff;
227  }
228 
229  /* Source address */
230  for(c = flen.src_addr_len; c > 0; c--) {
231  tx_frame_buffer[pos++] = p->src_addr[c - 1];
232  }
233 
234  /* Aux header */
235  if(flen.aux_sec_len) {
236  /* TODO Aux security header not yet implemented */
237 /* pos += flen.aux_sec_len; */
238  }
239 
240  return pos;
241 }
242 /*----------------------------------------------------------------------------*/
243 /**
244  * \brief Parses an input frame. Scans the input frame to find each
245  * section, and stores the information of each section in a
246  * frame802154_t structure.
247  *
248  * \param data The input data from the radio chip.
249  * \param len The size of the input data
250  * \param pf The frame802154_t struct to store the parsed frame information.
251  */
252 uint8_t
253 frame802154_parse(uint8_t *data, uint8_t len, frame802154_t *pf)
254 {
255  uint8_t *p;
256  frame802154_fcf_t fcf;
257  uint8_t c;
258 
259  if(len < 3) {
260  return 0;
261  }
262 
263  p = data;
264 
265  /* decode the FCF */
266  fcf.frame_type = p[0] & 7;
267  fcf.security_enabled = (p[0] >> 3) & 1;
268  fcf.frame_pending = (p[0] >> 4) & 1;
269  fcf.ack_required = (p[0] >> 5) & 1;
270  fcf.panid_compression = (p[0] >> 6) & 1;
271 
272  fcf.dest_addr_mode = (p[1] >> 2) & 3;
273  fcf.frame_version = (p[1] >> 4) & 3;
274  fcf.src_addr_mode = (p[1] >> 6) & 3;
275 
276  /* copy fcf and seqNum */
277  memcpy(&pf->fcf, &fcf, sizeof(frame802154_fcf_t));
278  pf->seq = p[2];
279  p += 3; /* Skip first three bytes */
280 
281  /* Destination address, if any */
282  if(fcf.dest_addr_mode) {
283  /* Destination PAN */
284  pf->dest_pid = p[0] + (p[1] << 8);
285  p += 2;
286 
287  /* Destination address */
288 /* l = addr_len(fcf.dest_addr_mode); */
289 /* for(c = 0; c < l; c++) { */
290 /* pf->dest_addr.u8[c] = p[l - c - 1]; */
291 /* } */
292 /* p += l; */
293  if(fcf.dest_addr_mode == FRAME802154_SHORTADDRMODE) {
294  rimeaddr_copy((rimeaddr_t *)&(pf->dest_addr), &rimeaddr_null);
295  pf->dest_addr[0] = p[1];
296  pf->dest_addr[1] = p[0];
297  p += 2;
298  } else if(fcf.dest_addr_mode == FRAME802154_LONGADDRMODE) {
299  for(c = 0; c < 8; c++) {
300  pf->dest_addr[c] = p[7 - c];
301  }
302  p += 8;
303  }
304  } else {
305  rimeaddr_copy((rimeaddr_t *)&(pf->dest_addr), &rimeaddr_null);
306  pf->dest_pid = 0;
307  }
308 
309  /* Source address, if any */
310  if(fcf.src_addr_mode) {
311  /* Source PAN */
312  if(!fcf.panid_compression) {
313  pf->src_pid = p[0] + (p[1] << 8);
314  p += 2;
315  } else {
316  pf->src_pid = pf->dest_pid;
317  }
318 
319  /* Source address */
320 /* l = addr_len(fcf.src_addr_mode); */
321 /* for(c = 0; c < l; c++) { */
322 /* pf->src_addr.u8[c] = p[l - c - 1]; */
323 /* } */
324 /* p += l; */
325  if(fcf.src_addr_mode == FRAME802154_SHORTADDRMODE) {
326  rimeaddr_copy((rimeaddr_t *)&(pf->src_addr), &rimeaddr_null);
327  pf->src_addr[0] = p[1];
328  pf->src_addr[1] = p[0];
329  p += 2;
330  } else if(fcf.src_addr_mode == FRAME802154_LONGADDRMODE) {
331  for(c = 0; c < 8; c++) {
332  pf->src_addr[c] = p[7 - c];
333  }
334  p += 8;
335  }
336  } else {
337  rimeaddr_copy((rimeaddr_t *)&(pf->src_addr), &rimeaddr_null);
338  pf->src_pid = 0;
339  }
340 
341  if(fcf.security_enabled) {
342  /* TODO aux security header, not yet implemented */
343 /* return 0; */
344  }
345 
346  /* header length */
347  c = p - data;
348  /* payload length */
349  pf->payload_len = len - c;
350  /* payload */
351  pf->payload = p;
352 
353  /* return header length if successful */
354  return c > len ? 0 : c;
355 }
356 /** \} */