]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ip6_forward.c
xnu-1504.9.37.tar.gz
[apple/xnu.git] / bsd / netinet6 / ip6_forward.c
CommitLineData
b0d623f7
A
1/*
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
55e303ae 29/* $FreeBSD: src/sys/netinet6/ip6_forward.c,v 1.16 2002/10/16 02:25:05 sam Exp $ */
9bccf70c 30/* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $ */
1c79356b
A
31
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
1c79356b
A
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/malloc.h>
65#include <sys/mbuf.h>
66#include <sys/domain.h>
67#include <sys/protosw.h>
68#include <sys/socket.h>
69#include <sys/errno.h>
70#include <sys/time.h>
71#include <sys/kernel.h>
72#include <sys/syslog.h>
73
74#include <net/if.h>
75#include <net/route.h>
76
77#include <netinet/in.h>
78#include <netinet/in_var.h>
9bccf70c
A
79#include <netinet/in_systm.h>
80#include <netinet/ip.h>
1c79356b 81#include <netinet/ip_var.h>
9bccf70c 82#include <netinet6/in6_var.h>
1c79356b
A
83#include <netinet/ip6.h>
84#include <netinet6/ip6_var.h>
85#include <netinet/icmp6.h>
86#include <netinet6/nd6.h>
87
9bccf70c
A
88#include <netinet/in_pcb.h>
89
90#if IPSEC
1c79356b 91#include <netinet6/ipsec.h>
9bccf70c
A
92#if INET6
93#include <netinet6/ipsec6.h>
94#endif
1c79356b 95#include <netkey/key.h>
9bccf70c
A
96extern int ipsec_bypass;
97#endif /* IPSEC */
2d21ac55 98extern lck_mtx_t *ip6_mutex;
1c79356b 99
1c79356b 100#include <netinet6/ip6_fw.h>
1c79356b
A
101
102#include <net/net_osdep.h>
103
b0d623f7
A
104#if PF
105#include <net/pfvar.h>
106#endif /* PF */
107
1c79356b
A
108/*
109 * Forward a packet. If some error occurs return the sender
110 * an icmp packet. Note we can't always generate a meaningful
111 * icmp message because icmp doesn't have a large enough repertoire
112 * of codes and types.
113 *
114 * If not forwarding, just drop the packet. This could be confusing
115 * if ipforwarding was zero but some routing protocol was advancing
116 * us as a gateway to somewhere. However, we must let the routing
117 * protocol deal with that.
118 *
119 */
120
121void
2d21ac55
A
122ip6_forward(struct mbuf *m, struct route_in6 *ip6forward_rt,
123 int srcrt, int locked)
1c79356b
A
124{
125 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
9bccf70c
A
126 struct sockaddr_in6 *dst;
127 struct rtentry *rt;
1c79356b
A
128 int error, type = 0, code = 0;
129 struct mbuf *mcopy = NULL;
b0d623f7 130 struct ifnet *ifp, *origifp; /* maybe unnecessary */
9bccf70c 131#if IPSEC
1c79356b
A
132 struct secpolicy *sp = NULL;
133#endif
91447636 134 struct timeval timenow;
2d21ac55 135 int tunneledv4 = 0;
91447636
A
136
137 getmicrotime(&timenow);
138
1c79356b 139
9bccf70c 140#if IPSEC
1c79356b
A
141 /*
142 * Check AH/ESP integrity.
143 */
144 /*
145 * Don't increment ip6s_cantforward because this is the check
146 * before forwarding packet actually.
147 */
91447636 148 if (ipsec_bypass == 0) {
91447636 149 if (ipsec6_in_reject(m, NULL)) {
2d21ac55 150 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
91447636
A
151 m_freem(m);
152 return;
153 }
1c79356b 154 }
9bccf70c 155#endif /*IPSEC*/
1c79356b 156
9bccf70c
A
157 /*
158 * Do not forward packets to multicast destination (should be handled
159 * by ip6_mforward().
160 * Do not forward packets with unspecified source. It was discussed
161 * in July 2000, on ipngwg mailing list.
162 */
1c79356b 163 if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
9bccf70c
A
164 IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
165 IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1c79356b
A
166 ip6stat.ip6s_cantforward++;
167 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
91447636
A
168 if (ip6_log_time + ip6_log_interval < timenow.tv_sec) {
169 ip6_log_time = timenow.tv_sec;
1c79356b
A
170 log(LOG_DEBUG,
171 "cannot forward "
172 "from %s to %s nxt %d received on %s\n",
173 ip6_sprintf(&ip6->ip6_src),
174 ip6_sprintf(&ip6->ip6_dst),
175 ip6->ip6_nxt,
176 if_name(m->m_pkthdr.rcvif));
177 }
178 m_freem(m);
179 return;
180 }
181
182 if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
183 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
91447636
A
184 if (locked)
185 lck_mtx_unlock(ip6_mutex);
1c79356b
A
186 icmp6_error(m, ICMP6_TIME_EXCEEDED,
187 ICMP6_TIME_EXCEED_TRANSIT, 0);
91447636
A
188 if (locked)
189 lck_mtx_lock(ip6_mutex);
1c79356b
A
190 return;
191 }
192 ip6->ip6_hlim -= IPV6_HLIMDEC;
193
194 /*
195 * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
196 * size of IPv6 + ICMPv6 headers) bytes of the packet in case
197 * we need to generate an ICMP6 message to the src.
198 * Thanks to M_EXT, in most cases copy will not occur.
199 *
200 * It is important to save it before IPsec processing as IPsec
201 * processing may modify the mbuf.
202 */
203 mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
204
9bccf70c
A
205#if IPSEC
206 if (ipsec_bypass != 0)
207 goto skip_ipsec;
1c79356b 208 /* get a security policy for this packet */
9bccf70c
A
209 sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
210 &error);
1c79356b 211 if (sp == NULL) {
2d21ac55 212 IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
1c79356b
A
213 ip6stat.ip6s_cantforward++;
214 if (mcopy) {
215#if 0
216 /* XXX: what icmp ? */
217#else
218 m_freem(mcopy);
219#endif
220 }
221 m_freem(m);
222 return;
223 }
224
225 error = 0;
226
227 /* check policy */
228 switch (sp->policy) {
229 case IPSEC_POLICY_DISCARD:
2d21ac55 230 case IPSEC_POLICY_GENERATE:
1c79356b
A
231 /*
232 * This packet is just discarded.
233 */
2d21ac55 234 IPSEC_STAT_INCREMENT(ipsec6stat.out_polvio);
1c79356b 235 ip6stat.ip6s_cantforward++;
2d21ac55 236 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b
A
237 if (mcopy) {
238#if 0
239 /* XXX: what icmp ? */
240#else
241 m_freem(mcopy);
242#endif
243 }
244 m_freem(m);
245 return;
246
247 case IPSEC_POLICY_BYPASS:
248 case IPSEC_POLICY_NONE:
249 /* no need to do IPsec. */
2d21ac55 250 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b 251 goto skip_ipsec;
9bccf70c 252
1c79356b
A
253 case IPSEC_POLICY_IPSEC:
254 if (sp->req == NULL) {
255 /* XXX should be panic ? */
256 printf("ip6_forward: No IPsec request specified.\n");
257 ip6stat.ip6s_cantforward++;
2d21ac55 258 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b
A
259 if (mcopy) {
260#if 0
261 /* XXX: what icmp ? */
262#else
263 m_freem(mcopy);
264#endif
265 }
266 m_freem(m);
267 return;
268 }
269 /* do IPsec */
270 break;
271
272 case IPSEC_POLICY_ENTRUST:
273 default:
274 /* should be panic ?? */
275 printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
2d21ac55 276 key_freesp(sp, KEY_SADB_UNLOCKED);
1c79356b
A
277 goto skip_ipsec;
278 }
279
280 {
281 struct ipsec_output_state state;
282
283 /*
284 * All the extension headers will become inaccessible
285 * (since they can be encrypted).
286 * Don't panic, we need no more updates to extension headers
287 * on inner IPv6 packet (since they are now encapsulated).
288 *
289 * IPv6 [ESP|AH] IPv6 [extension headers] payload
290 */
291 bzero(&state, sizeof(state));
292 state.m = m;
293 state.ro = NULL; /* update at ipsec6_output_tunnel() */
294 state.dst = NULL; /* update at ipsec6_output_tunnel() */
295
13fec989 296 if (locked)
2d21ac55
A
297 lck_mtx_unlock(ip6_mutex);
298 error = ipsec6_output_tunnel(&state, sp, 0, &tunneledv4);
299 if (locked)
300 lck_mtx_lock(ip6_mutex);
301 key_freesp(sp, KEY_SADB_UNLOCKED);
302 if (tunneledv4)
303 return; /* packet is gone - sent over IPv4 */
304
1c79356b 305 m = state.m;
1c79356b
A
306 if (error) {
307 /* mbuf is already reclaimed in ipsec6_output_tunnel. */
308 switch (error) {
309 case EHOSTUNREACH:
310 case ENETUNREACH:
311 case EMSGSIZE:
312 case ENOBUFS:
313 case ENOMEM:
314 break;
315 default:
316 printf("ip6_output (ipsec): error code %d\n", error);
55e303ae 317 /* fall through */
1c79356b
A
318 case ENOENT:
319 /* don't show these error codes to the user */
320 break;
321 }
322 ip6stat.ip6s_cantforward++;
323 if (mcopy) {
324#if 0
325 /* XXX: what icmp ? */
326#else
327 m_freem(mcopy);
328#endif
329 }
330 m_freem(m);
331 return;
332 }
333 }
334 skip_ipsec:
9bccf70c
A
335#endif /* IPSEC */
336
b0d623f7
A
337 /*
338 * If "locked", ip6forward_rt points to the globally defined
339 * struct route cache which requires ip6_mutex, e.g. when this
340 * is called from ip6_input(). Else the caller is responsible
341 * for the struct route and its serialization (if needed), e.g.
342 * when this is called from ip6_rthdr0().
343 */
344 if (locked)
345 lck_mtx_assert(ip6_mutex, LCK_MTX_ASSERT_OWNED);
2d21ac55 346 dst = (struct sockaddr_in6 *)&ip6forward_rt->ro_dst;
b0d623f7
A
347 if ((rt = ip6forward_rt->ro_rt) != NULL) {
348 RT_LOCK(rt);
349 /* Take an extra ref for ourselves */
350 RT_ADDREF_LOCKED(rt);
351 }
352
1c79356b
A
353 if (!srcrt) {
354 /*
2d21ac55 355 * ip6forward_rt->ro_dst.sin6_addr is equal to ip6->ip6_dst
1c79356b 356 */
b0d623f7
A
357 if (rt == NULL || !(rt->rt_flags & RTF_UP) ||
358 rt->generation_id != route_generation) {
359 if (rt != NULL) {
360 /* Release extra ref */
361 RT_REMREF_LOCKED(rt);
362 RT_UNLOCK(rt);
363 rtfree(rt);
364 ip6forward_rt->ro_rt = NULL;
1c79356b
A
365 }
366 /* this probably fails but give it a try again */
2d21ac55 367 rtalloc_ign((struct route *)ip6forward_rt,
b0d623f7
A
368 RTF_PRCLONING);
369 if ((rt = ip6forward_rt->ro_rt) != NULL) {
370 RT_LOCK(rt);
371 /* Take an extra ref for ourselves */
372 RT_ADDREF_LOCKED(rt);
373 }
1c79356b 374 }
9bccf70c 375
b0d623f7 376 if (rt == NULL) {
1c79356b 377 ip6stat.ip6s_noroute++;
9bccf70c 378 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
1c79356b 379 if (mcopy) {
91447636
A
380 if (locked)
381 lck_mtx_unlock(ip6_mutex);
1c79356b
A
382 icmp6_error(mcopy, ICMP6_DST_UNREACH,
383 ICMP6_DST_UNREACH_NOROUTE, 0);
91447636
A
384 if (locked)
385 lck_mtx_lock(ip6_mutex);
1c79356b
A
386 }
387 m_freem(m);
388 return;
389 }
b0d623f7
A
390 RT_LOCK_ASSERT_HELD(rt);
391 } else if (rt == NULL || !(rt->rt_flags & RTF_UP) ||
392 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr) ||
393 rt->generation_id != route_generation) {
394 if (rt != NULL) {
395 /* Release extra ref */
396 RT_REMREF_LOCKED(rt);
397 RT_UNLOCK(rt);
398 rtfree(rt);
399 ip6forward_rt->ro_rt = NULL;
1c79356b
A
400 }
401 bzero(dst, sizeof(*dst));
402 dst->sin6_len = sizeof(struct sockaddr_in6);
403 dst->sin6_family = AF_INET6;
404 dst->sin6_addr = ip6->ip6_dst;
405
b0d623f7
A
406 rtalloc_ign((struct route *)ip6forward_rt, RTF_PRCLONING);
407 if ((rt = ip6forward_rt->ro_rt) == NULL) {
1c79356b 408 ip6stat.ip6s_noroute++;
9bccf70c 409 in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
1c79356b 410 if (mcopy) {
91447636
A
411 if (locked)
412 lck_mtx_unlock(ip6_mutex);
1c79356b 413 icmp6_error(mcopy, ICMP6_DST_UNREACH,
b0d623f7 414 ICMP6_DST_UNREACH_NOROUTE, 0);
91447636
A
415 if (locked)
416 lck_mtx_lock(ip6_mutex);
1c79356b
A
417 }
418 m_freem(m);
419 return;
420 }
b0d623f7
A
421 RT_LOCK(rt);
422 /* Take an extra ref for ourselves */
423 RT_ADDREF_LOCKED(rt);
1c79356b 424 }
1c79356b
A
425
426 /*
427 * Scope check: if a packet can't be delivered to its destination
428 * for the reason that the destination is beyond the scope of the
429 * source address, discard the packet and return an icmp6 destination
430 * unreachable error with Code 2 (beyond scope of source address).
55e303ae 431 * [draft-ietf-ipngwg-icmp-v3-02.txt, Section 3.1]
1c79356b
A
432 */
433 if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
434 in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
435 ip6stat.ip6s_cantforward++;
436 ip6stat.ip6s_badscope++;
437 in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
438
91447636
A
439 if (ip6_log_time + ip6_log_interval < timenow.tv_sec) {
440 ip6_log_time = timenow.tv_sec;
1c79356b
A
441 log(LOG_DEBUG,
442 "cannot forward "
443 "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
444 ip6_sprintf(&ip6->ip6_src),
445 ip6_sprintf(&ip6->ip6_dst),
446 ip6->ip6_nxt,
447 if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
448 }
b0d623f7
A
449 /* Release extra ref */
450 RT_REMREF_LOCKED(rt);
451 RT_UNLOCK(rt);
91447636
A
452 if (mcopy) {
453 if (locked)
454 lck_mtx_unlock(ip6_mutex);
1c79356b
A
455 icmp6_error(mcopy, ICMP6_DST_UNREACH,
456 ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
91447636
A
457 if (locked)
458 lck_mtx_lock(ip6_mutex);
459 }
1c79356b
A
460 m_freem(m);
461 return;
462 }
463
464 if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
465 in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
466 if (mcopy) {
b0d623f7 467 uint32_t mtu;
9bccf70c 468#if IPSEC
2d21ac55 469 struct secpolicy *sp2;
1c79356b
A
470 int ipsecerror;
471 size_t ipsechdrsiz;
472#endif
473
474 mtu = rt->rt_ifp->if_mtu;
55e303ae 475#if IPSEC
1c79356b
A
476 /*
477 * When we do IPsec tunnel ingress, we need to play
478 * with if_mtu value (decrement IPsec header size
479 * from mtu value). The code is much simpler than v4
480 * case, as we have the outgoing interface for
481 * encapsulated packet as "rt->rt_ifp".
482 */
2d21ac55 483 sp2 = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
1c79356b 484 IP_FORWARDING, &ipsecerror);
2d21ac55 485 if (sp2) {
1c79356b
A
486 ipsechdrsiz = ipsec6_hdrsiz(mcopy,
487 IPSEC_DIR_OUTBOUND, NULL);
488 if (ipsechdrsiz < mtu)
489 mtu -= ipsechdrsiz;
2d21ac55 490 key_freesp(sp2, KEY_SADB_UNLOCKED);
1c79356b 491 }
1c79356b
A
492 /*
493 * if mtu becomes less than minimum MTU,
494 * tell minimum MTU (and I'll need to fragment it).
495 */
496 if (mtu < IPV6_MMTU)
497 mtu = IPV6_MMTU;
498#endif
b0d623f7
A
499 /* Release extra ref */
500 RT_REMREF_LOCKED(rt);
501 RT_UNLOCK(rt);
91447636
A
502 if (locked)
503 lck_mtx_unlock(ip6_mutex);
1c79356b 504 icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
91447636
A
505 if (locked)
506 lck_mtx_lock(ip6_mutex);
b0d623f7
A
507 } else {
508 /* Release extra ref */
509 RT_REMREF_LOCKED(rt);
510 RT_UNLOCK(rt);
1c79356b
A
511 }
512 m_freem(m);
513 return;
514 }
515
516 if (rt->rt_flags & RTF_GATEWAY)
517 dst = (struct sockaddr_in6 *)rt->rt_gateway;
518
519 /*
520 * If we are to forward the packet using the same interface
521 * as one we got the packet from, perhaps we should send a redirect
522 * to sender to shortcut a hop.
523 * Only send redirect if source is sending directly to us,
524 * and if packet was not source routed (or has any options).
525 * Also, don't send redirect if forwarding using a route
526 * modified by a redirect.
527 */
528 if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
9bccf70c
A
529 (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
530 if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) {
531 /*
532 * If the incoming interface is equal to the outgoing
533 * one, and the link attached to the interface is
534 * point-to-point, then it will be highly probable
535 * that a routing loop occurs. Thus, we immediately
536 * drop the packet and send an ICMPv6 error message.
537 *
538 * type/code is based on suggestion by Rich Draves.
539 * not sure if it is the best pick.
540 */
b0d623f7
A
541 RT_REMREF_LOCKED(rt); /* Release extra ref */
542 RT_UNLOCK(rt);
91447636
A
543 if (locked)
544 lck_mtx_unlock(ip6_mutex);
9bccf70c
A
545 icmp6_error(mcopy, ICMP6_DST_UNREACH,
546 ICMP6_DST_UNREACH_ADDR, 0);
91447636
A
547 if (locked)
548 lck_mtx_lock(ip6_mutex);
9bccf70c
A
549 m_freem(m);
550 return;
551 }
1c79356b 552 type = ND_REDIRECT;
9bccf70c 553 }
1c79356b 554
7e4a7d39 555#if IPFW2
1c79356b
A
556 /*
557 * Check with the firewall...
558 */
9bccf70c 559 if (ip6_fw_enable && ip6_fw_chk_ptr) {
1c79356b 560 u_short port = 0;
b0d623f7
A
561 ifp = rt->rt_ifp;
562 /* Drop the lock but retain the extra ref */
563 RT_UNLOCK(rt);
1c79356b 564 /* If ipfw says divert, we have to just drop packet */
b0d623f7 565 if (ip6_fw_chk_ptr(&ip6, ifp, &port, &m)) {
1c79356b
A
566 m_freem(m);
567 goto freecopy;
568 }
b0d623f7 569 if (!m) {
1c79356b 570 goto freecopy;
b0d623f7
A
571 }
572 /* We still have the extra ref on rt */
573 RT_LOCK(rt);
1c79356b 574 }
7e4a7d39 575#endif
1c79356b 576
9bccf70c
A
577 /*
578 * Fake scoped addresses. Note that even link-local source or
579 * destinaion can appear, if the originating node just sends the
580 * packet to us (without address resolution for the destination).
581 * Since both icmp6_error and icmp6_redirect_output fill the embedded
582 * link identifiers, we can do this stuff after making a copy for
583 * returning an error.
584 */
585 if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
586 /*
587 * See corresponding comments in ip6_output.
588 * XXX: but is it possible that ip6_forward() sends a packet
589 * to a loopback interface? I don't think so, and thus
590 * I bark here. (jinmei@kame.net)
591 * XXX: it is common to route invalid packets to loopback.
592 * also, the codepath will be visited on use of ::1 in
593 * rthdr. (itojun)
594 */
595#if 1
596 if (0)
1c79356b 597#else
9bccf70c
A
598 if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
599#endif
600 {
601 printf("ip6_forward: outgoing interface is loopback. "
55e303ae
A
602 "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
603 ip6_sprintf(&ip6->ip6_src),
604 ip6_sprintf(&ip6->ip6_dst),
605 ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
606 if_name(rt->rt_ifp));
9bccf70c
A
607 }
608
609 /* we can just use rcvif in forwarding. */
610 origifp = m->m_pkthdr.rcvif;
611 }
612 else
613 origifp = rt->rt_ifp;
614#ifndef SCOPEDROUTING
615 /*
616 * clear embedded scope identifiers if necessary.
617 * in6_clearscope will touch the addresses only when necessary.
618 */
619 in6_clearscope(&ip6->ip6_src);
620 in6_clearscope(&ip6->ip6_dst);
621#endif
622
b0d623f7
A
623 ifp = rt->rt_ifp;
624 /* Drop the lock but retain the extra ref */
625 RT_UNLOCK(rt);
626
627#if PF
628 if (locked)
629 lck_mtx_unlock(ip6_mutex);
630
631 /* Invoke outbound packet filter */
632 error = pf_af_hook(ifp, NULL, &m, AF_INET6, FALSE);
633
634 if (locked)
635 lck_mtx_lock(ip6_mutex);
636
637 if (error) {
638 if (m != NULL) {
639 panic("%s: unexpected packet %p\n", __func__, m);
640 /* NOTREACHED */
641 }
642 /* Already freed by callee */
643 goto senderr;
644 }
645 ip6 = mtod(m, struct ip6_hdr *);
646#endif /* PF */
647
648 error = nd6_output(ifp, origifp, m, dst, rt, locked);
1c79356b 649 if (error) {
b0d623f7 650 in6_ifstat_inc(ifp, ifs6_out_discard);
1c79356b
A
651 ip6stat.ip6s_cantforward++;
652 } else {
653 ip6stat.ip6s_forward++;
b0d623f7 654 in6_ifstat_inc(ifp, ifs6_out_forward);
1c79356b
A
655 if (type)
656 ip6stat.ip6s_redirectsent++;
657 else {
b0d623f7 658 if (mcopy) {
1c79356b 659 goto freecopy;
b0d623f7 660 }
1c79356b
A
661 }
662 }
b0d623f7
A
663#if PF
664senderr:
665#endif /* PF */
666 if (mcopy == NULL) {
667 /* Release extra ref */
668 RT_REMREF(rt);
1c79356b 669 return;
b0d623f7 670 }
1c79356b
A
671 switch (error) {
672 case 0:
673#if 1
674 if (type == ND_REDIRECT) {
675 icmp6_redirect_output(mcopy, rt);
b0d623f7
A
676 /* Release extra ref */
677 RT_REMREF(rt);
1c79356b
A
678 return;
679 }
680#endif
681 goto freecopy;
682
683 case EMSGSIZE:
684 /* xxx MTU is constant in PPP? */
685 goto freecopy;
686
687 case ENOBUFS:
688 /* Tell source to slow down like source quench in IP? */
689 goto freecopy;
690
691 case ENETUNREACH: /* shouldn't happen, checked above */
692 case EHOSTUNREACH:
693 case ENETDOWN:
694 case EHOSTDOWN:
695 default:
696 type = ICMP6_DST_UNREACH;
697 code = ICMP6_DST_UNREACH_ADDR;
698 break;
699 }
91447636
A
700 if (locked)
701 lck_mtx_unlock(ip6_mutex);
1c79356b 702 icmp6_error(mcopy, type, code, 0);
91447636
A
703 if (locked)
704 lck_mtx_lock(ip6_mutex);
b0d623f7
A
705 /* Release extra ref */
706 RT_REMREF(rt);
1c79356b
A
707 return;
708
709 freecopy:
710 m_freem(mcopy);
b0d623f7
A
711 /* Release extra ref */
712 RT_REMREF(rt);
1c79356b
A
713 return;
714}