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
);
245 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
248 MALLOC(np
, struct ndrv_cb
*, sizeof(*np
), M_PCB
, M_WAITOK
);
251 so
->so_pcb
= (caddr_t
)np
;
252 bzero(np
, sizeof(*np
));
254 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
256 TAILQ_INIT(&np
->nd_dlist
);
257 np
->nd_signature
= NDRV_SIGNATURE
;
259 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
260 np
->nd_proto
.sp_protocol
= proto
;
265 insque((queue_t
)np
, (queue_t
)&ndrvl
);
270 * Destroy state just before socket deallocation.
271 * Flush data or not depending on the options.
275 ndrv_detach(struct socket
*so
)
277 register struct ndrv_cb
*np
= sotondrvcb(so
);
281 return ndrv_do_detach(np
);
286 * If a socket isn't bound to a single address,
287 * the ndrv input routine will hand it anything
288 * within that protocol family (assuming there's
289 * nothing else around it should go to).
291 * Don't expect this to be used.
294 int ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
296 register struct ndrv_cb
*np
= sotondrvcb(so
);
305 /* Allocate memory to store the remote address */
306 MALLOC(np
->nd_faddr
, struct sockaddr_ndrv
*,
307 nam
->sa_len
, M_IFADDR
, M_WAITOK
);
310 if (np
->nd_faddr
== NULL
)
313 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, nam
->sa_len
);
319 * This is the "driver open" hook - we 'bind' to the
321 * Here's where we latch onto the driver.
324 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
326 register struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
327 register char *dname
;
328 register struct ndrv_cb
*np
;
329 register struct ifnet
*ifp
;
330 extern int name_cmp(struct ifnet
*, char *);
333 if TAILQ_EMPTY(&ifnet
)
334 return(EADDRNOTAVAIL
); /* Quick sanity check */
340 return EINVAL
; /* XXX */
342 /* I think we just latch onto a copy here; the caller frees */
343 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
344 if (np
->nd_laddr
== NULL
)
346 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
347 dname
= sa
->snd_name
;
351 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
353 /* Track down the driver and its ifnet structure.
354 * There's no internal call for this so we have to dup the code
357 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
358 if (name_cmp(ifp
, dname
) == 0)
363 return(EADDRNOTAVAIL
);
366 * Loopback demuxing doesn't work with PF_NDRV.
367 * The first 4 bytes of the packet must be the
368 * protocol ptr. Can't get that from userland.
370 if (ifp
->if_family
== APPLE_IF_FAM_LOOPBACK
)
373 if ((dlil_find_dltag(ifp
->if_family
, ifp
->if_unit
,
374 PF_NDRV
, &np
->nd_send_tag
) != 0) &&
375 (ifp
->if_family
!= APPLE_IF_FAM_PPP
)) {
376 /* NDRV isn't registered on this interface, lets change that */
377 struct dlil_proto_reg_str ndrv_proto
;
379 bzero(&ndrv_proto
, sizeof(ndrv_proto
));
380 TAILQ_INIT(&ndrv_proto
.demux_desc_head
);
382 ndrv_proto
.interface_family
= ifp
->if_family
;
383 ndrv_proto
.protocol_family
= PF_NDRV
;
384 ndrv_proto
.unit_number
= ifp
->if_unit
;
386 result
= dlil_attach_protocol(&ndrv_proto
, &np
->nd_send_tag
);
389 * If the interface does not allow PF_NDRV to attach, we will
390 * respect it's wishes. Sending will be disabled. No error is
391 * returned because the client may later attach a real protocol
392 * that the interface may accept.
399 np
->nd_family
= ifp
->if_family
;
400 np
->nd_unit
= ifp
->if_unit
;
406 ndrv_disconnect(struct socket
*so
)
408 register struct ndrv_cb
*np
= sotondrvcb(so
);
413 if (np
->nd_faddr
== 0)
416 ndrv_do_disconnect(np
);
424 ndrv_get_ifp(caddr_t ndrv_pcb
)
426 struct ndrv_cb
* np
= (struct ndrv_cb
*)ndrv_pcb
;
430 struct ndrv_cb
* temp
= ndrvl
.nd_next
;
431 /* Verify existence of pcb */
432 for (temp
= ndrvl
.nd_next
; temp
!= &ndrvl
; temp
= temp
->nd_next
)
440 log(LOG_WARNING
, "PF_NDRV: ndrv_get_ifp called with invalid ndrv_cb!");
450 * Mark the connection as being incapable of further input.
453 ndrv_shutdown(struct socket
*so
)
460 * Ship a packet out. The ndrv output will pass it
461 * to the appropriate driver. The really tricky part
462 * is the destination address...
465 ndrv_send(struct socket
*so
, int flags
, struct mbuf
*m
,
466 struct sockaddr
*addr
, struct mbuf
*control
,
474 error
= ndrv_output(m
, so
);
481 ndrv_abort(struct socket
*so
)
483 register struct ndrv_cb
*np
= sotondrvcb(so
);
488 ndrv_do_disconnect(np
);
493 ndrv_sense(struct socket
*so
, struct stat
*sb
)
496 * stat: don't bother with a blocksize.
502 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
504 register struct ndrv_cb
*np
= sotondrvcb(so
);
510 if (np
->nd_laddr
== 0)
513 len
= np
->nd_laddr
->snd_len
;
514 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
521 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
523 register struct ndrv_cb
*np
= sotondrvcb(so
);
529 if (np
->nd_faddr
== 0)
532 len
= np
->nd_faddr
->snd_len
;
533 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
542 ndrv_ctlinput(int dummy1
, struct sockaddr
*dummy2
, void *dummy3
)
549 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
551 register struct ndrv_cb
*np
= sotondrvcb(so
);
554 switch(sopt
->sopt_name
)
556 case NDRV_DELDMXSPEC
: /* Delete current spec */
557 /* Verify no parameter was passed */
558 if (sopt
->sopt_val
!= NULL
|| sopt
->sopt_valsize
!= 0) {
560 * We don't support deleting a specific demux, it's
565 error
= ndrv_delspec(np
);
567 case NDRV_SETDMXSPEC
: /* Set protocol spec */
568 error
= ndrv_setspec(np
, sopt
);
570 case NDRV_ADDMULTICAST
:
571 error
= ndrv_do_add_multicast(np
, sopt
);
573 case NDRV_DELMULTICAST
:
574 error
= ndrv_do_remove_multicast(np
, sopt
);
580 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
586 /* Drain the queues */
592 /* Sysctl hook for NDRV */
600 ndrv_do_detach(register struct ndrv_cb
*np
)
602 struct ndrv_cb
* cur_np
= NULL
;
603 struct socket
*so
= np
->nd_socket
;
604 struct ndrv_multicast
* next
;
608 kprintf("NDRV detach: %x, %x\n", so
, np
);
610 ndrv_remove_all_multicast(np
);
614 error
= dlil_detach_protocol(np
->nd_tag
);
617 log(LOG_WARNING
, "NDRV ndrv_do_detach: error %d removing dl_tag %d",
623 /* Remove from the linked list of control blocks */
626 if (np
->nd_send_tag
!= 0)
628 /* Check if this is the last socket attached to this interface */
629 for (cur_np
= ndrvl
.nd_next
; cur_np
!= &ndrvl
; cur_np
= cur_np
->nd_next
)
631 if (cur_np
->nd_family
== np
->nd_family
&&
632 cur_np
->nd_unit
== np
->nd_unit
)
638 /* If there are no other interfaces, detach PF_NDRV from the interface */
639 if (cur_np
== &ndrvl
)
641 dlil_detach_protocol(np
->nd_send_tag
);
645 FREE((caddr_t
)np
, M_PCB
);
652 ndrv_do_disconnect(register struct ndrv_cb
*np
)
655 kprintf("NDRV disconnect: %x\n", np
);
659 FREE(np
->nd_faddr
, M_IFADDR
);
662 if (np
->nd_socket
->so_state
& SS_NOFDREF
)
664 soisdisconnected(np
->nd_socket
);
669 * Try to compare a device name (q) with one of the funky ifnet
670 * device names (ifp).
672 int name_cmp(register struct ifnet
*ifp
, register char *q
)
676 static char *sprint_d();
679 len
= strlen(ifp
->if_name
);
680 strncpy(r
, ifp
->if_name
, IFNAMSIZ
);
682 (void)sprint_d(ifp
->if_unit
, r
, IFNAMSIZ
-(r
-buf
));
684 kprintf("Comparing %s, %s\n", buf
, q
);
686 return(strncmp(buf
, q
, IFNAMSIZ
));
689 /* Hackery - return a string version of a decimal number */
691 sprint_d(n
, buf
, buflen
)
695 { char dbuf
[IFNAMSIZ
];
696 register char *cp
= dbuf
+IFNAMSIZ
-1;
701 *cp
= "0123456789"[n
% 10];
703 } while (n
!= 0 && buflen
> 0);
704 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
709 * When closing, dump any enqueued mbufs.
712 ndrv_flushq(register struct ifqueue
*q
)
714 register struct mbuf
*m
;
727 ndrv_setspec(struct ndrv_cb
*np
, struct sockopt
*sopt
)
729 struct dlil_proto_reg_str dlilSpec
;
730 struct ndrv_protocol_desc ndrvSpec
;
731 struct dlil_demux_desc
* dlilDemux
= NULL
;
732 struct ndrv_demux_desc
* ndrvDemux
= NULL
;
735 /* Sanity checking */
738 if (np
->nd_if
== NULL
)
740 if (sopt
->sopt_valsize
!= sizeof(struct ndrv_protocol_desc
))
743 /* Copy the ndrvSpec */
744 error
= sooptcopyin(sopt
, &ndrvSpec
, sizeof(struct ndrv_protocol_desc
),
745 sizeof(struct ndrv_protocol_desc
));
749 /* Verify the parameter */
750 if (ndrvSpec
.version
> NDRV_PROTOCOL_DESC_VERS
)
751 return ENOTSUP
; // version is too new!
752 else if (ndrvSpec
.version
< 1)
753 return EINVAL
; // version is not valid
755 /* Allocate storage for demux array */
756 MALLOC(ndrvDemux
, struct ndrv_demux_desc
*,
757 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
), M_TEMP
, M_WAITOK
);
758 if (ndrvDemux
== NULL
)
761 /* Allocate enough dlil_demux_descs */
762 MALLOC(dlilDemux
, struct dlil_demux_desc
*,
763 sizeof(*dlilDemux
) * ndrvSpec
.demux_count
, M_TEMP
, M_WAITOK
);
764 if (dlilDemux
== NULL
)
769 /* Copy the ndrv demux array from userland */
770 error
= copyin(ndrvSpec
.demux_list
, ndrvDemux
,
771 ndrvSpec
.demux_count
* sizeof(struct ndrv_demux_desc
));
772 ndrvSpec
.demux_list
= ndrvDemux
;
777 /* At this point, we've at least got enough bytes to start looking around */
780 bzero(&dlilSpec
, sizeof(dlilSpec
));
781 TAILQ_INIT(&dlilSpec
.demux_desc_head
);
782 dlilSpec
.interface_family
= np
->nd_family
;
783 dlilSpec
.unit_number
= np
->nd_unit
;
784 dlilSpec
.input
= ndrv_input
;
785 dlilSpec
.protocol_family
= ndrvSpec
.protocol_family
;
787 for (demuxOn
= 0; demuxOn
< ndrvSpec
.demux_count
; demuxOn
++)
789 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
790 error
= ndrv_to_dlil_demux(&ndrvSpec
.demux_list
[demuxOn
], &dlilDemux
[demuxOn
]);
794 /* Add the dlil_demux_desc to the list */
795 TAILQ_INSERT_TAIL(&dlilSpec
.demux_desc_head
, &dlilDemux
[demuxOn
], next
);
801 /* We've got all our ducks lined up...lets attach! */
802 error
= dlil_attach_protocol(&dlilSpec
, &np
->nd_tag
);
805 /* Free any memory we've allocated */
807 FREE(dlilDemux
, M_TEMP
);
809 FREE(ndrvDemux
, M_TEMP
);
816 ndrv_to_dlil_demux(struct ndrv_demux_desc
* ndrv
, struct dlil_demux_desc
* dlil
)
818 bzero(dlil
, sizeof(*dlil
));
820 if (ndrv
->type
< DLIL_DESC_ETYPE2
)
822 /* using old "type", not supported */
826 if (ndrv
->length
> 28)
831 dlil
->type
= ndrv
->type
;
832 dlil
->native_type
= ndrv
->data
.other
;
833 dlil
->variants
.native_type_length
= ndrv
->length
;
839 ndrv_delspec(struct ndrv_cb
*np
)
846 /* Detach the protocol */
847 result
= dlil_detach_protocol(np
->nd_tag
);
857 ndrv_find_tag(unsigned int tag
)
865 for (np
= ndrvl
.nd_next
; np
!= NULL
; np
= np
->nd_next
)
867 if (np
->nd_tag
== tag
)
878 static int ndrv_dominited
= 0;
880 if (ndrv_dominited
== 0 &&
881 net_add_proto(&ndrvsw
, &ndrvdomain
) == 0)
886 ndrv_read_event(struct socket
* so
, caddr_t ref
, int waitf
)
889 struct mbuf
*m
= NULL
;
890 struct kern_event_msg
*msg
;
891 struct uio auio
= {0};
896 auio
.uio_resid
= 1000000; // large number to get all of the data
897 flags
= MSG_DONTWAIT
;
898 result
= soreceive(so
, (struct sockaddr
**)NULL
, &auio
, &m
,
899 (struct mbuf
**)NULL
, &flags
);
900 if (result
!= 0 || m
== NULL
)
903 // cast the mbuf to a kern_event_msg
904 // this is dangerous, doesn't handle linked mbufs
905 msg
= mtod(m
, struct kern_event_msg
*);
907 // check for detaches, assume even filtering is working
908 if (msg
->event_code
== KEV_DL_IF_DETACHING
||
909 msg
->event_code
== KEV_DL_IF_DETACHED
)
911 struct net_event_data
*ev_data
;
912 ev_data
= (struct net_event_data
*)msg
->event_data
;
913 ndrv_handle_ifp_detach(ev_data
->if_family
, ev_data
->if_unit
);
920 ndrv_handle_ifp_detach(u_long family
, short unit
)
925 /* Find all sockets using this interface. */
926 for (np
= ndrvl
.nd_next
; np
!= &ndrvl
; np
= np
->nd_next
)
928 if (np
->nd_family
== family
&&
931 /* This cb is using the detaching interface, but not for long. */
932 /* Let the protocol go */
936 /* Delete the multicasts first */
937 ndrv_remove_all_multicast(np
);
939 /* Disavow all knowledge of the ifp */
945 /* Make sure sending returns an error */
946 /* Is this safe? Will we drop the funnel? */
947 socantsendmore(np
->nd_socket
);
948 socantrcvmore(np
->nd_socket
);
952 /* Unregister our protocol */
953 if (dlil_find_dltag(family
, unit
, PF_NDRV
, &dl_tag
) == 0) {
954 dlil_detach_protocol(dl_tag
);
959 ndrv_do_add_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
961 struct ndrv_multiaddr
* ndrv_multi
;
964 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
965 sopt
->sopt_level
!= SOL_NDRVPROTO
)
967 if (np
->nd_if
== NULL
)
971 MALLOC(ndrv_multi
, struct ndrv_multiaddr
*, sizeof(struct ndrv_multiaddr
) -
972 sizeof(struct sockaddr
) + sopt
->sopt_valsize
, M_IFADDR
, M_WAITOK
);
973 if (ndrv_multi
== NULL
)
976 // Copy in the address
977 result
= copyin(sopt
->sopt_val
, &ndrv_multi
->addr
, sopt
->sopt_valsize
);
979 // Validate the sockaddr
980 if (result
== 0 && sopt
->sopt_valsize
!= ndrv_multi
->addr
.sa_len
)
983 if (result
== 0 && ndrv_have_multicast(np
, &ndrv_multi
->addr
))
988 // Try adding the multicast
989 result
= if_addmulti(np
->nd_if
, &ndrv_multi
->addr
, NULL
);
994 // Add to our linked list
995 ndrv_multi
->next
= np
->nd_multiaddrs
;
996 np
->nd_multiaddrs
= ndrv_multi
;
1000 // Free up the memory, something went wrong
1001 FREE(ndrv_multi
, M_IFADDR
);
1008 ndrv_do_remove_multicast(struct ndrv_cb
*np
, struct sockopt
*sopt
)
1010 struct sockaddr
* multi_addr
;
1011 struct ndrv_multiaddr
* ndrv_entry
= NULL
;
1014 if (sopt
->sopt_val
== NULL
|| sopt
->sopt_valsize
< 2 ||
1015 sopt
->sopt_level
!= SOL_NDRVPROTO
)
1017 if (np
->nd_if
== NULL
)
1021 MALLOC(multi_addr
, struct sockaddr
*, sopt
->sopt_valsize
,
1023 if (multi_addr
== NULL
)
1026 // Copy in the address
1027 result
= copyin(sopt
->sopt_val
, multi_addr
, sopt
->sopt_valsize
);
1029 // Validate the sockaddr
1030 if (result
== 0 && sopt
->sopt_valsize
!= multi_addr
->sa_len
)
1035 /* Find the old entry */
1036 ndrv_entry
= ndrv_have_multicast(np
, multi_addr
);
1038 if (ndrv_entry
== NULL
)
1044 // Try deleting the multicast
1045 result
= if_delmulti(np
->nd_if
, &ndrv_entry
->addr
);
1050 // Remove from our linked list
1051 struct ndrv_multiaddr
* cur
= np
->nd_multiaddrs
;
1053 if (cur
== ndrv_entry
)
1055 np
->nd_multiaddrs
= cur
->next
;
1059 for (cur
= cur
->next
; cur
!= NULL
; cur
= cur
->next
)
1061 if (cur
->next
== ndrv_entry
)
1063 cur
->next
= cur
->next
->next
;
1070 FREE(ndrv_entry
, M_IFADDR
);
1072 FREE(multi_addr
, M_TEMP
);
1077 static struct ndrv_multiaddr
*
1078 ndrv_have_multicast(struct ndrv_cb
*np
, struct sockaddr
* inAddr
)
1080 struct ndrv_multiaddr
* cur
;
1081 for (cur
= np
->nd_multiaddrs
; cur
!= NULL
; cur
= cur
->next
)
1084 if ((inAddr
->sa_len
== cur
->addr
.sa_len
) &&
1085 (bcmp(&cur
->addr
, inAddr
, inAddr
->sa_len
) == 0))
1096 ndrv_remove_all_multicast(struct ndrv_cb
* np
)
1098 struct ndrv_multiaddr
* cur
;
1100 if (np
->nd_if
!= NULL
)
1102 while (np
->nd_multiaddrs
!= NULL
)
1104 cur
= np
->nd_multiaddrs
;
1105 np
->nd_multiaddrs
= cur
->next
;
1107 if_delmulti(np
->nd_if
, &cur
->addr
);
1108 FREE(cur
, M_IFADDR
);
1113 struct pr_usrreqs ndrv_usrreqs
= {
1114 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
1115 ndrv_connect
, pru_connect2_notsupp
, ndrv_control
, ndrv_detach
,
1116 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
1117 pru_rcvoob_notsupp
, ndrv_send
, ndrv_sense
, ndrv_shutdown
,
1118 ndrv_sockaddr
, sosend
, soreceive
, sopoll
1121 struct protosw ndrvsw
=
1122 { SOCK_RAW
, &ndrvdomain
, NDRVPROTO_NDRV
, PR_ATOMIC
|PR_ADDR
,
1123 0, ndrv_output
, ndrv_ctlinput
, ndrv_ctloutput
,
1125 ndrv_drain
, ndrv_sysctl
, &ndrv_usrreqs
1128 struct domain ndrvdomain
=
1129 { AF_NDRV
, "NetDriver", ndrv_dominit
, NULL
, NULL
,
1131 NULL
, NULL
, 0, 0, 0, 0