Fixed signed comparison warnings
[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.38 2005/03/10 20:43:13 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  */
241 int
242 net_outbuffer_bytes_left(struct interface *ifp)
243 {
244   int remaining;
245
246   if(!netbufs[ifp->if_nr])
247     return 0;
248
249   remaining = netbufs[ifp->if_nr]->maxsize - netbufs[ifp->if_nr]->pending;
250
251   return remaining ? remaining : 0;
252 }
253
254
255 /**
256  * Add a packet transform function. Theese are functions
257  * called just prior to sending data in a buffer.
258  *
259  * @param f the function pointer
260  *
261  * @returns 1
262  */
263 int
264 add_ptf(int (*f)(char *, int *))
265 {
266
267   struct ptf *new_ptf;
268
269   new_ptf = olsr_malloc(sizeof(struct ptf), "Add PTF");
270
271   new_ptf->next = ptf_list;
272   new_ptf->function = f;
273
274   ptf_list = new_ptf;
275
276   return 1;
277 }
278
279 /**
280  * Remove a packet transform function
281  *
282  * @param f the function pointer
283  *
284  * @returns 1 if a functionpointer was removed
285  *  0 if not
286  */
287 int
288 del_ptf(int (*f)(char *, int *))
289 {
290   struct ptf *tmp_ptf, *prev;
291
292   tmp_ptf = ptf_list;
293   prev = NULL;
294
295   while(tmp_ptf)
296     {
297       if(tmp_ptf->function == f)
298         {
299           /* Remove entry */
300           if(prev == NULL)
301             {
302               ptf_list = tmp_ptf->next;
303               free(tmp_ptf);
304             }
305           else
306             {
307               prev->next = tmp_ptf->next;
308               free(tmp_ptf);
309             }
310           return 1;
311         }
312       prev = tmp_ptf;
313       tmp_ptf = tmp_ptf->next;
314     }
315
316   return 0;
317 }
318
319
320
321 /**
322  *Sends a packet on a given interface.
323  *
324  *@param ifp the interface to send on.
325  *
326  *@return negative on error
327  */
328 int
329 net_output(struct interface *ifp)
330 {
331   struct sockaddr_in *sin;  
332   struct sockaddr_in dst;
333   struct sockaddr_in6 *sin6;  
334   struct sockaddr_in6 dst6;
335   struct ptf *tmp_ptf_list;
336   int i, x;
337   union olsr_packet *outmsg;
338
339   sin = NULL;
340   sin6 = NULL;
341
342   if(!netbufs[ifp->if_nr])
343     return -1;
344
345   if(!netbufs[ifp->if_nr]->pending)
346     return 0;
347
348   netbufs[ifp->if_nr]->pending += OLSR_HEADERSIZE;
349
350   outmsg = (union olsr_packet *)netbufs[ifp->if_nr]->buff;
351   /* Add the Packet seqno */
352   outmsg->v4.olsr_seqno = htons(ifp->olsr_seqnum++);
353   /* Set the packetlength */
354   outmsg->v4.olsr_packlen = htons(netbufs[ifp->if_nr]->pending);
355
356   if(olsr_cnf->ip_version == AF_INET)
357     {
358       /* IP version 4 */
359       sin = (struct sockaddr_in *)&ifp->int_broadaddr;
360
361       /* Copy sin */
362       dst = *sin;
363       sin = &dst;
364
365       if (sin->sin_port == 0)
366         sin->sin_port = olsr_udp_port;
367     }
368   else
369     {
370       /* IP version 6 */
371       sin6 = (struct sockaddr_in6 *)&ifp->int6_multaddr;
372       /* Copy sin */
373       dst6 = *sin6;
374       sin6 = &dst6;
375     }
376
377   /*
378    *Call possible packet transform functions registered by plugins  
379    */
380   tmp_ptf_list = ptf_list;
381   while(tmp_ptf_list != NULL)
382     {
383       tmp_ptf_list->function(netbufs[ifp->if_nr]->buff, &netbufs[ifp->if_nr]->pending);
384       tmp_ptf_list = tmp_ptf_list->next;
385     }
386
387   /*
388    *if the -dispout option was given
389    *we print the contetnt of the packets
390    */
391   if(disp_pack_out)
392     {
393       switch(netbufs[ifp->if_nr]->buff[4])
394         {
395         case(HELLO_MESSAGE):printf("\n\tHELLO ");break;
396         case(TC_MESSAGE):printf("\n\tTC ");break;
397         case(MID_MESSAGE):printf("\n\tMID ");break;
398         case(HNA_MESSAGE):printf("\n\tHNA ");break;
399         default:printf("\n\tTYPE: %d ", netbufs[ifp->if_nr]->buff[4]); break;
400         }
401       if(olsr_cnf->ip_version == AF_INET)
402         printf("to %s size: %d\n\t", ip_to_string((olsr_u32_t *)&sin->sin_addr.s_addr), netbufs[ifp->if_nr]->pending);
403       else
404         printf("to %s size: %d\n\t", ip6_to_string(&sin6->sin6_addr), netbufs[ifp->if_nr]->pending);
405
406       x = 0;
407
408       for(i = 0; i < netbufs[ifp->if_nr]->pending;i++)
409         {
410           if(x == 4)
411             {
412               x = 0;
413               printf("\n\t");
414             }
415           x++;
416           if(olsr_cnf->ip_version == AF_INET)
417             printf(" %3i", (u_char) netbufs[ifp->if_nr]->buff[i]);
418           else
419             printf(" %2x", (u_char) netbufs[ifp->if_nr]->buff[i]);
420         }
421       
422       printf("\n");
423     }
424   
425   if(olsr_cnf->ip_version == AF_INET)
426     {
427       /* IP version 4 */
428       if(olsr_sendto(ifp->olsr_socket, 
429                      netbufs[ifp->if_nr]->buff, 
430                      netbufs[ifp->if_nr]->pending, 
431                      MSG_DONTROUTE, 
432                      (struct sockaddr *)sin, 
433                      sizeof (*sin))
434          < 0)
435         {
436           perror("sendto(v4)");
437           olsr_syslog(OLSR_LOG_ERR, "OLSR: sendto IPv4 %m");
438           netbufs[ifp->if_nr]->pending = 0;
439           return -1;
440         }
441     }
442   else
443     {
444       /* IP version 6 */
445       if(olsr_sendto(ifp->olsr_socket, 
446                      netbufs[ifp->if_nr]->buff,
447                      netbufs[ifp->if_nr]->pending, 
448                      MSG_DONTROUTE, 
449                      (struct sockaddr *)sin6, 
450                      sizeof (*sin6))
451          < 0)
452         {
453           perror("sendto(v6)");
454           olsr_syslog(OLSR_LOG_ERR, "OLSR: sendto IPv6 %m");
455           fprintf(stderr, "Socket: %d interface: %d\n", ifp->olsr_socket, ifp->if_nr);
456           fprintf(stderr, "To: %s (size: %d)\n", ip6_to_string(&sin6->sin6_addr), (int)sizeof(*sin6));
457           fprintf(stderr, "Outputsize: %d\n", netbufs[ifp->if_nr]->pending);
458           netbufs[ifp->if_nr]->pending = 0;
459           return -1;
460         }
461     }
462   
463   netbufs[ifp->if_nr]->pending = 0;
464
465   return 1;
466 }
467
468
469
470 /**
471  * Create a IPv6 netmask based on a prefix length
472  *
473  * @param allocated address to build the netmask in
474  * @param prefix the prefix length
475  *
476  * @returns 1 on success 0 on failure
477  */
478 int
479 olsr_prefix_to_netmask(union olsr_ip_addr *adr, olsr_u16_t prefix)
480 {
481   int p, i;
482
483   if(adr == NULL)
484     return 0;
485
486   p = prefix;
487   i = 0;
488
489   memset(adr, 0, ipsize);
490
491   for(;p > 0; p -= 8)
492     {
493       adr->v6.s6_addr[i] = (p < 8) ? 0xff ^ (0xff << p) : 0xff;
494       i++;
495     }
496
497 #ifdef DEBUG
498   OLSR_PRINTF(3, "Prefix %d = Netmask: %s\n", prefix, olsr_ip_to_string(adr))
499 #endif
500
501   return 1;
502 }
503
504
505
506 /**
507  * Calculate prefix length based on a netmask
508  *
509  * @param adr the address to use to calculate the prefix length
510  *
511  * @return the prefix length
512  */
513 olsr_u16_t
514 olsr_netmask_to_prefix(union olsr_ip_addr *adr)
515 {
516   olsr_u16_t prefix;
517   int i, tmp;
518
519   prefix = 0;
520
521   for(i = 0; i < 16; i++)
522     {
523       if(adr->v6.s6_addr[i] == 0xff)
524         {
525           prefix += 8;
526         }
527       else
528         {
529           for(tmp = adr->v6.s6_addr[i];
530               tmp > 0;
531               tmp = tmp >> 1)
532             prefix++;
533         }
534     }
535
536 #ifdef DEBUG
537   OLSR_PRINTF(3, "Netmask: %s = Prefix %d\n", olsr_ip_to_string(adr), prefix)
538 #endif
539
540   return prefix;
541 }
542
543
544
545 /**
546  *Converts a sockaddr struct to a string representing
547  *the IP address from the sockaddr struct
548  *
549  *<b>NON REENTRANT!!!!</b>
550  *
551  *@param address_to_convert the sockaddr struct to "convert"
552  *@return a char pointer to the string containing the IP
553  */
554 char *
555 sockaddr_to_string(struct sockaddr *address_to_convert)
556 {
557   struct sockaddr_in           *address;
558   
559   address=(struct sockaddr_in *)address_to_convert; 
560   return(inet_ntoa(address->sin_addr));
561   
562 }
563
564
565 /**
566  *Converts the 32bit olsr_u32_t datatype to
567  *a char array.
568  *
569  *<b>NON REENTRANT!!!!</b>
570  *
571  *@param address the olsr_u32_t to "convert"
572  *@return a char pointer to the string containing the IP
573  */
574
575 char *
576 ip_to_string(olsr_u32_t *address)
577 {
578
579   struct in_addr in;
580   in.s_addr=*address;
581   return(inet_ntoa(in));
582   
583 }
584
585
586
587
588 /**
589  *Converts the 32bit olsr_u32_t datatype to
590  *a char array.
591  *
592  *<b>NON REENTRANT</b>
593  *
594  *@param addr6 the address to "convert"
595  *@return a char pointer to the string containing the IP
596  */
597
598 char *
599 ip6_to_string(struct in6_addr *addr6)
600 {
601   return (char *)inet_ntop(AF_INET6, addr6, ipv6_buf, sizeof(ipv6_buf));
602 }
603
604
605 char *
606 olsr_ip_to_string(union olsr_ip_addr *addr)
607 {
608   static int index = 0;
609   static char buff[4][100];
610   char *ret;
611   struct in_addr in;
612   
613   if(olsr_cnf->ip_version == AF_INET)
614     {
615       in.s_addr=addr->v4;
616       ret = inet_ntoa(in);
617     }
618   else
619     {
620       /* IPv6 */
621       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
622     }
623
624   strncpy(buff[index], ret, 100);
625
626   ret = buff[index];
627
628   index = (index + 1) & 3;
629
630   return ret;
631 }