• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "lwip/raw.h"
52 #if LWIP_USE_L2_METRICS
53 #include "lwip/link_quality.h"
54 #endif
55 #include <string.h>
56 
57 #ifdef LWIP_HOOK_FILENAME
58 #include LWIP_HOOK_FILENAME
59 #endif
60 
61 #define MAC_MUTLTICAST            1
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 #if PF_PKT_SUPPORT
67 extern struct raw_pcb *pkt_raw_pcbs;
68 #endif
69 
70 /**
71  * @ingroup lwip_nosys
72  * Process received ethernet frames. Using this function instead of directly
73  * calling ip_input and passing ARP frames through etharp in ethernetif_input,
74  * the ARP cache is protected from concurrent access.\n
75  * Don't call directly, pass to netif_add() and call netif->input().
76  *
77  * @param p the received packet, p->payload pointing to the ethernet header
78  * @param netif the network interface on which the packet was received
79  *
80  * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
81  * @see ETHARP_SUPPORT_VLAN
82  * @see LWIP_HOOK_VLAN_CHECK
83  */
84 err_t
ethernet_input(struct pbuf * p,struct netif * netif)85 ethernet_input(struct pbuf *p, struct netif *netif)
86 {
87   struct eth_hdr *ethhdr;
88   u16_t type;
89 #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6
90   u16_t next_hdr_offset = SIZEOF_ETH_HDR;
91 #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */
92   u8_t is_otherhost = 0;
93   LWIP_ASSERT_CORE_LOCKED();
94 
95   if (p->len <= SIZEOF_ETH_HDR) {
96     /* a packet with only an ethernet header (or less) is not valid for us */
97     ETHARP_STATS_INC(etharp.proterr);
98     ETHARP_STATS_INC(etharp.drop);
99     MIB2_STATS_NETIF_INC(netif, ifinerrors);
100     goto free_and_return;
101   }
102 
103   if (p->if_idx == NETIF_NO_INDEX) {
104     p->if_idx = netif_get_index(netif);
105   }
106 
107   /* points to packet payload, which starts with an Ethernet header */
108   ethhdr = (struct eth_hdr *)p->payload;
109   LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
110               ("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",
111                (unsigned char)ethhdr->dest.addr[0], (unsigned char)ethhdr->dest.addr[1], (unsigned char)ethhdr->dest.addr[2],
112                (unsigned char)ethhdr->dest.addr[3], (unsigned char)ethhdr->dest.addr[4], (unsigned char)ethhdr->dest.addr[5],
113                (unsigned char)ethhdr->src.addr[0],  (unsigned char)ethhdr->src.addr[1],  (unsigned char)ethhdr->src.addr[2],
114                (unsigned char)ethhdr->src.addr[3],  (unsigned char)ethhdr->src.addr[4],  (unsigned char)ethhdr->src.addr[5],
115                lwip_htons(ethhdr->type)));
116 
117   if (ethhdr->src.addr[0] & MAC_MUTLTICAST) {
118     /* src mac should valid for us */
119     goto free_and_return;
120   }
121 
122   type = ethhdr->type;
123 #if ETHARP_SUPPORT_VLAN
124   if (type == PP_HTONS(ETHTYPE_VLAN)) {
125     struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr *)(((char *)ethhdr) + SIZEOF_ETH_HDR);
126     next_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
127     if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
128       /* a packet with only an ethernet/vlan header (or less) is not valid for us */
129       ETHARP_STATS_INC(etharp.proterr);
130       ETHARP_STATS_INC(etharp.drop);
131       MIB2_STATS_NETIF_INC(netif, ifinerrors);
132       goto free_and_return;
133     }
134 #if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */
135 #ifdef LWIP_HOOK_VLAN_CHECK
136     if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan))
137 #elif defined(ETHARP_VLAN_CHECK_FN)
138     if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan))
139 #elif defined(ETHARP_VLAN_CHECK)
140     if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK)
141 #endif
142     {
143       /* silently ignore this packet: not for our VLAN */
144       pbuf_free(p);
145       return ERR_OK;
146     }
147 #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
148     type = vlan->tpid;
149   }
150 #endif /* ETHARP_SUPPORT_VLAN */
151 
152 #if LWIP_ARP_FILTER_NETIF
153   netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type));
154 #endif /* LWIP_ARP_FILTER_NETIF*/
155 
156   if (ethhdr->dest.addr[0] & 1) {
157     /* this might be a multicast or broadcast packet */
158     if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) {
159 #if LWIP_IPV4
160       if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) &&
161           (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) {
162         /* mark the pbuf as link-layer multicast */
163         p->flags |= PBUF_FLAG_LLMCAST;
164       }
165 #endif /* LWIP_IPV4 */
166     }
167 #if LWIP_IPV6
168     else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) &&
169              (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) {
170       /* mark the pbuf as link-layer multicast */
171       p->flags |= PBUF_FLAG_LLMCAST;
172     }
173 #endif /* LWIP_IPV6 */
174     else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
175       /* mark the pbuf as link-layer broadcast */
176       p->flags |= PBUF_FLAG_LLBCAST;
177     }
178   } else if (memcmp(&ethhdr->dest, netif->hwaddr, ETH_HWADDR_LEN) == 0) {
179     p->flags |= PBUF_FLAG_HOST;
180   } else {
181     /* else will be treates as other host */
182     is_otherhost = 1;
183   }
184 
185   LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("tcpip_inpkt: dest:\
186     %"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", hwaddr:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F"\n",
187    (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2],
188    (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5],
189    (unsigned)netif->hwaddr[0],  (unsigned)netif->hwaddr[1],  (unsigned)netif->hwaddr[2],
190    (unsigned)netif->hwaddr[3],  (unsigned)netif->hwaddr[4],  (unsigned)netif->hwaddr[5]));
191   /* If PROMISC mode disable, drop the packet for other host no need to process further */
192 #if LWIP_NETIF_PROMISC
193   if (is_otherhost && !(atomic_read(&netif->flags_ext) == NETIF_FLAG_PROMISC)) {
194 #else
195   if (is_otherhost) {
196 #endif
197     ETHARP_STATS_INC(etharp.drop);
198     /* silently ignore this packet: not for us */
199     (void)pbuf_free(p);
200     return ERR_OK;
201   }
202 
203 #if PF_PKT_SUPPORT
204   p->flags = (u16_t)(p->flags & ~PBUF_FLAG_OUTGOING);
205   if (pkt_raw_pcbs != NULL) {
206     raw_pkt_input(p, netif, NULL);
207   }
208 
209 #if LWIP_NETIF_PROMISC
210   if (!(p->flags & (PBUF_FLAG_LLMCAST | PBUF_FLAG_LLBCAST | PBUF_FLAG_HOST))) {
211     is_otherhost = 1;
212   }
213 
214   /* If PROMISC mode enable, drop the packet for other host no need to process further */
215 
216   if (((u32_t)atomic_read(&netif->flags_ext) & (u32_t)NETIF_FLAG_PROMISC) && is_otherhost) {
217     /* silently ignore this packet: not for us */
218       (void)pbuf_free(p);
219       return ERR_OK;
220   }
221 #endif /* LWIP_NETIF_PROMISC */
222 #endif /* PF_PKT_SUPPORT */
223 
224   switch (type) {
225 #if LWIP_IPV4 && LWIP_ARP
226     /* IP packet? */
227     case PP_HTONS(ETHTYPE_IP):
228       if (!(netif->flags & NETIF_FLAG_ETHARP)) {
229         goto free_and_return;
230       }
231 #if ETHARP_TRUST_IP_MAC
232       /* update ARP table */
233       etharp_ip_input(netif, p);
234 #endif /* ETHARP_TRUST_IP_MAC */
235       /* skip Ethernet header (min. size checked above) */
236       if (pbuf_remove_header(p, next_hdr_offset)) {
237         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
238                     ("ethernet_input: IPv4 packet dropped, too short (%"U16_F"/%"U16_F")\n",
239                      p->tot_len, next_hdr_offset));
240         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
241         goto free_and_return;
242       } else {
243         /* pass to IP layer */
244         ip4_input(p, netif);
245       }
246       break;
247 
248     case PP_HTONS(ETHTYPE_ARP):
249       if (!(netif->flags & NETIF_FLAG_ETHARP)) {
250         goto free_and_return;
251       }
252       /* skip Ethernet header (min. size checked above) */
253       if (pbuf_remove_header(p, next_hdr_offset)) {
254         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
255                     ("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n",
256                      p->tot_len, next_hdr_offset));
257         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
258         ETHARP_STATS_INC(etharp.lenerr);
259         ETHARP_STATS_INC(etharp.drop);
260         goto free_and_return;
261       } else {
262         /* pass p to ARP module */
263         etharp_input(p, netif);
264       }
265       break;
266 #endif /* LWIP_IPV4 && LWIP_ARP */
267 
268 #if LWIP_IPV6
269     case PP_HTONS(ETHTYPE_IPV6): { /* IPv6 */
270 #if LWIP_RIPPLE
271       struct linklayer_addr sendermac = {0};
272       if (memcpy_s(sendermac.addr, sizeof(sendermac.addr), ethhdr->src.addr, sizeof(ethhdr->src.addr)) != EOK) {
273         goto free_and_return;
274       }
275       sendermac.addrlen = (u8_t)(sizeof(sendermac.addr));
276 #if LWIP_USE_L2_METRICS
277       lwip_update_nbr_signal_quality(netif, &sendermac, PBUF_GET_RSSI(p), PBUF_GET_LQI(p));
278 #endif
279       (void)memcpy_s(p->mac_address, sizeof(p->mac_address), sendermac.addr, sizeof(sendermac.addr));
280 #endif
281       /* skip Ethernet header */
282       if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) {
283         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
284                     ("ethernet_input: IPv6 packet dropped, too short (%"U16_F"/%"U16_F")\n",
285                      p->tot_len, next_hdr_offset));
286         goto free_and_return;
287       } else {
288         /* pass to IPv6 layer */
289         ip6_input(p, netif);
290       }
291       break;
292     }
293 #endif /* LWIP_IPV6 */
294 
295     default:
296 #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
297       if (LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) {
298         break;
299       }
300 #endif
301       ETHARP_STATS_INC(etharp.proterr);
302       ETHARP_STATS_INC(etharp.drop);
303       MIB2_STATS_NETIF_INC(netif, ifinunknownprotos);
304       goto free_and_return;
305   }
306 
307   /* This means the pbuf is freed or consumed,
308      so the caller doesn't have to free it again */
309   return ERR_OK;
310 
311 free_and_return:
312   pbuf_free(p);
313   return ERR_OK;
314 }
315 
316 /* For support of ethernet packet batching */
317 err_t
318 ethernet_input_list(struct pbuf *p, struct netif *netif)
319 {
320   struct pbuf *next = NULL;
321   struct pbuf *cur = p;
322   while (cur) {
323     next = cur->list;
324     (void)ethernet_input(cur, netif);
325     cur = next;
326   }
327 
328   return ERR_OK;
329 }
330 
331 /**
332  * @ingroup ethernet
333  * Send an ethernet packet on the network using netif->linkoutput().
334  * The ethernet header is filled in before sending.
335  *
336  * @see LWIP_HOOK_VLAN_SET
337  *
338  * @param netif the lwIP network interface on which to send the packet
339  * @param p the packet to send. pbuf layer must be @ref PBUF_LINK.
340  * @param src the source MAC address to be copied into the ethernet header
341  * @param dst the destination MAC address to be copied into the ethernet header
342  * @param eth_type ethernet type (@ref lwip_ieee_eth_type)
343  * @return ERR_OK if the packet was sent, any other err_t on failure
344  */
345 err_t
346 ethernet_output(struct netif * netif, struct pbuf * p,
347                 const struct eth_addr * src, const struct eth_addr * dst,
348                 u16_t eth_type) {
349   struct eth_hdr *ethhdr;
350   u16_t eth_type_be = lwip_htons(eth_type);
351 
352 #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
353   s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type);
354   if (vlan_prio_vid >= 0) {
355     struct eth_vlan_hdr *vlanhdr;
356 
357     LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF);
358 
359     if (pbuf_add_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) {
360       goto pbuf_header_failed;
361     }
362     vlanhdr = (struct eth_vlan_hdr *)(((u8_t *)p->payload) + SIZEOF_ETH_HDR);
363     vlanhdr->tpid     = eth_type_be;
364     vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid);
365 
366     eth_type_be = PP_HTONS(ETHTYPE_VLAN);
367   } else
368 #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
369   {
370     if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) {
371       goto pbuf_header_failed;
372     }
373   }
374 
375   LWIP_ASSERT_CORE_LOCKED();
376 
377   ethhdr = (struct eth_hdr *)p->payload;
378   ethhdr->type = eth_type_be;
379   SMEMCPY(&ethhdr->dest, dst, ETH_HWADDR_LEN);
380   SMEMCPY(&ethhdr->src,  src, ETH_HWADDR_LEN);
381 
382   LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!",
383               (netif->hwaddr_len == ETH_HWADDR_LEN));
384   LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
385               ("ethernet_output: sending packet %p\n", (void *)p));
386 
387   /* send the packet */
388   return netif->linkoutput(netif, p);
389 
390 pbuf_header_failed:
391   LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
392               ("ethernet_output: could not allocate room for header.\n"));
393   LINK_STATS_INC(link.lenerr);
394   return ERR_BUF;
395 }
396 
397 #endif /* LWIP_ARP || LWIP_ETHERNET */
398