46#include "dev/watchdog.h"
49#include "lib/random.h"
53#include "lib/assert.h"
57#define LOG_MODULE "CSMA"
58#define LOG_LEVEL LOG_LEVEL_MAC
63#ifdef CSMA_CONF_MIN_BE
64#define CSMA_MIN_BE CSMA_CONF_MIN_BE
70#ifdef CSMA_CONF_MAX_BE
71#define CSMA_MAX_BE CSMA_CONF_MAX_BE
77#ifdef CSMA_CONF_MAX_BACKOFF
78#define CSMA_MAX_BACKOFF CSMA_CONF_MAX_BACKOFF
80#define CSMA_MAX_BACKOFF 5
84#ifdef CSMA_CONF_MAX_FRAME_RETRIES
85#define CSMA_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES
87#define CSMA_MAX_FRAME_RETRIES 7
94 uint8_t max_transmissions;
98struct neighbor_queue {
99 struct neighbor_queue *next;
101 struct ctimer transmit_timer;
102 uint8_t transmissions;
108#ifdef CSMA_CONF_MAX_NEIGHBOR_QUEUES
109#define CSMA_MAX_NEIGHBOR_QUEUES CSMA_CONF_MAX_NEIGHBOR_QUEUES
111#define CSMA_MAX_NEIGHBOR_QUEUES 2
115#ifdef CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
116#define CSMA_MAX_PACKET_PER_NEIGHBOR CSMA_CONF_MAX_PACKET_PER_NEIGHBOR
118#define CSMA_MAX_PACKET_PER_NEIGHBOR MAX_QUEUED_PACKETS
121#define MAX_QUEUED_PACKETS QUEUEBUF_NUM
125 struct packet_queue *next;
126 struct queuebuf *buf;
130MEMB(neighbor_memb,
struct neighbor_queue, CSMA_MAX_NEIGHBOR_QUEUES);
131MEMB(packet_memb,
struct packet_queue, MAX_QUEUED_PACKETS);
132MEMB(metadata_memb,
struct qbuf_metadata, MAX_QUEUED_PACKETS);
136 struct packet_queue *q,
138 int num_transmissions);
139static void transmit_from_queue(
void *ptr);
141static struct neighbor_queue *
142neighbor_queue_from_addr(
const linkaddr_t *
addr)
144 struct neighbor_queue *n =
list_head(neighbor_list);
157#if CONTIKI_TARGET_COOJA
169send_one_packet(
struct neighbor_queue *n,
struct packet_queue *q)
172 int last_sent_ok = 0;
175 packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
177#if LLSEC802154_ENABLED
178#if LLSEC802154_USES_EXPLICIT_KEYS
180 packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, CSMA_LLSEC_KEY_ID_MODE);
184 if(csma_security_create_frame() < 0) {
186 LOG_ERR(
"failed to create packet, seqno: %d\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
197 if(NETSTACK_RADIO.receiving_packet() ||
198 (!is_broadcast && NETSTACK_RADIO.pending_packet())) {
217 if(NETSTACK_RADIO.receiving_packet() ||
218 NETSTACK_RADIO.pending_packet() ||
219 NETSTACK_RADIO.channel_clear() == 0) {
221 uint8_t ackbuf[CSMA_ACK_LEN];
226 if(NETSTACK_RADIO.pending_packet()) {
227 len = NETSTACK_RADIO.read(ackbuf, CSMA_ACK_LEN);
228 if(len == CSMA_ACK_LEN && ackbuf[2] == dsn) {
257transmit_from_queue(
void *ptr)
259 struct neighbor_queue *n = ptr;
261 struct packet_queue *q =
list_head(n->packet_queue);
263 LOG_INFO(
"preparing packet for ");
264 LOG_INFO_LLADDR(&n->addr);
265 LOG_INFO_(
", seqno %u, tx %u, queue %d\n",
266 queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO),
269 queuebuf_to_packetbuf(q->buf);
270 send_one_packet(n, q);
276schedule_transmission(
struct neighbor_queue *n)
279 int backoff_exponent;
281 backoff_exponent = MIN(n->collisions + CSMA_MIN_BE, CSMA_MAX_BE);
284 delay = ((1 << backoff_exponent) - 1) * backoff_period();
290 LOG_DBG(
"scheduling transmission in %u ticks, NB=%u, BE=%u\n",
291 (
unsigned)delay, n->collisions, backoff_exponent);
292 ctimer_set(&n->transmit_timer, delay, transmit_from_queue, n);
296free_packet(
struct neighbor_queue *n,
struct packet_queue *p,
int status)
302 queuebuf_free(p->buf);
305 LOG_DBG(
"free_queued_packet, queue length %d, free packets %d\n",
309 n->transmissions = 0;
312 schedule_transmission(n);
323tx_done(
int status,
struct packet_queue *q,
struct neighbor_queue *n)
326 struct qbuf_metadata *metadata;
330 metadata = (
struct qbuf_metadata *)q->ptr;
331 sent = metadata->sent;
332 cptr = metadata->cptr;
333 ntx = n->transmissions;
335 LOG_INFO(
"packet sent to ");
336 LOG_INFO_LLADDR(&n->addr);
337 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
338 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
339 status, n->transmissions, n->collisions);
341 free_packet(n, q, status);
342 mac_call_sent_callback(sent, cptr, status, ntx);
346rexmit(
struct packet_queue *q,
struct neighbor_queue *n)
348 schedule_transmission(n);
351 queuebuf_update_attr_from_packetbuf(q->buf);
355collision(
struct packet_queue *q,
struct neighbor_queue *n,
356 int num_transmissions)
358 struct qbuf_metadata *metadata;
360 metadata = (
struct qbuf_metadata *)q->ptr;
362 n->collisions += num_transmissions;
364 if(n->collisions > CSMA_MAX_BACKOFF) {
370 if(n->transmissions >= metadata->max_transmissions) {
378noack(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
380 struct qbuf_metadata *metadata;
382 metadata = (
struct qbuf_metadata *)q->ptr;
385 n->transmissions += num_transmissions;
387 if(n->transmissions >= metadata->max_transmissions) {
395tx_ok(
struct packet_queue *q,
struct neighbor_queue *n,
int num_transmissions)
398 n->transmissions += num_transmissions;
404 struct packet_queue *q,
406 int num_transmissions)
412 LOG_WARN(
"packet sent: no metadata\n");
417 LOG_INFO_LLADDR(&n->addr);
418 LOG_INFO_(
", seqno %u, status %u, tx %u, coll %u\n",
419 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
420 status, n->transmissions, n->collisions);
424 tx_ok(q, n, num_transmissions);
427 noack(q, n, num_transmissions);
430 collision(q, n, num_transmissions);
435 tx_done(status, q, n);
441csma_output_packet(mac_callback_t sent,
void *ptr)
443 struct packet_queue *q;
444 struct neighbor_queue *n;
445 static uint8_t initialized = 0;
446 static uint8_t seqno;
447 const linkaddr_t *
addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
460 packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
461 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
464 n = neighbor_queue_from_addr(
addr);
471 n->transmissions = 0;
482 if(
list_length(n->packet_queue) < CSMA_MAX_PACKET_PER_NEIGHBOR) {
487 q->buf = queuebuf_new_from_packetbuf();
489 struct qbuf_metadata *metadata = (
struct qbuf_metadata *)q->ptr;
491 metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
492 if(metadata->max_transmissions == 0) {
494 metadata->max_transmissions = CSMA_MAX_FRAME_RETRIES + 1;
496 metadata->sent = sent;
497 metadata->cptr = ptr;
500 LOG_INFO(
"sending to ");
501 LOG_INFO_LLADDR(
addr);
502 LOG_INFO_(
", len %u, seqno %u, queue length %d, free packets %d\n",
504 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
508 schedule_transmission(n);
513 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
516 LOG_WARN(
"could not allocate queuebuf, dropping packet\n");
524 LOG_WARN(
"Neighbor queue full\n");
526 LOG_WARN(
"could not allocate packet, dropping packet\n");
528 LOG_WARN(
"could not allocate neighbor, dropping packet\n");
530 mac_call_sent_callback(sent, ptr, MAC_TX_QUEUE_FULL, 1);
534csma_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.
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
void * list_head(const list_t list)
Get a pointer to the first element of a list.
#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.
#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().
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().
int memb_numfree(struct memb *m)
Count free memory blocks.
#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.
int 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.
@ 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.