X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/21362eb3e66fd2c787aee132bce100a44d71a99c..316670eb35587141e969394ae8537d66b9211e80:/bsd/net/ndrv.c

diff --git a/bsd/net/ndrv.c b/bsd/net/ndrv.c
index f2f42839f..dc49773ed 100644
--- a/bsd/net/ndrv.c
+++ b/bsd/net/ndrv.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1997-2008, 2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -25,7 +25,6 @@
  * 
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
-/* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
 /*
  *	@(#)ndrv.c	1.1 (MacOSX) 6/10/43
  * Justin Walker, 970604
@@ -37,15 +36,14 @@
 /*
  * PF_NDRV allows raw access to a specified network device, directly
  *  with a socket.  Expected use involves a socket option to request
- *  protocol packets.  This lets ndrv_output() call dlil_output(), and
+ *  protocol packets.  This lets ndrv_output() call ifnet_output(), and
  *  lets DLIL find the proper recipient for incoming packets.
  *  The purpose here is for user-mode protocol implementation.
  * Note that "pure raw access" will still be accomplished with BPF.
  *
  * In addition to the former use, when combined with socket NKEs,
  * PF_NDRV permits a fairly flexible mechanism for implementing
- * strange protocol support.  One of the main ones will be the
- * BlueBox/Classic Shared IP Address support.
+ * strange protocol support.
  */
 #include <mach/mach_types.h>
 
@@ -59,6 +57,7 @@
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/ioctl.h>
+#include <sys/sysctl.h>
 #include <sys/errno.h>
 #include <sys/syslog.h>
 #include <sys/proc.h>
@@ -71,6 +70,7 @@
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <net/ndrv_var.h>
+#include <net/dlil.h>
 
 #if INET
 #include <netinet/in.h>
@@ -80,27 +80,31 @@
 
 #include <machine/spl.h>
 
+static unsigned int ndrv_multi_max_count = NDRV_DMUX_MAX_DESCR;
+SYSCTL_UINT(_net, OID_AUTO, ndrv_multi_max_count, CTLFLAG_RW | CTLFLAG_LOCKED,
+        &ndrv_multi_max_count, 0, "Number of allowed multicast addresses per NRDV socket");
+
 static int ndrv_do_detach(struct ndrv_cb *);
 static int ndrv_do_disconnect(struct ndrv_cb *);
-static struct ndrv_cb *ndrv_find_inbound(struct ifnet *ifp, u_long protocol_family);
+static struct ndrv_cb *ndrv_find_inbound(struct ifnet *ifp, u_int32_t protocol_family);
 static int ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt);
 static int ndrv_delspec(struct ndrv_cb *);
-static int ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil);
-static void ndrv_handle_ifp_detach(u_long family, short unit);
+static int ndrv_to_ifnet_demux(struct ndrv_demux_desc* ndrv, struct ifnet_demux_desc* ifdemux);
+static void ndrv_handle_ifp_detach(u_int32_t family, short unit);
 static int ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt);
 static int ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt);
 static struct ndrv_multiaddr* ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* addr);
 static void ndrv_remove_all_multicast(struct ndrv_cb *np);
+static void ndrv_dominit(void) __attribute__((section("__TEXT, initcode")));
 
-unsigned long  ndrv_sendspace = NDRVSNDQ;
-unsigned long  ndrv_recvspace = NDRVRCVQ;
+u_int32_t  ndrv_sendspace = NDRVSNDQ;
+u_int32_t  ndrv_recvspace = NDRVRCVQ;
 TAILQ_HEAD(, ndrv_cb)	ndrvl = TAILQ_HEAD_INITIALIZER(ndrvl);
 
 extern struct domain ndrvdomain;
 extern struct protosw ndrvsw;
-extern lck_mtx_t *domain_proto_mtx;
 
-extern void kprintf(const char *, ...);
+#define NDRV_PROTODEMUX_COUNT	10
 
 /*
  * Verify these values match.
@@ -139,15 +143,14 @@ ndrv_output(struct mbuf *m, struct socket *so)
 	if ((m->m_flags&M_PKTHDR) == 0)
 		return(EINVAL);
 
-	/* Unlock before calling dlil_output */
+	/* Unlock before calling ifnet_output */
 	socket_unlock(so, 0);
 	
 	/*
      * Call DLIL if we can. DLIL is much safer than calling the
      * ifp directly.
      */
