3 * Ethernet common functions
5 * @defgroup ethernet Ethernet
6 * @ingroup callbackstyle_api
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.
15 * Redistribution and use in source and binary forms, with or without modification,
16 * are permitted provided that the following conditions are met:
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.
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
37 * This file is part of the lwIP TCP/IP stack.
43 #if LWIP_ARP || LWIP_ETHERNET
45 #include "netif/ethernet.h"
47 #include "lwip/stats.h"
48 #include "lwip/etharp.h"
50 #include "lwip/snmp.h"
54 #include "netif/ppp/ppp_opts.h"
56 #include "netif/ppp/pppoe.h"
57 #endif /* PPPOE_SUPPORT */
59 #ifdef LWIP_HOOK_FILENAME
60 #include LWIP_HOOK_FILENAME
63 const struct eth_addr ethbroadcast
= {{0xff,0xff,0xff,0xff,0xff,0xff}};
64 const struct eth_addr ethzero
= {{0,0,0,0,0,0}};
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().
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
76 * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
77 * @see ETHARP_SUPPORT_VLAN
78 * @see LWIP_HOOK_VLAN_CHECK
81 ethernet_input(struct pbuf
*p
, struct netif
*netif
)
83 struct eth_hdr
* ethhdr
;
85 #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6
86 s16_t ip_hdr_offset
= SIZEOF_ETH_HDR
;
87 #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */
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
);
97 if (p
->if_idx
== NETIF_NO_INDEX
) {
98 p
->if_idx
= netif_get_index(netif
);
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
)));
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
;
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
) {
130 /* silently ignore this packet: not for our VLAN */
134 #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
136 ip_hdr_offset
= SIZEOF_ETH_HDR
+ SIZEOF_VLAN_HDR
;
138 #endif /* ETHARP_SUPPORT_VLAN */
140 #if LWIP_ARP_FILTER_NETIF
141 netif
= LWIP_ARP_FILTER_NETIF_FN(p
, netif
, lwip_htons(type
));
142 #endif /* LWIP_ARP_FILTER_NETIF*/
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
) {
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
;
153 #endif /* LWIP_IPV4 */
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
;
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
;
169 #if LWIP_IPV4 && LWIP_ARP
171 case PP_HTONS(ETHTYPE_IP
):
172 if (!(netif
->flags
& NETIF_FLAG_ETHARP
)) {
173 goto free_and_return
;
175 /* skip Ethernet header */
176 if ((p
->len
< ip_hdr_offset
) || pbuf_header(p
, (s16_t
)-ip_hdr_offset
)) {
177 LWIP_DEBUGF(ETHARP_DEBUG
| LWIP_DBG_TRACE
| LWIP_DBG_LEVEL_WARNING
,
178 ("ethernet_input: IPv4 packet dropped, too short (%"S16_F
"/%"S16_F
")\n",
179 p
->tot_len
, ip_hdr_offset
));
180 LWIP_DEBUGF(ETHARP_DEBUG
| LWIP_DBG_TRACE
, ("Can't move over header in packet"));
181 goto free_and_return
;
183 /* pass to IP layer */
188 case PP_HTONS(ETHTYPE_ARP
):
189 if (!(netif
->flags
& NETIF_FLAG_ETHARP
)) {
190 goto free_and_return
;
192 /* skip Ethernet header */
193 if ((p
->len
< ip_hdr_offset
) || pbuf_header(p
, (s16_t
)-ip_hdr_offset
)) {
194 LWIP_DEBUGF(ETHARP_DEBUG
| LWIP_DBG_TRACE
| LWIP_DBG_LEVEL_WARNING
,
195 ("ethernet_input: ARP response packet dropped, too short (%"S16_F
"/%"S16_F
")\n",
196 p
->tot_len
, ip_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
;
202 /* pass p to ARP module */
203 etharp_input(p
, netif
);
206 #endif /* LWIP_IPV4 && LWIP_ARP */
208 case PP_HTONS(ETHTYPE_PPPOEDISC
): /* PPP Over Ethernet Discovery Stage */
209 pppoe_disc_input(netif
, p
);
212 case PP_HTONS(ETHTYPE_PPPOE
): /* PPP Over Ethernet Session Stage */
213 pppoe_data_input(netif
, p
);
215 #endif /* PPPOE_SUPPORT */
218 case PP_HTONS(ETHTYPE_IPV6
): /* IPv6 */
219 /* skip Ethernet header */
220 if ((p
->len
< ip_hdr_offset
) || pbuf_header(p
, (s16_t
)-ip_hdr_offset
)) {
221 LWIP_DEBUGF(ETHARP_DEBUG
| LWIP_DBG_TRACE
| LWIP_DBG_LEVEL_WARNING
,
222 ("ethernet_input: IPv6 packet dropped, too short (%"S16_F
"/%"S16_F
")\n",
223 p
->tot_len
, ip_hdr_offset
));
224 goto free_and_return
;
226 /* pass to IPv6 layer */
230 #endif /* LWIP_IPV6 */
233 #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
234 if(LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p
, netif
) == ERR_OK
) {
238 ETHARP_STATS_INC(etharp
.proterr
);
239 ETHARP_STATS_INC(etharp
.drop
);
240 MIB2_STATS_NETIF_INC(netif
, ifinunknownprotos
);
241 goto free_and_return
;
244 /* This means the pbuf is freed or consumed,
245 so the caller doesn't have to free it again */
255 * Send an ethernet packet on the network using netif->linkoutput().
256 * The ethernet header is filled in before sending.
258 * @see LWIP_HOOK_VLAN_SET
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
268 ethernet_output(struct netif
* netif
, struct pbuf
* p
,
269 const struct eth_addr
* src
, const struct eth_addr
* dst
,
272 struct eth_hdr
* ethhdr
;
273 u16_t eth_type_be
= lwip_htons(eth_type
);
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
;
280 LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid
<= 0xFFFF);
282 if (pbuf_header(p
, SIZEOF_ETH_HDR
+ SIZEOF_VLAN_HDR
) != 0) {
283 goto pbuf_header_failed
;
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
);
289 eth_type_be
= PP_HTONS(ETHTYPE_VLAN
);
291 #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
293 if (pbuf_header(p
, SIZEOF_ETH_HDR
) != 0) {
294 goto pbuf_header_failed
;
298 ethhdr
= (struct eth_hdr
*)p
->payload
;
299 ethhdr
->type
= eth_type_be
;
300 ETHADDR16_COPY(ðhdr
->dest
, dst
);
301 ETHADDR16_COPY(ðhdr
->src
, src
);
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
));
308 /* send the packet */
309 return netif
->linkoutput(netif
, p
);
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
);
318 #endif /* LWIP_ARP || LWIP_ETHERNET */