1 //==========================================================================
3 // src/sys/netinet6/dest6.c
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
8 // -------------------------------------------
10 // Portions of this software may have been derived from OpenBSD,
11 // FreeBSD or other sources, and are covered by the appropriate
12 // copyright disclaimers included herein.
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
17 // -------------------------------------------
19 //####BSDCOPYRIGHTEND####
20 //==========================================================================
22 /* $KAME: dest6.c,v 1.33 2001/10/05 10:01:32 itojun Exp $ */
25 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26 * All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. Neither the name of the project nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
40 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 #include <sys/param.h>
54 #include <sys/malloc.h>
56 #include <sys/domain.h>
57 #include <sys/protosw.h>
58 #include <sys/socket.h>
59 #include <sys/errno.h>
62 #include <net/route.h>
64 #include <netinet/in.h>
65 #include <netinet/in_var.h>
66 #include <netinet/ip6.h>
67 #include <netinet6/ip6_var.h>
68 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__) && !(defined(__bsdi__) && _BSDI_VERSION >= 199802)
69 #include <netinet6/in6_pcb.h>
71 #include <netinet/icmp6.h>
73 #include <netinet6/mip6.h>
77 * Destination options header processing.
80 dest6_input(mp, offp, proto)
85 int off = *offp, dstoptlen, optlen;
86 struct ip6_dest *dstopts;
88 struct ip6_opt_home_address *haopt = NULL;
89 struct ip6aux *ip6a = NULL;
93 ip6 = mtod(m, struct ip6_hdr *);
95 /* validation of the length of the header */
97 IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE);
98 dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
100 IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts));
104 dstoptlen = (dstopts->ip6d_len + 1) << 3;
106 #ifndef PULLDOWN_TEST
107 IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE);
108 dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
110 IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen);
115 dstoptlen -= sizeof(struct ip6_dest);
116 opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest);
118 /* search header for all options. */
119 for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) {
120 if (*opt != IP6OPT_PAD1 &&
121 (dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) {
122 ip6stat.ip6s_toosmall++;
131 optlen = *(opt + 1) + 2;
133 case IP6OPT_HOME_ADDRESS:
135 * XXX we assume that home address option appear after
136 * AH. if the assumption does not hold, the validation
137 * of AH will fail due to the address swap.
140 /* be picky about alignment: 8n+6 */
141 if ((opt - (u_int8_t *)dstopts) % 8 != 6)
145 /* HA option must appear only once */
148 /* not enough core */
151 ip6a = mtod(n, struct ip6aux *);
152 if ((ip6a->ip6a_flags & IP6A_HASEEN) != 0) {
153 /* XXX icmp6 paramprob? */
157 haopt = (struct ip6_opt_home_address *)opt;
158 optlen = haopt->ip6oh_len + 2;
161 * don't complain even if it is larger,
162 * we don't support suboptions at this moment.
164 if (optlen < sizeof(*haopt)) {
165 ip6stat.ip6s_toosmall++;
169 /* XXX check header ordering */
171 bcopy(haopt->ip6oh_addr, &ip6a->ip6a_home,
172 sizeof(ip6a->ip6a_home));
173 bcopy(&ip6->ip6_src, &ip6a->ip6a_careof,
174 sizeof(ip6a->ip6a_careof));
175 ip6a->ip6a_flags |= IP6A_HASEEN;
178 * reject invalid home-addresses
180 /* XXX linklocal-address is not supported */
181 if (IN6_IS_ADDR_MULTICAST(&ip6a->ip6a_home) ||
182 IN6_IS_ADDR_LINKLOCAL(&ip6a->ip6a_home) ||
183 IN6_IS_ADDR_V4MAPPED(&ip6a->ip6a_home) ||
184 IN6_IS_ADDR_UNSPECIFIED(&ip6a->ip6a_home) ||
185 IN6_IS_ADDR_LOOPBACK(&ip6a->ip6a_home)) {
186 ip6stat.ip6s_badscope++;
191 * Currently, no valid sub-options are
192 * defined for use in a Home Address option.
198 case IP6OPT_BINDING_UPDATE:
199 case IP6OPT_BINDING_ACK:
200 case IP6OPT_BINDING_REQ:
201 if (mip6_process_destopt(m, dstopts, opt, dstoptlen)
204 optlen = *(opt + 1) + 2;
208 default: /* unknown option */
209 optlen = ip6_unknown_opt(opt, m,
210 opt - mtod(m, u_int8_t *));
212 return (IPPROTO_DONE);
218 /* if haopt is non-NULL, we are sure we have seen fresh HA option */
220 (ip6a->ip6a_flags & (IP6A_HASEEN | IP6A_SWAP)) == IP6A_HASEEN) {
221 /* XXX should we do this at all? do it now or later? */
222 /* XXX interaction with 2292bis IPV6_RECVDSTOPT */
223 /* XXX interaction with ipsec - should be okay */
224 /* XXX icmp6 responses is modified - which is bad */
225 bcopy(&ip6a->ip6a_careof, haopt->ip6oh_addr,
226 sizeof(haopt->ip6oh_addr));
227 bcopy(&ip6a->ip6a_home, &ip6->ip6_src,
228 sizeof(ip6->ip6_src));
230 /* XXX linklocal address is (currently) not supported */
231 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
232 ip6->ip6_src.s6_addr16[1]
233 = htons(m->m_pkthdr.rcvif->if_index);
235 ip6a->ip6a_flags |= IP6A_SWAP;
239 return (dstopts->ip6d_nxt);
243 return (IPPROTO_DONE);