static uint16_t _ip6_addr_to_netif(const ip6_addr_p_t *_addr) { ip6_addr_t addr; assert(_addr != NULL); ip6_addr_copy_from_packed(addr, *_addr); if (!ip6_addr_isany_val(addr)) { for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { if (netif_get_ip6_addr_match(netif, &addr) >= 0) { return (int)netif->num + 1; } } } return SOCK_ADDR_ANY_NETIF; }
/** * Free a datagram (struct ip6_reassdata) and all its pbufs. * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), * sends an ICMP time exceeded packet. * * @param ipr datagram to free */ static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) { struct ip6_reassdata *prev; u16_t pbufs_freed = 0; u16_t clen; struct pbuf *p; struct ip6_reass_helper *iprh; #if LWIP_ICMP6 iprh = (struct ip6_reass_helper *)ipr->p->payload; if (iprh->start == 0) { /* The first fragment was received, send ICMP time exceeded. */ /* First, de-queue the first pbuf from r->p. */ p = ipr->p; ipr->p = iprh->next_pbuf; /* Restore the part that we've overwritten with our helper structure, or we * might send garbage (and disclose a pointer) in the ICMPv6 reply. */ MEMCPY(p->payload, ipr->orig_hdr, sizeof(iprh)); /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). This cannot fail since we already checked when receiving this fragment. */ if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr))) { LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); } else { /* Reconstruct the zoned source and destination addresses, so that we do * not end up sending the ICMP response over the wrong link. */ ip6_addr_t src_addr, dest_addr; ip6_addr_copy_from_packed(src_addr, IPV6_FRAG_SRC(ipr)); ip6_addr_set_zone(&src_addr, ipr->src_zone); ip6_addr_copy_from_packed(dest_addr, IPV6_FRAG_DEST(ipr)); ip6_addr_set_zone(&dest_addr, ipr->dest_zone); /* Send the actual ICMP response. */ icmp6_time_exceeded_with_addrs(p, ICMP6_TE_FRAG, &src_addr, &dest_addr); } clen = pbuf_clen(p); LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); pbufs_freed = (u16_t)(pbufs_freed + clen); pbuf_free(p); } #endif /* LWIP_ICMP6 */ /* First, free all received pbufs. The individual pbufs need to be released separately as they have not yet been chained */ p = ipr->p; while (p != NULL) { struct pbuf *pcur; iprh = (struct ip6_reass_helper *)p->payload; pcur = p; /* get the next pointer before freeing */ p = iprh->next_pbuf; clen = pbuf_clen(pcur); LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); pbufs_freed = (u16_t)(pbufs_freed + clen); pbuf_free(pcur); } /* Then, unchain the struct ip6_reassdata from the list and free it. */ if (ipr == reassdatagrams) { reassdatagrams = ipr->next; } else { prev = reassdatagrams; while (prev != NULL) { if (prev->next == ipr) { break; } prev = prev->next; } if (prev != NULL) { prev->next = ipr->next; } } memp_free(MEMP_IP6_REASSDATA, ipr); /* Finally, update number of pbufs in reassembly queue */ LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed); ip6_reass_pbufcount = (u16_t)(ip6_reass_pbufcount - pbufs_freed); }