diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c index 3092dc94..9cef3190 100644 --- a/src/core/ipv4/etharp.c +++ b/src/core/ipv4/etharp.c @@ -626,6 +626,8 @@ etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth } } +#define Swap(X,Y) do{ __typeof__ (X) _T = X; X = Y; Y = _T; }while(0) + /** * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache * send out queued IP packets. Updates cache with snooped address pairs. @@ -635,11 +637,17 @@ etharp_get_entry(size_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth * * @param p The ARP packet that arrived on netif. Is freed by this function. * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * @param header_size_document pass ethernet header size to handle both arp and ethernet headers + * here for more effective memory usage (see LWIP_ARP_REUSE_MEMORY description in opts.h) * * @see pbuf_free() */ void -etharp_input(struct pbuf *p, struct netif *netif) +etharp_input(struct pbuf *p, struct netif *netif +#if LWIP_ARP_REUSE_MEMORY +, size_t header_size_decrement +#endif /* LWIP_ARP_REUSE_MEMORY */ +) { struct etharp_hdr *hdr; /* these are aligned properly, whereas the ARP header fields might not be */ @@ -650,7 +658,11 @@ etharp_input(struct pbuf *p, struct netif *netif) LWIP_ERROR("netif != NULL", (netif != NULL), return;); +#if LWIP_ARP_REUSE_MEMORY + hdr = (struct etharp_hdr *)((u8_t *)p->payload + header_size_decrement); +#else hdr = (struct etharp_hdr *)p->payload; +#endif /* LWIP_ARP_REUSE_MEMORY */ /* RFC 826 "Packet Reception": */ if ((hdr->hwtype != PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET)) || @@ -714,11 +726,81 @@ etharp_input(struct pbuf *p, struct netif *netif) /* ARP request for our address? */ if (for_us && !from_us) { /* send ARP response */ +#if !LWIP_ARP_REUSE_MEMORY etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &hdr->shwaddr, (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), &hdr->shwaddr, &sipaddr, ARP_REPLY); +#else + struct eth_hdr *ethhdr; + u16_t eth_type_be; + + + hdr->opcode = lwip_htons(ARP_REPLY); + Swap(hdr->shwaddr, hdr->dhwaddr); + Swap(hdr->sipaddr, hdr->dipaddr); + SMEMCPY(&hdr->shwaddr, (struct eth_addr *)netif->hwaddr, ETH_HWADDR_LEN); + + + + + ethhdr = (struct eth_hdr *)p->payload; + + eth_type_be = lwip_htons(ETHTYPE_ARP); + + +#if ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP) + s32_t vlan_prio_vid; +#ifdef LWIP_HOOK_VLAN_SET + vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, ethhdr->src, ethhdr->dest, ETHTYPE_ARP); +#elif LWIP_VLAN_PCP + vlan_prio_vid = -1; + if (netif->hints && (netif->hints->tci >= 0)) { + vlan_prio_vid = (u16_t)netif->hints->tci; + } +#endif + if (vlan_prio_vid >= 0) { + struct eth_vlan_hdr *vlanhdr; + + LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF); + + 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); + } +#endif /* ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP) */ + + + LWIP_ASSERT_CORE_LOCKED(); + + ethhdr = (struct eth_hdr *)p->payload; + ethhdr->type = eth_type_be; + Swap(ethhdr->dest, ethhdr->src); +#if LWIP_AUTOIP + /* If we are using Link-Local, all ARP packets that contain a Link-Local + * 'sender IP address' MUST be sent using link-layer broadcast instead of + * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ + if (ip4_addr_islinklocal(netif_ip4_addr(netif))) { + SMEMCPY(ðhdr->src, ðbroadcast, ETH_HWADDR_LEN); + } else +#endif /* LWIP_AUTOIP */ + { + SMEMCPY(ðhdr->src, &hdr->shwaddr, ETH_HWADDR_LEN); + } + + 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)); + + netif->linkoutput(netif, p); + + + ETHARP_STATS_INC(etharp.xmit); +#endif /* !LWIP_ARP_REUSE_MEMORY */ /* we are not configured? */ } else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { /* { for_us == 0 and netif->ip_addr.addr == 0 } */ diff --git a/src/include/lwip/etharp.h b/src/include/lwip/etharp.h index 48a1d229..3896fde0 100644 --- a/src/include/lwip/etharp.h +++ b/src/include/lwip/etharp.h @@ -98,7 +98,11 @@ err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr); #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ -void etharp_input(struct pbuf *p, struct netif *netif); +void etharp_input(struct pbuf *p, struct netif *netif +#if LWIP_ARP_REUSE_MEMORY +, size_t header_size_decrement +#endif +); #ifdef __cplusplus } diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 2573285f..d25beaa2 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -731,6 +731,16 @@ #if !defined ETHARP_TABLE_MATCH_NETIF || defined __DOXYGEN__ #define ETHARP_TABLE_MATCH_NETIF !LWIP_SINGLE_NETIF #endif + +/** LWIP_ARP_REUSE_MEMORY==1: Reuse pbuf used for arp request to send an + * arp reply as described in RFC 826. + * If disabled, new pbuf will be allocated and all required data from request + * packet will be copied with SMEMCPY (better if you want to separate layers + * but worse in terms of memory usage) + */ +#if !defined LWIP_ARP_REUSE_MEMORY || defined __DOXYGEN__ +#define LWIP_ARP_REUSE_MEMORY 1 +#endif /** * @} */ diff --git a/src/netif/ethernet.c b/src/netif/ethernet.c index db5c514b..04b92af8 100644 --- a/src/netif/ethernet.c +++ b/src/netif/ethernet.c @@ -192,6 +192,7 @@ ethernet_input(struct pbuf *p, struct netif *netif) goto free_and_return; } /* skip Ethernet header (min. size checked above) */ +#if !LWIP_ARP_REUSE_MEMORY if (pbuf_remove_header(p, next_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n", @@ -204,6 +205,9 @@ ethernet_input(struct pbuf *p, struct netif *netif) /* pass p to ARP module */ etharp_input(p, netif); } +#else + etharp_input(p, netif, next_hdr_offset); +#endif /* !LWIP_ARP_REUSE_MEMORY */ break; #endif /* LWIP_IPV4 && LWIP_ARP */ #if PPPOE_SUPPORT