1 /*
2 * Copyright (c) 2021 Bestechnic (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hal_trace.h"
17 #include "lwip/opt.h"
18
19 #include "lwip/def.h"
20 #include "lwip/mem.h"
21 #include "lwip/pbuf.h"
22 #include <lwip/stats.h>
23 #include <lwip/snmp.h>
24 #include "lwip/igmp.h"
25 #include "lwip/prot/tcp.h"
26 #include "lwip/prot/udp.h"
27 #include "lwip/prot/ip.h"
28 #include "lwip/prot/ethernet.h"
29 #include "lwip/sys.h"
30 #include "netif/etharp.h"
31 #include "hal_trace.h"
32 typedef unsigned short uint16;
33 typedef short int16;
34 typedef unsigned char uint8;
35
36
37 /* Define those to better describe your network interface. */
38 #define IFNAME0 'e'
39 #define IFNAME1 'n'
40 #define LWIP_ETH_HDR_LEN (SIZEOF_ETH_HDR - ETH_PAD_SIZE)
41 #ifdef LITEOS_LWIP
42 extern void driverif_input(struct netif *netif, struct pbuf *p);
43 extern err_t driverif_init(struct netif *netif);
44 #endif
45 struct netif if_wifi;
46 struct netif if_wifi_ap;
47
48 extern void *mymemcpy(void *dst, const void *src, size_t num);
49 extern void hw_checksum_init(void);
50 extern uint16 hw_checksum(void *data, int16 len, uint32_t src, uint32_t dest, uint8_t proto);
51 extern uint8 **wifi_agent_get_tx_buf(void);
52 extern int wifi_agent_send_tx_buf(uint8 devnum, uint8 **tx_buf, uint16 tx_len);
53
54 static sys_mutex_t hw_checksum_mutex;
55
56 /* Forward declarations. */
57
58 /**
59 * In this function, the hardware should be initialized.
60 * Called from ethernetif_init().
61 *
62 * @param netif the already initialized lwip network interface structure
63 * for this ethernetif
64 */
65 static void
low_level_init(struct netif * netif)66 low_level_init(struct netif *netif)
67 {
68 /* Set MAC hardware address length */
69 netif->hwaddr_len = ETHARP_HWADDR_LEN;
70 #ifdef LITEOS_LWIP
71 netif->link_layer_type = WIFI_DRIVER_IF;
72 #endif
73
74 /* maximum transfer unit */
75 netif->mtu = 1500;
76
77 /* device capabilities */
78 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
79 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_IGMP;
80
81 /* Do whatever else is needed to initialize interface. */
82 }
83
84 int
eth_hw_checksum_init(void)85 eth_hw_checksum_init(void)
86 {
87 if (sys_mutex_new(&hw_checksum_mutex) != ERR_OK)
88 return -1;
89 hw_checksum_init();
90 return 0;
91 }
92
93 uint16
eth_hw_checksum(void * data,int16 len,uint32_t src,uint32_t dest,uint8_t proto)94 eth_hw_checksum(void *data, int16 len, uint32_t src, uint32_t dest, uint8_t proto)
95 {
96 uint16 sum = 0;
97
98 sys_mutex_lock(&hw_checksum_mutex);
99 sum = hw_checksum(data, len, src, dest, proto);
100 sys_mutex_unlock(&hw_checksum_mutex);
101 TRACE(0, "%s %d: %d", __func__, __LINE__, sum);
102 return sum;
103 }
104
105 void
lwip_netif_mac_addr_init(struct netif * netif,uint8 * mac,int mac_len)106 lwip_netif_mac_addr_init(struct netif *netif, uint8 *mac, int mac_len)
107 {
108 memcpy(netif->hwaddr, mac, mac_len);
109 }
110
111 int
mac_data_xmit(uint8 devnum,struct pbuf * p)112 mac_data_xmit(uint8 devnum, struct pbuf *p)
113 {
114 unsigned char **tx_buf;
115 unsigned char *p802x_hdr;
116 unsigned char *tmp;
117 struct pbuf *q;
118 int ret;
119
120 tx_buf = wifi_agent_get_tx_buf();
121 if (tx_buf == NULL)
122 return -1;
123 p802x_hdr = *tx_buf;
124
125 tmp = p802x_hdr;
126 for (q = p; q != NULL; q = q->next) {
127 memcpy(p802x_hdr, q->payload, q->len);
128 p802x_hdr += q->len;
129 }
130 p802x_hdr = tmp;
131
132 #ifdef CHECKSUM_BY_HARDWARE
133 #if (!(CHECKSUM_GEN_TCP) || !(CHECKSUM_GEN_UDP))
134 struct eth_hdr *ethhdr = (struct eth_hdr *)(p802x_hdr - ETH_PAD_SIZE);
135 if (htons(ethhdr->type) == ETHTYPE_IP) {
136 uint32_t dst, src;
137 struct ip_hdr *ip_hdr;
138 ip_hdr = (struct ip_hdr *)(p802x_hdr + LWIP_ETH_HDR_LEN);
139 memcpy(&dst, &ip_hdr->dest, 4);
140 memcpy(&src, &ip_hdr->src, 4);
141 #if !(CHECKSUM_GEN_TCP)
142 if (ip_hdr->_proto == IP_PROTO_TCP) {
143 struct tcp_hdr *tcphdr = (struct tcp_hdr *)((unsigned char *)ip_hdr + sizeof(struct ip_hdr));
144 tcphdr->chksum = 0;
145 tcphdr->chksum = eth_hw_checksum((void *)tcphdr, p->tot_len - sizeof(struct ip_hdr) - LWIP_ETH_HDR_LEN, src, dst, IP_PROTO_TCP);
146 }
147 #endif
148
149 #if !(CHECKSUM_GEN_UDP)
150 if (ip_hdr->_proto == IP_PROTO_UDP) {
151 struct udp_hdr *udphdr = (struct udp_hdr *)((unsigned char *)ip_hdr + sizeof(struct ip_hdr));
152 udphdr->chksum = 0;
153 udphdr->chksum = eth_hw_checksum((void *)udphdr, p->tot_len - sizeof(struct ip_hdr) - LWIP_ETH_HDR_LEN, src, dst, IP_PROTO_UDP);
154 }
155 #endif
156 }
157 #endif /* !(CHECKSUM_GEN_TCP) || !(CHECKSUM_GEN_UDP) */
158 #endif /* CHECKSUM_BY_HARDWARE */
159
160
161 ret = wifi_agent_send_tx_buf(devnum, tx_buf, p->tot_len);
162 if (ret < 0)
163 return -1;
164
165 return 0;
166 }
167
168 #define LWIP_ETH_HDR_LEN (SIZEOF_ETH_HDR - ETH_PAD_SIZE)
169 /**
170 * This function should do the actual transmission of the packet. The packet is
171 * contained in the pbuf that is passed to the function. This pbuf
172 * might be chained.
173 *
174 * @param netif the lwip network interface structure for this ethernetif
175 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
176 * @return ERR_OK if the packet could be sent
177 * an err_t value if the packet couldn't be sent
178 *
179 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
180 * strange results. You might consider waiting for space in the DMA queue
181 * to become availale since the stack doesn't retry to send a packet
182 * dropped because of memory failure (except for the TCP timers).
183 */
184
185 static err_t
low_level_output(struct netif * netif,struct pbuf * p)186 low_level_output(struct netif *netif, struct pbuf *p)
187 {
188 uint8 RetryCnt = 2, devnum;
189 int xmit;
190 err_t ret;
191
192 #if ETH_PAD_SIZE
193 /* Note:hmos tx should not drop the paddiing word */
194 #ifndef LITEOS_LWIP
195 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
196 #endif
197 #endif
198 (netif == &if_wifi) ? (devnum = 0) : (devnum = 1);
199
200 while (xmit = mac_data_xmit(devnum, p) < 0 && (RetryCnt--)) {
201 osDelay(10);
202 }
203
204 #if ETH_PAD_SIZE
205 /* Note: hmos tx should not drop the paddiing word */
206 #ifndef LITEOS_LWIP
207 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
208 #endif
209 #endif
210
211 (xmit == 0) ? (ret = ERR_OK) : (ret = ERR_MEM);
212 return ret;
213 }
214
215
216 /**
217 * Should allocate a pbuf and transfer the bytes of the incoming
218 * packet from the interface into the pbuf.
219 *
220 * @param netif the lwip network interface structure for this ethernetif
221 * @return a pbuf filled with the received packet (including MAC header)
222 * NULL on memory error
223 */
224 struct pbuf *
low_level_input(struct netif * netif,void * p_buf,int size)225 low_level_input(struct netif *netif, void *p_buf, int size)
226 {
227 struct pbuf *p, *q;
228 u16_t len;
229 int rem_len;
230
231 /* Obtain the size of the packet and put it into the "len"
232 * variable. */
233 len = size;
234
235 #if ETH_PAD_SIZE
236 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
237 #endif
238
239 p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
240
241 if (p != NULL && (p->tot_len >= len)) {
242
243 #if ETH_PAD_SIZE
244 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
245 #endif
246
247 /* We iterate over the pbuf chain until we have read the entire
248 * packet into the pbuf. */
249 rem_len = p->tot_len;
250 for (q = p; q != NULL; q = q->next) {
251 /* Read enough bytes to fill this pbuf in the chain. The
252 * available data in the pbuf is given by the q->len
253 * variable.
254 * This does not necessarily have to be a memcpy, you can also preallocate
255 * pbufs for a DMA-enabled MAC and after receiving truncate it to the
256 * actually received size. In this case, ensure the tot_len member of the
257 * pbuf is the sum of the chained pbuf len members.
258 */
259 if (rem_len > 0) {
260 //printk(KERN_DEBUG, "low_level_input: 0x%x, 0x%x.\n", (uint32)q->payload, (uint32)((char*)p_buf + (p->tot_len - rem_len)));
261 mymemcpy(q->payload, (char *)p_buf + (p->tot_len - rem_len), q->len);
262 rem_len -= q->len;
263 } else
264 printf("low_level_input memcpy err\n");
265 }
266
267 #if ETH_PAD_SIZE
268 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
269 #endif
270 LINK_STATS_INC(link.recv);
271 } else {
272 printf("low_level_input alloc failed, drop frame!\n");
273 LINK_STATS_INC(link.memerr);
274 LINK_STATS_INC(link.drop);
275 }
276 return p;
277 }
278
279 #ifdef LITEOS_LWIP
280
281 static void
liteos_low_level_output(struct netif * netif,struct pbuf * p)282 liteos_low_level_output(struct netif *netif, struct pbuf *p)
283 {
284 low_level_output(netif, p);
285 }
286 #endif
287 /**
288 * This function should be called when a packet is ready to be read
289 * from the interface. It uses the function low_level_input() that
290 * should handle the actual reception of bytes from the network
291 * interface. Then the type of the received packet is determined and
292 * the appropriate input function is called.
293 *
294 * @param netif the lwip network interface structure for this ethernetif
295 */
296 void
ethernetif_input(u16_t devnum,void * p_buf,int size)297 ethernetif_input(u16_t devnum, void *p_buf, int size)
298 {
299 TRACE(0, "%s %d, %d", __func__, __LINE__, size);
300
301 struct eth_hdr *ethhdr;
302 struct netif *netif;
303 struct pbuf *p;
304
305 (devnum == 0) ? (netif = &if_wifi) : (netif = &if_wifi_ap);
306 /* move received packet into a new pbuf */
307 #if(SKB_SRAM == 2)
308 p = (struct pbuf *)p_buf;
309 #else
310 p = low_level_input(netif, p_buf, size);
311 #endif
312 #ifdef LITEOS_LWIP
313 driverif_input(netif, p);
314 return;
315 #endif
316 /* no packet could be read, silently ignore this */
317 if (p == NULL) return;
318 /* points to packet payload, which starts with an Ethernet header */
319 ethhdr = p->payload;
320
321 switch (htons(ethhdr->type)) {
322 /* IP or ARP packet? */
323 case ETHTYPE_IP:
324 #if defined(CHECKSUM_BY_HARDWARE) && (!(CHECKSUM_CHECK_TCP) || !(CHECKSUM_CHECK_UDP))
325 {
326 char *trpkt;
327 uint16_t trpkt_len;
328 uint16_t chksum_cal = 0;
329 uint32_t dst, src;
330 struct ip_hdr *ip_hdr = (struct ip_hdr *)((char *)ethhdr + SIZEOF_ETH_HDR);
331
332 LWIP_ASSERT("eth input invalid size", (size >= (sizeof(struct ip_hdr) + LWIP_ETH_HDR_LEN)));
333 #if(SKB_SRAM == 2)
334 trpkt = (struct pbuf *)p_buf->payload;
335 #else
336 trpkt = (char *)p_buf;
337 #endif
338 trpkt += (SIZEOF_ETH_HDR - ETH_PAD_SIZE) + sizeof(struct ip_hdr);
339 trpkt_len = size - sizeof(struct ip_hdr) - (SIZEOF_ETH_HDR - ETH_PAD_SIZE);
340 memcpy(&dst, &ip_hdr->dest, 4);
341 memcpy(&src, &ip_hdr->src, 4);
342 #if !(CHECKSUM_CHECK_TCP)
343 if ((IP_HDR_GET_VERSION(ip_hdr) != 6) && ip_hdr->_proto == IP_PROTO_TCP) {
344 struct tcp_hdr *tcphdr = (struct tcp_hdr *)((char *)ip_hdr + sizeof(struct ip_hdr));
345 if (tcphdr->chksum)
346 chksum_cal = eth_hw_checksum((void *)trpkt, trpkt_len, src, dst, IP_PROTO_TCP);
347 if (chksum_cal != 0) {
348 //printk(KERN_DEBUG, "hw tcp checksum error\n");
349 }
350 }
351 #endif
352
353 #if !(CHECKSUM_CHECK_UDP)
354 if ((IP_HDR_GET_VERSION(ip_hdr) != 6) && ip_hdr->_proto == IP_PROTO_UDP) {
355 struct udp_hdr *udphdr = (struct udp_hdr *)((char *)ip_hdr + sizeof(struct ip_hdr));
356 if (udphdr->chksum) {
357 chksum_cal = eth_hw_checksum((void *)trpkt, trpkt_len, src, dst, IP_PROTO_UDP);
358 if (chksum_cal != 0) {
359 //printk(KERN_DEBUG, "hw udp chksum error src=%x dst=%x pkt=%x len=%x\n", src, dst, trpkt, trpkt_len);
360 }
361 }
362 }
363 #endif
364 }
365 #endif
366
367 case ETHTYPE_ARP:
368 #if PPPOE_SUPPORT
369 /* PPPoE packet? */
370 case ETHTYPE_PPPOEDISC:
371 case ETHTYPE_PPPOE:
372 #endif /* PPPOE_SUPPORT */
373 /* full packet send to tcpip_thread to process */
374 if (netif->input(p, netif) != ERR_OK) {
375 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
376 pbuf_free(p);
377 p = NULL;
378 }
379 break;
380
381 default:
382 pbuf_free(p);
383 p = NULL;
384 break;
385 }
386 }
387
388 /**
389 * Should be called at the beginning of the program to set up the
390 * network interface. It calls the function low_level_init() to do the
391 * actual setup of the hardware.
392 *
393 * This function should be passed as a parameter to netif_add().
394 *
395 * @param netif the lwip network interface structure for this ethernetif
396 * @return ERR_OK if the loopif is initialized
397 * ERR_MEM if private data couldn't be allocated
398 * any other err_t on error
399 */
400 err_t
ethernetif_init(struct netif * netif)401 ethernetif_init(struct netif *netif)
402 {
403
404 TRACE(0, "%s %d", __func__, __LINE__);
405
406 LWIP_ASSERT("netif != NULL", (netif != NULL));
407
408 #ifdef CHECKSUM_BY_HARDWARE
409 eth_hw_checksum_init();
410 #endif
411
412 #ifdef LITEOS_LWIP
413 #if LWIP_IPV4
414 netif->output = etharp_output;
415 #endif /* LWIP_IPV4 */
416 #if LWIP_IPV6
417 netif->output_ip6 = ethip6_output;
418 #endif /* LWIP_IPV6 */
419 netif->linkoutput = low_level_output;
420
421 netif->drv_send = liteos_low_level_output;
422 netif->hwaddr_len = NETIF_MAX_HWADDR_LEN;
423 low_level_init(netif);
424 driverif_init(netif);
425 return ERR_OK;
426 #else
427 #if LWIP_NETIF_HOSTNAME
428 /* Initialize interface hostname */
429 netif->hostname = "lwip";
430 #endif /* LWIP_NETIF_HOSTNAME */
431
432 /*
433 * Initialize the snmp variables and counters inside the struct netif.
434 * The last argument should be replaced with your link speed, in units
435 * of bits per second.
436 */
437 //NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
438
439 netif->state = NULL;
440 netif->name[0] = IFNAME0;
441 netif->name[1] = IFNAME1;
442 /*
443 * We directly use etharp_output() here to save a function call.
444 * You can instead declare your own function an call etharp_output()
445 * from it if you have to do some checks before sending (e.g. if link
446 * is available...)
447 */
448 #if LWIP_IPV4
449 netif->output = etharp_output;
450 #endif /* LWIP_IPV4 */
451 #if LWIP_IPV6
452 netif->output_ip6 = ethip6_output;
453 #endif /* LWIP_IPV6 */
454 netif->linkoutput = low_level_output;
455
456 /* initialize the hardware */
457 low_level_init(netif);
458 return ERR_OK;
459 #endif
460 }
461
462