-	result = dlil_output(ifp, np->nd_proto_family, m, (caddr_t)NULL,
-						(struct sockaddr*)NULL, 1);
+	result = ifnet_output_raw(ifp, np->nd_proto_family, m);
 	
 	socket_lock(so, 0);
 	
@@ -155,18 +158,21 @@ ndrv_output(struct mbuf *m, struct socket *so)
 }
 
 /* Our input routine called from DLIL */
-static int
-ndrv_input(struct mbuf *m,
-	   char *frame_header,
-	   struct ifnet *ifp,
-	   u_long  proto_family,
-	   __unused int sync_ok)
+static errno_t
+ndrv_input(
+	ifnet_t				ifp,
+	protocol_family_t	proto_family,
+	mbuf_t				m,
+	char				*frame_header)
 {
 	struct socket *so;
-	struct sockaddr_dl ndrvsrc = {sizeof (struct sockaddr_dl), AF_NDRV};
+	struct sockaddr_dl ndrvsrc;
 	struct ndrv_cb *np;
 	int error = 0;
 
+    ndrvsrc.sdl_len = sizeof (struct sockaddr_dl);
+    ndrvsrc.sdl_family = AF_NDRV;
+    ndrvsrc.sdl_index = 0;
 
     /* move packet from if queue to socket */
 	/* Should be media-independent */
@@ -183,10 +189,10 @@ ndrv_input(struct mbuf *m,
 	}
 	so = np->nd_socket;
     /* prepend the frame header */
-    m = m_prepend(m, ifp->if_hdrlen, M_NOWAIT);
+    m = m_prepend(m, ifnet_hdrlen(ifp), M_NOWAIT);
     if (m == NULL)
         return EJUSTRETURN;
-    bcopy(frame_header, m->m_data, ifp->if_hdrlen);
+    bcopy(frame_header, m->m_data, ifnet_hdrlen(ifp));
 
 	lck_mtx_assert(so->so_proto->pr_domain->dom_mtx, LCK_MTX_ASSERT_NOTOWNED);
 	lck_mtx_lock(so->so_proto->pr_domain->dom_mtx);
@@ -267,7 +273,6 @@ static int
 ndrv_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
 {
 	struct ndrv_cb *np = sotondrvcb(so);
-    int	result = 0;
 
 	if (np == 0)
 		return EINVAL;
@@ -275,13 +280,11 @@ ndrv_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
 	if (np->nd_faddr)
 		return EISCONN;
     
-    /* Allocate memory to store the remote address */
-    MALLOC(np->nd_faddr, struct sockaddr_ndrv*,
+	/* Allocate memory to store the remote address */
+	MALLOC(np->nd_faddr, struct sockaddr_ndrv*,
                 nam->sa_len, M_IFADDR, M_WAITOK);
-    if (result != 0)
-        return result;
-    if (np->nd_faddr == NULL)
-        return ENOMEM;
+	if (np->nd_faddr == NULL)
+		return ENOMEM;
     
 	bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, nam->sa_len);
 	soisconnected(so);
@@ -289,13 +292,17 @@ ndrv_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
 }
 
 static void
-ndrv_event(struct ifnet *ifp, struct kev_msg *event)
+ndrv_event(struct ifnet *ifp, __unused protocol_family_t protocol,
+		   const struct kev_msg *event)
 {
 	if (event->vendor_code == KEV_VENDOR_APPLE &&
 		event->kev_class == KEV_NETWORK_CLASS &&
 		event->kev_subclass == KEV_DL_SUBCLASS &&
 		event->event_code == KEV_DL_IF_DETACHING) {
-		ndrv_handle_ifp_detach(ifp->if_family, ifp->if_unit);
+		lck_mtx_assert(ndrvdomain.dom_mtx, LCK_MTX_ASSERT_NOTOWNED);
+		lck_mtx_lock(ndrvdomain.dom_mtx);
+		ndrv_handle_ifp_detach(ifnet_family(ifp), ifnet_unit(ifp));
+		lck_mtx_unlock(ndrvdomain.dom_mtx);
 	}
 }
 
@@ -329,7 +336,7 @@ ndrv_bind(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
 	if (np->nd_laddr == NULL)
 		return(ENOMEM);
 	bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
-	dname = sa->snd_name;
+	dname = (char *) sa->snd_name;
 	if (*dname == '\0')
 		return(EINVAL);
 #if NDRV_DEBUG
@@ -350,21 +357,18 @@ ndrv_bind(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
 		return(EADDRNOTAVAIL);
 	
 	// PPP doesn't support PF_NDRV.
-	if (ifp->if_family != APPLE_IF_FAM_PPP)
+	if (ifnet_family(ifp) != APPLE_IF_FAM_PPP)
 	{
 		/* NDRV on this interface */
-		struct dlil_proto_reg_str	ndrv_proto;
+		struct ifnet_attach_proto_param	ndrv_proto;
 		result = 0;
 		bzero(&ndrv_proto, sizeof(ndrv_proto));
-		TAILQ_INIT(&ndrv_proto.demux_desc_head);
-		
-		ndrv_proto.interface_family = ifp->if_family;
-		ndrv_proto.protocol_family = PF_NDRV;
-		ndrv_proto.unit_number = ifp->if_unit;
 		ndrv_proto.event = ndrv_event;
 		
 		/* We aren't worried about double attaching, that should just return an error */
-		result = dlil_attach_protocol(&ndrv_proto);
+		socket_unlock(so, 0);
+		result = ifnet_attach_protocol(ifp, PF_NDRV, &ndrv_proto);
+		socket_lock(so, 0);
 		if (result && result != EEXIST) {
 			return result;
 		}
@@ -375,8 +379,8 @@ ndrv_bind(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
 	}
     
 	np->nd_if = ifp;
-    np->nd_family = ifp->if_family;
-    np->nd_unit = ifp->if_unit;
+    np->nd_family = ifnet_family(ifp);
+    np->nd_unit = ifnet_unit(ifp);
     
 	return(0);
 }
@@ -496,7 +500,7 @@ ndrv_ctloutput(struct socket *so, struct sockopt *sopt)
     {
         case NDRV_DELDMXSPEC: /* Delete current spec */
             /* Verify no parameter was passed */
-            if (sopt->sopt_val != NULL || sopt->sopt_valsize != 0) {
+            if (sopt->sopt_val != 0 || sopt->sopt_valsize != 0) {
                 /*
                  * We don't support deleting a specific demux, it's
                  * all or nothing.
@@ -530,21 +534,25 @@ ndrv_do_detach(struct ndrv_cb *np)
     struct ndrv_cb*	cur_np = NULL;
     struct socket *so = np->nd_socket;
     int error = 0;
+    struct ifnet * ifp;
 
 #if NDRV_DEBUG
 	kprintf("NDRV detach: %x, %x\n", so, np);
 #endif
     ndrv_remove_all_multicast(np);
-    
-    if (np->nd_if) {
-		if (np->nd_proto_family != PF_NDRV &&
-			np->nd_proto_family != 0) {
-			dlil_detach_protocol(np->nd_if, np->nd_proto_family);
+
+    ifp = np->nd_if;
+    /* Remove from the linked list of control blocks */
+    TAILQ_REMOVE(&ndrvl, np, nd_next);
+    if (ifp != NULL) {
+		u_int32_t proto_family = np->nd_proto_family;
+
+		if (proto_family != PF_NDRV && proto_family != 0) {
+			socket_unlock(so, 0);
+			ifnet_detach_protocol(ifp, proto_family);
+			socket_lock(so, 0);
 		}
 		
-		/* Remove from the linked list of control blocks */
-		TAILQ_REMOVE(&ndrvl, np, nd_next);
-		
 		/* Check if this is the last socket attached to this interface */
 		TAILQ_FOREACH(cur_np, &ndrvl, nd_next) {
 			if (cur_np->nd_family == np->nd_family &&
@@ -555,13 +563,15 @@ ndrv_do_detach(struct ndrv_cb *np)
 		
 		/* If there are no other interfaces, detach PF_NDRV from the interface */
 		if (cur_np == NULL) {
-			dlil_detach_protocol(np->nd_if, PF_NDRV);
+			socket_unlock(so, 0);
+			ifnet_detach_protocol(ifp, PF_NDRV);
+			socket_lock(so, 0);
 		}
-	} else {
-		/* Remove from the linked list of control blocks */
-		TAILQ_REMOVE(&ndrvl, np, nd_next);
 	}
-    
+    	if (np->nd_laddr != NULL) {
+		FREE((caddr_t)np->nd_laddr, M_IFADDR);
+		np->nd_laddr = NULL;
+	}
 	FREE((caddr_t)np, M_PCB);
 	so->so_pcb = 0;
 	so->so_flags |= SOF_PCBCLEARING;
@@ -572,6 +582,7 @@ ndrv_do_detach(struct ndrv_cb *np)
 static int
 ndrv_do_disconnect(struct ndrv_cb *np)
 {
+	struct socket * so = np->nd_socket;
 #if NDRV_DEBUG
 	kprintf("NDRV disconnect: %x\n", np);
 #endif
@@ -580,14 +591,14 @@ ndrv_do_disconnect(struct ndrv_cb *np)
         FREE(np->nd_faddr, M_IFADDR);
 		np->nd_faddr = 0;
 	}
-	if (np->nd_socket->so_state & SS_NOFDREF)
+	if (so->so_state & SS_NOFDREF)
 		ndrv_do_detach(np);
-	soisdisconnected(np->nd_socket);
+	soisdisconnected(so);
 	return(0);
 }
 
 /* Hackery - return a string version of a decimal number */
-static char *
+static void
 sprint_d(u_int n, char *buf, int buflen)
 {	char dbuf[IFNAMSIZ];
 	char *cp = dbuf+IFNAMSIZ-1;
@@ -599,7 +610,7 @@ sprint_d(u_int n, char *buf, int buflen)
                 n /= 10;
         } while (n != 0 && buflen > 0);
 	strncpy(buf, cp, IFNAMSIZ-buflen);
-        return (cp);
+        return;
 }
 
 /*
@@ -612,10 +623,10 @@ static int name_cmp(struct ifnet *ifp, char *q)
 	char buf[IFNAMSIZ];
 
 	r = buf;
-	len = strlen(ifp->if_name);
-	strncpy(r, ifp->if_name, IFNAMSIZ);
+	len = strlen(ifnet_name(ifp));
+	strncpy(r, ifnet_name(ifp), IFNAMSIZ);
 	r += len;
-	(void)sprint_d(ifp->if_unit, r, IFNAMSIZ-(r-buf));
+	sprint_d(ifnet_unit(ifp), r, IFNAMSIZ-(r-buf));
 #if NDRV_DEBUG
 	kprintf("Comparing %s, %s\n", buf, q);
 #endif
@@ -646,99 +657,129 @@ ndrv_flushq(struct ifqueue *q)
 int
 ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt)
 {
-    struct dlil_proto_reg_str	dlilSpec;
-    struct ndrv_protocol_desc	ndrvSpec;
-    struct dlil_demux_desc*		dlilDemux = NULL;
-    struct ndrv_demux_desc*		ndrvDemux = NULL;
-    int							error = 0;
-    
-    /* Sanity checking */
-    if (np->nd_proto_family != PF_NDRV)
-        return EBUSY;
-    if (np->nd_if == NULL)
-        return EINVAL;
-    if (sopt->sopt_valsize != sizeof(struct ndrv_protocol_desc))
-        return EINVAL;
-    
-    /* Copy the ndrvSpec */
-    error = sooptcopyin(sopt, &ndrvSpec, sizeof(struct ndrv_protocol_desc),
-                        sizeof(struct ndrv_protocol_desc));
-    if (error != 0)
-        return error;
-    
-    /* Verify the parameter */
-    if (ndrvSpec.version > NDRV_PROTOCOL_DESC_VERS)
-        return ENOTSUP; // version is too new!
-    else if (ndrvSpec.version < 1)
-        return EINVAL; // version is not valid
-    
-    /* Allocate storage for demux array */
-    MALLOC(ndrvDemux, struct ndrv_demux_desc*,
-            ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc), M_TEMP, M_WAITOK);
-    if (ndrvDemux == NULL)
-        return ENOMEM;
-    
-    /* Allocate enough dlil_demux_descs */
-    MALLOC(dlilDemux, struct dlil_demux_desc*,
-            sizeof(*dlilDemux) * ndrvSpec.demux_count, M_TEMP, M_WAITOK);
-    if (dlilDemux == NULL)
-        error = ENOMEM;
-    
-    if (error == 0)
-    {
-        /* Copy the ndrv demux array from userland */
-        error = copyin(CAST_USER_ADDR_T(ndrvSpec.demux_list), ndrvDemux,
-                    ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc));
-        ndrvSpec.demux_list = ndrvDemux;
-    }
-    
-    if (error == 0)
-    {
-        /* At this point, we've at least got enough bytes to start looking around */
-        u_long	demuxOn = 0;
-        
-        bzero(&dlilSpec, sizeof(dlilSpec));
-        TAILQ_INIT(&dlilSpec.demux_desc_head);
-        dlilSpec.interface_family = np->nd_family;
-        dlilSpec.unit_number = np->nd_unit;
-        dlilSpec.input = ndrv_input;
-		dlilSpec.event = ndrv_event;
-        dlilSpec.protocol_family = ndrvSpec.protocol_family;
-        
-        for (demuxOn = 0; demuxOn < ndrvSpec.demux_count; demuxOn++)
-        {
-            /* Convert an ndrv_demux_desc to a dlil_demux_desc */
-            error = ndrv_to_dlil_demux(&ndrvSpec.demux_list[demuxOn], &dlilDemux[demuxOn]);
-            if (error)
-                break;
-            
-            /* Add the dlil_demux_desc to the list */
-            TAILQ_INSERT_TAIL(&dlilSpec.demux_desc_head, &dlilDemux[demuxOn], next);
-        }
-    }
-    
-    if (error == 0)
-    {
-        /* We've got all our ducks lined up...lets attach! */
-        error = dlil_attach_protocol(&dlilSpec);
-        if (error == 0)
-        	np->nd_proto_family = dlilSpec.protocol_family;
-    }
-    
-    /* Free any memory we've allocated */
-    if (dlilDemux)
-        FREE(dlilDemux, M_TEMP);
-    if (ndrvDemux)
-        FREE(ndrvDemux, M_TEMP);
-    
-    return error;
+	struct ifnet_attach_proto_param	proto_param;
+	struct ndrv_protocol_desc	ndrvSpec;
+	struct ndrv_demux_desc*		ndrvDemux = NULL;
+	int							error = 0;
+	struct socket *				so = np->nd_socket; 
+	user_addr_t					user_addr;
+	
+	/* Sanity checking */
+	if (np->nd_proto_family != PF_NDRV)
+		return EBUSY;
+	if (np->nd_if == NULL)
+		return EINVAL;
+
+	/* Copy the ndrvSpec */
+	if (proc_is64bit(sopt->sopt_p)) {
+		struct ndrv_protocol_desc64	ndrvSpec64;
+
+		if (sopt->sopt_valsize != sizeof(ndrvSpec64))
+			return EINVAL;
+	
+		error = sooptcopyin(sopt, &ndrvSpec64, sizeof(ndrvSpec64), sizeof(ndrvSpec64));
+		if (error != 0)
+			return error;
+
+		ndrvSpec.version         = ndrvSpec64.version;
+		ndrvSpec.protocol_family = ndrvSpec64.protocol_family;
+		ndrvSpec.demux_count     = ndrvSpec64.demux_count;
+
+		user_addr = ndrvSpec64.demux_list;
+	}
+	else {
+		struct ndrv_protocol_desc32	ndrvSpec32;
+
+		if (sopt->sopt_valsize != sizeof(ndrvSpec32))
+			return EINVAL;
+	
+		error = sooptcopyin(sopt, &ndrvSpec32, sizeof(ndrvSpec32), sizeof(ndrvSpec32));
+		if (error != 0)
+			return error;
+
+		ndrvSpec.version         = ndrvSpec32.version;
+		ndrvSpec.protocol_family = ndrvSpec32.protocol_family;
+		ndrvSpec.demux_count     = ndrvSpec32.demux_count;
+
+		user_addr = CAST_USER_ADDR_T(ndrvSpec32.demux_list);
+	}
+	
+	/* Verify the parameter */
+	if (ndrvSpec.version > NDRV_PROTOCOL_DESC_VERS)
+		return ENOTSUP; // version is too new!
+	else if (ndrvSpec.version < 1)
+		return EINVAL; // version is not valid
+	else if (ndrvSpec.demux_count > NDRV_PROTODEMUX_COUNT || ndrvSpec.demux_count == 0)
+		return EINVAL; // demux_count is not valid
+	
+	bzero(&proto_param, sizeof(proto_param));
+	proto_param.demux_count = ndrvSpec.demux_count;
+	
+	/* Allocate storage for demux array */
+	MALLOC(ndrvDemux, struct ndrv_demux_desc*, proto_param.demux_count *
+		   sizeof(struct ndrv_demux_desc), M_TEMP, M_WAITOK);
+	if (ndrvDemux == NULL)
+		return ENOMEM;
+	
+	/* Allocate enough ifnet_demux_descs */
+	MALLOC(proto_param.demux_array, struct ifnet_demux_desc*,
+		   sizeof(*proto_param.demux_array) * ndrvSpec.demux_count,
+		   M_TEMP, M_WAITOK);
+	if (proto_param.demux_array == NULL)
+		error = ENOMEM;
+	
+	if (error == 0)
+	{
+		/* Copy the ndrv demux array from userland */
+		error = copyin(user_addr, ndrvDemux,
+					   ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc));
+		ndrvSpec.demux_list = ndrvDemux;
+	}
+	
+	if (error == 0)
+	{
+		/* At this point, we've at least got enough bytes to start looking around */
+		u_int32_t	demuxOn = 0;
+		
+		proto_param.demux_count = ndrvSpec.demux_count;
+		proto_param.input = ndrv_input;
+		proto_param.event = ndrv_event;
+		
+		for (demuxOn = 0; demuxOn < ndrvSpec.demux_count; demuxOn++)
+		{
+			/* Convert an ndrv_demux_desc to a ifnet_demux_desc */
+			error = ndrv_to_ifnet_demux(&ndrvSpec.demux_list[demuxOn],
+										&proto_param.demux_array[demuxOn]);
+			if (error)
+				break;
+		}
+	}
+	
+	if (error == 0)
+	{
+		/* We've got all our ducks lined up...lets attach! */
+		socket_unlock(so, 0);
+		error = ifnet_attach_protocol(np->nd_if, ndrvSpec.protocol_family,
+									  &proto_param);
+		socket_lock(so, 0);
+		if (error == 0)
+			np->nd_proto_family = ndrvSpec.protocol_family;
+	}
+	
+	/* Free any memory we've allocated */
+	if (proto_param.demux_array)
+		FREE(proto_param.demux_array, M_TEMP);
+	if (ndrvDemux)
+		FREE(ndrvDemux, M_TEMP);
+	
+	return error;
 }
 
 
 int
-ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil)
+ndrv_to_ifnet_demux(struct ndrv_demux_desc* ndrv, struct ifnet_demux_desc* ifdemux)
 {
-    bzero(dlil, sizeof(*dlil));
+    bzero(ifdemux, sizeof(*ifdemux));
     
     if (ndrv->type < DLIL_DESC_ETYPE2)
     {
@@ -751,9 +792,9 @@ ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil)
         return EINVAL;
     }
     
-    dlil->type = ndrv->type;
-    dlil->native_type = ndrv->data.other;
-    dlil->variants.native_type_length = ndrv->length;
+    ifdemux->type = ndrv->type;
+    ifdemux->data = ndrv->data.other;
+    ifdemux->datalen = ndrv->length;
     
     return 0;
 }
