Defensive programming: make sure that we don't fail completely if we get a callback for a NULL pointer
This commit is contained in:
parent
82b755c017
commit
f2fbb4b49d
@ -186,15 +186,19 @@ free_first_packet(struct neighbor_queue *n)
|
|||||||
static void
|
static void
|
||||||
packet_sent(void *ptr, int status, int num_transmissions)
|
packet_sent(void *ptr, int status, int num_transmissions)
|
||||||
{
|
{
|
||||||
struct neighbor_queue *n = ptr;
|
struct neighbor_queue *n;
|
||||||
struct rdc_buf_list *q = list_head(n->queued_packet_list);
|
struct rdc_buf_list *q;
|
||||||
struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr;
|
struct qbuf_metadata *metadata;
|
||||||
clock_time_t time = 0;
|
clock_time_t time = 0;
|
||||||
mac_callback_t sent;
|
mac_callback_t sent;
|
||||||
void *cptr;
|
void *cptr;
|
||||||
int num_tx;
|
int num_tx;
|
||||||
int backoff_transmissions;
|
int backoff_transmissions;
|
||||||
|
|
||||||
|
n = ptr;
|
||||||
|
if(n == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case MAC_TX_OK:
|
case MAC_TX_OK:
|
||||||
case MAC_TX_NOACK:
|
case MAC_TX_NOACK:
|
||||||
@ -208,66 +212,72 @@ packet_sent(void *ptr, int status, int num_transmissions)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sent = metadata->sent;
|
q = list_head(n->queued_packet_list);
|
||||||
cptr = metadata->cptr;
|
if(q != NULL) {
|
||||||
num_tx = n->transmissions;
|
metadata = (struct qbuf_metadata *)q->ptr;
|
||||||
|
|
||||||
if(status == MAC_TX_COLLISION ||
|
if(metadata != NULL) {
|
||||||
status == MAC_TX_NOACK) {
|
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
|
/* If the transmission was not performed because of a
|
||||||
noack, we must retransmit the packet. */
|
collision or noack, we must retransmit the packet. */
|
||||||
|
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case MAC_TX_COLLISION:
|
case MAC_TX_COLLISION:
|
||||||
PRINTF("csma: rexmit collision %d\n", n->transmissions);
|
PRINTF("csma: rexmit collision %d\n", n->transmissions);
|
||||||
break;
|
break;
|
||||||
case MAC_TX_NOACK:
|
case MAC_TX_NOACK:
|
||||||
PRINTF("csma: rexmit noack %d\n", n->transmissions);
|
PRINTF("csma: rexmit noack %d\n", n->transmissions);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PRINTF("csma: rexmit err %d, %d\n", status, n->transmissions);
|
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 rdc_buf_list *q;
|
||||||
struct neighbor_queue *n;
|
struct neighbor_queue *n;
|
||||||
static uint16_t seqno;
|
static uint16_t seqno;
|
||||||
|
const rimeaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
|
||||||
|
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
|
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) {
|
if(n != NULL) {
|
||||||
/* Add packet to the neighbor's queue */
|
/* Init neighbor entry */
|
||||||
q = memb_alloc(&packet_memb);
|
rimeaddr_copy(&n->addr, addr);
|
||||||
if(q != NULL) {
|
n->transmissions = 0;
|
||||||
q->ptr = memb_alloc(&metadata_memb);
|
n->collisions = 0;
|
||||||
if(q->ptr != NULL) {
|
n->deferrals = 0;
|
||||||
q->buf = queuebuf_new_from_packetbuf();
|
/* Init packet list for this neighbor */
|
||||||
if(q->buf != NULL) {
|
LIST_STRUCT_INIT(n, queued_packet_list);
|
||||||
struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr;
|
/* Add neighbor to the list */
|
||||||
/* Neighbor and packet successfully allocated */
|
list_add(neighbor_list, n);
|
||||||
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);
|
|
||||||
} 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
|
static void
|
||||||
|
Loading…
Reference in New Issue
Block a user