b50d43f89fd924c7e366f5e2e804eac0bbeebc02
[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 int
297 getsocket4(int bufspace, struct interface *ifp, bool bind_to_unicast, uint16_t port)
298 {
299   struct sockaddr_in sin4;
300   int on;
301   int sock = socket(AF_INET, SOCK_DGRAM, 0);
302   if (sock < 0) {
303     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
304     olsr_exit(EXIT_FAILURE);
305   }
306
307   on = 1;
308   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) {
309     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
310     close(sock);
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 reuse address for OLSR PDUs (%s)\n", strerror(errno));
316     close(sock);
317     olsr_exit(EXIT_FAILURE);
318   }
319
320   if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
321     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse port for OLSR PDUs (%s)\n", strerror(errno));
322     close(sock);
323     olsr_exit(EXIT_FAILURE);
324   }
325
326   if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, (char *)&on, sizeof(on)) < 0) {
327     OLSR_ERROR(LOG_NETWORKING, "Cannot set protocol option REECVIF for OLSR PDUs (%s)\n", strerror(errno));
328     close(sock);
329     olsr_exit(EXIT_FAILURE);
330   }
331
332   if (bufspace > 0) {
333     for (on = bufspace;; on -= 1024) {
334       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0) {
335         OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
336         break;
337       }
338       if (on <= 8 * 1024) {
339         OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
340         break;
341       }
342     }
343   }
344   memset(&sin4, 0, sizeof(sin4));
345   sin4.sin_family = AF_INET;
346   sin4.sin_port = htons(port);
347
348   if(bind_to_unicast) {
349     sin4.sin_addr.s_addr = ifp->int_src.v4.sin_addr.s_addr;
350   }
351   else {
352     sin4.sin_addr.s_addr = INADDR_ANY;
353   }
354
355   if (bind(sock, (struct sockaddr *)&sin4, sizeof(sin4)) < 0) {
356     OLSR_ERROR(LOG_NETWORKING, "Coult not bind socket for OLSR PDUs to port (%s)\n", strerror(errno));
357     close(sock);
358     olsr_exit(EXIT_FAILURE);
359   }
360
361   set_nonblocking(sock);
362   return (sock);
363 }
364
365 int
366 getsocket6(int bufspace, struct interface *ifp, bool bind_to_unicast, uint16_t port)
367 {
368   struct sockaddr_in6 sin6;
369   int on;
370   int sock = socket(AF_INET6, SOCK_DGRAM, 0);
371
372   if (sock < 0) {
373     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
374     olsr_exit(EXIT_FAILURE);
375   }
376
377   if (bufspace > 0) {
378     for (on = bufspace;; on -= 1024) {
379       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&on, sizeof(on)) == 0) {
380         OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on);
381         break;
382       }
383       if (on <= 8 * 1024) {
384         OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno));
385         break;
386       }
387     }
388   }
389
390   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) {
391     OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno));
392     close(sock);
393     olsr_exit(EXIT_FAILURE);
394   }
395
396   if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) {
397     perror("SO_REUSEADDR failed");
398     close(sock);
399     return -1;
400   }
401 #ifdef IPV6_RECVPKTINFO
402   if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on, sizeof(on)) < 0) {
403     OLSR_ERROR(LOG_NETWORKING, "Cannot set protocol options RECVPKTINFO for OLSR PDUs (%s)\n", strerror(errno));
404     close(sock);
405     olsr_exit(EXIT_FAILURE);
406   }
407 #elif defined IPV6_PKTINFO
408   if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *)&on, sizeof(on)) < 0) {
409     OLSR_ERROR(LOG_NETWORKING, "Cannot set protocol options PKTINFO for OLSR PDUs (%s)\n", strerror(errno));
410     close(sock);
411     olsr_exit(EXIT_FAILURE);
412   }
413 #endif
414
415   memset(&sin6, 0, sizeof(sin6));
416   sin6.sin6_family = AF_INET6;
417   sin6.sin6_port = htons(port);
418
419   if(bind_to_unicast) {
420     memcpy(&sin6.sin6_addr, &ifp->int_src.v6.sin6_addr, sizeof(struct in6_addr));
421   }
422
423   if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
424     OLSR_ERROR(LOG_NETWORKING, "Coult not bind socket for OLSR PDUs to port (%s)\n", strerror(errno));
425     close(sock);
426     olsr_exit(EXIT_FAILURE);
427   }
428
429   set_nonblocking(sock);
430   return sock;
431 }
432
433 void
434 os_set_olsr_socketoptions(int sock __attribute__ ((unused))) {
435 }
436
437 int
438 join_mcast(struct interface *ifs, int sock)
439 {
440   /* See netinet6/in6.h */
441   struct ipaddr_str addrstr;
442   struct ipv6_mreq mcastreq;
443 #ifdef IPV6_USE_MIN_MTU
444   int on;
445 #endif
446
447   mcastreq.ipv6mr_multiaddr = ifs->int_multicast.v6.sin6_addr;
448   mcastreq.ipv6mr_interface = ifs->if_index;
449
450   OLSR_INFO(LOG_NETWORKING, "Interface %s joining multicast %s.\n", ifs->int_name,
451             olsr_ip_to_string(&addrstr, (union olsr_ip_addr *)&ifs->int_multicast.v6.sin6_addr));
452
453   /* rfc 3493 */
454 #ifdef IPV6_JOIN_GROUP
455   /* Join reciever group */
456   if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mcastreq, sizeof(struct ipv6_mreq))
457       < 0)
458 #else /* rfc 2133, obsoleted */
459   /* Join receiver group */
460   if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mcastreq, sizeof(struct ipv6_mreq)) < 0)
461 #endif
462   {
463     OLSR_WARN(LOG_NETWORKING, "Cannot join multicast group (%s)\n", strerror(errno));
464     return -1;
465   }
466
467
468   if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcastreq.ipv6mr_interface, sizeof(mcastreq.ipv6mr_interface)) < 0) {
469     OLSR_WARN(LOG_NETWORKING, "Cannot set multicast interface (%s)\n", strerror(errno));
470     return -1;
471   }
472 #ifdef IPV6_USE_MIN_MTU
473   /*
474    * This allow multicast packets to use the full interface MTU and not
475    * be limited to 1280 bytes.
476    */
477   on = 0;
478   if (setsockopt(sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (char *)&on, sizeof(on)) < 0) {
479     perror("IPV6_USE_MIN_MTU failed");
480     close(sock);
481     return -1;
482   }
483 #endif
484   return 0;
485 }
486
487
488
489
490 int
491 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int addrtype6)
492 {
493   struct ifaddrs *ifap, *ifa;
494   const struct sockaddr_in6 *sin6 = NULL;
495   struct in6_ifreq ifr6;
496   int found = 0;
497   int s6;
498   u_int32_t flags6;
499
500   if (getifaddrs(&ifap) != 0) {
501     OLSR_WARN(LOG_NETWORKING, "getifaddrs() failed (%s).\n", strerror(errno));
502     return 0;
503   }
504
505   for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
506     if ((ifa->ifa_addr->sa_family == AF_INET6) && (strcmp(ifa->ifa_name, ifname) == 0)) {
507       sin6 = (const struct sockaddr_in6 *)(ifa->ifa_addr);
508       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
509         continue;
510       strscpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
511       if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
512         OLSR_WARN(LOG_NETWORKING, "Cannot open datagram socket (%s)\n", strerror(errno));
513         break;
514       }
515       ifr6.ifr_addr = *sin6;
516       if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
517         OLSR_WARN(LOG_NETWORKING, "ioctl(SIOCGIFAFLAG_IN6) failed (%s)", strerror(errno));
518         close(s6);
519         break;
520       }
521       close(s6);
522       flags6 = ifr6.ifr_ifru.ifru_flags6;
523       if ((flags6 & IN6_IFF_ANYCAST) != 0)
524         continue;
525       if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
526         if (addrtype6 == OLSR_IP6T_SITELOCAL)
527           found = 1;
528       } else {
529         if (addrtype6 == OLSR_IP6T_GLOBAL && (sin6->sin6_addr.s6_addr[0] != 0xfc && sin6->sin6_addr.s6_addr[0] != 0xfd))
530           found = 1;
531         else if (addrtype6 == OLSR_IP6T_UNIQUELOCAL && (sin6->sin6_addr.s6_addr[0] == 0xfc || sin6->sin6_addr.s6_addr[0] == 0xfd))
532           found = 1;
533       }
534       if (found) {
535         memcpy(&saddr6->sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr));
536         break;
537       }
538     }
539   }
540   freeifaddrs(ifap);
541   if (found)
542     return 1;
543
544   return 0;
545 }
546
547
548
549
550 /**
551  * Wrapper for sendto(2)
552  */
553
554 #ifdef SPOOF
555 static u_int16_t ip_id = 0;
556 #endif /* SPOOF */
557
558 ssize_t
559 olsr_sendto(int s, const void *buf, size_t len, int flags __attribute__ ((unused)), const union olsr_sockaddr *sock)
560 {
561 #ifdef SPOOF
562   /* IPv4 for now! */
563
564   libnet_t *context;
565   char errbuf[LIBNET_ERRBUF_SIZE];
566   libnet_ptag_t udp_tag, ip_tag, ether_tag;
567   unsigned char enet_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
568   int status;
569   struct sockaddr_in *to_in = (struct sockaddr_in *)to;
570   u_int32_t destip;
571   struct interface *iface;
572
573   udp_tag = ip_tag = ether_tag = 0;
574   destip = to_in->sin_addr.s_addr;
575   iface = if_ifwithsock(s);
576
577   /* initialize libnet */
578   context = libnet_init(LIBNET_LINK, iface->int_name, errbuf);
579   if (context == NULL) {
580     OLSR_WARN(LOG_NETWORKING, "libnet init: %s\n", libnet_geterror(context));
581     return (0);
582   }
583
584   /* initialize IP ID field if necessary */
585   if (ip_id == 0) {
586     ip_id = (u_int16_t) (arc4random() & 0xffff);
587   }
588
589   udp_tag = libnet_build_udp(olsr_cnf->olsr_port,       /* src port */
590                              olsr_cnf->olsr_port,       /* dest port */
591                              LIBNET_UDP_H + len,        /* length */
592                              0, /* checksum */
593                              buf,       /* payload */
594                              len,       /* payload size */
595                              context,   /* context */
596                              udp_tag);  /* pblock */
597   if (udp_tag == -1) {
598     OLSR_WARN(LOG_NETWORKING, "libnet UDP header: %s\n", libnet_geterror(context));
599     return (0);
600   }
601
602   ip_tag = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + len,        /* len */
603                              0, /* TOS */
604                              ip_id++,   /* IP id */
605                              0, /* IP frag */
606                              1, /* IP TTL */
607                              IPPROTO_UDP,       /* protocol */
608                              0, /* checksum */
609                              libnet_get_ipaddr4(context),       /* src IP */
610                              destip,    /* dest IP */
611                              NULL,      /* payload */
612                              0, /* payload len */
613                              context,   /* context */
614                              ip_tag);   /* pblock */
615   if (ip_tag == -1) {
616     OLSR_WARN(LOG_NETWORKING, "libnet IP header: %s\n", libnet_geterror(context));
617     return (0);
618   }
619
620   ether_tag = libnet_build_ethernet(enet_broadcast,     /* ethernet dest */
621                                     libnet_get_hwaddr(context), /* ethernet source */
622                                     ETHERTYPE_IP,       /* protocol type */
623                                     NULL,       /* payload */
624                                     0,  /* payload size */
625                                     context,    /* libnet handle */
626                                     ether_tag); /* pblock tag */
627   if (ether_tag == -1) {
628     OLSR_WARN(LOG_NETWORKING, "libnet ethernet header: %s\n", libnet_geterror(context));
629     return (0);
630   }
631
632   status = libnet_write(context);
633   if (status == -1) {
634     OLSR_WARN(LOG_NETWORKING, "libnet packet write: %s\n", libnet_geterror(context));
635     return (0);
636   }
637
638   libnet_destroy(context);
639
640   return (len);
641
642 #else
643   return sendto(s, buf, len, flags, &sock->std, sizeof(*sock));
644 #endif
645 }
646
647
648 /**
649  * Wrapper for recvfrom(2)
650  */
651
652 ssize_t
653 olsr_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), union olsr_sockaddr *from, socklen_t * fromlen)
654 {
655   struct msghdr mhdr;
656   struct iovec iov;
657   union {
658     struct cmsghdr cmsg;
659     unsigned char chdr[4096];
660   } cmu;
661   struct cmsghdr *cm;
662   struct sockaddr_dl *sdl;
663   struct in6_addr *iaddr6;
664   struct in6_pktinfo *pkti;
665   struct interface *ifc;
666   char iname[IFNAMSIZ];
667   int count;
668 #ifndef REMOVE_LOG_DEBUG
669   struct ipaddr_str ipbuf;
670 #endif
671
672   memset(&mhdr, 0, sizeof(mhdr));
673   memset(&iov, 0, sizeof(iov));
674
675   mhdr.msg_name = from;
676   mhdr.msg_namelen = *fromlen;
677   mhdr.msg_iov = &iov;
678   mhdr.msg_iovlen = 1;
679   mhdr.msg_control = (caddr_t) & cmu;
680   mhdr.msg_controllen = sizeof(cmu);
681
682   iov.iov_len = len;
683   iov.iov_base = buf;
684
685   count = recvmsg(s, &mhdr, MSG_DONTWAIT);
686   if (count <= 0) {
687     return (count);
688   }
689
690   /* this needs to get communicated back to caller */
691   *fromlen = mhdr.msg_namelen;
692   if (olsr_cnf->ip_version == AF_INET6) {
693     for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) {
694       if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO) {
695         pkti = (struct in6_pktinfo *)CMSG_DATA(cm);
696         iaddr6 = &pkti->ipi6_addr;
697         if_indextoname(pkti->ipi6_ifindex, iname);
698       }
699     }
700   } else {
701     cm = &cmu.cmsg;
702     sdl = (struct sockaddr_dl *)CMSG_DATA(cm);
703     memset(iname, 0, sizeof(iname));
704     memcpy(iname, sdl->sdl_data, sdl->sdl_nlen);
705   }
706
707   ifc = if_ifwithsock(s);
708
709   OLSR_DEBUG(LOG_NETWORKING,
710              "%d bytes from %s, socket associated %s really received on %s\n",
711              count, olsr_sockaddr_to_string(&ipbuf, from), ifc->int_name, iname);
712
713   if (strcmp(ifc->int_name, iname) != 0) {
714     return (0);
715   }
716
717   return (count);
718 }
719
720 /**
721  * Wrapper for select(2)
722  */
723
724 int
725 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
726 {
727   return select(nfds, readfds, writefds, exceptfds, timeout);
728 }
729
730 /*
731  * Local Variables:
732  * c-basic-offset: 2
733  * indent-tabs-mode: nil
734  * End:
735  */