]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_gif.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / bsd / net / if_gif.c
index 79bacaf4303038b9b4737dce741c01645d682f86..feb7362732c52fbea037698878ef052ed2acce40 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
-/*     $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $       */
-/*     $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
+/* $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $ */
+/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*
+ * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
+ * support for mandatory and extensible security protections.  This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ */
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -74,6 +80,9 @@
 #include <net/if_types.h>
 #include <net/route.h>
 #include <net/bpf.h>
+#include <net/kpi_protocol.h>
+#include <net/kpi_interface.h>
+#include <net/init.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 
 #include <net/net_osdep.h>
 
-#define GIFNAME                "gif"
-#define GIFDEV         "if_gif"
-#define GIF_MAXUNIT    0x7fff  /* ifp->if_unit is only 15 bits */
-
-#ifndef __APPLE__
-static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
+#if CONFIG_MACF_NET
+#include <security/mac_framework.h>
 #endif
 
-TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
+#define        GIFNAME         "gif"
+#define        GIFDEV          "if_gif"
+#define        GIF_MAXUNIT     0x7fff  /* ifp->if_unit is only 15 bits */
 
-#ifdef __APPLE__
-void gifattach(void);
-int gif_pre_output(struct ifnet *ifp, u_long protocol_family, struct mbuf **m0,
-                                  const struct sockaddr *dst, caddr_t rt, char *frame, char *address);
-static void gif_create_dev(void);
-static int gif_encapcheck(const struct mbuf*, int, int, void*);
+/* gif lock variables */
+static lck_grp_t       *gif_mtx_grp;
+static lck_grp_attr_t  *gif_mtx_grp_attr;
+static lck_attr_t      *gif_mtx_attr;
+decl_lck_mtx_data(static, gif_mtx_data);
+static lck_mtx_t       *gif_mtx = &gif_mtx_data;
 
+TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
 
-int ngif = 0;          /* number of interfaces */
-#endif
+static int gif_encapcheck(const struct mbuf *, int, int, void *);
+static errno_t gif_output(ifnet_t ifp, mbuf_t m);
+static errno_t gif_input(ifnet_t ifp, protocol_family_t protocol_family,
+    mbuf_t m, char *frame_header);
+static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data);
+
+static int ngif = 0;           /* number of interfaces */
 
 #if INET
-struct protosw in_gif_protosw =
-{ SOCK_RAW,    0,      0/*IPPROTO_IPV[46]*/,   PR_ATOMIC|PR_ADDR,
-  in_gif_input,        0,      0,              0,
-  0,
-  0,           0,      0,      0,      
-  0,
-  &rip_usrreqs,
-  0,           rip_unlock,     0
+static struct protosw in_gif_protosw =
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          0, /* IPPROTO_IPV[46] */
+       .pr_flags =             PR_ATOMIC|PR_ADDR,
+       .pr_input =             in_gif_input,
+       .pr_usrreqs =           &rip_usrreqs,
+       .pr_unlock =            rip_unlock,
 };
 #endif
 #if INET6
