diff --git a/sys/net/pfil.h b/sys/net/pfil.h --- a/sys/net/pfil.h +++ b/sys/net/pfil.h @@ -80,7 +80,7 @@ #define PFIL_IN 0x00010000 #define PFIL_OUT 0x00020000 -/* UNUSED 0x00040000 */ +#define PFIL_FWD 0x00040000 #define PFIL_DIR(f) ((f) & (PFIL_IN|PFIL_OUT)) #define PFIL_HEADPTR 0x00100000 #define PFIL_HOOKPTR 0x00200000 @@ -179,6 +179,8 @@ struct inpcb *inp); int pfil_mbuf_out(struct pfil_head *, struct mbuf **, struct ifnet *, struct inpcb *inp); +int pfil_mbuf_fwd(struct pfil_head *, struct mbuf **, struct ifnet *, + struct inpcb *); /* * Minimally exposed structure to avoid function call in case of absence diff --git a/sys/net/pfil.c b/sys/net/pfil.c --- a/sys/net/pfil.c +++ b/sys/net/pfil.c @@ -202,8 +202,11 @@ pfil_return_t rv; NET_EPOCH_ASSERT(); - KASSERT(flags == PFIL_IN || flags == PFIL_OUT, - ("%s: unsupported flags %d", __func__, flags)); + KASSERT((flags & ~(PFIL_IN|PFIL_OUT|PFIL_FWD)) == 0, + ("%s: unsupported flags %#x", __func__, flags)); + KASSERT((flags & ~PFIL_FWD) == PFIL_IN || + (flags & ~PFIL_FWD) == PFIL_OUT, + ("%s: conflicting directions %#x", __func__, flags)); rv = PFIL_PASS; CK_STAILQ_FOREACH(link, pch, link_chain) { @@ -231,6 +234,14 @@ return (pfil_mbuf_common(&head->head_out, m, ifp, PFIL_OUT, inp)); } +int +pfil_mbuf_fwd(struct pfil_head *head, struct mbuf **m, struct ifnet *ifp, + struct inpcb *inp) +{ + + return (pfil_mbuf_common(&head->head_out, m, ifp, PFIL_OUT | PFIL_FWD, inp)); +} + /* * pfil_head_register() registers a pfil_head with the packet filter hook * mechanism. diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2135,7 +2135,7 @@ void pf_poolmask(struct pf_addr *, struct pf_addr*, struct pf_addr *, struct pf_addr *, u_int8_t); void pf_addr_inc(struct pf_addr *, sa_family_t); -int pf_refragment6(struct ifnet *, struct mbuf **, struct m_tag *); +int pf_refragment6(struct ifnet *, struct mbuf **, struct m_tag *, bool); #endif /* INET6 */ u_int32_t pf_new_isn(struct pf_kstate *); diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -321,7 +321,7 @@ odst = ip6->ip6_dst; /* Run through list of hooks for forwarded packets. */ - if (pfil_mbuf_out(V_inet6_pfil_head, &m, nh->nh_ifp, + if (pfil_mbuf_fwd(V_inet6_pfil_head, &m, nh->nh_ifp, NULL) != PFIL_PASS) goto freecopy; ip6 = mtod(m, struct ip6_hdr *); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -7953,7 +7953,7 @@ /* If reassembled packet passed, create new fragments. */ if (action == PF_PASS && *m0 && dir == PF_OUT && (mtag = m_tag_find(m, PF_REASSEMBLED, NULL)) != NULL) - action = pf_refragment6(ifp, m0, mtag); + action = pf_refragment6(ifp, m0, mtag, pflags & PFIL_FWD); SDT_PROBE4(pf, ip, test6, done, action, reason, r, s); diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c --- a/sys/netpfil/pf/pf_norm.c +++ b/sys/netpfil/pf/pf_norm.c @@ -942,7 +942,8 @@ #ifdef INET6 int -pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag) +pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag, + bool forward) { struct mbuf *m = *m0, *t; struct pf_fragment_tag *ftag = (struct pf_fragment_tag *)(mtag + 1); @@ -1009,7 +1010,12 @@ memset(&pd, 0, sizeof(pd)); pd.pf_mtag = pf_find_mtag(m); if (error == 0) - ip6_forward(m, 0); + if (forward) { + MPASS(m->m_pkthdr.rcvif != NULL); + ip6_forward(m, 0); + } else { + ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + } else m_freem(m); }