summaryrefslogtreecommitdiff
path: root/sys/netinet6/ip6_input.c
diff options
context:
space:
mode:
authoritojun <itojun@NetBSD.org>2000-03-21 23:53:30 +0000
committeritojun <itojun@NetBSD.org>2000-03-21 23:53:30 +0000
commitfadbd2b29a157d2a6e1a110c3eef3d445aab496b (patch)
tree5826e7203e42497083fe99810a24ddf0eb187001 /sys/netinet6/ip6_input.c
parent3b3bcd2a107e669d64b473712b518bc826b9f8f0 (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.c111
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
*/