-struct ip6protosw in6_gif_protosw =
-{ SOCK_RAW,    0,      0/*IPPROTO_IPV[46]*/,   PR_ATOMIC|PR_ADDR,
-  in6_gif_input, 0,            0,              0,
-  0,
-  0,           0,              0,              0,
-  0,  
-  &rip6_usrreqs,
-  0,           rip_unlock,             0,
-
+static struct ip6protosw in6_gif_protosw =
+{
+       .pr_type =              SOCK_RAW,
+       .pr_protocol =          0, /* IPPROTO_IPV[46] */
+       .pr_flags =             PR_ATOMIC|PR_ADDR,
+       .pr_input =             in6_gif_input,
+       .pr_usrreqs =           &rip6_usrreqs,
+       .pr_unlock =            rip_unlock,
 };
 #endif
 
-#ifndef MAX_GIF_NEST
-/*
- * This macro controls the upper limitation on nesting of gif tunnels.
- * Since, setting a large value to this macro with a careless configuration
- * may introduce system crash, we don't allow any nestings by default.
- * If you need to configure nested gif tunnels, you can define this macro
- * in your kernel configuration file. However, if you do so, please be
- * careful to configure the tunnels so that it won't make a loop.
- */
-#define MAX_GIF_NEST 1
-#endif
-static int max_gif_nesting = MAX_GIF_NEST;
+static if_clone_t gif_cloner = NULL;
+static int gif_clone_create(struct if_clone *, uint32_t, void *);
+static int gif_clone_destroy(struct ifnet *);
+static void gif_delete_tunnel(struct gif_softc *);
+static void gif_detach(struct ifnet *);
 
-
-
-#ifdef __APPLE__
 /*
  * Theory of operation: initially, one gif interface is created.
  * Any time a gif interface is configured, if there are no other
@@ -170,185 +172,330 @@ static int max_gif_nesting = MAX_GIF_NEST;
  */
 
 /* GIF interface module support */
-int gif_demux(
-    struct ifnet *ifp,
-    struct mbuf  *m,
-    char         *frame_header,
-    u_long *protocol_family)
+static int
+gif_demux(
+       ifnet_t ifp,
+       __unused mbuf_t m,
+       __unused char *frame_header,
+       protocol_family_t *protocol_family)
 {
-       struct gif_softc* gif = (struct gif_softc*)ifp->if_softc;
-       
+       struct gif_softc *sc = ifnet_softc(ifp);
+
+       GIF_LOCK(sc);
        /* Only one protocol may be attached to a gif interface. */
-       *protocol_family = gif->gif_proto;
-       
-       return 0;
+       *protocol_family = sc->gif_proto;
+       GIF_UNLOCK(sc);
+
+       return (0);
 }
 
-static
-int  gif_add_proto(struct ifnet *ifp, u_long protocol_family, struct ddesc_head_str *desc_head)
+static errno_t
+gif_add_proto(
+       ifnet_t ifp,
+       protocol_family_t protocol_family,
+       __unused const struct ifnet_demux_desc *demux_array,
+       __unused u_int32_t demux_count)
 {
        /* Only one protocol may be attached at a time */
-       struct gif_softc* gif = (struct gif_softc*)ifp->if_softc;
+       struct gif_softc *sc = ifnet_softc(ifp);
 
-       if (gif->gif_proto != 0)
-               printf("gif_add_proto: request add_proto for gif%d\n", gif->gif_if.if_unit);
+       GIF_LOCK(sc);
+       if (sc->gif_proto != 0)
+               printf("gif_add_proto: request add_proto for gif%d\n",
+                   ifnet_unit(ifp));
 
-       gif->gif_proto = protocol_family;
+       sc->gif_proto = protocol_family;
+       GIF_UNLOCK(sc);
 
-       return 0;
+       return (0);
 }
 
-static
-int  gif_del_proto(struct ifnet *ifp, u_long protocol_family)
+static errno_t
+gif_del_proto(
+       ifnet_t ifp,
+       protocol_family_t protocol_family)
 {
-       if (((struct gif_softc*)ifp)->gif_proto == protocol_family)
-               ((struct gif_softc*)ifp)->gif_proto = 0;
-       else
-               return ENOENT;
+       struct gif_softc *sc = ifnet_softc(ifp);
+
+       GIF_LOCK(sc);
+       if (sc->gif_proto == protocol_family)
+               sc->gif_proto = 0;
+       GIF_UNLOCK(sc);
 
-       return 0;
+       return (0);
 }
 
 /* Glue code to attach inet to a gif interface through DLIL */
-int
+static errno_t
 gif_attach_proto_family(
-       struct ifnet *ifp,
-       u_long protocol_family)
+       ifnet_t ifp,
+       protocol_family_t protocol_family)
 {
-    struct dlil_proto_reg_str   reg;
-    int   stat;
-
-       bzero(&reg, sizeof(reg));
-    TAILQ_INIT(&reg.demux_desc_head);
-    reg.interface_family = ifp->if_family;
-    reg.unit_number      = ifp->if_unit;
-    reg.input            = gif_input;
-    reg.pre_output       = gif_pre_output;
-    reg.protocol_family  = protocol_family;
-
-    stat = dlil_attach_protocol(&reg);
-    if (stat && stat != EEXIST) {
-        panic("gif_attach_proto_family can't attach interface fam=%d\n", protocol_family);
-    }
-
-    return stat;
-}
+       struct ifnet_attach_proto_param reg;
+       errno_t stat;
 
-#endif
+       bzero(&reg, sizeof (reg));
+       reg.input = gif_input;
+
+       stat = ifnet_attach_protocol(ifp, protocol_family, &reg);
+       if (stat && stat != EEXIST) {
+               printf("gif_attach_proto_family can't attach interface  \
+                   fam=%d\n", protocol_family);
+       }
+
+       return (stat);
+}
 
 /* Function to setup the first gif interface */
 void
-gifattach(void)
+gif_init(void)
 {
-       int error;
+       errno_t result;
+       struct ifnet_clone_params ifnet_clone_params;
+       struct if_clone *ifc = NULL;
 
-       /* Init the list of interfaces */
+       /* Initialize the list of interfaces */
        TAILQ_INIT(&gifs);
 
+       /* Initialize the gif global lock */
+       gif_mtx_grp_attr = lck_grp_attr_alloc_init();
+       gif_mtx_grp = lck_grp_alloc_init("gif", gif_mtx_grp_attr);
+       gif_mtx_attr = lck_attr_alloc_init();
+       lck_mtx_init(gif_mtx, gif_mtx_grp, gif_mtx_attr);
+
        /* Register protocol registration functions */
-       if ( error = dlil_reg_proto_module(AF_INET, APPLE_IF_FAM_GIF, gif_attach_proto_family, NULL) != 0)
-               printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
-       
-       if ( error = dlil_reg_proto_module(AF_INET6, APPLE_IF_FAM_GIF, gif_attach_proto_family, NULL) != 0)
-               printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
+       result = proto_register_plumber(PF_INET, APPLE_IF_FAM_GIF,
+           gif_attach_proto_family, NULL);
+       if (result != 0)
+               printf("proto_register_plumber failed for AF_INET error=%d\n",
+                   result);
+
+       result = proto_register_plumber(PF_INET6, APPLE_IF_FAM_GIF,
+           gif_attach_proto_family, NULL);
+       if (result != 0)
+               printf("proto_register_plumber failed for AF_INET6 error=%d\n",
+                   result);
+
+       ifnet_clone_params.ifc_name = "gif";
+       ifnet_clone_params.ifc_create = gif_clone_create;
+       ifnet_clone_params.ifc_destroy = gif_clone_destroy;
+
+       result = ifnet_clone_attach(&ifnet_clone_params, &gif_cloner);
+       if (result != 0)
+               printf("gifattach: ifnet_clone_attach failed %d\n", result);
 
        /* Create first device */
-       gif_create_dev();
+       ifc = if_clone_lookup("gif", NULL);
+       gif_clone_create(ifc, 0, NULL);
+}
+
+static errno_t
+gif_set_bpf_tap(
+       ifnet_t ifp,
+       bpf_tap_mode mode,
+       bpf_packet_func callback)
+{
+       struct gif_softc *sc = ifnet_softc(ifp);
+
+       GIF_LOCK(sc);
+       sc->tap_mode = mode;
+       sc->tap_callback = callback;
+       GIF_UNLOCK(sc);
+
+       return (0);
 }
 
