From Lorenz Shori <lorenz.schori@gmx.ch>: Mac OSX fixes
[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)
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)
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)) 
502      < 0)
503 #endif 
504     {
505       perror("Join multicast send");
506       return -1;
507     }
508
509   
510   if(setsockopt(sock, 
511                 IPPROTO_IPV6, 
512                 IPV6_MULTICAST_IF, 
513                 (char *)&mcastreq.ipv6mr_interface, 
514                 sizeof(mcastreq.ipv6mr_interface)) 
515      < 0)
516     {
517       perror("Set multicast if");
518       return -1;
519     }
520
521
522   OLSR_PRINTF(3, "OK\n");
523   return 0;
524 }
525
526
527
528
529 int get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
530 {
531   struct ifaddrs *ifap, *ifa;
532   const struct sockaddr_in6 *sin6 = NULL;
533   struct in6_ifreq ifr6;
534   int found = 0;
535   int s6;
536   u_int32_t flags6;
537
538   if (getifaddrs(&ifap) != 0)
539     {
540       OLSR_PRINTF(3, "get_ipv6_address: getifaddrs() failed.\n");
541       return 0;
542     }
543
544   for (ifa = ifap; ifa; ifa = ifa->ifa_next)
545     {
546       if (ifa->ifa_addr->sa_family == AF_INET6 &&
547           strcmp(ifa->ifa_name, ifname) == 0)
548         {
549           sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
550           if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
551             continue;
552           strncpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
553           if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
554             {
555               OLSR_PRINTF(3, "socket(AF_INET6,SOCK_DGRAM)");
556               break;
557             }
558           ifr6.ifr_addr = *sin6;
559           if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0)
560             {
561               OLSR_PRINTF(3, "ioctl(SIOCGIFAFLAG_IN6)");
562               close(s6);
563               break;
564             }
565           close(s6);
566           flags6 = ifr6.ifr_ifru.ifru_flags6;
567           if ((flags6 & IN6_IFF_ANYCAST) != 0)
568             continue;
569           if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
570             {
571               if (scope_in)
572                 {
573                   memcpy(&saddr6->sin6_addr, &sin6->sin6_addr,
574                          sizeof(struct in6_addr));
575                   found = 1;
576                   break;
577                 }
578             }
579           else
580             {
581               if (scope_in == 0)
582                 {
583                   memcpy(&saddr6->sin6_addr, &sin6->sin6_addr,
584                          sizeof(struct in6_addr));
585                   found = 1;
586                   break;
587                 }
588             }
589         }
590     }
591   freeifaddrs(ifap);
592   if (found)
593     return 1;
594
595   return 0;
596 }
597
598
599
600
601 /**
602  * Wrapper for sendto(2)
603  */
604
605 #ifdef SPOOF
606 static u_int16_t ip_id = 0;
607 #endif /* SPOOF */
608
609 ssize_t
610 olsr_sendto(int s, 
611             const void *buf, 
612             size_t len, 
613             int flags, 
614             const struct sockaddr *to, 
615             socklen_t tolen)
616 {
617 #ifdef SPOOF
618   /* IPv4 for now! */
619
620   libnet_t *context;
621   char errbuf[LIBNET_ERRBUF_SIZE];
622   libnet_ptag_t udp_tag, ip_tag, ether_tag;
623   unsigned char enet_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
624   int status;
625   struct sockaddr_in *to_in = (struct sockaddr_in *) to;
626   u_int32_t destip;
627   struct interface *iface;
628
629   udp_tag = ip_tag = ether_tag = 0;
630   destip = to_in->sin_addr.s_addr;
631   iface = if_ifwithsock (s);
632
633   /* initialize libnet */
634   context = libnet_init(LIBNET_LINK, iface->int_name, errbuf);
635   if (context == NULL)
636     {
637       OLSR_PRINTF (1, "libnet init: %s\n", libnet_geterror (context));
638       return (0);
639     }
640
641   /* initialize IP ID field if necessary */
642   if (ip_id == 0)
643     {
644       ip_id = (u_int16_t) (arc4random () & 0xffff);
645     }
646
647   udp_tag = libnet_build_udp (698,                              /* src port */
648                               698,                              /* dest port */
649                               LIBNET_UDP_H + len,               /* length */
650                               0,                                /* checksum */
651                               buf,                              /* payload */
652                               len,                              /* payload size */
653                               context,                          /* context */
654                               udp_tag);                         /* pblock */
655   if (udp_tag == -1)
656     {
657       OLSR_PRINTF (1, "libnet UDP header: %s\n", libnet_geterror (context));
658         return (0);
659     }
660
661   ip_tag = libnet_build_ipv4 (LIBNET_IPV4_H + LIBNET_UDP_H + len, /* len */
662                               0,                                /* TOS */
663                               ip_id++,                          /* IP id */
664                               0,                                /* IP frag */
665                               1,                                /* IP TTL */
666                               IPPROTO_UDP,                      /* protocol */
667                               0,                                /* checksum */
668                               libnet_get_ipaddr4 (context),     /* src IP */
669                               destip,                           /* dest IP */
670                               NULL,                             /* payload */
671                               0,                                /* payload len */
672                               context,                          /* context */
673                               ip_tag);                          /* pblock */
674   if (ip_tag == -1)
675     {
676       OLSR_PRINTF (1, "libnet IP header: %s\n", libnet_geterror (context));
677       return (0);
678     }
679
680   ether_tag = libnet_build_ethernet (enet_broadcast,            /* ethernet dest */
681                                      libnet_get_hwaddr (context), /* ethernet source */
682                                      ETHERTYPE_IP,              /* protocol type */
683                                      NULL,                      /* payload */
684                                      0,                         /* payload size */
685                                      context,                   /* libnet handle */
686                                      ether_tag);                /* pblock tag */
687   if (ether_tag == -1)
688     {
689       OLSR_PRINTF (1, "libnet ethernet header: %s\n", libnet_geterror (context));
690       return (0);
691     }
692  
693   status = libnet_write (context);
694   if (status == -1)
695     {
696       OLSR_PRINTF (1, "libnet packet write: %s\n", libnet_geterror (context));
697       return (0);
698     }
699
700   libnet_destroy (context);
701
702   return (len);
703
704 #else
705   return sendto(s, buf, len, flags, to, tolen);
706 #endif
707 }
708
709
710 /**
711  * Wrapper for recvfrom(2)
712  */
713
714 ssize_t  
715 olsr_recvfrom(int  s, 
716               void *buf, 
717               size_t len, 
718               int flags, 
719               struct sockaddr *from,
720               socklen_t *fromlen)
721 {
722   struct msghdr mhdr;
723   struct iovec iov;
724   union {
725         struct cmsghdr cmsg;
726         unsigned char chdr[4096];
727   } cmu;
728   struct cmsghdr *cm;
729   struct sockaddr_dl *sdl;
730   struct sockaddr_in *sin = (struct sockaddr_in *) from; //XXX
731   struct sockaddr_in6 *sin6;
732   struct in6_addr *iaddr6;
733   struct in6_pktinfo *pkti;
734   struct interface *ifc;
735   char addrstr[INET6_ADDRSTRLEN];
736   char iname[IFNAMSIZ];
737   int count;
738
739   memset(&mhdr, 0, sizeof(mhdr));
740   memset(&iov, 0, sizeof(iov));
741
742   mhdr.msg_name = (caddr_t) from;
743   mhdr.msg_namelen = *fromlen;
744   mhdr.msg_iov = &iov;
745   mhdr.msg_iovlen = 1;
746   mhdr.msg_control = (caddr_t) &cmu;
747   mhdr.msg_controllen = sizeof (cmu);
748
749   iov.iov_len = len;
750   iov.iov_base = buf;
751
752   count = recvmsg (s, &mhdr, MSG_DONTWAIT);
753   if (count <= 0)
754     {
755       return (count);
756     }
757
758   /* this needs to get communicated back to caller */
759   *fromlen = mhdr.msg_namelen;
760   if (olsr_cnf->ip_version == AF_INET6)
761     {
762       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm;
763            cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm))
764         {
765           if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
766             {
767               pkti = (struct in6_pktinfo *) CMSG_DATA(cm);
768               iaddr6 = &pkti->ipi6_addr;
769               if_indextoname(pkti->ipi6_ifindex, iname);
770             }
771         }
772     }
773   else
774     {
775       cm = &cmu.cmsg;
776       sdl = (struct sockaddr_dl *) CMSG_DATA (cm);
777       memset (iname, 0, sizeof (iname));
778       memcpy (iname, sdl->sdl_data, sdl->sdl_nlen);
779     }
780
781   ifc = if_ifwithsock (s);
782
783   sin6 = (struct sockaddr_in6 *)from;
784   OLSR_PRINTF (4, "%d bytes from %s, socket associated %s really received on %s\n",
785                count,          
786                inet_ntop(olsr_cnf->ip_version, olsr_cnf->ip_version == AF_INET6 ?
787                          (char *)&sin6->sin6_addr : (char *)&sin->sin_addr, addrstr, sizeof(addrstr)),
788                ifc->int_name,
789                iname);
790
791   if (strcmp (ifc->int_name, iname) != 0)
792     {
793       return (0);
794     }
795
796   return (count);
797 }
798
799 /**
800  * Wrapper for select(2)
801  */
802
803 int
804 olsr_select(int nfds,
805             fd_set *readfds,
806             fd_set *writefds,
807             fd_set *exceptfds,
808             struct timeval *timeout)
809 {
810   return select(nfds,
811                 readfds,
812                 writefds,
813                 exceptfds,
814                 timeout);
815 }
816
817
818 int 
819 check_wireless_interface(char *ifname)
820 {
821 #if defined __FreeBSD__ &&  !defined FBSD_NO_80211
822 /* From FreeBSD ifconfig/ifieee80211.c ieee80211_status() */
823   struct ieee80211req ireq;
824   u_int8_t data[32];
825
826   memset(&ireq, 0, sizeof(ireq));
827   strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
828   ireq.i_data = &data;
829   ireq.i_type = IEEE80211_IOC_SSID;
830   ireq.i_val = -1;
831   return (ioctl(olsr_cnf->ioctl_s, SIOCG80211, &ireq) >= 0) ? 1 : 0;
832 #elif defined __OpenBSD__
833   struct ieee80211_nodereq nr;
834   bzero(&nr, sizeof(nr));
835   strlcpy(nr.nr_ifname, ifname, sizeof(nr.nr_ifname));
836   return (ioctl(olsr_cnf->ioctl_s, SIOCG80211FLAGS, &nr) >=0) ? 1: 0;
837 #else
838   return 0;
839 #endif
840 }
841
842 #include <sys/sockio.h>
843
844 int
845 calculate_if_metric(char *ifname)
846 {
847   if(check_wireless_interface(ifname))
848     {
849       /* Wireless */
850       return 1;
851     }
852   else
853     {
854       /* Ethernet */
855 #if 0
856       /* Andreas: Perhaps SIOCGIFMEDIA is the way to do this? */
857       struct ifmediareq ifm;
858
859       memset(&ifm, 0, sizeof(ifm));
860       strlcpy(ifm.ifm_name, ifname, sizeof(ifm.ifm_name));
861
862       if(ioctl(olsr_cnf->ioctl_s, SIOCGIFMEDIA, &ifm) < 0)
863         {
864           OLSR_PRINTF(1, "Error SIOCGIFMEDIA(%s)\n", ifm.ifm_name);
865           return WEIGHT_ETHERNET_DEFAULT;
866         }
867
868       OLSR_PRINTF(1, "%s: STATUS 0x%08x\n", ifm.ifm_name, ifm.ifm_status);
869 #endif
870       return WEIGHT_ETHERNET_DEFAULT;
871     }
872 }