Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 19 Sep 2007 21:00:16 +0200
From:      Max Laier <max@love2party.net>
To:        freebsd-pf@freebsd.org
Cc:        Ingo Flaschberger <if@xip.at>, Henrik Brix Andersen <henrik@brixandersen.dk>
Subject:   Re: ifconfig carpdev
Message-ID:  <200709192100.24173.max@love2party.net>
In-Reply-To: <200709151343.37635.max@love2party.net>
References:  <8e10486b0708212053w3769b68dxd33b90b7b906e5e9@mail.gmail.com> <12687223.post@talk.nabble.com> <200709151343.37635.max@love2party.net>

next in thread | previous in thread | raw e-mail | index | archive | help
--nextPart2869418.BCtFpRmQ1Q
Content-Type: multipart/mixed;
  boundary="Boundary-01=_CHX8GSw9Ne9ETUl"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

--Boundary-01=_CHX8GSw9Ne9ETUl
Content-Type: text/plain;
  charset="iso-8859-6"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

On Saturday 15 September 2007, I wrote:
> On Saturday 15 September 2007, Ingo Flaschberger wrote:
> > Ingo Flaschberger wrote:
> > > I have implemented at FreeBSD 6.2-STABLE.
> > >  http://www.nabble.com/file/p12686194/carpdev.diff carpdev.diff
> > > Is a working solution, but not 100% failsave.
> > > See fixme.
> >
> > argl.. need some more tweaks.
> >
> > carp adds only a hostroute, and no network.
> > fixed that it add a network, but now kernels cries to receive the arp
> > at the parent interface and not at the carp interface...
>
> There is a lot more to this.  Please hold your breath just a few more
> days and I'll have a working sollution as promised.  Also, the proposed
> ioctl change is not the preferred way of doing things.  If you pass in
> an interface index, there is no way of making sure that the interface
> didn't change underneath you - that's why we rather pass the whole
> string and do the resolution in the kernel.

So here you go ... this is the ***ALPHA*** version of carpdev support. =20
Note that there are *a lot* of raw edges, untested areas and missing=20
features still, but "it's working"[tm].

=46or the moment that means the IPv4 carpdev case is working. i.e.=20
configuring a carp on an otherwise unused interface:

 ifconfig carp create
 ifconfig carp0 carpdev rl0 vhid 1 pass foo 10.0.0.1
 ifconfig rl0 up

This patch is FYI, not something I'd recommend to use or even test.  I'll=20
do cleanup, testing and polishing over the coming days and let you know=20
when it's in testable shape.

This work is generously sponsored by pil.dk.

=2D-=20
/"\  Best regards,                      | mlaier@freebsd.org
\ /  Max Laier                          | ICQ #67774661
 X   http://pf4freebsd.love2party.net/  | mlaier@EFnet
/ \  ASCII Ribbon Campaign              | Against HTML Mail and News

--Boundary-01=_CHX8GSw9Ne9ETUl
Content-Type: text/x-diff; charset="iso-8859-6"; name="carpdev.ALPHA.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="carpdev.ALPHA.diff"

=2D-- //depot/vendor/freebsd/src/sbin/ifconfig/ifcarp.c	2005/02/22 14:37:13
+++ //depot/user/mlaier/carp2/sbin/ifconfig/ifcarp.c	2007/09/12 16:12:46
@@ -52,13 +52,7 @@
=20
 static const char *carp_states[] =3D { CARP_STATES };
=20
=2Dvoid carp_status(int s);
=2Dvoid setcarp_advbase(const char *,int, int, const struct afswtch *rafp);
=2Dvoid setcarp_advskew(const char *, int, int, const struct afswtch *rafp);
=2Dvoid setcarp_passwd(const char *, int, int, const struct afswtch *rafp);
=2Dvoid setcarp_vhid(const char *, int, int, const struct afswtch *rafp);
=2D
=2Dvoid
+static void
 carp_status(int s)
 {
 	const char *state;
@@ -76,17 +70,17 @@
 		else
 			state =3D carp_states[carpr.carpr_state];
=20
=2D		printf("\tcarp: %s vhid %d advbase %d advskew %d\n",
=2D		    state, carpr.carpr_vhid, carpr.carpr_advbase,
=2D		    carpr.carpr_advskew);
+		printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n",
+		    state, carpr.carpr_carpdev, carpr.carpr_vhid,
+		    carpr.carpr_advbase, carpr.carpr_advskew);
 	}
=20
 	return;
=20
 }
=20
=2Dvoid
=2Dsetcarp_passwd(const char *val, int d, int s, const struct afswtch *afp)
+static
+DECL_CMD_FUNC(setcarp_passwd, val, d)
 {
 	struct carpreq carpr;
=20
@@ -105,8 +99,8 @@
 	return;
 }
=20
=2Dvoid
=2Dsetcarp_vhid(const char *val, int d, int s, const struct afswtch *afp)
+static
+DECL_CMD_FUNC(setcarp_vhid, val, d)
 {
 	int vhid;
 	struct carpreq carpr;
@@ -130,8 +124,8 @@
 	return;
 }
=20
=2Dvoid
=2Dsetcarp_advskew(const char *val, int d, int s, const struct afswtch *afp)
+static
+DECL_CMD_FUNC(setcarp_advskew, val, d)
 {
 	int advskew;
 	struct carpreq carpr;
@@ -152,8 +146,8 @@
 	return;
 }
=20
=2Dvoid
=2Dsetcarp_advbase(const char *val, int d, int s, const struct afswtch *afp)
+static
+DECL_CMD_FUNC(setcarp_advbase, val, d)
 {
 	int advbase;
 	struct carpreq carpr;
@@ -174,11 +168,51 @@
 	return;
 }
=20
+static
+DECL_CMD_FUNC(setcarp_carpdev, val, d)
+{
+	struct carpreq carpr;
+
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data =3D (caddr_t)&carpr;
+
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) =3D=3D -1)
+		err(1, "SIOCGVH");
+
+	strlcpy(carpr.carpr_carpdev, val, sizeof(carpr.carpr_carpdev));
+
+	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) =3D=3D -1)
+		err(1, "SIOCSVH");
+
+	return;
+}
+
+static
+DECL_CMD_FUNC(setcarp_unsetcarpdev, val, d)
+{
+	struct carpreq carpr;
+
+	memset((char *)&carpr, 0, sizeof(struct carpreq));
+	ifr.ifr_data =3D (caddr_t)&carpr;
+
+	if (ioctl(s, SIOCGVH, (caddr_t)&ifr) =3D=3D -1)
+		err(1, "SIOCGVH");
+
+	memset(carpr.carpr_carpdev, 0, sizeof(carpr.carpr_carpdev));
+
+	if (ioctl(s, SIOCSVH, (caddr_t)&ifr) =3D=3D -1)
+		err(1, "SIOCSVH");
+
+	return;
+}
+
 static struct cmd carp_cmds[] =3D {
 	DEF_CMD_ARG("advbase",	setcarp_advbase),
 	DEF_CMD_ARG("advskew",	setcarp_advskew),
 	DEF_CMD_ARG("pass",	setcarp_passwd),
 	DEF_CMD_ARG("vhid",	setcarp_vhid),
+	DEF_CMD_ARG("carpdev",	setcarp_carpdev),
+	DEF_CMD_OPTARG("-carpdev",	setcarp_unsetcarpdev),
 };
 static struct afswtch af_carp =3D {
 	.af_name	=3D "af_carp",
=2D-- //depot/vendor/freebsd/src/sys/net/ethernet.h	2007/05/29 12:43:19
+++ //depot/user/mlaier/carp2/sys/net/ethernet.h	2007/09/19 18:47:18
@@ -380,6 +380,7 @@
 extern	void ether_ifattach(struct ifnet *, const u_int8_t *);
 extern	void ether_ifdetach(struct ifnet *);
 extern	int  ether_ioctl(struct ifnet *, u_long, caddr_t);
+extern	void ether_input(struct ifnet *, struct mbuf *);
 extern	int  ether_output(struct ifnet *,
 		   struct mbuf *, struct sockaddr *, struct rtentry *);
 extern	int  ether_output_frame(struct ifnet *, struct mbuf *);
=2D-- //depot/vendor/freebsd/src/sys/net/if.c	2007/07/27 12:03:05
+++ //depot/user/mlaier/carp2/sys/net/if.c	2007/09/19 18:47:18
@@ -1309,8 +1309,7 @@
 			pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
 	if_qflush(&ifp->if_snd);
 #ifdef DEV_CARP
=2D	if (ifp->if_carp)
=2D		carp_carpdev_state(ifp->if_carp);
+	carp_carpdev_state(ifp);
 #endif
 	rt_ifmsg(ifp);
 }
@@ -1333,8 +1332,7 @@
 		if (fam =3D=3D PF_UNSPEC || (fam =3D=3D ifa->ifa_addr->sa_family))
 			pfctlinput(PRC_IFUP, ifa->ifa_addr);
 #ifdef DEV_CARP
=2D	if (ifp->if_carp)
=2D		carp_carpdev_state(ifp->if_carp);
+	carp_carpdev_state(ifp);
 #endif
 	rt_ifmsg(ifp);
 #ifdef INET6
