]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/bsd_tcpip/v2_0/src/sys/netinet6/dest6.c
Initial revision
[karo-tx-redboot.git] / packages / net / bsd_tcpip / v2_0 / src / sys / netinet6 / dest6.c
1 //==========================================================================
2 //
3 //      src/sys/netinet6/dest6.c
4 //
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
7 //
8 // -------------------------------------------
9 //
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.
13 //
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16 //
17 // -------------------------------------------
18 //
19 //####BSDCOPYRIGHTEND####
20 //==========================================================================
21
22 /*      $KAME: dest6.c,v 1.33 2001/10/05 10:01:32 itojun Exp $  */
23
24 /*
25  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26  * All rights reserved.
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
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.
39  *
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
50  * SUCH DAMAGE.
51  */
52
53 #include <sys/param.h>
54 #include <sys/malloc.h>
55 #include <sys/mbuf.h>
56 #include <sys/domain.h>
57 #include <sys/protosw.h>
58 #include <sys/socket.h>
59 #include <sys/errno.h>
60
61 #include <net/if.h>
62 #include <net/route.h>
63
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>
70 #endif
71 #include <netinet/icmp6.h>
72 #ifdef MIP6
73 #include <netinet6/mip6.h>
74 #endif
75
76 /*
77  * Destination options header processing.
78  */
79 int
80 dest6_input(mp, offp, proto)
81         struct mbuf **mp;
82         int *offp, proto;
83 {
84         struct mbuf *m = *mp;
85         int off = *offp, dstoptlen, optlen;
86         struct ip6_dest *dstopts;
87         struct mbuf *n;
88         struct ip6_opt_home_address *haopt = NULL;
89         struct ip6aux *ip6a = NULL;
90         u_int8_t *opt;
91         struct ip6_hdr *ip6;
92
93         ip6 = mtod(m, struct ip6_hdr *);
94
95         /* validation of the length of the header */
96 #ifndef PULLDOWN_TEST
97         IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE);
98         dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
99 #else
100         IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts));
101         if (dstopts == NULL)
102                 return IPPROTO_DONE;
103 #endif
104         dstoptlen = (dstopts->ip6d_len + 1) << 3;
105
106 #ifndef PULLDOWN_TEST
107         IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE);
108         dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
109 #else
110         IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen);
111         if (dstopts == NULL)
112                 return IPPROTO_DONE;
113 #endif
114         off += dstoptlen;
115         dstoptlen -= sizeof(struct ip6_dest);
116         opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest);
117
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++;
123                         goto bad;
124                 }
125
126                 switch (*opt) {
127                 case IP6OPT_PAD1:
128                         optlen = 1;
129                         break;
130                 case IP6OPT_PADN:
131                         optlen = *(opt + 1) + 2;
132                         break;
133                 case IP6OPT_HOME_ADDRESS:
134                         /*
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.
138                          */
139 #if 0
140                         /* be picky about alignment: 8n+6 */
141                         if ((opt - (u_int8_t *)dstopts) % 8 != 6)
142                                 goto bad;
143 #endif
144
145                         /* HA option must appear only once */
146                         n = ip6_addaux(m);
147                         if (!n) {
148                                 /* not enough core */
149                                 goto bad;
150                         }
151                         ip6a = mtod(n, struct ip6aux *);
152                         if ((ip6a->ip6a_flags & IP6A_HASEEN) != 0) {
153                                 /* XXX icmp6 paramprob? */
154                                 goto bad;
155                         }
156
157                         haopt = (struct ip6_opt_home_address *)opt;
158                         optlen = haopt->ip6oh_len + 2;
159
160                         /*
161                          * don't complain even if it is larger,
162                          * we don't support suboptions at this moment.
163                          */
164                         if (optlen < sizeof(*haopt)) {
165                                 ip6stat.ip6s_toosmall++;
166                                 goto bad;
167                         }
168
169                         /* XXX check header ordering */
170
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;
176
177                         /*
178                          * reject invalid home-addresses
179                          */
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++;
187                                 goto bad;
188                         }
189
190                         /*
191                          * Currently, no valid sub-options are
192                          * defined for use in a Home Address option.
193                          */
194
195                         break;
196
197 #ifdef MIP6
198                 case IP6OPT_BINDING_UPDATE:
199                 case IP6OPT_BINDING_ACK:
200                 case IP6OPT_BINDING_REQ:
201                         if (mip6_process_destopt(m, dstopts, opt, dstoptlen)
202                             == -1)
203                                 goto bad;
204                         optlen = *(opt + 1) + 2;
205                         break;
206 #endif /* MIP6 */
207
208                 default:                /* unknown option */
209                         optlen = ip6_unknown_opt(opt, m,
210                             opt - mtod(m, u_int8_t *));
211                         if (optlen == -1)
212                                 return (IPPROTO_DONE);
213                         optlen += 2;
214                         break;
215                 }
216         }
217
218         /* if haopt is non-NULL, we are sure we have seen fresh HA option */
219         if (haopt && ip6a &&
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));
229 #if 0
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);
234 #endif
235                 ip6a->ip6a_flags |= IP6A_SWAP;
236         }
237
238         *offp = off;
239         return (dstopts->ip6d_nxt);
240
241   bad:
242         m_freem(m);
243         return (IPPROTO_DONE);
244 }