]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ndrv.c
xnu-201.14.tar.gz
[apple/xnu.git] / bsd / net / ndrv.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
23 /*
24 * @(#)ndrv.c 1.1 (MacOSX) 6/10/43
25 * Justin Walker, 970604
26 * AF_NDRV support
27 * 980130 - Cleanup, reorg, performance improvemements
28 * 000816 - Removal of Y adapter cruft
29 */
30
31 /*
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.
38 *
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.
43 */
44 #include <mach/mach_types.h>
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mbuf.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>
58 #include <sys/proc.h>
59
60 #include <kern/queue.h>
61
62 #include <net/ndrv.h>
63 #include <net/netisr.h>
64 #include <net/route.h>
65 #include <net/if_llc.h>
66 #include <net/if_dl.h>
67 #include <net/if_types.h>
68 #include <net/ndrv_var.h>
69
70 #if INET
71 #include <netinet/in.h>
72 #include <netinet/in_var.h>
73 #endif
74 #include <netinet/if_ether.h>
75
76 #if NS
77 #include <netns/ns.h>
78 #include <netns/ns_if.h>
79 #endif
80
81 #if ISO
82 #include <netiso/argo_debug.h>
83 #include <netiso/iso.h>
84 #include <netiso/iso_var.h>
85 #include <netiso/iso_snpac.h>
86 #endif
87
88 #if LLC
89 #include <netccitt/dll.h>
90 #include <netccitt/llc_var.h>
91 #endif
92
93 #include <machine/spl.h>
94
95 int ndrv_do_detach(struct ndrv_cb *);
96 int ndrv_do_disconnect(struct ndrv_cb *);
97 struct ndrv_cb *ndrv_find_tag(unsigned int);
98 void ndrv_read_event(struct socket* inSo, caddr_t ref, int waitf);
99 int ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt);
100 int ndrv_delspec(struct ndrv_cb *);
101 int ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil);
102 void ndrv_handle_ifp_detach(u_long family, short unit);
103
104 unsigned long ndrv_sendspace = NDRVSNDQ;
105 unsigned long ndrv_recvspace = NDRVRCVQ;
106 struct ndrv_cb ndrvl; /* Head of controlblock list */
107
108 struct domain ndrvdomain;
109 struct protosw ndrvsw;
110 static struct socket* ndrv_so;
111
112
113 /*
114 * Protocol init function for NDRV protocol
115 * Init the control block list.
116 */
117 void
118 ndrv_init()
119 {
120 int retval;
121 struct kev_request kev_request;
122
123 ndrvl.nd_next = ndrvl.nd_prev = &ndrvl;
124
125 /* Create a PF_SYSTEM socket so we can listen for events */
126 retval = socreate(PF_SYSTEM, &ndrv_so, SOCK_RAW, SYSPROTO_EVENT);
127 if (retval != 0 || ndrv_so == NULL)
128 retval = KERN_FAILURE;
129
130 /* Install a callback function for the socket */
131 ndrv_so->so_rcv.sb_flags |= SB_NOTIFY|SB_UPCALL;
132 ndrv_so->so_upcall = ndrv_read_event;
133 ndrv_so->so_upcallarg = NULL;
134
135 /* Configure the socket to receive the events we're interested in */
136 kev_request.vendor_code = KEV_VENDOR_APPLE;
137 kev_request.kev_class = KEV_NETWORK_CLASS;
138 kev_request.kev_subclass = KEV_DL_SUBCLASS;
139 retval = ndrv_so->so_proto->pr_usrreqs->pru_control(ndrv_so, SIOCSKEVFILT, (caddr_t)&kev_request, 0, 0);
140 if (retval != 0)
141 {
142 /*
143 * We will not get attaching or detaching events in this case.
144 * We should probably prevent any sockets from binding so we won't
145 * panic later if the interface goes away.
146 */
147 log(LOG_WARNING, "PF_NDRV: ndrv_init - failed to set event filter (%d)",
148 retval);
149 }
150 }
151
152 /*
153 * Protocol output - Called to output a raw network packet directly
154 * to the driver.
155 */
156 int
157 ndrv_output(register struct mbuf *m, register struct socket *so)
158 {
159 register struct ndrv_cb *np = sotondrvcb(so);
160 register struct ifnet *ifp = np->nd_if;
161 extern void kprintf(const char *, ...);
162 int result = 0;
163
164 #if NDRV_DEBUG
165 kprintf("NDRV output: %x, %x, %x\n", m, so, np);
166 #endif
167
168 /*
169 * No header is a format error
170 */
171 if ((m->m_flags&M_PKTHDR) == 0)
172 return(EINVAL);
173
174 /*
175 * Call DLIL if we can. DLIL is much safer than calling the
176 * ifp directly.
177 */
178 if (np->nd_tag != 0)
179 result = dlil_output(np->nd_tag, m, (caddr_t)NULL,
180 (struct sockaddr*)NULL, 1);
181 else if (np->nd_send_tag != 0)
182 result = dlil_output(np->nd_send_tag, m, (caddr_t)NULL,
183 (struct sockaddr*)NULL, 1);
184 else
185 result = ENXIO;
186 return (result);
187 }
188
189 /* Our input routine called from DLIL */
190 int
191 ndrv_input(struct mbuf *m,
192 char *frame_header,
193 struct ifnet *ifp,
194 u_long dl_tag,
195 int sync_ok)
196 {
197 struct socket *so;
198 struct sockaddr_dl ndrvsrc = {sizeof (struct sockaddr_dl), AF_NDRV};
199 register struct ndrv_cb *np;
200
201
202 /* move packet from if queue to socket */
203 /* Should be media-independent */
204 ndrvsrc.sdl_type = IFT_ETHER;
205 ndrvsrc.sdl_nlen = 0;
206 ndrvsrc.sdl_alen = 6;
207 ndrvsrc.sdl_slen = 0;
208 bcopy(frame_header, &ndrvsrc.sdl_data, 6);
209
210 np = ndrv_find_tag(dl_tag);
211 if (np == NULL)
212 {
213 return(ENOENT);
214 }
215 so = np->nd_socket;
216 /* prepend the frame header */
217 m = m_prepend(m, ifp->if_data.ifi_hdrlen, M_NOWAIT);
218 if (m == NULL)
219 return EJUSTRETURN;
220 bcopy(frame_header, m->m_data, ifp->if_data.ifi_hdrlen);
221 if (sbappendaddr(&(so->so_rcv), (struct sockaddr *)&ndrvsrc,
222 m, (struct mbuf *)0) == 0)
223 {
224 /* yes, sbappendaddr returns zero if the sockbuff is full... */
225 /* caller will free m */
226 return(ENOMEM);
227 } else
228 sorwakeup(so);
229 return(0);
230 }
231
232 int
233 ndrv_control(struct socket *so, u_long cmd, caddr_t data,
234 struct ifnet *ifp, struct proc *p)
235 {
236 return (0);
237 }
238
239 /*
240 * Allocate an ndrv control block and some buffer space for the socket
241 */
242 int
243 ndrv_attach(struct socket *so, int proto, struct proc *p)
244 {
245 int error;
246 register struct ndrv_cb *np = sotondrvcb(so);
247
248 if ((so->so_state & SS_PRIV) == 0)
249 return(EPERM);
250
251 #if NDRV_DEBUG
252 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
253 #endif
254 MALLOC(np, struct ndrv_cb *, sizeof(*np), M_PCB, M_WAITOK);
255 if (np == NULL)
256 return (ENOMEM);
257 so->so_pcb = (caddr_t)np;
258 bzero(np, sizeof(*np));
259 #if NDRV_DEBUG
260 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
261 #endif
262 if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace)))
263 return(error);
264 TAILQ_INIT(&np->nd_dlist);
265 np->nd_signature = NDRV_SIGNATURE;
266 np->nd_socket = so;
267 np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family;
268 np->nd_proto.sp_protocol = proto;
269 np->nd_if = NULL;
270 np->nd_tag = 0;
271 np->nd_family = 0;
272 np->nd_unit = 0;
273 insque((queue_t)np, (queue_t)&ndrvl);
274 return(0);
275 }
276
277 /*
278 * Destroy state just before socket deallocation.
279 * Flush data or not depending on the options.
280 */
281
282 int
283 ndrv_detach(struct socket *so)
284 {
285 register struct ndrv_cb *np = sotondrvcb(so);
286
287 if (np == 0)
288 return EINVAL;
289 return ndrv_do_detach(np);
290 }
291
292
293 /*
294 * If a socket isn't bound to a single address,
295 * the ndrv input routine will hand it anything
296 * within that protocol family (assuming there's
297 * nothing else around it should go to).
298 *
299 * Don't expect this to be used.
300 */
301
302 int ndrv_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
303 {
304 register struct ndrv_cb *np = sotondrvcb(so);
305 int result = 0;
306
307 if (np == 0)
308 return EINVAL;
309
310 if (np->nd_faddr)
311 return EISCONN;
312
313 /* Allocate memory to store the remote address */
314 MALLOC(np->nd_faddr, struct sockaddr_ndrv*,
315 nam->sa_len, M_IFADDR, M_WAITOK);
316 if (result != 0)
317 return result;
318 if (np->nd_faddr == NULL)
319 return ENOMEM;
320
321 bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, nam->sa_len);
322 soisconnected(so);
323 return 0;
324 }
325
326 /*
327 * This is the "driver open" hook - we 'bind' to the
328 * named driver.
329 * Here's where we latch onto the driver.
330 */
331 int
332 ndrv_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
333 {
334 register struct sockaddr_ndrv *sa = (struct sockaddr_ndrv *) nam;
335 register char *dname;
336 register struct ndrv_cb *np;
337 register struct ifnet *ifp;
338 extern int name_cmp(struct ifnet *, char *);
339 int result;
340
341 if TAILQ_EMPTY(&ifnet)
342 return(EADDRNOTAVAIL); /* Quick sanity check */
343 np = sotondrvcb(so);
344 if (np == 0)
345 return EINVAL;
346
347 if (np->nd_laddr)
348 return EINVAL; /* XXX */
349
350 /* I think we just latch onto a copy here; the caller frees */
351 np->nd_laddr = _MALLOC(sizeof(struct sockaddr_ndrv), M_IFADDR, M_WAITOK);
352 if (np->nd_laddr == NULL)
353 return(ENOMEM);
354 bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
355 dname = sa->snd_name;
356 if (*dname == '\0')
357 return(EINVAL);
358 #if NDRV_DEBUG
359 kprintf("NDRV bind: %x, %x, %s\n", so, np, dname);
360 #endif
361 /* Track down the driver and its ifnet structure.
362 * There's no internal call for this so we have to dup the code
363 * in if.c/ifconf()
364 */
365 TAILQ_FOREACH(ifp, &ifnet, if_link) {
366 if (name_cmp(ifp, dname) == 0)
367 break;
368 }
369
370 if (ifp == NULL)
371 return(EADDRNOTAVAIL);
372
373 /*
374 * Loopback demuxing doesn't work with PF_NDRV.
375 * The first 4 bytes of the packet must be the
376 * protocol ptr. Can't get that from userland.
377 */
378 if (ifp->if_family == APPLE_IF_FAM_LOOPBACK)
379 return (ENOTSUP);
380
381 if ((dlil_find_dltag(ifp->if_family, ifp->if_unit,
382 PF_NDRV, &np->nd_send_tag) != 0) &&
383 (ifp->if_family != APPLE_IF_FAM_PPP))
384 {
385 /* NDRV isn't registered on this interface, lets change that */
386 struct dlil_proto_reg_str ndrv_proto;
387 int result = 0;
388 bzero(&ndrv_proto, sizeof(ndrv_proto));
389 TAILQ_INIT(&ndrv_proto.demux_desc_head);
390
391 ndrv_proto.interface_family = ifp->if_family;
392 ndrv_proto.protocol_family = PF_NDRV;
393 ndrv_proto.unit_number = ifp->if_unit;
394
395 result = dlil_attach_protocol(&ndrv_proto, &np->nd_send_tag);
396
397 /*
398 * If the interface does not allow PF_NDRV to attach, we will
399 * respect it's wishes. Sending will be disabled. No error is
400 * returned because the client may later attach a real protocol
401 * that the interface may accept.
402 */
403 if (result != 0)
404 np->nd_send_tag = 0;
405 }
406
407 np->nd_if = ifp;
408 np->nd_family = ifp->if_family;
409 np->nd_unit = ifp->if_unit;
410
411 return(0);
412 }
413
414 int
415 ndrv_disconnect(struct socket *so)
416 {
417 register struct ndrv_cb *np = sotondrvcb(so);
418
419 if (np == 0)
420 return EINVAL;
421
422 if (np->nd_faddr == 0)
423 return ENOTCONN;
424
425 ndrv_do_disconnect(np);
426 return 0;
427 }
428
429 /*
430 * Accessor function
431 */
432 struct ifnet*
433 ndrv_get_ifp(caddr_t ndrv_pcb)
434 {
435 struct ndrv_cb* np = (struct ndrv_cb*)ndrv_pcb;
436
437 #if DEBUG
438 {
439 struct ndrv_cb* temp = ndrvl.nd_next;
440 /* Verify existence of pcb */
441 for (temp = ndrvl.nd_next; temp != &ndrvl; temp = temp->nd_next)
442 {
443 if (temp == np)
444 break;
445 }
446
447 if (temp != np)
448 {
449 log(LOG_WARNING, "PF_NDRV: ndrv_get_ifp called with invalid ndrv_cb!");
450 return NULL;
451 }
452 }
453 #endif
454
455 return np->nd_if;
456 }
457
458 /*
459 * Mark the connection as being incapable of further input.
460 */
461 int
462 ndrv_shutdown(struct socket *so)
463 {
464 socantsendmore(so);
465 return 0;
466 }
467
468 /*
469 * Ship a packet out. The ndrv output will pass it
470 * to the appropriate driver. The really tricky part
471 * is the destination address...
472 */
473 int
474 ndrv_send(struct socket *so, int flags, struct mbuf *m,
475 struct sockaddr *addr, struct mbuf *control,
476 struct proc *p)
477 {
478 int error;
479
480 if (control)
481 return EOPNOTSUPP;
482
483 error = ndrv_output(m, so);
484 m = NULL;
485 return error;
486 }
487
488
489 int
490 ndrv_abort(struct socket *so)
491 {
492 register struct ndrv_cb *np = sotondrvcb(so);
493
494 if (np == 0)
495 return EINVAL;
496
497 ndrv_do_disconnect(np);
498 return 0;
499 }
500
501 int
502 ndrv_sense(struct socket *so, struct stat *sb)
503 {
504 /*
505 * stat: don't bother with a blocksize.
506 */
507 return (0);
508 }
509
510 int
511 ndrv_sockaddr(struct socket *so, struct sockaddr **nam)
512 {
513 register struct ndrv_cb *np = sotondrvcb(so);
514 int len;
515
516 if (np == 0)
517 return EINVAL;
518
519 if (np->nd_laddr == 0)
520 return EINVAL;
521
522 len = np->nd_laddr->snd_len;
523 bcopy((caddr_t)np->nd_laddr, *nam,
524 (unsigned)len);
525 return 0;
526 }
527
528
529 int
530 ndrv_peeraddr(struct socket *so, struct sockaddr **nam)
531 {
532 register struct ndrv_cb *np = sotondrvcb(so);
533 int len;
534
535 if (np == 0)
536 return EINVAL;
537
538 if (np->nd_faddr == 0)
539 return ENOTCONN;
540
541 len = np->nd_faddr->snd_len;
542 bcopy((caddr_t)np->nd_faddr, *nam,
543 (unsigned)len);
544 return 0;
545 }
546
547
548 /* Control input */
549
550 void
551 ndrv_ctlinput(int dummy1, struct sockaddr *dummy2, void *dummy3)
552 {
553 }
554
555 /* Control output */
556
557 int
558 ndrv_ctloutput(struct socket *so, struct sockopt *sopt)
559 {
560 register struct ndrv_cb *np = sotondrvcb(so);
561 int error = 0;
562
563 switch(sopt->sopt_name)
564 {
565 case NDRV_DELDMXSPEC: /* Delete current spec */
566 /* Verify no parameter was passed */
567 if (sopt->sopt_val != NULL || sopt->sopt_valsize != 0) {
568 /*
569 * We don't support deleting a specific demux, it's
570 * all or nothing.
571 */
572 return EINVAL;
573 }
574 error = ndrv_delspec(np);
575 break;
576 case NDRV_SETDMXSPEC: /* Set protocol spec */
577 error = ndrv_setspec(np, sopt);
578 break;
579 default:
580 error = ENOTSUP;
581 }
582 #ifdef NDRV_DEBUG
583 log(LOG_WARNING, "NDRV CTLOUT: %x returns %d\n", sopt->sopt_name,
584 error);
585 #endif
586 return(error);
587 }
588
589 /* Drain the queues */
590 void
591 ndrv_drain()
592 {
593 }
594
595 /* Sysctl hook for NDRV */
596 int
597 ndrv_sysctl()
598 {
599 return(0);
600 }
601
602 int
603 ndrv_do_detach(register struct ndrv_cb *np)
604 {
605 struct ndrv_cb* cur_np = NULL;
606 struct socket *so = np->nd_socket;
607 struct ndrv_multicast* next;
608 int error;
609
610 #if NDRV_DEBUG
611 kprintf("NDRV detach: %x, %x\n", so, np);
612 #endif
613 if (np->nd_tag != 0)
614 {
615 error = dlil_detach_protocol(np->nd_tag);
616 if (error)
617 {
618 log(LOG_WARNING, "NDRV ndrv_do_detach: error %d removing dl_tag %d",
619 error, np->nd_tag);
620 return error;
621 }
622 }
623
624 /* Remove from the linked list of control blocks */
625 remque((queue_t)np);
626
627 if (np->nd_send_tag != 0)
628 {
629 /* Check if this is the last socket attached to this interface */
630 for (cur_np = ndrvl.nd_next; cur_np != &ndrvl; cur_np = cur_np->nd_next)
631 {
632 if (cur_np->nd_family == np->nd_family &&
633 cur_np->nd_unit == np->nd_unit)
634 {
635 break;
636 }
637 }
638
639 /* If there are no other interfaces, detach PF_NDRV from the interface */
640 if (cur_np == &ndrvl)
641 {
642 dlil_detach_protocol(np->nd_send_tag);
643 }
644 }
645
646 FREE((caddr_t)np, M_PCB);
647 so->so_pcb = 0;
648 sofree(so);
649 return error;
650 }
651
652 int
653 ndrv_do_disconnect(register struct ndrv_cb *np)
654 {
655 #if NDRV_DEBUG
656 kprintf("NDRV disconnect: %x\n", np);
657 #endif
658 if (np->nd_faddr)
659 {
660 FREE(np->nd_faddr, M_IFADDR);
661 np->nd_faddr = 0;
662 }
663 if (np->nd_socket->so_state & SS_NOFDREF)
664 ndrv_do_detach(np);
665 soisdisconnected(np->nd_socket);
666 return(0);
667 }
668
669 /*
670 * Try to compare a device name (q) with one of the funky ifnet
671 * device names (ifp).
672 */
673 int name_cmp(register struct ifnet *ifp, register char *q)
674 { register char *r;
675 register int len;
676 char buf[IFNAMSIZ];
677 static char *sprint_d();
678
679 r = buf;
680 len = strlen(ifp->if_name);
681 strncpy(r, ifp->if_name, IFNAMSIZ);
682 r += len;
683 (void)sprint_d(ifp->if_unit, r, IFNAMSIZ-(r-buf));
684 #if NDRV_DEBUG
685 kprintf("Comparing %s, %s\n", buf, q);
686 #endif
687 return(strncmp(buf, q, IFNAMSIZ));
688 }
689
690 /* Hackery - return a string version of a decimal number */
691 static char *
692 sprint_d(n, buf, buflen)
693 u_int n;
694 char *buf;
695 int buflen;
696 { char dbuf[IFNAMSIZ];
697 register char *cp = dbuf+IFNAMSIZ-1;
698
699 *cp = 0;
700 do { buflen--;
701 cp--;
702 *cp = "0123456789"[n % 10];
703 n /= 10;
704 } while (n != 0 && buflen > 0);
705 strncpy(buf, cp, IFNAMSIZ-buflen);
706 return (cp);
707 }
708
709 /*
710 * When closing, dump any enqueued mbufs.
711 */
712 void
713 ndrv_flushq(register struct ifqueue *q)
714 {
715 register struct mbuf *m;
716 for (;;)
717 {
718 IF_DEQUEUE(q, m);
719 if (m == NULL)
720 break;
721 IF_DROP(q);
722 if (m)
723 m_freem(m);
724 }
725 }
726
727 int
728 ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt)
729 {
730 struct dlil_proto_reg_str dlilSpec;
731 struct ndrv_protocol_desc ndrvSpec;
732 struct dlil_demux_desc* dlilDemux = NULL;
733 struct ndrv_demux_desc* ndrvDemux = NULL;
734 int error = 0;
735
736 /* Sanity checking */
737 if (np->nd_tag)
738 return EBUSY;
739 if (np->nd_if == NULL)
740 return EINVAL;
741 if (sopt->sopt_valsize != sizeof(struct ndrv_protocol_desc))
742 return EINVAL;
743
744 /* Copy the ndrvSpec */
745 error = sooptcopyin(sopt, &ndrvSpec, sizeof(struct ndrv_protocol_desc),
746 sizeof(struct ndrv_protocol_desc));
747 if (error != 0)
748 return error;
749
750 /* Verify the parameter */
751 if (ndrvSpec.version > NDRV_PROTOCOL_DESC_VERS)
752 return ENOTSUP; // version is too new!
753 else if (ndrvSpec.version < 1)
754 return EINVAL; // version is not valid
755
756 /* Allocate storage for demux array */
757 MALLOC(ndrvDemux, struct ndrv_demux_desc*,
758 ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc), M_TEMP, M_WAITOK);
759 if (ndrvDemux == NULL)
760 return ENOMEM;
761
762 /* Allocate enough dlil_demux_descs */
763 MALLOC(dlilDemux, struct dlil_demux_desc*,
764 sizeof(*dlilDemux) * ndrvSpec.demux_count, M_TEMP, M_WAITOK);
765 if (dlilDemux == NULL)
766 error = ENOMEM;
767
768 if (error == 0)
769 {
770 /* Copy the ndrv demux array from userland */
771 error = copyin(ndrvSpec.demux_list, ndrvDemux,
772 ndrvSpec.demux_count * sizeof(struct ndrv_demux_desc));
773 ndrvSpec.demux_list = ndrvDemux;
774 }
775
776 if (error == 0)
777 {
778 /* At this point, we've at least got enough bytes to start looking around */
779 u_long demuxOn = 0;
780
781 bzero(&dlilSpec, sizeof(dlilSpec));
782 TAILQ_INIT(&dlilSpec.demux_desc_head);
783 dlilSpec.interface_family = np->nd_family;
784 dlilSpec.unit_number = np->nd_unit;
785 dlilSpec.input = ndrv_input;
786 dlilSpec.protocol_family = ndrvSpec.protocol_family;
787
788 for (demuxOn = 0; demuxOn < ndrvSpec.demux_count; demuxOn++)
789 {
790 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
791 error = ndrv_to_dlil_demux(&ndrvSpec.demux_list[demuxOn], &dlilDemux[demuxOn]);
792 if (error)
793 break;
794
795 /* Add the dlil_demux_desc to the list */
796 TAILQ_INSERT_TAIL(&dlilSpec.demux_desc_head, &dlilDemux[demuxOn], next);
797 }
798 }
799
800 if (error == 0)
801 {
802 /* We've got all our ducks lined up...lets attach! */
803 error = dlil_attach_protocol(&dlilSpec, &np->nd_tag);
804 }
805
806 /* Free any memory we've allocated */
807 if (dlilDemux)
808 FREE(dlilDemux, M_TEMP);
809 if (ndrvDemux)
810 FREE(ndrvDemux, M_TEMP);
811
812 return error;
813 }
814
815
816 int
817 ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil)
818 {
819 bzero(dlil, sizeof(*dlil));
820
821 if (ndrv->type < DLIL_DESC_ETYPE2)
822 {
823 /* using old "type", not supported */
824 return ENOTSUP;
825 }
826
827 if (ndrv->length > 28)
828 {
829 return EINVAL;
830 }
831
832 dlil->type = ndrv->type;
833 dlil->native_type = ndrv->data.other;
834 dlil->variants.native_type_length = ndrv->length;
835
836 return 0;
837 }
838
839 int
840 ndrv_delspec(struct ndrv_cb *np)
841 {
842 int result = 0;
843
844 if (np->nd_tag == 0)
845 return EINVAL;
846
847 /* Detach the protocol */
848 result = dlil_detach_protocol(np->nd_tag);
849 if (result == 0)
850 {
851 np->nd_tag = 0;
852 }
853
854 return result;
855 }
856
857 struct ndrv_cb *
858 ndrv_find_tag(unsigned int tag)
859 {
860 struct ndrv_cb* np;
861 int i;
862
863 if (tag == 0)
864 return NULL;
865
866 for (np = ndrvl.nd_next; np != NULL; np = np->nd_next)
867 {
868 if (np->nd_tag == tag)
869 {
870 return np;
871 }
872 }
873
874 return NULL;
875 }
876
877 void ndrv_dominit()
878 {
879 static int ndrv_dominited = 0;
880
881 if (ndrv_dominited == 0 &&
882 net_add_proto(&ndrvsw, &ndrvdomain) == 0)
883 ndrv_dominited = 1;
884 }
885
886 void
887 ndrv_read_event(struct socket* so, caddr_t ref, int waitf)
888 {
889 // Read an event
890 struct mbuf *m = NULL;
891 struct kern_event_msg *msg;
892 struct uio auio = {0};
893 int result = 0;
894 int flags = 0;
895
896 // Get the data
897 auio.uio_resid = 1000000; // large number to get all of the data
898 flags = MSG_DONTWAIT;
899 result = soreceive(so, (struct sockaddr**)NULL, &auio, &m,
900 (struct mbuf**)NULL, &flags);
901 if (result != 0 || m == NULL)
902 return;
903
904 // cast the mbuf to a kern_event_msg
905 // this is dangerous, doesn't handle linked mbufs
906 msg = mtod(m, struct kern_event_msg*);
907
908 // check for detaches, assume even filtering is working
909 if (msg->event_code == KEV_DL_IF_DETACHING ||
910 msg->event_code == KEV_DL_IF_DETACHED)
911 {
912 struct net_event_data *ev_data;
913 ev_data = (struct net_event_data*)msg->event_data;
914 ndrv_handle_ifp_detach(ev_data->if_family, ev_data->if_unit);
915 }
916
917 m_free(m);
918 }
919
920 void
921 ndrv_handle_ifp_detach(u_long family, short unit)
922 {
923 struct ndrv_cb* np;
924 u_long dl_tag;
925
926 /* Find all sockets using this interface. */
927 for (np = ndrvl.nd_next; np != &ndrvl; np = np->nd_next)
928 {
929 if (np->nd_family == family &&
930 np->nd_unit == unit)
931 {
932 /* This cb is using the detaching interface, but not for long. */
933 /* Let the protocol go */
934 if (np->nd_tag != 0)
935 ndrv_delspec(np);
936
937 /* Disavow all knowledge of the ifp */
938 np->nd_if = NULL;
939 np->nd_unit = 0;
940 np->nd_family = 0;
941 np->nd_send_tag = 0;
942
943 /* Make sure sending returns an error */
944 /* Is this safe? Will we drop the funnel? */
945 socantsendmore(np->nd_socket);
946 socantrcvmore(np->nd_socket);
947 }
948 }
949
950 /* Unregister our protocol */
951 if (dlil_find_dltag(family, unit, PF_NDRV, &dl_tag) == 0) {
952 dlil_detach_protocol(dl_tag);
953 }
954 }
955
956 struct pr_usrreqs ndrv_usrreqs = {
957 ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind,
958 ndrv_connect, pru_connect2_notsupp, ndrv_control, ndrv_detach,
959 ndrv_disconnect, pru_listen_notsupp, ndrv_peeraddr, pru_rcvd_notsupp,
960 pru_rcvoob_notsupp, ndrv_send, ndrv_sense, ndrv_shutdown,
961 ndrv_sockaddr, sosend, soreceive, sopoll
962 };
963
964 struct protosw ndrvsw =
965 { SOCK_RAW, &ndrvdomain, NDRVPROTO_NDRV, PR_ATOMIC|PR_ADDR,
966 0, ndrv_output, ndrv_ctlinput, ndrv_ctloutput,
967 0, ndrv_init, 0, 0,
968 ndrv_drain, ndrv_sysctl, &ndrv_usrreqs
969 };
970
971 struct domain ndrvdomain =
972 { AF_NDRV, "NetDriver", ndrv_dominit, NULL, NULL,
973 NULL,
974 NULL, NULL, 0, 0, 0, 0
975 };