Contiki-NG
csma-output.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  * The 802.15.4 standard CSMA protocol (nonbeacon-enabled).
36  * Output functions.
37  * \author
38  * Adam Dunkels <adam@sics.se>
39  * Simon Duquennoy <simon.duquennoy@inria.fr>
40  */
41 
42 #include "net/mac/csma/csma.h"
43 #include "net/packetbuf.h"
44 #include "net/queuebuf.h"
45 #include "dev/watchdog.h"
46 #include "sys/ctimer.h"
47 #include "sys/clock.h"
48 #include "lib/random.h"
49 #include "net/netstack.h"
50 #include "lib/list.h"
51 #include "lib/memb.h"
52 
53 /* Log configuration */
54 #include "sys/log.h"
55 #define LOG_MODULE "CSMA"
56 #define LOG_LEVEL LOG_LEVEL_MAC
57 
58 /* Constants of the IEEE 802.15.4 standard */
59 
60 /* macMinBE: Initial backoff exponent. Range 0--CSMA_MAX_BE */
61 #ifdef CSMA_CONF_MIN_BE
62 #define CSMA_MIN_BE CSMA_CONF_MIN_BE
63 #else
64 #define CSMA_MIN_BE 3
65 #endif
66 
67 /* macMaxBE: Maximum backoff exponent. Range 3--8 */
68 #ifdef CSMA_CONF_MAX_BE
69 #define CSMA_MAX_BE CSMA_CONF_MAX_BE
70 #else
71 #define CSMA_MAX_BE 5
72 #endif
73 
74 /* macMaxCSMABackoffs: Maximum number of backoffs in case of channel busy/collision. Range 0--5 */
75 #ifdef CSMA_CONF_MAX_BACKOFF
76 #define CSMA_MAX_BACKOFF CSMA_CONF_MAX_BACKOFF
77 #else
78 #define CSMA_MAX_BACKOFF 5
79 #endif
80 
81 /* macMaxFrameRetries: Maximum number of re-transmissions attampts. Range 0--7 */
82 #ifdef CSMA_CONF_MAX_FRAME_RETRIES
83 #define CSMA_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES
84 #else
85 #define CSMA_MAX_FRAME_RETRIES 7
86 #endif
87 
88 /* Packet metadata */
89 struct qbuf_metadata {
90  mac_callback_t sent;
91  void *cptr;
92  uint8_t max_transmissions;
93 };
94 
95 /* Every neighbor has its own packet queue */
96 struct neighbor_queue {
97  struct neighbor_queue *next;
98  linkaddr_t addr;
99  struct ctimer transmit_timer;
100  uint8_t transmissions;
101  uint8_t collisions;
102  LIST_STRUCT(packet_queue);
103 };
104 
105 /* The maximum number of co-existing neighbor queues */
106 #ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
107 #define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
108 #else
109 #define CSMA_MAX_NEIGHBOR_QUEUES 2
110 #endif /* CSMA_CONF_MAX_NEIGHBOR_QUEUES */
111 
112 /* The maximum number of pending packet per neighbor */
113 #ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
114 #define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
115 #else
116 #define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
117 #endif /* CSMA_CONF_MAX_PACKET_PER_NEIGHBOR */
118 
119 #define MAX_QUEUED_PACKETS QUEUEBUF_NUM
120 
121 /* Neighbor packet queue */
122 struct packet_queue {
123  struct packet_queue *next;
124  struct queuebuf *buf;
125  void *ptr;
126 };
127 
128 MEMB(neighbor_memb, struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
129 MEMB(packet_memb, struct packet_queue, 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_from_queue(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 #if CONTIKI_TARGET_COOJA
153  /* Increase normal value by 20 to compensate for the coarse-grained
154  radio medium with Cooja motes */
155  return MAX(20 * CLOCK_SECOND / 3125, 1);
156 #else /* CONTIKI_TARGET_COOJA */
157  /* Use the default in IEEE 802.15.4: aUnitBackoffPeriod which is
158  * 20 symbols i.e. 320 usec. That is, 1/3125 second. */
159  return MAX(CLOCK_SECOND / 3125, 1);
160 #endif /* CONTIKI_TARGET_COOJA */
161 }
162 /*---------------------------------------------------------------------------*/
163 static int
164 send_one_packet(void *ptr)
165 {
166  int ret;
167  int last_sent_ok = 0;
168 
169  packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr);
170  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
171 
172  if(NETSTACK_FRAMER.create() < 0) {
173  /* Failed to allocate space for headers */
174  LOG_ERR("failed to create packet\n");
175  ret = MAC_TX_ERR_FATAL;
176  } else {
177  int is_broadcast;
178  uint8_t dsn;
179  dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff;
180 
181  NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen());
182 
183  is_broadcast = packetbuf_holds_broadcast();
184 
185  if(NETSTACK_RADIO.receiving_packet() ||
186  (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
187 
188  /* Currently receiving a packet over air or the radio has
189  already received a packet that needs to be read before
190  sending with auto ack. */
191  ret = MAC_TX_COLLISION;
192  } else {
193 
194  switch(NETSTACK_RADIO.transmit(packetbuf_totlen())) {
195  case RADIO_TX_OK:
196  if(is_broadcast) {
197  ret = MAC_TX_OK;
198  } else {
199  /* Check for ack */
200 
201  /* Wait for max CSMA_ACK_WAIT_TIME */
202  RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_ACK_WAIT_TIME);
203 
204  ret = MAC_TX_NOACK;
205  if(NETSTACK_RADIO.receiving_packet() ||
206  NETSTACK_RADIO.pending_packet() ||
207  NETSTACK_RADIO.channel_clear() == 0) {
208  int len;
209  uint8_t ackbuf[CSMA_ACK_LEN];
210 
211  /* Wait an additional CSMA_AFTER_ACK_DETECTED_WAIT_TIME to complete reception */
212  RTIMER_BUSYWAIT_UNTIL(NETSTACK_RADIO.pending_packet(), CSMA_AFTER_ACK_DETECTED_WAIT_TIME);
213 
214  if(NETSTACK_RADIO.pending_packet()) {
215  len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN);
216  if(len == CSMA_ACK_LEN && ackbuf[2] == dsn) {
217  /* Ack received */
218  ret = MAC_TX_OK;
219  } else {
220  /* Not an ack or ack not for us: collision */
221  ret = MAC_TX_COLLISION;
222  }
223  }
224  }
225  }
226  break;
227  case RADIO_TX_COLLISION:
228  ret = MAC_TX_COLLISION;
229  break;
230  default:
231  ret = MAC_TX_ERR;
232  break;
233  }
234  }
235  }
236  if(ret == MAC_TX_OK) {
237  last_sent_ok = 1;
238  }
239 
240  packet_sent(ptr, ret, 1);
241  return last_sent_ok;
242 }
243 /*---------------------------------------------------------------------------*/
244 static void
245 transmit_from_queue(void *ptr)
246 {
247  struct neighbor_queue *n = ptr;
248  if(n) {
249  struct packet_queue *q = list_head(n->packet_queue);
250  if(q != NULL) {
251  LOG_INFO("preparing packet for ");
252  LOG_INFO_LLADDR(&n->addr);
253  LOG_INFO_(", seqno %u, tx %u, queue %d\n",
254  queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO),
255  n->transmissions, list_length(n->packet_queue));
256  /* Send first packet in the neighbor queue */
257  queuebuf_to_packetbuf(q->buf);
258  send_one_packet(n);
259  }
260  }
261 }
262 /*---------------------------------------------------------------------------*/
263 static void
264 schedule_transmission(struct neighbor_queue *n)
265 {
266  clock_time_t delay;
267  int backoff_exponent; /* BE in IEEE 802.15.4 */
268 
269  backoff_exponent = MIN(n->collisions + CSMA_MIN_BE, CSMA_MAX_BE);
270 
271  /* Compute max delay as per IEEE 802.15.4: 2^BE-1 backoff periods */
272  delay = ((1 << backoff_exponent) - 1) * backoff_period();
273  if(delay > 0) {
274  /* Pick a time for next transmission */
275  delay = random_rand() % delay;
276  }
277 
278  LOG_DBG("scheduling transmission in %u ticks, NB=%u, BE=%u\n",
279  (unsigned)delay, n->collisions, backoff_exponent);
280  ctimer_set(&n->transmit_timer, delay, transmit_from_queue, n);
281 }
282 /*---------------------------------------------------------------------------*/
283 static void
284 free_packet(struct neighbor_queue *n, struct packet_queue *p, int status)
285 {
286  if(p != NULL) {
287  /* Remove packet from queue and deallocate */
288  list_remove(n->packet_queue, p);
289 
290  queuebuf_free(p->buf);
291  memb_free(&metadata_memb, p->ptr);
292  memb_free(&packet_memb, p);
293  LOG_DBG("free_queued_packet, queue length %d, free packets %d\n",
294  list_length(n->packet_queue), memb_numfree(&packet_memb));
295  if(list_head(n->packet_queue) != NULL) {
296  /* There is a next packet. We reset current tx information */
297  n->transmissions = 0;
298  n->collisions = 0;
299  /* Schedule next transmissions */
300  schedule_transmission(n);
301  } else {
302  /* This was the last packet in the queue, we free the neighbor */
303  ctimer_stop(&n->transmit_timer);
304  list_remove(neighbor_list, n);
305  memb_free(&neighbor_memb, n);
306  }
307  }
308 }
309 /*---------------------------------------------------------------------------*/
310 static void
311 tx_done(int status, struct packet_queue *q, struct neighbor_queue *n)
312 {
313  mac_callback_t sent;
314  struct qbuf_metadata *metadata;
315  void *cptr;
316  uint8_t ntx;
317 
318  metadata = (struct qbuf_metadata *)q->ptr;
319  sent = metadata->sent;
320  cptr = metadata->cptr;
321  ntx = n->transmissions;
322 
323  LOG_INFO("packet sent to ");
324  LOG_INFO_LLADDR(&n->addr);
325  LOG_INFO_(", seqno %u, status %u, tx %u, coll %u\n",
326  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
327  status, n->transmissions, n->collisions);
328 
329  free_packet(n, q, status);
330  mac_call_sent_callback(sent, cptr, status, ntx);
331 }
332 /*---------------------------------------------------------------------------*/
333 static void
334 rexmit(struct packet_queue *q, struct neighbor_queue *n)
335 {
336  schedule_transmission(n);
337  /* This is needed to correctly attribute energy that we spent
338  transmitting this packet. */
339  queuebuf_update_attr_from_packetbuf(q->buf);
340 }
341 /*---------------------------------------------------------------------------*/
342 static void
343 collision(struct packet_queue *q, struct neighbor_queue *n,
344  int num_transmissions)
345 {
346  struct qbuf_metadata *metadata;
347 
348  metadata = (struct qbuf_metadata *)q->ptr;
349 
350  n->collisions += num_transmissions;
351 
352  if(n->collisions > CSMA_MAX_BACKOFF) {
353  n->collisions = 0;
354  /* Increment to indicate a next retry */
355  n->transmissions++;
356  }
357 
358  if(n->transmissions >= metadata->max_transmissions) {
359  tx_done(MAC_TX_COLLISION, q, n);
360  } else {
361  rexmit(q, n);
362  }
363 }
364 /*---------------------------------------------------------------------------*/
365 static void
366 noack(struct packet_queue *q, struct neighbor_queue *n, int num_transmissions)
367 {
368  struct qbuf_metadata *metadata;
369 
370  metadata = (struct qbuf_metadata *)q->ptr;
371 
372  n->collisions = 0;
373  n->transmissions += num_transmissions;
374 
375  if(n->transmissions >= metadata->max_transmissions) {
376  tx_done(MAC_TX_NOACK, q, n);
377  } else {
378  rexmit(q, n);
379  }
380 }
381 /*---------------------------------------------------------------------------*/
382 static void
383 tx_ok(struct packet_queue *q, struct neighbor_queue *n, int num_transmissions)
384 {
385  n->collisions = 0;
386  n->transmissions += num_transmissions;
387  tx_done(MAC_TX_OK, q, n);
388 }
389 /*---------------------------------------------------------------------------*/
390 static void
391 packet_sent(void *ptr, int status, int num_transmissions)
392 {
393  struct neighbor_queue *n;
394  struct packet_queue *q;
395 
396  n = ptr;
397  if(n == NULL) {
398  return;
399  }
400 
401  /* Find out what packet this callback refers to */
402  for(q = list_head(n->packet_queue);
403  q != NULL; q = list_item_next(q)) {
404  if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) ==
405  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) {
406  break;
407  }
408  }
409 
410  if(q == NULL) {
411  LOG_WARN("packet sent: seqno %u not found\n",
412  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
413  return;
414  } else if(q->ptr == NULL) {
415  LOG_WARN("packet sent: no metadata\n");
416  return;
417  }
418 
419  LOG_INFO("tx to ");
420  LOG_INFO_LLADDR(&n->addr);
421  LOG_INFO_(", seqno %u, status %u, tx %u, coll %u\n",
422  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
423  status, n->transmissions, n->collisions);
424 
425  switch(status) {
426  case MAC_TX_OK:
427  tx_ok(q, n, num_transmissions);
428  break;
429  case MAC_TX_NOACK:
430  noack(q, n, num_transmissions);
431  break;
432  case MAC_TX_COLLISION:
433  collision(q, n, num_transmissions);
434  break;
435  case MAC_TX_DEFERRED:
436  break;
437  default:
438  tx_done(status, q, n);
439  break;
440  }
441 }
442 /*---------------------------------------------------------------------------*/
443 void
444 csma_output_packet(mac_callback_t sent, void *ptr)
445 {
446  struct packet_queue *q;
447  struct neighbor_queue *n;
448  static uint8_t initialized = 0;
449  static uint8_t seqno;
450  const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
451 
452  if(!initialized) {
453  initialized = 1;
454  /* Initialize the sequence number to a random value as per 802.15.4. */
455  seqno = random_rand();
456  }
457 
458  if(seqno == 0) {
459  /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity
460  in framer-802154.c. */
461  seqno++;
462  }
463  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
464  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
465 
466  /* Look for the neighbor entry */
467  n = neighbor_queue_from_addr(addr);
468  if(n == NULL) {
469  /* Allocate a new neighbor entry */
470  n = memb_alloc(&neighbor_memb);
471  if(n != NULL) {
472  /* Init neighbor entry */
473  linkaddr_copy(&n->addr, addr);
474  n->transmissions = 0;
475  n->collisions = 0;
476  /* Init packet queue for this neighbor */
477  LIST_STRUCT_INIT(n, packet_queue);
478  /* Add neighbor to the neighbor list */
479  list_add(neighbor_list, n);
480  }
481  }
482 
483  if(n != NULL) {
484  /* Add packet to the neighbor's queue */
485  if(list_length(n->packet_queue) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
486  q = memb_alloc(&packet_memb);
487  if(q != NULL) {
488  q->ptr = memb_alloc(&metadata_memb);
489  if(q->ptr != NULL) {
490  q->buf = queuebuf_new_from_packetbuf();
491  if(q->buf != NULL) {
492  struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr;
493  /* Neighbor and packet successfully allocated */
494  metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
495  if(metadata->max_transmissions == 0) {
496  /* If not set by the application, use the default CSMA value */
497  metadata->max_transmissions = CSMA_MAX_FRAME_RETRIES + 1;
498  }
499  metadata->sent = sent;
500  metadata->cptr = ptr;
501  list_add(n->packet_queue, q);
502 
503  LOG_INFO("sending to ");
504  LOG_INFO_LLADDR(addr);
505  LOG_INFO_(", len %u, seqno %u, queue length %d, free packets %d\n",
507  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
508  list_length(n->packet_queue), memb_numfree(&packet_memb));
509  /* If q is the first packet in the neighbor's queue, send asap */
510  if(list_head(n->packet_queue) == q) {
511  schedule_transmission(n);
512  }
513  return;
514  }
515  memb_free(&metadata_memb, q->ptr);
516  LOG_WARN("could not allocate queuebuf, dropping packet\n");
517  }
518  memb_free(&packet_memb, q);
519  LOG_WARN("could not allocate queuebuf, dropping packet\n");
520  }
521  /* The packet allocation failed. Remove and free neighbor entry if empty. */
522  if(list_length(n->packet_queue) == 0) {
523  list_remove(neighbor_list, n);
524  memb_free(&neighbor_memb, n);
525  }
526  } else {
527  LOG_WARN("Neighbor queue full\n");
528  }
529  LOG_WARN("could not allocate packet, dropping packet\n");
530  } else {
531  LOG_WARN("could not allocate neighbor, dropping packet\n");
532  }
533  mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1);
534 }
535 /*---------------------------------------------------------------------------*/
536 void
537 csma_output_init(void)
538 {
539  memb_init(&packet_memb);
540  memb_init(&metadata_memb);
541  memb_init(&neighbor_memb);
542  queuebuf_init();
543 }
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:124
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:98
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:116
The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
static void packet_sent(void *ptr, int status, int transmissions)
Callback function for the MAC packet sent callback.
Definition: sicslowpan.c:1444
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
Definition: rtimer.h:202
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:155
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
Header file for the callback timer
Header file for the Packet queue buffer management
Linked list manipulation routines.
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:88
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:167
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
The MAC layer transmission was OK.
Definition: mac.h:84
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:94
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
int packetbuf_holds_broadcast(void)
Checks whether the current packet is a broadcast.
Definition: packetbuf.c:231
Memory block allocation routines.
The MAC layer deferred the transmission for a later time.
Definition: mac.h:91
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition: linkaddr.c:63
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:149
#define LIST(name)
Declare a linked list.
Definition: list.h:88
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
Definition: list.h:110
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
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 logging system
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:237
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:322
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
int list_length(list_t list)
Get the length of a list.
Definition: list.c:272