preliminary multi-interface hack for FreeBSD
authorDave Cornejo <dcornejo@gmail.com>
Wed, 2 Mar 2005 20:53:43 +0000 (20:53 +0000)
committerDave Cornejo <dcornejo@gmail.com>
Wed, 2 Mar 2005 20:53:43 +0000 (20:53 +0000)
Makefile
README-FreeBSD-libnet [new file with mode: 0644]
src/bsd/net.c
src/net.c

index 6268074..2de8ffe 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@
 # to the project. For more information see the website or contact
 # the copyright holders.
 #
-# $Id: Makefile,v 1.47 2005/03/02 00:13:20 tlopatic Exp $
+# $Id: Makefile,v 1.48 2005/03/02 20:53:43 spoggle Exp $
 
 VERS =         0.4.9
 
@@ -90,6 +90,15 @@ LIBS =               -lm
 MAKEDEPEND =   makedepend -f $(DEPFILE) -D__FreeBSD__ $(INCLUDES) $(SRCS)
 
 else
+ifeq ($(OS), fbsd-ll)
+
+SRCS +=                $(wildcard src/bsd/*.c) $(wildcard src/unix/*.c)
+HDRS +=                $(wildcard src/bsd/*.h) $(wildcard src/unix/*.h)
+CFLAGS ?=      -Wall -Wmissing-prototypes -O2 -g -DSPOOF -I/usr/local/include
+LIBS =         -lm -L/usr/local/lib -lnet
+MAKEDEPEND =   makedepend -f $(DEPFILE) -D__FreeBSD__ $(INCLUDES) $(SRCS)
+
+else
 ifeq ($(OS), nbsd)
 
 SRCS +=                $(wildcard src/bsd/*.c) $(wildcard src/unix/*.c)
@@ -191,6 +200,7 @@ endif
 endif
 endif
 endif
+endif
 
 ifneq ($(NODEBUG), )
 CFLAGS += -DNODEBUG
diff --git a/README-FreeBSD-libnet b/README-FreeBSD-libnet
new file mode 100644 (file)
index 0000000..313d765
--- /dev/null
@@ -0,0 +1,35 @@
+Instructions for FreeBSD libnet build
+spoggle@gmail.com
+
+libnet URL: http://www.packetfactory.net/libnet/
+FreeBSD Ports: /usr/ports/net/libnet-devel/
+
+
+The BSD networking is missing features that prevent the use of
+multiple interfaces with olsrd.  By using libnet we can get around
+the problem and support this feature.
+
+1) From the FreeBSD ports collection install libnet-devel, plain
+   libnet is NOT sufficient!
+
+  % cd /usr/ports/net/libnet-devel
+  % make install
+
+   Additionally, you must have gmake installed (/usr/ports/devel/gmake)
+
+2) If you're reading this, you have the proper olsrd distribution.  So
+   I won't bore you with getting that.
+
+3) Change into the main directory of the olsrd source and build the
+   daemon:
+
+  % cd <blah>
+  % gmake OS=fbsd-ll
+
+4) If that succeeds, then just follow all the other documentation on
+   the use of olsrd.
+
+The code is pretty ugly right now and I know there are some efficiency
+things I can do to make it better.  Bug reports, better ways to do
+this are welcomed.
+
index 01e380f..8f1546a 100644 (file)
@@ -36,7 +36,7 @@
  * to the project. For more information see the website or contact
  * the copyright holders.
  *
- * $Id: net.c,v 1.17 2005/03/02 08:58:12 kattemat Exp $
+ * $Id: net.c,v 1.18 2005/03/02 20:53:43 spoggle Exp $
  */
 
 #include "defs.h"
 #include <dev/wi/if_wavelan_ieee.h>
 #include <dev/wi/if_wireg.h>
 
+#ifdef SPOOF
+#include <net/if_dl.h>
+#include <libnet.h>
+#endif /* SPOOF */
+
 //#define      SIOCGIFGENERIC  _IOWR('i', 58, struct ifreq)    /* generic IF get op */
 //#define SIOCGWAVELAN SIOCGIFGENERIC
 
@@ -218,6 +223,20 @@ getsocket(struct sockaddr *sa, int bufspace, char *int_name)
       return (-1);
     }
 
