Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 2 Jun 2007 12:35:43 GMT
From:      Fredrik Lindberg <fli@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 120775 for review
Message-ID:  <200706021235.l52CZhK3018909@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=120775

Change 120775 by fli@fli_genesis on 2007/06/02 12:34:55

	- Add a generic timer functions tmr_{start,stop}
	- Add a periodic cache cleaner.
	- Add link up/down and address add/remove events. 
	- Add basic packet parsing to pkgprocess(), including caching.
	- Add wrapper functions to interface locks. 
	- Move socket and read-ready event setup to its own function.
	- Add cache initialization to interface setup.
	- Add if_del() that frees resources allocated to an interface.
	- Add get_linkstatus() returns current link status for an interface.
	- Add if_indextodata() returns ifindex -> struct md_if
	- Debugging and style fixes.

Affected files ...

.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/mdnsd.c#2 edit

Differences ...

==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/mdnsd.c#2 (text+ko) ====

@@ -24,15 +24,23 @@
  *
  */
 
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/route.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <ifaddrs.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <signal.h>
+#include <string.h>
 #include <strings.h>
 #include <unistd.h>
-#include <err.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <ifaddrs.h>
 
 #include "mdnsd.h"
 #include "log.h"
@@ -43,6 +51,9 @@
 int stack_unlock(void *);
 
 static struct md_if * if_new(struct md_glob *, const char *);
+static int if_del(struct md_glob *, struct md_if *);
+static inline int if_aquire(struct md_if *, int);
+static inline void if_release(struct md_if *, int);
 
 int sig(struct event_sig *, ev_arg);
 int sig_init(int, struct event_sig *, ev_arg);
@@ -50,10 +61,101 @@
 int evh_udp_recv(const struct event_io *, const ev_arg);
 int evh_tcp_recv(const struct event_io *, const ev_arg);
 int evh_tcpcli(const struct event_io *, const ev_arg);
+int evh_routesock_init(int, struct event_io *, ev_arg);
+int evh_routesock(struct event_io *, ev_arg);
+
+int tmr_start(struct md_glob *, uint32_t, ev_handler_tmr, void *);
+void tmr_stop(struct md_glob *, int);
+static int evh_cacheclean(const struct event_tmr *, const ev_arg);
 
 static void usage(char *);
 
 /*
+ * Generic timer intialization
+ */
+static int
+tmr_init(int what, struct event_tmr *ev, ev_arg arg)
+{
+
+	switch (what) {
+	case EVENT_INIT_OPEN:
+		ev->evtmr_timeout = arg.int32;
+		break;
+	case EVENT_INIT_CLOSE:
+		break;
+	}
+	return (0);
+}
+
+/*
+ * Start a timer, returns a unique timer identifier
+ */
+int
+tmr_start(struct md_glob *g, uint32_t timeout, ev_handler_tmr handler,
+    void *arg)
+{
+	int id;
+	ev_arg eva, evai;
+
+	evai.int32 = timeout;
+	eva.ptr = arg;
+	id = event_add(g->g_evl, EVENT_TYPE_TMR, handler, &eva,
+		tmr_init, &evai);
+	return (id);
+}
+
+void
+tmr_stop(struct md_glob *g, int timer)
+{
+
+	event_del(g->g_evl, timer, NULL);
+}
+
+/*
+ * Periodic cache cleaner, removes expired cache entries
+ */
+static int
+evh_cacheclean(const struct event_tmr *ev, const ev_arg arg)
+{
+	struct md_if *mif = arg.ptr;
+
+	if (if_aquire(mif, 1) != 0)
+		return (0);
+	cache_clean(&mif->mif_cache);	
+	if_release(mif, 1);
+	return (0);
+}
+
+/*
+ * Link state change.
+ * This routine is called 3 seconds after the real link state change
+ * occured, this is to catch and ignore sporadic link changes.
+ */
+static int
+evh_linkchg(const struct event_tmr *ev, const ev_arg arg)
+{
+	struct md_if *mif = arg.ptr;
+
+	if (if_aquire(mif, 1) != 0)
+		return (0);
+	mif->mif_flags &= ~MIF_LINKCHG;
+	tmr_stop(mif->mif_glob, mif->mif_tmr);
+	if (mif->mif_flags & MIF_LINKUP) {
+		mif->mif_flags &= ~MIF_LINKUP;
+		cache_destroy(&mif->mif_cache);
+		cache_init(&mif->mif_cache);
+		dprintf(DEBUG_MISC, "Link state change to DOWN on %s", mif->mif_ifnam);
+	}
+	else {
+		mif->mif_flags |= MIF_LINKUP;
+		/* TODO: call verify unique records */
+		dprintf(DEBUG_MISC, "Link state change to UP on %s", mif->mif_ifnam);
+	}
+	if_release(mif, 1);
+	return (0);
+}
+
+/*
  * Signal handler to SIG{INT,HUP}
  */
 int