@@ -768,14 +809,14 @@ ndrv_delspec(struct ndrv_cb *np)
         return EINVAL;
     
     /* Detach the protocol */
-    result = dlil_detach_protocol(np->nd_if, np->nd_proto_family);
+    result = ifnet_detach_protocol(np->nd_if, np->nd_proto_family);
     np->nd_proto_family = PF_NDRV;
     
 	return result;
 }
 
 struct ndrv_cb *
-ndrv_find_inbound(struct ifnet *ifp, u_long protocol)
+ndrv_find_inbound(struct ifnet *ifp, u_int32_t protocol)
 {
     struct ndrv_cb* np;
 	
@@ -801,7 +842,7 @@ static void ndrv_dominit(void)
 }
 
 static void
-ndrv_handle_ifp_detach(u_long family, short unit)
+ndrv_handle_ifp_detach(u_int32_t family, short unit)
 {
     struct ndrv_cb* np;
     struct ifnet	*ifp = NULL;
@@ -837,7 +878,7 @@ ndrv_handle_ifp_detach(u_long family, short unit)
     
     /* Unregister our protocol */
     if (ifp) {
-        dlil_detach_protocol(ifp, PF_NDRV);
+        ifnet_detach_protocol(ifp, PF_NDRV);
     }
 }
 
