47#include "dev/watchdog.h"
50#include "lib/random.h"
54#include "lib/assert.h"
58#define LOG_MODULE "CSMA"
59#define LOG_LEVEL LOG_LEVEL_MAC
64#ifdef CSMA_CONF_MIN_BE
65#define CSMA_MIN_BE CSMA_CONF_MIN_BE
71#ifdef CSMA_CONF_MAX_BE
72#define CSMA_MAX_BE CSMA_CONF_MAX_BE
78#ifdef CSMA_CONF_MAX_BACKOFF
79#define CSMA_MAX_BACKOFF CSMA_CONF_MAX_BACKOFF
81#define CSMA_MAX_BACKOFF 5
85#ifdef CSMA_CONF_MAX_FRAME_RETRIES
86#define CSMA_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES
88#define CSMA_MAX_FRAME_RETRIES 7
95 uint8_t max_transmissions;
99struct neighbor_queue {
100 struct neighbor_queue *next;
102 struct ctimer transmit_timer;
103 uint8_t transmissions;
109#ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
110#define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
112#define CSMA_MAX_NEIGHBOR_QUEUES 2
116#ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
117#define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
119#define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
122#define MAX_QUEUED_PACKETS QUEUEBUF_NUM
126 struct packet_queue *next;
127 struct queuebuf *buf;
131MEMB(neighbor_memb,
struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
132MEMB(packet_memb,
struct packet_queue, MAX_QUEUED_PACKETS);
133MEMB(metadata_memb,
struct qbuf_metadata, MAX_QUEUED_PACKETS);
137 struct packet_queue *q,
139 int num_transmissions);
140static void transmit_from_queue(
void *ptr);
142static struct neighbor_queue *
143neighbor_queue_from_addr(
const linkaddr_t *
addr)
145 struct neighbor_queue *n =
list_head(neighbor_list);
158#if CONTIKI_TARGET_COOJA
170send_one_packet(
struct neighbor_queue *n,
struct packet_queue *q)
173 int last_sent_ok = 0;
176 packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
178#if LLSEC802154_ENABLED
179#if LLSEC802154_USES_EXPLICIT_KEYS
181 packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, CSMA_LLSEC_KEY_ID_MODE);
185 if(csma_security_create_frame() < 0) {
187 LOG_ERR(
"failed to create packet, seqno: %d\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
198 if(NETSTACK_RADIO.receiving_packet() ||
199 (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
218 if(NETSTACK_RADIO.receiving_packet() ||
219 NETSTACK_RADIO.pending_packet() ||
220 NETSTACK_RADIO.channel_clear() == 0) {
222 uint8_t ackbuf[CSMA_ACK_LEN];
227 if(NETSTACK_RADIO.pending_packet()) {
228 len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN);
229 if(len == CSMA_ACK_LEN && ackbuf[2] == dsn) {
258transmit_from_queue(
void *ptr)
260 struct neighbor_queue *n = ptr;
262 struct packet_queue *q =
list_head(n->packet_queue);
264 LOG_INFO(
"preparing packet for ");
265 LOG_INFO_LLADDR(&n->addr);
266 LOG_INFO_(
", seqno %u, tx %u, queue %d\n",
267 queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO),
270 queuebuf_to_packetbuf(q->buf);
271 send_one_packet(n, q);
277schedule_transmission(
struct neighbor_queue *n)
280 int backoff_exponent;
282 backoff_exponent = MIN(n->collisions + CSMA_MIN_BE, CSMA_MAX_BE);
285 delay = ((1 << backoff_exponent) - 1) * backoff_period();
291 LOG_DBG(
"scheduling transmission in %u ticks, NB=%u, BE=%u\n",
292 (
unsigned)delay, n->collisions, backoff_exponent);
293 ctimer_set(&n->transmit_timer, delay, transmit_from_queue, n);
297free_packet(
struct neighbor_queue *n,
struct packet_queue *p,
int status)
303 queuebuf_free(p->buf);
306 LOG_DBG(
"free_queued_packet, queue length %d, free packets %zu\n",
310 n->transmissions = 0;
313 schedule_transmission(n);
324tx_done(
int status,
struct packet_queue *q,
struct neighbor_queue *n)
327 struct qbuf_metadata *metadata;
331 metadata = (
struct qbuf_metadata *)q->ptr;
332 sent = metadata->sent;
333 cptr = metadata->cptr;
334 ntx = n->transmissions;
336 LOG_INFO(
"packet sent to ");
337 LOG_INFO_LLADDR(&n->addr);
338 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
339 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
340 status, n->transmissions, n->collisions);
342 free_packet(n, q, status);
343 mac_call_sent_callback(sent, cptr, status, ntx);
347rexmit(
struct packet_queue *q,
struct neighbor_queue *n)
349 schedule_transmission(n);
352 queuebuf_update_attr_from_packetbuf(q->buf);
356collision(
struct packet_queue *q,
struct neighbor_queue *n,
357 int num_transmissions)
359 struct qbuf_metadata *metadata;
361 metadata = (
struct qbuf_metadata *)q->ptr;
363 n->collisions += num_transmissions;
365 if(n->collisions > CSMA_MAX_BACKOFF) {
371 if(n->transmissions >= metadata->max_transmissions) {
379noack(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
381 struct qbuf_metadata *metadata;
383 metadata = (
struct qbuf_metadata *)q->ptr;
386 n->transmissions += num_transmissions;
388 if(n->transmissions >= metadata->max_transmissions) {
396tx_ok(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
399 n->transmissions += num_transmissions;
405 struct packet_queue *q,
407 int num_transmissions)
413 LOG_WARN(
"packet sent: no metadata\n");
418 LOG_INFO_LLADDR(&n->addr);
419 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
420 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
421 status, n->transmissions, n->collisions);
425 tx_ok(q, n, num_transmissions);
428 noack(q, n, num_transmissions);
431 collision(q, n, num_transmissions);
436 tx_done(status, q, n);
442csma_output_packet(mac_callback_t sent,
void *ptr)
444 struct packet_queue *q;
445 struct neighbor_queue *n;
446 const linkaddr_t *
addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
449 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
452 n = neighbor_queue_from_addr(
addr);
459 n->transmissions = 0;
470 if(
list_length(n->packet_queue) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
475 q->buf = queuebuf_new_from_packetbuf();
477 struct qbuf_metadata *metadata = (
struct qbuf_metadata *)q->ptr;
479 metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
480 if(metadata->max_transmissions == 0) {
482 metadata->max_transmissions = CSMA_MAX_FRAME_RETRIES + 1;
484 metadata->sent = sent;
485 metadata->cptr = ptr;
488 LOG_INFO(
"sending to ");
489 LOG_INFO_LLADDR(
addr);
490 LOG_INFO_(
", len %u, seqno %u, queue length %d, free packets %zu\n",
492 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
496 schedule_transmission(n);
501 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
504 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
512 LOG_WARN(
"Neighbor queue full\n");
514 LOG_WARN(
"could not allocate packet, dropping packet\n");
516 LOG_WARN(
"could not allocate neighbor, dropping packet\n");
518 mac_call_sent_callback(sent, ptr, MAC_TX_QUEUE_FULL, 1);
522csma_output_init(
void)
LLSEC802154 Security related configuration.
The 802.15.4 standard CSMA protocol (nonbeacon-enabled)
Header file for the callback timer.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
#define LIST(name)
Declare a linked list.
int list_length(const_list_t list)
Get the length of a list.
void list_add(list_t list, void *item)
Add an item at the end of a list.
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
void * list_item_next(const void *item)
Get the next item following this item.
void * list_head(const_list_t list)
Get a pointer to the first element of a list.
#define LIST_STRUCT(name)
Declare a linked list inside a structure declaraction.
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
size_t memb_numfree(struct memb *m)
Count free memory blocks.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
#define MEMB(name, structure, num)
Declare a memory block.
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
bool packetbuf_holds_broadcast(void)
Checks whether the current packet is a broadcast.
@ RADIO_TX_COLLISION
TX failed due to a collision.
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
static void packet_sent(void *ptr, int status, int transmissions)
Callback function for the MAC packet sent callback.
Linked list manipulation routines.
Header file for the logging system.
void mac_sequence_set_dsn(void)
Sets and increments the destination sequence number.
Header file for MAC sequence numbers management.
@ MAC_TX_COLLISION
The MAC layer did not get an acknowledgement for the packet.
@ MAC_TX_DEFERRED
The MAC layer transmission could not be performed because of an error.
@ MAC_TX_OK
The MAC layer transmission was OK.
@ MAC_TX_NOACK
The MAC layer deferred the transmission for a later time.
@ MAC_TX_ERR_FATAL
The MAC layer transmission could not be performed because of insufficient queue space,...
@ MAC_TX_ERR
The MAC layer transmission could not be performed because of a fatal error.
Memory block allocation routines.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Header file for the Packet queue buffer management.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.