I'm trying to use the lwIP Demo 4.0.0 as a basis for a new firmware. However, after sending about 60 UDP packets to it, the code halts in the interruption handler, more precisely, at function hdkif_rx_inthandler, due to a NULL pointer in curr_bd->next (curr_bd being hdkif[0]->state->rxch->active_head). Trying to check for this pointer in the loop of the function prevents the break, but no more interrupts are issued.
I'm currently using CCS 11.1.0.00011 with TI compiler v20.2.7.LTS. For easier, reference I'm pasting the interrupt handler below, with the very few alterations I've made to try to isolate the problem:
/** * Handler for Receive interrupt. Packet processing is done in this * interrupt handler itself. * * @param netif the lwip network interface structure for this ethernetif * @return none */ uint32 last_curr_bd, last_next_bd; uint32 no_prob_last = 1; void hdkif_rx_inthandler(struct netif *netif) { struct hdkif *hdkif; struct rxch *rxch; volatile struct emac_rx_bdp *curr_bd, *processed_bd, *curr_tail, *last_bd; volatile struct pbuf *pbuf, *q, *new_pbuf; uint32 ex_len = 0, len_to_alloc = 0; uint16 tot_len; hdkif = netif->state; rxch = &(hdkif->rxch); /* Get the bd which contains the earliest filled data */ curr_bd = rxch->active_head; last_bd = rxch->active_tail; /** * Process the descriptors as long as data is available * when the DMA is receiving data, SOP flag will be set */ while((hdkif_swizzle_data(curr_bd->flags_pktlen) & EMAC_BUF_DESC_SOP) && (curr_bd != NULL)) { ex_len = 0; len_to_alloc = 0; /* Start processing once the packet is loaded */ if((hdkif_swizzle_data(curr_bd->flags_pktlen) & EMAC_BUF_DESC_OWNER) != EMAC_BUF_DESC_OWNER) { if(rxch->free_head == NULL) { /* this bd chain will be freed after processing */ rxch->free_head = curr_bd; } /* Get the total length of the packet. curr_bd points to the start * of the packet. */ tot_len = hdkif_swizzle_data(curr_bd->flags_pktlen) & 0xFFFF; /* Get the start of the pbuf queue */ q = curr_bd->pbuf; do { /* Get the pbuf pointer which is associated with the current bd */ pbuf = curr_bd->pbuf; /* If the earlier pbuf ended, update the chain */ if(pbuf->next == NULL) { pbuf->next = (struct pbuf*)hdkif_swizzle_rxp(curr_bd->next)->pbuf; } len_to_alloc += pbuf->len; /* Update the len and tot_len fields for the pbuf in the chain*/ pbuf->len = hdkif_swizzle_data(curr_bd->bufoff_len) & 0xFFFF; pbuf->tot_len = tot_len - ex_len ; processed_bd = curr_bd; ex_len += pbuf->len; /* if(hdkif_swizzle_rxp(curr_bd->next) == NULL){ */ /* break; */ /* }else{ */ curr_bd = hdkif_swizzle_rxp(curr_bd->next); /* } */ } while((hdkif_swizzle_data(processed_bd->flags_pktlen) & EMAC_BUF_DESC_EOP) != EMAC_BUF_DESC_EOP); /** * Close the chain for this pbuf. A full packet is received in * this pbuf chain. Now this pbuf can be given to upper layers for * processing. The start of the pbuf chain is now 'q'. */ pbuf->next = NULL; /* Adjust the link statistics */ LINK_STATS_INC(link.recv); /* Process the packet */ if(ethernet_input((struct pbuf *)q, netif) != ERR_OK) { /* Adjust the link statistics */ LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } /* Acknowledge that this packet is processed */ EMACRxCPWrite(hdkif->emac_base, 0, (unsigned int)processed_bd); rxch->active_head = curr_bd; /** * The earlier pbuf chain is freed from the upper layer. So, we need to * allocate a new pbuf chain and update the descriptors with the pbuf info. * To support chaining, the total length freed by the upper layer is tracked. * Care should be taken even if the allocation fails. */ /** * now len_to_alloc will contain the length of the pbuf which was freed * from the upper layer */ rxch->freed_pbuf_len += len_to_alloc; new_pbuf = pbuf_alloc(PBUF_RAW, (rxch->freed_pbuf_len), PBUF_POOL); /* Write the descriptors with the pbuf info till either of them expires */ if(new_pbuf != NULL) { curr_bd = rxch->free_head; for(q = new_pbuf; (q != NULL) && (curr_bd != rxch->active_head); q = q->next) { curr_bd->bufptr = hdkif_swizzle_data((uint32)(q->payload)); /* no support for buf_offset. RXBUFFEROFFEST register is 0 */ curr_bd->bufoff_len = hdkif_swizzle_data((q->len) & 0xFFFF); curr_bd->flags_pktlen = hdkif_swizzle_data(EMAC_BUF_DESC_OWNER); rxch->freed_pbuf_len -= q->len; /* Save the pbuf */ curr_bd->pbuf = q; last_bd = curr_bd; curr_bd = hdkif_swizzle_rxp(curr_bd->next); } /** * At this point either pbuf expired or no rxbd to allocate. If * there are no, enough rx bds to allocate all pbufs in the chain, * free the rest of the pbuf */ if(q != NULL) { pbuf_free((struct pbuf *)q); } curr_tail = rxch->active_tail; last_bd->next = NULL; curr_tail->next = hdkif_swizzle_rxp(rxch->free_head); /** * Check if the reception has ended. If the EOQ flag is set, the NULL * Pointer is taken by the DMA engine. So we need to write the RX HDP * with the next descriptor. */ if(hdkif_swizzle_data(curr_tail->flags_pktlen) & EMAC_BUF_DESC_EOQ) { EMACRxHdrDescPtrWrite(hdkif->emac_base, (uint32)(rxch->free_head), 0); } rxch->free_head = curr_bd; rxch->active_tail = last_bd; } } curr_bd = rxch->active_head; } EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_RX); EMACCoreIntAck(hdkif->emac_base, EMAC_INT_CORE0_TX); }