]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/ether_if_module.c
xnu-517.3.15.tar.gz
[apple/xnu.git] / bsd / net / ether_if_module.c
index 86ea43d32463693ccf653a772e494e10508847c9..126f377dbf7937a67085fb3683cc8be2734ea822 100644 (file)
@@ -3,19 +3,22 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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.
+ * 
+ * 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,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * 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_LICENSE_HEADER_END@
  */
@@ -71,6 +74,7 @@
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <netinet/if_ether.h>
+#include <netinet/in.h>        /* For M_LOOP */
 
 /*
 #if INET
 */
 
 #include <sys/socketvar.h>
+#include <net/if_vlan_var.h>
 
 #include <net/dlil.h>
 
+extern int  vlan_demux(struct ifnet * ifp, struct mbuf *, 
+                      char * frame_header, struct if_proto * * proto);
 
 #if LLC && CCITT
 extern struct ifqueue pkintrq;
@@ -103,13 +110,7 @@ extern struct ifqueue atalkintrq;
 #include <net/bridge.h>
 #endif
 
-/* #include "vlan.h" */
-#if NVLAN > 0
-#include <net/if_vlan_var.h>
-#endif /* NVLAN > 0 */
-
 static u_long lo_dlt = 0;
-static ivedonethis = 0;
 
 #define IFP2AC(IFP) ((struct arpcom *)IFP)
 
@@ -136,13 +137,17 @@ struct ether_desc_blk_str {
 static struct ether_desc_blk_str ether_desc_blk[MAX_INTERFACES];
 
 
+/* from if_ethersubr.c */
+int ether_resolvemulti __P((struct ifnet *, struct sockaddr **,
+                                    struct sockaddr *));
+
 /*
  * Release all descriptor entries owned by this dl_tag (there may be several).
  * Setting the type to 0 releases the entry. Eventually we should compact-out
  * the unused entries.
  */
-static
-int  ether_del_proto(struct if_proto *proto, u_long dl_tag)
+__private_extern__ int
+ether_del_proto(struct if_proto *proto, u_long dl_tag)
 {
     struct en_desc*    ed = ether_desc_blk[proto->ifp->family_cookie].block_ptr;
     u_long     current = 0;
@@ -165,7 +170,8 @@ int  ether_del_proto(struct if_proto *proto, u_long dl_tag)
 
 
 
-static int
+
+__private_extern__ int
 ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
 {
    char *current_ptr;
@@ -213,7 +219,6 @@ ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long
                 return EINVAL;
         }
     
-    restart:
         ed = ether_desc_blk[proto->ifp->family_cookie].block_ptr;
         
         /* Find a free entry */
@@ -241,6 +246,7 @@ ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long
             FREE(ether_desc_blk[proto->ifp->family_cookie].block_ptr, M_IFADDR);
             ether_desc_blk[proto->ifp->family_cookie].n_count = new_count;
             ether_desc_blk[proto->ifp->family_cookie].block_ptr = (struct en_desc*)tmp;
+           ed = ether_desc_blk[proto->ifp->family_cookie].block_ptr;
         }
         
         /* Bump n_max_used if appropriate */
@@ -249,7 +255,7 @@ ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long
         }
         
         ed[i].proto    = proto;
-        ed[i].data[0]  = 0;
+        ed[i].data[0] = 0;
         ed[i].data[1] = 0;
         
         switch (desc->type) {
@@ -291,7 +297,7 @@ ether_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long
             case DLIL_DESC_SNAP: {
                 u_int8_t*      pDest = ((u_int8_t*)&ed[i].data[0]) + 3;
                 ed[i].type = DLIL_DESC_SNAP;
-                bcopy(&desc->native_type, pDest, 5);
+                bcopy(desc->native_type, pDest, 5);
             }
             break;
         }
@@ -317,6 +323,7 @@ int ether_demux(ifp, m, frame_header, proto)
 {
     register struct ether_header *eh = (struct ether_header *)frame_header;
     u_short                    ether_type = eh->ether_type;
+    u_short                    ether_type_host;
     u_int16_t          type;
     u_int8_t           *data;
     u_long                     i = 0;
@@ -332,16 +339,37 @@ int ether_demux(ifp, m, frame_header, proto)
             m->m_flags |= M_BCAST;
         else
             m->m_flags |= M_MCAST;
-    }
+    } else {
+        /*
+         * When the driver is put into promiscuous mode we may receive unicast
+         * frames that are not intended for our interfaces.  They are filtered
+         * here to keep them from traveling further up the stack to code that
+         * is not expecting them or prepared to deal with them.  In the near
+         * future, the filtering done here will be moved even further down the
+         * stack into the IONetworkingFamily, preventing even interface
+         * filter NKE's from receiving promiscuous packets.  Please use BPF.
+         */
+        #define ETHER_CMP(x, y) ( ((u_int16_t *) x)[0] != ((u_int16_t *) y)[0] || \
+                                  ((u_int16_t *) x)[1] != ((u_int16_t *) y)[1] || \
+                                  ((u_int16_t *) x)[2] != ((u_int16_t *) y)[2] )
     
+        if (ETHER_CMP(eh->ether_dhost, ((struct arpcom *) ifp)->ac_enaddr)) {
+            m_freem(m);
+            return EJUSTRETURN;
+        }
+    }
+    ether_type_host = ntohs(ether_type);
+    if ((m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID)
+       || ether_type_host == ETHERTYPE_VLAN) {
+       return (vlan_demux(ifp, m, frame_header, proto));
+    }
     data = mtod(m, u_int8_t*);
