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