From owner-freebsd-pf@FreeBSD.ORG Sun Dec 9 17:35:38 2007 Return-Path: Delivered-To: freebsd-pf@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CFA5A16A418 for ; Sun, 9 Dec 2007 17:35:38 +0000 (UTC) (envelope-from max@love2party.net) Received: from moutng.kundenserver.de (moutng.kundenserver.de [212.227.126.186]) by mx1.freebsd.org (Postfix) with ESMTP id C980513C44B for ; Sun, 9 Dec 2007 17:35:37 +0000 (UTC) (envelope-from max@love2party.net) Received: from amd64.laiers.local (dslb-088-064-178-153.pools.arcor-ip.net [88.64.178.153]) by mrelayeu.kundenserver.de (node=mrelayeu4) with ESMTP (Nemesis) id 0ML21M-1J1Q3z1f0D-0001td; Sun, 09 Dec 2007 18:35:36 +0100 From: Max Laier Organization: FreeBSD To: freebsd-pf@freebsd.org Date: Sun, 9 Dec 2007 18:35:25 +0100 User-Agent: KMail/1.9.7 References: <200710272311.09059.max@love2party.net> <8e10486b0712041257p6a54c50by4c340bba9c4a39b3@mail.gmail.com> <200712051432.29703.max@love2party.net> In-Reply-To: <200712051432.29703.max@love2party.net> X-Face: ,,8R(x[kmU]tKN@>gtH1yQE4aslGdu+2]; R]*pL,U>^H?)gW@49@wdJ`H<=?utf-8?q?=25=7D*=5FBD=0A=09U=5For=3D=5CmOZf764=26nYj=3DJYbR1PW0ud?=>|!~,,CPC.1-D$FG@0h3#'5"k{V]a~.<=?utf-8?q?mZ=7D44=23Se=7Em=0A=09Fe=7E=5C=5DX5B=5D=5Fxj?=(ykz9QKMw_l0C2AQ]}Ym8)fU MIME-Version: 1.0 Content-Type: multipart/signed; boundary="nextPart1795943.NKanXysAve"; protocol="application/pgp-signature"; micalg=pgp-sha1 Content-Transfer-Encoding: 7bit Message-Id: <200712091835.33608.max@love2party.net> X-Provags-ID: V01U2FsdGVkX1/kneH91LBkIpVdudE6afKAZaGbl7z62svyOl7 eSq3COjNI0fI4lURNaLtmAu7c/nzQwIdai+QlHGQJtvpxWWPns DIPOe+c9kzmdkGbQLPGpVRD3kqYmSZ9qp+2Qu+EJTE= Subject: Re: carpdev ... X-BeenThere: freebsd-pf@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Technical discussion and general questions about packet filter \(pf\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 09 Dec 2007 17:35:39 -0000 --nextPart1795943.NKanXysAve Content-Type: multipart/mixed; boundary="Boundary-01=_gdCXHstQkL2YQhf" Content-Transfer-Encoding: 7bit Content-Disposition: inline --Boundary-01=_gdCXHstQkL2YQhf Content-Type: text/plain; charset="iso-8859-6" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline All, the arp error print turned out to be a really stupid error - as suspected. = =20 The attached should now be all quite and works for me in every possible=20 IPv4 scenario I could think up (mixed environment with OpenBSD and=20 unpatched FreeBSD tested, too). All is still IPv4 only!!! But I'll see to remedy this last problem next=20 week. I'd be very, very eager to hear test reports now! This is still use with=20 care etc. but you can easily patch your BACKUP for testing. The patch is=20 relative to HEAD and should apply to RELENG_7 ... I'll see what RELENG_6=20 does in a few days ... unless somebody beats me to it. Please report in case of failure *and* success! Thanks. This work is 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=_gdCXHstQkL2YQhf Content-Type: text/plain; charset="iso-8859-6"; name="carpdev.BETA2.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="carpdev.BETA2.diff" diff --git a/sbin/ifconfig/ifcarp.c b/sbin/ifconfig/ifcarp.c index 9c961b7..82dbd50 100644 =2D-- a/sbin/ifconfig/ifcarp.c +++ b/sbin/ifconfig/ifcarp.c @@ -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 @@ carp_status(int s) 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 @@ setcarp_passwd(const char *val, int d, int s, const stru= ct afswtch *afp) 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 @@ setcarp_vhid(const char *val, int d, int s, const struc= t afswtch *afp) 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 @@ setcarp_advskew(const char *val, int d, int s, const st= ruct afswtch *afp) 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 @@ setcarp_advbase(const char *val, int d, int s, const = struct afswtch *afp) 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", diff --git a/sys/amd64/conf/CARP b/sys/amd64/conf/CARP new file mode 100644 index 0000000..710a970 =2D-- /dev/null +++ b/sys/amd64/conf/CARP @@ -0,0 +1,4 @@ +include GENERIC +ident CARP + +device carp diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h index 7d45ce3..e7a3450 100644 =2D-- a/sys/net/ethernet.h +++ b/sys/net/ethernet.h @@ -380,6 +380,7 @@ extern void ether_demux(struct ifnet *, struct mbuf *); 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 *); diff --git a/sys/net/if.c b/sys/net/if.c index 9db8935..9178a3d 100644 =2D-- a/sys/net/if.c +++ b/sys/net/if.c @@ -1309,8 +1309,7 @@ if_unroute(struct ifnet *ifp, int flag, int fam) 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_route(struct ifnet *ifp, int flag, int fam) 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 @@ do_link_state_change(void *arg, int pending) 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!")); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 7023e9c..170bcc7 100644 =2D-- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -153,6 +153,9 @@ ether_output(struct ifnet *ifp, struct mbuf *m, 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 @@ ether_output(struct ifnet *ifp, struct mbuf *m, 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 @@ ether_output(struct ifnet *ifp, struct mbuf *m, 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 @@ ether_output(struct ifnet *ifp, struct mbuf *m, (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 @@ ether_output(struct ifnet *ifp, struct mbuf *m, 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 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, * 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; @@ -658,19 +680,15 @@ ether_input(struct ifnet *ifp, struct mbuf *m) } =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 { /* diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index bd15bdf..1706f58 100644 =2D-- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -98,8 +98,6 @@ struct lo_softc { =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 diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 44a297e..b0da599 100644 =2D-- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -131,7 +131,12 @@ struct ifnet { */ 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 */ @@ -692,6 +697,8 @@ struct ifaddr *ifa_ifwithroute(int, struct sockaddr *, = struct sockaddr *); 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); diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 13f2c06..b4f667d 100644 =2D-- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -110,7 +110,6 @@ SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CT= LFLAG_RW, &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 *); @@ -144,7 +143,7 @@ arptimer(void *arg) /* * Parallel to llc_rtrequest. */ =2Dstatic void +void arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) { struct sockaddr *gate; @@ -575,9 +574,6 @@ in_arpinput(struct mbuf *m) int op, rif_len; int req_len; int bridged =3D 0; =2D#ifdef DEV_CARP =2D int carp_match =3D 0; =2D#endif =20 if (ifp->if_bridge) bridged =3D 1; @@ -608,12 +604,11 @@ in_arpinput(struct mbuf *m) itaddr.s_addr =3D=3D ia->ia_addr.sin_addr.s_addr) goto match; #ifdef DEV_CARP =2D if (ifp->if_carp !=3D NULL && + if (ifp->if_type !=3D IFT_CARP && ifp->if_carp !=3D NULL && + ia->ia_ifp->if_type =3D=3D IFT_CARP && carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) && =2D itaddr.s_addr =3D=3D ia->ia_addr.sin_addr.s_addr) { =2D carp_match =3D 1; + itaddr.s_addr =3D=3D ia->ia_addr.sin_addr.s_addr) goto match; =2D } #endif } LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) @@ -676,7 +671,9 @@ match: /* The following is not an error when doing bridging. */ if (!bridged && rt->rt_ifp !=3D ifp #ifdef DEV_CARP =2D && (ifp->if_type !=3D IFT_CARP || !carp_match) + && !(rt->rt_ifp->if_type =3D=3D IFT_CARP && + rt->rt_ifp->if_carpdev =3D=3D ifp) && + !(ifp->if_type =3D=3D IFT_CARP && ifp->if_carpdev =3D=3D rt->rt_ifp) #endif ) { if (log_arp_wrong_iface) diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h index 9bc6b7b..8c36e02 100644 =2D-- a/sys/netinet/if_ether.h +++ b/sys/netinet/if_ether.h @@ -113,6 +113,7 @@ int arpresolve(struct ifnet *ifp, struct rtentry *rt, 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 diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 5239805..f642bb9 100644 =2D-- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -318,7 +318,7 @@ struct protosw inetsw[] =3D { .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 diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index c08d39f..aea3518 100644 =2D-- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -92,11 +92,9 @@ SYSCTL_DECL(_net_inet_carp); =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; @@ -159,7 +157,7 @@ struct carp_if { 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 */ @@ -190,7 +188,7 @@ static void carp_hmac_generate(struct carp_softc *, u_i= nt32_t *, 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); @@ -203,7 +201,7 @@ static void carp_send_arp(struct carp_softc *); 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); @@ -212,13 +210,16 @@ static int carp_addrcount(struct carp_if *, struct in= _ifaddr *, int); 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 @@ -247,9 +248,9 @@ carp_hmac_prepare(struct carp_softc *sc) #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)); @@ -285,8 +286,6 @@ carp_hmac_prepare(struct carp_softc *sc) 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 @@ -334,13 +333,106 @@ carp_setroute(struct carp_softc *sc, int cmd) 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; + } =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); + /* 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; + + 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) { @@ -360,6 +452,7 @@ carp_clone_create(struct if_clone *ifc, int unit, caddr= _t params) =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); @@ -391,16 +484,13 @@ carp_clone_create(struct if_clone *ifc, int unit, cad= dr_t params) =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); @@ -503,7 +593,7 @@ carp_ifdetach(void *arg __unused, struct ifnet *ifp) * 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; @@ -517,9 +607,9 @@ carp_input(struct mbuf *m, int hlen) } =20 /* check if received on a valid carp interface */ =2D if (m->m_pkthdr.rcvif->if_carp =3D=3D NULL) { + if (m->m_pkthdr.rcvif->if_type !=3D IFT_CARP) { 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); @@ -529,7 +619,7 @@ carp_input(struct mbuf *m, int hlen) /* 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); @@ -540,7 +630,7 @@ carp_input(struct mbuf *m, int hlen) =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); @@ -550,7 +640,7 @@ carp_input(struct mbuf *m, int hlen) 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 *); @@ -564,7 +654,7 @@ carp_input(struct mbuf *m, int hlen) 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); @@ -582,19 +672,19 @@ carp_input(struct mbuf *m, int hlen) 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 *); @@ -609,9 +699,9 @@ carp6_input(struct mbuf **mp, int *offp, int proto) } =20 /* check if received on a valid carp interface */ =2D if (m->m_pkthdr.rcvif->if_carp =3D=3D NULL) { + if (m->m_pkthdr.rcvif->if_type !=3D IFT_CARP) { 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); @@ -621,7 +711,7 @@ carp6_input(struct mbuf **mp, int *offp, int proto) /* 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); @@ -633,7 +723,7 @@ carp6_input(struct mbuf **mp, int *offp, int proto) 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 @@ -642,22 +732,22 @@ carp6_input(struct mbuf **mp, int *offp, int proto) 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) { =2D struct ifnet *ifp =3D m->m_pkthdr.rcvif; + struct ifnet *ifp =3D m->m_pkthdr.rcvif->if_carpdev; struct carp_softc *sc; u_int64_t tmp_counter; struct timeval sc_tv, ch_tv; @@ -793,9 +883,6 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa= _family_t af) 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(); @@ -809,16 +896,6 @@ carp_prepare_ad(struct mbuf *m, struct carp_softc *sc,= struct carp_header *ch) =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 @@ -859,6 +936,8 @@ carp_send_ad_locked(struct carp_softc *sc) struct carp_header *ch_ptr; struct mbuf *m; int len, advbase, advskew; + struct ifaddr *ifa; + struct sockaddr sa; =20 CARP_SCLOCK_ASSERT(sc); =20 @@ -887,7 +966,7 @@ carp_send_ad_locked(struct carp_softc *sc) 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); @@ -916,7 +995,15 @@ carp_send_ad_locked(struct carp_softc *sc) 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]); @@ -959,7 +1046,7 @@ carp_send_ad_locked(struct carp_softc *sc) } #endif /* INET */ #ifdef INET6 =2D if (sc->sc_ia6) { + if (sc->sc_naddrs6) { struct ip6_hdr *ip6; =20 MGETHDR(m, M_DONTWAIT, MT_HEADER); @@ -983,8 +1070,15 @@ carp_send_ad_locked(struct carp_softc *sc) 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); @@ -1058,7 +1152,7 @@ carp_send_arp(struct carp_softc *sc) 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 */ } @@ -1211,7 +1305,6 @@ carp_iamatch6(void *v, struct in6_addr *taddr) 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; @@ -1223,18 +1316,6 @@ carp_macmatch6(void *v, struct mbuf *m, const struct= in6_addr *taddr) &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)); } @@ -1423,15 +1504,116 @@ carp_multicast6_cleanup(struct carp_softc *sc) #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)) @@ -1443,7 +1625,7 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_= in *sin) } =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) && @@ -1451,106 +1633,65 @@ carp_set_addr(struct carp_softc *sc, struct sockad= dr_in *sin) (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; =2D } =2D if ((error =3D ifpromisc(ifp, 1))) { =2D FREE(cif, M_CARP); =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 =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); =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; =2D } + if (sc->sc_carpdev =3D=3D NULL) + return (EADDRNOTAVAIL); =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 } + 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); =2D =2D CARP_UNLOCK(cif); + CARP_SCUNLOCK(sc); =20 return (0); =20 =2Dcleanup: =2D in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); =2D return (error); +/* + * XXX: cleanup multi? + * cleanup: + * return (error); + */ +} + +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; + + return (0); } =20 static int @@ -1587,12 +1728,8 @@ static int 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)) @@ -1633,93 +1770,12 @@ carp_set_addr6(struct carp_softc *sc, struct sockad= dr_in6 *sin6) 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; =2D =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); =2D =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 } =2D =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 } =2D =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 } =2D sc->sc_ia6 =3D ia; 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; =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; =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 } =2D } =2D sc->sc_naddrs6++; SC2IFP(sc)->if_flags |=3D IFF_UP; if (own) @@ -1727,20 +1783,61 @@ carp_set_addr6(struct carp_softc *sc, struct sockad= dr_in6 *sin6) carp_sc_state_locked(sc); carp_setrun(sc, 0); =20 =2D CARP_UNLOCK(cif); =2D return (0); =20 =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 } +/* 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); + */ +} + +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; + + /* 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); + + /* 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 return (error); + if ((imm2 =3D in6_joingroup(sc->sc_carpdev, &in6, &error, 0)) =3D=3D NULL= ) { + in6_leavegroup(imm); + return (error); + } + + im6o->im6o_multicast_ifp =3D sc->sc_carpdev; + + LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain); + LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2, i6mm_chain); + + return (0); } =20 static int @@ -1786,7 +1883,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t add= r) 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; @@ -1794,12 +1892,12 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t a= ddr) =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 */ @@ -1815,29 +1913,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t ad= dr) } 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: @@ -1881,6 +1958,14 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t ad= dr) 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); @@ -1959,64 +2044,37 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t a= ddr) 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 @@ -2027,81 +2085,84 @@ carp_start(struct ifnet *ifp) #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; =20 =2D if (!sa) =2D return (0); + 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); + } +} =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); +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; + + if (src) + ena =3D (u_int8_t *)&eh->ether_shost; + else + ena =3D (u_int8_t *)&eh->ether_dhost; + + 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; =2D =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; =2D =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; =2D } =2D break; =2D case IFT_FDDI: { =2D struct fddi_header *fh; =2D =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; + eh =3D mtod(m, struct ether_header *); + + 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; + + /* + * 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 default: =2D printf("%s: carp is not supported for this interface type\n", =2D ifp->if_xname); =2D return (EOPNOTSUPP); + return (1); } =20 + if (ifp =3D=3D NULL) + return (1); + + m->m_pkthdr.rcvif =3D ifp; + +#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); + return (0); } =20 @@ -2131,9 +2192,14 @@ carp_set_state(struct carp_softc *sc, int state) } =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); diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h index 1688b01..3525ab9 100644 =2D-- a/sys/netinet/ip_carp.h +++ b/sys/netinet/ip_carp.h @@ -117,6 +117,13 @@ struct carpstats { 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 @@ struct carpreq { 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 @@ struct carpreq { } =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 */ diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 2230741..fbd022d 100644 =2D-- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -319,7 +319,7 @@ struct ip6protosw inet6sw[] =3D { .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=_gdCXHstQkL2YQhf-- --nextPart1795943.NKanXysAve 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) iD8DBQBHXCdlXyyEoT62BG0RAqOOAJ0a/PRe61xOY9a+1Ns8cJP9CO2B8wCfZn9k c9XkbPcouqlTXaOkc6zFHJM= =5f0T -----END PGP SIGNATURE----- --nextPart1795943.NKanXysAve--