发送ARP请求包
发送ARP请求包的时候,需要填充已知的目标IP地址、源MAC地址、源IP地址等,并且需要该ARP包进行广播出去,所以以太网首部的目标MAC地址为FF-FF-FF-FF-FF-FF。
LwIP先调用etharp_request()函数进行发送ARP请求包,在etharp_request()函数中会调用etharp_request_dst()函数进行发送,此时指定的目标MAC地址是ethbroadcast,而在etharp_request_dst()函数中会调用etharp_raw()进行发送ARP请求包,层层调用,并且每层的参数都是越来越多的,这样子封装对于上层程序来说更加好处理,在etharp_raw()函数中,会对ARP数据包进行封装,然后再封装到以太网数据帧中,最终调用以太网底层发送函数进行将以太网数据帧发送出去。
LwIP的实现函数是etharp_raw()。
/* --------------------------------------------------------------------------------------------- */
err_t
etharp_request(struct netif *netif, const ip4_addr_t *ipaddr)
{
return etharp_request_dst(netif, ipaddr, ðbroadcast);
}
/* --------------------------------------------------------------------------------------------- */
const struct eth_addr ethbroadcast = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; //FF-FF-FF-FF-FF-FF
const struct eth_addr ethzero = {{0, 0, 0, 0, 0, 0}}; //00-00-00-00-00-00
static err_t
etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr *hw_dst_addr)
{
return etharp_raw(netif,
(struct eth_addr *)netif->hwaddr,
hw_dst_addr,
(struct eth_addr *)netif->hwaddr,
netif_ip4_addr(netif),
ðzero,
ipaddr,
ARP_REQUEST);
}
/* --------------------------------------------------------------------------------------------- */
* @param netif 用于发送ARP数据包的lwip网络接口
* @param ethsrc_addr 以太网头的源MAC地址
* @param ethdst_addr 以太网头的目标MAC地址
* @param hwsrc_addr ARP协议头的源MAC地址
* @param ipsrc_addr ARP协议头的源IP地址
* @param hwdst_addr ARP协议头的目标MAC地址
* @param ipdst_addr ARP协议头的目标IP地址
* @param opcode ARP数据包的类型
* @return ERR_OK 如果已发送ARP数据包
* 如果无法分配ARP数据包,则为ERR_MEM
static 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 ip4_addr_t *ipsrc_addr,
const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr,
const u16_t opcode)
{
struct pbuf *p;
err_t result = ERR_OK;
struct etharp_hdr *hdr;
LWIP_ASSERT("netif != NULL", netif != NULL);
/* 申请ARP报文的内存空间 */
p = pbuf_alloc(PBUF_LINK, SIZEOF_ETHARP_HDR, PBUF_RAM);
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_HDR));
hdr = (struct etharp_hdr *)p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
hdr->opcode = lwip_htons(opcode);
LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!",
(netif->hwaddr_len == ETH_HWADDR_LEN));
/* 填写源MAC地址与目标MAC地址 */
SMEMCPY(&hdr->shwaddr, hwsrc_addr, ETH_HWADDR_LEN);
SMEMCPY(&hdr->dhwaddr, hwdst_addr, ETH_HWADDR_LEN);
/* 以太网首部源ip地址与目标ip地址 */
IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->sipaddr, ipsrc_addr);
IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->dipaddr, ipdst_addr);
//填写ARP首部硬件类型与协议类型
hdr->hwtype = PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET);
hdr->proto = PP_HTONS(ETHTYPE_IP);
/* 填写ARP数据包硬件地址长度与协议地址长度 */
hdr->hwlen = ETH_HWADDR_LEN;
hdr->protolen = sizeof(ip4_addr_t);
/* 发送请求包 */
#if LWIP_AUTOIP
if (ip4_addr_islinklocal(ipsrc_addr))
{
ethernet_output(netif, p, ethsrc_addr, ðbroadcast, ETHTYPE_ARP);
}
else
#endif /* LWIP_AUTOIP */
{
ethernet_output(netif, p, ethsrc_addr, ethdst_addr, ETHTYPE_ARP);
}
ETHARP_STATS_INC(etharp.xmit);
/* 释放内存 */
pbuf_free(p);
p = NULL;
return result;
}