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