Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 14 Jun 2012 21:36:17 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r237104 - in stable/8/sys: net netinet
Message-ID:  <201206142136.q5ELaHv8022348@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Thu Jun 14 21:36:16 2012
New Revision: 237104
URL: http://svn.freebsd.org/changeset/base/237104

Log:
  MFC r236916
  
   Fix a panic I introduced in r234487, the bridge softc pointer is set to null
   early in the detach so rearrange things not to explode.
  
  Reported by:	David Roffiaen, Gustau Perez Querol

Modified:
  stable/8/sys/net/if_bridge.c
  stable/8/sys/netinet/ip_carp.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/sys/net/if_bridge.c
==============================================================================
--- stable/8/sys/net/if_bridge.c	Thu Jun 14 21:35:20 2012	(r237103)
+++ stable/8/sys/net/if_bridge.c	Thu Jun 14 21:36:16 2012	(r237104)
@@ -334,6 +334,7 @@ static int	bridge_ip6_checkbasic(struct 
 static int	bridge_fragment(struct ifnet *, struct mbuf *,
 		    struct ether_header *, int, struct llc *);
 static void	bridge_linkstate(struct ifnet *ifp);
+static void	bridge_linkcheck(struct bridge_softc *sc);
 
 extern void (*bridge_linkstate_p)(struct ifnet *ifp);
 
@@ -964,6 +965,7 @@ bridge_delete_member(struct bridge_softc
 		EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
 	}
 
+	bridge_linkcheck(sc);
 	bridge_mutecaps(sc);	/* recalcuate now this interface is removed */
 	bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
 	KASSERT(bif->bif_addrcnt == 0,
@@ -993,7 +995,6 @@ bridge_delete_member(struct bridge_softc
 		bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
 	}
 	bstp_destroy(&bif->bif_stp);	/* prepare to free */
-	bridge_linkstate(ifs);
 	BRIDGE_LOCK(sc);
 	free(bif, M_DEVBUF);
 }
@@ -1092,18 +1093,17 @@ bridge_ioctl_add(struct bridge_softc *sc
 
 	/* Set interface capabilities to the intersection set of all members */
 	bridge_mutecaps(sc);
+	bridge_linkcheck(sc);
 
-	BRIDGE_UNLOCK(sc);
-	/* Update the linkstate for the bridge */
-	bridge_linkstate(ifs);
 	/* Place the interface into promiscuous mode */
 	switch (ifs->if_type) {
 		case IFT_ETHER:
 		case IFT_L2VLAN:
+			BRIDGE_UNLOCK(sc);
 			error = ifpromisc(ifs, 1);
+			BRIDGE_LOCK(sc);
 			break;
 	}
-	BRIDGE_LOCK(sc);
 	if (error)
 		bridge_delete_member(sc, bif, 0);
 out:
@@ -3485,8 +3485,7 @@ static void
 bridge_linkstate(struct ifnet *ifp)
 {
 	struct bridge_softc *sc = ifp->if_bridge;
-	struct bridge_iflist *bif, *bif2;
-	int new_link, hasls;
+	struct bridge_iflist *bif;
 
 	BRIDGE_LOCK(sc);
 	bif = bridge_lookup_member_if(sc, ifp);
@@ -3494,13 +3493,26 @@ bridge_linkstate(struct ifnet *ifp)
 		BRIDGE_UNLOCK(sc);
 		return;
 	}
+	bridge_linkcheck(sc);
+	BRIDGE_UNLOCK(sc);
+
+	bstp_linkstate(&bif->bif_stp);
+}
+
+static void
+bridge_linkcheck(struct bridge_softc *sc)
+{
+	struct bridge_iflist *bif;
+	int new_link, hasls;
+
+	BRIDGE_LOCK_ASSERT(sc);
 	new_link = LINK_STATE_DOWN;
 	hasls = 0;
 	/* Our link is considered up if at least one of our ports is active */
-	LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
-		if (bif2->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
+	LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+		if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
 			hasls++;
-		if (bif2->bif_ifp->if_link_state == LINK_STATE_UP) {
+		if (bif->bif_ifp->if_link_state == LINK_STATE_UP) {
 			new_link = LINK_STATE_UP;
 			break;
 		}
@@ -3510,8 +3522,4 @@ bridge_linkstate(struct ifnet *ifp)
 		new_link = LINK_STATE_UP;
 	}
 	if_link_state_change(sc->sc_ifp, new_link);
-	BRIDGE_UNLOCK(sc);
-
-	bstp_linkstate(&bif->bif_stp);
 }
-

Modified: stable/8/sys/netinet/ip_carp.c
==============================================================================
--- stable/8/sys/netinet/ip_carp.c	Thu Jun 14 21:35:20 2012	(r237103)
+++ stable/8/sys/netinet/ip_carp.c	Thu Jun 14 21:36:16 2012	(r237104)
@@ -100,6 +100,7 @@ struct carp_softc {
 #ifdef INET6
 	struct in6_ifaddr 	*sc_ia6;	/* primary iface address v6 */
 	struct ip6_moptions 	 sc_im6o;
+	struct in6_ifaddr	*sc_llia;
 #endif /* INET6 */
 	TAILQ_ENTRY(carp_softc)	 sc_list;
 
@@ -1239,6 +1240,16 @@ carp_iamatch6(struct ifnet *ifp, struct 
 	cif = ifp->if_carp;
 	CARP_LOCK(cif);
 	TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
+		if (IN6_ARE_ADDR_EQUAL(taddr,
+			    &vh->sc_llia->ia_addr.sin6_addr) &&
+		    (SC2IFP(vh)->if_flags & IFF_UP) &&
+		    (SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING) &&
+		    vh->sc_state == MASTER) {
+			ifa = &vh->sc_llia->ia_addr;
+			ifa_ref(ifa);
+			CARP_UNLOCK(cif);
+			return (ifa);
+		}
 		IF_ADDR_RLOCK(SC2IFP(vh));
 		TAILQ_FOREACH(ifa, &SC2IFP(vh)->if_addrlist, ifa_list) {
 			if (IN6_ARE_ADDR_EQUAL(taddr,
@@ -1270,6 +1281,28 @@ carp_macmatch6(struct ifnet *ifp, struct
 	cif = ifp->if_carp;
 	CARP_LOCK(cif);
 	TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
+		if (IN6_ARE_ADDR_EQUAL(taddr,
+			    sc->sc_llia->ia_addr.sin6_addr) &&
+		    (SC2IFP(sc)->if_flags & IFF_UP) &&
+		    (SC2IFP(sc)->if_drv_flags & IFF_DRV_RUNNING) &&
+		    sc->sc_state == MASTER) {
+			struct ifnet *ifp = SC2IFP(sc);
+			mtag = m_tag_get(PACKET_TAG_CARP,
+			    sizeof(struct ifnet *), M_NOWAIT);
+			if (mtag == NULL) {
+				/* better a bit than nothing */
+				IF_ADDR_RUNLOCK(SC2IFP(sc));
+				CARP_UNLOCK(cif);
+				return (IF_LLADDR(sc->sc_ifp));
+			}
+			bcopy(&ifp, (caddr_t)(mtag + 1),
+			    sizeof(struct ifnet *));
+			m_tag_prepend(m, mtag);
+
+			IF_ADDR_RUNLOCK(SC2IFP(sc));
+			CARP_UNLOCK(cif);
+			return (IF_LLADDR(sc->sc_ifp));
+		}
 		IF_ADDR_RLOCK(SC2IFP(sc));
 		TAILQ_FOREACH(ifa, &SC2IFP(sc)->if_addrlist, ifa_list) {
 			if (IN6_ARE_ADDR_EQUAL(taddr,
@@ -1749,6 +1782,33 @@ carp_set_addr6(struct carp_softc *sc, st
 			goto cleanup;
 		im6o->im6o_membership[1] = in6m;
 		im6o->im6o_num_memberships++;
+
+		/* Add link local */
+		bzero(&ifra, sizeof(ifra));
+		ifra.ifra_addr.sin6_family = AF_INET6;
+		ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
+		ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000);
+		ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
+		if ((error = in6_get_hw_ifid(sc->sc_ifp, NULL, &ifra.ifra_addr.sin6_addr)) != 0)
+			goto cleanup;
+		if ((error = in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)))
+			goto cleanup;
+		ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
+		ifra.ifra_prefixmask.sin6_family = AF_INET6;
+		ifra.ifra_prefixmask.sin6_addr = in6mask64;
+		/* link-local addresses should NEVER expire. */
+		ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+		ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+
+		if ((error = in6_update_ifa(ifp, &ifra, NULL,
+				    IN6_IFAUPDATE_DADDELAY)) != 0)
+			goto cleanup;
+		sc->sc_llia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
+		if (sc->sc_llia == NULL) {
+			error = ESRCH;
+			goto cleanup;
+		}
+		ifa_free(&sc->sc_llia->ia_ifa);
 	}
 
 	if (!ifp->if_carp) {



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