LwIP的ARP协议实现(4)

编程入门 行业动态 更新时间:2024-10-18 14:25:28

LwIP的ARP<a href=https://www.elefans.com/category/jswz/34/1771197.html style=协议实现(4)"/>

LwIP的ARP协议实现(4)

LwIP的ARP协议实现系列文章

LwIP中的ARP实现(1)之 ARP缓存表的数据结构
LwIP中的ARP实现(2)之 ARP缓存表的超时处理
LwIP中的ARP实现(3)之 发送ARP请求包
LwIP中的ARP实现(4)之 ARP数据包接收
LwIP中的ARP实现(5)之 ARP数据包发送

ARP数据包处理

以太网是有自己独立的寻址方式(MAC地址),而对于TCP/IP的上层协议(如TCP协议、IP协议),它们是以IP地址作为网络的标识,如果没有IP地址则无法进行收发数据。当数据通过网卡中接收回来的时候,LwIP内核就需要将数据进行分解,如果是IP数据报则递交给IP协议去处理,如果是ARP数据包则交由ARP协议去处理。
真正让LwIP内核去处理接收到的数据包是ethernet_input()函数。代码太多了,简单截取部分代码。

err_t
ethernet_input(struct pbuf *p, struct netif *netif)
{struct eth_hdr *ethhdr;u16_t type;LWIP_ASSERT_CORE_LOCKED();//校验数据长度if (p->len <= SIZEOF_ETH_HDR) {ETHARP_STATS_INC(etharp.proterr);ETHARP_STATS_INC(etharp.drop);MIB2_STATS_NETIF_INC(netif, ifinerrors);goto free_and_return;}if (p->if_idx == NETIF_NO_INDEX) {p->if_idx = netif_get_index(netif);}/* ethhdr指针指向以太网帧头部,并且强制转换成eth_hdr结构 */ethhdr = (struct eth_hdr *)p->payload;//获取类型type = ethhdr->type;if (ethhdr->dest.addr[0] & 1) {/*  这可能是多播或广播数据包,如果目标IP地址的第一个字节的bit0是1,那么有可能是多播或者是广播数据包,所以,还需要进行判断,如果是多播的,就将pbuf标记为链路层多播。 */if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) {if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) &&(ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) {/* 将pbuf标记为链路层多播 */p->flags |= PBUF_FLAG_LLMCAST;}}else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) {/* 将pbuf标记为链路层广播 */p->flags |= PBUF_FLAG_LLBCAST;}}switch (type) {/* 如果是IP数据报 */case PP_HTONS(ETHTYPE_IP):if (!(netif->flags & NETIF_FLAG_ETHARP)) {goto free_and_return;}/* 去掉太网首部 */if (pbuf_remove_header(p, next_hdr_offset)) {goto free_and_return;} else{/* 递交到IP层处理 */ip4_input(p, netif);}break;//对于是ARP包case PP_HTONS(ETHTYPE_ARP):if (!(netif->flags & NETIF_FLAG_ETHARP)) {goto free_and_return;}/* 去掉太网首部 */if (pbuf_remove_header(p, next_hdr_offset)) {ETHARP_STATS_INC(etharp.lenerr);ETHARP_STATS_INC(etharp.drop);goto free_and_return;} else {/* 传递到ARP协议处理 */etharp_input(p, netif);}break;default:ETHARP_STATS_INC(etharp.proterr);ETHARP_STATS_INC(etharp.drop);MIB2_STATS_NETIF_INC(netif, ifinunknownprotos);goto free_and_return;}return ERR_OK;free_and_return:pbuf_free(p);return ERR_OK;
}

ARP数据包的处理

重点来了,我们主要是讲解对收到的ARP数据包处理
ARP数据包的处理函数为etharp_input(),在这里它完成两个任务:

  1. 如果收到的是ARP应答包,说明本机之前发出的ARP请求包有了回应,就根据应答包更新自身的ARP缓存表;
  2. 如果收到的是ARP请求包,如果包中的目标IP地址与主机IP地址匹配,除了记录原主机的IP与MAC地址,更新自身的ARP表外,还要向源主机发送一个ARP应答包。但是如果如果包中目标IP地址与主机IP地址不匹配,则尽可能记录源主机的IP与MAC地址,更新自身的ARP表,并丢弃该请求包,为什么说是尽可能呢,因为主机的ARP缓存表是有限的,不可能记录太多的ARP表项,所以在有空闲的表项时才记录,如果没有空闲的表项,ARP觉得它自己已经尽力了,也记不住那么多表项。
