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