Contiki 3.x
csma.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, 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  */
32 
33 /**
34  * \file
35  * A Carrier Sense Multiple Access (CSMA) MAC layer
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 #include "net/mac/csma.h"
41 #include "net/packetbuf.h"
42 #include "net/queuebuf.h"
43 
44 #include "sys/ctimer.h"
45 #include "sys/clock.h"
46 
47 #include "lib/random.h"
48 
49 #include "net/netstack.h"
50 
51 #include "lib/list.h"
52 #include "lib/memb.h"
53 
54 #include <string.h>
55 
56 #include <stdio.h>
57 
58 #define DEBUG 0
59 #if DEBUG
60 #include <stdio.h>
61 #define PRINTF(...) printf(__VA_ARGS__)
62 #else /* DEBUG */
63 #define PRINTF(...)
64 #endif /* DEBUG */
65 
66 /* Constants of the IEEE 802.15.4 standard */
67 
68 /* macMinBE: Initial backoff exponent. Range 0--CSMA_MAX_BE */
69 #ifdef CSMA_CONF_MIN_BE
70 #define CSMA_MIN_BE CSMA_CONF_MIN_BE
71 #else
72 #define CSMA_MIN_BE 0
73 #endif
74 
75 /* macMaxBE: Maximum backoff exponent. Range 3--8 */
76 #ifdef CSMA_CONF_MAX_BE
77 #define CSMA_MAX_BE CSMA_CONF_MAX_BE
78 #else
79 #define CSMA_MAX_BE 4
80 #endif
81 
82 /* macMaxCSMABackoffs: Maximum number of backoffs in case of channel busy/collision. Range 0--5 */
83 #ifdef CSMA_CONF_MAX_BACKOFF
84 #define CSMA_MAX_BACKOFF CSMA_CONF_MAX_BACKOFF
85 #else
86 #define CSMA_MAX_BACKOFF 5
87 #endif
88 
89 /* macMaxFrameRetries: Maximum number of re-transmissions attampts. Range 0--7 */
90 #ifdef CSMA_CONF_MAX_FRAME_RETRIES
91 #define CSMA_MAX_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES
92 #else
93 #define CSMA_MAX_MAX_FRAME_RETRIES 7
94 #endif
95 
96 /* Packet metadata */
97 struct qbuf_metadata {
98  mac_callback_t sent;
99  void *cptr;
100  uint8_t max_transmissions;
101 };
102 
103 /* Every neighbor has its own packet queue */
104 struct neighbor_queue {
105  struct neighbor_queue *next;
106  linkaddr_t addr;
107  struct ctimer transmit_timer;
108  uint8_t transmissions;
109  uint8_t collisions;
110  LIST_STRUCT(queued_packet_list);
111 };
112 
113 /* The maximum number of co-existing neighbor queues */
114 #ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
115 #define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
116 #else
117 #define CSMA_MAX_NEIGHBOR_QUEUES 2
118 #endif /* CSMA_CONF_MAX_NEIGHBOR_QUEUES */
119 
120 /* The maximum number of pending packet per neighbor */
121 #ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
122 #define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
123 #else
124 #define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
125 #endif /* CSMA_CONF_MAX_PACKET_PER_NEIGHBOR */
126 
127 #define MAX_QUEUED_PACKETS QUEUEBUF_NUM
128 MEMB(neighbor_memb, struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
129 MEMB(packet_memb, struct rdc_buf_list, MAX_QUEUED_PACKETS);
130 MEMB(metadata_memb, struct qbuf_metadata, MAX_QUEUED_PACKETS);
131 LIST(neighbor_list);
132 
133 static void packet_sent(void *ptr, int status, int num_transmissions);
134 static void transmit_packet_list(void *ptr);
135 /*---------------------------------------------------------------------------*/
136 static struct neighbor_queue *
137 neighbor_queue_from_addr(const linkaddr_t *addr)
138 {
139  struct neighbor_queue *n = list_head(neighbor_list);
140  while(n != NULL) {
141  if(linkaddr_cmp(&n->addr, addr)) {
142  return n;
143  }
144  n = list_item_next(n);
145  }
146  return NULL;
147 }
148 /*---------------------------------------------------------------------------*/
149 static clock_time_t
150 backoff_period(void)
151 {
152  clock_time_t time;
153  /* The retransmission time must be proportional to the channel
154  check interval of the underlying radio duty cycling layer. */
155  time = NETSTACK_RDC.channel_check_interval();
156 
157  /* If the radio duty cycle has no channel check interval, we use
158  * the default in IEEE 802.15.4: aUnitBackoffPeriod which is
159  * 20 symbols i.e. 320 usec. That is, 1/3125 second. */
160  if(time == 0) {
161  time = MAX(CLOCK_SECOND / 3125, 1);
162  }
163  return time;
164 }
165 /*---------------------------------------------------------------------------*/
166 static void
167 transmit_packet_list(void *ptr)
168 {
169  struct neighbor_queue *n = ptr;
170  if(n) {
171  struct rdc_buf_list *q = list_head(n->queued_packet_list);
172  if(q != NULL) {
173  PRINTF("csma: preparing number %d %p, queue len %d\n", n->transmissions, q,
174  list_length(n->queued_packet_list));
175  /* Send packets in the neighbor's list */
176  NETSTACK_RDC.send_list(packet_sent, n, q);
177  }
178  }
179 }
180 /*---------------------------------------------------------------------------*/
181 static void
182 schedule_transmission(struct neighbor_queue *n)
183 {
184  clock_time_t delay;
185  int backoff_exponent; /* BE in IEEE 802.15.4 */
186 
187  backoff_exponent = MIN(n->collisions, CSMA_MAX_BE);
188 
189  /* Compute max delay as per IEEE 802.15.4: 2^BE-1 backoff periods */
190  delay = ((1 << backoff_exponent) - 1) * backoff_period();
191  if(delay > 0) {
192  /* Pick a time for next transmission */
193  delay = random_rand() % delay;
194  }
195 
196  PRINTF("csma: scheduling transmission in %u ticks, NB=%u, BE=%u\n",
197  (unsigned)delay, n->collisions, backoff_exponent);
198  ctimer_set(&n->transmit_timer, delay, transmit_packet_list, n);
199 }
200 /*---------------------------------------------------------------------------*/
201 static void
202 free_packet(struct neighbor_queue *n, struct rdc_buf_list *p, int status)
203 {
204  if(p != NULL) {
205  /* Remove packet from list and deallocate */
206  list_remove(n->queued_packet_list, p);
207 
208  queuebuf_free(p->buf);
209  memb_free(&metadata_memb, p->ptr);
210  memb_free(&packet_memb, p);
211  PRINTF("csma: free_queued_packet, queue length %d, free packets %d\n",
212  list_length(n->queued_packet_list), memb_numfree(&packet_memb));
213  if(list_head(n->queued_packet_list) != NULL) {
214  /* There is a next packet. We reset current tx information */
215  n->transmissions = 0;
216  n->collisions = CSMA_MIN_BE;
217  /* Schedule next transmissions */
218  schedule_transmission(n);
219  } else {
220  /* This was the last packet in the queue, we free the neighbor */
221  ctimer_stop(&n->transmit_timer);
222  list_remove(neighbor_list, n);
223  memb_free(&neighbor_memb, n);
224  }
225  }
226 }
227 /*---------------------------------------------------------------------------*/
228 static void
229 tx_done(int status, struct rdc_buf_list *q, struct neighbor_queue *n)
230 {
231  mac_callback_t sent;
232  struct qbuf_metadata *metadata;
233  void *cptr;
234 
235  metadata = (struct qbuf_metadata *)q->ptr;
236  sent = metadata->sent;
237  cptr = metadata->cptr;
238 
239  switch(status) {
240  case MAC_TX_OK:
241  PRINTF("csma: rexmit ok %d\n", n->transmissions);
242  break;
243  case MAC_TX_COLLISION:
244  case MAC_TX_NOACK:
245  PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n",
246  status, n->transmissions, n->collisions);
247  break;
248  default:
249  PRINTF("csma: rexmit failed %d: %d\n", n->transmissions, status);
250  break;
251  }
252 
253  free_packet(n, q, status);
254  mac_call_sent_callback(sent, cptr, status, n->transmissions);
255 }
256 /*---------------------------------------------------------------------------*/
257 static void
258 rexmit(struct rdc_buf_list *q, struct neighbor_queue *n)
259 {
260  schedule_transmission(n);
261  /* This is needed to correctly attribute energy that we spent
262  transmitting this packet. */
263  queuebuf_update_attr_from_packetbuf(q->buf);
264 }
265 /*---------------------------------------------------------------------------*/
266 static void
267 collision(struct rdc_buf_list *q, struct neighbor_queue *n,
268  int num_transmissions)
269 {
270  struct qbuf_metadata *metadata;
271 
272  metadata = (struct qbuf_metadata *)q->ptr;
273 
274  n->collisions += num_transmissions;
275 
276  if(n->collisions > CSMA_MAX_BACKOFF) {
277  n->collisions = CSMA_MIN_BE;
278  /* Increment to indicate a next retry */
279  n->transmissions++;
280  }
281 
282  if(n->transmissions >= metadata->max_transmissions) {
283  tx_done(MAC_TX_COLLISION, q, n);
284  } else {
285  PRINTF("csma: rexmit collision %d\n", n->transmissions);
286  rexmit(q, n);
287  }
288 }
289 /*---------------------------------------------------------------------------*/
290 static void
291 noack(struct rdc_buf_list *q, struct neighbor_queue *n, int num_transmissions)
292 {
293  struct qbuf_metadata *metadata;
294 
295  metadata = (struct qbuf_metadata *)q->ptr;
296 
297  n->collisions = CSMA_MIN_BE;
298  n->transmissions += num_transmissions;
299 
300  if(n->transmissions >= metadata->max_transmissions) {
301  tx_done(MAC_TX_NOACK, q, n);
302  } else {
303  PRINTF("csma: rexmit noack %d\n", n->transmissions);
304  rexmit(q, n);
305  }
306 }
307 /*---------------------------------------------------------------------------*/
308 static void
309 tx_ok(struct rdc_buf_list *q, struct neighbor_queue *n, int num_transmissions)
310 {
311  n->collisions = CSMA_MIN_BE;
312  n->transmissions += num_transmissions;
313  tx_done(MAC_TX_OK, q, n);
314 }
315 /*---------------------------------------------------------------------------*/
316 static void
317 packet_sent(void *ptr, int status, int num_transmissions)
318 {
319  struct neighbor_queue *n;
320  struct rdc_buf_list *q;
321 
322  n = ptr;
323  if(n == NULL) {
324  return;
325  }
326 
327  /* Find out what packet this callback refers to */
328  for(q = list_head(n->queued_packet_list);
329  q != NULL; q = list_item_next(q)) {
330  if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) ==
331  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) {
332  break;
333  }
334  }
335 
336  if(q == NULL) {
337  PRINTF("csma: seqno %d not found\n",
338  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
339  return;
340  } else if(q->ptr == NULL) {
341  PRINTF("csma: no metadata\n");
342  return;
343  }
344 
345  switch(status) {
346  case MAC_TX_OK:
347  tx_ok(q, n, num_transmissions);
348  break;
349  case MAC_TX_NOACK:
350  noack(q, n, num_transmissions);
351  break;
352  case MAC_TX_COLLISION:
353  collision(q, n, num_transmissions);
354  break;
355  case MAC_TX_DEFERRED:
356  break;
357  default:
358  tx_done(status, q, n);
359  break;
360  }
361 }
362 /*---------------------------------------------------------------------------*/
363 static void
364 send_packet(mac_callback_t sent, void *ptr)
365 {
366  struct rdc_buf_list *q;
367  struct neighbor_queue *n;
368  static uint8_t initialized = 0;
369  static uint16_t seqno;
370  const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
371 
372  if(!initialized) {
373  initialized = 1;
374  /* Initialize the sequence number to a random value as per 802.15.4. */
375  seqno = random_rand();
376  }
377 
378  if(seqno == 0) {
379  /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity
380  in framer-802154.c. */
381  seqno++;
382  }
383  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
384 
385  /* Look for the neighbor entry */
386  n = neighbor_queue_from_addr(addr);
387  if(n == NULL) {
388  /* Allocate a new neighbor entry */
389  n = memb_alloc(&neighbor_memb);
390  if(n != NULL) {
391  /* Init neighbor entry */
392  linkaddr_copy(&n->addr, addr);
393  n->transmissions = 0;
394  n->collisions = CSMA_MIN_BE;
395  /* Init packet list for this neighbor */
396  LIST_STRUCT_INIT(n, queued_packet_list);
397  /* Add neighbor to the list */
398  list_add(neighbor_list, n);
399  }
400  }
401 
402  if(n != NULL) {
403  /* Add packet to the neighbor's queue */
404  if(list_length(n->queued_packet_list) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
405  q = memb_alloc(&packet_memb);
406  if(q != NULL) {
407  q->ptr = memb_alloc(&metadata_memb);
408  if(q->ptr != NULL) {
409  q->buf = queuebuf_new_from_packetbuf();
410  if(q->buf != NULL) {
411  struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr;
412  /* Neighbor and packet successfully allocated */
413  if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
414  /* Use default configuration for max transmissions */
415  metadata->max_transmissions = CSMA_MAX_MAX_FRAME_RETRIES + 1;
416  } else {
417  metadata->max_transmissions =
418  packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
419  }
420  metadata->sent = sent;
421  metadata->cptr = ptr;
422 #if PACKETBUF_WITH_PACKET_TYPE
423  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
424  PACKETBUF_ATTR_PACKET_TYPE_ACK) {
425  list_push(n->queued_packet_list, q);
426  } else
427 #endif
428  {
429  list_add(n->queued_packet_list, q);
430  }
431 
432  PRINTF("csma: send_packet, queue length %d, free packets %d\n",
433  list_length(n->queued_packet_list), memb_numfree(&packet_memb));
434  /* If q is the first packet in the neighbor's queue, send asap */
435  if(list_head(n->queued_packet_list) == q) {
436  schedule_transmission(n);
437  }
438  return;
439  }
440  memb_free(&metadata_memb, q->ptr);
441  PRINTF("csma: could not allocate queuebuf, dropping packet\n");
442  }
443  memb_free(&packet_memb, q);
444  PRINTF("csma: could not allocate queuebuf, dropping packet\n");
445  }
446  /* The packet allocation failed. Remove and free neighbor entry if empty. */
447  if(list_length(n->queued_packet_list) == 0) {
448  list_remove(neighbor_list, n);
449  memb_free(&neighbor_memb, n);
450  }
451  } else {
452  PRINTF("csma: Neighbor queue full\n");
453  }
454  PRINTF("csma: could not allocate packet, dropping packet\n");
455  } else {
456  PRINTF("csma: could not allocate neighbor, dropping packet\n");
457  }
458  mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1);
459 }
460 /*---------------------------------------------------------------------------*/
461 static void
462 input_packet(void)
463 {
464  NETSTACK_LLSEC.input();
465 }
466 /*---------------------------------------------------------------------------*/
467 static int
468 on(void)
469 {
470  return NETSTACK_RDC.on();
471 }
472 /*---------------------------------------------------------------------------*/
473 static int
474 off(int keep_radio_on)
475 {
476  return NETSTACK_RDC.off(keep_radio_on);
477 }
478 /*---------------------------------------------------------------------------*/
479 static unsigned short
480 channel_check_interval(void)
481 {
482  if(NETSTACK_RDC.channel_check_interval) {
483  return NETSTACK_RDC.channel_check_interval();
484  }
485  return 0;
486 }
487 /*---------------------------------------------------------------------------*/
488 static void
489 init(void)
490 {
491  memb_init(&packet_memb);
492  memb_init(&metadata_memb);
493  memb_init(&neighbor_memb);
494 }
495 /*---------------------------------------------------------------------------*/
496 const struct mac_driver csma_driver = {
497  "CSMA",
498  init,
499  send_packet,
500  input_packet,
501  on,
502  off,
504 };
505 /*---------------------------------------------------------------------------*/
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
The MAC layer deferred the transmission for a later time.
Definition: mac.h:86
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:83
#define LIST(name)
Declare a linked list.
Definition: list.h:86
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
Header file for the Rime buffer (packetbuf) management
int(* off)(int keep_radio_on)
Turn the MAC layer off.
Definition: mac.h:70
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:93
static void packet_sent(void *ptr, int status, int transmissions)
Callback function for the MAC packet sent callback.
Definition: sicslowpan.c:1227
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:89
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
The MAC layer transmission was OK.
Definition: mac.h:79
Header file for the callback timer
#define NULL
The null pointer.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:47
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:54
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
Linked list manipulation routines.
unsigned short(* channel_check_interval)(void)
Returns the channel check interval, expressed in clock_time_t ticks.
Definition: mac.h:73
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
Definition: list.h:108
void(* init)(void)
Initialize the MAC driver.
Definition: mac.h:58
Memory block allocation routines.
Header file for the Rime queue buffer management
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
int(* on)(void)
Turn the MAC layer on.
Definition: mac.h:67
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
Definition: linkaddr.c:60
int list_length(list_t list)
Get the length of a list.
Definition: list.c:275
A MAC stack protocol that performs retransmissions when the underlying MAC layer has problems...
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:122
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
Include file for the Contiki low-layer network stack (NETSTACK)
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:79
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition: list.c:165