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