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