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