howl patch for better BSD support

Andrea Campi andrea+freebsd_net at webcom.it
Fri Jan 7 08:57:13 PST 2005


Hi,

as promised, I've been working on improving howl. I've been in touch
with the authors, so in fact this is also resulting in cross-platform
fixes.

You can find the results of my work so far either attached to this
email (provided they get through mailing list filters) or at this URL:
http://www.webcom.it/ports/howl/files/patch-BSD ; you can just drop in
the ports/net/howl/files directory.

The current status is that autoipd and nifd are working (for people not
familiar with howl, these deal with address negotiation and interface
status monitoring respectively). I haven't done anything with
mDNSResponder apart from checking it still compiles.

There's a lot of stuff to cleanup. Style sucks beyond telling, but that's
because at this stage I'm striving to keep the sources diffable to their
Linux counterpart. This will change at a later stage.

Could some kind folk familiar look at the diff and maybe try it? Apart
from feedback of the "it works/doesn't" kind, I'm also looking for
guidance on the preferred way to do things.


On this note: I'm still using SIOCAIFADDR, as mentioned before, to add
a new IP address. I'm still not sure on how to do it best.

The way things currently work is:

 - when autoipd starts, it figures out a random IP, using the MAC
address as a seed. It starts probing for someone else already using it,
and if nobody is, it start announcing it;

 - autoipd then starts monitoring for conflicts, and when it detects
one it either tries to defend or picks a different one;

 - nifd is charged with monitoring link state changes; if it detects
one, or it notices that an interface changed IP address, it signals
autoipd to go through all the process again.

Now all this all nice, except it doesn't work! If I manually change
the interface address, to simulate what for instance dhclient would do,
nifd notices and signals autoipd, who then goes, picks a new IP address
and sets it!

This happens because nothing is checking whether the IP is valid before
letting autoipd loose. The problem is that this is too hard to do in the
general case; however, I think we can reasonably deal with the common
DHCP+zeroconf case by using dhclient-script(8). Basically, I'd start
autoipd on EXPIRE or FAIL and kill it on BOUND.

I will go this way, at least for a beginning, unless someone with more
experience is willing to guide me. I do plan on creating a sample script
that could be provided in the port to give a complete solution.

Thought?

Bye,
	Andrea
-- 
           Intel: where Quality is job number 0.9998782345!
-------------- next part --------------
Index: configure
===================================================================
RCS file: /home/CVS/howl/work/howl-0.9.7/configure,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- configure	12 Dec 2004 08:24:26 -0000	1.1.1.1
+++ configure	12 Dec 2004 09:16:29 -0000	1.3
@@ -8516,6 +8516,17 @@
 		PLATFORM_LIBS="-framework CoreFoundation"
 		HOWL_MAN_PAGES=
 		;;
+	*-*-freebsd*)
+		SRC_SUBDIRS="lib mDNSResponder autoipd nifd"
+		LIB_SUBDIRS="howl mDNSResponder"
+		HOWL_LIB_SUBDIRS="Posix NotOSX"
+		HOWL_LIB_OBJECTS='posix_salt.lo posix_socket.lo posix_time.lo posix_signal.lo posix_interface.lo notosx_mdns_stub.lo'
+		MDNSRESPONDER_LIB_SUBDIRS="Posix"
+		MDNSRESPONDER_LIB_OBJECTS='posix_mdns.lo'
+		AUTOIPD_EXTRA_OBJECTS='freebsd_autoip.lo posix_main.lo'
+		PLATFORM_LIBS=-lpthread
+		HOWL_MAN_PAGES='mDNSResponder.8 autoipd.8 nifd.8'
+		;;
 	*-*-linux*)
 		SRC_SUBDIRS="lib mDNSResponder autoipd nifd"
 		LIB_SUBDIRS="howl mDNSResponder"
@@ -8562,7 +8573,7 @@
 
 
 
-                                                                                                                                                                                                                                                                                                                                                                        ac_config_files="$ac_config_files Makefile include/Makefile include/salt/Makefile include/corby/Makefile include/discovery/Makefile include/rendezvous/Makefile src/Makefile src/lib/Makefile src/lib/howl/Makefile src/lib/howl/MacOSX/Makefile src/lib/howl/Posix/Makefile src/lib/howl/Win32/Makefile src/lib/howl/NotOSX/Makefile src/lib/mDNSResponder/Makefile src/lib/mDNSResponder/Posix/Makefile src/lib/mDNSResponder/Win32/Makefile src/mDNSResponder/Makefile src/mDNSResponder/Posix/Makefile src/mDNSResponder/Win32/Makefile src/autoipd/Makefile src/autoipd/Posix/Makefile src/autoipd/Linux/Makefile src/nifd/Makefile test/Makefile test/step/Makefile samples/Makefile samples/console/Makefile samples/console/publish/Makefile samples/console/browse/Makefile samples/console/resolve/Makefile samples/console/query/Makefile samples/Win32/Makefile samples/Win32/IEBar/Makefile docs/Makefile etc/Makefile howl.pc"
+                                                                                                                                                                                                                                                                                                                                                                        ac_config_files="$ac_config_files Makefile include/Makefile include/salt/Makefile include/corby/Makefile include/discovery/Makefile include/rendezvous/Makefile src/Makefile src/lib/Makefile src/lib/howl/Makefile src/lib/howl/MacOSX/Makefile src/lib/howl/Posix/Makefile src/lib/howl/Win32/Makefile src/lib/howl/NotOSX/Makefile src/lib/mDNSResponder/Makefile src/lib/mDNSResponder/Posix/Makefile src/lib/mDNSResponder/Win32/Makefile src/mDNSResponder/Makefile src/mDNSResponder/Posix/Makefile src/mDNSResponder/Win32/Makefile src/autoipd/Makefile src/autoipd/Posix/Makefile src/autoipd/BSD/Makefile src/autoipd/Linux/Makefile src/nifd/Makefile test/Makefile test/step/Makefile samples/Makefile samples/console/Makefile samples/console/publish/Makefile samples/console/browse/Makefile samples/console/resolve/Makefile samples/console/query/Makefile samples/Win32/Makefile samples/Win32/IEBar/Makefile docs/Makefile etc/Makefile howl.pc"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -9125,6 +9136,7 @@
   "src/mDNSResponder/Win32/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/mDNSResponder/Win32/Makefile" ;;
   "src/autoipd/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/autoipd/Makefile" ;;
   "src/autoipd/Posix/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/autoipd/Posix/Makefile" ;;
