因为权限原因,直接附上链接,供自己和其他人学习
2.lwip---(五)以太网数据接收_cycy小陈的博客-CSDN博客_lwip接收数据
这里只做简单的记录,供以后自己回忆起来用,如有错误欢迎指正。
1.两个设备数据收发都是有地址才能准确收发(否则就是广播了),MAC地址就是两个以太网设备的通信地址。
2.以太网帧格式简介:
3.网络协议的分层模型
对应以太网帧的关系
4.基于lwip的mac层通信
1 err_t
2 ethernet_input(struct pbuf *p, struct netif *netif)
3 {
4 struct eth_hdr *ethhdr;
5 u16_t type;
6
7 #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6
8
9 u16_t next_hdr_offset = SIZEOF_ETH_HDR;
10
11 #endif
12
13 LWIP_ASSERT_CORE_LOCKED();
14
15 //校验数据长度
16 if (p->len <= SIZEOF_ETH_HDR)
17 {
18 ETHARP_STATS_INC(etharp.proterr);
19 ETHARP_STATS_INC(etharp.drop);
20 MIB2_STATS_NETIF_INC(netif, ifinerrors);
21 goto free_and_return;
22 }
23
24 if (p->if_idx == NETIF_NO_INDEX)
25 {
26 p->if_idx = netif_get_index(netif);
27 }
28
29 /* ethhdr指针指向以太网帧头部,并且强制转换成eth_hdr结构 */
30 ethhdr = (struct eth_hdr *)p->payload; (1)
31
32 type = ethhdr->type;
33
34 if (ethhdr->dest.addr[0] & 1)
35 {
36 /* 这可能是多播或广播数据包 */
37 if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0)
38 {
39 if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) &&
40 (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2))
41 {
42 /* 将pbuf标记为链路层多播 */
43 p->flags |= PBUF_FLAG_LLMCAST; (2)
44 }
45 }
46
47 else if (eth_addr_cmp(ðhdr->dest, ðbroadcast))
48 {
49 /* 将pbuf标记为链路层广播 */
50 p->flags |= PBUF_FLAG_LLBCAST; (3)
51 }
52 }
53
54 switch (type)
55 {
56 /* 如果是IP数据报 */
57 case PP_HTONS(ETHTYPE_IP):
58 if (!(netif->flags & NETIF_FLAG_ETHARP))
59 {
60 goto free_and_return;
61 }
62 /* 跳过以太网首部 */
63 if (pbuf_remove_header(p, next_hdr_offset)) (4)
64 {
65 goto free_and_return;
66 }
67 else
68 {
69 /* 传递到IP协议去处理 */
70 ip4_input(p, netif); (5)
71 }
72 break;
73
74 //对于是ARP包
75 case PP_HTONS(ETHTYPE_ARP):
76 if (!(netif->flags & NETIF_FLAG_ETHARP))
77 {
78 goto free_and_return;
79 }
80 /* 跳过以太网首部 */
81 if (pbuf_remove_header(p, next_hdr_offset)) (6)
82 {
83 ETHARP_STATS_INC(etharp.lenerr);
84 ETHARP_STATS_INC(etharp.drop);
85 goto free_and_return;
86 }
87 else
88 {
89 /*传递到ARP协议处理 */
90 etharp_input(p, netif); (7)
91 }
92 break;
93
94 //如果支持PPPOE
95 #if PPPOE_SUPPORT
96 case PP_HTONS(ETHTYPE_PPPOEDISC):
97 pppoe_disc_input(netif, p);
98 break;
99
100 case PP_HTONS(ETHTYPE_PPPOE):
101 pppoe_data_input(netif, p);
102 break;
103 #endif /* PPPOE_SUPPORT */
104
105 //如果支持ipv6
106 #if LWIP_IPV6
107 case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */
108 /* skip Ethernet header */
109 if ((p->len < next_hdr_offset) ||
110 pbuf_remove_header(p, next_hdr_offset))
111 {
112 goto free_and_return;
113 }
114 else
115 {
116 /* pass to IPv6 layer */
117 ip6_input(p, netif);
118 }
119 break;
120 #endif /* LWIP_IPV6 */
121
122 default:
123 #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
124 if (LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK)
125 {
126 break;
127 }
128 #endif
129 ETHARP_STATS_INC(etharp.proterr);
130 ETHARP_STATS_INC(etharp.drop);
131 MIB2_STATS_NETIF_INC(netif, ifinunknownprotos);
132 goto free_and_return;
133 }
134
135 return ERR_OK;
136
137 free_and_return:
138 pbuf_free(p);
139 return ERR_OK;
140 }
以上代码为了说明功能简写了。大概流程:
1)收到一帧数据校验长度, ethhdr指针指向以太网帧头部,并且强制转换成eth_hdr结构.
2)获取数据类型(ip数据包,ARP包等),如果是自定义数据,那么就在以太网帧格式里面数据类型增加自己的协议,在判断为是自己的数据时,把整个数据包取走不再用lwip协议处理后续数据。
以上图片均来源网络,如有侵权联系我删除。