]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
11 | * | |
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 | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */ | |
23 | /* | |
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 | |
28 | */ | |
29 | ||
30 | #include <sys/kdebug.h> | |
31 | #if KDEBUG | |
32 | ||
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) | |
38 | ||
39 | #endif | |
40 | ||
41 | ||
42 | #include <sys/param.h> | |
43 | #include <sys/systm.h> | |
44 | #include <sys/kernel.h> | |
45 | #include <sys/malloc.h> | |
46 | #include <sys/mbuf.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> | |
53 | #include <sys/proc.h> | |
54 | #include <sys/vm.h> | |
55 | ||
56 | #include <kern/cpu_number.h> | |
57 | ||
58 | #include <net/if.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> | |
64 | #include "if_blue.h" | |
65 | #include "ndrv.h" | |
66 | ||
67 | #if INET | |
68 | #include <netinet/in.h> | |
69 | #include <netinet/in_var.h> | |
70 | #endif | |
71 | #include <netinet/if_ether.h> | |
72 | ||
73 | #if NS | |
74 | #include <netns/ns.h> | |
75 | #include <netns/ns_if.h> | |
76 | #endif | |
77 | ||
78 | #if ISO | |
79 | #include <netiso/argo_debug.h> | |
80 | #include <netiso/iso.h> | |
81 | #include <netiso/iso_var.h> | |
82 | #include <netiso/iso_snpac.h> | |
83 | #endif | |
84 | ||
85 | #if LLC | |
86 | #include <netccitt/dll.h> | |
87 | #include <netccitt/llc_var.h> | |
88 | #endif | |
89 | ||
90 | #include <sys/systm.h> | |
91 | #include <machine/spl.h> | |
92 | #include <kern/thread.h> | |
93 | #include <kern/queue.h> | |
94 | ||
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}; | |
100 | ||
101 | struct ifqueue blueq; | |
102 | ||
103 | extern int if_register(register struct BlueFilter *f | |
104 | #ifdef BF_if | |
105 | , | |
106 | register struct ifnet *ifp | |
107 | #endif | |
108 | ); | |
109 | ||
110 | /* | |
111 | * Blue Box support: | |
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 | |
116 | * interface. | |
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: | |
119 | * broadcast | |
120 | * multicast | |
121 | */ | |
122 | int | |
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; | |
128 | int retval; | |
129 | ||
130 | if ((ifb = _MALLOC(sizeof (struct ifnet_blue), M_PCB, M_WAITOK)) | |
131 | == NULL) | |
132 | { | |
133 | #if BLUE_DEBUG | |
134 | kprintf("Can't create new splitter\n"); | |
135 | #endif | |
136 | return(ENOBUFS); | |
137 | } | |
138 | bzero(ifb, sizeof(struct ifnet_blue)); | |
139 | np = (struct ndrv_cb *)so->so_pcb; | |
140 | #if BLUE_DEBUG | |
141 | kprintf("NEW SPLT: %x, %x\n", so, np); | |
142 | if (np) | |
143 | printf("SIG: %x, ifp: %x\n", np->nd_signature, np->nd_if); | |
144 | #endif | |
145 | if (np == NULL) | |
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) | |
152 | return(EBUSY); | |
153 | if ((ifp->if_flags&IFF_UP) == 0) | |
154 | return(ENXIO); | |
155 | /* | |
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. | |
159 | */ | |
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) | |
164 | return(ENOBUFS); | |
165 | } | |
166 | ifp->if_flags |= IFF_SPLITTER; | |
167 | /* | |
168 | * Register each IP address associated with this ifnet | |
169 | * This takes care of addresses registered prior to startup | |
170 | * of the BlueBox. | |
171 | * TODO: Appletalk sockaddrs | |
172 | */ | |
173 | #define IFA2IN(ifa) \ | |
174 | ((struct in_addr) \ | |
175 | ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr).s_addr | |
176 | { struct ifaddr *ifa; | |
177 | ||
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); | |
182 | #if BLUE_DEBUG | |
183 | kprintf("[1] IP registering [%x] %x\n", | |
184 | filter.BF_flags, | |
185 | (unsigned int)filter.BF_address); | |
186 | #endif | |
187 | retval = if_register(&filter); | |
188 | #if BLUE_DEBUG | |
189 | if (retval) | |
190 | kprintf("if_register(IP) returns %d\n", | |
191 | retval); | |
192 | #endif | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
197 | blue_if = (struct ifnet_blue *)ifb; | |
198 | ifb->blue_pid = ((struct proc *)current_proc())->p_pid; | |
199 | ifb->ifb_so = so; | |
200 | ifp->if_Y = (void *)ifb; | |
201 | return(0); | |
202 | } | |
203 | ||
204 | /* | |
205 | * Determine if destined for BlueBox or not. Called from ether_output() | |
206 | * and ether_input(). | |
207 | * Returns NULL if we ate the packet, otherwise, the mbuf to continue with. | |
208 | */ | |
209 | struct mbuf * | |
210 | splitter_input(register struct mbuf *m, register struct ifnet *ifp) | |
211 | { register struct ifnet_blue *ifb; | |
212 | #if 0 | |
213 | register int s, flags; | |
214 | #else | |
215 | register int flags; | |
216 | #endif | |
217 | int rv; | |
218 | register struct mbuf *m0 = NULL; | |
219 | struct mbuf *m1; | |
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 *); | |
224 | ||
225 | if ((ifb = (struct ifnet_blue *)ifp->if_Y) == NULL) | |
226 | { ifp->if_flags &= ~IFF_SPLITTER; | |
227 | return(m); | |
228 | } | |
229 | flags = m->m_flags; | |
230 | m1 = m; | |
231 | /* Check filters */ | |
232 | if ((rv = BlueFilter_check(&m1, ifb)) == -1) | |
233 | return(m1); /* Not for BB, MacOSX will want to see it. */ | |
234 | m = m1; | |
235 | if (rv == 0) /* It's for both - dup the packet */ | |
236 | { m0 = m_dup(m, M_DONTWAIT); | |
237 | if (m0 == NULL) | |
238 | { blue_if->no_bufs1++; | |
239 | return(m); /* Give it to MacOSX */ | |
240 | } | |
241 | } else | |
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); | |
247 | if (m0) | |
248 | { m_freem(m); | |
249 | m = NULL; | |
250 | } else | |
251 | m0 = m; | |
252 | } else | |
253 | m0 = m; | |
254 | } | |
255 | if (flags & 0x10) | |
256 | blue_if->pkts_looped_r2b++; | |
257 | ||
258 | #if 0 | |
259 | schednetisr(NETISR_BLUE); | |
260 | s = splimp(); | |
261 | if (IF_QFULL(&blueq)) { | |
262 | IF_DROP(&blueq); | |
263 | m_freem(m0); | |
264 | } else | |
265 | IF_ENQUEUE(&blueq, m0); | |
266 | splx(s); | |
267 | #else | |
268 | blue_notify1(m0); | |
269 | sorwakeup(blue_if->ifb_so); | |
270 | blue_if->sig_sent++; | |
271 | #endif | |
272 | /* If we eat the packet (rv==1) return NULL */ | |
273 | return(rv == 0 ? m : NULL); | |
274 | } | |
275 | ||
276 | void | |
277 | blue_notify() | |
278 | { register int do_notify = 0; | |
279 | register int s; | |
280 | register struct mbuf *m; | |
281 | extern int blue_notify1(struct mbuf *); | |
282 | ||
283 | /* | |
284 | * Move the packets from the blue queue to the indicated socket | |
285 | * If we haven't told anyone yet, send a signal. | |
286 | */ | |
287 | for (;;) | |
288 | { s = splimp(); | |
289 | IF_DEQUEUE(&blueq, m); | |
290 | splx(s); | |
291 | if (m == 0) | |
292 | break; | |
293 | ||
294 | do_notify = blue_notify1(m); | |
295 | } | |
296 | if (do_notify) | |
297 | sorwakeup(blue_if->ifb_so); /* Start by using SIGIO */ | |
298 | } | |
299 | ||
300 | int | |
301 | blue_notify1(register struct mbuf *m) | |
302 | { register int rv; | |
303 | ||
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); | |
311 | ||
312 | if (sbappendaddr(&(blue_if->ifb_so->so_rcv), | |
313 | (struct sockaddr *)&ndrvsrc, m, | |
314 | (struct mbuf *)0) == 0) | |
315 | { register struct mbuf *n; | |
316 | ||
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, | |
325 | m->m_flags, 0, 0); | |
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, | |
329 | n->m_flags); | |
330 | m_freem(m); | |
331 | blue_if->full_sockbuf++; | |
332 | rv = 1; | |
333 | } else | |
334 | { register struct mbuf *n; | |
335 | ||
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, | |
344 | m->m_flags, 0, 0); | |
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, | |
348 | n->m_flags); | |
349 | blue_if->pkts_up++; | |
350 | rv = 0; | |
351 | } | |
352 | return(rv); | |
353 | } | |
354 | ||
355 | /* | |
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): | |
359 | * For BB: return 1 | |
360 | * For Both: return 0 | |
361 | * Not For BB: return -1 | |
362 | * Multicast/Broadcast => For Both | |
363 | * Hack: | |
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 | |
369 | * Not For BB | |
370 | * WARNING: this is a big-endian routine. | |
371 | * WARNING 2: m_pullup can give you a new mbuf! | |
372 | */ | |
373 | int | |
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; | |
379 | int total, flags; | |
380 | register struct mbuf *m; | |
381 | extern struct mbuf *m_pullup(struct mbuf *, int); | |
382 | #define FILTER_LEN 32 | |
383 | ||
384 | KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_START, 0, 0, 0, 0, 0 ); | |
385 | ||
386 | m = *m0; | |
387 | if (FILTER_LEN > m->m_pkthdr.len) | |
388 | { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 0, 0, 0, 0, 0 ); | |
389 | return(-1); | |
390 | } | |
391 | flags = m->m_flags; | |
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); | |
396 | return(-1); | |
397 | } | |
398 | } | |
399 | *m0 = m; /* Update, just in case */ | |
400 | ||
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 ); | |
404 | return(0); | |
405 | } | |
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 ); | |
410 | return(0); | |
411 | } | |
412 | #if BLUE_DEBUG | |
413 | kprintf("PKT: %x, %x, %x\n", s[6], s[7], s[8]); | |
414 | #endif | |
415 | if (bf->BF_flags) /* Filtering Appletalk */ | |
416 | { l = (unsigned long *)&s[8]; | |
417 | #if BLUE_DEBUG | |
418 | kprintf("AT: %x, %x, %x, %x, %x, %x\n", s[6], s[7], | |
419 | *l, s[10], s[13], p[30]); | |
420 | #endif | |
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 ); | |
430 | return(1); | |
431 | } | |
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 ); | |
435 | return(0); | |
436 | } | |
437 | /* Not for us */ | |
438 | KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 6, s[13], p[30], 0, 0 ); | |
439 | return(-1); | |
440 | } else /* Not for us? */ | |
441 | { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 7, s[7], 0, 0, 0 ); | |
442 | return(-1); | |
443 | } | |
444 | } /* Fall through */ | |
445 | } /* Fall through */ | |
446 | bf++; /* Look for IP next */ | |
447 | if (bf->BF_flags) /* Filtering IP */ | |
448 | { | |
449 | l = (unsigned long *)&s[15]; | |
450 | #if BLUE_DEBUG | |
451 | kprintf("IP: %x, %x\n", s[6], *l); | |
452 | #endif | |
453 | if (s[6] > ETHERMTU) | |
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 ); | |
459 | return(1); | |
460 | } else /* Not for us */ | |
461 | { KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 9, *l, 0, 0, 0 ); | |
462 | return(-1); | |
463 | } | |
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 ); | |
467 | return(0); | |
468 | } | |
469 | } | |
470 | } | |
471 | KERNEL_DEBUG(DBG_SPLT_BFCHK | DBG_FUNC_END, 11, s[6], 0, 0, 0 ); | |
472 | return(-1); | |
473 | } | |
474 | ||
475 | int | |
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; | |
481 | u_long at_dl_tag; | |
482 | ||
483 | ||
484 | if ((ifb = np->nd_if->if_Y) == NULL) | |
485 | return(ENXIO); | |
486 | ||
487 | if (cmd == SIOCSSPLTFILT) | |
488 | { | |
489 | #if BLUE_DEBUG | |
490 | kprintf("Filter: %s, %x, %x, %x\n", bf->ifr_name, bf->BF_flags, bf->BF_address, | |
491 | bf->BF_node); | |
492 | #endif | |
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]; | |
497 | else | |
498 | return(EINVAL); | |
499 | if (bf->BF_flags&BF_ALLOC) | |
500 | { if ((bf1->BF_flags&(BF_ALLOC|BF_VALID)) == | |
501 | (BF_ALLOC|BF_VALID)) | |
502 | return(EBUSY); | |
503 | *bf1 = *bf; | |
504 | bf1->BF_flags |= BF_VALID; | |
505 | } else if (bf->BF_flags&BF_DEALLOC) | |
506 | { if (bf1->BF_flags&BF_ALLOC) | |
507 | bf1->BF_flags = 0; | |
508 | else | |
509 | return(EINVAL); | |
510 | } | |
511 | /* Register AppleTalk Tags if not registered */ | |
512 | ||
513 | ether_attach_at(ifp, &at_dl_tag, | |
514 | &at_dl_tag); | |
515 | ||
516 | ||
517 | } else if (cmd == SIOCZSPLTSTAT) | |
518 | { ifb->pkts_up = 0; | |
519 | ifb->pkts_out = 0; | |
520 | ifb->pkts_looped_r2b = 0; | |
521 | ifb->pkts_looped_b2r = 0; | |
522 | ifb->no_bufs1 = 0; | |
523 | ifb->no_bufs2 = 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; | |
537 | } else | |
538 | return(EINVAL); | |
539 | return(0); | |
540 | } | |
541 | ||
542 | void | |
543 | splitter_close(register struct ndrv_cb *np) | |
544 | { extern struct ifnet_blue *blue_if; | |
545 | extern void ndrv_flushq(struct ifqueue *); | |
546 | ||
547 | if (blue_if) | |
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) | |
551 | { if (np->nd_if) | |
552 | { np->nd_if->if_flags &= ~IFF_SPLITTER; | |
553 | np->nd_if->if_Y = 0; | |
554 | } | |
555 | ||
556 | BFIx = 0; | |
557 | /* Clean out the filter supply */ | |
558 | bzero(RhapFilter, | |
559 | sizeof(struct BlueFilter) * BFCount); | |
560 | blue_if->ifb_so = 0; | |
561 | blue_if->filter[0].BF_flags = 0; | |
562 | blue_if->filter[1].BF_flags = 0; | |
563 | ndrv_flushq(&blueq); | |
564 | if (np->nd_laddr) | |
565 | { FREE((caddr_t) np->nd_laddr, M_IFADDR); | |
566 | np->nd_laddr = 0; | |
567 | } | |
568 | } | |
569 | } | |
570 | remque((queue_t)np); | |
571 | FREE((caddr_t)np, M_PCB); | |
572 | } | |
573 | ||
574 | /* | |
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()). | |
581 | */ | |
582 | int MDFail; | |
583 | ||
584 | struct mbuf * | |
585 | m_dup(register struct mbuf *m, int how) | |
586 | { register struct mbuf *n, **np; | |
587 | struct mbuf *top; | |
588 | int copyhdr = 0; | |
589 | ||
590 | KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_START, m->m_flags, m->m_len, | |
591 | m->m_pkthdr.len, 0, 0 ); | |
592 | np = ⊤ | |
593 | top = 0; | |
594 | if (m->m_flags & M_PKTHDR) | |
595 | copyhdr = 1; | |
596 | ||
597 | /* | |
598 | * Quick check: if we have one mbuf and its data fits in an | |
599 | * mbuf with packet header, just copy and go. | |
600 | */ | |
601 | if (m->m_next == NULL) | |
602 | { /* Then just move the data into an mbuf and be done... */ | |
603 | if (copyhdr) | |
604 | { if (m->m_pkthdr.len <= MHLEN) | |
605 | { if ((n = m_gethdr(how, m->m_type)) == NULL) | |
606 | return(NULL); | |
607 | bcopy(m->m_data, n->m_data, m->m_pkthdr.len); | |
608 | n->m_pkthdr.len = m->m_pkthdr.len; | |
609 | n->m_len = m->m_len; | |
610 | KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 2, | |
611 | m->m_pkthdr.len, m->m_flags, | |
612 | n->m_flags, 0 ); | |
613 | return(n); | |
614 | } | |
615 | } else if (m->m_len <= MLEN) | |
616 | { if ((n = m_get(how, m->m_type)) == NULL) | |
617 | return(NULL); | |
618 | bcopy(m->m_data, n->m_data, m->m_len); | |
619 | n->m_len = m->m_len; | |
620 | KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 3, m->m_len, | |
621 | m->m_flags, n->m_flags, 0 ); | |
622 | return(n); | |
623 | } | |
624 | } | |
625 | while (m) | |
626 | { | |
627 | #if BLUE_DEBUG | |
628 | kprintf("<%x: %x, %x, %x\n", m, m->m_flags, m->m_len, | |
629 | m->m_data); | |
630 | #endif | |
631 | if (copyhdr) | |
632 | n = m_gethdr(how, m->m_type); | |
633 | else | |
634 | n = m_get(how, m->m_type); | |
635 | if (n == 0) | |
636 | goto nospace; | |
637 | if (m->m_flags & M_EXT) | |
638 | { MCLGET(n, how); | |
639 | if ((n->m_flags & M_EXT) == 0) | |
640 | goto nospace; | |
641 | } | |
642 | *np = n; | |
643 | if (copyhdr) | |
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 */ | |
647 | ||
648 | n->m_flags |= (m->m_flags & M_COPYFLAGS); | |
649 | copyhdr = 0; | |
650 | if ((n->m_flags & M_EXT) == 0) | |
651 | n->m_data = n->m_pktdat; | |
652 | } | |
653 | n->m_len = m->m_len; | |
654 | /* | |
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) | |
658 | */ | |
659 | bcopy(mtod(m, caddr_t), mtod(n, caddr_t), (unsigned)n->m_len); | |
660 | m = m->m_next; | |
661 | np = &n->m_next; | |
662 | #if BLUE_DEBUG | |
663 | kprintf(">%x: %x, %x, %x\n", n, n->m_flags, n->m_len, | |
664 | n->m_data); | |
665 | #endif | |
666 | } | |
667 | ||
668 | if (top == 0) | |
669 | MDFail++; | |
670 | KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 0, (int)top, 0, 0, 0 ); | |
671 | return (top); | |
672 | nospace: | |
673 | m_freem(top); | |
674 | MDFail++; | |
675 | KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 1, 0, 0, 0, 0 ); | |
676 | return (0); | |
677 | } |