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