diff options
Diffstat (limited to 'freebsd/sys/netinet6/ip6_input.c')
-rw-r--r-- | freebsd/sys/netinet6/ip6_input.c | 97 |
1 files changed, 58 insertions, 39 deletions
diff --git a/freebsd/sys/netinet6/ip6_input.c b/freebsd/sys/netinet6/ip6_input.c index 6af5acd7..e34ac0e6 100644 --- a/freebsd/sys/netinet6/ip6_input.c +++ b/freebsd/sys/netinet6/ip6_input.c @@ -121,6 +121,7 @@ __FBSDID("$FreeBSD$"); #include <netinet6/in6_rss.h> #ifdef IPSEC +#include <netipsec/key.h> #include <netipsec/ipsec.h> #include <netinet6/ip6_ipsec.h> #include <netipsec/ipsec6.h> @@ -550,12 +551,20 @@ ip6_input(struct mbuf *m) struct in6_addr odst; struct ip6_hdr *ip6; struct in6_ifaddr *ia; + struct ifnet *rcvif; u_int32_t plen; u_int32_t rtalert = ~0; int off = sizeof(struct ip6_hdr), nest; int nxt, ours = 0; int srcrt = 0; + /* + * Drop the packet if IPv6 operation is disabled on the interface. + */ + rcvif = m->m_pkthdr.rcvif; + if ((ND_IFINFO(rcvif)->flags & ND6_IFF_IFDISABLED)) + goto bad; + #ifdef IPSEC /* * should the inner packet be considered authentic? @@ -590,20 +599,15 @@ ip6_input(struct mbuf *m) if (m->m_next) { if (m->m_flags & M_LOOP) { IP6STAT_INC(ip6s_m2m[V_loif->if_index]); - } else if (m->m_pkthdr.rcvif->if_index < IP6S_M2MMAX) - IP6STAT_INC( - ip6s_m2m[m->m_pkthdr.rcvif->if_index]); + } else if (rcvif->if_index < IP6S_M2MMAX) + IP6STAT_INC(ip6s_m2m[rcvif->if_index]); else IP6STAT_INC(ip6s_m2m[0]); } else IP6STAT_INC(ip6s_m1); } - /* drop the packet if IPv6 operation is disabled on the IF */ - if ((ND_IFINFO(m->m_pkthdr.rcvif)->flags & ND6_IFF_IFDISABLED)) - goto bad; - - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); + in6_ifstat_inc(rcvif, ifs6_in_receive); IP6STAT_INC(ip6s_total); #ifndef PULLDOWN_TEST @@ -619,10 +623,8 @@ ip6_input(struct mbuf *m) n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); else n = m_gethdr(M_NOWAIT, MT_DATA); - if (n == NULL) { - m_freem(m); - return; /* ENOBUFS */ - } + if (n == NULL) + goto bad; m_move_pkthdr(n, m); m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); @@ -634,26 +636,22 @@ ip6_input(struct mbuf *m) #endif if (m->m_len < sizeof(struct ip6_hdr)) { - struct ifnet *inifp; - inifp = m->m_pkthdr.rcvif; if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { IP6STAT_INC(ip6s_toosmall); - in6_ifstat_inc(inifp, ifs6_in_hdrerr); - return; + in6_ifstat_inc(rcvif, ifs6_in_hdrerr); + goto bad; } } ip6 = mtod(m, struct ip6_hdr *); - if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { IP6STAT_INC(ip6s_badvers); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); + in6_ifstat_inc(rcvif, ifs6_in_hdrerr); goto bad; } IP6STAT_INC(ip6s_nxthist[ip6->ip6_nxt]); - - IP_PROBE(receive, NULL, NULL, ip6, m->m_pkthdr.rcvif, NULL, ip6); + IP_PROBE(receive, NULL, NULL, ip6, rcvif, NULL, ip6); /* * Check against address spoofing/corruption. @@ -664,7 +662,7 @@ ip6_input(struct mbuf *m) * XXX: "badscope" is not very suitable for a multicast source. */ IP6STAT_INC(ip6s_badscope); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) && @@ -676,7 +674,7 @@ ip6_input(struct mbuf *m) * as the outgoing/incoming interface. */ IP6STAT_INC(ip6s_badscope); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && @@ -688,7 +686,7 @@ ip6_input(struct mbuf *m) * a packet is received, it must be silently dropped. */ IP6STAT_INC(ip6s_badscope); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } #ifdef ALTQ @@ -712,7 +710,7 @@ ip6_input(struct mbuf *m) if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { IP6STAT_INC(ip6s_badscope); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } #if 0 @@ -730,14 +728,36 @@ ip6_input(struct mbuf *m) goto bad; } #endif + /* + * Try to forward the packet, but if we fail continue. + * ip6_tryforward() does inbound and outbound packet firewall + * processing. If firewall has decided that destination becomes + * our local address, it sets M_FASTFWD_OURS flag. In this + * case skip another inbound firewall processing and update + * ip6 pointer. + */ + if (V_ip6_forwarding != 0 +#ifdef IPSEC + && !key_havesp(IPSEC_DIR_INBOUND) + && !key_havesp(IPSEC_DIR_OUTBOUND) +#endif + ) { + if ((m = ip6_tryforward(m)) == NULL) + return; + if (m->m_flags & M_FASTFWD_OURS) { + m->m_flags &= ~M_FASTFWD_OURS; + ours = 1; + ip6 = mtod(m, struct ip6_hdr *); + goto hbhcheck; + } + } #ifdef IPSEC /* * Bypass packet filtering for packets previously handled by IPsec. */ if (ip6_ipsec_filtertunnel(m)) goto passin; -#endif /* IPSEC */ - +#endif /* * Run through list of hooks for input packets. * @@ -745,12 +765,12 @@ ip6_input(struct mbuf *m) * (e.g. by NAT rewriting). When this happens, * tell ip6_forward to do the right thing. */ - odst = ip6->ip6_dst; /* Jump over all PFIL processing if hooks are not active. */ if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto passin; + odst = ip6->ip6_dst; if (pfil_run_hooks(&V_inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL)) return; @@ -790,8 +810,8 @@ passin: IP6STAT_INC(ip6s_badscope); /* XXX */ goto bad; } - if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) || - in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) { + if (in6_setscope(&ip6->ip6_src, rcvif, NULL) || + in6_setscope(&ip6->ip6_dst, rcvif, NULL)) { IP6STAT_INC(ip6s_badscope); goto bad; } @@ -801,7 +821,7 @@ passin: */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { ours = 1; - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); + in6_ifstat_inc(rcvif, ifs6_in_mcast); goto hbhcheck; } /* @@ -836,7 +856,6 @@ passin: */ if (!V_ip6_forwarding) { IP6STAT_INC(ip6s_cantforward); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } @@ -868,7 +887,7 @@ passin: */ if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { IP6STAT_INC(ip6s_tooshort); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); + in6_ifstat_inc(rcvif, ifs6_in_truncated); goto bad; } if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { @@ -895,10 +914,8 @@ passin: * XXX TODO: Check hlim and multicast scope here to avoid * unnecessarily calling into ip6_mforward(). */ - if (ip6_mforward && - ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { + if (ip6_mforward && ip6_mforward(ip6, rcvif, m)) { IP6STAT_INC(ip6s_cantforward); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } } else if (!ours) { @@ -920,7 +937,7 @@ passin: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { IP6STAT_INC(ip6s_badscope); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } @@ -928,7 +945,7 @@ passin: * Tell launch routine the next header */ IP6STAT_INC(ip6s_delivered); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_deliver); + in6_ifstat_inc(rcvif, ifs6_in_deliver); nest = 0; while (nxt != IPPROTO_DONE) { @@ -943,7 +960,7 @@ passin: */ if (m->m_pkthdr.len < off) { IP6STAT_INC(ip6s_tooshort); - in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); + in6_ifstat_inc(rcvif, ifs6_in_truncated); goto bad; } @@ -961,7 +978,9 @@ passin: } return; bad: - m_freem(m); + in6_ifstat_inc(rcvif, ifs6_in_discard); + if (m != NULL) + m_freem(m); } /* |