2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
24 * @(#)ndrv.c 1.1 (MacOSX) 6/10/43
25 * Justin Walker, 970604
27 * 980130 - Cleanup, reorg, performance improvemements
28 * 000816 - Removal of Y adapter cruft
32 * PF_NDRV allows raw access to a specified network device, directly
33 * with a socket. Expected use involves a socket option to request
34 * protocol packets. This lets ndrv_output() call dlil_output(), and
35 * lets DLIL find the proper recipient for incoming packets.
36 * The purpose here is for user-mode protocol implementation.
37 * Note that "pure raw access" will still be accomplished with BPF.
39 * In addition to the former use, when combined with socket NKEs,
40 * PF_NDRV permits a fairly flexible mechanism for implementing
41 * strange protocol support. One of the main ones will be the
42 * BlueBox/Classic Shared IP Address support.
44 #include <mach/mach_types.h>
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
51 #include <sys/protosw.h>
52 #include <sys/domain.h>
53 #include <sys/socket.h>
54 #include <sys/socketvar.h>
55 #include <sys/ioctl.h>
56 #include <sys/errno.h>
57 #include <sys/syslog.h>
60 #include <kern/queue.h>
63 #include <net/netisr.h>
64 #include <net/route.h>
65 #include <net/if_llc.h>
66 #include <net/if_dl.h>
67 #include <net/if_types.h>
68 #include <net/ndrv_var.h>
71 #include <netinet/in.h>
72 #include <netinet/in_var.h>
74 #include <netinet/if_ether.h>
78 #include <netns/ns_if.h>
82 #include <netiso/argo_debug.h>
83 #include <netiso/iso.h>
84 #include <netiso/iso_var.h>
85 #include <netiso/iso_snpac.h>
89 #include <netccitt/dll.h>
90 #include <netccitt/llc_var.h>
93 #include <machine/spl.h>
95 int ndrv_do_detach(struct ndrv_cb
*);
96 int ndrv_do_disconnect(struct ndrv_cb
*);
97 struct ndrv_cb
*ndrv_find_tag(unsigned int);
98 void ndrv_read_event(struct socket
* inSo
, caddr_t ref
, int waitf
);
99 int ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
);
100 int ndrv_delspec(struct ndrv_cb
*);
101 int ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
);
102 void ndrv_handle_ifp_detach(u_long family
, short unit
);
104 unsigned long ndrv_sendspace
= NDRVSNDQ
;
105 unsigned long ndrv_recvspace
= NDRVRCVQ
;
106 struct ndrv_cb ndrvl
; /* Head of controlblock list */
108 struct domain ndrvdomain
;
109 struct protosw ndrvsw
;
110 static struct socket
* ndrv_so
;
114 * Protocol init function for NDRV protocol
115 * Init the control block list.
121 struct kev_request kev_request
;
123 ndrvl
.nd_next
= ndrvl
.nd_prev
= &ndrvl
;
125 /* Create a PF_SYSTEM socket so we can listen for events */
126 retval
= socreate(PF_SYSTEM
, &ndrv_so
, SOCK_RAW
, SYSPROTO_EVENT
);
127 if (retval
!= 0 || ndrv_so
== NULL
)
128 retval
= KERN_FAILURE
;
130 /* Install a callback function for the socket */
131 ndrv_so
->so_rcv
.sb_flags
|= SB_NOTIFY
|SB_UPCALL
;
132 ndrv_so
->so_upcall
= ndrv_read_event
;
133 ndrv_so
->so_upcallarg
= NULL
;
135 /* Configure the socket to receive the events we're interested in */
136 kev_request
.vendor_code
= KEV_VENDOR_APPLE
;
137 kev_request
.kev_class
= KEV_NETWORK_CLASS
;
138 kev_request
.kev_subclass
= KEV_DL_SUBCLASS
;
139 retval
= ndrv_so
->so_proto
->pr_usrreqs
->pru_control(ndrv_so
, SIOCSKEVFILT
, (caddr_t
)&kev_request
, 0, 0);
143 * We will not get attaching or detaching events in this case.
144 * We should probably prevent any sockets from binding so we won't
145 * panic later if the interface goes away.
147 log(LOG_WARNING
, "PF_NDRV: ndrv_init - failed to set event filter (%d)",
153 * Protocol output - Called to output a raw network packet directly
157 ndrv_output(register struct mbuf
*m
, register struct socket
*so
)
159 register struct ndrv_cb
*np
= sotondrvcb(so
);
160 register struct ifnet
*ifp
= np
->nd_if
;
161 extern void kprintf(const char *, ...);
165 kprintf("NDRV output: %x, %x, %x\n", m
, so
, np
);
169 * No header is a format error
171 if ((m
->m_flags
&M_PKTHDR
) == 0)
175 * Call DLIL if we can. DLIL is much safer than calling the
179 result
= dlil_output(np
->nd_tag
, m
, (caddr_t
)NULL
,
180 (struct sockaddr
*)NULL
, 1);
181 else if (np
->nd_send_tag
!= 0)
182 result
= dlil_output(np
->nd_send_tag
, m
, (caddr_t
)NULL
,
183 (struct sockaddr
*)NULL
, 1);
189 /* Our input routine called from DLIL */
191 ndrv_input(struct mbuf
*m
,
198 struct sockaddr_dl ndrvsrc
= {sizeof (struct sockaddr_dl
), AF_NDRV
};
199 register struct ndrv_cb
*np
;
202 /* move packet from if queue to socket */
203 /* Should be media-independent */
204 ndrvsrc
.sdl_type
= IFT_ETHER
;
205 ndrvsrc
.sdl_nlen
= 0;
206 ndrvsrc
.sdl_alen
= 6;
207 ndrvsrc
.sdl_slen
= 0;
208 bcopy(frame_header
, &ndrvsrc
.sdl_data
, 6);
210 np
= ndrv_find_tag(dl_tag
);
216 /* prepend the frame header */
217 m
= m_prepend(m
, ifp
->if_data
.ifi_hdrlen
, M_NOWAIT
);
220 bcopy(frame_header
, m
->m_data
, ifp
->if_data
.ifi_hdrlen
);
221 if (sbappendaddr(&(so
->so_rcv
), (struct sockaddr
*)&ndrvsrc
,
222 m
, (struct mbuf
*)0) == 0)
224 /* yes, sbappendaddr returns zero if the sockbuff is full... */
225 /* caller will free m */
233 ndrv_control(struct socket
*so
, u_long cmd
, caddr_t data
,
234 struct ifnet
*ifp
, struct proc
*p
)
240 * Allocate an ndrv control block and some buffer space for the socket
243 ndrv_attach(struct socket
*so
, int proto
, struct proc
*p
)
246 register struct ndrv_cb
*np
= sotondrvcb(so
);
248 if ((so
->so_state
& SS_PRIV
) == 0)
252 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
254 MALLOC(np
, struct ndrv_cb
*, sizeof(*np
), M_PCB
, M_WAITOK
);
257 so
->so_pcb
= (caddr_t
)np
;
258 bzero(np
, sizeof(*np
));
260 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
262 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
264 TAILQ_INIT(&np
->nd_dlist
);
265 np
->nd_signature
= NDRV_SIGNATURE
;
267 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
268 np
->nd_proto
.sp_protocol
= proto
;
273 insque((queue_t
)np
, (queue_t
)&ndrvl
);
278 * Destroy state just before socket deallocation.
279 * Flush data or not depending on the options.
283 ndrv_detach(struct socket
*so
)
285 register struct ndrv_cb
*np
= sotondrvcb(so
);
289 return ndrv_do_detach(np
);
294 * If a socket isn't bound to a single address,
295 * the ndrv input routine will hand it anything
296 * within that protocol family (assuming there's
297 * nothing else around it should go to).
299 * Don't expect this to be used.
302 int ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
304 register struct ndrv_cb
*np
= sotondrvcb(so
);
313 /* Allocate memory to store the remote address */
314 MALLOC(np
->nd_faddr
, struct sockaddr_ndrv
*,
315 nam
->sa_len
, M_IFADDR
, M_WAITOK
);
318 if (np
->nd_faddr
== NULL
)
321 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, nam
->sa_len
);
327 * This is the "driver open" hook - we 'bind' to the
329 * Here's where we latch onto the driver.
332 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
334 register struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
335 register char *dname
;
336 register struct ndrv_cb
*np
;
337 register struct ifnet
*ifp
;
338 extern int name_cmp(struct ifnet
*, char *);
341 if TAILQ_EMPTY(&ifnet
)
342 return(EADDRNOTAVAIL
); /* Quick sanity check */
348 return EINVAL
; /* XXX */
350 /* I think we just latch onto a copy here; the caller frees */
351 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
352 if (np
->nd_laddr
== NULL
)
354 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
355 dname
= sa
->snd_name
;
359 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
361 /* Track down the driver and its ifnet structure.
362 * There's no internal call for this so we have to dup the code
365 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
366 if (name_cmp(ifp
, dname
) == 0)
371 return(EADDRNOTAVAIL
);
374 * Loopback demuxing doesn't work with PF_NDRV.
375 * The first 4 bytes of the packet must be the
376 * protocol ptr. Can't get that from userland.
378 if (ifp
->if_family
== APPLE_IF_FAM_LOOPBACK
)
381 if ((dlil_find_dltag(ifp
->if_family
, ifp
->if_unit
,
382 PF_NDRV
, &np
->nd_send_tag
) != 0) &&
383 (ifp
->if_family
!= APPLE_IF_FAM_PPP
))
385 /* NDRV isn't registered on this interface, lets change that */
386 struct dlil_proto_reg_str ndrv_proto
;
388 bzero(&ndrv_proto
, sizeof(ndrv_proto
));
389 TAILQ_INIT(&ndrv_proto
.demux_desc_head
);
391 ndrv_proto
.interface_family
= ifp
->if_family
;
392 ndrv_proto
.protocol_family
= PF_NDRV
;
393 ndrv_proto
.unit_number
= ifp
->if_unit
;
395 result
= dlil_attach_protocol(&ndrv_proto
, &np
->nd_send_tag
);
398 * If the interface does not allow PF_NDRV to attach, we will
399 * respect it's wishes. Sending will be disabled. No error is
400 * returned because the client may later attach a real protocol
401 * that the interface may accept.
408 np
->nd_family
= ifp
->if_family
;
409 np
->nd_unit
= ifp
->if_unit
;
415 ndrv_disconnect(struct socket
*so
)
417 register struct ndrv_cb
*np
= sotondrvcb(so
);
422 if (np
->nd_faddr
== 0)
425 ndrv_do_disconnect(np
);
433 ndrv_get_ifp(caddr_t ndrv_pcb
)
435 struct ndrv_cb
* np
= (struct ndrv_cb
*)ndrv_pcb
;
439 struct ndrv_cb
* temp
= ndrvl
.nd_next
;
440 /* Verify existence of pcb */
441 for (temp
= ndrvl
.nd_next
; temp
!= &ndrvl
; temp
= temp
->nd_next
)
449 log(LOG_WARNING
, "PF_NDRV: ndrv_get_ifp called with invalid ndrv_cb!");
459 * Mark the connection as being incapable of further input.
462 ndrv_shutdown(struct socket
*so
)
469 * Ship a packet out. The ndrv output will pass it
470 * to the appropriate driver. The really tricky part
471 * is the destination address...
474 ndrv_send(struct socket
*so
, int flags
, struct mbuf
*m
,
475 struct sockaddr
*addr
, struct mbuf
*control
,
483 error
= ndrv_output(m
, so
);
490 ndrv_abort(struct socket
*so
)
492 register struct ndrv_cb
*np
= sotondrvcb(so
);
497 ndrv_do_disconnect(np
);
502 ndrv_sense(struct socket
*so
, struct stat
*sb
)
505 * stat: don't bother with a blocksize.
511 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
513 register struct ndrv_cb
*np
= sotondrvcb(so
);
519 if (np
->nd_laddr
== 0)
522 len
= np
->nd_laddr
->snd_len
;
523 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
530 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
532 register struct ndrv_cb
*np
= sotondrvcb(so
);
538 if (np
->nd_faddr
== 0)
541 len
= np
->nd_faddr
->snd_len
;
542 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
551 ndrv_ctlinput(int dummy1
, struct sockaddr
*dummy2
, void *dummy3
)
558 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
560 register struct ndrv_cb
*np
= sotondrvcb(so
);
563 switch(sopt
->sopt_name
)
565 case NDRV_DELDMXSPEC
: /* Delete current spec */
566 /* Verify no parameter was passed */
567 if (sopt
->sopt_val
!= NULL
|| sopt
->sopt_valsize
!= 0) {
569 * We don't support deleting a specific demux, it's
574 error
= ndrv_delspec(np
);
576 case NDRV_SETDMXSPEC
: /* Set protocol spec */
577 error
= ndrv_setspec(np
, sopt
);
583 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
589 /* Drain the queues */
595 /* Sysctl hook for NDRV */
603 ndrv_do_detach(register struct ndrv_cb
*np
)
605 struct ndrv_cb
* cur_np
= NULL
;
606 struct socket
*so
= np
->nd_socket
;
607 struct ndrv_multicast
* next
;
611 kprintf("NDRV detach: %x, %x\n", so
, np
);
615 error
= dlil_detach_protocol(np
->nd_tag
);
618 log(LOG_WARNING
, "NDRV ndrv_do_detach: error %d removing dl_tag %d",
624 /* Remove from the linked list of control blocks */
627 if (np
->nd_send_tag
!= 0)
629 /* Check if this is the last socket attached to this interface */
630 for (cur_np
= ndrvl
.nd_next
; cur_np
!= &ndrvl
; cur_np
= cur_np
->nd_next
)
632 if (cur_np
->nd_family
== np
->nd_family
&&
633 cur_np
->nd_unit
== np
->nd_unit
)
639 /* If there are no other interfaces, detach PF_NDRV from the interface */
640 if (cur_np
== &ndrvl
)
642 dlil_detach_protocol(np
->nd_send_tag
);
646 FREE((caddr_t
)np
, M_PCB
);
653 ndrv_do_disconnect(register struct ndrv_cb
*np
)
656 kprintf("NDRV disconnect: %x\n", np
);
660 FREE(np
->nd_faddr
, M_IFADDR
);
663 if (np
->nd_socket
->so_state
& SS_NOFDREF
)
665 soisdisconnected(np
->nd_socket
);
670 * Try to compare a device name (q) with one of the funky ifnet
671 * device names (ifp).
673 int name_cmp(register struct ifnet
*ifp
, register char *q
)
677 static char *sprint_d();
680 len
= strlen(ifp
->if_name
);
681 strncpy(r
, ifp
->if_name
, IFNAMSIZ
);
683 (void)sprint_d(ifp
->if_unit
, r
, IFNAMSIZ
-(r
-buf
));
685 kprintf("Comparing %s, %s\n", buf
, q
);
687 return(strncmp(buf
, q
, IFNAMSIZ
));
690 /* Hackery - return a string version of a decimal number */
692 sprint_d(n
, buf
, buflen
)
696 { char dbuf
[IFNAMSIZ
];
697 register char *cp
= dbuf
+IFNAMSIZ
-1;
702 *cp
= "0123456789"[n
% 10];
704 } while (n
!= 0 && buflen
> 0);
705 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
710 * When closing, dump any enqueued mbufs.
713 ndrv_flushq(register struct ifqueue
*q
)
715 register struct mbuf
*m
;
728 ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
)
730 struct dlil_proto_reg_str dlilSpec
;
731 struct ndrv_protocol_desc ndrvSpec
;
732 struct dlil_demux_desc
* dlilDemux
= NULL
;
733 struct ndrv_demux_desc
* ndrvDemux
= NULL
;
736 /* Sanity checking */
739 if (np
->nd_if
== NULL
)
741 if (sopt
->sopt_valsize
!= sizeof(struct ndrv_protocol_desc
))
744 /* Copy the ndrvSpec */
745 error
= sooptcopyin(sopt
, &ndrvSpec
, sizeof(struct ndrv_protocol_desc
),
746 sizeof(struct ndrv_protocol_desc
));
750 /* Verify the parameter */
751 if (ndrvSpec
.version
> NDRV_PROTOCOL_DESC_VERS
)
752 return ENOTSUP
; // version is too new!
753 else if (ndrvSpec
.version
< 1)
754 return EINVAL
; // version is not valid
756 /* Allocate storage for demux array */
757 MALLOC(ndrvDemux
, struct ndrv_demux_desc
*,
758 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
), M_TEMP
, M_WAITOK
);
759 if (ndrvDemux
== NULL
)
762 /* Allocate enough dlil_demux_descs */
763 MALLOC(dlilDemux
, struct dlil_demux_desc
*,
764 sizeof(*dlilDemux
) * ndrvSpec
.demux_count
, M_TEMP
, M_WAITOK
);
765 if (dlilDemux
== NULL
)
770 /* Copy the ndrv demux array from userland */
771 error
= copyin(ndrvSpec
.demux_list
, ndrvDemux
,
772 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
));
773 ndrvSpec
.demux_list
= ndrvDemux
;
778 /* At this point, we've at least got enough bytes to start looking around */
781 bzero(&dlilSpec
, sizeof(dlilSpec
));
782 TAILQ_INIT(&dlilSpec
.demux_desc_head
);
783 dlilSpec
.interface_family
= np
->nd_family
;
784 dlilSpec
.unit_number
= np
->nd_unit
;
785 dlilSpec
.input
= ndrv_input
;
786 dlilSpec
.protocol_family
= ndrvSpec
.protocol_family
;
788 for (demuxOn
= 0; demuxOn
< ndrvSpec
.demux_count
; demuxOn
++)
790 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
791 error
= ndrv_to_dlil_demux(&ndrvSpec
.demux_list
[demuxOn
], &dlilDemux
[demuxOn
]);
795 /* Add the dlil_demux_desc to the list */
796 TAILQ_INSERT_TAIL(&dlilSpec
.demux_desc_head
, &dlilDemux
[demuxOn
], next
);
802 /* We've got all our ducks lined up...lets attach! */
803 error
= dlil_attach_protocol(&dlilSpec
, &np
->nd_tag
);
806 /* Free any memory we've allocated */
808 FREE(dlilDemux
, M_TEMP
);
810 FREE(ndrvDemux
, M_TEMP
);
817 ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
)
819 bzero(dlil
, sizeof(*dlil
));
821 if (ndrv
->type
< DLIL_DESC_ETYPE2
)
823 /* using old "type", not supported */
827 if (ndrv
->length
> 28)
832 dlil
->type
= ndrv
->type
;
833 dlil
->native_type
= ndrv
->data
.other
;
834 dlil
->variants
.native_type_length
= ndrv
->length
;
840 ndrv_delspec(struct ndrv_cb
*np
)
847 /* Detach the protocol */
848 result
= dlil_detach_protocol(np
->nd_tag
);
858 ndrv_find_tag(unsigned int tag
)
866 for (np
= ndrvl
.nd_next
; np
!= NULL
; np
= np
->nd_next
)
868 if (np
->nd_tag
== tag
)
879 static int ndrv_dominited
= 0;
881 if (ndrv_dominited
== 0 &&
882 net_add_proto(&ndrvsw
, &ndrvdomain
) == 0)
887 ndrv_read_event(struct socket
* so
, caddr_t ref
, int waitf
)
890 struct mbuf
*m
= NULL
;
891 struct kern_event_msg
*msg
;
892 struct uio auio
= {0};
897 auio
.uio_resid
= 1000000; // large number to get all of the data
898 flags
= MSG_DONTWAIT
;
899 result
= soreceive(so
, (struct sockaddr
**)NULL
, &auio
, &m
,
900 (struct mbuf
**)NULL
, &flags
);
901 if (result
!= 0 || m
== NULL
)
904 // cast the mbuf to a kern_event_msg
905 // this is dangerous, doesn't handle linked mbufs
906 msg
= mtod(m
, struct kern_event_msg
*);
908 // check for detaches, assume even filtering is working
909 if (msg
->event_code
== KEV_DL_IF_DETACHING
||
910 msg
->event_code
== KEV_DL_IF_DETACHED
)
912 struct net_event_data
*ev_data
;
913 ev_data
= (struct net_event_data
*)msg
->event_data
;
914 ndrv_handle_ifp_detach(ev_data
->if_family
, ev_data
->if_unit
);
921 ndrv_handle_ifp_detach(u_long family
, short unit
)
926 /* Find all sockets using this interface. */
927 for (np
= ndrvl
.nd_next
; np
!= &ndrvl
; np
= np
->nd_next
)
929 if (np
->nd_family
== family
&&
932 /* This cb is using the detaching interface, but not for long. */
933 /* Let the protocol go */
937 /* Disavow all knowledge of the ifp */
943 /* Make sure sending returns an error */
944 /* Is this safe? Will we drop the funnel? */
945 socantsendmore(np
->nd_socket
);
946 socantrcvmore(np
->nd_socket
);
950 /* Unregister our protocol */
951 if (dlil_find_dltag(family
, unit
, PF_NDRV
, &dl_tag
) == 0) {
952 dlil_detach_protocol(dl_tag
);
956 struct pr_usrreqs ndrv_usrreqs
= {
957 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
958 ndrv_connect
, pru_connect2_notsupp
, ndrv_control
, ndrv_detach
,
959 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
960 pru_rcvoob_notsupp
, ndrv_send
, ndrv_sense
, ndrv_shutdown
,
961 ndrv_sockaddr
, sosend
, soreceive
, sopoll
964 struct protosw ndrvsw
=
965 { SOCK_RAW
, &ndrvdomain
, NDRVPROTO_NDRV
, PR_ATOMIC
|PR_ADDR
,
966 0, ndrv_output
, ndrv_ctlinput
, ndrv_ctloutput
,
968 ndrv_drain
, ndrv_sysctl
, &ndrv_usrreqs
971 struct domain ndrvdomain
=
972 { AF_NDRV
, "NetDriver", ndrv_dominit
, NULL
, NULL
,
974 NULL
, NULL
, 0, 0, 0, 0