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