]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/api/tcpip.c
Comments Fix for Doxygen documentation
[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
48 #include "lwip/ip.h"
49 #include "lwip/ip_frag.h"
50 #include "lwip/udp.h"
51 #include "lwip/tcp.h"
52
53 #include "lwip/tcpip.h"
54 #include "lwip/igmp.h"
55
56 #if !NO_SYS
57
58 /* global variables */
59 static void (* tcpip_init_done)(void *arg) = NULL;
60 static void *tcpip_init_done_arg           = NULL;
61 static sys_mbox_t mbox                     = SYS_MBOX_NULL;
62
63 #if LWIP_TCPIP_CORE_LOCKING
64 /** The global semaphore to lock the stack. */
65 sys_sem_t lock_tcpip_core = 0;
66 #endif /* LWIP_TCPIP_CORE_LOCKING */
67
68 #if LWIP_TCP
69 /* global variable that shows if the tcp timer is currently scheduled or not */
70 static int tcpip_tcp_timer_active = 0;
71
72 /**
73  * Timer callback function that calls tcp_tmr() and reschedules itself.
74  *
75  * @param arg unused argument
76  */
77 static void
78 tcpip_tcp_timer(void *arg)
79 {
80   LWIP_UNUSED_ARG(arg);
81
82   /* call TCP timer handler */
83   tcp_tmr();
84   /* timer still needed? */
85   if (tcp_active_pcbs || tcp_tw_pcbs) {
86     /* restart timer */
87     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
88   } else {
89     /* disable timer */
90     tcpip_tcp_timer_active = 0;
91   }
92 }
93
94 #if !NO_SYS
95 /**
96  * Called from TCP_REG when registering a new PCB:
97  * the reason is to have the TCP timer only running when
98  * there are active (or time-wait) PCBs.
99  */
100 void
101 tcp_timer_needed(void)
102 {
103   /* timer is off but needed again? */
104   if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
105     /* enable and start timer */
106     tcpip_tcp_timer_active = 1;
107     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
108   }
109 }
110 #endif /* !NO_SYS */
111 #endif /* LWIP_TCP */
112
113 #if IP_REASSEMBLY
114 /**
115  * Timer callback function that calls ip_reass_tmr() and reschedules itself.
116  *
117  * @param arg unused argument
118  */
119 static void
120 ip_reass_timer(void *arg)
121 {
122   LWIP_UNUSED_ARG(arg);
123   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
124   ip_reass_tmr();
125   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
126 }
127 #endif /* IP_REASSEMBLY */
128
129 #if LWIP_ARP
130 /**
131  * Timer callback function that calls etharp_tmr() and reschedules itself.
132  *
133  * @param arg unused argument
134  */
135 static void
136 arp_timer(void *arg)
137 {
138   LWIP_UNUSED_ARG(arg);
139   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
140   etharp_tmr();
141   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
142 }
143 #endif /* LWIP_ARP */
144
145 #if LWIP_DHCP
146 /**
147  * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
148  *
149  * @param arg unused argument
150  */
151 static void
152 dhcp_timer_coarse(void *arg)
153 {
154   LWIP_UNUSED_ARG(arg);
155   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
156   dhcp_coarse_tmr();
157   sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
158 }
159
160 /**
161  * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
162  *
163  * @param arg unused argument
164  */
165 static void
166 dhcp_timer_fine(void *arg)
167 {
168   LWIP_UNUSED_ARG(arg);
169   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
170   dhcp_fine_tmr();
171   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
172 }
173 #endif /* LWIP_DHCP */
174
175 #if LWIP_AUTOIP
176 /**
177  * Timer callback function that calls autoip_tmr() and reschedules itself.
178  *
179  * @param arg unused argument
180  */
181 static void
182 autoip_timer(void *arg)
183 {
184   LWIP_UNUSED_ARG(arg);
185   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
186   autoip_tmr();
187   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
188 }
189 #endif /* LWIP_AUTOIP */
190
191 #if LWIP_IGMP
192 /**
193  * Timer callback function that calls igmp_tmr() and reschedules itself.
194  *
195  * @param arg unused argument
196  */
197 static void
198 igmp_timer(void *arg)
199 {
200   LWIP_UNUSED_ARG(arg);
201   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
202   igmp_tmr();
203   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
204 }
205 #endif /* LWIP_IGMP */
206
207 #if ETHARP_TCPIP_ETHINPUT
208 /**
209  * Process received ethernet frames. Using this function instead of directly
210  * calling ip_input and passing ARP frames through etharp in ethernetif_input,
211  * the ARP cache is protected from concurrent access.
212  *
213  * @param p the recevied packet, p->payload pointing to the ethernet header
214  * @param netif the network interface on which the packet was received
215  */
216 static void
217 ethernet_input(struct pbuf *p, struct netif *netif)
218 {
219   struct eth_hdr* ethhdr;
220
221   /* points to packet payload, which starts with an Ethernet header */
222   ethhdr = p->payload;
223   
224   switch (htons(ethhdr->type)) {
225     /* IP packet? */
226     case ETHTYPE_IP:
227 #if ETHARP_TRUST_IP_MAC
228       /* update ARP table */
229       etharp_ip_input( netif, p);
230 #endif
231       /* skip Ethernet header */
232       if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {
233         LWIP_ASSERT("Can't move over header in packet", 0);
234         pbuf_free(p);
235         p = NULL;
236       }
237       else
238         /* pass to IP layer */
239         ip_input(p, netif);
240       break;
241       
242     case ETHTYPE_ARP:
243       /* pass p to ARP module  */
244       etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);
245       break;
246
247     default:
248       pbuf_free(p);
249       p = NULL;
250       break;
251   }
252 }
253 #endif /* ETHARP_TCPIP_ETHINPUT */
254
255 /**
256  * The main lwIP thread. This thread has exclusive access to lwIP core functions
257  * (unless access to them is not locked). Other threads communicate with this
258  * thread using message boxes.
259  *
260  * It also starts all the timers to make sure they are running in the right
261  * thread context.
262  *
263  * @param arg unused argument
264  */
265 static void
266 tcpip_thread(void *arg)
267 {
268   struct tcpip_msg *msg;
269   LWIP_UNUSED_ARG(arg);
270
271 #if IP_REASSEMBLY
272   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
273 #endif /* IP_REASSEMBLY */
274 #if LWIP_ARP
275   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
276 #endif /* LWIP_ARP */
277 #if LWIP_DHCP
278   sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
279   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
280 #endif /* LWIP_DHCP */
281 #if LWIP_AUTOIP
282   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
283 #endif /* LWIP_AUTOIP */
284
285   if (tcpip_init_done != NULL) {
286     tcpip_init_done(tcpip_init_done_arg);
287   }
288
289 #if LWIP_IGMP
290   igmp_init();
291   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
292 #endif /* LWIP_IGMP */
293
294   LOCK_TCPIP_CORE();
295   while (1) {                          /* MAIN Loop */
296     sys_mbox_fetch(mbox, (void *)&msg);
297     switch (msg->type) {
298     case TCPIP_MSG_API:
299       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
300       msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
301       break;
302
303 #if ETHARP_TCPIP_INPUT      
304     case TCPIP_MSG_INPUT:
305       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: IP packet %p\n", (void *)msg));
306       ip_input(msg->msg.inp.p, msg->msg.inp.netif);
307       memp_free(MEMP_TCPIP_MSG, msg);
308       break;
309 #endif /* ETHARP_TCPIP_INPUT */
310
311 #if ETHARP_TCPIP_ETHINPUT
312     case TCPIP_MSG_ETHINPUT:
313       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Ethernet packet %p\n", (void *)msg));
314       ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
315       memp_free(MEMP_TCPIP_MSG, msg);
316       break;
317 #endif /* ETHARP_TCPIP_ETHINPUT */
318
319 #if LWIP_NETIF_API
320     case TCPIP_MSG_NETIFAPI:
321       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
322       msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
323       break;
324 #endif /* LWIP_NETIF_API */
325
326     case TCPIP_MSG_CALLBACK:
327       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
328       msg->msg.cb.f(msg->msg.cb.ctx);
329       memp_free(MEMP_TCPIP_MSG, msg);
330       break;
331     default:
332       break;
333     }
334   }
335 }
336
337 #if ETHARP_TCPIP_INPUT
338 /**
339  * Pass a received IP packet to tcpip_thread for input processing
340  *
341  * @param p the recevied packet, p->payload pointing to the IP header
342  * @param netif the network interface on which the packet was received
343  */
344 err_t
345 tcpip_input(struct pbuf *p, struct netif *inp)
346 {
347   struct tcpip_msg *msg;
348
349   if (mbox != SYS_MBOX_NULL) {
350     msg = memp_malloc(MEMP_TCPIP_MSG);
351     if (msg == NULL) {
352       return ERR_MEM;
353     }
354
355     msg->type = TCPIP_MSG_INPUT;
356     msg->msg.inp.p = p;
357     msg->msg.inp.netif = inp;
358     sys_mbox_post(mbox, msg);
359     return ERR_OK;
360   }
361   return ERR_VAL;
362 }
363 #endif /* ETHARP_TCPIP_INPUT */
364
365 #if ETHARP_TCPIP_ETHINPUT
366 /**
367  * Pass a received IP packet to tcpip_thread for input processing
368  *
369  * @param p the recevied packet, p->payload pointing to the ethernet header
370  * @param netif the network interface on which the packet was received
371  */
372 err_t
373 tcpip_ethinput(struct pbuf *p, struct netif *inp)
374 {
375   struct tcpip_msg *msg;
376
377   if (mbox != SYS_MBOX_NULL) {
378     msg = memp_malloc(MEMP_TCPIP_MSG);
379     if (msg == NULL) {
380       return ERR_MEM;
381     }
382     
383     msg->type = TCPIP_MSG_ETHINPUT;
384     msg->msg.inp.p = p;
385     msg->msg.inp.netif = inp;
386     sys_mbox_post(mbox, msg);
387     return ERR_OK;
388   }
389   return ERR_VAL;
390 }
391 #endif /* ETHARP_TCPIP_ETHINPUT */
392
393 /**
394  * Call a specific function in the thread context of
395  * tcpip_thread for easy access synchronization.
396  * A function called in that way may access lwIP core code
397  * without fearing concurrent access.
398  *
399  * @param f the function to call
400  * @param ctx parameter passed to f
401  * @return ERR_OK if the function was called, another err_t if not
402  */
403 err_t
404 tcpip_callback(void (*f)(void *ctx), void *ctx)
405 {
406   struct tcpip_msg *msg;
407
408   if (mbox != SYS_MBOX_NULL) {
409     msg = memp_malloc(MEMP_TCPIP_MSG);
410     if (msg == NULL) {
411       return ERR_MEM;
412     }
413
414     msg->type = TCPIP_MSG_CALLBACK;
415     msg->msg.cb.f = f;
416     msg->msg.cb.ctx = ctx;
417     sys_mbox_post(mbox, msg);
418     return ERR_OK;
419   }
420   return ERR_VAL;
421 }
422
423 /**
424  * Call the lower part of a netconn_* function
425  * This function is then running in the thread context
426  * of tcpip_thread and has exclusive access to lwIP core code.
427  *
428  * @param apimsg a struct containing the function to call and its parameters
429  * @return ERR_OK if the function was called, another err_t if not
430  */
431 err_t
432 tcpip_apimsg(struct api_msg *apimsg)
433 {
434   struct tcpip_msg msg;
435   
436   if (mbox != SYS_MBOX_NULL) {
437     msg.type = TCPIP_MSG_API;
438     msg.msg.apimsg = apimsg;
439     sys_mbox_post(mbox, &msg);
440     sys_arch_mbox_fetch(apimsg->msg.conn->mbox, NULL, 0);
441     return ERR_OK;
442   }
443   return ERR_VAL;
444 }
445
446 #if LWIP_TCPIP_CORE_LOCKING
447 /**
448  * Call the lower part of a netconn_* function
449  * This function has exclusive access to lwIP core code by locking it
450  * before the function is called.
451  *
452  * @param apimsg a struct containing the function to call and its parameters
453  * @return ERR_OK (only for compatibility fo tcpip_apimsg())
454  */
455 err_t
456 tcpip_apimsg_lock(struct api_msg *apimsg)
457 {
458   LOCK_TCPIP_CORE();
459   apimsg->function(&(apimsg->msg));
460   UNLOCK_TCPIP_CORE();
461   return ERR_OK;
462
463 }
464 #endif /* LWIP_TCPIP_CORE_LOCKING */
465
466 #if LWIP_NETIF_API
467 #if !LWIP_TCPIP_CORE_LOCKING
468 /**
469  * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
470  * function.
471  *
472  * @param netifapimsg a struct containing the function to call and its parameters
473  * @return error code given back by the function that was called
474  */
475 err_t
476 tcpip_netifapi(struct netifapi_msg* netifapimsg)
477 {
478   struct tcpip_msg msg;
479   
480   if (mbox != SYS_MBOX_NULL) {
481     netifapimsg->msg.sem = sys_sem_new(0);
482     if (netifapimsg->msg.sem == SYS_SEM_NULL) {
483       netifapimsg->msg.err = ERR_MEM;
484       return netifapimsg->msg.err;
485     }
486     
487     msg.type = TCPIP_MSG_NETIFAPI;
488     msg.msg.netifapimsg = netifapimsg;
489     sys_mbox_post(mbox, &msg);
490     sys_sem_wait(netifapimsg->msg.sem);
491     sys_sem_free(netifapimsg->msg.sem);
492     return netifapimsg->msg.err;
493   }
494   return ERR_VAL;
495 }
496 #else /* !LWIP_TCPIP_CORE_LOCKING */
497 /**
498  * Call the lower part of a netifapi_* function
499  * This function has exclusive access to lwIP core code by locking it
500  * before the function is called.
501  *
502  * @param netifapimsg a struct containing the function to call and its parameters
503  * @return ERR_OK (only for compatibility fo tcpip_netifapi())
504  */
505 err_t
506 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
507 {
508   LOCK_TCPIP_CORE();  
509   netifapimsg->function(&(netifapimsg->msg));
510   UNLOCK_TCPIP_CORE();
511   return netifapimsg->msg.err;
512 }
513 #endif /* !LWIP_TCPIP_CORE_LOCKING */
514 #endif /* LWIP_NETIF_API */
515
516 /**
517  * Initialize this module:
518  * - initialize ARP, IP, UDP and TCP
519  * - start the tcpip_thread
520  *
521  * @param initfunc a function to call when tcpip_thread is running and
522  *        finished initializing
523  * @param arg argument to pass to initfunc
524  */
525 void
526 tcpip_init(void (* initfunc)(void *), void *arg)
527 {
528 #if LWIP_ARP
529   etharp_init();
530 #endif /* LWIP_ARP */
531 #if LWIP_AUTOIP
532   autoip_init();
533 #endif /* LWIP_AUTOIP */
534   ip_init();
535 #if LWIP_UDP
536   udp_init();
537 #endif /* LWIP_UDP */
538 #if LWIP_TCP
539   tcp_init();
540 #endif /* LWIP_TCP */
541
542   tcpip_init_done = initfunc;
543   tcpip_init_done_arg = arg;
544   mbox = sys_mbox_new();
545 #if LWIP_TCPIP_CORE_LOCKING
546   lock_tcpip_core = sys_sem_new(1);
547 #endif /* LWIP_TCPIP_CORE_LOCKING */
548
549   sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);
550 }
551
552 #endif /* !NO_SYS */