]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ndrv.c
xnu-517.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
245 if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace)))
246 return(error);
247
248 MALLOC(np, struct ndrv_cb *, sizeof(*np), M_PCB, M_WAITOK);
249 if (np == NULL)
250 return (ENOMEM);
251 so->so_pcb = (caddr_t)np;
252 bzero(np, sizeof(*np));
253 #if NDRV_DEBUG
254 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
255 #endif
256 TAILQ_INIT(&np->nd_dlist);
257 np->nd_signature = NDRV_SIGNATURE;
258 np->nd_socket = so;
259 np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family;
260 np->nd_proto.sp_protocol = proto;
261 np->nd_if = NULL;
262 np->nd_tag = 0;
263 np->nd_family = 0;
264 np->nd_unit = 0;
265 insque((queue_t)np, (queue_t)&ndrvl);
266 return(0);
267 }
268
269 /*
270 * Destroy state just before socket deallocation.
271 * Flush data or not depending on the options.
272 */
273
274 int
275 ndrv_detach(struct socket *so)
276 {
277 register struct ndrv_cb *np = sotondrvcb(so);
278
279 if (np == 0)
280 return EINVAL;
281 return ndrv_do_detach(np);
282 }
283
284
285 /*
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).
290 *
291 * Don't expect this to be used.
292 */
293
294 int ndrv_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
295 {
296 register struct ndrv_cb *np = sotondrvcb(so);
297 int result = 0;
298
299 if (np == 0)
300 return EINVAL;
301
302 if (np->nd_faddr)
303 return EISCONN;
304
305 /* Allocate memory to store the remote address */
306 MALLOC(np->nd_faddr, struct sockaddr_ndrv*,
307 nam->sa_len, M_IFADDR, M_WAITOK);
308 if (result != 0)
309 return result;
310 if (np->nd_faddr == NULL)
311 return ENOMEM;
312
313 bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, nam->sa_len);
314 soisconnected(so);
315 return 0;
316 }
317
318 /*
319 * This is the "driver open" hook - we 'bind' to the
320 * named driver.
321 * Here's where we latch onto the driver.
322 */
323 int
324 ndrv_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
325 {
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 *);
331 int result;
332
333 if TAILQ_EMPTY(&ifnet)
334 return(EADDRNOTAVAIL); /* Quick sanity check */
335 np = sotondrvcb(so);
336 if (np == 0)
337 return EINVAL;
338
339 if (np->nd_laddr)
340 return EINVAL; /* XXX */
341
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)
345 return(ENOMEM);
346 bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
347 dname = sa->snd_name;
348 if (*dname == '\0')
349 return(EINVAL);
350 #if NDRV_DEBUG
351 kprintf("NDRV bind: %x, %x, %s\n", so, np, dname);
352 #endif
353 /* Track down the driver and its ifnet structure.
354 * There's no internal call for this so we have to dup the code
355 * in if.c/ifconf()
356 */
357 TAILQ_FOREACH(ifp, &ifnet, if_link) {
358 if (name_cmp(ifp, dname) == 0)
359 break;
360 }
361
362 if (ifp == NULL)
363 return(EADDRNOTAVAIL);
364
365 /*
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.
369 */
370 if (ifp->if_family == APPLE_IF_FAM_LOOPBACK)
371 return (ENOTSUP);
372
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;
378 int result = 0;
379 bzero(&ndrv_proto, sizeof(ndrv_proto));
380 TAILQ_INIT(&ndrv_proto.demux_desc_head);
381
382 ndrv_proto.interface_family = ifp->if_family;
383 ndrv_proto.protocol_family = PF_NDRV;
384 ndrv_proto.unit_number = ifp->if_unit;
385
386 result = dlil_attach_protocol(&ndrv_proto, &np->nd_send_tag);
387
388 /*
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.
393 */
394 if (result != 0)
395 np->nd_send_tag = 0;
396 }
397
398 np->nd_if = ifp;
399 np->nd_family = ifp->if_family;
400 np->nd_unit = ifp->if_unit;
401
402 return(0);
403 }
404
405 int
406 ndrv_disconnect(struct socket *so)
407 {
408 register struct ndrv_cb *np = sotondrvcb(so);
409
410 if (np == 0)
411 return EINVAL;
412
413 if (np->nd_faddr == 0)
414 return ENOTCONN;
415
416 ndrv_do_disconnect(np);
417 return 0;
418 }
419
420 /*
421 * Accessor function
422 */
423 struct ifnet*
424 ndrv_get_ifp(caddr_t ndrv_pcb)
425 {
426 struct ndrv_cb* np = (struct ndrv_cb*)ndrv_pcb;
427
428 #if DEBUG
429 {
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)
433 {
434 if (temp == np)
435 break;
436 }
437
438 if (temp != np)
439 {
440 log(LOG_WARNING, "PF_NDRV: ndrv_get_ifp called with invalid ndrv_cb!");
441 return NULL;
442 }
443 }
444 #endif
445
446 return np->nd_if;
447 }
448
449 /*
450 * Mark the connection as being incapable of further input.
451 */
452 int
453 ndrv_shutdown(struct socket *so)
454 {
455 socantsendmore(so);
456 return 0;
457 }
458
459 /*
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...
463 */
464 int
465 ndrv_send(struct socket *so, int flags, struct mbuf *m,
466 struct sockaddr *addr, struct mbuf *control,
467 struct proc *p)
468 {
469 int error;
470
471 if (control)
472 return EOPNOTSUPP;
473
474 error = ndrv_output(m, so);
475 m = NULL;
476 return error;
477 }
478
479
480 int
481 ndrv_abort(struct socket *so)
482 {
483 register struct ndrv_cb *np = sotondrvcb(so);
484
485 if (np == 0)
486 return EINVAL;
487
488 ndrv_do_disconnect(np);
489 return 0;
490 }
491
492 int
493 ndrv_sense(struct socket *so, struct stat *sb)
494 {
495 /*
496 * stat: don't bother with a blocksize.
497 */
498 return (0);
499 }
500
501 int
502 ndrv_sockaddr(struct socket *so, struct sockaddr **nam)
503 {
504 register struct ndrv_cb *np = sotondrvcb(so);
505 int len;
506
507 if (np == 0)
508 return EINVAL;
509
510 if (np->nd_laddr == 0)
511 return EINVAL;
512
513 len = np->nd_laddr->snd_len;
514 bcopy((caddr_t)np->nd_laddr, *nam,
515 (unsigned)len);
516 return 0;
517 }
518
519
520 int
521 ndrv_peeraddr(struct socket *so, struct sockaddr **nam)
522 {
523 register struct ndrv_cb *np = sotondrvcb(so);
524 int len;
525
526 if (np == 0)
527 return EINVAL;
528
529 if (np->nd_faddr == 0)
530 return ENOTCONN;
531
532 len = np->nd_faddr->snd_len;
533 bcopy((caddr_t)np->nd_faddr, *nam,
534 (unsigned)len);
535 return 0;
536 }
537
538
539 /* Control input */
540
541 void
542 ndrv_ctlinput(int dummy1, struct sockaddr *dummy2, void *dummy3)
543 {
544 }
545
546 /* Control output */
547
548 int
549 ndrv_ctloutput(struct socket *so, struct sockopt *sopt)
550 {
551 register struct ndrv_cb *np = sotondrvcb(so);
552 int error = 0;
553
554 switch(sopt->sopt_name)
555 {
556 case NDRV_DELDMXSPEC: /* Delete current spec */
557 /* Verify no parameter was passed */
558 if (sopt->sopt_val != NULL || sopt->sopt_valsize != 0) {
559 /*
560 * We don't support deleting a specific demux, it's
561 * all or nothing.
562 */
563 return EINVAL;
564 }
565 error = ndrv_delspec(np);
566 break;
567 case NDRV_SETDMXSPEC: /* Set protocol spec */
568 error = ndrv_setspec(np, sopt);
569 break;
570 case NDRV_ADDMULTICAST:
571 error = ndrv_do_add_multicast(np, sopt);
572 break;
573 case NDRV_DELMULTICAST:
574 error = ndrv_do_remove_multicast(np, sopt);
575 break;
576 default:
577 error = ENOTSUP;
578 }
579 #ifdef NDRV_DEBUG
580 log(LOG_WARNING, "NDRV CTLOUT: %x returns %d\n", sopt->sopt_name,
581 error);
582 #endif
583 return(error);
584 }
585
586 /* Drain the queues */
587 void
588 ndrv_drain()
589 {
590 }
591
592 /* Sysctl hook for NDRV */
593 int
594 ndrv_sysctl()
595 {
596 return(0);
597 }
598
599 int
600 ndrv_do_detach(register struct ndrv_cb *np)
601 {
602 struct ndrv_cb* cur_np = NULL;
603 struct socket *so = np->nd_socket;
604 struct ndrv_multicast* next;
605 int error = 0;
606
607 #if NDRV_DEBUG
608 kprintf("NDRV detach: %x, %x\n", so, np);
609 #endif
610 ndrv_remove_all_multicast(np);
611
612 if (np->nd_tag != 0)
613 {
614 error = dlil_detach_protocol(np->nd_tag);
615 if (error)
616 {
617 log(LOG_WARNING, "NDRV ndrv_do_detach: error %d removing dl_tag %d",
618 error, np->nd_tag);
619 return error;
620 }
621 }
622
623 /* Remove from the linked list of control blocks */
624 remque((queue_t)np);
625
626 if (np->nd_send_tag != 0)
627 {
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)
630 {
631 if (cur_np->nd_family == np->nd_family &&
632 cur_np->nd_unit == np->nd_unit)
633 {
634 break;
635 }
636 }
637
638 /* If there are no other interfaces, detach PF_NDRV from the interface */
639 if (cur_np == &ndrvl)
640 {
641 dlil_detach_protocol(np->nd_send_tag);
642 }
643 }
644
645 FREE((caddr_t)np, M_PCB);
646 so->so_pcb = 0;
647 sofree(so);
648 return error;
649 }
650
651 int
652 ndrv_do_disconnect(register struct ndrv_cb *np)
653 {
654 #if NDRV_DEBUG
655 kprintf("NDRV disconnect: %x\n", np);
656 #endif
657 if (np->nd_faddr)
658 {
659 FREE(np->nd_faddr, M_IFADDR);
660 np->nd_faddr = 0;
661 }
662 if (np->nd_socket->so_state & SS_NOFDREF)
663 ndrv_do_detach(np);
664 soisdisconnected(np->nd_socket);
665 return(0);
666 }
667
668 /*
669 * Try to compare a device name (q) with one of the funky ifnet
670 * device names (ifp).
671 */
672 int name_cmp(register struct ifnet *ifp, register char *q)
673 { register char *r;
674 register int len;
675 char buf[IFNAMSIZ];
676 static char *sprint_d();
677
678 r = buf;
679 len = strlen(ifp->if_name);
680 strncpy(r, ifp->if_name, IFNAMSIZ);
681 r += len;
682 (void)sprint_d(ifp->if_unit, r, IFNAMSIZ-(r-buf));
683 #if NDRV_DEBUG
684 kprintf("Comparing %s, %s\n", buf, q);
685 #endif
686 return(strncmp(buf, q, IFNAMSIZ));
687 }
688
689 /* Hackery - return a string version of a decimal number */
690 static char *
691 sprint_d(n, buf, buflen)
692 u_int n;
693 char *buf;
694 int buflen;
695 { char dbuf[IFNAMSIZ];
696 register char *cp = dbuf+IFNAMSIZ-1;
697
698 *cp = 0;
699 do { buflen--;
700 cp--;
701 *cp = "0123456789"[n % 10];
702 n /= 10;
703 } while (n != 0 && buflen > 0);
704 strncpy(buf, cp, IFNAMSIZ-buflen);
705 return (cp);
706 }
707
708 /*
709 * When closing, dump any enqueued mbufs.
710 */
711 void
712 ndrv_flushq(register struct ifqueue *q)
713 {
714 register struct mbuf *m;
715 for (;;)
716 {
717 IF_DEQUEUE(q, m);
718 if (m == NULL)
719 break;
720 IF_DROP(q);
721 if (m)
722 m_freem(m);
723 }
724 }
725
726 int
727 ndrv_setspec(struct ndrv_cb *np, struct sockopt *sopt)
728 {
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;
733 int error = 0;
734
735 /* Sanity checking */
736 if (np->nd_tag)
737 return EBUSY;
738 if (np->nd_if == NULL)
739 return EINVAL;
740 if (sopt->sopt_valsize != sizeof(struct ndrv_protocol_desc))
741 return EINVAL;
742
743 /* Copy the ndrvSpec */
744 error = sooptcopyin(sopt, &ndrvSpec, sizeof(struct ndrv_protocol_desc),
745 sizeof(struct ndrv_protocol_desc));
746 if (error != 0)
747 return error;
748
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
754
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)
759 return ENOMEM;
760
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)
765 error = ENOMEM;
766
767 if (error == 0)
768 {
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;
773 }
774
775 if (error == 0)
776 {
777 /* At this point, we've at least got enough bytes to start looking around */
778 u_long demuxOn = 0;
779
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;
786
787 for (demuxOn = 0; demuxOn < ndrvSpec.demux_count; demuxOn++)
788 {
789 /* Convert an ndrv_demux_desc to a dlil_demux_desc */
790 error = ndrv_to_dlil_demux(&ndrvSpec.demux_list[demuxOn], &dlilDemux[demuxOn]);
791 if (error)
792 break;
793
794 /* Add the dlil_demux_desc to the list */
795 TAILQ_INSERT_TAIL(&dlilSpec.demux_desc_head, &dlilDemux[demuxOn], next);
796 }
797 }
798
799 if (error == 0)
800 {
801 /* We've got all our ducks lined up...lets attach! */
802 error = dlil_attach_protocol(&dlilSpec, &np->nd_tag);
803 }
804
805 /* Free any memory we've allocated */
806 if (dlilDemux)
807 FREE(dlilDemux, M_TEMP);
808 if (ndrvDemux)
809 FREE(ndrvDemux, M_TEMP);
810
811 return error;
812 }
813
814
815 int
816 ndrv_to_dlil_demux(struct ndrv_demux_desc* ndrv, struct dlil_demux_desc* dlil)
817 {
818 bzero(dlil, sizeof(*dlil));
819
820 if (ndrv->type < DLIL_DESC_ETYPE2)
821 {
822 /* using old "type", not supported */
823 return ENOTSUP;
824 }
825
826 if (ndrv->length > 28)
827 {
828 return EINVAL;
829 }
830
831 dlil->type = ndrv->type;
832 dlil->native_type = ndrv->data.other;
833 dlil->variants.native_type_length = ndrv->length;
834
835 return 0;
836 }
837
838 int
839 ndrv_delspec(struct ndrv_cb *np)
840 {
841 int result = 0;
842
843 if (np->nd_tag == 0)
844 return EINVAL;
845
846 /* Detach the protocol */
847 result = dlil_detach_protocol(np->nd_tag);
848 if (result == 0)
849 {
850 np->nd_tag = 0;
851 }
852
853 return result;
854 }
855
856 struct ndrv_cb *
857 ndrv_find_tag(unsigned int tag)
858 {
859 struct ndrv_cb* np;
860 int i;
861
862 if (tag == 0)
863 return NULL;
864
865 for (np = ndrvl.nd_next; np != NULL; np = np->nd_next)
866 {
867 if (np->nd_tag == tag)
868 {
869 return np;
870 }
871 }
872
873 return NULL;
874 }
875
876 void ndrv_dominit()
877 {
878 static int ndrv_dominited = 0;
879
880 if (ndrv_dominited == 0 &&
881 net_add_proto(&ndrvsw, &ndrvdomain) == 0)
882 ndrv_dominited = 1;
883 }
884
885 void
886 ndrv_read_event(struct socket* so, caddr_t ref, int waitf)
887 {
888 // Read an event
889 struct mbuf *m = NULL;
890 struct kern_event_msg *msg;
891 struct uio auio = {0};
892 int result = 0;
893 int flags = 0;
894
895 // Get the data
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)
901 return;
902
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*);
906
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)
910 {
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);
914 }
915
916 m_free(m);
917 }
918
919 void
920 ndrv_handle_ifp_detach(u_long family, short unit)
921 {
922 struct ndrv_cb* np;
923 u_long dl_tag;
924
925 /* Find all sockets using this interface. */
926 for (np = ndrvl.nd_next; np != &ndrvl; np = np->nd_next)
927 {
928 if (np->nd_family == family &&
929 np->nd_unit == unit)
930 {
931 /* This cb is using the detaching interface, but not for long. */
932 /* Let the protocol go */
933 if (np->nd_tag != 0)
934 ndrv_delspec(np);
935
936 /* Delete the multicasts first */
937 ndrv_remove_all_multicast(np);
938
939 /* Disavow all knowledge of the ifp */
940 np->nd_if = NULL;
941 np->nd_unit = 0;
942 np->nd_family = 0;
943 np->nd_send_tag = 0;
944
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);
949 }
950 }
951
952 /* Unregister our protocol */
953 if (dlil_find_dltag(family, unit, PF_NDRV, &dl_tag) == 0) {
954 dlil_detach_protocol(dl_tag);
955 }
956 }
957
958 static int
959 ndrv_do_add_multicast(struct ndrv_cb *np, struct sockopt *sopt)
960 {
961 struct ndrv_multiaddr* ndrv_multi;
962 int result;
963
964 if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
965 sopt->sopt_level != SOL_NDRVPROTO)
966 return EINVAL;
967 if (np->nd_if == NULL)
968 return ENXIO;
969
970 // Allocate storage
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)
974 return ENOMEM;
975
976 // Copy in the address
977 result = copyin(sopt->sopt_val, &ndrv_multi->addr, sopt->sopt_valsize);
978
979 // Validate the sockaddr
980 if (result == 0 && sopt->sopt_valsize != ndrv_multi->addr.sa_len)
981 result = EINVAL;
982
983 if (result == 0 && ndrv_have_multicast(np, &ndrv_multi->addr))
984 result = EEXIST;
985
986 if (result == 0)
987 {
988 // Try adding the multicast
989 result = if_addmulti(np->nd_if, &ndrv_multi->addr, NULL);
990 }
991
992 if (result == 0)
993 {
994 // Add to our linked list
995 ndrv_multi->next = np->nd_multiaddrs;
996 np->nd_multiaddrs = ndrv_multi;
997 }
998 else
999 {
1000 // Free up the memory, something went wrong
1001 FREE(ndrv_multi, M_IFADDR);
1002 }
1003
1004 return result;
1005 }
1006
1007 static int
1008 ndrv_do_remove_multicast(struct ndrv_cb *np, struct sockopt *sopt)
1009 {
1010 struct sockaddr* multi_addr;
1011 struct ndrv_multiaddr* ndrv_entry = NULL;
1012 int result;
1013
1014 if (sopt->sopt_val == NULL || sopt->sopt_valsize < 2 ||
1015 sopt->sopt_level != SOL_NDRVPROTO)
1016 return EINVAL;
1017 if (np->nd_if == NULL)
1018 return ENXIO;
1019
1020 // Allocate storage
1021 MALLOC(multi_addr, struct sockaddr*, sopt->sopt_valsize,
1022 M_TEMP, M_WAITOK);
1023 if (multi_addr == NULL)
1024 return ENOMEM;
1025
1026 // Copy in the address
1027 result = copyin(sopt->sopt_val, multi_addr, sopt->sopt_valsize);
1028
1029 // Validate the sockaddr
1030 if (result == 0 && sopt->sopt_valsize != multi_addr->sa_len)
1031 result = EINVAL;
1032
1033 if (result == 0)
1034 {
1035 /* Find the old entry */
1036 ndrv_entry = ndrv_have_multicast(np, multi_addr);
1037
1038 if (ndrv_entry == NULL)
1039 result = ENOENT;
1040 }
1041
1042 if (result == 0)
1043 {
1044 // Try deleting the multicast
1045 result = if_delmulti(np->nd_if, &ndrv_entry->addr);
1046 }
1047
1048 if (result == 0)
1049 {
1050 // Remove from our linked list
1051 struct ndrv_multiaddr* cur = np->nd_multiaddrs;
1052
1053 if (cur == ndrv_entry)
1054 {
1055 np->nd_multiaddrs = cur->next;
1056 }
1057 else
1058 {
1059 for (cur = cur->next; cur != NULL; cur = cur->next)
1060 {
1061 if (cur->next == ndrv_entry)
1062 {
1063 cur->next = cur->next->next;
1064 break;
1065 }
1066 }
1067 }
1068
1069 // Free the memory
1070 FREE(ndrv_entry, M_IFADDR);
1071 }
1072 FREE(multi_addr, M_TEMP);
1073
1074 return result;
1075 }
1076
1077 static struct ndrv_multiaddr*
1078 ndrv_have_multicast(struct ndrv_cb *np, struct sockaddr* inAddr)
1079 {
1080 struct ndrv_multiaddr* cur;
1081 for (cur = np->nd_multiaddrs; cur != NULL; cur = cur->next)
1082 {
1083
1084 if ((inAddr->sa_len == cur->addr.sa_len) &&
1085 (bcmp(&cur->addr, inAddr, inAddr->sa_len) == 0))
1086 {
1087 // Found a match
1088 return cur;
1089 }
1090 }
1091
1092 return NULL;
1093 }
1094
1095 static void
1096 ndrv_remove_all_multicast(struct ndrv_cb* np)
1097 {
1098 struct ndrv_multiaddr* cur;
1099
1100 if (np->nd_if != NULL)
1101 {
1102 while (np->nd_multiaddrs != NULL)
1103 {
1104 cur = np->nd_multiaddrs;
1105 np->nd_multiaddrs = cur->next;
1106
1107 if_delmulti(np->nd_if, &cur->addr);
1108 FREE(cur, M_IFADDR);
1109 }
1110 }
1111 }
1112
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
1119 };
1120
1121 struct protosw ndrvsw =
1122 { SOCK_RAW, &ndrvdomain, NDRVPROTO_NDRV, PR_ATOMIC|PR_ADDR,
1123 0, ndrv_output, ndrv_ctlinput, ndrv_ctloutput,
1124 0, ndrv_init, 0, 0,
1125 ndrv_drain, ndrv_sysctl, &ndrv_usrreqs
1126 };
1127
1128 struct domain ndrvdomain =
1129 { AF_NDRV, "NetDriver", ndrv_dominit, NULL, NULL,
1130 NULL,
1131 NULL, NULL, 0, 0, 0, 0
1132 };