2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
24 * @(#)ndrv.c 1.1 (MacOSX) 6/10/43
25 * Justin Walker, 970604
27 * 980130 - Cleanup, reorg, performance improvemements
28 * 000816 - Removal of Y adapter cruft
32 * PF_NDRV allows raw access to a specified network device, directly
33 * with a socket. Expected use involves a socket option to request
34 * protocol packets. This lets ndrv_output() call dlil_output(), and
35 * lets DLIL find the proper recipient for incoming packets.
36 * The purpose here is for user-mode protocol implementation.
37 * Note that "pure raw access" will still be accomplished with BPF.
39 * In addition to the former use, when combined with socket NKEs,
40 * PF_NDRV permits a fairly flexible mechanism for implementing
41 * strange protocol support. One of the main ones will be the
42 * BlueBox/Classic Shared IP Address support.
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
50 #include <sys/protosw.h>
51 #include <sys/domain.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/ioctl.h>
55 #include <sys/errno.h>
56 #include <sys/syslog.h>
59 #include <kern/queue.h>
62 #include <net/netisr.h>
63 #include <net/route.h>
64 #include <net/if_llc.h>
65 #include <net/if_dl.h>
66 #include <net/if_types.h>
71 #include <netinet/in.h>
72 #include <netinet/in_var.h>
74 #include <netinet/if_ether.h>
78 #include <netns/ns_if.h>
82 #include <netiso/argo_debug.h>
83 #include <netiso/iso.h>
84 #include <netiso/iso_var.h>
85 #include <netiso/iso_snpac.h>
89 #include <netccitt/dll.h>
90 #include <netccitt/llc_var.h>
93 #include <machine/spl.h>
95 int ndrv_do_detach(struct ndrv_cb
*);
96 int ndrv_do_disconnect(struct ndrv_cb
*);
98 unsigned long ndrv_sendspace
= NDRVSNDQ
;
99 unsigned long ndrv_recvspace
= NDRVRCVQ
;
100 struct ndrv_cb ndrvl
; /* Head of controlblock list */
102 /* To handle input, need to map tag to ndrv_cb */
104 { unsigned int tm_tag
; /* Tag in use */
105 struct ndrv_cb
*tm_np
; /* Owning device */
106 struct dlil_demux_desc
*tm_dm
; /* Our local copy */
109 struct ndrv_tag_map
*ndrv_tags
;
110 #define TAG_MAP_COUNT 10
113 struct domain ndrvdomain
;
114 extern struct protosw ndrvsw
[];
118 * Protocol init function for NDRV protocol
119 * Init the control block list.
124 ndrvl
.nd_next
= ndrvl
.nd_prev
= &ndrvl
;
128 * Protocol output - Called to output a raw network packet directly
132 ndrv_output(register struct mbuf
*m
, register struct socket
*so
)
133 { register struct ndrv_cb
*np
= sotondrvcb(so
);
134 register struct ifnet
*ifp
= np
->nd_if
;
136 extern void kprintf(const char *, ...);
139 kprintf("NDRV output: %x, %x, %x\n", m
, so
, np
);
143 * No header is a format error
145 if ((m
->m_flags
&M_PKTHDR
) == 0)
149 * Can't do multicast accounting because we don't know
150 * (a) if our interface does multicast; and
151 * (b) what a multicast address looks like
156 * Can't call DLIL to do the job - we don't have a tag
157 * and we aren't really a protocol
160 (*ifp
->if_output
)(ifp
, m
);
166 ndrv_input(struct mbuf
*m
,
173 struct sockaddr_dl ndrvsrc
= {sizeof (struct sockaddr_dl
), AF_NDRV
};
174 register struct ndrv_cb
*np
;
175 extern struct ndrv_cb
*ndrv_find_tag(unsigned int);
178 /* move packet from if queue to socket */
179 /* Should be media-independent */
180 ndrvsrc
.sdl_type
= IFT_ETHER
;
181 ndrvsrc
.sdl_nlen
= 0;
182 ndrvsrc
.sdl_alen
= 6;
183 ndrvsrc
.sdl_slen
= 0;
184 bcopy(frame_header
, &ndrvsrc
.sdl_data
, 6);
187 np
= ndrv_find_tag(dl_tag
);
193 if (sbappendaddr(&(so
->so_rcv
), (struct sockaddr
*)&ndrvsrc
,
194 m
, (struct mbuf
*)0) == 0)
195 { /* yes, sbappendaddr returns zero if the sockbuff is full... */
205 ndrv_ioctl(unsigned long dl_tag
,
207 unsigned long command
,
211 return((*ifp
->if_ioctl
)(ifp
, command
, data
));
215 ndrv_control(struct socket
*so
, u_long cmd
, caddr_t data
,
216 struct ifnet
*ifp
, struct proc
*p
)
222 * Allocate an ndrv control block and some buffer space for the socket
225 ndrv_attach(struct socket
*so
, int proto
, struct proc
*p
)
227 register struct ndrv_cb
*np
= sotondrvcb(so
);
229 if ((so
->so_state
& SS_PRIV
) == 0)
233 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
235 MALLOC(np
, struct ndrv_cb
*, sizeof(*np
), M_PCB
, M_WAITOK
);
239 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
241 if ((so
->so_pcb
= (caddr_t
)np
))
242 bzero(np
, sizeof(*np
));
245 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
247 TAILQ_INIT(&np
->nd_dlist
);
248 np
->nd_signature
= NDRV_SIGNATURE
;
250 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
251 np
->nd_proto
.sp_protocol
= proto
;
252 insque((queue_t
)np
, (queue_t
)&ndrvl
);
257 * Destroy state just before socket deallocation.
258 * Flush data or not depending on the options.
262 ndrv_detach(struct socket
*so
)
264 register struct ndrv_cb
*np
= sotondrvcb(so
);
268 return ndrv_do_detach(np
);
273 * If a socket isn't bound to a single address,
274 * the ndrv input routine will hand it anything
275 * within that protocol family (assuming there's
276 * nothing else around it should go to).
278 * Don't expect this to be used.
281 int ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
283 register struct ndrv_cb
*np
= sotondrvcb(so
);
291 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, sizeof(struct sockaddr_ndrv
));
297 * This is the "driver open" hook - we 'bind' to the
299 * Here's where we latch onto the driver and make it ours.
302 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
303 { register struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
304 register char *dname
;
305 register struct ndrv_cb
*np
;
306 register struct ifnet
*ifp
;
307 extern int name_cmp(struct ifnet
*, char *);
309 if TAILQ_EMPTY(&ifnet
)
310 return(EADDRNOTAVAIL
); /* Quick sanity check */
316 return EINVAL
; /* XXX */
318 /* I think we just latch onto a copy here; the caller frees */
319 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
320 if (np
->nd_laddr
== NULL
)
322 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
323 dname
= sa
->snd_name
;
327 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
329 /* Track down the driver and its ifnet structure.
330 * There's no internal call for this so we have to dup the code
333 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
334 if (name_cmp(ifp
, dname
) == 0)
339 return(EADDRNOTAVAIL
);
345 ndrv_disconnect(struct socket
*so
)
347 register struct ndrv_cb
*np
= sotondrvcb(so
);
352 if (np
->nd_faddr
== 0)
355 ndrv_do_disconnect(np
);
360 * Mark the connection as being incapable of further input.
363 ndrv_shutdown(struct socket
*so
)
370 * Ship a packet out. The ndrv output will pass it
371 * to the appropriate driver. The really tricky part
372 * is the destination address...
375 ndrv_send(struct socket
*so
, int flags
, struct mbuf
*m
,
376 struct sockaddr
*addr
, struct mbuf
*control
,
384 error
= ndrv_output(m
, so
);
391 ndrv_abort(struct socket
*so
)
393 register struct ndrv_cb
*np
= sotondrvcb(so
);
398 ndrv_do_disconnect(np
);
403 ndrv_sense(struct socket
*so
, struct stat
*sb
)
406 * stat: don't bother with a blocksize.
412 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
414 register struct ndrv_cb
*np
= sotondrvcb(so
);
420 if (np
->nd_laddr
== 0)
423 len
= np
->nd_laddr
->snd_len
;
424 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
431 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
433 register struct ndrv_cb
*np
= sotondrvcb(so
);
439 if (np
->nd_faddr
== 0)
442 len
= np
->nd_faddr
->snd_len
;
443 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
452 ndrv_ctlinput(int dummy1
, struct sockaddr
*dummy2
, void *dummy3
)
459 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
460 { register struct ndrv_cb
*np
= sotondrvcb(so
);
461 struct ndrv_descr nd
;
462 int count
= 0, error
= 0;
463 int ndrv_getspec(struct ndrv_cb
*,
465 struct ndrv_descr
*);
466 int ndrv_setspec(struct ndrv_cb
*, struct ndrv_descr
*);
467 int ndrv_delspec(struct ndrv_cb
*, struct ndrv_descr
*);
469 if (sopt
->sopt_name
!= NDRV_DMXSPECCNT
)
470 error
= sooptcopyin(sopt
, &nd
, sizeof nd
, sizeof nd
);
472 { switch(sopt
->sopt_name
)
473 { case NDRV_DMXSPEC
: /* Get/Set(Add) spec list */
474 if (sopt
->sopt_dir
== SOPT_GET
)
475 error
= ndrv_getspec(np
, sopt
, &nd
);
477 error
= ndrv_setspec(np
, &nd
);
479 case NDRV_DELDMXSPEC
: /* Delete specified specs */
480 error
= ndrv_delspec(np
, &nd
);
482 case NDRV_DMXSPECCNT
: /* How many are in the list */
483 count
= np
->nd_descrcnt
;
484 error
= sooptcopyout(sopt
, &count
, sizeof count
);
489 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
495 /* Drain the queues */
501 /* Sysctl hook for NDRV */
509 ndrv_do_detach(register struct ndrv_cb
*np
)
510 { register struct socket
*so
= np
->nd_socket
;
511 int ndrv_dump_descr(struct ndrv_cb
*);
514 kprintf("NDRV detach: %x, %x\n", so
, np
);
516 if (!TAILQ_EMPTY(&np
->nd_dlist
))
520 FREE((caddr_t
)np
, M_PCB
);
527 ndrv_do_disconnect(register struct ndrv_cb
*np
)
530 kprintf("NDRV disconnect: %x\n", np
);
533 { m_freem(dtom(np
->nd_faddr
));
536 if (np
->nd_socket
->so_state
& SS_NOFDREF
)
538 soisdisconnected(np
->nd_socket
);
543 * Try to compare a device name (q) with one of the funky ifnet
544 * device names (ifp).
546 int name_cmp(register struct ifnet
*ifp
, register char *q
)
550 static char *sprint_d();
553 len
= strlen(ifp
->if_name
);
554 strncpy(r
, ifp
->if_name
, IFNAMSIZ
);
556 (void)sprint_d(ifp
->if_unit
, r
, IFNAMSIZ
-(r
-buf
));
558 kprintf("Comparing %s, %s\n", buf
, q
);
560 return(strncmp(buf
, q
, IFNAMSIZ
));
563 /* Hackery - return a string version of a decimal number */
565 sprint_d(n
, buf
, buflen
)
569 { char dbuf
[IFNAMSIZ
];
570 register char *cp
= dbuf
+IFNAMSIZ
-1;
575 *cp
= "0123456789"[n
% 10];
577 } while (n
!= 0 && buflen
> 0);
578 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
583 * When closing, dump any enqueued mbufs.
586 ndrv_flushq(register struct ifqueue
*q
)
587 { register struct mbuf
*m
;
603 ndrv_getspec(struct ndrv_cb
*np
,
604 struct sockopt
*sopt
,
605 struct ndrv_descr
*nd
)
606 { struct dlil_demux_desc
*mp
, *mp1
;
609 /* Compute # structs to copy */
610 i
= k
= min(np
->nd_descrcnt
,
611 (nd
->nd_len
/ sizeof (struct dlil_demux_desc
)));
612 mp
= (struct dlil_demux_desc
*)nd
->nd_buf
;
613 TAILQ_FOREACH(mp1
, &np
->nd_dlist
, next
)
616 error
= copyout(mp1
, mp
++, sizeof (struct dlil_demux_desc
));
621 { nd
->nd_len
= i
* (sizeof (struct dlil_demux_desc
));
622 error
= sooptcopyout(sopt
, nd
, sizeof (*nd
));
628 * Install a protocol descriptor, making us a protocol handler.
629 * We expect the client to handle all output tasks (we get fully
630 * formed frames from the client and hand them to the driver
631 * directly). The reason we register is to get those incoming
632 * frames. We do it as a protocol handler because the network layer
633 * already knows how find the ones we want, so there's no need to
635 * Since this mechanism is mostly for user mode, most of the procedures
636 * to be registered will be null.
637 * Note that we jam the pair (PF_XXX, native_type) into the native_type
638 * field of the demux descriptor. Yeah, it's a hack.
641 ndrv_setspec(struct ndrv_cb
*np
, struct ndrv_descr
*nd
)
642 { struct dlil_demux_desc
*mp
, *mp1
;
643 int i
= 0, error
= 0, j
;
646 struct dlil_proto_reg_str proto_spec
;
647 int ndrv_add_descr(struct ndrv_cb
*, struct dlil_proto_reg_str
*);
649 bzero((caddr_t
)&proto_spec
, sizeof (proto_spec
));
650 i
= nd
->nd_len
/ (sizeof (struct dlil_demux_desc
)); /* # elts */
651 MALLOC(native_values
,int *, i
* sizeof (int), M_TEMP
, M_WAITOK
);
652 if (native_values
== NULL
)
654 mp
= (struct dlil_demux_desc
*)nd
->nd_buf
;
655 for (j
= 0; j
++ < i
;)
656 { MALLOC(mp1
, struct dlil_demux_desc
*,
657 sizeof (struct dlil_demux_desc
), M_PCB
, M_WAITOK
);
662 error
= copyin(mp
++, mp1
, sizeof (struct dlil_demux_desc
));
665 TAILQ_INSERT_TAIL(&np
->nd_dlist
, mp1
, next
);
666 value
= (unsigned long)mp1
->native_type
;
667 native_values
[j
] = (unsigned short)value
;
668 mp1
->native_type
= (char *)&native_values
[j
];
669 proto_spec
.protocol_family
= (unsigned char)(value
>>16); /* Oy! */
670 proto_spec
.interface_family
= np
->nd_if
->if_family
;
671 proto_spec
.unit_number
= np
->nd_if
->if_unit
;
673 proto_spec
.input
= ndrv_input
;
674 proto_spec
.pre_output
= NULL
;
675 /* No event/offer functionality needed */
676 proto_spec
.event
= NULL
;
677 proto_spec
.offer
= NULL
;
678 proto_spec
.ioctl
= ndrv_ioctl
; /* ??? */
679 /* What exactly does this do again? */
680 proto_spec
.default_proto
= 0;
685 { struct dlil_demux_desc
*mp2
;
687 while ((mp2
= TAILQ_FIRST(&np
->nd_dlist
))) {
688 TAILQ_REMOVE(&np
->nd_dlist
, mp2
, next
);
692 error
= ndrv_add_descr(np
, &proto_spec
);
694 log(LOG_WARNING
, "NDRV ADDSPEC: got error %d\n", error
);
696 FREE(native_values
, M_TEMP
);
701 ndrv_delspec(struct ndrv_cb
*np
, struct ndrv_descr
*nd
)
702 { struct dlil_demux_desc
*mp
;
708 ndrv_find_tag(unsigned int tag
)
709 { struct ndrv_tag_map
*tmp
;
713 for (i
=0; i
++ < tag_map_count
; tmp
++)
714 if (tmp
->tm_tag
== tag
)
720 ndrv_add_tag(struct ndrv_cb
*np
, unsigned int tag
,
721 struct dlil_demux_desc
*mp
)
722 { struct ndrv_tag_map
*tmp
;
726 for (i
=0; i
++ < tag_map_count
; tmp
++)
727 if (tmp
->tm_tag
== 0)
731 log(LOG_WARNING
, "NDRV ADDING TAG %d\n", tag
);
736 /* Oops - ran out of space. Realloc */
737 i
= tag_map_count
+ TAG_MAP_COUNT
;
738 MALLOC(tmp
, struct ndrv_tag_map
*, i
* sizeof (struct ndrv_tag_map
),
742 /* Clear tail of new table, except for the slot we are creating ... */
743 bzero((caddr_t
)&tmp
[tag_map_count
+1],
744 (TAG_MAP_COUNT
-1) * sizeof (struct ndrv_tag_map
));
745 /* ...and then copy in the original piece */
747 bcopy(ndrv_tags
, tmp
,
748 tag_map_count
* sizeof (struct ndrv_tag_map
));
749 /* ...and then install the new tag... */
750 tmp
[tag_map_count
].tm_tag
= tag
;
751 tmp
[tag_map_count
].tm_np
= np
;
754 FREE(ndrv_tags
, M_PCB
);
757 log(LOG_WARNING
, "NDRV ADDING TAG %d (new chunk)\n", tag
);
763 * Attach the proto spec list, and record the tags.
766 ndrv_add_descr(struct ndrv_cb
*np
, struct dlil_proto_reg_str
*proto_spec
)
767 { unsigned long dl_tag
;
769 struct dlil_demux_desc
*mp
;
771 /* Attach to our device to get requested packets */
772 TAILQ_INIT(&proto_spec
->demux_desc_head
);
773 error
= dlil_attach_protocol(proto_spec
, &dl_tag
);
776 error
= ndrv_add_tag(np
, dl_tag
, mp
);
782 ndrv_dump_descr(struct ndrv_cb
*np
)
783 { struct dlil_demux_desc
*dm1
, *dm2
;
784 struct ndrv_tag_map
*tmp
;
787 if (dm1
= TAILQ_FIRST(&np
->nd_dlist
))
788 { for (i
= 0, tmp
= &ndrv_tags
[0]; i
++ < tag_map_count
; tmp
++)
789 if (tmp
->tm_np
== np
)
790 { error
= dlil_detach_protocol(tmp
->tm_tag
);
792 { dm2
= TAILQ_NEXT(dm1
, next
);
797 "Detached tag %d (error %d)\n",
808 static int ndrv_dominited
= 0;
810 if (ndrv_dominited
== 0) {
811 net_add_proto(&ndrvsw
[0], &ndrvdomain
);
817 struct pr_usrreqs ndrv_usrreqs
= {
818 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
819 ndrv_connect
, pru_connect2_notsupp
, ndrv_control
, ndrv_detach
,
820 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
821 pru_rcvoob_notsupp
, ndrv_send
, ndrv_sense
, ndrv_shutdown
,
822 ndrv_sockaddr
, sosend
, soreceive
, sopoll
825 struct protosw ndrvsw
[] =
826 { { SOCK_RAW
, &ndrvdomain
, 0, PR_ATOMIC
|PR_ADDR
,
827 0, ndrv_output
, ndrv_ctlinput
, ndrv_ctloutput
,
829 ndrv_drain
, ndrv_sysctl
, &ndrv_usrreqs
833 struct domain ndrvdomain
=
834 { AF_NDRV
, "NetDriver", ndrv_dominit
, NULL
, NULL
,
836 NULL
, NULL
, 0, 0, 0, 0