]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_pflog.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / net / if_pflog.c
index 278a7b19897a5c8a161827cf0b503ab197e555e6..e1c0c84ca5aa0b851829521e0d11358c4747baf0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2018 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 /*     $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $      */
 /*
  * The authors of this code are John Ioannidis (ji@tla.org),
- * Angelos D. Keromytis (kermit@csd.uch.gr) and 
+ * Angelos D. Keromytis (kermit@csd.uch.gr) and
  * Niels Provos (provos@physnet.uni-hamburg.de).
  *
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
  * in November 1995.
  *
  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
@@ -49,7 +49,7 @@
  * Permission to use, copy, and modify this software with or without fee
  * is hereby granted, provided that this entire notice is included in
  * all copies of any software which is or includes a copy or
- * modification of this software. 
+ * modification of this software.
  * You may use this code under the GNU public license if you so wish. Please
  * contribute changes back to the authors under this freer than GPL license
  * so that we may further the use of strong encryption without limitations to
 #include <sys/proc_internal.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
+#include <sys/mcache.h>
+
+#include <kern/zalloc.h>
 
 #include <net/if.h>
+#include <net/if_var.h>
 #include <net/if_types.h>
 #include <net/route.h>
 #include <net/bpf.h>
 #include <netinet/ip.h>
 #endif
 
-#if INET6
 #if !INET
 #include <netinet/in.h>
 #endif
 #include <netinet6/nd6.h>
-#endif /* INET6 */
 
 #include <net/pfvar.h>
 #include <net/if_pflog.h>
 
-#define        PFLOGNAME       "pflog"
-#define PFLOGMTU       (32768 + MHLEN + MLEN)
+#define PFLOGNAME       "pflog"
+#define PFLOGMTU        (32768 + MHLEN + MLEN)
 
 #ifdef PFLOGDEBUG
 #define DPRINTF(x)    do { if (pflogdebug) printf x ; } while (0)
 #define DPRINTF(x)
 #endif
 
