]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_gif.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / net / if_gif.c
index d21d77d40290562957fc85b3dc5754f39d23d391..1381fc6fd597376599f1e7fc79b44a0fde964583 100644 (file)
@@ -1,14 +1,19 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @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
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * 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
@@ -18,7 +23,7 @@
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @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 $ */
  * 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>
@@ -69,6 +80,8 @@
 #include <net/if_types.h>
 #include <net/route.h>
 #include <net/bpf.h>
+#include <net/kpi_protocol.h>
+#include <net/kpi_interface.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 
 #include <net/net_osdep.h>
 
+#if CONFIG_MACF_NET
+#include <security/mac_framework.h>
+#endif
+
 #define GIFNAME                "gif"
 #define GIFDEV         "if_gif"
 #define GIF_MAXUNIT    0x7fff  /* ifp->if_unit is only 15 bits */
@@ -105,11 +122,12 @@ TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
 
 #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*);
-
+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_int32_t cmd, void *data);
 
 int ngif = 0;          /* number of interfaces */
 #endif
@@ -122,7 +140,7 @@ struct protosw in_gif_protosw =
   0,           0,      0,      0,      
   0,
   &rip_usrreqs,
-  0,           rip_unlock,     0
+  0,           rip_unlock,     0, {0, 0}, 0, {0}
 };
 #endif
 #if INET6
@@ -133,26 +151,11 @@ struct ip6protosw in6_gif_protosw =
   0,           0,              0,              0,
   0,  
   &rip6_usrreqs,
-  0,           rip_unlock,             0,
+  0,           rip_unlock,             0, {0, 0}, 0, {0}
 
 };
 #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;
-
-
-
 #ifdef __APPLE__
 /*
  * Theory of operation: initially, one gif interface is created.
@@ -165,65 +168,63 @@ 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;
-       
        /* Only one protocol may be attached to a gif interface. */
-       *protocol_family = gif->gif_proto;
+       *protocol_family = ((struct gif_softc*)ifnet_softc(ifp))->gif_proto;
        
        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* gif = ifnet_softc(ifp);
 
        if (gif->gif_proto != 0)
-               printf("gif_add_proto: request add_proto for gif%d\n", gif->gif_if.if_unit);
+               printf("gif_add_proto: request add_proto for gif%d\n", ifnet_unit(ifp));
 
        gif->gif_proto = protocol_family;
 
        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;
-
+       if (((struct gif_softc*)ifnet_softc(ifp))->gif_proto == protocol_family)
+               ((struct gif_softc*)ifnet_softc(ifp))->gif_proto = 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;
+    struct ifnet_attach_proto_param    reg;
+    errno_t                                                    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);
+    stat = ifnet_attach_protocol(ifp, protocol_family, &reg);
     if (stat && stat != EEXIST) {
-        panic("gif_attach_proto_family can't attach interface fam=%d\n", protocol_family);
+        printf("gif_attach_proto_family can't attach interface fam=%d\n",
+                  protocol_family);
     }
 
     return stat;
