summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if.c3
-rw-r--r--sys/net/if_ethersubr.c22
-rw-r--r--sys/netinet/if_ether.c11
-rw-r--r--sys/netinet/ip_carp.c330
-rw-r--r--sys/netinet/ip_carp.h5
-rw-r--r--sys/netinet/ip_icmp.c30
-rw-r--r--sys/netinet/ip_input.c25
-rw-r--r--sys/netinet6/icmp6.c17
-rw-r--r--sys/netinet6/ip6_input.c24
-rw-r--r--sys/netinet6/nd6_nbr.c11
10 files changed, 376 insertions, 102 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 165f044713a..7231c29be4b 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.c,v 1.155 2007/02/14 00:53:48 jsg Exp $ */
+/* $OpenBSD: if.c,v 1.156 2007/03/18 23:23:17 mpf Exp $ */
/* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
/*
@@ -1329,6 +1329,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
return (EINVAL);
switch (ifp->if_type) {
case IFT_ETHER:
+ case IFT_CARP:
case IFT_FDDI:
case IFT_XETHER:
case IFT_ISO88025:
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index cdf78cb50c1..45d030e548a 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ethersubr.c,v 1.105 2006/12/07 18:15:29 reyk Exp $ */
+/* $OpenBSD: if_ethersubr.c,v 1.106 2007/03/18 23:23:17 mpf Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
/*
@@ -401,7 +401,8 @@ ether_output(ifp0, m0, dst, rt0)
sizeof(eh->ether_shost));
#if NCARP > 0
- if (ifp0 != ifp && ifp0->if_type == IFT_CARP) {
+ if (ifp0 != ifp && ifp0->if_type == IFT_CARP &&
+ !(ifp0->if_flags & IFF_LINK1)) {
bcopy((caddr_t)((struct arpcom *)ifp0)->ac_enaddr,
(caddr_t)eh->ether_shost, sizeof(eh->ether_shost));
}
@@ -595,10 +596,19 @@ ether_input(ifp, eh, m)
#endif /* NVLAN > 0 */
#if NCARP > 0
- if (ifp->if_carp && ifp->if_type != IFT_CARP &&
- (carp_input(m, (u_int8_t *)&eh->ether_shost,
- (u_int8_t *)&eh->ether_dhost, eh->ether_type) == 0))
- return;
+ if (ifp->if_carp) {
+ if (ifp->if_type != IFT_CARP &&
+ (carp_input(m, (u_int8_t *)&eh->ether_shost,
+ (u_int8_t *)&eh->ether_dhost, eh->ether_type) == 0))
+ return;
+ /* Always clear multicast flags if received on a carp address */
+ else if (ifp->if_type == IFT_CARP &&
+ ifp->if_flags & IFF_LINK2 &&
+ m->m_flags & (M_BCAST|M_MCAST) &&
+ !bcmp(((struct arpcom *)ifp)->ac_enaddr,
+ (caddr_t)eh->ether_dhost, ETHER_ADDR_LEN))
+ m->m_flags &= ~(M_BCAST|M_MCAST);
+ }
#endif /* NCARP > 0 */
ac = (struct arpcom *)ifp;
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 4d99bb1e294..cf9c1662d81 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ether.c,v 1.66 2007/03/16 16:58:40 deraadt Exp $ */
+/* $OpenBSD: if_ether.c,v 1.67 2007/03/18 23:23:17 mpf Exp $ */
/* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */
/*
@@ -720,7 +720,14 @@ reply:
ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
eh = (struct ether_header *)sa.sa_data;
bcopy(ea->arp_tha, eh->ether_dhost, sizeof(eh->ether_dhost));
- bcopy(enaddr, eh->ether_shost, sizeof(eh->ether_shost));
+#if NCARP > 0
+ if (ac->ac_if.if_type == IFT_CARP && ac->ac_if.if_flags & IFF_LINK1)
+ bcopy(((struct arpcom *)ac->ac_if.if_carpdev)->ac_enaddr,
+ eh->ether_shost, sizeof(eh->ether_shost));
+ else
+#endif
+ bcopy(enaddr, eh->ether_shost, sizeof(eh->ether_shost));
+
eh->ether_type = htons(ETHERTYPE_ARP);
sa.sa_family = pseudo_AF_HDRCMPLT;
sa.sa_len = sizeof(sa);
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 61bd993ba19..d2719316dc9 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_carp.c,v 1.132 2006/12/13 09:01:59 itojun Exp $ */
+/* $OpenBSD: ip_carp.c,v 1.133 2007/03/18 23:23:17 mpf Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -126,6 +126,8 @@ struct carp_softc {
int sc_sendad_success;
#define CARP_SENDAD_MIN_SUCCESS 3
+ char sc_carplladdr[ETHER_ADDR_LEN];
+ char sc_curlladdr[ETHER_ADDR_LEN];
int sc_vhid;
int sc_advskew;
int sc_naddrs;
@@ -141,6 +143,8 @@ struct carp_softc {
SHA1_CTX sc_sha1[HMAC_MAX];
u_int32_t sc_hashkey[2];
+ u_int32_t sc_lsmask; /* load sharing mask */
+ int sc_lscount; /* # load sharing interfaces (max 32) */
struct timeout sc_ad_tmo; /* advertisement timeout */
struct timeout sc_md_tmo; /* master down timeout */
@@ -192,9 +196,8 @@ void carp_ifgroup_ioctl(struct ifnet *, u_long, caddr_t);
void carp_start(struct ifnet *);
void carp_setrun(struct carp_softc *, sa_family_t);
void carp_set_state(struct carp_softc *, int);
-int carp_addrcount(struct carp_if *, struct in_ifaddr *, int);
-enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING };
-
+int carp_addrcount(struct carp_if *, struct ifaddr *, int);
+enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING, CARP_COUNT_LINK0 };
void carp_multicast_cleanup(struct carp_softc *);
int carp_set_ifp(struct carp_softc *, struct ifnet *);
void carp_set_enaddr(struct carp_softc *);
@@ -213,6 +216,7 @@ int carp_ether_addmulti(struct carp_softc *, struct ifreq *);
int carp_ether_delmulti(struct carp_softc *, struct ifreq *);
void carp_ether_purgemulti(struct carp_softc *);
int carp_group_demote_count(struct carp_softc *);
+void carp_update_lsmask(struct carp_softc *);
struct if_clone carp_cloner =
IF_CLONE_INITIALIZER("carp", carp_clone_create, carp_clone_destroy);
@@ -265,6 +269,10 @@ carp_hmac_prepare_ctx(struct carp_softc *sc, u_int8_t ctx)
sc->sc_hashkey[1] = kmd[2] ^ kmd[3];
/* the rest of the precomputation */
+ if (bcmp(sc->sc_ac.ac_enaddr, &sc->sc_carplladdr, ETHER_ADDR_LEN) != 0)
+ SHA1Update(&sc->sc_sha1[ctx], sc->sc_ac.ac_enaddr,
+ ETHER_ADDR_LEN);
+
SHA1Update(&sc->sc_sha1[ctx], (void *)&vhid, sizeof(vhid));
/* Hash the addresses from smallest to largest, not interface order */
@@ -379,7 +387,7 @@ carp_setroute(struct carp_softc *sc, int cmd)
sc->sc_carpdev->if_carp != NULL) {
count = carp_addrcount(
(struct carp_if *)sc->sc_carpdev->if_carp,
- ifatoia(ifa), CARP_COUNT_MASTER);
+ ifa, CARP_COUNT_MASTER);
if ((cmd == RTM_ADD && count != 1) ||
(cmd == RTM_DELETE && count != 0))
continue;
@@ -832,7 +840,6 @@ carp_clone_create(ifc, unit)
if_attach(ifp);
if_alloc_sadl(ifp);
- carp_set_enaddr(sc);
LIST_INIT(&sc->sc_ac.ac_multiaddrs);
#if NBPFILTER > 0
bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
@@ -1175,6 +1182,10 @@ carp_send_arp(struct carp_softc *sc)
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
+ if (carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp,
+ ifa, CARP_COUNT_LINK0))
+ continue;
+
in = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
arprequest(sc->sc_carpdev, &in, &in, sc->sc_ac.ac_enaddr);
DELAY(1000); /* XXX */
@@ -1242,26 +1253,131 @@ carp_hash(struct carp_softc *sc, u_char *src)
}
int
-carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type)
+carp_addrcount(struct carp_if *cif, struct ifaddr *ifa0, int type)
{
struct carp_softc *vh;
struct ifaddr *ifa;
int count = 0;
TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
- if ((type == CARP_COUNT_RUNNING &&
- (vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
- (IFF_UP|IFF_RUNNING)) ||
- (type == CARP_COUNT_MASTER && vh->sc_state == MASTER)) {
+ switch (type) {
+ case CARP_COUNT_RUNNING:
+ if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
+ (IFF_UP|IFF_RUNNING))
+ continue;
+ break;
+ case CARP_COUNT_MASTER:
+ if (vh->sc_state != MASTER)
+ continue;
+ break;
+ case CARP_COUNT_LINK0:
+ if (!(vh->sc_if.if_flags & IFF_LINK0) ||
+ (vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
+ (IFF_UP|IFF_RUNNING))
+ continue;
+ break;
+ }
+ TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) {
+ if (ifa->ifa_addr->sa_family == AF_INET &&
+ ifa0->ifa_addr->sa_family == AF_INET &&
+ ifatoia(ifa0)->ia_addr.sin_addr.s_addr ==
+ ifatoia(ifa)->ia_addr.sin_addr.s_addr)
+ count++;
+#ifdef INET6
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ ifa0->ifa_addr->sa_family == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa0), IFA_IN6(ifa)))
+ count++;
+#endif
+ }
+ }
+ return (count);
+}
+
+void
+carp_update_lsmask(struct carp_softc *sc)
+{
+ struct carp_softc *curvh, *vh, *sc0 = NULL;
+ struct carp_if *cif;
+ struct ifaddr *ifa, *ifa0 = NULL;
+ int cur, last, count, found;
+
+ if (!sc->sc_carpdev)
+ return;
+ cif = (struct carp_if *)sc->sc_carpdev->if_carp;
+
+ /*
+ * Take the first IPv4 address from the LINK0 carp interface
+ * to determine the load sharing group.
+ * Fallback on the first IPv6 address.
+ */
+ TAILQ_FOREACH(sc0, &cif->vhif_vrs, sc_list)
+ if (sc0->sc_if.if_flags & IFF_LINK0)
+ break;
+ if (sc0 == NULL)
+ return;
+
+ TAILQ_FOREACH(ifa0, &sc0->sc_if.if_addrlist, ifa_list)
+ if (ifa0->ifa_addr->sa_family == AF_INET)
+ break;
+#ifdef INET6
+ if (ifa0 == NULL)
+ TAILQ_FOREACH(ifa0, &sc0->sc_if.if_addrlist, ifa_list)
+ if (ifa0->ifa_addr->sa_family == AF_INET6 &&
+ !IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa0)))
+ break;
+#endif
+ if (ifa0 == NULL)
+ return;
+ /*
+ * Calculate the load sharing mask w/ all carp interfaces
+ * that share the first address of the LINK0 interface.
+ * Sort by virtual host ID.
+ */
+ sc0->sc_lsmask = 0;
+ cur = 0;
+ curvh = NULL;
+ count = 0;
+ do {
+ found = 0;
+ last = cur;
+ cur = 255;
+ TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+ if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
+ (IFF_UP|IFF_RUNNING))
+ continue;
TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family == AF_INET &&
- ia->ia_addr.sin_addr.s_addr ==
+ ifa0->ifa_addr->sa_family == AF_INET &&
+ ifatoia(ifa0)->ia_addr.sin_addr.s_addr ==
ifatoia(ifa)->ia_addr.sin_addr.s_addr)
- count++;
+ break;
+#ifdef INET6
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ ifa0->ifa_addr->sa_family == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa0), IFA_IN6(ifa)))
+ break;
+#endif
+ }
+ if (ifa && vh->sc_vhid > last && vh->sc_vhid < cur) {
+ cur = vh->sc_vhid;
+ curvh = vh;
+ found++;
}
}
- }
- return (count);
+ if (found) {
+ if (curvh->sc_state == MASTER &&
+ count < sizeof(sc0->sc_lsmask) * 8)
+ sc0->sc_lsmask |= 1 << count;
+ count++;
+ }
+ } while (found);
+
+ sc0->sc_lscount = count;
+ if (count == 0)
+ return;
+
+ CARP_LOG(sc, ("carp_update_lsmask: %x", sc0->sc_lsmask))
}
int
@@ -1270,6 +1386,15 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src,
{
struct carp_softc *sc = ia->ia_ifp->if_softc;
+ /*
+ * If the asked address is found on a LINK0 interface
+ * don't answer the arp reply unless we are MASTER on it.
+ */
+ if (!(sc->sc_if.if_flags & IFF_LINK0) && sc->sc_carpdev &&
+ carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp,
+ (struct ifaddr *)ia, CARP_COUNT_LINK0))
+ return (0);
+
if (carp_opts[CARPCTL_ARPBALANCE]) {
/*
* We use the source ip to decide which virtual host should
@@ -1278,11 +1403,11 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src,
* the floor.
*/
- /* Count the elegible carp interfaces with this address */
+ /* Count the eligible carp interfaces with this address */
if (*count == 0)
*count = carp_addrcount(
(struct carp_if *)ia->ia_ifp->if_carpdev->if_carp,
- ia, CARP_COUNT_RUNNING);
+ (struct ifaddr *)ia, CARP_COUNT_RUNNING);
/* This should never happen, but... */
if (*count == 0)
@@ -1301,24 +1426,24 @@ carp_iamatch(struct in_ifaddr *ia, u_char *src,
}
#ifdef INET6
-struct ifaddr *
-carp_iamatch6(void *v, struct in6_addr *taddr)
+int
+carp_iamatch6(struct ifnet *ifp, struct ifaddr *ifa)
{
- struct carp_if *cif = v;
- struct carp_softc *vh;
- struct ifaddr *ifa;
+ struct carp_softc *sc = ifp->if_softc;
- TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
- TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) {
- if (IN6_ARE_ADDR_EQUAL(taddr,
- &ifatoia6(ifa)->ia_addr.sin6_addr) &&
- ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
- (IFF_UP|IFF_RUNNING)) && vh->sc_state == MASTER)
- return (ifa);
- }
- }
+ /*
+ * If the asked address is found on a LINK0 interface
+ * don't answer the arp request unless we are MASTER on it.
+ */
+ if (!(sc->sc_if.if_flags & IFF_LINK0) && sc->sc_carpdev &&
+ carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp,
+ ifa, CARP_COUNT_LINK0))
+ return (0);
- return (NULL);
+ if (sc->sc_state == MASTER)
+ return (1);
+
+ return (0);
}
#endif /* INET6 */
@@ -1334,28 +1459,14 @@ carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src)
else
ena = (u_int8_t *)&eh->ether_dhost;
- switch (iftype) {
- case IFT_ETHER:
- case IFT_FDDI:
- if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1)
- return (NULL);
- break;
- case IFT_ISO88025:
- if (ena[0] != 3 || ena[1] || ena[4] || ena[5])
- return (NULL);
- break;
- default:
- return (NULL);
- break;
- }
-
- TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list)
- if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
- (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER &&
- !bcmp(ena, vh->sc_ac.ac_enaddr,
- ETHER_ADDR_LEN))
+ TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+ if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
+ (IFF_UP|IFF_RUNNING))
+ continue;
+ if ((vh->sc_state == MASTER || vh->sc_if.if_flags & IFF_LINK0)
+ && !bcmp(ena, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
return (&vh->sc_if);
-
+ }
return (NULL);
}
@@ -1370,7 +1481,9 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype)
bcopy(dhost, &eh.ether_dhost, sizeof(eh.ether_dhost));
eh.ether_type = etype;
- if (m->m_flags & (M_BCAST|M_MCAST)) {
+ if ((ifp = 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;
@@ -1388,7 +1501,6 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype)
return (1);
}
- ifp = carp_ourether(cif, &eh, m->m_pkthdr.rcvif->if_type, 0);
if (ifp == NULL)
return (1);
@@ -1405,6 +1517,35 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype)
return (0);
}
+int
+carp_lsdrop(struct mbuf *m, sa_family_t af, u_int32_t *src, u_int32_t *dst)
+{
+ struct carp_softc *sc = m->m_pkthdr.rcvif->if_softc;
+ int match;
+ u_int32_t fold;
+
+ /*
+ * Never drop carp advertisements.
+ * XXX Bad idea to pass all broadcast / multicast traffic?
+ */
+ if (m->m_flags & (M_BCAST|M_MCAST))
+ return (0);
+
+ fold = src[0] ^ dst[0];
+#ifdef INET6
+ if (af == AF_INET6) {
+ int i;
+ for (i = 1; i < 4; i++)
+ fold ^= src[i] ^ dst[i];
+ }
+#endif
+ if (sc->sc_lscount == 0) /* just to be safe */
+ return (1);
+ match = (1 << (ntohl(fold) % sc->sc_lscount)) & sc->sc_lsmask;
+
+ return (!match);
+}
+
void
carp_master_down(void *v)
{
@@ -1627,31 +1768,45 @@ carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp)
void
carp_set_enaddr(struct carp_softc *sc)
{
- if (sc->sc_vhid == -1 || !sc->sc_carpdev) {
- bzero(&sc->sc_ac.ac_enaddr, sizeof (sc->sc_ac.ac_enaddr));
+ if (sc->sc_vhid != -1 && sc->sc_carpdev) {
/* XXX detach ipv6 link-local address? */
- } else if (sc->sc_carpdev && sc->sc_carpdev->if_type == IFT_ISO88025) {
- sc->sc_ac.ac_enaddr[0] = 3;
- sc->sc_ac.ac_enaddr[1] = 0;
- sc->sc_ac.ac_enaddr[2] = 0x40 >> (sc->sc_vhid - 1);
- sc->sc_ac.ac_enaddr[3] = 0x40000 >> (sc->sc_vhid - 1);
- sc->sc_ac.ac_enaddr[4] = 0;
- sc->sc_ac.ac_enaddr[5] = 0;
- } else {
- sc->sc_ac.ac_enaddr[0] = 0;
- sc->sc_ac.ac_enaddr[1] = 0;
- sc->sc_ac.ac_enaddr[2] = 0x5e;
- sc->sc_ac.ac_enaddr[3] = 0;
- sc->sc_ac.ac_enaddr[4] = 1;
- sc->sc_ac.ac_enaddr[5] = sc->sc_vhid;
- }
+ if (sc->sc_carpdev->if_type == IFT_ISO88025) {
+ sc->sc_carplladdr[0] = 3;
+ sc->sc_carplladdr[1] = 0;
+ sc->sc_carplladdr[2] = 0x40 >> (sc->sc_vhid - 1);
+ sc->sc_carplladdr[3] = 0x40000 >> (sc->sc_vhid - 1);
+ sc->sc_carplladdr[4] = 0;
+ sc->sc_carplladdr[5] = 0;
+ } else {
+ if (sc->sc_if.if_flags & IFF_LINK2)
+ sc->sc_carplladdr[0] = 1;
+ else
+ sc->sc_carplladdr[0] = 0;
+ sc->sc_carplladdr[1] = 0;
+ sc->sc_carplladdr[2] = 0x5e;
+ sc->sc_carplladdr[3] = 0;
+ sc->sc_carplladdr[4] = 1;
+ sc->sc_carplladdr[5] = sc->sc_vhid;
+ }
+ } else
+ bzero(&sc->sc_carplladdr, ETHER_ADDR_LEN);
- /* Make sure the enaddr has changed before further twiddling. */
- if (bcmp(&sc->sc_ac.ac_enaddr, LLADDR(sc->sc_if.if_sadl),
- sc->sc_if.if_addrlen) != 0) {
- bcopy(&sc->sc_ac.ac_enaddr,
- LLADDR(sc->sc_if.if_sadl), sc->sc_if.if_addrlen);
+ /*
+ * Use the carp lladdr if the running one isn't manually set.
+ * Only compare static parts of the lladdr.
+ */
+ if ((bcmp(sc->sc_ac.ac_enaddr + 1, sc->sc_carplladdr + 1,
+ ETHER_ADDR_LEN - 2) == 0) ||
+ (!sc->sc_ac.ac_enaddr[0] && !sc->sc_ac.ac_enaddr[1] &&
+ !sc->sc_ac.ac_enaddr[2] && !sc->sc_ac.ac_enaddr[3] &&
+ !sc->sc_ac.ac_enaddr[4] && !sc->sc_ac.ac_enaddr[5]))
+ bcopy(sc->sc_carplladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
+ /* Make sure the enaddr has changed before further twiddling. */
+ if (bcmp(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN) != 0) {
+ bcopy(sc->sc_ac.ac_enaddr, LLADDR(sc->sc_if.if_sadl),
+ ETHER_ADDR_LEN);
+ bcopy(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN);
#ifdef INET6
/*
* (re)attach a link-local address which matches
@@ -1659,6 +1814,8 @@ carp_set_enaddr(struct carp_softc *sc)
*/
in6_ifattach_linklocal(&sc->sc_if, NULL);
#endif
+ carp_set_state(sc, INIT);
+ carp_setrun(sc, 0);
}
}
@@ -1933,7 +2090,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
#endif /* INET */
#ifdef INET6
case AF_INET6:
- sc->sc_if.if_flags|= IFF_UP;
+ sc->sc_if.if_flags |= IFF_UP;
error = carp_set_addr6(sc, satosin6(ifa->ifa_addr));
break;
#endif /* INET6 */
@@ -1961,6 +2118,9 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
sc->sc_if.if_flags |= IFF_UP;
carp_setrun(sc, 0);
}
+ carp_set_enaddr(sc); /* for changes on LINK2 */
+ if (ifr->ifr_flags & IFF_LINK0)
+ carp_update_lsmask(sc);
break;
case SIOCSVH:
@@ -1989,7 +2149,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
break;
}
}
- if (carpr.carpr_vhid > 0) {
+ if (carpr.carpr_vhid > 0 && carpr.carpr_vhid != sc->sc_vhid) {
if (carpr.carpr_vhid > 255) {
error = EINVAL;
break;
@@ -2002,9 +2162,11 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
vr->sc_vhid == carpr.carpr_vhid)
return (EINVAL);
}
- sc->sc_vhid = carpr.carpr_vhid;
- carp_set_enaddr(sc);
- carp_set_state(sc, INIT);
+ if (carpr.carpr_vhid != sc->sc_vhid) {
+ sc->sc_vhid = carpr.carpr_vhid;
+ carp_set_enaddr(sc);
+ carp_set_state(sc, INIT);
+ }
error--;
}
if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) {
@@ -2060,6 +2222,8 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
error = EINVAL;
}
+ if (bcmp(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN) != 0)
+ carp_set_enaddr(sc);
carp_hmac_prepare(sc);
return (error);
}
@@ -2114,6 +2278,8 @@ carp_set_state(struct carp_softc *sc, int state)
return;
sc->sc_state = state;
+ carp_update_lsmask(sc);
+
switch (state) {
case BACKUP:
sc->sc_if.if_link_state = LINK_STATE_DOWN;
diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h
index a2d966736bf..874b96abed9 100644
--- a/sys/netinet/ip_carp.h
+++ b/sys/netinet/ip_carp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_carp.h,v 1.21 2006/06/02 19:53:12 mpf Exp $ */
+/* $OpenBSD: ip_carp.h,v 1.22 2007/03/18 23:23:17 mpf Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
@@ -159,11 +159,12 @@ void carp_group_demote_adj(struct ifnet *, int);
int carp6_proto_input(struct mbuf **, int *, int);
int carp_iamatch(struct in_ifaddr *, u_char *,
u_int32_t *, u_int32_t);
-struct ifaddr *carp_iamatch6(void *, struct in6_addr *);
+int carp_iamatch6(struct ifnet *, struct ifaddr *);
struct ifnet *carp_ourether(void *, struct ether_header *, u_char, int);
int carp_input(struct mbuf *, u_int8_t *, u_int8_t *, u_int16_t);
int carp_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
int carp_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int carp_lsdrop(struct mbuf *, sa_family_t, u_int32_t *, u_int32_t *);
#endif /* _KERNEL */
#endif /* _NETINET_IP_CARP_H_ */
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index 08861700058..ad48e0ca815 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_icmp.c,v 1.72 2007/01/03 18:39:56 claudio Exp $ */
+/* $OpenBSD: ip_icmp.c,v 1.73 2007/03/18 23:23:17 mpf Exp $ */
/* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */
/*
@@ -68,6 +68,8 @@
* Research Laboratory (NRL).
*/
+#include "carp.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
@@ -86,6 +88,11 @@
#include <netinet/ip_var.h>
#include <netinet/icmp_var.h>
+#if NCARP > 0
+#include <net/if_types.h>
+#include <netinet/ip_carp.h>
+#endif
+
/*
* ICMP routines: error generation, receive packet processing, and
* routines to turnaround packets back to the originator, and
@@ -450,6 +457,13 @@ icmp_input(struct mbuf *m, ...)
printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
#endif
icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ carp_lsdrop(m, AF_INET, &icmpsrc.sin_addr.s_addr,
+ &ip->ip_dst.s_addr))
+ goto freeit;
+#endif
/*
* XXX if the packet contains [IPv4 AH TCP], we can't make a
* notification to TCP layer.
@@ -521,6 +535,13 @@ icmp_input(struct mbuf *m, ...)
ip->ip_src = ia->ia_dstaddr.sin_addr;
}
reflect:
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr,
+ &ip->ip_dst.s_addr))
+ goto freeit;
+#endif
/* Free packet atttributes */
if (m->m_flags & M_PKTHDR)
m_tag_delete_chain(m);
@@ -563,6 +584,13 @@ reflect:
}
#endif
icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ carp_lsdrop(m, AF_INET, &icmpsrc.sin_addr.s_addr,
+ &ip->ip_dst.s_addr))
+ goto freeit;
+#endif
rt = NULL;
rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst),
(struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index deca652ad8a..af1a440c73a 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_input.c,v 1.146 2006/12/28 20:06:10 deraadt Exp $ */
+/* $OpenBSD: ip_input.c,v 1.147 2007/03/18 23:23:17 mpf Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
@@ -33,6 +33,7 @@
*/
#include "pf.h"
+#include "carp.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -65,6 +66,11 @@
#include <netinet/ip_ipsp.h>
#endif /* IPSEC */
+#if NCARP > 0
+#include <net/if_types.h>
+#include <netinet/ip_carp.h>
+#endif
+
#define IPMTUDISCTIMEOUT (10 * 60) /* as per RFC 1191 */
struct ipqhead ipq;
@@ -370,6 +376,15 @@ ipv4_input(m)
m_adj(m, len - m->m_pkthdr.len);
}
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ ip->ip_p != IPPROTO_ICMP &&
+ carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr,
+ &ip->ip_dst.s_addr))
+ goto bad;
+#endif
+
#if NPF > 0
/*
* Packet filter
@@ -462,6 +477,14 @@ ipv4_input(m)
ip->ip_dst.s_addr == INADDR_ANY)
goto ours;
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ ip->ip_p == IPPROTO_ICMP &&
+ carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr,
+ &ip->ip_dst.s_addr))
+ goto bad;
+#endif
/*
* Not for us; forward if possible and desirable.
*/
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index e16442596cb..aaa3c57f5f1 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: icmp6.c,v 1.92 2007/01/16 11:05:25 itojun Exp $ */
+/* $OpenBSD: icmp6.c,v 1.93 2007/03/18 23:23:17 mpf Exp $ */
/* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
/*
@@ -61,6 +61,9 @@
* @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
*/
+#include "faith.h"
+#include "carp.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -91,7 +94,9 @@
#include <netinet6/in6_ifattach.h>
#include <netinet6/ip6protosw.h>
-#include "faith.h"
+#if NCARP > 0
+#include <netinet/ip_carp.h>
+#endif
/* inpcb members */
#define in6pcb inpcb
@@ -474,6 +479,14 @@ icmp6_input(mp, offp, proto)
}
#endif
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ icmp6->icmp6_type == ICMP6_ECHO_REQUEST &&
+ carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32,
+ ip6->ip6_dst.s6_addr32))
+ goto freeit;
+#endif
icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
switch (icmp6->icmp6_type) {
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 71b6c4f43b3..030d2bdbfea 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_input.c,v 1.74 2006/12/28 20:08:15 deraadt Exp $ */
+/* $OpenBSD: ip6_input.c,v 1.75 2007/03/18 23:23:17 mpf Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@@ -62,6 +62,7 @@
*/
#include "pf.h"
+#include "carp.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -109,6 +110,11 @@
#include <net/pfvar.h>
#endif
+#if NCARP > 0
+#include <netinet/in_var.h>
+#include <netinet/ip_carp.h>
+#endif
+
extern struct domain inet6domain;
extern struct ip6protosw inet6sw[];
@@ -246,6 +252,14 @@ ip6_input(m)
goto bad;
}
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ ip6->ip6_nxt != IPPROTO_ICMPV6 &&
+ carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32,
+ ip6->ip6_dst.s6_addr32))
+ goto bad;
+#endif
ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
/*
@@ -523,6 +537,14 @@ ip6_input(m)
}
#endif
+#if NCARP > 0
+ if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
+ m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
+ ip6->ip6_nxt == IPPROTO_ICMPV6 &&
+ carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32,
+ ip6->ip6_dst.s6_addr32))
+ goto bad;
+#endif
/*
* Now there is no reason to process the packet if it's not our own
* and we're not a router.
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index e3a1fe72926..a5f425eef0b 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nd6_nbr.c,v 1.42 2006/11/17 01:11:23 itojun Exp $ */
+/* $OpenBSD: nd6_nbr.c,v 1.43 2007/03/18 23:23:17 mpf Exp $ */
/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
/*
@@ -193,10 +193,13 @@ nd6_ns_input(m, off, icmp6len)
*/
/* (1) and (3) check. */
#if NCARP > 0
- if (ifp->if_carp && ifp->if_type != IFT_CARP)
- ifa = carp_iamatch6(ifp->if_carp, &taddr6);
- if (!ifa)
+ if (ifp->if_type == IFT_CARP) {
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
+ if (ifa && !carp_iamatch6(ifp, ifa))
+ ifa = NULL;
+ } else {
+ ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
+ }
#else
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
#endif