@@ -1386,8 +1384,7 @@
 	    IFP2AC(ifp)->ac_netgraph !=3D NULL)
 		(*ng_ether_link_state_p)(ifp, link_state);
 #ifdef DEV_CARP
=2D	if (ifp->if_carp)
=2D		carp_carpdev_state(ifp->if_carp);
+	carp_carpdev_state(ifp);
 #endif
 	if (ifp->if_bridge) {
 		KASSERT(bstp_linkstate_p !=3D NULL,("if_bridge bstp not loaded!"));
=2D-- //depot/vendor/freebsd/src/sys/net/if_ethersubr.c	2007/07/27 12:03:05
+++ //depot/user/mlaier/carp2/sys/net/if_ethersubr.c	2007/09/19 18:47:18
@@ -153,6 +153,9 @@
 	u_char esrc[ETHER_ADDR_LEN], edst[ETHER_ADDR_LEN];
 	struct ether_header *eh;
 	struct pf_mtag *t;
+#ifdef DEV_CARP
+	struct ifnet *ifp0 =3D ifp;
+#endif
 	int loop_copy =3D 1;
 	int hlen;	/* link layer header length */
=20
@@ -162,6 +165,19 @@
 		senderr(error);
 #endif
=20
+#ifdef DEV_CARP
+	if (ifp->if_type =3D=3D IFT_CARP) {
+		struct ifaddr *ifa;
+
+		if (dst !=3D NULL && ifp->if_link_state =3D=3D LINK_STATE_UP &&
+		    (ifa =3D ifa_ifwithaddr(dst)) !=3D NULL &&
+		    ifa->ifa_ifp =3D=3D ifp)
+			return (looutput(ifp, m, dst, rt0));
+
+		ifp =3D ifp->if_carpdev;
+	}
+#endif
+
 	if (ifp->if_flags & IFF_MONITOR)
 		senderr(ENETDOWN);
 	if (!((ifp->if_flags & IFF_UP) &&
@@ -172,7 +188,11 @@
 	switch (dst->sa_family) {
 #ifdef INET
 	case AF_INET:
+#ifdef DEV_CARP
+		error =3D arpresolve(ifp0, rt0, m, dst, edst);
+#else
 		error =3D arpresolve(ifp, rt0, m, dst, edst);
+#endif
 		if (error)
 			return (error =3D=3D EWOULDBLOCK ? 0 : error);
 		type =3D htons(ETHERTYPE_IP);
@@ -293,6 +313,14 @@
 		(void)memcpy(eh->ether_shost, IF_LLADDR(ifp),
 			sizeof(eh->ether_shost));
=20
+#ifdef DEV_CARP
+	if (ifp0 !=3D ifp && ifp0->if_type =3D=3D IFT_CARP) {
+		/* XXX: LINK1 */
+		(void)memcpy(eh->ether_shost, IF_LLADDR(ifp0),
+		    sizeof(eh->ether_shost));
+	}
+#endif
+
 	/*
 	 * If a simplex interface, and the packet is being sent to our
 	 * Ethernet address or a broadcast address, loopback a copy.
@@ -351,12 +379,6 @@
 		return (error);
 	}
=20
=2D#ifdef DEV_CARP
=2D	if (ifp->if_carp &&
=2D	    (error =3D carp_output(ifp, m, dst, NULL)))
=2D		goto bad;
=2D#endif
=2D
 	/* Handle ng_ether(4) processing, if any */
 	if (IFP2AC(ifp)->ac_netgraph !=3D NULL) {
 		KASSERT(ng_ether_output_p !=3D NULL,
@@ -506,7 +528,7 @@
  * Process a received Ethernet packet; the packet is in the
  * mbuf chain m with the ethernet header at the front.
  */
=2Dstatic void
+void
 ether_input(struct ifnet *ifp, struct mbuf *m)
 {
 	struct ether_header *eh;
@@ -672,19 +694,15 @@
 	}
=20
 #ifdef DEV_CARP
=2D	/*
=2D	 * Clear M_PROMISC on frame so that carp(4) will see it when the
=2D	 * mbuf flows up to Layer 3.
=2D	 * FreeBSD's implementation of carp(4) uses the inprotosw
=2D	 * to dispatch IPPROTO_CARP. carp(4) also allocates its own
=2D	 * Ethernet addresses of the form 00:00:5e:00:01:xx, which
=2D	 * is outside the scope of the M_PROMISC test below.
=2D	 * TODO: Maintain a hash table of ethernet addresses other than
=2D	 * ether_dhost which may be active on this ifp.
=2D	 */
=2D	if (ifp->if_carp && carp_forus(ifp->if_carp, eh->ether_dhost)) {
=2D		m->m_flags &=3D ~M_PROMISC;
=2D	} else
+	if (ifp->if_carp) {
+		if (ifp->if_type !=3D IFT_CARP && (carp_input(m) =3D=3D 0))
+			return;
+		else if (ifp->if_type =3D=3D IFT_CARP &&
+		    /* XXX: LINK2 */
+		    m->m_flags & (M_BCAST | M_MCAST) &&
+		    !bcmp(IFP2AC(ifp), eh->ether_dhost, ETHER_ADDR_LEN))
+			m->m_flags &=3D ~(M_BCAST | M_MCAST);
+	}
 #endif
 	{
 		/*
=2D-- //depot/vendor/freebsd/src/sys/net/if_loop.c	2007/02/09 00:13:58
+++ //depot/user/mlaier/carp2/sys/net/if_loop.c	2007/09/19 18:47:18
@@ -99,8 +99,6 @@
=20
 int		loioctl(struct ifnet *, u_long, caddr_t);
 static void	lortrequest(int, struct rtentry *, struct rt_addrinfo *);
=2Dint		looutput(struct ifnet *ifp, struct mbuf *m,
=2D		    struct sockaddr *dst, struct rtentry *rt);
 static int	lo_clone_create(struct if_clone *, int, caddr_t);
 static void	lo_clone_destroy(struct ifnet *);
=20
=2D-- //depot/vendor/freebsd/src/sys/net/if_var.h	2007/05/16 18:42:49
+++ //depot/user/mlaier/carp2/sys/net/if_var.h	2007/09/19 18:47:18
@@ -131,7 +131,12 @@
 		 */
 	struct	knlist if_klist;	/* events attached to this if */
 	int	if_pcount;		/* number of promiscuous listeners */
=2D	struct	carp_if *if_carp;	/* carp interface structure */
+	union {
+		struct carp_if *carp_s;
+		struct ifnet *carp_d;
+	} if_carp_ptr;
+#define	if_carp		if_carp_ptr.carp_s
+#define	if_carpdev	if_carp_ptr.carp_d
 	struct	bpf_if *if_bpf;		/* packet filter structure */
 	u_short	if_index;		/* numeric abbreviation for this if  */
 	short	if_timer;		/* time 'til if_watchdog called */
@@ -691,6 +696,8 @@
 struct	ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *);
=20
 int	if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen);
+int	looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+	    struct rtentry *rt);
=20
 typedef	void *if_com_alloc_t(u_char type, struct ifnet *ifp);
 typedef	void if_com_free_t(void *com, u_char type);
=2D-- //depot/vendor/freebsd/src/sys/netinet/if_ether.c	2007/05/10 16:01:35
+++ //depot/user/mlaier/carp2/sys/netinet/if_ether.c	2007/09/19 18:47:18
@@ -108,7 +108,6 @@
 	   &arp_proxyall, 0, "Enable proxy ARP for all suitable requests");
=20
 static void	arp_init(void);
=2Dstatic void	arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
 static void	arprequest(struct ifnet *,
 			struct in_addr *, struct in_addr *, u_char *);
 static void	arpintr(struct mbuf *);
@@ -142,7 +141,7 @@
 /*
  * Parallel to llc_rtrequest.
  */
=2Dstatic void
+void
 arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
 {
 	struct sockaddr *gate;
=2D-- //depot/vendor/freebsd/src/sys/netinet/if_ether.h	2005/02/22 13:06:15
+++ //depot/user/mlaier/carp2/sys/netinet/if_ether.h	2007/09/19 18:47:18
@@ -113,6 +113,7 @@
 		struct mbuf *m, struct sockaddr *dst, u_char *desten);
 void	arp_ifinit(struct ifnet *, struct ifaddr *);
 void	arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *);
+void	arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
 #endif
=20
 #endif
=2D-- //depot/vendor/freebsd/src/sys/netinet/in_proto.c	2007/07/03 12:18:07
+++ //depot/user/mlaier/carp2/sys/netinet/in_proto.c	2007/09/19 18:47:18
@@ -316,7 +316,7 @@
 	.pr_domain =3D		&inetdomain,
 	.pr_protocol =3D		IPPROTO_CARP,
 	.pr_flags =3D		PR_ATOMIC|PR_ADDR,
=2D	.pr_input =3D		carp_input,
+	.pr_input =3D		carp_proto_input,
 	.pr_output =3D		(pr_output_t*)rip_output,
 	.pr_ctloutput =3D		rip_ctloutput,
 	.pr_usrreqs =3D		&rip_usrreqs
=2D-- //depot/vendor/freebsd/src/sys/netinet/ip_carp.c	2007/07/28 07:32:18
+++ //depot/user/mlaier/carp2/sys/netinet/ip_carp.c	2007/09/19 18:47:18
@@ -91,11 +91,9 @@
=20
 struct carp_softc {
 	struct ifnet	 	*sc_ifp;	/* Interface clue */
=2D	struct ifnet		*sc_carpdev;	/* Pointer to parent interface */
=2D	struct in_ifaddr 	*sc_ia;		/* primary iface address */
+#define	sc_carpdev sc_ifp->if_carpdev
 	struct ip_moptions 	 sc_imo;
 #ifdef INET6
=2D	struct in6_ifaddr 	*sc_ia6;	/* primary iface address v6 */
 	struct ip6_moptions 	 sc_im6o;
 #endif /* INET6 */
 	TAILQ_ENTRY(carp_softc)	 sc_list;
@@ -158,7 +156,7 @@
 	struct mtx	 vhif_mtx;
 };
=20
=2D/* Get carp_if from softc. Valid after carp_set_addr{,6}. */
+/* Get carp_if from softc. Valid after carp_set_{addr[6],ifp}. */
 #define	SC2CIF(sc)		((struct carp_if *)(sc)->sc_carpdev->if_carp)
=20
 /* lock per carp_if queue */
@@ -189,7 +187,7 @@
 static int	carp_hmac_verify(struct carp_softc *, u_int32_t *,
 		    unsigned char *);
 static void	carp_setroute(struct carp_softc *, int);
=2Dstatic void	carp_input_c(struct mbuf *, struct carp_header *, sa_family_=
t);
+static void	carp_proto_input_c(struct mbuf *, struct carp_header *, sa_fam=
ily_t);
 static int 	carp_clone_create(struct if_clone *, int, caddr_t);
 static void 	carp_clone_destroy(struct ifnet *);
 static void	carpdetach(struct carp_softc *, int);
@@ -202,7 +200,7 @@
 static void	carp_master_down(void *);
 static void	carp_master_down_locked(struct carp_softc *);
 static int	carp_ioctl(struct ifnet *, u_long, caddr_t);
=2Dstatic int	carp_looutput(struct ifnet *, struct mbuf *, struct sockaddr =
*,
+static int	carp_output(struct ifnet *, struct mbuf *, struct sockaddr *,
 		    struct rtentry *);
 static void	carp_start(struct ifnet *);
 static void	carp_setrun(struct carp_softc *, sa_family_t);
@@ -211,13 +209,16 @@
 enum	{ CARP_COUNT_MASTER, CARP_COUNT_RUNNING };
=20
 static void	carp_multicast_cleanup(struct carp_softc *);
+static int	carp_set_ifp(struct carp_softc *, struct ifnet *);
 static int	carp_set_addr(struct carp_softc *, struct sockaddr_in *);
+static int	carp_join_multicast(struct carp_softc *);
 static int	carp_del_addr(struct carp_softc *, struct sockaddr_in *);
 static void	carp_carpdev_state_locked(struct carp_if *);
 static void	carp_sc_state_locked(struct carp_softc *);
 #ifdef INET6
 static void	carp_send_na(struct carp_softc *);
 static int	carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *);
+static int	carp_join_multicast6(struct carp_softc *);
 static int	carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *);
 static void	carp_multicast6_cleanup(struct carp_softc *);
 #endif
@@ -246,9 +247,9 @@
 #endif
=20
 	if (sc->sc_carpdev)
=2D		CARP_SCLOCK(sc);
+		CARP_SCLOCK_ASSERT(sc);
=20
=2D	/* XXX: possible race here */
+	/* XXX: possible race here - really? */
=20
 	/* compute ipad from key */
 	bzero(sc->sc_pad, sizeof(sc->sc_pad));
@@ -284,8 +285,6 @@
 	for (i =3D 0; i < sizeof(sc->sc_pad); i++)
 		sc->sc_pad[i] ^=3D 0x36 ^ 0x5c;
=20
=2D	if (sc->sc_carpdev)
=2D		CARP_SCUNLOCK(sc);
 }