+  "src/autoipd/BSD/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/autoipd/BSD/Makefile" ;;
   "src/autoipd/Linux/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/autoipd/Linux/Makefile" ;;
   "src/nifd/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/nifd/Makefile" ;;
   "test/Makefile" ) CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
Index: src/autoipd/Makefile.in
===================================================================
RCS file: /home/CVS/howl/work/howl-0.9.7/src/autoipd/Makefile.in,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/autoipd/Makefile.in	12 Dec 2004 08:24:39 -0000	1.1.1.1
+++ src/autoipd/Makefile.in	12 Dec 2004 09:16:29 -0000	1.2
@@ -96,13 +96,13 @@
 am__include = @am__include@
 am__quote = @am__quote@
 install_sh = @install_sh@
-SUBDIRS = Posix Linux
+SUBDIRS = Posix BSD Linux
 INCLUDES = -I$(top_srcdir)/include/
 LDADD = $(AUTOIPD_EXTRA_OBJECTS) $(top_srcdir)/src/lib/howl/libhowl.la $(PLATFORM_LIBS)
 AM_LDFLAGS = -static
 bin_PROGRAMS = autoipd
 autoipd_SOURCES = autoip.c autoip.h
-EXTRA_autoipd_SOURCES = Linux/linux_autoip.c Posix/posix_main.c
+EXTRA_autoipd_SOURCES = BSD/freebsd_autoip.c Linux/linux_autoip.c Posix/posix_main.c
 autoipd_DEPENDENCIES = $(AUTOIPD_EXTRA_OBJECTS)
 subdir = src/autoipd
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -124,6 +124,7 @@
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
 @AMDEP_TRUE at DEP_FILES = ./$(DEPDIR)/autoip.Po \
+ at AMDEP_TRUE@	./$(DEPDIR)/freebsd_autoip.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/linux_autoip.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/posix_main.Po
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -182,6 +183,7 @@
 	  echo " rm -f $$p $$f"; \
 	  rm -f $$p $$f ; \
 	done
+freebsd_autoip.$(OBJEXT): BSD/freebsd_autoip.c
 linux_autoip.$(OBJEXT): Linux/linux_autoip.c
 posix_main.$(OBJEXT): Posix/posix_main.c
 autoipd$(EXEEXT): $(autoipd_OBJECTS) $(autoipd_DEPENDENCIES) 
@@ -195,6 +197,7 @@
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/autoip.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/freebsd_autoip.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/linux_autoip.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/posix_main.Po at am__quote@
 
@@ -219,6 +222,24 @@
 @AMDEP_TRUE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 	$(LTCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
 
+freebsd_autoip.o: BSD/freebsd_autoip.c
+ at AMDEP_TRUE@	source='BSD/freebsd_autoip.c' object='freebsd_autoip.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@	depfile='$(DEPDIR)/freebsd_autoip.Po' tmpdepfile='$(DEPDIR)/freebsd_autoip.TPo' @AMDEPBACKSLASH@
+ at AMDEP_TRUE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o freebsd_autoip.o `test -f 'BSD/freebsd_autoip.c' || echo '$(srcdir)/'`BSD/freebsd_autoip.c
+
+freebsd_autoip.obj: BSD/freebsd_autoip.c
+ at AMDEP_TRUE@	source='BSD/freebsd_autoip.c' object='freebsd_autoip.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@	depfile='$(DEPDIR)/freebsd_autoip.Po' tmpdepfile='$(DEPDIR)/freebsd_autoip.TPo' @AMDEPBACKSLASH@
+ at AMDEP_TRUE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o freebsd_autoip.obj `cygpath -w BSD/freebsd_autoip.c`
+
+freebsd_autoip.lo: BSD/freebsd_autoip.c
+ at AMDEP_TRUE@	source='BSD/freebsd_autoip.c' object='freebsd_autoip.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@	depfile='$(DEPDIR)/freebsd_autoip.Plo' tmpdepfile='$(DEPDIR)/freebsd_autoip.TPlo' @AMDEPBACKSLASH@
+ at AMDEP_TRUE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o freebsd_autoip.lo `test -f 'BSD/freebsd_autoip.c' || echo '$(srcdir)/'`BSD/freebsd_autoip.c
+
 linux_autoip.o: Linux/linux_autoip.c
 @AMDEP_TRUE@	source='Linux/linux_autoip.c' object='linux_autoip.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@	depfile='$(DEPDIR)/linux_autoip.Po' tmpdepfile='$(DEPDIR)/linux_autoip.TPo' @AMDEPBACKSLASH@
Index: src/autoipd/autoip.c
===================================================================
RCS file: /home/CVS/howl/work/howl-0.9.7/src/autoipd/autoip.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- src/autoipd/autoip.c	12 Dec 2004 08:24:39 -0000	1.1.1.1
+++ src/autoipd/autoip.c	12 Dec 2004 09:09:50 -0000	1.2
@@ -212,6 +212,12 @@
 	sw_debug(SW_LOG_VERBOSE, "IDLE\n");
 
 	/*
+	 * initialize the MAC address
+	 */
+	err = sw_network_interface_mac_address(self->m_nif, &self->m_mac_addr);
+	sw_check_okay(err, exit);
+
+	/*
 	 * initialize the ip address
 	 */
 	err = sw_autoip_network_interface_make_initial_ip_address(self);
Index: src/lib/howl/Posix/posix_interface.c
===================================================================
RCS file: /home/CVS/howl/work/howl-0.9.7/src/lib/howl/Posix/posix_interface.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 posix_interface.c
--- src/lib/howl/Posix/posix_interface.c	12 Dec 2004 08:24:31 -0000	1.1.1.1
+++ src/lib/howl/Posix/posix_interface.c	7 Jan 2005 15:39:58 -0000
@@ -45,6 +45,14 @@
 #	include <linux/ethtool.h> 
 #endif
 
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#include <net/ethernet.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/route.h>
+#endif
+
 #ifndef SIOCGIFCONF
 #	include <sys/sockio.h>
 #endif
@@ -231,13 +240,16 @@
 			sw_network_interface 	self, 
 			sw_bool					*	islinked)
 {
-#if defined(__linux__)
 	int 						fd;
-	struct ifreq			ifr;
 	int						r;
-	struct ethtool_value edata;
+	struct ifreq			ifr;
 	int						res;
 	sw_result 				err = SW_OKAY;
+#if defined(__linux__)
+	struct ethtool_value edata;
+#elif defined(__FreeBSD__)
+	struct ifmediareq			ifmr;
+#endif
 
 	sw_assert(self != NULL);		/* must be initialized */
 	sw_assert(islinked != NULL);	/* must be allocated */
@@ -251,6 +263,19 @@
 	memset(&ifr, 0, sizeof(ifr));
 	strncpy(ifr.ifr_name, self->m_name, sizeof(ifr.ifr_name) - 1);
 
+	/* get the interface flags */
+	res = ioctl(fd, SIOCGIFFLAGS, &ifr);
+	err = sw_translate_error(res == 0, errno);
+	sw_check_okay_log(err, exit);
+
+	/* if it's down, we can't have a link */
+	if ((ifr.ifr_flags & IFF_UP) != IFF_UP)
+	{
+		*islinked = SW_FALSE;
+		goto exit;
+	}
+
+#if defined(__linux__)
 	edata.cmd = ETHTOOL_GLINK;
 	ifr.ifr_data = (caddr_t) &edata;
 
@@ -259,15 +284,25 @@
 	sw_check_okay_log(err, exit);
 
 	*islinked = edata.data ? SW_TRUE : SW_FALSE;
+#elif defined(__FreeBSD__)
+	memset(&ifmr, 0, sizeof(ifmr));
+	strncpy(ifmr.ifm_name, self->m_name, sizeof(ifmr.ifm_name) - 1);
+
+	res = ioctl(fd, SIOCGIFMEDIA, (caddr_t)&ifmr);
+	err = sw_translate_error(res == 0, errno);
+	sw_check_okay_log(err, exit);
+
+        if (!ifmr.ifm_status & IFM_AVALID)
+		goto exit;
+
+	*islinked = (ifmr.ifm_status & IFM_ACTIVE)? SW_TRUE : SW_FALSE;
+#endif
 
 exit:
 
 	close(fd);
 
 	return err;
-#else
-	return SW_OKAY;
-#endif
 }
 
 
