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