• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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