@@ -280,6 +315,77 @@
 }
 
 
+#if defined(__FreeBSD__)
+static int
+get_interface_lladdr_by_index(unsigned int ifindex, sw_mac_address *m_mac_addr) {
+
+	int			mib[6];
+	struct if_msghdr       *ifm;
+	struct sockaddr_dl     *sdl;
+
+	int			needed, count = 0;
+	int			res;
+	sw_result		err = SW_OKAY;
+
+retry:
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = 0;			/* address family */
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = ifindex;		/* interface index */
+
+	/* determine how much memory is needed */
+	res = sysctl(mib, 6, NULL, &needed, NULL, 0);
+	err = sw_translate_error(res == 0, errno);
+	sw_check_okay_log(err, exit);
+
+	ifm = (struct if_msghdr *)malloc(needed);
+	err = sw_translate_error(ifm != NULL, SW_E_MEM);
+	sw_check_okay_log(err, exit);
+
+	/* retrieve information */
+	res = sysctl(mib, 6, ifm, &needed, NULL, 0);
+	if (res < 0) {
+		if (errno == ENOMEM && count++ < 10) {
+			sw_debug(SW_LOG_WARNING,
+				"Routing table grew, retrying");
+			free(ifm);
+			sleep(1);
+			goto retry;
+		}
+
+		err = sw_translate_error(res == 0, errno);
+		sw_check_okay_log(err, exit);
+	}
+
+	sw_debug(SW_LOG_ERROR, "ifm->ifm_type %d=%d\n",
+				ifm->ifm_type, RTM_IFINFO);
+	if (ifm->ifm_type != RTM_IFINFO)
+		return 0;
+
+	if (ifm->ifm_data.ifi_datalen == 0)
+		ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
+
+	sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
+		 	sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
+
+	sw_debug(SW_LOG_ERROR, "sdl->sdl_alen %d\n", sdl->sdl_alen);
+	if (sdl->sdl_alen > 1) {
+		if (sdl->sdl_type == IFT_ETHER &&
+		    sdl->sdl_alen == ETHER_ADDR_LEN) {
+			sw_memcpy(m_mac_addr->m_id,
+				  (struct ether_addr *)LLADDR(sdl),
+				  sizeof(struct ether_addr));
+			return 1;
+		}
+	}
+
+exit:
+	return 0;
+}
+#endif
+
 static sw_result
 sw_posix_network_interface_init_from_name(
 	sw_posix_network_interface	nif,
@@ -332,6 +438,7 @@
 	sw_debug(SW_LOG_VERBOSE, "got ip address: %s\n", tmpname);
 
 	/* mac address */
+#if !defined(__FreeBSD__)
 #if defined(SIOCGIFHWADDR)
 	res = ioctl(sock, SIOCGIFHWADDR, &ifr);
 	err = sw_translate_error(res == 0, errno);
@@ -343,10 +450,17 @@
 	sw_check_okay_log(err, exit);
 	sw_memcpy(nif->m_super.m_mac_address.m_id, (sw_uint8*)(ifr.ifr_ifru.ifru_enaddr), sizeof(sw_mac_address)); 
 #endif
+#endif
 
 	/* index */
 	nif->m_super.m_index = if_nametoindex(ifr.ifr_name);
 
+#if defined(__FreeBSD__)
+	res = get_interface_lladdr_by_index(nif->m_super.m_index, &nif->m_super.m_mac_address);
+	err = sw_translate_error(res == 1, SW_E_UNKNOWN);
+	sw_check_okay_log(err, exit);
+#endif
+
 	/* initialize link status field */
 	sw_network_interface_link_status(&nif->m_super, &(nif->m_super.m_linked));
 
@@ -387,6 +501,12 @@
 	/* ip address */
 	sw_ipv4_address_init_from_saddr(&(nif->m_super.m_ipv4_address), ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr);
 
+#if defined(__FreeBSD__)
+	res = get_interface_lladdr_by_index(nif->m_super.m_index, &nif->m_super.m_mac_address);
+	sw_debug(SW_LOG_ERROR, "%d %s res %d\n", nif->m_super.m_index, ifr->ifr_name, res);
+	err = sw_translate_error(res == 1, SW_E_UNKNOWN);
+	sw_check_okay_log(err, exit);
+#else
 	/* get a socket for ioctling */
 	err = sw_posix_inet_socket(&sock);
 	sw_check_okay(err, exit);
@@ -403,6 +523,7 @@
 	sw_check_okay_log(err, exit);
 	sw_memcpy(nif->m_super.m_mac_address.m_id, (sw_uint8*)(ifr->ifr_ifru.ifru_enaddr), sizeof(sw_mac_address)); 
 #endif
+#endif
 
 	/* initialize link status field */
 	sw_network_interface_link_status(&nif->m_super, &(nif->m_super.m_linked));
@@ -515,6 +636,7 @@
 		sw_uint32					* 	nifc,
 		sw_network_interface	**	nifv)
 {
+#if defined(__linux__)
 	FILE * fh;
 	char buf[512];
 	int procnetdev_vsn;
@@ -585,6 +707,132 @@
 	}
 
 	return err;