-/* Creates another gif device if there are none free */
 static void
-gif_create_dev(void)
+gif_detach(struct ifnet *ifp)
 {
-       struct gif_softc *sc;
-       
-       
+       struct gif_softc *sc = ifp->if_softc;
+       lck_mtx_destroy(&sc->gif_lock, gif_mtx_grp);
+       _FREE(ifp->if_softc, M_DEVBUF);
+       ifp->if_softc = NULL;
+       (void) ifnet_release(ifp);
+}
+
+static int
+gif_clone_create(struct if_clone *ifc, uint32_t unit, __unused void *params)
+{
+       struct gif_softc *sc = NULL;
+       struct ifnet_init_params gif_init_params;
+       errno_t error = 0;
+
+       lck_mtx_lock(gif_mtx);
+
        /* Can't create more than GIF_MAXUNIT */
-       if (ngif >= GIF_MAXUNIT)
-               return;
-       
-       /* Check for unused gif interface */
-       TAILQ_FOREACH(sc, &gifs, gif_link) {
-               /* If unused, return, no need to create a new interface */
-               if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
-                       return;
+       if (ngif >= GIF_MAXUNIT) {
+               error = ENXIO;
+               goto done;
        }
 
-       sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
+       sc = _MALLOC(sizeof (struct gif_softc), M_DEVBUF, M_WAITOK);
        if (sc == NULL) {
-               log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif);
-               return;
+               log(LOG_ERR, "gif_clone_create: failed to allocate gif%d\n",
+                   unit);
+               error = ENOBUFS;
+               goto done;
+       }
+       bzero(sc, sizeof (struct gif_softc));
+
+       /* use the interface name as the unique id for ifp recycle */
+       snprintf(sc->gif_ifname, sizeof (sc->gif_ifname), "%s%d",
+           ifc->ifc_name, unit);
+
+       lck_mtx_init(&sc->gif_lock, gif_mtx_grp, gif_mtx_attr);
+
+       bzero(&gif_init_params, sizeof (gif_init_params));
+       gif_init_params.uniqueid = sc->gif_ifname;
+       gif_init_params.uniqueid_len = strlen(sc->gif_ifname);
+       gif_init_params.name = GIFNAME;
+       gif_init_params.unit = unit;
+       gif_init_params.type = IFT_GIF;
+       gif_init_params.family = IFNET_FAMILY_GIF;
+       gif_init_params.output = gif_output;
+       gif_init_params.demux = gif_demux;
+       gif_init_params.add_proto = gif_add_proto;
+       gif_init_params.del_proto = gif_del_proto;
+       gif_init_params.softc = sc;
+       gif_init_params.ioctl = gif_ioctl;
+       gif_init_params.set_bpf_tap = gif_set_bpf_tap;
+       gif_init_params.detach = gif_detach;
+
+       error = ifnet_allocate(&gif_init_params, &sc->gif_if);
+       if (error != 0) {
+               printf("gif_clone_create, ifnet_allocate failed - %d\n", error);
+               _FREE(sc, M_DEVBUF);
+               error = ENOBUFS;
+               goto done;
        }
 
-       bzero(sc, sizeof(struct gif_softc));
-       sc->gif_if.if_softc     = sc;
-       sc->gif_if.if_name      = GIFNAME;
-       sc->gif_if.if_unit      = ngif;
-       
        sc->encap_cookie4 = sc->encap_cookie6 = NULL;
-#ifdef INET
+#if INET
        sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
-           gif_encapcheck, &in_gif_protosw, sc);
+                       gif_encapcheck, &in_gif_protosw, sc);
        if (sc->encap_cookie4 == NULL) {
-               printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
+               printf("%s: unable to attach encap4\n", if_name(sc->gif_if));
+               ifnet_release(sc->gif_if);
                FREE(sc, M_DEVBUF);
-               return;
+               error = ENOBUFS;
+               goto done;
        }
 #endif
-#ifdef INET6
+#if INET6
        sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
-           gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc);
+           gif_encapcheck, (struct protosw *)&in6_gif_protosw, sc);
        if (sc->encap_cookie6 == NULL) {
                if (sc->encap_cookie4) {
                        encap_detach(sc->encap_cookie4);
                        sc->encap_cookie4 = NULL;
                }
-               printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
+               printf("%s: unable to attach encap6\n", if_name(sc->gif_if));
+               ifnet_release(sc->gif_if);
                FREE(sc, M_DEVBUF);
-               return;
+               error = ENOBUFS;
+               goto done;
        }
 #endif
-       
        sc->gif_called = 0;
