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