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
);
237 kprintf("NDRV attach: %x, %x, %x\n", so
, proto
, np
);
239 if ((so
->so_pcb
= (caddr_t
)np
))
240 bzero(np
, sizeof(*np
));
243 if ((error
= soreserve(so
, ndrv_sendspace
, ndrv_recvspace
)))
245 TAILQ_INIT(&np
->nd_dlist
);
246 np
->nd_signature
= NDRV_SIGNATURE
;
248 np
->nd_proto
.sp_family
= so
->so_proto
->pr_domain
->dom_family
;
249 np
->nd_proto
.sp_protocol
= proto
;
250 insque((queue_t
)np
, (queue_t
)&ndrvl
);
255 * Destroy state just before socket deallocation.
256 * Flush data or not depending on the options.
260 ndrv_detach(struct socket
*so
)
262 register struct ndrv_cb
*np
= sotondrvcb(so
);
266 return ndrv_do_detach(np
);
271 * If a socket isn't bound to a single address,
272 * the ndrv input routine will hand it anything
273 * within that protocol family (assuming there's
274 * nothing else around it should go to).
276 * Don't expect this to be used.
279 int ndrv_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
281 register struct ndrv_cb
*np
= sotondrvcb(so
);
289 bcopy((caddr_t
) nam
, (caddr_t
) np
->nd_faddr
, sizeof(struct sockaddr_ndrv
));
295 * This is the "driver open" hook - we 'bind' to the
297 * Here's where we latch onto the driver and make it ours.
300 ndrv_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
301 { register struct sockaddr_ndrv
*sa
= (struct sockaddr_ndrv
*) nam
;
302 register char *dname
;
303 register struct ndrv_cb
*np
;
304 register struct ifnet
*ifp
;
305 extern int name_cmp(struct ifnet
*, char *);
307 if TAILQ_EMPTY(&ifnet
)
308 return(EADDRNOTAVAIL
); /* Quick sanity check */
314 return EINVAL
; /* XXX */
316 /* I think we just latch onto a copy here; the caller frees */
317 np
->nd_laddr
= _MALLOC(sizeof(struct sockaddr_ndrv
), M_IFADDR
, M_WAITOK
);
318 if (np
->nd_laddr
== NULL
)
320 bcopy((caddr_t
) sa
, (caddr_t
) np
->nd_laddr
, sizeof(struct sockaddr_ndrv
));
321 dname
= sa
->snd_name
;
325 kprintf("NDRV bind: %x, %x, %s\n", so
, np
, dname
);
327 /* Track down the driver and its ifnet structure.
328 * There's no internal call for this so we have to dup the code
331 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
332 if (name_cmp(ifp
, dname
) == 0)
337 return(EADDRNOTAVAIL
);
343 ndrv_disconnect(struct socket
*so
)
345 register struct ndrv_cb
*np
= sotondrvcb(so
);
350 if (np
->nd_faddr
== 0)
353 ndrv_do_disconnect(np
);
358 * Mark the connection as being incapable of further input.
361 ndrv_shutdown(struct socket
*so
)
368 * Ship a packet out. The ndrv output will pass it
369 * to the appropriate driver. The really tricky part
370 * is the destination address...
373 ndrv_send(struct socket
*so
, int flags
, struct mbuf
*m
,
374 struct sockaddr
*addr
, struct mbuf
*control
,
382 error
= ndrv_output(m
, so
);
389 ndrv_abort(struct socket
*so
)
391 register struct ndrv_cb
*np
= sotondrvcb(so
);
396 ndrv_do_disconnect(np
);
401 ndrv_sense(struct socket
*so
, struct stat
*sb
)
404 * stat: don't bother with a blocksize.
410 ndrv_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
412 register struct ndrv_cb
*np
= sotondrvcb(so
);
418 if (np
->nd_laddr
== 0)
421 len
= np
->nd_laddr
->snd_len
;
422 bcopy((caddr_t
)np
->nd_laddr
, *nam
,
429 ndrv_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
431 register struct ndrv_cb
*np
= sotondrvcb(so
);
437 if (np
->nd_faddr
== 0)
440 len
= np
->nd_faddr
->snd_len
;
441 bcopy((caddr_t
)np
->nd_faddr
, *nam
,
450 ndrv_ctlinput(int dummy1
, struct sockaddr
*dummy2
, void *dummy3
)
457 ndrv_ctloutput(struct socket
*so
, struct sockopt
*sopt
)
458 { register struct ndrv_cb
*np
= sotondrvcb(so
);
459 struct ndrv_descr nd
;
460 int count
= 0, error
= 0;
461 int ndrv_getspec(struct ndrv_cb
*,
463 struct ndrv_descr
*);
464 int ndrv_setspec(struct ndrv_cb
*, struct ndrv_descr
*);
465 int ndrv_delspec(struct ndrv_cb
*, struct ndrv_descr
*);
467 if (sopt
->sopt_name
!= NDRV_DMXSPECCNT
)
468 error
= sooptcopyin(sopt
, &nd
, sizeof nd
, sizeof nd
);
470 { switch(sopt
->sopt_name
)
471 { case NDRV_DMXSPEC
: /* Get/Set(Add) spec list */
472 if (sopt
->sopt_dir
== SOPT_GET
)
473 error
= ndrv_getspec(np
, sopt
, &nd
);
475 error
= ndrv_setspec(np
, &nd
);
477 case NDRV_DELDMXSPEC
: /* Delete specified specs */
478 error
= ndrv_delspec(np
, &nd
);
480 case NDRV_DMXSPECCNT
: /* How many are in the list */
481 count
= np
->nd_descrcnt
;
482 error
= sooptcopyout(sopt
, &count
, sizeof count
);
487 log(LOG_WARNING
, "NDRV CTLOUT: %x returns %d\n", sopt
->sopt_name
,
493 /* Drain the queues */
499 /* Sysctl hook for NDRV */
507 ndrv_do_detach(register struct ndrv_cb
*np
)
508 { register struct socket
*so
= np
->nd_socket
;
509 int ndrv_dump_descr(struct ndrv_cb
*);
512 kprintf("NDRV detach: %x, %x\n", so
, np
);
514 if (!TAILQ_EMPTY(&np
->nd_dlist
))
518 FREE((caddr_t
)np
, M_PCB
);
525 ndrv_do_disconnect(register struct ndrv_cb
*np
)
528 kprintf("NDRV disconnect: %x\n", np
);
531 { m_freem(dtom(np
->nd_faddr
));
534 if (np
->nd_socket
->so_state
& SS_NOFDREF
)
536 soisdisconnected(np
->nd_socket
);
541 * Try to compare a device name (q) with one of the funky ifnet
542 * device names (ifp).
544 int name_cmp(register struct ifnet
*ifp
, register char *q
)
548 static char *sprint_d();
551 len
= strlen(ifp
->if_name
);
552 strncpy(r
, ifp
->if_name
, IFNAMSIZ
);
554 (void)sprint_d(ifp
->if_unit
, r
, IFNAMSIZ
-(r
-buf
));
556 kprintf("Comparing %s, %s\n", buf
, q
);
558 return(strncmp(buf
, q
, IFNAMSIZ
));
561 /* Hackery - return a string version of a decimal number */
563 sprint_d(n
, buf
, buflen
)
567 { char dbuf
[IFNAMSIZ
];
568 register char *cp
= dbuf
+IFNAMSIZ
-1;
573 *cp
= "0123456789"[n
% 10];
575 } while (n
!= 0 && buflen
> 0);
576 strncpy(buf
, cp
, IFNAMSIZ
-buflen
);
581 * When closing, dump any enqueued mbufs.
584 ndrv_flushq(register struct ifqueue
*q
)
585 { register struct mbuf
*m
;
601 ndrv_getspec(struct ndrv_cb
*np
,
602 struct sockopt
*sopt
,
603 struct ndrv_descr
*nd
)
604 { struct dlil_demux_desc
*mp
, *mp1
;
607 /* Compute # structs to copy */
608 i
= k
= min(np
->nd_descrcnt
,
609 (nd
->nd_len
/ sizeof (struct dlil_demux_desc
)));
610 mp
= (struct dlil_demux_desc
*)nd
->nd_buf
;
611 TAILQ_FOREACH(mp1
, &np
->nd_dlist
, next
)
614 error
= copyout(mp1
, mp
++, sizeof (struct dlil_demux_desc
));
619 { nd
->nd_len
= i
* (sizeof (struct dlil_demux_desc
));
620 error
= sooptcopyout(sopt
, nd
, sizeof (*nd
));
626 * Install a protocol descriptor, making us a protocol handler.
627 * We expect the client to handle all output tasks (we get fully
628 * formed frames from the client and hand them to the driver
629 * directly). The reason we register is to get those incoming
630 * frames. We do it as a protocol handler because the network layer
631 * already knows how find the ones we want, so there's no need to
633 * Since this mechanism is mostly for user mode, most of the procedures
634 * to be registered will be null.
635 * Note that we jam the pair (PF_XXX, native_type) into the native_type
636 * field of the demux descriptor. Yeah, it's a hack.
639 ndrv_setspec(struct ndrv_cb
*np
, struct ndrv_descr
*nd
)
640 { struct dlil_demux_desc
*mp
, *mp1
;
641 int i
= 0, error
= 0, j
;
644 struct dlil_proto_reg_str proto_spec
;
645 int ndrv_add_descr(struct ndrv_cb
*, struct dlil_proto_reg_str
*);
647 bzero((caddr_t
)&proto_spec
, sizeof (proto_spec
));
648 i
= nd
->nd_len
/ (sizeof (struct dlil_demux_desc
)); /* # elts */
649 MALLOC(native_values
,int *, i
* sizeof (int), M_TEMP
, M_WAITOK
);
650 mp
= (struct dlil_demux_desc
*)nd
->nd_buf
;
651 for (j
= 0; j
++ < i
;)
652 { MALLOC(mp1
, struct dlil_demux_desc
*,
653 sizeof (struct dlil_demux_desc
), M_PCB
, M_WAITOK
);
658 error
= copyin(mp
++, mp1
, sizeof (struct dlil_demux_desc
));
661 TAILQ_INSERT_TAIL(&np
->nd_dlist
, mp1
, next
);
662 value
= (unsigned long)mp1
->native_type
;
663 native_values
[j
] = (unsigned short)value
;
664 mp1
->native_type
= (char *)&native_values
[j
];
665 proto_spec
.protocol_family
= (unsigned char)(value
>>16); /* Oy! */
666 proto_spec
.interface_family
= np
->nd_if
->if_family
;
667 proto_spec
.unit_number
= np
->nd_if
->if_unit
;
669 proto_spec
.input
= ndrv_input
;
670 proto_spec
.pre_output
= NULL
;
671 /* No event/offer functionality needed */
672 proto_spec
.event
= NULL
;
673 proto_spec
.offer
= NULL
;
674 proto_spec
.ioctl
= ndrv_ioctl
; /* ??? */
675 /* What exactly does this do again? */
676 proto_spec
.default_proto
= 0;
681 { struct dlil_demux_desc
*mp2
;
683 TAILQ_FOREACH(mp2
, &np
->nd_dlist
, next
)
686 error
= ndrv_add_descr(np
, &proto_spec
);
688 log(LOG_WARNING
, "NDRV ADDSPEC: got error %d\n", error
);
690 FREE(native_values
, M_TEMP
);
695 ndrv_delspec(struct ndrv_cb
*np
, struct ndrv_descr
*nd
)
696 { struct dlil_demux_desc
*mp
;
702 ndrv_find_tag(unsigned int tag
)
703 { struct ndrv_tag_map
*tmp
;
707 for (i
=0; i
++ < tag_map_count
; tmp
++)
708 if (tmp
->tm_tag
== tag
)
714 ndrv_add_tag(struct ndrv_cb
*np
, unsigned int tag
,
715 struct dlil_demux_desc
*mp
)
716 { struct ndrv_tag_map
*tmp
;
720 for (i
=0; i
++ < tag_map_count
; tmp
++)
721 if (tmp
->tm_tag
== 0)
725 log(LOG_WARNING
, "NDRV ADDING TAG %d\n", tag
);
730 /* Oops - ran out of space. Realloc */
731 i
= tag_map_count
+ TAG_MAP_COUNT
;
732 MALLOC(tmp
, struct ndrv_tag_map
*, i
* sizeof (struct ndrv_tag_map
),
736 /* Clear tail of new table, except for the slot we are creating ... */
737 bzero((caddr_t
)&tmp
[tag_map_count
+1],
738 (TAG_MAP_COUNT
-1) * sizeof (struct ndrv_tag_map
));
739 /* ...and then copy in the original piece */
741 bcopy(ndrv_tags
, tmp
,
742 tag_map_count
* sizeof (struct ndrv_tag_map
));
743 /* ...and then install the new tag... */
744 tmp
[tag_map_count
].tm_tag
= tag
;
745 tmp
[tag_map_count
].tm_np
= np
;
748 FREE(ndrv_tags
, M_PCB
);
751 log(LOG_WARNING
, "NDRV ADDING TAG %d (new chunk)\n", tag
);
757 * Attach the proto spec list, and record the tags.
760 ndrv_add_descr(struct ndrv_cb
*np
, struct dlil_proto_reg_str
*proto_spec
)
761 { unsigned long dl_tag
;
763 struct dlil_demux_desc
*mp
;
765 /* Attach to our device to get requested packets */
766 TAILQ_INIT(&proto_spec
->demux_desc_head
);
767 error
= dlil_attach_protocol(proto_spec
, &dl_tag
);
770 error
= ndrv_add_tag(np
, dl_tag
, mp
);
776 ndrv_dump_descr(struct ndrv_cb
*np
)
777 { struct dlil_demux_desc
*dm1
, *dm2
;
778 struct ndrv_tag_map
*tmp
;
781 if (dm1
= TAILQ_FIRST(&np
->nd_dlist
))
782 { for (i
= 0, tmp
= &ndrv_tags
[0]; i
++ < tag_map_count
; tmp
++)
783 if (tmp
->tm_np
== np
)
784 { error
= dlil_detach_protocol(tmp
->tm_tag
);
786 { dm2
= TAILQ_NEXT(dm1
, next
);
791 "Detached tag %d (error %d)\n",
802 static int ndrv_dominited
= 0;
804 if (ndrv_dominited
== 0) {
805 net_add_proto(&ndrvsw
[0], &ndrvdomain
);
811 struct pr_usrreqs ndrv_usrreqs
= {
812 ndrv_abort
, pru_accept_notsupp
, ndrv_attach
, ndrv_bind
,
813 ndrv_connect
, pru_connect2_notsupp
, ndrv_control
, ndrv_detach
,
814 ndrv_disconnect
, pru_listen_notsupp
, ndrv_peeraddr
, pru_rcvd_notsupp
,
815 pru_rcvoob_notsupp
, ndrv_send
, ndrv_sense
, ndrv_shutdown
,
816 ndrv_sockaddr
, sosend
, soreceive
, sopoll
819 struct protosw ndrvsw
[] =
820 { { SOCK_RAW
, &ndrvdomain
, 0, PR_ATOMIC
|PR_ADDR
,
821 0, ndrv_output
, ndrv_ctlinput
, ndrv_ctloutput
,
823 ndrv_drain
, ndrv_sysctl
, &ndrv_usrreqs
827 struct domain ndrvdomain
=
828 { AF_NDRV
, "NetDriver", ndrv_dominit
, NULL
, NULL
,
830 NULL
, NULL
, 0, 0, 0, 0