-       sc->gif_if.if_family= APPLE_IF_FAM_GIF;
-       sc->gif_if.if_mtu       = GIF_MTU;
-       sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
+       ifnet_set_mtu(sc->gif_if, GIF_MTU);
+       ifnet_set_flags(sc->gif_if, IFF_POINTOPOINT | IFF_MULTICAST, 0xffff);
 #if 0
        /* turn off ingress filter */
        sc->gif_if.if_flags  |= IFF_LINK2;
 #endif
-       sc->gif_if.if_demux = gif_demux;
-       sc->gif_if.if_ioctl     = gif_ioctl;
-       sc->gif_if.if_output = NULL;    /* pre_output returns error or EJUSTRETURN */
-       sc->gif_if.if_type   = IFT_GIF;
-       sc->gif_if.if_add_proto = gif_add_proto;
-       sc->gif_if.if_del_proto = gif_del_proto;
-       dlil_if_attach(&sc->gif_if);
-       bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
+       error = ifnet_attach(sc->gif_if, NULL);
+       if (error != 0) {
+               printf("gif_clone_create - ifnet_attach failed - %d\n", error);
+               ifnet_release(sc->gif_if);
+               if (sc->encap_cookie4) {
+                       encap_detach(sc->encap_cookie4);
+                       sc->encap_cookie4 = NULL;
+               }
+               if (sc->encap_cookie6) {
+                       encap_detach(sc->encap_cookie6);
+                       sc->encap_cookie6 = NULL;
+               }
+               FREE(sc, M_DEVBUF);
+               goto done;
+       }
+#if CONFIG_MACF_NET
+       mac_ifnet_label_init(&sc->gif_if);
+#endif
+       bpfattach(sc->gif_if, DLT_NULL, sizeof (u_int));
        TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
        ngif++;
+done:
+       lck_mtx_unlock(gif_mtx);
+
+       return (error);
 }
 
 static int
-gif_encapcheck(m, off, proto, arg)
-       const struct mbuf *m;
-       int off;
-       int proto;
-       void *arg;
+gif_clone_destroy(struct ifnet *ifp)
 {
+#if defined(INET) || defined(INET6)
+       int error = 0;
+#endif
+       struct gif_softc *sc = ifp->if_softc;
+
+       lck_mtx_lock(gif_mtx);
+       TAILQ_REMOVE(&gifs, sc, gif_link);
+       ngif--;
+
+       GIF_LOCK(sc);
+       gif_delete_tunnel(sc);
+#ifdef INET6
+       if (sc->encap_cookie6 != NULL) {
+               error = encap_detach(sc->encap_cookie6);
+               KASSERT(error == 0, ("gif_clone_destroy: Unexpected     \
+                   error detaching encap_cookie6"));
+       }
+#endif
+#ifdef INET
+       if (sc->encap_cookie4 != NULL) {
+               error = encap_detach(sc->encap_cookie4);
+               KASSERT(error == 0, ("gif_clone_destroy: Unexpected     \
+                   error detaching encap_cookie4"));
+       }
+#endif
+       error = ifnet_set_flags(ifp, 0, IFF_UP);
+       if (error != 0) {
+               printf("gif_clone_destroy: ifnet_set_flags failed %d\n", error);
+       }
+
+       error = ifnet_detach(ifp);
+       if (error != 0)
+               panic("gif_clone_destroy: ifnet_detach(%p) failed %d\n", ifp,
+                   error);
+
+       GIF_UNLOCK(sc);
+       lck_mtx_unlock(gif_mtx);
+
+       return (0);
+}
+
+static int
+gif_encapcheck(
+       const struct mbuf *m,
+       int off,
+       int proto,
+       void *arg)
+{
+       int error = 0;
        struct ip ip;
        struct gif_softc *sc;
 
        sc = (struct gif_softc *)arg;
        if (sc == NULL)
-               return 0;
+               return (error);
 
-       if ((sc->gif_if.if_flags & IFF_UP) == 0)
-               return 0;
+       GIF_LOCK(sc);
+       if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0)
+               goto done;
 
        /* no physical address */
        if (!sc->gif_psrc || !sc->gif_pdst)
-               return 0;
+               goto done;
 
        switch (proto) {
 #if INET
@@ -360,90 +507,66 @@ gif_encapcheck(m, off, proto, arg)
                break;
 #endif
        default:
-               return 0;
+               goto done;
        }
 
-       /* LINTED const cast */
-       m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
+       mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof (ip), &ip);
 
        switch (ip.ip_v) {
 #if INET
        case 4:
                if (sc->gif_psrc->sa_family != AF_INET ||
                    sc->gif_pdst->sa_family != AF_INET)
-                       return 0;
-               return gif_encapcheck4(m, off, proto, arg);
+                       goto done;
+               error = gif_encapcheck4(m, off, proto, arg);
 #endif
 #if INET6
        case 6:
                if (sc->gif_psrc->sa_family != AF_INET6 ||
                    sc->gif_pdst->sa_family != AF_INET6)
-                       return 0;
-               return gif_encapcheck6(m, off, proto, arg);
+                       goto done;
+               error = gif_encapcheck6(m, off, proto, arg);
 #endif
        default:
-               return 0;
+               goto done;
        }
+done:
+       GIF_UNLOCK(sc);
+       return (error);
 }
 
