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