2 * Copyright (c) 1997-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * @(#)ndrv.c 1.1 (MacOSX) 6/10/43
30 * Justin Walker, 970604
32 * 980130 - Cleanup, reorg, performance improvemements
33 * 000816 - Removal of Y adapter cruft
37 * PF_NDRV allows raw access to a specified network device, directly
38 * with a socket. Expected use involves a socket option to request
39 * protocol packets. This lets ndrv_output() call ifnet_output(), and
40 * lets DLIL find the proper recipient for incoming packets.
41 * The purpose here is for user-mode protocol implementation.
42 * Note that "pure raw access" will still be accomplished with BPF.
44 * In addition to the former use, when combined with socket NKEs,
45 * PF_NDRV permits a fairly flexible mechanism for implementing
46 * strange protocol support.
48 #include <mach/mach_types.h>
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/malloc.h>
55 #include <sys/protosw.h>
56 #include <sys/domain.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
59 #include <sys/ioctl.h>
60 #include <sys/errno.h>
61 #include <sys/syslog.h>
64 #include <kern/queue.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>
75 #include <netinet/in.h>
76 #include <netinet/in_var.h>
78 #include <netinet/if_ether.h>
80 #include <machine/spl.h>
82 static int ndrv_do_detach(struct ndrv_cb
*);
83 static int ndrv_do_disconnect(struct ndrv_cb
*);
84 static struct ndrv_cb
*ndrv_find_inbound(struct ifnet
*ifp
, u_int32_t protocol_family
);
85 static int ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
);
86 static int ndrv_delspec(struct ndrv_cb
*);
87 static int ndrv_to_ifnet_demux(struct ndrv_demux_desc
* ndrv
, struct ifnet_demux_desc
* ifdemux
);
88 static void ndrv_handle_ifp_detach(u_int32_t 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
);
93 static void ndrv_dominit(void) __attribute__((section("__TEXT, initcode")));
95 u_int32_t ndrv_sendspace
= NDRVSNDQ
;
96 u_int32_t ndrv_recvspace
= NDRVRCVQ
;
97 TAILQ_HEAD(, ndrv_cb
) ndrvl
= TAILQ_HEAD_INITIALIZER(ndrvl
);
99 extern struct domain ndrvdomain
;
100 extern struct protosw ndrvsw
;
101 extern lck_mtx_t
*domain_proto_mtx
;
104 * Verify these values match.
105 * To keep clients from including dlil.h, we define
106 * these values independently in ndrv.h. They must
107 * match or a conversion function must be written.
109 #if NDRV_DEMUXTYPE_ETHERTYPE != DLIL_DESC_ETYPE2
110 #error NDRV_DEMUXTYPE_ETHERTYPE must match DLIL_DESC_ETYPE2
112 #if NDRV_DEMUXTYPE_SAP != DLIL_DESC_SAP
113 #error NDRV_DEMUXTYPE_SAP must match DLIL_DESC_SAP
115 #if NDRV_DEMUXTYPE_SNAP != DLIL_DESC_SNAP
116 #error NDRV_DEMUXTYPE_SNAP must match DLIL_DESC_SNAP
120 * Protocol output - Called to output a raw network packet directly
124 ndrv_output(struct mbuf
*m
, struct socket
*so
)
126 struct ndrv_cb
*np
= sotondrvcb(so
);
127 struct ifnet
*ifp
= np
->nd_if
;
131 kprintf("NDRV output: %x, %x, %x\n", m
, so
, np
);
135 * No header is a format error
137 if ((m
->m_flags
&M_PKTHDR
) == 0)
140 /* Unlock before calling ifnet_output */
141 socket_unlock(so
, 0);
144 * Call DLIL if we can. DLIL is much safer than calling the
147 result
= ifnet_output_raw(ifp
, np
->nd_proto_family
, m
);
154 /* Our input routine called from DLIL */
158 protocol_family_t proto_family
,
163 struct sockaddr_dl ndrvsrc
;
167 ndrvsrc
.sdl_len
= sizeof (struct sockaddr_dl
);
168 ndrvsrc
.sdl_family
= AF_NDRV
;
169 ndrvsrc
.sdl_index
= 0;
171 /* move packet from if queue to socket */
172 /* Should be media-independent */
173 ndrvsrc
.sdl_type
= IFT_ETHER
;
174 ndrvsrc
.sdl_nlen
= 0;
175 ndrvsrc
.sdl_alen
= 6;
176 ndrvsrc
.sdl_slen
= 0;
177 bcopy(frame_header
, &ndrvsrc
.sdl_data
, 6);
179 np
= ndrv_find_inbound(ifp
, proto_family
);
185 /* prepend the frame header */
186 m
= m_prepend(m
, ifnet_hdrlen(ifp
), M_NOWAIT
);
189 bcopy(frame_header
, m
->m_data
, ifnet_hdrlen(ifp
));
191 lck_mtx_assert(so
->so_proto
->pr_domain
->dom_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
192 lck_mtx_lock(so
->so_proto
->pr_domain
->dom_mtx
);
193 if (sbappendaddr(&(so
->so_rcv
), (struct sockaddr
*)&ndrvsrc
,
194 m
, (struct mbuf
*)0, &error
) != 0) {
197 lck_mtx_unlock(so
->so_proto
->pr_domain
->dom_mtx
);
198 return 0; /* radar 4030377 - always return 0 */
202 * Allocate an ndrv control block and some buffer space for the socket
205 ndrv_attach(struct socket
*so
, int proto
, __unused
struct proc
*p
)
208 struct ndrv_cb
*np
= sotondrvcb(so
);
210 if ((so
->so_state
& SS_PRIV
) == 0)
214 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
217 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
220 MALLOC(np
, struct ndrv_cb
*, sizeof(*np
), M_PCB
, M_WAITOK
);
223 so
->so_pcb
= (caddr_t
)np
;
224 bzero(np
, sizeof(*np
));
226 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
228 TAILQ_INIT(&np
->nd_dlist
);
229 np
->nd_signature
= NDRV_SIGNATURE
;
231 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
232 np
->nd_proto
.sp_protocol
= proto
;
234 np
->nd_proto_family
= 0;
237 TAILQ_INSERT_TAIL(&ndrvl
, np
, nd_next
);
242 * Destroy state just before socket deallocation.
243 * Flush data or not depending on the options.
247 ndrv_detach(struct socket
*so
)
249 struct ndrv_cb
*np
= sotondrvcb(so
);
253 return ndrv_do_detach(np
);
258 * If a socket isn't bound to a single address,
259 * the ndrv input routine will hand it anything
260 * within that protocol family (assuming there's
261 * nothing else around it should go to).
263 * Don't expect this to be used.
267 ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, __unused
struct proc
*p
)
269 struct ndrv_cb
*np
= sotondrvcb(so
);
277 /* Allocate memory to store the remote address */
278 MALLOC(np
->nd_faddr
, struct sockaddr_ndrv
*,
279 nam
->sa_len
, M_IFADDR
, M_WAITOK
);
280 if (np
->nd_faddr
== NULL
)
283 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, nam
->sa_len
);
289 ndrv_event(struct ifnet
*ifp
, __unused protocol_family_t protocol
,
290 const struct kev_msg
*event
)
292 if (event
->vendor_code
== KEV_VENDOR_APPLE
&&
293 event
->kev_class
== KEV_NETWORK_CLASS
&&
294 event
->kev_subclass
== KEV_DL_SUBCLASS
&&
295 event
->event_code
== KEV_DL_IF_DETACHING
) {
296 lck_mtx_assert(ndrvdomain
.dom_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
297 lck_mtx_lock(ndrvdomain
.dom_mtx
);
298 ndrv_handle_ifp_detach(ifnet_family(ifp
), ifnet_unit(ifp
));
299 lck_mtx_unlock(ndrvdomain
.dom_mtx
);
303 static int name_cmp(struct ifnet
*, char *);
306 * This is the "driver open" hook - we 'bind' to the
308 * Here's where we latch onto the driver.
311 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, __unused
struct proc
*p
)
313 struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
319 if TAILQ_EMPTY(&ifnet_head
)
320 return(EADDRNOTAVAIL
); /* Quick sanity check */
326 return EINVAL
; /* XXX */
328 /* I think we just latch onto a copy here; the caller frees */
329 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
330 if (np
->nd_laddr
== NULL
)
332 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
333 dname
= (char *) sa
->snd_name
;
337 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
339 /* Track down the driver and its ifnet structure.
340 * There's no internal call for this so we have to dup the code
343 ifnet_head_lock_shared();
344 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
345 if (name_cmp(ifp
, dname
) == 0)
351 return(EADDRNOTAVAIL
);
353 // PPP doesn't support PF_NDRV.
354 if (ifnet_family(ifp
) != APPLE_IF_FAM_PPP
)
356 /* NDRV on this interface */
357 struct ifnet_attach_proto_param ndrv_proto
;
359 bzero(&ndrv_proto
, sizeof(ndrv_proto
));
360 ndrv_proto
.event
= ndrv_event
;
362 /* We aren't worried about double attaching, that should just return an error */
363 socket_unlock(so
, 0);
364 result
= ifnet_attach_protocol(ifp
, PF_NDRV
, &ndrv_proto
);
366 if (result
&& result
!= EEXIST
) {
369 np
->nd_proto_family
= PF_NDRV
;
372 np
->nd_proto_family
= 0;
376 np
->nd_family
= ifnet_family(ifp
);
377 np
->nd_unit
= ifnet_unit(ifp
);
383 ndrv_disconnect(struct socket
*so
)
385 struct ndrv_cb
*np
= sotondrvcb(so
);
390 if (np
->nd_faddr
== 0)
393 ndrv_do_disconnect(np
);
398 * Mark the connection as being incapable of further input.
401 ndrv_shutdown(struct socket
*so
)
403 lck_mtx_assert(so
->so_proto
->pr_domain
->dom_mtx
, LCK_MTX_ASSERT_OWNED
);
409 * Ship a packet out. The ndrv output will pass it
410 * to the appropriate driver. The really tricky part
411 * is the destination address...
414 ndrv_send(struct socket
*so
, __unused
int flags
, struct mbuf
*m
,
415 __unused
struct sockaddr
*addr
, struct mbuf
*control
,
416 __unused
struct proc
*p
)
423 error
= ndrv_output(m
, so
);
430 ndrv_abort(struct socket
*so
)
432 struct ndrv_cb
*np
= sotondrvcb(so
);
437 ndrv_do_disconnect(np
);
442 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
444 struct ndrv_cb
*np
= sotondrvcb(so
);
450 if (np
->nd_laddr
== 0)
453 len
= np
->nd_laddr
->snd_len
;
454 MALLOC(*nam
, struct sockaddr
*, len
, M_SONAME
, M_WAITOK
);
457 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
464 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
466 struct ndrv_cb
*np
= sotondrvcb(so
);
472 if (np
->nd_faddr
== 0)
475 len
= np
->nd_faddr
->snd_len
;
476 MALLOC(*nam
, struct sockaddr
*, len
, M_SONAME
, M_WAITOK
);
479 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
488 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
490 struct ndrv_cb
*np
= sotondrvcb(so
);
493 switch(sopt
->sopt_name
)
495 case NDRV_DELDMXSPEC
: /* Delete current spec */
496 /* Verify no parameter was passed */
497 if (sopt
->sopt_val
!= 0 || sopt
->sopt_valsize
!= 0) {
499 * We don't support deleting a specific demux, it's
504 error
= ndrv_delspec(np
);
506 case NDRV_SETDMXSPEC
: /* Set protocol spec */
507 error
= ndrv_setspec(np
, sopt
);
509 case NDRV_ADDMULTICAST
:
510 error
= ndrv_do_add_multicast(np
, sopt
);
512 case NDRV_DELMULTICAST
:
513 error
= ndrv_do_remove_multicast(np
, sopt
);
519 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
526 ndrv_do_detach(struct ndrv_cb
*np
)
528 struct ndrv_cb
* cur_np
= NULL
;
529 struct socket
*so
= np
->nd_socket
;
534 kprintf("NDRV detach: %x, %x\n", so
, np
);
536 ndrv_remove_all_multicast(np
);
539 /* Remove from the linked list of control blocks */
540 TAILQ_REMOVE(&ndrvl
, np
, nd_next
);
542 u_int32_t proto_family
= np
->nd_proto_family
;
544 if (proto_family
!= PF_NDRV
&& proto_family
!= 0) {
545 socket_unlock(so
, 0);
546 ifnet_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 ifnet_detach_protocol(ifp
, PF_NDRV
);
565 if (np
->nd_laddr
!= NULL
) {
566 FREE((caddr_t
)np
->nd_laddr
, M_IFADDR
);
569 FREE((caddr_t
)np
, M_PCB
);
571 so
->so_flags
|= SOF_PCBCLEARING
;
577 ndrv_do_disconnect(struct ndrv_cb
*np
)
579 struct socket
* so
= np
->nd_socket
;
581 kprintf("NDRV disconnect: %x\n", np
);
585 FREE(np
->nd_faddr
, M_IFADDR
);
588 if (so
->so_state
& SS_NOFDREF
)
590 soisdisconnected(so
);
594 /* Hackery - return a string version of a decimal number */
596 sprint_d(u_int n
, char *buf
, int buflen
)
597 { char dbuf
[IFNAMSIZ
];
598 char *cp
= dbuf
+IFNAMSIZ
-1;
603 *cp
= "0123456789"[n
% 10];
605 } while (n
!= 0 && buflen
> 0);
606 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
611 * Try to compare a device name (q) with one of the funky ifnet
612 * device names (ifp).
614 static int name_cmp(struct ifnet
*ifp
, char *q
)
620 len
= strlen(ifnet_name(ifp
));
621 strncpy(r
, ifnet_name(ifp
), IFNAMSIZ
);
623 (void)sprint_d(ifnet_unit(ifp
), r
, IFNAMSIZ
-(r
-buf
));
625 kprintf("Comparing %s, %s\n", buf
, q
);
627 return(strncmp(buf
, q
, IFNAMSIZ
));
633 * When closing, dump any enqueued mbufs.
636 ndrv_flushq(struct ifqueue
*q
)
652 ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
)
654 struct ifnet_attach_proto_param proto_param
;
655 struct ndrv_protocol_desc ndrvSpec
;
656 struct ndrv_demux_desc
* ndrvDemux
= NULL
;
658 struct socket
* so
= np
->nd_socket
;
659 user_addr_t user_addr
;
661 /* Sanity checking */
662 if (np
->nd_proto_family
!= PF_NDRV
)
664 if (np
->nd_if
== NULL
)
667 /* Copy the ndrvSpec */
668 if (proc_is64bit(sopt
->sopt_p
)) {
669 struct ndrv_protocol_desc64 ndrvSpec64
;
671 if (sopt
->sopt_valsize
!= sizeof(ndrvSpec64
))
674 error
= sooptcopyin(sopt
, &ndrvSpec64
, sizeof(ndrvSpec64
), sizeof(ndrvSpec64
));
678 ndrvSpec
.version
= ndrvSpec64
.version
;
679 ndrvSpec
.protocol_family
= ndrvSpec64
.protocol_family
;
680 ndrvSpec
.demux_count
= ndrvSpec64
.demux_count
;
682 user_addr
= ndrvSpec64
.demux_list
;
685 struct ndrv_protocol_desc32 ndrvSpec32
;
687 if (sopt
->sopt_valsize
!= sizeof(ndrvSpec32
))
690 error
= sooptcopyin(sopt
, &ndrvSpec32
, sizeof(ndrvSpec32
), sizeof(ndrvSpec32
));
694 ndrvSpec
.version
= ndrvSpec32
.version
;
695 ndrvSpec
.protocol_family
= ndrvSpec32
.protocol_family
;
696 ndrvSpec
.demux_count
= ndrvSpec32
.demux_count
;
698 user_addr
= CAST_USER_ADDR_T(ndrvSpec32
.demux_list
);
701 /* Verify the parameter */
702 if (ndrvSpec
.version
> NDRV_PROTOCOL_DESC_VERS
)
703 return ENOTSUP
; // version is too new!
704 else if (ndrvSpec
.version
< 1)
705 return EINVAL
; // version is not valid
707 bzero(&proto_param
, sizeof(proto_param
));
708 proto_param
.demux_count
= ndrvSpec
.demux_count
;
710 /* Allocate storage for demux array */
711 MALLOC(ndrvDemux
, struct ndrv_demux_desc
*, proto_param
.demux_count
*
712 sizeof(struct ndrv_demux_desc
), M_TEMP
, M_WAITOK
);
713 if (ndrvDemux
== NULL
)
716 /* Allocate enough ifnet_demux_descs */
717 MALLOC(proto_param
.demux_array
, struct ifnet_demux_desc
*,
718 sizeof(*proto_param
.demux_array
) * ndrvSpec
.demux_count
,
720 if (proto_param
.demux_array
== NULL
)
725 /* Copy the ndrv demux array from userland */
726 error
= copyin(user_addr
, ndrvDemux
,
727 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
));
728 ndrvSpec
.demux_list
= ndrvDemux
;
733 /* At this point, we've at least got enough bytes to start looking around */
734 u_int32_t demuxOn
= 0;
736 proto_param
.demux_count
= ndrvSpec
.demux_count
;
737 proto_param
.input
= ndrv_input
;
738 proto_param
.event
= ndrv_event
;
740 for (demuxOn
= 0; demuxOn
< ndrvSpec
.demux_count
; demuxOn
++)
742 /* Convert an ndrv_demux_desc to a ifnet_demux_desc */
743 error
= ndrv_to_ifnet_demux(&ndrvSpec
.demux_list
[demuxOn
],
744 &proto_param
.demux_array
[demuxOn
]);
752 /* We've got all our ducks lined up...lets attach! */
753 socket_unlock(so
, 0);
754 error
= ifnet_attach_protocol(np
->nd_if
, ndrvSpec
.protocol_family
,
758 np
->nd_proto_family
= ndrvSpec
.protocol_family
;
761 /* Free any memory we've allocated */
762 if (proto_param
.demux_array
)
763 FREE(proto_param
.demux_array
, M_TEMP
);
765 FREE(ndrvDemux
, M_TEMP
);
772 ndrv_to_ifnet_demux(struct ndrv_demux_desc
* ndrv
, struct ifnet_demux_desc
* ifdemux
)
774 bzero(ifdemux
, sizeof(*ifdemux
));
776 if (ndrv
->type
< DLIL_DESC_ETYPE2
)
778 /* using old "type", not supported */
782 if (ndrv
->length
> 28)
787 ifdemux
->type
= ndrv
->type
;
788 ifdemux
->data
= ndrv
->data
.other
;
789 ifdemux
->datalen
= ndrv
->length
;
795 ndrv_delspec(struct ndrv_cb
*np
)
799 if (np
->nd_proto_family
== PF_NDRV
||
800 np
->nd_proto_family
== 0)
803 /* Detach the protocol */
804 result
= ifnet_detach_protocol(np
->nd_if
, np
->nd_proto_family
);
805 np
->nd_proto_family
= PF_NDRV
;
811 ndrv_find_inbound(struct ifnet
*ifp
, u_int32_t protocol
)
815 if (protocol
== PF_NDRV
) return NULL
;
817 TAILQ_FOREACH(np
, &ndrvl
, nd_next
) {
818 if (np
->nd_proto_family
== protocol
&&
827 static void ndrv_dominit(void)
829 static int ndrv_dominited
= 0;
831 if (ndrv_dominited
== 0 &&
832 net_add_proto(&ndrvsw
, &ndrvdomain
) == 0)
837 ndrv_handle_ifp_detach(u_int32_t family
, short unit
)
840 struct ifnet
*ifp
= NULL
;
843 /* Find all sockets using this interface. */
844 TAILQ_FOREACH(np
, &ndrvl
, nd_next
) {
845 if (np
->nd_family
== family
&&
848 /* This cb is using the detaching interface, but not for long. */
849 /* Let the protocol go */
851 if (np
->nd_proto_family
!= 0)
854 /* Delete the multicasts first */
855 ndrv_remove_all_multicast(np
);
857 /* Disavow all knowledge of the ifp */
863 /* Make sure sending returns an error */
864 /* Is this safe? Will we drop the funnel? */
865 lck_mtx_assert(so
->so_proto
->pr_domain
->dom_mtx
, LCK_MTX_ASSERT_OWNED
);
871 /* Unregister our protocol */
873 ifnet_detach_protocol(ifp
, PF_NDRV
);
878 ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
880 struct ndrv_multiaddr
* ndrv_multi
;
883 if (sopt
->sopt_val
== 0 || sopt
->sopt_valsize
< 2 ||
884 sopt
->sopt_level
!= SOL_NDRVPROTO
)
886 if (np
->nd_if
== NULL
)
890 MALLOC(ndrv_multi
, struct ndrv_multiaddr
*, sizeof(struct ndrv_multiaddr
) -
891 sizeof(struct sockaddr
) + sopt
->sopt_valsize
, M_IFADDR
, M_WAITOK
);
892 if (ndrv_multi
== NULL
)
895 // Copy in the address
896 result
= copyin(sopt
->sopt_val
, &ndrv_multi
->addr
, sopt
->sopt_valsize
);
898 // Validate the sockaddr
899 if (result
== 0 && sopt
->sopt_valsize
!= ndrv_multi
->addr
.sa_len
)
902 if (result
== 0 && ndrv_have_multicast(np
, &ndrv_multi
->addr
))
907 // Try adding the multicast
908 result
= ifnet_add_multicast(np
->nd_if
, &ndrv_multi
->addr
,
914 // Add to our linked list
915 ndrv_multi
->next
= np
->nd_multiaddrs
;
916 np
->nd_multiaddrs
= ndrv_multi
;
920 // Free up the memory, something went wrong
921 FREE(ndrv_multi
, M_IFADDR
);
928 ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
930 struct sockaddr
* multi_addr
;
931 struct ndrv_multiaddr
* ndrv_entry
= NULL
;
934 if (sopt
->sopt_val
== 0 || sopt
->sopt_valsize
< 2 ||
935 sopt
->sopt_level
!= SOL_NDRVPROTO
)
937 if (np
->nd_if
== NULL
)
941 MALLOC(multi_addr
, struct sockaddr
*, sopt
->sopt_valsize
,
943 if (multi_addr
== NULL
)
946 // Copy in the address
947 result
= copyin(sopt
->sopt_val
, multi_addr
, sopt
->sopt_valsize
);
949 // Validate the sockaddr
950 if (result
== 0 && sopt
->sopt_valsize
!= multi_addr
->sa_len
)
955 /* Find the old entry */
956 ndrv_entry
= ndrv_have_multicast(np
, multi_addr
);
958 if (ndrv_entry
== NULL
)
964 // Try deleting the multicast
965 result
= ifnet_remove_multicast(ndrv_entry
->ifma
);
970 // Remove from our linked list
971 struct ndrv_multiaddr
* cur
= np
->nd_multiaddrs
;
973 ifmaddr_release(ndrv_entry
->ifma
);
975 if (cur
== ndrv_entry
)
977 np
->nd_multiaddrs
= cur
->next
;
981 for (cur
= cur
->next
; cur
!= NULL
; cur
= cur
->next
)
983 if (cur
->next
== ndrv_entry
)
985 cur
->next
= cur
->next
->next
;
992 FREE(ndrv_entry
, M_IFADDR
);
994 FREE(multi_addr
, M_TEMP
);
999 static struct ndrv_multiaddr
*
1000 ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* inAddr
)
1002 struct ndrv_multiaddr
* cur
;
1003 for (cur
= np
->nd_multiaddrs
; cur
!= NULL
; cur
= cur
->next
)
1006 if ((inAddr
->sa_len
== cur
->addr
.sa_len
) &&
1007 (bcmp(&cur
->addr
, inAddr
, inAddr
->sa_len
) == 0))
1018 ndrv_remove_all_multicast(struct ndrv_cb
* np
)
1020 struct ndrv_multiaddr
* cur
;
1022 if (np
->nd_if
!= NULL
)
1024 while (np
->nd_multiaddrs
!= NULL
)
1026 cur
= np
->nd_multiaddrs
;
1027 np
->nd_multiaddrs
= cur
->next
;
1029 ifnet_remove_multicast(cur
->ifma
);
1030 ifmaddr_release(cur
->ifma
);
1031 FREE(cur
, M_IFADDR
);
1036 struct pr_usrreqs ndrv_usrreqs
= {
1037 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
1038 ndrv_connect
, pru_connect2_notsupp
, pru_control_notsupp
, ndrv_detach
,
1039 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
1040 pru_rcvoob_notsupp
, ndrv_send
, pru_sense_null
, ndrv_shutdown
,
1041 ndrv_sockaddr
, sosend
, soreceive
, pru_sopoll_notsupp
1044 struct protosw ndrvsw
=
1045 { SOCK_RAW
, &ndrvdomain
, NDRVPROTO_NDRV
, PR_ATOMIC
|PR_ADDR
,
1046 NULL
, ndrv_output
, NULL
, ndrv_ctloutput
,
1048 NULL
, NULL
, NULL
, NULL
, NULL
,
1051 { NULL
, NULL
}, NULL
,
1055 struct domain ndrvdomain
=