|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
26: /*
27: *
28: * @(#)if_blue.c 1.1 (Rhapsody) 6/10/97
29: * Justin Walker, 9970520
30: * First wave - splitter and notification support for the Blue Box
31: * 980130 - Second wave - Performance improvements, reorg and cleanup
32: */
33:
34: #include <kern/kdebug.h>
35: #if KDEBUG
36:
37: #define DBG_SPLT_BFCHK DRVDBG_CODE(DBG_DRVSPLT, 0)
38: #define DBG_SPLT_APPND DRVDBG_CODE(DBG_DRVSPLT, 1)
39: #define DBG_SPLT_MBUF DRVDBG_CODE(DBG_DRVSPLT, 2)
40: #define DBG_SPLT_DUP DRVDBG_CODE(DBG_DRVSPLT, 3)
41: #define DBG_SPLT_PAD DRVDBG_CODE(DBG_DRVSPLT, 4)
42:
43: #endif
44:
45:
46: #include <sys/param.h>
47: #include <sys/systm.h>
48: #include <sys/kernel.h>
49: #include <sys/malloc.h>
50: #include <sys/mbuf.h>
51: #include <sys/protosw.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>
57: #include <sys/proc.h>
58:
59: #include <machine/cpu.h>
60:
61: #include <net/if.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>
67: #include "if_blue.h"
68: #include "ndrv.h"
69:
70: #if INET
71: #include <netinet/in.h>
72: #include <netinet/in_var.h>
73: #endif
74: #include <netinet/if_ether.h>
75:
76: #if NS
77: #include <netns/ns.h>
78: #include <netns/ns_if.h>
79: #endif
80:
81: #if ISO
82: #include <netiso/argo_debug.h>
83: #include <netiso/iso.h>
84: #include <netiso/iso_var.h>
85: #include <netiso/iso_snpac.h>
86: #endif
87:
88: #if LLC
89: #include <netccitt/dll.h>
90: #include <netccitt/llc_var.h>
91: #endif
92:
93: #include <sys/systm.h>
94: #include <machine/spl.h>
95:
96: /* Dummy IFs to differentiate source of looped packets */
97: struct ifnet rhap_if_s;
98: struct ifnet *rhap_if = &rhap_if_s;
99: struct ifnet_blue *blue_if;
100: struct sockaddr_dl ndrvsrc = {sizeof (struct sockaddr_dl), AF_NDRV};
101:
102: struct ifqueue blueq;
103:
104: extern int if_register(register struct BlueFilter *f
105: #ifdef BF_if
106: ,
107: register struct ifnet *ifp
108: #endif
109: );
110:
111: /*
112: * Blue Box support:
113: * 1st cut: the Y splitter
114: * A process turns on the splitter by opening the "raw" device
115: * (socket() for AF_NDRV) and issuing an SIOCSSPLITTER ioctl.
116: * Incoming packets are routed into Rhapsody as well as to the requesting
117: * interface.
118: * Outbound packets are sent, and are examined to see if they should go
119: * back up (loopback, sort of). Packets that are looped back include:
120: * broadcast
121: * multicast
122: */
123: int
124: new_splitter(register struct socket *so)
125: { register struct ifnet_blue *ifb;
126: register struct ndrv_cb *np;
127: register struct ifnet *ifp;
128: struct BlueFilter filter;
129: int retval;
130:
131: if ((ifb = _MALLOC(sizeof (struct ifnet_blue), M_PCB, M_WAITOK))
132: == NULL)
133: {
134: #if 0
135: kprintf("Can't create new splitter\n");
136: #endif
137: return(ENOBUFS);
138: }
139: bzero(ifb, sizeof(struct ifnet_blue));
140: np = (struct ndrv_cb *)so->so_pcb;
141: #if 0
142: printf("NEW SPLT: %x, %x\n", so, np);
143: if (np)
144: printf("SIG: %x, ifp: %x\n", np->nd_signature, np->nd_if);
145: #endif
146: if (np == NULL)
147: return(EINVAL); /* XXX */
148: if (np->nd_signature != NDRV_SIGNATURE)
149: return(EINVAL); /* XXX */
150: if ((ifp = np->nd_if) == NULL)
151: return(EINVAL); /* XXX */
152: if (ifp->if_flags & IFF_SPLITTER)
153: return(EBUSY);
154: if ((ifp->if_flags&IFF_UP) == 0)
155: return(ENXIO);
156: /*
157: * Bump the receive sockbuf size - need a big buffer
158: * to offset the scheduling latencies of the system
159: * Try to get something if our grandiose design fails.
160: */
161: if (sbreserve(&so->so_rcv, 131072) == 0)
162: { if (sbreserve(&so->so_rcv, 65536) == 0 &&
163: sbreserve(&so->so_rcv, 32768) == 0 &&
164: sbreserve(&so->so_rcv, 16384) == 0)
165: return(ENOBUFS);
166: }
167: ifp->if_flags |= IFF_SPLITTER;
168: /*
169: * Register each IP address associated with this ifnet
170: * This takes care of addresses registered prior to startup
171: * of the BlueBox.
172: * TODO: Appletalk sockaddrs
173: */
174: #define IFA2IN(ifa) \
175: ((struct in_addr) \
176: ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr).s_addr
177: { struct ifaddr *ifa;
178: for (ifa = ifp->if_addrlist; (ifa = ifa->ifa_next);)
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 0
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 0
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 = current_thread()->task->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, Rhapsody 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 Rhapsody */
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 0
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 0
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 0
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:
482: if ((ifb = np->nd_if->if_Y) == NULL)
483: return(ENXIO);
484:
485: if (cmd == SIOCSSPLTFILT)
486: {
487: #if 0
488: kprintf("Filter: %s, %x, %x, %x\n", bf->ifr_name, bf->BF_flags, bf->BF_address,
489: bf->BF_node);
490: #endif
491: if (bf->BF_flags & BF_ATALK)
492: bf1 = &ifb->filter[BFS_ATALK];
493: else if (bf->BF_flags & BF_IP)
494: bf1 = &ifb->filter[BFS_IP];
495: else
496: return(EINVAL);
497: if (bf->BF_flags&BF_ALLOC)
498: { if ((bf1->BF_flags&(BF_ALLOC|BF_VALID)) ==
499: (BF_ALLOC|BF_VALID))
500: return(EBUSY);
501: *bf1 = *bf;
502: bf1->BF_flags |= BF_VALID;
503: } else if (bf->BF_flags&BF_DEALLOC)
504: { if (bf1->BF_flags&BF_ALLOC)
505: bf1->BF_flags = 0;
506: else
507: return(EINVAL);
508: }
509: } else if (cmd == SIOCZSPLTSTAT)
510: { ifb->pkts_up = 0;
511: ifb->pkts_out = 0;
512: ifb->pkts_looped_r2b = 0;
513: ifb->pkts_looped_b2r = 0;
514: ifb->no_bufs1 = 0;
515: ifb->no_bufs2 = 0;
516: ifb->full_sockbuf = 0;
517: } else if (cmd == SIOCGSPLTSTAT)
518: { register struct Ystats *ys = (struct Ystats *)data;
519: ys->YS_blue_pid = ifb->blue_pid;
520: ys->YS_filter[BFS_ATALK] = ifb->filter[BFS_ATALK];
521: ys->YS_filter[BFS_IP] = ifb->filter[BFS_IP];
522: ys->YS_pkts_up = ifb->pkts_up;
523: ys->YS_pkts_out = ifb->pkts_out;
524: ys->YS_pkts_looped_b2r = ifb->pkts_looped_b2r;
525: ys->YS_pkts_looped_r2b = ifb->pkts_looped_r2b;
526: ys->YS_no_bufs1 = ifb->no_bufs1;
527: ys->YS_no_bufs2 = ifb->no_bufs2;
528: ys->YS_full_sockbuf = ifb->full_sockbuf;
529: } else
530: return(EINVAL);
531: return(0);
532: }
533:
534: void
535: splitter_close(register struct ndrv_cb *np)
536: { extern struct ifnet_blue *blue_if;
537: extern void ndrv_flushq(struct ifqueue *);
538:
539: if (blue_if)
540: { /* If we're the guy holding the Y-adapter, clean it up */
541: if (blue_if->blue_pid == current_thread()->task->proc->p_pid)
542: { if (np->nd_if)
543: { np->nd_if->if_flags &= ~IFF_SPLITTER;
544: np->nd_if->if_Y = 0;
545: }
546:
547: BFIx = 0;
548: /* Clean out the filter supply */
549: bzero(RhapFilter,
550: sizeof(struct BlueFilter) * BFCount);
551: blue_if->ifb_so = 0;
552: blue_if->filter[0].BF_flags = 0;
553: blue_if->filter[1].BF_flags = 0;
554: ndrv_flushq(&blueq);
555: if (np->nd_laddr)
556: { m_freem(dtom(np->nd_laddr));
557: np->nd_laddr = 0;
558: }
559: }
560: }
561: remque((queue_t)np);
562: _FREE((caddr_t)np, M_PCB);
563: }
564:
565: /*
566: * Dup the mbuf chain passed in. The whole thing. No cute additional cruft.
567: * And really copy the thing. That way, we don't "precompute" checksums
568: * for unsuspecting consumers.
569: * Assumption: m->m_nextpkt == 0.
570: * Trick: for small packets, don't dup into a cluster. That way received
571: * packets don't take up too much room in the sockbuf (cf. sbspace()).
572: */
573: int MDFail;
574:
575: struct mbuf *
576: m_dup(register struct mbuf *m, int how)
577: { register struct mbuf *n, **np;
578: struct mbuf *top;
579: int copyhdr = 0;
580:
581: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_START, m->m_flags, m->m_len,
582: m->m_pkthdr.len, 0, 0 );
583: np = ⊤
584: top = 0;
585: if (m->m_flags & M_PKTHDR)
586: copyhdr = 1;
587:
588: /*
589: * Quick check: if we have one mbuf and its data fits in an
590: * mbuf with packet header, just copy and go.
591: */
592: if (m->m_next == NULL)
593: { /* Then just move the data into an mbuf and be done... */
594: if (copyhdr)
595: { if (m->m_pkthdr.len <= MHLEN)
596: { n = m_gethdr(how, m->m_type);
597: bcopy(m->m_data, n->m_data, m->m_pkthdr.len);
598: n->m_pkthdr.len = m->m_pkthdr.len;
599: n->m_len = m->m_len;
600: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 2,
601: m->m_pkthdr.len, m->m_flags,
602: n->m_flags, 0 );
603: return(n);
604: }
605: } else if (m->m_len <= MLEN)
606: { n = m_get(how, m->m_type);
607: bcopy(m->m_data, n->m_data, m->m_len);
608: n->m_len = m->m_len;
609: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 3, m->m_len,
610: m->m_flags, n->m_flags, 0 );
611: return(n);
612: }
613: }
614: while (m)
615: {
616: #if 0
617: kprintf("<%x: %x, %x, %x\n", m, m->m_flags, m->m_len,
618: m->m_data);
619: #endif
620: if (copyhdr)
621: n = m_gethdr(how, m->m_type);
622: else
623: n = m_get(how, m->m_type);
624: if (n == 0)
625: goto nospace;
626: if (m->m_flags & M_EXT)
627: { MCLGET(n, how);
628: if ((n->m_flags & M_EXT) == 0)
629: goto nospace;
630: }
631: *np = n;
632: if (copyhdr)
633: { /* Don't use M_COPY_PKTHDR: preserve m_data */
634: n->m_pkthdr = m->m_pkthdr;
635: n->m_flags |= (m->m_flags & M_COPYFLAGS);
636: copyhdr = 0;
637: if ((n->m_flags & M_EXT) == 0)
638: n->m_data = n->m_pktdat;
639: }
640: n->m_len = m->m_len;
641: /*
642: * Get the dup on the same bdry as the original
643: * Assume that the two mbufs have the same offset to data area
644: * (up to word bdries)
645: */
646: bcopy(mtod(m, caddr_t), mtod(n, caddr_t), (unsigned)n->m_len);
647: m = m->m_next;
648: np = &n->m_next;
649: #if 0
650: kprintf(">%x: %x, %x, %x\n", n, n->m_flags, n->m_len,
651: n->m_data);
652: #endif
653: }
654:
655: if (top == 0)
656: MDFail++;
657: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 0, (int)top, 0, 0, 0 );
658: return (top);
659: nospace:
660: m_freem(top);
661: MDFail++;
662: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 1, 0, 0, 0, 0 );
663: return (0);
664: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.