-static int pflog_create_dev(void);
+static int pflog_remove(struct ifnet *);
+static int pflog_clone_create(struct if_clone *, u_int32_t, void *);
+static int pflog_clone_destroy(struct ifnet *);
 static errno_t pflogoutput(struct ifnet *, struct mbuf *);
 static errno_t pflogioctl(struct ifnet *, unsigned long, void *);
 static errno_t pflogdemux(struct ifnet *, struct mbuf *, char *,
@@ -108,61 +112,53 @@ static errno_t pflogdemux(struct ifnet *, struct mbuf *, char *,
 static errno_t pflogaddproto(struct ifnet *, protocol_family_t,
     const struct ifnet_demux_desc *, u_int32_t);
 static errno_t pflogdelproto(struct ifnet *, protocol_family_t);
+static void pflogfree(struct ifnet *);
 
-static LIST_HEAD(, pflog_softc)        pflogif_list;
+static LIST_HEAD(, pflog_softc) pflogif_list;
+static struct if_clone pflog_cloner =
+    IF_CLONE_INITIALIZER(PFLOGNAME, pflog_clone_create, pflog_clone_destroy,
+    0, (PFLOGIFS_MAX - 1), PFLOGIF_ZONE_MAX_ELEM, sizeof(struct pflog_softc));
 
-struct ifnet *pflogifs[PFLOGIFS_MAX];  /* for fast access */
-static int npflog;
-static lck_attr_t *pflog_lock_attr;
-static lck_grp_t *pflog_lock_grp;
-static lck_grp_attr_t *pflog_lock_grp_attr;
-static lck_mtx_t *pflog_lock;
+struct ifnet *pflogifs[PFLOGIFS_MAX];   /* for fast access */
 
 void
 pfloginit(void)
 {
        int i;
 
-       if (pflog_lock != NULL)
-               return;
-
-       pflog_lock_grp_attr = lck_grp_attr_alloc_init();
-       pflog_lock_grp = lck_grp_alloc_init("pflog", pflog_lock_grp_attr);
-       pflog_lock_attr = lck_attr_alloc_init();
-       pflog_lock = lck_mtx_alloc_init(pflog_lock_grp, pflog_lock_attr);
-       if (pflog_lock == NULL) {
-               panic("%s: unable to allocate lock", __func__);
-               /* NOTREACHED */
-       }
        LIST_INIT(&pflogif_list);
-       for (i = 0; i < PFLOGIFS_MAX; i++)
+       for (i = 0; i < PFLOGIFS_MAX; i++) {
                pflogifs[i] = NULL;
+       }
 
-       pflog_create_dev();
+       (void) if_clone_attach(&pflog_cloner);
 }
 
 static int
-pflog_create_dev(void)
+pflog_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params)
 {
        struct pflog_softc *pflogif;
-       struct ifnet_init_params pf_init;
+       struct ifnet_init_eparams pf_init;
        int error = 0;
 
-       lck_mtx_lock(pflog_lock);
-       if (npflog >= PFLOGIFS_MAX) {
-               error = EINVAL;
-               goto done;
+       if (unit >= PFLOGIFS_MAX) {
+               /* Either the interface cloner or our initializer is broken */
+               panic("%s: unit (%d) exceeds max (%d)", __func__, unit,
+                   PFLOGIFS_MAX);
+               /* NOTREACHED */
        }
 
-       if ((pflogif = _MALLOC(sizeof (*pflogif),
-           M_DEVBUF, M_WAITOK|M_ZERO)) == NULL) {
+       if ((pflogif = if_clone_softc_allocate(&pflog_cloner)) == NULL) {
                error = ENOMEM;
                goto done;
        }
 
-       bzero(&pf_init, sizeof (pf_init));
-       pf_init.name = PFLOGNAME;
-       pf_init.unit = npflog;
+       bzero(&pf_init, sizeof(pf_init));
+       pf_init.ver = IFNET_INIT_CURRENT_VERSION;
+       pf_init.len = sizeof(pf_init);
+       pf_init.flags = IFNET_INIT_LEGACY;
+       pf_init.name = ifc->ifc_name;
+       pf_init.unit = unit;
        pf_init.type = IFT_PFLOG;
        pf_init.family = IFNET_FAMILY_LOOPBACK;
        pf_init.output = pflogoutput;
@@ -171,14 +167,16 @@ pflog_create_dev(void)
        pf_init.del_proto = pflogdelproto;
        pf_init.softc = pflogif;
        pf_init.ioctl = pflogioctl;
+       pf_init.detach = pflogfree;
 
-       bzero(pflogif, sizeof (*pflogif));
-       pflogif->sc_unit = npflog;
+       bzero(pflogif, sizeof(*pflogif));
+       pflogif->sc_unit = unit;
+       pflogif->sc_flags |= IFPFLF_DETACHING;
 
-       error = ifnet_allocate(&pf_init, &pflogif->sc_if);
+       error = ifnet_allocate_extended(&pf_init, &pflogif->sc_if);
        if (error != 0) {
                printf("%s: ifnet_allocate failed - %d\n", __func__, error);
-               _FREE(pflogif, M_DEVBUF);
+               if_clone_softc_deallocate(&pflog_cloner, pflogif);
                goto done;
        }
 
@@ -189,7 +187,7 @@ pflog_create_dev(void)
        if (error != 0) {
                printf("%s: ifnet_attach failed - %d\n", __func__, error);
                ifnet_release(pflogif->sc_if);
-               _FREE(pflogif, M_DEVBUF);
+               if_clone_softc_deallocate(&pflog_cloner, pflogif);
                goto done;
        }
 
@@ -197,42 +195,62 @@ pflog_create_dev(void)
        bpfattach(pflogif->sc_if, DLT_PFLOG, PFLOG_HDRLEN);
 #endif
 
+       lck_rw_lock_shared(pf_perim_lock);
+       lck_mtx_lock(pf_lock);
        LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
-       pflogifs[npflog] = pflogif->sc_if;
-       ++npflog;
-done:
-       lck_mtx_unlock(pflog_lock);
+       pflogifs[unit] = pflogif->sc_if;
+       pflogif->sc_flags &= ~IFPFLF_DETACHING;
+       lck_mtx_unlock(pf_lock);
+       lck_rw_done(pf_perim_lock);
 
-       return (error);
+done:
+       return error;
 }
 
-#if 0
-int
-pflog_destroy_dev(struct ifnet *ifp)
+static int
+pflog_remove(struct ifnet *ifp)
 {
-       struct pflog_softc      *pflogif = ifp->if_softc;
+       int error = 0;
+       struct pflog_softc *pflogif = NULL;
 
-       lck_mtx_lock(pflog_lock);
-       pflogifs[pflogif->sc_unit] = NULL;
+       lck_rw_lock_shared(pf_perim_lock);
+       lck_mtx_lock(pf_lock);
+       pflogif = ifp->if_softc;
+
+       if (pflogif == NULL ||
+           (pflogif->sc_flags & IFPFLF_DETACHING) != 0) {
+               error = EINVAL;
+               goto done;
+       }
+
+       pflogif->sc_flags |= IFPFLF_DETACHING;
        LIST_REMOVE(pflogif, sc_list);
-       lck_mtx_unlock(pflog_lock);
+done:
+       lck_mtx_unlock(pf_lock);
+       lck_rw_done(pf_perim_lock);
+       return error;
+}
 
-#if NBPFILTER > 0
-       bpfdetach(ifp);
-#endif
-       if_detach(ifp);
-       _FREE(pflogif, M_DEVBUF);
-       return (0);
+static int
+pflog_clone_destroy(struct ifnet *ifp)
+{
+       int error = 0;
+
+       if ((error = pflog_remove(ifp)) != 0) {
+               goto done;
+       }
+       /* bpfdetach() is taken care of as part of interface detach */
+       (void)ifnet_detach(ifp);
+done:
+       return error;
 }
-#endif
 
 static errno_t
 pflogoutput(struct ifnet *ifp, struct mbuf *m)
 {
-       printf("%s: freeing data for %s%d\n", __func__, ifp->if_name,
-           ifp->if_unit);
+       printf("%s: freeing data for %s\n", __func__, if_name(ifp));
        m_freem(m);
-       return (ENOTSUP);
+       return ENOTSUP;
 }
 
 static errno_t
@@ -244,26 +262,26 @@ pflogioctl(struct ifnet *ifp, unsigned long cmd, void *data)
        case SIOCAIFADDR:
        case SIOCSIFDSTADDR:
        case SIOCSIFFLAGS:
-               if (ifnet_flags(ifp) & IFF_UP)
+               if (ifnet_flags(ifp) & IFF_UP) {
                        ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
-               else
+               } else {
                        ifnet_set_flags(ifp, 0, IFF_RUNNING);
+               }
                break;
        default:
-               return (ENOTTY);
+               return ENOTTY;
        }
 
-       return (0);
+       return 0;
 }
 
 static errno_t
 pflogdemux(struct ifnet *ifp, struct mbuf *m, char *h, protocol_family_t *ppf)
 {
 #pragma unused(h, ppf)
-       printf("%s: freeing data for %s%d\n", __func__, ifp->if_name,
-           ifp->if_unit);
+       printf("%s: freeing data for %s\n", __func__, if_name(ifp));
        m_freem(m);
-       return (EJUSTRETURN);
+       return EJUSTRETURN;
 }
 
 static errno_t
@@ -271,39 +289,55 @@ pflogaddproto(struct ifnet *ifp, protocol_family_t pf,
     const struct ifnet_demux_desc *d, u_int32_t cnt)
 {
 #pragma unused(ifp, pf, d, cnt)
-       return (0);
+       return 0;
 }
 
 static errno_t
 pflogdelproto(struct ifnet *ifp, protocol_family_t pf)
 {
 #pragma unused(ifp, pf)
-       return (0);
+       return 0;
+}
+
+static void
+pflogfree(struct ifnet *ifp)
+{
+       if_clone_softc_deallocate(&pflog_cloner, ifp->if_softc);
+       ifp->if_softc = NULL;
+       (void) ifnet_release(ifp);
 }
 
 int
-pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
+pflog_packet(struct pfi_kif *kif, pbuf_t *pbuf, sa_family_t af, u_int8_t dir,
     u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
     struct pf_ruleset *ruleset, struct pf_pdesc *pd)
 {
 #if NBPFILTER > 0
        struct ifnet *ifn;
        struct pfloghdr hdr;
+       struct mbuf *m;
 
-       if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
-               return (-1);
+       LCK_MTX_ASSERT(pf_lock, LCK_MTX_ASSERT_OWNED);
+
+       if (kif == NULL || !pbuf_is_valid(pbuf) || rm == NULL || pd == NULL) {
+               return -1;
+       }
 
        if (rm->logif >= PFLOGIFS_MAX ||
            (ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) {
-               return (0);
+               return 0;
+       }
+
+       if ((m = pbuf_to_mbuf(pbuf, FALSE)) == NULL) {
+               return 0;
        }
 
-       bzero(&hdr, sizeof (hdr));
+       bzero(&hdr, sizeof(hdr));
        hdr.length = PFLOG_REAL_HDRLEN;
        hdr.af = af;
        hdr.action = rm->action;
        hdr.reason = reason;
-       memcpy(hdr.ifname, kif->pfik_name, sizeof (hdr.ifname));
+       memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
 
        if (am == NULL) {
                hdr.rulenr = htonl(rm->nr);
@@ -311,12 +345,14 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
        } else {
                hdr.rulenr = htonl(am->nr);
                hdr.subrulenr = htonl(rm->nr);
-               if (ruleset != NULL && ruleset->anchor != NULL)
+               if (ruleset != NULL && ruleset->anchor != NULL) {
                        strlcpy(hdr.ruleset, ruleset->anchor->name,
-                           sizeof (hdr.ruleset));
+                           sizeof(hdr.ruleset));
+               }
        }
-       if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
+       if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) {
                pd->lookup.done = pf_socket_lookup(dir, pd);
+       }
        if (pd->lookup.done > 0) {
                hdr.uid = pd->lookup.uid;
                hdr.pid = pd->lookup.pid;
@@ -338,8 +374,8 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
        }
 #endif /* INET */
 
-       ifn->if_opackets++;
-       ifn->if_obytes += m->m_pkthdr.len;
+       atomic_add_64(&ifn->if_opackets, 1);
+       atomic_add_64(&ifn->if_obytes, m->m_pkthdr.len);
 
        switch (dir) {
        case PF_IN:
@@ -354,5 +390,5 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
                break;
        }
 #endif /* NBPFILTER > 0 */
-       return (0);
+       return 0;
 }