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