[BACK]Return to ip6_forward.c CVS log [TXT][DIR] Up to [local] / sys / netinet6

Annotation of sys/netinet6/ip6_forward.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ip6_forward.c,v 1.39 2007/06/01 00:52:38 henning Exp $        */
        !             2: /*     $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $    */
        !             3:
        !             4: /*
        !             5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the project nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  */
        !            32:
        !            33: #include "pf.h"
        !            34:
        !            35: #include <sys/param.h>
        !            36: #include <sys/systm.h>
        !            37: #include <sys/malloc.h>
        !            38: #include <sys/mbuf.h>
        !            39: #include <sys/domain.h>
        !            40: #include <sys/protosw.h>
        !            41: #include <sys/socket.h>
        !            42: #include <sys/errno.h>
        !            43: #include <sys/time.h>
        !            44: #include <sys/kernel.h>
        !            45: #include <sys/syslog.h>
        !            46:
        !            47: #include <net/if.h>
        !            48: #include <net/route.h>
        !            49:
        !            50: #include <netinet/in.h>
        !            51: #include <netinet/in_var.h>
        !            52: #include <netinet/ip_var.h>
        !            53: #include <netinet/ip6.h>
        !            54: #include <netinet6/ip6_var.h>
        !            55: #include <netinet/icmp6.h>
        !            56: #include <netinet6/nd6.h>
        !            57:
        !            58: #if NPF > 0
        !            59: #include <net/pfvar.h>
        !            60: #endif
        !            61:
        !            62: #ifdef IPSEC
        !            63: #include <netinet/ip_ipsp.h>
        !            64: #include <netinet/ip_ah.h>
        !            65: #include <netinet/ip_esp.h>
        !            66: #include <netinet/udp.h>
        !            67: #include <netinet/tcp.h>
        !            68: #include <net/pfkeyv2.h>
        !            69: #endif
        !            70:
        !            71: struct route_in6 ip6_forward_rt;
        !            72: int    ip6_forward_rtableid;
        !            73:
        !            74: /*
        !            75:  * Forward a packet.  If some error occurs return the sender
        !            76:  * an icmp packet.  Note we can't always generate a meaningful
        !            77:  * icmp message because icmp doesn't have a large enough repertoire
        !            78:  * of codes and types.
        !            79:  *
        !            80:  * If not forwarding, just drop the packet.  This could be confusing
        !            81:  * if ipforwarding was zero but some routing protocol was advancing
        !            82:  * us as a gateway to somewhere.  However, we must let the routing
        !            83:  * protocol deal with that.
        !            84:  *
        !            85:  */
        !            86:
        !            87: void
        !            88: ip6_forward(m, srcrt)
        !            89:        struct mbuf *m;
        !            90:        int srcrt;
        !            91: {
        !            92:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        !            93:        struct sockaddr_in6 *dst;
        !            94:        struct rtentry *rt;
        !            95:        int error = 0, type = 0, code = 0;
        !            96:        struct mbuf *mcopy = NULL;
        !            97:        struct ifnet *origifp;  /* maybe unnecessary */
        !            98: #ifdef IPSEC
        !            99:        u_int8_t sproto = 0;
        !           100:        struct m_tag *mtag;
        !           101:        union sockaddr_union sdst;
        !           102:        struct tdb_ident *tdbi;
        !           103:        u_int32_t sspi;
        !           104:        struct tdb *tdb;
        !           105:        int s;
        !           106: #endif /* IPSEC */
        !           107:        int rtableid = 0;
        !           108:
        !           109:        /*
        !           110:         * Do not forward packets to multicast destination (should be handled
        !           111:         * by ip6_mforward().
        !           112:         * Do not forward packets with unspecified source.  It was discussed
        !           113:         * in July 2000, on ipngwg mailing list.
        !           114:         */
        !           115:        if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
        !           116:            IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
        !           117:            IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
        !           118:                ip6stat.ip6s_cantforward++;
        !           119:                /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
        !           120:                if (ip6_log_time + ip6_log_interval < time_second) {
        !           121:                        ip6_log_time = time_second;
        !           122:                        log(LOG_DEBUG,
        !           123:                            "cannot forward "
        !           124:                            "from %s to %s nxt %d received on %s\n",
        !           125:                            ip6_sprintf(&ip6->ip6_src),
        !           126:                            ip6_sprintf(&ip6->ip6_dst),
        !           127:                            ip6->ip6_nxt,
        !           128:                            m->m_pkthdr.rcvif->if_xname);
        !           129:                }
        !           130:                m_freem(m);
        !           131:                return;
        !           132:        }
        !           133:
        !           134:        if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
        !           135:                /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
        !           136:                icmp6_error(m, ICMP6_TIME_EXCEEDED,
        !           137:                                ICMP6_TIME_EXCEED_TRANSIT, 0);
        !           138:                return;
        !           139:        }
        !           140:        ip6->ip6_hlim -= IPV6_HLIMDEC;
        !           141:
        !           142: #ifdef IPSEC
        !           143:        if (!ipsec_in_use)
        !           144:                goto done_spd;
        !           145:
        !           146:        s = splnet();
        !           147:
        !           148:        /*
        !           149:         * Check if there was an outgoing SA bound to the flow
        !           150:         * from a transport protocol.
        !           151:         */
        !           152:
        !           153:        /* Do we have any pending SAs to apply ? */
        !           154:        mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
        !           155:        if (mtag != NULL) {
        !           156: #ifdef DIAGNOSTIC
        !           157:                if (mtag->m_tag_len != sizeof (struct tdb_ident))
        !           158:                        panic("ip6_forward: tag of length %d (should be %d",
        !           159:                            mtag->m_tag_len, sizeof (struct tdb_ident));
        !           160: #endif
        !           161:                tdbi = (struct tdb_ident *)(mtag + 1);
        !           162:                tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
        !           163:                if (tdb == NULL)
        !           164:                        error = -EINVAL;
        !           165:                m_tag_delete(m, mtag);
        !           166:        } else
        !           167:                tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
        !           168:                    &error, IPSP_DIRECTION_OUT, NULL, NULL);
        !           169:
        !           170:        if (tdb == NULL) {
        !           171:                splx(s);
        !           172:
        !           173:                if (error == 0) {
        !           174:                        /*
        !           175:                         * No IPsec processing required, we'll just send the
        !           176:                         * packet out.
        !           177:                         */
        !           178:                        sproto = 0;
        !           179:
        !           180:                        /* Fall through to routing/multicast handling */
        !           181:                } else {
        !           182:                        /*
        !           183:                         * -EINVAL is used to indicate that the packet should
        !           184:                         * be silently dropped, typically because we've asked
        !           185:                         * key management for an SA.
        !           186:                         */
        !           187:                        if (error == -EINVAL) /* Should silently drop packet */
        !           188:                                error = 0;
        !           189:
        !           190:                        goto freecopy;
        !           191:                }
        !           192:        } else {
        !           193:                /* Loop detection */
        !           194:                for (mtag = m_tag_first(m); mtag != NULL;
        !           195:                    mtag = m_tag_next(m, mtag)) {
        !           196:                        if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
        !           197:                            mtag->m_tag_id !=
        !           198:                            PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
        !           199:                                continue;
        !           200:                        tdbi = (struct tdb_ident *)(mtag + 1);
        !           201:                        if (tdbi->spi == tdb->tdb_spi &&
        !           202:                            tdbi->proto == tdb->tdb_sproto &&
        !           203:                            !bcmp(&tdbi->dst, &tdb->tdb_dst,
        !           204:                            sizeof(union sockaddr_union))) {
        !           205:                                splx(s);
        !           206:                                sproto = 0; /* mark as no-IPsec-needed */
        !           207:                                goto done_spd;
        !           208:                        }
        !           209:                }
        !           210:
        !           211:                /* We need to do IPsec */
        !           212:                bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
        !           213:                sspi = tdb->tdb_spi;
        !           214:                sproto = tdb->tdb_sproto;
        !           215:                splx(s);
        !           216:        }
        !           217:
        !           218:        /* Fall through to the routing/multicast handling code */
        !           219:  done_spd:
        !           220: #endif /* IPSEC */
        !           221:
        !           222: #if NPF > 0
        !           223:        rtableid = m->m_pkthdr.pf.rtableid;
        !           224: #endif
        !           225:
        !           226:        /*
        !           227:         * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
        !           228:         * size of IPv6 + ICMPv6 headers) bytes of the packet in case
        !           229:         * we need to generate an ICMP6 message to the src.
        !           230:         * Thanks to M_EXT, in most cases copy will not occur.
        !           231:         *
        !           232:         * It is important to save it before IPsec processing as IPsec
        !           233:         * processing may modify the mbuf.
        !           234:         */
        !           235:        mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
        !           236:
        !           237:        dst = &ip6_forward_rt.ro_dst;
        !           238:        if (!srcrt) {
        !           239:                /*
        !           240:                 * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
        !           241:                 */
        !           242:                if (ip6_forward_rt.ro_rt == 0 ||
        !           243:                    (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0 ||
        !           244:                    ip6_forward_rtableid != rtableid) {
        !           245:                        if (ip6_forward_rt.ro_rt) {
        !           246:                                RTFREE(ip6_forward_rt.ro_rt);
        !           247:                                ip6_forward_rt.ro_rt = 0;
        !           248:                        }
        !           249:                        /* this probably fails but give it a try again */
        !           250:                        rtalloc_mpath((struct route *)&ip6_forward_rt,
        !           251:                            &ip6->ip6_src.s6_addr32[0], rtableid);
        !           252:                        ip6_forward_rtableid = rtableid;
        !           253:                }
        !           254:
        !           255:                if (ip6_forward_rt.ro_rt == 0) {
        !           256:                        ip6stat.ip6s_noroute++;
        !           257:                        /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
        !           258:                        if (mcopy) {
        !           259:                                icmp6_error(mcopy, ICMP6_DST_UNREACH,
        !           260:                                            ICMP6_DST_UNREACH_NOROUTE, 0);
        !           261:                        }
        !           262:                        m_freem(m);
        !           263:                        return;
        !           264:                }
        !           265:        } else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
        !           266:                 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
        !           267:                if (ip6_forward_rt.ro_rt) {
        !           268:                        RTFREE(ip6_forward_rt.ro_rt);
        !           269:                        ip6_forward_rt.ro_rt = 0;
        !           270:                }
        !           271:                bzero(dst, sizeof(*dst));
        !           272:                dst->sin6_len = sizeof(struct sockaddr_in6);
        !           273:                dst->sin6_family = AF_INET6;
        !           274:                dst->sin6_addr = ip6->ip6_dst;
        !           275:
        !           276:                rtalloc_mpath((struct route *)&ip6_forward_rt,
        !           277:                    &ip6->ip6_src.s6_addr32[0], 0);
        !           278:
        !           279:                if (ip6_forward_rt.ro_rt == 0) {
        !           280:                        ip6stat.ip6s_noroute++;
        !           281:                        /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
        !           282:                        if (mcopy) {
        !           283:                                icmp6_error(mcopy, ICMP6_DST_UNREACH,
        !           284:                                            ICMP6_DST_UNREACH_NOROUTE, 0);
        !           285:                        }
        !           286:                        m_freem(m);
        !           287:                        return;
        !           288:                }
        !           289:        }
        !           290:        rt = ip6_forward_rt.ro_rt;
        !           291:
        !           292:        /*
        !           293:         * Scope check: if a packet can't be delivered to its destination
        !           294:         * for the reason that the destination is beyond the scope of the
        !           295:         * source address, discard the packet and return an icmp6 destination
        !           296:         * unreachable error with Code 2 (beyond scope of source address).
        !           297:         * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
        !           298:         */
        !           299:        if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
        !           300:            in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
        !           301:                ip6stat.ip6s_cantforward++;
        !           302:                ip6stat.ip6s_badscope++;
        !           303:                in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
        !           304:
        !           305:                if (ip6_log_time + ip6_log_interval < time_second) {
        !           306:                        ip6_log_time = time_second;
        !           307:                        log(LOG_DEBUG,
        !           308:                            "cannot forward "
        !           309:                            "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
        !           310:                            ip6_sprintf(&ip6->ip6_src),
        !           311:                            ip6_sprintf(&ip6->ip6_dst),
        !           312:                            ip6->ip6_nxt,
        !           313:                            m->m_pkthdr.rcvif->if_xname, rt->rt_ifp->if_xname);
        !           314:                }
        !           315:                if (mcopy)
        !           316:                        icmp6_error(mcopy, ICMP6_DST_UNREACH,
        !           317:                                    ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
        !           318:                m_freem(m);
        !           319:                goto freert;
        !           320:        }
        !           321:
        !           322: #ifdef IPSEC
        !           323:        /*
        !           324:         * Check if the packet needs encapsulation.
        !           325:         * ipsp_process_packet will never come back to here.
        !           326:         * XXX ipsp_process_packet() calls ip6_output(), and there'll be no
        !           327:         * PMTU notification.  is it okay?
        !           328:         */
        !           329:        if (sproto != 0) {
        !           330:                s = splnet();
        !           331:
        !           332:                tdb = gettdb(sspi, &sdst, sproto);
        !           333:                if (tdb == NULL) {
        !           334:                        splx(s);
        !           335:                        error = EHOSTUNREACH;
        !           336:                        m_freem(m);
        !           337:                        goto senderr;   /*XXX*/
        !           338:                }
        !           339:
        !           340:                m->m_flags &= ~(M_BCAST | M_MCAST);     /* just in case */
        !           341:
        !           342:                /* Callee frees mbuf */
        !           343:                error = ipsp_process_packet(m, tdb, AF_INET6, 0);
        !           344:                splx(s);
        !           345:                m_freem(mcopy);
        !           346:                goto freert;
        !           347:        }
        !           348: #endif /* IPSEC */
        !           349:
        !           350:        if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
        !           351:                in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
        !           352:                if (mcopy) {
        !           353:                        u_long mtu;
        !           354:
        !           355:                        mtu = IN6_LINKMTU(rt->rt_ifp);
        !           356:
        !           357:                        icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
        !           358:                }
        !           359:                m_freem(m);
        !           360:                goto freert;
        !           361:        }
        !           362:
        !           363:        if (rt->rt_flags & RTF_GATEWAY)
        !           364:                dst = (struct sockaddr_in6 *)rt->rt_gateway;
        !           365:
        !           366:        /*
        !           367:         * If we are to forward the packet using the same interface
        !           368:         * as one we got the packet from, perhaps we should send a redirect
        !           369:         * to sender to shortcut a hop.
        !           370:         * Only send redirect if source is sending directly to us,
        !           371:         * and if packet was not source routed (or has any options).
        !           372:         * Also, don't send redirect if forwarding using a route
        !           373:         * modified by a redirect.
        !           374:         */
        !           375:        if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && ip6_sendredirects &&
        !           376:            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
        !           377:                if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
        !           378:                    nd6_is_addr_neighbor((struct sockaddr_in6 *)&ip6_forward_rt.ro_dst, rt->rt_ifp)) {
        !           379:                        /*
        !           380:                         * If the incoming interface is equal to the outgoing
        !           381:                         * one, the link attached to the interface is
        !           382:                         * point-to-point, and the IPv6 destination is
        !           383:                         * regarded as on-link on the link, then it will be
        !           384:                         * highly probable that the destination address does
        !           385:                         * not exist on the link and that the packet is going
        !           386:                         * to loop.  Thus, we immediately drop the packet and
        !           387:                         * send an ICMPv6 error message.
        !           388:                         * For other routing loops, we dare to let the packet
        !           389:                         * go to the loop, so that a remote diagnosing host
        !           390:                         * can detect the loop by traceroute.
        !           391:                         * type/code is based on suggestion by Rich Draves.
        !           392:                         * not sure if it is the best pick.
        !           393:                         */
        !           394:                        icmp6_error(mcopy, ICMP6_DST_UNREACH,
        !           395:                                    ICMP6_DST_UNREACH_ADDR, 0);
        !           396:                        m_freem(m);
        !           397:                        goto freert;
        !           398:                }
        !           399:                type = ND_REDIRECT;
        !           400:        }
        !           401:
        !           402:        /*
        !           403:         * Fake scoped addresses. Note that even link-local source or
        !           404:         * destinaion can appear, if the originating node just sends the
        !           405:         * packet to us (without address resolution for the destination).
        !           406:         * Since both icmp6_error and icmp6_redirect_output fill the embedded
        !           407:         * link identifiers, we can do this stuff after making a copy for
        !           408:         * returning an error.
        !           409:         */
        !           410:        if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
        !           411:                /*
        !           412:                 * See corresponding comments in ip6_output.
        !           413:                 * XXX: but is it possible that ip6_forward() sends a packet
        !           414:                 *      to a loopback interface? I don't think so, and thus
        !           415:                 *      I bark here. (jinmei@kame.net)
        !           416:                 * XXX: it is common to route invalid packets to loopback.
        !           417:                 *      also, the codepath will be visited on use of ::1 in
        !           418:                 *      rthdr. (itojun)
        !           419:                 */
        !           420: #if 1
        !           421:                if (0)
        !           422: #else
        !           423:                if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
        !           424: #endif
        !           425:                {
        !           426:                        printf("ip6_forward: outgoing interface is loopback. "
        !           427:                               "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
        !           428:                               ip6_sprintf(&ip6->ip6_src),
        !           429:                               ip6_sprintf(&ip6->ip6_dst),
        !           430:                               ip6->ip6_nxt, m->m_pkthdr.rcvif->if_xname,
        !           431:                               rt->rt_ifp->if_xname);
        !           432:                }
        !           433:
        !           434:                /* we can just use rcvif in forwarding. */
        !           435:                origifp = m->m_pkthdr.rcvif;
        !           436:        }
        !           437:        else
        !           438:                origifp = rt->rt_ifp;
        !           439:        if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
        !           440:                ip6->ip6_src.s6_addr16[1] = 0;
        !           441:        if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
        !           442:                ip6->ip6_dst.s6_addr16[1] = 0;
        !           443:
        !           444: #if NPF > 0
        !           445:        if (pf_test6(PF_OUT, rt->rt_ifp, &m, NULL) != PF_PASS) {
        !           446:                m_freem(m);
        !           447:                goto senderr;
        !           448:        }
        !           449:        if (m == NULL)
        !           450:                goto senderr;
        !           451:
        !           452:        ip6 = mtod(m, struct ip6_hdr *);
        !           453: #endif
        !           454:
        !           455:        error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
        !           456:        if (error) {
        !           457:                in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
        !           458:                ip6stat.ip6s_cantforward++;
        !           459:        } else {
        !           460:                ip6stat.ip6s_forward++;
        !           461:                in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
        !           462:                if (type)
        !           463:                        ip6stat.ip6s_redirectsent++;
        !           464:                else {
        !           465:                        if (mcopy)
        !           466:                                goto freecopy;
        !           467:                }
        !           468:        }
        !           469:
        !           470: #if NPF > 0 || defined(IPSEC)
        !           471: senderr:
        !           472: #endif
        !           473:        if (mcopy == NULL)
        !           474:                goto freert;
        !           475:        switch (error) {
        !           476:        case 0:
        !           477:                if (type == ND_REDIRECT) {
        !           478:                        icmp6_redirect_output(mcopy, rt);
        !           479:                        goto freert;
        !           480:                }
        !           481:                goto freecopy;
        !           482:
        !           483:        case EMSGSIZE:
        !           484:                /* xxx MTU is constant in PPP? */
        !           485:                goto freecopy;
        !           486:
        !           487:        case ENOBUFS:
        !           488:                /* Tell source to slow down like source quench in IP? */
        !           489:                goto freecopy;
        !           490:
        !           491:        case ENETUNREACH:       /* shouldn't happen, checked above */
        !           492:        case EHOSTUNREACH:
        !           493:        case ENETDOWN:
        !           494:        case EHOSTDOWN:
        !           495:        default:
        !           496:                type = ICMP6_DST_UNREACH;
        !           497:                code = ICMP6_DST_UNREACH_ADDR;
        !           498:                break;
        !           499:        }
        !           500:        icmp6_error(mcopy, type, code, 0);
        !           501:        goto freert;
        !           502:
        !           503:  freecopy:
        !           504:        m_freem(mcopy);
        !           505:  freert:
        !           506: #ifndef SMALL_KERNEL
        !           507:        if (ip6_multipath && ip6_forward_rt.ro_rt &&
        !           508:            (ip6_forward_rt.ro_rt->rt_flags & RTF_MPATH)) {
        !           509:                RTFREE(ip6_forward_rt.ro_rt);
        !           510:                ip6_forward_rt.ro_rt = 0;
        !           511:        }
        !           512: #endif
        !           513:        return;
        !           514: }

CVSweb