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 used for WiFi
11 *
12 */
13
14 #include <stdio.h>
15 #include <string.h>
16 #include "lwip/opt.h"
17 #include "lwip/pbuf.h"
18 #include "lwip/snmp.h"
19 #include "lwip/ethip6.h"
20 #include "netif/etharp.h"
21
22 #include "esp_netif.h"
23 #include "esp_netif_net_stack.h"
24 #include "lwip/esp_netif_net_stack.h"
25 #include "esp_compiler.h"
26 #include "lwip/esp_pbuf_ref.h"
27
28 /**
29 * In this function, the hardware should be initialized.
30 * Called from wlanif_input().
31 *
32 * @param netif the already initialized lwip network interface structure
33 * for this wlanif
34 */
35 static void
low_level_init(struct netif * netif)36 low_level_init(struct netif *netif)
37 {
38 /* set MAC hardware address length */
39 netif->hwaddr_len = ETH_HWADDR_LEN;
40
41 /* set MAC hardware address */
42
43 /* maximum transfer unit */
44 netif->mtu = 1500;
45
46 /* device capabilities */
47 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
48 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
49
50 #if ESP_LWIP
51 #if LWIP_IGMP
52 netif->flags |= NETIF_FLAG_IGMP;
53 #endif
54 #endif
55
56 #if ESP_IPV6
57 #if LWIP_IPV6 && LWIP_IPV6_MLD
58 netif->flags |= NETIF_FLAG_MLD6;
59 #endif
60 #endif
61
62 }
63
64 /**
65 * This function should do the actual transmission of the packet. The packet is
66 * contained in the pbuf that is passed to the function. This pbuf
67 * might be chained.
68 *
69 * @param netif the lwip network interface structure for this wlanif
70 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
71 * @return ERR_OK if the packet could be sent
72 * an err_t value if the packet couldn't be sent
73 *
74 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
75 * strange results. You might consider waiting for space in the DMA queue
76 * to become available since the stack doesn't retry to send a packet
77 * dropped because of memory failure (except for the TCP timers).
78 */
low_level_output(struct netif * netif,struct pbuf * p)79 static err_t low_level_output(struct netif *netif, struct pbuf *p)
80 {
81 esp_netif_t *esp_netif = netif->state;
82 if (esp_netif == NULL) {
83 return ERR_IF;
84 }
85
86 struct pbuf *q = p;
87 esp_err_t ret;
88
89 if(q->next == NULL) {
90 ret = esp_netif_transmit_wrap(esp_netif, q->payload, q->len, q);
91
92 } else {
93 LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
94 q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
95 if (q != NULL) {
96 pbuf_copy(q, p);
97 } else {
98 return ERR_MEM;
99 }
100 ret = esp_netif_transmit_wrap(esp_netif, q->payload, q->len, q);
101
102 pbuf_free(q);
103 }
104
105 if (ret == ESP_OK) {
106 return ERR_OK;
107 }
108 if (ret == ESP_ERR_NO_MEM) {
109 return ERR_MEM;
110 }
111 if (ret == ESP_ERR_INVALID_ARG) {
112 return ERR_ARG;
113 }
114 return ERR_IF;
115 }
116
117 /**
118 * This function should be called when a packet is ready to be read
119 * from the interface. It uses the function low_level_input() that
120 * should handle the actual reception of bytes from the network
121 * interface. Then the type of the received packet is determined and
122 * the appropriate input function is called.
123 *
124 * @param h lwip network interface structure (struct netif) for this ethernetif
125 * @param buffer wlan buffer
126 * @param len length of buffer
127 * @param l2_buff wlan's L2 buffer pointer
128 */
wlanif_input(void * h,void * buffer,size_t len,void * l2_buff)129 esp_netif_recv_ret_t wlanif_input(void *h, void *buffer, size_t len, void* l2_buff)
130 {
131 struct netif * netif = h;
132 esp_netif_t *esp_netif = netif->state;
133 struct pbuf *p;
134
135 if(unlikely(!buffer || !netif_is_up(netif))) {
136 if (l2_buff) {
137 esp_netif_free_rx_buffer(esp_netif, l2_buff);
138 }
139 return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_FAIL);
140 }
141
142 #ifdef CONFIG_LWIP_L2_TO_L3_COPY
143 p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
144 if (p == NULL) {
145 esp_netif_free_rx_buffer(esp_netif, l2_buff);
146 return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_ERR_NO_MEM);
147 }
148 memcpy(p->payload, buffer, len);
149 esp_netif_free_rx_buffer(esp_netif, l2_buff);
150 #else
151 p = esp_pbuf_allocate(esp_netif, buffer, len, l2_buff);
152 if (p == NULL) {
153 esp_netif_free_rx_buffer(esp_netif, l2_buff);
154 return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_ERR_NO_MEM);
155 }
156
157 #endif
158
159 /* full packet send to tcpip_thread to process */
160 if (unlikely(netif->input(p, netif) != ERR_OK)) {
161 LWIP_DEBUGF(NETIF_DEBUG, ("wlanif_input: IP input error\n"));
162 pbuf_free(p);
163 return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_FAIL);
164 }
165 return ESP_NETIF_OPTIONAL_RETURN_CODE(ESP_OK);
166 }
167
168 /**
169 * Should be called at the beginning of the program to set up the
170 * network interface. It calls the function low_level_init() to do the
171 * actual setup of the hardware.
172 *
173 * This function should be passed as a parameter to netif_add().
174 *
175 * @param netif the lwip network interface structure for this wlanif
176 * @return ERR_OK if the loopif is initialized
177 * ERR_MEM if private data couldn't be allocated
178 * any other err_t on error
179 */
180 err_t
wlanif_init(struct netif * netif)181 wlanif_init(struct netif *netif)
182 {
183 LWIP_ASSERT("netif != NULL", (netif != NULL));
184
185 #if LWIP_NETIF_HOSTNAME
186 /* Initialize interface hostname */
187
188 #if ESP_LWIP
189 if (esp_netif_get_hostname(netif->state, &netif->hostname) != ESP_OK) {
190 netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME;
191 }
192 #else
193 netif->hostname = "lwip";
194 #endif
195
196 #endif /* LWIP_NETIF_HOSTNAME */
197
198 /*
199 * Initialize the snmp variables and counters inside the struct netif.
200 * The last argument should be replaced with your link speed, in units
201 * of bits per second.
202 */
203 NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100);
204
205 /* We directly use etharp_output() here to save a function call.
206 * You can instead declare your own function an call etharp_output()
207 * from it if you have to do some checks before sending (e.g. if link
208 * is available...) */
209 #if LWIP_IPV4
210 netif->output = etharp_output;
211 #endif
212 #if LWIP_IPV6
213 netif->output_ip6 = ethip6_output;
214 #endif /* LWIP_IPV6 */
215 netif->linkoutput = low_level_output;
216
217 /* initialize the hardware */
218 low_level_init(netif);
219
220 return ERR_OK;
221 }
222
wlanif_init_sta(struct netif * netif)223 err_t wlanif_init_sta(struct netif *netif) {
224 netif->name[0] = 's';
225 netif->name[1] = 't';
226 return wlanif_init(netif);
227 }
228
wlanif_init_ap(struct netif * netif)229 err_t wlanif_init_ap(struct netif *netif) {
230 netif->name[0] = 'a';
231 netif->name[1] = 'p';
232 return wlanif_init(netif);
233 }
234
wlanif_init_nan(struct netif * netif)235 err_t wlanif_init_nan(struct netif *netif) {
236 netif->name[0] = 'n';
237 netif->name[1] = 'a';
238 return wlanif_init(netif);
239 }
240