📄 etharp.c
字号:
((arp_table[i].state == ETHARP_STATE_PENDING) || (arp_table[i].state == ETHARP_STATE_STABLE))); /* do we have a pending entry? or an implicit query request? */ if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { /* try to resolve it; send out ARP request */ result = etharp_request(netif, ipaddr); if (result != ERR_OK) { /* ARP request couldn't be sent */ /* We don't re-send arp request in etharp_tmr, but we still queue packets, since this failure could be temporary, and the next packet calling etharp_query again could lead to sending the queued packets. */ } if (q == NULL) { return result; } } /* packet given? */ LWIP_ASSERT("q != NULL", q != NULL); /* stable entry? */ if (arp_table[i].state == ETHARP_STATE_STABLE) { /* we have a valid IP->Ethernet address mapping */ ETHARP_SET_HINT(netif, i); /* send the packet */ result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); /* pending entry? (either just created or already pending */ } else if (arp_table[i].state == ETHARP_STATE_PENDING) { /* entry is still pending, queue the given packet 'q' */ struct pbuf *p; int copy_needed = 0; /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but * to copy the whole queue into a new PBUF_RAM (see bug #11400) * PBUF_ROMs can be left as they are, since ROM must not get changed. */ p = q; while (p) { LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); if(p->type != PBUF_ROM) { copy_needed = 1; break; } p = p->next; } if(copy_needed) { /* copy the whole packet into new pbufs */ p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if(p != NULL) { if (pbuf_copy(p, q) != ERR_OK) { pbuf_free(p); p = NULL; } } } else { /* referencing the old pbuf is enough */ p = q; pbuf_ref(p); } /* packet could be taken over? */ if (p != NULL) { /* queue packet ... */#if ARP_QUEUEING struct etharp_q_entry *new_entry; /* allocate a new arp queue entry */ new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); if (new_entry != NULL) { new_entry->next = 0; new_entry->p = p; if(arp_table[i].q != NULL) { /* queue was already existent, append the new entry to the end */ struct etharp_q_entry *r; r = arp_table[i].q; while (r->next != NULL) { r = r->next; } r->next = new_entry; } else { /* queue did not exist, first item in queue */ arp_table[i].q = new_entry; } LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); result = ERR_OK; } else { /* the pool MEMP_ARP_QUEUE is empty */ pbuf_free(p); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); result = ERR_MEM; }#else /* ARP_QUEUEING */ /* always queue one packet per ARP request only, freeing a previously queued packet */ if (arp_table[i].q != NULL) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); pbuf_free(arp_table[i].q); } arp_table[i].q = p; result = ERR_OK; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));#endif /* ARP_QUEUEING */ } else { ETHARP_STATS_INC(etharp.memerr); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); result = ERR_MEM; } } return result;}/** * Send a raw ARP packet (opcode and all addresses can be modified) * * @param netif the lwip network interface on which to send the ARP packet * @param ethsrc_addr the source MAC address for the ethernet header * @param ethdst_addr the destination MAC address for the ethernet header * @param hwsrc_addr the source MAC address for the ARP protocol header * @param ipsrc_addr the source IP address for the ARP protocol header * @param hwdst_addr the destination MAC address for the ARP protocol header * @param ipdst_addr the destination IP address for the ARP protocol header * @param opcode the type of the ARP packet * @return ERR_OK if the ARP packet has been sent * ERR_MEM if the ARP packet couldn't be allocated * any other err_t on failure */#if !LWIP_AUTOIPstatic#endif /* LWIP_AUTOIP */err_tetharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, const u16_t opcode){ struct pbuf *p; err_t result = ERR_OK; struct eth_hdr *ethhdr; struct etharp_hdr *hdr;#if LWIP_AUTOIP const u8_t * ethdst_hwaddr;#endif /* LWIP_AUTOIP */ /* allocate a pbuf for the outgoing ARP request packet */ p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM); /* could allocate a pbuf for an ARP request? */ if (p == NULL) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("etharp_raw: could not allocate pbuf for ARP request.\n")); ETHARP_STATS_INC(etharp.memerr); return ERR_MEM; } LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", (p->len >= SIZEOF_ETHARP_PACKET)); ethhdr = (struct eth_hdr *)p->payload; hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); hdr->opcode = htons(opcode); LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN));#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) */ ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;#endif /* LWIP_AUTOIP */ /* Write the ARP MAC-Addresses */ ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); /* Write the Ethernet MAC-Addresses */#if LWIP_AUTOIP ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr);#else /* LWIP_AUTOIP */ ETHADDR16_COPY(ðhdr->dest, ethdst_addr);#endif /* LWIP_AUTOIP */ ETHADDR16_COPY(ðhdr->src, ethsrc_addr); /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing. */ IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); hdr->proto = PP_HTONS(ETHTYPE_IP); /* set hwlen and protolen */ hdr->hwlen = ETHARP_HWADDR_LEN; hdr->protolen = sizeof(ip_addr_t); ethhdr->type = PP_HTONS(ETHTYPE_ARP); /* send ARP query */ result = netif->linkoutput(netif, p); ETHARP_STATS_INC(etharp.xmit); /* free ARP query packet */ pbuf_free(p); p = NULL; /* could not allocate pbuf for ARP request */ return result;}/** * Send an ARP request packet asking for ipaddr. * * @param netif the lwip network interface on which to send the request * @param ipaddr the IP address for which to ask * @return ERR_OK if the request has been sent * ERR_MEM if the ARP packet couldn't be allocated * any other err_t on failure */err_tetharp_request(struct netif *netif, ip_addr_t *ipaddr){ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, ipaddr, ARP_REQUEST);}#endif /* LWIP_ARP *//** * 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. * * @param p the recevied packet, p->payload pointing to the ethernet header * @param netif the network interface on which the packet was received */err_tethernet_input(struct pbuf *p, struct netif *netif){ struct eth_hdr* ethhdr; u16_t type; s16_t ip_hdr_offset = SIZEOF_ETH_HDR; 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); 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], (unsigned)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); goto free_and_return; }#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */ if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { /* silently ignore this packet: not for our VLAN */ pbuf_free(p); return ERR_OK; }#endif /* ETHARP_VLAN_CHECK */ 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, htons(type));#endif /* LWIP_ARP_FILTER_NETIF*/ switch (type) {#if LWIP_ARP /* IP packet? */ case PP_HTONS(ETHTYPE_IP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; }#if ETHARP_TRUST_IP_MAC /* update ARP table */ etharp_ip_input(netif, p);#endif /* ETHARP_TRUST_IP_MAC */ /* skip Ethernet header */ if(pbuf_header(p, -ip_hdr_offset)) { LWIP_ASSERT("Can't move over header in packet", 0); goto free_and_return; } else { /* pass to IP layer */ ip_input(p, netif); } break; case PP_HTONS(ETHTYPE_ARP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* pass p to ARP module */ etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); break;#endif /* 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 */ default: ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); 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;}#endif /* LWIP_ARP || LWIP_ETHERNET */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -