📄 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_AUTOIP
static
#endif /* LWIP_AUTOIP */
err_t
etharp_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_t
etharp_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_t
ethernet_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 + -