2 * Copyright (c) 2000-2004 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/route.h>
64 #include <net/if_llc.h>
65 #include <net/if_dl.h>
66 #include <net/if_types.h>
67 #include <net/ndrv_var.h>
70 #include <netinet/in.h>
71 #include <netinet/in_var.h>
73 #include <netinet/if_ether.h>
75 #include <machine/spl.h>
77 static int ndrv_do_detach(struct ndrv_cb
*);
78 static int ndrv_do_disconnect(struct ndrv_cb
*);
79 static struct ndrv_cb
*ndrv_find_inbound(struct ifnet
*ifp
, u_long protocol_family
);
80 static int ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
);
81 static int ndrv_delspec(struct ndrv_cb
*);
82 static int ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
);
83 static void ndrv_handle_ifp_detach(u_long family
, short unit
);
84 static int ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
);
85 static int ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
);
86 static struct ndrv_multiaddr
* ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* addr
);
87 static void ndrv_remove_all_multicast(struct ndrv_cb
*np
);
89 unsigned long ndrv_sendspace
= NDRVSNDQ
;
90 unsigned long ndrv_recvspace
= NDRVRCVQ
;
91 TAILQ_HEAD(, ndrv_cb
) ndrvl
= TAILQ_HEAD_INITIALIZER(ndrvl
);
93 extern struct domain ndrvdomain
;
94 extern struct protosw ndrvsw
;
95 extern lck_mtx_t
*domain_proto_mtx
;
97 extern void kprintf(const char *, ...);
100 * Verify these values match.
101 * To keep clients from including dlil.h, we define
102 * these values independently in ndrv.h. They must
103 * match or a conversion function must be written.
105 #if NDRV_DEMUXTYPE_ETHERTYPE != DLIL_DESC_ETYPE2
106 #error NDRV_DEMUXTYPE_ETHERTYPE must match DLIL_DESC_ETYPE2
108 #if NDRV_DEMUXTYPE_SAP != DLIL_DESC_SAP
109 #error NDRV_DEMUXTYPE_SAP must match DLIL_DESC_SAP
111 #if NDRV_DEMUXTYPE_SNAP != DLIL_DESC_SNAP
112 #error NDRV_DEMUXTYPE_SNAP must match DLIL_DESC_SNAP
116 * Protocol output - Called to output a raw network packet directly
120 ndrv_output(struct mbuf
*m
, struct socket
*so
)
122 struct ndrv_cb
*np
= sotondrvcb(so
);
123 struct ifnet
*ifp
= np
->nd_if
;
127 kprintf("NDRV output: %x, %x, %x\n", m
, so
, np
);
131 * No header is a format error
133 if ((m
->m_flags
&M_PKTHDR
) == 0)
136 /* Unlock before calling dlil_output */
137 socket_unlock(so
, 0);
140 * Call DLIL if we can. DLIL is much safer than calling the
143 result
= dlil_output(ifp
, np
->nd_proto_family
, m
, (caddr_t
)NULL
,
144 (struct sockaddr
*)NULL
, 1);
151 /* Our input routine called from DLIL */
153 ndrv_input(struct mbuf
*m
,
157 __unused
int sync_ok
)
160 struct sockaddr_dl ndrvsrc
= {sizeof (struct sockaddr_dl
), AF_NDRV
};
165 /* move packet from if queue to socket */
166 /* Should be media-independent */
167 ndrvsrc
.sdl_type
= IFT_ETHER
;
168 ndrvsrc
.sdl_nlen
= 0;
169 ndrvsrc
.sdl_alen
= 6;
170 ndrvsrc
.sdl_slen
= 0;
171 bcopy(frame_header
, &ndrvsrc
.sdl_data
, 6);
173 np
= ndrv_find_inbound(ifp
, proto_family
);
179 /* prepend the frame header */
180 m
= m_prepend(m
, ifp
->if_hdrlen
, M_NOWAIT
);
183 bcopy(frame_header
, m
->m_data
, ifp
->if_hdrlen
);
185 lck_mtx_assert(so
->so_proto
->pr_domain
->dom_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
186 lck_mtx_lock(so
->so_proto
->pr_domain
->dom_mtx
);
187 if (sbappendaddr(&(so
->so_rcv
), (struct sockaddr
*)&ndrvsrc
,
188 m
, (struct mbuf
*)0, &error
) != 0) {
191 lck_mtx_unlock(so
->so_proto
->pr_domain
->dom_mtx
);
192 return 0; /* radar 4030377 - always return 0 */
196 * Allocate an ndrv control block and some buffer space for the socket
199 ndrv_attach(struct socket
*so
, int proto
, __unused
struct proc
*p
)
202 struct ndrv_cb
*np
= sotondrvcb(so
);
204 if ((so
->so_state
& SS_PRIV
) == 0)
208 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
211 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
214 MALLOC(np
, struct ndrv_cb
*, sizeof(*np
), M_PCB
, M_WAITOK
);
217 so
->so_pcb
= (caddr_t
)np
;
218 bzero(np
, sizeof(*np
));
220 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
222 TAILQ_INIT(&np
->nd_dlist
);
223 np
->nd_signature
= NDRV_SIGNATURE
;
225 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
226 np
->nd_proto
.sp_protocol
= proto
;
228 np
->nd_proto_family
= 0;
231 TAILQ_INSERT_TAIL(&ndrvl
, np
, nd_next
);
236 * Destroy state just before socket deallocation.
237 * Flush data or not depending on the options.
241 ndrv_detach(struct socket
*so
)
243 struct ndrv_cb
*np
= sotondrvcb(so
);
247 return ndrv_do_detach(np
);
252 * If a socket isn't bound to a single address,
253 * the ndrv input routine will hand it anything
254 * within that protocol family (assuming there's
255 * nothing else around it should go to).
257 * Don't expect this to be used.
261 ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, __unused
struct proc
*p
)
263 struct ndrv_cb
*np
= sotondrvcb(so
);
272 /* Allocate memory to store the remote address */
273 MALLOC(np
->nd_faddr
, struct sockaddr_ndrv
*,
274 nam
->sa_len
, M_IFADDR
, M_WAITOK
);
277 if (np
->nd_faddr
== NULL
)
280 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, nam
->sa_len
);
286 ndrv_event(struct ifnet
*ifp
, struct kev_msg
*event
)
288 if (event
->vendor_code
== KEV_VENDOR_APPLE
&&
289 event
->kev_class
== KEV_NETWORK_CLASS
&&
290 event
->kev_subclass
== KEV_DL_SUBCLASS
&&
291 event
->event_code
== KEV_DL_IF_DETACHING
) {
292 lck_mtx_assert(ndrvdomain
.dom_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
293 lck_mtx_lock(ndrvdomain
.dom_mtx
);
294 ndrv_handle_ifp_detach(ifp
->if_family
, ifp
->if_unit
);
295 lck_mtx_unlock(ndrvdomain
.dom_mtx
);
299 static int name_cmp(struct ifnet
*, char *);
302 * This is the "driver open" hook - we 'bind' to the
304 * Here's where we latch onto the driver.
307 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, __unused
struct proc
*p
)
309 struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
315 if TAILQ_EMPTY(&ifnet_head
)
316 return(EADDRNOTAVAIL
); /* Quick sanity check */
322 return EINVAL
; /* XXX */
324 /* I think we just latch onto a copy here; the caller frees */
325 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
326 if (np
->nd_laddr
== NULL
)
328 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
329 dname
= sa
->snd_name
;
333 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
335 /* Track down the driver and its ifnet structure.
336 * There's no internal call for this so we have to dup the code
339 ifnet_head_lock_shared();
340 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
341 if (name_cmp(ifp
, dname
) == 0)
347 return(EADDRNOTAVAIL
);
349 // PPP doesn't support PF_NDRV.
350 if (ifp
->if_family
!= APPLE_IF_FAM_PPP
)
352 /* NDRV on this interface */
353 struct dlil_proto_reg_str ndrv_proto
;
355 bzero(&ndrv_proto
, sizeof(ndrv_proto
));
356 TAILQ_INIT(&ndrv_proto
.demux_desc_head
);
358 ndrv_proto
.interface_family
= ifp
->if_family
;
359 ndrv_proto
.protocol_family
= PF_NDRV
;
360 ndrv_proto
.unit_number
= ifp
->if_unit
;
361 ndrv_proto
.event
= ndrv_event
;
363 /* We aren't worried about double attaching, that should just return an error */
364 socket_unlock(so
, 0);
365 result
= dlil_attach_protocol(&ndrv_proto
);
367 if (result
&& result
!= EEXIST
) {
370 np
->nd_proto_family
= PF_NDRV
;
373 np
->nd_proto_family
= 0;
377 np
->nd_family
= ifp
->if_family
;
378 np
->nd_unit
= ifp
->if_unit
;
384 ndrv_disconnect(struct socket
*so
)
386 struct ndrv_cb
*np
= sotondrvcb(so
);
391 if (np
->nd_faddr
== 0)
394 ndrv_do_disconnect(np
);
399 * Mark the connection as being incapable of further input.
402 ndrv_shutdown(struct socket
*so
)
404 lck_mtx_assert(so
->so_proto
->pr_domain
->dom_mtx
, LCK_MTX_ASSERT_OWNED
);
410 * Ship a packet out. The ndrv output will pass it
411 * to the appropriate driver. The really tricky part
412 * is the destination address...
415 ndrv_send(struct socket
*so
, __unused
int flags
, struct mbuf
*m
,
416 __unused
struct sockaddr
*addr
, struct mbuf
*control
,
417 __unused
struct proc
*p
)
424 error
= ndrv_output(m
, so
);
431 ndrv_abort(struct socket
*so
)
433 struct ndrv_cb
*np
= sotondrvcb(so
);
438 ndrv_do_disconnect(np
);
443 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
445 struct ndrv_cb
*np
= sotondrvcb(so
);
451 if (np
->nd_laddr
== 0)
454 len
= np
->nd_laddr
->snd_len
;
455 MALLOC(*nam
, struct sockaddr
*, len
, M_SONAME
, M_WAITOK
);
458 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
465 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
467 struct ndrv_cb
*np
= sotondrvcb(so
);
473 if (np
->nd_faddr
== 0)
476 len
= np
->nd_faddr
->snd_len
;
477 MALLOC(*nam
, struct sockaddr
*, len
, M_SONAME
, M_WAITOK
);
480 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
489 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
491 struct ndrv_cb
*np
= sotondrvcb(so
);
494 switch(sopt
->sopt_name
)
496 case NDRV_DELDMXSPEC
: /* Delete current spec */
497 /* Verify no parameter was passed */
498 if (sopt
->sopt_val
!= NULL
|| sopt
->sopt_valsize
!= 0) {
500 * We don't support deleting a specific demux, it's
505 error
= ndrv_delspec(np
);
507 case NDRV_SETDMXSPEC
: /* Set protocol spec */
508 error
= ndrv_setspec(np
, sopt
);
510 case NDRV_ADDMULTICAST
:
511 error
= ndrv_do_add_multicast(np
, sopt
);
513 case NDRV_DELMULTICAST
:
514 error
= ndrv_do_remove_multicast(np
, sopt
);
520 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
527 ndrv_do_detach(struct ndrv_cb
*np
)
529 struct ndrv_cb
* cur_np
= NULL
;
530 struct socket
*so
= np
->nd_socket
;
535 kprintf("NDRV detach: %x, %x\n", so
, np
);
537 ndrv_remove_all_multicast(np
);
539 /* Remove from the linked list of control blocks */
540 TAILQ_REMOVE(&ndrvl
, np
, nd_next
);
542 u_long proto_family
= np
->nd_proto_family
;
544 if (proto_family
!= PF_NDRV
&& proto_family
!= 0) {
545 socket_unlock(so
, 0);
546 dlil_detach_protocol(ifp
, proto_family
);
550 /* Check if this is the last socket attached to this interface */
551 TAILQ_FOREACH(cur_np
, &ndrvl
, nd_next
) {
552 if (cur_np
->nd_family
== np
->nd_family
&&
553 cur_np
->nd_unit
== np
->nd_unit
) {
558 /* If there are no other interfaces, detach PF_NDRV from the interface */
559 if (cur_np
== NULL
) {
560 socket_unlock(so
, 0);
561 dlil_detach_protocol(ifp
, PF_NDRV
);
566 if (np
->nd_laddr
!= NULL
) {
567 FREE((caddr_t
)np
->nd_laddr
, M_IFADDR
);
570 FREE((caddr_t
)np
, M_PCB
);
572 so
->so_flags
|= SOF_PCBCLEARING
;
578 ndrv_do_disconnect(struct ndrv_cb
*np
)
580 struct socket
* so
= np
->nd_socket
;
582 kprintf("NDRV disconnect: %x\n", np
);
586 FREE(np
->nd_faddr
, M_IFADDR
);
589 if (so
->so_state
& SS_NOFDREF
)
591 soisdisconnected(so
);
595 /* Hackery - return a string version of a decimal number */
597 sprint_d(u_int n
, char *buf
, int buflen
)
598 { char dbuf
[IFNAMSIZ
];
599 char *cp
= dbuf
+IFNAMSIZ
-1;
604 *cp
= "0123456789"[n
% 10];
606 } while (n
!= 0 && buflen
> 0);
607 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
612 * Try to compare a device name (q) with one of the funky ifnet
613 * device names (ifp).
615 static int name_cmp(struct ifnet
*ifp
, char *q
)
621 len
= strlen(ifp
->if_name
);
622 strncpy(r
, ifp
->if_name
, IFNAMSIZ
);
624 (void)sprint_d(ifp
->if_unit
, r
, IFNAMSIZ
-(r
-buf
));
626 kprintf("Comparing %s, %s\n", buf
, q
);
628 return(strncmp(buf
, q
, IFNAMSIZ
));
634 * When closing, dump any enqueued mbufs.
637 ndrv_flushq(struct ifqueue
*q
)
653 ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
)
655 struct dlil_proto_reg_str dlilSpec
;
656 struct ndrv_protocol_desc ndrvSpec
;
657 struct dlil_demux_desc
* dlilDemux
= NULL
;
658 struct ndrv_demux_desc
* ndrvDemux
= NULL
;
660 struct socket
*so
= np
->nd_socket
;
662 /* Sanity checking */
663 if (np
->nd_proto_family
!= PF_NDRV
)
665 if (np
->nd_if
== NULL
)
667 if (sopt
->sopt_valsize
!= sizeof(struct ndrv_protocol_desc
))
670 /* Copy the ndrvSpec */
671 error
= sooptcopyin(sopt
, &ndrvSpec
, sizeof(struct ndrv_protocol_desc
),
672 sizeof(struct ndrv_protocol_desc
));
676 /* Verify the parameter */
677 if (ndrvSpec
.version
> NDRV_PROTOCOL_DESC_VERS
)
678 return ENOTSUP
; // version is too new!
679 else if (ndrvSpec
.version
< 1)
680 return EINVAL
; // version is not valid
682 /* Allocate storage for demux array */
683 MALLOC(ndrvDemux
, struct ndrv_demux_desc
*,
684 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
), M_TEMP
, M_WAITOK
);
685 if (ndrvDemux
== NULL
)
688 /* Allocate enough dlil_demux_descs */
689 MALLOC(dlilDemux
, struct dlil_demux_desc
*,
690 sizeof(*dlilDemux
) * ndrvSpec
.demux_count
, M_TEMP
, M_WAITOK
);
691 if (dlilDemux
== NULL
)
696 /* Copy the ndrv demux array from userland */
697 error
= copyin(CAST_USER_ADDR_T(ndrvSpec
.demux_list
), ndrvDemux
,
698 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
));
699 ndrvSpec
.demux_list
= ndrvDemux
;
704 /* At this point, we've at least got enough bytes to start looking around */
707 bzero(&dlilSpec
, sizeof(dlilSpec
));
708 TAILQ_INIT(&dlilSpec
.demux_desc_head
);
709 dlilSpec
.interface_family
= np
->nd_family
;
710 dlilSpec
.unit_number
= np
->nd_unit
;
711 dlilSpec
.input
= ndrv_input
;
712 dlilSpec
.event
= ndrv_event
;
713 dlilSpec
.protocol_family
= ndrvSpec
.protocol_family
;
715 for (demuxOn
= 0; demuxOn
< ndrvSpec
.demux_count
; demuxOn
++)
717 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
718 error
= ndrv_to_dlil_demux(&ndrvSpec
.demux_list
[demuxOn
], &dlilDemux
[demuxOn
]);
722 /* Add the dlil_demux_desc to the list */
723 TAILQ_INSERT_TAIL(&dlilSpec
.demux_desc_head
, &dlilDemux
[demuxOn
], next
);
729 /* We've got all our ducks lined up...lets attach! */
730 socket_unlock(so
, 0);
731 error
= dlil_attach_protocol(&dlilSpec
);
734 np
->nd_proto_family
= dlilSpec
.protocol_family
;
737 /* Free any memory we've allocated */
739 FREE(dlilDemux
, M_TEMP
);
741 FREE(ndrvDemux
, M_TEMP
);
748 ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
)
750 bzero(dlil
, sizeof(*dlil
));
752 if (ndrv
->type
< DLIL_DESC_ETYPE2
)
754 /* using old "type", not supported */
758 if (ndrv
->length
> 28)
763 dlil
->type
= ndrv
->type
;
764 dlil
->native_type
= ndrv
->data
.other
;
765 dlil
->variants
.native_type_length
= ndrv
->length
;
771 ndrv_delspec(struct ndrv_cb
*np
)
775 if (np
->nd_proto_family
== PF_NDRV
||
776 np
->nd_proto_family
== 0)
779 /* Detach the protocol */
780 result
= dlil_detach_protocol(np
->nd_if
, np
->nd_proto_family
);
781 np
->nd_proto_family
= PF_NDRV
;
787 ndrv_find_inbound(struct ifnet
*ifp
, u_long protocol
)
791 if (protocol
== PF_NDRV
) return NULL
;
793 TAILQ_FOREACH(np
, &ndrvl
, nd_next
) {
794 if (np
->nd_proto_family
== protocol
&&
803 static void ndrv_dominit(void)
805 static int ndrv_dominited
= 0;
807 if (ndrv_dominited
== 0 &&
808 net_add_proto(&ndrvsw
, &ndrvdomain
) == 0)
813 ndrv_handle_ifp_detach(u_long family
, short unit
)
816 struct ifnet
*ifp
= NULL
;
819 /* Find all sockets using this interface. */
820 TAILQ_FOREACH(np
, &ndrvl
, nd_next
) {
821 if (np
->nd_family
== family
&&
824 /* This cb is using the detaching interface, but not for long. */
825 /* Let the protocol go */
827 if (np
->nd_proto_family
!= 0)
830 /* Delete the multicasts first */
831 ndrv_remove_all_multicast(np
);
833 /* Disavow all knowledge of the ifp */
839 /* Make sure sending returns an error */
840 /* Is this safe? Will we drop the funnel? */
841 lck_mtx_assert(so
->so_proto
->pr_domain
->dom_mtx
, LCK_MTX_ASSERT_OWNED
);
847 /* Unregister our protocol */
849 dlil_detach_protocol(ifp
, PF_NDRV
);
854 ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
856 struct ndrv_multiaddr
* ndrv_multi
;
859 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
860 sopt
->sopt_level
!= SOL_NDRVPROTO
)
862 if (np
->nd_if
== NULL
)
866 MALLOC(ndrv_multi
, struct ndrv_multiaddr
*, sizeof(struct ndrv_multiaddr
) -
867 sizeof(struct sockaddr
) + sopt
->sopt_valsize
, M_IFADDR
, M_WAITOK
);
868 if (ndrv_multi
== NULL
)
871 // Copy in the address
872 result
= copyin(sopt
->sopt_val
, &ndrv_multi
->addr
, sopt
->sopt_valsize
);
874 // Validate the sockaddr
875 if (result
== 0 && sopt
->sopt_valsize
!= ndrv_multi
->addr
.sa_len
)
878 if (result
== 0 && ndrv_have_multicast(np
, &ndrv_multi
->addr
))
883 // Try adding the multicast
884 result
= if_addmulti(np
->nd_if
, &ndrv_multi
->addr
, &ndrv_multi
->ifma
);
889 // Add to our linked list
890 ndrv_multi
->next
= np
->nd_multiaddrs
;
891 np
->nd_multiaddrs
= ndrv_multi
;
895 // Free up the memory, something went wrong
896 FREE(ndrv_multi
, M_IFADDR
);
903 ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
905 struct sockaddr
* multi_addr
;
906 struct ndrv_multiaddr
* ndrv_entry
= NULL
;
909 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
910 sopt
->sopt_level
!= SOL_NDRVPROTO
)
912 if (np
->nd_if
== NULL
)
916 MALLOC(multi_addr
, struct sockaddr
*, sopt
->sopt_valsize
,
918 if (multi_addr
== NULL
)
921 // Copy in the address
922 result
= copyin(sopt
->sopt_val
, multi_addr
, sopt
->sopt_valsize
);
924 // Validate the sockaddr
925 if (result
== 0 && sopt
->sopt_valsize
!= multi_addr
->sa_len
)
930 /* Find the old entry */
931 ndrv_entry
= ndrv_have_multicast(np
, multi_addr
);
933 if (ndrv_entry
== NULL
)
939 // Try deleting the multicast
940 result
= if_delmultiaddr(ndrv_entry
->ifma
, 0);
945 // Remove from our linked list
946 struct ndrv_multiaddr
* cur
= np
->nd_multiaddrs
;
948 ifma_release(ndrv_entry
->ifma
);
950 if (cur
== ndrv_entry
)
952 np
->nd_multiaddrs
= cur
->next
;
956 for (cur
= cur
->next
; cur
!= NULL
; cur
= cur
->next
)
958 if (cur
->next
== ndrv_entry
)
960 cur
->next
= cur
->next
->next
;
967 FREE(ndrv_entry
, M_IFADDR
);
969 FREE(multi_addr
, M_TEMP
);
974 static struct ndrv_multiaddr
*
975 ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* inAddr
)
977 struct ndrv_multiaddr
* cur
;
978 for (cur
= np
->nd_multiaddrs
; cur
!= NULL
; cur
= cur
->next
)
981 if ((inAddr
->sa_len
== cur
->addr
.sa_len
) &&
982 (bcmp(&cur
->addr
, inAddr
, inAddr
->sa_len
) == 0))
993 ndrv_remove_all_multicast(struct ndrv_cb
* np
)
995 struct ndrv_multiaddr
* cur
;
997 if (np
->nd_if
!= NULL
)
999 while (np
->nd_multiaddrs
!= NULL
)
1001 cur
= np
->nd_multiaddrs
;
1002 np
->nd_multiaddrs
= cur
->next
;
1004 if_delmultiaddr(cur
->ifma
, 0);
1005 ifma_release(cur
->ifma
);
1006 FREE(cur
, M_IFADDR
);
1011 struct pr_usrreqs ndrv_usrreqs
= {
1012 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
1013 ndrv_connect
, pru_connect2_notsupp
, pru_control_notsupp
, ndrv_detach
,
1014 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
1015 pru_rcvoob_notsupp
, ndrv_send
, pru_sense_null
, ndrv_shutdown
,
1016 ndrv_sockaddr
, sosend
, soreceive
, pru_sopoll_notsupp
1019 struct protosw ndrvsw
=
1020 { SOCK_RAW
, &ndrvdomain
, NDRVPROTO_NDRV
, PR_ATOMIC
|PR_ADDR
,
1021 0, ndrv_output
, 0, ndrv_ctloutput
,
1028 struct domain ndrvdomain
=
1029 { AF_NDRV
, "NetDriver", ndrv_dominit
, NULL
, NULL
,
1031 NULL
, NULL
, 0, 0, 0, 0