@@ -847,11 +888,13 @@ ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt)
     struct ndrv_multiaddr*	ndrv_multi;
     int						result;
     
-    if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
-        sopt->sopt_level != SOL_NDRVPROTO)
+    if (sopt->sopt_val == 0 || sopt->sopt_valsize < 2 ||
+        sopt->sopt_level != SOL_NDRVPROTO || sopt->sopt_valsize > SOCK_MAXADDRLEN)
         return EINVAL;
     if (np->nd_if == NULL)
         return ENXIO;
+	if (!(np->nd_dlist_cnt < ndrv_multi_max_count))
+		return EPERM;
     
     // Allocate storage
     MALLOC(ndrv_multi, struct ndrv_multiaddr*, sizeof(struct ndrv_multiaddr) -
@@ -872,7 +915,8 @@ ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt)
     if (result == 0)
     {
         // Try adding the multicast
-        result = if_addmulti(np->nd_if, &ndrv_multi->addr, &ndrv_multi->ifma);
+        result = ifnet_add_multicast(np->nd_if, &ndrv_multi->addr,
+        							 &ndrv_multi->ifma);
     }
     
     if (result == 0)
@@ -880,6 +924,7 @@ ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt)
         // Add to our linked list
         ndrv_multi->next = np->nd_multiaddrs;
         np->nd_multiaddrs = ndrv_multi;
