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