97085c2041c60593a0ecde8f36034727c87fd41c
[olsrd.git] / src / net.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: net.c,v 1.35 2005/02/27 18:39:43 kattemat Exp $
40  */
41
42 #include "net.h"
43 #include "log.h"
44 #include "olsr.h"
45 #include "net_os.h"
46 #include <stdlib.h>
47
48 #ifdef WIN32
49 #define perror(x) WinSockPError(x)
50 void
51 WinSockPError(char *);
52 #endif
53
54
55 /* Packet transform functions */
56
57 struct ptf
58 {
59   int (*function)(char *, int *);
60   struct ptf *next;
61 };
62
63 static struct ptf *ptf_list;
64
65 struct olsr_netbuf *netbufs[MAX_IFS];
66
67 static char ipv6_buf[100]; /* for address coversion */
68
69 /**
70  * Create a outputbuffer for the given interface. This
71  * function will allocate the needed storage according 
72  * to the MTU of the interface.
73  *
74  * @param ifp the interface to create a buffer for
75  *
76  * @return 0 on success, negative if a buffer already existed
77  *  for the given interface
78  */ 
79 int
80 net_add_buffer(struct interface *ifp)
81 {
82   struct olsr_netbuf *new_buf;
83
84   /* If a buffer already exists for this interface back off */
85   if(netbufs[ifp->if_nr])
86     return -1;
87
88   new_buf = olsr_malloc(sizeof(struct olsr_netbuf), "add_netbuff1");
89   new_buf->buff = olsr_malloc(ifp->int_mtu, "add_netbuff2");
90
91   /* Fill struct */
92   new_buf->bufsize = ifp->int_mtu;
93   new_buf->if_index = ifp->if_nr;
94   new_buf->maxsize = ifp->int_mtu - OLSR_HEADERSIZE;
95   new_buf->pending = 0;
96   new_buf->reserved = 0;
97
98   netbufs[ifp->if_nr] = new_buf;
99
100   return 0;
101 }
102
103
104 /**
105  * Remove a outputbuffer. Frees the allocated memory.
106  *
107  * @param ifp the interface corresponding to the buffer
108  * to remove
109  *
110  * @return 0 on success, negative if no buffer is found
111  */
112 int
113 net_remove_buffer(struct interface *ifp)
114 {
115
116   /* If a buffer does no exist for this interface back off */
117   if(!netbufs[ifp->if_nr])
118     return -1;
119   
120   /* Flush pending data */
121   if(netbufs[ifp->if_nr]->pending)
122     net_output(ifp);
123
124   free(netbufs[ifp->if_nr]->buff);
125   free(netbufs[ifp->if_nr]);
126   netbufs[ifp->if_nr] = NULL;
127
128   return 0;
129 }
130
131
132
133 /**
134  * Reserve space in a outputbuffer. This should only be needed
135  * in very special cases. This will decrease the reported size
136  * of the buffer so that there is always <i>size</i> bytes
137  * of data available in the buffer. To add data in the reserved
138  * area one must use the net_outbuffer_push_reserved function.
139  *
140  * @param ifp the interface corresponding to the buffer
141  * to reserve space on
142  * @param size the number of bytes to reserve
143  *
144  * @return 0 on success, negative if there was not enough
145  *  bytes to reserve
146  */
147 int
148 net_reserve_bufspace(struct interface *ifp, int size)
149 {
150   if((!netbufs[ifp->if_nr]) || (size > netbufs[ifp->if_nr]->maxsize))
151     return -1;
152   
153   netbufs[ifp->if_nr]->reserved = size;
154   netbufs[ifp->if_nr]->maxsize -= size;
155   
156   return 0;
157 }
158
159 /**
160  * Returns the number of bytes pending in the buffer. That
161  * is the number of bytes added but not sent.
162  *
163  * @param ifp the interface corresponding to the buffer
164  *
165  * @return the number of bytes currently pending
166  */
167 olsr_u16_t
168 net_output_pending(struct interface *ifp)
169 {
170   if(!netbufs[ifp->if_nr])
171     return -1;
172
173   return netbufs[ifp->if_nr]->pending;
174 }
175
176
177
178 /**
179  * Add data to a buffer.
180  *
181  * @param ifp the interface corresponding to the buffer
182  * @param data a pointer to the data to add
183  * @param size the number of byte to copy from data
184  *
185  * @return -1 if no buffer was found, 0 if there was not 
186  *  enough room in buffer or the number of bytes added on 
187  *  success
188  */
189 int
190 net_outbuffer_push(struct interface *ifp, olsr_u8_t *data, olsr_u16_t size)
191 {
192
193   if(!netbufs[ifp->if_nr])
194     return -1;
195
196   if((netbufs[ifp->if_nr]->pending + size) > netbufs[ifp->if_nr]->maxsize)
197     return 0;
198
199   memcpy(&netbufs[ifp->if_nr]->buff[netbufs[ifp->if_nr]->pending + OLSR_HEADERSIZE], data, size);
200   netbufs[ifp->if_nr]->pending += size;
201
202   return size;
203 }
204
205
206 /**
207  * Add data to the reserved part of a buffer
208  *
209  * @param ifp the interface corresponding to the buffer
210  * @param data a pointer to the data to add
211  * @param size the number of byte to copy from data
212  *
213  * @return -1 if no buffer was found, 0 if there was not 
214  *  enough room in buffer or the number of bytes added on 
215  *  success
216  */
217 int
218 net_outbuffer_push_reserved(struct interface *ifp, olsr_u8_t *data, olsr_u16_t size)
219 {
220
221   if(!netbufs[ifp->if_nr])
222     return -1;
223
224   if((netbufs[ifp->if_nr]->pending + size) > (netbufs[ifp->if_nr]->maxsize + netbufs[ifp->if_nr]->reserved))
225     return 0;
226
227   memcpy(&netbufs[ifp->if_nr]->buff[netbufs[ifp->if_nr]->pending + OLSR_HEADERSIZE], data, size);
228   netbufs[ifp->if_nr]->pending += size;
229
230   return size;
231 }
232
233 /**
234  * Report the number of bytes currently available in the buffer
235  * (not including possible reserved bytes)
236  *
237  * @param ifp the interface corresponding to the buffer
238  *
239  * @return the number of bytes available in the buffer or
240  *  -1 if no buffer was found
241  */
242 int
243 net_outbuffer_bytes_left(struct interface *ifp)
244 {
245
246   if(!netbufs[ifp->if_nr])
247     return -1;
248
249   return (netbufs[ifp->if_nr]->maxsize - netbufs[ifp->if_nr]->pending);
250 }
251
252
253 /**
254  * Add a packet transform function. Theese are functions
255  * called just prior to sending data in a buffer.
256  *
257  * @param f the function pointer
258  *
259  * @returns 1
260  */
261 int
262 add_ptf(int (*f)(char *, int *))
263 {
264
265   struct ptf *new_ptf;
266
267   new_ptf = olsr_malloc(sizeof(struct ptf), "Add PTF");
268
269   new_ptf->next = ptf_list;
270   new_ptf->function = f;
271
272   ptf_list = new_ptf;
273
274   return 1;
275 }
276
277 /**
278  * Remove a packet transform function
279  *
280  * @param f the function pointer
281  *
282  * @returns 1 if a functionpointer was removed
283  *  0 if not
284  */
285 int
286 del_ptf(int (*f)(char *, int *))
287 {
288   struct ptf *tmp_ptf, *prev;
289
290   tmp_ptf = ptf_list;
291   prev = NULL;
292
293   while(tmp_ptf)
294     {
295       if(tmp_ptf->function == f)
296         {
297           /* Remove entry */
298           if(prev == NULL)
299             {
300               ptf_list = tmp_ptf->next;
301               free(tmp_ptf);
302             }
303           else
304             {
305               prev->next = tmp_ptf->next;
306               free(tmp_ptf);
307             }
308           return 1;
309         }
310       prev = tmp_ptf;
311       tmp_ptf = tmp_ptf->next;
312     }
313
314   return 0;
315 }
316
317
318
319 /**
320  *Sends a packet on a given interface.
321  *
322  *@param ifp the interface to send on.
323  *
324  *@return negative on error
325  */
326 int
327 net_output(struct interface *ifp)
328 {
329   struct sockaddr_in *sin;  
330   struct sockaddr_in dst;
331   struct sockaddr_in6 *sin6;  
332   struct sockaddr_in6 dst6;
333   struct ptf *tmp_ptf_list;
334   int i, x;
335   union olsr_packet *outmsg;
336
337   sin = NULL;
338   sin6 = NULL;
339
340   if(!netbufs[ifp->if_nr])
341     return -1;
342
343   if(!netbufs[ifp->if_nr]->pending)
344     return 0;
345
346   netbufs[ifp->if_nr]->pending += OLSR_HEADERSIZE;
347
348   outmsg = (union olsr_packet *)netbufs[ifp->if_nr]->buff;
349   /* Add the Packet seqno */
350   outmsg->v4.olsr_seqno = htons(ifp->olsr_seqnum++);
351   /* Set the packetlength */
352   outmsg->v4.olsr_packlen = htons(netbufs[ifp->if_nr]->pending);
353
354   if(olsr_cnf->ip_version == AF_INET)
355     {
356       /* IP version 4 */
357       sin = (struct sockaddr_in *)&ifp->int_broadaddr;
358
359       /* Copy sin */
360       dst = *sin;
361       sin = &dst;
362
363       if (sin->sin_port == 0)
364         sin->sin_port = olsr_udp_port;
365     }
366   else
367     {
368       /* IP version 6 */
369       sin6 = (struct sockaddr_in6 *)&ifp->int6_multaddr;
370       /* Copy sin */
371       dst6 = *sin6;
372       sin6 = &dst6;
373     }
374
375   /*
376    *Call possible packet transform functions registered by plugins  
377    */
378   tmp_ptf_list = ptf_list;
379   while(tmp_ptf_list != NULL)
380     {
381       tmp_ptf_list->function(netbufs[ifp->if_nr]->buff, &netbufs[ifp->if_nr]->pending);
382       tmp_ptf_list = tmp_ptf_list->next;
383     }
384
385   /*
386    *if the -dispout option was given
387    *we print the contetnt of the packets
388    */
389   if(disp_pack_out)
390     {
391       switch(netbufs[ifp->if_nr]->buff[4])
392         {
393         case(HELLO_MESSAGE):printf("\n\tHELLO ");break;
394         case(TC_MESSAGE):printf("\n\tTC ");break;
395         case(MID_MESSAGE):printf("\n\tMID ");break;
396         case(HNA_MESSAGE):printf("\n\tHNA ");break;
397         default:printf("\n\tTYPE: %d ", netbufs[ifp->if_nr]->buff[4]); break;
398         }
399       if(olsr_cnf->ip_version == AF_INET)
400         printf("to %s size: %d\n\t", ip_to_string((olsr_u32_t *)&sin->sin_addr.s_addr), netbufs[ifp->if_nr]->pending);
401       else
402         printf("to %s size: %d\n\t", ip6_to_string(&sin6->sin6_addr), netbufs[ifp->if_nr]->pending);
403
404       x = 0;
405
406       for(i = 0; i < netbufs[ifp->if_nr]->pending;i++)
407         {
408           if(x == 4)
409             {
410               x = 0;
411               printf("\n\t");
412             }
413           x++;
414           if(olsr_cnf->ip_version == AF_INET)
415             printf(" %3i", (u_char) netbufs[ifp->if_nr]->buff[i]);
416           else
417             printf(" %2x", (u_char) netbufs[ifp->if_nr]->buff[i]);
418         }
419       
420       printf("\n");
421     }
422   
423   if(olsr_cnf->ip_version == AF_INET)
424     {
425       /* IP version 4 */
426       if(olsr_sendto(ifp->olsr_socket, 
427                      netbufs[ifp->if_nr]->buff, 
428                      netbufs[ifp->if_nr]->pending, 
429                      MSG_DONTROUTE, 
430                      (struct sockaddr *)sin, 
431                      sizeof (*sin)) 
432          < 0)
433         {
434           perror("sendto(v4)");
435           olsr_syslog(OLSR_LOG_ERR, "OLSR: sendto IPv4 %m");
436           netbufs[ifp->if_nr]->pending = 0;
437           return -1;
438         }
439     }
440   else
441     {
442       /* IP version 6 */
443       if(olsr_sendto(ifp->olsr_socket, 
444                      netbufs[ifp->if_nr]->buff,
445                      netbufs[ifp->if_nr]->pending, 
446                      MSG_DONTROUTE, 
447                      (struct sockaddr *)sin6, 
448                      sizeof (*sin6)) 
449          < 0)
450         {
451           perror("sendto(v6)");
452           olsr_syslog(OLSR_LOG_ERR, "OLSR: sendto IPv6 %m");
453           fprintf(stderr, "Socket: %d interface: %d\n", ifp->olsr_socket, ifp->if_nr);
454           fprintf(stderr, "To: %s (size: %d)\n", ip6_to_string(&sin6->sin6_addr), (int)sizeof(*sin6));
455           fprintf(stderr, "Outputsize: %d\n", netbufs[ifp->if_nr]->pending);
456           netbufs[ifp->if_nr]->pending = 0;
457           return -1;
458         }
459     }
460   
461   netbufs[ifp->if_nr]->pending = 0;
462
463   return 1;
464 }
465
466
467
468 int
469 join_mcast(struct interface *ifs, int sock)
470 {
471   /* See linux/in6.h */
472
473   struct ipv6_mreq mcastreq;
474
475   COPY_IP(&mcastreq.ipv6mr_multiaddr, &ifs->int6_multaddr.sin6_addr);
476   mcastreq.ipv6mr_interface = ifs->if_index;
477
478 #if !defined __FreeBSD__ && !defined __MacOSX__ && !defined __NetBSD__
479   OLSR_PRINTF(3, "Interface %s joining multicast %s...",        ifs->int_name, olsr_ip_to_string((union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr))
480   /* Send multicast */
481   if(setsockopt(sock, 
482                 IPPROTO_IPV6, 
483                 IPV6_ADD_MEMBERSHIP, 
484                 (char *)&mcastreq, 
485                 sizeof(struct ipv6_mreq)) 
486      < 0)
487     {
488       perror("Join multicast");
489       return -1;
490     }
491 #else
492 #warning implement IPV6_ADD_MEMBERSHIP
493 #endif
494
495   /* Old libc fix */
496 #ifdef IPV6_JOIN_GROUP
497   /* Join reciever group */
498   if(setsockopt(sock, 
499                 IPPROTO_IPV6, 
500                 IPV6_JOIN_GROUP, 
501                 (char *)&mcastreq, 
502                 sizeof(struct ipv6_mreq)) 
503      < 0)
504 #else
505   /* Join reciever group */
506   if(setsockopt(sock, 
507                 IPPROTO_IPV6, 
508                 IPV6_ADD_MEMBERSHIP, 
509                 (char *)&mcastreq, 
510                 sizeof(struct ipv6_mreq)) 
511      < 0)
512 #endif 
513     {
514       perror("Join multicast send");
515       return -1;
516     }
517
518   
519   if(setsockopt(sock, 
520                 IPPROTO_IPV6, 
521                 IPV6_MULTICAST_IF, 
522                 (char *)&mcastreq.ipv6mr_interface, 
523                 sizeof(mcastreq.ipv6mr_interface)) 
524      < 0)
525     {
526       perror("Set multicast if");
527       return -1;
528     }
529
530
531   OLSR_PRINTF(3, "OK\n")
532   return 0;
533 }
534
535
536 /**
537  * Create a IPv6 netmask based on a prefix length
538  *
539  * @param allocated address to build the netmask in
540  * @param prefix the prefix length
541  *
542  * @returns 1 on success 0 on failure
543  */
544 int
545 olsr_prefix_to_netmask(union olsr_ip_addr *adr, olsr_u16_t prefix)
546 {
547   int p, i;
548
549   if(adr == NULL)
550     return 0;
551
552   p = prefix;
553   i = 0;
554
555   memset(adr, 0, ipsize);
556
557   for(;p > 0; p -= 8)
558     {
559       adr->v6.s6_addr[i] = (p < 8) ? 0xff ^ (0xff << p) : 0xff;
560       i++;
561     }
562
563 #ifdef DEBUG
564   OLSR_PRINTF(3, "Prefix %d = Netmask: %s\n", prefix, olsr_ip_to_string(adr))
565 #endif
566
567   return 1;
568 }
569
570
571
572 /**
573  * Calculate prefix length based on a netmask
574  *
575  * @param adr the address to use to calculate the prefix length
576  *
577  * @return the prefix length
578  */
579 olsr_u16_t
580 olsr_netmask_to_prefix(union olsr_ip_addr *adr)
581 {
582   olsr_u16_t prefix;
583   int i, tmp;
584
585   prefix = 0;
586
587   for(i = 0; i < 16; i++)
588     {
589       if(adr->v6.s6_addr[i] == 0xff)
590         {
591           prefix += 8;
592         }
593       else
594         {
595           for(tmp = adr->v6.s6_addr[i];
596               tmp > 0;
597               tmp = tmp >> 1)
598             prefix++;
599         }
600     }
601
602 #ifdef DEBUG
603   OLSR_PRINTF(3, "Netmask: %s = Prefix %d\n", olsr_ip_to_string(adr), prefix)
604 #endif
605
606   return prefix;
607 }
608
609
610
611 /**
612  *Converts a sockaddr struct to a string representing
613  *the IP address from the sockaddr struct
614  *
615  *<b>NON REENTRANT!!!!</b>
616  *
617  *@param address_to_convert the sockaddr struct to "convert"
618  *@return a char pointer to the string containing the IP
619  */
620 char *
621 sockaddr_to_string(struct sockaddr *address_to_convert)
622 {
623   struct sockaddr_in           *address;
624   
625   address=(struct sockaddr_in *)address_to_convert; 
626   return(inet_ntoa(address->sin_addr));
627   
628 }
629
630
631 /**
632  *Converts the 32bit olsr_u32_t datatype to
633  *a char array.
634  *
635  *<b>NON REENTRANT!!!!</b>
636  *
637  *@param address the olsr_u32_t to "convert"
638  *@return a char pointer to the string containing the IP
639  */
640
641 char *
642 ip_to_string(olsr_u32_t *address)
643 {
644
645   struct in_addr in;
646   in.s_addr=*address;
647   return(inet_ntoa(in));
648   
649 }
650
651
652
653
654 /**
655  *Converts the 32bit olsr_u32_t datatype to
656  *a char array.
657  *
658  *<b>NON REENTRANT</b>
659  *
660  *@param addr6 the address to "convert"
661  *@return a char pointer to the string containing the IP
662  */
663
664 char *
665 ip6_to_string(struct in6_addr *addr6)
666 {
667   return (char *)inet_ntop(AF_INET6, addr6, ipv6_buf, sizeof(ipv6_buf));
668 }
669
670
671 char *
672 olsr_ip_to_string(union olsr_ip_addr *addr)
673 {
674   static int index = 0;
675   static char buff[4][100];
676   char *ret;
677   struct in_addr in;
678   
679   if(olsr_cnf->ip_version == AF_INET)
680     {
681       in.s_addr=addr->v4;
682       ret = inet_ntoa(in);
683     }
684   else
685     {
686       /* IPv6 */
687       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
688     }
689
690   strncpy(buff[index], ret, 100);
691
692   ret = buff[index];
693
694   index = (index + 1) & 3;
695
696   return ret;
697 }