source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/SERVICES/LWIP/lwip-port-1.3.2/HD/if/netif/wlif.c @ 4837

Last change on this file since 4837 was 4837, checked in by daduve, 2 years ago

Adding new version

File size: 11.4 KB
Line 
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
27struct 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
53static 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 */
110static void
111rx_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 */
126static err_t
127low_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 */
164static err_t
165low_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 */
194static struct pbuf *
195low_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 */
255static void
256wlif_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
295static 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 */
324err_t
325wlif_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 */
360void
361wlif_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}
Note: See TracBrowser for help on using the repository browser.