+#ifdef SPOOF
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) 
+    {
+      perror("SO_REUSEPORT failed");
+      return (-1);
+    }
+
+  if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0) 
+    {
+      perror("IP_RECVIF failed");
+      return (-1);
+    }
+#endif /* SPOOF */
+
   for (on = bufspace; ; on -= 1024) 
     {
       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
@@ -301,6 +320,10 @@ int get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
  * Wrapper for sendto(2)
  */
 
+#ifdef SPOOF
+static u_int16_t ip_id = 0;
+#endif /* SPOOF */
+
 ssize_t
 olsr_sendto(int s, 
            const void *buf, 
@@ -309,7 +332,96 @@ olsr_sendto(int s,
            const struct sockaddr *to, 
            socklen_t tolen)
 {
+#ifdef SPOOF
+  /* IPv4 for now! */
+
+  libnet_t *context;
+  char errbuf[LIBNET_ERRBUF_SIZE];
+  libnet_ptag_t udp_tag, ip_tag, ether_tag;
+  unsigned char enet_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+  int status;
+  struct sockaddr_in *to_in = (struct sockaddr_in *) to;
+  u_int32_t destip;
+  struct interface *iface;
+
+  udp_tag = ip_tag = ether_tag = 0;
+  destip = to_in->sin_addr.s_addr;
+  iface = if_ifwithsock (s);
+
+  /* initialize libnet */
+  context = libnet_init(LIBNET_LINK, iface->int_name, errbuf);
+  if (context == NULL)
+    {
+      OLSR_PRINTF (1, "libnet init: %s\n", libnet_geterror (context))
+      return (0);
+    }
+
+  /* initialize IP ID field if necessary */
+  if (ip_id == 0)
+    {
+      ip_id = (u_int16_t) (arc4random () & 0xffff);
+    }
+
+  udp_tag = libnet_build_udp (698,                             /* src port */
+                             698,                              /* dest port */
+                             LIBNET_UDP_H + len,               /* length */
+                             0,                                /* checksum */
+                             buf,                              /* payload */
+                             len,                              /* payload size */
+                             context,                          /* context */
+                             udp_tag);                         /* pblock */
+  if (udp_tag == -1)
+    {
+      OLSR_PRINTF (1, "libnet UDP header: %s\n", libnet_geterror (context))
+       return (0);
+    }
+
+  ip_tag = libnet_build_ipv4 (LIBNET_IPV4_H + LIBNET_UDP_H + len, /* len */
+                             0,                                /* TOS */
+                             ip_id++,                          /* IP id */
+                             0,                                /* IP frag */
+                             1,                                /* IP TTL */
+                             IPPROTO_UDP,                      /* protocol */
+                             0,                                /* checksum */
+                             libnet_get_ipaddr4 (context),     /* src IP */
+                             destip,                           /* dest IP */
+                             NULL,                             /* payload */
+                             0,                                /* payload len */
+                             context,                          /* context */
+                             ip_tag);                          /* pblock */
+  if (ip_tag == -1)
+    {
+      OLSR_PRINTF (1, "libnet IP header: %s\n", libnet_geterror (context))
+      return (0);
+    }
+
+  ether_tag = libnet_build_ethernet (enet_broadcast,           /* ethernet dest */
+                                    libnet_get_hwaddr (context), /* ethernet source */
+                                    ETHERTYPE_IP,              /* protocol type */
+                                    NULL,                      /* payload */
+                                    0,                         /* payload size */
+                                    context,                   /* libnet handle */
+                                    ether_tag);                /* pblock tag */
+  if (ether_tag == -1)
+    {
+      OLSR_PRINTF (1, "libnet ethernet header: %s\n", libnet_geterror (context))
+      return (0);
+    }
+  status = libnet_write (context);
+  if (status == -1)
+    {
+      OLSR_PRINTF (1, "libnet packet write: %s\n", libnet_geterror (context))
+      return (0);
+    }
+
+  libnet_destroy (context);
+
+  return (len);
+
+#else
   return sendto(s, buf, len, flags, to, tolen);
+#endif
 }
 
 
@@ -325,12 +437,67 @@ olsr_recvfrom(int  s,
              struct sockaddr *from,
              socklen_t *fromlen)
 {
+#if SPOOF
+  struct msghdr mhdr;
+  struct iovec iov;
+  struct cmsghdr *cm;
+  struct sockaddr_dl *sdl;
+  struct sockaddr_in *sin = (struct sockaddr_in *) from; //XXX
+  unsigned char chdr[4096];
+  int count;
+  struct interface *ifc;
+  char iname[32];
+
+  bzero(&mhdr, sizeof(mhdr));
+  bzero(&iov, sizeof(iov));
+
+  mhdr.msg_name = (caddr_t) from;
+  mhdr.msg_namelen = *fromlen;
+  mhdr.msg_iov = &iov;
+  mhdr.msg_iovlen = 1;
+  mhdr.msg_control = (caddr_t) chdr;
+  mhdr.msg_controllen = sizeof (chdr);
+
+  iov.iov_len = MAXMESSAGESIZE;
+  iov.iov_base = buf;
+
+  count = recvmsg (s, &mhdr, MSG_DONTWAIT);
+  if (count <= 0)
+    {
+      return (count);
+    }
+
+  /* this needs to get communicated back to caller */
+  *fromlen = mhdr.msg_namelen;
+
+  cm = (struct cmsghdr *) chdr;
+  sdl = (struct sockaddr_dl *) CMSG_DATA (cm);
+  bzero (iname, sizeof (iname));
+  memcpy (iname, sdl->sdl_data, sdl->sdl_nlen);
+
+  ifc = if_ifwithsock (s);
+
+  if (strcmp (ifc->int_name, iname) != 0)
+    {
+      return (0);
+    }
+
+  OLSR_PRINTF (2, "%d bytes from %s, socket associated %s really received on %s\n",
+              count,
+              inet_ntoa (sin->sin_addr),
+              ifc->int_name,
+              iname);
+
+  return (count);
+
+#else /* SPOOF */
   return recvfrom(s, 
                  buf, 
                  len, 
                  0, 
                  from, 
                  fromlen);
+#endif /* SPOOF */
 }
 
 /**
index 97085c2..ab35b96 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -36,7 +36,7 @@
  * to the project. For more information see the website or contact
  * the copyright holders.
  *
- * $Id: net.c,v 1.35 2005/02/27 18:39:43 kattemat Exp $
+ * $Id: net.c,v 1.36 2005/03/02 20:53:43 spoggle Exp $
  */
 
 #include "net.h"
@@ -428,7 +428,7 @@ net_output(struct interface *ifp)
                     netbufs[ifp->if_nr]->pending, 
                     MSG_DONTROUTE, 
                     (struct sockaddr *)sin, 
-                    sizeof (*sin)) 
+                    sizeof (*sin))
         < 0)
        {
          perror("sendto(v4)");
@@ -445,7 +445,7 @@ net_output(struct interface *ifp)
                     netbufs[ifp->if_nr]->pending, 
                     MSG_DONTROUTE, 
                     (struct sockaddr *)sin6, 
-                    sizeof (*sin6)) 
+                    sizeof (*sin6))
         < 0)
        {
          perror("sendto(v6)");