1 /*
2  * SPDX-FileCopyrightText: 2001-2004 Swedish Institute of Computer Science
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * SPDX-FileContributor: 2015-2022 Espressif Systems (Shanghai) CO LTD
7  */
8 /**
9  * @file
10  * Ethernet Interface Skeleton
11  *
12  */
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include "lwip/opt.h"
17 #include "lwip/pbuf.h"
18 #include "lwip/ethip6.h"
19 #include "netif/etharp.h"
20 
21 #include "esp_compiler.h"
22 #include "esp_netif.h"
23 #include "esp_netif_net_stack.h"
24 #include "lwip/esp_netif_net_stack.h"
25 #include "lwip/esp_pbuf_ref.h"
26 
27 /* Define those to better describe your network interface. */
28 #define IFNAME0 'e'
29 #define IFNAME1 'n'
30 
31 /**
32  * In this function, the hardware should be initialized.
33  * Invoked by ethernetif_init().
34  *
35  * @param netif lwip network interface which has already been initialized
36  */
ethernet_low_level_init(struct netif * netif)37 static void ethernet_low_level_init(struct netif *netif)
38 {
39     /* set MAC hardware address length */
40     netif->hwaddr_len = ETH_HWADDR_LEN;
41 
42     /* maximum transfer unit */
43     netif->mtu = 1500;
44 
45     /* device capabilities */
46     /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
47     netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
48 
49 #if ESP_LWIP
50 #if LWIP_IGMP
51     netif->flags |= NETIF_FLAG_IGMP;
52 #endif
53 #endif
54 
55 #if ESP_IPV6
56 #if LWIP_IPV6 && LWIP_IPV6_MLD
57     netif->flags |= NETIF_FLAG_MLD6;
58 #endif
59 #endif
60 }
61 
62 /**
63  * @brief This function should do the actual transmission of the packet. The packet is
64  * contained in the pbuf that is passed to the function. This pbuf might be chained.
65  *
66  * @param netif lwip network interface structure for this ethernetif
67  * @param p MAC packet to send (e.g. IP packet including MAC addresses and type)
68  * @return err_t ERR_OK if the packet has been sent to Ethernet DMA buffer successfully
69  *               ERR_MEM if private data couldn't be allocated
70  *               ERR_IF if netif is not supported
71  *               ERR_ABORT if there's some wrong when send pbuf payload to DMA buffer
72  */
ethernet_low_level_output(struct netif * netif,struct pbuf * p)73 static err_t ethernet_low_level_output(struct netif *netif, struct pbuf *p)
74 {
75     struct pbuf *q = p;
76     esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(netif);
77     esp_err_t ret = ESP_FAIL;
78     if (!esp_netif) {
79         LWIP_DEBUGF(NETIF_DEBUG, ("corresponding esp-netif is NULL: netif=%p pbuf=%p len=%d\n", netif, p, p->len));
80         return ERR_IF;
81     }
82 
83     if (q->next == NULL) {
84         ret = esp_netif_transmit(esp_netif, q->payload, q->len);
85     } else {
86         LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
87         q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
88         if (q != NULL) {
89             pbuf_copy(q, p);
90         } else {
91             return ERR_MEM;
92         }
93         ret = esp_netif_transmit(esp_netif, q->payload, q->len);
94         /* content in payload has been copied to DMA buffer, it's safe to free pbuf now */
95         pbuf_free(q);
96     }
97     /* Check error */
98     if (likely(ret == ESP_OK)) {
99         return ERR_OK;
100     }
101     if (ret == ESP_ERR_NO_MEM) {
102         return ERR_MEM;
103     }
104     return ERR_IF;
105 }
106 
107 /**
108  * @brief This function should be called when a packet is ready to be read
109  * from the interface. It uses the function low_level_input() that
110  * should handle the actual reception of bytes from the network
111  * interface. Then the type of the received packet is determined and
112  * the appropriate input function is called.
113  *
114  * @param h lwip network interface structure (struct netif) for this ethernetif
115  * @param buffer ethernet buffer
116  * @param len length of buffer
117  * @param l2_buff Placeholder for a separate L2 buffer. Unused for ethernet interface
118  */
ethernetif_input(void * h,void * buffer,size_t len,void * l2_buff)119 esp_netif_recv_ret_t ethernetif_input(void *h, void *buffer, size_t len, void *l2_buff)
120 {
121     struct netif *netif = h;
122     esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(netif);
123     struct pbuf *p;
124 
125     if (unlikely(buffer == NULL || !netif_is_up(netif))) {
126         if (buffer) {
127             esp_netif_free_rx_buffer(esp_netif, buffer);
128         }
129         return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_FAIL);
130     }
131 
132     /* allocate custom pbuf to hold  */
133     p = esp_pbuf_allocate(esp_netif, buffer, len, buffer);
134     if (p == NULL) {
135         esp_netif_free_rx_buffer(esp_netif, buffer);
136         return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_ERR_NO_MEM);
137     }
138     /* full packet send to tcpip_thread to process */
139     if (unlikely(netif->input(p, netif) != ERR_OK)) {
140         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
141         pbuf_free(p);
142         return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_FAIL);
143     }
144     /* the pbuf will be free in upper layer, eg: ethernet_input */
145     return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_OK);
146 }
147 
148 /**
149  * Set up the network interface. It calls the function low_level_init() to do the
150  * actual init work of the hardware.
151  *
152  * This function should be passed as a parameter to netif_add().
153  *
154  * @param netif the lwip network interface structure for this ethernetif
155  * @return ERR_OK if the ethernetif is initialized
156  */
ethernetif_init(struct netif * netif)157 err_t ethernetif_init(struct netif *netif)
158 {
159     LWIP_ASSERT("netif != NULL", (netif != NULL));
160     /* Have to get the esp-netif handle from netif first and then driver==ethernet handle from there */
161     esp_netif_t *esp_netif = netif->state;
162     /* Initialize interface hostname */
163 #if LWIP_NETIF_HOSTNAME
164 #if ESP_LWIP
165     if (esp_netif_get_hostname(esp_netif, &netif->hostname) != ESP_OK) {
166         netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME;
167     }
168 #else
169     netif->hostname = "lwip";
170 #endif
171 
172 #endif /* LWIP_NETIF_HOSTNAME */
173 
174     netif->name[0] = IFNAME0;
175     netif->name[1] = IFNAME1;
176 #if LWIP_IPV4
177     netif->output = etharp_output;
178 #endif
179 #if LWIP_IPV6
180     netif->output_ip6 = ethip6_output;
181 #endif /* LWIP_IPV6 */
182     netif->linkoutput = ethernet_low_level_output;
183 
184     ethernet_low_level_init(netif);
185 
186     return ERR_OK;
187 }
188