@@ -107,12 +209,15 @@
 pkgprocess(struct md_if *mif, struct mdns_pkgchain *pc, int type,
 	struct sockaddr *from, socklen_t fromlen)
 {
+	struct mdns_packet *pkg;
+	struct mdns_rrset rs;
+	struct mdns_qset qs;
+	struct mdns_head hdr;
+	int i, error;
 #ifdef DEBUG
 	char addr[SOCK_MAXADDRLEN+1];
 	void *sinaddr = NULL;
-#endif
 
-#ifdef DEBUG
 	switch (from->sa_family) {
 	case AF_INET:
 		sinaddr = &((struct sockaddr_in *)from)->sin_addr;
@@ -121,12 +226,49 @@
 	case AF_INET6:
 		sinaddr = &((struct sockaddr_in6 *)from)->sin6_addr;
 		break;
-#endif
+#endif /* INET6 */
 	}
 	inet_ntop(from->sa_family, sinaddr, addr, SOCK_MAXADDRLEN);
-	dprintf(DEBUG_MISC, "Packet from: %s", addr);
-#endif
+	dprintf(DEBUG_RECV, "Packet received peer=%s, if=%s", addr, mif->mif_ifnam);
+#endif /* DEBUG */
+
+	pkg = mdns_pkgchain_curpkg(pc);
+	mdns_pkg_gethdr(pkg, &hdr);
+	dprintf(DEBUG_RECV, "questions=%d, answers=%d, authority=%d",
+	    hdr.h_cquestion, hdr.h_canswer, hdr.h_cauth);
+
+	if (hdr.h_flags & MDNS_HEAD_QUERY) {
+		for (i = 0; i < hdr.h_cquestion; i++) {
+			error = mdns_pkg_getquestion(pkg, i, &qs);
+			if (error != 0)
+				break;
+
+			/* TODO: check db and reply. Do not reply if answer is
+			in answer section with ttl > own ttl/2 */
+		}
+	}
+	else if (hdr.h_flags & MDNS_HEAD_RESP) {
+		for (i = 0; i < hdr.h_canswer; i++) {
+			error = mdns_pkg_getanswer(pkg, i, &rs);
+			if (error != 0)
+				break;
+			/* TODO: check db for conflicts */
+			/* TODO: check for waiting clients */
+			/* TODO: check for pending questions matching this */
+			/* TODO: check for pending answers matching this */
+
+			/*
+			 * Purge records older than 1 second if this is supposed to
+			 * be a uniqe rrset (cache flush bit set)
+			 */
+			if (rs.r_cflush)
+				cache_purge(&mif->mif_cache, 1, rs.r_name, rs.r_type);
 
+			error = cache_add(&mif->mif_cache, &rs, NULL);
+			if (error == 1)
+				free(rs.r_data);
+		}
+	}
 	return (0);
 }
 
@@ -158,7 +300,7 @@
 #endif
 	}
 
