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