]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_blue.c
xnu-123.5.tar.gz
[apple/xnu.git] / bsd / net / if_blue.c
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 = &top;
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 }