summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2016-01-10 11:59:55 +0000
committermelifaro <melifaro@FreeBSD.org>2016-01-10 11:59:55 +0000
commit62e557108e3812d8e8b16b2a263c2b82ea2538e5 (patch)
treee0fe9d1076b87f4ef788e8f86076f231075d5c44 /sys/netinet6
parent25fae8119f7fc434ba67e024cd3cd0742085edc7 (diff)
downloadFreeBSD-src-62e557108e3812d8e8b16b2a263c2b82ea2538e5.zip
FreeBSD-src-62e557108e3812d8e8b16b2a263c2b82ea2538e5.tar.gz
Do not hold ifaddr reference for the whole icmp6_reflect() exec time.
Copy source address, calculate hlim and release refcount instead.
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/icmp6.c37
1 files changed, 21 insertions, 16 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 54d7e1e..2007a18 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -2114,13 +2114,13 @@ icmp6_rip6_input(struct mbuf **mp, int off)
void
icmp6_reflect(struct mbuf *m, size_t off)
{
- struct in6_addr src, *srcp = NULL;
+ struct in6_addr src6, *srcp;
struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia = NULL;
struct ifnet *outif = NULL;
int plen;
- int type, code;
+ int type, code, hlim;
/* too short to reflect */
if (off < sizeof(struct ip6_hdr)) {
@@ -2166,6 +2166,8 @@ icmp6_reflect(struct mbuf *m, size_t off)
icmp6 = (struct icmp6_hdr *)(ip6 + 1);
type = icmp6->icmp6_type; /* keep type for statistics */
code = icmp6->icmp6_code; /* ditto. */
+ hlim = 0;
+ srcp = NULL;
/*
* If the incoming packet was addressed directly to us (i.e. unicast),
@@ -2177,8 +2179,18 @@ icmp6_reflect(struct mbuf *m, size_t off)
if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
if (ia != NULL && !(ia->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
- srcp = &ia->ia_addr.sin6_addr;
+ (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
+ src6 = ia->ia_addr.sin6_addr;
+ srcp = &src6;
+
+ if (m->m_pkthdr.rcvif != NULL) {
+ /* XXX: This may not be the outgoing interface */
+ hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
+ } else
+ hlim = V_ip6_defhlim;
+ }
+ if (ia != NULL)
+ ifa_free(&ia->ia_ifa);
}
if (srcp == NULL) {
@@ -2195,16 +2207,16 @@ icmp6_reflect(struct mbuf *m, size_t off)
sin6.sin6_len = sizeof(sin6);
sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
- e = in6_selectsrc(&sin6, NULL, NULL, NULL, &outif, &src);
+ e = in6_selectsrc(&sin6, NULL, NULL, NULL, &outif, &src6);
if (e) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG,
"icmp6_reflect: source can't be determined: "
"dst=%s, error=%d\n",
- ip6_sprintf(ip6buf, &sin6.sin6_addr), e));
+ ip6_sprintf(ip6buf, &ip6->ip6_dst), e));
goto bad;
}
- srcp = &src;
+ srcp = &src6;
}
/*
* ip6_input() drops a packet if its src is multicast.
@@ -2218,11 +2230,8 @@ icmp6_reflect(struct mbuf *m, size_t off)
ip6->ip6_nxt = IPPROTO_ICMPV6;
if (outif)
ip6->ip6_hlim = ND_IFINFO(outif)->chlim;
- else if (m->m_pkthdr.rcvif) {
- /* XXX: This may not be the outgoing interface */
- ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
- } else
- ip6->ip6_hlim = V_ip6_defhlim;
+ else
+ ip6->ip6_hlim = hlim;
icmp6->icmp6_cksum = 0;
icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
@@ -2238,13 +2247,9 @@ icmp6_reflect(struct mbuf *m, size_t off)
if (outif)
icmp6_ifoutstat_inc(outif, type, code);
- if (ia != NULL)
- ifa_free(&ia->ia_ifa);
return;
bad:
- if (ia != NULL)
- ifa_free(&ia->ia_ifa);
m_freem(m);
return;
}
OpenPOWER on IntegriCloud