]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/api/tcpip.c
Change parameters list for sys_thread_new (see "task #7252 : Create sys_thread_new_ex...
[pes-rpp/rpp-lwip.git] / src / api / tcpip.c
1 /**
2  * @file
3  * Sequential API Main thread module
4  *
5  */
6
7 /*
8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  *    this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  *    this list of conditions and the following disclaimer in the documentation
18  *    and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31  * OF SUCH DAMAGE.
32  *
33  * This file is part of the lwIP TCP/IP stack.
34  *
35  * Author: Adam Dunkels <adam@sics.se>
36  *
37  */
38
39 #include "lwip/opt.h"
40
41 #include "lwip/sys.h"
42
43 #include "lwip/memp.h"
44 #include "lwip/pbuf.h"
45
46 #include "netif/etharp.h"
47 #include "netif/ppp_oe.h"
48
49 #include "lwip/ip_frag.h"
50 #include "lwip/igmp.h"
51
52 #include "lwip/tcpip.h"
53 #include "lwip/init.h"
54
55 #if !NO_SYS
56
57 /* global variables */
58 static void (* tcpip_init_done)(void *arg) = NULL;
59 static void *tcpip_init_done_arg           = NULL;
60 static sys_mbox_t mbox                     = SYS_MBOX_NULL;
61
62 #if LWIP_TCPIP_CORE_LOCKING
63 /** The global semaphore to lock the stack. */
64 sys_sem_t lock_tcpip_core = 0;
65 #endif /* LWIP_TCPIP_CORE_LOCKING */
66
67 #if LWIP_TCP
68 /* global variable that shows if the tcp timer is currently scheduled or not */
69 static int tcpip_tcp_timer_active = 0;
70
71 /**
72  * Timer callback function that calls tcp_tmr() and reschedules itself.
73  *
74  * @param arg unused argument
75  */
76 static void
77 tcpip_tcp_timer(void *arg)
78 {
79   LWIP_UNUSED_ARG(arg);
80
81   /* call TCP timer handler */
82   tcp_tmr();
83   /* timer still needed? */
84   if (tcp_active_pcbs || tcp_tw_pcbs) {
85     /* restart timer */
86     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
87   } else {
88     /* disable timer */
89     tcpip_tcp_timer_active = 0;
90   }
91 }
92
93 #if !NO_SYS
94 /**
95  * Called from TCP_REG when registering a new PCB:
96  * the reason is to have the TCP timer only running when
97  * there are active (or time-wait) PCBs.
98  */
99 void
100 tcp_timer_needed(void)
101 {
102   /* timer is off but needed again? */
103   if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
104     /* enable and start timer */
105     tcpip_tcp_timer_active = 1;
106     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
107   }
108 }
109 #endif /* !NO_SYS */
110 #endif /* LWIP_TCP */
111
112 #if IP_REASSEMBLY
113 /**
114  * Timer callback function that calls ip_reass_tmr() and reschedules itself.
115  *
116  * @param arg unused argument
117  */
118 static void
119 ip_reass_timer(void *arg)
120 {
121   LWIP_UNUSED_ARG(arg);
122   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
123   ip_reass_tmr();
124   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
125 }
126 #endif /* IP_REASSEMBLY */
127
128 #if LWIP_ARP
129 /**
130  * Timer callback function that calls etharp_tmr() and reschedules itself.
131  *
132  * @param arg unused argument
133  */
134 static void
135 arp_timer(void *arg)
136 {
137   LWIP_UNUSED_ARG(arg);
138   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
139   etharp_tmr();
140   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
141 }
142 #endif /* LWIP_ARP */
143
144 #if LWIP_DHCP
145 /**
146  * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
147  *
148  * @param arg unused argument
149  */
150 static void
151 dhcp_timer_coarse(void *arg)
152 {
153   LWIP_UNUSED_ARG(arg);
154   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
155   dhcp_coarse_tmr();
156   sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
157 }
158
159 /**
160  * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
161  *
162  * @param arg unused argument
163  */
164 static void
165 dhcp_timer_fine(void *arg)
166 {
167   LWIP_UNUSED_ARG(arg);
168   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
169   dhcp_fine_tmr();
170   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
171 }
172 #endif /* LWIP_DHCP */
173
174 #if LWIP_AUTOIP
175 /**
176  * Timer callback function that calls autoip_tmr() and reschedules itself.
177  *
178  * @param arg unused argument
179  */
180 static void
181 autoip_timer(void *arg)
182 {
183   LWIP_UNUSED_ARG(arg);
184   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
185   autoip_tmr();
186   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
187 }
188 #endif /* LWIP_AUTOIP */
189
190 #if LWIP_IGMP
191 /**
192  * Timer callback function that calls igmp_tmr() and reschedules itself.
193  *
194  * @param arg unused argument
195  */
196 static void
197 igmp_timer(void *arg)
198 {
199   LWIP_UNUSED_ARG(arg);
200   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
201   igmp_tmr();
202   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
203 }
204 #endif /* LWIP_IGMP */
205
206 #if LWIP_ARP
207 /**
208  * Process received ethernet frames. Using this function instead of directly
209  * calling ip_input and passing ARP frames through etharp in ethernetif_input,
210  * the ARP cache is protected from concurrent access.
211  *
212  * @param p the recevied packet, p->payload pointing to the ethernet header
213  * @param netif the network interface on which the packet was received
214  */
215 static err_t
216 ethernet_input(struct pbuf *p, struct netif *netif)
217 {
218   struct eth_hdr* ethhdr;
219
220   /* points to packet payload, which starts with an Ethernet header */
221   ethhdr = p->payload;
222   
223   switch (htons(ethhdr->type)) {
224     /* IP packet? */
225     case ETHTYPE_IP:
226 #if ETHARP_TRUST_IP_MAC
227       /* update ARP table */
228       etharp_ip_input( netif, p);
229 #endif /* ETHARP_TRUST_IP_MAC */
230       /* skip Ethernet header */
231       if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {
232         LWIP_ASSERT("Can't move over header in packet", 0);
233         pbuf_free(p);
234         p = NULL;
235       } else {
236         /* pass to IP layer */
237         ip_input(p, netif);
238       }
239       break;
240       
241     case ETHTYPE_ARP:
242       /* pass p to ARP module */
243       etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);
244       break;
245
246 #if PPPOE_SUPPORT
247     case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */
248       pppoe_disc_input(netif, p);
249       break;
250
251     case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */
252       pppoe_data_input(netif, p);
253       break;
254 #endif /* PPPOE_SUPPORT */
255
256     default:
257       pbuf_free(p);
258       p = NULL;
259       break;
260   }
261
262   return ERR_OK; /* return value ignored */
263 }
264 #endif /* LWIP_ARP */
265
266 /**
267  * The main lwIP thread. This thread has exclusive access to lwIP core functions
268  * (unless access to them is not locked). Other threads communicate with this
269  * thread using message boxes.
270  *
271  * It also starts all the timers to make sure they are running in the right
272  * thread context.
273  *
274  * @param arg unused argument
275  */
276 static void
277 tcpip_thread(void *arg)
278 {
279   struct tcpip_msg *msg;
280   LWIP_UNUSED_ARG(arg);
281
282 #if IP_REASSEMBLY
283   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
284 #endif /* IP_REASSEMBLY */
285 #if LWIP_ARP
286   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
287 #endif /* LWIP_ARP */
288 #if LWIP_DHCP
289   sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
290   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
291 #endif /* LWIP_DHCP */
292 #if LWIP_AUTOIP
293   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
294 #endif /* LWIP_AUTOIP */
295 #if LWIP_IGMP
296   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
297 #endif /* LWIP_IGMP */
298
299   if (tcpip_init_done != NULL) {
300     tcpip_init_done(tcpip_init_done_arg);
301   }
302
303   LOCK_TCPIP_CORE();
304   while (1) {                          /* MAIN Loop */
305     sys_mbox_fetch(mbox, (void *)&msg);
306     switch (msg->type) {
307     case TCPIP_MSG_API:
308       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
309       msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
310       break;
311
312     case TCPIP_MSG_INPKT:
313       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
314 #if LWIP_ARP
315       if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
316         ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
317       } else
318 #endif /* LWIP_ARP */
319       { ip_input(msg->msg.inp.p, msg->msg.inp.netif);
320       }
321       memp_free(MEMP_TCPIP_MSG_INPKT, msg);
322       break;
323
324 #if LWIP_NETIF_API
325     case TCPIP_MSG_NETIFAPI:
326       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
327       msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
328       break;
329 #endif /* LWIP_NETIF_API */
330
331     case TCPIP_MSG_CALLBACK:
332       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
333       msg->msg.cb.f(msg->msg.cb.ctx);
334       memp_free(MEMP_TCPIP_MSG_API, msg);
335       break;
336
337     case TCPIP_MSG_TIMEOUT:
338       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
339
340       if(msg->msg.tmo.msecs != 0xffffffff)
341         sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
342       else
343         sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);
344       memp_free(MEMP_TCPIP_MSG_API, msg);
345       break;
346
347     default:
348       break;
349     }
350   }
351 }
352
353 #if LWIP_ARP
354 /**
355  * Pass a received packet to tcpip_thread for input processing
356  *
357  * @param p the received packet, p->payload pointing to the Ethernet header or
358  *          to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)
359  * @param netif the network interface on which the packet was received
360  */
361 err_t
362 tcpip_input(struct pbuf *p, struct netif *inp)
363 {
364   struct tcpip_msg *msg;
365
366   if (mbox != SYS_MBOX_NULL) {
367     msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);
368     if (msg == NULL) {
369       return ERR_MEM;
370     }
371
372     msg->type = TCPIP_MSG_INPKT;
373     msg->msg.inp.p = p;
374     msg->msg.inp.netif = inp;
375     sys_mbox_post(mbox, msg);
376     return ERR_OK;
377   }
378   return ERR_VAL;
379 }
380 #endif /* LWIP_ARP */
381
382 /**
383  * Call a specific function in the thread context of
384  * tcpip_thread for easy access synchronization.
385  * A function called in that way may access lwIP core code
386  * without fearing concurrent access.
387  *
388  * @param f the function to call
389  * @param ctx parameter passed to f
390  * @return ERR_OK if the function was called, another err_t if not
391  */
392 err_t
393 tcpip_callback(void (*f)(void *ctx), void *ctx)
394 {
395   struct tcpip_msg *msg;
396
397   if (mbox != SYS_MBOX_NULL) {
398     msg = memp_malloc(MEMP_TCPIP_MSG_API);
399     if (msg == NULL) {
400       return ERR_MEM;
401     }
402
403     msg->type = TCPIP_MSG_CALLBACK;
404     msg->msg.cb.f = f;
405     msg->msg.cb.ctx = ctx;
406     sys_mbox_post(mbox, msg);
407     return ERR_OK;
408   }
409   return ERR_VAL;
410 }
411
412 err_t
413 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
414 {
415   struct tcpip_msg *msg;
416
417   if (mbox != SYS_MBOX_NULL) {
418     msg = memp_malloc(MEMP_TCPIP_MSG_API);
419     if (msg == NULL) {
420       return ERR_MEM;
421     }
422
423     msg->type = TCPIP_MSG_TIMEOUT;
424     msg->msg.tmo.msecs = msecs;
425     msg->msg.tmo.h = h;
426     msg->msg.tmo.arg = arg;
427     sys_mbox_post(mbox, msg);
428     return ERR_OK;
429   }
430   return ERR_VAL;
431 }
432
433 /**
434  * Call the lower part of a netconn_* function
435  * This function is then running in the thread context
436  * of tcpip_thread and has exclusive access to lwIP core code.
437  *
438  * @param apimsg a struct containing the function to call and its parameters
439  * @return ERR_OK if the function was called, another err_t if not
440  */
441 err_t
442 tcpip_apimsg(struct api_msg *apimsg)
443 {
444   struct tcpip_msg msg;
445   
446   if (mbox != SYS_MBOX_NULL) {
447     msg.type = TCPIP_MSG_API;
448     msg.msg.apimsg = apimsg;
449     sys_mbox_post(mbox, &msg);
450     sys_arch_mbox_fetch(apimsg->msg.conn->mbox, NULL, 0);
451     return ERR_OK;
452   }
453   return ERR_VAL;
454 }
455
456 #if LWIP_TCPIP_CORE_LOCKING
457 /**
458  * Call the lower part of a netconn_* function
459  * This function has exclusive access to lwIP core code by locking it
460  * before the function is called.
461  *
462  * @param apimsg a struct containing the function to call and its parameters
463  * @return ERR_OK (only for compatibility fo tcpip_apimsg())
464  */
465 err_t
466 tcpip_apimsg_lock(struct api_msg *apimsg)
467 {
468   LOCK_TCPIP_CORE();
469   apimsg->function(&(apimsg->msg));
470   UNLOCK_TCPIP_CORE();
471   return ERR_OK;
472
473 }
474 #endif /* LWIP_TCPIP_CORE_LOCKING */
475
476 #if LWIP_NETIF_API
477 #if !LWIP_TCPIP_CORE_LOCKING
478 /**
479  * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
480  * function.
481  *
482  * @param netifapimsg a struct containing the function to call and its parameters
483  * @return error code given back by the function that was called
484  */
485 err_t
486 tcpip_netifapi(struct netifapi_msg* netifapimsg)
487 {
488   struct tcpip_msg msg;
489   
490   if (mbox != SYS_MBOX_NULL) {
491     netifapimsg->msg.sem = sys_sem_new(0);
492     if (netifapimsg->msg.sem == SYS_SEM_NULL) {
493       netifapimsg->msg.err = ERR_MEM;
494       return netifapimsg->msg.err;
495     }
496     
497     msg.type = TCPIP_MSG_NETIFAPI;
498     msg.msg.netifapimsg = netifapimsg;
499     sys_mbox_post(mbox, &msg);
500     sys_sem_wait(netifapimsg->msg.sem);
501     sys_sem_free(netifapimsg->msg.sem);
502     return netifapimsg->msg.err;
503   }
504   return ERR_VAL;
505 }
506 #else /* !LWIP_TCPIP_CORE_LOCKING */
507 /**
508  * Call the lower part of a netifapi_* function
509  * This function has exclusive access to lwIP core code by locking it
510  * before the function is called.
511  *
512  * @param netifapimsg a struct containing the function to call and its parameters
513  * @return ERR_OK (only for compatibility fo tcpip_netifapi())
514  */
515 err_t
516 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
517 {
518   LOCK_TCPIP_CORE();  
519   netifapimsg->function(&(netifapimsg->msg));
520   UNLOCK_TCPIP_CORE();
521   return netifapimsg->msg.err;
522 }
523 #endif /* !LWIP_TCPIP_CORE_LOCKING */
524 #endif /* LWIP_NETIF_API */
525
526 /**
527  * Initialize this module:
528  * - initialize all sub modules
529  * - start the tcpip_thread
530  *
531  * @param initfunc a function to call when tcpip_thread is running and finished initializing
532  * @param arg argument to pass to initfunc
533  */
534 void
535 tcpip_init(void (* initfunc)(void *), void *arg)
536 {
537   lwip_init();
538
539   tcpip_init_done = initfunc;
540   tcpip_init_done_arg = arg;
541   mbox = sys_mbox_new();
542 #if LWIP_TCPIP_CORE_LOCKING
543   lock_tcpip_core = sys_sem_new(1);
544 #endif /* LWIP_TCPIP_CORE_LOCKING */
545
546   sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
547 }
548
549 #endif /* !NO_SYS */