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>
76 #include <machine/spl.h>
78 int ndrv_do_detach(struct ndrv_cb
*);
79 int ndrv_do_disconnect(struct ndrv_cb
*);
80 struct ndrv_cb
*ndrv_find_tag(unsigned int);
81 void ndrv_read_event(struct socket
* inSo
, caddr_t ref
, int waitf
);
82 int ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
);
83 int ndrv_delspec(struct ndrv_cb
*);
84 int ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
);
85 void ndrv_handle_ifp_detach(u_long family
, short unit
);
86 static int ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
);
87 static int ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
);
88 static struct ndrv_multiaddr
* ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* addr
);
89 static void ndrv_remove_all_multicast(struct ndrv_cb
*np
);
91 unsigned long ndrv_sendspace
= NDRVSNDQ
;
92 unsigned long ndrv_recvspace
= NDRVRCVQ
;
93 struct ndrv_cb ndrvl
; /* Head of controlblock list */
95 struct domain ndrvdomain
;
96 struct protosw ndrvsw
;
97 static struct socket
* ndrv_so
;
101 * Protocol init function for NDRV protocol
102 * Init the control block list.
108 struct kev_request kev_request
;
110 ndrvl
.nd_next
= ndrvl
.nd_prev
= &ndrvl
;
112 /* Create a PF_SYSTEM socket so we can listen for events */
113 retval
= socreate(PF_SYSTEM
, &ndrv_so
, SOCK_RAW
, SYSPROTO_EVENT
);
114 if (retval
!= 0 || ndrv_so
== NULL
)
115 retval
= KERN_FAILURE
;
117 /* Install a callback function for the socket */
118 ndrv_so
->so_rcv
.sb_flags
|= SB_NOTIFY
|SB_UPCALL
;
119 ndrv_so
->so_upcall
= ndrv_read_event
;
120 ndrv_so
->so_upcallarg
= NULL
;
122 /* Configure the socket to receive the events we're interested in */
123 kev_request
.vendor_code
= KEV_VENDOR_APPLE
;
124 kev_request
.kev_class
= KEV_NETWORK_CLASS
;
125 kev_request
.kev_subclass
= KEV_DL_SUBCLASS
;
126 retval
= ndrv_so
->so_proto
->pr_usrreqs
->pru_control(ndrv_so
, SIOCSKEVFILT
, (caddr_t
)&kev_request
, 0, 0);
130 * We will not get attaching or detaching events in this case.
131 * We should probably prevent any sockets from binding so we won't
132 * panic later if the interface goes away.
134 log(LOG_WARNING
, "PF_NDRV: ndrv_init - failed to set event filter (%d)",
140 * Protocol output - Called to output a raw network packet directly
144 ndrv_output(register struct mbuf
*m
, register struct socket
*so
)
146 register struct ndrv_cb
*np
= sotondrvcb(so
);
147 register struct ifnet
*ifp
= np
->nd_if
;
148 extern void kprintf(const char *, ...);
152 kprintf("NDRV output: %x, %x, %x\n", m
, so
, np
);
156 * No header is a format error
158 if ((m
->m_flags
&M_PKTHDR
) == 0)
162 * Call DLIL if we can. DLIL is much safer than calling the
166 result
= dlil_output(np
->nd_tag
, m
, (caddr_t
)NULL
,
167 (struct sockaddr
*)NULL
, 1);
168 else if (np
->nd_send_tag
!= 0)
169 result
= dlil_output(np
->nd_send_tag
, m
, (caddr_t
)NULL
,
170 (struct sockaddr
*)NULL
, 1);
176 /* Our input routine called from DLIL */
178 ndrv_input(struct mbuf
*m
,
185 struct sockaddr_dl ndrvsrc
= {sizeof (struct sockaddr_dl
), AF_NDRV
};
186 register struct ndrv_cb
*np
;
189 /* move packet from if queue to socket */
190 /* Should be media-independent */
191 ndrvsrc
.sdl_type
= IFT_ETHER
;
192 ndrvsrc
.sdl_nlen
= 0;
193 ndrvsrc
.sdl_alen
= 6;
194 ndrvsrc
.sdl_slen
= 0;
195 bcopy(frame_header
, &ndrvsrc
.sdl_data
, 6);
197 np
= ndrv_find_tag(dl_tag
);
203 /* prepend the frame header */
204 m
= m_prepend(m
, ifp
->if_data
.ifi_hdrlen
, M_NOWAIT
);
207 bcopy(frame_header
, m
->m_data
, ifp
->if_data
.ifi_hdrlen
);
208 if (sbappendaddr(&(so
->so_rcv
), (struct sockaddr
*)&ndrvsrc
,
209 m
, (struct mbuf
*)0) == 0)
211 /* yes, sbappendaddr returns zero if the sockbuff is full... */
212 /* caller will free m */
220 ndrv_control(struct socket
*so
, u_long cmd
, caddr_t data
,
221 struct ifnet
*ifp
, struct proc
*p
)
227 * Allocate an ndrv control block and some buffer space for the socket
230 ndrv_attach(struct socket
*so
, int proto
, struct proc
*p
)
233 register struct ndrv_cb
*np
= sotondrvcb(so
);
235 if ((so
->so_state
& SS_PRIV
) == 0)
239 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
241 MALLOC(np
, struct ndrv_cb
*, sizeof(*np
), M_PCB
, M_WAITOK
);
244 so
->so_pcb
= (caddr_t
)np
;
245 bzero(np
, sizeof(*np
));
247 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
249 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
251 TAILQ_INIT(&np
->nd_dlist
);
252 np
->nd_signature
= NDRV_SIGNATURE
;
254 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
255 np
->nd_proto
.sp_protocol
= proto
;
260 insque((queue_t
)np
, (queue_t
)&ndrvl
);
265 * Destroy state just before socket deallocation.
266 * Flush data or not depending on the options.
270 ndrv_detach(struct socket
*so
)
272 register struct ndrv_cb
*np
= sotondrvcb(so
);
276 return ndrv_do_detach(np
);
281 * If a socket isn't bound to a single address,
282 * the ndrv input routine will hand it anything
283 * within that protocol family (assuming there's
284 * nothing else around it should go to).
286 * Don't expect this to be used.
289 int ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
291 register struct ndrv_cb
*np
= sotondrvcb(so
);
300 /* Allocate memory to store the remote address */
301 MALLOC(np
->nd_faddr
, struct sockaddr_ndrv
*,
302 nam
->sa_len
, M_IFADDR
, M_WAITOK
);
305 if (np
->nd_faddr
== NULL
)
308 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, nam
->sa_len
);
314 * This is the "driver open" hook - we 'bind' to the
316 * Here's where we latch onto the driver.
319 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
321 register struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
322 register char *dname
;
323 register struct ndrv_cb
*np
;
324 register struct ifnet
*ifp
;
325 extern int name_cmp(struct ifnet
*, char *);
328 if TAILQ_EMPTY(&ifnet
)
329 return(EADDRNOTAVAIL
); /* Quick sanity check */
335 return EINVAL
; /* XXX */
337 /* I think we just latch onto a copy here; the caller frees */
338 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
339 if (np
->nd_laddr
== NULL
)
341 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
342 dname
= sa
->snd_name
;
346 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
348 /* Track down the driver and its ifnet structure.
349 * There's no internal call for this so we have to dup the code
352 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
353 if (name_cmp(ifp
, dname
) == 0)
358 return(EADDRNOTAVAIL
);
361 * Loopback demuxing doesn't work with PF_NDRV.
362 * The first 4 bytes of the packet must be the
363 * protocol ptr. Can't get that from userland.
365 if (ifp
->if_family
== APPLE_IF_FAM_LOOPBACK
)
368 if ((dlil_find_dltag(ifp
->if_family
, ifp
->if_unit
,
369 PF_NDRV
, &np
->nd_send_tag
) != 0) &&
370 (ifp
->if_family
!= APPLE_IF_FAM_PPP
)) {
371 /* NDRV isn't registered on this interface, lets change that */
372 struct dlil_proto_reg_str ndrv_proto
;
374 bzero(&ndrv_proto
, sizeof(ndrv_proto
));
375 TAILQ_INIT(&ndrv_proto
.demux_desc_head
);
377 ndrv_proto
.interface_family
= ifp
->if_family
;
378 ndrv_proto
.protocol_family
= PF_NDRV
;
379 ndrv_proto
.unit_number
= ifp
->if_unit
;
381 result
= dlil_attach_protocol(&ndrv_proto
, &np
->nd_send_tag
);
384 * If the interface does not allow PF_NDRV to attach, we will
385 * respect it's wishes. Sending will be disabled. No error is
386 * returned because the client may later attach a real protocol
387 * that the interface may accept.
394 np
->nd_family
= ifp
->if_family
;
395 np
->nd_unit
= ifp
->if_unit
;
401 ndrv_disconnect(struct socket
*so
)
403 register struct ndrv_cb
*np
= sotondrvcb(so
);
408 if (np
->nd_faddr
== 0)
411 ndrv_do_disconnect(np
);
419 ndrv_get_ifp(caddr_t ndrv_pcb
)
421 struct ndrv_cb
* np
= (struct ndrv_cb
*)ndrv_pcb
;
425 struct ndrv_cb
* temp
= ndrvl
.nd_next
;
426 /* Verify existence of pcb */
427 for (temp
= ndrvl
.nd_next
; temp
!= &ndrvl
; temp
= temp
->nd_next
)
435 log(LOG_WARNING
, "PF_NDRV: ndrv_get_ifp called with invalid ndrv_cb!");
445 * Mark the connection as being incapable of further input.
448 ndrv_shutdown(struct socket
*so
)
455 * Ship a packet out. The ndrv output will pass it
456 * to the appropriate driver. The really tricky part
457 * is the destination address...
460 ndrv_send(struct socket
*so
, int flags
, struct mbuf
*m
,
461 struct sockaddr
*addr
, struct mbuf
*control
,
469 error
= ndrv_output(m
, so
);
476 ndrv_abort(struct socket
*so
)
478 register struct ndrv_cb
*np
= sotondrvcb(so
);
483 ndrv_do_disconnect(np
);
488 ndrv_sense(struct socket
*so
, struct stat
*sb
)
491 * stat: don't bother with a blocksize.
497 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
499 register struct ndrv_cb
*np
= sotondrvcb(so
);
505 if (np
->nd_laddr
== 0)
508 len
= np
->nd_laddr
->snd_len
;
509 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
516 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
518 register struct ndrv_cb
*np
= sotondrvcb(so
);
524 if (np
->nd_faddr
== 0)
527 len
= np
->nd_faddr
->snd_len
;
528 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
537 ndrv_ctlinput(int dummy1
, struct sockaddr
*dummy2
, void *dummy3
)
544 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
546 register struct ndrv_cb
*np
= sotondrvcb(so
);
549 switch(sopt
->sopt_name
)
551 case NDRV_DELDMXSPEC
: /* Delete current spec */
552 /* Verify no parameter was passed */
553 if (sopt
->sopt_val
!= NULL
|| sopt
->sopt_valsize
!= 0) {
555 * We don't support deleting a specific demux, it's
560 error
= ndrv_delspec(np
);
562 case NDRV_SETDMXSPEC
: /* Set protocol spec */
563 error
= ndrv_setspec(np
, sopt
);
565 case NDRV_ADDMULTICAST
:
566 error
= ndrv_do_add_multicast(np
, sopt
);
568 case NDRV_DELMULTICAST
:
569 error
= ndrv_do_remove_multicast(np
, sopt
);
575 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
581 /* Drain the queues */
587 /* Sysctl hook for NDRV */
595 ndrv_do_detach(register struct ndrv_cb
*np
)
597 struct ndrv_cb
* cur_np
= NULL
;
598 struct socket
*so
= np
->nd_socket
;
599 struct ndrv_multicast
* next
;
603 kprintf("NDRV detach: %x, %x\n", so
, np
);
605 ndrv_remove_all_multicast(np
);
609 error
= dlil_detach_protocol(np
->nd_tag
);
612 log(LOG_WARNING
, "NDRV ndrv_do_detach: error %d removing dl_tag %d",
618 /* Remove from the linked list of control blocks */
621 if (np
->nd_send_tag
!= 0)
623 /* Check if this is the last socket attached to this interface */
624 for (cur_np
= ndrvl
.nd_next
; cur_np
!= &ndrvl
; cur_np
= cur_np
->nd_next
)
626 if (cur_np
->nd_family
== np
->nd_family
&&
627 cur_np
->nd_unit
== np
->nd_unit
)
633 /* If there are no other interfaces, detach PF_NDRV from the interface */
634 if (cur_np
== &ndrvl
)
636 dlil_detach_protocol(np
->nd_send_tag
);
640 FREE((caddr_t
)np
, M_PCB
);
647 ndrv_do_disconnect(register struct ndrv_cb
*np
)
650 kprintf("NDRV disconnect: %x\n", np
);
654 FREE(np
->nd_faddr
, M_IFADDR
);
657 if (np
->nd_socket
->so_state
& SS_NOFDREF
)
659 soisdisconnected(np
->nd_socket
);
664 * Try to compare a device name (q) with one of the funky ifnet
665 * device names (ifp).
667 int name_cmp(register struct ifnet
*ifp
, register char *q
)
671 static char *sprint_d();
674 len
= strlen(ifp
->if_name
);
675 strncpy(r
, ifp
->if_name
, IFNAMSIZ
);
677 (void)sprint_d(ifp
->if_unit
, r
, IFNAMSIZ
-(r
-buf
));
679 kprintf("Comparing %s, %s\n", buf
, q
);
681 return(strncmp(buf
, q
, IFNAMSIZ
));
684 /* Hackery - return a string version of a decimal number */
686 sprint_d(n
, buf
, buflen
)
690 { char dbuf
[IFNAMSIZ
];
691 register char *cp
= dbuf
+IFNAMSIZ
-1;
696 *cp
= "0123456789"[n
% 10];
698 } while (n
!= 0 && buflen
> 0);
699 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
704 * When closing, dump any enqueued mbufs.
707 ndrv_flushq(register struct ifqueue
*q
)
709 register struct mbuf
*m
;
722 ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
)
724 struct dlil_proto_reg_str dlilSpec
;
725 struct ndrv_protocol_desc ndrvSpec
;
726 struct dlil_demux_desc
* dlilDemux
= NULL
;
727 struct ndrv_demux_desc
* ndrvDemux
= NULL
;
730 /* Sanity checking */
733 if (np
->nd_if
== NULL
)
735 if (sopt
->sopt_valsize
!= sizeof(struct ndrv_protocol_desc
))
738 /* Copy the ndrvSpec */
739 error
= sooptcopyin(sopt
, &ndrvSpec
, sizeof(struct ndrv_protocol_desc
),
740 sizeof(struct ndrv_protocol_desc
));
744 /* Verify the parameter */
745 if (ndrvSpec
.version
> NDRV_PROTOCOL_DESC_VERS
)
746 return ENOTSUP
; // version is too new!
747 else if (ndrvSpec
.version
< 1)
748 return EINVAL
; // version is not valid
750 /* Allocate storage for demux array */
751 MALLOC(ndrvDemux
, struct ndrv_demux_desc
*,
752 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
), M_TEMP
, M_WAITOK
);
753 if (ndrvDemux
== NULL
)
756 /* Allocate enough dlil_demux_descs */
757 MALLOC(dlilDemux
, struct dlil_demux_desc
*,
758 sizeof(*dlilDemux
) * ndrvSpec
.demux_count
, M_TEMP
, M_WAITOK
);
759 if (dlilDemux
== NULL
)
764 /* Copy the ndrv demux array from userland */
765 error
= copyin(ndrvSpec
.demux_list
, ndrvDemux
,
766 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
));
767 ndrvSpec
.demux_list
= ndrvDemux
;
772 /* At this point, we've at least got enough bytes to start looking around */
775 bzero(&dlilSpec
, sizeof(dlilSpec
));
776 TAILQ_INIT(&dlilSpec
.demux_desc_head
);
777 dlilSpec
.interface_family
= np
->nd_family
;
778 dlilSpec
.unit_number
= np
->nd_unit
;
779 dlilSpec
.input
= ndrv_input
;
780 dlilSpec
.protocol_family
= ndrvSpec
.protocol_family
;
782 for (demuxOn
= 0; demuxOn
< ndrvSpec
.demux_count
; demuxOn
++)
784 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
785 error
= ndrv_to_dlil_demux(&ndrvSpec
.demux_list
[demuxOn
], &dlilDemux
[demuxOn
]);
789 /* Add the dlil_demux_desc to the list */
790 TAILQ_INSERT_TAIL(&dlilSpec
.demux_desc_head
, &dlilDemux
[demuxOn
], next
);
796 /* We've got all our ducks lined up...lets attach! */
797 error
= dlil_attach_protocol(&dlilSpec
, &np
->nd_tag
);
800 /* Free any memory we've allocated */
802 FREE(dlilDemux
, M_TEMP
);
804 FREE(ndrvDemux
, M_TEMP
);
811 ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
)
813 bzero(dlil
, sizeof(*dlil
));
815 if (ndrv
->type
< DLIL_DESC_ETYPE2
)
817 /* using old "type", not supported */
821 if (ndrv
->length
> 28)
826 dlil
->type
= ndrv
->type
;
827 dlil
->native_type
= ndrv
->data
.other
;
828 dlil
->variants
.native_type_length
= ndrv
->length
;
834 ndrv_delspec(struct ndrv_cb
*np
)
841 /* Detach the protocol */
842 result
= dlil_detach_protocol(np
->nd_tag
);
852 ndrv_find_tag(unsigned int tag
)
860 for (np
= ndrvl
.nd_next
; np
!= NULL
; np
= np
->nd_next
)
862 if (np
->nd_tag
== tag
)
873 static int ndrv_dominited
= 0;
875 if (ndrv_dominited
== 0 &&
876 net_add_proto(&ndrvsw
, &ndrvdomain
) == 0)
881 ndrv_read_event(struct socket
* so
, caddr_t ref
, int waitf
)
884 struct mbuf
*m
= NULL
;
885 struct kern_event_msg
*msg
;
886 struct uio auio
= {0};
891 auio
.uio_resid
= 1000000; // large number to get all of the data
892 flags
= MSG_DONTWAIT
;
893 result
= soreceive(so
, (struct sockaddr
**)NULL
, &auio
, &m
,
894 (struct mbuf
**)NULL
, &flags
);
895 if (result
!= 0 || m
== NULL
)
898 // cast the mbuf to a kern_event_msg
899 // this is dangerous, doesn't handle linked mbufs
900 msg
= mtod(m
, struct kern_event_msg
*);
902 // check for detaches, assume even filtering is working
903 if (msg
->event_code
== KEV_DL_IF_DETACHING
||
904 msg
->event_code
== KEV_DL_IF_DETACHED
)
906 struct net_event_data
*ev_data
;
907 ev_data
= (struct net_event_data
*)msg
->event_data
;
908 ndrv_handle_ifp_detach(ev_data
->if_family
, ev_data
->if_unit
);
915 ndrv_handle_ifp_detach(u_long family
, short unit
)
920 /* Find all sockets using this interface. */
921 for (np
= ndrvl
.nd_next
; np
!= &ndrvl
; np
= np
->nd_next
)
923 if (np
->nd_family
== family
&&
926 /* This cb is using the detaching interface, but not for long. */
927 /* Let the protocol go */
931 /* Delete the multicasts first */
932 ndrv_remove_all_multicast(np
);
934 /* Disavow all knowledge of the ifp */
940 /* Make sure sending returns an error */
941 /* Is this safe? Will we drop the funnel? */
942 socantsendmore(np
->nd_socket
);
943 socantrcvmore(np
->nd_socket
);
947 /* Unregister our protocol */
948 if (dlil_find_dltag(family
, unit
, PF_NDRV
, &dl_tag
) == 0) {
949 dlil_detach_protocol(dl_tag
);
954 ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
956 struct ndrv_multiaddr
* ndrv_multi
;
959 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
960 sopt
->sopt_level
!= SOL_NDRVPROTO
)
962 if (np
->nd_if
== NULL
)
966 MALLOC(ndrv_multi
, struct ndrv_multiaddr
*, sizeof(struct ndrv_multiaddr
) -
967 sizeof(struct sockaddr
) + sopt
->sopt_valsize
, M_IFADDR
, M_WAITOK
);
968 if (ndrv_multi
== NULL
)
971 // Copy in the address
972 result
= copyin(sopt
->sopt_val
, &ndrv_multi
->addr
, sopt
->sopt_valsize
);
974 // Validate the sockaddr
975 if (result
== 0 && sopt
->sopt_valsize
!= ndrv_multi
->addr
.sa_len
)
978 if (result
== 0 && ndrv_have_multicast(np
, &ndrv_multi
->addr
))
983 // Try adding the multicast
984 result
= if_addmulti(np
->nd_if
, &ndrv_multi
->addr
, NULL
);
989 // Add to our linked list
990 ndrv_multi
->next
= np
->nd_multiaddrs
;
991 np
->nd_multiaddrs
= ndrv_multi
;
995 // Free up the memory, something went wrong
996 FREE(ndrv_multi
, M_IFADDR
);
1003 ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
1005 struct sockaddr
* multi_addr
;
1006 struct ndrv_multiaddr
* ndrv_entry
= NULL
;
1009 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
1010 sopt
->sopt_level
!= SOL_NDRVPROTO
)
1012 if (np
->nd_if
== NULL
)
1016 MALLOC(multi_addr
, struct sockaddr
*, sopt
->sopt_valsize
,
1018 if (multi_addr
== NULL
)
1021 // Copy in the address
1022 result
= copyin(sopt
->sopt_val
, multi_addr
, sopt
->sopt_valsize
);
1024 // Validate the sockaddr
1025 if (result
== 0 && sopt
->sopt_valsize
!= multi_addr
->sa_len
)
1030 /* Find the old entry */
1031 ndrv_entry
= ndrv_have_multicast(np
, multi_addr
);
1033 if (ndrv_entry
== NULL
)
1039 // Try deleting the multicast
1040 result
= if_delmulti(np
->nd_if
, &ndrv_entry
->addr
);
1045 // Remove from our linked list
1046 struct ndrv_multiaddr
* cur
= np
->nd_multiaddrs
;
1048 if (cur
== ndrv_entry
)
1050 np
->nd_multiaddrs
= cur
->next
;
1054 for (cur
= cur
->next
; cur
!= NULL
; cur
= cur
->next
)
1056 if (cur
->next
== ndrv_entry
)
1058 cur
->next
= cur
->next
->next
;
1065 FREE(ndrv_entry
, M_IFADDR
);
1067 FREE(multi_addr
, M_TEMP
);
1072 static struct ndrv_multiaddr
*
1073 ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* inAddr
)
1075 struct ndrv_multiaddr
* cur
;
1076 for (cur
= np
->nd_multiaddrs
; cur
!= NULL
; cur
= cur
->next
)
1079 if ((inAddr
->sa_len
== cur
->addr
.sa_len
) &&
1080 (bcmp(&cur
->addr
, inAddr
, inAddr
->sa_len
) == 0))
1091 ndrv_remove_all_multicast(struct ndrv_cb
* np
)
1093 struct ndrv_multiaddr
* cur
;
1095 if (np
->nd_if
!= NULL
)
1097 while (np
->nd_multiaddrs
!= NULL
)
1099 cur
= np
->nd_multiaddrs
;
1100 np
->nd_multiaddrs
= cur
->next
;
1102 if_delmulti(np
->nd_if
, &cur
->addr
);
1103 FREE(cur
, M_IFADDR
);
1108 struct pr_usrreqs ndrv_usrreqs
= {
1109 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
1110 ndrv_connect
, pru_connect2_notsupp
, ndrv_control
, ndrv_detach
,
1111 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
1112 pru_rcvoob_notsupp
, ndrv_send
, ndrv_sense
, ndrv_shutdown
,
1113 ndrv_sockaddr
, sosend
, soreceive
, sopoll
1116 struct protosw ndrvsw
=
1117 { SOCK_RAW
, &ndrvdomain
, NDRVPROTO_NDRV
, PR_ATOMIC
|PR_ADDR
,
1118 0, ndrv_output
, ndrv_ctlinput
, ndrv_ctloutput
,
1120 ndrv_drain
, ndrv_sysctl
, &ndrv_usrreqs
1123 struct domain ndrvdomain
=
1124 { AF_NDRV
, "NetDriver", ndrv_dominit
, NULL
, NULL
,
1126 NULL
, NULL
, 0, 0, 0, 0