|
|
1.1 root 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: int error=0;
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: /* Check if a tag was already registered for AppleTalk */
514: error = dlil_find_dltag(ifp->if_family, ifp->if_unit,
515: PF_APPLETALK, &at_dl_tag);
516:
517: #if BLUE_DEBUG
518: kprintf("splitter_ctl: ifp=%s%u find_dltag returns=%d dl_tag=%d\n",
519: ifp->if_name, ifp->if_unit, error, at_dl_tag);
520: #endif
521:
522: if (error == EPROTONOSUPPORT) {
523: ether_attach_at(ifp, &at_dl_tag,
524: &at_dl_tag);
525: error = 0;
526: }
527:
528: } else if (cmd == SIOCZSPLTSTAT)
529: { ifb->pkts_up = 0;
530: ifb->pkts_out = 0;
531: ifb->pkts_looped_r2b = 0;
532: ifb->pkts_looped_b2r = 0;
533: ifb->no_bufs1 = 0;
534: ifb->no_bufs2 = 0;
535: ifb->full_sockbuf = 0;
536: } else if (cmd == SIOCGSPLTSTAT)
537: { register struct Ystats *ys = (struct Ystats *)data;
538: ys->YS_blue_pid = ifb->blue_pid;
539: ys->YS_filter[BFS_ATALK] = ifb->filter[BFS_ATALK];
540: ys->YS_filter[BFS_IP] = ifb->filter[BFS_IP];
541: ys->YS_pkts_up = ifb->pkts_up;
542: ys->YS_pkts_out = ifb->pkts_out;
543: ys->YS_pkts_looped_b2r = ifb->pkts_looped_b2r;
544: ys->YS_pkts_looped_r2b = ifb->pkts_looped_r2b;
545: ys->YS_no_bufs1 = ifb->no_bufs1;
546: ys->YS_no_bufs2 = ifb->no_bufs2;
547: ys->YS_full_sockbuf = ifb->full_sockbuf;
548: } else
549: return(EINVAL);
550: return(0);
551: }
552:
553: void
554: splitter_close(register struct ndrv_cb *np)
555: { extern struct ifnet_blue *blue_if;
556: extern void ndrv_flushq(struct ifqueue *);
557:
558: if (blue_if)
559: { /* If we're the guy holding the Y-adapter, clean it up */
560: if (blue_if->blue_pid ==
561: ((struct proc *)current_proc())->p_pid)
562: { if (np->nd_if)
563: { np->nd_if->if_flags &= ~IFF_SPLITTER;
564: np->nd_if->if_Y = 0;
565: }
566:
567: BFIx = 0;
568: /* Clean out the filter supply */
569: bzero(RhapFilter,
570: sizeof(struct BlueFilter) * BFCount);
571: blue_if->ifb_so = 0;
572: blue_if->filter[0].BF_flags = 0;
573: blue_if->filter[1].BF_flags = 0;
574: ndrv_flushq(&blueq);
575: if (np->nd_laddr)
576: { FREE((caddr_t) np->nd_laddr, M_IFADDR);
577: np->nd_laddr = 0;
578: }
579: }
580: }
581: remque((queue_t)np);
582: FREE((caddr_t)np, M_PCB);
583: }
584:
585: /*
586: * Dup the mbuf chain passed in. The whole thing. No cute additional cruft.
587: * And really copy the thing. That way, we don't "precompute" checksums
588: * for unsuspecting consumers.
589: * Assumption: m->m_nextpkt == 0.
590: * Trick: for small packets, don't dup into a cluster. That way received
591: * packets don't take up too much room in the sockbuf (cf. sbspace()).
592: */
593: int MDFail;
594:
595: struct mbuf *
596: m_dup(register struct mbuf *m, int how)
597: { register struct mbuf *n, **np;
598: struct mbuf *top;
599: int copyhdr = 0;
600:
601: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_START, m->m_flags, m->m_len,
602: m->m_pkthdr.len, 0, 0 );
603: np = ⊤
604: top = 0;
605: if (m->m_flags & M_PKTHDR)
606: copyhdr = 1;
607:
608: /*
609: * Quick check: if we have one mbuf and its data fits in an
610: * mbuf with packet header, just copy and go.
611: */
612: if (m->m_next == NULL)
613: { /* Then just move the data into an mbuf and be done... */
614: if (copyhdr)
615: { if (m->m_pkthdr.len <= MHLEN)
616: { if ((n = m_gethdr(how, m->m_type)) == NULL)
617: return(NULL);
618: bcopy(m->m_data, n->m_data, m->m_pkthdr.len);
619: n->m_pkthdr.len = m->m_pkthdr.len;
620: n->m_len = m->m_len;
621: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 2,
622: m->m_pkthdr.len, m->m_flags,
623: n->m_flags, 0 );
624: return(n);
625: }
626: } else if (m->m_len <= MLEN)
627: { if ((n = m_get(how, m->m_type)) == NULL)
628: return(NULL);
629: bcopy(m->m_data, n->m_data, m->m_len);
630: n->m_len = m->m_len;
631: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 3, m->m_len,
632: m->m_flags, n->m_flags, 0 );
633: return(n);
634: }
635: }
636: while (m)
637: {
638: #if BLUE_DEBUG
639: kprintf("<%x: %x, %x, %x\n", m, m->m_flags, m->m_len,
640: m->m_data);
641: #endif
642: if (copyhdr)
643: n = m_gethdr(how, m->m_type);
644: else
645: n = m_get(how, m->m_type);
646: if (n == 0)
647: goto nospace;
648: if (m->m_flags & M_EXT)
649: { MCLGET(n, how);
650: if ((n->m_flags & M_EXT) == 0)
651: goto nospace;
652: }
653: *np = n;
654: if (copyhdr)
655: { /* Don't use M_COPY_PKTHDR: preserve m_data */
656: n->m_pkthdr = m->m_pkthdr;
657: n->m_flags |= (m->m_flags & M_COPYFLAGS);
658: copyhdr = 0;
659: if ((n->m_flags & M_EXT) == 0)
660: n->m_data = n->m_pktdat;
661: }
662: n->m_len = m->m_len;
663: /*
664: * Get the dup on the same bdry as the original
665: * Assume that the two mbufs have the same offset to data area
666: * (up to word bdries)
667: */
668: bcopy(mtod(m, caddr_t), mtod(n, caddr_t), (unsigned)n->m_len);
669: m = m->m_next;
670: np = &n->m_next;
671: #if BLUE_DEBUG
672: kprintf(">%x: %x, %x, %x\n", n, n->m_flags, n->m_len,
673: n->m_data);
674: #endif
675: }
676:
677: if (top == 0)
678: MDFail++;
679: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 0, (int)top, 0, 0, 0 );
680: return (top);
681: nospace:
682: m_freem(top);
683: MDFail++;
684: KERNEL_DEBUG(DBG_SPLT_DUP | DBG_FUNC_END, 1, 0, 0, 0, 0 );
685: return (0);
686: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.