Implementation of duplicate filter and UDP destination address/port filter (intermedi...
[olsrd.git] / lib / p2pd / src / p2pd.c
1 /*\r
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)\r
3  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file\r
4  * All rights reserved.\r
5  *\r
6  * Redistribution and use in source and binary forms, with or without\r
7  * modification, are permitted provided that the following conditions\r
8  * are met:\r
9  *\r
10  * * Redistributions of source code must retain the above copyright\r
11  *   notice, this list of conditions and the following disclaimer.\r
12  * * Redistributions in binary form must reproduce the above copyright\r
13  *   notice, this list of conditions and the following disclaimer in\r
14  *   the documentation and/or other materials provided with the\r
15  *   distribution.\r
16  * * Neither the name of olsr.org, olsrd nor the names of its\r
17  *   contributors may be used to endorse or promote products derived\r
18  *   from this software without specific prior written permission.\r
19  *\r
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
31  * POSSIBILITY OF SUCH DAMAGE.\r
32  *\r
33  * Visit http://www.olsr.org for more information.\r
34  *\r
35  * If you find this software useful feel free to make a donation\r
36  * to the project. For more information see the website or contact\r
37  * the copyright holders.\r
38  *\r
39  */\r
40 \r
41 \r
42 #include "p2pd.h"\r
43 \r
44 /* System includes */\r
45 #include <stddef.h>             /* NULL */\r
46 #include <sys/types.h>          /* ssize_t */\r
47 #include <string.h>             /* strerror() */\r
48 #include <stdarg.h>             /* va_list, va_start, va_end */\r
49 #include <errno.h>              /* errno */\r
50 #include <assert.h>             /* assert() */\r
51 #include <unistd.h>\r
52 #include <fcntl.h>\r
53 #include <linux/if_ether.h>     /* ETH_P_IP */\r
54 #include <linux/if_packet.h>    /* struct sockaddr_ll, PACKET_MULTICAST */\r
55 //#include <pthread.h> /* pthread_t, pthread_create() */\r
56 #include <signal.h>             /* sigset_t, sigfillset(), sigdelset(), SIGINT */\r
57 #include <netinet/ip.h>         /* struct ip */\r
58 #include <netinet/udp.h>        /* struct udphdr */\r
59 #include <unistd.h>             /* close() */\r
60 \r
61 #include <netinet/in.h>\r
62 #include <netinet/ip6.h>\r
63 \r
64 #include <time.h>\r
65 \r
66 /* OLSRD includes */\r
67 #include "plugin_util.h"        /* set_plugin_int */\r
68 #include "defs.h"               /* olsr_cnf, //OLSR_PRINTF */\r
69 #include "ipcalc.h"\r
70 #include "olsr.h"               /* //OLSR_PRINTF */\r
71 #include "mid_set.h"            /* mid_lookup_main_addr() */\r
72 #include "link_set.h"           /* get_best_link_to_neighbor() */\r
73 #include "net_olsr.h"           /* ipequal */\r
74 #include "parser.h"\r
75 \r
76 /* plugin includes */\r
77 #include "NetworkInterfaces.h"  /* NonOlsrInterface,\r
78                                    CreateBmfNetworkInterfaces(),\r
79                                    CloseBmfNetworkInterfaces() */\r
80 //#include "Address.h"          /* IsMulticast() */\r
81 #include "Packet.h"             /* ENCAP_HDR_LEN,\r
82                                    BMF_ENCAP_TYPE,\r
83                                    BMF_ENCAP_LEN etc. */\r
84 #include "PacketHistory.h"\r
85 #include "dllist.h"\r
86 \r
87 int P2pdTtl                        = 0;\r
88 int P2pdUseHash                    = 0;  /* Switch off hash filter by default */\r
89 int P2pdDuplicateTimeout           = P2PD_VALID_TIME;\r
90 \r
91 /* List of UDP destination address and port information */\r
92 struct UdpDestPort *                 UdpDestPortList = NULL;\r
93 \r
94 /* List of filter entries to check for duplicate messages\r
95  */\r
96 struct node *                        dupFilterHead = NULL;\r
97 struct node *                        dupFilterTail = NULL;\r
98 \r
99 clockid_t clockid = CLOCK_MONOTONIC;\r
100 \r
101 bool is_broadcast(const struct sockaddr_in addr);\r
102 bool is_multicast(const struct sockaddr_in addr);\r
103 char * get_ipv4_str(uint32_t address, char *s, size_t maxlen);\r
104 char * get_ipv6_str(unsigned char* address, char *s, size_t maxlen);\r
105 void dump_packet(unsigned char* packet, int length);\r
106 bool check_and_mark_recent_packet(unsigned char *data, int len);\r
107 \r
108 /* -------------------------------------------------------------------------\r
109  * Function   : PacketReceivedFromOLSR\r
110  * Description: Handle a received packet from a OLSR message\r
111  * Input      : ipPacket into an unsigned char and the lenght of the packet\r
112  * Output     : none\r
113  * Return     : none\r
114  * Data Used  : BmfInterfaces\r
115  * ------------------------------------------------------------------------- */\r
116 static void\r
117 PacketReceivedFromOLSR(unsigned char *encapsulationUdpData, int len)\r
118 {\r
119   struct ip *ipHeader;        /* IP header inside the encapsulated IP packet */\r
120   struct ip6_hdr *ip6Header;  /* IP header inside the encapsulated IP packet */\r
121   struct udphdr *udpHeader;\r
122   struct NonOlsrInterface *walker;\r
123   int stripped_len = 0;\r
124   union olsr_ip_addr destAddr;\r
125   int destPort;\r
126   bool isInList = false;\r
127 \r
128   ipHeader = (struct ip *)encapsulationUdpData;\r
129   ip6Header = (struct ip6_hdr *)encapsulationUdpData;\r
130   //OLSR_DEBUG(LOG_PLUGINS, "P2PD PLUGIN got packet from OLSR message\n");\r
131 \r
132   if (check_and_mark_recent_packet(encapsulationUdpData, len))\r
133     return;\r
134 \r
135   /* Check with each network interface what needs to be done on it */\r
136   for (walker = nonOlsrInterfaces; walker != NULL; walker = walker->next) {\r
137     /* To a non-OLSR interface: unpack encapsulated IP packet and forward it */\r
138     if (walker->olsrIntf == NULL) {\r
139       int nBytesWritten;\r
140       struct sockaddr_ll dest;\r
141 \r
142       memset(&dest, 0, sizeof(dest));\r
143       dest.sll_family = AF_PACKET;\r
144       if ((encapsulationUdpData[0] & 0xf0) == 0x40) {\r
145         dest.sll_protocol = htons(ETH_P_IP);\r
146         stripped_len = ntohs(ipHeader->ip_len);\r
147       }\r
148 \r
149       if ((encapsulationUdpData[0] & 0xf0) == 0x60) {\r
150         dest.sll_protocol = htons(ETH_P_IPV6);\r
151         stripped_len = 40 + ntohs(ip6Header->ip6_plen); // IPv6 Header size (40)\r
152                                                         // + payload_len\r
153       }\r
154 \r
155       // Sven-Ola: Don't know how to handle the "stripped_len is uninitialized"\r
156       // condition, maybe exit(1) is better...?\r
157       if (0 == stripped_len)\r
158         return;\r
159 \r
160       //TODO: if packet is not IP die here\r
161 \r
162       if (stripped_len > len) {\r
163       }\r
164 \r
165       dest.sll_ifindex = if_nametoindex(walker->ifName);\r
166       dest.sll_halen = IFHWADDRLEN;\r
167 \r
168       if (olsr_cnf->ip_version == AF_INET) {\r
169         /* Use all-ones as destination MAC address. When the IP destination is\r
170          * a multicast address, the destination MAC address should normally also\r
171          * be a multicast address. E.g., when the destination IP is 224.0.0.1,\r
172          * the destination MAC should be 01:00:5e:00:00:01. However, it does not\r
173          * seem to matter when the destination MAC address is set to all-ones\r
174          * in that case.\r
175          */\r
176 \r
177         if (IsMulticastv4(ipHeader)) {\r
178           dest.sll_addr[0] = 0x01;\r
179           dest.sll_addr[1] = 0x00;\r
180           dest.sll_addr[2] = 0x5E;\r
181           dest.sll_addr[3] = (ipHeader->ip_dst.s_addr >> 16) & 0x7F;\r
182           dest.sll_addr[4] = (ipHeader->ip_dst.s_addr >> 8) & 0xFF;\r
183           dest.sll_addr[5] = ipHeader->ip_dst.s_addr & 0xFF;\r
184         } else /* if (IsBroadcast(ipHeader)) */ {\r
185           memset(dest.sll_addr, 0xFF, IFHWADDRLEN);\r
186         }\r
187       } else /*(olsr_cnf->ip_version == AF_INET6) */ {\r
188         if (IsMulticastv6(ip6Header)) {\r
189           dest.sll_addr[0] = 0x33;\r
190           dest.sll_addr[1] = 0x33;\r
191           dest.sll_addr[2] = ip6Header->ip6_dst.s6_addr[12];\r
192           dest.sll_addr[3] = ip6Header->ip6_dst.s6_addr[13];\r
193           dest.sll_addr[4] = ip6Header->ip6_dst.s6_addr[14];\r
194           dest.sll_addr[5] = ip6Header->ip6_dst.s6_addr[15];\r
195         }\r
196       }\r
197 \r
198       if (olsr_cnf->ip_version == AF_INET) {\r
199         // Determine the IP address and the port from the header information\r
200         if (ipHeader->ip_p == SOL_UDP && !IsIpv4Fragment(ipHeader)) {\r
201           udpHeader = (struct udphdr*)(encapsulationUdpData +\r
202                                        GetIpHeaderLength(encapsulationUdpData));\r
203           destAddr.v4.s_addr = ipHeader->ip_dst.s_addr;\r
204           destPort = htons(udpHeader->dest);\r
205           isInList = InUdpDestPortList(AF_INET, &destAddr, destPort);\r
206 #ifdef INCLUDE_DEBUG_OUTPUT\r
207           if (!isInList) {\r
208             char tmp[32];\r
209             OLSR_PRINTF(1,\r
210                         "%s: Not in dest/port list: %s:%d\n",\r
211                         PLUGIN_NAME_SHORT,\r
212                         get_ipv4_str(destAddr.v4.s_addr,\r
213                                      tmp,\r
214                                      sizeof(tmp)),\r
215                         destPort);\r
216           }\r
217 #endif\r
218         }\r
219       } else /* (olsr_cnf->ip_version == AF_INET6) */ {\r
220         if (ip6Header->ip6_nxt == SOL_UDP && !IsIpv6Fragment(ip6Header)) {\r
221           udpHeader = (struct udphdr*)(encapsulationUdpData + 40);\r
222           memcpy(&destAddr.v6, &ip6Header->ip6_dst, sizeof(struct in6_addr));\r
223           destPort = htons(udpHeader->dest);\r
224           isInList = InUdpDestPortList(AF_INET6, &destAddr, destPort);\r
225 #ifdef INCLUDE_DEBUG_OUTPUT\r
226           if (!isInList) {\r
227             char tmp[64];\r
228             OLSR_PRINTF(1,\r
229                         "%s: Not in dest/port list: %s:%d\n",\r
230                         PLUGIN_NAME_SHORT,\r
231                         get_ipv6_str(destAddr.v6.s6_addr,\r
232                                      tmp,\r
233                                      sizeof(tmp)),\r
234                         destPort);\r
235           }\r
236 #endif\r
237         }\r
238       }\r
239 \r
240       if (!isInList) {\r
241         /* Address/port combination of this packet is not in the UDP dest/port\r
242          * list and will therefore be suppressed. I.e. just continue with the\r
243          * next interface to emit on.\r
244          */\r
245         continue;\r
246       }\r
247       \r
248       nBytesWritten = sendto(walker->capturingSkfd,\r
249                              encapsulationUdpData,\r
250                              stripped_len,\r
251                              0,\r
252                              (struct sockaddr *)&dest,\r
253                              sizeof(dest));\r
254       if (nBytesWritten != stripped_len) {\r
255         P2pdPError("sendto() error forwarding unpacked encapsulated pkt on \"%s\"",\r
256                    walker->ifName);\r
257       } else {\r
258 \r
259         //OLSR_PRINTF(\r
260         //  2,\r
261         //  "%s: --> unpacked and forwarded on \"%s\"\n",\r
262         //  PLUGIN_NAME_SHORT,\r
263         //  walker->ifName);\r
264       }\r
265     }                           /* if (walker->olsrIntf == NULL) */\r
266   }\r
267 }                               /* PacketReceivedFromOLSR */\r
268 \r
269 /* Highest-numbered open socket file descriptor. To be used as first\r
270  * parameter in calls to select(...).\r
271  */\r
272 int HighestSkfd = -1;\r
273 \r
274 /* Set of socket file descriptors */\r
275 fd_set InputSet;\r
276 \r
277 /* -------------------------------------------------------------------------\r
278  * Function   : p2pd_message_seen\r
279  * Description: Check whether the current message has been seen before\r
280  * Input      : head - start of the list to check for the message\r
281  *              tail - end of the list to check for the message\r
282  *              m    - message to check for in the list\r
283  * Output     : none\r
284  * Return     : true if message was found, false otherwise\r
285  * Data Used  : P2pdDuplicateTimeout\r
286  * ------------------------------------------------------------------------- */\r
287 bool\r
288 p2pd_message_seen(struct node **head, struct node **tail, union olsr_message *m)\r
289 {\r
290   struct node * curr;\r
291   time_t now;\r
292 \r
293   now = time(NULL);\r
294 \r
295   // Check whether any entries have aged\r
296   curr = *head;\r
297   while (curr) {\r
298     struct DupFilterEntry *filter;\r
299     struct node * next = curr->next; // Save the current pointer since curr may\r
300                                      // be destroyed\r
301 \r
302     filter = (struct DupFilterEntry*)curr->data;\r
303 \r
304     if ((filter->creationtime + P2pdDuplicateTimeout) < now)\r
305       remove_node(head, tail, curr, true);\r
306 \r
307     // Skip to the next element\r
308     curr = next;\r
309   }\r
310 \r
311   // Now check whether there are any duplicates\r
312   for (curr = *head; curr; curr = curr->next) {\r
313     struct DupFilterEntry *filter = (struct DupFilterEntry*)curr->data;\r
314 \r
315     if (olsr_cnf->ip_version == AF_INET) {\r
316       if (filter->address.v4.s_addr == m->v4.originator &&\r
317           filter->msgtype == m->v4.olsr_msgtype &&\r
318           filter->seqno == m->v4.seqno) {\r
319           return true;\r
320       }\r
321     } else /* if (olsr_cnf->ip_version == AF_INET6) */ {\r
322       if (memcmp(filter->address.v6.s6_addr,\r
323                  m->v6.originator.s6_addr,\r
324                  sizeof(m->v6.originator.s6_addr)) == 0 &&\r
325           filter->msgtype == m->v6.olsr_msgtype &&\r
326           filter->seqno == m->v6.seqno) {\r
327           return true;\r
328       }\r
329     }\r
330   }\r
331 \r
332   return false;\r
333 }\r
334 \r
335 /* -------------------------------------------------------------------------\r
336  * Function   : p2pd_store_message\r
337  * Description: Store a new message in the duplicate message check list\r
338  * Input      : head - start of the list to add the message to\r
339  *              tail - end of the list to add the message to\r
340  *              m    - message to add to the list\r
341  * Output     : none\r
342  * Return     : nothing\r
343  * Data Used  : none\r
344  * ------------------------------------------------------------------------- */\r
345 void\r
346 p2pd_store_message(struct node **head, struct node **tail, union olsr_message *m)\r
347 {\r
348   time_t now;\r
349 \r
350   // Store a message into the database\r
351   struct DupFilterEntry *new_dup = calloc(1, sizeof(struct DupFilterEntry));\r
352   if (new_dup == NULL) {\r
353     OLSR_PRINTF(1, "%s: Out of memory\n", PLUGIN_NAME_SHORT);\r
354     return;\r
355   }\r
356 \r
357   now = time(NULL);\r
358 \r
359   new_dup->creationtime = now;\r
360   if (olsr_cnf->ip_version == AF_INET) {\r
361     new_dup->address.v4.s_addr = m->v4.originator;\r
362     new_dup->msgtype           = m->v4.olsr_msgtype;\r
363     new_dup->seqno             = m->v4.seqno;\r
364   } else /* if (olsr_cnf->ip_version == AF_INET6) */ {\r
365     memcpy(new_dup->address.v6.s6_addr,\r
366            m->v6.originator.s6_addr,\r
367            sizeof(m->v6.originator.s6_addr));\r
368     new_dup->msgtype           = m->v6.olsr_msgtype;\r
369     new_dup->seqno             = m->v6.seqno;\r
370   }\r
371 \r
372   // Add the element to the head of the list\r
373   append_node(head, tail, new_dup);\r
374 }\r
375 \r
376 /* -------------------------------------------------------------------------\r
377  * Function   : p2pd_is_duplicate_message\r
378  * Description: Check whether the specified message is a duplicate\r
379  * Input      : msg - message to check for in the list of duplicate messages\r
380  * Output     : none\r
381  * Return     : true if message was found, false otherwise\r
382  * Data Used  : none\r
383  * ------------------------------------------------------------------------- */\r
384 bool\r
385 p2pd_is_duplicate_message(union olsr_message *msg)\r
386 {\r
387   if(p2pd_message_seen(&dupFilterHead, &dupFilterTail, msg)) {\r
388     return true;\r
389   }\r
390 \r
391   p2pd_store_message(&dupFilterHead, &dupFilterTail, msg);\r
392 \r
393   return false;\r
394 }\r
395 \r
396 /* -------------------------------------------------------------------------\r
397  * Function   : olsr_parser\r
398  * Description: Function to be passed to the parser engine. This function\r
399  *              processes the incoming message and passes it on if necessary.\r
400  * Input      : m      - message to parse\r
401  *              in_if  - interface to use (unused in this application)\r
402  *              ipaddr - IP-address to use (unused in this application)\r
403  * Output     : none\r
404  * Return     : false if message should be supressed, true otherwise\r
405  * Data Used  : none\r
406  * ------------------------------------------------------------------------- */\r
407 bool\r
408 olsr_parser(union olsr_message *m,\r
409             struct interface *in_if __attribute__ ((unused)),\r
410             union olsr_ip_addr *ipaddr __attribute__ ((unused)))\r
411 {\r
412   union olsr_ip_addr originator;\r
413   int size;\r
414   uint32_t vtime;\r
415 \r
416   //OLSR_DEBUG(LOG_PLUGINS, "P2PD PLUGIN: Received msg in parser\n");\r
417 \r
418         /* Fetch the originator of the messsage */\r
419   if (olsr_cnf->ip_version == AF_INET) {\r
420     memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);\r
421     vtime = me_to_reltime(m->v4.olsr_vtime);\r
422     size = ntohs(m->v4.olsr_msgsize);\r
423   } else {\r
424     memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);\r
425     vtime = me_to_reltime(m->v6.olsr_vtime);\r
426     size = ntohs(m->v6.olsr_msgsize);\r
427   }\r
428 \r
429   /* Check if message originated from this node.\r
430    *         If so - back off */\r
431   if (ipequal(&originator, &olsr_cnf->main_addr))\r
432     return false;          /* Don't forward either */\r
433 \r
434   /* Check for duplicate messages for processing */\r
435   if (p2pd_is_duplicate_message(m))\r
436     return true;  /* Don't process but allow to be forwarded */\r
437 \r
438   if (olsr_cnf->ip_version == AF_INET) {\r
439     PacketReceivedFromOLSR((unsigned char *)&m->v4.message, size - 12);\r
440   } else {\r
441     PacketReceivedFromOLSR((unsigned char *)&m->v6.message, size - 12 - 96);\r
442   }\r
443 \r
444         return true;\r
445 }\r
446 \r
447 /* -------------------------------------------------------------------------\r
448  * Function   : olsr_p2pd_gen\r
449  * Description: Sends a packet in the OLSR network\r
450  * Input      : packet - packet to send in the OLSR network\r
451  *              len    - length of the packet to send\r
452  * Output     : none\r
453  * Return     : nothing\r
454  * Data Used  : none\r
455  * ------------------------------------------------------------------------- */\r
456 void\r
457 olsr_p2pd_gen(unsigned char *packet, int len)\r
458 {\r
459   /* send buffer: huge */\r
460   char buffer[10240];\r
461   int aligned_size;\r
462   union olsr_message *message = (union olsr_message *)buffer;\r
463   struct interface *ifn;\r
464 \r
465   aligned_size=len;\r
466 \r
467   if ((aligned_size % 4) != 0) {\r
468     aligned_size = (aligned_size - (aligned_size % 4)) + 4;\r
469   }\r
470 \r
471   /* fill message */\r
472   if (olsr_cnf->ip_version == AF_INET) {\r
473     /* IPv4 */\r
474     message->v4.olsr_msgtype  = P2PD_MESSAGE_TYPE;\r
475     message->v4.olsr_vtime    = reltime_to_me(P2PD_VALID_TIME * MSEC_PER_SEC);\r
476     memcpy(&message->v4.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);\r
477     message->v4.ttl           = P2pdTtl ? P2pdTtl : MAX_TTL;\r
478     message->v4.hopcnt        = 0;\r
479     message->v4.seqno         = htons(get_msg_seqno());\r
480     message->v4.olsr_msgsize  = htons(aligned_size + 12);\r
481     memset(&message->v4.message, 0, aligned_size);\r
482     memcpy(&message->v4.message, packet, len);\r
483     aligned_size = aligned_size + 12;\r
484   } else /* if (olsr_cnf->ip_version == AF_INET6) */ {\r
485     /* IPv6 */\r
486     message->v6.olsr_msgtype  = P2PD_MESSAGE_TYPE;\r
487     message->v6.olsr_vtime    = reltime_to_me(P2PD_VALID_TIME * MSEC_PER_SEC);\r
488     memcpy(&message->v6.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);\r
489     message->v6.ttl           = P2pdTtl ? P2pdTtl : MAX_TTL;\r
490     message->v6.hopcnt        = 0;\r
491     message->v6.seqno         = htons(get_msg_seqno());\r
492     message->v6.olsr_msgsize  = htons(aligned_size + 12 + 96);\r
493     memset(&message->v6.message, 0, aligned_size);\r
494     memcpy(&message->v6.message, packet, len);\r
495     aligned_size = aligned_size + 12 + 96;\r
496   }\r
497 \r
498   /* looping through interfaces */\r
499   for (ifn = ifnet; ifn; ifn = ifn->int_next) {\r
500     //OLSR_PRINTF(1, "%s: Generating packet - [%s]\n", PLUGIN_NAME_SHORT, ifn->int_name);\r
501 \r
502     if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {\r
503       /* send data and try again */\r
504       net_output(ifn);\r
505       if (net_outbuffer_push(ifn, message, aligned_size) != aligned_size) {\r
506         //OLSR_PRINTF(1, "%s: could not send on interface: %s\n", PLUGIN_NAME_SHORT, ifn->int_name);\r
507       }\r
508     }\r
509   }\r
510 }\r
511 \r
512 /* -------------------------------------------------------------------------\r
513  * Function   : P2pdPError\r
514  * Description: Prints an error message at OLSR debug level 1.\r
515  *              First the plug-in name is printed. Then (if format is not NULL\r
516  *              and *format is not empty) the arguments are printed, followed\r
517  *              by a colon and a blank. Then the message and a new-line.\r
518  * Input      : format, arguments\r
519  * Output     : none\r
520  * Return     : none\r
521  * Data Used  : none\r
522  * ------------------------------------------------------------------------- */\r
523 void\r
524 P2pdPError(const char *format, ...)\r
525 {\r
526 #define MAX_STR_DESC 255\r
527   char strDesc[MAX_STR_DESC];\r
528 \r
529 #if !defined REMOVE_LOG_DEBUG\r
530   char *stringErr = strerror(errno);\r
531 #endif\r
532 \r
533   /* Rely on short-circuit boolean evaluation */\r
534   if (format == NULL || *format == '\0') {\r
535     //OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", PLUGIN_NAME, stringErr);\r
536   } else {\r
537     va_list arglist;\r
538 \r
539     va_start(arglist, format);\r
540     vsnprintf(strDesc, MAX_STR_DESC, format, arglist);\r
541     va_end(arglist);\r
542 \r
543     strDesc[MAX_STR_DESC - 1] = '\0';   /* Ensures null termination */\r
544 \r
545 #if !defined REMOVE_LOG_DEBUG\r
546     OLSR_DEBUG(LOG_PLUGINS, "%s: %s\n", strDesc, stringErr);\r
547 #endif\r
548   }\r
549 }                               /* P2pdPError */\r
550 \r
551 /* -------------------------------------------------------------------------\r
552  * Function   : MainAddressOf\r
553  * Description: Lookup the main address of a node\r
554  * Input      : ip - IP address of the node\r
555  * Output     : none\r
556  * Return     : The main IP address of the node\r
557  * Data Used  : none\r
558  * ------------------------------------------------------------------------- */\r
559 union olsr_ip_addr *\r
560 MainAddressOf(union olsr_ip_addr *ip)\r
561 {\r
562   union olsr_ip_addr *result;\r
563 \r
564   /* TODO: mid_lookup_main_addr() is not thread-safe! */\r
565   result = mid_lookup_main_addr(ip);\r
566   if (result == NULL) {\r
567     result = ip;\r
568   }\r
569   return result;\r
570 }                               /* MainAddressOf */\r
571 \r
572 \r
573 /* -------------------------------------------------------------------------\r
574  * Function   : InUdpDestPortList\r
575  * Description: Check whether the specified address and port is in the list of\r
576  *              configured UDP destination/port entries\r
577  * Input      : ip_version  - IP version to use for this check\r
578  *              addr        - address to check for in the list\r
579  *              port        - port to check for in the list\r
580  * Output     : none\r
581  * Return     : true if destination/port combination was found, false otherwise\r
582  * Data Used  : UdpDestPortList\r
583  * ------------------------------------------------------------------------- */\r
584 bool\r
585 InUdpDestPortList(int ip_version, union olsr_ip_addr *addr, uint16_t port)\r
586 {\r
587   struct UdpDestPort *walker;\r
588 \r
589   for (walker = UdpDestPortList; walker; walker = walker->next) {\r
590     if (walker->ip_version == ip_version) {\r
591       if (ip_version == AF_INET) {\r
592         if (addr->v4.s_addr == walker->address.v4.s_addr &&\r
593             walker->port == port)\r
594           return true;  // Found so we can stop here\r
595       } else /* ip_version == AF_INET6 */ {\r
596         if ((memcmp(addr->v6.s6_addr,\r
597                    walker->address.v6.s6_addr,\r
598                    sizeof(addr->v6.s6_addr)) == 0) &&\r
599             (walker->port == port))\r
600           return true;  // Found so we can stop here\r
601       }\r
602     }\r
603   }\r
604   return false;\r
605 }\r
606 \r
607 /* -------------------------------------------------------------------------\r
608  * Function   : P2pdPacketCaptured\r
609  * Description: Handle a captured IP packet\r
610  * Input      : encapsulationUdpData - space for the encapsulation header,\r
611  *              followed by the captured IP packet\r
612  *              nBytes - The number of bytes in the data packet\r
613  * Output     : none\r
614  * Return     : none\r
615  * Data Used  : P2pdInterfaces\r
616  * Notes      : The IP packet is assumed to be captured on a socket of family\r
617  *              PF_PACKET and type SOCK_DGRAM (cooked).\r
618  * ------------------------------------------------------------------------- */\r
619 static void\r
620 P2pdPacketCaptured(unsigned char *encapsulationUdpData, int nBytes)\r
621 {\r
622   union olsr_ip_addr src;      /* Source IP address in captured packet */\r
623   union olsr_ip_addr dst;      /* Destination IP address in captured packet */\r
624   union olsr_ip_addr *origIp;  /* Main OLSR address of source of captured packet */\r
625   struct ip *ipHeader;         /* The IP header inside the captured IP packet */\r
626   struct ip6_hdr *ipHeader6;   /* The IP header inside the captured IP packet */\r
627   struct udphdr *udpHeader;\r
628   u_int16_t destPort;\r
629 \r
630   if ((encapsulationUdpData[0] & 0xf0) == 0x40) {       //IPV4\r
631 \r
632     ipHeader = (struct ip *)encapsulationUdpData;\r
633 \r
634     dst.v4 = ipHeader->ip_dst;\r
635 \r
636     if (ipHeader->ip_p != SOL_UDP) {\r
637       /* Not UDP */\r
638 #ifdef INCLUDE_DEBUG_OUTPUT\r
639       OLSR_PRINTF(1,"%s: NON UDP PACKET\n", PLUGIN_NAME_SHORT);\r
640 #endif\r
641       return;                   /* for */\r
642     }\r
643 \r
644     // If we're dealing with a fragment we bail out here since there's no valid\r
645     // UDP header in this message\r
646     if (IsIpv4Fragment(ipHeader)) {\r
647 #ifdef INCLUDE_DEBUG_OUTPUT\r
648       OLSR_PRINTF(1, "%s: Is IPv4 fragment\n", PLUGIN_NAME_SHORT);\r
649 #endif\r
650       return;\r
651     }\r
652 \r
653     if (check_and_mark_recent_packet(encapsulationUdpData, nBytes))\r
654       return;\r
655 \r
656     udpHeader = (struct udphdr *)(encapsulationUdpData +\r
657                                   GetIpHeaderLength(encapsulationUdpData));\r
658     destPort = ntohs(udpHeader->dest);\r
659 \r
660     if (!InUdpDestPortList(AF_INET, &dst, destPort)) {\r
661 #ifdef INCLUDE_DEBUG_OUTPUT\r
662       char tmp[32];\r
663       OLSR_PRINTF(1, "%s: Not in dest/port list: %s:%d\n", PLUGIN_NAME_SHORT,\r
664                   get_ipv4_str(dst.v4.s_addr, tmp, sizeof(tmp)), destPort);\r
665 #endif\r
666        return;\r
667     }\r
668   }                            //END IPV4\r
669   else if ((encapsulationUdpData[0] & 0xf0) == 0x60) {  //IPv6\r
670 \r
671     ipHeader6 = (struct ip6_hdr *)encapsulationUdpData;\r
672 \r
673     memcpy(&dst.v6, &ipHeader6->ip6_dst, sizeof(struct in6_addr));\r
674 \r
675     if (ipHeader6->ip6_dst.s6_addr[0] == 0xff)  //Multicast\r
676     {\r
677       //Continue\r
678     } else {\r
679       return;                   //not multicast\r
680     }\r
681     if (ipHeader6->ip6_nxt != SOL_UDP) {\r
682       /* Not UDP */\r
683       //OLSR_PRINTF(1,"%s: NON UDP PACKET\n", PLUGIN_NAME_SHORT);\r
684       return;                   /* for */\r
685     }\r
686 \r
687     // Check whether this is a IPv6 fragment\r
688     if (IsIpv6Fragment(ipHeader6)) {\r
689 #ifdef INCLUDE_DEBUG_OUTPUT\r
690       OLSR_PRINTF(1, "%s: Is IPv6 fragment\n", PLUGIN_NAME_SHORT);\r
691 #endif\r
692       return;\r
693     }\r
694 \r
695     if (check_and_mark_recent_packet(encapsulationUdpData, nBytes))\r
696       return;\r
697 \r
698     udpHeader = (struct udphdr *)(encapsulationUdpData + 40);\r
699     destPort = ntohs(udpHeader->dest);\r
700 \r
701     if (!InUdpDestPortList(AF_INET6, &dst, destPort)) {\r
702 #ifdef INCLUDE_DEBUG_OUTPUT\r
703       char tmp[64];\r
704       OLSR_PRINTF(1, "%s: Not in dest/port list: %s:%d\n", PLUGIN_NAME_SHORT,\r
705                   get_ipv6_str(dst.v6.s6_addr, tmp, sizeof(tmp)), destPort);\r
706 #endif\r
707       return;\r
708     }\r
709   }                             //END IPV6\r
710   else {\r
711     return;                     //Is not IP packet\r
712   }\r
713 \r
714   /* Lookup main address of source in the MID table of OLSR */\r
715   origIp = MainAddressOf(&src);\r
716 \r
717   // send the packet to OLSR forward mechanism\r
718   olsr_p2pd_gen(encapsulationUdpData, nBytes);\r
719 }                               /* P2pdPacketCaptured */\r
720 \r
721 \r
722 /* -------------------------------------------------------------------------\r
723  * Function   : DoP2pd\r
724  * Description: This function is registered with the OLSR scheduler and called\r
725  *              when something is captured\r
726  * Input      : none\r
727  * Output     : none\r
728  * Return     : none\r
729  * Data Used  :\r
730  * ------------------------------------------------------------------------- */\r
731 void\r
732 DoP2pd(int skfd,\r
733        void *data __attribute__ ((unused)),\r
734        unsigned int flags __attribute__ ((unused)))\r
735 {\r
736   unsigned char rxBuffer[P2PD_BUFFER_SIZE];\r
737   if (skfd >= 0) {\r
738     struct sockaddr_ll pktAddr;\r
739     socklen_t addrLen = sizeof(pktAddr);\r
740     int nBytes;\r
741     unsigned char *ipPacket;\r
742 \r
743     /* Receive the captured Ethernet frame, leaving space for the BMF\r
744      * encapsulation header */\r
745     ipPacket = GetIpPacket(rxBuffer);\r
746     nBytes = recvfrom(skfd, ipPacket, P2PD_BUFFER_SIZE,\r
747                       0, (struct sockaddr *)&pktAddr, &addrLen);\r
748 #ifdef INCLUDE_DEBUG_OUTPUT\r
749     OLSR_PRINTF(1, "%s: Received %d bytes\n", PLUGIN_NAME_SHORT, nBytes);\r
750 #endif\r
751 \r
752     if (nBytes < 0) {\r
753 \r
754       return;                   /* for */\r
755     }\r
756 \r
757     /* if (nBytes < 0) */\r
758     /* Check if the number of received bytes is large enough for an IP\r
759      * packet which contains at least a minimum-size IP header.\r
760      * Note: There is an apparent bug in the packet socket implementation in\r
761      * combination with VLAN interfaces. On a VLAN interface, the value returned\r
762      * by 'recvfrom' may (but need not) be 4 (bytes) larger than the value\r
763      * returned on a non-VLAN interface, for the same ethernet frame. */\r
764     if (nBytes < (int)sizeof(struct ip)) {\r
765       ////OLSR_PRINTF(\r
766       //              1,\r
767       //              "%s: captured frame too short (%d bytes) on \"%s\"\n",\r
768       //              PLUGIN_NAME_SHORT,\r
769       //              nBytes,\r
770       //              walker->ifName);\r
771 \r
772       return;                   /* for */\r
773     }\r
774 \r
775     if (pktAddr.sll_pkttype == PACKET_OUTGOING ||\r
776         pktAddr.sll_pkttype == PACKET_MULTICAST ||\r
777         pktAddr.sll_pkttype == PACKET_BROADCAST) {\r
778 #ifdef INCLUDE_DEBUG_OUTPUT\r
779       OLSR_PRINTF(1, "%s: Multicast or broadcast packet was captured.\n",\r
780                   PLUGIN_NAME_SHORT);\r
781       dump_packet(ipPacket, nBytes);\r
782 #endif\r
783       /* A multicast or broadcast packet was captured */\r
784       P2pdPacketCaptured(ipPacket, nBytes);\r
785 \r
786     }                           /* if (pktAddr.sll_pkttype == ...) */\r
787   }                             /* if (skfd >= 0 && (FD_ISSET...)) */\r
788 }                               /* DoP2pd */\r
789 \r
790 /* -------------------------------------------------------------------------\r
791  * Function   : InitP2pd\r
792  * Description: Initialize the P2pd plugin\r
793  * Input      : skipThisInterface - pointer to interface to skip\r
794  * Output     : none\r
795  * Return     : Always 0\r
796  * Data Used  : none\r
797  * ------------------------------------------------------------------------- */\r
798 int\r
799 InitP2pd(struct interface *skipThisIntf)\r
800 {\r
801   if (P2pdUseHash) {\r
802     // Initialize hash table for hash based duplicate IP packet check\r
803     InitPacketHistory();\r
804   }\r
805 \r
806   //Tells OLSR to launch olsr_parser when the packets for this plugin arrive\r
807   //olsr_parser_add_function(&olsr_parser, PARSER_TYPE,1);\r
808   olsr_parser_add_function(&olsr_parser, PARSER_TYPE);\r
809 \r
810   //Creates captures sockets and register them to the OLSR scheduler\r
811   CreateNonOlsrNetworkInterfaces(skipThisIntf);\r
812 \r
813   return 0;\r
814 }                               /* InitP2pd */\r
815 \r
816 /* -------------------------------------------------------------------------\r
817  * Function   : CloseP2pd\r
818  * Description: Close the P2pd plugin and clean up\r
819  * Input      : none\r
820  * Output     : none\r
821  * Return     : none\r
822  * Data Used  :\r
823  * ------------------------------------------------------------------------- */\r
824 void\r
825 CloseP2pd(void)\r
826 {\r
827   CloseNonOlsrNetworkInterfaces();\r
828 }\r
829 \r
830 /* -------------------------------------------------------------------------\r
831  * Function   : SetP2pdTtl\r
832  * Description: Set the TTL for message from this plugin\r
833  * Input      : value - parameter value to evaluate\r
834  * Output     : none\r
835  * Return     : Always 0\r
836  * Data Used  : P2pdTtl\r
837  * ------------------------------------------------------------------------- */\r
838 int\r
839 SetP2pdTtl(const char *value,\r
840            void *data __attribute__ ((unused)),\r
841            set_plugin_parameter_addon addon __attribute__ ((unused)))\r
842 {\r
843   assert(value != NULL);\r
844   P2pdTtl = atoi(value);\r
845 \r
846   return 0;\r
847 }\r
848 \r
849 /* -------------------------------------------------------------------------\r
850  * Function   : SetP2pdUseHashFilter\r
851  * Description: Set the Hash filter flag for this plug-in\r
852  * Input      : value - parameter value to evaluate\r
853  *              data  - data associated with this parameter (unused in this app)\r
854  *              addon - additional parameter data\r
855  * Output     : none\r
856  * Return     : Always 0\r
857  * Data Used  : P2pdUseHash\r
858  * ------------------------------------------------------------------------- */\r
859 int\r
860 SetP2pdUseHashFilter(const char *value,\r
861                      void *data __attribute__ ((unused)),\r
862                      set_plugin_parameter_addon addon __attribute__ ((unused)))\r
863 {\r
864   assert(value != NULL);\r
865   P2pdUseHash = atoi(value);\r
866   \r
867   return 0;\r
868 }\r
869 \r
870 /* -------------------------------------------------------------------------\r
871  * Function   : AddUdpDestPort\r
872  * Description: Set the UDP destination/port combination as an entry in the\r
873  *              UdpDestPortList\r
874  * Input      : value - parameter value to evaluate\r
875  * Output     : none\r
876  * Return     : -1 on error condition, 0 if all is ok\r
877  * Data Used  : UdpDestPortList\r
878  * ------------------------------------------------------------------------- */\r
879 int\r
880 AddUdpDestPort(const char *value,\r
881                void *data __attribute__ ((unused)),\r
882                set_plugin_parameter_addon addon __attribute__ ((unused)))\r
883 {\r
884   char destAddr[INET6_ADDRSTRLEN];\r
885   uint16_t destPort;\r
886   int num;\r
887   struct UdpDestPort *    new;\r
888   struct sockaddr_in      addr4;\r
889   struct sockaddr_in6     addr6;\r
890   int                     ip_version    = AF_INET;\r
891   int                     res;\r
892 \r
893   assert(value != NULL);\r
894 \r
895   // Retrieve the data from the argument string passed\r
896   memset(destAddr, 0, sizeof(destAddr));\r
897   num = sscanf(value, "%45s %hd", destAddr, &destPort);\r
898   if (num != 2) {\r
899     OLSR_PRINTF(1, "%s: Invalid argument for \"UdpDestPort\"",\r
900                 PLUGIN_NAME_SHORT);\r
901     return -1;\r
902   }\r
903 \r
904   // Check whether we're dealing with an IPv4 or IPv6 address\r
905   // When the string contains a ':' we can assume we're dealing with IPv6\r
906   if (strchr(destAddr, (int)':')) {\r
907     ip_version = AF_INET6;\r
908   }\r
909 \r
910   // Check whether the specified address was either IPv4 multicast,\r
911   // IPv4 broadcast or IPv6 multicast.\r
912 \r
913   switch (ip_version) {\r
914   case AF_INET:\r
915     res = inet_pton(AF_INET, destAddr, &addr4.sin_addr);\r
916     if (!is_broadcast(addr4) && !is_multicast(addr4)) {\r
917       OLSR_PRINTF(1,"WARNING: IPv4 address must be multicast or broadcast... ");\r
918     }\r
919     break;\r
920   case AF_INET6:\r
921     res = inet_pton(AF_INET6, destAddr, &addr6.sin6_addr);\r
922     if (addr6.sin6_addr.s6_addr[0] != 0xFF) {\r
923       OLSR_PRINTF(1,"WARNING: IPv6 address must be multicast... ");\r
924       return -1;\r
925     }\r
926     break;\r
927   }\r
928   // Determine whether it is a valid IP address\r
929   if (res == 0) {\r
930     OLSR_PRINTF(1, "Invalid address specified for \"UdpDestPort\"");\r
931     return -1;\r
932   }\r
933 \r
934   // Create a new entry and link it into the chain\r
935   new = calloc(1, sizeof(struct UdpDestPort));\r
936   if (new == NULL) {\r
937     OLSR_PRINTF(1, "%s: Out of memory", PLUGIN_NAME_SHORT);\r
938     return -1;\r
939   }\r
940 \r
941   new->ip_version = ip_version;\r
942   switch (ip_version) {\r
943   case AF_INET:\r
944     new->address.v4.s_addr = addr4.sin_addr.s_addr;\r
945     break;\r
946   case AF_INET6:\r
947     memcpy(&new->address.v6.s6_addr,\r
948            &addr6.sin6_addr.s6_addr,\r
949            sizeof(addr6.sin6_addr.s6_addr));\r
950     break;\r
951   }\r
952   new->port = destPort;\r
953   new->next = UdpDestPortList;\r
954   UdpDestPortList = new;\r
955 \r
956   // And then we're done\r
957   return 0;\r
958 }\r
959 \r
960 /* -------------------------------------------------------------------------\r
961  * Function   : get_ipv4_str\r
962  * Description: Convert the specified address to an IPv4 compatible string\r
963  * Input      : address - IPv4 address to convert to string\r
964  *              s       - string buffer to contain the resulting string\r
965  *              maxlen  - maximum length of the string buffer\r
966  * Output     : none\r
967  * Return     : Pointer to the string buffer containing the result\r
968  * Data Used  : none\r
969  * ------------------------------------------------------------------------- */\r
970 char *\r
971 get_ipv4_str(uint32_t address, char *s, size_t maxlen)\r
972 {\r
973   struct sockaddr_in v4;\r
974 \r
975   v4.sin_addr.s_addr = address;\r
976   inet_ntop(AF_INET, &v4.sin_addr, s, maxlen);\r
977 \r
978   return s;\r
979 }\r
980 \r
981 /* -------------------------------------------------------------------------\r
982  * Function   : get_ipv6_str\r
983  * Description: Convert the specified address to an IPv4 compatible string\r
984  * Input      : address - IPv6 address to convert to string\r
985  *              s       - string buffer to contain the resulting string\r
986  *              maxlen  - maximum length of the string buffer\r
987  * Output     : none\r
988  * Return     : Pointer to the string buffer containing the result\r
989  * Data Used  : none\r
990  * ------------------------------------------------------------------------- */\r
991 char *\r
992 get_ipv6_str(unsigned char* address, char *s, size_t maxlen)\r
993 {\r
994   struct sockaddr_in6 v6;\r
995 \r
996   memcpy(v6.sin6_addr.s6_addr, address, sizeof(v6.sin6_addr.s6_addr));\r
997   inet_ntop(AF_INET6, &v6.sin6_addr, s, maxlen);\r
998 \r
999   return s;\r
1000 }\r
1001 \r
1002 /* -------------------------------------------------------------------------\r
1003  * Function   : is_broadcast\r
1004  * Description: Check whether the address represents a broadcast address\r
1005  * Input      : addr - IPv4 address to check\r
1006  * Output     : none\r
1007  * Return     : true if broadcast address, false otherwise\r
1008  * Data Used  : none\r
1009  * ------------------------------------------------------------------------- */\r
1010 bool\r
1011 is_broadcast(const struct sockaddr_in addr)\r
1012 {\r
1013   if (addr.sin_addr.s_addr == 0xFFFFFFFF)\r
1014     return true;\r
1015 \r
1016   return false;\r
1017 }\r
1018 \r
1019 /* -------------------------------------------------------------------------\r
1020  * Function   : is_multicast\r
1021  * Description: Check whether the address represents a multicast address\r
1022  * Input      : addr - IPv4 address to check\r
1023  * Output     : none\r
1024  * Return     : true if broadcast address, false otherwise\r
1025  * Data Used  : none\r
1026  * ------------------------------------------------------------------------- */\r
1027 bool\r
1028 is_multicast(const struct sockaddr_in addr)\r
1029 {\r
1030   if ((htonl(addr.sin_addr.s_addr) & 0xE0000000) == 0xE0000000)\r
1031     return true;\r
1032 \r
1033   return false;\r
1034 }\r
1035 \r
1036 #ifdef INCLUDE_DEBUG_OUTPUT\r
1037 /* -------------------------------------------------------------------------\r
1038  * Function   : dump_packet\r
1039  * Description: Dump the specified data as hex output\r
1040  * Input      : packet - packet to dump to output\r
1041  *              length - length of the data in the packet\r
1042  * Output     : none\r
1043  * Return     : nothing\r
1044  * Data Used  : none\r
1045  * ------------------------------------------------------------------------- */\r
1046 void\r
1047 dump_packet(unsigned char* packet, int length)\r
1048 {\r
1049   int idx;\r
1050 \r
1051   OLSR_PRINTF(1, "%s: ", PLUGIN_NAME_SHORT);\r
1052   for (idx = 0; idx < length; idx++) {\r
1053     if (idx > 0 && ((idx % 16) == 0))\r
1054       OLSR_PRINTF(1, "\n%s: ", PLUGIN_NAME_SHORT);\r
1055     OLSR_PRINTF(1, "%2.2X ", packet[idx]);\r
1056   }\r
1057   OLSR_PRINTF(1, "\n");\r
1058 }\r
1059 #endif\r
1060 \r
1061 /* -------------------------------------------------------------------------\r
1062  * Function   : check_and_mark_recent_packet\r
1063  * Description: Wrapper function for the Hash based duplicate check\r
1064  * Input      : data - pointer to a packet of data to be checked\r
1065  * Output     : none\r
1066  * Return     : true if duplicate packet, false otherwise\r
1067  * Data Used  : P2pdUseHash\r
1068  * ------------------------------------------------------------------------- */\r
1069 bool\r
1070 check_and_mark_recent_packet(unsigned char *data,\r
1071                              int len __attribute__ ((unused)))\r
1072 {\r
1073   unsigned char * ipPacket;\r
1074   uint16_t ipPacketLen;\r
1075   uint32_t crc32;\r
1076 \r
1077   /* If we don't use this filter bail out here */\r
1078   if (!P2pdUseHash)\r
1079     return false;\r
1080     \r
1081   /* Clean up the hash table each time before we check it */\r
1082   PrunePacketHistory(NULL);\r
1083 \r
1084   /* Check for duplicate IP packets now based on a hash */\r
1085   ipPacket = GetIpPacket(data);\r
1086   ipPacketLen = GetIpTotalLength(ipPacket);\r
1087 \r
1088   /* Calculate packet fingerprint */\r
1089   crc32 = PacketCrc32(ipPacket, ipPacketLen);\r
1090 \r
1091   /* Check if this packet was seen recently */\r
1092   if (CheckAndMarkRecentPacket(crc32))\r
1093   {\r
1094     OLSR_PRINTF(\r
1095       8,\r
1096       "%s: --> discarding: packet is duplicate\n",\r
1097       PLUGIN_NAME_SHORT);\r
1098     return true;\r
1099   }\r
1100 \r
1101   return false;\r
1102 }\r