-	RW_RLOCK(mif, mif_lock);
+	if_aquire(mif, 0);
 
 	/*
 	 * Initialize a packet chain, receive the packet and hand it to the
@@ -169,7 +311,10 @@
 
 	n = mdns_recv(&mif->mif_handle, &pc, sa.sa_family, saptr, &salen);
 	if (n <= 0) {
-		dprintf(DEBUG_MISC, "Failed to read anything from socket");
+		if (n == 0) {
+			dprintf(DEBUG_RECV, "No data on UDP socket sock=%d, mif=%x",
+			    fd, mif);
+		}
 		error = -1;
 		goto out;
 	}
@@ -179,7 +324,7 @@
 
 out:
 	mdns_pkgchain_free(&mif->mif_handle, &pc);
-	RW_UNLOCK(mif, mif_lock);
+	if_release(mif, 0);
 	return (error);
 }
 
@@ -213,8 +358,9 @@
 
 	error = event_add(g->g_evl, EVENT_TYPE_IO, evh_tcp_recv, &eva,
 		evh_ioread_init, &evai);
-	if (error < 0)
+	if (error < 0) {
 		dprintf(DEBUG_EVENT, "Failed to add event to TCP client sock");
+	}
 
 #ifdef DEBUG
 	switch (sa.sa_family) {
@@ -228,7 +374,7 @@
 #endif
 	}
 	inet_ntop(sa.sa_family, sinaddr, addr, SOCK_MAXADDRLEN);
-	dprintf(DEBUG_MISC, "TCP connection from: %s, sock=%d\n", addr, sock);
+	dprintf(DEBUG_RECV, "TCP connection from: %s, sock=%d\n", addr, sock);
 #endif
 
 	RW_UNLOCK(g, g_lock);
@@ -250,14 +396,18 @@
 	socklen_t salen;
 
 	fd = ev->evio_fd;
-	RW_RLOCK(mif, mif_lock);
+	if (if_aquire(mif, 0) != 0)
+		return (-1);
 
 	mdns_pkgchain_init(&mif->mif_handle, &pc, MDNS_PC_CONT, stack_lock,
 		stack_unlock, mif);
 
 	n = mdns_tcp_recv(&mif->mif_handle, fd, &pc);
 	if (n <= 0) {
-		dprintf(DEBUG_MISC, "Failed to read anything from socket");
+		if (n == 0) {
+			dprintf(DEBUG_RECV, "No data on TCP socket sock=%d, mif=%x",
+			    fd, mif);
+		}
 		error = -1;
 		goto out;
 	}
@@ -270,7 +420,7 @@
 
 out:
 	mdns_pkgchain_free(&mif->mif_handle, &pc);
-	RW_UNLOCK(mif, mif_lock);
+	if_release(mif, 0);
 	return (error);
 }
 
@@ -284,8 +434,8 @@
 	struct md_if *mif;
 
 	mif = (struct md_if *)arg;
-	RW_UNLOCK(mif, mif_lock);	
-	RW_WLOCK(mif, mif_lock);
+	if_release(mif, 0);
+	if_aquire(mif, 1);
 	return (0);	
 }
 
@@ -299,8 +449,8 @@
 	struct md_if *mif;
 
 	mif = (struct md_if *)arg;	
-	RW_UNLOCK(mif, mif_lock);
-	RW_RLOCK(mif, mif_lock);
+	if_release(mif, 1);
+	if_aquire(mif, 0);
 	return (0);	
 }
 
@@ -337,43 +487,68 @@
 	return (0);
 }
 
+static inline int
+if_aquire(struct md_if *mif, int write)
+{
 
+	RW_WLOCK(mif, mif_lock);
+	if (mif->mif_flags & MIF_DYING) {
+		RW_UNLOCK(mif, mif_lock);
+		return (-1);;
+	}
+	mif->mif_refcnt++;
+	if (!write) {
+		RW_UNLOCK(mif, mif_lock);
+		RW_RLOCK(mif, mif_lock);
+	}
+	return (0);
+}
+
+static inline void
+if_release(struct md_if *mif, int write)
+{
+
+	if (!write) {
+		RW_UNLOCK(mif, mif_lock);
+		RW_WLOCK(mif, mif_lock);
+	}
+	
+	mif->mif_refcnt--;
+	if ((mif->mif_flags & MIF_DYING) && mif->mif_refcnt == 0) {
+		MDNS_INIT_UNSET(mif, mif_magic);
+		free(mif);
+	}
+	else {
+		RW_UNLOCK(mif, mif_lock);
+	}
+}
+
+#define ADD2EVLIST(mif, id) { \
+	struct md_if_ev *ifev; \
+	ifev = malloc(sizeof(struct md_if_ev)); \
+	ifev->ifev_id = id; \
+	TAILQ_INSERT_TAIL(&mif->mif_evlist, ifev, ifev_next); \
+}
+
 /*
- * Allocate a new interface
+ * Intialize sockets and hooks up read-ready events
  */
