? .Makefile.swp ? work Index: Makefile =================================================================== RCS file: /home/pcvs/ports/net/avahi/Makefile,v retrieving revision 1.44 diff -u -p -r1.44 Makefile --- Makefile 2 Jan 2007 06:30:23 -0000 1.44 +++ Makefile 1 Feb 2007 01:29:00 -0000 @@ -23,10 +23,12 @@ USE_GNOME?= gnomehack ltverhack glib20 USE_GNOME_SUBR=yes USE_RC_SUBR= yes USE_GMAKE= yes -USE_AUTOTOOLS= libtool:15 +USE_AUTOTOOLS= autoconf:259 automake:19 libtool:15 USE_LDCONFIG= yes USE_GETOPT_LONG=yes CONFIGURE_ARGS?=--with-distro=freebsd \ + --with-autoipd-user=avahi \ + --with-autoipd-group=avahi \ --with-dbus-system-address=unix:path=/var/run/dbus/system_bus_socket \ --disable-qt3 \ --disable-qt4 \ @@ -37,7 +39,6 @@ CONFIGURE_ARGS?=--with-distro=freebsd \ --disable-doxygen-dot \ --localstatedir=/var \ --enable-compat-howl \ - --disable-autoipd \ --mandir=${PREFIX}/man CONFIGURE_ENV= CPPFLAGS="-I${LOCALBASE}/include" \ LDFLAGS="-L${LOCALBASE}/lib" \ @@ -51,7 +52,8 @@ MAN1= avahi-browse-domains.1 avahi-brows avahi-publish-service.1 avahi-publish.1 avahi-resolve-address.1 \ avahi-resolve-host-name.1 avahi-resolve.1 avahi-set-host-name.1 MAN5= avahi-daemon.conf.5 avahi.service.5 avahi.hosts.5 -MAN8= avahi-daemon.8 avahi-dnsconfd.8 avahi-dnsconfd.action.8 +MAN8= avahi-autoipd.8 avahi-autoipd.action.8 \ + avahi-daemon.8 avahi-dnsconfd.8 avahi-dnsconfd.action.8 OPTIONS= GTK2 "Build a GTK+ 2 browser utility" off \ LIBDNS "Enable mDNSResponder compatibility" off Index: pkg-plist =================================================================== RCS file: /home/pcvs/ports/net/avahi/pkg-plist,v retrieving revision 1.13 diff -u -p -r1.13 pkg-plist --- pkg-plist 14 Oct 2006 08:35:38 -0000 1.13 +++ pkg-plist 1 Feb 2007 01:29:00 -0000 @@ -8,6 +8,7 @@ bin/avahi-resolve bin/avahi-resolve-address bin/avahi-resolve-host-name bin/avahi-set-host-name +etc/avahi/avahi-autoipd.action etc/avahi/avahi-daemon.conf etc/avahi/avahi-dnsconfd.action etc/avahi/hosts @@ -90,6 +91,7 @@ libdata/pkgconfig/avahi-compat-howl.pc %%LIBDNS%%libdata/pkgconfig/avahi-compat-libdns_sd.pc libdata/pkgconfig/avahi-core.pc libdata/pkgconfig/avahi-glib.pc +sbin/avahi-autoipd sbin/avahi-daemon sbin/avahi-dnsconfd %%DATADIR%%/avahi-service.dtd Index: files/patch-Makefile.am =================================================================== RCS file: files/patch-Makefile.am diff -N files/patch-Makefile.am --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ files/patch-Makefile.am 1 Feb 2007 01:29:00 -0000 @@ -0,0 +1,11 @@ +--- Makefile.am.orig Wed Jan 31 23:58:47 2007 ++++ Makefile.am Wed Jan 31 23:59:06 2007 +@@ -118,7 +118,7 @@ + $(srcdir)/avahi-core/log.h + endif + +-pkgconfigdir = $(libdir)/pkgconfig ++pkgconfigdir = $(prefix)/libdata/pkgconfig + pkgconfig_DATA = avahi-core.pc + + avahi-core.pc: avahi-core.pc.in Index: files/patch-avahi-autoipd__Makefile.am =================================================================== RCS file: files/patch-avahi-autoipd__Makefile.am diff -N files/patch-avahi-autoipd__Makefile.am --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ files/patch-avahi-autoipd__Makefile.am 1 Feb 2007 01:29:00 -0000 @@ -0,0 +1,23 @@ +--- avahi-autoipd/Makefile.am.orig Tue Dec 26 10:42:17 2006 ++++ avahi-autoipd/Makefile.am Thu Feb 1 01:19:30 2007 +@@ -36,12 +36,19 @@ + avahi_autoipd_SOURCES = \ + main.c main.h \ + ../avahi-daemon/setproctitle.c ../avahi-daemon/setproctitle.h \ +- iface.h iface-linux.c \ ++ iface.h \ + ../avahi-common/malloc.h ../avahi-common/malloc.c \ + ../avahi-common/timeval.h ../avahi-common/timeval.c + + avahi_autoipd_CFLAGS = $(AM_CFLAGS) $(LIBDAEMON_CFLAGS) + avahi_autoipd_LDADD = $(AM_LDADD) $(LIBDAEMON_LIBS) ++ ++if TARGET_FREEBSD ++avahi_autoipd_SOURCES += iface-bsd.c ++avahi_autoipd_LDADD += -lpcap ++else ++avahi_autoipd_SOURCES += iface-linux.c ++endif + + pkgsysconf_SCRIPTS=avahi-autoipd.action + Index: files/patch-avahi-autoipd__avahi-autoipd.action =================================================================== RCS file: files/patch-avahi-autoipd__avahi-autoipd.action diff -N files/patch-avahi-autoipd__avahi-autoipd.action --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ files/patch-avahi-autoipd__avahi-autoipd.action 1 Feb 2007 01:29:00 -0000 @@ -0,0 +1,65 @@ +--- avahi-autoipd/avahi-autoipd.action.orig Tue Dec 26 10:42:17 2006 ++++ avahi-autoipd/avahi-autoipd.action Thu Feb 1 01:19:30 2007 +@@ -30,49 +30,21 @@ + # $2 interface name + # $3 IP adddress + +-if [ -x /bin/ip -o -x /sbin/ip ] ; then ++# We have the BSD ifconfig tool + +- # We have the Linux ip tool from the iproute package ++case "$1" in ++BIND) ++ ifconfig "$2" "$3"/16 ++ ;; ++ ++CONFLICT|STOP|UNBIND) ++ ifconfig "$2" "$3"/16 delete ++ ;; + +- case "$1" in +- BIND) +- ip addr add "$3"/16 brd 169.254.255.255 label "$2:avahi" scope link dev "$2" +- ;; +- +- CONFLICT|UNBIND|STOP) +- ip addr del "$3"/16 brd 169.254.255.255 label "$2:avahi" scope link dev "$2" +- ;; +- +- *) +- echo "Unknown event $1" >&2 +- exit 1 +- ;; +- esac +- +-elif [ -x /bin/ifconfig -o -x /sbin/ifconfig ] ; then +- +- # We have the old ifconfig tool +- +- case "$1" in +- BIND) +- ifconfig "$2:3" inet "$3" netmask 255.255.0.0 broadcast 169.254.255.255 up +- ;; +- +- CONFLICT|STOP|UNBIND) +- ifconfig "$2:3" down +- ;; +- +- *) +- echo "Unknown event $1" >&2 +- exit 1 +- ;; +- esac +- +-else +- +- echo "No network configuration tool found." >&2 ++*) ++ echo "Unknown event $1" >&2 + exit 1 +- +-fi ++ ;; ++esac + + exit 0 Index: files/patch-avahi-autoipd__iface-bsd.c =================================================================== RCS file: files/patch-avahi-autoipd__iface-bsd.c diff -N files/patch-avahi-autoipd__iface-bsd.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ files/patch-avahi-autoipd__iface-bsd.c 1 Feb 2007 01:29:01 -0000 @@ -0,0 +1,419 @@ +--- avahi-autoipd/iface-bsd.c.orig Thu Feb 1 01:19:30 2007 ++++ avahi-autoipd/iface-bsd.c Thu Feb 1 01:19:30 2007 +@@ -0,0 +1,416 @@ ++/* rcs tags go here */ ++/* Original author: Bruce M. Simpson */ ++ ++/*** ++ This file is part of avahi. ++ ++ avahi is free software; you can redistribute it and/or modify it ++ under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ avahi is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General ++ Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with avahi; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#include ++#include ++ ++#include "iface.h" ++ ++#ifndef IN_LINKLOCAL ++#define IN_LINKLOCAL(i) (((u_int32_t)(i) & (0xffff0000)) == (0xa9fe0000)) ++#endif ++ ++#ifndef elementsof ++#define elementsof(array) (sizeof(array)/sizeof(array[0])) ++#endif ++ ++#ifndef so_set_nonblock ++#define so_set_nonblock(s, val) \ ++ do { \ ++ int __flags; \ ++ __flags = fcntl((s), F_GETFL); \ ++ if (__flags == -1) \ ++ break; \ ++ if (val != 0) \ ++ __flags |= O_NONBLOCK; \ ++ else \ ++ __flags &= ~O_NONBLOCK; \ ++ (void)fcntl((s), F_SETFL, __flags); \ ++ } while (0) ++#endif ++ ++#define MAX_RTMSG_SIZE 2048 ++ ++struct rtm_dispinfo { ++ u_char *di_buf; ++ ssize_t di_buflen; ++ ssize_t di_len; ++}; ++ ++union rtmunion { ++ struct rt_msghdr rtm; ++ struct if_msghdr ifm; ++ struct ifa_msghdr ifam; ++ struct ifma_msghdr ifmam; ++ struct if_announcemsghdr ifan; ++}; ++typedef union rtmunion rtmunion_t; ++ ++struct Address; ++typedef struct Address Address; ++ ++struct Address { ++ in_addr_t address; ++ AVAHI_LLIST_FIELDS(Address, addresses); ++}; ++ ++static int rtm_dispatch(void); ++static int rtm_dispatch_newdeladdr(struct rtm_dispinfo *di); ++static int rtm_dispatch_ifannounce(struct rtm_dispinfo *di); ++static struct sockaddr *next_sa(struct sockaddr *sa); ++ ++static int fd = -1; ++static int ifindex = -1; ++static AVAHI_LLIST_HEAD(Address, addresses) = NULL; ++ ++int ++iface_init(int idx) ++{ ++ ++ fd = socket(PF_ROUTE, SOCK_RAW, 0); ++ if (fd == -1) { ++ daemon_log(LOG_ERR, "socket(PF_ROUTE): %s", strerror(errno)); ++ return (-1); ++ } ++ ++ so_set_nonblock(fd, 1); ++ ++ ifindex = idx; ++ ++ return (fd); ++} ++ ++int ++iface_get_initial_state(State *state) ++{ ++ int mib[6]; ++ char *buf; ++ struct if_msghdr *ifm; ++ struct ifa_msghdr *ifam; ++ char *lim; ++ char *next; ++ struct sockaddr *sa; ++ size_t len; ++ int naddrs; ++ ++ assert(state != NULL); ++ assert(fd != -1); ++ ++ naddrs = 0; ++ ++ mib[0] = CTL_NET; ++ mib[1] = PF_ROUTE; ++ mib[2] = 0; ++ mib[3] = 0; ++ mib[4] = NET_RT_IFLIST; ++ mib[5] = ifindex; ++ ++ if (sysctl(mib, elementsof(mib), NULL, &len, NULL, 0) != 0) { ++ daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s", ++ strerror(errno)); ++ return (-1); ++ } ++ ++ buf = malloc(len); ++ if (buf == NULL) { ++ daemon_log(LOG_ERR, "malloc(%d): %s", len, strerror(errno)); ++ return (-1); ++ } ++ ++ if (sysctl(mib, elementsof(mib), buf, &len, NULL, 0) != 0) { ++ daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s", ++ strerror(errno)); ++ free(buf); ++ return (-1); ++ } ++ ++ lim = buf + len; ++ for (next = buf; next < lim; next += ifm->ifm_msglen) { ++ ifm = (struct if_msghdr *)next; ++ if (ifm->ifm_type == RTM_NEWADDR) { ++ ifam = (struct ifa_msghdr *)next; ++ sa = (struct sockaddr *)(ifam + 1); ++ if (sa->sa_family != AF_INET) ++ continue; ++ ++naddrs; ++ } ++ } ++ free(buf); ++ ++ *state = (naddrs > 0) ? STATE_SLEEPING : STATE_START; ++ ++ return (0); ++} ++ ++int ++iface_process(Event *event) ++{ ++ int b; ++ ++ assert(fd != -1); ++ ++ b = !!addresses; ++ ++ if (rtm_dispatch() == -1) ++ return (-1); ++ ++ if (b && !addresses) ++ *event = EVENT_ROUTABLE_ADDR_UNCONFIGURED; ++ else if (!b && addresses) ++ *event = EVENT_ROUTABLE_ADDR_CONFIGURED; ++ ++ return (0); ++} ++ ++void ++iface_done(void) ++{ ++ Address *a; ++ ++ if (fd != -1) { ++ close(fd); ++ fd = -1; ++ } ++ ++ while ((a = addresses) != NULL) { ++ AVAHI_LLIST_REMOVE(Address, addresses, addresses, a); ++ avahi_free(a); ++ } ++} ++ ++/* ++ * Dispatch kernel routing socket messages. ++ */ ++static int ++rtm_dispatch(void) ++{ ++ struct msghdr mh; ++ struct iovec iov[1]; ++ struct rt_msghdr *rtm; ++ struct rtm_dispinfo *di; ++ ssize_t len; ++ int retval; ++ ++ di = malloc(sizeof(*di)); ++ if (di == NULL) { ++ daemon_log(LOG_ERR, "malloc(%d): %s", sizeof(*di), ++ strerror(errno)); ++ return (-1); ++ } ++ di->di_buflen = MAX_RTMSG_SIZE; ++ di->di_buf = calloc(MAX_RTMSG_SIZE, 1); ++ if (di->di_buf == NULL) { ++ free(di); ++ daemon_log(LOG_ERR, "calloc(%d): %s", MAX_RTMSG_SIZE, ++ strerror(errno)); ++ return (-1); ++ } ++ ++ memset(&mh, 0, sizeof(mh)); ++ iov[0].iov_base = di->di_buf; ++ iov[0].iov_len = di->di_buflen; ++ mh.msg_iov = iov; ++ mh.msg_iovlen = 1; ++ ++ retval = 0; ++ for (;;) { ++ len = recvmsg(fd, &mh, MSG_DONTWAIT); ++ if (len == -1) { ++ if (errno == EWOULDBLOCK) ++ break; ++ else { ++ daemon_log(LOG_ERR, "recvmsg(): %s", ++ strerror(errno)); ++ retval = -1; ++ break; ++ } ++ } ++ ++ rtm = (void *)di->di_buf; ++ if (rtm->rtm_version != RTM_VERSION) { ++ daemon_log(LOG_ERR, ++ "unknown routing socket message (version %d)\n", ++ rtm->rtm_version); ++ /* this is non-fatal; just ignore it for now. */ ++ continue; ++ } ++ ++ switch (rtm->rtm_type) { ++ case RTM_NEWADDR: ++ case RTM_DELADDR: ++ retval = rtm_dispatch_newdeladdr(di); ++ break; ++ case RTM_IFANNOUNCE: ++ retval = rtm_dispatch_ifannounce(di); ++ break; ++ default: ++ break; ++ } ++ ++ /* ++ * If we got an error; assume our position on the call ++ * stack is enclosed by a level-triggered event loop, ++ * and signal the error condition. ++ */ ++ if (retval != 0) ++ break; ++ } ++ free(di->di_buf); ++ free(di); ++ ++ return (retval); ++} ++ ++/* handle link coming or going away */ ++static int ++rtm_dispatch_ifannounce(struct rtm_dispinfo *di) ++{ ++ rtmunion_t *rtm = (void *)di->di_buf; ++ ++ assert(rtm->rtm.rtm_type == RTM_IFANNOUNCE); ++ ++ switch (rtm->ifan.ifan_what) { ++ case IFAN_ARRIVAL: ++ if (rtm->ifan.ifan_index == ifindex) { ++ daemon_log(LOG_ERR, ++"RTM_IFANNOUNCE IFAN_ARRIVAL, for ifindex %d, which we already manage.", ++ ifindex); ++ return (-1); ++ } ++ break; ++ case IFAN_DEPARTURE: ++ if (rtm->ifan.ifan_index == ifindex) { ++ daemon_log(LOG_ERR, "Interface vanished."); ++ return (-1); ++ } ++ break; ++ default: ++ /* ignore */ ++ break; ++ } ++ ++ return (0); ++} ++ ++static struct sockaddr * ++next_sa(struct sockaddr *sa) ++{ ++ void *p; ++ size_t sa_size; ++ ++ sa_size = sa->sa_len; ++ if (sa_size < sizeof(u_long)) ++ sa_size = sizeof(u_long); ++ p = ((char *)sa) + sa_size; ++ ++ return (struct sockaddr *)p; ++} ++ ++/* handle address coming or going away */ ++static int ++rtm_dispatch_newdeladdr(struct rtm_dispinfo *di) ++{ ++ Address *ap; ++ rtmunion_t *rtm; ++ struct sockaddr *sa; ++ struct sockaddr_in *sin; ++ ++/* macro to skip to next RTA; has side-effects */ ++#define SKIPRTA(rtmsgp, rta, sa) \ ++ do { \ ++ if ((rtmsgp)->rtm_addrs & (rta)) \ ++ (sa) = next_sa((sa)); \ ++ } while (0) ++ ++ rtm = (void *)di->di_buf; ++ ++ assert(rtm->rtm.rtm_type == RTM_NEWADDR || ++ rtm->rtm.rtm_type == RTM_DELADDR); ++ ++ if (rtm->rtm.rtm_index != ifindex) ++ return (0); ++ ++ if (!(rtm->rtm.rtm_addrs & RTA_IFA)) { ++ daemon_log(LOG_ERR, "ifa msg has no RTA_IFA."); ++ return (0); ++ } ++ ++ /* skip over rtmsg padding correctly */ ++ sa = (struct sockaddr *)((&rtm->ifam) + 1); ++ SKIPRTA(&rtm->rtm, RTA_DST, sa); ++ SKIPRTA(&rtm->rtm, RTA_GATEWAY, sa); ++ SKIPRTA(&rtm->rtm, RTA_NETMASK, sa); ++ SKIPRTA(&rtm->rtm, RTA_GENMASK, sa); ++ SKIPRTA(&rtm->rtm, RTA_IFP, sa); ++ ++ /* ++ * sa now points to RTA_IFA sockaddr; we are only interested ++ * in updates for link-local addresses. ++ */ ++ if (sa->sa_family != AF_INET) ++ return (0); ++ sin = (struct sockaddr_in *)sa; ++ if (!IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr))) ++ return (0); ++ ++ for (ap = addresses; ap; ap = ap->addresses_next) { ++ if (ap->address == sin->sin_addr.s_addr) ++ break; ++ } ++ if (rtm->rtm.rtm_type == RTM_DELADDR && ap != NULL) { ++ AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap); ++ avahi_free(ap); ++ } ++ if (rtm->rtm.rtm_type == RTM_NEWADDR && ap == NULL) { ++ ap = avahi_new(Address, 1); ++ ap->address = sin->sin_addr.s_addr; ++ AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap); ++ } ++ ++ return (0); ++#undef SKIPRTA ++} Index: files/patch-avahi-autoipd__main.c =================================================================== RCS file: files/patch-avahi-autoipd__main.c diff -N files/patch-avahi-autoipd__main.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ files/patch-avahi-autoipd__main.c 1 Feb 2007 01:29:01 -0000 @@ -0,0 +1,395 @@ +--- avahi-autoipd/main.c.orig Tue Dec 26 10:42:17 2006 ++++ avahi-autoipd/main.c Thu Feb 1 01:19:30 2007 +@@ -23,32 +23,49 @@ + #include + #endif + +-#include +-#include ++#include ++#include ++#include ++#include + #include ++#include ++#ifdef __FreeBSD__ ++#include ++#endif ++ ++#ifdef __linux__ + #include ++#endif + #include +-#include +-#include ++#include ++#ifdef __FreeBSD__ ++#include ++#include ++#endif ++#include ++ + #include + #include +-#include + #include +-#include +-#include +-#include +-#include +-#include ++#include ++#include + #include +-#include + #include +-#include +-#include ++#include ++#include ++#include ++ + #include ++#include ++#include ++#include ++ ++#ifndef __linux__ ++#include ++#endif + + #include + #include +- + #include + + #include +@@ -60,10 +77,6 @@ + #include "main.h" + #include "iface.h" + +-#ifndef __linux__ +-#error "avahi-autoipd is only available on Linux for now" +-#endif +- + /* An implementation of RFC 3927 */ + + /* Constants from the RFC */ +@@ -249,6 +262,15 @@ + return -1; + } + ++static void packet_free(uint8_t *packet){ ++#ifdef __FreeBSD__ ++ uint8_t *r = packet - sizeof(struct ether_header); /* XXX */ ++ avahi_free(r); ++#else ++ avahi_free(packet); ++#endif ++} ++ + static void* packet_new(const ArpPacketInfo *info, size_t *packet_len) { + uint8_t *r; + +@@ -258,6 +280,17 @@ + + *packet_len = ARP_PACKET_SIZE; + r = avahi_new0(uint8_t, *packet_len); ++ ++#ifdef __FreeBSD__ ++ /* XXX: Cheat. Put link-layer header in front. */ ++ r = avahi_new0(uint8_t, ARP_PACKET_SIZE + sizeof(struct ether_header)); ++ assert(r != NULL); ++ r += sizeof(struct ether_header); ++ *packet_len = ARP_PACKET_SIZE; ++#else ++ *packet_len = ARP_PACKET_SIZE; ++ r = avahi_new0(uint8_t, *packet_len); ++#endif + + r[1] = 1; /* HTYPE */ + r[2] = 8; /* PTYPE */ +@@ -392,6 +425,10 @@ + return -1; + } + ++#ifdef __linux__ ++ ++/* Linux 'packet socket' specific implementation */ ++ + static int open_socket(int iface, uint8_t *hw_address) { + int fd = -1; + struct sockaddr_ll sa; +@@ -493,13 +530,221 @@ + + fail: + if (*packet) { +- avahi_free(*packet); ++ packet_free(*packet); + *packet = NULL; + } + + return -1; + } +- ++ ++static void ++close_socket(int fd) { ++ close(fd); ++} ++ ++#else /* !__linux__ */ ++/* PCAP-based implementation */ ++ ++static pcap_t *__pp; ++static char __pcap_errbuf[PCAP_ERRBUF_SIZE]; ++static uint8_t __lladdr[ETHER_ADDRLEN]; ++ ++#ifndef elementsof ++#define elementsof(array) (sizeof(array)/sizeof(array[0])) ++#endif ++ ++static int ++__get_ether_addr(int ifindex, u_char *lladdr) ++{ ++ int mib[6]; ++ char *buf; ++ struct if_msghdr *ifm; ++ char *lim; ++ char *next; ++ struct sockaddr_dl *sdl; ++ size_t len; ++ ++ mib[0] = CTL_NET; ++ mib[1] = PF_ROUTE; ++ mib[2] = 0; ++ mib[3] = 0; ++ mib[4] = NET_RT_IFLIST; ++ mib[5] = ifindex; ++ ++ if (sysctl(mib, elementsof(mib), NULL, &len, NULL, 0) != 0) { ++ daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s", ++ strerror(errno)); ++ return (-1); ++ } ++ ++ buf = malloc(len); ++ if (buf == NULL) { ++ daemon_log(LOG_ERR, "malloc(%d): %s", len, strerror(errno)); ++ return (-1); ++ } ++ ++ if (sysctl(mib, elementsof(mib), buf, &len, NULL, 0) != 0) { ++ daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s", ++ strerror(errno)); ++ free(buf); ++ return (-1); ++ } ++ ++ lim = buf + len; ++ for (next = buf; next < lim; next += ifm->ifm_msglen) { ++ ifm = (struct if_msghdr *)next; ++ if (ifm->ifm_type == RTM_IFINFO) { ++ sdl = (struct sockaddr_dl *)(ifm + 1); ++ memcpy(lladdr, LLADDR(sdl), ETHER_ADDRLEN); ++ } ++ } ++ free(buf); ++ ++ return (0); ++} ++ ++static int ++open_socket(int iface, uint8_t *hw_address) ++{ ++ struct bpf_program bpf; ++ char ifname[IFNAMSIZ]; ++ pcap_t *pp; ++ int err; ++ int fd; ++ ++ assert(__pp == NULL); ++ ++ if (interface_up(iface) < 0) { ++ return (-1); ++ } ++ if (__get_ether_addr(iface, __lladdr) == -1) { ++ return (-1); ++ } ++ if (if_indextoname(iface, ifname) == NULL) { ++ return (-1); ++ } ++ ++ pp = pcap_open_live(ifname, 1500, 0, 0, __pcap_errbuf); ++ if (pp == NULL) { ++ return (-1); ++ } ++ err = pcap_set_datalink(pp, DLT_EN10MB); ++ if (err == -1) { ++ daemon_log(LOG_ERR, "pcap_set_datalink: %s", pcap_geterr(pp)); ++ pcap_close(pp); ++ return (-1); ++ } ++ err = pcap_setdirection(pp, PCAP_D_IN); ++ if (err == -1) { ++ daemon_log(LOG_ERR, "pcap_setdirection: %s", pcap_geterr(pp)); ++ pcap_close(pp); ++ return (-1); ++ } ++ ++ fd = pcap_get_selectable_fd(pp); ++ if (fd == -1) { ++ pcap_close(pp); ++ return (-1); ++ } ++#if 0 ++ /* XXX: can we use this with pcap_next_ex() ? */ ++ err = pcap_setnonblock(pp, 1, __pcap_errbuf); ++ if (err == -1) { ++ pcap_close(pp); ++ return (-1); ++ } ++#endif ++ ++ err = pcap_compile(pp, &bpf, "arp and ether dst ff:ff:ff:ff:ff:ff", ++ 1, 0); ++ if (err == -1) { ++ daemon_log(LOG_ERR, "pcap_compile: %s", pcap_geterr(pp)); ++ pcap_close(pp); ++ return (-1); ++ } ++ err = pcap_setfilter(pp, &bpf); ++ if (err == -1) { ++ daemon_log(LOG_ERR, "pcap_setfilter: %s", pcap_geterr(pp)); ++ pcap_close(pp); ++ return (-1); ++ } ++ pcap_freecode(&bpf); ++ ++ /* Stash pcap-specific context away. */ ++ memcpy(hw_address, __lladdr, ETHER_ADDRLEN); ++ __pp = pp; ++ ++ return (fd); ++} ++ ++static void ++close_socket(int fd __unused) ++{ ++ ++ assert(__pp != NULL); ++ pcap_close(__pp); ++ __pp = NULL; ++} ++ ++/* ++ * We trick avahi into allocating sizeof(packet) + sizeof(ether_header), ++ * and prepend the required ethernet header information before sending. ++ */ ++static int ++send_packet(int fd __unused, int iface __unused, void *packet, ++ size_t packet_len) ++{ ++ struct ether_header *eh; ++ ++ assert(__pp != NULL); ++ assert(packet != NULL); ++ ++ eh = (struct ether_header *)((char *)packet - sizeof(*eh)); ++ memset(eh->ether_dhost, 0xFF, ETHER_ADDRLEN); ++ memcpy(eh->ether_shost, __lladdr, ETHER_ADDRLEN); ++ eh->ether_type = htons(0x0806); ++ ++ return (pcap_inject(__pp, (void *)eh, packet_len + sizeof(*eh))); ++} ++ ++static int ++recv_packet(int fd __unused, void **packet, size_t *packet_len) ++{ ++ struct pcap_pkthdr *ph; ++ u_char *pd; ++ uint8_t *buf; ++ int err; ++ int retval; ++ ++ assert(__pp != NULL); ++ assert(packet != NULL); ++ assert(packet_len != NULL); ++ ++ *packet = NULL; ++ *packet_len = 0; ++ retval = -1; ++ ++ err = pcap_next_ex(__pp, &ph, (const u_char **)&pd); ++ if (err == 1 && ph->caplen <= ph->len) { ++ buf = avahi_new(uint8_t, ph->caplen + ++ sizeof(struct ether_header)); ++ memcpy(buf, pd, ph->caplen); ++ *packet = buf + sizeof(struct ether_header); ++ *packet_len = (ph->caplen - sizeof(struct ether_header)); ++ retval = 0; ++ } else { ++ if (err == 1) { ++ daemon_log(LOG_ERR, "pcap len > caplen"); ++ } else { ++ daemon_log(LOG_ERR, "pcap_next_ex: %s", ++ pcap_geterr(__pp)); ++ } ++ } ++ ++ return (retval); ++} ++#endif /* __linux__ */ ++ + int is_ll_address(uint32_t addr) { + return + (ntohl(addr) & IPV4LL_NETMASK) == IPV4LL_NETWORK && +@@ -507,6 +752,7 @@ + ntohl(addr) != IPV4LL_BROADCAST; + } + ++ + static struct timeval *elapse_time(struct timeval *tv, unsigned msec, unsigned jitter) { + assert(tv); + +@@ -1018,12 +1264,12 @@ + if (send_packet(fd, iface, out_packet, out_packet_len) < 0) + goto fail; + +- avahi_free(out_packet); ++ packet_free(out_packet); + out_packet = NULL; + } + + if (in_packet) { +- avahi_free(in_packet); ++ packet_free(in_packet); + in_packet = NULL; + } + +@@ -1054,7 +1300,7 @@ + if (pollfds[FD_ARP].revents == POLLERR) { + /* The interface is probably down, let's recreate our socket */ + +- close(fd); ++ close_socket(fd); + + if ((fd = open_socket(iface, hw_address)) < 0) + goto fail; +@@ -1120,11 +1366,13 @@ + if (state == STATE_RUNNING || state == STATE_ANNOUNCING) + do_callout(dispatcher, CALLOUT_STOP, iface, addr); + +- avahi_free(out_packet); +- avahi_free(in_packet); ++#if 0 ++ packet_free(out_packet); ++ packet_free(in_packet); ++#endif + + if (fd >= 0) +- close(fd); ++ close_socket(fd); + + if (iface_fd >= 0) + iface_done();