+		np->nd_dlist_cnt++;
     }
     else
     {
@@ -897,10 +942,10 @@ ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt)
     struct ndrv_multiaddr*	ndrv_entry = NULL;
     int					result;
     
-    if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
+    if (sopt->sopt_val == 0 || sopt->sopt_valsize < 2 ||
         sopt->sopt_level != SOL_NDRVPROTO)
         return EINVAL;
-    if (np->nd_if == NULL)
+    if (np->nd_if == NULL || np->nd_dlist_cnt == 0)
         return ENXIO;
     
     // Allocate storage
@@ -928,7 +973,7 @@ ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt)
     if (result == 0)
     {
         // Try deleting the multicast
-        result = if_delmultiaddr(ndrv_entry->ifma, 0);
+        result = ifnet_remove_multicast(ndrv_entry->ifma);
     }
     
     if (result == 0)
@@ -936,7 +981,7 @@ ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt)
         // Remove from our linked list
         struct ndrv_multiaddr*	cur = np->nd_multiaddrs;
         
-        ifma_release(ndrv_entry->ifma);
+        ifmaddr_release(ndrv_entry->ifma);
         
         if (cur == ndrv_entry)
         {
@@ -954,6 +999,8 @@ ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt)
             }
         }
         
+		np->nd_dlist_cnt--;
+		
         // Free the memory
         FREE(ndrv_entry, M_IFADDR);
     }
