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