* applied osx-ip6.patch made by Gregoire Henry <gregoire.henry@pps.jussieu.fr>, poste...
[olsrd.git] / src / bsd / 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.32 2007/03/14 14:01:13 bernd67 Exp $
40  */
41
42 #include "defs.h"
43 #include "net_os.h"
44 #include "parser.h" /* dnc: needed for call to packet_parser() */
45 #include "net.h"
46
47 #include <net/if.h>
48
49 #ifdef __NetBSD__
50 #include <sys/param.h>
51 #include <net/if_ether.h>
52 #endif
53
54 #ifdef __OpenBSD__
55 #include <netinet/if_ether.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_icmp.h>
59 #include <netinet/icmp_var.h>
60 #include <netinet/icmp6.h>
61 #endif
62
63 #ifdef __FreeBSD__
64 #include <ifaddrs.h>
65 #include <net/if_var.h>
66 #include <net/ethernet.h>
67 #include <netinet/in_var.h>
68 #ifndef FBSD_NO_80211
69 #include <net80211/ieee80211.h>
70 #include <net80211/ieee80211_ioctl.h>
71 #include <dev/wi/if_wavelan_ieee.h>
72 #include <dev/wi/if_wireg.h>
73 #endif
74 #endif
75
76 #ifdef __MacOSX__
77 #include <ifaddrs.h>
78 #include <net/if_var.h>
79 #include <net/ethernet.h>
80 #include <netinet/in_var.h>
81 #endif
82
83 #include <net/if_dl.h>
84 #ifdef SPOOF
85 #include <libnet.h>
86 #endif /* SPOOF */
87
88 //#define       SIOCGIFGENERIC  _IOWR('i', 58, struct ifreq)    /* generic IF get op */
89 //#define SIOCGWAVELAN SIOCGIFGENERIC
90
91 #include <sys/sysctl.h>
92
93 static int ignore_redir;
94 static int send_redir;
95 static int gateway;
96
97 static int set_sysctl_int(char *name, int new)
98 {
99   int old;
100 #if __MacOSX__
101   size_t len = sizeof (old);
102 #else
103   unsigned int len = sizeof (old);
104 #endif
105
106 #ifdef __OpenBSD__
107   int mib[4];
108
109   /* Set net.inet.ip.forwarding by default. */
110   mib[0] = CTL_NET;
111   mib[1] = PF_INET;
112   mib[2] = IPPROTO_IP;
113   mib[3] = IPCTL_FORWARDING;
114
115   if (!strcmp(name, "net.inet6.ip6.forwarding"))
116   {
117     mib[1] = PF_INET6;
118     mib[2] = IPPROTO_IPV6;
119   }
120   else if (!strcmp(name, "net.inet.icmp.rediraccept"))
121   {
122     mib[2] = IPPROTO_ICMP;
123     mib[3] = ICMPCTL_REDIRACCEPT;
124   }
125   else if (!strcmp(name, "net.inet6.icmp6.rediraccept"))
126   {
127     mib[2] = IPPROTO_ICMPV6;
128     mib[3] = ICMPV6CTL_REDIRACCEPT;
129   }
130   else if (!strcmp(name, "net.inet.ip.redirect"))
131   {
132     mib[3] = IPCTL_SENDREDIRECTS;
133   }
134   else if (!strcmp(name, "net.inet6.ip6.redirect"))
135   {
136     mib[1] = PF_INET6;
137     mib[2] = IPPROTO_IPV6;
138     mib[3] = IPCTL_SENDREDIRECTS;
139   }
140
141   if (sysctl(mib, 4, &old, &len, &new, sizeof (new)) < 0)
142     return -1;
143 #else
144
145   if (sysctlbyname(name, &old, &len, &new, sizeof (new)) < 0)
146     return -1;
147 #endif
148
149   return old;
150 }
151
152 int enable_ip_forwarding(int version)
153 {
154   char *name;
155
156   if (olsr_cnf->ip_version == AF_INET)
157     name = "net.inet.ip.forwarding";
158
159   else
160     name = "net.inet6.ip6.forwarding";
161
162   gateway = set_sysctl_int(name, 1);
163
164   if (gateway < 0)
165     {
166       fprintf(stderr, "Cannot enable IP forwarding. Please enable IP forwarding manually. Continuing in 3 seconds...\n");
167       sleep(3);
168     }
169
170   return 1;
171 }
172
173 int
174 disable_redirects_global(int version)
175 {
176   char *name;
177
178   // do not accept ICMP redirects
179
180 #ifdef __OpenBSD__
181   if (olsr_cnf->ip_version == AF_INET)
182     name = "net.inet.icmp.rediraccept";
183
184   else
185     name = "net.inet6.icmp6.rediraccept";
186
187   ignore_redir = set_sysctl_int(name, 0);
188 #elif defined __FreeBSD__ || defined __MacOSX__
189   if (olsr_cnf->ip_version == AF_INET)
190   {
191     name = "net.inet.icmp.drop_redirect";
192     ignore_redir = set_sysctl_int(name, 1);
193   }
194   else
195   {
196     name = "net.inet6.icmp6.rediraccept";
197     ignore_redir = set_sysctl_int(name, 0);
198   }
199 #else
200   if (olsr_cnf->ip_version == AF_INET)
201     name = "net.inet.icmp.drop_redirect";
202
203   else
204     name = "net.inet6.icmp6.drop_redirect";
205
206   ignore_redir = set_sysctl_int(name, 1);
207 #endif
208
209   if (ignore_redir < 0)
210     {
211       fprintf(stderr, "Cannot disable incoming ICMP redirect messages. Please disable them manually. Continuing in 3 seconds...\n");
212       sleep(3);
213     }
214
215   // do not send ICMP redirects
216
217   if (olsr_cnf->ip_version == AF_INET)
218     name = "net.inet.ip.redirect";
219
220   else
221     name = "net.inet6.ip6.redirect";
222
223   send_redir = set_sysctl_int(name, 0);
224
225   if (send_redir < 0)
226     {
227       fprintf(stderr, "Cannot disable outgoing ICMP redirect messages. Please disable them manually. Continuing in 3 seconds...\n");
228       sleep(3);
229     }
230
231   return 1;
232 }
233
234 int disable_redirects(const char *if_name, struct interface *iface, int version)
235 {
236   // this function gets called for each interface olsrd uses; however,
237   // FreeBSD can only globally control ICMP redirects, and not on a
238   // per-interface basis; hence, only disable ICMP redirects in the "global"
239   // function
240   return 1;
241 }
242
243 int deactivate_spoof(const char *if_name, struct interface *iface, int version)
244 {
245   return 1;
246 }
247
248 int restore_settings(int version)
249 {
250   char *name;
251
252   // reset IP forwarding
253
254   if (olsr_cnf->ip_version == AF_INET)
255     name = "net.inet.ip.forwarding";
256
257   else
258     name = "net.inet6.ip6.forwarding";
259
260   set_sysctl_int(name, gateway);
261
262   // reset incoming ICMP redirects
263
264 #ifdef __OpenBSD__
265   if (olsr_cnf->ip_version == AF_INET)
266     name = "net.inet.icmp.rediraccept";
267   else
268     name = "net.inet6.icmp6.rediraccept";
269
270 #elif defined __FreeBSD__ || defined __MacOSX__
271   if (olsr_cnf->ip_version == AF_INET)
272     name = "net.inet.icmp.drop_redirect";
273
274   else
275     name = "net.inet6.icmp6.rediraccept";
276 #else
277   if (olsr_cnf->ip_version == AF_INET)
278     name = "net.inet.icmp.drop_redirect";
279
280   else
281     name = "net.inet6.icmp6.drop_redirect";
282 #endif
283
284   set_sysctl_int(name, ignore_redir);
285
286   // reset outgoing ICMP redirects
287
288   if (olsr_cnf->ip_version == AF_INET)
289     name = "net.inet.ip.redirect";
290
291   else
292     name = "net.inet6.ip6.redirect";
293
294   set_sysctl_int(name, send_redir);
295
296   return 1;
297 }
298
299
300 /**
301  *Creates a nonblocking broadcast socket.
302  *@param sa sockaddr struct. Used for bind(2).
303  *@return the FD of the socket or -1 on error.
304  */
305 int
306 gethemusocket(struct sockaddr_in *pin)
307 {
308   int sock, on = 1;
309
310   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
311
312
313   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
314     {
315       perror("hcsocket");
316       syslog(LOG_ERR, "hcsocket: %m");
317       return (-1);
318     }
319
320   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
321     {
322       perror("SO_REUSEADDR failed");
323       close(sock);
324       return (-1);
325     }
326   /* connect to PORT on HOST */
327   if (connect(sock,(struct sockaddr *) pin, sizeof(*pin)) < 0) 
328     {
329       printf("FAILED\n");
330       fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
331       printf("connection refused\n");
332       close(sock);
333       return (-1);
334     }
335
336   printf("OK\n");
337
338   /* Keep TCP socket blocking */  
339   return (sock);
340 }
341
342
343 int
344 getsocket(struct sockaddr *sa, int bufspace, char *int_name)
345 {
346   struct sockaddr_in *sin = (struct sockaddr_in *)sa;
347   int sock, on = 1;
348
349   if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
350     {
351       perror("socket");
352       syslog(LOG_ERR, "socket: %m");
353       return (-1);
354     }
355
356   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
357     {
358       perror("setsockopt");
359       syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
360       close(sock);
361       return (-1);
362     }
363
364   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
365     {
366       perror("SO_REUSEADDR failed");
367       close(sock);
368       return (-1);
369     }
370
371   if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) 
372     {
373       perror("SO_REUSEPORT failed");
374       close(sock);
375       return (-1);
376     }
377
378   if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0) 
379     {
380       perror("IP_RECVIF failed");
381       close(sock);
382       return (-1);
383     }
384
385   for (on = bufspace; ; on -= 1024) 
386     {
387       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
388                      &on, sizeof (on)) == 0)
389         break;
390       if (on <= 8*1024) 
391         {
392           perror("setsockopt");
393           syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
394           break;
395         }
396     }
397
398   if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) 
399     {
400       perror("bind");
401       syslog(LOG_ERR, "bind: %m");
402       close(sock);
403       return (-1);
404     }
405
406   if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
407     syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
408
409   return (sock);
410 }
411
412 int getsocket6(struct sockaddr_in6 *sin, int bufspace, char *int_name)
413 {
414   int sock, on = 1;
415
416   if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 
417     {
418       perror("socket");
419       syslog(LOG_ERR, "socket: %m");
420       return (-1);
421     }
422
423   for (on = bufspace; ; on -= 1024) 
424     {
425       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
426                      &on, sizeof (on)) == 0)
427         break;
428       if (on <= 8*1024) 
429         {
430           perror("setsockopt");
431           syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
432           break;
433         }
434     }
435
436   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
437     {
438       perror("SO_REUSEADDR failed");
439       close(sock);
440       return (-1);
441     }
442
443   if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) 
444     {
445       perror("SO_REUSEPORT failed");
446       return (-1);
447     }
448
449 #ifdef IPV6_RECVPKTINFO
450   if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0)
451     {
452       perror("IPV6_RECVPKTINFO failed");
453       return (-1);
454     }
455 #elif defined IPV6_PKTINFO
456     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0)
457       {
458         perror("IPV6_PKTINFO failed");
459         return (-1);
460       }
461 #endif
462
463   if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) 
464     {
465       perror("bind");
466       syslog(LOG_ERR, "bind: %m");
467       close(sock);
468       return (-1);
469     }
470
471   if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
472     syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
473
474   return (sock);
475 }
476
477
478
479 int
480 join_mcast(struct interface *ifs, int sock)
481 {
482   /* See netinet6/in6.h */
483
484   struct ipv6_mreq mcastreq;
485
486   COPY_IP(&mcastreq.ipv6mr_multiaddr, &ifs->int6_multaddr.sin6_addr);
487   mcastreq.ipv6mr_interface = ifs->if_index;
488
489   OLSR_PRINTF(3, "Interface %s joining multicast %s...",        ifs->int_name, olsr_ip_to_string((union olsr_ip_addr *)&ifs->int6_multaddr.sin6_addr))
490
491   /* rfc 3493 */
492 #ifdef IPV6_JOIN_GROUP
493   /* Join reciever group */
494   if(setsockopt(sock, 
495                 IPPROTO_IPV6, 
496                 IPV6_JOIN_GROUP, 
497                 (char *)&mcastreq, 
498                 sizeof(struct ipv6_mreq)) 
499      < 0)
500 #else /* rfc 2133, obsoleted */
501   /* Join receiver group */
502   if(setsockopt(sock, 
503                 IPPROTO_IPV6, 
504                 IPV6_ADD_MEMBERSHIP, 
505                 (char *)&mcastreq, 
506                 sizeof(struct ipv6_mreq)) 
507      < 0)
508 #endif 
509     {
510       perror("Join multicast send");
511       return -1;
512     }
513
514   
515   if(setsockopt(sock, 
516                 IPPROTO_IPV6, 
517                 IPV6_MULTICAST_IF, 
518                 (char *)&mcastreq.ipv6mr_interface, 
519                 sizeof(mcastreq.ipv6mr_interface)) 
520      < 0)
521     {
522       perror("Set multicast if");
523       return -1;
524     }
525
526
527   OLSR_PRINTF(3, "OK\n")
528   return 0;
529 }
530
531
532
533
534 int get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
535 {
536   struct ifaddrs *ifap, *ifa;
537   const struct sockaddr_in6 *sin6 = NULL;
538   struct in6_ifreq ifr6;
539   int found = 0;
540   int s6;
541   u_int32_t flags6;
542
543   if (getifaddrs(&ifap) != 0)
544     {
545       OLSR_PRINTF(3, "get_ipv6_address: getifaddrs() failed.\n")
546       return 0;
547     }
548
549   for (ifa = ifap; ifa; ifa = ifa->ifa_next)
550     {
551       if (ifa->ifa_addr->sa_family == AF_INET6 &&
552           strcmp(ifa->ifa_name, ifname) == 0)
553         {
554           sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
555           if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
556             continue;
557           strncpy(ifr6.ifr_name, ifname, sizeof(ifname));
558           if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
559             {
560               OLSR_PRINTF(3, "socket(AF_INET6,SOCK_DGRAM)");
561               break;
562             }
563           ifr6.ifr_addr = *sin6;
564           if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0)
565             {
566               OLSR_PRINTF(3, "ioctl(SIOCGIFAFLAG_IN6)");
567               close(s6);
568               break;
569             }
570           close(s6);
571           flags6 = ifr6.ifr_ifru.ifru_flags6;
572           if ((flags6 & IN6_IFF_ANYCAST) != 0)
573             continue;
574           if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
575             {
576               if (scope_in)
577                 {
578                   memcpy(&saddr6->sin6_addr, &sin6->sin6_addr,
579                          sizeof(struct in6_addr));
580                   found = 1;
581                   break;
582                 }
583             }
584           else
585             {
586               if (scope_in == 0)
587                 {
588                   memcpy(&saddr6->sin6_addr, &sin6->sin6_addr,
589                          sizeof(struct in6_addr));
590                   found = 1;
591                   break;
592                 }
593             }
594         }
595     }
596   freeifaddrs(ifap);
597   if (found)
598     return 1;
599
600   return 0;
601 }
602
603
604
605
606 /**
607  * Wrapper for sendto(2)
608  */
609
610 #ifdef SPOOF
611 static u_int16_t ip_id = 0;
612 #endif /* SPOOF */
613
614 ssize_t
615 olsr_sendto(int s, 
616             const void *buf, 
617             size_t len, 
618             int flags, 
619             const struct sockaddr *to, 
620             socklen_t tolen)
621 {
622 #ifdef SPOOF
623   /* IPv4 for now! */
624
625   libnet_t *context;
626   char errbuf[LIBNET_ERRBUF_SIZE];
627   libnet_ptag_t udp_tag, ip_tag, ether_tag;
628   unsigned char enet_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
629   int status;
630   struct sockaddr_in *to_in = (struct sockaddr_in *) to;
631   u_int32_t destip;
632   struct interface *iface;
633
634   udp_tag = ip_tag = ether_tag = 0;
635   destip = to_in->sin_addr.s_addr;
636   iface = if_ifwithsock (s);
637
638   /* initialize libnet */
639   context = libnet_init(LIBNET_LINK, iface->int_name, errbuf);
640   if (context == NULL)
641     {
642       OLSR_PRINTF (1, "libnet init: %s\n", libnet_geterror (context))
643       return (0);
644     }
645
646   /* initialize IP ID field if necessary */
647   if (ip_id == 0)
648     {
649       ip_id = (u_int16_t) (arc4random () & 0xffff);
650     }
651
652   udp_tag = libnet_build_udp (698,                              /* src port */
653                               698,                              /* dest port */
654                               LIBNET_UDP_H + len,               /* length */
655                               0,                                /* checksum */
656                               buf,                              /* payload */
657                               len,                              /* payload size */
658                               context,                          /* context */
659                               udp_tag);                         /* pblock */
660   if (udp_tag == -1)
661     {
662       OLSR_PRINTF (1, "libnet UDP header: %s\n", libnet_geterror (context))
663         return (0);
664     }
665
666   ip_tag = libnet_build_ipv4 (LIBNET_IPV4_H + LIBNET_UDP_H + len, /* len */
667                               0,                                /* TOS */
668                               ip_id++,                          /* IP id */
669                               0,                                /* IP frag */
670                               1,                                /* IP TTL */
671                               IPPROTO_UDP,                      /* protocol */
672                               0,                                /* checksum */
673                               libnet_get_ipaddr4 (context),     /* src IP */
674                               destip,                           /* dest IP */
675                               NULL,                             /* payload */
676                               0,                                /* payload len */
677                               context,                          /* context */
678                               ip_tag);                          /* pblock */
679   if (ip_tag == -1)
680     {
681       OLSR_PRINTF (1, "libnet IP header: %s\n", libnet_geterror (context))
682       return (0);
683     }
684
685   ether_tag = libnet_build_ethernet (enet_broadcast,            /* ethernet dest */
686                                      libnet_get_hwaddr (context), /* ethernet source */
687                                      ETHERTYPE_IP,              /* protocol type */
688                                      NULL,                      /* payload */
689                                      0,                         /* payload size */
690                                      context,                   /* libnet handle */
691                                      ether_tag);                /* pblock tag */
692   if (ether_tag == -1)
693     {
694       OLSR_PRINTF (1, "libnet ethernet header: %s\n", libnet_geterror (context))
695       return (0);
696     }
697  
698   status = libnet_write (context);
699   if (status == -1)
700     {
701       OLSR_PRINTF (1, "libnet packet write: %s\n", libnet_geterror (context))
702       return (0);
703     }
704
705   libnet_destroy (context);
706
707   return (len);
708
709 #else
710   return sendto(s, buf, len, flags, to, tolen);
711 #endif
712 }
713
714
715 /**
716  * Wrapper for recvfrom(2)
717  */
718
719 ssize_t  
720 olsr_recvfrom(int  s, 
721               void *buf, 
722               size_t len, 
723               int flags, 
724               struct sockaddr *from,
725               socklen_t *fromlen)
726 {
727   struct msghdr mhdr;
728   struct iovec iov;
729   struct cmsghdr *cm;
730   struct sockaddr_dl *sdl;
731   struct sockaddr_in *sin = (struct sockaddr_in *) from; //XXX
732   struct sockaddr_in6 *sin6;
733   struct in6_addr *iaddr6;
734   struct in6_pktinfo *pkti;
735   struct interface *ifc;
736   char addrstr[INET6_ADDRSTRLEN];
737   char iname[IFNAMSIZ];
738   unsigned char chdr[4096];
739   int count;
740
741   bzero(&mhdr, sizeof(mhdr));
742   bzero(&iov, sizeof(iov));
743
744   mhdr.msg_name = (caddr_t) from;
745   mhdr.msg_namelen = *fromlen;
746   mhdr.msg_iov = &iov;
747   mhdr.msg_iovlen = 1;
748   mhdr.msg_control = (caddr_t) chdr;
749   mhdr.msg_controllen = sizeof (chdr);
750
751   iov.iov_len = MAXMESSAGESIZE;
752   iov.iov_base = buf;
753
754   count = recvmsg (s, &mhdr, MSG_DONTWAIT);
755   if (count <= 0)
756     {
757       return (count);
758     }
759
760   /* this needs to get communicated back to caller */
761   *fromlen = mhdr.msg_namelen;
762   if (olsr_cnf->ip_version == AF_INET6)
763     {
764       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm;
765            cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm))
766         {
767           if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
768             {
769               pkti = (struct in6_pktinfo *) CMSG_DATA(cm);
770               iaddr6 = &pkti->ipi6_addr;
771               if_indextoname(pkti->ipi6_ifindex, iname);
772             }
773         }
774     }
775   else
776     {
777       cm = (struct cmsghdr *) chdr;
778       sdl = (struct sockaddr_dl *) CMSG_DATA (cm);
779       bzero (iname, sizeof (iname));
780       memcpy (iname, sdl->sdl_data, sdl->sdl_nlen);
781     }
782
783   ifc = if_ifwithsock (s);
784
785   sin6 = (struct sockaddr_in6 *)from;
786   OLSR_PRINTF (4, "%d bytes from %s, socket associated %s really received on %s\n",
787                count,
788                (olsr_cnf->ip_version == AF_INET6) ?
789                  inet_ntop(AF_INET6, (char *)&sin6->sin6_addr, addrstr,
790                                      INET6_ADDRSTRLEN):
791                  inet_ntoa (sin->sin_addr),
792                ifc->int_name,
793                iname);
794
795   if (strcmp (ifc->int_name, iname) != 0)
796     {
797       return (0);
798     }
799
800   return (count);
801 }
802
803 /**
804  * Wrapper for select(2)
805  */
806
807 int
808 olsr_select(int nfds,
809             fd_set *readfds,
810             fd_set *writefds,
811             fd_set *exceptfds,
812             struct timeval *timeout)
813 {
814   return select(nfds,
815                 readfds,
816                 writefds,
817                 exceptfds,
818                 timeout);
819 }
820
821
822 int 
823 check_wireless_interface(char *ifname)
824 {
825 #if defined __FreeBSD__ &&  !defined FBSD_NO_80211
826   struct wi_req wreq;
827   struct ifreq ifr;
828
829   memset((char *)&wreq, 0, sizeof(wreq));
830   memset((char *)&ifr, 0, sizeof(ifr));
831
832   wreq.wi_len = WI_MAX_DATALEN;
833   wreq.wi_type = WI_RID_IFACE_STATS;
834
835   strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
836   ifr.ifr_data = (caddr_t)&wreq;
837
838   return (ioctl(olsr_cnf->ioctl_s, SIOCGWAVELAN, &ifr) >= 0) ? 1 : 0;
839 #else
840   return 0;
841 #endif
842 }
843
844 #include <sys/sockio.h>
845
846 int
847 calculate_if_metric(char *ifname)
848 {
849   if(check_wireless_interface(ifname))
850     {
851       /* Wireless */
852       return 1;
853     }
854   else
855     {
856       /* Ethernet */
857 #if 0
858       /* Andreas: Perhaps SIOCGIFMEDIA is the way to do this? */
859       struct ifmediareq ifm;
860
861       memset(&ifm, 0, sizeof(ifm));
862       strlcpy(ifm.ifm_name, ifname, sizeof(ifm.ifm_name));
863
864       if(ioctl(olsr_cnf->ioctl_s, SIOCGIFMEDIA, &ifm) < 0)
865         {
866           OLSR_PRINTF(1, "Error SIOCGIFMEDIA(%s)\n", ifm.ifm_name)
867           return WEIGHT_ETHERNET_DEFAULT;
868         }
869
870       OLSR_PRINTF(1, "%s: STATUS 0x%08x\n", ifm.ifm_name, ifm.ifm_status)
871 #endif
872       return WEIGHT_ETHERNET_DEFAULT;
873     }
874 }