Deleted Added
full compact
ip6_forward.c (54263) ip6_forward.c (55009)
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/netinet6/ip6_forward.c 54263 1999-12-07 17:39:16Z shin $
29 * $FreeBSD: head/sys/netinet6/ip6_forward.c 55009 1999-12-22 19:13:38Z shin $
30 */
31
30 */
31
32#include "opt_key.h"
32#include "opt_ipsec.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/malloc.h>
37#include <sys/mbuf.h>
38#include <sys/domain.h>
39#include <sys/protosw.h>
40#include <sys/socket.h>
41#include <sys/errno.h>
42#include <sys/time.h>
43#include <sys/kernel.h>
44#include <sys/syslog.h>
45
46#include <net/if.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/in_var.h>
51#include <netinet6/ip6.h>
52#include <netinet6/ip6_var.h>
53#include <netinet6/icmp6.h>
54#include <netinet6/nd6.h>
55
56#ifdef IPSEC_IPV6FWD
57#include <netinet6/ipsec.h>
58#include <netinet6/ipsec6.h>
59#include <netkey/key.h>
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/malloc.h>
37#include <sys/mbuf.h>
38#include <sys/domain.h>
39#include <sys/protosw.h>
40#include <sys/socket.h>
41#include <sys/errno.h>
42#include <sys/time.h>
43#include <sys/kernel.h>
44#include <sys/syslog.h>
45
46#include <net/if.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/in_var.h>
51#include <netinet6/ip6.h>
52#include <netinet6/ip6_var.h>
53#include <netinet6/icmp6.h>
54#include <netinet6/nd6.h>
55
56#ifdef IPSEC_IPV6FWD
57#include <netinet6/ipsec.h>
58#include <netinet6/ipsec6.h>
59#include <netkey/key.h>
60#ifdef KEY_DEBUG
60#ifdef IPSEC_DEBUG
61#include <netkey/key_debug.h>
62#else
61#include <netkey/key_debug.h>
62#else
63#define DPRINTF(lev,arg)
64#define DDO(lev, stmt)
65#define DP(x, y, z)
66#endif /* KEY_DEBUG */
63#define KEYDEBUG(lev,arg)
64#endif
67#endif /* IPSEC_IPV6FWD */
68
69#ifdef IPV6FIREWALL
70#include <netinet6/ip6_fw.h>
71#endif
72
73#include <net/net_osdep.h>
74
75struct route_in6 ip6_forward_rt;
76
77/*
78 * Forward a packet. If some error occurs return the sender
79 * an icmp packet. Note we can't always generate a meaningful
80 * icmp message because icmp doesn't have a large enough repertoire
81 * of codes and types.
82 *
83 * If not forwarding, just drop the packet. This could be confusing
84 * if ipforwarding was zero but some routing protocol was advancing
85 * us as a gateway to somewhere. However, we must let the routing
86 * protocol deal with that.
87 *
88 */
89
90void
91ip6_forward(m, srcrt)
92 struct mbuf *m;
93 int srcrt;
94{
95 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
96 register struct sockaddr_in6 *dst;
97 register struct rtentry *rt;
98 int error, type = 0, code = 0;
99 struct mbuf *mcopy;
100#ifdef IPSEC_IPV6FWD
101 struct secpolicy *sp = NULL;
102#endif
103
104#ifdef IPSEC_IPV6FWD
105 /*
106 * Check AH/ESP integrity.
107 */
108 /*
109 * Don't increment ip6s_cantforward because this is the check
110 * before forwarding packet actually.
111 */
112 if (ipsec6_in_reject(m, NULL)) {
113 ipsec6stat.in_polvio++;
114 m_freem(m);
115 return;
116 }
117#endif /*IPSEC_IPV6FWD*/
118
119 if (m->m_flags & (M_BCAST|M_MCAST) ||
120 in6_canforward(&ip6->ip6_src, &ip6->ip6_dst) == 0) {
121 ip6stat.ip6s_cantforward++;
122 ip6stat.ip6s_badscope++;
123 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
124 if (ip6_log_time + ip6_log_interval < time_second) {
125 char addr[INET6_ADDRSTRLEN];
126 ip6_log_time = time_second;
127 strncpy(addr, ip6_sprintf(&ip6->ip6_src), sizeof(addr));
128 log(LOG_DEBUG,
129 "cannot forward "
130 "from %s to %s nxt %d received on %s\n",
131 addr, ip6_sprintf(&ip6->ip6_dst),
132 ip6->ip6_nxt,
133 if_name(m->m_pkthdr.rcvif));
134 }
135 m_freem(m);
136 return;
137 }
138
139 if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
140 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
141 icmp6_error(m, ICMP6_TIME_EXCEEDED,
142 ICMP6_TIME_EXCEED_TRANSIT, 0);
143 return;
144 }
145 ip6->ip6_hlim -= IPV6_HLIMDEC;
146
147#ifdef IPSEC_IPV6FWD
148 /* get a security policy for this packet */
149 sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
150 if (sp == NULL) {
151 ipsec6stat.out_inval++;
152 ip6stat.ip6s_cantforward++;
153 /* XXX: any icmp ? */
154 m_freem(m);
155 return;
156 }
157
158 error = 0;
159
160 /* check policy */
161 switch (sp->policy) {
162 case IPSEC_POLICY_DISCARD:
163 /*
164 * This packet is just discarded.
165 */
166 ipsec6stat.out_polvio++;
167 ip6stat.ip6s_cantforward++;
168 key_freesp(sp);
169 /* XXX: any icmp ? */
170 m_freem(m);
171 return;
172
173 case IPSEC_POLICY_BYPASS:
174 case IPSEC_POLICY_NONE:
175 /* no need to do IPsec. */
176 key_freesp(sp);
177 goto skip_ipsec;
178
179 case IPSEC_POLICY_IPSEC:
180 if (sp->req == NULL) {
181 /* XXX should be panic ? */
182 printf("ip6_forward: No IPsec request specified.\n");
183 ip6stat.ip6s_cantforward++;
184 key_freesp(sp);
185 /* XXX: any icmp ? */
186 m_freem(m);
187 return;
188 }
189 /* do IPsec */
190 break;
191
192 case IPSEC_POLICY_ENTRUST:
193 default:
194 /* should be panic ?? */
195 printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
196 key_freesp(sp);
197 goto skip_ipsec;
198 }
199
200 {
201 struct ipsec_output_state state;
202
203 /*
204 * All the extension headers will become inaccessible
205 * (since they can be encrypted).
206 * Don't panic, we need no more updates to extension headers
207 * on inner IPv6 packet (since they are now encapsulated).
208 *
209 * IPv6 [ESP|AH] IPv6 [extension headers] payload
210 */
211 bzero(&state, sizeof(state));
212 state.m = m;
213 state.ro = NULL; /* update at ipsec6_output_tunnel() */
214 state.dst = NULL; /* update at ipsec6_output_tunnel() */
215
216 error = ipsec6_output_tunnel(&state, sp, 0);
217
218 m = state.m;
219 /* XXX allocate a route (ro, dst) again later */
220 key_freesp(sp);
221
222 if (error) {
223 /* mbuf is already reclaimed in ipsec6_output_tunnel. */
224 switch (error) {
225 case EHOSTUNREACH:
226 case ENETUNREACH:
227 case EMSGSIZE:
228 case ENOBUFS:
229 case ENOMEM:
230 break;
231 default:
232 printf("ip6_output (ipsec): error code %d\n", error);
233 /*fall through*/
234 case ENOENT:
235 /* don't show these error codes to the user */
236 break;
237 }
238 ip6stat.ip6s_cantforward++;
239 /* XXX: any icmp ? */
240 m_freem(m);
241 return;
242 }
243 }
244 skip_ipsec:
245#endif /* IPSEC_IPV6FWD */
246
247 dst = &ip6_forward_rt.ro_dst;
248 if (!srcrt) {
249 /*
250 * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
251 */
252 if (ip6_forward_rt.ro_rt == 0 ||
253 (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) {
254 if (ip6_forward_rt.ro_rt) {
255 RTFREE(ip6_forward_rt.ro_rt);
256 ip6_forward_rt.ro_rt = 0;
257 }
258 /* this probably fails but give it a try again */
259 rtalloc_ign((struct route *)&ip6_forward_rt,
260 RTF_PRCLONING);
261 }
262
263 if (ip6_forward_rt.ro_rt == 0) {
264 ip6stat.ip6s_noroute++;
265 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
266 icmp6_error(m, ICMP6_DST_UNREACH,
267 ICMP6_DST_UNREACH_NOROUTE, 0);
268 return;
269 }
270 } else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
271 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
272 if (ip6_forward_rt.ro_rt) {
273 RTFREE(ip6_forward_rt.ro_rt);
274 ip6_forward_rt.ro_rt = 0;
275 }
276 bzero(dst, sizeof(*dst));
277 dst->sin6_len = sizeof(struct sockaddr_in6);
278 dst->sin6_family = AF_INET6;
279 dst->sin6_addr = ip6->ip6_dst;
280
281 rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
282 if (ip6_forward_rt.ro_rt == 0) {
283 ip6stat.ip6s_noroute++;
284 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
285 icmp6_error(m, ICMP6_DST_UNREACH,
286 ICMP6_DST_UNREACH_NOROUTE, 0);
287 return;
288 }
289 }
290 rt = ip6_forward_rt.ro_rt;
291 if (m->m_pkthdr.len > rt->rt_ifp->if_mtu){
292 in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
293 icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, rt->rt_ifp->if_mtu);
294 return;
295 }
296
297 if (rt->rt_flags & RTF_GATEWAY)
298 dst = (struct sockaddr_in6 *)rt->rt_gateway;
299 /*
300 * Save at most 528 bytes of the packet in case
301 * we need to generate an ICMP6 message to the src.
302 * Thanks to M_EXT, in most cases copy will not occur.
303 */
304 mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
305
306 /*
307 * If we are to forward the packet using the same interface
308 * as one we got the packet from, perhaps we should send a redirect
309 * to sender to shortcut a hop.
310 * Only send redirect if source is sending directly to us,
311 * and if packet was not source routed (or has any options).
312 * Also, don't send redirect if forwarding using a route
313 * modified by a redirect.
314 */
315 if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
316 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0)
317 type = ND_REDIRECT;
318
319#ifdef IPV6FIREWALL
320 /*
321 * Check with the firewall...
322 */
323 if (ip6_fw_chk_ptr) {
324 u_short port = 0;
325 /* If ipfw says divert, we have to just drop packet */
326 if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &port, &m)) {
327 m_freem(m);
328 goto freecopy;
329 }
330 if (!m)
331 goto freecopy;
332 }
333#endif
334
335 error = nd6_output(rt->rt_ifp, m, dst, rt);
336 if (error) {
337 in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
338 ip6stat.ip6s_cantforward++;
339 } else {
340 ip6stat.ip6s_forward++;
341 in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
342 if (type)
343 ip6stat.ip6s_redirectsent++;
344 else {
345 if (mcopy)
346 goto freecopy;
347 }
348 }
349 if (mcopy == NULL)
350 return;
351
352 switch (error) {
353 case 0:
354 if (type == ND_REDIRECT) {
355 icmp6_redirect_output(mcopy, rt);
356 return;
357 }
358 goto freecopy;
359
360 case EMSGSIZE:
361 /* xxx MTU is constant in PPP? */
362 goto freecopy;
363
364 case ENOBUFS:
365 /* Tell source to slow down like source quench in IP? */
366 goto freecopy;
367
368 case ENETUNREACH: /* shouldn't happen, checked above */
369 case EHOSTUNREACH:
370 case ENETDOWN:
371 case EHOSTDOWN:
372 default:
373 type = ICMP6_DST_UNREACH;
374 code = ICMP6_DST_UNREACH_ADDR;
375 break;
376 }
377 icmp6_error(mcopy, type, code, 0);
378 return;
379
380 freecopy:
381 m_freem(mcopy);
382 return;
383}
65#endif /* IPSEC_IPV6FWD */
66
67#ifdef IPV6FIREWALL
68#include <netinet6/ip6_fw.h>
69#endif
70
71#include <net/net_osdep.h>
72
73struct route_in6 ip6_forward_rt;
74
75/*
76 * Forward a packet. If some error occurs return the sender
77 * an icmp packet. Note we can't always generate a meaningful
78 * icmp message because icmp doesn't have a large enough repertoire
79 * of codes and types.
80 *
81 * If not forwarding, just drop the packet. This could be confusing
82 * if ipforwarding was zero but some routing protocol was advancing
83 * us as a gateway to somewhere. However, we must let the routing
84 * protocol deal with that.
85 *
86 */
87
88void
89ip6_forward(m, srcrt)
90 struct mbuf *m;
91 int srcrt;
92{
93 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
94 register struct sockaddr_in6 *dst;
95 register struct rtentry *rt;
96 int error, type = 0, code = 0;
97 struct mbuf *mcopy;
98#ifdef IPSEC_IPV6FWD
99 struct secpolicy *sp = NULL;
100#endif
101
102#ifdef IPSEC_IPV6FWD
103 /*
104 * Check AH/ESP integrity.
105 */
106 /*
107 * Don't increment ip6s_cantforward because this is the check
108 * before forwarding packet actually.
109 */
110 if (ipsec6_in_reject(m, NULL)) {
111 ipsec6stat.in_polvio++;
112 m_freem(m);
113 return;
114 }
115#endif /*IPSEC_IPV6FWD*/
116
117 if (m->m_flags & (M_BCAST|M_MCAST) ||
118 in6_canforward(&ip6->ip6_src, &ip6->ip6_dst) == 0) {
119 ip6stat.ip6s_cantforward++;
120 ip6stat.ip6s_badscope++;
121 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
122 if (ip6_log_time + ip6_log_interval < time_second) {
123 char addr[INET6_ADDRSTRLEN];
124 ip6_log_time = time_second;
125 strncpy(addr, ip6_sprintf(&ip6->ip6_src), sizeof(addr));
126 log(LOG_DEBUG,
127 "cannot forward "
128 "from %s to %s nxt %d received on %s\n",
129 addr, ip6_sprintf(&ip6->ip6_dst),
130 ip6->ip6_nxt,
131 if_name(m->m_pkthdr.rcvif));
132 }
133 m_freem(m);
134 return;
135 }
136
137 if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
138 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
139 icmp6_error(m, ICMP6_TIME_EXCEEDED,
140 ICMP6_TIME_EXCEED_TRANSIT, 0);
141 return;
142 }
143 ip6->ip6_hlim -= IPV6_HLIMDEC;
144
145#ifdef IPSEC_IPV6FWD
146 /* get a security policy for this packet */
147 sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
148 if (sp == NULL) {
149 ipsec6stat.out_inval++;
150 ip6stat.ip6s_cantforward++;
151 /* XXX: any icmp ? */
152 m_freem(m);
153 return;
154 }
155
156 error = 0;
157
158 /* check policy */
159 switch (sp->policy) {
160 case IPSEC_POLICY_DISCARD:
161 /*
162 * This packet is just discarded.
163 */
164 ipsec6stat.out_polvio++;
165 ip6stat.ip6s_cantforward++;
166 key_freesp(sp);
167 /* XXX: any icmp ? */
168 m_freem(m);
169 return;
170
171 case IPSEC_POLICY_BYPASS:
172 case IPSEC_POLICY_NONE:
173 /* no need to do IPsec. */
174 key_freesp(sp);
175 goto skip_ipsec;
176
177 case IPSEC_POLICY_IPSEC:
178 if (sp->req == NULL) {
179 /* XXX should be panic ? */
180 printf("ip6_forward: No IPsec request specified.\n");
181 ip6stat.ip6s_cantforward++;
182 key_freesp(sp);
183 /* XXX: any icmp ? */
184 m_freem(m);
185 return;
186 }
187 /* do IPsec */
188 break;
189
190 case IPSEC_POLICY_ENTRUST:
191 default:
192 /* should be panic ?? */
193 printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
194 key_freesp(sp);
195 goto skip_ipsec;
196 }
197
198 {
199 struct ipsec_output_state state;
200
201 /*
202 * All the extension headers will become inaccessible
203 * (since they can be encrypted).
204 * Don't panic, we need no more updates to extension headers
205 * on inner IPv6 packet (since they are now encapsulated).
206 *
207 * IPv6 [ESP|AH] IPv6 [extension headers] payload
208 */
209 bzero(&state, sizeof(state));
210 state.m = m;
211 state.ro = NULL; /* update at ipsec6_output_tunnel() */
212 state.dst = NULL; /* update at ipsec6_output_tunnel() */
213
214 error = ipsec6_output_tunnel(&state, sp, 0);
215
216 m = state.m;
217 /* XXX allocate a route (ro, dst) again later */
218 key_freesp(sp);
219
220 if (error) {
221 /* mbuf is already reclaimed in ipsec6_output_tunnel. */
222 switch (error) {
223 case EHOSTUNREACH:
224 case ENETUNREACH:
225 case EMSGSIZE:
226 case ENOBUFS:
227 case ENOMEM:
228 break;
229 default:
230 printf("ip6_output (ipsec): error code %d\n", error);
231 /*fall through*/
232 case ENOENT:
233 /* don't show these error codes to the user */
234 break;
235 }
236 ip6stat.ip6s_cantforward++;
237 /* XXX: any icmp ? */
238 m_freem(m);
239 return;
240 }
241 }
242 skip_ipsec:
243#endif /* IPSEC_IPV6FWD */
244
245 dst = &ip6_forward_rt.ro_dst;
246 if (!srcrt) {
247 /*
248 * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
249 */
250 if (ip6_forward_rt.ro_rt == 0 ||
251 (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) {
252 if (ip6_forward_rt.ro_rt) {
253 RTFREE(ip6_forward_rt.ro_rt);
254 ip6_forward_rt.ro_rt = 0;
255 }
256 /* this probably fails but give it a try again */
257 rtalloc_ign((struct route *)&ip6_forward_rt,
258 RTF_PRCLONING);
259 }
260
261 if (ip6_forward_rt.ro_rt == 0) {
262 ip6stat.ip6s_noroute++;
263 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
264 icmp6_error(m, ICMP6_DST_UNREACH,
265 ICMP6_DST_UNREACH_NOROUTE, 0);
266 return;
267 }
268 } else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
269 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
270 if (ip6_forward_rt.ro_rt) {
271 RTFREE(ip6_forward_rt.ro_rt);
272 ip6_forward_rt.ro_rt = 0;
273 }
274 bzero(dst, sizeof(*dst));
275 dst->sin6_len = sizeof(struct sockaddr_in6);
276 dst->sin6_family = AF_INET6;
277 dst->sin6_addr = ip6->ip6_dst;
278
279 rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
280 if (ip6_forward_rt.ro_rt == 0) {
281 ip6stat.ip6s_noroute++;
282 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
283 icmp6_error(m, ICMP6_DST_UNREACH,
284 ICMP6_DST_UNREACH_NOROUTE, 0);
285 return;
286 }
287 }
288 rt = ip6_forward_rt.ro_rt;
289 if (m->m_pkthdr.len > rt->rt_ifp->if_mtu){
290 in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
291 icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, rt->rt_ifp->if_mtu);
292 return;
293 }
294
295 if (rt->rt_flags & RTF_GATEWAY)
296 dst = (struct sockaddr_in6 *)rt->rt_gateway;
297 /*
298 * Save at most 528 bytes of the packet in case
299 * we need to generate an ICMP6 message to the src.
300 * Thanks to M_EXT, in most cases copy will not occur.
301 */
302 mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
303
304 /*
305 * If we are to forward the packet using the same interface
306 * as one we got the packet from, perhaps we should send a redirect
307 * to sender to shortcut a hop.
308 * Only send redirect if source is sending directly to us,
309 * and if packet was not source routed (or has any options).
310 * Also, don't send redirect if forwarding using a route
311 * modified by a redirect.
312 */
313 if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
314 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0)
315 type = ND_REDIRECT;
316
317#ifdef IPV6FIREWALL
318 /*
319 * Check with the firewall...
320 */
321 if (ip6_fw_chk_ptr) {
322 u_short port = 0;
323 /* If ipfw says divert, we have to just drop packet */
324 if ((*ip6_fw_chk_ptr)(&ip6, rt->rt_ifp, &port, &m)) {
325 m_freem(m);
326 goto freecopy;
327 }
328 if (!m)
329 goto freecopy;
330 }
331#endif
332
333 error = nd6_output(rt->rt_ifp, m, dst, rt);
334 if (error) {
335 in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
336 ip6stat.ip6s_cantforward++;
337 } else {
338 ip6stat.ip6s_forward++;
339 in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
340 if (type)
341 ip6stat.ip6s_redirectsent++;
342 else {
343 if (mcopy)
344 goto freecopy;
345 }
346 }
347 if (mcopy == NULL)
348 return;
349
350 switch (error) {
351 case 0:
352 if (type == ND_REDIRECT) {
353 icmp6_redirect_output(mcopy, rt);
354 return;
355 }
356 goto freecopy;
357
358 case EMSGSIZE:
359 /* xxx MTU is constant in PPP? */
360 goto freecopy;
361
362 case ENOBUFS:
363 /* Tell source to slow down like source quench in IP? */
364 goto freecopy;
365
366 case ENETUNREACH: /* shouldn't happen, checked above */
367 case EHOSTUNREACH:
368 case ENETDOWN:
369 case EHOSTDOWN:
370 default:
371 type = ICMP6_DST_UNREACH;
372 code = ICMP6_DST_UNREACH_ADDR;
373 break;
374 }
375 icmp6_error(mcopy, type, code, 0);
376 return;
377
378 freecopy:
379 m_freem(mcopy);
380 return;
381}