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