1139825Simp/*-
286231Stmm * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3117119Stmm * All rights reserved.
4167308Smarius *
586231Stmm * Redistribution and use in source and binary forms, with or without
686231Stmm * modification, are permitted provided that the following conditions
786231Stmm * are met:
886231Stmm * 1. Redistributions of source code must retain the above copyright
986231Stmm *    notice, this list of conditions and the following disclaimer.
1086231Stmm * 2. Redistributions in binary form must reproduce the above copyright
1186231Stmm *    notice, this list of conditions and the following disclaimer in the
1286231Stmm *    documentation and/or other materials provided with the distribution.
1386231Stmm * 3. Neither the name of the project nor the names of its contributors
1486231Stmm *    may be used to endorse or promote products derived from this software
1586231Stmm *    without specific prior written permission.
1686231Stmm *
1786231Stmm * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1886231Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1986231Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2086231Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2186231Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2286231Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2386231Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2486231Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2586231Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2686231Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2786231Stmm * SUCH DAMAGE.
2886231Stmm *
2986231Stmm *	$KAME: dest6.c,v 1.59 2003/07/11 13:21:16 t-momose Exp $
3090617Stmm */
3186231Stmm
3286231Stmm#include <sys/cdefs.h>
33152696Smarius__FBSDID("$FreeBSD$");
34152696Smarius
35152696Smarius#include "opt_inet.h"
3686231Stmm#include "opt_inet6.h"
37153052Smarius
38153052Smarius#include <sys/param.h>
3986231Stmm#include <sys/systm.h>
4086231Stmm#include <sys/malloc.h>
41117119Stmm#include <sys/mbuf.h>
4286231Stmm#include <sys/domain.h>
4386231Stmm#include <sys/protosw.h>
4486231Stmm#include <sys/socket.h>
4586231Stmm#include <sys/errno.h>
4686231Stmm#include <sys/time.h>
47174117Smarius#include <sys/kernel.h>
48131949Smarcel
4986231Stmm#include <net/if.h>
50170851Smarius#include <net/route.h>
51167308Smarius
52130068Sphk#include <netinet/in.h>
53170851Smarius#include <netinet/in_var.h>
54107477Stmm#include <netinet/ip6.h>
55153055Smarius#include <netinet6/ip6_var.h>
56171730Smarius#include <netinet/icmp6.h>
57247600Smarius
5886231Stmm/*
59133589Smarius * Destination options header processing.
60133589Smarius */
61119338Simpint
6286231Stmmdest6_input(struct mbuf **mp, int *offp, int proto)
6386231Stmm{
64167308Smarius	struct mbuf *m = *mp;
65116541Stmm	int off = *offp, dstoptlen, optlen;
6686231Stmm	struct ip6_dest *dstopts;
67167308Smarius	u_int8_t *opt;
6886231Stmm
69152698Smarius	/* validation of the length of the header */
7086231Stmm#ifndef PULLDOWN_TEST
71165886Smarius	IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE);
72119291Simp	dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
7386231Stmm#else
7486231Stmm	IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts));
7586231Stmm	if (dstopts == NULL)
7686231Stmm		return IPPROTO_DONE;
7786231Stmm#endif
7886231Stmm	dstoptlen = (dstopts->ip6d_len + 1) << 3;
7986231Stmm
80152696Smarius#ifndef PULLDOWN_TEST
81152696Smarius	IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE);
82167308Smarius	dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
83172066Smarius#else
84247620Smarius	IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen);
85172066Smarius	if (dstopts == NULL)
8690617Stmm		return IPPROTO_DONE;
87220039Smarius#endif
88220039Smarius	off += dstoptlen;
89172066Smarius	dstoptlen -= sizeof(struct ip6_dest);
90172066Smarius	opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest);
91178443Smarius
92178443Smarius	/* search header for all options. */
9386231Stmm	for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) {
9486231Stmm		if (*opt != IP6OPT_PAD1 &&
95167308Smarius		    (dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) {
96167308Smarius			IP6STAT_INC(ip6s_toosmall);
97167308Smarius			goto bad;
98247600Smarius		}
99247620Smarius
100247620Smarius		switch (*opt) {
10186231Stmm		case IP6OPT_PAD1:
102167308Smarius			optlen = 1;
10386231Stmm			break;
10486231Stmm		case IP6OPT_PADN:
10586231Stmm			optlen = *(opt + 1) + 2;
106152698Smarius			break;
10786231Stmm		default:		/* unknown option */
10886231Stmm			optlen = ip6_unknown_opt(opt, m,
109152696Smarius			    opt - mtod(m, u_int8_t *));
11086231Stmm			if (optlen == -1)
111117119Stmm				return (IPPROTO_DONE);
112117119Stmm			optlen += 2;
113117119Stmm			break;
114117119Stmm		}
115117119Stmm	}
116117119Stmm
117225931Smarius	*offp = off;
118167308Smarius	return (dstopts->ip6d_nxt);
119117119Stmm
120117119Stmm  bad:
121117119Stmm	m_freem(m);
122117119Stmm	return (IPPROTO_DONE);
123133589Smarius}
124220039Smarius