diff --git a/core/net/mac/csma.c b/core/net/mac/csma.c index cb0430341..37d8f4998 100644 --- a/core/net/mac/csma.c +++ b/core/net/mac/csma.c @@ -186,15 +186,19 @@ free_first_packet(struct neighbor_queue *n) static void packet_sent(void *ptr, int status, int num_transmissions) { - struct neighbor_queue *n = ptr; - struct rdc_buf_list *q = list_head(n->queued_packet_list); - struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr; + struct neighbor_queue *n; + struct rdc_buf_list *q; + struct qbuf_metadata *metadata; clock_time_t time = 0; mac_callback_t sent; void *cptr; int num_tx; int backoff_transmissions; + n = ptr; + if(n == NULL) { + return; + } switch(status) { case MAC_TX_OK: case MAC_TX_NOACK: @@ -208,66 +212,72 @@ packet_sent(void *ptr, int status, int num_transmissions) break; } - sent = metadata->sent; - cptr = metadata->cptr; - num_tx = n->transmissions; + q = list_head(n->queued_packet_list); + if(q != NULL) { + metadata = (struct qbuf_metadata *)q->ptr; - if(status == MAC_TX_COLLISION || - status == MAC_TX_NOACK) { + if(metadata != NULL) { + sent = metadata->sent; + cptr = metadata->cptr; + num_tx = n->transmissions; + if(status == MAC_TX_COLLISION || + status == MAC_TX_NOACK) { - /* If the transmission was not performed because of a collision or - noack, we must retransmit the packet. */ - - switch(status) { - case MAC_TX_COLLISION: - PRINTF("csma: rexmit collision %d\n", n->transmissions); - break; - case MAC_TX_NOACK: - PRINTF("csma: rexmit noack %d\n", n->transmissions); - break; - default: - PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions); + /* If the transmission was not performed because of a + collision or noack, we must retransmit the packet. */ + + switch(status) { + case MAC_TX_COLLISION: + PRINTF("csma: rexmit collision %d\n", n->transmissions); + break; + case MAC_TX_NOACK: + PRINTF("csma: rexmit noack %d\n", n->transmissions); + break; + default: + PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions); + } + + /* The retransmission time must be proportional to the channel + check interval of the underlying radio duty cycling layer. */ + time = default_timebase(); + + /* The retransmission time uses a linear backoff so that the + interval between the transmissions increase with each + retransmit. */ + backoff_transmissions = n->transmissions + 1; + + /* Clamp the number of backoffs so that we don't get a too long + timeout here, since that will delay all packets in the + queue. */ + if(backoff_transmissions > 3) { + backoff_transmissions = 3; + } + + time = time + (random_rand() % (backoff_transmissions * time)); + + if(n->transmissions < metadata->max_transmissions) { + PRINTF("csma: retransmitting with time %lu %p\n", time, q); + ctimer_set(&n->transmit_timer, time, + transmit_packet_list, n); + /* This is needed to correctly attribute energy that we spent + transmitting this packet. */ + queuebuf_update_attr_from_packetbuf(q->buf); + } else { + PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n", + status, n->transmissions, n->collisions); + free_first_packet(n); + mac_call_sent_callback(sent, cptr, status, num_tx); + } + } else { + if(status == MAC_TX_OK) { + PRINTF("csma: rexmit ok %d\n", n->transmissions); + } else { + PRINTF("csma: rexmit failed %d: %d\n", n->transmissions, status); + } + free_first_packet(n); + mac_call_sent_callback(sent, cptr, status, num_tx); + } } - - /* The retransmission time must be proportional to the channel - check interval of the underlying radio duty cycling layer. */ - time = default_timebase(); - - /* The retransmission time uses a linear backoff so that the - interval between the transmissions increase with each - retransmit. */ - backoff_transmissions = n->transmissions + 1; - - /* Clamp the number of backoffs so that we don't get a too long - timeout here, since that will delay all packets in the - queue. */ - if(backoff_transmissions > 3) { - backoff_transmissions = 3; - } - - time = time + (random_rand() % (backoff_transmissions * time)); - - if(n->transmissions < metadata->max_transmissions) { - PRINTF("csma: retransmitting with time %lu %p\n", time, q); - ctimer_set(&n->transmit_timer, time, - transmit_packet_list, n); - /* This is needed to correctly attribute energy that we spent - transmitting this packet. */ - queuebuf_update_attr_from_packetbuf(q->buf); - } else { - PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n", - status, n->transmissions, n->collisions); - free_first_packet(n); - mac_call_sent_callback(sent, cptr, status, num_tx); - } - } else { - if(status == MAC_TX_OK) { - PRINTF("csma: rexmit ok %d\n", n->transmissions); - } else { - PRINTF("csma: rexmit failed %d: %d\n", n->transmissions, status); - } - free_first_packet(n); - mac_call_sent_callback(sent, cptr, status, num_tx); } } /*---------------------------------------------------------------------------*/ @@ -277,86 +287,77 @@ send_packet(mac_callback_t sent, void *ptr) struct rdc_buf_list *q; struct neighbor_queue *n; static uint16_t seqno; + const rimeaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++); - - /* If the packet is a broadcast, do not allocate a queue - entry. Instead, just send it out. */ - if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), - &rimeaddr_null)) { - const rimeaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); - - /* Look for the neighbor entry */ - n = neighbor_queue_from_addr(addr); - if(n == NULL) { - /* Allocate a new neighbor entry */ - n = memb_alloc(&neighbor_memb); - if(n != NULL) { - /* Init neighbor entry */ - rimeaddr_copy(&n->addr, addr); - n->transmissions = 0; - n->collisions = 0; - n->deferrals = 0; - /* Init packet list for this neighbor */ - LIST_STRUCT_INIT(n, queued_packet_list); - /* Add neighbor to the list */ - list_add(neighbor_list, n); - } - } + /* Look for the neighbor entry */ + n = neighbor_queue_from_addr(addr); + if(n == NULL) { + /* Allocate a new neighbor entry */ + n = memb_alloc(&neighbor_memb); if(n != NULL) { - /* Add packet to the neighbor's queue */ - q = memb_alloc(&packet_memb); - if(q != NULL) { - q->ptr = memb_alloc(&metadata_memb); - if(q->ptr != NULL) { - q->buf = queuebuf_new_from_packetbuf(); - if(q->buf != NULL) { - struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr; - /* Neighbor and packet successfully allocated */ - if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) { - /* Use default configuration for max transmissions */ - metadata->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS; - } else { - metadata->max_transmissions = - packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); - } - metadata->sent = sent; - metadata->cptr = ptr; - - if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == - PACKETBUF_ATTR_PACKET_TYPE_ACK) { - list_push(n->queued_packet_list, q); - } else { - list_add(n->queued_packet_list, q); - } - - /* If q is the first packet in the neighbor's queue, send asap */ - if(list_head(n->queued_packet_list) == q) { - ctimer_set(&n->transmit_timer, 0, transmit_packet_list, n); - } - return; - } - memb_free(&metadata_memb, q->ptr); - PRINTF("csma: could not allocate queuebuf, dropping packet\n"); - } - memb_free(&packet_memb, q); - PRINTF("csma: could not allocate queuebuf, dropping packet\n"); - } - /* The packet allocation failed. Remove and free neighbor entry if empty. */ - if(list_length(n->queued_packet_list) == 0) { - list_remove(neighbor_list, n); - memb_free(&neighbor_memb, n); - } - PRINTF("csma: could not allocate packet, dropping packet\n"); - } else { - PRINTF("csma: could not allocate neighbor, dropping packet\n"); + /* Init neighbor entry */ + rimeaddr_copy(&n->addr, addr); + n->transmissions = 0; + n->collisions = 0; + n->deferrals = 0; + /* Init packet list for this neighbor */ + LIST_STRUCT_INIT(n, queued_packet_list); + /* Add neighbor to the list */ + list_add(neighbor_list, n); } - mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1); - } else { - PRINTF("csma: send broadcast\n"); - NETSTACK_RDC.send(sent, ptr); } + + if(n != NULL) { + /* Add packet to the neighbor's queue */ + q = memb_alloc(&packet_memb); + if(q != NULL) { + q->ptr = memb_alloc(&metadata_memb); + if(q->ptr != NULL) { + q->buf = queuebuf_new_from_packetbuf(); + if(q->buf != NULL) { + struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr; + /* Neighbor and packet successfully allocated */ + if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) { + /* Use default configuration for max transmissions */ + metadata->max_transmissions = CSMA_MAX_MAC_TRANSMISSIONS; + } else { + metadata->max_transmissions = + packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); + } + metadata->sent = sent; + metadata->cptr = ptr; + + if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == + PACKETBUF_ATTR_PACKET_TYPE_ACK) { + list_push(n->queued_packet_list, q); + } else { + list_add(n->queued_packet_list, q); + } + + /* If q is the first packet in the neighbor's queue, send asap */ + if(list_head(n->queued_packet_list) == q) { + ctimer_set(&n->transmit_timer, 0, transmit_packet_list, n); + } + return; + } + memb_free(&metadata_memb, q->ptr); + PRINTF("csma: could not allocate queuebuf, dropping packet\n"); + } + memb_free(&packet_memb, q); + PRINTF("csma: could not allocate queuebuf, dropping packet\n"); + } + /* The packet allocation failed. Remove and free neighbor entry if empty. */ + if(list_length(n->queued_packet_list) == 0) { + list_remove(neighbor_list, n); + memb_free(&neighbor_memb, n); + } + PRINTF("csma: could not allocate packet, dropping packet\n"); + } else { + PRINTF("csma: could not allocate neighbor, dropping packet\n"); + } + mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1); } /*---------------------------------------------------------------------------*/ static void