diff options
Diffstat (limited to 'freebsd/sys/netinet6/mld6.c')
-rw-r--r-- | freebsd/sys/netinet6/mld6.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/freebsd/sys/netinet6/mld6.c b/freebsd/sys/netinet6/mld6.c index a0d045d5..e7b400ae 100644 --- a/freebsd/sys/netinet6/mld6.c +++ b/freebsd/sys/netinet6/mld6.c @@ -1254,20 +1254,27 @@ out_locked: * Return IPPROTO_DONE if we freed m. Otherwise, return 0. */ int -mld_input(struct mbuf *m, int off, int icmp6len) +mld_input(struct mbuf **mp, int off, int icmp6len) { struct ifnet *ifp; struct ip6_hdr *ip6; + struct mbuf *m; struct mld_hdr *mld; int mldlen; + m = *mp; CTR3(KTR_MLD, "%s: called w/mbuf (%p,%d)", __func__, m, off); ifp = m->m_pkthdr.rcvif; - ip6 = mtod(m, struct ip6_hdr *); - /* Pullup to appropriate size. */ + if (m->m_len < off + sizeof(*mld)) { + m = m_pullup(m, off + sizeof(*mld)); + if (m == NULL) { + ICMP6STAT_INC(icp6s_badlen); + return (IPPROTO_DONE); + } + } mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off); if (mld->mld_type == MLD_LISTENER_QUERY && icmp6len >= sizeof(struct mldv2_query)) { @@ -1275,11 +1282,16 @@ mld_input(struct mbuf *m, int off, int icmp6len) } else { mldlen = sizeof(struct mld_hdr); } - IP6_EXTHDR_GET(mld, struct mld_hdr *, m, off, mldlen); - if (mld == NULL) { - ICMP6STAT_INC(icp6s_badlen); - return (IPPROTO_DONE); + if (m->m_len < off + mldlen) { + m = m_pullup(m, off + mldlen); + if (m == NULL) { + ICMP6STAT_INC(icp6s_badlen); + return (IPPROTO_DONE); + } } + *mp = m; + ip6 = mtod(m, struct ip6_hdr *); + mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off); /* * Userland needs to see all of this traffic for implementing |