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