-    
+
     /*
      * Determine the packet's protocol type and stuff the protocol into
      * longs for quick compares.
      */
-    
-    if (ntohs(ether_type) < 1500) {
+    if (ether_type_host <= 1500) {
         extProto1 = *(u_int32_t*)data;
         
         // SAP or SNAP
@@ -393,7 +421,7 @@ int ether_demux(ifp, m, frame_header, proto)
     }
     
     return ENOENT;
-}                      
+}
 
 
 
@@ -413,7 +441,7 @@ ether_frameout(ifp, m, ndest, edst, ether_type)
        char                    *ether_type;
 {
        register struct ether_header *eh;
-       int hlen;       /* link layer header lenght */
+       int hlen;       /* link layer header length */
        struct arpcom *ac = IFP2AC(ifp);
 
 
@@ -471,14 +499,17 @@ ether_frameout(ifp, m, ndest, edst, ether_type)
 }
 
 
-static
-int  ether_add_if(struct ifnet *ifp)
+
+__private_extern__ int
+ether_add_if(struct ifnet *ifp)
 {
     u_long  i;
 
     ifp->if_framer = ether_frameout;
     ifp->if_demux  = ether_demux;
     ifp->if_event  = 0;
+    ifp->if_resolvemulti = ether_resolvemulti;
+    ifp->if_nvlans = 0;
 
     for (i=0; i < MAX_INTERFACES; i++)
         if (ether_desc_blk[i].n_count == 0)
@@ -500,8 +531,8 @@ int  ether_add_if(struct ifnet *ifp)
     return 0;
 }
 
-static
-int  ether_del_if(struct ifnet *ifp)
+__private_extern__ int
+ether_del_if(struct ifnet *ifp)
 {
     if ((ifp->family_cookie < MAX_INTERFACES) &&
         (ether_desc_blk[ifp->family_cookie].n_count))
@@ -516,6 +547,24 @@ int  ether_del_if(struct ifnet *ifp)
         return ENOENT;
 }
 
+__private_extern__ int
+ether_init_if(struct ifnet *ifp)
+{
+    register struct ifaddr *ifa;
+    register struct sockaddr_dl *sdl;
+
+    ifa = ifnet_addrs[ifp->if_index - 1];
+    if (ifa == 0) {
+            printf("ether_ifattach: no lladdr!\n");
+            return (EINVAL);
+    }
+    sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+    sdl->sdl_type = IFT_ETHER;
+    sdl->sdl_alen = ifp->if_addrlen;
+    bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
+
+    return 0;
+}
 
 
 int
@@ -566,18 +615,24 @@ ether_ifmod_ioctl(ifp, command, data)
 }
 
 
+extern int ether_attach_inet(struct ifnet *ifp, u_long *dl_tag);
+extern int ether_detach_inet(struct ifnet *ifp, u_long dl_tag);
+extern int ether_attach_inet6(struct ifnet *ifp, u_long *dl_tag);
+extern int ether_detach_inet6(struct ifnet *ifp, u_long dl_tag);
 int ether_family_init()
 {
-    int  i;
+    int  i, error=0;
     struct dlil_ifmod_reg_str  ifmod_reg;
+    struct dlil_protomod_reg_str enet_protoreg;
+    extern int vlan_family_init(void);
 
-    if (ivedonethis)
-        return 0;
-
-    ivedonethis = 1;
+    /* ethernet family is built-in, called from bsd_init */
+    thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
 
+    bzero(&ifmod_reg, sizeof(ifmod_reg));
     ifmod_reg.add_if = ether_add_if;
     ifmod_reg.del_if = ether_del_if;
+    ifmod_reg.init_if = ether_init_if;
     ifmod_reg.add_proto = ether_add_proto;
     ifmod_reg.del_proto = ether_del_proto;
     ifmod_reg.ifmod_ioctl = ether_ifmod_ioctl;
@@ -585,11 +640,33 @@ int ether_family_init()
 
     if (dlil_reg_if_modules(APPLE_IF_FAM_ETHERNET, &ifmod_reg)) {
         printf("WARNING: ether_family_init -- Can't register if family modules\n");
-        return EIO;
+        error = EIO;
+       goto done;
     }
 
-    for (i=0; i < MAX_INTERFACES; i++)
-        ether_desc_blk[i].n_count = 0;
 
-    return 0;
+    /* Register protocol registration functions */
+    
+    bzero(&enet_protoreg, sizeof(enet_protoreg));
+    enet_protoreg.attach_proto = ether_attach_inet;
+    enet_protoreg.detach_proto = ether_detach_inet;
+    
+    if (error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_ETHERNET, &enet_protoreg) != 0) {
+       printf("ether_family_init: dlil_reg_proto_module failed for AF_INET error=%d\n", error);
+       goto done;
+    }
+    
+    enet_protoreg.attach_proto = ether_attach_inet6;
+    enet_protoreg.detach_proto = ether_detach_inet6;
+    
+    if (error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_ETHERNET, &enet_protoreg) != 0) {
+       printf("ether_family_init: dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
+       goto done;
+    }
+    vlan_family_init();
+
+ done:
+    thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
+
+    return (error);
 }