summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/dest6.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/dest6.c')
-rw-r--r--freebsd/sys/netinet6/dest6.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/freebsd/sys/netinet6/dest6.c b/freebsd/sys/netinet6/dest6.c
index 50a836ba..354457e2 100644
--- a/freebsd/sys/netinet6/dest6.c
+++ b/freebsd/sys/netinet6/dest6.c
@@ -66,30 +66,35 @@ __FBSDID("$FreeBSD$");
int
dest6_input(struct mbuf **mp, int *offp, int proto)
{
- struct mbuf *m = *mp;
- int off = *offp, dstoptlen, optlen;
+ struct mbuf *m;
+ int off, dstoptlen, optlen;
struct ip6_dest *dstopts;
u_int8_t *opt;
- /* validation of the length of the header */
-#ifndef PULLDOWN_TEST
- IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE);
+ m = *mp;
+ off = *offp;
+
+ /* Validation of the length of the header. */
+ if (m->m_len < off + sizeof(*dstopts)) {
+ m = m_pullup(m, off + sizeof(*dstopts));
+ if (m == NULL) {
+ IP6STAT_INC(ip6s_exthdrtoolong);
+ *mp = m;
+ return (IPPROTO_DONE);
+ }
+ }
dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
-#else
- IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts));
- if (dstopts == NULL)
- return IPPROTO_DONE;
-#endif
dstoptlen = (dstopts->ip6d_len + 1) << 3;
-#ifndef PULLDOWN_TEST
- IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE);
+ if (m->m_len < off + dstoptlen) {
+ m = m_pullup(m, off + dstoptlen);
+ if (m == NULL) {
+ IP6STAT_INC(ip6s_exthdrtoolong);
+ *mp = m;
+ return (IPPROTO_DONE);
+ }
+ }
dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
-#else
- IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen);
- if (dstopts == NULL)
- return IPPROTO_DONE;
-#endif
off += dstoptlen;
dstoptlen -= sizeof(struct ip6_dest);
opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest);
@@ -112,17 +117,21 @@ dest6_input(struct mbuf **mp, int *offp, int proto)
default: /* unknown option */
optlen = ip6_unknown_opt(opt, m,
opt - mtod(m, u_int8_t *));
- if (optlen == -1)
+ if (optlen == -1) {
+ *mp = NULL;
return (IPPROTO_DONE);
+ }
optlen += 2;
break;
}
}
*offp = off;
+ *mp = m;
return (dstopts->ip6d_nxt);
bad:
m_freem(m);
+ *mp = NULL;
return (IPPROTO_DONE);
}