diff options
| author | itojun <itojun@NetBSD.org> | 2000-03-21 23:53:30 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 2000-03-21 23:53:30 +0000 |
| commit | fadbd2b29a157d2a6e1a110c3eef3d445aab496b (patch) | |
| tree | 5826e7203e42497083fe99810a24ddf0eb187001 /sys/netinet6/ip6_input.c | |
| parent | 3b3bcd2a107e669d64b473712b518bc826b9f8f0 (diff) | |
cleanup AH/policy processing.
- parse IPv6 header by using common function, ip6_{last,next}hdr.
- fix behaivior in multiple AH cases.
make strict boundary checks on mbuf chasing.
(sync with latest kame)
Diffstat (limited to 'sys/netinet6/ip6_input.c')
| -rw-r--r-- | sys/netinet6/ip6_input.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 4d1d3d5d07e..129433a8d73 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.17 2000/03/21 11:05:12 itojun Exp $ */ +/* $NetBSD: ip6_input.c,v 1.18 2000/03/21 23:53:30 itojun Exp $ */ /* $KAME: ip6_input.c,v 1.72 2000/03/21 09:23:19 itojun Exp $ */ /* @@ -1185,6 +1185,115 @@ ip6_get_prevhdr(m, off) } /* + * get next header offset. m will be retained. + */ +int +ip6_nexthdr(m, off, proto, nxtp) + struct mbuf *m; + int off; + int proto; + int *nxtp; +{ + struct ip6_hdr ip6; + struct ip6_ext ip6e; + struct ip6_frag fh; + + /* just in case */ + if (m == NULL) + panic("ip6_nexthdr: m == NULL"); + if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) + return -1; + + switch (proto) { + case IPPROTO_IPV6: + if (m->m_pkthdr.len < off + sizeof(ip6)) + return -1; + m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); + if (nxtp) + *nxtp = ip6.ip6_nxt; + off += sizeof(ip6); + return off; + + case IPPROTO_FRAGMENT: + /* + * terminate parsing if it is not the first fragment, + * it does not make sense to parse through it. + */ + if (m->m_pkthdr.len < off + sizeof(fh)) + return -1; + m_copydata(m, off, sizeof(fh), (caddr_t)&fh); + if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0) + return -1; + if (nxtp) + *nxtp = fh.ip6f_nxt; + off += sizeof(struct ip6_frag); + return off; + + case IPPROTO_AH: + if (m->m_pkthdr.len < off + sizeof(ip6e)) + return -1; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxtp) + *nxtp = ip6e.ip6e_nxt; + off += (ip6e.ip6e_len + 2) << 2; + return off; + + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: + if (m->m_pkthdr.len < off + sizeof(ip6e)) + return -1; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxtp) + *nxtp = ip6e.ip6e_nxt; + off += (ip6e.ip6e_len + 1) << 3; + return off; + + case IPPROTO_NONE: + case IPPROTO_ESP: + case IPPROTO_IPCOMP: + /* give up */ + return -1; + + default: + return -1; + } + + return -1; +} + +/* + * get offset for the last header in the chain. m will be kept untainted. + */ +int +ip6_lasthdr(m, off, proto, nxtp) + struct mbuf *m; + int off; + int proto; + int *nxtp; +{ + int newoff; + int nxt; + + if (!nxtp) { + nxt = -1; + nxtp = &nxt; + } + while (1) { + newoff = ip6_nexthdr(m, off, proto, nxtp); + if (newoff < 0) + return off; + else if (newoff < off) + return -1; /* invalid */ + else if (newoff == off) + return newoff; + + off = newoff; + proto = *nxtp; + } +} + +/* * System control for IP6 */ |
