BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * Ethernet common functions |
||
4 | * |
||
5 | * @defgroup ethernet Ethernet |
||
6 | * @ingroup callbackstyle_api |
||
7 | */ |
||
8 | |||
9 | /* |
||
10 | * Copyright (c) 2001-2003 Swedish Institute of Computer Science. |
||
11 | * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv> |
||
12 | * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. |
||
13 | * All rights reserved. |
||
14 | * |
||
15 | * Redistribution and use in source and binary forms, with or without modification, |
||
16 | * are permitted provided that the following conditions are met: |
||
17 | * |
||
18 | * 1. Redistributions of source code must retain the above copyright notice, |
||
19 | * this list of conditions and the following disclaimer. |
||
20 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
21 | * this list of conditions and the following disclaimer in the documentation |
||
22 | * and/or other materials provided with the distribution. |
||
23 | * 3. The name of the author may not be used to endorse or promote products |
||
24 | * derived from this software without specific prior written permission. |
||
25 | * |
||
26 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
27 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
28 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
29 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
30 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
31 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
34 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
35 | * OF SUCH DAMAGE. |
||
36 | * |
||
37 | * This file is part of the lwIP TCP/IP stack. |
||
38 | * |
||
39 | */ |
||
40 | |||
41 | #include "lwip/opt.h" |
||
42 | |||
43 | #if LWIP_ARP || LWIP_ETHERNET |
||
44 | |||
45 | #include "netif/ethernet.h" |
||
46 | #include "lwip/def.h" |
||
47 | #include "lwip/stats.h" |
||
48 | #include "lwip/etharp.h" |
||
49 | #include "lwip/ip.h" |
||
50 | #include "lwip/snmp.h" |
||
51 | |||
52 | #include <string.h> |
||
53 | |||
54 | #include "netif/ppp/ppp_opts.h" |
||
55 | #if PPPOE_SUPPORT |
||
56 | #include "netif/ppp/pppoe.h" |
||
57 | #endif /* PPPOE_SUPPORT */ |
||
58 | |||
59 | #ifdef LWIP_HOOK_FILENAME |
||
60 | #include LWIP_HOOK_FILENAME |
||
61 | #endif |
||
62 | |||
63 | const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; |
||
64 | const struct eth_addr ethzero = {{0,0,0,0,0,0}}; |
||
65 | |||
66 | /** |
||
67 | * @ingroup lwip_nosys |
||
68 | * Process received ethernet frames. Using this function instead of directly |
||
69 | * calling ip_input and passing ARP frames through etharp in ethernetif_input, |
||
70 | * the ARP cache is protected from concurrent access.\n |
||
71 | * Don't call directly, pass to netif_add() and call netif->input(). |
||
72 | * |
||
73 | * @param p the received packet, p->payload pointing to the ethernet header |
||
74 | * @param netif the network interface on which the packet was received |
||
75 | * |
||
76 | * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL |
||
77 | * @see ETHARP_SUPPORT_VLAN |
||
78 | * @see LWIP_HOOK_VLAN_CHECK |
||
79 | */ |
||
80 | err_t |
||
81 | ethernet_input(struct pbuf *p, struct netif *netif) |
||
82 | { |
||
83 | struct eth_hdr* ethhdr; |
||
84 | u16_t type; |
||
85 | #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6 |
||
86 | u16_t next_hdr_offset = SIZEOF_ETH_HDR; |
||
87 | #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ |
||
88 | |||
89 | if (p->len <= SIZEOF_ETH_HDR) { |
||
90 | /* a packet with only an ethernet header (or less) is not valid for us */ |
||
91 | ETHARP_STATS_INC(etharp.proterr); |
||
92 | ETHARP_STATS_INC(etharp.drop); |
||
93 | MIB2_STATS_NETIF_INC(netif, ifinerrors); |
||
94 | goto free_and_return; |
||
95 | } |
||
96 | |||
97 | if (p->if_idx == NETIF_NO_INDEX) { |
||
98 | p->if_idx = netif_get_index(netif); |
||
99 | } |
||
100 | |||
101 | /* points to packet payload, which starts with an Ethernet header */ |
||
102 | ethhdr = (struct eth_hdr *)p->payload; |
||
103 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, |
||
104 | ("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", |
||
105 | (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], |
||
106 | (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], |
||
107 | (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], |
||
108 | (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], |
||
109 | lwip_htons(ethhdr->type))); |
||
110 | |||
111 | type = ethhdr->type; |
||
112 | #if ETHARP_SUPPORT_VLAN |
||
113 | if (type == PP_HTONS(ETHTYPE_VLAN)) { |
||
114 | struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); |
||
115 | if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { |
||
116 | /* a packet with only an ethernet/vlan header (or less) is not valid for us */ |
||
117 | ETHARP_STATS_INC(etharp.proterr); |
||
118 | ETHARP_STATS_INC(etharp.drop); |
||
119 | MIB2_STATS_NETIF_INC(netif, ifinerrors); |
||
120 | goto free_and_return; |
||
121 | } |
||
122 | #if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ |
||
123 | #ifdef LWIP_HOOK_VLAN_CHECK |
||
124 | if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { |
||
125 | #elif defined(ETHARP_VLAN_CHECK_FN) |
||
126 | if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { |
||
127 | #elif defined(ETHARP_VLAN_CHECK) |
||
128 | if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { |
||
129 | #endif |
||
130 | /* silently ignore this packet: not for our VLAN */ |
||
131 | pbuf_free(p); |
||
132 | return ERR_OK; |
||
133 | } |
||
134 | #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ |
||
135 | type = vlan->tpid; |
||
136 | next_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; |
||
137 | } |
||
138 | #endif /* ETHARP_SUPPORT_VLAN */ |
||
139 | |||
140 | #if LWIP_ARP_FILTER_NETIF |
||
141 | netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); |
||
142 | #endif /* LWIP_ARP_FILTER_NETIF*/ |
||
143 | |||
144 | if (ethhdr->dest.addr[0] & 1) { |
||
145 | /* this might be a multicast or broadcast packet */ |
||
146 | if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { |
||
147 | #if LWIP_IPV4 |
||
148 | if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && |
||
149 | (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { |
||
150 | /* mark the pbuf as link-layer multicast */ |
||
151 | p->flags |= PBUF_FLAG_LLMCAST; |
||
152 | } |
||
153 | #endif /* LWIP_IPV4 */ |
||
154 | } |
||
155 | #if LWIP_IPV6 |
||
156 | else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && |
||
157 | (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { |
||
158 | /* mark the pbuf as link-layer multicast */ |
||
159 | p->flags |= PBUF_FLAG_LLMCAST; |
||
160 | } |
||
161 | #endif /* LWIP_IPV6 */ |
||
162 | else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { |
||
163 | /* mark the pbuf as link-layer broadcast */ |
||
164 | p->flags |= PBUF_FLAG_LLBCAST; |
||
165 | } |
||
166 | } |
||
167 | |||
168 | switch (type) { |
||
169 | #if LWIP_IPV4 && LWIP_ARP |
||
170 | /* IP packet? */ |
||
171 | case PP_HTONS(ETHTYPE_IP): |
||
172 | if (!(netif->flags & NETIF_FLAG_ETHARP)) { |
||
173 | goto free_and_return; |
||
174 | } |
||
175 | /* skip Ethernet header */ |
||
176 | if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) { |
||
177 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, |
||
178 | ("ethernet_input: IPv4 packet dropped, too short (%"U16_F"/%"U16_F")\n", |
||
179 | p->tot_len, next_hdr_offset)); |
||
180 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); |
||
181 | goto free_and_return; |
||
182 | } else { |
||
183 | /* pass to IP layer */ |
||
184 | ip4_input(p, netif); |
||
185 | } |
||
186 | break; |
||
187 | |||
188 | case PP_HTONS(ETHTYPE_ARP): |
||
189 | if (!(netif->flags & NETIF_FLAG_ETHARP)) { |
||
190 | goto free_and_return; |
||
191 | } |
||
192 | /* skip Ethernet header */ |
||
193 | if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) { |
||
194 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, |
||
195 | ("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n", |
||
196 | p->tot_len, next_hdr_offset)); |
||
197 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); |
||
198 | ETHARP_STATS_INC(etharp.lenerr); |
||
199 | ETHARP_STATS_INC(etharp.drop); |
||
200 | goto free_and_return; |
||
201 | } else { |
||
202 | /* pass p to ARP module */ |
||
203 | etharp_input(p, netif); |
||
204 | } |
||
205 | break; |
||
206 | #endif /* LWIP_IPV4 && LWIP_ARP */ |
||
207 | #if PPPOE_SUPPORT |
||
208 | case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ |
||
209 | pppoe_disc_input(netif, p); |
||
210 | break; |
||
211 | |||
212 | case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ |
||
213 | pppoe_data_input(netif, p); |
||
214 | break; |
||
215 | #endif /* PPPOE_SUPPORT */ |
||
216 | |||
217 | #if LWIP_IPV6 |
||
218 | case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ |
||
219 | /* skip Ethernet header */ |
||
220 | if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) { |
||
221 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, |
||
222 | ("ethernet_input: IPv6 packet dropped, too short (%"U16_F"/%"U16_F")\n", |
||
223 | p->tot_len, next_hdr_offset)); |
||
224 | goto free_and_return; |
||
225 | } else { |
||
226 | /* pass to IPv6 layer */ |
||
227 | ip6_input(p, netif); |
||
228 | } |
||
229 | break; |
||
230 | #endif /* LWIP_IPV6 */ |
||
231 | |||
232 | default: |
||
233 | #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL |
||
234 | if(LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) { |
||
235 | break; |
||
236 | } |
||
237 | #endif |
||
238 | ETHARP_STATS_INC(etharp.proterr); |
||
239 | ETHARP_STATS_INC(etharp.drop); |
||
240 | MIB2_STATS_NETIF_INC(netif, ifinunknownprotos); |
||
241 | goto free_and_return; |
||
242 | } |
||
243 | |||
244 | /* This means the pbuf is freed or consumed, |
||
245 | so the caller doesn't have to free it again */ |
||
246 | return ERR_OK; |
||
247 | |||
248 | free_and_return: |
||
249 | pbuf_free(p); |
||
250 | return ERR_OK; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * @ingroup ethernet |
||
255 | * Send an ethernet packet on the network using netif->linkoutput(). |
||
256 | * The ethernet header is filled in before sending. |
||
257 | * |
||
258 | * @see LWIP_HOOK_VLAN_SET |
||
259 | * |
||
260 | * @param netif the lwIP network interface on which to send the packet |
||
261 | * @param p the packet to send. pbuf layer must be @ref PBUF_LINK. |
||
262 | * @param src the source MAC address to be copied into the ethernet header |
||
263 | * @param dst the destination MAC address to be copied into the ethernet header |
||
264 | * @param eth_type ethernet type (@ref eth_type) |
||
265 | * @return ERR_OK if the packet was sent, any other err_t on failure |
||
266 | */ |
||
267 | err_t |
||
268 | ethernet_output(struct netif* netif, struct pbuf* p, |
||
269 | const struct eth_addr* src, const struct eth_addr* dst, |
||
270 | u16_t eth_type) |
||
271 | { |
||
272 | struct eth_hdr* ethhdr; |
||
273 | u16_t eth_type_be = lwip_htons(eth_type); |
||
274 | |||
275 | #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) |
||
276 | s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); |
||
277 | if (vlan_prio_vid >= 0) { |
||
278 | struct eth_vlan_hdr* vlanhdr; |
||
279 | |||
280 | LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF); |
||
281 | |||
282 | if (pbuf_add_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) { |
||
283 | goto pbuf_header_failed; |
||
284 | } |
||
285 | vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)p->payload) + SIZEOF_ETH_HDR); |
||
286 | vlanhdr->tpid = eth_type_be; |
||
287 | vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid); |
||
288 | |||
289 | eth_type_be = PP_HTONS(ETHTYPE_VLAN); |
||
290 | } else |
||
291 | #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ |
||
292 | { |
||
293 | if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) { |
||
294 | goto pbuf_header_failed; |
||
295 | } |
||
296 | } |
||
297 | |||
298 | ethhdr = (struct eth_hdr*)p->payload; |
||
299 | ethhdr->type = eth_type_be; |
||
300 | SMEMCPY(ðhdr->dest, dst, ETH_HWADDR_LEN); |
||
301 | SMEMCPY(ðhdr->src, src, ETH_HWADDR_LEN); |
||
302 | |||
303 | LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!", |
||
304 | (netif->hwaddr_len == ETH_HWADDR_LEN)); |
||
305 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, |
||
306 | ("ethernet_output: sending packet %p\n", (void *)p)); |
||
307 | |||
308 | /* send the packet */ |
||
309 | return netif->linkoutput(netif, p); |
||
310 | |||
311 | pbuf_header_failed: |
||
312 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, |
||
313 | ("ethernet_output: could not allocate room for header.\n")); |
||
314 | LINK_STATS_INC(link.lenerr); |
||
315 | return ERR_BUF; |
||
316 | } |
||
317 | |||
318 | #endif /* LWIP_ARP || LWIP_ETHERNET */ |