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