]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ndrv.c
f2f42839f45271bbb91e4b7ab33ad4e263109ed0
[apple/xnu.git] / bsd / net / ndrv.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
29 /*
30 * @(#)ndrv.c 1.1 (MacOSX) 6/10/43
31 * Justin Walker, 970604
32 * AF_NDRV support
33 * 980130 - Cleanup, reorg, performance improvemements
34 * 000816 - Removal of Y adapter cruft
35 */
36
37 /*
38 * PF_NDRV allows raw access to a specified network device, directly
39 * with a socket. Expected use involves a socket option to request
40 * protocol packets. This lets ndrv_output() call dlil_output(), and
41 * lets DLIL find the proper recipient for incoming packets.
42 * The purpose here is for user-mode protocol implementation.
43 * Note that "pure raw access" will still be accomplished with BPF.
44 *
45 * In addition to the former use, when combined with socket NKEs,
46 * PF_NDRV permits a fairly flexible mechanism for implementing
47 * strange protocol support. One of the main ones will be the
48 * BlueBox/Classic Shared IP Address support.
49 */
50 #include <mach/mach_types.h>
51
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/kernel.h>
55 #include <sys/malloc.h>
56 #include <sys/mbuf.h>
57 #include <sys/protosw.h>
58 #include <sys/domain.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/ioctl.h>
62 #include <sys/errno.h>
63 #include <sys/syslog.h>
64 #include <sys/proc.h>
65
66 #include <kern/queue.h>
67
68 #include <net/ndrv.h>
69 #include <net/route.h>
70 #include <net/if_llc.h>
71 #include <net/if_dl.h>
72 #include <net/if_types.h>
73 #include <net/ndrv_var.h>
74
75 #if INET
76 #include <netinet/in.h>
77 #include <netinet/in_var.h>
78 #endif
79 #include <netinet/if_ether.h>
80
81 #include <machine/spl.h>
82
83 static int ndrv_do_detach(struct ndrv_cb *);
84 static int ndrv_do_disconnect(struct ndrv_cb *);
85 static struct ndrv_cb *ndrv_find_inbound(struct ifnet *ifp, u_long protocol_family);
86 static int ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt);
87 static int ndrv_delspec(struct ndrv_cb *);
88 static int ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil);
89 static void ndrv_handle_ifp_detach(u_long family, short unit);
90 static int ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt);
91 static int ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt);
92 static struct ndrv_multiaddr* ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* addr);
93 static void ndrv_remove_all_multicast(struct ndrv_cb *np);
94
95 unsigned long ndrv_sendspace = NDRVSNDQ;
96 unsigned long ndrv_recvspace = NDRVRCVQ;
97 TAILQ_HEAD(, ndrv_cb) ndrvl = TAILQ_HEAD_INITIALIZER(ndrvl);
98
99 extern struct domain ndrvdomain;
100 extern struct protosw ndrvsw;
101 extern lck_mtx_t *domain_proto_mtx;
102
103 extern void kprintf(const char *, ...);
104
105 /*
106 * Verify these values match.
107 * To keep clients from including dlil.h, we define
108 * these values independently in ndrv.h. They must
109 * match or a conversion function must be written.
110 */
111 #if NDRV_DEMUXTYPE_ETHERTYPE != DLIL_DESC_ETYPE2
112 #error NDRV_DEMUXTYPE_ETHERTYPE must match DLIL_DESC_ETYPE2
113 #endif
114 #if NDRV_DEMUXTYPE_SAP != DLIL_DESC_SAP
115 #error NDRV_DEMUXTYPE_SAP must match DLIL_DESC_SAP
116 #endif
117 #if NDRV_DEMUXTYPE_SNAP != DLIL_DESC_SNAP
118 #error NDRV_DEMUXTYPE_SNAP must match DLIL_DESC_SNAP
119 #endif
120
121 /*
122 * Protocol output - Called to output a raw network packet directly
123 * to the driver.
124 */
125 static int
126 ndrv_output(struct mbuf *m, struct socket *so)
127 {
128 struct ndrv_cb *np = sotondrvcb(so);
129 struct ifnet *ifp = np->nd_if;
130 int result = 0;
131
132 #if NDRV_DEBUG
133 kprintf("NDRV output: %x, %x, %x\n", m, so, np);
134 #endif
135
136 /*
137 * No header is a format error
138 */
139 if ((m->m_flags&M_PKTHDR) == 0)
140 return(EINVAL);
141
142 /* Unlock before calling dlil_output */
143 socket_unlock(so, 0);
144
145 /*
146 * Call DLIL if we can. DLIL is much safer than calling the
147 * ifp directly.
148 */
149 result = dlil_output(ifp, np->nd_proto_family, m, (caddr_t)NULL,
150 (struct sockaddr*)NULL, 1);
151
152 socket_lock(so, 0);
153
154 return (result);
155 }
156
157 /* Our input routine called from DLIL */
158 static int
159 ndrv_input(struct mbuf *m,
160 char *frame_header,
161 struct ifnet *ifp,
162 u_long proto_family,
163 __unused int sync_ok)
164 {
165 struct socket *so;
166 struct sockaddr_dl ndrvsrc = {sizeof (struct sockaddr_dl), AF_NDRV};
167 struct ndrv_cb *np;
168 int error = 0;
169
170
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);
178
179 np = ndrv_find_inbound(ifp, proto_family);
180 if (np == NULL)
181 {
182 return(ENOENT);
183 }
184 so = np->nd_socket;
185 /* prepend the frame header */
186 m = m_prepend(m, ifp->if_hdrlen, M_NOWAIT);
187 if (m == NULL)
188 return EJUSTRETURN;
189 bcopy(frame_header, m->m_data, ifp->if_hdrlen);
190
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) {
195 sorwakeup(so);
196 }
197 lck_mtx_unlock(so->so_proto->pr_domain->dom_mtx);
198 return 0; /* radar 4030377 - always return 0 */
199 }
200
201 /*
202 * Allocate an ndrv control block and some buffer space for the socket
203 */
204 static int
205 ndrv_attach(struct socket *so, int proto, __unused struct proc *p)
206 {
207 int error;
208 struct ndrv_cb *np = sotondrvcb(so);
209
210 if ((so->so_state & SS_PRIV) == 0)
211 return(EPERM);
212
213 #if NDRV_DEBUG
214 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
215 #endif
216
217 if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace)))
218 return(error);
219
220 MALLOC(np, struct ndrv_cb *, sizeof(*np), M_PCB, M_WAITOK);
221 if (np == NULL)
222 return (ENOMEM);
223 so->so_pcb = (caddr_t)np;
224 bzero(np, sizeof(*np));
225 #if NDRV_DEBUG
226 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
227 #endif
228 TAILQ_INIT(&np->nd_dlist);
229 np->nd_signature = NDRV_SIGNATURE;
230 np->nd_socket = so;
231 np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family;
232 np->nd_proto.sp_protocol = proto;
233 np->nd_if = NULL;
234 np->nd_proto_family = 0;
235 np->nd_family = 0;
236 np->nd_unit = 0;
237 TAILQ_INSERT_TAIL(&ndrvl, np, nd_next);
238 return(0);
239 }
240
241 /*
242 * Destroy state just before socket deallocation.
243 * Flush data or not depending on the options.
244 */
245
246 static int
247 ndrv_detach(struct socket *so)
248 {
249 struct ndrv_cb *np = sotondrvcb(so);
250
251 if (np == 0)
252 return EINVAL;
253 return ndrv_do_detach(np);
254 }
255
256
257 /*
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).
262 *
263 * Don't expect this to be used.
264 */
265
266 static int
267 ndrv_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
268 {
269 struct ndrv_cb *np = sotondrvcb(so);
270 int result = 0;
271
272 if (np == 0)
273 return EINVAL;
274
275 if (np->nd_faddr)
276 return EISCONN;
277
278 /* Allocate memory to store the remote address */
279 MALLOC(np->nd_faddr, struct sockaddr_ndrv*,
280 nam->sa_len, M_IFADDR, M_WAITOK);
281 if (result != 0)
282 return result;
283 if (np->nd_faddr == NULL)
284 return ENOMEM;
285
286 bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, nam->sa_len);
287 soisconnected(so);
288 return 0;
289 }
290
291 static void
292 ndrv_event(struct ifnet *ifp, struct kev_msg *event)
293 {
294 if (event->vendor_code == KEV_VENDOR_APPLE &&
295 event->kev_class == KEV_NETWORK_CLASS &&
296 event->kev_subclass == KEV_DL_SUBCLASS &&
297 event->event_code == KEV_DL_IF_DETACHING) {
298 ndrv_handle_ifp_detach(ifp->if_family, ifp->if_unit);
299 }
300 }
301
302 static int name_cmp(struct ifnet *, char *);
303
304 /*
305 * This is the "driver open" hook - we 'bind' to the
306 * named driver.
307 * Here's where we latch onto the driver.
308 */
309 static int
310 ndrv_bind(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
311 {
312 struct sockaddr_ndrv *sa = (struct sockaddr_ndrv *) nam;
313 char *dname;
314 struct ndrv_cb *np;
315 struct ifnet *ifp;
316 int result;
317
318 if TAILQ_EMPTY(&ifnet_head)
319 return(EADDRNOTAVAIL); /* Quick sanity check */
320 np = sotondrvcb(so);
321 if (np == 0)
322 return EINVAL;
323
324 if (np->nd_laddr)
325 return EINVAL; /* XXX */
326
327 /* I think we just latch onto a copy here; the caller frees */
328 np->nd_laddr = _MALLOC(sizeof(struct sockaddr_ndrv), M_IFADDR, M_WAITOK);
329 if (np->nd_laddr == NULL)
330 return(ENOMEM);
331 bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
332 dname = sa->snd_name;
333 if (*dname == '\0')
334 return(EINVAL);
335 #if NDRV_DEBUG
336 kprintf("NDRV bind: %x, %x, %s\n", so, np, dname);
337 #endif
338 /* Track down the driver and its ifnet structure.
339 * There's no internal call for this so we have to dup the code
340 * in if.c/ifconf()
341 */
342 ifnet_head_lock_shared();
343 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
344 if (name_cmp(ifp, dname) == 0)
345 break;
346 }
347 ifnet_head_done();
348
349 if (ifp == NULL)
350 return(EADDRNOTAVAIL);
351
352 // PPP doesn't support PF_NDRV.
353 if (ifp->if_family != APPLE_IF_FAM_PPP)
354 {
355 /* NDRV on this interface */
356 struct dlil_proto_reg_str ndrv_proto;
357 result = 0;
358 bzero(&ndrv_proto, sizeof(ndrv_proto));
359 TAILQ_INIT(&ndrv_proto.demux_desc_head);
360
361 ndrv_proto.interface_family = ifp->if_family;
362 ndrv_proto.protocol_family = PF_NDRV;
363 ndrv_proto.unit_number = ifp->if_unit;
364 ndrv_proto.event = ndrv_event;
365
366 /* We aren't worried about double attaching, that should just return an error */
367 result = dlil_attach_protocol(&ndrv_proto);
368 if (result && result != EEXIST) {
369 return result;
370 }
371 np->nd_proto_family = PF_NDRV;
372 }
373 else {
374 np->nd_proto_family = 0;
375 }
376
377 np->nd_if = ifp;
378 np->nd_family = ifp->if_family;
379 np->nd_unit = ifp->if_unit;
380
381 return(0);
382 }
383
384 static int
385 ndrv_disconnect(struct socket *so)
386 {
387 struct ndrv_cb *np = sotondrvcb(so);
388
389 if (np == 0)
390 return EINVAL;
391
392 if (np->nd_faddr == 0)
393 return ENOTCONN;
394
395 ndrv_do_disconnect(np);
396 return 0;
397 }
398
399 /*
400 * Mark the connection as being incapable of further input.
401 */
402 static int
403 ndrv_shutdown(struct socket *so)
404 {
405 lck_mtx_assert(so->so_proto->pr_domain->dom_mtx, LCK_MTX_ASSERT_OWNED);
406 socantsendmore(so);
407 return 0;
408 }
409
410 /*
411 * Ship a packet out. The ndrv output will pass it
412 * to the appropriate driver. The really tricky part
413 * is the destination address...
414 */
415 static int
416 ndrv_send(struct socket *so, __unused int flags, struct mbuf *m,
417 __unused struct sockaddr *addr, struct mbuf *control,
418 __unused struct proc *p)
419 {
420 int error;
421
422 if (control)
423 return EOPNOTSUPP;
424
425 error = ndrv_output(m, so);
426 m = NULL;
427 return error;
428 }
429
430
431 static int
432 ndrv_abort(struct socket *so)
433 {
434 struct ndrv_cb *np = sotondrvcb(so);
435
436 if (np == 0)
437 return EINVAL;
438
439 ndrv_do_disconnect(np);
440 return 0;
441 }
442
443 static int
444 ndrv_sockaddr(struct socket *so, struct sockaddr **nam)
445 {
446 struct ndrv_cb *np = sotondrvcb(so);
447 int len;
448
449 if (np == 0)
450 return EINVAL;
451
452 if (np->nd_laddr == 0)
453 return EINVAL;
454
455 len = np->nd_laddr->snd_len;
456 MALLOC(*nam, struct sockaddr *, len, M_SONAME, M_WAITOK);
457 if (*nam == NULL)
458 return ENOMEM;
459 bcopy((caddr_t)np->nd_laddr, *nam,
460 (unsigned)len);
461 return 0;
462 }
463
464
465 static int
466 ndrv_peeraddr(struct socket *so, struct sockaddr **nam)
467 {
468 struct ndrv_cb *np = sotondrvcb(so);
469 int len;
470
471 if (np == 0)
472 return EINVAL;
473
474 if (np->nd_faddr == 0)
475 return ENOTCONN;
476
477 len = np->nd_faddr->snd_len;
478 MALLOC(*nam, struct sockaddr *, len, M_SONAME, M_WAITOK);
479 if (*nam == NULL)
480 return ENOMEM;
481 bcopy((caddr_t)np->nd_faddr, *nam,
482 (unsigned)len);
483 return 0;
484 }
485
486
487 /* Control output */
488
489 static int
490 ndrv_ctloutput(struct socket *so, struct sockopt *sopt)
491 {
492 struct ndrv_cb *np = sotondrvcb(so);
493 int error = 0;
494
495 switch(sopt->sopt_name)
496 {
497 case NDRV_DELDMXSPEC: /* Delete current spec */
498 /* Verify no parameter was passed */
499 if (sopt->sopt_val != NULL || sopt->sopt_valsize != 0) {
500 /*
501 * We don't support deleting a specific demux, it's
502 * all or nothing.
503 */
504 return EINVAL;
505 }
506 error = ndrv_delspec(np);
507 break;
508 case NDRV_SETDMXSPEC: /* Set protocol spec */
509 error = ndrv_setspec(np, sopt);
510 break;
511 case NDRV_ADDMULTICAST:
512 error = ndrv_do_add_multicast(np, sopt);
513 break;
514 case NDRV_DELMULTICAST:
515 error = ndrv_do_remove_multicast(np, sopt);
516 break;
517 default:
518 error = ENOTSUP;
519 }
520 #ifdef NDRV_DEBUG
521 log(LOG_WARNING, "NDRV CTLOUT: %x returns %d\n", sopt->sopt_name,
522 error);
523 #endif
524 return(error);
525 }
526
527 static int
528 ndrv_do_detach(struct ndrv_cb *np)
529 {
530 struct ndrv_cb* cur_np = NULL;
531 struct socket *so = np->nd_socket;
532 int error = 0;
533
534 #if NDRV_DEBUG
535 kprintf("NDRV detach: %x, %x\n", so, np);
536 #endif
537 ndrv_remove_all_multicast(np);
538
539 if (np->nd_if) {
540 if (np->nd_proto_family != PF_NDRV &&
541 np->nd_proto_family != 0) {
542 dlil_detach_protocol(np->nd_if, np->nd_proto_family);
543 }
544
545 /* Remove from the linked list of control blocks */
546 TAILQ_REMOVE(&ndrvl, np, nd_next);
547
548 /* Check if this is the last socket attached to this interface */
549 TAILQ_FOREACH(cur_np, &ndrvl, nd_next) {
550 if (cur_np->nd_family == np->nd_family &&
551 cur_np->nd_unit == np->nd_unit) {
552 break;
553 }
554 }
555
556 /* If there are no other interfaces, detach PF_NDRV from the interface */
557 if (cur_np == NULL) {
558 dlil_detach_protocol(np->nd_if, PF_NDRV);
559 }
560 } else {
561 /* Remove from the linked list of control blocks */
562 TAILQ_REMOVE(&ndrvl, np, nd_next);
563 }
564
565 FREE((caddr_t)np, M_PCB);
566 so->so_pcb = 0;
567 so->so_flags |= SOF_PCBCLEARING;
568 sofree(so);
569 return error;
570 }
571
572 static int
573 ndrv_do_disconnect(struct ndrv_cb *np)
574 {
575 #if NDRV_DEBUG
576 kprintf("NDRV disconnect: %x\n", np);
577 #endif
578 if (np->nd_faddr)
579 {
580 FREE(np->nd_faddr, M_IFADDR);
581 np->nd_faddr = 0;
582 }
583 if (np->nd_socket->so_state & SS_NOFDREF)
584 ndrv_do_detach(np);
585 soisdisconnected(np->nd_socket);
586 return(0);
587 }
588
589 /* Hackery - return a string version of a decimal number */
590 static char *
591 sprint_d(u_int n, char *buf, int buflen)
592 { char dbuf[IFNAMSIZ];
593 char *cp = dbuf+IFNAMSIZ-1;
594
595 *cp = 0;
596 do { buflen--;
597 cp--;
598 *cp = "0123456789"[n % 10];
599 n /= 10;
600 } while (n != 0 && buflen > 0);
601 strncpy(buf, cp, IFNAMSIZ-buflen);
602 return (cp);
603 }
604
605 /*
606 * Try to compare a device name (q) with one of the funky ifnet
607 * device names (ifp).
608 */
609 static int name_cmp(struct ifnet *ifp, char *q)
610 { char *r;
611 int len;
612 char buf[IFNAMSIZ];
613
614 r = buf;
615 len = strlen(ifp->if_name);
616 strncpy(r, ifp->if_name, IFNAMSIZ);
617 r += len;
618 (void)sprint_d(ifp->if_unit, r, IFNAMSIZ-(r-buf));
619 #if NDRV_DEBUG
620 kprintf("Comparing %s, %s\n", buf, q);
621 #endif
622 return(strncmp(buf, q, IFNAMSIZ));
623 }
624
625 #if 0
626 //### Not used
627 /*
628 * When closing, dump any enqueued mbufs.
629 */
630 void
631 ndrv_flushq(struct ifqueue *q)
632 {
633 struct mbuf *m;
634 for (;;)
635 {
636 IF_DEQUEUE(q, m);
637 if (m == NULL)
638 break;
639 IF_DROP(q);
640 if (m)
641 m_freem(m);
642 }
643 }
644 #endif
645
646 int
647 ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt)
648 {
649 struct dlil_proto_reg_str dlilSpec;
650 struct ndrv_protocol_desc ndrvSpec;
651 struct dlil_demux_desc* dlilDemux = NULL;
652 struct ndrv_demux_desc* ndrvDemux = NULL;
653 int error = 0;
654
655 /* Sanity checking */
656 if (np->nd_proto_family != PF_NDRV)
657 return EBUSY;
658 if (np->nd_if == NULL)
659 return EINVAL;
660 if (sopt->sopt_valsize != sizeof(struct ndrv_protocol_desc))
661 return EINVAL;
662
663 /* Copy the ndrvSpec */
664 error = sooptcopyin(sopt, &ndrvSpec, sizeof(struct ndrv_protocol_desc),
665 sizeof(struct ndrv_protocol_desc));
666 if (error != 0)
667 return error;
668
669 /* Verify the parameter */
670 if (ndrvSpec.version > NDRV_PROTOCOL_DESC_VERS)
671 return ENOTSUP; // version is too new!
672 else if (ndrvSpec.version < 1)
673 return EINVAL; // version is not valid
674
675 /* Allocate storage for demux array */
676 MALLOC(ndrvDemux, struct ndrv_demux_desc*,
677 ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc), M_TEMP, M_WAITOK);
678 if (ndrvDemux == NULL)
679 return ENOMEM;
680
681 /* Allocate enough dlil_demux_descs */
682 MALLOC(dlilDemux, struct dlil_demux_desc*,
683 sizeof(*dlilDemux) * ndrvSpec.demux_count, M_TEMP, M_WAITOK);
684 if (dlilDemux == NULL)
685 error = ENOMEM;
686
687 if (error == 0)
688 {
689 /* Copy the ndrv demux array from userland */
690 error = copyin(CAST_USER_ADDR_T(ndrvSpec.demux_list), ndrvDemux,
691 ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc));
692 ndrvSpec.demux_list = ndrvDemux;
693 }
694
695 if (error == 0)
696 {
697 /* At this point, we've at least got enough bytes to start looking around */
698 u_long demuxOn = 0;
699
700 bzero(&dlilSpec, sizeof(dlilSpec));
701 TAILQ_INIT(&dlilSpec.demux_desc_head);
702 dlilSpec.interface_family = np->nd_family;
703 dlilSpec.unit_number = np->nd_unit;
704 dlilSpec.input = ndrv_input;
705 dlilSpec.event = ndrv_event;
706 dlilSpec.protocol_family = ndrvSpec.protocol_family;
707
708 for (demuxOn = 0; demuxOn < ndrvSpec.demux_count; demuxOn++)
709 {
710 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
711 error = ndrv_to_dlil_demux(&ndrvSpec.demux_list[demuxOn], &dlilDemux[demuxOn]);
712 if (error)
713 break;
714
715 /* Add the dlil_demux_desc to the list */
716 TAILQ_INSERT_TAIL(&dlilSpec.demux_desc_head, &dlilDemux[demuxOn], next);
717 }
718 }
719
720 if (error == 0)
721 {
722 /* We've got all our ducks lined up...lets attach! */
723 error = dlil_attach_protocol(&dlilSpec);
724 if (error == 0)
725 np->nd_proto_family = dlilSpec.protocol_family;
726 }
727
728 /* Free any memory we've allocated */
729 if (dlilDemux)
730 FREE(dlilDemux, M_TEMP);
731 if (ndrvDemux)
732 FREE(ndrvDemux, M_TEMP);
733
734 return error;
735 }
736
737
738 int
739 ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil)
740 {
741 bzero(dlil, sizeof(*dlil));
742
743 if (ndrv->type < DLIL_DESC_ETYPE2)
744 {
745 /* using old "type", not supported */
746 return ENOTSUP;
747 }
748
749 if (ndrv->length > 28)
750 {
751 return EINVAL;
752 }
753
754 dlil->type = ndrv->type;
755 dlil->native_type = ndrv->data.other;
756 dlil->variants.native_type_length = ndrv->length;
757
758 return 0;
759 }
760
761 int
762 ndrv_delspec(struct ndrv_cb *np)
763 {
764 int result = 0;
765
766 if (np->nd_proto_family == PF_NDRV ||
767 np->nd_proto_family == 0)
768 return EINVAL;
769
770 /* Detach the protocol */
771 result = dlil_detach_protocol(np->nd_if, np->nd_proto_family);
772 np->nd_proto_family = PF_NDRV;
773
774 return result;
775 }
776
777 struct ndrv_cb *
778 ndrv_find_inbound(struct ifnet *ifp, u_long protocol)
779 {
780 struct ndrv_cb* np;
781
782 if (protocol == PF_NDRV) return NULL;
783
784 TAILQ_FOREACH(np, &ndrvl, nd_next) {
785 if (np->nd_proto_family == protocol &&
786 np->nd_if == ifp) {
787 return np;
788 }
789 }
790
791 return NULL;
792 }
793
794 static void ndrv_dominit(void)
795 {
796 static int ndrv_dominited = 0;
797
798 if (ndrv_dominited == 0 &&
799 net_add_proto(&ndrvsw, &ndrvdomain) == 0)
800 ndrv_dominited = 1;
801 }
802
803 static void
804 ndrv_handle_ifp_detach(u_long family, short unit)
805 {
806 struct ndrv_cb* np;
807 struct ifnet *ifp = NULL;
808 struct socket *so;
809
810 /* Find all sockets using this interface. */
811 TAILQ_FOREACH(np, &ndrvl, nd_next) {
812 if (np->nd_family == family &&
813 np->nd_unit == unit)
814 {
815 /* This cb is using the detaching interface, but not for long. */
816 /* Let the protocol go */
817 ifp = np->nd_if;
818 if (np->nd_proto_family != 0)
819 ndrv_delspec(np);
820
821 /* Delete the multicasts first */
822 ndrv_remove_all_multicast(np);
823
824 /* Disavow all knowledge of the ifp */
825 np->nd_if = NULL;
826 np->nd_unit = 0;
827 np->nd_family = 0;
828
829 so = np->nd_socket;
830 /* Make sure sending returns an error */
831 /* Is this safe? Will we drop the funnel? */
832 lck_mtx_assert(so->so_proto->pr_domain->dom_mtx, LCK_MTX_ASSERT_OWNED);
833 socantsendmore(so);
834 socantrcvmore(so);
835 }
836 }
837
838 /* Unregister our protocol */
839 if (ifp) {
840 dlil_detach_protocol(ifp, PF_NDRV);
841 }
842 }
843
844 static int
845 ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt)
846 {
847 struct ndrv_multiaddr* ndrv_multi;
848 int result;
849
850 if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
851 sopt->sopt_level != SOL_NDRVPROTO)
852 return EINVAL;
853 if (np->nd_if == NULL)
854 return ENXIO;
855
856 // Allocate storage
857 MALLOC(ndrv_multi, struct ndrv_multiaddr*, sizeof(struct ndrv_multiaddr) -
858 sizeof(struct sockaddr) + sopt->sopt_valsize, M_IFADDR, M_WAITOK);
859 if (ndrv_multi == NULL)
860 return ENOMEM;
861
862 // Copy in the address
863 result = copyin(sopt->sopt_val, &ndrv_multi->addr, sopt->sopt_valsize);
864
865 // Validate the sockaddr
866 if (result == 0 && sopt->sopt_valsize != ndrv_multi->addr.sa_len)
867 result = EINVAL;
868
869 if (result == 0 && ndrv_have_multicast(np, &ndrv_multi->addr))
870 result = EEXIST;
871
872 if (result == 0)
873 {
874 // Try adding the multicast
875 result = if_addmulti(np->nd_if, &ndrv_multi->addr, &ndrv_multi->ifma);
876 }
877
878 if (result == 0)
879 {
880 // Add to our linked list
881 ndrv_multi->next = np->nd_multiaddrs;
882 np->nd_multiaddrs = ndrv_multi;
883 }
884 else
885 {
886 // Free up the memory, something went wrong
887 FREE(ndrv_multi, M_IFADDR);
888 }
889
890 return result;
891 }
892
893 static int
894 ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt)
895 {
896 struct sockaddr* multi_addr;
897 struct ndrv_multiaddr* ndrv_entry = NULL;
898 int result;
899
900 if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
901 sopt->sopt_level != SOL_NDRVPROTO)
902 return EINVAL;
903 if (np->nd_if == NULL)
904 return ENXIO;
905
906 // Allocate storage
907 MALLOC(multi_addr, struct sockaddr*, sopt->sopt_valsize,
908 M_TEMP, M_WAITOK);
909 if (multi_addr == NULL)
910 return ENOMEM;
911
912 // Copy in the address
913 result = copyin(sopt->sopt_val, multi_addr, sopt->sopt_valsize);
914
915 // Validate the sockaddr
916 if (result == 0 && sopt->sopt_valsize != multi_addr->sa_len)
917 result = EINVAL;
918
919 if (result == 0)
920 {
921 /* Find the old entry */
922 ndrv_entry = ndrv_have_multicast(np, multi_addr);
923
924 if (ndrv_entry == NULL)
925 result = ENOENT;
926 }
927
928 if (result == 0)
929 {
930 // Try deleting the multicast
931 result = if_delmultiaddr(ndrv_entry->ifma, 0);
932 }
933
934 if (result == 0)
935 {
936 // Remove from our linked list
937 struct ndrv_multiaddr* cur = np->nd_multiaddrs;
938
939 ifma_release(ndrv_entry->ifma);
940
941 if (cur == ndrv_entry)
942 {
943 np->nd_multiaddrs = cur->next;
944 }
945 else
946 {
947 for (cur = cur->next; cur != NULL; cur = cur->next)
948 {
949 if (cur->next == ndrv_entry)
950 {
951 cur->next = cur->next->next;
952 break;
953 }
954 }
955 }
956
957 // Free the memory
958 FREE(ndrv_entry, M_IFADDR);
959 }
960 FREE(multi_addr, M_TEMP);
961
962 return result;
963 }
964
965 static struct ndrv_multiaddr*
966 ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* inAddr)
967 {
968 struct ndrv_multiaddr* cur;
969 for (cur = np->nd_multiaddrs; cur != NULL; cur = cur->next)
970 {
971
972 if ((inAddr->sa_len == cur->addr.sa_len) &&
973 (bcmp(&cur->addr, inAddr, inAddr->sa_len) == 0))
974 {
975 // Found a match
976 return cur;
977 }
978 }
979
980 return NULL;
981 }
982
983 static void
984 ndrv_remove_all_multicast(struct ndrv_cb* np)
985 {
986 struct ndrv_multiaddr* cur;
987
988 if (np->nd_if != NULL)
989 {
990 while (np->nd_multiaddrs != NULL)
991 {
992 cur = np->nd_multiaddrs;
993 np->nd_multiaddrs = cur->next;
994
995 if_delmultiaddr(cur->ifma, 0);
996 ifma_release(cur->ifma);
997 FREE(cur, M_IFADDR);
998 }
999 }
1000 }
1001
1002 struct pr_usrreqs ndrv_usrreqs = {
1003 ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind,
1004 ndrv_connect, pru_connect2_notsupp, pru_control_notsupp, ndrv_detach,
1005 ndrv_disconnect, pru_listen_notsupp, ndrv_peeraddr, pru_rcvd_notsupp,
1006 pru_rcvoob_notsupp, ndrv_send, pru_sense_null, ndrv_shutdown,
1007 ndrv_sockaddr, sosend, soreceive, pru_sopoll_notsupp
1008 };
1009
1010 struct protosw ndrvsw =
1011 { SOCK_RAW, &ndrvdomain, NDRVPROTO_NDRV, PR_ATOMIC|PR_ADDR,
1012 0, ndrv_output, 0, ndrv_ctloutput,
1013 0, 0, 0, 0,
1014 0, 0,
1015 &ndrv_usrreqs,
1016 0, 0, 0
1017 };
1018
1019 struct domain ndrvdomain =
1020 { AF_NDRV, "NetDriver", ndrv_dominit, NULL, NULL,
1021 NULL,
1022 NULL, NULL, 0, 0, 0, 0
1023 };