Index: sys/netinet/ip_fastfwd.c =================================================================== --- sys/netinet/ip_fastfwd.c +++ sys/netinet/ip_fastfwd.c @@ -154,7 +154,6 @@ struct in_addr odest, dest; uint16_t ip_len, ip_off; int error = 0; - struct m_tag *fwd_tag = NULL; /* * Are we active and forwarding packets? @@ -317,9 +316,8 @@ /* * Destination address changed? */ - if (m->m_flags & M_IP_NEXTHOP) - fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); - if (odest.s_addr != dest.s_addr || fwd_tag != NULL) { + if (odest.s_addr != dest.s_addr || + (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &dst, NULL))) { /* * Is it now for a local address on this host? */ @@ -331,15 +329,13 @@ m->m_flags |= M_FASTFWD_OURS; return (m); } + if (IP_HAS_NEXTHOP(m)) { + dest.s_addr = dst.sin_addr.s_addr; + ip_flush_fwdtag(m); + } /* * Redo route lookup with new destination address */ - if (fwd_tag) { - dest.s_addr = ((struct sockaddr_in *) - (fwd_tag + 1))->sin_addr.s_addr; - m_tag_delete(m, fwd_tag); - m->m_flags &= ~M_IP_NEXTHOP; - } if (ip_findroute(&nh, dest, m) != 0) return (NULL); /* icmp unreach already sent */ } Index: sys/netinet/ip_input.c =================================================================== --- sys/netinet/ip_input.c +++ sys/netinet/ip_input.c @@ -605,16 +605,14 @@ m->m_flags &= ~M_FASTFWD_OURS; goto ours; } - if (m->m_flags & M_IP_NEXTHOP) { - if (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) { - /* - * Directly ship the packet on. This allows - * forwarding packets originally destined to us - * to some other directly connected host. - */ - ip_forward(m, 1); - return; - } + if (IP_HAS_NEXTHOP(m)) { + /* + * Directly ship the packet on. This allows + * forwarding packets originally destined to us + * to some other directly connected host. + */ + ip_forward(m, 1); + return; } passin: Index: sys/netinet/ip_output.c =================================================================== --- sys/netinet/ip_output.c +++ sys/netinet/ip_output.c @@ -108,7 +108,6 @@ ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp, struct sockaddr_in *dst, int *fibnum, int *error) { - struct m_tag *fwd_tag = NULL; struct mbuf *m; struct in_addr odst; struct ip *ip; @@ -182,13 +181,9 @@ return 1; /* Finished */ } /* Or forward to some other address? */ - if ((m->m_flags & M_IP_NEXTHOP) && - ((fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL)) { - bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in)); + if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, dst, NULL)) { m->m_flags |= M_SKIP_FIREWALL; - m->m_flags &= ~M_IP_NEXTHOP; - m_tag_delete(m, fwd_tag); - + ip_flush_fwdtag(m); return -1; /* Reloop for CHANGE of dst */ } @@ -1415,3 +1410,82 @@ if_simloop(ifp, copym, AF_INET, 0); } } + +int +ip_set_fwdtag(struct mbuf *m, struct sockaddr_in *dst, u_short ifidx) +{ + struct sockaddr_in *sa; + struct m_tag *fwd_tag; + + (void)ifidx; /* XXX: store after dst, or make struct? */ + + KASSERT(dst != NULL, ("%s: !dst", __func__)); + KASSERT(dst->sin_family == AF_INET, ("%s: !AF_INET", __func__)); + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET, ("%s: !AF_INET", __func__)); + + m_tag_unlink(m, fwd_tag); + } else { + fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, sizeof(*dst), + M_NOWAIT); + if (fwd_tag == NULL) { + return (ENOBUFS); + } + } + + sa = (struct sockaddr_in *)(fwd_tag+1); + + bcopy(dst, sa, sizeof(*dst)); + m->m_flags |= M_IP_NEXTHOP; + + if (in_localip(sa->sin_addr)) + m->m_flags |= M_FASTFWD_OURS; + else + m->m_flags &= ~M_FASTFWD_OURS; + + m_tag_prepend(m, fwd_tag); + + return (0); +} + +int +ip_get_fwdtag(struct mbuf *m, struct sockaddr_in *dst, u_short *ifidx) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag == NULL) { + return (ENOENT); + } + + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == AF_INET, + ("%s: !AF_INET", __func__)); + + if (dst != NULL) { + bcopy((fwd_tag+1), dst, sizeof(*dst)); + } + + if (ifidx != NULL) { + /* XXX ifidx is not yet defined */ + } + + return (0); +} + +void +ip_flush_fwdtag(struct mbuf *m) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET, ("%s: !AF_INET", __func__)); + + m->m_flags &= ~(M_IP_NEXTHOP | M_FASTFWD_OURS); + m_tag_delete(m, fwd_tag); + } +} Index: sys/netinet/ip_var.h =================================================================== --- sys/netinet/ip_var.h +++ sys/netinet/ip_var.h @@ -236,6 +236,11 @@ extern void (*ip_rsvp_force_done)(struct socket *); extern int (*rsvp_input_p)(struct mbuf **, int *, int); +#define IP_HAS_NEXTHOP(m) ((m)->m_flags & M_IP_NEXTHOP) +int ip_set_fwdtag(struct mbuf *, struct sockaddr_in *, u_short); +int ip_get_fwdtag(struct mbuf *, struct sockaddr_in *, u_short *); +void ip_flush_fwdtag(struct mbuf *); + VNET_DECLARE(struct pfil_head, inet_pfil_hook); /* packet filter hooks */ #define V_inet_pfil_hook VNET(inet_pfil_hook) Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -605,6 +605,7 @@ int off0; int optlen = 0; #ifdef INET + struct sockaddr_in next_hop; int len; #endif int tlen = 0, off; @@ -615,8 +616,8 @@ uint8_t sig_checked = 0; #endif uint8_t iptos; - struct m_tag *fwd_tag = NULL; #ifdef INET6 + struct sockaddr_in6 next_hop6; struct ip6_hdr *ip6 = NULL; int isipv6; #else @@ -810,22 +811,6 @@ } else ti_locked = TI_UNLOCKED; - /* - * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. - */ - if ( -#ifdef INET6 - (isipv6 && (m->m_flags & M_IP6_NEXTHOP)) -#ifdef INET - || (!isipv6 && (m->m_flags & M_IP_NEXTHOP)) -#endif -#endif -#if defined(INET) && !defined(INET6) - (m->m_flags & M_IP_NEXTHOP) -#endif - ) - fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); - findpcb: #ifdef INVARIANTS if (ti_locked == TI_RLOCKED) { @@ -835,10 +820,11 @@ } #endif #ifdef INET6 - if (isipv6 && fwd_tag != NULL) { - struct sockaddr_in6 *next_hop6; - - next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); + /* + * Grab info from IP forward tag prepended to the chain. + */ + if (isipv6 && IP6_HAS_NEXTHOP(m) && + !ip6_get_fwdtag(m, &next_hop6, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * Already got one like this? @@ -853,11 +839,13 @@ * any hardware-generated hash is ignored. */ inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_src, - th->th_sport, &next_hop6->sin6_addr, - next_hop6->sin6_port ? ntohs(next_hop6->sin6_port) : + th->th_sport, &next_hop6.sin6_addr, + next_hop6.sin6_port ? ntohs(next_hop6.sin6_port) : th->th_dport, INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif); } + /* Remove the tag from the packet. We don't need it anymore. */ + ip6_flush_fwdtag(m); } else if (isipv6) { inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src, th->th_sport, &ip6->ip6_dst, th->th_dport, @@ -869,10 +857,10 @@ else #endif #ifdef INET - if (fwd_tag != NULL) { - struct sockaddr_in *next_hop; - - next_hop = (struct sockaddr_in *)(fwd_tag+1); + /* + * Grab info from IP forward tag prepended to the chain. + */ + if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &next_hop, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * already got one like this? @@ -887,11 +875,13 @@ * any hardware-generated hash is ignored. */ inp = in_pcblookup(&V_tcbinfo, ip->ip_src, - th->th_sport, next_hop->sin_addr, - next_hop->sin_port ? ntohs(next_hop->sin_port) : + th->th_sport, next_hop.sin_addr, + next_hop.sin_port ? ntohs(next_hop.sin_port) : th->th_dport, INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif); } + /* Remove the tag from the packet. We don't need it anymore. */ + ip_flush_fwdtag(m); } else inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, th->th_sport, ip->ip_dst, th->th_dport, Index: sys/netinet/udp_usrreq.c =================================================================== --- sys/netinet/udp_usrreq.c +++ sys/netinet/udp_usrreq.c @@ -407,7 +407,7 @@ struct ip save_ip; struct sockaddr_in udp_in; struct mbuf *m; - struct m_tag *fwd_tag; + struct sockaddr_in next_hop; int cscov_partial, iphlen; m = *mp; @@ -647,14 +647,9 @@ */ /* - * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + * Grab info from IP forward tag prepended to the chain. */ - if ((m->m_flags & M_IP_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { - struct sockaddr_in *next_hop; - - next_hop = (struct sockaddr_in *)(fwd_tag + 1); - + if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &next_hop, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * Already got one like this? @@ -668,14 +663,13 @@ * any hardware-generated hash is ignored. */ inp = in_pcblookup(pcbinfo, ip->ip_src, - uh->uh_sport, next_hop->sin_addr, - next_hop->sin_port ? htons(next_hop->sin_port) : + uh->uh_sport, next_hop.sin_addr, + next_hop.sin_port ? htons(next_hop.sin_port) : uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, ifp); } /* Remove the tag from the packet. We don't need it anymore. */ - m_tag_delete(m, fwd_tag); - m->m_flags &= ~M_IP_NEXTHOP; + ip_flush_fwdtag(m); } else inp = in_pcblookup_mbuf(pcbinfo, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD | Index: sys/netinet6/ip6_fastfwd.c =================================================================== --- sys/netinet6/ip6_fastfwd.c +++ sys/netinet6/ip6_fastfwd.c @@ -87,7 +87,6 @@ { struct sockaddr_in6 dst; struct nhop6_basic nh; - struct m_tag *fwd_tag; struct ip6_hdr *ip6; struct ifnet *rcvif; uint32_t plen; @@ -167,24 +166,20 @@ * XXX: should we decrement ip6_hlim in such case? * * Also it can forward packet to another destination, e.g. - * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf. + * M_IP6_NEXTHOP flag set and forward tag attached to mbuf. */ if (m->m_flags & M_FASTFWD_OURS) return (m); ip6 = mtod(m, struct ip6_hdr *); - if ((m->m_flags & M_IP6_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { - /* - * Now we will find route to forwarded by pfil destination. - */ - bcopy((fwd_tag + 1), &dst, sizeof(dst)); - m->m_flags &= ~M_IP6_NEXTHOP; - m_tag_delete(m, fwd_tag); + if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &dst, NULL)) { + /* Request from pfil to forward to destination */ + ip6_flush_fwdtag(m); } else { /* Update dst since pfil could change it */ dst.sin6_addr = ip6->ip6_dst; } + passin: /* * Find route to destination. @@ -219,7 +214,7 @@ * So, we can just go back to ip6_input. * * Also it can forward packet to another destination, e.g. - * M_IP6_NEXTHOP flag is set and fwd_tag is attached to mbuf. + * M_IP6_NEXTHOP flag set and forward tag attached to mbuf. */ if (m->m_flags & M_FASTFWD_OURS) { /* @@ -232,19 +227,19 @@ * Again. A packet filter could change the destination address. */ ip6 = mtod(m, struct ip6_hdr *); - if (m->m_flags & M_IP6_NEXTHOP) - fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); - else - fwd_tag = NULL; + if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &dst, NULL)) { + ip6_flush_fwdtag(m); + + /* + * Redo route lookup with new destination address + */ + if (ip6_findroute(&nh, &dst, m) != 0) { + m = NULL; + goto dropout; + } + } else if (!IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &ip6->ip6_dst)) { + dst.sin6_addr = ip6->ip6_dst; - if (fwd_tag != NULL || - !IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &ip6->ip6_dst)) { - if (fwd_tag != NULL) { - bcopy((fwd_tag + 1), &dst, sizeof(dst)); - m->m_flags &= ~M_IP6_NEXTHOP; - m_tag_delete(m, fwd_tag); - } else - dst.sin6_addr = ip6->ip6_dst; /* * Redo route lookup with new destination address */ @@ -253,6 +248,7 @@ goto dropout; } } + passout: #ifdef IPSTEALTH if (!V_ip6stealth) Index: sys/netinet6/ip6_forward.c =================================================================== --- sys/netinet6/ip6_forward.c +++ sys/netinet6/ip6_forward.c @@ -103,7 +103,6 @@ #ifdef IPSEC struct secpolicy *sp = NULL; #endif - struct m_tag *fwd_tag; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; /* @@ -525,13 +524,17 @@ goto out; } /* Or forward to some other address? */ - if ((m->m_flags & M_IP6_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { + if (IP6_HAS_NEXTHOP(m)) { dst = (struct sockaddr_in6 *)&rin6.ro_dst; - bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in6)); + if (ip6_get_fwdtag(m, dst, NULL) != 0) { + if (mcopy) { + m_freem(m); + goto freecopy; + } + goto bad; + } m->m_flags |= M_SKIP_FIREWALL; - m->m_flags &= ~M_IP6_NEXTHOP; - m_tag_delete(m, fwd_tag); + ip6_flush_fwdtag(m); RTFREE(rt); goto again2; } Index: sys/netinet6/ip6_input.c =================================================================== --- sys/netinet6/ip6_input.c +++ sys/netinet6/ip6_input.c @@ -782,8 +782,7 @@ ours = 1; goto hbhcheck; } - if ((m->m_flags & M_IP6_NEXTHOP) && - m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) { + if (IP6_HAS_NEXTHOP(m)) { /* * Directly ship the packet on. This allows forwarding * packets originally destined to us to some other directly Index: sys/netinet6/ip6_output.c =================================================================== --- sys/netinet6/ip6_output.c +++ sys/netinet6/ip6_output.c @@ -322,8 +322,8 @@ int hdrsplit = 0; int sw_csum, tso; int needfiblookup; + int has_fwd_tag = 0; uint32_t fibnum; - struct m_tag *fwd_tag = NULL; uint32_t id; if (inp != NULL) { @@ -547,7 +547,7 @@ ro->ro_dst.sin6_family = AF_INET6; RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, fibnum); } - if (ro->ro_rt && fwd_tag == NULL && (ro->ro_rt->rt_flags & RTF_UP) && + if (ro->ro_rt && !has_fwd_tag && (ro->ro_rt->rt_flags & RTF_UP) && ro->ro_dst.sin6_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) { rt = ro->ro_rt; @@ -556,7 +556,7 @@ if (ro->ro_lle) LLE_FREE(ro->ro_lle); /* zeros ro_lle */ ro->ro_lle = NULL; - if (fwd_tag == NULL) { + if (!has_fwd_tag) { bzero(&dst_sa, sizeof(dst_sa)); dst_sa.sin6_family = AF_INET6; dst_sa.sin6_len = sizeof(dst_sa); @@ -860,13 +860,11 @@ goto done; } /* Or forward to some other address? */ - if ((m->m_flags & M_IP6_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { + if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &dst_sa, NULL)) { dst = (struct sockaddr_in6 *)&ro->ro_dst; - bcopy((fwd_tag+1), &dst_sa, sizeof(struct sockaddr_in6)); m->m_flags |= M_SKIP_FIREWALL; - m->m_flags &= ~M_IP6_NEXTHOP; - m_tag_delete(m, fwd_tag); + ip6_flush_fwdtag(m); + has_fwd_tag = 1; goto again; } @@ -3096,3 +3094,95 @@ return len; #undef elen } + +int +ip6_set_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, u_short ifidx) +{ + struct sockaddr_in6 *sa6; + struct m_tag *fwd_tag; + int error; + + (void)ifidx; /* XXX: store after dst, or make struct? */ + + KASSERT(dst != NULL, ("%s: !dst", __func__)); + KASSERT(dst->sin6_family == AF_INET6, ("%s: !AF_INET6", __func__)); + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET6, ("%s: !AF_INET6", __func__)); + + m_tag_unlink(m, fwd_tag); + } else { + fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, sizeof(*dst), + M_NOWAIT); + if (fwd_tag == NULL) { + return (ENOBUFS); + } + } + + sa6 = (struct sockaddr_in6 *)(fwd_tag+1); + + bcopy(dst, sa6, sizeof(*dst)); + + /* + * If nh6 address is link-local we should convert + * it to kernel internal form before doing any + * comparisons. + */ + error = sa6_embedscope(sa6, V_ip6_use_defzone); + if (error != 0) { + m_tag_free(fwd_tag); + return (error); + } + + if (in6_localip(&sa6->sin6_addr)) + m->m_flags |= M_FASTFWD_OURS; + else + m->m_flags &= ~M_FASTFWD_OURS; + + m->m_flags |= M_IP6_NEXTHOP; + + m_tag_prepend(m, fwd_tag); + + return (0); +} + +int +ip6_get_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, u_short *ifidx) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag == NULL) { + return (ENOENT); + } + + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == AF_INET6, + ("%s: !AF_INET6", __func__)); + + if (dst != NULL) { + bcopy((fwd_tag+1), dst, sizeof(*dst)); + } + + if (ifidx != NULL) { + /* XXX ifidx is not yet defined */ + } + + return (0); +} + +void +ip6_flush_fwdtag(struct mbuf *m) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET6, ("%s: !AF_INET6", __func__)); + + m->m_flags &= ~(M_IP6_NEXTHOP | M_FASTFWD_OURS); + m_tag_delete(m, fwd_tag); + } +} Index: sys/netinet6/ip6_var.h =================================================================== --- sys/netinet6/ip6_var.h +++ sys/netinet6/ip6_var.h @@ -397,6 +397,11 @@ int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int, uint32_t); +#define IP6_HAS_NEXTHOP(m) ((m)->m_flags & M_IP6_NEXTHOP) +int ip6_set_fwdtag(struct mbuf *, struct sockaddr_in6 *, u_short); +int ip6_get_fwdtag(struct mbuf *, struct sockaddr_in6 *, u_short *); +void ip6_flush_fwdtag(struct mbuf *); + int route6_input(struct mbuf **, int *, int); void frag6_init(void); Index: sys/netinet6/udp6_usrreq.c =================================================================== --- sys/netinet6/udp6_usrreq.c +++ sys/netinet6/udp6_usrreq.c @@ -204,7 +204,7 @@ int cscov_partial; int plen, ulen; struct sockaddr_in6 fromsa; - struct m_tag *fwd_tag; + struct sockaddr_in6 next_hop6; uint16_t uh_sum; uint8_t nxt; @@ -413,14 +413,9 @@ */ /* - * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + * Grab info from IP forward tag prepended to the chain. */ - if ((m->m_flags & M_IP6_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { - struct sockaddr_in6 *next_hop6; - - next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); - + if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &next_hop6, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * Already got one like this? @@ -435,14 +430,13 @@ * any hardware-generated hash is ignored. */ inp = in6_pcblookup(pcbinfo, &ip6->ip6_src, - uh->uh_sport, &next_hop6->sin6_addr, - next_hop6->sin6_port ? htons(next_hop6->sin6_port) : + uh->uh_sport, &next_hop6.sin6_addr, + next_hop6.sin6_port ? htons(next_hop6.sin6_port) : uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); } /* Remove the tag from the packet. We don't need it anymore. */ - m_tag_delete(m, fwd_tag); - m->m_flags &= ~M_IP6_NEXTHOP; + ip6_flush_fwdtag(m); } else inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, Index: sys/netpfil/ipfw/ip_fw_pfil.c =================================================================== --- sys/netpfil/ipfw/ip_fw_pfil.c +++ sys/netpfil/ipfw/ip_fw_pfil.c @@ -165,66 +165,25 @@ ret = EACCES; #else { - struct m_tag *fwd_tag; - size_t len; - KASSERT(args.next_hop == NULL || args.next_hop6 == NULL, ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__, args.next_hop, args.next_hop6)); #ifdef INET6 - if (args.next_hop6 != NULL) - len = sizeof(struct sockaddr_in6); -#endif -#ifdef INET - if (args.next_hop != NULL) - len = sizeof(struct sockaddr_in); -#endif - - /* Incoming packets should not be tagged so we do not - * m_tag_find. Outgoing packets may be tagged, so we - * reuse the tag if present. - */ - fwd_tag = (dir == DIR_IN) ? NULL : - m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL); - if (fwd_tag != NULL) { - m_tag_unlink(*m0, fwd_tag); - } else { - fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len, - M_NOWAIT); - if (fwd_tag == NULL) { - ret = EACCES; - break; /* i.e. drop */ - } - } -#ifdef INET6 if (args.next_hop6 != NULL) { - struct sockaddr_in6 *sa6; - - sa6 = (struct sockaddr_in6 *)(fwd_tag + 1); - bcopy(args.next_hop6, sa6, len); - /* - * If nh6 address is link-local we should convert - * it to kernel internal form before doing any - * comparisons. - */ - if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) { + if (ip6_set_fwdtag(*m0, args.next_hop6, 0)) { ret = EACCES; break; } - if (in6_localip(&sa6->sin6_addr)) - (*m0)->m_flags |= M_FASTFWD_OURS; - (*m0)->m_flags |= M_IP6_NEXTHOP; } #endif #ifdef INET if (args.next_hop != NULL) { - bcopy(args.next_hop, (fwd_tag+1), len); - if (in_localip(args.next_hop->sin_addr)) - (*m0)->m_flags |= M_FASTFWD_OURS; - (*m0)->m_flags |= M_IP_NEXTHOP; + if (ip_set_fwdtag(*m0, args.next_hop, 0)) { + ret = EACCES; + break; + } } #endif - m_tag_prepend(*m0, fwd_tag); } #endif /* INET || INET6 */ break;