1 #include "lwip/opt.h"
2 #include "lwip/def.h"
3 #include "lwip/mem.h"
4 #include "lwip/pbuf.h"
5 #include "lwip/stats.h"
6 #include "lwip/sys.h"
7 #include "netif/etharp.h"
8 #include "netif/wlif.h"
9 #include <wl_api.h>
10 #include <wlap_api.h>
11 
12 #define IFNAME0 'w'
13 #define IFNAME1 'l'
14 
15 /* the queue size will affect the tx performance when using power save.
16  * A small queue will quickly become filled up if we have to wake the device
17  * before the actual transmission can occur. When the queue is filled up, the
18  * packets will be discarded and retransmission will be handled by the upper
19  * layers. In case of TCP, the retransmission time might be quite long.
20  *
21  * If the packets can be put in the pqueue instead, all the packets
22  * (if possible) will be transmitted when the device wakes up, so we don't have
23  * to wait for retransmission from upper layers.
24  */
25 #define PQUEUE_SIZE 8
26 
27 struct wlif_t {
28 	volatile uint8_t rx_pending;
29 
30 	struct {
31 		struct pbuf* buf[PQUEUE_SIZE];
32 		uint8_t first;
33 		uint8_t last;
34 	} pqueue;
35 };
36 
37 #define PQUEUE_EMPTY(q) (q.last == q.first)
38 #define PQUEUE_FULL(q) ((q.last + 1) % PQUEUE_SIZE == q.first)
39 #define PQUEUE_FIRST(q) (q.buf[q.first])
40 #define PQUEUE_DEQUEUE(q)                                               \
41         ({                                                              \
42                 struct pbuf* __p = PQUEUE_FIRST(q);                     \
43                 q.first = (q.first + 1) % PQUEUE_SIZE;                  \
44                 __p;                                                    \
45         })
46 #define PQUEUE_ENQUEUE(q, p)                                            \
47         ({                                                              \
48                 q.buf[q.last] = p;                                      \
49                 q.last = (q.last + 1) % PQUEUE_SIZE;                    \
50         })
51 
52 
process_pqueue(struct netif * netif)53 static err_t process_pqueue(struct netif* netif)
54 {
55         struct pbuf *p;
56         struct pbuf *q;
57         int status;
58 	struct wlif_t *priv = (struct wlif_t*) netif->state;
59 
60         /* queue empty? finished */
61         if (PQUEUE_EMPTY(priv->pqueue))
62                 return ERR_OK;
63 
64         /* get first packet in queue */
65         p = PQUEUE_FIRST(priv->pqueue);
66 
67         status = wl_process_tx(
68                 p->payload + WL_HEADER_SIZE, /* ptr to eth hdr */
69                 p->len - WL_HEADER_SIZE,     /* input buffer len */
70                 p->tot_len - WL_HEADER_SIZE, /* pkt len */
71                 p->payload,                  /* ptr to WE hdr */
72                 0,                           /* prio */
73                 p);                          /* pkt handle */
74 
75         /* if we fail due to power save mode, leave packet in queue and
76          * try again when target is awake again (upon WL_RX_EVENT_WAKEUP).
77          */
78 	if (status == WL_RESOURCES)
79 		return ERR_IF;
80 
81         /* if we fail for another reason, just discard the packet */
82         if (status != WL_SUCCESS) {
83                 PQUEUE_DEQUEUE(priv->pqueue);
84                 pbuf_free(p);
85                 return ERR_IF;
86         }
87 
88         /* Send the data from the pbuf to the interface, one pbuf at a
89          * time. The size of the data in each pbuf is kept in the ->len
90          * variable.
91          */
92         for (q = p; q != NULL; q = q->next)
93 		wl_tx(q->payload, q->len);
94 
95         /* remove packet from queue and dec refcnt */
96         PQUEUE_DEQUEUE(priv->pqueue);
97         pbuf_free(p);
98 
99         LINK_STATS_INC(link.xmit);
100 
101         /* tell caller to process next packet */
102         return ERR_INPROGRESS;
103 }
104 
105 
106 /**
107  * Called in interrupt context when we can read more data from the mac.
108  *
109  */
110 static void
rx_isr(void * ctx)111 rx_isr(void* ctx)
112 {
113 	struct netif *netif = ctx;
114 	struct wlif_t *priv = (struct wlif_t*) netif->state;
115 	priv->rx_pending = 1;
116 }
117 
118 
119 /**
120  * In this function, the hardware should be initialized.
121  * Called from wlif_init().
122  *
123  * @param netif the already initialized lwip network interface structure
124  *        for this ethernetif
125  */
126 static err_t
low_level_init(struct netif * netif)127 low_level_init(struct netif *netif)
128 {
129         /* device capabilities */
130         netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP |
131                 NETIF_FLAG_IGMP;
132 
133         /* NETIF_FLAG_LINK_UP must be set only when we have an wlan assoc */
134 
135         /* set MAC hardware address length */
136         netif->hwaddr_len = ETHARP_HWADDR_LEN;
137 
138 	if (wl_get_mac_addr(netif->hwaddr) != WL_SUCCESS)
139 		return ERR_IF;
140 
141         /* maximum transfer unit */
142         netif->mtu = 1500;
143 
144         return ERR_OK;
145 }
146 
147 
148 /**
149  * This function should do the actual transmission of the packet. The packet is
150  * contained in the pbuf that is passed to the function. This pbuf
151  * might be chained.
152  *
153  * @param netif the lwip network interface structure for this ethernetif
154  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and
155  *        type)
156  * @return ERR_OK if the packet could be sent
157  *         an err_t value if the packet couldn't be sent
158  *
159  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
160  *       strange results. You might consider waiting for space in the DMA queue
161  *       to become availale since the stack doesn't retry to send a packet
162  *       dropped because of memory failure (except for the TCP timers).
163  */
164 static err_t
low_level_output(struct netif * netif,struct pbuf * p)165 low_level_output(struct netif *netif, struct pbuf *p)
166 {
167 	struct wlif_t* priv = (struct wlif_t*) netif->state;
168 
169         /* must have a linear buffer containing up to and including
170          * the ethernet header
171          */
172         if (p->len < sizeof(struct eth_hdr))
173                 return ERR_IF;
174 
175         /* queue full? drop packet */
176         if (PQUEUE_FULL(priv->pqueue))
177                 return ERR_INPROGRESS; /* no one seems to check this anyway */
178 
179         /* queue packet */
180         PQUEUE_ENQUEUE(priv->pqueue, p);
181         pbuf_ref(p);
182         while (process_pqueue(netif) == ERR_INPROGRESS);
183         return ERR_OK; /* no one seems to check this anyway */
184 }
185 
186 /**
187  * Should allocate a pbuf and transfer the bytes of the incoming
188  * packet from the interface into the pbuf.
189  *
190  * @param netif the lwip network interface structure for this ethernetif
191  * @return a pbuf filled with the received packet (including MAC header)
192  *         NULL on memory error
193  */
194 static struct pbuf *
low_level_input(struct netif * netif)195 low_level_input(struct netif *netif)
196 {
197         struct pbuf *p;
198 	struct wlif_t *priv = (struct wlif_t*) netif->state;
199 
200         char *stripped_pkt;
201         size_t stripped_pkt_len;
202         u16_t vlan;
203         u8_t rx_hdr_size;
204         int status;
205         u16_t len;
206 
207         /* maximum packet length from wl_rx() */
208         len = WL_MAX_PKT_LEN;
209 
210         /* We allocate a continous pbuf */
211         p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
212         if (p == NULL) {
213                 LWIP_DEBUGF(NETIF_DEBUG, ("low_level_input: fail to alloc "
214                                           "pbuf of len:%"S32_F"\n", len));
215                 return NULL;
216         }
217 
218         /* Read the entire msg */
219 	priv->rx_pending = 0;
220         wl_rx(p->payload, &len);
221         if (len == 0) {
222                 LWIP_DEBUGF(NETIF_DEBUG, ("low_level_input: len was 0"));
223                 return NULL;
224         }
225 
226         status = wl_process_rx(
227                 p->payload,             /* input buf */
228                 len,                    /* input buf length */
229                 &stripped_pkt,
230                 &stripped_pkt_len,
231                 &vlan);
232 
233         if (status == WL_ABSORBED) {
234                 LWIP_DEBUGF(NETIF_DEBUG, ("low_level_input: absorbed"));
235                 pbuf_free(p);
236                 return NULL;
237         }
238 
239         /* Data packet, remove padding */
240         rx_hdr_size = stripped_pkt - (char*) p->payload;
241         pbuf_realloc(p, stripped_pkt_len + rx_hdr_size);
242 
243         LINK_STATS_INC(link.recv);
244         return p;
245 }
246 
247 
248 /**
249  * This function will be called by wlif_poll() when a packet has been received
250  * from the mac. Then the type of the received packet is determined and
251  * the appropriate input function is called.
252  *
253  * @param netif the lwip network interface structure for this ethernetif
254  */
255 static void
wlif_input(struct netif * netif)256 wlif_input(struct netif *netif)
257 {
258         struct eth_hdr *ethhdr;
259         struct pbuf *p;
260 
261         /* move received packet into a new pbuf */
262         p = low_level_input(netif);
263 
264         /* no packet could be read, silently ignore this */
265         if (p == NULL)
266                 return;
267 
268         /* points to packet payload, which starts with an Ethernet header */
269         ethhdr = p->payload;
270         switch (htons(ethhdr->type)) {
271                 /* IP or ARP packet? */
272         case ETHTYPE_IP:
273         case ETHTYPE_ARP:
274 #if PPPOE_SUPPORT
275                 /* PPPoE packet? */
276         case ETHTYPE_PPPOEDISC:
277         case ETHTYPE_PPPOE:
278 #endif /* PPPOE_SUPPORT */
279                 /* full packet send to tcpip_thread to process */
280                 if (netif->input(p, netif) != ERR_OK) {
281                         LWIP_DEBUGF(NETIF_DEBUG,
282                                     ("wlif_input: IP input error\n"));
283                         pbuf_free(p);
284                         p = NULL;
285                 }
286                 break;
287 
288         default:
289                 pbuf_free(p);
290                 p = NULL;
291                 break;
292         }
293 }
294 
pkt_read_cb(char * dst,void * src_handle,size_t read_len,int offset)295 static ssize_t pkt_read_cb(char *dst,
296                            void *src_handle,
297                            size_t read_len,
298                            int offset) {
299         ssize_t rc;
300 
301         rc = pbuf_copy_partial((struct pbuf *)src_handle,
302                                dst,
303                                read_len,
304                                offset + WL_HEADER_SIZE);
305         if ( 0 == rc ) {
306                 return -1;
307         }
308 
309         return rc;
310 }
311 
312 /**
313  * Should be called at the beginning of the program to set up the
314  * network interface. It calls the function low_level_init() to do the
315  * actual setup of the hardware.
316  *
317  * This function should be passed as a parameter to netif_add().
318  *
319  * @param netif the lwip network interface structure for this ethernetif
320  * @return ERR_OK if the loopif is initialized
321  *         ERR_MEM if private data couldn't be allocated
322  *         any other err_t on error
323  */
324 err_t
wlif_init(struct netif * netif)325 wlif_init(struct netif *netif)
326 {
327         static struct wlif_t wlif;
328 
329         LWIP_ASSERT("netif != NULL", (netif != NULL));
330 
331 #if LWIP_NETIF_HOSTNAME
332         /* Initialize interface hostname */
333         if ( NULL == netif->hostname ) {
334                 netif->hostname = "wlif";
335         }
336 #endif /* LWIP_NETIF_HOSTNAME */
337 
338 	netif->state = &wlif;
339         netif->name[0] = IFNAME0;
340         netif->name[1] = IFNAME1;
341 
342         /* We directly use etharp_output() here to save a function call.
343          * You can instead declare your own function an call etharp_output()
344          * from it if you have to do some checks before sending (e.g. if link
345          * is available...) */
346         netif->output = etharp_output;
347         netif->linkoutput = low_level_output;
348 
349 	wl_register_rx_isr(rx_isr, netif);
350         wl_register_pkt_read_cb(pkt_read_cb);
351 
352         /* initialize the hardware */
353         return low_level_init(netif);
354 }
355 
356 
357 /**
358  *
359  */
360 void
wlif_poll(struct netif * netif)361 wlif_poll(struct netif* netif)
362 {
363         struct wlif_t* priv = NULL;
364 
365         /* wl api forward progress */
366         wl_poll();
367 
368         if (netif)
369                 priv = (struct wlif_t*) netif->state;
370 
371         /* wlif_init() not called yet? */
372         if (priv == NULL)
373                 return;
374 
375 	/* no packets pending? */
376 	if (!priv->rx_pending)
377 		return;
378 
379 	/* read the pending packet */
380 	wlif_input(netif);
381 
382 	/* send any packets that was queued due to filled up target queue
383 	 * or power save mode.
384 	 */
385 	process_pqueue(netif);
386 }
387