-static struct md_if *
-if_new(struct md_glob *g, const char *ifnam)
+static void
+setup_socks(struct md_if *mif)
 {
-	struct md_if *mif;
+	struct md_glob *g;
 	int i, error, *socks, socklen;
 	ev_arg eva, evai;
 
-	mif = malloc(sizeof(struct md_if));
-	if (mif == NULL)
-		return (NULL);
-	bzero(mif, sizeof(struct md_if));
-	mif->mif_index = if_nametoindex(ifnam);
-	if (mif->mif_index == 0)
-		goto out;
-
-	/* Initialize low-level mdns stack on this interface */
-	error = mdns_init(&mif->mif_handle, g->g_bp, ifnam);
-	if (error != 0)
-		goto out;
-
-	RW_INIT(mif, mif_lock, NULL);	
-	RW_WLOCK(mif, mif_lock);
-	mif->mif_glob = g;
-
+	g = mif->mif_glob;
 	eva.ptr = mif;
-
 	/* Open up UDP and TCP INET sockets */
 	error = mdns_open(&mif->mif_handle, MDNS_UDP, PF_INET);
 	if (error != 0)
-		logger(LOG_ERR,"Failed to setup multicast UDP sockets (INET)");
+		logger(LOG_ERR, "Failed to setup multicast UDP sockets (INET)");
 	error = mdns_open(&mif->mif_handle, MDNS_TCP, PF_INET);
 	if (error != 0)
-		logger(LOG_ERR,"Failed to setup TCP sockets (INET)");
+		logger(LOG_ERR, "Failed to setup TCP sockets (INET)");
 
 	/* Install read-ready event to UDP INET socket */
 	socks = mdns_get_sock(&mif->mif_handle, MDNS_UDP, PF_INET, &socklen);    	
@@ -381,18 +556,27 @@
 		evai.fd = socks[0];
 		error = event_add(g->g_evl, EVENT_TYPE_IO, evh_udp_recv, &eva,
 		    evh_ioread_init, &evai);
-		if (error < 0)
-			dprintf(DEBUG_EVENT, "Failed to add event to UDP INET socks");
+		if (error >= 0) {
+			ADD2EVLIST(mif, error);
+		}
+		else {
+			dprintf(DEBUG_EVENT, "Failed to add read event for UDP (INET)");
+		}
 	}
 
+	/* Install read-ready event to TCP INET socket */
 	socks = mdns_get_sock(&mif->mif_handle, MDNS_TCP, PF_INET, &socklen);    	
 	if (socklen > 0) {
 		for (i = 0; i < socklen; i++) {
 			evai.fd = socks[i];
 			error = event_add(g->g_evl, EVENT_TYPE_IO, evh_tcpcli, &eva,
 			    evh_ioread_init, &evai);
-			if (error < 0)
-				dprintf(DEBUG_EVENT, "Failed to add event to TCP INET sock");
+			if (error >= 0) {
+				ADD2EVLIST(mif, error);
+			}
+			else {
+				dprintf(DEBUG_EVENT, "Failed to add read event to TCP (INET)");
+			}
 		}
 	}
 
@@ -403,7 +587,7 @@
 		logger(LOG_ERR, "Failed to setup multicast UDP sockets (INET6)");
 	error = mdns_open(&mif->mif_handle, MDNS_TCP, PF_INET6);
 	if (error != 0)
