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 #ifndef CSMA_MAX_BACKOFF_EXPONENT
67 #ifdef CSMA_CONF_MAX_BACKOFF_EXPONENT
68 #define CSMA_MAX_BACKOFF_EXPONENT CSMA_CONF_MAX_BACKOFF_EXPONENT
69 #else
70 #define CSMA_MAX_BACKOFF_EXPONENT 3
71 #endif /* CSMA_CONF_MAX_BACKOFF_EXPONENT */
72 #endif /* CSMA_MAX_BACKOFF_EXPONENT */
73 
74 #ifndef CSMA_MAX_MAC_TRANSMISSIONS
75 #ifdef CSMA_CONF_MAX_MAC_TRANSMISSIONS
76 #define CSMA_MAX_MAC_TRANSMISSIONS CSMA_CONF_MAX_MAC_TRANSMISSIONS
77 #else
78 #define CSMA_MAX_MAC_TRANSMISSIONS 3
79 #endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS */
80 #endif /* CSMA_MAX_MAC_TRANSMISSIONS */
81 
82 #if CSMA_MAX_MAC_TRANSMISSIONS < 1
83 #error CSMA_CONF_MAX_MAC_TRANSMISSIONS must be at least 1.
84 #error Change CSMA_CONF_MAX_MAC_TRANSMISSIONS in contiki-conf.h or in your Makefile.
85 #endif /* CSMA_CONF_MAX_MAC_TRANSMISSIONS < 1 */
86 
87 /* Packet metadata */
88 struct qbuf_metadata {
89  mac_callback_t sent;
90  void *cptr;
91  uint8_t max_transmissions;
92 };
93 
94 /* Every neighbor has its own packet queue */
95 struct neighbor_queue {
96  struct neighbor_queue *next;
97  linkaddr_t addr;
98  struct ctimer transmit_timer;
99  uint8_t transmissions;
100  uint8_t collisions, deferrals;
101  LIST_STRUCT(queued_packet_list);
102 };
103 
104 /* The maximum number of co-existing neighbor queues */
105 #ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
106 #define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
107 #else
108 #define CSMA_MAX_NEIGHBOR_QUEUES 2
109 #endif /* CSMA_CONF_MAX_NEIGHBOR_QUEUES */
110 
111 /* The maximum number of pending packet per neighbor */
112 #ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
113 #define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
114 #else
115 #define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
116 #endif /* CSMA_CONF_MAX_PACKET_PER_NEIGHBOR */
117 
118 #define MAX_QUEUED_PACKETS QUEUEBUF_NUM
119 MEMB(neighbor_memb, struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
120 MEMB(packet_memb, struct rdc_buf_list, MAX_QUEUED_PACKETS);
121 MEMB(metadata_memb, struct qbuf_metadata, MAX_QUEUED_PACKETS);
122 LIST(neighbor_list);
123 
124 static void packet_sent(void *ptr, int status, int num_transmissions);
125 static void transmit_packet_list(void *ptr);
126 
127 /*---------------------------------------------------------------------------*/
128 static struct neighbor_queue *
129 neighbor_queue_from_addr(const linkaddr_t *addr)
130 {
131  struct neighbor_queue *n = list_head(neighbor_list);
132  while(n != NULL) {
133  if(linkaddr_cmp(&n->addr, addr)) {
134  return n;
135  }
136  n = list_item_next(n);
137  }
138  return NULL;
139 }
140 /*---------------------------------------------------------------------------*/
141 static clock_time_t
142 default_timebase(void)
143 {
144  clock_time_t time;
145  /* The retransmission time must be proportional to the channel
146  check interval of the underlying radio duty cycling layer. */
147  time = NETSTACK_RDC.channel_check_interval();
148 
149  /* If the radio duty cycle has no channel check interval (i.e., it
150  does not turn the radio off), we make the retransmission time
151  proportional to the configured MAC channel check rate. */
152  if(time == 0) {
153  time = CLOCK_SECOND / NETSTACK_RDC_CHANNEL_CHECK_RATE;
154  }
155  return time;
156 }
157 /*---------------------------------------------------------------------------*/
158 static void
159 transmit_packet_list(void *ptr)
160 {
161  struct neighbor_queue *n = ptr;
162  if(n) {
163  struct rdc_buf_list *q = list_head(n->queued_packet_list);
164  if(q != NULL) {
165  PRINTF("csma: preparing number %d %p, queue len %d\n", n->transmissions, q,
166  list_length(n->queued_packet_list));
167  /* Send packets in the neighbor's list */
168  NETSTACK_RDC.send_list(packet_sent, n, q);
169  }
170  }
171 }
172 /*---------------------------------------------------------------------------*/
173 static void
174 free_packet(struct neighbor_queue *n, struct rdc_buf_list *p)
175 {
176  if(p != NULL) {
177  /* Remove packet from list and deallocate */
178  list_remove(n->queued_packet_list, p);
179 
180  queuebuf_free(p->buf);
181  memb_free(&metadata_memb, p->ptr);
182  memb_free(&packet_memb, p);
183  PRINTF("csma: free_queued_packet, queue length %d, free packets %d\n",
184  list_length(n->queued_packet_list), memb_numfree(&packet_memb));
185  if(list_head(n->queued_packet_list) != NULL) {
186  /* There is a next packet. We reset current tx information */
187  n->transmissions = 0;
188  n->collisions = 0;
189  n->deferrals = 0;
190  /* Set a timer for next transmissions */
191  ctimer_set(&n->transmit_timer, default_timebase(),
192  transmit_packet_list, n);
193  } else {
194  /* This was the last packet in the queue, we free the neighbor */
195  ctimer_stop(&n->transmit_timer);
196  list_remove(neighbor_list, n);
197  memb_free(&neighbor_memb, n);
198  }
199  }
200 }
201 /*---------------------------------------------------------------------------*/
202 static void
203 packet_sent(void *ptr, int status, int num_transmissions)
204 {
205  struct neighbor_queue *n;
206  struct rdc_buf_list *q;
207  struct qbuf_metadata *metadata;
208  clock_time_t time = 0;
209  mac_callback_t sent;
210  void *cptr;
211  int num_tx;
212  int backoff_exponent;
213  int backoff_transmissions;
214 
215  n = ptr;
216  if(n == NULL) {
217  return;
218  }
219  switch(status) {
220  case MAC_TX_OK:
221  case MAC_TX_NOACK:
222  n->transmissions += num_transmissions;
223  break;
224  case MAC_TX_COLLISION:
225  n->collisions += num_transmissions;
226  break;
227  case MAC_TX_DEFERRED:
228  n->deferrals += num_transmissions;
229  break;
230  }
231 
232  /* Find out what packet this callback refers to */
233  for(q = list_head(n->queued_packet_list);
234  q != NULL; q = list_item_next(q)) {
235  if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) ==
236  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) {
237  break;
238  }
239  }
240 
241  if(q != NULL) {
242  metadata = (struct qbuf_metadata *)q->ptr;
243 
244  if(metadata != NULL) {
245  sent = metadata->sent;
246  cptr = metadata->cptr;
247  num_tx = n->transmissions;
248  if(status == MAC_TX_COLLISION ||
249  status == MAC_TX_NOACK) {
250 
251  /* If the transmission was not performed because of a
252  collision or noack, we must retransmit the packet. */
253 
254  switch(status) {
255  case MAC_TX_COLLISION:
256  PRINTF("csma: rexmit collision %d\n", n->transmissions);
257  break;
258  case MAC_TX_NOACK:
259  PRINTF("csma: rexmit noack %d\n", n->transmissions);
260  break;
261  default:
262  PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions);
263  }
264 
265  /* The retransmission time must be proportional to the channel
266  check interval of the underlying radio duty cycling layer. */
267  time = default_timebase();
268 
269  /* The retransmission time uses a truncated exponential backoff
270  * so that the interval between the transmissions increase with
271  * each retransmit. */
272  backoff_exponent = num_tx;
273 
274  /* Truncate the exponent if needed. */
275  if(backoff_exponent > CSMA_MAX_BACKOFF_EXPONENT) {
276  backoff_exponent = CSMA_MAX_BACKOFF_EXPONENT;
277  }
278 
279  /* Proceed to exponentiation. */
280  backoff_transmissions = 1 << backoff_exponent;
281 
282  /* Pick a time for next transmission, within the interval:
283  * [time, time + 2^backoff_exponent * time[ */
284  time = time + (random_rand() % (backoff_transmissions * time));
285 
286  if(n->transmissions < metadata->max_transmissions) {
287  PRINTF("csma: retransmitting with time %lu %p\n", time, q);
288  ctimer_set(&n->transmit_timer, time,
289  transmit_packet_list, n);
290  /* This is needed to correctly attribute energy that we spent
291  transmitting this packet. */
292  queuebuf_update_attr_from_packetbuf(q->buf);
293  } else {
294  PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n",
295  status, n->transmissions, n->collisions);
296  free_packet(n, q);
297  mac_call_sent_callback(sent, cptr, status, num_tx);
298  }
299  } else {
300  if(status == MAC_TX_OK) {
301  PRINTF("csma: rexmit ok %d\n", n->transmissions);
302  } else {
303  PRINTF("csma: rexmit failed %d: %d\n", n->transmissions, status);
304  }
305  free_packet(n, q);
306  mac_call_sent_callback(sent, cptr, status, num_tx);
307  }
308  } else {
309  PRINTF("csma: no metadata\n");
310  }
311  } else {
312  PRINTF("csma: seqno %d not found\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
313  }
314 }
315 /*---------------------------------------------------------------------------*/
316 static void
317 send_packet(mac_callback_t sent, void *ptr)
318 {
319  struct rdc_buf_list *q;
320  struct neighbor_queue *n;
321  static uint8_t initialized = 0;
322  static uint16_t seqno;
323  const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
324 
325  if(!initialized) {
326  initialized = 1;
327  /* Initialize the sequence number to a random value as per 802.15.4. */
328  seqno = random_rand();
329  }
330 
331  if(seqno == 0) {
332  /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity
333  in framer-802154.c. */
334  seqno++;
335  }
336  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
337 
338  /* Look for the neighbor entry */
339  n = neighbor_queue_from_addr(addr);
340  if(n == NULL) {
341  /* Allocate a new neighbor entry */
342  n = memb_alloc(&neighbor_memb);
343  if(n != NULL) {
344  /* Init neighbor entry */
345  linkaddr_copy(&n->addr, addr);
346  n->transmissions = 0;
347  n->collisions = 0;
348  n->deferrals = 0;
349  /* Init packet list for this neighbor */
350  LIST_STRUCT_INIT(n, queued_packet_list);
351  /* Add neighbor to the list */
352  list_add(neighbor_list, n);
353  }
354  }
355 
356  if(n != NULL) {
357  /* Add packet to the neighbor's queue */
358  if(list_length(n->queued_packet_list) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
359  q = memb_alloc(&packet_memb);
360  if(q != NULL) {
361  q->ptr = memb_alloc(&metadata_memb);
362  if(q->ptr != NULL) {
363  q->buf = queuebuf_new_from_packetbuf();
364  if(q->buf != NULL) {
365  struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr;
366  /* Neighbor and packet successfully allocated */
367  if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
368  /* Use default configuration for max transmissions */
369  metadata->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS;
370  } else {
371  metadata->max_transmissions =
372  packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
373  }
374  metadata->sent = sent;
375  metadata->cptr = ptr;
376 
377  if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
378  PACKETBUF_ATTR_PACKET_TYPE_ACK) {
379  list_push(n->queued_packet_list, q);
380  } else {
381  list_add(n->queued_packet_list, q);
382  }
383 
384  PRINTF("csma: send_packet, queue length %d, free packets %d\n",
385  list_length(n->queued_packet_list), memb_numfree(&packet_memb));
386  /* If q is the first packet in the neighbor's queue, send asap */
387  if(list_head(n->queued_packet_list) == q) {
388  ctimer_set(&n->transmit_timer, 0, transmit_packet_list, n);
389  }
390  return;
391  }
392  memb_free(&metadata_memb, q->ptr);
393  PRINTF("csma: could not allocate queuebuf, dropping packet\n");
394  }
395  memb_free(&packet_memb, q);
396  PRINTF("csma: could not allocate queuebuf, dropping packet\n");
397  }
398  /* The packet allocation failed. Remove and free neighbor entry if empty. */
399  if(list_length(n->queued_packet_list) == 0) {
400  list_remove(neighbor_list, n);
401  memb_free(&neighbor_memb, n);
402  }
403  } else {
404  PRINTF("csma: Neighbor queue full\n");
405  }
406  PRINTF("csma: could not allocate packet, dropping packet\n");
407  } else {
408  PRINTF("csma: could not allocate neighbor, dropping packet\n");
409  }
410  mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1);
411 }
412 /*---------------------------------------------------------------------------*/
413 static void
414 input_packet(void)
415 {
416  NETSTACK_LLSEC.input();
417 }
418 /*---------------------------------------------------------------------------*/
419 static int
420 on(void)
421 {
422  return NETSTACK_RDC.on();
423 }
424 /*---------------------------------------------------------------------------*/
425 static int
426 off(int keep_radio_on)
427 {
428  return NETSTACK_RDC.off(keep_radio_on);
429 }
430 /*---------------------------------------------------------------------------*/
431 static unsigned short
432 channel_check_interval(void)
433 {
434  if(NETSTACK_RDC.channel_check_interval) {
435  return NETSTACK_RDC.channel_check_interval();
436  }
437  return 0;
438 }
439 /*---------------------------------------------------------------------------*/
440 static void
441 init(void)
442 {
443  memb_init(&packet_memb);
444  memb_init(&metadata_memb);
445  memb_init(&neighbor_memb);
446 }
447 /*---------------------------------------------------------------------------*/
448 const struct mac_driver csma_driver = {
449  "CSMA",
450  init,
451  send_packet,
452  input_packet,
453  on,
454  off,
456 };
457 /*---------------------------------------------------------------------------*/
Linked list manipulation routines.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition: list.c:165
The MAC layer deferred the transmission for a later time.
Definition: mac.h:86
unsigned short(* channel_check_interval)(void)
Returns the channel check interval, expressed in clock_time_t ticks.
Definition: mac.h:73
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:79
Header file for the Rime buffer (packetbuf) management
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
#define NULL
The null pointer.
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
A MAC stack protocol that performs retransmissions when the underlying MAC layer has problems...
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
Definition: list.h:108
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
int list_length(list_t list)
Get the length of a list.
Definition: list.c:275
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
Definition: linkaddr.c:60
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
int(* on)(void)
Turn the MAC layer on.
Definition: mac.h:67
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
Header file for the Rime queue buffer management
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define LIST(name)
Declare a linked list.
Definition: list.h:86
void(* init)(void)
Initialize the MAC driver.
Definition: mac.h:58
Header file for the callback timer
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:122
The MAC layer transmission was OK.
Definition: mac.h:79
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:54
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:89
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:83
Memory block allocation routines.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:142
unsigned short random_rand(void)
Generate the next state and return the upper part of it.
Definition: random.c:47
Include file for the Contiki low-layer network stack (NETSTACK)
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82