+#elif defined(__FreeBSD__)
+	int				mib[6];
+	struct if_msghdr	       *ifm, *nextifm;
+	struct ifa_msghdr	       *ifam;
+	int				addrcount;
+	struct sockaddr_dl	       *sdl;
+	char				name[IFNAMSIZ];
+	sw_posix_network_interface	nif;
+	sw_ipv4_address			ipaddr;
+
+	int				needed, count = 0;
+	char			       *buf, *lim, *next;
+	int				res;
+	sw_result			err = SW_OKAY;
+
+	/* TODO hard code 10 for now */
+	/* allocate nifv  */
+	*nifv = (sw_network_interface*) sw_malloc(10 * sizeof(sw_network_interface));
+	err = sw_translate_error(*nifv, SW_E_MEM);
+	sw_check_okay_log(err, exit);
+	
+	*nifc = 0;
+
+retry:
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = 0;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = 0;
+
+	/* determine how much memory is needed */
+	res = sysctl(mib, 6, NULL, &needed, NULL, 0);
+	err = sw_translate_error(res == 0, errno);
+	sw_check_okay_log(err, exit);
+
+	buf = malloc(needed);
+	err = sw_translate_error(buf != NULL, SW_E_MEM);
+	sw_check_okay_log(err, exit);
+
+	/* retrieve information */
+	res = sysctl(mib, 6, buf, &needed, NULL, 0);
+	if (res < 0) {
+		if (errno == ENOMEM && count++ < 10) {
+			warnx("Routing table grew, retrying");
+			free(ifm);
+			sleep(1);
+			goto retry;
+		}
+
+		err = sw_translate_error(res == 0, errno);
+		sw_check_okay_log(err, exit);
+	}
+
+	lim = buf + needed;
+	next = buf;
+	while (next < lim) {
+		ifm = (struct if_msghdr *)next;
+
+		if (ifm->ifm_type == RTM_IFINFO) {
+			if (ifm->ifm_data.ifi_datalen == 0)
+			    ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
+
+			sdl = (struct sockaddr_dl *)((char *)ifm +
+			       sizeof(struct if_msghdr) -
+			       sizeof(struct if_data) +
+			       ifm->ifm_data.ifi_datalen);
+		} else {
+			sw_debug(SW_LOG_ERROR,
+				"out of sync parsing NET_RT_IFLIST\n");
+			err = SW_E_INIT;
+			goto exit;
+		}
+
+		next += ifm->ifm_msglen;
+		ifam = NULL;
+		addrcount = 0;
+		while (next < lim) {
+			nextifm = (struct if_msghdr *)next;
+			if (nextifm->ifm_type != RTM_NEWADDR)
+				break;
+
+			if (ifam == NULL)
+				ifam = (struct ifa_msghdr *)nextifm;
+
+			next += nextifm->ifm_msglen;
+		}
+
+		memcpy(name, sdl->sdl_data,
+			sizeof(name) < sdl->sdl_nlen ?
+				sizeof(name)-1 : sdl->sdl_nlen);
+		name[sizeof(name) < sdl->sdl_nlen ?
+		     sizeof(name)-1 : sdl->sdl_nlen] = '\0';
+
+		sw_debug(SW_LOG_ERROR, "name=%s", name);
+
+		if ((ifm->ifm_flags & IFF_BROADCAST) == 0)
+		{
+			continue;
+		}
+
+		/* create a new netif */
+		err = sw_network_interface_init((sw_network_interface*)&nif); 
+		sw_check_okay(err, exit);
+
+		/* initialize fields */
+		err = sw_posix_network_interface_init_from_name(nif, name);
+		sw_check_okay(err, exit);
+
+		err = sw_network_interface_ipv4_address((sw_network_interface)nif, &ipaddr);
+		sw_check_okay(err, exit);
+
+		(*nifv)[(*nifc)++] = (sw_network_interface)nif;
+	}
+	
+	err = SW_OKAY;
+
+exit:
+
+	if (err && *nifv)
+	{
+		sw_network_interfaces_fina(*nifc, *nifv);
+	}
+
+	return err;
+#endif
 }
 
 sw_result