-		logger(LOG_ERR,"Failed to setup TCP sockets (INET6)");
+		logger(LOG_ERR, "Failed to setup TCP sockets (INET6)");
 
 	/* Install read-ready event to UDP INET6 socket */
 	socks = mdns_get_sock(&mif->mif_handle, MDNS_UDP, PF_INET6, &socklen);    	
@@ -411,34 +595,269 @@
 		evai.fd = socks[0];
 		error = event_add(g->g_evl, EVENT_TYPE_IO, evh_udp_recv, &eva,
 		    evh_ioread_init, &evai);
-		if (error < 0)
-			dprintf(DEBUG_EVENT, "Failed to add event to UDP INET6 socks");
+		if (error >= 0) {
+			ADD2EVLIST(mif, error);
+		}
+		else {
+			dprintf(DEBUG_EVENT, "Failed to add read event for UDP (INET6)");
+		}
 	}
+
+	/* Install read-ready event to TCP INET6 socket */
 	socks = mdns_get_sock(&mif->mif_handle, MDNS_TCP, PF_INET6, &socklen);    	
 	if (socklen > 0) {
 		for (i = 0; i < socklen; i++) {
 			evai.fd = socks[i];
 			error = event_add(g->g_evl, EVENT_TYPE_IO, evh_tcpcli, &eva,
 			    evh_ioread_init, &evai);
-			if (error < 0)
-				dprintf(DEBUG_EVENT, "Failed to add event to TCP INET6 sock");
+			if (error >= 0) {
+				ADD2EVLIST(mif, error);
+			}
+			else {
+				dprintf(DEBUG_EVENT, "Failed to add read event to TCP (INET6)");
+			}
 		}
 	}
 #endif
+}
+#undef ADD2EVLIST
+
+/*
+ * Get link status for an interface
+ */
+static int
+get_linkstatus(const char *ifnam)
+{
+	struct ifmediareq ifmr;
+	int fd, error;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0)
+		return (LINK_STATE_UNKNOWN);
+
+	memset(&ifmr, 0, sizeof(ifmr));
+	strlcpy(ifmr.ifm_name, ifnam, sizeof(ifmr.ifm_name));
+	error = ioctl(fd, SIOCGIFMEDIA, &ifmr);
+	if (error < 0) {
+		close(fd);
+		return (LINK_STATE_UNKNOWN);
+	}
+	close(fd);
+
+	if (ifmr.ifm_status & IFM_AVALID) {
+		if (ifmr.ifm_status & IFM_ACTIVE)
+			return (LINK_STATE_UP);
+		else
+			return (LINK_STATE_DOWN);
+	}
+	return (LINK_STATE_UNKNOWN);
+}
+
+
+/*
+ * Allocate a new interface
+ */
+static struct md_if *
+if_new(struct md_glob *g, const char *ifnam)
+{
+	struct md_if *mif;
+	int error;
+
+	mif = malloc(sizeof(struct md_if));
+	if (mif == NULL)
+		return (NULL);
+	bzero(mif, sizeof(struct md_if));
+	mif->mif_index = if_nametoindex(ifnam);
+	if (mif->mif_index == 0)
+		goto out;
+	strncpy(mif->mif_ifnam, ifnam, IFNAMSIZ);
 
+	/* Initialize low-level mdns stack on this interface */
+	error = mdns_init(&mif->mif_handle, g->g_bp, ifnam);
+	if (error != 0)
+		goto out;
+
+	RW_INIT(mif, mif_lock, NULL);	
+	RW_WLOCK(mif, mif_lock);
+	mif->mif_glob = g;
+	TAILQ_INIT(&mif->mif_evlist);
+	cache_init(&mif->mif_cache);
+	mif->mif_cache.c_timer = tmr_start(g, 1000, evh_cacheclean, mif);
+	if (get_linkstatus(ifnam) != LINK_STATE_DOWN)
+		mif->mif_flags |= MIF_LINKUP;
+	setup_socks(mif);
+	MDNS_INIT_SET(mif, mif_magic);
+	RW_UNLOCK(mif, mif_lock);
+
 	RW_WLOCK(g, g_lock);
 	TAILQ_INSERT_TAIL(&g->g_ifs, mif, mif_next);
 	RW_UNLOCK(g, g_lock);
-	RW_UNLOCK(mif, mif_lock);
+	logger(LOG_NOTICE, "Added interface %s", mif->mif_ifnam);
 
-	logger(LOG_NOTICE, "Added interface %s", ifnam);
-
 	return (mif);
 out:
 	free(mif);
 	return (NULL);
 }
 
