/** * Handles every incoming ARP Packet, called by etharp_arp_input. * * @param netif network interface to use for autoip processing * @param hdr Incoming ARP packet */ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { /* when ip.src == llipaddr && hw.src != netif->hwaddr * * when probing ip.dst == llipaddr && hw.src != netif->hwaddr * we have a conflict and must solve it */ ip_addr_t sipaddr, dipaddr; struct eth_addr netifaddr; ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ IPADDR2_COPY(&sipaddr, &hdr->sipaddr); IPADDR2_COPY(&dipaddr, &hdr->dipaddr); if ((netif->autoip->state == AUTOIP_STATE_PROBING) || ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && (netif->autoip->sent_num == 0))) { /* RFC 3927 Section 2.2.1: * from beginning to after ANNOUNCE_WAIT * seconds we have a conflict if * ip.src == llipaddr OR * ip.dst == llipaddr && hw.src != own hwaddr */ if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("autoip_arp_reply(): Probe Conflict detected\n")); /* Clear stored lladdr in case of conflict. As device should now * re-probe conflicted address. */ memset(&prev_llipaddr, 0, sizeof(ip_addr_t)); autoip_restart(netif); } } else { /* RFC 3927 Section 2.5: * in any state we have a conflict if * ip.src == llipaddr && hw.src != own hwaddr */ if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); /* Clear stored lladdr in case of conflict. As device should now * re-probe conflicted address. * Clear stored address only if it was not announced */ if (netif->autoip->state != AUTOIP_STATE_BOUND) memset(&prev_llipaddr, 0, sizeof(ip_addr_t)); autoip_handle_arp_conflict(netif); } } } }
/** * Handles every incoming ARP Packet, called by etharp_arp_input. * * @param netif network interface to use for autoip processing * @param hdr Incoming ARP packet */ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { /* when ip.src == llipaddr && hw.src != netif->hwaddr * * when probing ip.dst == llipaddr && hw.src != netif->hwaddr * we have a conflict and must solve it */ struct ip_addr sipaddr, dipaddr; struct eth_addr netifaddr; netifaddr.addr[0] = netif->hwaddr[0]; netifaddr.addr[1] = netif->hwaddr[1]; netifaddr.addr[2] = netif->hwaddr[2]; netifaddr.addr[3] = netif->hwaddr[3]; netifaddr.addr[4] = netif->hwaddr[4]; netifaddr.addr[5] = netif->hwaddr[5]; /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); if ((netif->autoip->state == AUTOIP_STATE_PROBING) || ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && (netif->autoip->sent_num == 0))) { /* RFC 3927 Section 2.2.1: * from beginning to after ANNOUNCE_WAIT * seconds we have a conflict if * ip.src == llipaddr OR * ip.dst == llipaddr && hw.src != own hwaddr */ if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("autoip_arp_reply(): Probe Conflict detected\n")); autoip_start(netif); } } else { /* RFC 3927 Section 2.5: * in any state we have a conflict if * ip.src == llipaddr && hw.src != own hwaddr */ if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); autoip_handle_arp_conflict(netif); } } } }
/** * @ingroup lwip_nosys * Process received ethernet frames. Using this function instead of directly * calling ip_input and passing ARP frames through etharp in ethernetif_input, * the ARP cache is protected from concurrent access.\n * Don't call directly, pass to netif_add() and call netif->input(). * * @param p the received packet, p->payload pointing to the ethernet header * @param netif the network interface on which the packet was received * * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL * @see ETHARP_SUPPORT_VLAN * @see LWIP_HOOK_VLAN_CHECK */ err_t ethernet_input(struct pbuf *p, struct netif *netif) { struct eth_hdr* ethhdr; u16_t type; #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6 s16_t ip_hdr_offset = SIZEOF_ETH_HDR; #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ if (p->len <= SIZEOF_ETH_HDR) { /* a packet with only an ethernet header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinerrors); goto free_and_return; } /* points to packet payload, which starts with an Ethernet header */ ethhdr = (struct eth_hdr *)p->payload; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], lwip_htons(ethhdr->type))); type = ethhdr->type; #if ETHARP_SUPPORT_VLAN if (type == PP_HTONS(ETHTYPE_VLAN)) { struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { /* a packet with only an ethernet/vlan header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinerrors); goto free_and_return; } #if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ #ifdef LWIP_HOOK_VLAN_CHECK if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK_FN) if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK) if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { #endif /* silently ignore this packet: not for our VLAN */ pbuf_free(p); return ERR_OK; } #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ type = vlan->tpid; ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } #endif /* ETHARP_SUPPORT_VLAN */ #if LWIP_ARP_FILTER_NETIF netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); #endif /* LWIP_ARP_FILTER_NETIF*/ if (ethhdr->dest.addr[0] & 1) { /* this might be a multicast or broadcast packet */ if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { #if LWIP_IPV4 if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { /* mark the pbuf as link-layer multicast */ p->flags |= PBUF_FLAG_LLMCAST; } #endif /* LWIP_IPV4 */ } #if LWIP_IPV6 else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { /* mark the pbuf as link-layer multicast */ p->flags |= PBUF_FLAG_LLMCAST; } #endif /* LWIP_IPV6 */ else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { /* mark the pbuf as link-layer broadcast */ p->flags |= PBUF_FLAG_LLBCAST; } } switch (type) { #if LWIP_IPV4 && LWIP_ARP /* IP packet? */ case PP_HTONS(ETHTYPE_IP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: IPv4 packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); goto free_and_return; } else { /* pass to IP layer */ ip4_input(p, netif); } break; case PP_HTONS(ETHTYPE_ARP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: ARP response packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); ETHARP_STATS_INC(etharp.lenerr); ETHARP_STATS_INC(etharp.drop); goto free_and_return; } else { /* pass p to ARP module */ etharp_input(p, netif); } break; #endif /* LWIP_IPV4 && LWIP_ARP */ #if PPPOE_SUPPORT case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ pppoe_disc_input(netif, p); break; case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ pppoe_data_input(netif, p); break; #endif /* PPPOE_SUPPORT */ #if LWIP_IPV6 case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: IPv6 packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); goto free_and_return; } else { /* pass to IPv6 layer */ ip6_input(p, netif); } break; #endif /* LWIP_IPV6 */ default: #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL if(LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) { break; } #endif ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinunknownprotos); goto free_and_return; } /* This means the pbuf is freed or consumed, so the caller doesn't have to free it again */ return ERR_OK; free_and_return: pbuf_free(p); return ERR_OK; } /** * @ingroup ethernet * Send an ethernet packet on the network using netif->linkoutput(). * The ethernet header is filled in before sending. * * @see LWIP_HOOK_VLAN_SET * * @param netif the lwIP network interface on which to send the packet * @param p the packet to send. pbuf layer must be @ref PBUF_LINK. * @param src the source MAC address to be copied into the ethernet header * @param dst the destination MAC address to be copied into the ethernet header * @param eth_type ethernet type (@ref eth_type) * @return ERR_OK if the packet was sent, any other err_t on failure */ err_t ethernet_output(struct netif* netif, struct pbuf* p, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type) { struct eth_hdr* ethhdr; u16_t eth_type_be = lwip_htons(eth_type); #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); if (vlan_prio_vid >= 0) { struct eth_vlan_hdr* vlanhdr; LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF); if (pbuf_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) { goto pbuf_header_failed; } vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)p->payload) + SIZEOF_ETH_HDR); vlanhdr->tpid = eth_type_be; vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid); eth_type_be = PP_HTONS(ETHTYPE_VLAN); } else #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ { if (pbuf_header(p, SIZEOF_ETH_HDR) != 0) { goto pbuf_header_failed; } } ethhdr = (struct eth_hdr*)p->payload; ethhdr->type = eth_type_be; ETHADDR32_COPY(ðhdr->dest, dst); ETHADDR16_COPY(ðhdr->src, src); LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!", (netif->hwaddr_len == ETH_HWADDR_LEN)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_output: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); pbuf_header_failed: LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("ethernet_output: could not allocate room for header.\n")); LINK_STATS_INC(link.lenerr); return ERR_BUF; }
/** * Initializes and sets up a netfront interface for lwIP. * This function should be passed as a parameter to netfrontif_add(). * * @param netif * the lwip network interface structure for this netfrontif * @return * ERR_OK if the interface was successfully initialized; * An err_t value otherwise */ err_t netfrontif_init(struct netif *netif) { struct netfrontif *nfi; static uint8_t netfrontif_id = 0; LWIP_ASSERT("netif != NULL", (netif != NULL)); if (!(netif->state)) { nfi = mem_calloc(1, sizeof(*nfi)); if (!nfi) { LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: " "Could not allocate \n")); goto err_out; } netif->state = nfi; nfi->_state_is_private = 1; nfi->_dev_is_private = 1; nfi->_hwaddr_is_private = 1; } else { nfi = netif->state; nfi->_state_is_private = 0; nfi->_dev_is_private = !(nfi->dev); nfi->_hwaddr_is_private = eth_addr_cmp(&nfi->hwaddr, ðzero); } /* Netfront */ if (nfi->_dev_is_private) { /* user did not provide an opened netfront, we need to do it here */ if (!nfi->_state_is_private) { /* use vif_id to open an specific NIC interface */ /* Note: netfront will duplicate the passed nodename */ char nodename[128]; snprintf(nodename, sizeof(nodename), "device/vif/%u", nfi->vif_id); nfi->dev = init_netfront(nodename, NULL, NULL, NULL); } else { /* open the next available net interface */ nfi->dev = init_netfront(NULL, NULL, NULL, NULL); } if (!nfi->dev) { LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: " "Could not init netfront\n")); goto err_free_nfi; } } netfront_set_rx_pbuf_handler(nfi->dev, netfrontif_rx_handler, netif); /* Interface identifier */ netif->name[0] = NETFRONTIF_NPREFIX; netif->name[1] = '0' + netfrontif_id; netfrontif_id++; /* We directly use etharp_output() here to save a function call. * Instead, there could be function declared that calls etharp_output() * only if there is a link is available... */ netif->output = etharp_output; netif->linkoutput = netfrontif_transmit; #if LWIP_NETIF_REMOVE_CALLBACK netif->remove_callback = netfrontif_exit; #endif /* CONFIG_NETIF_REMOVE_CALLBACK */ /* Hardware address */ if (nfi->_hwaddr_is_private) { if (!netfront_get_hwaddr(nfi->dev, &nfi->hwaddr)) { LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: " "Could not retrieve hardware address\n", netif->name[0], netif->name[1])); goto err_shutdown_netfront; } } else { LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: " "Overwriting hardware address\n", netif->name[0], netif->name[1])); } SMEMCPY(&netif->hwaddr, &nfi->hwaddr, ETHARP_HWADDR_LEN); netif->hwaddr_len = ETHARP_HWADDR_LEN; LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: hardware address: " "%02x:%02x:%02x:%02x:%02x:%02x\n", netif->name[0], netif->name[1], netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5])); /* Initialize the snmp variables and counters inside the struct netif. * The last argument is the link speed, in units of bits per second. */ NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, NETFRONTIF_SPEED); LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: Link speed: %llu bps\n", netif->name[0], netif->name[1], NETFRONTIF_SPEED)); /* Device capabilities */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; /* Maximum transfer unit */ netif->mtu = NETFRONTIF_MTU; LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: MTU: %u\n", netif->name[0], netif->name[1], netif->mtu)); #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ if (!netif->hostname) netif->hostname = NULL; #endif /* LWIP_NETIF_HOSTNAME */ #ifndef CONFIG_LWIP_NOTHREADS nfi->_thread_exit = 0; nfi->_thread_name[0] = netif->name[0]; nfi->_thread_name[1] = netif->name[1]; nfi->_thread_name[2] = '-'; nfi->_thread_name[3] = 'r'; nfi->_thread_name[4] = 'x'; nfi->_thread_name[5] = '\0'; create_thread(nfi->_thread_name, netfrontif_thread, netif); #endif /* CONFIG_LWIP_NOTHREADS */ return ERR_OK; err_shutdown_netfront: if (nfi->_dev_is_private) { shutdown_netfront(nfi->dev); nfi->dev = NULL; } err_free_nfi: if (nfi->_state_is_private) { mem_free(nfi); netif->state = NULL; } err_out: return ERR_IF; }