@@ -232,30 +233,50 @@ gif_attach_proto_family(
 #endif
 
 /* Function to setup the first gif interface */
-void
+__private_extern__ void
 gifattach(void)
 {
-       int error;
+       errno_t result;
 
        /* Init the list of interfaces */
        TAILQ_INIT(&gifs);
 
        /* 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);
+       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);
        
-       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_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);
 
        /* Create first device */
        gif_create_dev();
 }
 
+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);
+       
+       sc->tap_mode = mode;
+       sc->tap_callback = callback;
+       
+       return 0;
+}
+
 /* Creates another gif device if there are none free */
 static void
 gif_create_dev(void)
 {
-       struct gif_softc *sc;
+       struct gif_softc                        *sc;
+       struct ifnet_init_params        gif_init;
+       errno_t                                         result = 0;
        
        
        /* Can't create more than GIF_MAXUNIT */
@@ -265,7 +286,7 @@ gif_create_dev(void)
        /* 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)
+               if ((ifnet_flags(sc->gif_if) & IFF_RUNNING) == 0)
                        return;
        }
 
@@ -274,23 +295,39 @@ gif_create_dev(void)
                log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif);
                return;
        }
+       
+       bzero(&gif_init, sizeof(gif_init));
+       gif_init.name = GIFNAME;
+       gif_init.unit = ngif;
+       gif_init.type = IFT_GIF;
+       gif_init.family = IFNET_FAMILY_GIF;
+       gif_init.output = gif_output;
+       gif_init.demux = gif_demux;
+       gif_init.add_proto = gif_add_proto;
+       gif_init.del_proto = gif_del_proto;
+       gif_init.softc = sc;
+       gif_init.ioctl = gif_ioctl;
+       gif_init.set_bpf_tap = gif_set_bpf_tap;
 
        bzero(sc, sizeof(struct gif_softc));
-       sc->gif_if.if_softc     = sc;
-       sc->gif_if.if_name      = GIFNAME;
-       sc->gif_if.if_unit      = ngif;
-       
+       result = ifnet_allocate(&gif_init, &sc->gif_if);
+       if (result != 0) {
+               printf("gif_create_dev, ifnet_allocate failed - %d\n", result);
+               _FREE(sc, M_DEVBUF);
+               return;
+       }
        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);
        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;
        }
 #endif
-#ifdef INET6
+#if INET6
        sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
            gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc);
        if (sc->encap_cookie6 == NULL) {
@@ -298,38 +335,40 @@ gif_create_dev(void)
                        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;
        }
 #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));
+       result = ifnet_attach(sc->gif_if, NULL);
+       if (result != 0) {
+               printf("gif_create_dev - ifnet_attach failed - %d\n", result);
+               ifnet_release(sc->gif_if);
+               FREE(sc, M_DEVBUF);
+               return;
+       }
+#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++;
 }
 
 static int
-gif_encapcheck(m, off, proto, arg)
-       const struct mbuf *m;
-       int off;
-       int proto;
-       void *arg;
+gif_encapcheck(
+       const struct mbuf *m,
+       int off,
+       int proto,
+       void *arg)
 {
        struct ip ip;
        struct gif_softc *sc;
@@ -338,7 +377,7 @@ gif_encapcheck(m, off, proto, arg)
        if (sc == NULL)
                return 0;
 
-       if ((sc->gif_if.if_flags & IFF_UP) == 0)
+       if ((ifnet_flags(sc->gif_if) & IFF_UP) == 0)
                return 0;
 
        /* no physical address */
@@ -358,8 +397,7 @@ gif_encapcheck(m, off, proto, arg)
                return 0;
        }
 
-       /* LINTED const cast */
-       m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
+       mbuf_copydata(m, 0, sizeof(ip), &ip);
 
        switch (ip.ip_v) {
 #if INET
@@ -381,65 +419,31 @@ gif_encapcheck(m, off, proto, arg)
        }
 }
 
-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);
        int error = 0;
        
        /*
-        * 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) ||
+       if (!(ifnet_flags(ifp) & IFF_UP) ||
            sc->gif_psrc == NULL || sc->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));
+       
        /* inner AF-specific encapsulation */
 
        /* XXX should we check if our outer source is legal? */
@@ -448,12 +452,12 @@ 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:
@@ -462,52 +466,32 @@ gif_pre_output(
        }
 
   end:
-       sc->gif_called = 0;             /* reset recursion counter */
        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) 
                error = EJUSTRETURN; /* if no error, packet got sent already */
        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)
 {
-
-       if (gifp == NULL) {
-               /* just in case */
-               m_freem(m);
-               return;
-       }
-
-       if (m->m_pkthdr.rcvif)
-               m->m_pkthdr.rcvif = gifp;
+       errno_t error;
+       struct gif_softc *sc = ifnet_softc(ifp);
        
-       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
@@ -521,26 +505,24 @@ 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;
+       error = proto_input(protocol_family, m);
+       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_int32_t               cmd,
+       void                    *data)
 {
-       struct gif_softc *sc  = (struct gif_softc*)ifp;
+       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;
                
@@ -566,7 +548,7 @@ gif_ioctl(ifp, cmd, data)
                        if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
                                return (EINVAL);
                        }
-                       ifp->if_mtu = mtu;
+                       ifnet_set_mtu(ifp, mtu);
                }
                break;
 #endif /* SIOCSIFMTU */
@@ -657,9 +639,9 @@ gif_ioctl(ifp, cmd, data)
 
                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)
@@ -715,15 +697,12 @@ gif_ioctl(ifp, cmd, data)
                bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
                sc->gif_pdst = sa;
 
-               ifp->if_flags |= IFF_RUNNING;
-
-               s = splimp();
-               if_up(ifp);     /* mark interface UP and send up RTM_IFINFO */
+               ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING | IFF_UP);
+               
 #ifdef __APPLE__
                /* Make sure at least one unused device is still available */
                gif_create_dev();
 #endif
-               splx(s);
 
                error = 0;
                break;