squelch compiler warnings on freebsd
[olsrd.git] / src / bsd / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions 
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright 
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright 
14  *   notice, this list of conditions and the following disclaimer in 
15  *   the documentation and/or other materials provided with the 
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its 
18  *   contributors may be used to endorse or promote products derived 
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include "../defs.h"
43 #include "../net_os.h"
44 #include "../ipcalc.h"
45 #include "../parser.h"          /* dnc: needed for call to packet_parser() */
46 #include "../olsr_protocol.h"
47
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 _WRS_KERNEL
61 #include <vxWorks.h>
62 #include "wrn/coreip/netinet6/in6_var.h"
63 #include <sockLib.h>
64 #include <sys/socket.h>
65 #include "wrn/coreip/net/ifaddrs.h"
66 #include <selectLib.h>
67 #include <logLib.h>
68 #define syslog(a, b) fdprintf(a, b);
69 #else
70 #include <sys/param.h>
71 #endif
72
73
74 #ifdef __NetBSD__
75 #include <net/if_ether.h>
76 #endif
77
78 #ifdef __OpenBSD__
79 #include <netinet/if_ether.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/ip.h>
82 #include <netinet/ip_icmp.h>
83 #include <netinet/icmp_var.h>
84 #include <netinet/icmp6.h>
85 #include <netinet6/in6_var.h>   /* For struct in6_ifreq */
86 #include <ifaddrs.h>
87 #include <sys/uio.h>
88 #include <net80211/ieee80211.h>
89 #include <net80211/ieee80211_ioctl.h>
90 #endif
91
92 #ifdef __FreeBSD__
93 #include <ifaddrs.h>
94 #include <net/if_var.h>
95 #include <net/ethernet.h>
96 #include <netinet/in_var.h>
97 #ifndef FBSD_NO_80211
98 #include <net80211/ieee80211.h>
99 #include <net80211/ieee80211_ioctl.h>
100 #endif
101 #endif
102
103 #ifdef __MacOSX__
104 #include <ifaddrs.h>
105 #include <net/if_var.h>
106 #include <net/ethernet.h>
107 #include <netinet/in_var.h>
108 #endif
109
110 #include <net/if_dl.h>
111 #ifdef SPOOF
112 #include <libnet.h>
113 #endif /* SPOOF */
114
115 #if 0
116 #define SIOCGIFGENERIC  _IOWR('i', 58, struct ifreq)    /* generic IF get op */
117 #define SIOCGWAVELAN SIOCGIFGENERIC
118 #endif
119
120 #include <sys/sysctl.h>
121
122 static int ignore_redir;
123 static int send_redir;
124 static int gateway;
125
126 static int
127 set_sysctl_int(const char *name, int new)
128 {
129   int old;
130 #if __MacOSX__ || __OpenBSD__
131   size_t len = sizeof(old);
132 #else
133   unsigned int len = sizeof(old);
134 #endif
135
136 #ifdef __OpenBSD__
137   int mib[4];
138
139   /* Set net.inet.ip.forwarding by default. */
140   mib[0] = CTL_NET;
141   mib[1] = PF_INET;
142   mib[2] = IPPROTO_IP;
143   mib[3] = IPCTL_FORWARDING;
144
145   if (!strcmp(name, "net.inet6.ip6.forwarding")) {
146     mib[1] = PF_INET6;
147     mib[2] = IPPROTO_IPV6;
148   } else if (!strcmp(name, "net.inet.icmp.rediraccept")) {
149     mib[2] = IPPROTO_ICMP;
150     mib[3] = ICMPCTL_REDIRACCEPT;
151   } else if (!strcmp(name, "net.inet6.icmp6.rediraccept")) {
152     mib[2] = IPPROTO_ICMPV6;
153     mib[3] = ICMPV6CTL_REDIRACCEPT;
154   } else if (!strcmp(name, "net.inet.ip.redirect")) {
155     mib[3] = IPCTL_SENDREDIRECTS;
156   } else if (!strcmp(name, "net.inet6.ip6.redirect")) {
157     mib[1] = PF_INET6;
158     mib[2] = IPPROTO_IPV6;
159     mib[3] = IPCTL_SENDREDIRECTS;
160   }
161
162   if (sysctl(mib, 4, &old, &len, &new, sizeof(new)) < 0)
163     return -1;
164 #else
165
166   if (sysctlbyname((const char *)name, &old, &len, &new, sizeof(new)) < 0)
167     return -1;
168 #endif
169
170   return old;
171 }
172
173 int
174 enable_ip_forwarding(int version)
175 {
176   const char *name =
177     version == AF_INET ? "net.inet.ip.forwarding" : "net.inet6.ip6.forwarding";
178
179   gateway = set_sysctl_int(name, 1);
180   if (gateway < 0) {
181     fprintf(stderr,
182             "Cannot enable IP forwarding. Please enable IP forwarding manually."
183             " Continuing in 3 seconds...\n");
184     sleep(3);
185   }
186
187   return 1;
188 }
189
190 int
191 disable_redirects_global(int version)
192 {
193   const char *name;
194
195   /* do not accept ICMP redirects */
196
197 #ifdef __OpenBSD__
198   if (version == AF_INET)
199     name = "net.inet.icmp.rediraccept";
200   else
201     name = "net.inet6.icmp6.rediraccept";
202
203   ignore_redir = set_sysctl_int(name, 0);
204 #elif defined __FreeBSD__ || defined __MacOSX__
205   if (version == AF_INET) {
206     name = "net.inet.icmp.drop_redirect";
207     ignore_redir = set_sysctl_int(name, 1);
208   } else {
209     name = "net.inet6.icmp6.rediraccept";
210     ignore_redir = set_sysctl_int(name, 0);
211   }
212 #else
213   if (version == AF_INET)
214     name = "net.inet.icmp.drop_redirect";
215   else
216     name = "net.inet6.icmp6.drop_redirect";
217
218   ignore_redir = set_sysctl_int(name, 1);
219 #endif
220
221   if (ignore_redir < 0) {
222     fprintf(stderr,
223             "Cannot disable incoming ICMP redirect messages. "
224             "Please disable them manually. Continuing in 3 seconds...\n");
225     sleep(3);
226   }
227
228   /* do not send ICMP redirects */
229
230   if (version == AF_INET)
231     name = "net.inet.ip.redirect";
232   else
233     name = "net.inet6.ip6.redirect";
234
235   send_redir = set_sysctl_int(name, 0);
236   if (send_redir < 0) {
237     fprintf(stderr,
238             "Cannot disable outgoing ICMP redirect messages. "
239             "Please disable them manually. Continuing in 3 seconds...\n");
240     sleep(3);
241   }
242
243   return 1;
244 }
245
246 int
247 disable_redirects(const char *if_name
248                   __attribute__ ((unused)), struct interface *iface
249                   __attribute__ ((unused)), int version
250                   __attribute__ ((unused)))
251 {
252   /*
253    *  this function gets called for each interface olsrd uses; however,
254    * FreeBSD can only globally control ICMP redirects, and not on a
255    * per-interface basis; hence, only disable ICMP redirects in the "global"
256    * function
257    */
258   return 1;
259 }
260
261 int
262 deactivate_spoof(const char *if_name
263                  __attribute__ ((unused)), struct interface *iface
264                  __attribute__ ((unused)), int version __attribute__ ((unused)))
265 {
266   return 1;
267 }
268
269 int
270 restore_settings(int version)
271 {
272   /* reset IP forwarding */
273   const char *name =
274     version == AF_INET ? "net.inet.ip.forwarding" : "net.inet6.ip6.forwarding";
275
276   set_sysctl_int(name, gateway);
277
278   /* reset incoming ICMP redirects */
279
280 #ifdef __OpenBSD__
281   name =
282     version ==
283     AF_INET ? "net.inet.icmp.rediraccept" : "net.inet6.icmp6.rediraccept";
284 #elif defined __FreeBSD__ || defined __MacOSX__
285   name =
286     version ==
287     AF_INET ? "net.inet.icmp.drop_redirect" : "net.inet6.icmp6.rediraccept";
288 #else
289   name =
290     version ==
291     AF_INET ? "net.inet.icmp.drop_redirect" : "net.inet6.icmp6.drop_redirect";
292 #endif
293   set_sysctl_int(name, ignore_redir);
294
295   /* reset outgoing ICMP redirects */
296   name = version == AF_INET ? "net.inet.ip.redirect" : "net.inet6.ip6.redirect";
297   set_sysctl_int(name, send_redir);
298   return 1;
299 }
300
301
302 /**
303  *Creates a nonblocking broadcast socket.
304  *@param sa sockaddr struct. Used for bind(2).
305  *@return the FD of the socket or -1 on error.
306  */
307 int
308 gethemusocket(struct sockaddr_in *pin)
309 {
310   int sock, on = 1;
311
312   OLSR_PRINTF(1, "       Connecting to switch daemon port 10150...");
313
314
315   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
316     perror("hcsocket");
317     syslog(LOG_ERR, "hcsocket: %m");
318     return (-1);
319   }
320
321   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
322     perror("SO_REUSEADDR failed");
323     close(sock);
324     return (-1);
325   }
326   /* connect to PORT on HOST */
327   if (connect(sock, (struct sockaddr *)pin, sizeof(*pin)) < 0) {
328     printf("FAILED\n");
329     fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
330     printf("connection refused\n");
331     close(sock);
332     return (-1);
333   }
334
335   printf("OK\n");
336
337   /* Keep TCP socket blocking */
338   return (sock);
339 }
340
341
342 int
343 getsocket(int bufspace, char *int_name __attribute__ ((unused)))
344 {
345   struct sockaddr_in sin;
346   int on;
347   int sock = socket(AF_INET, SOCK_DGRAM, 0);
348   if (sock < 0) {
349     perror("socket");
350     syslog(LOG_ERR, "socket: %m");
351     return -1;
352   }
353
354   on = 1;
355   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) {
356     perror("setsockopt");
357     syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
358     close(sock);
359     return -1;
360   }
361
362   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
363     perror("SO_REUSEADDR failed");
364     close(sock);
365     return -1;
366   }
367
368   if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
369     perror("SO_REUSEPORT failed");
370     close(sock);
371     return -1;
372   }
373
374   if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, (char *)&on, sizeof(on)) < 0) {
375     perror("IP_RECVIF failed");
376     close(sock);
377     return -1;
378   }
379
380   for (on = bufspace;; on -= 1024) {
381     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0)
382       break;
383     if (on <= 8 * 1024) {
384       perror("setsockopt");
385       syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
386       break;
387     }
388   }
389
390   memset(&sin, 0, sizeof(sin));
391   sin.sin_family = AF_INET;
392   sin.sin_port = htons(OLSRPORT);
393   sin.sin_addr.s_addr = INADDR_ANY;
394   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
395     perror("bind");
396     syslog(LOG_ERR, "bind: %m");
397     close(sock);
398     return -1;
399   }
400
401   on = fcntl(sock, F_GETFL);
402   if (on == -1) {
403     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
404   } else {
405     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
406       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
407     }
408   }
409   return (sock);
410 }
411
412 int
413 getsocket6(int bufspace, char *int_name __attribute__ ((unused)))
414 {
415   struct sockaddr_in6 sin;
416   int on;
417   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
418
419   if (sock < 0) {
420     perror("socket");
421     syslog(LOG_ERR, "socket: %m");
422     return -1;
423   }
424
425   for (on = bufspace;; on -= 1024) {
426     if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0)
427       break;
428     if (on <= 8 * 1024) {
429       perror("setsockopt");
430       syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
431       break;
432     }
433   }
434
435   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
436     perror("SO_REUSEADDR failed");
437     close(sock);
438     return -1;
439   }
440
441   if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
442     perror("SO_REUSEPORT failed");
443     close(sock);
444     return -1;
445   }
446 #ifdef IPV6_RECVPKTINFO
447   if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on, sizeof(on))
448       < 0) {
449     perror("IPV6_RECVPKTINFO failed");
450     close(sock);
451     return -1;
452   }
453 #elif defined IPV6_PKTINFO
454   if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on, sizeof(on)) < 0) {
455     perror("IPV6_PKTINFO failed");
456     close(sock);
457     return -1;
458   }
459 #endif
460
461   memset(&sin, 0, sizeof(sin));
462   sin.sin6_family = AF_INET6;
463   sin.sin6_port = htons(OLSRPORT);
464   if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
465     perror("bind");
466     syslog(LOG_ERR, "bind: %m");
467     close(sock);
468     return -1;
469   }
470
471   on = fcntl(sock, F_GETFL);
472   if (on == -1) {
473     syslog(LOG_ERR, "fcntl (F_GETFL): %m\n");
474   } else {
475     if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) {
476       syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
477     }
478   }
479   return sock;
480 }
481
482
483
484 int
485 join_mcast(struct interface *ifs, int sock)
486 {
487   /* See netinet6/in6.h */
488   struct ipaddr_str addrstr;
489   struct ipv6_mreq mcastreq;
490
491   mcastreq.ipv6mr_multiaddr = ifs->int6_multaddr.sin6_addr;
492   mcastreq.ipv6mr_interface = ifs->if_index;
493
494   OLSR_PRINTF(3, "Interface %s joining multicast %s...", ifs->int_name,
495               olsr_ip_to_string(&addrstr,
496                                 (union olsr_ip_addr *)&ifs->int6_multaddr.
497                                 sin6_addr));
498
499   /* rfc 3493 */
500 #ifdef IPV6_JOIN_GROUP
501   /* Join reciever group */
502   if (setsockopt(sock,
503                  IPPROTO_IPV6,
504                  IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
505       < 0)
506 #else /* rfc 2133, obsoleted */
507   /* Join receiver group */
508   if (setsockopt(sock,
509                  IPPROTO_IPV6,
510                  IPV6_ADD_MEMBERSHIP,
511                  (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
512 #endif
513   {
514     perror("Join multicast send");
515     return -1;
516   }
517
518
519   if (setsockopt(sock,
520                  IPPROTO_IPV6,
521                  IPV6_MULTICAST_IF,
522                  (char *)&mcastreq.ipv6mr_interface,
523                  sizeof(mcastreq.ipv6mr_interface)) < 0) {
524     perror("Set multicast if");
525     return -1;
526   }
527
528
529   OLSR_PRINTF(3, "OK\n");
530   return 0;
531 }
532
533
534
535
536 int
537 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     OLSR_PRINTF(3, "get_ipv6_address: getifaddrs() failed.\n");
548     return 0;
549   }
550
551   for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
552     if ((ifa->ifa_addr->sa_family == AF_INET6) &&
553         (strcmp(ifa->ifa_name, ifname) == 0)) {
554       sin6 = (const struct sockaddr_in6 *)(ifa->ifa_addr);
555       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
556         continue;
557       strncpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
558       if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
559         OLSR_PRINTF(3, "socket(AF_INET6,SOCK_DGRAM)");
560         break;
561       }
562       ifr6.ifr_addr = *sin6;
563       if (ioctl(s6, SIOCGIFAFLAG_IN6, (int)&ifr6) < 0) {
564         OLSR_PRINTF(3, "ioctl(SIOCGIFAFLAG_IN6)");
565         close(s6);
566         break;
567       }
568       close(s6);
569       flags6 = ifr6.ifr_ifru.ifru_flags6;
570       if ((flags6 & IN6_IFF_ANYCAST) != 0)
571         continue;
572       if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
573         if (scope_in) {
574           memcpy(&saddr6->sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
575           found = 1;
576           break;
577         }
578       } else {
579         if (scope_in == 0) {
580           memcpy(&saddr6->sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
581           found = 1;
582           break;
583         }
584       }
585     }
586   }
587   freeifaddrs(ifap);
588   if (found)
589     return 1;
590
591   return 0;
592 }
593
594
595
596
597 /**
598  * Wrapper for sendto(2)
599  */
600
601 #ifdef SPOOF
602 static u_int16_t ip_id = 0;
603 #endif /* SPOOF */
604
605 ssize_t
606 olsr_sendto(int s,
607             const void *buf,
608             size_t len,
609             int flags __attribute__ ((unused)),
610             const struct sockaddr *to, 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     OLSR_PRINTF(1, "libnet init: %s\n", libnet_geterror(context));
632     return (0);
633   }
634
635   /* initialize IP ID field if necessary */
636   if (ip_id == 0) {
637     ip_id = (u_int16_t) (arc4random() & 0xffff);
638   }
639
640   udp_tag = libnet_build_udp(698,       /* src port */
641                              698,       /* dest port */
642                              LIBNET_UDP_H + len,        /* length */
643                              0, /* checksum */
644                              buf,       /* payload */
645                              len,       /* payload size */
646                              context,   /* context */
647                              udp_tag);  /* pblock */
648   if (udp_tag == -1) {
649     OLSR_PRINTF(1, "libnet UDP header: %s\n", libnet_geterror(context));
650     return (0);
651   }
652
653   ip_tag = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + len,        /* len */
654                              0, /* TOS */
655                              ip_id++,   /* IP id */
656                              0, /* IP frag */
657                              1, /* IP TTL */
658                              IPPROTO_UDP,       /* protocol */
659                              0, /* checksum */
660                              libnet_get_ipaddr4(context),       /* src IP */
661                              destip,    /* dest IP */
662                              NULL,      /* payload */
663                              0, /* payload len */
664                              context,   /* context */
665                              ip_tag);   /* pblock */
666   if (ip_tag == -1) {
667     OLSR_PRINTF(1, "libnet IP header: %s\n", libnet_geterror(context));
668     return (0);
669   }
670
671   ether_tag = libnet_build_ethernet(enet_broadcast,     /* ethernet dest */
672                                     libnet_get_hwaddr(context), /* ethernet source */
673                                     ETHERTYPE_IP,       /* protocol type */
674                                     NULL,       /* payload */
675                                     0,  /* payload size */
676                                     context,    /* libnet handle */
677                                     ether_tag); /* pblock tag */
678   if (ether_tag == -1) {
679     OLSR_PRINTF(1, "libnet ethernet header: %s\n", libnet_geterror(context));
680     return (0);
681   }
682
683   status = libnet_write(context);
684   if (status == -1) {
685     OLSR_PRINTF(1, "libnet packet write: %s\n", libnet_geterror(context));
686     return (0);
687   }
688
689   libnet_destroy(context);
690
691   return (len);
692
693 #else
694   return sendto(s, buf, len, flags, (const struct sockaddr *)to,
695                 tolen);
696 #endif
697 }
698
699
700 /**
701  * Wrapper for recvfrom(2)
702  */
703
704 ssize_t
705 olsr_recvfrom(int s,
706               void *buf,
707               size_t len,
708               int flags __attribute__ ((unused)),
709               struct sockaddr *from, socklen_t * fromlen)
710 {
711   struct msghdr mhdr;
712   struct iovec iov;
713   union {
714     struct cmsghdr cmsg;
715     unsigned char chdr[4096];
716   } cmu;
717   struct cmsghdr *cm;
718   struct sockaddr_dl *sdl;
719   struct sockaddr_in *sin = (struct sockaddr_in *)from;
720   struct sockaddr_in6 *sin6;
721   struct in6_addr *iaddr6;
722   struct in6_pktinfo *pkti;
723   struct interface *ifc;
724   char addrstr[INET6_ADDRSTRLEN];
725   char iname[IFNAMSIZ];
726   int count;
727
728   memset(&mhdr, 0, sizeof(mhdr));
729   memset(&iov, 0, sizeof(iov));
730
731   mhdr.msg_name = (caddr_t) from;
732   mhdr.msg_namelen = *fromlen;
733   mhdr.msg_iov = &iov;
734   mhdr.msg_iovlen = 1;
735   mhdr.msg_control = (caddr_t) & cmu;
736   mhdr.msg_controllen = sizeof(cmu);
737
738   iov.iov_len = len;
739   iov.iov_base = buf;
740
741   count = recvmsg(s, &mhdr, MSG_DONTWAIT);
742   if (count <= 0) {
743     return (count);
744   }
745
746   /* this needs to get communicated back to caller */
747   *fromlen = mhdr.msg_namelen;
748   if (olsr_cnf->ip_version == AF_INET6) {
749     for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm;
750          cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) {
751       if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO) {
752         pkti = (struct in6_pktinfo *)CMSG_DATA(cm);
753         iaddr6 = &pkti->ipi6_addr;
754         if_indextoname(pkti->ipi6_ifindex, iname);
755       }
756     }
757   } else {
758     cm = &cmu.cmsg;
759     sdl = (struct sockaddr_dl *)CMSG_DATA(cm);
760     memset(iname, 0, sizeof(iname));
761     memcpy(iname, sdl->sdl_data, sdl->sdl_nlen);
762   }
763
764   ifc = if_ifwithsock(s);
765
766   sin6 = (struct sockaddr_in6 *)from;
767   OLSR_PRINTF(4,
768               "%d bytes from %s, socket associated %s really received on %s\n",
769               count, inet_ntop(olsr_cnf->ip_version,
770                                olsr_cnf->ip_version ==
771                                AF_INET6 ? (char *)&sin6->
772                                sin6_addr : (char *)&sin->sin_addr, addrstr,
773                                sizeof(addrstr)), ifc->int_name, iname);
774
775   if (strcmp(ifc->int_name, iname) != 0) {
776     return (0);
777   }
778
779   return (count);
780 }
781
782 /**
783  * Wrapper for select(2)
784  */
785
786 int
787 olsr_select(int nfds,
788             fd_set * readfds,
789             fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
790 {
791   return select(nfds, readfds, writefds, exceptfds, timeout);
792 }
793
794
795 int
796 check_wireless_interface(char *ifname)
797 {
798 #if defined __FreeBSD__ &&  !defined FBSD_NO_80211
799
800 /* From FreeBSD ifconfig/ifieee80211.c ieee80211_status() */
801   struct ieee80211req ireq;
802   u_int8_t data[32];
803
804   memset(&ireq, 0, sizeof(ireq));
805   strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
806   ireq.i_data = &data;
807   ireq.i_type = IEEE80211_IOC_SSID;
808   ireq.i_val = -1;
809   return (ioctl(olsr_cnf->ioctl_s, SIOCG80211, &ireq) >= 0) ? 1 : 0;
810 #elif defined __OpenBSD__
811   struct ieee80211_nodereq nr;
812   bzero(&nr, sizeof(nr));
813   strlcpy(nr.nr_ifname, ifname, sizeof(nr.nr_ifname));
814   return (ioctl(olsr_cnf->ioctl_s, SIOCG80211FLAGS, &nr) >= 0) ? 1 : 0;
815 #else
816   ifname = NULL;                /* squelsh compiler warning */
817   return 0;
818 #endif
819 }
820
821 #include <sys/sockio.h>
822
823 int
824 calculate_if_metric(char *ifname)
825 {
826   if (check_wireless_interface(ifname)) {
827     /* Wireless */
828     return 1;
829   } else {
830     /* Ethernet */
831 #if 0
832     /* Andreas: Perhaps SIOCGIFMEDIA is the way to do this? */
833     struct ifmediareq ifm;
834
835     memset(&ifm, 0, sizeof(ifm));
836     strlcpy(ifm.ifm_name, ifname, sizeof(ifm.ifm_name));
837
838     if (ioctl(olsr_cnf->ioctl_s, SIOCGIFMEDIA, &ifm) < 0) {
839       OLSR_PRINTF(1, "Error SIOCGIFMEDIA(%s)\n", ifm.ifm_name);
840       return WEIGHT_ETHERNET_DEFAULT;
841     }
842
843     OLSR_PRINTF(1, "%s: STATUS 0x%08x\n", ifm.ifm_name, ifm.ifm_status);
844 #endif
845     return WEIGHT_ETHERNET_DEFAULT;
846   }
847 }