-int
-gif_pre_output(
-       struct ifnet *ifp,
-       u_long protocol_family,
-       struct mbuf **m0,
-       const struct sockaddr *dst,
-       caddr_t rt,
-       char *frame,
-       char *address)
+static errno_t
+gif_output(
+       ifnet_t ifp,
+       mbuf_t m)
 {
-       struct gif_softc *sc = (struct gif_softc*)ifp;
-       register struct mbuf * m = *m0;
+       struct gif_softc *sc = ifnet_softc(ifp);
+       struct sockaddr *gif_psrc;
+       struct sockaddr *gif_pdst;
        int error = 0;
-       
+
+       GIF_LOCK(sc);
+       gif_psrc = sc->gif_psrc;
+       gif_pdst = sc->gif_pdst;
+       GIF_UNLOCK(sc);
+
        /*
-        * gif may cause infinite recursion calls when misconfigured.
-        * We'll prevent this by introducing upper limit.
-        * XXX: this mechanism may introduce another problem about
-        *      mutual exclusion of the variable CALLED, especially if we
-        *      use kernel thread.
+        * max_gif_nesting check used to live here. It doesn't anymore
+        * because there is no guaruntee that we won't be called
+        * concurrently from more than one thread.
         */
-       if (++sc->gif_called > max_gif_nesting) {
-               log(LOG_NOTICE,
-                   "gif_output: recursively called too many times(%d)\n",
-                   sc->gif_called);
-               m_freem(m);     /* free it here not in dlil_output*/
-               error = EIO;    /* is there better errno? */
-               goto end;
-       }
-
-       ifnet_touch_lastchange(ifp);
        m->m_flags &= ~(M_BCAST|M_MCAST);
-       if (!(ifp->if_flags & IFF_UP) ||
-           sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+       if (!(ifnet_flags(ifp) & IFF_UP) ||
+           gif_psrc == NULL || gif_pdst == NULL) {
+               ifnet_touch_lastchange(ifp);
                m_freem(m);     /* free it here not in dlil_output */
                error = ENETDOWN;
                goto end;
        }
 
-       if (ifp->if_bpf) {
-               /*
-                * We need to prepend the address family as
-                * a four byte field.  Cons up a dummy header
-                * to pacify bpf.  This is safe because bpf
-                * will only read from the mbuf (i.e., it won't
-                * try to free it or keep a pointer a to it).
-                */
-               struct mbuf m0;
-               u_int32_t protocol_family = dst->sa_family;
-
-               m0.m_next = m;
-               m0.m_len = 4;
-               m0.m_data = (char *)&protocol_family;
-               
-               bpf_mtap(ifp, &m0);
-       }
-       ifp->if_opackets++;     
-       ifp->if_obytes += m->m_pkthdr.len;
+       bpf_tap_out(ifp, 0, m, &sc->gif_proto, sizeof (sc->gif_proto));
+
+       GIF_LOCK(sc);
 
        /* inner AF-specific encapsulation */
 
@@ -453,66 +576,45 @@ gif_pre_output(
        switch (sc->gif_psrc->sa_family) {
 #if INET
        case AF_INET:
-               error = in_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
+               error = in_gif_output(ifp, sc->gif_proto, m, NULL);
                break;
 #endif
 #if INET6
        case AF_INET6:
-               error = in6_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
+               error = in6_gif_output(ifp, sc->gif_proto, m, NULL);
                break;
 #endif
        default:
                error = ENETDOWN;
-               goto end;
+               break;
        }
 
-  end:
-       sc->gif_called = 0;             /* reset recursion counter */
+       GIF_UNLOCK(sc);
+end:        
        if (error) {
                /* the mbuf was freed either by in_gif_output or in here */
-               *m0 = NULL; /* avoid getting dlil_output freeing it */
-               ifp->if_oerrors++;
+               ifnet_stat_increment_out(ifp, 0, 0, 1);
+       } else {
+               ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
        }
-       if (error == 0) 
+       if (error == 0)
                error = EJUSTRETURN; /* if no error, packet got sent already */
-       return error;
+       return (error);
 }
 
-int
+/*
+ * gif_input is the input handler for IP and IPv6 attached to gif
+ */
+static errno_t
 gif_input(
-       struct mbuf *m,
-       char* frame_header,
-       struct ifnet* gifp,
-       u_long protocol_family,
-       int sync_ok)
+       ifnet_t ifp,
+       protocol_family_t protocol_family,
+       mbuf_t m,
+       __unused char *frame_header)
 {
+       struct gif_softc *sc = ifnet_softc(ifp);
 
-       if (gifp == NULL) {
-               /* just in case */
-               m_freem(m);
-               return;
-       }
-
-       if (m->m_pkthdr.rcvif)
-               m->m_pkthdr.rcvif = gifp;
-       
-       if (gifp->if_bpf) {
-               /*
-                * We need to prepend the address family as
-                * a four byte field.  Cons up a dummy header
-                * to pacify bpf.  This is safe because bpf
-                * will only read from the mbuf (i.e., it won't
-                * try to free it or keep a pointer a to it).
-                */
-               struct mbuf m0;
-               u_int32_t protocol_family1 = protocol_family;
-               
-               m0.m_next = m;
-               m0.m_len = 4;
-               m0.m_data = (char *)&protocol_family1;
-               
-               bpf_mtap(gifp, &m0);
-       }
+       bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof (sc->gif_proto));
 
        /*
         * Put the packet to the network layer input queue according to the
@@ -526,33 +628,34 @@ gif_input(
         * it occurs more times than we thought, we may change the policy
         * again.
         */
-       proto_input(protocol_family, m);
-       gifp->if_ipackets++;
-       gifp->if_ibytes += m->m_pkthdr.len;
+       if (proto_input(protocol_family, m) != 0) {
+               ifnet_stat_increment_in(ifp, 0, 0, 1);
+               m_freem(m);
+       } else
+               ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0);
 
        return (0);
 }
 
 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