diff -urN empty/Makefile src/autoipd/BSD/Makefile
--- src/autoipd/BSD/Makefile	Thu Jan  1 01:00:00 1970
+++ src/autoipd/BSD/Makefile	Sun Dec 12 10:36:27 2004
@@ -0,0 +1,232 @@
+# Makefile.in generated by automake 1.6.3 from Makefile.am.
+# src/autoipd/BSD/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = ../../..
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/howl
+pkglibdir = $(libdir)/howl
+pkgincludedir = $(includedir)/howl
+top_builddir = ../../..
+
+ACLOCAL = ${SHELL} /usr/ports/net/howl/work/howl-0.9.7/missing --run aclocal-1.6
+AUTOCONF = ${SHELL} /usr/ports/net/howl/work/howl-0.9.7/missing --run autoconf
+AUTOMAKE = ${SHELL} /usr/ports/net/howl/work/howl-0.9.7/missing --run automake-1.6
+AUTOHEADER = ${SHELL} /usr/ports/net/howl/work/howl-0.9.7/missing --run autoheader
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = /usr/bin/install -c 
+INSTALL_PROGRAM = install  -s  -m 555
+INSTALL_DATA = install   -m 444
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_SCRIPT = install   -m 555
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = s,x,x,
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = 
+host_triplet = i386-portbld-freebsd5.3
+
+EXEEXT = 
+OBJEXT = o
+PATH_SEPARATOR = :
+AMTAR = ${SHELL} /usr/ports/net/howl/work/howl-0.9.7/missing --run tar
+AS = @AS@
+AUTOIPD_EXTRA_OBJECTS = freebsd_autoip.lo posix_main.lo
+AWK = nawk
+CC = cc
+CXX = c++
+DEPDIR = .deps
+DLLTOOL = @DLLTOOL@
+ECHO = echo
+HOWL_LIBRARY_VERSION = 1:0:0
+HOWL_LIB_OBJECTS = posix_salt.lo posix_socket.lo posix_time.lo posix_signal.lo posix_interface.lo notosx_mdns_stub.lo
+HOWL_LIB_SUBDIRS = Posix NotOSX
+HOWL_MAN_PAGES = mDNSResponder.8 autoipd.8 nifd.8
+HOWL_RELEASE = 
+INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s
+LIBTOOL = $(SHELL) /usr/local/bin/libtool15
+LIB_SUBDIRS = howl mDNSResponder
+LN_S = ln -s
+MDNSRESPONDER_LIBRARY_VERSION = 0:0:0
+MDNSRESPONDER_LIB_OBJECTS = posix_mdns.lo
+MDNSRESPONDER_LIB_SUBDIRS = Posix
+OBJDUMP = @OBJDUMP@
+PACKAGE = howl
+PLATFORM_LIBS = -lpthread
+RANLIB = ranlib
+SRC_SUBDIRS = lib mDNSResponder autoipd nifd
+STRIP = strip
+VERSION = 0.9.7
+am__include = include
+am__quote = 
+install_sh = /usr/ports/net/howl/work/howl-0.9.7/install-sh
+sources_h = freebsd_autoip.h
+sources_c = freebsd_autoip.c
+DIST_SOURCES = $(sources_h) $(sources_c) Makefile.am
+INCLUDES = -I$(top_srcdir)/include/
+subdir = src/autoipd/BSD
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/include/howl_config.h
+CONFIG_CLEAN_FILES =
+DIST_COMMON = Makefile.am Makefile.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  src/autoipd/BSD/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+	@list='$(DISTFILES)'; for file in $$list; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkinstalldirs) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	distclean distclean-generic distclean-libtool distdir dvi \
+	dvi-am info info-am install install-am install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-man install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool uninstall uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff -urN empty/Makefile.in src/autoipd/BSD/Makefile.in
--- src/autoipd/BSD/Makefile.in	Thu Jan  1 01:00:00 1970
+++ src/autoipd/BSD/Makefile.in	Sun Dec 12 10:35:09 2004
@@ -0,0 +1,232 @@
+# Makefile.in generated by automake 1.6.3 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+
+EXEEXT = @EXEEXT@
+OBJEXT = @OBJEXT@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+AMTAR = @AMTAR@
+AS = @AS@
+AUTOIPD_EXTRA_OBJECTS = @AUTOIPD_EXTRA_OBJECTS@
+AWK = @AWK@
+CC = @CC@
+CXX = @CXX@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+HOWL_LIBRARY_VERSION = @HOWL_LIBRARY_VERSION@
+HOWL_LIB_OBJECTS = @HOWL_LIB_OBJECTS@
+HOWL_LIB_SUBDIRS = @HOWL_LIB_SUBDIRS@
+HOWL_MAN_PAGES = @HOWL_MAN_PAGES@
+HOWL_RELEASE = @HOWL_RELEASE@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LIBTOOL = @LIBTOOL@
+LIB_SUBDIRS = @LIB_SUBDIRS@
+LN_S = @LN_S@
+MDNSRESPONDER_LIBRARY_VERSION = @MDNSRESPONDER_LIBRARY_VERSION@
+MDNSRESPONDER_LIB_OBJECTS = @MDNSRESPONDER_LIB_OBJECTS@
+MDNSRESPONDER_LIB_SUBDIRS = @MDNSRESPONDER_LIB_SUBDIRS@
+OBJDUMP = @OBJDUMP@
+PACKAGE = @PACKAGE@
+PLATFORM_LIBS = @PLATFORM_LIBS@
+RANLIB = @RANLIB@
+SRC_SUBDIRS = @SRC_SUBDIRS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+sources_h = freebsd_autoip.h
+sources_c = freebsd_autoip.c
+DIST_SOURCES = $(sources_h) $(sources_c) Makefile.am
+INCLUDES = -I$(top_srcdir)/include/
+subdir = src/autoipd/BSD
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/include/howl_config.h
+CONFIG_CLEAN_FILES =
+DIST_COMMON = Makefile.am Makefile.in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  src/autoipd/BSD/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+tags: TAGS
+TAGS:
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+	@list='$(DISTFILES)'; for file in $$list; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkinstalldirs) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-generic distclean-libtool
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+	distclean distclean-generic distclean-libtool distdir dvi \
+	dvi-am info info-am install install-am install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-man install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool uninstall uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff -urN empty/freebsd_autoip.c src/autoipd/BSD/freebsd_autoip.c
--- src/autoipd/BSD/freebsd_autoip.c	Thu Jan  1 01:00:00 1970
+++ src/autoipd/BSD/freebsd_autoip.c	Fri Jan  7 16:07:11 2005
@@ -0,0 +1,511 @@
+/*
+ * Copyright 2003, 2004 Porchdog Software. All rights reserved.
+ * Copyright 2004, 2005	Andrea Campi <andrea PLUS freebsd AT webcom DOT it>
+ *
+ *	Redistribution and use in source and binary forms, with or without modification,
+ *	are permitted provided that the following conditions are met:
+ *
+ *		1. Redistributions of source code must retain the above copyright notice,
+ *		   this list of conditions and the following disclaimer.   
+ *		2. Redistributions in binary form must reproduce the above copyright notice,
+ *		   this list of conditions and the following disclaimer in the documentation
+ *		   and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY PORCHDOG SOFTWARE ``AS IS'' AND ANY
+ *	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *	IN NO EVENT SHALL THE HOWL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ *	INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *	BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ *	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *	OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ *	OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	The views and conclusions contained in the software and documentation are those
+ *	of the authors and should not be interpreted as representing official policies,
+ *	either expressed or implied, of Porchdog Software.
+ */
+
+#include "freebsd_autoip.h"
+#include <sys/sysctl.h>
+#include <netinet/in.h>
+#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <salt/socket.h>
+#include <salt/address.h>
+#include <salt/debug.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static sw_result
+sw_freebsd_autoip_network_interface_socket_event_handler(
+         								sw_socket_handler handler,
+         								sw_salt           salt,
+         								sw_socket         socket,
+         								sw_socket_event   events,
+         								sw_opaque         extra);
+
+
+static struct bpf_insn arp_bpf_filter [] = {
+	/* Make sure this is an IP packet... */
+	BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 1),
+
+	/* If we passed all the tests, ask for the whole packet. */
+	BPF_STMT(BPF_RET+BPF_K, 96),
+
+	/* Otherwise, drop it. */
+	BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+int arp_bpf_filter_len = (sizeof arp_bpf_filter / sizeof (struct bpf_insn));
+
+
+sw_string
+sw_platform_autoip_network_interface_default_interface_name()
+{
+	sw_string			ret = NULL;
+	int				mib[6];
+	struct if_msghdr	       *ifm, *nextifm;
+	struct ifa_msghdr	       *ifam;
+	struct sockaddr_dl	       *sdl;
+	char				name[IFNAMSIZ];
+
+	int				needed, count = 0;
+	char			       *buf, *lim, *next;
+	int				res;
+	sw_result			err = SW_OKAY;
+
+retry:
+	mib[0] = CTL_NET;
+	mib[1] = PF_ROUTE;
+	mib[2] = 0;
+	mib[3] = 0;
+	mib[4] = NET_RT_IFLIST;
+	mib[5] = 0;
+
+	/* determine how much memory is needed */
+	res = sysctl(mib, 6, NULL, &needed, NULL, 0);
+	err = sw_translate_error(res == 0, errno);
+	sw_check_okay_log(err, exit);
+
+	buf = malloc(needed);
+	err = sw_translate_error(buf != NULL, SW_E_MEM);
+	sw_check_okay_log(err, exit);
+
+	/* retrieve information */
+	res = sysctl(mib, 6, buf, &needed, NULL, 0);
+	if (res < 0) {
+		if (errno == ENOMEM && count++ < 10) {
+			warnx("Routing table grew, retrying");
+			free(ifm);
+			sleep(1);
+			goto retry;
+		}
+
+		err = sw_translate_error(res == 0, errno);
+		sw_check_okay_log(err, exit);
+	}
+
+	lim = buf + needed;
+	next = buf;
+	while (next < lim) {
+		ifm = (struct if_msghdr *)next;
+
+		if (ifm->ifm_type == RTM_IFINFO) {
+			if (ifm->ifm_data.ifi_datalen == 0)
+			    ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
+
+			sdl = (struct sockaddr_dl *)((char *)ifm +
+			       sizeof(struct if_msghdr) -
+			       sizeof(struct if_data) +
+			       ifm->ifm_data.ifi_datalen);
+		} else {
+			sw_debug(SW_LOG_ERROR,
+				"out of sync parsing NET_RT_IFLIST\n");
+			err = SW_E_INIT;
+			goto exit;
+		}
+
+		next += ifm->ifm_msglen;
+		ifam = NULL;
+		while (next < lim) {
+			nextifm = (struct if_msghdr *)next;
+			if (nextifm->ifm_type != RTM_NEWADDR)
+				break;
+
+			if (ifam == NULL)
+				ifam = (struct ifa_msghdr *)nextifm;
+
+			next += nextifm->ifm_msglen;
+		}
+
+		if ((ifm->ifm_flags & IFF_BROADCAST) == 0)
+		{
+			continue;
+		}
+
+		memcpy(name, sdl->sdl_data,
+			sizeof(name) < sdl->sdl_nlen ?
+				sizeof(name)-1 : sdl->sdl_nlen);
+		name[sizeof(name) < sdl->sdl_nlen ?
+		     sizeof(name)-1 : sdl->sdl_nlen] = '\0';
+
+		ret = strdup(name);
+		break;
+	}
+	
+	err = SW_OKAY;
+
+exit:
+
+	return ret;
+}
+
+
+sw_result
+sw_platform_autoip_network_interface_new(
+					sw_autoip_network_interface	*	anif,
+					sw_salt									salt,
+					sw_network_interface					nif)
+{
+	sw_freebsd_autoip_network_interface	self;
+	int											res;
+	int 											macsock;
+	struct ifreq								ifr;
+	char 											tname[IFNAMSIZ];
+	sw_result									err = SW_OKAY;
+	int					fd;
+	char					name[IFNAMSIZ];
+	struct bpf_version			v;
+	struct bpf_program			p;
+	int					flag, n;
+
+	self = (sw_freebsd_autoip_network_interface) sw_malloc(sizeof(struct _sw_freebsd_autoip_network_interface));
+	sw_check(self, exit, err = SW_E_MEM);
+
+	err = sw_autoip_network_interface_init(&self->m_super, salt, nif);
+	sw_check_okay(err, exit);
+	
+	/*
+	 * create out socket
+	 */
+	n = 0;
+	do {
+		sprintf(tname, "/dev/bpf%d", n++);
+		fd = open(tname, O_RDWR);
+	} while (fd < 0 && errno == EBUSY && n < 1000);
+	err = sw_translate_error(fd != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	self->m_osock = fd;
+	self->m_isock = fd;
+
+	/* Make sure the BPF version is in range... */
+	res = ioctl(fd, BIOCVERSION, &v);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	if (v.bv_major != BPF_MAJOR_VERSION || v.bv_minor < BPF_MINOR_VERSION) {
+		fprintf(stderr, "BPF version mismatch\n");
+		err = sw_translate_error(0, SW_E_UNKNOWN);
+		sw_check_okay_log(err, exit);
+	}
+
+	/*
+	 * initialize the device name
+	 */
+	sw_memset(&ifr, 0, sizeof(ifr));
+	sw_network_interface_name(self->m_super.m_nif, name, IFNAMSIZ);
+	strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
+
+	/*
+	 * bind to the interface
+	 */
+	res = ioctl(fd, BIOCSETIF, &ifr);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	/* Set immediate mode so that reads return as soon as a packet
+	 * comes in, rather than waiting for the input buffer to fill with
+	 * packets. */
+	flag = 1;
+	res = ioctl(fd, BIOCIMMEDIATE, &flag);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	/* */
+	flag = 0;
+	res = ioctl(fd, BIOCSSEESENT, &flag);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	/* */
+	flag = 1;
+	res = ioctl(fd, BIOCSHDRCMPLT, &flag);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	/* Get the required BPF buffer length from the kernel. */
+	res = ioctl(fd, BIOCGBLEN, &self->m_blen);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	self->m_buf = malloc(self->m_blen);
+	err = sw_translate_error(self->m_buf != NULL, errno);
+	sw_check_okay_log(err, exit);
+
+	/*
+	 * set BPF filter
+	 */
+	p.bf_len = arp_bpf_filter_len;
+	p.bf_insns = arp_bpf_filter;
+	res = ioctl(fd, BIOCSETF, &p);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	/*
+	 * set non-blocking socket
+	 */
+	res = fcntl(self->m_isock, F_GETFL);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	res = fcntl(self->m_isock, F_SETFL, res | O_NONBLOCK);
+	err = sw_translate_error(res != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	err = sw_tcp_socket_init_with_desc(&self->m_socket, self->m_isock);
+	sw_check_okay(err, exit);
+
+	err = sw_autoip_network_interface_handle_wakeup(&self->m_super);
+	sw_check_okay(err, exit);
+
+	*anif = &self->m_super;
+
+exit:
+
+	if (err && self)
+	{
+		sw_platform_autoip_network_interface_delete(&self->m_super);
+		*anif = NULL;
+	}
+
+	return err;
+}
+
+
+sw_result
+sw_platform_autoip_network_interface_delete(
+					sw_autoip_network_interface anif)
+{
+	sw_freebsd_autoip_network_interface self = (sw_freebsd_autoip_network_interface) anif;
+
+	sw_autoip_network_interface_fina(&self->m_super);
+
+	sw_platform_autoip_network_interface_stop_monitoring(anif);
+
+	/*
+	 * free
+	 */
+	close(self->m_isock);
+	close(self->m_osock);
+
+	/* 
+	 * and we're good
+	 */
+	sw_free(self);
+
+	return SW_OKAY;
+}
+
+
+sw_result
+sw_platform_autoip_network_interface_set_mac_address(
+		const char * s)
+{
+	return SW_E_INIT;
+}
+
+
+sw_result
+sw_platform_autoip_network_interface_start_monitoring(
+											sw_autoip_network_interface	anif)
+{
+	sw_freebsd_autoip_network_interface self = (sw_freebsd_autoip_network_interface) anif;
+	sw_result									err;
+
+	err = sw_salt_register_socket(self->m_super.m_salt, self->m_socket, SW_SOCKET_READ, (sw_socket_handler) self, sw_freebsd_autoip_network_interface_socket_event_handler, (sw_opaque) NULL);
+	sw_check_okay(err, exit);
+
+exit:
+
+	return err;
+}
+
+
+sw_result
+sw_platform_autoip_network_interface_stop_monitoring(
+											sw_autoip_network_interface	anif)
+{
+	sw_freebsd_autoip_network_interface self = (sw_freebsd_autoip_network_interface) anif;
+	sw_result									err;
+
+	err = sw_salt_unregister_socket(self->m_super.m_salt, self->m_socket);
+	sw_check_okay(err, exit);
+
+exit:
+
+	return err;
+}
+
+											
+
+sw_result
+sw_platform_autoip_network_interface_send_arp_packet(
+											sw_autoip_network_interface	anif, 
+											sw_arp_packet					*	packet)
+{
+	sw_freebsd_autoip_network_interface	self = (sw_freebsd_autoip_network_interface) anif;
+	struct sockaddr 							sndarp;
+	char											name[IFNAMSIZ];
+	sw_mac_address								mymac;
+	int											res;
+	sw_result									err = SW_OKAY;
+
+	/*
+	 * get interface name
+	 */
+	sw_network_interface_name(self->m_super.m_nif, name, IFNAMSIZ);
+	strcpy(sndarp.sa_data, name);
+
+	/*
+	 * send packet
+	 */
+	res = write(self->m_osock, packet, sizeof(struct _sw_arp_packet));
+	err = sw_translate_error(res >= 0, errno);
+	sw_check_okay_log(err, exit);
+
+exit:
+
+	return err;
+}
+
+
+sw_result
+sw_platform_autoip_network_interface_set_ip_address(
+											sw_autoip_network_interface	anif)
+{
+	sw_freebsd_autoip_network_interface	self = (sw_freebsd_autoip_network_interface) anif;
+   int            r;
+   int            sock_fd;
+   struct ifreq   ifr;
+   struct in_addr saddr;
+   char           name[IFNAMSIZ];
+	int				res;
+   sw_result      err = SW_OKAY;
+	struct ifaliasreq			ifra;
+	struct sockaddr_in			addr;
+
+   /*
+	 * socket for ioctl
+	 */
+	sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+	err = sw_translate_error(sock_fd != -1, errno);
+	sw_check_okay_log(err, exit);
+
+	/*
+	 * initialize the device name
+	 */
+   sw_memset(&ifra, 0, sizeof(ifra));
+   sw_network_interface_name(self->m_super.m_nif, name, IFNAMSIZ);
+   strncpy(ifra.ifra_name, name, IFNAMSIZ - 1);
+                                                          
+	/*
+	 * initialize the ip address
+	 */
+	addr.sin_addr.s_addr = sw_ipv4_address_saddr(self->m_super.m_ip_addr);
+	addr.sin_family	= AF_INET;
+	addr.sin_len	= sizeof(struct sockaddr_in);
+	memcpy(&ifra.ifra_addr,		&addr, sizeof(struct sockaddr_in));
+
+	addr.sin_addr.s_addr |= ntohl(0x0000ffff);
+	memcpy(&ifra.ifra_broadaddr,	&addr, sizeof(struct sockaddr_in));
+
+	addr.sin_addr.s_addr = ntohl(0xffff0000);
+	memcpy(&ifra.ifra_mask,		&addr, sizeof(struct sockaddr_in));
+
+	res = ioctl(sock_fd, SIOCAIFADDR, &ifra);
+	err = sw_translate_error(res == 0, errno);
+	sw_check_okay_log(err, exit);
+
+	err = sw_network_interface_set_ipv4_address(self->m_super.m_nif, self->m_super.m_ip_addr);
+	sw_check_okay(err, exit);
+
+exit:
+
+	if (sock_fd != -1)
+	{
+	   close(sock_fd);
+	}
+}
+
+
+static sw_result
+sw_freebsd_autoip_network_interface_socket_event_handler(
+         								sw_socket_handler handler,
+         								sw_salt           salt,
+         								sw_socket         socket,
+         								sw_socket_event   events,
+         								sw_opaque         extra)
+{
+	static sw_mac_address	ProbeSenderMAC = { 0, 0, 0, 0, 0, 0 };
+
+	sw_freebsd_autoip_network_interface self = (sw_freebsd_autoip_network_interface) handler;
+	char						       *ptr, *limit;
+	struct bpf_hdr					       *hdr;
+	sw_arp_packet					       *packet; 
+	char 							smyip[18], spacketip[18];
+	char 							smymac[18], spacketmac[18];
+	int							bytes;
+	sw_result					err = SW_OKAY;
+	
+   sw_assert(self != NULL);
+
+	/*
+	 * ignore invocations if not our socket
+	 */
+	sw_check(self->m_isock == sw_socket_desc(socket), exit, err = SW_OKAY);
+
+	bytes = read(self->m_isock, self->m_buf, self->m_blen);
+	err = sw_translate_error(bytes >= 0, errno);
+	sw_check_okay_log(err, exit);
+
+
+	for (ptr = (char *)self->m_buf, limit = ptr + bytes;
+	     ptr < limit;
+	     ptr += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen)) {
+		hdr = (struct bpf_hdr *)ptr;
+		packet = (sw_arp_packet *)(ptr + hdr->bh_hdrlen);
+
+		if (hdr->bh_caplen >= (sizeof(struct _sw_ethernet_header) + sizeof(struct _sw_arp_header)))
+		{
+			if (((ntohs(packet->m_arp_header.m_op)) == SW_AUTOIP_ARP_REQUEST) ||
+			    ((ntohs(packet->m_arp_header.m_op)) == SW_AUTOIP_ARP_REPLY))
+			{
+				err = sw_autoip_network_interface_read_arp_packet(&self->m_super, packet);
+				sw_check_okay(err, exit);
+			}
+		}
+	}
+
+exit:
+
+	return err;
+}
diff -urN empty/freebsd_autoip.h src/autoipd/BSD/freebsd_autoip.h
--- src/autoipd/BSD/freebsd_autoip.h	Thu Jan  1 01:00:00 1970
+++ src/autoipd/BSD/freebsd_autoip.h	Thu Dec  9 17:49:04 2004
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2003, 2004 Porchdog Software. All rights reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without modification,
+ *	are permitted provided that the following conditions are met:
+ *
+ *		1. Redistributions of source code must retain the above copyright notice,
+ *		   this list of conditions and the following disclaimer.   
+ *		2. Redistributions in binary form must reproduce the above copyright notice,
+ *		   this list of conditions and the following disclaimer in the documentation
+ *		   and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY PORCHDOG SOFTWARE ``AS IS'' AND ANY
+ *	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *	IN NO EVENT SHALL THE HOWL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ *	INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *	BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ *	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *	OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ *	OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	The views and conclusions contained in the software and documentation are those
+ *	of the authors and should not be interpreted as representing official policies,
+ *	either expressed or implied, of Porchdog Software.
+ */
+
+#ifndef _freebsd_autoip_h
+#define _freebsd_autoip_h
+
+
+#include "../autoip.h"
+#include <salt/address.h>
+#include <salt/socket.h>
+#include <salt/interface.h> 
+#include <net/if.h>
+
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+
+struct																_sw_freebsd_autoip_network_interface;
+typedef struct _sw_freebsd_autoip_network_interface	*	sw_freebsd_autoip_network_interface;
+
+
+struct _sw_freebsd_autoip_network_interface
+{
+	struct _sw_autoip_network_interface	m_super;
+	sw_socket									m_socket;
+	sw_sockdesc_t								m_osock;
+	sw_sockdesc_t								m_isock;
+
+	u_int					m_blen;
+	unsigned char			       *m_buf;
+};
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+ 
+#endif
Index: src/autoipd/BSD/Makefile.am
===================================================================
RCS file: src/autoipd/BSD/Makefile.am
diff -N src/autoipd/BSD/Makefile.am
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/autoipd/BSD/Makefile.am	12 Dec 2004 09:36:10 -0000	1.1
@@ -0,0 +1,4 @@
+sources_h		=	freebsd_autoip.h
+sources_c		=	freebsd_autoip.c
+DIST_SOURCES	= 	$(sources_h) $(sources_c) Makefile.am
+INCLUDES			=	-I$(top_srcdir)/include/


More information about the freebsd-net mailing list