From b16cb0a948acd6a3b5f47aa494607a001944c194 Mon Sep 17 00:00:00 2001 From: sam Date: Mon, 30 Dec 2002 20:22:40 +0000 Subject: Correct mbuf packet header propagation. Previously, packet headers were sometimes propagated using M_COPY_PKTHDR which actually did something between a "move" and a "copy" operation. This is replaced by M_MOVE_PKTHDR (which copies the pkthdr contents and "removes" it from the source mbuf) and m_dup_pkthdr which copies the packet header contents including any m_tag chain. This corrects numerous problems whereby mbuf tags could be lost during packet manipulations. These changes also introduce arguments to m_tag_copy and m_tag_copy_chain to specify if the tag copy work should potentially block. This introduces an incompatibility with openbsd which we may want to revisit. Note that move/dup of packet headers does not handle target mbufs that have a cluster bound to them. We may want to support this; for now we watch for it with an assert. Finally, M_COPYFLAGS was updated to include M_FIRSTFRAG|M_LASTFRAG. Supported by: Vernier Networks Reviewed by: Robert Watson --- sys/dev/awi/awi.c | 2 +- sys/dev/awi/awi_wep.c | 2 +- sys/dev/en/midway.c | 2 +- sys/dev/hifn/hifn7751.c | 7 +++-- sys/dev/ubsec/ubsec.c | 6 ++-- sys/kern/uipc_mbuf.c | 68 +++++++++++++++++++++++++++++++++++---------- sys/kern/uipc_mbuf2.c | 14 ++++++---- sys/net/if_loop.c | 20 ++++++------- sys/netatm/port.h | 3 +- sys/netinet/ip_input.c | 11 +++++++- sys/netinet6/esp_input.c | 3 +- sys/netinet6/icmp6.c | 17 +++++++++--- sys/netinet6/ip6_input.c | 2 +- sys/netinet6/ip6_output.c | 2 +- sys/netinet6/ipsec.c | 16 ++++------- sys/netipsec/ipsec_mbuf.c | 2 +- sys/netipsec/ipsec_output.c | 2 +- sys/sys/mbuf.h | 14 ++++++---- 18 files changed, 126 insertions(+), 67 deletions(-) diff --git a/sys/dev/awi/awi.c b/sys/dev/awi/awi.c index 3718198..e77fae6 100644 --- a/sys/dev/awi/awi.c +++ b/sys/dev/awi/awi.c @@ -1326,7 +1326,7 @@ awi_fix_rxhdr(sc, m0) m_freem(m0); return NULL; } - M_COPY_PKTHDR(n, m0); + M_MOVE_PKTHDR(n, m0); n->m_len = MHLEN; } else { MGET(n, M_DONTWAIT, MT_DATA); diff --git a/sys/dev/awi/awi_wep.c b/sys/dev/awi/awi_wep.c index b24bd9f..ecaf548 100644 --- a/sys/dev/awi/awi_wep.c +++ b/sys/dev/awi/awi_wep.c @@ -323,7 +323,7 @@ awi_wep_encrypt(sc, m0, txflag) n0 = n; if (n == NULL) goto fail; - M_COPY_PKTHDR(n, m); + M_MOVE_PKTHDR(n, m); len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; if (txflag) { n->m_pkthdr.len += len; diff --git a/sys/dev/en/midway.c b/sys/dev/en/midway.c index 915fd14..ffcc6c9 100644 --- a/sys/dev/en/midway.c +++ b/sys/dev/en/midway.c @@ -1843,7 +1843,7 @@ STATIC int en_makeexclusive(sc, mm, prev) return(0); } if (m->m_flags & M_PKTHDR) - M_COPY_PKTHDR(new, m); + M_MOVE_PKTHDR(new, m); MCLGET(new, M_DONTWAIT); if ((new->m_flags & M_EXT) == 0) { m_free(new); diff --git a/sys/dev/hifn/hifn7751.c b/sys/dev/hifn/hifn7751.c index ea87bd6..accb531 100644 --- a/sys/dev/hifn/hifn7751.c +++ b/sys/dev/hifn/hifn7751.c @@ -1668,6 +1668,10 @@ hifn_crypto( if (cmd->src_m->m_flags & M_PKTHDR) { len = MHLEN; MGETHDR(m0, M_DONTWAIT, MT_DATA); + if (m0 && !m_dup_pkthdr(m0, cmd->src_m, M_DONTWAIT)) { + m_free(m0); + m0 = NULL; + } } else { len = MLEN; MGET(m0, M_DONTWAIT, MT_DATA); @@ -1677,9 +1681,6 @@ hifn_crypto( err = dma->cmdu ? ERESTART : ENOMEM; goto err_srcmap; } - if (len == MHLEN) { - M_COPY_PKTHDR(m0, cmd->src_m); - } if (totlen >= MINCLSIZE) { MCLGET(m0, M_DONTWAIT); if ((m0->m_flags & M_EXT) == 0) { diff --git a/sys/dev/ubsec/ubsec.c b/sys/dev/ubsec/ubsec.c index 37cb37e..b62a425 100644 --- a/sys/dev/ubsec/ubsec.c +++ b/sys/dev/ubsec/ubsec.c @@ -1269,6 +1269,10 @@ ubsec_process(void *arg, struct cryptop *crp, int hint) if (q->q_src_m->m_flags & M_PKTHDR) { len = MHLEN; MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m && !m_dup_pkthdr(m, q->q_src_m, M_DONTWAIT)) { + m_free(m); + m = NULL; + } } else { len = MLEN; MGET(m, M_DONTWAIT, MT_DATA); @@ -1278,8 +1282,6 @@ ubsec_process(void *arg, struct cryptop *crp, int hint) err = sc->sc_nqueue ? ERESTART : ENOMEM; goto errout; } - if (len == MHLEN) - M_COPY_PKTHDR(m, q->q_src_m); if (totlen >= MINCLSIZE) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 6aedd11..bc6aa71 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -66,30 +66,70 @@ SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RW, &max_datalen, 0, ""); /* - * Copy mbuf pkthdr from "from" to "to". + * "Move" mbuf pkthdr from "from" to "to". * "from" must have M_PKTHDR set, and "to" must be empty. - * aux pointer will be moved to "to". */ void -m_copy_pkthdr(struct mbuf *to, struct mbuf *from) +m_move_pkthdr(struct mbuf *to, struct mbuf *from) { #if 0 + /* see below for why these are not enabled */ KASSERT(to->m_flags & M_PKTHDR, - ("m_copy_pkthdr() called on non-header")); + ("m_move_pkthdr: called on non-header")); + KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags), + ("m_move_pkthdr: to has tags")); #endif + KASSERT((to->m_flags & M_EXT) == 0, ("m_move_pkthdr: to has cluster")); #ifdef MAC if (to->m_flags & M_PKTHDR) mac_destroy_mbuf(to); #endif + to->m_flags = from->m_flags & M_COPYFLAGS; to->m_data = to->m_pktdat; + to->m_pkthdr = from->m_pkthdr; /* especially tags */ +#ifdef MAC + mac_init_mbuf(to, 1); /* XXXMAC no way to fail */ + mac_create_mbuf_from_mbuf(from, to); +#endif + SLIST_INIT(&from->m_pkthdr.tags); /* purge tags from src */ + from->m_flags &= ~M_PKTHDR; +} + +/* + * Duplicate "from"'s mbuf pkthdr in "to". + * "from" must have M_PKTHDR set, and "to" must be empty. + * In particular, this does a deep copy of the packet tags. + */ +int +m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int how) +{ + +#if 0 + /* + * The mbuf allocator only initializes the pkthdr + * when the mbuf is allocated with MGETHDR. Many users + * (e.g. m_copy*, m_prepend) use MGET and then + * smash the pkthdr as needed causing these + * assertions to trip. For now just disable them. + */ + KASSERT(to->m_flags & M_PKTHDR, ("m_dup_pkthdr: called on non-header")); + KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags), ("m_dup_pkthdr: to has tags")); +#endif + KASSERT((to->m_flags & M_EXT) == 0, ("m_dup_pkthdr: to has cluster")); +#ifdef MAC + if (to->m_flags & M_PKTHDR) + mac_destroy_mbuf(to); +#endif to->m_flags = from->m_flags & M_COPYFLAGS; + to->m_data = to->m_pktdat; to->m_pkthdr = from->m_pkthdr; #ifdef MAC mac_init_mbuf(to, 1); /* XXXMAC no way to fail */ mac_create_mbuf_from_mbuf(from, to); #endif - SLIST_INIT(&from->m_pkthdr.tags); + SLIST_INIT(&to->m_pkthdr.tags); + return (m_tag_copy_chain(to, from, how)); } /* @@ -108,11 +148,10 @@ m_prepend(struct mbuf *m, int len, int how) return (NULL); } if (m->m_flags & M_PKTHDR) { - M_COPY_PKTHDR(mn, m); + M_MOVE_PKTHDR(mn, m); #ifdef MAC mac_destroy_mbuf(m); #endif - m->m_flags &= ~M_PKTHDR; } mn->m_next = m; m = mn; @@ -161,7 +200,8 @@ m_copym(struct mbuf *m, int off0, int len, int wait) if (n == NULL) goto nospace; if (copyhdr) { - M_COPY_PKTHDR(n, m); + if (!m_dup_pkthdr(n, m, wait)) + goto nospace; if (len == M_COPYALL) n->m_pkthdr.len -= off0; else @@ -212,7 +252,8 @@ m_copypacket(struct mbuf *m, int how) if (n == NULL) goto nospace; - M_COPY_PKTHDR(n, m); + if (!m_dup_pkthdr(n, m, how)) + goto nospace; n->m_len = m->m_len; if (m->m_flags & M_EXT) { n->m_data = m->m_data; @@ -309,7 +350,8 @@ m_dup(struct mbuf *m, int how) if (n == NULL) goto nospace; if (top == NULL) { /* first one, must be PKTHDR */ - M_COPY_PKTHDR(n, m); + if (!m_dup_pkthdr(n, m, how)) + goto nospace; nsize = MHLEN; } else /* not the first one */ nsize = MLEN; @@ -484,10 +526,8 @@ m_pullup(struct mbuf *n, int len) if (m == NULL) goto bad; m->m_len = 0; - if (n->m_flags & M_PKTHDR) { - M_COPY_PKTHDR(m, n); - n->m_flags &= ~M_PKTHDR; - } + if (n->m_flags & M_PKTHDR) + M_MOVE_PKTHDR(m, n); } space = &m->m_dat[MLEN] - (m->m_data + m->m_len); do { diff --git a/sys/kern/uipc_mbuf2.c b/sys/kern/uipc_mbuf2.c index 63d86b7..9dbb7a3 100644 --- a/sys/kern/uipc_mbuf2.c +++ b/sys/kern/uipc_mbuf2.c @@ -298,8 +298,10 @@ m_dup1(struct mbuf *m, int off, int len, int wait) if (!n) return NULL; - if (copyhdr) - M_COPY_PKTHDR(n, m); + if (copyhdr && !m_dup_pkthdr(n, m, wait)) { + m_free(n); + return NULL; + } m_copydata(m, off, len, mtod(n, caddr_t)); return n; } @@ -392,12 +394,12 @@ m_tag_locate(struct mbuf *m, u_int32_t cookie, int type, struct m_tag *t) /* Copy a single tag. */ struct m_tag * -m_tag_copy(struct m_tag *t) +m_tag_copy(struct m_tag *t, int how) { struct m_tag *p; KASSERT(t, ("m_tag_copy: null tag")); - p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, M_NOWAIT); + p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how); if (p == NULL) return (NULL); bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */ @@ -411,7 +413,7 @@ m_tag_copy(struct m_tag *t) * destination mbuf. */ int -m_tag_copy_chain(struct mbuf *to, struct mbuf *from) +m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how) { struct m_tag *p, *t, *tprev = NULL; @@ -419,7 +421,7 @@ m_tag_copy_chain(struct mbuf *to, struct mbuf *from) ("m_tag_copy_chain: null argument, to %p from %p", to, from)); m_tag_delete_chain(to, NULL); SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) { - t = m_tag_copy(p); + t = m_tag_copy(p, how); if (t == NULL) { m_tag_delete_chain(to, NULL); return 0; diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 9c3affc..7c07931b 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -214,19 +214,11 @@ looutput(ifp, m, dst, rt) if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { struct mbuf *n; + /* XXX MT_HEADER should be m->m_type */ MGETHDR(n, M_DONTWAIT, MT_HEADER); if (!n) goto contiguousfail; - MCLGET(n, M_DONTWAIT); - if (! (n->m_flags & M_EXT)) { - m_freem(n); - goto contiguousfail; - } - - m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); - n->m_pkthdr = m->m_pkthdr; - n->m_len = m->m_pkthdr.len; - SLIST_INIT(&m->m_pkthdr.tags); + M_MOVE_PKTHDR(n, m); #ifdef MAC /* * XXXMAC: Once we put labels in tags and proper @@ -235,6 +227,14 @@ looutput(ifp, m, dst, rt) */ m->m_pkthdr.label.l_flags &= ~MAC_FLAG_INITIALIZED; #endif + MCLGET(n, M_DONTWAIT); + if (! (n->m_flags & M_EXT)) { + m_freem(n); + goto contiguousfail; + } + + m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); + n->m_len = m->m_pkthdr.len; m_freem(m); m = n; } diff --git a/sys/netatm/port.h b/sys/netatm/port.h index 83e0654..df599ad 100644 --- a/sys/netatm/port.h +++ b/sys/netatm/port.h @@ -178,8 +178,7 @@ typedef struct mbuf KBuffer; } #define KB_LINKHEAD(new, head) { \ if ((head) && KB_ISPKT(new) && KB_ISPKT(head)) {\ - M_COPY_PKTHDR((new), (head)); \ - (head)->m_flags &= ~M_PKTHDR; \ + M_MOVE_PKTHDR((new), (head)); \ } \ (new)->m_next = (head); \ } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 90f54e0..51332a5 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1763,8 +1763,17 @@ ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop) * data in a cluster may change before we reach icmp_error(). */ MGET(mcopy, M_DONTWAIT, m->m_type); + if (mcopy != NULL && !m_dup_pkthdr(mcopy, m, M_DONTWAIT)) { + /* + * It's probably ok if the pkthdr dup fails (because + * the deep copy of the tag chain failed), but for now + * be conservative and just discard the copy since + * code below may some day want the tags. + */ + m_free(mcopy); + mcopy = NULL; + } if (mcopy != NULL) { - M_COPY_PKTHDR(mcopy, m); mcopy->m_len = imin((ip->ip_hl << 2) + 8, (int)ip->ip_len); m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); diff --git a/sys/netinet6/esp_input.c b/sys/netinet6/esp_input.c index b038f6c..ad40e64 100644 --- a/sys/netinet6/esp_input.c +++ b/sys/netinet6/esp_input.c @@ -813,7 +813,7 @@ noreplaycheck: MGETHDR(n, M_DONTWAIT, MT_HEADER); maxlen = MHLEN; if (n) - M_COPY_PKTHDR(n, m); + M_MOVE_PKTHDR(n, m); if (n && m->m_pkthdr.len > maxlen) { MCLGET(n, M_DONTWAIT); maxlen = MCLBYTES; @@ -839,7 +839,6 @@ noreplaycheck: n->m_pkthdr.len = m->m_pkthdr.len; n->m_next = m; m_adj(m, maxlen); - m->m_flags &= ~M_PKTHDR; } m = n; } diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 9e3015d..a0bc165 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -574,7 +574,7 @@ icmp6_input(mp, offp, proto) m_freem(n0); break; } - M_COPY_PKTHDR(n, n0); + M_MOVE_PKTHDR(n, n0); /* * Copy IPv6 and ICMPv6 only. */ @@ -592,7 +592,6 @@ icmp6_input(mp, offp, proto) m_adj(n0, off + sizeof(struct icmp6_hdr)); n->m_pkthdr.len += n0->m_pkthdr.len; n->m_next = n0; - n0->m_flags &= ~M_PKTHDR; } else { nip6 = mtod(n, struct ip6_hdr *); nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off); @@ -690,6 +689,17 @@ icmp6_input(mp, offp, proto) n = NULL; } } + if (!m_dup_pkthdr(n, m, M_DONTWAIT)) { + /* + * Previous code did a blind M_COPY_PKTHDR + * and said "just for rcvif". If true, then + * we could tolerate the dup failing (due to + * the deep copy of the tag chain). For now + * be conservative and just fail. + */ + m_free(n); + n = NULL; + } if (n == NULL) { /* Give up remote */ break; @@ -710,7 +720,6 @@ icmp6_input(mp, offp, proto) bzero(p, 4); bcopy(hostname, p + 4, maxhlen); /* meaningless TTL */ noff = sizeof(struct ip6_hdr); - M_COPY_PKTHDR(n, m); /* just for rcvif */ n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4 + maxhlen; nicmp6->icmp6_type = ICMP6_WRUREPLY; @@ -1387,7 +1396,7 @@ ni6_input(m, off) m_freem(m); return(NULL); } - M_COPY_PKTHDR(n, m); /* just for recvif */ + M_MOVE_PKTHDR(n, m); /* just for recvif */ if (replylen > MHLEN) { if (replylen > MCLBYTES) { /* diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index e76727f..15a44bb 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -319,7 +319,7 @@ ip6_input(m) MGETHDR(n, M_DONTWAIT, MT_HEADER); if (n) - M_COPY_PKTHDR(n, m); + M_MOVE_PKTHDR(n, m); if (n && m->m_pkthdr.len > MHLEN) { MCLGET(n, M_DONTWAIT); if ((n->m_flags & M_EXT) == 0) { diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 94be84a..75ed4dc 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -2575,7 +2575,7 @@ ip6_splithdr(m, exthdrs) m_freem(m); return ENOBUFS; } - M_COPY_PKTHDR(mh, m); + M_MOVE_PKTHDR(mh, m); MH_ALIGN(mh, sizeof(*ip6)); m->m_flags &= ~M_PKTHDR; m->m_len -= sizeof(*ip6); diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c index b91470e..c25b1bf 100644 --- a/sys/netinet6/ipsec.c +++ b/sys/netinet6/ipsec.c @@ -3124,7 +3124,7 @@ ipsec4_splithdr(m) m_freem(m); return NULL; } - M_COPY_PKTHDR(mh, m); + M_MOVE_PKTHDR(mh, m); MH_ALIGN(mh, hlen); m->m_flags &= ~M_PKTHDR; m->m_len -= hlen; @@ -3161,7 +3161,7 @@ ipsec6_splithdr(m) m_freem(m); return NULL; } - M_COPY_PKTHDR(mh, m); + M_MOVE_PKTHDR(mh, m); MH_ALIGN(mh, hlen); m->m_flags &= ~M_PKTHDR; m->m_len -= hlen; @@ -3371,16 +3371,10 @@ ipsec_copypkt(m) MGETHDR(mnew, M_DONTWAIT, MT_HEADER); if (mnew == NULL) goto fail; - mnew->m_pkthdr = n->m_pkthdr; -#if 0 - if (n->m_pkthdr.aux) { - mnew->m_pkthdr.aux = - m_copym(n->m_pkthdr.aux, - 0, M_COPYALL, M_DONTWAIT); + if (!m_dup_pkthdr(mnew, n, M_DONTWAIT)) { + m_free(mnew); + goto fail; } -#endif - M_COPY_PKTHDR(mnew, n); - mnew->m_flags = n->m_flags & M_COPYFLAGS; } else { MGET(mnew, M_DONTWAIT, MT_DATA); diff --git a/sys/netipsec/ipsec_mbuf.c b/sys/netipsec/ipsec_mbuf.c index 4cf1c7c..b2969ae 100644 --- a/sys/netipsec/ipsec_mbuf.c +++ b/sys/netipsec/ipsec_mbuf.c @@ -101,7 +101,7 @@ m_clone(struct mbuf *m0) m_freem(m0); return (NULL); } - M_COPY_PKTHDR(n, m); + M_MOVE_PKTHDR(n, m); MCLGET(n, M_DONTWAIT); if ((n->m_flags & M_EXT) == 0) { m_free(n); diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c index 836e17b..3748747 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -474,7 +474,7 @@ ipsec6_splithdr(struct mbuf *m) m_freem(m); return NULL; } - M_COPY_PKTHDR(mh, m); + M_MOVE_PKTHDR(mh, m); MH_ALIGN(mh, hlen); m->m_len -= hlen; m->m_data += hlen; diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 69821f7..adc4832 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -177,8 +177,9 @@ struct mbuf { /* * Flags copied when copying m_pkthdr. */ -#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_PROTO1|M_PROTO1|M_PROTO2|M_PROTO3 | \ - M_PROTO4|M_PROTO5|M_BCAST|M_MCAST|M_FRAG|M_RDONLY) +#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_RDONLY|M_PROTO1|M_PROTO1|M_PROTO2|\ + M_PROTO3|M_PROTO4|M_PROTO5|M_BCAST|M_MCAST|\ + M_FRAG|M_FIRSTFRAG|M_LASTFRAG) /* * Flags indicating hw checksum support and sw checksum requirements. @@ -294,7 +295,8 @@ struct mbstat { * mbuf, cluster, and external object allocation macros * (for compatibility purposes). */ -#define M_COPY_PKTHDR(to, from) m_copy_pkthdr((to), (from)) +/* NB: M_COPY_PKTHDR is deprecated, use M_MOVE_PKTHDR or m_dup_pktdr */ +#define M_MOVE_PKTHDR(to, from) m_move_pkthdr((to), (from)) #define m_getclr(how, type) m_get_clrd((how), (type)) #define MGET(m, how, type) ((m) = m_get((how), (type))) #define MGETHDR(m, how, type) ((m) = m_gethdr((how), (type))) @@ -428,6 +430,7 @@ void m_copy_pkthdr(struct mbuf *, struct mbuf *); struct mbuf *m_devget(char *, int, int, struct ifnet *, void (*)(char *, caddr_t, u_int)); struct mbuf *m_dup(struct mbuf *, int); +int m_dup_pkthdr(struct mbuf *, struct mbuf *, int); u_int m_fixhdr(struct mbuf *); struct mbuf *m_free(struct mbuf *); void m_freem(struct mbuf *); @@ -438,6 +441,7 @@ struct mbuf *m_gethdr(int, short); struct mbuf *m_gethdr_clrd(int, short); struct mbuf *m_getm(struct mbuf *, int, int, short); u_int m_length(struct mbuf *, struct mbuf **); +void m_move_pkthdr(struct mbuf *, struct mbuf *); struct mbuf *m_prepend(struct mbuf *, int, int); void m_print(const struct mbuf *); struct mbuf *m_pulldown(struct mbuf *, int, int, int *); @@ -528,8 +532,8 @@ void m_tag_unlink(struct mbuf *, struct m_tag *); void m_tag_delete(struct mbuf *, struct m_tag *); void m_tag_delete_chain(struct mbuf *, struct m_tag *); struct m_tag *m_tag_locate(struct mbuf *, u_int32_t, int, struct m_tag *); -struct m_tag *m_tag_copy(struct m_tag *); -int m_tag_copy_chain(struct mbuf *, struct mbuf *); +struct m_tag *m_tag_copy(struct m_tag *, int); +int m_tag_copy_chain(struct mbuf *, struct mbuf *, int); void m_tag_init(struct mbuf *); struct m_tag *m_tag_first(struct mbuf *); struct m_tag *m_tag_next(struct mbuf *, struct m_tag *); -- cgit v1.1