-int
-gif_ioctl(ifp, cmd, data)
-       struct ifnet *ifp;
-       u_long cmd;
-       void* data;
+static errno_t
+gif_ioctl(
+       ifnet_t                 ifp,
+       u_long                  cmd,
+       void                    *data)
 {
-       struct gif_softc *sc  = (struct gif_softc*)ifp;
-       struct ifreq     *ifr = (struct ifreq*)data;
+       struct gif_softc *sc  = ifnet_softc(ifp);
+       struct ifreq *ifr = (struct ifreq *)data;
        int error = 0, size;
-       struct sockaddr *dst, *src;
+       struct sockaddr *dst = NULL, *src = NULL;
        struct sockaddr *sa;
-       int s;
        struct ifnet *ifp2;
        struct gif_softc *sc2;
-               
+
        switch (cmd) {
        case SIOCSIFADDR:
                break;
-               
+
        case SIOCSIFDSTADDR:
                break;
 
@@ -566,19 +669,20 @@ gif_ioctl(ifp, cmd, data)
 
        case SIOCSIFMTU:
                {
-                       u_long mtu;
+                       u_int32_t mtu;
                        mtu = ifr->ifr_mtu;
                        if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
                                return (EINVAL);
                        }
-                       ifp->if_mtu = mtu;
+                       ifnet_set_mtu(ifp, mtu);
                }
                break;
 #endif /* SIOCSIFMTU */
 
        case SIOCSIFPHYADDR:
 #if INET6
-       case SIOCSIFPHYADDR_IN6:
+       case SIOCSIFPHYADDR_IN6_32:
+       case SIOCSIFPHYADDR_IN6_64:
 #endif /* INET6 */
        case SIOCSLIFPHYADDR:
                switch (cmd) {
@@ -591,12 +695,23 @@ gif_ioctl(ifp, cmd, data)
                        break;
 #endif
 #if INET6
-               case SIOCSIFPHYADDR_IN6:
-                       src = (struct sockaddr *)
-                               &(((struct in6_aliasreq *)data)->ifra_addr);
-                       dst = (struct sockaddr *)
-                               &(((struct in6_aliasreq *)data)->ifra_dstaddr);
+               case SIOCSIFPHYADDR_IN6_32: {
+                       struct in6_aliasreq_32 *ifra_32 =
+                           (struct in6_aliasreq_32 *)data;
+
+                       src = (struct sockaddr *)&ifra_32->ifra_addr;
+                       dst = (struct sockaddr *)&ifra_32->ifra_dstaddr;
+                       break;
+               }
+
+               case SIOCSIFPHYADDR_IN6_64: {
+                       struct in6_aliasreq_64 *ifra_64 =
+                           (struct in6_aliasreq_64 *)data;
+
+                       src = (struct sockaddr *)&ifra_64->ifra_addr;
+                       dst = (struct sockaddr *)&ifra_64->ifra_dstaddr;
                        break;
+               }
 #endif
                case SIOCSLIFPHYADDR:
                        src = (struct sockaddr *)
@@ -607,40 +722,40 @@ gif_ioctl(ifp, cmd, data)
 
                /* sa_family must be equal */
                if (src->sa_family != dst->sa_family)
-                       return EINVAL;
+                       return (EINVAL);
 
                /* validate sa_len */
                switch (src->sa_family) {
 #if INET
                case AF_INET:
-                       if (src->sa_len != sizeof(struct sockaddr_in))
-                               return EINVAL;
+                       if (src->sa_len != sizeof (struct sockaddr_in))
+                               return (EINVAL);
                        break;
 #endif
 #if INET6
                case AF_INET6:
-                       if (src->sa_len != sizeof(struct sockaddr_in6))
-                               return EINVAL;
+                       if (src->sa_len != sizeof (struct sockaddr_in6))
+                               return (EINVAL);
                        break;
 #endif
                default:
-                       return EAFNOSUPPORT;
+                       return (EAFNOSUPPORT);
                }
                switch (dst->sa_family) {
 #if INET
                case AF_INET:
-                       if (dst->sa_len != sizeof(struct sockaddr_in))
-                               return EINVAL;
+                       if (dst->sa_len != sizeof (struct sockaddr_in))
+                               return (EINVAL);
                        break;
 #endif
 #if INET6
                case AF_INET6:
-                       if (dst->sa_len != sizeof(struct sockaddr_in6))
-                               return EINVAL;
+                       if (dst->sa_len != sizeof (struct sockaddr_in6))
+                               return (EINVAL);
                        break;
 #endif
                default:
-                       return EAFNOSUPPORT;
+                       return (EAFNOSUPPORT);
                }
 
                /* check sa_family looks sane for the cmd */
@@ -648,36 +763,62 @@ gif_ioctl(ifp, cmd, data)
                case SIOCSIFPHYADDR:
                        if (src->sa_family == AF_INET)
                                break;
-                       return EAFNOSUPPORT;
+                       return (EAFNOSUPPORT);
 #if INET6
-               case SIOCSIFPHYADDR_IN6:
+               case SIOCSIFPHYADDR_IN6_32:
+               case SIOCSIFPHYADDR_IN6_64:
                        if (src->sa_family == AF_INET6)
                                break;
-                       return EAFNOSUPPORT;
+                       return (EAFNOSUPPORT);
 #endif /* INET6 */
                case SIOCSLIFPHYADDR:
                        /* checks done in the above */
                        break;
                }
 
+#define        GIF_ORDERED_LOCK(sc, sc2)       \
+       if (sc < sc2) {                 \
+               GIF_LOCK(sc);           \
+               GIF_LOCK(sc2);          \
+       } else {                        \
+               GIF_LOCK(sc2);          \
+               GIF_LOCK(sc);           \
+       }
+
+#define        GIF_ORDERED_UNLOCK(sc, sc2)     \
+       if (sc > sc2) {                 \
+               GIF_UNLOCK(sc);         \
+               GIF_UNLOCK(sc2);        \
+       } else {                        \
+               GIF_UNLOCK(sc2);        \
+               GIF_UNLOCK(sc);         \
+       }
+
                ifnet_head_lock_shared();
                TAILQ_FOREACH(ifp2, &ifnet_head, if_link) {
-                       if (strcmp(ifp2->if_name, GIFNAME) != 0)
+                       if (strcmp(ifnet_name(ifp2), GIFNAME) != 0)
                                continue;
-                       sc2 = ifp2->if_softc;
+                       sc2 = ifnet_softc(ifp2);
                        if (sc2 == sc)
                                continue;
-                       if (!sc2->gif_pdst || !sc2->gif_psrc)
+                       /* lock sc and sc2 in increasing order of ifnet index */
+                       GIF_ORDERED_LOCK(sc, sc2);
+                       if (!sc2->gif_pdst || !sc2->gif_psrc) {
+                               GIF_ORDERED_UNLOCK(sc, sc2);
                                continue;
+                       }
                        if (sc2->gif_pdst->sa_family != dst->sa_family ||
                            sc2->gif_pdst->sa_len != dst->sa_len ||
                            sc2->gif_psrc->sa_family != src->sa_family ||
-                           sc2->gif_psrc->sa_len != src->sa_len)
+                           sc2->gif_psrc->sa_len != src->sa_len) {
+                               GIF_ORDERED_UNLOCK(sc, sc2);
                                continue;
+                       }
 #ifndef XBONEHACK
                        /* can't configure same pair of address onto two gifs */
                        if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
                            bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
+                               GIF_ORDERED_UNLOCK(sc, sc2);
                                error = EADDRNOTAVAIL;
                                ifnet_head_done();
                                goto bad;
@@ -685,14 +826,16 @@ gif_ioctl(ifp, cmd, data)
 #endif
 
                        /* can't configure multiple multi-dest interfaces */
-#define multidest(x) \
-       (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
+#define        multidest(x) \
+       (((struct sockaddr_in *)(void *)(x))->sin_addr.s_addr == INADDR_ANY)
 #if INET6
-#define multidest6(x) \
-       (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
+#define        multidest6(x) \
+       (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)      \
+           (void *)(x))->sin6_addr))
 #endif
                        if (dst->sa_family == AF_INET &&
                            multidest(dst) && multidest(sc2->gif_pdst)) {
+                               GIF_ORDERED_UNLOCK(sc, sc2);
                                error = EADDRNOTAVAIL;
                                ifnet_head_done();
                                goto bad;
@@ -700,41 +843,49 @@ gif_ioctl(ifp, cmd, data)
 #if INET6
                        if (dst->sa_family == AF_INET6 &&
                            multidest6(dst) && multidest6(sc2->gif_pdst)) {
+                               GIF_ORDERED_UNLOCK(sc, sc2);
                                error = EADDRNOTAVAIL;
                                ifnet_head_done();
                                goto bad;
                        }
 #endif
+                       GIF_ORDERED_UNLOCK(sc, sc2);
                }
                ifnet_head_done();
 
