Added support for dynamic change of outputbuffersize based on the interfaces with...
[olsrd.git] / src / net.c
1
2 /*
3  * OLSR ad-hoc routing table management protocol
4  * Copyright (C) 2003 Andreas T√łnnesen (andreto@ifi.uio.no)
5  *
6  * This file is part of the olsr.org OLSR daemon.
7  *
8  * olsr.org is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * olsr.org is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with olsr.org; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  * 
22  * 
23  * $Id: net.c,v 1.12 2004/09/22 20:57:50 kattemat Exp $
24  *
25  */
26
27 #include "net.h"
28 #include "olsr.h"
29 #include <stdlib.h>
30
31 #ifdef WIN32
32 #define perror(x) WinSockPError(x)
33 void
34 WinSockPError(char *);
35 #endif
36
37 #warning HEAPS of changes in net.c!!!
38
39 static char out_buffer[MAXMESSAGESIZE+1];
40 static char fwd_buffer[MAXMESSAGESIZE+1];
41
42 static union olsr_packet *outmsg = (union olsr_packet *)out_buffer;
43 static union olsr_packet *fwdmsg = (union olsr_packet *)fwd_buffer;
44
45 int outputsize = 0;         /* current size of the output buffer */
46 int fwdsize = 0;         /* current size of the forward buffer */
47
48
49 /* Default max OLSR packet size */
50 static int maxmessagesize = MAXMESSAGESIZE - OLSR_HEADERSIZE - UDP_IP_HDRSIZE;
51
52
53 void
54 init_net()
55 {
56   ptf_list = NULL;
57
58   return;
59 }
60
61 int
62 net_set_maxmsgsize(olsr_u16_t new_size)
63 {
64
65   if(new_size > (MAXMESSAGESIZE - OLSR_HEADERSIZE - UDP_IP_HDRSIZE))
66     return -1;
67
68   else
69     maxmessagesize = new_size;
70
71   olsr_printf(1, "Not outputbuffer maxsize set to %d\n", maxmessagesize);
72   return maxmessagesize;
73 }
74
75
76 inline olsr_u16_t
77 net_get_maxmsgsize()
78 {
79   return maxmessagesize;
80 }
81
82
83 inline olsr_u16_t
84 net_fwd_pending()
85 {
86   return fwdsize;
87 }
88
89
90 inline olsr_u16_t
91 net_output_pending()
92 {
93   return outputsize;
94 }
95
96 /**
97  * Add data to the buffer that is to be transmitted
98  *
99  * @return 0 if there was not enough room in buffer
100  */
101 int
102 net_outbuffer_push(olsr_u8_t *data, olsr_u16_t size)
103 {
104
105   if((outputsize + size) > maxmessagesize)
106     return 0;
107
108   memcpy(&out_buffer[outputsize + OLSR_HEADERSIZE], data, size);
109   outputsize += size;
110
111   return 1;
112 }
113
114
115
116 /**
117  * Add data to the buffer that is to be transmitted
118  *
119  * @return 0 if there was not enough room in buffer
120  */
121 inline int
122 net_outbuffer_bytes_left()
123 {
124   return (maxmessagesize - outputsize);
125 }
126
127
128 /**
129  * Add data to the buffer that is to be forwarded
130  *
131  * @return 0 if there was not enough room in buffer
132  */
133 int
134 net_fwdbuffer_push(olsr_u8_t *data, olsr_u16_t size)
135 {
136
137   if((fwdsize + size) > maxmessagesize)
138     return 0;
139
140   memcpy(&fwd_buffer[fwdsize + OLSR_HEADERSIZE], data, size);
141   fwdsize += size;
142
143   return 1;
144 }
145
146
147 /**
148  *Sends a packet on a given interface.
149  *
150  *@param ifp the interface to send on.
151  *
152  *@return negative on error
153  */
154 int
155 net_output(struct interface *ifp)
156 {
157   struct sockaddr_in *sin;  
158   struct sockaddr_in dst;
159   struct sockaddr_in6 *sin6;  
160   struct sockaddr_in6 dst6;
161   struct ptf *tmp_ptf_list;
162   int i, x;
163
164   sin = NULL;
165   sin6 = NULL;
166
167   if(outputsize <= 0)
168     return -1;
169
170   outputsize += OLSR_HEADERSIZE;
171   /* Add the Packet seqno */
172   outmsg->v4.olsr_seqno = htons(ifp->olsr_seqnum++);
173   /* Set the packetlength */
174   outmsg->v4.olsr_packlen = htons(outputsize);
175
176   if(ipversion == AF_INET)
177     {
178       /* IP version 4 */
179       sin = (struct sockaddr_in *)&ifp->int_broadaddr;
180
181       /* Copy sin */
182       dst = *sin;
183       sin = &dst;
184
185       /* Set user defined broadcastaddr */
186       if(bcast_set)
187         memcpy(&dst.sin_addr.s_addr, &bcastaddr.sin_addr, sizeof(olsr_u32_t));
188
189       if (sin->sin_port == 0)
190         sin->sin_port = olsr_udp_port;
191     }
192   else
193     {
194       /* IP version 6 */
195       sin6 = (struct sockaddr_in6 *)&ifp->int6_multaddr;
196       /* Copy sin */
197       dst6 = *sin6;
198       sin6 = &dst6;
199     }
200
201   /*
202    *if the '-disp- option was given
203    *we print her decimal contetnt of the packets
204    */
205   /*
206   if(disp_pack_out)
207     {
208       switch(out_buffer[4])
209         {
210         case(HELLO_MESSAGE):printf("\n\tHELLO ");break;
211         case(TC_MESSAGE):printf("\n\tTC ");break;
212         case(MID_MESSAGE):printf("\n\tMID ");break;
213         case(HNA_MESSAGE):printf("\n\tHNA ");break;
214         }
215       if(ipversion == AF_INET)
216         printf("to %s size: %d\n\t", ip_to_string(&sin->sin_addr.s_addr), outputsize);
217       else
218         printf("to %s size: %d\n\t", ip6_to_string(&sin6->sin6_addr), outputsize);
219
220       x = 0;
221
222       for(i = 0; i < outputsize;i++)
223         {
224           if(x == 4)
225             {
226               x = 0;
227               printf("\n\t");
228             }
229           x++;
230           if(ipversion == AF_INET)
231             printf(" %3i", (u_char) out_buffer[i]);
232           else
233             printf(" %2x", (u_char) out_buffer[i]);
234         }
235       
236       printf("\n");
237     }
238   */
239
240   /*
241    *Call possible packet transform functions registered by plugins  
242    */
243   tmp_ptf_list = ptf_list;
244   while(tmp_ptf_list != NULL)
245     {
246       tmp_ptf_list->function(out_buffer, &outputsize);
247       tmp_ptf_list = tmp_ptf_list->next;
248     }
249
250   /*
251    *if the '-disp- option was given
252    *we print her decimal contetnt of the packets
253    */
254   if(disp_pack_out)
255     {
256       switch(out_buffer[4])
257         {
258         case(HELLO_MESSAGE):printf("\n\tHELLO ");break;
259         case(TC_MESSAGE):printf("\n\tTC ");break;
260         case(MID_MESSAGE):printf("\n\tMID ");break;
261         case(HNA_MESSAGE):printf("\n\tHNA ");break;
262         default:printf("\n\tTYPE: %d ", out_buffer[4]); break;
263         }
264       if(ipversion == AF_INET)
265         printf("to %s size: %d\n\t", ip_to_string((olsr_u32_t *)&sin->sin_addr.s_addr), outputsize);
266       else
267         printf("to %s size: %d\n\t", ip6_to_string(&sin6->sin6_addr), outputsize);
268
269       x = 0;
270
271       for(i = 0; i < outputsize;i++)
272         {
273           if(x == 4)
274             {
275               x = 0;
276               printf("\n\t");
277             }
278           x++;
279           if(ipversion == AF_INET)
280             printf(" %3i", (u_char) out_buffer[i]);
281           else
282             printf(" %2x", (u_char) out_buffer[i]);
283         }
284       
285       printf("\n");
286     }
287
288   /*
289    *packet points to the same memory area as the *msg pointer
290    *used when building packets.
291    */
292   
293   if(ipversion == AF_INET)
294     {
295       /* IP version 4 */
296       if(sendto(ifp->olsr_socket, out_buffer, outputsize, MSG_DONTROUTE, (struct sockaddr *)sin, sizeof (*sin)) < 0)
297         {
298           perror("sendto(v4)");
299           olsr_syslog(OLSR_LOG_ERR, "OLSR: sendto IPv4 %m");
300           outputsize = 0;
301           return -1;
302         }
303     }
304   else
305     {
306       /* IP version 6 */
307       if(sendto(ifp->olsr_socket, out_buffer, outputsize, MSG_DONTROUTE, (struct sockaddr *)sin6, sizeof (*sin6)) < 0)
308         {
309           perror("sendto(v6)");
310           olsr_syslog(OLSR_LOG_ERR, "OLSR: sendto IPv6 %m");
311           fprintf(stderr, "Socket: %d interface: %d\n", ifp->olsr_socket, ifp->if_nr);
312           fprintf(stderr, "To: %s (size: %d)\n", ip6_to_string(&sin6->sin6_addr), sizeof(*sin6));
313           fprintf(stderr, "Outputsize: %d\n", outputsize);
314           outputsize = 0;
315           return -1;
316         }
317     }
318   
319   outputsize = 0;
320
321   return 1;
322 }
323
324
325
326
327
328
329 /**
330  *Forward a message on all interfaces
331  *
332  *@return negative on error
333  */
334 int
335 net_forward()
336 {
337   struct sockaddr_in *sin;  
338   struct sockaddr_in dst;
339   struct sockaddr_in6 *sin6;  
340   struct sockaddr_in6 dst6;
341   struct interface *ifn;
342   struct ptf *tmp_ptf_list;
343   int i, x;
344   
345   sin = NULL;
346   sin6 = NULL;
347   
348   for (ifn = ifnet; ifn; ifn = ifn->int_next) 
349     {
350       
351       fwdsize += OLSR_HEADERSIZE;      
352       /* Add the Packet seqno */
353       fwdmsg->v4.olsr_seqno = htons(ifn->olsr_seqnum++);
354       /* Set the packetlength */
355       fwdmsg->v4.olsr_packlen = htons(fwdsize);
356
357       if(ipversion == AF_INET)
358         {
359           /* IP version 4 */
360           sin = (struct sockaddr_in *)&ifn->int_broadaddr;
361           
362           /* Copy sin */
363           dst = *sin;
364           sin = &dst;
365
366           /* Set user defined broadcastaddr */
367           if(bcast_set)
368             memcpy(&dst.sin_addr.s_addr, &bcastaddr.sin_addr, sizeof(olsr_u32_t));
369           
370           if (sin->sin_port == 0)
371             sin->sin_port = olsr_udp_port;
372         }
373       else
374         {
375           /* IP version 6 */
376           sin6 = (struct sockaddr_in6 *)&ifn->int6_multaddr;
377           /* Copy sin */
378           dst6 = *sin6;
379           sin6 = &dst6;
380         }
381
382       /*
383        *if the '-disp- option was given
384        *we print her decimal contetnt of the packets
385        */
386       if(disp_pack_out)
387         {
388           if(ipversion == AF_INET)
389             printf("FORWARDING to %s size: %d\n\t", ip_to_string((olsr_u32_t *)&sin->sin_addr.s_addr), fwdsize);
390           else
391             printf("FORWARDING to %s size: %d\n\t", ip6_to_string(&sin6->sin6_addr), fwdsize);
392           
393           x = 0;
394           
395           for(i = 0; i < fwdsize;i++)
396             {
397               if(x == 4)
398                 {
399                   x = 0;
400                   printf("\n\t");
401                 }
402               x++;
403               if(ipversion == AF_INET)
404                 printf(" %3i", (u_char) fwd_buffer[i]);
405               else
406                 printf(" %2x", (u_char) fwd_buffer[i]);
407             }
408           
409           printf("\n");
410         }
411   
412       
413       /*
414        *Call possible packet transform functions registered by plugins  
415        */
416       tmp_ptf_list = ptf_list;
417       while(tmp_ptf_list != NULL)
418         {
419           tmp_ptf_list->function(fwd_buffer, &fwdsize);
420           tmp_ptf_list = tmp_ptf_list->next;
421         }
422
423
424       if(ipversion == AF_INET)
425         {
426           /* IP version 4 */
427           if(sendto(ifn->olsr_socket, fwd_buffer, fwdsize, MSG_DONTROUTE, (struct sockaddr *)sin, sizeof (*sin)) < 0)
428             {
429               perror("sendto(v4)");
430               olsr_syslog(OLSR_LOG_ERR, "OLSR: forward sendto IPv4 %m");
431               return -1;
432             }
433         }
434       else
435         {
436           /* IP version 6 */
437           if(sendto(ifn->olsr_socket, fwd_buffer, fwdsize, MSG_DONTROUTE, (struct sockaddr *)sin6, sizeof (*sin6)) < 0)
438             {
439               perror("sendto(v6)");
440               olsr_syslog(OLSR_LOG_ERR, "OLSR: forward sendto IPv6 %m");
441               fprintf(stderr, "Socket: %d interface: %d\n", ifn->olsr_socket, ifn->if_nr);
442               fprintf(stderr, "To: %s (size: %d)\n", ip6_to_string(&sin6->sin6_addr), sizeof(*sin6));
443               fprintf(stderr, "Outputsize: %d\n", fwdsize);
444               return -1;
445             }
446         }
447
448     }      
449   return 1;
450 }
451
452 /*
453  * Add a packet transform function
454  */
455 int
456 add_ptf(int (*f)(char *, int *))
457 {
458
459   struct ptf *new_ptf;
460
461   new_ptf = olsr_malloc(sizeof(struct ptf), "Add PTF");
462
463   new_ptf->next = ptf_list;
464   new_ptf->function = f;
465
466   ptf_list = new_ptf;
467
468   return 1;
469 }
470
471 /*
472  * Remove a packet transform function
473  */
474 int
475 del_ptf(int (*f)(char *, int *))
476 {
477   struct ptf *tmp_ptf, *prev;
478
479   tmp_ptf = ptf_list;
480   prev = NULL;
481
482   while(tmp_ptf)
483     {
484       if(tmp_ptf->function == f)
485         {
486           /* Remove entry */
487           if(prev == NULL)
488             {
489               ptf_list = tmp_ptf->next;
490               free(tmp_ptf);
491             }
492           else
493             {
494               prev->next = tmp_ptf->next;
495               free(tmp_ptf);
496             }
497           return 1;
498         }
499       prev = tmp_ptf;
500       tmp_ptf = tmp_ptf->next;
501     }
502
503   return 0;
504 }
505
506
507 int
508 join_mcast(struct interface *ifs, int sock)
509 {
510   /* See linux/in6.h */
511
512   struct ipv6_mreq mcastreq;
513
514   COPY_IP(&mcastreq.ipv6mr_multiaddr, &ifs->int6_multaddr.sin6_addr);
515   mcastreq.ipv6mr_interface = ifs->if_index;
516
517   olsr_printf(3, "Interface %s joining multicast %s...",        ifs->int_name, olsr_ip_to_string((union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr));
518   /* Send multicast */
519   if(setsockopt(sock, 
520                 IPPROTO_IPV6, 
521                 IPV6_ADD_MEMBERSHIP, 
522                 (char *)&mcastreq, 
523                 sizeof(struct ipv6_mreq)) 
524      < 0)
525     {
526       perror("Join multicast");
527       return -1;
528     }
529
530
531   /* Join reciever group */
532   if(setsockopt(sock, 
533                 IPPROTO_IPV6, 
534                 IPV6_JOIN_GROUP, 
535                 (char *)&mcastreq, 
536                 sizeof(struct ipv6_mreq)) 
537      < 0)
538     {
539       perror("Join multicast send");
540       return -1;
541     }
542
543   
544   if(setsockopt(sock, 
545                 IPPROTO_IPV6, 
546                 IPV6_MULTICAST_IF, 
547                 (char *)&mcastreq.ipv6mr_interface, 
548                 sizeof(mcastreq.ipv6mr_interface)) 
549      < 0)
550     {
551       perror("Set multicast if");
552       return -1;
553     }
554
555
556   olsr_printf(3, "OK\n");
557   return 0;
558 }
559
560
561 /**
562  * Create a IPv6 netmask based on a prefix length
563  *
564  */
565 int
566 olsr_prefix_to_netmask(union olsr_ip_addr *adr, olsr_u16_t prefix)
567 {
568   int p, i;
569
570   if(adr == NULL)
571     return 0;
572
573   p = prefix;
574   i = 0;
575
576   memset(adr, 0, ipsize);
577
578   for(;p > 0; p -= 8)
579     {
580       adr->v6.s6_addr[i] = (p < 8) ? 0xff ^ (0xff << p) : 0xff;
581       i++;
582     }
583
584 #ifdef DEBUG
585   olsr_printf(3, "Prefix %d = Netmask: %s\n", prefix, olsr_ip_to_string(adr));
586 #endif
587
588   return 1;
589 }
590
591
592
593 /**
594  * Calculate prefix length based on a netmask
595  *
596  */
597 olsr_u16_t
598 olsr_netmask_to_prefix(union olsr_ip_addr *adr)
599 {
600   olsr_u16_t prefix;
601   int i, tmp;
602
603   prefix = 0;
604
605   memset(adr, 0, ipsize);
606
607   for(i = 0; i < 16; i++)
608     {
609       if(adr->v6.s6_addr[i] == 0xff)
610         {
611           prefix += 8;
612         }
613       else
614         {
615           for(tmp = adr->v6.s6_addr[i];
616               tmp > 0;
617               tmp = tmp >> 1)
618             prefix++;
619         }
620     }
621
622 #ifdef DEBUG
623   olsr_printf(3, "Netmask: %s = Prefix %d\n", olsr_ip_to_string(adr), prefix);
624 #endif
625
626   return prefix;
627 }
628
629
630
631 /**
632  *Converts a sockaddr struct to a string representing
633  *the IP address from the sockaddr struct
634  *
635  *<b>NON REENTRANT!!!!</b>
636  *
637  *@param address_to_convert the sockaddr struct to "convert"
638  *@return a char pointer to the string containing the IP
639  */
640 char *
641 sockaddr_to_string(struct sockaddr *address_to_convert)
642 {
643   struct sockaddr_in           *address;
644   
645   address=(struct sockaddr_in *)address_to_convert; 
646   return(inet_ntoa(address->sin_addr));
647   
648 }
649
650
651 /**
652  *Converts the 32bit olsr_u32_t datatype to
653  *a char array.
654  *
655  *<b>NON REENTRANT!!!!</b>
656  *
657  *@param address the olsr_u32_t to "convert"
658  *@return a char pointer to the string containing the IP
659  */
660
661 char *
662 ip_to_string(olsr_u32_t *address)
663 {
664
665   struct in_addr in;
666   in.s_addr=*address;
667   return(inet_ntoa(in));
668   
669 }
670
671
672
673
674 /**
675  *Converts the 32bit olsr_u32_t datatype to
676  *a char array.
677  *
678  *<b>NON REENTRANT!!!!</b>
679  *
680  *@param addr6 the address to "convert"
681  *@return a char pointer to the string containing the IP
682  */
683
684 char *
685 ip6_to_string(struct in6_addr *addr6)
686 {
687   return (char *)inet_ntop(AF_INET6, addr6, ipv6_buf, sizeof(ipv6_buf));
688 }
689
690
691 char *
692 olsr_ip_to_string(union olsr_ip_addr *addr)
693 {
694
695   char *ret;
696   struct in_addr in;
697   
698   if(ipversion == AF_INET)
699     {
700       in.s_addr=addr->v4;
701       ret = inet_ntoa(in);
702     }
703   else
704     {
705       /* IPv6 */
706       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
707     }
708
709   return ret;
710 }