2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
27 * @(#)ndrv.c 1.1 (MacOSX) 6/10/43
28 * Justin Walker, 970604
30 * 980130 - Cleanup, reorg, performance improvemements
31 * 000816 - Removal of Y adapter cruft
35 * PF_NDRV allows raw access to a specified network device, directly
36 * with a socket. Expected use involves a socket option to request
37 * protocol packets. This lets ndrv_output() call dlil_output(), and
38 * lets DLIL find the proper recipient for incoming packets.
39 * The purpose here is for user-mode protocol implementation.
40 * Note that "pure raw access" will still be accomplished with BPF.
42 * In addition to the former use, when combined with socket NKEs,
43 * PF_NDRV permits a fairly flexible mechanism for implementing
44 * strange protocol support. One of the main ones will be the
45 * BlueBox/Classic Shared IP Address support.
47 #include <mach/mach_types.h>
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/malloc.h>
54 #include <sys/protosw.h>
55 #include <sys/domain.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/ioctl.h>
59 #include <sys/errno.h>
60 #include <sys/syslog.h>
63 #include <kern/queue.h>
66 #include <net/netisr.h>
67 #include <net/route.h>
68 #include <net/if_llc.h>
69 #include <net/if_dl.h>
70 #include <net/if_types.h>
71 #include <net/ndrv_var.h>
74 #include <netinet/in.h>
75 #include <netinet/in_var.h>
77 #include <netinet/if_ether.h>
79 #include <machine/spl.h>
81 int ndrv_do_detach(struct ndrv_cb
*);
82 int ndrv_do_disconnect(struct ndrv_cb
*);
83 struct ndrv_cb
*ndrv_find_tag(unsigned int);
84 void ndrv_read_event(struct socket
* inSo
, caddr_t ref
, int waitf
);
85 int ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
);
86 int ndrv_delspec(struct ndrv_cb
*);
87 int ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
);
88 void ndrv_handle_ifp_detach(u_long family
, short unit
);
89 static int ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
);
90 static int ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
);
91 static struct ndrv_multiaddr
* ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* addr
);
92 static void ndrv_remove_all_multicast(struct ndrv_cb
*np
);
94 unsigned long ndrv_sendspace
= NDRVSNDQ
;
95 unsigned long ndrv_recvspace
= NDRVRCVQ
;
96 struct ndrv_cb ndrvl
; /* Head of controlblock list */
98 struct domain ndrvdomain
;
99 struct protosw ndrvsw
;
100 static struct socket
* ndrv_so
;
104 * Protocol init function for NDRV protocol
105 * Init the control block list.
111 struct kev_request kev_request
;
113 ndrvl
.nd_next
= ndrvl
.nd_prev
= &ndrvl
;
115 /* Create a PF_SYSTEM socket so we can listen for events */
116 retval
= socreate(PF_SYSTEM
, &ndrv_so
, SOCK_RAW
, SYSPROTO_EVENT
);
117 if (retval
!= 0 || ndrv_so
== NULL
)
118 retval
= KERN_FAILURE
;
120 /* Install a callback function for the socket */
121 ndrv_so
->so_rcv
.sb_flags
|= SB_NOTIFY
|SB_UPCALL
;
122 ndrv_so
->so_upcall
= ndrv_read_event
;
123 ndrv_so
->so_upcallarg
= NULL
;
125 /* Configure the socket to receive the events we're interested in */
126 kev_request
.vendor_code
= KEV_VENDOR_APPLE
;
127 kev_request
.kev_class
= KEV_NETWORK_CLASS
;
128 kev_request
.kev_subclass
= KEV_DL_SUBCLASS
;
129 retval
= ndrv_so
->so_proto
->pr_usrreqs
->pru_control(ndrv_so
, SIOCSKEVFILT
, (caddr_t
)&kev_request
, 0, 0);
133 * We will not get attaching or detaching events in this case.
134 * We should probably prevent any sockets from binding so we won't
135 * panic later if the interface goes away.
137 log(LOG_WARNING
, "PF_NDRV: ndrv_init - failed to set event filter (%d)",
143 * Protocol output - Called to output a raw network packet directly
147 ndrv_output(register struct mbuf
*m
, register struct socket
*so
)
149 register struct ndrv_cb
*np
= sotondrvcb(so
);
150 register struct ifnet
*ifp
= np
->nd_if
;
151 extern void kprintf(const char *, ...);
155 kprintf("NDRV output: %x, %x, %x\n", m
, so
, np
);
159 * No header is a format error
161 if ((m
->m_flags
&M_PKTHDR
) == 0)
165 * Call DLIL if we can. DLIL is much safer than calling the
169 result
= dlil_output(np
->nd_tag
, m
, (caddr_t
)NULL
,
170 (struct sockaddr
*)NULL
, 1);
171 else if (np
->nd_send_tag
!= 0)
172 result
= dlil_output(np
->nd_send_tag
, m
, (caddr_t
)NULL
,
173 (struct sockaddr
*)NULL
, 1);
179 /* Our input routine called from DLIL */
181 ndrv_input(struct mbuf
*m
,
188 struct sockaddr_dl ndrvsrc
= {sizeof (struct sockaddr_dl
), AF_NDRV
};
189 register struct ndrv_cb
*np
;
192 /* move packet from if queue to socket */
193 /* Should be media-independent */
194 ndrvsrc
.sdl_type
= IFT_ETHER
;
195 ndrvsrc
.sdl_nlen
= 0;
196 ndrvsrc
.sdl_alen
= 6;
197 ndrvsrc
.sdl_slen
= 0;
198 bcopy(frame_header
, &ndrvsrc
.sdl_data
, 6);
200 np
= ndrv_find_tag(dl_tag
);
206 /* prepend the frame header */
207 m
= m_prepend(m
, ifp
->if_data
.ifi_hdrlen
, M_NOWAIT
);
210 bcopy(frame_header
, m
->m_data
, ifp
->if_data
.ifi_hdrlen
);
211 if (sbappendaddr(&(so
->so_rcv
), (struct sockaddr
*)&ndrvsrc
,
212 m
, (struct mbuf
*)0) == 0)
214 /* yes, sbappendaddr returns zero if the sockbuff is full... */
215 /* caller will free m */
223 ndrv_control(struct socket
*so
, u_long cmd
, caddr_t data
,
224 struct ifnet
*ifp
, struct proc
*p
)
230 * Allocate an ndrv control block and some buffer space for the socket
233 ndrv_attach(struct socket
*so
, int proto
, struct proc
*p
)
236 register struct ndrv_cb
*np
= sotondrvcb(so
);
238 if ((so
->so_state
& SS_PRIV
) == 0)
242 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
244 MALLOC(np
, struct ndrv_cb
*, sizeof(*np
), M_PCB
, M_WAITOK
);
247 so
->so_pcb
= (caddr_t
)np
;
248 bzero(np
, sizeof(*np
));
250 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
252 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
254 TAILQ_INIT(&np
->nd_dlist
);
255 np
->nd_signature
= NDRV_SIGNATURE
;
257 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
258 np
->nd_proto
.sp_protocol
= proto
;
263 insque((queue_t
)np
, (queue_t
)&ndrvl
);
268 * Destroy state just before socket deallocation.
269 * Flush data or not depending on the options.
273 ndrv_detach(struct socket
*so
)
275 register struct ndrv_cb
*np
= sotondrvcb(so
);
279 return ndrv_do_detach(np
);
284 * If a socket isn't bound to a single address,
285 * the ndrv input routine will hand it anything
286 * within that protocol family (assuming there's
287 * nothing else around it should go to).
289 * Don't expect this to be used.
292 int ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
294 register struct ndrv_cb
*np
= sotondrvcb(so
);
303 /* Allocate memory to store the remote address */
304 MALLOC(np
->nd_faddr
, struct sockaddr_ndrv
*,
305 nam
->sa_len
, M_IFADDR
, M_WAITOK
);
308 if (np
->nd_faddr
== NULL
)
311 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, nam
->sa_len
);
317 * This is the "driver open" hook - we 'bind' to the
319 * Here's where we latch onto the driver.
322 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
324 register struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
325 register char *dname
;
326 register struct ndrv_cb
*np
;
327 register struct ifnet
*ifp
;
328 extern int name_cmp(struct ifnet
*, char *);
331 if TAILQ_EMPTY(&ifnet
)
332 return(EADDRNOTAVAIL
); /* Quick sanity check */
338 return EINVAL
; /* XXX */
340 /* I think we just latch onto a copy here; the caller frees */
341 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
342 if (np
->nd_laddr
== NULL
)
344 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
345 dname
= sa
->snd_name
;
349 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
351 /* Track down the driver and its ifnet structure.
352 * There's no internal call for this so we have to dup the code
355 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
356 if (name_cmp(ifp
, dname
) == 0)
361 return(EADDRNOTAVAIL
);
364 * Loopback demuxing doesn't work with PF_NDRV.
365 * The first 4 bytes of the packet must be the
366 * protocol ptr. Can't get that from userland.
368 if (ifp
->if_family
== APPLE_IF_FAM_LOOPBACK
)
371 if ((dlil_find_dltag(ifp
->if_family
, ifp
->if_unit
,
372 PF_NDRV
, &np
->nd_send_tag
) != 0) &&
373 (ifp
->if_family
!= APPLE_IF_FAM_PPP
)) {
374 /* NDRV isn't registered on this interface, lets change that */
375 struct dlil_proto_reg_str ndrv_proto
;
377 bzero(&ndrv_proto
, sizeof(ndrv_proto
));
378 TAILQ_INIT(&ndrv_proto
.demux_desc_head
);
380 ndrv_proto
.interface_family
= ifp
->if_family
;
381 ndrv_proto
.protocol_family
= PF_NDRV
;
382 ndrv_proto
.unit_number
= ifp
->if_unit
;
384 result
= dlil_attach_protocol(&ndrv_proto
, &np
->nd_send_tag
);
387 * If the interface does not allow PF_NDRV to attach, we will
388 * respect it's wishes. Sending will be disabled. No error is
389 * returned because the client may later attach a real protocol
390 * that the interface may accept.
397 np
->nd_family
= ifp
->if_family
;
398 np
->nd_unit
= ifp
->if_unit
;
404 ndrv_disconnect(struct socket
*so
)
406 register struct ndrv_cb
*np
= sotondrvcb(so
);
411 if (np
->nd_faddr
== 0)
414 ndrv_do_disconnect(np
);
422 ndrv_get_ifp(caddr_t ndrv_pcb
)
424 struct ndrv_cb
* np
= (struct ndrv_cb
*)ndrv_pcb
;
428 struct ndrv_cb
* temp
= ndrvl
.nd_next
;
429 /* Verify existence of pcb */
430 for (temp
= ndrvl
.nd_next
; temp
!= &ndrvl
; temp
= temp
->nd_next
)
438 log(LOG_WARNING
, "PF_NDRV: ndrv_get_ifp called with invalid ndrv_cb!");
448 * Mark the connection as being incapable of further input.
451 ndrv_shutdown(struct socket
*so
)
458 * Ship a packet out. The ndrv output will pass it
459 * to the appropriate driver. The really tricky part
460 * is the destination address...
463 ndrv_send(struct socket
*so
, int flags
, struct mbuf
*m
,
464 struct sockaddr
*addr
, struct mbuf
*control
,
472 error
= ndrv_output(m
, so
);
479 ndrv_abort(struct socket
*so
)
481 register struct ndrv_cb
*np
= sotondrvcb(so
);
486 ndrv_do_disconnect(np
);
491 ndrv_sense(struct socket
*so
, struct stat
*sb
)
494 * stat: don't bother with a blocksize.
500 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
502 register struct ndrv_cb
*np
= sotondrvcb(so
);
508 if (np
->nd_laddr
== 0)
511 len
= np
->nd_laddr
->snd_len
;
512 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
519 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
521 register struct ndrv_cb
*np
= sotondrvcb(so
);
527 if (np
->nd_faddr
== 0)
530 len
= np
->nd_faddr
->snd_len
;
531 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
540 ndrv_ctlinput(int dummy1
, struct sockaddr
*dummy2
, void *dummy3
)
547 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
549 register struct ndrv_cb
*np
= sotondrvcb(so
);
552 switch(sopt
->sopt_name
)
554 case NDRV_DELDMXSPEC
: /* Delete current spec */
555 /* Verify no parameter was passed */
556 if (sopt
->sopt_val
!= NULL
|| sopt
->sopt_valsize
!= 0) {
558 * We don't support deleting a specific demux, it's
563 error
= ndrv_delspec(np
);
565 case NDRV_SETDMXSPEC
: /* Set protocol spec */
566 error
= ndrv_setspec(np
, sopt
);
568 case NDRV_ADDMULTICAST
:
569 error
= ndrv_do_add_multicast(np
, sopt
);
571 case NDRV_DELMULTICAST
:
572 error
= ndrv_do_remove_multicast(np
, sopt
);
578 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
584 /* Drain the queues */
590 /* Sysctl hook for NDRV */
598 ndrv_do_detach(register struct ndrv_cb
*np
)
600 struct ndrv_cb
* cur_np
= NULL
;
601 struct socket
*so
= np
->nd_socket
;
602 struct ndrv_multicast
* next
;
606 kprintf("NDRV detach: %x, %x\n", so
, np
);
608 ndrv_remove_all_multicast(np
);
612 error
= dlil_detach_protocol(np
->nd_tag
);
615 log(LOG_WARNING
, "NDRV ndrv_do_detach: error %d removing dl_tag %d",
621 /* Remove from the linked list of control blocks */
624 if (np
->nd_send_tag
!= 0)
626 /* Check if this is the last socket attached to this interface */
627 for (cur_np
= ndrvl
.nd_next
; cur_np
!= &ndrvl
; cur_np
= cur_np
->nd_next
)
629 if (cur_np
->nd_family
== np
->nd_family
&&
630 cur_np
->nd_unit
== np
->nd_unit
)
636 /* If there are no other interfaces, detach PF_NDRV from the interface */
637 if (cur_np
== &ndrvl
)
639 dlil_detach_protocol(np
->nd_send_tag
);
643 FREE((caddr_t
)np
, M_PCB
);
650 ndrv_do_disconnect(register struct ndrv_cb
*np
)
653 kprintf("NDRV disconnect: %x\n", np
);
657 FREE(np
->nd_faddr
, M_IFADDR
);
660 if (np
->nd_socket
->so_state
& SS_NOFDREF
)
662 soisdisconnected(np
->nd_socket
);
667 * Try to compare a device name (q) with one of the funky ifnet
668 * device names (ifp).
670 int name_cmp(register struct ifnet
*ifp
, register char *q
)
674 static char *sprint_d();
677 len
= strlen(ifp
->if_name
);
678 strncpy(r
, ifp
->if_name
, IFNAMSIZ
);
680 (void)sprint_d(ifp
->if_unit
, r
, IFNAMSIZ
-(r
-buf
));
682 kprintf("Comparing %s, %s\n", buf
, q
);
684 return(strncmp(buf
, q
, IFNAMSIZ
));
687 /* Hackery - return a string version of a decimal number */
689 sprint_d(n
, buf
, buflen
)
693 { char dbuf
[IFNAMSIZ
];
694 register char *cp
= dbuf
+IFNAMSIZ
-1;
699 *cp
= "0123456789"[n
% 10];
701 } while (n
!= 0 && buflen
> 0);
702 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
707 * When closing, dump any enqueued mbufs.
710 ndrv_flushq(register struct ifqueue
*q
)
712 register struct mbuf
*m
;
725 ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
)
727 struct dlil_proto_reg_str dlilSpec
;
728 struct ndrv_protocol_desc ndrvSpec
;
729 struct dlil_demux_desc
* dlilDemux
= NULL
;
730 struct ndrv_demux_desc
* ndrvDemux
= NULL
;
733 /* Sanity checking */
736 if (np
->nd_if
== NULL
)
738 if (sopt
->sopt_valsize
!= sizeof(struct ndrv_protocol_desc
))
741 /* Copy the ndrvSpec */
742 error
= sooptcopyin(sopt
, &ndrvSpec
, sizeof(struct ndrv_protocol_desc
),
743 sizeof(struct ndrv_protocol_desc
));
747 /* Verify the parameter */
748 if (ndrvSpec
.version
> NDRV_PROTOCOL_DESC_VERS
)
749 return ENOTSUP
; // version is too new!
750 else if (ndrvSpec
.version
< 1)
751 return EINVAL
; // version is not valid
753 /* Allocate storage for demux array */
754 MALLOC(ndrvDemux
, struct ndrv_demux_desc
*,
755 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
), M_TEMP
, M_WAITOK
);
756 if (ndrvDemux
== NULL
)
759 /* Allocate enough dlil_demux_descs */
760 MALLOC(dlilDemux
, struct dlil_demux_desc
*,
761 sizeof(*dlilDemux
) * ndrvSpec
.demux_count
, M_TEMP
, M_WAITOK
);
762 if (dlilDemux
== NULL
)
767 /* Copy the ndrv demux array from userland */
768 error
= copyin(ndrvSpec
.demux_list
, ndrvDemux
,
769 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
));
770 ndrvSpec
.demux_list
= ndrvDemux
;
775 /* At this point, we've at least got enough bytes to start looking around */
778 bzero(&dlilSpec
, sizeof(dlilSpec
));
779 TAILQ_INIT(&dlilSpec
.demux_desc_head
);
780 dlilSpec
.interface_family
= np
->nd_family
;
781 dlilSpec
.unit_number
= np
->nd_unit
;
782 dlilSpec
.input
= ndrv_input
;
783 dlilSpec
.protocol_family
= ndrvSpec
.protocol_family
;
785 for (demuxOn
= 0; demuxOn
< ndrvSpec
.demux_count
; demuxOn
++)
787 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
788 error
= ndrv_to_dlil_demux(&ndrvSpec
.demux_list
[demuxOn
], &dlilDemux
[demuxOn
]);
792 /* Add the dlil_demux_desc to the list */
793 TAILQ_INSERT_TAIL(&dlilSpec
.demux_desc_head
, &dlilDemux
[demuxOn
], next
);
799 /* We've got all our ducks lined up...lets attach! */
800 error
= dlil_attach_protocol(&dlilSpec
, &np
->nd_tag
);
803 /* Free any memory we've allocated */
805 FREE(dlilDemux
, M_TEMP
);
807 FREE(ndrvDemux
, M_TEMP
);
814 ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
)
816 bzero(dlil
, sizeof(*dlil
));
818 if (ndrv
->type
< DLIL_DESC_ETYPE2
)
820 /* using old "type", not supported */
824 if (ndrv
->length
> 28)
829 dlil
->type
= ndrv
->type
;
830 dlil
->native_type
= ndrv
->data
.other
;
831 dlil
->variants
.native_type_length
= ndrv
->length
;
837 ndrv_delspec(struct ndrv_cb
*np
)
844 /* Detach the protocol */
845 result
= dlil_detach_protocol(np
->nd_tag
);
855 ndrv_find_tag(unsigned int tag
)
863 for (np
= ndrvl
.nd_next
; np
!= NULL
; np
= np
->nd_next
)
865 if (np
->nd_tag
== tag
)
876 static int ndrv_dominited
= 0;
878 if (ndrv_dominited
== 0 &&
879 net_add_proto(&ndrvsw
, &ndrvdomain
) == 0)
884 ndrv_read_event(struct socket
* so
, caddr_t ref
, int waitf
)
887 struct mbuf
*m
= NULL
;
888 struct kern_event_msg
*msg
;
889 struct uio auio
= {0};
894 auio
.uio_resid
= 1000000; // large number to get all of the data
895 flags
= MSG_DONTWAIT
;
896 result
= soreceive(so
, (struct sockaddr
**)NULL
, &auio
, &m
,
897 (struct mbuf
**)NULL
, &flags
);
898 if (result
!= 0 || m
== NULL
)
901 // cast the mbuf to a kern_event_msg
902 // this is dangerous, doesn't handle linked mbufs
903 msg
= mtod(m
, struct kern_event_msg
*);
905 // check for detaches, assume even filtering is working
906 if (msg
->event_code
== KEV_DL_IF_DETACHING
||
907 msg
->event_code
== KEV_DL_IF_DETACHED
)
909 struct net_event_data
*ev_data
;
910 ev_data
= (struct net_event_data
*)msg
->event_data
;
911 ndrv_handle_ifp_detach(ev_data
->if_family
, ev_data
->if_unit
);
918 ndrv_handle_ifp_detach(u_long family
, short unit
)
923 /* Find all sockets using this interface. */
924 for (np
= ndrvl
.nd_next
; np
!= &ndrvl
; np
= np
->nd_next
)
926 if (np
->nd_family
== family
&&
929 /* This cb is using the detaching interface, but not for long. */
930 /* Let the protocol go */
934 /* Delete the multicasts first */
935 ndrv_remove_all_multicast(np
);
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
);
957 ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
959 struct ndrv_multiaddr
* ndrv_multi
;
962 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
963 sopt
->sopt_level
!= SOL_NDRVPROTO
)
965 if (np
->nd_if
== NULL
)
969 MALLOC(ndrv_multi
, struct ndrv_multiaddr
*, sizeof(struct ndrv_multiaddr
) -
970 sizeof(struct sockaddr
) + sopt
->sopt_valsize
, M_IFADDR
, M_WAITOK
);
971 if (ndrv_multi
== NULL
)
974 // Copy in the address
975 result
= copyin(sopt
->sopt_val
, &ndrv_multi
->addr
, sopt
->sopt_valsize
);
977 // Validate the sockaddr
978 if (result
== 0 && sopt
->sopt_valsize
!= ndrv_multi
->addr
.sa_len
)
981 if (result
== 0 && ndrv_have_multicast(np
, &ndrv_multi
->addr
))
986 // Try adding the multicast
987 result
= if_addmulti(np
->nd_if
, &ndrv_multi
->addr
, NULL
);
992 // Add to our linked list
993 ndrv_multi
->next
= np
->nd_multiaddrs
;
994 np
->nd_multiaddrs
= ndrv_multi
;
998 // Free up the memory, something went wrong
999 FREE(ndrv_multi
, M_IFADDR
);
1006 ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
1008 struct sockaddr
* multi_addr
;
1009 struct ndrv_multiaddr
* ndrv_entry
= NULL
;
1012 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
1013 sopt
->sopt_level
!= SOL_NDRVPROTO
)
1015 if (np
->nd_if
== NULL
)
1019 MALLOC(multi_addr
, struct sockaddr
*, sopt
->sopt_valsize
,
1021 if (multi_addr
== NULL
)
1024 // Copy in the address
1025 result
= copyin(sopt
->sopt_val
, multi_addr
, sopt
->sopt_valsize
);
1027 // Validate the sockaddr
1028 if (result
== 0 && sopt
->sopt_valsize
!= multi_addr
->sa_len
)
1033 /* Find the old entry */
1034 ndrv_entry
= ndrv_have_multicast(np
, multi_addr
);
1036 if (ndrv_entry
== NULL
)
1042 // Try deleting the multicast
1043 result
= if_delmulti(np
->nd_if
, &ndrv_entry
->addr
);
1048 // Remove from our linked list
1049 struct ndrv_multiaddr
* cur
= np
->nd_multiaddrs
;
1051 if (cur
== ndrv_entry
)
1053 np
->nd_multiaddrs
= cur
->next
;
1057 for (cur
= cur
->next
; cur
!= NULL
; cur
= cur
->next
)
1059 if (cur
->next
== ndrv_entry
)
1061 cur
->next
= cur
->next
->next
;
1068 FREE(ndrv_entry
, M_IFADDR
);
1070 FREE(multi_addr
, M_TEMP
);
1075 static struct ndrv_multiaddr
*
1076 ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* inAddr
)
1078 struct ndrv_multiaddr
* cur
;
1079 for (cur
= np
->nd_multiaddrs
; cur
!= NULL
; cur
= cur
->next
)
1082 if ((inAddr
->sa_len
== cur
->addr
.sa_len
) &&
1083 (bcmp(&cur
->addr
, inAddr
, inAddr
->sa_len
) == 0))
1094 ndrv_remove_all_multicast(struct ndrv_cb
* np
)
1096 struct ndrv_multiaddr
* cur
;
1098 if (np
->nd_if
!= NULL
)
1100 while (np
->nd_multiaddrs
!= NULL
)
1102 cur
= np
->nd_multiaddrs
;
1103 np
->nd_multiaddrs
= cur
->next
;
1105 if_delmulti(np
->nd_if
, &cur
->addr
);
1106 FREE(cur
, M_IFADDR
);
1111 struct pr_usrreqs ndrv_usrreqs
= {
1112 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
1113 ndrv_connect
, pru_connect2_notsupp
, ndrv_control
, ndrv_detach
,
1114 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
1115 pru_rcvoob_notsupp
, ndrv_send
, ndrv_sense
, ndrv_shutdown
,
1116 ndrv_sockaddr
, sosend
, soreceive
, sopoll
1119 struct protosw ndrvsw
=
1120 { SOCK_RAW
, &ndrvdomain
, NDRVPROTO_NDRV
, PR_ATOMIC
|PR_ADDR
,
1121 0, ndrv_output
, ndrv_ctlinput
, ndrv_ctloutput
,
1123 ndrv_drain
, ndrv_sysctl
, &ndrv_usrreqs
1126 struct domain ndrvdomain
=
1127 { AF_NDRV
, "NetDriver", ndrv_dominit
, NULL
, NULL
,
1129 NULL
, NULL
, 0, 0, 0, 0