+               GIF_LOCK(sc);
                if (sc->gif_psrc)
                        FREE((caddr_t)sc->gif_psrc, M_IFADDR);
-               sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK);
+               sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR,
+                   M_WAITOK);
+               if (sa == NULL) {
+                       GIF_UNLOCK(sc);
+                       return (ENOBUFS);
+               }
                bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
                sc->gif_psrc = sa;
 
                if (sc->gif_pdst)
                        FREE((caddr_t)sc->gif_pdst, M_IFADDR);
-               sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK);
+               sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR,
+                   M_WAITOK);
+               if (sa == NULL) {
+                       GIF_UNLOCK(sc);
+                       return (ENOBUFS);
+               }
                bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
                sc->gif_pdst = sa;
+               GIF_UNLOCK(sc);
 
-               ifp->if_flags |= IFF_RUNNING;
-
-               s = splimp();
-               if_up(ifp);     /* mark interface UP and send up RTM_IFINFO */
-#ifdef __APPLE__
-               /* Make sure at least one unused device is still available */
-               gif_create_dev();
-#endif
-               splx(s);
+               ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING |
+                   IFF_UP);
 
                error = 0;
                break;
 
 #ifdef SIOCDIFPHYADDR
        case SIOCDIFPHYADDR:
+               GIF_LOCK(sc);
                if (sc->gif_psrc) {
                        FREE((caddr_t)sc->gif_psrc, M_IFADDR);
                        sc->gif_psrc = NULL;
@@ -743,15 +894,18 @@ gif_ioctl(ifp, cmd, data)
                        FREE((caddr_t)sc->gif_pdst, M_IFADDR);
                        sc->gif_pdst = NULL;
                }
