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