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