summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2007-03-19 17:52:15 +0000
committerbms <bms@FreeBSD.org>2007-03-19 17:52:15 +0000
commit21bccff9b0f1abeba3cdaab4d86f884e98e79f8d (patch)
tree6beac89d7a981d409c246d34397f105bcfd6e420 /sys
parentb5f0c3495e2dcd41e0c98a429a4f3f2396d9aef9 (diff)
downloadFreeBSD-src-21bccff9b0f1abeba3cdaab4d86f884e98e79f8d.zip
FreeBSD-src-21bccff9b0f1abeba3cdaab4d86f884e98e79f8d.tar.gz
Teach pfsync(4) that its member interfaces may go away.
This change partially resolves the issue in the PR. Further architectural fixes, in the form of reference counting, are needed. PR: 86848 Reviewed by: yar MFC after: 1 month
Diffstat (limited to 'sys')
-rw-r--r--sys/contrib/pf/net/if_pfsync.c49
-rw-r--r--sys/contrib/pf/net/if_pfsync.h1
2 files changed, 50 insertions, 0 deletions
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c
index 24687de..fa35ad6 100644
--- a/sys/contrib/pf/net/if_pfsync.c
+++ b/sys/contrib/pf/net/if_pfsync.c
@@ -170,6 +170,9 @@ void pfsync_timeout(void *);
void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
void pfsync_bulk_update(void *);
void pfsync_bulkfail(void *);
+#ifdef __FreeBSD__
+static void pfsync_ifdetach(void *, struct ifnet *);
+#endif
int pfsync_sync_ok;
#ifndef __FreeBSD__
@@ -191,6 +194,9 @@ pfsync_clone_destroy(struct ifnet *ifp)
struct pfsync_softc *sc;
sc = ifp->if_softc;
+#ifdef __FreeBSD__
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag);
+#endif
callout_stop(&sc->sc_tmo);
callout_stop(&sc->sc_bulk_tmo);
callout_stop(&sc->sc_bulkfail_tmo);
@@ -225,6 +231,16 @@ pfsync_clone_create(struct if_clone *ifc, int unit)
return (ENOSPC);
}
+#ifdef __FreeBSD__
+ sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
+ pfsync_ifdetach, sc, EVENTHANDLER_PRI_ANY);
+ if (sc->sc_detachtag == NULL) {
+ if_free(ifp);
+ free(sc, M_PFSYNC);
+ return (ENOSPC);
+ }
+#endif
+
pfsync_sync_ok = 1;
sc->sc_mbuf = NULL;
sc->sc_mbuf_net = NULL;
@@ -1870,6 +1886,33 @@ pfsync_sendout(sc)
#ifdef __FreeBSD__
static void
+pfsync_ifdetach(void *arg, struct ifnet *ifp)
+{
+ struct pfsync_softc *sc = (struct pfsync_softc *)arg;
+ struct ip_moptions *imo;
+
+ if (sc == NULL || sc->sc_sync_ifp != ifp)
+ return; /* not for us; unlocked read */
+
+ PF_LOCK();
+
+ /* Deal with a member interface going away from under us. */
+ sc->sc_sync_ifp = NULL;
+ if (sc->sc_mbuf_net != NULL) {
+ m_freem(sc->sc_mbuf_net);
+ sc->sc_mbuf_net = NULL;
+ sc->sc_statep_net.s = NULL;
+ }
+ imo = &sc->sc_imo;
+ if (imo->imo_num_memberships > 0) {
+ in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
+ imo->imo_multicast_ifp = NULL;
+ }
+
+ PF_UNLOCK();
+}
+
+static void
pfsync_senddef(void *arg)
{
struct pfsync_softc *sc = (struct pfsync_softc *)arg;
@@ -1879,6 +1922,12 @@ pfsync_senddef(void *arg)
IF_DEQUEUE(&sc->sc_ifq, m);
if (m == NULL)
break;
+ /* Deal with a member interface going away from under us. */
+ if (sc->sc_sync_ifp == NULL) {
+ pfsyncstats.pfsyncs_oerrors++;
+ m_freem(m);
+ continue;
+ }
if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
pfsyncstats.pfsyncs_oerrors++;
}
diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h
index f9df354..77ef3a5 100644
--- a/sys/contrib/pf/net/if_pfsync.h
+++ b/sys/contrib/pf/net/if_pfsync.h
@@ -181,6 +181,7 @@ struct pfsync_softc {
int sc_maxupdates; /* number of updates/state */
#ifdef __FreeBSD__
LIST_ENTRY(pfsync_softc) sc_next;
+ eventhandler_tag sc_detachtag;
#endif
};
#endif
OpenPOWER on IntegriCloud