/** * Same as ip6_output_if() but 'src' address is not replaced by netif address * when it is 'any'. */ err_t ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif) { struct ip6_hdr *ip6hdr; ip6_addr_t dest_addr; LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p); /* Should the IPv6 header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { /* generate IPv6 header */ if (pbuf_header(p, IP6_HLEN)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); IP6_STATS_INC(ip6.err); return ERR_BUF; } ip6hdr = (struct ip6_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", (p->len >= sizeof(struct ip6_hdr))); IP6H_HOPLIM_SET(ip6hdr, hl); IP6H_NEXTH_SET(ip6hdr, nexth); /* dest cannot be NULL here */ ip6_addr_copy(ip6hdr->dest, *dest); IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); if (src == NULL) { src = IP6_ADDR_ANY6; } /* src cannot be NULL here */ ip6_addr_copy(ip6hdr->src, *src); } else { /* IP header already included in p */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy(dest_addr, ip6hdr->dest); dest = &dest_addr; } IP6_STATS_INC(ip6.xmit); LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip6_debug_print(p); #if ENABLE_LOOPBACK { int i; #if !LWIP_HAVE_LOOPIF if (ip6_addr_isloopback(dest)) { return netif_loop_output(netif, p); } #endif /* !LWIP_HAVE_LOOPIF */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) { /* Packet to self, enqueue it for loopback */ LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n")); return netif_loop_output(netif, p); } } } #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { return ip6_frag(p, netif, dest); } #endif /* LWIP_IPV6_FRAG */ LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n")); return netif->output_ip6(netif, p, dest); }
/** * Sends an IPv6 packet on a network interface. This function constructs * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is * used as source (usually during network startup). If the source IPv6 address it * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network * interface is filled in as source address. If the destination IPv6 address is * IP_HDRINCL, p is assumed to already include an IPv6 header and p->payload points * to it instead of the data. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IPv6 header and p->payload points to that IPv6 header) * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an * IP address of the netif is selected and used as source address. * if src == NULL, IP6_ADDR_ANY is used as source) * @param dest the destination IPv6 address to send the packet to * @param hl the Hop Limit value to be set in the IPv6 header * @param tc the Traffic Class value to be set in the IPv6 header * @param nexth the Next Header to be set in the IPv6 header * @param netif the netif on which to send this packet * @return ERR_OK if the packet was sent OK * ERR_BUF if p doesn't have enough space for IPv6/LINK headers * returns errors returned by netif->output */ err_t ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif) { struct ip6_hdr *ip6hdr; ip6_addr_t dest_addr; /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); /* Should the IPv6 header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { /* generate IPv6 header */ if (pbuf_header(p, IP6_HLEN)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); IP6_STATS_INC(ip6.err); return ERR_BUF; } ip6hdr = (struct ip6_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", (p->len >= sizeof(struct ip6_hdr))); IP6H_HOPLIM_SET(ip6hdr, hl); IP6H_NEXTH_SET(ip6hdr, nexth); /* dest cannot be NULL here */ ip6_addr_copy(ip6hdr->dest, *dest); IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); if (src == NULL) { src = IP6_ADDR_ANY; } else if (ip6_addr_isany(src)) { src = ip6_select_source_address(netif, dest); if ((src == NULL) || ip6_addr_isany(src)) { /* No appropriate source address was found for this packet. */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); IP6_STATS_INC(ip6.rterr); return ERR_RTE; } } /* src cannot be NULL here */ ip6_addr_copy(ip6hdr->src, *src); } else { /* IP header already included in p */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy(dest_addr, ip6hdr->dest); dest = &dest_addr; } IP6_STATS_INC(ip6.xmit); LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip6_debug_print(p); #if ENABLE_LOOPBACK /* TODO implement loopback for v6 if (ip6_addr_cmp(dest, netif_ip6_addr(0))) { return netif_loop_output(netif, p, dest); }*/ #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { return ip6_frag(p, netif, dest); } #endif /* LWIP_IPV6_FRAG */ LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()")); return netif->output_ip6(netif, p, dest); }