+               GIF_UNLOCK(sc);
                /* change the IFF_{UP, RUNNING} flag as well? */
                break;
 #endif
-                       
+
        case SIOCGIFPSRCADDR:
 #if INET6
        case SIOCGIFPSRCADDR_IN6:
 #endif /* INET6 */
+               GIF_LOCK(sc);
                if (sc->gif_psrc == NULL) {
+                       GIF_UNLOCK(sc);
                        error = EADDRNOTAVAIL;
                        goto bad;
                }
@@ -760,30 +914,36 @@ gif_ioctl(ifp, cmd, data)
 #if INET
                case SIOCGIFPSRCADDR:
                        dst = &ifr->ifr_addr;
-                       size = sizeof(ifr->ifr_addr);
+                       size = sizeof (ifr->ifr_addr);
                        break;
 #endif /* INET */
 #if INET6
                case SIOCGIFPSRCADDR_IN6:
                        dst = (struct sockaddr *)
                                &(((struct in6_ifreq *)data)->ifr_addr);
-                       size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
+                       size = sizeof (((struct in6_ifreq *)data)->ifr_addr);
                        break;
 #endif /* INET6 */
                default:
+                       GIF_UNLOCK(sc);
                        error = EADDRNOTAVAIL;
                        goto bad;
                }
-               if (src->sa_len > size)
-                       return EINVAL;
+               if (src->sa_len > size) {
+                       GIF_UNLOCK(sc);
+                       return (EINVAL);
+               }
                bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
+               GIF_UNLOCK(sc);
                break;
-                       
+
        case SIOCGIFPDSTADDR:
 #if INET6
        case SIOCGIFPDSTADDR_IN6:
 #endif /* INET6 */
+               GIF_LOCK(sc);
                if (sc->gif_pdst == NULL) {
+                       GIF_UNLOCK(sc);
                        error = EADDRNOTAVAIL;
                        goto bad;
                }
@@ -792,27 +952,33 @@ gif_ioctl(ifp, cmd, data)
 #if INET
                case SIOCGIFPDSTADDR:
                        dst = &ifr->ifr_addr;
-                       size = sizeof(ifr->ifr_addr);
+                       size = sizeof (ifr->ifr_addr);
                        break;
 #endif /* INET */
 #if INET6
                case SIOCGIFPDSTADDR_IN6:
                        dst = (struct sockaddr *)
                                &(((struct in6_ifreq *)data)->ifr_addr);
-                       size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
+                       size = sizeof (((struct in6_ifreq *)data)->ifr_addr);
                        break;
 #endif /* INET6 */
                default:
                        error = EADDRNOTAVAIL;
+                       GIF_UNLOCK(sc);
                        goto bad;
                }
-               if (src->sa_len > size)
-                       return EINVAL;
+               if (src->sa_len > size) {
+                       GIF_UNLOCK(sc);
+                       return (EINVAL);
+               }
                bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
+               GIF_UNLOCK(sc);
                break;
 
        case SIOCGLIFPHYADDR:
+               GIF_LOCK(sc);
                if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+                       GIF_UNLOCK(sc);
                        error = EADDRNOTAVAIL;
                        goto bad;
                }
@@ -821,19 +987,24 @@ gif_ioctl(ifp, cmd, data)
                src = sc->gif_psrc;
                dst = (struct sockaddr *)
                        &(((struct if_laddrreq *)data)->addr);
-               size = sizeof(((struct if_laddrreq *)data)->addr);
-               if (src->sa_len > size)
-                       return EINVAL;
+               size = sizeof (((struct if_laddrreq *)data)->addr);
+               if (src->sa_len > size) {
+                       GIF_UNLOCK(sc);
+                       return (EINVAL);
+               }
                bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
 
                /* copy dst */
                src = sc->gif_pdst;
                dst = (struct sockaddr *)
                        &(((struct if_laddrreq *)data)->dstaddr);
-               size = sizeof(((struct if_laddrreq *)data)->dstaddr);
-               if (src->sa_len > size)
-                       return EINVAL;
+               size = sizeof (((struct if_laddrreq *)data)->dstaddr);
+               if (src->sa_len > size) {
+                       GIF_UNLOCK(sc);
+                       return (EINVAL);
+               }
                bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
+               GIF_UNLOCK(sc);
                break;
 
        case SIOCSIFFLAGS:
@@ -844,18 +1015,14 @@ gif_ioctl(ifp, cmd, data)
                error = EOPNOTSUPP;
                break;
        }
- bad:
-       return error;
+bad:
+       return (error);
 }
 
-#ifndef __APPLE__
-/* This function is not used in our stack */
-void
-gif_delete_tunnel(sc)
-       struct gif_softc *sc;
+static void
+gif_delete_tunnel(struct gif_softc *sc)
 {
-       /* XXX: NetBSD protects this function with splsoftnet() */
-
+       GIF_LOCK_ASSERT(sc);
        if (sc->gif_psrc) {
                FREE((caddr_t)sc->gif_psrc, M_IFADDR);
                sc->gif_psrc = NULL;
@@ -864,6 +1031,6 @@ gif_delete_tunnel(sc)
                FREE((caddr_t)sc->gif_pdst, M_IFADDR);
                sc->gif_pdst = NULL;
        }
+       ROUTE_RELEASE(&sc->gif_ro);
        /* change the IFF_UP flag as well? */
 }
-#endif