Contiki 2.5
sicslowmac.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Swedish Institute of Computer Science.
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  * $Id: sicslowmac.c,v 1.8 2010/06/14 19:19:17 adamdunkels Exp $
32  */
33 
34 
35 /**
36  * \file
37  * MAC interface for packaging radio packets into 802.15.4 frames
38  *
39  * \author
40  * Adam Dunkels <adam@sics.se>
41  * Eric Gnoske <egnoske@gmail.com>
42  * Blake Leverett <bleverett@gmail.com>
43  * Niclas Finne <nfi@sics.se>
44  * Joakim Eriksson <joakime@sics.se>
45  */
46 
47 #include <string.h>
48 #include "net/mac/sicslowmac.h"
49 #include "net/mac/frame802154.h"
50 #include "net/packetbuf.h"
51 #include "net/netstack.h"
52 #include "lib/random.h"
53 
54 #define DEBUG 0
55 
56 #if DEBUG
57 #include <stdio.h>
58 #define PRINTF(...) printf(__VA_ARGS__)
59 #define PRINTADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7])
60 #else
61 #define PRINTF(...)
62 #define PRINTADDR(addr)
63 #endif
64 
65 /** \brief The sequence number (0x00 - 0xff) added to the transmitted
66  * data or MAC command frame. The default is a random value within
67  * the range.
68  */
69 static uint8_t mac_dsn;
70 
71 /** \brief The 16-bit identifier of the PAN on which the device is
72  * sending to. If this value is 0xffff, the device is not
73  * associated.
74  */
75 static uint16_t mac_dst_pan_id = IEEE802154_PANID;
76 
77 /** \brief The 16-bit identifier of the PAN on which the device is
78  * operating. If this value is 0xffff, the device is not
79  * associated.
80  */
81 static uint16_t mac_src_pan_id = IEEE802154_PANID;
82 
83 /*---------------------------------------------------------------------------*/
84 static int
85 is_broadcast_addr(uint8_t mode, uint8_t *addr)
86 {
87  int i = mode == FRAME802154_SHORTADDRMODE ? 2 : 8;
88  while(i-- > 0) {
89  if(addr[i] != 0xff) {
90  return 0;
91  }
92  }
93  return 1;
94 }
95 /*---------------------------------------------------------------------------*/
96 static void
97 send_packet(mac_callback_t sent, void *ptr)
98 {
99  frame802154_t params;
100  uint8_t len;
101 
102  /* init to zeros */
103  memset(&params, 0, sizeof(params));
104 
105  /* Build the FCF. */
106  params.fcf.frame_type = FRAME802154_DATAFRAME;
107  params.fcf.security_enabled = 0;
108  params.fcf.frame_pending = 0;
109  params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
110  params.fcf.panid_compression = 0;
111 
112  /* Insert IEEE 802.15.4 (2003) version bit. */
113  params.fcf.frame_version = FRAME802154_IEEE802154_2003;
114 
115  /* Increment and set the data sequence number. */
116  params.seq = mac_dsn++;
117 
118  /* Complete the addressing fields. */
119  /**
120  \todo For phase 1 the addresses are all long. We'll need a mechanism
121  in the rime attributes to tell the mac to use long or short for phase 2.
122  */
123  params.fcf.src_addr_mode = FRAME802154_LONGADDRMODE;
124  params.dest_pid = mac_dst_pan_id;
125 
126  /*
127  * If the output address is NULL in the Rime buf, then it is broadcast
128  * on the 802.15.4 network.
129  */
130  if(rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &rimeaddr_null)) {
131  /* Broadcast requires short address mode. */
132  params.fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
133  params.dest_addr[0] = 0xFF;
134  params.dest_addr[1] = 0xFF;
135 
136  } else {
137  rimeaddr_copy((rimeaddr_t *)&params.dest_addr,
138  packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
139  params.fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
140  }
141 
142  /* Set the source PAN ID to the global variable. */
143  params.src_pid = mac_src_pan_id;
144 
145  /*
146  * Set up the source address using only the long address mode for
147  * phase 1.
148  */
149  rimeaddr_copy((rimeaddr_t *)&params.src_addr, &rimeaddr_node_addr);
150 
151  params.payload = packetbuf_dataptr();
152  params.payload_len = packetbuf_datalen();
153  len = frame802154_hdrlen(&params);
154  if(packetbuf_hdralloc(len)) {
155  int ret;
156  frame802154_create(&params, packetbuf_hdrptr(), len);
157 
158  PRINTF("6MAC-UT: %2X", params.fcf.frame_type);
159  PRINTADDR(params.dest_addr.u8);
160  PRINTF("%u %u (%u)\n", len, packetbuf_datalen(), packetbuf_totlen());
161 
162  ret = NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen());
163  if(sent) {
164  switch(ret) {
165  case RADIO_TX_OK:
166  sent(ptr, MAC_TX_OK, 1);
167  break;
168  case RADIO_TX_ERR:
169  sent(ptr, MAC_TX_ERR, 1);
170  break;
171  }
172  }
173  } else {
174  PRINTF("6MAC-UT: too large header: %u\n", len);
175  }
176 }
177 /*---------------------------------------------------------------------------*/
178 static void
179 input_packet(void)
180 {
181  frame802154_t frame;
182  int len;
183 
184  len = packetbuf_datalen();
185 
186  if(frame802154_parse(packetbuf_dataptr(), len, &frame) &&
187  packetbuf_hdrreduce(len - frame.payload_len)) {
188  if(frame.fcf.dest_addr_mode) {
189  if(frame.dest_pid != mac_src_pan_id &&
190  frame.dest_pid != FRAME802154_BROADCASTPANDID) {
191  /* Not broadcast or for our PAN */
192  PRINTF("6MAC: for another pan %u\n", frame.dest_pid);
193  return;
194  }
195  if(!is_broadcast_addr(frame.fcf.dest_addr_mode, frame.dest_addr)) {
196  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, (rimeaddr_t *)&frame.dest_addr);
197  if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
198  &rimeaddr_node_addr)) {
199  /* Not for this node */
200  PRINTF("6MAC: not for us\n");
201  return;
202  }
203  }
204  }
205  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (rimeaddr_t *)&frame.src_addr);
206 
207  PRINTF("6MAC-IN: %2X", frame.fcf.frame_type);
208  PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
209  PRINTADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
210  PRINTF("%u\n", packetbuf_datalen());
211  NETSTACK_MAC.input();
212  } else {
213  PRINTF("6MAC: failed to parse hdr\n");
214  }
215 }
216 /*---------------------------------------------------------------------------*/
217 static int
218 on(void)
219 {
220  return NETSTACK_RADIO.on();
221 }
222 /*---------------------------------------------------------------------------*/
223 static int
224 off(int keep_radio_on)
225 {
226  if(keep_radio_on) {
227  return NETSTACK_RADIO.on();
228  } else {
229  return NETSTACK_RADIO.off();
230  }
231 }
232 /*---------------------------------------------------------------------------*/
233 static void
234 init(void)
235 {
236  mac_dsn = random_rand() % 256;
237 
238  NETSTACK_RADIO.on();
239 }
240 /*---------------------------------------------------------------------------*/
241 static unsigned short
242 channel_check_interval(void)
243 {
244  return 0;
245 }
246 /*---------------------------------------------------------------------------*/
247 const struct rdc_driver sicslowmac_driver = {
248  "sicslowmac",
249  init,
250  send_packet,
251  input_packet,
252  on,
253  off,
255 };
256 /*---------------------------------------------------------------------------*/