]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_blue.c
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 * @(#)if_blue.c 1.1 (MacOSX) 6/10/43
25 * Justin Walker, 9970520
26 * First wave - splitter and notification support for the Blue Box
27 * 980130 - Second wave - Performance improvements, reorg and cleanup
30 #include <sys/kdebug.h>
33 #define DBG_SPLT_BFCHK DRVDBG_CODE(DBG_DRVSPLT, 0)
34 #define DBG_SPLT_APPND DRVDBG_CODE(DBG_DRVSPLT, 1)
35 #define DBG_SPLT_MBUF DRVDBG_CODE(DBG_DRVSPLT, 2)
36 #define DBG_SPLT_DUP DRVDBG_CODE(DBG_DRVSPLT, 3)
37 #define DBG_SPLT_PAD DRVDBG_CODE(DBG_DRVSPLT, 4)
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/ioctl.h>
51 #include <sys/errno.h>
52 #include <sys/syslog.h>
56 #include <kern/cpu_number.h>
59 #include <net/netisr.h>
60 #include <net/route.h>
61 #include <net/if_llc.h>
62 #include <net/if_dl.h>
63 #include <net/if_types.h>
68 #include <netinet/in.h>
69 #include <netinet/in_var.h>
71 #include <netinet/if_ether.h>
75 #include <netns/ns_if.h>
79 #include <netiso/argo_debug.h>
80 #include <netiso/iso.h>
81 #include <netiso/iso_var.h>
82 #include <netiso/iso_snpac.h>
86 #include <netccitt/dll.h>
87 #include <netccitt/llc_var.h>
90 #include <sys/systm.h>
91 #include <machine/spl.h>
92 #include <kern/thread.h>
93 #include <kern/queue.h>
95 /* Dummy IFs to differentiate source of looped packets */
96 struct ifnet rhap_if_s
;
97 struct ifnet
*rhap_if
= &rhap_if_s
;
98 struct ifnet_blue
*blue_if
;
99 struct sockaddr_dl ndrvsrc
= {sizeof (struct sockaddr_dl
), AF_NDRV
};
101 struct ifqueue blueq
;
103 extern int if_register(register struct BlueFilter
*f
106 register struct ifnet
*ifp
112 * 1st cut: the Y splitter
113 * A process turns on the splitter by opening the "raw" device
114 * (socket() for AF_NDRV) and issuing an SIOCSSPLITTER ioctl.
115 * Incoming packets are routed into MacOSX as well as to the requesting
117 * Outbound packets are sent, and are examined to see if they should go
118 * back up (loopback, sort of). Packets that are looped back include:
123 new_splitter(register struct socket
*so
)
124 { register struct ifnet_blue
*ifb
;
125 register struct ndrv_cb
*np
;
126 register struct ifnet
*ifp
;
127 struct BlueFilter filter
;
130 if ((ifb
= _MALLOC(sizeof (struct ifnet_blue
), M_PCB
, M_WAITOK
))
134 kprintf("Can't create new splitter\n");
138 bzero(ifb
, sizeof(struct ifnet_blue
));
139 np
= (struct ndrv_cb
*)so
->so_pcb
;
141 kprintf("NEW SPLT: %x, %x\n", so
, np
);
143 printf("SIG: %x, ifp: %x\n", np
->nd_signature
, np
->nd_if
);
146 return(EINVAL
); /* XXX */
147 if (np
->nd_signature
!= NDRV_SIGNATURE
)
148 return(EINVAL
); /* XXX */
149 if ((ifp
= np
->nd_if
) == NULL
)
150 return(EINVAL
); /* XXX */
151 if (ifp
->if_flags
& IFF_SPLITTER
)
153 if ((ifp
->if_flags
&IFF_UP
) == 0)
156 * Bump the receive sockbuf size - need a big buffer
157 * to offset the scheduling latencies of the system
158 * Try to get something if our grandiose design fails.
160 if (sbreserve(&so
->so_rcv
, 131072) == 0)
161 { if (sbreserve(&so
->so_rcv
, 65536) == 0 &&
162 sbreserve(&so
->so_rcv
, 32768) == 0 &&
163 sbreserve(&so
->so_rcv
, 16384) == 0)
166 ifp
->if_flags
|= IFF_SPLITTER
;
168 * Register each IP address associated with this ifnet
169 * This takes care of addresses registered prior to startup
171 * TODO: Appletalk sockaddrs
173 #define IFA2IN(ifa) \
175 ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr).s_addr
176 { struct ifaddr
*ifa
;
178 TAILQ_FOREACH(ifa
, &ifp
->if_addrhead
, ifa_link
)
179 { if (ifa
->ifa_addr
->sa_family
== AF_INET
)
180 { filter
.BF_flags
= (BF_ALLOC
|BF_IP
);
181 filter
.BF_address
= IFA2IN(ifa
);
183 kprintf("[1] IP registering [%x] %x\n",
185 (unsigned int)filter
.BF_address
);
187 retval
= if_register(&filter
);
190 kprintf("if_register(IP) returns %d\n",
197 blue_if
= (struct ifnet_blue
*)ifb
;
198 ifb
->blue_pid
= ((struct proc
*)current_proc())->p_pid
;
200 ifp
->if_Y
= (void *)ifb
;
205 * Determine if destined for BlueBox or not. Called from ether_output()
207 * Returns NULL if we ate the packet, otherwise, the mbuf to continue with.
210 splitter_input(register struct mbuf
*m
, register struct ifnet
*ifp
)
211 { register struct ifnet_blue
*ifb
;
213 register int s
, flags
;
218 register struct mbuf
*m0
= NULL
;
220 extern struct mbuf
*m_dup(struct mbuf
*, int);
221 extern int BlueFilter_check(struct mbuf
**, struct ifnet_blue
*);
222 extern void blue_notify(struct mbuf
*);
223 extern int blue_notify1(struct mbuf
*);
225 if ((ifb
= (struct ifnet_blue
*)ifp
->if_Y
) == NULL
)
226 { ifp
->if_flags
&= ~IFF_SPLITTER
;
232 if ((rv
= BlueFilter_check(&m1
, ifb
)) == -1)
233 return(m1
); /* Not for BB, MacOSX will want to see it. */
235 if (rv
== 0) /* It's for both - dup the packet */
236 { m0
= m_dup(m
, M_DONTWAIT
);
238 { blue_if
->no_bufs1
++;
239 return(m
); /* Give it to MacOSX */
242 { /* Oy, veh! The depths to which we stoop! */
243 /* We'll just assume M_PKTHDR is set */
244 if (m
->m_next
== 0 && (m
->m_flags
& M_EXT
)
245 && m
->m_pkthdr
.len
<= MHLEN
)
246 { m0
= m_dup(m
, M_DONTWAIT
);
256 blue_if
->pkts_looped_r2b
++;
259 schednetisr(NETISR_BLUE
);
261 if (IF_QFULL(&blueq
)) {
265 IF_ENQUEUE(&blueq
, m0
);
269 sorwakeup(blue_if
->ifb_so
);
272 /* If we eat the packet (rv==1) return NULL */
273 return(rv
== 0 ? m
: NULL
);
278 { register int do_notify
= 0;
280 register struct mbuf
*m
;
281 extern int blue_notify1(struct mbuf
*);
284 * Move the packets from the blue queue to the indicated socket
285 * If we haven't told anyone yet, send a signal.
289 IF_DEQUEUE(&blueq
, m
);
294 do_notify
= blue_notify1(m
);
297 sorwakeup(blue_if
->ifb_so
); /* Start by using SIGIO */
301 blue_notify1(register struct mbuf
*m
)
304 /* move packet from if queue to socket */
305 /* !!!Fix this to work generically!!! */
306 ndrvsrc
.sdl_type
= IFT_ETHER
;
307 ndrvsrc
.sdl_nlen
= 0;
308 ndrvsrc
.sdl_alen
= 6;
309 ndrvsrc
.sdl_slen
= 0;
310 bcopy(m
->m_data
+6, &ndrvsrc
.sdl_data
, 6);
312 if (sbappendaddr(&(blue_if
->ifb_so
->so_rcv
),
313 (struct sockaddr
*)&ndrvsrc
, m
,
314 (struct mbuf
*)0) == 0)
315 { register struct mbuf
*n
;
317 KERNEL_DEBUG(DBG_SPLT_APPND
| DBG_FUNC_NONE
,
318 blue_if
->ifb_so
->so_rcv
.sb_cc
,
319 blue_if
->ifb_so
->so_rcv
.sb_hiwat
,
320 blue_if
->ifb_so
->so_rcv
.sb_mbcnt
,
321 blue_if
->ifb_so
->so_rcv
.sb_mbmax
,
322 blue_if
->ifb_so
->so_rcv
.sb_lowat
);
323 if (m
->m_flags
& M_PKTHDR
)
324 KERNEL_DEBUG(DBG_SPLT_MBUF
, 0, m
->m_pkthdr
.len
,
326 for (n
= m
; n
; n
= n
->m_next
)
327 KERNEL_DEBUG(DBG_SPLT_MBUF
, 1,
328 (int)n
, (int)n
->m_next
, n
->m_len
,
331 blue_if
->full_sockbuf
++;
334 { register struct mbuf
*n
;
336 KERNEL_DEBUG(DBG_SPLT_APPND
| DBG_FUNC_NONE
,
337 blue_if
->ifb_so
->so_rcv
.sb_cc
,
338 blue_if
->ifb_so
->so_rcv
.sb_hiwat
,
339 blue_if
->ifb_so
->so_rcv
.sb_mbcnt
,
340 blue_if
->ifb_so
->so_rcv
.sb_mbmax
,
341 blue_if
->ifb_so
->so_rcv
.sb_lowat
);
342 if (m
->m_flags
& M_PKTHDR
)
343 KERNEL_DEBUG(DBG_SPLT_MBUF
, 2, m
->m_pkthdr
.len
,
345 for (n
= m
; n
; n
= n
->m_next
)
346 KERNEL_DEBUG(DBG_SPLT_MBUF
, 3,
347 (int)n
, (int)n
->m_next
, n
->m_len
,
356 * Check the incoming packet against the registered filters
357 * Rules (the rules are subtly different for input to the
358 * y-adapter customer and the "real" stacks):
361 * Not For BB: return -1
362 * Multicast/Broadcast => For Both
364 * if no registered filters, For Both
365 * Atalk filter registered
366 * filter matches => For BB else Not For BB
367 * IP filter registered
368 * filter matches => For BB else Not For BB
370 * WARNING: this is a big-endian routine.
371 * WARNING 2: m_pullup can give you a new mbuf!
374 BlueFilter_check(struct mbuf
**m0
, register struct ifnet_blue
*ifb
)
375 { register struct BlueFilter
*bf
;
376 register unsigned char *p
;
377 register unsigned short *s
;
378 register unsigned long *l
;
380 register struct mbuf
*m
;
381 extern struct mbuf
*m_pullup(struct mbuf
*, int);
382 #define FILTER_LEN 32
384 KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_START
, 0, 0, 0, 0, 0 );
387 if (FILTER_LEN
> m
->m_pkthdr
.len
)
388 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 0, 0, 0, 0, 0 );
392 while ((FILTER_LEN
> m
->m_len
) && m
->m_next
) {
393 total
= m
->m_len
+ (m
->m_next
)->m_len
;
394 if ((m
= m_pullup(m
, min(FILTER_LEN
, total
))) == 0)
395 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 1, flags
, total
, 0, 0);
399 *m0
= m
; /* Update, just in case */
401 p
= mtod(m
, unsigned char *); /* Point to destination media addr */
402 if (p
[0] & 0x01) /* Multicast/broadcast */
403 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 2, 0, 0, 0, 0 );
406 s
= (unsigned short *)p
;
407 bf
= &ifb
->filter
[BFS_ATALK
];
408 if (!bf
->BF_flags
&& !bf
[1].BF_flags
) /* Hack for Developer Release Blue Box */
409 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 3, 0, 0, 0, 0 );
413 kprintf("PKT: %x, %x, %x\n", s
[6], s
[7], s
[8]);
415 if (bf
->BF_flags
) /* Filtering Appletalk */
416 { l
= (unsigned long *)&s
[8];
418 kprintf("AT: %x, %x, %x, %x, %x, %x\n", s
[6], s
[7],
419 *l
, s
[10], s
[13], p
[30]);
421 if (s
[6] <= ETHERMTU
)
422 { if (s
[7] == 0xaaaa) /* Could be Atalk */
423 { /* Verify SNAP header */
424 if (*l
== 0x03080007 && s
[10] == 0x809b)
425 { if ((bf
->BF_flags
&BF_VALID
) == 0 ||
426 (s
[13] == bf
->BF_address
&&
427 p
[30] == bf
->BF_node
))
428 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 4,
429 s
[13], p
[30], 0, 0 );
432 } else if (*l
== 0x03000000 && s
[10] == 0x80f3)
433 /* AARP pkts aren't net-addressed */
434 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 5, 0, 0, 0, 0 );
438 KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 6, s
[13], p
[30], 0, 0 );
440 } else /* Not for us? */
441 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 7, s
[7], 0, 0, 0 );
446 bf
++; /* Look for IP next */
447 if (bf
->BF_flags
) /* Filtering IP */
449 l
= (unsigned long *)&s
[15];
451 kprintf("IP: %x, %x\n", s
[6], *l
);
454 { if (s
[6] == 0x800) /* Is IP */
455 { /* Verify IP address */
456 if ((bf
->BF_flags
&BF_VALID
) == 0 ||
457 *l
== bf
->BF_address
)
458 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 8, *l
, 0, 0, 0 );
460 } else /* Not for us */
461 { KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 9, *l
, 0, 0, 0 );
464 } else if (s
[6] == 0x806)
465 { /* ARP pkts aren't net-addressed */
466 KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 10, 0, 0, 0, 0 );
471 KERNEL_DEBUG(DBG_SPLT_BFCHK
| DBG_FUNC_END
, 11, s
[6], 0, 0, 0 );
476 splitter_ctl(register struct socket
*so
, register int cmd
,
477 register caddr_t data
, register struct ifnet
*ifp
)
478 { register struct ndrv_cb
*np
= sotondrvcb(so
);
479 register struct ifnet_blue
*ifb
;
480 register struct BlueFilter
*bf
= (struct BlueFilter
*)data
, *bf1
;
484 if ((ifb
= np
->nd_if
->if_Y
) == NULL
)
487 if (cmd
== SIOCSSPLTFILT
)
490 kprintf("Filter: %s, %x, %x, %x\n", bf
->ifr_name
, bf
->BF_flags
, bf
->BF_address
,
493 if (bf
->BF_flags
& BF_ATALK
)
494 bf1
= &ifb
->filter
[BFS_ATALK
];
495 else if (bf
->BF_flags
& BF_IP
)
496 bf1
= &ifb
->filter
[BFS_IP
];
499 if (bf
->BF_flags
&BF_ALLOC
)
500 { if ((bf1
->BF_flags
&(BF_ALLOC
|BF_VALID
)) ==
504 bf1
->BF_flags
|= BF_VALID
;
505 } else if (bf
->BF_flags
&BF_DEALLOC
)
506 { if (bf1
->BF_flags
&BF_ALLOC
)
511 /* Register AppleTalk Tags if not registered */
513 ether_attach_at(ifp
, &at_dl_tag
,
517 } else if (cmd
== SIOCZSPLTSTAT
)
520 ifb
->pkts_looped_r2b
= 0;
521 ifb
->pkts_looped_b2r
= 0;
524 ifb
->full_sockbuf
= 0;
525 } else if (cmd
== SIOCGSPLTSTAT
)
526 { register struct Ystats
*ys
= (struct Ystats
*)data
;
527 ys
->YS_blue_pid
= ifb
->blue_pid
;
528 ys
->YS_filter
[BFS_ATALK
] = ifb
->filter
[BFS_ATALK
];
529 ys
->YS_filter
[BFS_IP
] = ifb
->filter
[BFS_IP
];
530 ys
->YS_pkts_up
= ifb
->pkts_up
;
531 ys
->YS_pkts_out
= ifb
->pkts_out
;
532 ys
->YS_pkts_looped_b2r
= ifb
->pkts_looped_b2r
;
533 ys
->YS_pkts_looped_r2b
= ifb
->pkts_looped_r2b
;
534 ys
->YS_no_bufs1
= ifb
->no_bufs1
;
535 ys
->YS_no_bufs2
= ifb
->no_bufs2
;
536 ys
->YS_full_sockbuf
= ifb
->full_sockbuf
;
543 splitter_close(register struct ndrv_cb
*np
)
544 { extern struct ifnet_blue
*blue_if
;
545 extern void ndrv_flushq(struct ifqueue
*);
548 { /* If we're the guy holding the Y-adapter, clean it up */
549 if (blue_if
->blue_pid
==
550 ((struct proc
*)current_proc())->p_pid
)
552 { np
->nd_if
->if_flags
&= ~IFF_SPLITTER
;
557 /* Clean out the filter supply */
559 sizeof(struct BlueFilter
) * BFCount
);
561 blue_if
->filter
[0].BF_flags
= 0;
562 blue_if
->filter
[1].BF_flags
= 0;
565 { FREE((caddr_t
) np
->nd_laddr
, M_IFADDR
);
571 FREE((caddr_t
)np
, M_PCB
);
575 * Dup the mbuf chain passed in. The whole thing. No cute additional cruft.
576 * And really copy the thing. That way, we don't "precompute" checksums
577 * for unsuspecting consumers.
578 * Assumption: m->m_nextpkt == 0.
579 * Trick: for small packets, don't dup into a cluster. That way received
580 * packets don't take up too much room in the sockbuf (cf. sbspace()).
585 m_dup(register struct mbuf
*m
, int how
)
586 { register struct mbuf
*n
, **np
;
590 KERNEL_DEBUG(DBG_SPLT_DUP
| DBG_FUNC_START
, m
->m_flags
, m
->m_len
,
591 m
->m_pkthdr
.len
, 0, 0 );
594 if (m
->m_flags
& M_PKTHDR
)
598 * Quick check: if we have one mbuf and its data fits in an
599 * mbuf with packet header, just copy and go.
601 if (m
->m_next
== NULL
)
602 { /* Then just move the data into an mbuf and be done... */
604 { if (m
->m_pkthdr
.len
<= MHLEN
)
605 { if ((n
= m_gethdr(how
, m
->m_type
)) == NULL
)
607 bcopy(m
->m_data
, n
->m_data
, m
->m_pkthdr
.len
);
608 n
->m_pkthdr
.len
= m
->m_pkthdr
.len
;
610 KERNEL_DEBUG(DBG_SPLT_DUP
| DBG_FUNC_END
, 2,
611 m
->m_pkthdr
.len
, m
->m_flags
,
615 } else if (m
->m_len
<= MLEN
)
616 { if ((n
= m_get(how
, m
->m_type
)) == NULL
)
618 bcopy(m
->m_data
, n
->m_data
, m
->m_len
);
620 KERNEL_DEBUG(DBG_SPLT_DUP
| DBG_FUNC_END
, 3, m
->m_len
,
621 m
->m_flags
, n
->m_flags
, 0 );
628 kprintf("<%x: %x, %x, %x\n", m
, m
->m_flags
, m
->m_len
,
632 n
= m_gethdr(how
, m
->m_type
);
634 n
= m_get(how
, m
->m_type
);
637 if (m
->m_flags
& M_EXT
)
639 if ((n
->m_flags
& M_EXT
) == 0)
644 { /* Don't use M_COPY_PKTHDR: preserve m_data */
645 n
->m_pkthdr
= m
->m_pkthdr
;
646 n
->m_pkthdr
.aux
= (struct mbuf
*)NULL
; /*###LD080800 Avoid problems with IPsec */
648 n
->m_flags
|= (m
->m_flags
& M_COPYFLAGS
);
650 if ((n
->m_flags
& M_EXT
) == 0)
651 n
->m_data
= n
->m_pktdat
;
655 * Get the dup on the same bdry as the original
656 * Assume that the two mbufs have the same offset to data area
657 * (up to word bdries)
659 bcopy(mtod(m
, caddr_t
), mtod(n
, caddr_t
), (unsigned)n
->m_len
);
663 kprintf(">%x: %x, %x, %x\n", n
, n
->m_flags
, n
->m_len
,
670 KERNEL_DEBUG(DBG_SPLT_DUP
| DBG_FUNC_END
, 0, (int)top
, 0, 0, 0 );
675 KERNEL_DEBUG(DBG_SPLT_DUP
| DBG_FUNC_END
, 1, 0, 0, 0, 0 );