1139826Simp/*-
253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. Neither the name of the project nor the names of its contributors
1453541Sshin *    may be used to endorse or promote products derived from this software
1553541Sshin *    without specific prior written permission.
1653541Sshin *
1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2753541Sshin * SUCH DAMAGE.
28174510Sobrien *
29174510Sobrien *	$KAME: dest6.c,v 1.59 2003/07/11 13:21:16 t-momose Exp $
3053541Sshin */
3153541Sshin
32174510Sobrien#include <sys/cdefs.h>
33174510Sobrien__FBSDID("$FreeBSD$");
34174510Sobrien
3562587Sitojun#include "opt_inet.h"
3662587Sitojun#include "opt_inet6.h"
3762587Sitojun
3853541Sshin#include <sys/param.h>
3953541Sshin#include <sys/systm.h>
4078064Sume#include <sys/malloc.h>
4153541Sshin#include <sys/mbuf.h>
4253541Sshin#include <sys/domain.h>
4353541Sshin#include <sys/protosw.h>
4453541Sshin#include <sys/socket.h>
4553541Sshin#include <sys/errno.h>
4653541Sshin#include <sys/time.h>
4778064Sume#include <sys/kernel.h>
4853541Sshin
4953541Sshin#include <net/if.h>
5053541Sshin#include <net/route.h>
5153541Sshin
5253541Sshin#include <netinet/in.h>
5353541Sshin#include <netinet/in_var.h>
5462587Sitojun#include <netinet/ip6.h>
5553541Sshin#include <netinet6/ip6_var.h>
5662587Sitojun#include <netinet/icmp6.h>
5753541Sshin
5853541Sshin/*
5953541Sshin * Destination options header processing.
6053541Sshin */
6153541Sshinint
62171259Sdelphijdest6_input(struct mbuf **mp, int *offp, int proto)
6353541Sshin{
6478064Sume	struct mbuf *m = *mp;
6553541Sshin	int off = *offp, dstoptlen, optlen;
6653541Sshin	struct ip6_dest *dstopts;
6753541Sshin	u_int8_t *opt;
6853541Sshin
6953541Sshin	/* validation of the length of the header */
7062587Sitojun#ifndef PULLDOWN_TEST
7153541Sshin	IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE);
7253541Sshin	dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
7362587Sitojun#else
7462587Sitojun	IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts));
7562587Sitojun	if (dstopts == NULL)
7662587Sitojun		return IPPROTO_DONE;
7762587Sitojun#endif
7853541Sshin	dstoptlen = (dstopts->ip6d_len + 1) << 3;
7953541Sshin
8062587Sitojun#ifndef PULLDOWN_TEST
8153541Sshin	IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE);
8253541Sshin	dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
8362587Sitojun#else
8462587Sitojun	IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen);
8562587Sitojun	if (dstopts == NULL)
8662587Sitojun		return IPPROTO_DONE;
8762587Sitojun#endif
8853541Sshin	off += dstoptlen;
8953541Sshin	dstoptlen -= sizeof(struct ip6_dest);
9053541Sshin	opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest);
9153541Sshin
9253541Sshin	/* search header for all options. */
9353541Sshin	for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) {
9473059Skris		if (*opt != IP6OPT_PAD1 &&
9573059Skris		    (dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) {
96250044Sae			IP6STAT_INC(ip6s_toosmall);
9773059Skris			goto bad;
9873059Skris		}
9973059Skris
10073059Skris		switch (*opt) {
10173059Skris		case IP6OPT_PAD1:
10273059Skris			optlen = 1;
10373059Skris			break;
10473059Skris		case IP6OPT_PADN:
10573059Skris			optlen = *(opt + 1) + 2;
10673059Skris			break;
10778064Sume		default:		/* unknown option */
10878064Sume			optlen = ip6_unknown_opt(opt, m,
10978064Sume			    opt - mtod(m, u_int8_t *));
11078064Sume			if (optlen == -1)
11178064Sume				return (IPPROTO_DONE);
11278064Sume			optlen += 2;
11378064Sume			break;
11453541Sshin		}
11553541Sshin	}
11653541Sshin
11753541Sshin	*offp = off;
11878064Sume	return (dstopts->ip6d_nxt);
11953541Sshin
12053541Sshin  bad:
12153541Sshin	m_freem(m);
12278064Sume	return (IPPROTO_DONE);
12353541Sshin}
124