]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/bsd_tcpip/v2_0/src/sys/netinet6/in6_gif.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / bsd_tcpip / v2_0 / src / sys / netinet6 / in6_gif.c
1 //==========================================================================
2 //
3 //      src/sys/netinet6/in6_gif.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: in6_gif.c,v 1.88 2001/12/21 03:32:34 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 /* define it if you want to use encap_attach_func (it helps *BSD merge) */
54 /*#define USE_ENCAPCHECK*/
55
56 #include <sys/param.h>
57 #include <sys/socket.h>
58 #include <sys/sockio.h>
59 #include <sys/mbuf.h>
60 #include <sys/errno.h>
61 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
62 #include <sys/ioctl.h>
63 #endif
64 #include <sys/queue.h>
65 #include <sys/protosw.h>
66
67 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
68 #include <sys/malloc.h>
69 #endif
70
71 #include <net/if.h>
72 #include <net/route.h>
73
74 #include <netinet/in.h>
75 #include <netinet/in_systm.h>
76 #ifdef INET
77 #include <netinet/ip.h>
78 #endif
79 #include <netinet/ip_encap.h>
80 #ifdef INET6
81 #include <netinet/ip6.h>
82 #include <netinet6/ip6_var.h>
83 #include <netinet6/in6_gif.h>
84 #include <netinet6/in6_var.h>
85 #endif
86 #include <netinet6/ip6protosw.h>
87 #include <netinet/ip_ecn.h>
88 #ifdef __OpenBSD__
89 #include <netinet/ip_ipsp.h>
90 #endif
91
92 #include <net/if_gif.h>
93
94 #ifdef __OpenBSD__
95 #include "bridge.h"
96 #endif
97
98 static int gif_validate6 __P((const struct ip6_hdr *, struct gif_softc *,
99         struct ifnet *));
100 static int in6_gif_rtcachettl = 300; /* XXX see in_gif.c */
101
102 int     ip6_gif_hlim = GIF_HLIM;
103
104 extern struct domain inet6domain;
105 struct ip6protosw in6_gif_protosw =
106 { SOCK_RAW,     &inet6domain,   0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR,
107   in6_gif_input, rip6_output,   in6_gif_ctlinput, rip6_ctloutput,
108 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
109   0,
110 #else
111   rip6_usrreq,
112 #endif
113   0,            0,              0,              0,
114 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
115   &rip6_usrreqs
116 #endif
117 };
118
119 extern LIST_HEAD(, gif_softc) gif_softc_list;
120
121 #ifndef offsetof
122 #define offsetof(s, e) ((int)&((s *)0)->e)
123 #endif
124
125 int
126 in6_gif_output(ifp, family, m)
127         struct ifnet *ifp;
128         int family; /* family of the packet to be encapsulate. */
129         struct mbuf *m;
130 {
131 #ifdef __OpenBSD__
132         struct gif_softc *sc = (struct gif_softc*)ifp;
133         struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
134         struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
135         struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
136         struct tdb tdb;
137         struct xformsw xfs;
138         int error;
139         int hlen, poff;
140         struct mbuf *mp;
141         long time_second;
142
143         if (sin6_src == NULL || sin6_dst == NULL ||
144             sin6_src->sin6_family != AF_INET6 ||
145             sin6_dst->sin6_family != AF_INET6) {
146                 m_freem(m);
147                 return EAFNOSUPPORT;
148         }
149
150         /* setup dummy tdb.  it highly depends on ipip_output() code. */
151         bzero(&tdb, sizeof(tdb));
152         bzero(&xfs, sizeof(xfs));
153         tdb.tdb_src.sin6.sin6_family = AF_INET6;
154         tdb.tdb_src.sin6.sin6_len = sizeof(struct sockaddr_in6);
155         tdb.tdb_src.sin6.sin6_addr = sin6_src->sin6_addr;
156         tdb.tdb_dst.sin6.sin6_family = AF_INET6;
157         tdb.tdb_dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
158         tdb.tdb_dst.sin6.sin6_addr = sin6_dst->sin6_addr;
159         tdb.tdb_xform = &xfs;
160         xfs.xf_type = -1;       /* not XF_IP4 */
161
162         switch (family) {
163 #ifdef INET
164         case AF_INET:
165             {
166                 if (m->m_len < sizeof(struct ip)) {
167                         m = m_pullup(m, sizeof(struct ip));
168                         if (!m)
169                                 return ENOBUFS;
170                 }
171                 hlen = (mtod(m, struct ip *)->ip_hl) << 2;
172                 poff = offsetof(struct ip, ip_p);
173                 break;
174             }
175 #endif
176 #ifdef INET6
177         case AF_INET6:
178             {
179                 hlen = sizeof(struct ip6_hdr);
180                 poff = offsetof(struct ip6_hdr, ip6_nxt);
181                 break;
182             }
183 #endif
184 #if NBRIDGE > 0
185         case AF_LINK:
186                 break;
187 #endif /* NBRIDGE */
188         default:
189 #ifdef DEBUG
190                 printf("in6_gif_output: warning: unknown family %d passed\n",
191                         family);
192 #endif
193                 m_freem(m);
194                 return EAFNOSUPPORT;
195         }
196         
197 #if NBRIDGE > 0
198         if (family == AF_LINK) {
199                 mp = NULL;
200                 error = etherip_output(m, &tdb, &mp, 0, 0);
201                 if (error)
202                         return error;
203                 else if (mp == NULL)
204                         return EFAULT;
205
206                 m = mp;
207                 goto sendit;
208         }
209 #endif /* NBRIDGE */
210
211         /* encapsulate into IPv6 packet */
212         mp = NULL;
213         error = ipip_output(m, &tdb, &mp, hlen, poff);
214         if (error)
215                 return error;
216         else if (mp == NULL)
217                 return EFAULT;
218
219         m = mp;
220
221 #if NBRIDGE > 0
222  sendit:
223 #endif /* NBRIDGE */
224         /*
225          * compare address family just for safety.  other validity checks
226          * are made in in6_selectsrc() called from ip6_output().
227          */
228         if (sc->gif_ro6.ro_rt && (dst->sin6_family != sin6_dst->sin6_family ||
229                                   sc->rtcache_expire == 0 ||
230                                   time_second >= sc->rtcache_expire)) {
231                 RTFREE(sc->gif_ro6.ro_rt);
232                 sc->gif_ro6.ro_rt = NULL;
233         }
234
235 #ifdef IPV6_MINMTU
236         /*
237          * force fragmentation to minimum MTU, to avoid path MTU discovery.
238          * it is too painful to ask for resend of inner packet, to achieve
239          * path MTU discovery for encapsulated packets.
240          */
241         error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL);
242 #else
243         error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL);
244 #endif
245
246         if (sc->gif_ro6.ro_rt && time_second >= sc->rtcache_expire)
247                 sc->rtcache_expire = time_second + in6_gif_rtcachettl;
248
249         return(error);
250 #else   /* !__OpenBSD__ */
251         struct gif_softc *sc = (struct gif_softc*)ifp;
252         struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
253         struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
254         struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
255         struct ip6_hdr *ip6;
256         int proto, error;
257         u_int8_t itos, otos;
258 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
259         long time_second;
260 #endif
261
262         if (sin6_src == NULL || sin6_dst == NULL ||
263             sin6_src->sin6_family != AF_INET6 ||
264             sin6_dst->sin6_family != AF_INET6) {
265                 m_freem(m);
266                 return EAFNOSUPPORT;
267         }
268
269         switch (family) {
270 #ifdef INET
271         case AF_INET:
272             {
273                 struct ip *ip;
274
275                 proto = IPPROTO_IPV4;
276                 if (m->m_len < sizeof(*ip)) {
277                         m = m_pullup(m, sizeof(*ip));
278                         if (!m)
279                                 return ENOBUFS;
280                 }
281                 ip = mtod(m, struct ip *);
282                 itos = ip->ip_tos;
283                 break;
284             }
285 #endif
286 #ifdef INET6
287         case AF_INET6:
288             {
289                 struct ip6_hdr *ip6;
290                 proto = IPPROTO_IPV6;
291                 if (m->m_len < sizeof(*ip6)) {
292                         m = m_pullup(m, sizeof(*ip6));
293                         if (!m)
294                                 return ENOBUFS;
295                 }
296                 ip6 = mtod(m, struct ip6_hdr *);
297                 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
298                 break;
299             }
300 #endif
301 #if defined(__NetBSD__) && defined(ISO)
302         case AF_ISO:
303                 proto = IPPROTO_EON;
304                 itos = 0;
305                 break;
306 #endif
307         default:
308 #ifdef DEBUG
309                 printf("in6_gif_output: warning: unknown family %d passed\n",
310                         family);
311 #endif
312                 m_freem(m);
313                 return EAFNOSUPPORT;
314         }
315         
316         /* prepend new IP header */
317         M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
318         if (m && m->m_len < sizeof(struct ip6_hdr))
319                 m = m_pullup(m, sizeof(struct ip6_hdr));
320         if (m == NULL)
321                 return ENOBUFS;
322
323         ip6 = mtod(m, struct ip6_hdr *);
324         ip6->ip6_flow   = 0;
325         ip6->ip6_vfc    &= ~IPV6_VERSION_MASK;
326         ip6->ip6_vfc    |= IPV6_VERSION;
327         ip6->ip6_plen   = htons((u_short)m->m_pkthdr.len);
328         ip6->ip6_nxt    = proto;
329         ip6->ip6_hlim   = ip6_gif_hlim;
330         ip6->ip6_src    = sin6_src->sin6_addr;
331         /* bidirectional configured tunnel mode */
332         if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
333                 ip6->ip6_dst = sin6_dst->sin6_addr;
334         else  {
335                 m_freem(m);
336                 return ENETUNREACH;
337         }
338         if (ifp->if_flags & IFF_LINK1)
339                 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
340         else
341                 ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
342         ip6->ip6_flow &= ~ntohl(0xff00000);
343         ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
344
345 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
346         time_second = time.tv_sec;
347 #endif
348         /*
349          * compare address family just for safety.  other validity checks
350          * are made in in6_selectsrc() called from ip6_output().
351          */
352         if (sc->gif_ro6.ro_rt && (dst->sin6_family != sin6_dst->sin6_family ||
353                                   sc->rtcache_expire == 0 ||
354                                   time_second >= sc->rtcache_expire)) {
355                 /*
356                  * If the cached route is not valid or has expired,
357                  * clear the stale cache and let ip6_output make a new cached
358                  * route.
359                  */
360                 RTFREE(sc->gif_ro6.ro_rt);
361                 sc->gif_ro6.ro_rt = NULL;
362         }
363
364 #ifdef IPV6_MINMTU
365         /*
366          * force fragmentation to minimum MTU, to avoid path MTU discovery.
367          * it is too painful to ask for resend of inner packet, to achieve
368          * path MTU discovery for encapsulated packets.
369          */
370         error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL);
371 #else
372         error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL);
373 #endif
374
375         /*
376          * if a (new) cached route has been created in ip6_output(), extend
377          * the expiration time.
378          */
379         if (sc->gif_ro6.ro_rt && time_second >= sc->rtcache_expire)
380                 sc->rtcache_expire = time_second + in6_gif_rtcachettl;
381
382         return(error);
383 #endif  /* __OpenBSD__ */
384 }
385
386 int in6_gif_input(mp, offp, proto)
387         struct mbuf **mp;
388         int *offp, proto;
389 {
390         struct mbuf *m = *mp;
391         struct ifnet *gifp = NULL;
392         struct ip6_hdr *ip6;
393 #ifndef __OpenBSD__
394         int af = 0;
395         u_int32_t otos;
396 #endif
397
398         ip6 = mtod(m, struct ip6_hdr *);
399
400         gifp = (struct ifnet *)encap_getarg(m);
401
402         if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
403                 m_freem(m);
404                 ip6stat.ip6s_nogif++;
405                 return IPPROTO_DONE;
406         }
407 #ifndef USE_ENCAPCHECK
408         if (!gif_validate6(ip6, (struct gif_softc *)gifp, m->m_pkthdr.rcvif)) {
409                 m_freem(m);
410                 ip6stat.ip6s_nogif++;
411                 return IPPROTO_DONE;
412         }
413 #endif
414
415 #ifdef __OpenBSD__
416         m->m_pkthdr.rcvif = gifp;
417         gifp->if_ipackets++;
418         gifp->if_ibytes += m->m_pkthdr.len;
419         ipip_input(m, *offp, gifp);
420         return IPPROTO_DONE;
421 #else
422         otos = ip6->ip6_flow;
423         m_adj(m, *offp);
424
425         switch (proto) {
426 #ifdef INET
427         case IPPROTO_IPV4:
428             {
429                 struct ip *ip;
430                 u_int8_t otos8;
431                 af = AF_INET;
432                 otos8 = (ntohl(otos) >> 20) & 0xff;
433                 if (m->m_len < sizeof(*ip)) {
434                         m = m_pullup(m, sizeof(*ip));
435                         if (!m)
436                                 return IPPROTO_DONE;
437                 }
438                 ip = mtod(m, struct ip *);
439                 if (gifp->if_flags & IFF_LINK1)
440                         ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
441                 else
442                         ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
443                 break;
444             }
445 #endif /* INET */
446 #ifdef INET6
447         case IPPROTO_IPV6:
448             {
449                 struct ip6_hdr *ip6;
450                 af = AF_INET6;
451                 if (m->m_len < sizeof(*ip6)) {
452                         m = m_pullup(m, sizeof(*ip6));
453                         if (!m)
454                                 return IPPROTO_DONE;
455                 }
456                 ip6 = mtod(m, struct ip6_hdr *);
457                 if (gifp->if_flags & IFF_LINK1)
458                         ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6->ip6_flow);
459                 else
460                         ip6_ecn_egress(ECN_NOCARE, &otos, &ip6->ip6_flow);
461                 break;
462             }
463 #endif
464 #if defined(__NetBSD__) && defined(ISO)
465         case IPPROTO_EON:
466                 af = AF_ISO;
467                 break;
468 #endif
469         default:
470                 ip6stat.ip6s_nogif++;
471                 m_freem(m);
472                 return IPPROTO_DONE;
473         }
474                 
475         gif_input(m, af, gifp);
476         return IPPROTO_DONE;
477 #endif
478 }
479
480 /*
481  * validate outer address.
482  */
483 static int
484 gif_validate6(ip6, sc, ifp)
485         const struct ip6_hdr *ip6;
486         struct gif_softc *sc;
487         struct ifnet *ifp;
488 {
489         struct sockaddr_in6 *src, *dst;
490
491         src = (struct sockaddr_in6 *)sc->gif_psrc;
492         dst = (struct sockaddr_in6 *)sc->gif_pdst;
493
494         /* check for address match */
495         if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
496             !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
497                 return 0;
498
499         /* martian filters on outer source - done in ip6_input */
500
501         /* ingress filters on outer source */
502         if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
503                 struct sockaddr_in6 sin6;
504                 struct rtentry *rt;
505
506                 bzero(&sin6, sizeof(sin6));
507                 sin6.sin6_family = AF_INET6;
508                 sin6.sin6_len = sizeof(struct sockaddr_in6);
509                 sin6.sin6_addr = ip6->ip6_src;
510                 /* XXX scopeid */
511 #ifdef __FreeBSD__
512                 rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
513 #else
514                 rt = rtalloc1((struct sockaddr *)&sin6, 0);
515 #endif
516                 if (!rt || rt->rt_ifp != ifp) {
517 #if 0
518                         log(LOG_WARNING, "%s: packet from %s dropped "
519                             "due to ingress filter\n", if_name(&sc->gif_if),
520                             ip6_sprintf(&sin6.sin6_addr));
521 #endif
522                         if (rt)
523                                 rtfree(rt);
524                         return 0;
525                 }
526                 rtfree(rt);
527         }
528
529         return 128 * 2;
530 }
531
532 /*
533  * we know that we are in IFF_UP, outer address available, and outer family
534  * matched the physical addr family.  see gif_encapcheck().
535  */
536 int
537 gif_encapcheck6(m, off, proto, arg)
538         const struct mbuf *m;
539         int off;
540         int proto;
541         void *arg;
542 {
543         struct ip6_hdr ip6;
544         struct gif_softc *sc;
545         struct ifnet *ifp;
546
547         /* sanity check done in caller */
548         sc = (struct gif_softc *)arg;
549
550         /* LINTED const cast */
551         m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6);
552         ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
553
554         return gif_validate6(&ip6, sc, ifp);
555 }
556
557 int
558 in6_gif_attach(sc)
559         struct gif_softc *sc;
560 {
561 #ifndef USE_ENCAPCHECK
562         struct sockaddr_in6 mask6;
563
564         bzero(&mask6, sizeof(mask6));
565         mask6.sin6_len = sizeof(struct sockaddr_in6);
566         mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] = 
567             mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
568
569         if (!sc->gif_psrc || !sc->gif_pdst)
570                 return EINVAL;
571         sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc,
572             (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6,
573             (struct protosw *)&in6_gif_protosw, sc);
574 #else
575         sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
576             (struct protosw *)&in6_gif_protosw, sc);
577 #endif
578         if (sc->encap_cookie6 == NULL)
579                 return EEXIST;
580         return 0;
581 }
582
583 int
584 in6_gif_detach(sc)
585         struct gif_softc *sc;
586 {
587         int error;
588
589         error = encap_detach(sc->encap_cookie6);
590         if (error == 0)
591                 sc->encap_cookie6 = NULL;
592         return error;
593 }
594
595 void
596 in6_gif_ctlinput(cmd, sa, d)
597         int cmd;
598         struct sockaddr *sa;
599         void *d;
600 {
601         struct gif_softc *sc;
602         struct ip6ctlparam *ip6cp = NULL;
603         struct mbuf *m;
604         struct ip6_hdr *ip6;
605         int off;
606         void *cmdarg;
607         const struct sockaddr_in6 *sa6_src = NULL;
608         struct sockaddr_in6 *dst6;
609
610         if (sa->sa_family != AF_INET6 ||
611             sa->sa_len != sizeof(struct sockaddr_in6))
612                 return;
613
614         if ((unsigned)cmd >= PRC_NCMDS)
615                 return;
616         if (cmd == PRC_HOSTDEAD)
617                 d = NULL;
618         else if (inet6ctlerrmap[cmd] == 0)
619                 return;
620
621         /* if the parameter is from icmp6, decode it. */
622         if (d != NULL) {
623                 ip6cp = (struct ip6ctlparam *)d;
624                 m = ip6cp->ip6c_m;
625                 ip6 = ip6cp->ip6c_ip6;
626                 off = ip6cp->ip6c_off;
627                 cmdarg = ip6cp->ip6c_cmdarg;
628                 sa6_src = ip6cp->ip6c_src;
629         } else {
630                 m = NULL;
631                 ip6 = NULL;
632                 cmdarg = NULL;
633                 sa6_src = &sa6_any;
634         }
635
636         if (!ip6)
637                 return;
638
639         /*
640          * for now we don't care which type it was, just flush the route cache.
641          * XXX slow.  sc (or sc->encap_cookie6) should be passed from
642          * ip_encap.c.
643          */
644         for (sc = LIST_FIRST(&gif_softc_list); sc;
645              sc = LIST_NEXT(sc, gif_list)) {
646                 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
647                         continue;
648                 if (sc->gif_psrc->sa_family != AF_INET6)
649                         continue;
650                 if (!sc->gif_ro6.ro_rt)
651                         continue;
652
653                 dst6 = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
654                 /* XXX scope */
655                 if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr)) {
656                         /* flush route cache */
657                         RTFREE(sc->gif_ro6.ro_rt);
658                         sc->gif_ro6.ro_rt = NULL;
659                 }
660         }
661 }