+/*
+ * Remove an interface
+ */
+static int
+if_del(struct md_glob *g, struct md_if *mif)
+{
+	struct md_if_ev *ifev, *ifev2;
+
+	MDNS_INIT_ASSERT(mif, mif_magic);
+
+	if (if_aquire(mif, 1) != 0)
+		return (-1);
+	mif->mif_flags |= MIF_DYING;
+
+	RW_WLOCK(g, g_lock);
+	TAILQ_REMOVE(&g->g_ifs, mif, mif_next);
+	RW_UNLOCK(g, g_lock);
+
+	TAILQ_FOREACH_SAFE(ifev, &mif->mif_evlist, ifev_next, ifev2) {
+		event_del(g->g_evl, ifev->ifev_id, NULL);
+		free(ifev);
+	}
+	tmr_stop(g, mif->mif_cache.c_timer);
+
+	mdns_destroy(&mif->mif_handle);
+	cache_destroy(&mif->mif_cache);
+
+	logger(LOG_NOTICE, "Removed interface %s", mif->mif_ifnam);
+	if_release(mif, 1);
+	return (0);
+}
+
+static struct md_if *
+if_indextodata(struct md_glob *g, int index)
+{
+	struct md_if *mif;
+
+	TAILQ_FOREACH(mif, &g->g_ifs, mif_next) {
+		if (index == mif->mif_index)
+			return (mif);
+	}
+	return (NULL);
+}
+
+/*
+ * Routing socket event handler initialization
+ */
+int
+evh_routesock_init(int what, struct event_io *ev, ev_arg arg)
+{
+	int sock;
+
+	switch (what) {
+	case EVENT_INIT_OPEN:
+		sock = socket(AF_ROUTE, SOCK_RAW, 0);
+		if (sock < 0)
+			return (-1);
+		ev->evio_fd = sock;
+		ev->evio_dir = EVENT_IO_READ;
+		break;
+	case EVENT_INIT_CLOSE:
+		close(ev->evio_fd);
+		break;
+	}
+	return (0);
+}
+
+/*
+ * Routing socket event handler
+ * This will monitor a routing socket and add/remove interfaces as
+ * appropriate.
+ */
+int
+evh_routesock(struct event_io *ev, ev_arg arg)
+{
+#define RS_BUFLEN (sizeof(struct rt_msghdr) + 512)
+	struct md_glob *g = (struct md_glob *)arg.ptr;
+	struct md_if *mif;
+	struct if_msghdr *ifm;
+	int len, sock;
+	char *next, *lim;
+	struct md_if_ev *ifev, *ifev2;
+	char buf[RS_BUFLEN], ifnam[IFNAMSIZ];
+
+	sock = ev->evio_fd;
+
+	len = read(sock, buf, RS_BUFLEN);
+	if (len <= 0)
+		return (0);
+
+	lim = buf + len;
+	for (next = buf; next < lim; next += ifm->ifm_msglen) {
+		ifm = (struct if_msghdr *) next;
+		if (ifm->ifm_flags & IFF_LOOPBACK)
+			continue;
+
+		RW_RLOCK(g, g_lock);
+		mif = if_indextodata(g, ifm->ifm_index);
+		RW_UNLOCK(g, g_lock);
+
+		if (ifm->ifm_type == RTM_IFINFO) {
+			if (ifm->ifm_flags & IFF_UP && mif == NULL) {
+				if (ifm->ifm_flags & IFF_MULTICAST)
+					if (if_indextoname(ifm->ifm_index, ifnam) != NULL)
+						if_new(g, ifnam);
+			}
+			else if (!(ifm->ifm_flags & IFF_UP) && mif != NULL) {
+				if_del(g, mif);
+			}
+			else {
+				if (if_aquire(mif, 1) != 0)
+					continue;
+
+				if (mif->mif_flags & MIF_LINKCHG) {
+					tmr_stop(g, mif->mif_tmr);
+					mif->mif_flags &= ~MIF_LINKCHG;
+					dprintf(DEBUG_MISC,
+					    "Link on %s re-restored, ignoring state change",
+					    mif->mif_ifnam);
+				}
+				else if ((ifm->ifm_data.ifi_link_state == LINK_STATE_UP &&
+				    !(mif->mif_flags & MIF_LINKUP)) ||
+				    (ifm->ifm_data.ifi_link_state == LINK_STATE_DOWN &&
+				    mif->mif_flags & MIF_LINKUP)) {
+					mif->mif_flags |= MIF_LINKCHG;
+					mif->mif_tmr = tmr_start(g, 3000, evh_linkchg, mif);
+				}
+
+				if_release(mif, 1);
+			}
+		}
+		else if (mif == NULL) {
+			continue;
+		}
+
+		/* This is a bit crude */
+		if (ifm->ifm_type == RTM_NEWADDR || ifm->ifm_type == RTM_DELADDR ||
+			ifm->ifm_type == RTM_NEWMADDR) {
+			if_aquire(mif, 1);
+			TAILQ_FOREACH_SAFE(ifev, &mif->mif_evlist, ifev_next, ifev2) {
+				event_del(g->g_evl, ifev->ifev_id, NULL);
+				free(ifev);
+			}
+			mdns_close(&mif->mif_handle, MDNS_UDP, PF_INET);
+			mdns_close(&mif->mif_handle, MDNS_TCP, PF_INET);
+#ifdef INET6
+			mdns_close(&mif->mif_handle, MDNS_UDP, PF_INET6);
+			mdns_close(&mif->mif_handle, MDNS_TCP, PF_INET6);
+#endif
+			setup_socks(mif);
+			if_release(mif, 1);
+		}
+	}
+
+	return (0);
+#undef RS_BUFLEN
+}
+
 static void
 usage(char *exec)
 {
@@ -452,6 +871,7 @@
 	int error, ch, nodaemon = 0;
 	char *ifnam, *cfgfile = NULL;
 	struct ifaddrs *ifap, *ifa;
+	struct md_if *mif, *mif2;
 	struct md_glob glob;
 	ev_arg eva;
 
@@ -512,9 +932,9 @@
 	event_add(glob.g_evl, EVENT_TYPE_SIG, sig, NULL, sig_init, &eva);
 
 	/* Add interfaces that are up */
-    error = getifaddrs(&ifap);
-    if (error != 0)
-        err(EXIT_FAILURE, "getifaddrs");
+	error = getifaddrs(&ifap);
+	if (error != 0)
+		err(EXIT_FAILURE, "getifaddrs");
 	ifnam = NULL;
 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
 		if (ifa->ifa_flags & IFF_LOOPBACK ||
@@ -527,9 +947,17 @@
 	}
 	freeifaddrs(ifap);
 
+	eva.ptr = &glob;
+	event_add(glob.g_evl, EVENT_TYPE_IO, evh_routesock, &eva,
+	    evh_routesock_init, NULL);
+
 	/* Launch the event dispatcher */
 	error = event_dispatch(glob.g_evl, glob.g_wq);
 
+	TAILQ_FOREACH_SAFE(mif, &glob.g_ifs, mif_next, mif2) {
+		if_del(&glob, mif);
+	}
+
 	wq_destroy(glob.g_wq);
 	event_destroy(glob.g_evl);
 	mdns_bufpool_destroy(glob.g_bp);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200706021235.l52CZhK3018909>