void
etharp_input(struct pbuf *p, struct netif *netif)
{struct etharp_hdr *hdr;/* these are aligned properly, whereas the ARP header fields might not be */ip4_addr_t sipaddr, dipaddr;u8_t for_us;LWIP_ASSERT_CORE_LOCKED();LWIP_ERROR("netif != NULL", (netif != NULL), return;);hdr = (struct etharp_hdr *)p->payload;/* 判断ARP包的合法性,判断ARP包的合法性,已经类型是否为以太网、硬件地址长度是否为ETH_HWADDR_LEN、协议地址长度是否为sizeof(ip4_addr_t)以及协议是否为ARP协议,如果都满足则表示ARP包合法。 */if ((hdr->hwtype != PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET)) ||(hdr->hwlen != ETH_HWADDR_LEN) ||(hdr->protolen != sizeof(ip4_addr_t)) ||(hdr->proto != PP_HTONS(ETHTYPE_IP)))  {ETHARP_STATS_INC(etharp.proterr);ETHARP_STATS_INC(etharp.drop);pbuf_free(p);return;}ETHARP_STATS_INC(etharp.recv);//拷贝源IP地址与目标IP地址IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr);IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr);/* 看看主机网卡是否配置了IP地址 */if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {for_us = 0;} else {/* 判断ARP数据包的目标IP地址与主机IP地址是否一样 */for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif));}/* 更新ARP缓存表项 */etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);/* 更新完毕,根据包的类型处理 */switch (hdr->opcode) {/* ARP请求包 */case PP_HTONS(ARP_REQUEST):if (for_us) {/* 是请求自己的,那就要做出应答 */etharp_raw(netif,(struct eth_addr *)netif->hwaddr, &hdr->shwaddr,(struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif),&hdr->shwaddr, &sipaddr,ARP_REPLY);} /* 不是给自己的,如果不是给自己的,原因有两种,一种是网卡自身尚未配置IP地址,这样子就只打印相关调试信息。另一种是ARP包中的目标IP地址与主机IP地址不符合,也不用做出回应,直接丢弃即可,并输出相关调试信息*/else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: we are unconfigured, ARP request ignored.\n"));}else{LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP request was not for us.\n"));}break;/* 对于ARP应答包 不用处理,前面已经更新ARP表项了*/case PP_HTONS(ARP_REPLY):break;default:ETHARP_STATS_INC(etharp.err);break;}pbuf_free(p);
}

更新ARP表项

etharp_update_arp_entry()函数是用于更新ARP缓存表的,它会在收到一个ARP数据包的时候被调用,它会先查找一个ARP表项,如果没有找到这个ARP表项的记录,就会去新建一个ARP表项,然后重置ARP表项的参数(状态、网卡。IP地址与对应的MAC地址以及生存时间等),然后检测ARP表项中是否挂载数据包,如果有就将这些数据包发送出去。
表项的更新方式,动态表项有两种方式,分别为ETHARP_FLAG_TRY_HARD和ETHARP_FLAG_FIND_ONLY。前者表示无论如何都要创建一个表项,如果ARP缓存表中没有空间了,那就需要回收较老的表项,将他们删除,然后建立新的表项。而如果是后者,就让内核尽量更新表项,如果ARP缓存表中没有空间了,那么也无能为力,实在是添加不了新的表项。

static err_t
etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{s16_t i;if (ip4_addr_isany(ipaddr) ||ip4_addr_isbroadcast(ipaddr, netif) ||ip4_addr_ismulticast(ipaddr)) {return ERR_ARG;}/* 查找或者创建ARP表项,并且返回索引值 */i = etharp_find_entry(ipaddr, flags, netif);/* 如果索引值不合法,更新ARP表项失败 */if (i < 0) {return (err_t)i;}/* 设置表项状态为ETHARP_STATE_STABLE */arp_table[i].state = ETHARP_STATE_STABLE;/* 记录网卡 */arp_table[i]if = netif;/* 插入ARP索引树 */mib2_add_arp_entry(netif, &arp_table[i].ipaddr);LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", i));/* 更新缓存表中的MAC地址 */SMEMCPY(&arp_table[i].ethaddr, ethaddr, ETH_HWADDR_LEN);/* 重置生存时间 */arp_table[i].ctime = 0;/* 如果表项上与未发送的数据包,那就将这些数据包发送出去 */
#if ARP_QUEUEING		//使用队列方式while (arp_table[i].q != NULL) {struct pbuf *p;/* 定义q指向ARP表项中的数据包缓存队列 */struct etharp_q_entry *q = arp_table[i].q;/* 指向下一个数据包节点 */arp_table[i].q = q->next;/* 获取pbuf数据包 */p = q->p;/* 释放MEMP_ARP_QUEUE类型的内存块 */memp_free(MEMP_ARP_QUEUE, q);
#else if (arp_table[i].q != NULL) {struct pbuf *p = arp_table[i].q;arp_table[i].q = NULL;
#endif /* 发送缓存队列的数据包 */ethernet_output(netif, p, (struct eth_addr *)(netif->hwaddr), ethaddr, ETHTYPE_IP);/* free the queued IP packet */pbuf_free(p);}return ERR_OK;
}

欢迎关注杰杰个人公众号,一起进入物联网全栈开发~

更多推荐

LwIP的ARP协议实现(4)

本文发布于:2024-03-12 11:47:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1731438.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:协议   LwIP   ARP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!