* applied patches from the most recent FreiFunkFirmware (and fixed compile errors...
[olsrd.git] / src / parser.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  * $Id: parser.c,v 1.32 2007/01/31 12:36:50 bernd67 Exp $
40  */
41
42 #include "parser.h"
43 #include "defs.h"
44 #include "process_package.h"
45 #include "mantissa.h"
46 #include "hysteresis.h"
47 #include "duplicate_set.h"
48 #include "mid_set.h"
49 #include "olsr.h"
50 #include "rebuild_packet.h"
51 #include "net_os.h"
52 #include "log.h"
53 #include "print_packet.h"
54
55 #ifdef WIN32
56 #undef EWOULDBLOCK
57 #define EWOULDBLOCK WSAEWOULDBLOCK
58 #undef errno
59 #define errno WSAGetLastError()
60 #undef strerror
61 #define strerror(x) StrError(x)
62 #endif
63
64 /* Sven-Ola: On very slow devices used in huge networks
65  * the amount of lq_tc messages is so high, that the 
66  * recv() loop never ends. This is a small hack to end
67  * the loop in this cases
68  */
69  
70 unsigned int cpu_overload_exit = 0;
71
72 struct parse_function_entry *parse_functions;
73
74 static char inbuf[MAXMESSAGESIZE+1];
75
76 static olsr_bool disp_pack_in = OLSR_FALSE;
77
78 void
79 parser_set_disp_pack_in(olsr_bool val)
80 {
81   disp_pack_in = val;
82 }
83
84 /**
85  *Initialize the parser. 
86  *
87  *@return nada
88  */
89 void
90 olsr_init_parser()
91 {
92   OLSR_PRINTF(3, "Initializing parser...\n")
93
94   /* Initialize the packet functions */
95   olsr_init_package_process();
96
97 }
98
99 void
100 olsr_parser_add_function(void (*function)(union olsr_message *, struct interface *, union olsr_ip_addr *), olsr_u32_t type, int forwarding)
101 {
102   struct parse_function_entry *new_entry;
103
104   OLSR_PRINTF(3, "Parser: registering event for type %d\n", type)
105  
106
107   new_entry = olsr_malloc(sizeof(struct parse_function_entry), "Register parse function");
108
109   new_entry->function = function;
110   new_entry->type = type;
111   new_entry->caller_forwarding = forwarding;
112
113   /* Queue */
114   new_entry->next = parse_functions;
115   parse_functions = new_entry;
116
117   OLSR_PRINTF(3, "Register parse function: Added function for type %d\n", type)
118
119 }
120
121
122
123 int
124 olsr_parser_remove_function(void (*function)(union olsr_message *, struct interface *, union olsr_ip_addr *), olsr_u32_t type, int forwarding)
125 {
126   struct parse_function_entry *entry, *prev;
127
128   entry = parse_functions;
129   prev = NULL;
130
131   while(entry)
132     {
133       if((entry->function == function) &&
134          (entry->type == type) &&
135          (entry->caller_forwarding == forwarding))
136         {
137           if(entry == parse_functions)
138             {
139               parse_functions = entry->next;
140             }
141           else
142             {
143               prev->next = entry->next;
144             }
145           free(entry);
146           return 1;
147         }
148
149       prev = entry;
150       entry = entry->next;
151     }
152
153   return 0;
154 }
155
156
157 /**
158  *Process a newly received OLSR packet. Checks the type
159  *and to the neccessary convertions and call the
160  *corresponding functions to handle the information.
161  *@param from the sockaddr struct describing the sender
162  *@param olsr the olsr struct containing the message
163  *@param size the size of the message
164  *@return nada
165  */
166
167 void
168 parse_packet(struct olsr *olsr, int size, struct interface *in_if, union olsr_ip_addr *from_addr)
169 {
170   union olsr_message *m = (union olsr_message *)olsr->olsr_msg;
171   struct unknown_message unkpacket;
172   int count;
173   int msgsize;
174   int processed;
175   struct parse_function_entry *entry;
176
177   count = size - ((char *)m - (char *)olsr);
178
179   if (count < MIN_PACKET_SIZE(olsr_cnf->ip_version))
180     return;
181
182   if (ntohs(olsr->olsr_packlen) != size)
183     {
184       OLSR_PRINTF(1, "Size error detected in received packet.\nRecieved %d, in packet %d\n", size, ntohs(olsr->olsr_packlen))
185             
186       olsr_syslog(OLSR_LOG_ERR, " packet length error in  packet received from %s!",
187              olsr_ip_to_string(from_addr));
188       return;
189     }
190
191   //printf("Message from %s\n\n", olsr_ip_to_string(from_addr)); 
192       
193   /* Display packet */
194   if(disp_pack_in)
195     print_olsr_serialized_packet(stdout, (union olsr_packet *)olsr, size, from_addr);
196
197   if(olsr_cnf->ip_version == AF_INET)
198     msgsize = ntohs(m->v4.olsr_msgsize);
199   else
200     msgsize = ntohs(m->v6.olsr_msgsize);
201
202
203   /*
204    * Hysteresis update - for every OLSR package
205    */
206   if(olsr_cnf->use_hysteresis)
207     {
208       if(olsr_cnf->ip_version == AF_INET)
209         {
210           /* IPv4 */
211           update_hysteresis_incoming(from_addr, 
212                                      in_if,
213                                      ntohs(olsr->olsr_seqno));
214         }
215       else
216         {
217           /* IPv6 */
218           update_hysteresis_incoming(from_addr, 
219                                      in_if, 
220                                      ntohs(olsr->olsr_seqno));
221         }
222     }
223
224   if (olsr_cnf->lq_level > 0)
225     {
226       olsr_update_packet_loss(from_addr, in_if,
227                               ntohs(olsr->olsr_seqno));
228     }
229   
230   for ( ; count > 0; m = (union olsr_message *)((char *)m + (msgsize)))
231     {
232
233       processed = 0;      
234       if (count < MIN_PACKET_SIZE(olsr_cnf->ip_version))
235         break;
236       
237       if(olsr_cnf->ip_version == AF_INET)
238         msgsize = ntohs(m->v4.olsr_msgsize);
239       else
240         msgsize = ntohs(m->v6.olsr_msgsize);
241       
242       count -= msgsize;
243
244       /* Check size of message */
245       if(count < 0)
246         {
247           OLSR_PRINTF(1, "packet length error in  packet received from %s!",
248                       olsr_ip_to_string(from_addr))
249
250           olsr_syslog(OLSR_LOG_ERR, " packet length error in  packet received from %s!",
251                  olsr_ip_to_string(from_addr));
252           break;
253         }
254
255
256       /* Treat TTL hopcnt */
257       if(olsr_cnf->ip_version == AF_INET)
258         {
259           /* IPv4 */
260           if (m->v4.ttl <= 0 && olsr_cnf->lq_fish == 0)
261             {
262               OLSR_PRINTF(2, "Dropping packet type %d from neigh %s with TTL 0\n", 
263                           m->v4.olsr_msgtype,
264                           olsr_ip_to_string(from_addr))
265               continue;
266             }
267         }
268       else
269         {
270           /* IPv6 */
271           if (m->v6.ttl <= 0 && olsr_cnf->lq_fish == 0) 
272             {
273               OLSR_PRINTF(2, "Dropping packet type %d from %s with TTL 0\n", 
274                           m->v4.olsr_msgtype,
275                           olsr_ip_to_string(from_addr))
276               continue;
277             }
278         }
279
280       /*RFC 3626 section 3.4:
281        *  2    If the time to live of the message is less than or equal to
282        *  '0' (zero), or if the message was sent by the receiving node
283        *  (i.e., the Originator Address of the message is the main
284        *  address of the receiving node): the message MUST silently be
285        *  dropped.
286        */
287
288       /* Should be the same for IPv4 and IPv6 */
289       if(COMP_IP(&m->v4.originator, &olsr_cnf->main_addr))
290         {
291 #ifdef DEBUG
292           OLSR_PRINTF(3, "Not processing message originating from us!\n")
293 #endif
294           continue;
295         }
296
297
298       //printf("MESSAGETYPE: %d\n", m->v4.olsr_msgtype);
299
300       entry = parse_functions;
301
302       while(entry)
303         {
304           /* Should be the same for IPv4 and IPv6 */
305
306           /* Promiscuous or exact match */
307           if((entry->type == PROMISCUOUS) || 
308              (entry->type == m->v4.olsr_msgtype))
309             {
310               entry->function(m, in_if, from_addr);
311               if(entry->caller_forwarding)
312                 processed = 1;
313             }
314           entry = entry->next;
315         }
316
317
318       /* UNKNOWN PACKETTYPE */
319       if(processed == 0)
320         {
321           unk_chgestruct(&unkpacket, m);
322           
323           OLSR_PRINTF(3, "Unknown type: %d, size %d, from %s\n",
324                       m->v4.olsr_msgtype,
325                       size,
326                       olsr_ip_to_string(&unkpacket.originator))
327
328           /* Forward message */
329           if(!COMP_IP(&unkpacket.originator, &olsr_cnf->main_addr))
330             {         
331               /* Forward */
332               olsr_forward_message(m, 
333                                    &unkpacket.originator, 
334                                    unkpacket.seqno, 
335                                    in_if,
336                                    from_addr);
337             }
338
339         }
340
341     } /* for olsr_msg */ 
342
343
344 }
345
346
347
348
349 /**
350  *Processing OLSR data from socket. Reading data, setting 
351  *wich interface recieved the message, Sends IPC(if used) 
352  *and passes the packet on to parse_packet().
353  *
354  *@param fd the filedescriptor that data should be read from.
355  *@return nada
356  */
357 void
358 olsr_input(int fd)
359 {
360   /* sockaddr_in6 is bigger than sockaddr !!!! */
361   struct sockaddr_storage from;
362   socklen_t fromlen;
363   int cc;
364   struct interface *olsr_in_if;
365   union olsr_ip_addr from_addr;
366   cpu_overload_exit = 0;
367   
368   for (;;) 
369     {
370       if (32 < ++cpu_overload_exit)
371       {
372         OLSR_PRINTF(1, "CPU overload detected, ending olsr_input() loop\n")
373         break;
374       }
375       
376       fromlen = sizeof(struct sockaddr_storage);
377
378       cc = olsr_recvfrom(fd, 
379                          inbuf, 
380                          sizeof (inbuf), 
381                          0, 
382                          (struct sockaddr *)&from, 
383                          &fromlen);
384
385       if (cc <= 0) 
386         {
387           if (cc < 0 && errno != EWOULDBLOCK)
388             {
389               OLSR_PRINTF(1, "error recvfrom: %s", strerror(errno))
390               olsr_syslog(OLSR_LOG_ERR, "error recvfrom: %m");
391             }
392           break;
393         }
394
395       if(olsr_cnf->ip_version == AF_INET)
396         {
397           /* IPv4 sender address */
398           COPY_IP(&from_addr, &((struct sockaddr_in *)&from)->sin_addr.s_addr);
399         }
400       else
401         {
402           /* IPv6 sender address */
403           COPY_IP(&from_addr, &((struct sockaddr_in6 *)&from)->sin6_addr);
404         }
405       
406       
407 #ifdef DEBUG
408       OLSR_PRINTF(5, "Recieved a packet from %s\n", olsr_ip_to_string((union olsr_ip_addr *)&((struct sockaddr_in *)&from)->sin_addr.s_addr))
409 #endif
410         
411         if ((olsr_cnf->ip_version == AF_INET) && (fromlen != sizeof (struct sockaddr_in)))
412           break;
413         else if ((olsr_cnf->ip_version == AF_INET6) && (fromlen != sizeof (struct sockaddr_in6)))
414           break;
415       
416       /* are we talking to ourselves? */
417       if(if_ifwithaddr(&from_addr) != NULL)
418         return;
419       
420       if((olsr_in_if = if_ifwithsock(fd)) == NULL)
421         {
422           OLSR_PRINTF(1, "Could not find input interface for message from %s size %d\n",
423                       olsr_ip_to_string(&from_addr),
424                       cc)
425           olsr_syslog(OLSR_LOG_ERR, "Could not find input interface for message from %s size %d\n",
426                  olsr_ip_to_string(&from_addr),
427                  cc);
428           return ;
429         }
430
431       /*
432        * &from - sender
433        * &inbuf.olsr 
434        * cc - bytes read
435        */
436       parse_packet((struct olsr *)inbuf, cc, olsr_in_if, &from_addr);
437     
438     }
439 }
440
441
442
443
444 /**
445  *Processing OLSR data from socket. Reading data, setting 
446  *wich interface recieved the message, Sends IPC(if used) 
447  *and passes the packet on to parse_packet().
448  *
449  *@param fd the filedescriptor that data should be read from.
450  *@return nada
451  */
452 void
453 olsr_input_hostemu(int fd)
454 {
455   /* sockaddr_in6 is bigger than sockaddr !!!! */
456   struct sockaddr_storage from;
457   socklen_t fromlen;
458   int cc;
459   struct interface *olsr_in_if;
460   union olsr_ip_addr from_addr;
461   olsr_u16_t pcklen;
462
463   /* Host emulator receives IP address first to emulate
464      direct link */
465
466   if((cc = recv(fd, from_addr.v6.s6_addr, olsr_cnf->ipsize, 0)) != (int)olsr_cnf->ipsize)
467     {
468       fprintf(stderr, "Error receiving host-client IP hook(%d) %s!\n", cc, strerror(errno));
469       COPY_IP(&from_addr, &((struct olsr *)inbuf)->olsr_msg->originator);
470     }
471
472   /* are we talking to ourselves? */
473   if(if_ifwithaddr(&from_addr) != NULL)
474     return;
475       
476   /* Extract size */
477   if((cc = recv(fd, &pcklen, 2, MSG_PEEK)) != 2)
478     {
479       if(cc <= 0)
480         {
481           fprintf(stderr, "Lost olsr_switch connection - exit!\n");
482           olsr_exit(__func__, EXIT_FAILURE);
483         }
484       fprintf(stderr, "[hust-emu] error extracting size(%d) %s!\n", cc, strerror(errno));
485       return;
486     }
487   else
488     {
489       pcklen = ntohs(pcklen);
490     }
491
492   fromlen = sizeof(struct sockaddr_storage);
493   
494   cc = olsr_recvfrom(fd, 
495                      inbuf, 
496                      pcklen, 
497                      0, 
498                      (struct sockaddr *)&from, 
499                      &fromlen);
500
501   if (cc <= 0) 
502     {
503       if (cc < 0 && errno != EWOULDBLOCK)
504         {
505           OLSR_PRINTF(1, "error recvfrom: %s", strerror(errno))
506             olsr_syslog(OLSR_LOG_ERR, "error recvfrom: %m");
507         }
508       return;
509     }
510   
511   if(cc != pcklen)
512     {
513       printf("Could not read whole packet(size %d, read %d)\n", pcklen, cc);
514       return;
515     }
516
517   if((olsr_in_if = if_ifwithsock(fd)) == NULL)
518     {
519       OLSR_PRINTF(1, "Could not find input interface for message from %s size %d\n",
520                   olsr_ip_to_string(&from_addr),
521                   cc)
522         olsr_syslog(OLSR_LOG_ERR, "Could not find input interface for message from %s size %d\n",
523                     olsr_ip_to_string(&from_addr),
524                     cc);
525       return;
526     }
527   
528   /*
529    * &from - sender
530    * &inbuf.olsr 
531    * cc - bytes read
532    */
533   parse_packet((struct olsr *)inbuf, cc, olsr_in_if, &from_addr);
534   
535 }
536
537