=20
 static void
@@ -333,13 +332,106 @@
 	TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) {
 		if (ifa->ifa_addr->sa_family =3D=3D AF_INET &&
 		    sc->sc_carpdev !=3D NULL) {
=2D			int count =3D carp_addrcount(
=2D			    (struct carp_if *)sc->sc_carpdev->if_carp,
=2D			    ifatoia(ifa), CARP_COUNT_MASTER);
+			int count =3D 0, error;
+			struct sockaddr sa;
+			struct rtentry *rt;
+			struct radix_node_head *rnh;
+			struct radix_node *rn;
+			struct rt_addrinfo info;
+			int hr_otherif, nr_ourif;
+
+			/*
+			 * Avoid screwing with the routes if there are other
+			 * carp interfaces which are master and have the same
+			 * address.
+			 */
+			if (sc->sc_carpdev !=3D NULL &&
+			    sc->sc_carpdev->if_carp !=3D NULL) {
+				count =3D carp_addrcount(
+				    (struct carp_if *)sc->sc_carpdev->if_carp,
+				    ifatoia(ifa), CARP_COUNT_MASTER);
+				if ((cmd =3D=3D RTM_ADD && count !=3D 1) ||
+				    (cmd =3D=3D RTM_DELETE && count !=3D 0))
+					continue;
+			}
+
+			/* Remove the existing host route, if any */
+			bzero(&info, sizeof(info));
+			info.rti_info[RTAX_DST] =3D ifa->ifa_addr;
+			info.rti_flags =3D RTF_HOST;
+			error =3D rtrequest1(RTM_DELETE, &info, NULL);
+			rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
+
+			/* Check for our address on another interface */
+			/* XXX cries for proper API */
+			rnh =3D rt_tables[ifa->ifa_addr->sa_family];
+			RADIX_NODE_HEAD_LOCK(rnh);
+			rn =3D rnh->rnh_matchaddr(ifa->ifa_addr, rnh);
+			rt =3D (struct rtentry *)rn;
+			hr_otherif =3D (rt && rt->rt_ifp !=3D sc->sc_ifp &&
+			    rt->rt_flags & (RTF_CLONING|RTF_WASCLONED));
+
+			/* Check for a network route on our interface */
+			bcopy(ifa->ifa_addr, &sa, sizeof(sa));
+			satosin(&sa)->sin_addr.s_addr =3D satosin(ifa->ifa_netmask
+			    )->sin_addr.s_addr & satosin(&sa)->sin_addr.s_addr;
+			rn =3D rnh->rnh_lookup(&sa, ifa->ifa_netmask, rnh);
+			rt =3D (struct rtentry *)rn;
+			nr_ourif =3D (rt && rt->rt_ifp =3D=3D sc->sc_ifp);
+			RADIX_NODE_HEAD_UNLOCK(rnh);
+
+			switch (cmd) {
+			case RTM_ADD:
+				if (hr_otherif) {
+					ifa->ifa_rtrequest =3D NULL;
+					ifa->ifa_flags &=3D ~RTF_CLONING;
+					bzero(&info, sizeof(info));
+					info.rti_info[RTAX_DST] =3D
+					    ifa->ifa_addr;
+					info.rti_info[RTAX_GATEWAY] =3D
+					    ifa->ifa_addr;
+					info.rti_flags =3D RTF_UP | RTF_HOST;
+					error =3D rtrequest1(RTM_ADD, &info,
+					    NULL);
+					rt_missmsg(RTM_ADD, &info,
+					    info.rti_flags, error);
+				}
+				if (!hr_otherif || nr_ourif || !rt) {
+					if (nr_ourif && !(rt->rt_flags &
+					    RTF_CLONING)) {
+						bzero(&info, sizeof(info));
+						info.rti_info[RTAX_DST] =3D &sa;
+						info.rti_info[RTAX_NETMASK] =3D
+						    ifa->ifa_netmask;
+						error =3D rtrequest1(RTM_DELETE,
+						    &info, NULL);
+						rt_missmsg(RTM_DELETE, &info,
+						    info.rti_flags, error);
+					}
+
+					ifa->ifa_rtrequest =3D arp_rtrequest;
+					ifa->ifa_flags |=3D RTF_CLONING;
=20
=2D			if ((cmd =3D=3D RTM_ADD && count =3D=3D 1) ||
=2D			    (cmd =3D=3D RTM_DELETE && count =3D=3D 0))
=2D				rtinit(ifa, cmd, RTF_UP | RTF_HOST);
+					bzero(&info, sizeof(info));
+					info.rti_info[RTAX_DST] =3D &sa;
+					info.rti_info[RTAX_GATEWAY] =3D
+					    ifa->ifa_addr;
+					info.rti_info[RTAX_NETMASK] =3D
+					    ifa->ifa_netmask;
+					error =3D rtrequest1(RTM_ADD, &info,
+					    NULL);
+					if (error =3D=3D 0)
+						ifa->ifa_flags |=3D IFA_ROUTE;
+					rt_missmsg(RTM_ADD, &info,
+					    info.rti_flags, error);
+				}
+				break;
+			case RTM_DELETE:
+				break;
+			default:
+				break;
+			}
+			break;
 		}
 #ifdef INET6
 		if (ifa->ifa_addr->sa_family =3D=3D AF_INET6) {
@@ -359,6 +451,7 @@
=20
 	struct carp_softc *sc;
 	struct ifnet *ifp;
+	static const u_char eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */
=20
 	MALLOC(sc, struct carp_softc *, sizeof(*sc), M_CARP, M_WAITOK|M_ZERO);
 	ifp =3D SC2IFP(sc) =3D if_alloc(IFT_ETHER);
@@ -390,16 +483,13 @@
 =09
 	ifp->if_softc =3D sc;
 	if_initname(ifp, CARP_IFNAME, unit);
=2D	ifp->if_mtu =3D ETHERMTU;
=2D	ifp->if_flags =3D IFF_LOOPBACK;
+	ether_ifattach(ifp, eaddr);
+	ifp->if_flags =3D IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl =3D carp_ioctl;
=2D	ifp->if_output =3D carp_looutput;
+	ifp->if_output =3D carp_output;
 	ifp->if_start =3D carp_start;
 	ifp->if_type =3D IFT_CARP;
 	ifp->if_snd.ifq_maxlen =3D ifqmaxlen;
=2D	ifp->if_hdrlen =3D 0;
=2D	if_attach(ifp);
=2D	bpfattach(SC2IFP(sc), DLT_NULL, sizeof(u_int32_t));
 	mtx_lock(&carp_mtx);
 	LIST_INSERT_HEAD(&carpif_list, sc, sc_next);
 	mtx_unlock(&carp_mtx);
@@ -502,7 +592,7 @@
  * but it seems more efficient this way or not possible otherwise.
  */
 void
=2Dcarp_input(struct mbuf *m, int hlen)
+carp_proto_input(struct mbuf *m, int hlen)
 {
 	struct ip *ip =3D mtod(m, struct ip *);
 	struct carp_header *ch;
@@ -518,7 +608,7 @@
 	/* check if received on a valid carp interface */
 	if (m->m_pkthdr.rcvif->if_carp =3D=3D NULL) {
 		carpstats.carps_badif++;
=2D		CARP_LOG("carp_input: packet received on non-carp "
+		CARP_LOG("carp_proto_input: packet received on non-carp "
 		    "interface: %s\n",
 		    m->m_pkthdr.rcvif->if_xname);
 		m_freem(m);
@@ -528,7 +618,7 @@
 	/* verify that the IP TTL is 255.  */
 	if (ip->ip_ttl !=3D CARP_DFLTTL) {
 		carpstats.carps_badttl++;
=2D		CARP_LOG("carp_input: received ttl %d !=3D 255i on %s\n",
+		CARP_LOG("carp_proto_input: received ttl %d !=3D 255i on %s\n",
 		    ip->ip_ttl,
 		    m->m_pkthdr.rcvif->if_xname);
 		m_freem(m);
@@ -539,7 +629,7 @@
=20
 	if (m->m_pkthdr.len < iplen + sizeof(*ch)) {
 		carpstats.carps_badlen++;
=2D		CARP_LOG("carp_input: received len %zd < "
+		CARP_LOG("carp_proto_input: received len %zd < "
 		    "sizeof(struct carp_header)\n",
 		    m->m_len - sizeof(struct ip));
 		m_freem(m);
@@ -549,7 +639,7 @@
 	if (iplen + sizeof(*ch) < m->m_len) {
 		if ((m =3D m_pullup(m, iplen + sizeof(*ch))) =3D=3D NULL) {
 			carpstats.carps_hdrops++;
=2D			CARP_LOG("carp_input: pullup failed\n");
+			CARP_LOG("carp_proto_input: pullup failed\n");
 			return;
 		}
 		ip =3D mtod(m, struct ip *);
@@ -563,7 +653,7 @@
 	len =3D iplen + sizeof(*ch);
 	if (len > m->m_pkthdr.len) {
 		carpstats.carps_badlen++;
=2D		CARP_LOG("carp_input: packet too short %d on %s\n",
+		CARP_LOG("carp_proto_input: packet too short %d on %s\n",
 		    m->m_pkthdr.len,
 		    m->m_pkthdr.rcvif->if_xname);
 		m_freem(m);
@@ -581,19 +671,19 @@
 	m->m_data +=3D iplen;
 	if (carp_cksum(m, len - iplen)) {
 		carpstats.carps_badsum++;
=2D		CARP_LOG("carp_input: checksum failed on %s\n",
+		CARP_LOG("carp_proto_input: checksum failed on %s\n",
 		    m->m_pkthdr.rcvif->if_xname);
 		m_freem(m);
 		return;
 	}
 	m->m_data -=3D iplen;
=20
=2D	carp_input_c(m, ch, AF_INET);
+	carp_proto_input_c(m, ch, AF_INET);
 }
=20
 #ifdef INET6
 int
=2Dcarp6_input(struct mbuf **mp, int *offp, int proto)
+carp6_proto_input(struct mbuf **mp, int *offp, int proto)
 {
 	struct mbuf *m =3D *mp;
 	struct ip6_hdr *ip6 =3D mtod(m, struct ip6_hdr *);
@@ -610,7 +700,7 @@
 	/* check if received on a valid carp interface */
 	if (m->m_pkthdr.rcvif->if_carp =3D=3D NULL) {
 		carpstats.carps_badif++;
=2D		CARP_LOG("carp6_input: packet received on non-carp "
+		CARP_LOG("carp6_proto_input: packet received on non-carp "
 		    "interface: %s\n",
 		    m->m_pkthdr.rcvif->if_xname);
 		m_freem(m);
@@ -620,7 +710,7 @@
 	/* verify that the IP TTL is 255 */
 	if (ip6->ip6_hlim !=3D CARP_DFLTTL) {
 		carpstats.carps_badttl++;
=2D		CARP_LOG("carp6_input: received ttl %d !=3D 255 on %s\n",
+		CARP_LOG("carp6_proto_input: received ttl %d !=3D 255 on %s\n",
 		    ip6->ip6_hlim,
 		    m->m_pkthdr.rcvif->if_xname);
 		m_freem(m);
@@ -632,7 +722,7 @@
 	IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
 	if (ch =3D=3D NULL) {
 		carpstats.carps_badlen++;
=2D		CARP_LOG("carp6_input: packet size %u too small\n", len);
+		CARP_LOG("carp6_proto_input: packet size %u too small\n", len);
 		return (IPPROTO_DONE);
 	}
=20
@@ -641,20 +731,20 @@
 	m->m_data +=3D *offp;
 	if (carp_cksum(m, sizeof(*ch))) {
 		carpstats.carps_badsum++;
=2D		CARP_LOG("carp6_input: checksum failed, on %s\n",
+		CARP_LOG("carp6_proto_input: checksum failed, on %s\n",
 		    m->m_pkthdr.rcvif->if_xname);
 		m_freem(m);
 		return (IPPROTO_DONE);
 	}
 	m->m_data -=3D *offp;
=20
=2D	carp_input_c(m, ch, AF_INET6);
+	carp_proto_input_c(m, ch, AF_INET6);
 	return (IPPROTO_DONE);
 }
 #endif /* INET6 */
=20
 static void
=2Dcarp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
+carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
 {
 	struct ifnet *ifp =3D m->m_pkthdr.rcvif;
 	struct carp_softc *sc;
@@ -792,9 +882,6 @@
 static int
 carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header =
*ch)
 {
=2D	struct m_tag *mtag;
=2D	struct ifnet *ifp =3D SC2IFP(sc);
=2D
 	if (sc->sc_init_counter) {
 		/* this could also be seconds since unix epoch */
 		sc->sc_counter =3D arc4random();
@@ -808,16 +895,6 @@
=20
 	carp_hmac_generate(sc, ch->carp_counter, ch->carp_md);
=20
=2D	/* Tag packet for carp_output */
=2D	mtag =3D m_tag_get(PACKET_TAG_CARP, sizeof(struct ifnet *), M_NOWAIT);
=2D	if (mtag =3D=3D NULL) {
=2D		m_freem(m);
=2D		SC2IFP(sc)->if_oerrors++;
=2D		return (ENOMEM);
=2D	}
=2D	bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *));
=2D	m_tag_prepend(m, mtag);
=2D
 	return (0);
 }
=20
@@ -858,6 +935,8 @@
 	struct carp_header *ch_ptr;
 	struct mbuf *m;
 	int len, advbase, advskew;
+	struct ifaddr *ifa;
+	struct sockaddr sa;
=20
 	CARP_SCLOCK_ASSERT(sc);
=20
@@ -886,7 +965,7 @@
 	ch.carp_cksum =3D 0;
=20
 #ifdef INET
=2D	if (sc->sc_ia) {
+	if (sc->sc_naddrs) {
 		struct ip *ip;
=20
 		MGETHDR(m, M_DONTWAIT, MT_HEADER);
@@ -915,7 +994,15 @@
 		ip->ip_ttl =3D CARP_DFLTTL;
 		ip->ip_p =3D IPPROTO_CARP;
 		ip->ip_sum =3D 0;
=2D		ip->ip_src.s_addr =3D sc->sc_ia->ia_addr.sin_addr.s_addr;
+
+		bzero(&sa, sizeof(sa));
+		sa.sa_family =3D AF_INET;
+		ifa =3D ifaof_ifpforaddr(&sa, SC2IFP(sc));
+		if (ifa =3D=3D NULL)
+			ip->ip_src.s_addr =3D 0;
+		else
+			ip->ip_src.s_addr =3D
+			    ifatoia(ifa)->ia_addr.sin_addr.s_addr;
 		ip->ip_dst.s_addr =3D htonl(INADDR_CARP_GROUP);
=20
 		ch_ptr =3D (struct carp_header *)(&ip[1]);
@@ -958,7 +1045,7 @@
 	}
 #endif /* INET */
 #ifdef INET6
=2D	if (sc->sc_ia6) {
+	if (sc->sc_naddrs6) {
 		struct ip6_hdr *ip6;
=20
 		MGETHDR(m, M_DONTWAIT, MT_HEADER);
@@ -982,8 +1069,15 @@
 		ip6->ip6_vfc |=3D IPV6_VERSION;
 		ip6->ip6_hlim =3D CARP_DFLTTL;
 		ip6->ip6_nxt =3D IPPROTO_CARP;
=2D		bcopy(&sc->sc_ia6->ia_addr.sin6_addr, &ip6->ip6_src,
=2D		    sizeof(struct in6_addr));
+
+		bzero(&sa, sizeof(sa));
+		sa.sa_family =3D AF_INET6;
+		ifa =3D ifaof_ifpforaddr(&sa, SC2IFP(sc));
+		if (ifa =3D=3D NULL)
+			bzero(&ip6->ip6_src, sizeof(struct in6_addr));
+		else
+			bcopy(ifatoia6(ifa)->ia_addr.sin6_addr.s6_addr,
+			    &ip6->ip6_src, sizeof(struct in6_addr));
 		/* set the multicast destination */
=20
 		ip6->ip6_dst.s6_addr16[0] =3D htons(0xff02);
@@ -1057,7 +1151,7 @@
 			continue;
=20
 /*		arprequest(sc->sc_carpdev, &in, &in, IF_LLADDR(sc->sc_ifp)); */
=2D		arp_ifinit2(sc->sc_carpdev, ifa, IF_LLADDR(sc->sc_ifp));
+		arp_ifinit2(SC2IFP(sc), ifa, IF_LLADDR(sc->sc_ifp));
=20
 		DELAY(1000);	/* XXX */
 	}
@@ -1210,7 +1304,6 @@
 void *
 carp_macmatch6(void *v, struct mbuf *m, const struct in6_addr *taddr)
 {
=2D	struct m_tag *mtag;
 	struct carp_if *cif =3D v;
 	struct carp_softc *sc;
 	struct ifaddr *ifa;
@@ -1222,18 +1315,6 @@
 			    &ifatoia6(ifa)->ia_addr.sin6_addr) &&
  			    (SC2IFP(sc)->if_flags & IFF_UP) &&
 			    (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING)) {
=2D				struct ifnet *ifp =3D SC2IFP(sc);
=2D				mtag =3D m_tag_get(PACKET_TAG_CARP,
=2D				    sizeof(struct ifnet *), M_NOWAIT);
=2D				if (mtag =3D=3D NULL) {
=2D					/* better a bit than nothing */
=2D					CARP_UNLOCK(cif);
=2D					return (IF_LLADDR(sc->sc_ifp));
=2D				}
=2D				bcopy(&ifp, (caddr_t)(mtag + 1),
=2D				    sizeof(struct ifnet *));
=2D				m_tag_prepend(m, mtag);
=2D
 				CARP_UNLOCK(cif);
 				return (IF_LLADDR(sc->sc_ifp));
 			}
@@ -1422,15 +1503,116 @@
 #endif
=20
 static int
+carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp)
+{
+	struct carp_if *cif =3D NULL, *ncif =3D NULL;
+	struct carp_softc *vr, *after =3D NULL;
+	int myself =3D 0, error =3D 0;
+
+	if (ifp =3D=3D sc->sc_carpdev)
+		return (0);
+
+	if (ifp !=3D NULL) {
+		if ((ifp->if_flags & IFF_MULTICAST) =3D=3D 0)
+			return (ENODEV);
+		if (ifp->if_type =3D=3D IFT_CARP)
+			return (EINVAL);
+
+		if (ifp->if_carp =3D=3D NULL) {
+			MALLOC(ncif, struct carp_if *, sizeof(*ncif), M_CARP,
+			    M_WAITOK|M_ZERO);
+			if (!ncif)
+				return (ENOBUFS);
+			if ((error =3D ifpromisc(ifp, 1))) {
+				FREE(ncif, M_CARP);
+				return (error);
+			}
+		} else {
+			cif =3D (struct carp_if *)ifp->if_carp;
+			CARP_LOCK(cif);
+			TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
+				if (vr !=3D sc && vr->sc_vhid =3D=3D sc->sc_vhid) {
+					CARP_UNLOCK(cif);
+					return (EINVAL);
+				}
+		}
+
+		/* detach from old interface */
+		if (sc->sc_carpdev !=3D NULL) {
+			CARP_SCLOCK(sc);
+			carpdetach(sc, 1);
+		}
+
+		if (sc->sc_naddrs !=3D 0 &&
+		    (error =3D carp_join_multicast(sc)) !=3D 0)
+		    	goto cleanup;
+#ifdef INET6
+		if (sc->sc_naddrs6 !=3D 0 &&
+		    (error =3D carp_join_multicast6(sc)) !=3D 0) {
+		    	carp_multicast_cleanup(sc);
+		    	goto cleanup;
+		}
+#endif
+
+		/* attach carp glue to physical interface */
+		if (ncif !=3D NULL) {
+			CARP_LOCK_INIT(ncif);
+			CARP_LOCK(ncif);
+			ncif->vhif_ifp =3D ifp;
+			TAILQ_INIT(&ncif->vhif_vrs);
+			TAILQ_INSERT_HEAD(&ncif->vhif_vrs, sc, sc_list);
+			ncif->vhif_nvrs++;
+			ifp->if_carp =3D ncif;
+			CARP_UNLOCK(ncif);
+		} else {
+			cif =3D (struct carp_if *)ifp->if_carp;
+			TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
+				if (vr =3D=3D sc)
+					myself =3D 1;
+				if (vr->sc_vhid < sc->sc_vhid)
+					after =3D vr;
+			}
+			if (!myself) {
+				if (after =3D=3D NULL) {
+					TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc,
+					    sc_list);
+				} else {
+					TAILQ_INSERT_AFTER(&cif->vhif_vrs,
+					    after, sc, sc_list);
+				}
+				cif->vhif_nvrs++;
+			}
+			CARP_UNLOCK(cif);
+		}
+
+		sc->sc_carpdev =3D ifp;
+		if (sc->sc_naddrs || sc->sc_naddrs6)
+			sc->sc_ifp->if_flags |=3D IFF_UP;
+		carp_carpdev_state(ifp);
+	} else {
+		CARP_SCLOCK(sc);
+		carpdetach(sc, 1);
+		SC2IFP(sc)->if_flags &=3D ~IFF_UP;
+		SC2IFP(sc)->if_drv_flags &=3D ~IFF_DRV_RUNNING;
+	}
+
+	return (0);
+cleanup:
+	if (ncif)
+		FREE(ncif, M_CARP);
+	else
+		CARP_UNLOCK(cif);
+
+	return (error);
+}
+
+static int
 carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
 {
=2D	struct ifnet *ifp;
=2D	struct carp_if *cif;
+	struct ifnet *ifp =3D sc->sc_carpdev;
 	struct in_ifaddr *ia, *ia_if;
=2D	struct ip_moptions *imo =3D &sc->sc_imo;
=2D	struct in_addr addr;
 	u_long iaddr =3D htonl(sin->sin_addr.s_addr);
=2D	int own, error;
+	int error;
=20
 	if (sin->sin_addr.s_addr =3D=3D 0) {
 		if (!(SC2IFP(sc)->if_flags & IFF_UP))
@@ -1442,7 +1624,7 @@
 	}
=20
 	/* we have to do it by hands to check we won't match on us */
=2D	ia_if =3D NULL; own =3D 0;
+	ia_if =3D NULL;
 	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
 		/* and, yeah, we need a multicast-capable iface too */
 		if (ia->ia_ifp !=3D SC2IFP(sc) &&
@@ -1450,106 +1632,65 @@
 		    (iaddr & ia->ia_subnetmask) =3D=3D ia->ia_subnet) {
 			if (!ia_if)
 				ia_if =3D ia;
=2D			if (sin->sin_addr.s_addr =3D=3D
=2D			    ia->ia_addr.sin_addr.s_addr)
=2D				own++;
 		}
 	}
=20
=2D	if (!ia_if)
=2D		return (EADDRNOTAVAIL);
=2D
=2D	ia =3D ia_if;
=2D	ifp =3D ia->ia_ifp;
=2D
=2D	if (ifp =3D=3D NULL || (ifp->if_flags & IFF_MULTICAST) =3D=3D 0 ||
=2D	    (imo->imo_multicast_ifp && imo->imo_multicast_ifp !=3D ifp))
=2D		return (EADDRNOTAVAIL);
=2D
=2D	if (imo->imo_num_memberships =3D=3D 0) {
=2D		addr.s_addr =3D htonl(INADDR_CARP_GROUP);
=2D		if ((imo->imo_membership[0] =3D in_addmulti(&addr, ifp)) =3D=3D NULL)
=2D			return (ENOBUFS);
=2D		imo->imo_num_memberships++;
=2D		imo->imo_multicast_ifp =3D ifp;
=2D		imo->imo_multicast_ttl =3D CARP_DFLTTL;
=2D		imo->imo_multicast_loop =3D 0;
=2D	}
=2D
=2D	if (!ifp->if_carp) {
=2D
=2D		MALLOC(cif, struct carp_if *, sizeof(*cif), M_CARP,
=2D		    M_WAITOK|M_ZERO);
=2D		if (!cif) {
=2D			error =3D ENOBUFS;
=2D			goto cleanup;
+	if (ia_if) {
+		ia =3D ia_if;
+		if (ifp) {
+			if (ifp !=3D ia->ia_ifp)
+				return (EADDRNOTAVAIL);
+		} else {
+			ifp =3D ia->ia_ifp;
 		}
=2D		if ((error =3D ifpromisc(ifp, 1))) {
=2D			FREE(cif, M_CARP);
=2D			goto cleanup;
=2D		}
=2D	=09
=2D		CARP_LOCK_INIT(cif);
=2D		CARP_LOCK(cif);
=2D		cif->vhif_ifp =3D ifp;
=2D		TAILQ_INIT(&cif->vhif_vrs);
=2D		ifp->if_carp =3D cif;
=2D
=2D	} else {
=2D		struct carp_softc *vr;
=2D
=2D		cif =3D (struct carp_if *)ifp->if_carp;
=2D		CARP_LOCK(cif);
=2D		TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
=2D			if (vr !=3D sc && vr->sc_vhid =3D=3D sc->sc_vhid) {
=2D				CARP_UNLOCK(cif);
=2D				error =3D EINVAL;
=2D				goto cleanup;
=2D			}
 	}
=2D	sc->sc_ia =3D ia;
=2D	sc->sc_carpdev =3D ifp;
=20
=2D	{ /* XXX prevent endless loop if already in queue */
=2D	struct carp_softc *vr, *after =3D NULL;
=2D	int myself =3D 0;
=2D	cif =3D (struct carp_if *)ifp->if_carp;
+	if ((error =3D carp_set_ifp(sc, ifp)))
+		return (error);
=20
=2D	/* XXX: cif should not change, right? So we still hold the lock */
=2D	CARP_LOCK_ASSERT(cif);
+	if (sc->sc_carpdev =3D=3D NULL)
+		return (EADDRNOTAVAIL);
=20
=2D	TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
=2D		if (vr =3D=3D sc)
=2D			myself =3D 1;
=2D		if (vr->sc_vhid < sc->sc_vhid)
=2D			after =3D vr;
=2D	}
=2D
=2D	if (!myself) {
=2D		/* We're trying to keep things in order */
=2D		if (after =3D=3D NULL) {
=2D			TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
=2D		} else {
=2D			TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list);
=2D		}
=2D		cif->vhif_nvrs++;
=2D	}
+	CARP_SCLOCK(sc);
+	if (sc->sc_naddrs =3D=3D 0 && (error =3D carp_join_multicast(sc)) !=3D 0)=
 {
+		CARP_SCUNLOCK(sc);
+		return (error);
 	}
=20
 	sc->sc_naddrs++;
 	SC2IFP(sc)->if_flags |=3D IFF_UP;
=2D	if (own)
=2D		sc->sc_advskew =3D 0;
 	carp_sc_state_locked(sc);
 	carp_setrun(sc, 0);
+	CARP_SCUNLOCK(sc);
+
+	return (0);
+
+/*
+ * XXX: cleanup multi?
+ * cleanup:
+ *	return (error);
+ */
+}
=20
=2D	CARP_UNLOCK(cif);
+static int
+carp_join_multicast(struct carp_softc *sc)
+{
+	struct ip_moptions *imo =3D &sc->sc_imo;
+	struct in_addr addr;
+
+	KASSERT(imo->imo_num_memberships =3D=3D 0,
+	    ("carp_join_multicast: leftover multicast memberships"));
+
+	addr.s_addr =3D htonl(INADDR_CARP_GROUP);
+	if ((imo->imo_membership[0] =3D
+	    in_addmulti(&addr, SC2IFP(sc))) =3D=3D NULL)
+		return (ENOBUFS);
+	imo->imo_num_memberships++;
+	imo->imo_multicast_ifp =3D SC2IFP(sc);
+	imo->imo_multicast_ttl =3D CARP_DFLTTL;
+	imo->imo_multicast_loop =3D 0;
=20
 	return (0);
=2D
=2Dcleanup:
=2D	in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
=2D	return (error);
 }
=20
 static int
@@ -1586,12 +1727,8 @@
 carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
 {
 	struct ifnet *ifp;
=2D	struct carp_if *cif;
 	struct in6_ifaddr *ia, *ia_if;
=2D	struct ip6_moptions *im6o =3D &sc->sc_im6o;
=2D	struct in6_multi_mship *imm;
=2D	struct in6_addr in6;
=2D	int own, error;
+	int own;
=20
 	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 		if (!(SC2IFP(sc)->if_flags & IFF_UP))
@@ -1632,114 +1769,74 @@
 	ifp =3D ia->ia_ifp;
=20
 	if (ifp =3D=3D NULL || (ifp->if_flags & IFF_MULTICAST) =3D=3D 0 ||
=2D	    (im6o->im6o_multicast_ifp && im6o->im6o_multicast_ifp !=3D ifp))
+	    (sc->sc_im6o.im6o_multicast_ifp &&
+	    sc->sc_im6o.im6o_multicast_ifp !=3D ifp))
 		return (EADDRNOTAVAIL);
=20
=2D	if (!sc->sc_naddrs6) {
=2D		im6o->im6o_multicast_ifp =3D ifp;
+	sc->sc_carpdev =3D ifp;
=20
=2D		/* join CARP multicast address */
=2D		bzero(&in6, sizeof(in6));
=2D		in6.s6_addr16[0] =3D htons(0xff02);
=2D		in6.s6_addr8[15] =3D 0x12;
=2D		if (in6_setscope(&in6, ifp, NULL) !=3D 0)
=2D			goto cleanup;
=2D		if ((imm =3D in6_joingroup(ifp, &in6, &error, 0)) =3D=3D NULL)
=2D			goto cleanup;
=2D		LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
+	sc->sc_naddrs6++;
+	SC2IFP(sc)->if_flags |=3D IFF_UP;
+	if (own)
+		sc->sc_advskew =3D 0;
+	carp_sc_state_locked(sc);
+	carp_setrun(sc, 0);
=20
=2D		/* join solicited multicast address */
=2D		bzero(&in6, sizeof(in6));
=2D		in6.s6_addr16[0] =3D htons(0xff02);
=2D		in6.s6_addr32[1] =3D 0;
=2D		in6.s6_addr32[2] =3D htonl(1);
=2D		in6.s6_addr32[3] =3D sin6->sin6_addr.s6_addr32[3];
=2D		in6.s6_addr8[12] =3D 0xff;
=2D		if (in6_setscope(&in6, ifp, NULL) !=3D 0)
=2D			goto cleanup;
=2D		if ((imm =3D in6_joingroup(ifp, &in6, &error, 0)) =3D=3D NULL)
=2D			goto cleanup;
=2D		LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
=2D	}
+	return (0);
=20
=2D	if (!ifp->if_carp) {
=2D		MALLOC(cif, struct carp_if *, sizeof(*cif), M_CARP,
=2D		    M_WAITOK|M_ZERO);
=2D		if (!cif) {
=2D			error =3D ENOBUFS;
=2D			goto cleanup;
=2D		}
=2D		if ((error =3D ifpromisc(ifp, 1))) {
=2D			FREE(cif, M_CARP);
=2D			goto cleanup;
=2D		}
+/* XXX:
+ * cleanup:
+ *	 * clean up multicast memberships *
+ *	if (!sc->sc_naddrs6) {
+ *		while (!LIST_EMPTY(&im6o->im6o_memberships)) {
+ *			imm =3D LIST_FIRST(&im6o->im6o_memberships);
+ *			LIST_REMOVE(imm, i6mm_chain);
+ *			in6_leavegroup(imm);
+ *		}
+ *	}
+ *	return (error);
+ */
+}
=20
=2D		CARP_LOCK_INIT(cif);
=2D		CARP_LOCK(cif);
=2D		cif->vhif_ifp =3D ifp;
=2D		TAILQ_INIT(&cif->vhif_vrs);
=2D		ifp->if_carp =3D cif;
+static int
+carp_join_multicast6(struct carp_softc *sc)
+{
+	struct ip6_moptions *im6o =3D &sc->sc_im6o;
+	struct in6_multi_mship *imm, *imm2;
+	struct in6_addr in6;
+	int error =3D 0;
=20
=2D	} else {
=2D		struct carp_softc *vr;
+	/* join CARP multicast address */
+	bzero(&in6, sizeof(in6));
+	in6.s6_addr16[0] =3D htons(0xff02);
+	in6.s6_addr8[15] =3D 0x12;
+	if ((error =3D in6_setscope(&in6, sc->sc_carpdev, NULL)) !=3D 0)
+		return (error);
+	if ((imm =3D in6_joingroup(sc->sc_carpdev, &in6, &error, 0)) =3D=3D NULL)
+		return (error);
=20
=2D		cif =3D (struct carp_if *)ifp->if_carp;
=2D		CARP_LOCK(cif);
=2D		TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
=2D			if (vr !=3D sc && vr->sc_vhid =3D=3D sc->sc_vhid) {
=2D				CARP_UNLOCK(cif);
=2D				error =3D EINVAL;
=2D				goto cleanup;
=2D			}
+	/* join solicited multicast address */
+	bzero(&in6, sizeof(in6));
+	in6.s6_addr16[0] =3D htons(0xff02);
+	in6.s6_addr32[1] =3D 0;
+	in6.s6_addr32[2] =3D htonl(1);
+	in6.s6_addr32[3] =3D 0; /* XXX: sin6->sin6_addr.s6_addr32[3]; */
+	in6.s6_addr8[12] =3D 0xff;
+	if ((error =3D in6_setscope(&in6, sc->sc_carpdev, NULL)) !=3D 0) {
+		in6_leavegroup(imm);
+		return (error);
 	}
=2D	sc->sc_ia6 =3D ia;
=2D	sc->sc_carpdev =3D ifp;
=2D
=2D	{ /* XXX prevent endless loop if already in queue */
=2D	struct carp_softc *vr, *after =3D NULL;
=2D	int myself =3D 0;
=2D	cif =3D (struct carp_if *)ifp->if_carp;
=2D	CARP_LOCK_ASSERT(cif);
=2D
=2D	TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
=2D		if (vr =3D=3D sc)
=2D			myself =3D 1;
=2D		if (vr->sc_vhid < sc->sc_vhid)
=2D			after =3D vr;
+	if ((imm2 =3D in6_joingroup(sc->sc_carpdev, &in6, &error, 0)) =3D=3D NULL=
) {
+		in6_leavegroup(imm);
+		return (error);
 	}
=20
=2D	if (!myself) {
=2D		/* We're trying to keep things in order */
=2D		if (after =3D=3D NULL) {
=2D			TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
=2D		} else {
=2D			TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list);
=2D		}
=2D		cif->vhif_nvrs++;
=2D	}
=2D	}
+	im6o->im6o_multicast_ifp =3D sc->sc_carpdev;
=20
=2D	sc->sc_naddrs6++;
=2D	SC2IFP(sc)->if_flags |=3D IFF_UP;
=2D	if (own)
=2D		sc->sc_advskew =3D 0;
=2D	carp_sc_state_locked(sc);
=2D	carp_setrun(sc, 0);
=2D
=2D	CARP_UNLOCK(cif);
+	LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
+	LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2, i6mm_chain);
=20
 	return (0);
=2D
=2Dcleanup:
=2D	/* clean up multicast memberships */
=2D	if (!sc->sc_naddrs6) {
=2D		while (!LIST_EMPTY(&im6o->im6o_memberships)) {
=2D			imm =3D LIST_FIRST(&im6o->im6o_memberships);
=2D			LIST_REMOVE(imm, i6mm_chain);
=2D			in6_leavegroup(imm);
=2D		}
=2D	}
=2D	return (error);
 }
=20
 static int
@@ -1785,7 +1882,8 @@
 	struct ifaddr *ifa;
 	struct ifreq *ifr;
 	struct ifaliasreq *ifra;
=2D	int locked =3D 0, error =3D 0;
+	struct ifnet *cdev =3D NULL;
+	int locked =3D 0, error =3D 0, changed =3D 0;
=20
 	ifa =3D (struct ifaddr *)addr;
 	ifra =3D (struct ifaliasreq *)addr;
@@ -1793,12 +1891,12 @@
=20
 	switch (cmd) {
 	case SIOCSIFADDR:
+	case SIOCAIFADDR:
+		changed++;
 		switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
 		case AF_INET:
 			SC2IFP(sc)->if_flags |=3D IFF_UP;
=2D			bcopy(ifa->ifa_addr, ifa->ifa_dstaddr,
=2D			    sizeof(struct sockaddr));
 			error =3D carp_set_addr(sc, satosin(ifa->ifa_addr));
 			break;
 #endif /* INET */
@@ -1814,29 +1912,8 @@
 		}
 		break;
=20
=2D	case SIOCAIFADDR:
=2D		switch (ifa->ifa_addr->sa_family) {
=2D#ifdef INET
=2D		case AF_INET:
=2D			SC2IFP(sc)->if_flags |=3D IFF_UP;
=2D			bcopy(ifa->ifa_addr, ifa->ifa_dstaddr,
=2D			    sizeof(struct sockaddr));
=2D			error =3D carp_set_addr(sc, satosin(&ifra->ifra_addr));
=2D			break;
=2D#endif /* INET */
=2D#ifdef INET6
=2D		case AF_INET6:
=2D			SC2IFP(sc)->if_flags |=3D IFF_UP;
=2D			error =3D carp_set_addr6(sc, satosin6(&ifra->ifra_addr));
=2D			break;
=2D#endif /* INET6 */
=2D		default:
=2D			error =3D EAFNOSUPPORT;
=2D			break;
=2D		}
=2D		break;
=2D
 	case SIOCDIFADDR:
+		changed++;
 		switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
 		case AF_INET:
@@ -1880,6 +1957,14 @@
 		if ((error =3D copyin(ifr->ifr_data, &carpr, sizeof carpr)))
 			break;
 		error =3D 1;
+		changed++;
+		if (carpr.carpr_carpdev[0] !=3D '\0' &&
+		    (cdev =3D ifunit(carpr.carpr_carpdev)) =3D=3D NULL) {
+		    	error =3D EINVAL;
+		    	break;
+		}
+		if ((error =3D carp_set_ifp(sc, cdev)))
+			break;
 		if (sc->sc_carpdev) {
 			locked =3D 1;
 			CARP_SCLOCK(sc);
@@ -1958,64 +2043,37 @@
 		if (error =3D=3D 0)
 			bcopy(sc->sc_key, carpr.carpr_key,
 			    sizeof(carpr.carpr_key));
+		if (sc->sc_carpdev !=3D NULL)
+			strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname,
+			    CARPDEVNAMSIZ);
 		error =3D copyout(&carpr, ifr->ifr_data, sizeof(carpr));
 		break;
=20
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		/* TODO: tell carpdev */
+		break;
+
 	default:
 		error =3D EINVAL;
 	}
=20
+	if (changed) {
+		if (!locked && sc->sc_carpdev) {
+			/* XXX: This really shouldn't happen */
+			CARP_SCLOCK(sc);
+			locked =3D 1;
+		}
+		carp_hmac_prepare(sc);
+	}
+
 	if (locked)
 		CARP_SCUNLOCK(sc);
=20
=2D	carp_hmac_prepare(sc);
=2D
 	return (error);
 }
=20
 /*
=2D * XXX: this is looutput. We should eventually use it from there.
=2D */
=2Dstatic int
=2Dcarp_looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
=2D    struct rtentry *rt)
=2D{
=2D	u_int32_t af;
=2D
=2D	M_ASSERTPKTHDR(m); /* check if we have the packet header */
=2D
=2D	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
=2D		m_freem(m);
=2D		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
=2D			rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
=2D	}
=2D
=2D	ifp->if_opackets++;
=2D	ifp->if_obytes +=3D m->m_pkthdr.len;
=2D
=2D	/* BPF writes need to be handled specially. */
=2D	if (dst->sa_family =3D=3D AF_UNSPEC) {
=2D		bcopy(dst->sa_data, &af, sizeof(af));
=2D		dst->sa_family =3D af;
=2D	}
=2D
=2D#if 1	/* XXX */
=2D	switch (dst->sa_family) {
=2D	case AF_INET:
=2D	case AF_INET6:
=2D	case AF_IPX:
=2D	case AF_APPLETALK:
=2D		break;
=2D	default:
=2D		printf("carp_looutput: af=3D%d unexpected\n", dst->sa_family);
=2D		m_freem(m);
=2D		return (EAFNOSUPPORT);
=2D	}
=2D#endif
=2D	return(if_simloop(ifp, m, dst->sa_family, 0));
=2D}
=2D
=2D/*
  * Start output on carp interface. This function should never be called.
  */
 static void
@@ -2026,80 +2084,83 @@
 #endif
 }
=20
=2Dint
+static int
 carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
     struct rtentry *rt)
 {
=2D	struct m_tag *mtag;
=2D	struct carp_softc *sc;
=2D	struct ifnet *carp_ifp;
+	struct carp_softc *sc =3D ifp->if_softc;
+
+	if (sc->sc_carpdev !=3D NULL && sc->sc_state =3D=3D MASTER)
+		return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
+	else {
+		m_freem(m);
+		return (ENETUNREACH);
+	}
+}
+
+struct ifnet *
+carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src)
+{
+	struct carp_if *cif =3D (struct carp_if *)v;
+	struct carp_softc *vh;
+	u_int8_t *ena;
=20
=2D	if (!sa)
=2D		return (0);
+	if (src)
+		ena =3D (u_int8_t *)&eh->ether_shost;
+	else
+		ena =3D (u_int8_t *)&eh->ether_dhost;
=20
=2D	switch (sa->sa_family) {
=2D#ifdef INET
=2D	case AF_INET:
=2D		break;
=2D#endif /* INET */
=2D#ifdef INET6
=2D	case AF_INET6:
=2D		break;
=2D#endif /* INET6 */
=2D	default:
=2D		return (0);
+	TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+		if ((vh->sc_ifp->if_flags & (IFF_UP)) !=3D (IFF_UP))
+			continue;
+		if ((vh->sc_state =3D=3D MASTER /* || vh->sc_ifp->if_flags & IFF_LINK0 *=
/)
+		    && !bcmp(ena, IF_LLADDR(vh->sc_ifp), ETHER_ADDR_LEN))
+			return (vh->sc_ifp);
 	}
+	return (NULL);
+}
=20
=2D	mtag =3D m_tag_find(m, PACKET_TAG_CARP, NULL);
=2D	if (mtag =3D=3D NULL)
=2D		return (0);
+int
+carp_input(struct mbuf *m)
+{
+	struct ether_header *eh;
+	struct carp_if *cif =3D (struct carp_if *)m->m_pkthdr.rcvif->if_carp;
+	struct ifnet *ifp;
=20
=2D	bcopy(mtag + 1, &carp_ifp, sizeof(struct ifnet *));
=2D	sc =3D carp_ifp->if_softc;
+	eh =3D mtod(m, struct ether_header *);
=20
=2D	/* Set the source MAC address to Virtual Router MAC Address */
=2D	switch (ifp->if_type) {
=2D	case IFT_ETHER:
=2D	case IFT_L2VLAN: {
=2D			struct ether_header *eh;
+	if ((ifp =3D carp_ourether(cif, eh, m->m_pkthdr.rcvif->if_type, 0)))
+		;
+	else if (m->m_flags & (M_BCAST|M_MCAST)) {
+		struct carp_softc *vh;
+		struct mbuf *m0;
=20
=2D			eh =3D mtod(m, struct ether_header *);
=2D			eh->ether_shost[0] =3D 0;
=2D			eh->ether_shost[1] =3D 0;
=2D			eh->ether_shost[2] =3D 0x5e;
=2D			eh->ether_shost[3] =3D 0;
=2D			eh->ether_shost[4] =3D 1;
=2D			eh->ether_shost[5] =3D sc->sc_vhid;
+		/*
+		 * XXX Should really check the list of multicast addresses
+		 * for each CARP interface _before_ copying.
+		 */
+		TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+			m0 =3D m_dup(m, M_DONTWAIT);
+			if (m0 =3D=3D NULL)
+				continue;
+			m0->m_pkthdr.rcvif =3D vh->sc_ifp;
+			ether_input(vh->sc_ifp, m0);
 		}
=2D		break;
=2D	case IFT_FDDI: {
=2D			struct fddi_header *fh;
+		return (1);
+	}
+
+	if (ifp =3D=3D NULL)
+		return (1);
+
+	m->m_pkthdr.rcvif =3D ifp;
=20
=2D			fh =3D mtod(m, struct fddi_header *);
=2D			fh->fddi_shost[0] =3D 0;
=2D			fh->fddi_shost[1] =3D 0;
=2D			fh->fddi_shost[2] =3D 0x5e;
=2D			fh->fddi_shost[3] =3D 0;
=2D			fh->fddi_shost[4] =3D 1;
=2D			fh->fddi_shost[5] =3D sc->sc_vhid;
=2D		}
=2D		break;
=2D	case IFT_ISO88025: {
=2D 			struct iso88025_header *th;
=2D 			th =3D mtod(m, struct iso88025_header *);
=2D			th->iso88025_shost[0] =3D 3;
=2D			th->iso88025_shost[1] =3D 0;
=2D			th->iso88025_shost[2] =3D 0x40 >> (sc->sc_vhid - 1);
=2D			th->iso88025_shost[3] =3D 0x40000 >> (sc->sc_vhid - 1);
=2D			th->iso88025_shost[4] =3D 0;
=2D			th->iso88025_shost[5] =3D 0;
=2D		}
=2D		break;
=2D	default:
=2D		printf("%s: carp is not supported for this interface type\n",
=2D		    ifp->if_xname);
=2D		return (EOPNOTSUPP);
=2D	}
+#if 0 /* XXX: BPF */
+	if (ifp->if_bpf)
+		bpf_mtap_hdr(ifp->if_bpf, (char *)&eh, ETHER_HDR_LEN, m,
+		    BPF_DIRECTION_IN);
+#endif
+	ifp->if_ipackets++;
+	ether_input(ifp, m);
=20
 	return (0);
 }
@@ -2130,9 +2191,14 @@
 }
=20
 void
=2Dcarp_carpdev_state(void *v)
+carp_carpdev_state(struct ifnet *ifp)
 {
=2D	struct carp_if *cif =3D v;
+	struct carp_if *cif;
+
+	if (ifp->if_type =3D=3D IFT_CARP || ifp->if_carp =3D=3D NULL)
+		return;
+
+	cif =3D ifp->if_carp;
=20
 	CARP_LOCK(cif);
 	carp_carpdev_state_locked(cif);
=2D-- //depot/vendor/freebsd/src/sys/netinet/ip_carp.h	2006/12/01 18:41:18
+++ //depot/user/mlaier/carp2/sys/netinet/ip_carp.h	2007/09/19 18:47:18
@@ -117,6 +117,13 @@
 	uint64_t	carps_preempt;		/* if enabled, preemptions */
 };
=20
+#define	CARPDEVNAMSIZ	16
+#ifdef IFNAMSIZ
+#if CARPDEVNAMSIZ !=3D IFNAMSIZ
+#error
+#endif
+#endif
+
 /*
  * Configuration structure for SIOCSVH SIOCGVH
  */
@@ -128,6 +135,7 @@
 	int		carpr_advskew;
 	int		carpr_advbase;
 	unsigned char	carpr_key[CARP_KEY_LEN];
+	char		carpr_carpdev[CARPDEVNAMSIZ];
 };
 #define	SIOCSVH	_IOWR('i', 245, struct ifreq)
 #define	SIOCGVH	_IOWR('i', 246, struct ifreq)
@@ -152,15 +160,15 @@
 }
=20
 #ifdef _KERNEL
=2Dvoid		 carp_carpdev_state(void *);
=2Dvoid		 carp_input (struct mbuf *, int);
=2Dint		 carp6_input (struct mbuf **, int *, int);
=2Dint		 carp_output (struct ifnet *, struct mbuf *, struct sockaddr *,
=2D		     struct rtentry *);
=2Dint		 carp_iamatch (void *, struct in_ifaddr *, struct in_addr *,
+void		 carp_carpdev_state(struct ifnet *);
+void		 carp_proto_input(struct mbuf *, int);
+int		 carp6_proto_input(struct mbuf **, int *, int);
+int		 carp_iamatch(void *, struct in_ifaddr *, struct in_addr *,
 		     u_int8_t **);
 struct ifaddr	*carp_iamatch6(void *, struct in6_addr *);
 void		*carp_macmatch6(void *, struct mbuf *, const struct in6_addr *);
=2Dstruct	ifnet	*carp_forus (void *, void *);
+struct	ifnet	*carp_forus(void *, void *);
+struct ifnet	*carp_ourether(void *, struct ether_header *, u_char, int);
+int		 carp_input(struct mbuf *);
 #endif
 #endif /* _IP_CARP_H */
=2D-- //depot/vendor/freebsd/src/sys/netinet6/in6_proto.c	2007/07/05 16:32:=
05
+++ //depot/user/mlaier/carp2/sys/netinet6/in6_proto.c	2007/09/19 18:47:18
@@ -319,7 +319,7 @@
 	.pr_domain =3D		&inet6domain,
 	.pr_protocol =3D		IPPROTO_CARP,
 	.pr_flags =3D		PR_ATOMIC|PR_ADDR,
=2D	.pr_input =3D		carp6_input,
+	.pr_input =3D		carp6_proto_input,
 	.pr_output =3D		rip6_output,
 	.pr_ctloutput =3D		rip6_ctloutput,
 	.pr_usrreqs =3D		&rip6_usrreqs

--Boundary-01=_CHX8GSw9Ne9ETUl--

--nextPart2869418.BCtFpRmQ1Q
Content-Type: application/pgp-signature; name=signature.asc 
Content-Description: This is a digitally signed message part.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4 (FreeBSD)

iD8DBQBG8XHIXyyEoT62BG0RAlkpAJ9h/Ffdg3+p2XEUtIaYvRB8c5TCDgCfVM6e
FnEu7aejL4cDdaOdE+LO54I=
=rphQ
-----END PGP SIGNATURE-----

--nextPart2869418.BCtFpRmQ1Q--



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