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