7.7 接收以太网数据帧以太网链路层收包使用ethernet_input()
函数 。
该函数主要是根据以太网帧首部的类型字段,把包分发到不同的协议处理 。
IP数据包丢到:ip_input()
ARP数据包丢到:etharp_input()
/** * @ingroup lwip_nosys * 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.<br> * Don't call directly, pass to netif_add() and call netif->input(). * * @param p the received packet, p->payload pointing to the ethernet header * @param netif the network interface on which the packet was received * * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL * @see ETHARP_SUPPORT_VLAN * @see LWIP_HOOK_VLAN_CHECK */err_tethernet_input(struct pbuf *p, struct netif *netif){struct eth_hdr *ethhdr;u16_t type;#if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6u16_t next_hdr_offset = SIZEOF_ETH_HDR;#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */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;}/* 找到以太网首部字段 */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 char)ethhdr->dest.addr[0], (unsigned char)ethhdr->dest.addr[1], (unsigned char)ethhdr->dest.addr[2],(unsigned char)ethhdr->dest.addr[3], (unsigned char)ethhdr->dest.addr[4], (unsigned char)ethhdr->dest.addr[5],(unsigned char)ethhdr->src.addr[0],(unsigned char)ethhdr->src.addr[1],(unsigned char)ethhdr->src.addr[2],(unsigned char)ethhdr->src.addr[3],(unsigned char)ethhdr->src.addr[4],(unsigned char)ethhdr->src.addr[5],lwip_htons(ethhdr->type)));type = ethhdr->type;#if ETHARP_SUPPORT_VLANif (type == PP_HTONS(ETHTYPE_VLAN)) {struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr *)(((char *)ethhdr) + SIZEOF_ETH_HDR);next_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; /* 找到下一个协议层的首部 。这里就是以太网帧首部长度 */if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {/* 只有ethernet/vlan报头(或更少)的数据包,不处理 */ETHARP_STATS_INC(etharp.proterr);ETHARP_STATS_INC(etharp.drop);MIB2_STATS_NETIF_INC(netif, ifinerrors);goto free_and_return;}#if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */#ifdef LWIP_HOOK_VLAN_CHECKif (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { /* 优先使用VLAN钩子函数的过滤 */#elif defined(ETHARP_VLAN_CHECK_FN)if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { /* ETHARP_VLAN_CHECK_FN函数的过滤 */#elif defined(ETHARP_VLAN_CHECK)if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { /* 指定接收一个VLAN */#endif/* 静默忽略此报文:不是我们需要的VLAN */pbuf_free(p);return ERR_OK;}#endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */type = vlan->tpid; /* 这个字段其实就是以太网首部的协议类型字段 */}#endif /* ETHARP_SUPPORT_VLAN */#if LWIP_ARP_FILTER_NETIFnetif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); /* 一个硬件映射多个IP 。找到对应的netif */#endif /* LWIP_ARP_FILTER_NETIF*/if (p->if_idx == NETIF_NO_INDEX) {/* pbuf标记对应netif标识 */p->if_idx = netif_get_index(netif);}if (ethhdr->dest.addr[0] & 1) { /* 目标MAC分析,首个bit为1,说明是非单播包 *//* 多播或者广播包 */if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { /* 0x01 */#if LWIP_IPV4if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && /* 0x00 */(ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { /* 0x5e *//* 01-00-5e-开头的为IPV4链路层组播包:将pbuf标记为链路层组播 */p->flags |= PBUF_FLAG_LLMCAST;}#endif /* LWIP_IPV4 */}#if LWIP_IPV6else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && /* 0x33 */(ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { /* 0x33 *//* 33-33-开头的为IPV6链路层组播包:将pbuf标记为链路层组播 */p->flags |= PBUF_FLAG_LLMCAST;}#endif /* LWIP_IPV6 */else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) {/* FF:FF:FF:FF:FF:FF *//* 将pbuf标记为链路层广播 */p->flags |= PBUF_FLAG_LLBCAST;}}switch (type) { /* 以太网帧协议类型字段处理 */#if LWIP_IPV4 && LWIP_ARPcase PP_HTONS(ETHTYPE_IP): /* IPv4数据包 */if (!(netif->flags & NETIF_FLAG_ETHARP)) {/* 如果对应的netif不是以太网设备,那当前数据包不能流入这个netif */goto free_and_return;}/* 链路层处理完毕,pbuf数据区指向跳过以太网首部,指向以太网帧数据字段,然后递交给网络层处理 */if (pbuf_remove_header(p, next_hdr_offset)) {LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,("ethernet_input: IPv4 packet dropped, too short (%"U16_F"/%"U16_F")\n",p->tot_len, next_hdr_offset));LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));goto free_and_return;} else {/* 转交给ipv4模块处理 */ip4_input(p, netif);}break;case PP_HTONS(ETHTYPE_ARP): /* ARP数据包 */if (!(netif->flags & NETIF_FLAG_ETHARP)) {/* 如果对应的netif不是以太网设备,那当前数据包不能流入这个netif */goto free_and_return;}/* 链路层处理完毕,pbuf数据区指向跳过以太网首部,指向以太网帧数据字段,然后递交给网络层处理 */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",p->tot_len, next_hdr_offset));LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));ETHARP_STATS_INC(etharp.lenerr);ETHARP_STATS_INC(etharp.drop);goto free_and_return;} else {/* 转交给ARP模块处理 */etharp_input(p, netif);}break;#endif /* LWIP_IPV4 && LWIP_ARP */#if PPPOE_SUPPORTcase PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP以太网上发现阶段的数据包 *//* 转交给PPP分析并处理发现阶段的数据包 */pppoe_disc_input(netif, p);break;case PP_HTONS(ETHTYPE_PPPOE): /* PPP以太网上会话阶段的数据包 *//* 转交给PPP分析并处理会话节点的数据包 */pppoe_data_input(netif, p);break;#endif /* PPPOE_SUPPORT */#if LWIP_IPV6case PP_HTONS(ETHTYPE_IPV6): /* IPv6数据包 *//* 链路层处理完毕,pbuf数据区指向跳过以太网首部,指向以太网帧数据字段,然后递交给网络层处理 */if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) {LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,("ethernet_input: IPv6 packet dropped, too short (%"U16_F"/%"U16_F")\n",p->tot_len, next_hdr_offset));goto free_and_return;} else {/* 转交给IPV6模块处理 */ip6_input(p, netif);}break;#endif /* LWIP_IPV6 */default:#ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOLif (LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) { /* 其它协议的以太网帧,可用钩子函数处理 */break; /* 是用户需要的以太网数据帧 */}#endifETHARP_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; /* 以太网数据帧无效,丢弃这个数据包 */}
经验总结扩展阅读
- 梅花北服务区在哪个省
- 西瓜汁弄到衣服上能洗掉吗
- 埃菲尔铁塔和胡夫金字塔谁高
- 白茶有哪些品种 中国白茶五大知名品种排行榜
- 硫磺皂可以洗头发吗
- 新鲜香菇怎样算变质
- 一个泡芙的热量等于几碗饭
- 晚立秋热死牛有科学依据吗
- 卧鸡蛋怎么才能不飞
- 金铲铲之战黯灵龙技能是什么