/** * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. * * For IPv6 multicast, corresponding Ethernet addresses * are selected and the packet is transmitted on the link. * * For unicast addresses, ... * * @TODO anycast addresses * * @param netif The lwIP network interface which the IP packet will be sent on. * @param q The pbuf(s) containing the IP packet to be sent. * @param ip6addr The IP address of the packet destination. * * @return * - ERR_RTE No route to destination (no gateway to external networks), * or the return type of either etharp_query() or etharp_send_ip(). */ err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr) { struct eth_addr dest; s8_t i; /* make room for Ethernet header - should not fail */ if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { /* bail out */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("etharp_output: could not allocate room for header.\n")); return ERR_BUF; } /* multicast destination IP address? */ if (ip6_addr_ismulticast(ip6addr)) { /* Hash IP multicast address to MAC address.*/ dest.addr[0] = 0x33; dest.addr[1] = 0x33; dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0]; dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1]; dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2]; dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3]; /* Send out. */ return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); } /* We have a unicast destination IP address */ /* TODO anycast? */ /* Get next hop record. */ i = nd6_get_next_hop_entry(ip6addr, netif); if (i < 0) { /* failed to get a next hop neighbor record. */ return ERR_MEM; } /* Now that we have a destination record, send or queue the packet. */ if (neighbor_cache[i].state == ND6_STALE) { /* Switch to delay state. */ neighbor_cache[i].state = ND6_DELAY; neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; } /* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */ if ((neighbor_cache[i].state == ND6_REACHABLE) || (neighbor_cache[i].state == ND6_DELAY) || (neighbor_cache[i].state == ND6_PROBE)) { /* Send out. */ SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6); return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); } /* We should queue packet on this interface. */ pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR); return nd6_queue_packet(i, q); }
/** * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. * * For IPv6 multicast, corresponding Ethernet addresses * are selected and the packet is transmitted on the link. * * For unicast addresses, ... * * @todo anycast addresses * * @param netif The lwIP network interface which the IP packet will be sent on. * @param q The pbuf(s) containing the IP packet to be sent. * @param ip6addr The IP address of the packet destination. * * @return * - ERR_RTE No route to destination (no gateway to external networks), * or the return type of either nd6_queue_packet() or ethernet_output(). */ err_t ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr) { struct eth_addr dest; s8_t i; /* multicast destination IP address? */ if (ip6_addr_ismulticast(ip6addr)) { /* Hash IP multicast address to MAC address.*/ dest.addr[0] = 0x33; dest.addr[1] = 0x33; dest.addr[2] = ((const u8_t *)(&(ip6addr->addr[3])))[0]; dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1]; dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2]; dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3]; /* Send out. */ return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); } /* We have a unicast destination IP address */ /* @todo anycast? */ /* Get next hop record. */ i = nd6_get_next_hop_entry(ip6addr, netif); if (i < 0) { /* failed to get a next hop neighbor record. */ return ERR_MEM; } /* Now that we have a destination record, send or queue the packet. */ if (neighbor_cache[i].state == ND6_STALE) { /* Switch to delay state. */ neighbor_cache[i].state = ND6_DELAY; neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; } /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ if ((neighbor_cache[i].state == ND6_REACHABLE) || (neighbor_cache[i].state == ND6_DELAY) || (neighbor_cache[i].state == ND6_PROBE)) { /* Send out. */ SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6); return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6); } /* We should queue packet on this interface. */ return nd6_queue_packet(i, q); }