@@ -992,8 +1039,8 @@ ndrv_remove_all_multicast(struct ndrv_cb* np)
             cur = np->nd_multiaddrs;
             np->nd_multiaddrs = cur->next;
             
-            if_delmultiaddr(cur->ifma, 0);
-            ifma_release(cur->ifma);
+            ifnet_remove_multicast(cur->ifma);
+            ifmaddr_release(cur->ifma);
             FREE(cur, M_IFADDR);
         }
     }
@@ -1009,15 +1056,29 @@ struct pr_usrreqs ndrv_usrreqs = {
 
 struct protosw ndrvsw =
 {	SOCK_RAW, &ndrvdomain, NDRVPROTO_NDRV, PR_ATOMIC|PR_ADDR,
-	0, ndrv_output, 0, ndrv_ctloutput,
-	0, 0, 0, 0,
-	0, 0,
+	NULL, ndrv_output, NULL, ndrv_ctloutput,
+	NULL,
+	NULL, NULL, NULL, NULL, NULL, 
 	&ndrv_usrreqs,
-	0, 0, 0
+	NULL, NULL, NULL,
+	{ NULL, NULL}, NULL,
+	{ 0 }
 };
 
 struct domain ndrvdomain =
-{	AF_NDRV, "NetDriver", ndrv_dominit, NULL, NULL,
+{	AF_NDRV, 
+	"NetDriver", 
+	ndrv_dominit, 
+	NULL, 
+	NULL,
+	NULL, 
+	NULL, 
+	NULL, 
+	0, 
+	0, 
+	0, 
+	0,
 	NULL,
-	NULL, NULL, 0, 0, 0, 0
+	0, 
+	{0, 0}
 };