Annotation of embedaddon/quagga/ripngd/ripngd.c, revision 1.1

1.1     ! misho       1: /* RIPng daemon
        !             2:  * Copyright (C) 1998, 1999 Kunihiro Ishiguro
        !             3:  *
        !             4:  * This file is part of GNU Zebra.
        !             5:  *
        !             6:  * GNU Zebra is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2, or (at your option) any
        !             9:  * later version.
        !            10:  *
        !            11:  * GNU Zebra is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            14:  * General Public License for more details.
        !            15:  *
        !            16:  * You should have received a copy of the GNU General Public License
        !            17:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
        !            18:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
        !            19:  * 02111-1307, USA.  
        !            20:  */
        !            21: 
        !            22: #include <zebra.h>
        !            23: 
        !            24: #include "prefix.h"
        !            25: #include "filter.h"
        !            26: #include "log.h"
        !            27: #include "thread.h"
        !            28: #include "memory.h"
        !            29: #include "if.h"
        !            30: #include "stream.h"
        !            31: #include "table.h"
        !            32: #include "command.h"
        !            33: #include "sockopt.h"
        !            34: #include "distribute.h"
        !            35: #include "plist.h"
        !            36: #include "routemap.h"
        !            37: #include "if_rmap.h"
        !            38: #include "privs.h"
        !            39: 
        !            40: #include "ripngd/ripngd.h"
        !            41: #include "ripngd/ripng_route.h"
        !            42: #include "ripngd/ripng_debug.h"
        !            43: #include "ripngd/ripng_nexthop.h"
        !            44: 
        !            45: /* RIPng structure which includes many parameters related to RIPng
        !            46:    protocol. If ripng couldn't active or ripng doesn't configured,
        !            47:    ripng->fd must be negative value. */
        !            48: struct ripng *ripng = NULL;
        !            49: 
        !            50: enum
        !            51: {
        !            52:   ripng_all_route,
        !            53:   ripng_changed_route,
        !            54: };
        !            55: 
        !            56: extern struct zebra_privs_t ripngd_privs;
        !            57: 
        !            58: /* Prototypes. */
        !            59: void
        !            60: ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
        !            61: 
        !            62: int
        !            63: ripng_triggered_update (struct thread *);
        !            64: 
        !            65: /* RIPng next hop specification. */
        !            66: struct ripng_nexthop
        !            67: {
        !            68:   enum ripng_nexthop_type
        !            69:   {
        !            70:     RIPNG_NEXTHOP_UNSPEC,
        !            71:     RIPNG_NEXTHOP_ADDRESS
        !            72:   } flag;
        !            73:   struct in6_addr address;
        !            74: };
        !            75: 
        !            76: static int
        !            77: ripng_route_rte (struct ripng_info *rinfo)
        !            78: {
        !            79:   return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
        !            80: }
        !            81: 
        !            82: /* Allocate new ripng information. */
        !            83: struct ripng_info *
        !            84: ripng_info_new ()
        !            85: {
        !            86:   struct ripng_info *new;
        !            87: 
        !            88:   new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
        !            89:   return new;
        !            90: }
        !            91: 
        !            92: /* Free ripng information. */
        !            93: void
        !            94: ripng_info_free (struct ripng_info *rinfo)
        !            95: {
        !            96:   XFREE (MTYPE_RIPNG_ROUTE, rinfo);
        !            97: }
        !            98: 
        !            99: /* Create ripng socket. */
        !           100: static int 
        !           101: ripng_make_socket (void)
        !           102: {
        !           103:   int ret;
        !           104:   int sock;
        !           105:   struct sockaddr_in6 ripaddr;
        !           106: 
        !           107:   sock = socket (AF_INET6, SOCK_DGRAM, 0);
        !           108:   if (sock < 0)
        !           109:     {
        !           110:       zlog (NULL, LOG_ERR, "Can't make ripng socket");
        !           111:       return sock;
        !           112:     }
        !           113: 
        !           114:   ret = setsockopt_so_recvbuf (sock, 8096);
        !           115:   if (ret < 0)
        !           116:     return ret;
        !           117:   ret = setsockopt_ipv6_pktinfo (sock, 1);
        !           118:   if (ret < 0)
        !           119:     return ret;
        !           120:   ret = setsockopt_ipv6_multicast_hops (sock, 255);
        !           121:   if (ret < 0)
        !           122:     return ret;
        !           123:   ret = setsockopt_ipv6_multicast_loop (sock, 0);
        !           124:   if (ret < 0)
        !           125:     return ret;
        !           126:   ret = setsockopt_ipv6_hoplimit (sock, 1);
        !           127:   if (ret < 0)
        !           128:     return ret;
        !           129: 
        !           130:   memset (&ripaddr, 0, sizeof (ripaddr));
        !           131:   ripaddr.sin6_family = AF_INET6;
        !           132: #ifdef SIN6_LEN
        !           133:   ripaddr.sin6_len = sizeof (struct sockaddr_in6);
        !           134: #endif /* SIN6_LEN */
        !           135:   ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
        !           136: 
        !           137:   if (ripngd_privs.change (ZPRIVS_RAISE))
        !           138:     zlog_err ("ripng_make_socket: could not raise privs");
        !           139:   
        !           140:   ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
        !           141:   if (ret < 0)
        !           142:   {
        !           143:     zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
        !           144:     if (ripngd_privs.change (ZPRIVS_LOWER))
        !           145:       zlog_err ("ripng_make_socket: could not lower privs");
        !           146:     return ret;
        !           147:   }
        !           148:   if (ripngd_privs.change (ZPRIVS_LOWER))
        !           149:     zlog_err ("ripng_make_socket: could not lower privs");
        !           150:   return sock;
        !           151: }
        !           152: 
        !           153: /* Send RIPng packet. */
        !           154: int
        !           155: ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, 
        !           156:                   struct interface *ifp)
        !           157: {
        !           158:   int ret;
        !           159:   struct msghdr msg;
        !           160:   struct iovec iov;
        !           161:   struct cmsghdr  *cmsgptr;
        !           162:   char adata [256];
        !           163:   struct in6_pktinfo *pkt;
        !           164:   struct sockaddr_in6 addr;
        !           165: 
        !           166:   if (IS_RIPNG_DEBUG_SEND) {
        !           167:     if (to)
        !           168:       zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
        !           169:     zlog_debug ("  send interface %s", ifp->name);
        !           170:     zlog_debug ("  send packet size %d", bufsize);
        !           171:   }
        !           172: 
        !           173:   memset (&addr, 0, sizeof (struct sockaddr_in6));
        !           174:   addr.sin6_family = AF_INET6;
        !           175: #ifdef SIN6_LEN
        !           176:   addr.sin6_len = sizeof (struct sockaddr_in6);
        !           177: #endif /* SIN6_LEN */
        !           178:   addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
        !           179: 
        !           180:   /* When destination is specified. */
        !           181:   if (to != NULL)
        !           182:     {
        !           183:       addr.sin6_addr = to->sin6_addr;
        !           184:       addr.sin6_port = to->sin6_port;
        !           185:     }
        !           186:   else
        !           187:     {
        !           188:       inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
        !           189:       addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
        !           190:     }
        !           191: 
        !           192:   msg.msg_name = (void *) &addr;
        !           193:   msg.msg_namelen = sizeof (struct sockaddr_in6);
        !           194:   msg.msg_iov = &iov;
        !           195:   msg.msg_iovlen = 1;
        !           196:   msg.msg_control = (void *) adata;
        !           197:   msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
        !           198: 
        !           199:   iov.iov_base = buf;
        !           200:   iov.iov_len = bufsize;
        !           201: 
        !           202:   cmsgptr = (struct cmsghdr *)adata;
        !           203:   cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
        !           204:   cmsgptr->cmsg_level = IPPROTO_IPV6;
        !           205:   cmsgptr->cmsg_type = IPV6_PKTINFO;
        !           206: 
        !           207:   pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
        !           208:   memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
        !           209:   pkt->ipi6_ifindex = ifp->ifindex;
        !           210: 
        !           211:   ret = sendmsg (ripng->sock, &msg, 0);
        !           212: 
        !           213:   if (ret < 0) {
        !           214:     if (to)
        !           215:       zlog_err ("RIPng send fail on %s to %s: %s", ifp->name, 
        !           216:                 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
        !           217:     else
        !           218:       zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
        !           219:   }
        !           220: 
        !           221:   return ret;
        !           222: }
        !           223: 
        !           224: /* Receive UDP RIPng packet from socket. */
        !           225: static int
        !           226: ripng_recv_packet (int sock, u_char *buf, int bufsize,
        !           227:                   struct sockaddr_in6 *from, unsigned int *ifindex, 
        !           228:                   int *hoplimit)
        !           229: {
        !           230:   int ret;
        !           231:   struct msghdr msg;
        !           232:   struct iovec iov;
        !           233:   struct cmsghdr  *cmsgptr;
        !           234:   struct in6_addr dst;
        !           235: 
        !           236:   /* Ancillary data.  This store cmsghdr and in6_pktinfo.  But at this
        !           237:      point I can't determine size of cmsghdr */
        !           238:   char adata[1024];
        !           239: 
        !           240:   /* Fill in message and iovec. */
        !           241:   msg.msg_name = (void *) from;
        !           242:   msg.msg_namelen = sizeof (struct sockaddr_in6);
        !           243:   msg.msg_iov = &iov;
        !           244:   msg.msg_iovlen = 1;
        !           245:   msg.msg_control = (void *) adata;
        !           246:   msg.msg_controllen = sizeof adata;
        !           247:   iov.iov_base = buf;
        !           248:   iov.iov_len = bufsize;
        !           249: 
        !           250:   /* If recvmsg fail return minus value. */
        !           251:   ret = recvmsg (sock, &msg, 0);
        !           252:   if (ret < 0)
        !           253:     return ret;
        !           254: 
        !           255:   for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
        !           256:        cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) 
        !           257:     {
        !           258:       /* I want interface index which this packet comes from. */
        !           259:       if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
        !           260:          cmsgptr->cmsg_type == IPV6_PKTINFO) 
        !           261:        {
        !           262:          struct in6_pktinfo *ptr;
        !           263:          
        !           264:          ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
        !           265:          *ifindex = ptr->ipi6_ifindex;
        !           266:          dst = ptr->ipi6_addr;
        !           267: 
        !           268:          if (*ifindex == 0)
        !           269:            zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
        !           270:         }
        !           271: 
        !           272:       /* Incoming packet's multicast hop limit. */
        !           273:       if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
        !           274:          cmsgptr->cmsg_type == IPV6_HOPLIMIT)
        !           275:        {
        !           276:          int *phoplimit = (int *) CMSG_DATA (cmsgptr);
        !           277:          *hoplimit = *phoplimit;
        !           278:        }
        !           279:     }
        !           280: 
        !           281:   /* Hoplimit check shold be done when destination address is
        !           282:      multicast address. */
        !           283:   if (! IN6_IS_ADDR_MULTICAST (&dst))
        !           284:     *hoplimit = -1;
        !           285: 
        !           286:   return ret;
        !           287: }
        !           288: 
        !           289: /* Dump rip packet */
        !           290: void
        !           291: ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
        !           292: {
        !           293:   caddr_t lim;
        !           294:   struct rte *rte;
        !           295:   const char *command_str;
        !           296: 
        !           297:   /* Set command string. */
        !           298:   if (packet->command == RIPNG_REQUEST)
        !           299:     command_str = "request";
        !           300:   else if (packet->command == RIPNG_RESPONSE)
        !           301:     command_str = "response";
        !           302:   else
        !           303:     command_str = "unknown";
        !           304: 
        !           305:   /* Dump packet header. */
        !           306:   zlog_debug ("%s %s version %d packet size %d", 
        !           307:             sndrcv, command_str, packet->version, size);
        !           308: 
        !           309:   /* Dump each routing table entry. */
        !           310:   rte = packet->rte;
        !           311: 
        !           312:   for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
        !           313:     {
        !           314:       if (rte->metric == RIPNG_METRIC_NEXTHOP)
        !           315:        zlog_debug ("  nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
        !           316:       else
        !           317:        zlog_debug ("  %s/%d metric %d tag %d", 
        !           318:                   inet6_ntoa (rte->addr), rte->prefixlen, 
        !           319:                   rte->metric, ntohs (rte->tag));
        !           320:     }
        !           321: }
        !           322: 
        !           323: /* RIPng next hop address RTE (Route Table Entry). */
        !           324: static void
        !           325: ripng_nexthop_rte (struct rte *rte,
        !           326:                   struct sockaddr_in6 *from,
        !           327:                   struct ripng_nexthop *nexthop)
        !           328: {
        !           329:   char buf[INET6_BUFSIZ];
        !           330: 
        !           331:   /* Logging before checking RTE. */
        !           332:   if (IS_RIPNG_DEBUG_RECV)
        !           333:     zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
        !           334:               inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
        !           335: 
        !           336:   /* RFC2080 2.1.1 Next Hop: 
        !           337:    The route tag and prefix length in the next hop RTE must be
        !           338:    set to zero on sending and ignored on receiption.  */
        !           339:   if (ntohs (rte->tag) != 0)
        !           340:     zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
        !           341:               ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
        !           342: 
        !           343:   if (rte->prefixlen != 0)
        !           344:     zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
        !           345:               rte->prefixlen, inet6_ntoa (from->sin6_addr));
        !           346: 
        !           347:   /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
        !           348:    next hop RTE indicates that the next hop address should be the
        !           349:    originator of the RIPng advertisement.  An address specified as a
        !           350:    next hop must be a link-local address.  */
        !           351:   if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
        !           352:     {
        !           353:       nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
        !           354:       memset (&nexthop->address, 0, sizeof (struct in6_addr));
        !           355:       return;
        !           356:     }
        !           357: 
        !           358:   if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
        !           359:     {
        !           360:       nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
        !           361:       IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
        !           362:       return;
        !           363:     }
        !           364: 
        !           365:   /* The purpose of the next hop RTE is to eliminate packets being
        !           366:    routed through extra hops in the system.  It is particularly useful
        !           367:    when RIPng is not being run on all of the routers on a network.
        !           368:    Note that next hop RTE is "advisory".  That is, if the provided
        !           369:    information is ignored, a possibly sub-optimal, but absolutely
        !           370:    valid, route may be taken.  If the received next hop address is not
        !           371:    a link-local address, it should be treated as 0:0:0:0:0:0:0:0.  */
        !           372:   zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
        !           373:             inet6_ntoa (rte->addr),
        !           374:             inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
        !           375: 
        !           376:   nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
        !           377:   memset (&nexthop->address, 0, sizeof (struct in6_addr));
        !           378: 
        !           379:   return;
        !           380: }
        !           381: 
        !           382: /* If ifp has same link-local address then return 1. */
        !           383: static int
        !           384: ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
        !           385: {
        !           386:   struct listnode *node;
        !           387:   struct connected *connected;
        !           388:   struct prefix *p;
        !           389: 
        !           390:   for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
        !           391:     {
        !           392:       p = connected->address;
        !           393: 
        !           394:       if (p->family == AF_INET6 &&
        !           395:           IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
        !           396:           IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
        !           397:         return 1;
        !           398:     }
        !           399:   return 0;
        !           400: }
        !           401: 
        !           402: /* RIPng route garbage collect timer. */
        !           403: static int
        !           404: ripng_garbage_collect (struct thread *t)
        !           405: {
        !           406:   struct ripng_info *rinfo;
        !           407:   struct route_node *rp;
        !           408: 
        !           409:   rinfo = THREAD_ARG (t);
        !           410:   rinfo->t_garbage_collect = NULL;
        !           411: 
        !           412:   /* Off timeout timer. */
        !           413:   RIPNG_TIMER_OFF (rinfo->t_timeout);
        !           414:   
        !           415:   /* Get route_node pointer. */
        !           416:   rp = rinfo->rp;
        !           417: 
        !           418:   /* Unlock route_node. */
        !           419:   rp->info = NULL;
        !           420:   route_unlock_node (rp);
        !           421: 
        !           422:   /* Free RIPng routing information. */
        !           423:   ripng_info_free (rinfo);
        !           424: 
        !           425:   return 0;
        !           426: }
        !           427: 
        !           428: /* Timeout RIPng routes. */
        !           429: static int
        !           430: ripng_timeout (struct thread *t)
        !           431: {
        !           432:   struct ripng_info *rinfo;
        !           433:   struct route_node *rp;
        !           434: 
        !           435:   rinfo = THREAD_ARG (t);
        !           436:   rinfo->t_timeout = NULL;
        !           437: 
        !           438:   /* Get route_node pointer. */
        !           439:   rp = rinfo->rp;
        !           440: 
        !           441:   /* - The garbage-collection timer is set for 120 seconds. */
        !           442:   RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, 
        !           443:                  ripng->garbage_time);
        !           444: 
        !           445:   /* Delete this route from the kernel. */
        !           446:   ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
        !           447:                                rinfo->ifindex);
        !           448:   /* - The metric for the route is set to 16 (infinity).  This causes
        !           449:      the route to be removed from service. */
        !           450:   rinfo->metric = RIPNG_METRIC_INFINITY;
        !           451:   rinfo->flags &= ~RIPNG_RTF_FIB;
        !           452: 
        !           453:   /* Aggregate count decrement. */
        !           454:   ripng_aggregate_decrement (rp, rinfo);
        !           455: 
        !           456:   /* - The route change flag is to indicate that this entry has been
        !           457:      changed. */
        !           458:   rinfo->flags |= RIPNG_RTF_CHANGED;
        !           459: 
        !           460:   /* - The output process is signalled to trigger a response. */
        !           461:   ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
        !           462: 
        !           463:   return 0;
        !           464: }
        !           465: 
        !           466: static void
        !           467: ripng_timeout_update (struct ripng_info *rinfo)
        !           468: {
        !           469:   if (rinfo->metric != RIPNG_METRIC_INFINITY)
        !           470:     {
        !           471:       RIPNG_TIMER_OFF (rinfo->t_timeout);
        !           472:       RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
        !           473:     }
        !           474: }
        !           475: 
        !           476: static int
        !           477: ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
        !           478: {
        !           479:   struct distribute *dist;
        !           480:   struct access_list *alist;
        !           481:   struct prefix_list *plist;
        !           482: 
        !           483:   /* Input distribute-list filtering. */
        !           484:   if (ri->list[RIPNG_FILTER_IN])
        !           485:     {
        !           486:       if (access_list_apply (ri->list[RIPNG_FILTER_IN], 
        !           487:                             (struct prefix *) p) == FILTER_DENY)
        !           488:        {
        !           489:          if (IS_RIPNG_DEBUG_PACKET)
        !           490:            zlog_debug ("%s/%d filtered by distribute in",
        !           491:                       inet6_ntoa (p->prefix), p->prefixlen);
        !           492:          return -1;
        !           493:        }
        !           494:     }
        !           495:   if (ri->prefix[RIPNG_FILTER_IN])
        !           496:     {
        !           497:       if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], 
        !           498:                             (struct prefix *) p) == PREFIX_DENY)
        !           499:        {
        !           500:          if (IS_RIPNG_DEBUG_PACKET)
        !           501:            zlog_debug ("%s/%d filtered by prefix-list in",
        !           502:                       inet6_ntoa (p->prefix), p->prefixlen);
        !           503:          return -1;
        !           504:        }
        !           505:     }
        !           506: 
        !           507:   /* All interface filter check. */
        !           508:   dist = distribute_lookup (NULL);
        !           509:   if (dist)
        !           510:     {
        !           511:       if (dist->list[DISTRIBUTE_IN])
        !           512:        {
        !           513:          alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
        !           514:            
        !           515:          if (alist)
        !           516:            {
        !           517:              if (access_list_apply (alist,
        !           518:                                     (struct prefix *) p) == FILTER_DENY)
        !           519:                {
        !           520:                  if (IS_RIPNG_DEBUG_PACKET)
        !           521:                    zlog_debug ("%s/%d filtered by distribute in",
        !           522:                               inet6_ntoa (p->prefix), p->prefixlen);
        !           523:                  return -1;
        !           524:                }
        !           525:            }
        !           526:        }
        !           527:       if (dist->prefix[DISTRIBUTE_IN])
        !           528:        {
        !           529:          plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
        !           530:          
        !           531:          if (plist)
        !           532:            {
        !           533:              if (prefix_list_apply (plist,
        !           534:                                     (struct prefix *) p) == PREFIX_DENY)
        !           535:                {
        !           536:                  if (IS_RIPNG_DEBUG_PACKET)
        !           537:                    zlog_debug ("%s/%d filtered by prefix-list in",
        !           538:                               inet6_ntoa (p->prefix), p->prefixlen);
        !           539:                  return -1;
        !           540:                }
        !           541:            }
        !           542:        }
        !           543:     }
        !           544:   return 0;
        !           545: }
        !           546: 
        !           547: static int
        !           548: ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
        !           549: {
        !           550:   struct distribute *dist;
        !           551:   struct access_list *alist;
        !           552:   struct prefix_list *plist;
        !           553: 
        !           554:   if (ri->list[RIPNG_FILTER_OUT])
        !           555:     {
        !           556:       if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
        !           557:                             (struct prefix *) p) == FILTER_DENY)
        !           558:        {
        !           559:          if (IS_RIPNG_DEBUG_PACKET)
        !           560:            zlog_debug ("%s/%d is filtered by distribute out",
        !           561:                       inet6_ntoa (p->prefix), p->prefixlen);
        !           562:          return -1;
        !           563:        }
        !           564:     }
        !           565:   if (ri->prefix[RIPNG_FILTER_OUT])
        !           566:     {
        !           567:       if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
        !           568:                             (struct prefix *) p) == PREFIX_DENY)
        !           569:        {
        !           570:          if (IS_RIPNG_DEBUG_PACKET)
        !           571:            zlog_debug ("%s/%d is filtered by prefix-list out",
        !           572:                       inet6_ntoa (p->prefix), p->prefixlen);
        !           573:          return -1;
        !           574:        }
        !           575:     }
        !           576: 
        !           577:   /* All interface filter check. */
        !           578:   dist = distribute_lookup (NULL);
        !           579:   if (dist)
        !           580:     {
        !           581:       if (dist->list[DISTRIBUTE_OUT])
        !           582:        {
        !           583:          alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
        !           584:            
        !           585:          if (alist)
        !           586:            {
        !           587:              if (access_list_apply (alist,
        !           588:                                     (struct prefix *) p) == FILTER_DENY)
        !           589:                {
        !           590:                  if (IS_RIPNG_DEBUG_PACKET)
        !           591:                    zlog_debug ("%s/%d filtered by distribute out",
        !           592:                               inet6_ntoa (p->prefix), p->prefixlen);
        !           593:                  return -1;
        !           594:                }
        !           595:            }
        !           596:        }
        !           597:       if (dist->prefix[DISTRIBUTE_OUT])
        !           598:        {
        !           599:          plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
        !           600:          
        !           601:          if (plist)
        !           602:            {
        !           603:              if (prefix_list_apply (plist,
        !           604:                                     (struct prefix *) p) == PREFIX_DENY)
        !           605:                {
        !           606:                  if (IS_RIPNG_DEBUG_PACKET)
        !           607:                    zlog_debug ("%s/%d filtered by prefix-list out",
        !           608:                               inet6_ntoa (p->prefix), p->prefixlen);
        !           609:                  return -1;
        !           610:                }
        !           611:            }
        !           612:        }
        !           613:     }
        !           614:   return 0;
        !           615: }
        !           616: 
        !           617: /* Process RIPng route according to RFC2080. */
        !           618: static void
        !           619: ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
        !           620:                     struct ripng_nexthop *ripng_nexthop,
        !           621:                     struct interface *ifp)
        !           622: {
        !           623:   int ret;
        !           624:   struct prefix_ipv6 p;
        !           625:   struct route_node *rp;
        !           626:   struct ripng_info *rinfo;
        !           627:   struct ripng_interface *ri;
        !           628:   struct in6_addr *nexthop;
        !           629:   u_char oldmetric;
        !           630:   int same = 0;
        !           631: 
        !           632:   /* Make prefix structure. */
        !           633:   memset (&p, 0, sizeof (struct prefix_ipv6));
        !           634:   p.family = AF_INET6;
        !           635:   /* p.prefix = rte->addr; */
        !           636:   IPV6_ADDR_COPY (&p.prefix, &rte->addr);
        !           637:   p.prefixlen = rte->prefixlen;
        !           638: 
        !           639:   /* Make sure mask is applied. */
        !           640:   /* XXX We have to check the prefix is valid or not before call
        !           641:      apply_mask_ipv6. */
        !           642:   apply_mask_ipv6 (&p);
        !           643: 
        !           644:   /* Apply input filters. */
        !           645:   ri = ifp->info;
        !           646: 
        !           647:   ret = ripng_incoming_filter (&p, ri);
        !           648:   if (ret < 0)
        !           649:     return;
        !           650: 
        !           651:   /* Modify entry. */
        !           652:   if (ri->routemap[RIPNG_FILTER_IN])
        !           653:     {
        !           654:       int ret;
        !           655:       struct ripng_info newinfo;
        !           656: 
        !           657:       memset (&newinfo, 0, sizeof (struct ripng_info));
        !           658:       newinfo.type = ZEBRA_ROUTE_RIPNG;
        !           659:       newinfo.sub_type = RIPNG_ROUTE_RTE;
        !           660:       if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
        !           661:         newinfo.nexthop = ripng_nexthop->address;
        !           662:       else
        !           663:         newinfo.nexthop = from->sin6_addr;
        !           664:       newinfo.from   = from->sin6_addr;
        !           665:       newinfo.ifindex = ifp->ifindex;
        !           666:       newinfo.metric = rte->metric;
        !           667:       newinfo.metric_out = rte->metric; /* XXX */
        !           668:       newinfo.tag    = ntohs(rte->tag); /* XXX */
        !           669: 
        !           670:       ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN], 
        !           671:                             (struct prefix *)&p, RMAP_RIPNG, &newinfo);
        !           672: 
        !           673:       if (ret == RMAP_DENYMATCH)
        !           674:        {
        !           675:          if (IS_RIPNG_DEBUG_PACKET)
        !           676:            zlog_debug ("RIPng %s/%d is filtered by route-map in",
        !           677:                       inet6_ntoa (p.prefix), p.prefixlen);
        !           678:          return;
        !           679:        }
        !           680: 
        !           681:       /* Get back the object */
        !           682:       if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
        !           683:        if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
        !           684:          /* the nexthop get changed by the routemap */
        !           685:          if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
        !           686:            ripng_nexthop->address = newinfo.nexthop;
        !           687:          else
        !           688:            ripng_nexthop->address = in6addr_any;
        !           689:        }
        !           690:       } else {
        !           691:        if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
        !           692:          /* the nexthop get changed by the routemap */
        !           693:          if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
        !           694:            ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
        !           695:            ripng_nexthop->address = newinfo.nexthop;
        !           696:          }
        !           697:        }
        !           698:       }
        !           699:       rte->tag     = htons(newinfo.tag_out); /* XXX */
        !           700:       rte->metric  = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
        !           701:     }
        !           702: 
        !           703:   /* Once the entry has been validated, update the metric by
        !           704:    * adding the cost of the network on wich the message
        !           705:    * arrived. If the result is greater than infinity, use infinity
        !           706:    * (RFC2453 Sec. 3.9.2)
        !           707:    **/
        !           708:  
        !           709:   /* Zebra ripngd can handle offset-list in. */
        !           710:   ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
        !           711: 
        !           712:   /* If offset-list does not modify the metric use interface's
        !           713:    * one. */
        !           714:   if (! ret)
        !           715:     rte->metric += ifp->metric;
        !           716: 
        !           717:   if (rte->metric > RIPNG_METRIC_INFINITY)
        !           718:     rte->metric = RIPNG_METRIC_INFINITY;
        !           719: 
        !           720:   /* Set nexthop pointer. */
        !           721:   if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
        !           722:     nexthop = &ripng_nexthop->address;
        !           723:   else
        !           724:     nexthop = &from->sin6_addr;
        !           725: 
        !           726:   /* Lookup RIPng routing table. */
        !           727:   rp = route_node_get (ripng->table, (struct prefix *) &p);
        !           728: 
        !           729:   /* Sanity check */
        !           730:   rinfo = rp->info;
        !           731:   if (rinfo)
        !           732:     {
        !           733:       /* Redistributed route check. */
        !           734:       if (rinfo->type != ZEBRA_ROUTE_RIPNG
        !           735:          && rinfo->metric != RIPNG_METRIC_INFINITY)
        !           736:        return;
        !           737: 
        !           738:       /* Local static route. */
        !           739:       if (rinfo->type == ZEBRA_ROUTE_RIPNG
        !           740:          && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
        !           741:              (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
        !           742:          && rinfo->metric != RIPNG_METRIC_INFINITY)
        !           743:        return;
        !           744:     }
        !           745: 
        !           746:   if (rp->info == NULL)
        !           747:     {
        !           748:       /* Now, check to see whether there is already an explicit route
        !           749:         for the destination prefix.  If there is no such route, add
        !           750:         this route to the routing table, unless the metric is
        !           751:         infinity (there is no point in adding a route which
        !           752:         unusable). */
        !           753:       if (rte->metric != RIPNG_METRIC_INFINITY)
        !           754:        {
        !           755:          rinfo = ripng_info_new ();
        !           756:          
        !           757:          /* - Setting the destination prefix and length to those in
        !           758:             the RTE. */
        !           759:          rp->info = rinfo;
        !           760:          rinfo->rp = rp;
        !           761: 
        !           762:          /* - Setting the metric to the newly calculated metric (as
        !           763:             described above). */
        !           764:          rinfo->metric = rte->metric;
        !           765:          rinfo->tag = ntohs (rte->tag);
        !           766: 
        !           767:          /* - Set the next hop address to be the address of the router
        !           768:             from which the datagram came or the next hop address
        !           769:             specified by a next hop RTE. */
        !           770:          IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
        !           771:          IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
        !           772:          rinfo->ifindex = ifp->ifindex;
        !           773: 
        !           774:          /* - Initialize the timeout for the route.  If the
        !           775:             garbage-collection timer is running for this route, stop it. */
        !           776:          ripng_timeout_update (rinfo);
        !           777: 
        !           778:          /* - Set the route change flag. */
        !           779:          rinfo->flags |= RIPNG_RTF_CHANGED;
        !           780: 
        !           781:          /* - Signal the output process to trigger an update (see section
        !           782:             2.5). */
        !           783:          ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
        !           784: 
        !           785:          /* Finally, route goes into the kernel. */
        !           786:          rinfo->type = ZEBRA_ROUTE_RIPNG;
        !           787:          rinfo->sub_type = RIPNG_ROUTE_RTE;
        !           788: 
        !           789:          ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex,
        !           790:                                rinfo->metric);
        !           791:          rinfo->flags |= RIPNG_RTF_FIB;
        !           792: 
        !           793:          /* Aggregate check. */
        !           794:          ripng_aggregate_increment (rp, rinfo);
        !           795:        }
        !           796:     }
        !           797:   else
        !           798:     {
        !           799:       rinfo = rp->info;
        !           800:          
        !           801:       /* If there is an existing route, compare the next hop address
        !           802:         to the address of the router from which the datagram came.
        !           803:         If this datagram is from the same router as the existing
        !           804:         route, reinitialize the timeout.  */
        !           805:       same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) 
        !           806:              && (rinfo->ifindex == ifp->ifindex));
        !           807: 
        !           808:       if (same)
        !           809:        ripng_timeout_update (rinfo);
        !           810: 
        !           811:       /* Next, compare the metrics.  If the datagram is from the same
        !           812:         router as the existing route, and the new metric is different
        !           813:         than the old one; or, if the new metric is lower than the old
        !           814:         one; do the following actions: */
        !           815:       if ((same && rinfo->metric != rte->metric) ||
        !           816:          rte->metric < rinfo->metric)
        !           817:        {
        !           818:          /* - Adopt the route from the datagram.  That is, put the
        !           819:             new metric in, and adjust the next hop address (if
        !           820:             necessary). */
        !           821:          oldmetric = rinfo->metric;
        !           822:          rinfo->metric = rte->metric;
        !           823:          rinfo->tag = ntohs (rte->tag);
        !           824:          IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
        !           825:          rinfo->ifindex = ifp->ifindex;
        !           826: 
        !           827:          /* Should a new route to this network be established
        !           828:             while the garbage-collection timer is running, the
        !           829:             new route will replace the one that is about to be
        !           830:             deleted.  In this case the garbage-collection timer
        !           831:             must be cleared. */
        !           832: 
        !           833:          if (oldmetric == RIPNG_METRIC_INFINITY &&
        !           834:              rinfo->metric < RIPNG_METRIC_INFINITY)
        !           835:            {
        !           836:              rinfo->type = ZEBRA_ROUTE_RIPNG;
        !           837:              rinfo->sub_type = RIPNG_ROUTE_RTE;
        !           838: 
        !           839:              RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
        !           840: 
        !           841:              if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
        !           842:                IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
        !           843: 
        !           844:              ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
        !           845:              rinfo->flags |= RIPNG_RTF_FIB;
        !           846: 
        !           847:              /* The aggregation counter needs to be updated because
        !           848:                     the prefixes, which are into the gc, have been
        !           849:                         removed from the aggregator (see ripng_timout). */
        !           850:                  ripng_aggregate_increment (rp, rinfo);
        !           851:            }
        !           852: 
        !           853:          /* Update nexthop and/or metric value.  */
        !           854:          if (oldmetric != RIPNG_METRIC_INFINITY)
        !           855:            {
        !           856:              ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
        !           857:              ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
        !           858:              rinfo->flags |= RIPNG_RTF_FIB;
        !           859: 
        !           860:              if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
        !           861:                IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
        !           862:            }
        !           863: 
        !           864:          /* - Set the route change flag and signal the output process
        !           865:             to trigger an update. */
        !           866:          rinfo->flags |= RIPNG_RTF_CHANGED;
        !           867:          ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
        !           868: 
        !           869:          /* - If the new metric is infinity, start the deletion
        !           870:             process (described above); */
        !           871:          if (rinfo->metric == RIPNG_METRIC_INFINITY)
        !           872:            {
        !           873:              /* If the new metric is infinity, the deletion process
        !           874:                 begins for the route, which is no longer used for
        !           875:                 routing packets.  Note that the deletion process is
        !           876:                 started only when the metric is first set to
        !           877:                 infinity.  If the metric was already infinity, then a
        !           878:                 new deletion process is not started. */
        !           879:              if (oldmetric != RIPNG_METRIC_INFINITY)
        !           880:                {
        !           881:                  /* - The garbage-collection timer is set for 120 seconds. */
        !           882:                  RIPNG_TIMER_ON (rinfo->t_garbage_collect, 
        !           883:                                  ripng_garbage_collect, ripng->garbage_time);
        !           884:                  RIPNG_TIMER_OFF (rinfo->t_timeout);
        !           885: 
        !           886:                  /* - The metric for the route is set to 16
        !           887:                     (infinity).  This causes the route to be removed
        !           888:                     from service.*/
        !           889:                  ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
        !           890:                  rinfo->flags &= ~RIPNG_RTF_FIB;
        !           891: 
        !           892:                  /* Aggregate count decrement. */
        !           893:                  ripng_aggregate_decrement (rp, rinfo);
        !           894: 
        !           895:                  /* - The route change flag is to indicate that this
        !           896:                     entry has been changed. */
        !           897:                  /* - The output process is signalled to trigger a
        !           898:                      response. */
        !           899:                  ;  /* Above processes are already done previously. */
        !           900:                }
        !           901:            }
        !           902:          else
        !           903:            {
        !           904:              /* otherwise, re-initialize the timeout. */
        !           905:              ripng_timeout_update (rinfo);
        !           906:            }
        !           907:        }
        !           908:       /* Unlock tempolary lock of the route. */
        !           909:       route_unlock_node (rp);
        !           910:     }
        !           911: }
        !           912: 
        !           913: /* Add redistributed route to RIPng table. */
        !           914: void
        !           915: ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, 
        !           916:                        unsigned int ifindex, struct in6_addr *nexthop)
        !           917: {
        !           918:   struct route_node *rp;
        !           919:   struct ripng_info *rinfo;
        !           920: 
        !           921:   /* Redistribute route  */
        !           922:   if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
        !           923:     return;
        !           924:   if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
        !           925:     return;
        !           926: #if defined (MUSICA) || defined (LINUX)
        !           927:   /* XXX As long as the RIPng redistribution is applied to all the connected
        !           928:    *     routes, one needs to filter the ::/96 prefixes.
        !           929:    *     However it could be a wanted case, it will be removed soon.
        !           930:    */
        !           931:   if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
        !           932:       (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
        !           933:     return;
        !           934: #endif /* MUSICA or LINUX */
        !           935: 
        !           936:   rp = route_node_get (ripng->table, (struct prefix *) p);
        !           937:   rinfo = rp->info;
        !           938: 
        !           939:   if (rinfo)
        !           940:     {
        !           941:       if (rinfo->type == ZEBRA_ROUTE_CONNECT
        !           942:           && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
        !           943:          && rinfo->metric != RIPNG_METRIC_INFINITY) {
        !           944:         route_unlock_node (rp);
        !           945:           return;
        !           946:       }
        !           947: 
        !           948:       /* Manually configured RIPng route check.
        !           949:        * They have the precedence on all the other entries.
        !           950:        **/
        !           951:       if (rinfo->type == ZEBRA_ROUTE_RIPNG
        !           952:           && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
        !           953:               (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
        !           954:         if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
        !           955:                                           (sub_type != RIPNG_ROUTE_DEFAULT))) {
        !           956:          route_unlock_node (rp);
        !           957:          return;
        !           958:        }
        !           959:       }
        !           960:       
        !           961:       RIPNG_TIMER_OFF (rinfo->t_timeout);
        !           962:       RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
        !           963: 
        !           964:       /* Tells the other daemons about the deletion of
        !           965:        * this RIPng route
        !           966:        **/
        !           967:       if (ripng_route_rte (rinfo))
        !           968:        ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
        !           969:                               rinfo->metric);
        !           970: 
        !           971:       rp->info = NULL;
        !           972:       ripng_info_free (rinfo);
        !           973: 
        !           974:       route_unlock_node (rp);
        !           975: 
        !           976:     }
        !           977: 
        !           978:   rinfo = ripng_info_new ();
        !           979: 
        !           980:   rinfo->type = type;
        !           981:   rinfo->sub_type = sub_type;
        !           982:   rinfo->ifindex = ifindex;
        !           983:   rinfo->metric = 1;
        !           984:   rinfo->rp = rp;
        !           985:   
        !           986:   if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
        !           987:     rinfo->nexthop = *nexthop;
        !           988:   
        !           989:   rinfo->flags |= RIPNG_RTF_FIB;
        !           990:   rp->info = rinfo;
        !           991: 
        !           992:   /* Aggregate check. */
        !           993:   ripng_aggregate_increment (rp, rinfo);
        !           994: 
        !           995:   rinfo->flags |= RIPNG_RTF_CHANGED;
        !           996: 
        !           997:   if (IS_RIPNG_DEBUG_EVENT) {
        !           998:     if (!nexthop)
        !           999:       zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
        !          1000:                  inet6_ntoa(p->prefix), p->prefixlen,
        !          1001:                  ifindex2ifname(ifindex));
        !          1002:     else
        !          1003:       zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
        !          1004:                  inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
        !          1005:                  ifindex2ifname(ifindex));
        !          1006:   }
        !          1007: 
        !          1008:   ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
        !          1009: }
        !          1010: 
        !          1011: /* Delete redistributed route to RIPng table. */
        !          1012: void
        !          1013: ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, 
        !          1014:                           unsigned int ifindex)
        !          1015: {
        !          1016:   struct route_node *rp;
        !          1017:   struct ripng_info *rinfo;
        !          1018: 
        !          1019:   if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
        !          1020:     return;
        !          1021:   if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
        !          1022:     return;
        !          1023: #if defined (MUSICA) || defined (LINUX)
        !          1024:   /* XXX As long as the RIPng redistribution is applied to all the connected
        !          1025:    *     routes, one needs to filter the ::/96 prefixes.
        !          1026:    *     However it could be a wanted case, it will be removed soon.
        !          1027:    */
        !          1028:   if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
        !          1029:       (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
        !          1030:     return;
        !          1031: #endif /* MUSICA or LINUX */
        !          1032: 
        !          1033:   rp = route_node_lookup (ripng->table, (struct prefix *) p);
        !          1034: 
        !          1035:   if (rp)
        !          1036:     {
        !          1037:       rinfo = rp->info;
        !          1038: 
        !          1039:       if (rinfo != NULL
        !          1040:          && rinfo->type == type 
        !          1041:          && rinfo->sub_type == sub_type 
        !          1042:          && rinfo->ifindex == ifindex)
        !          1043:        {
        !          1044:          /* Perform poisoned reverse. */
        !          1045:          rinfo->metric = RIPNG_METRIC_INFINITY;
        !          1046:          RIPNG_TIMER_ON (rinfo->t_garbage_collect, 
        !          1047:                        ripng_garbage_collect, ripng->garbage_time);
        !          1048:          RIPNG_TIMER_OFF (rinfo->t_timeout);
        !          1049: 
        !          1050:          /* Aggregate count decrement. */
        !          1051:          ripng_aggregate_decrement (rp, rinfo);
        !          1052: 
        !          1053:          rinfo->flags |= RIPNG_RTF_CHANGED;
        !          1054:          
        !          1055:           if (IS_RIPNG_DEBUG_EVENT)
        !          1056:             zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
        !          1057:                        inet6_ntoa(p->prefix), p->prefixlen,
        !          1058:                        ifindex2ifname(ifindex));
        !          1059: 
        !          1060:          ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
        !          1061:        }
        !          1062:     }
        !          1063: }
        !          1064: 
        !          1065: /* Withdraw redistributed route. */
        !          1066: void
        !          1067: ripng_redistribute_withdraw (int type)
        !          1068: {
        !          1069:   struct route_node *rp;
        !          1070:   struct ripng_info *rinfo;
        !          1071: 
        !          1072:   if (!ripng)
        !          1073:     return;
        !          1074:   
        !          1075:   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
        !          1076:     if ((rinfo = rp->info) != NULL)
        !          1077:       {
        !          1078:        if ((rinfo->type == type)
        !          1079:            && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
        !          1080:          {
        !          1081:            /* Perform poisoned reverse. */
        !          1082:            rinfo->metric = RIPNG_METRIC_INFINITY;
        !          1083:            RIPNG_TIMER_ON (rinfo->t_garbage_collect, 
        !          1084:                          ripng_garbage_collect, ripng->garbage_time);
        !          1085:            RIPNG_TIMER_OFF (rinfo->t_timeout);
        !          1086: 
        !          1087:            /* Aggregate count decrement. */
        !          1088:            ripng_aggregate_decrement (rp, rinfo);
        !          1089: 
        !          1090:            rinfo->flags |= RIPNG_RTF_CHANGED;
        !          1091: 
        !          1092:            if (IS_RIPNG_DEBUG_EVENT) {
        !          1093:              struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
        !          1094: 
        !          1095:              zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
        !          1096:                         inet6_ntoa(p->prefix), p->prefixlen,
        !          1097:                         ifindex2ifname(rinfo->ifindex));
        !          1098:            }
        !          1099: 
        !          1100:            ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
        !          1101:          }
        !          1102:       }
        !          1103: }
        !          1104: 
        !          1105: /* RIP routing information. */
        !          1106: static void
        !          1107: ripng_response_process (struct ripng_packet *packet, int size, 
        !          1108:                        struct sockaddr_in6 *from, struct interface *ifp,
        !          1109:                        int hoplimit)
        !          1110: {
        !          1111:   caddr_t lim;
        !          1112:   struct rte *rte;
        !          1113:   struct ripng_nexthop nexthop;
        !          1114: 
        !          1115:   /* RFC2080 2.4.2  Response Messages:
        !          1116:    The Response must be ignored if it is not from the RIPng port.  */
        !          1117:   if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
        !          1118:     {
        !          1119:       zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
        !          1120:                 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
        !          1121:       ripng_peer_bad_packet (from);
        !          1122:       return;
        !          1123:     }
        !          1124: 
        !          1125:   /* The datagram's IPv6 source address should be checked to see
        !          1126:    whether the datagram is from a valid neighbor; the source of the
        !          1127:    datagram must be a link-local address.  */
        !          1128:   if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
        !          1129:    {
        !          1130:       zlog_warn ("RIPng packet comes from non link local address %s",
        !          1131:                 inet6_ntoa (from->sin6_addr));
        !          1132:       ripng_peer_bad_packet (from);
        !          1133:       return;
        !          1134:     }
        !          1135: 
        !          1136:   /* It is also worth checking to see whether the response is from one
        !          1137:    of the router's own addresses.  Interfaces on broadcast networks
        !          1138:    may receive copies of their own multicasts immediately.  If a
        !          1139:    router processes its own output as new input, confusion is likely,
        !          1140:    and such datagrams must be ignored. */
        !          1141:   if (ripng_lladdr_check (ifp, &from->sin6_addr))
        !          1142:     {
        !          1143:       zlog_warn ("RIPng packet comes from my own link local address %s",
        !          1144:                 inet6_ntoa (from->sin6_addr));
        !          1145:       ripng_peer_bad_packet (from);
        !          1146:       return;
        !          1147:     }
        !          1148: 
        !          1149:   /* As an additional check, periodic advertisements must have their
        !          1150:    hop counts set to 255, and inbound, multicast packets sent from the
        !          1151:    RIPng port (i.e. periodic advertisement or triggered update
        !          1152:    packets) must be examined to ensure that the hop count is 255. */
        !          1153:   if (hoplimit >= 0 && hoplimit != 255)
        !          1154:     {
        !          1155:       zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
        !          1156:                 hoplimit, inet6_ntoa (from->sin6_addr));
        !          1157:       ripng_peer_bad_packet (from);
        !          1158:       return;
        !          1159:     }
        !          1160: 
        !          1161:   /* Update RIPng peer. */
        !          1162:   ripng_peer_update (from, packet->version);
        !          1163:   
        !          1164:   /* Reset nexthop. */
        !          1165:   memset (&nexthop, 0, sizeof (struct ripng_nexthop));
        !          1166:   nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
        !          1167: 
        !          1168:   /* Set RTE pointer. */
        !          1169:   rte = packet->rte;
        !          1170: 
        !          1171:   for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++) 
        !          1172:     {
        !          1173:       /* First of all, we have to check this RTE is next hop RTE or
        !          1174:          not.  Next hop RTE is completely different with normal RTE so
        !          1175:          we need special treatment. */
        !          1176:       if (rte->metric == RIPNG_METRIC_NEXTHOP)
        !          1177:        {
        !          1178:          ripng_nexthop_rte (rte, from, &nexthop);
        !          1179:          continue;
        !          1180:        }
        !          1181: 
        !          1182:       /* RTE information validation. */
        !          1183: 
        !          1184:       /* - is the destination prefix valid (e.g., not a multicast
        !          1185:          prefix and not a link-local address) A link-local address
        !          1186:          should never be present in an RTE. */
        !          1187:       if (IN6_IS_ADDR_MULTICAST (&rte->addr))
        !          1188:        {
        !          1189:          zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
        !          1190:                     inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
        !          1191:          ripng_peer_bad_route (from);
        !          1192:          continue;
        !          1193:        }
        !          1194:       if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
        !          1195:        {
        !          1196:          zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
        !          1197:                     inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
        !          1198:          ripng_peer_bad_route (from);
        !          1199:          continue;
        !          1200:        }
        !          1201:       if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
        !          1202:        {
        !          1203:          zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
        !          1204:                     inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
        !          1205:          ripng_peer_bad_route (from);
        !          1206:          continue;
        !          1207:        }
        !          1208: 
        !          1209:       /* - is the prefix length valid (i.e., between 0 and 128,
        !          1210:          inclusive) */
        !          1211:       if (rte->prefixlen > 128)
        !          1212:        {
        !          1213:          zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
        !          1214:                     inet6_ntoa (rte->addr), rte->prefixlen,
        !          1215:                     inet6_ntoa (from->sin6_addr), ifp->name);
        !          1216:          ripng_peer_bad_route (from);
        !          1217:          continue;
        !          1218:        }
        !          1219: 
        !          1220:       /* - is the metric valid (i.e., between 1 and 16, inclusive) */
        !          1221:       if (! (rte->metric >= 1 && rte->metric <= 16))
        !          1222:        {
        !          1223:          zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
        !          1224:                     inet6_ntoa (from->sin6_addr), ifp->name);
        !          1225:          ripng_peer_bad_route (from);
        !          1226:          continue;
        !          1227:        }
        !          1228: 
        !          1229:       /* Vincent: XXX Should we compute the direclty reachable nexthop
        !          1230:        * for our RIPng network ?
        !          1231:        **/
        !          1232: 
        !          1233:       /* Routing table updates. */
        !          1234:       ripng_route_process (rte, from, &nexthop, ifp);
        !          1235:     }
        !          1236: }
        !          1237: 
        !          1238: /* Response to request message. */
        !          1239: static void
        !          1240: ripng_request_process (struct ripng_packet *packet,int size, 
        !          1241:                       struct sockaddr_in6 *from, struct interface *ifp)
        !          1242: {
        !          1243:   caddr_t lim;
        !          1244:   struct rte *rte;
        !          1245:   struct prefix_ipv6 p;
        !          1246:   struct route_node *rp;
        !          1247:   struct ripng_info *rinfo;
        !          1248:   struct ripng_interface *ri;
        !          1249: 
        !          1250:   /* Does not reponse to the requests on the loopback interfaces */
        !          1251:   if (if_is_loopback (ifp))
        !          1252:     return;
        !          1253: 
        !          1254:   /* Check RIPng process is enabled on this interface. */
        !          1255:   ri = ifp->info;
        !          1256:   if (! ri->running)
        !          1257:     return;
        !          1258: 
        !          1259:   /* When passive interface is specified, suppress responses */
        !          1260:   if (ri->passive)
        !          1261:     return;
        !          1262: 
        !          1263:   /* RIPng peer update. */
        !          1264:   ripng_peer_update (from, packet->version);
        !          1265: 
        !          1266:   lim = ((caddr_t) packet) + size;
        !          1267:   rte = packet->rte;
        !          1268: 
        !          1269:   /* The Request is processed entry by entry.  If there are no
        !          1270:      entries, no response is given. */
        !          1271:   if (lim == (caddr_t) rte)
        !          1272:     return;
        !          1273: 
        !          1274:   /* There is one special case.  If there is exactly one entry in the
        !          1275:      request, and it has a destination prefix of zero, a prefix length
        !          1276:      of zero, and a metric of infinity (i.e., 16), then this is a
        !          1277:      request to send the entire routing table.  In that case, a call
        !          1278:      is made to the output process to send the routing table to the
        !          1279:      requesting address/port. */
        !          1280:   if (lim == ((caddr_t) (rte + 1)) &&
        !          1281:       IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
        !          1282:       rte->prefixlen == 0 &&
        !          1283:       rte->metric == RIPNG_METRIC_INFINITY)
        !          1284:     {  
        !          1285:       /* All route with split horizon */
        !          1286:       ripng_output_process (ifp, from, ripng_all_route);
        !          1287:     }
        !          1288:   else
        !          1289:     {
        !          1290:       /* Except for this special case, processing is quite simple.
        !          1291:         Examine the list of RTEs in the Request one by one.  For each
        !          1292:         entry, look up the destination in the router's routing
        !          1293:         database and, if there is a route, put that route's metric in
        !          1294:         the metric field of the RTE.  If there is no explicit route
        !          1295:         to the specified destination, put infinity in the metric
        !          1296:         field.  Once all the entries have been filled in, change the
        !          1297:         command from Request to Response and send the datagram back
        !          1298:         to the requestor. */
        !          1299:       memset (&p, 0, sizeof (struct prefix_ipv6));
        !          1300:       p.family = AF_INET6;
        !          1301: 
        !          1302:       for (; ((caddr_t) rte) < lim; rte++)
        !          1303:        {
        !          1304:          p.prefix = rte->addr;
        !          1305:          p.prefixlen = rte->prefixlen;
        !          1306:          apply_mask_ipv6 (&p);
        !          1307:          
        !          1308:          rp = route_node_lookup (ripng->table, (struct prefix *) &p);
        !          1309: 
        !          1310:          if (rp)
        !          1311:            {
        !          1312:              rinfo = rp->info;
        !          1313:              rte->metric = rinfo->metric;
        !          1314:              route_unlock_node (rp);
        !          1315:            }
        !          1316:          else
        !          1317:            rte->metric = RIPNG_METRIC_INFINITY;
        !          1318:        }
        !          1319:       packet->command = RIPNG_RESPONSE;
        !          1320: 
        !          1321:       ripng_send_packet ((caddr_t) packet, size, from, ifp);
        !          1322:     }
        !          1323: }
        !          1324: 
        !          1325: /* First entry point of reading RIPng packet. */
        !          1326: static int
        !          1327: ripng_read (struct thread *thread)
        !          1328: {
        !          1329:   int len;
        !          1330:   int sock;
        !          1331:   struct sockaddr_in6 from;
        !          1332:   struct ripng_packet *packet;
        !          1333:   unsigned int ifindex;
        !          1334:   struct interface *ifp;
        !          1335:   int hoplimit = -1;
        !          1336: 
        !          1337:   /* Check ripng is active and alive. */
        !          1338:   assert (ripng != NULL);
        !          1339:   assert (ripng->sock >= 0);
        !          1340: 
        !          1341:   /* Fetch thread data and set read pointer to empty for event
        !          1342:      managing.  `sock' sould be same as ripng->sock. */
        !          1343:   sock = THREAD_FD (thread);
        !          1344:   ripng->t_read = NULL;
        !          1345: 
        !          1346:   /* Add myself to the next event. */
        !          1347:   ripng_event (RIPNG_READ, sock);
        !          1348: 
        !          1349:   /* Read RIPng packet. */
        !          1350:   len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf), 
        !          1351:                           STREAM_SIZE (ripng->ibuf), &from, &ifindex,
        !          1352:                           &hoplimit);
        !          1353:   if (len < 0) 
        !          1354:     {
        !          1355:       zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
        !          1356:       return len;
        !          1357:     }
        !          1358: 
        !          1359:   /* Check RTE boundary.  RTE size (Packet length - RIPng header size
        !          1360:      (4)) must be multiple size of one RTE size (20). */
        !          1361:   if (((len - 4) % 20) != 0)
        !          1362:     {
        !          1363:       zlog_warn ("RIPng invalid packet size %d from %s", len,
        !          1364:                 inet6_ntoa (from.sin6_addr));
        !          1365:       ripng_peer_bad_packet (&from);
        !          1366:       return 0;
        !          1367:     }
        !          1368: 
        !          1369:   packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
        !          1370:   ifp = if_lookup_by_index (ifindex);
        !          1371: 
        !          1372:   /* RIPng packet received. */
        !          1373:   if (IS_RIPNG_DEBUG_EVENT)
        !          1374:     zlog_debug ("RIPng packet received from %s port %d on %s",
        !          1375:               inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port), 
        !          1376:               ifp ? ifp->name : "unknown");
        !          1377: 
        !          1378:   /* Logging before packet checking. */
        !          1379:   if (IS_RIPNG_DEBUG_RECV)
        !          1380:     ripng_packet_dump (packet, len, "RECV");
        !          1381: 
        !          1382:   /* Packet comes from unknown interface. */
        !          1383:   if (ifp == NULL)
        !          1384:     {
        !          1385:       zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
        !          1386:       return 0;
        !          1387:     }
        !          1388: 
        !          1389:   /* Packet version mismatch checking. */
        !          1390:   if (packet->version != ripng->version) 
        !          1391:     {
        !          1392:       zlog_warn ("RIPng packet version %d doesn't fit to my version %d", 
        !          1393:                 packet->version, ripng->version);
        !          1394:       ripng_peer_bad_packet (&from);
        !          1395:       return 0;
        !          1396:     }
        !          1397: 
        !          1398:   /* Process RIPng packet. */
        !          1399:   switch (packet->command)
        !          1400:     {
        !          1401:     case RIPNG_REQUEST:
        !          1402:       ripng_request_process (packet, len, &from, ifp);
        !          1403:       break;
        !          1404:     case RIPNG_RESPONSE:
        !          1405:       ripng_response_process (packet, len, &from, ifp, hoplimit);
        !          1406:       break;
        !          1407:     default:
        !          1408:       zlog_warn ("Invalid RIPng command %d", packet->command);
        !          1409:       ripng_peer_bad_packet (&from);
        !          1410:       break;
        !          1411:     }
        !          1412:   return 0;
        !          1413: }
        !          1414: 
        !          1415: /* Walk down the RIPng routing table then clear changed flag. */
        !          1416: static void
        !          1417: ripng_clear_changed_flag (void)
        !          1418: {
        !          1419:   struct route_node *rp;
        !          1420:   struct ripng_info *rinfo;
        !          1421: 
        !          1422:   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
        !          1423:     if ((rinfo = rp->info) != NULL)
        !          1424:       if (rinfo->flags & RIPNG_RTF_CHANGED)
        !          1425:        rinfo->flags &= ~RIPNG_RTF_CHANGED;
        !          1426: }
        !          1427: 
        !          1428: /* Regular update of RIPng route.  Send all routing formation to RIPng
        !          1429:    enabled interface. */
        !          1430: static int
        !          1431: ripng_update (struct thread *t)
        !          1432: {
        !          1433:   struct listnode *node;
        !          1434:   struct interface *ifp;
        !          1435:   struct ripng_interface *ri;
        !          1436: 
        !          1437:   /* Clear update timer thread. */
        !          1438:   ripng->t_update = NULL;
        !          1439: 
        !          1440:   /* Logging update event. */
        !          1441:   if (IS_RIPNG_DEBUG_EVENT)
        !          1442:     zlog_debug ("RIPng update timer expired!");
        !          1443: 
        !          1444:   /* Supply routes to each interface. */
        !          1445:   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
        !          1446:     {
        !          1447:       ri = ifp->info;
        !          1448: 
        !          1449:       if (if_is_loopback (ifp) || ! if_is_up (ifp))
        !          1450:        continue;
        !          1451: 
        !          1452:       if (! ri->running)
        !          1453:        continue;
        !          1454: 
        !          1455:       /* When passive interface is specified, suppress announce to the
        !          1456:          interface. */
        !          1457:       if (ri->passive)
        !          1458:        continue;
        !          1459: 
        !          1460: #if RIPNG_ADVANCED
        !          1461:       if (ri->ri_send == RIPNG_SEND_OFF)
        !          1462:        {
        !          1463:          if (IS_RIPNG_DEBUG_EVENT)
        !          1464:            zlog (NULL, LOG_DEBUG, 
        !          1465:                  "[Event] RIPng send to if %d is suppressed by config",
        !          1466:                 ifp->ifindex);
        !          1467:          continue;
        !          1468:        }
        !          1469: #endif /* RIPNG_ADVANCED */
        !          1470: 
        !          1471:       ripng_output_process (ifp, NULL, ripng_all_route);
        !          1472:     }
        !          1473: 
        !          1474:   /* Triggered updates may be suppressed if a regular update is due by
        !          1475:      the time the triggered update would be sent. */
        !          1476:   if (ripng->t_triggered_interval)
        !          1477:     {
        !          1478:       thread_cancel (ripng->t_triggered_interval);
        !          1479:       ripng->t_triggered_interval = NULL;
        !          1480:     }
        !          1481:   ripng->trigger = 0;
        !          1482: 
        !          1483:   /* Reset flush event. */
        !          1484:   ripng_event (RIPNG_UPDATE_EVENT, 0);
        !          1485: 
        !          1486:   return 0;
        !          1487: }
        !          1488: 
        !          1489: /* Triggered update interval timer. */
        !          1490: static int
        !          1491: ripng_triggered_interval (struct thread *t)
        !          1492: {
        !          1493:   ripng->t_triggered_interval = NULL;
        !          1494: 
        !          1495:   if (ripng->trigger)
        !          1496:     {
        !          1497:       ripng->trigger = 0;
        !          1498:       ripng_triggered_update (t);
        !          1499:     }
        !          1500:   return 0;
        !          1501: }     
        !          1502: 
        !          1503: /* Execute triggered update. */
        !          1504: int
        !          1505: ripng_triggered_update (struct thread *t)
        !          1506: {
        !          1507:   struct listnode *node;
        !          1508:   struct interface *ifp;
        !          1509:   struct ripng_interface *ri;
        !          1510:   int interval;
        !          1511: 
        !          1512:   ripng->t_triggered_update = NULL;
        !          1513: 
        !          1514:   /* Cancel interval timer. */
        !          1515:   if (ripng->t_triggered_interval)
        !          1516:     {
        !          1517:       thread_cancel (ripng->t_triggered_interval);
        !          1518:       ripng->t_triggered_interval = NULL;
        !          1519:     }
        !          1520:   ripng->trigger = 0;
        !          1521: 
        !          1522:   /* Logging triggered update. */
        !          1523:   if (IS_RIPNG_DEBUG_EVENT)
        !          1524:     zlog_debug ("RIPng triggered update!");
        !          1525: 
        !          1526:   /* Split Horizon processing is done when generating triggered
        !          1527:      updates as well as normal updates (see section 2.6). */
        !          1528:   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
        !          1529:     {
        !          1530:       ri = ifp->info;
        !          1531: 
        !          1532:       if (if_is_loopback (ifp) || ! if_is_up (ifp))
        !          1533:        continue;
        !          1534: 
        !          1535:       if (! ri->running)
        !          1536:        continue;
        !          1537: 
        !          1538:       /* When passive interface is specified, suppress announce to the
        !          1539:          interface. */
        !          1540:       if (ri->passive)
        !          1541:        continue;
        !          1542: 
        !          1543:       ripng_output_process (ifp, NULL, ripng_changed_route);
        !          1544:     }
        !          1545: 
        !          1546:   /* Once all of the triggered updates have been generated, the route
        !          1547:      change flags should be cleared. */
        !          1548:   ripng_clear_changed_flag ();
        !          1549: 
        !          1550:   /* After a triggered update is sent, a timer should be set for a
        !          1551:      random interval between 1 and 5 seconds.  If other changes that
        !          1552:      would trigger updates occur before the timer expires, a single
        !          1553:      update is triggered when the timer expires. */
        !          1554:   interval = (random () % 5) + 1;
        !          1555: 
        !          1556:   ripng->t_triggered_interval = 
        !          1557:     thread_add_timer (master, ripng_triggered_interval, NULL, interval);
        !          1558: 
        !          1559:   return 0;
        !          1560: }
        !          1561: 
        !          1562: /* Write routing table entry to the stream and return next index of
        !          1563:    the routing table entry in the stream. */
        !          1564: int
        !          1565: ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
        !          1566:                 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
        !          1567: {
        !          1568:   /* RIPng packet header. */
        !          1569:   if (num == 0)
        !          1570:     {
        !          1571:       stream_putc (s, RIPNG_RESPONSE);
        !          1572:       stream_putc (s, RIPNG_V1);
        !          1573:       stream_putw (s, 0);
        !          1574:     }
        !          1575: 
        !          1576:   /* Write routing table entry. */
        !          1577:   if (!nexthop)
        !          1578:     stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
        !          1579:   else
        !          1580:     stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
        !          1581:   stream_putw (s, tag);
        !          1582:   if (p)
        !          1583:     stream_putc (s, p->prefixlen);
        !          1584:   else
        !          1585:     stream_putc (s, 0);
        !          1586:   stream_putc (s, metric);
        !          1587: 
        !          1588:   return ++num;
        !          1589: }
        !          1590: 
        !          1591: /* Send RESPONSE message to specified destination. */
        !          1592: void
        !          1593: ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
        !          1594:                      int route_type)
        !          1595: {
        !          1596:   int ret;
        !          1597:   struct route_node *rp;
        !          1598:   struct ripng_info *rinfo;
        !          1599:   struct ripng_interface *ri;
        !          1600:   struct ripng_aggregate *aggregate;
        !          1601:   struct prefix_ipv6 *p;
        !          1602:   struct list * ripng_rte_list;
        !          1603: 
        !          1604:   if (IS_RIPNG_DEBUG_EVENT) {
        !          1605:     if (to)
        !          1606:       zlog_debug ("RIPng update routes to neighbor %s",
        !          1607:                  inet6_ntoa(to->sin6_addr));
        !          1608:     else
        !          1609:       zlog_debug ("RIPng update routes on interface %s", ifp->name);
        !          1610:   }
        !          1611: 
        !          1612:   /* Get RIPng interface. */
        !          1613:   ri = ifp->info;
        !          1614:  
        !          1615:   ripng_rte_list = ripng_rte_new();
        !          1616:  
        !          1617:   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
        !          1618:     {
        !          1619:       if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
        !          1620:        {
        !          1621:          /* If no route-map are applied, the RTE will be these following
        !          1622:           * informations.
        !          1623:           */
        !          1624:          p = (struct prefix_ipv6 *) &rp->p;
        !          1625:          rinfo->metric_out = rinfo->metric;
        !          1626:          rinfo->tag_out    = rinfo->tag;
        !          1627:          memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
        !          1628:          /* In order to avoid some local loops,
        !          1629:           * if the RIPng route has a nexthop via this interface, keep the nexthop,
        !          1630:           * otherwise set it to 0. The nexthop should not be propagated
        !          1631:           * beyond the local broadcast/multicast area in order
        !          1632:           * to avoid an IGP multi-level recursive look-up.
        !          1633:           */
        !          1634:          if (rinfo->ifindex == ifp->ifindex)
        !          1635:            rinfo->nexthop_out = rinfo->nexthop;
        !          1636: 
        !          1637:          /* Apply output filters. */
        !          1638:          ret = ripng_outgoing_filter (p, ri);
        !          1639:          if (ret < 0)
        !          1640:            continue;
        !          1641: 
        !          1642:          /* Changed route only output. */
        !          1643:          if (route_type == ripng_changed_route &&
        !          1644:              (! (rinfo->flags & RIPNG_RTF_CHANGED)))
        !          1645:            continue;
        !          1646: 
        !          1647:          /* Split horizon. */
        !          1648:          if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
        !          1649:          {
        !          1650:            /* We perform split horizon for RIPng routes. */
        !          1651:            if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
        !          1652:                rinfo->ifindex == ifp->ifindex)
        !          1653:              continue;
        !          1654:          }
        !          1655: 
        !          1656:          /* Preparation for route-map. */
        !          1657:          rinfo->metric_set = 0;
        !          1658:          /* nexthop_out,
        !          1659:           * metric_out
        !          1660:           * and tag_out are already initialized.
        !          1661:           */
        !          1662: 
        !          1663:          /* Interface route-map */
        !          1664:          if (ri->routemap[RIPNG_FILTER_OUT])
        !          1665:            {
        !          1666:              int ret;
        !          1667: 
        !          1668:              ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], 
        !          1669:                                     (struct prefix *) p, RMAP_RIPNG, 
        !          1670:                                     rinfo);
        !          1671: 
        !          1672:              if (ret == RMAP_DENYMATCH)
        !          1673:                {
        !          1674:                  if (IS_RIPNG_DEBUG_PACKET)
        !          1675:                    zlog_debug ("RIPng %s/%d is filtered by route-map out",
        !          1676:                               inet6_ntoa (p->prefix), p->prefixlen);
        !          1677:                  continue;
        !          1678:                }
        !          1679: 
        !          1680:            }
        !          1681: 
        !          1682:          /* Redistribute route-map. */
        !          1683:          if (ripng->route_map[rinfo->type].name)
        !          1684:            {
        !          1685:              int ret;
        !          1686: 
        !          1687:              ret = route_map_apply (ripng->route_map[rinfo->type].map,
        !          1688:                                     (struct prefix *) p, RMAP_RIPNG,
        !          1689:                                     rinfo);
        !          1690: 
        !          1691:              if (ret == RMAP_DENYMATCH)
        !          1692:                {
        !          1693:                  if (IS_RIPNG_DEBUG_PACKET)
        !          1694:                    zlog_debug ("RIPng %s/%d is filtered by route-map",
        !          1695:                               inet6_ntoa (p->prefix), p->prefixlen);
        !          1696:                  continue;
        !          1697:                }
        !          1698:            }
        !          1699: 
        !          1700:          /* When the route-map does not set metric. */
        !          1701:          if (! rinfo->metric_set)
        !          1702:            {
        !          1703:              /* If the redistribute metric is set. */
        !          1704:              if (ripng->route_map[rinfo->type].metric_config
        !          1705:                  && rinfo->metric != RIPNG_METRIC_INFINITY)
        !          1706:                {
        !          1707:                  rinfo->metric_out = ripng->route_map[rinfo->type].metric;
        !          1708:                }
        !          1709:              else
        !          1710:                {
        !          1711:                  /* If the route is not connected or localy generated
        !          1712:                     one, use default-metric value */
        !          1713:                  if (rinfo->type != ZEBRA_ROUTE_RIPNG
        !          1714:                      && rinfo->type != ZEBRA_ROUTE_CONNECT
        !          1715:                      && rinfo->metric != RIPNG_METRIC_INFINITY)
        !          1716:                    rinfo->metric_out = ripng->default_metric;
        !          1717:                }
        !          1718:            }
        !          1719: 
        !          1720:           /* Apply offset-list */
        !          1721:          if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
        !          1722:             ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
        !          1723: 
        !          1724:           if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
        !          1725:             rinfo->metric_out = RIPNG_METRIC_INFINITY;
        !          1726: 
        !          1727:          /* Perform split-horizon with poisoned reverse 
        !          1728:           * for RIPng routes.
        !          1729:           **/
        !          1730:          if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
        !          1731:            if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
        !          1732:                 rinfo->ifindex == ifp->ifindex)
        !          1733:                 rinfo->metric_out = RIPNG_METRIC_INFINITY;
        !          1734:          }
        !          1735: 
        !          1736:          /* Add RTE to the list */
        !          1737:          ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
        !          1738:        }
        !          1739: 
        !          1740:       /* Process the aggregated RTE entry */
        !          1741:       if ((aggregate = rp->aggregate) != NULL && 
        !          1742:          aggregate->count > 0 && 
        !          1743:          aggregate->suppress == 0)
        !          1744:        {
        !          1745:          /* If no route-map are applied, the RTE will be these following
        !          1746:           * informations.
        !          1747:           */
        !          1748:          p = (struct prefix_ipv6 *) &rp->p;
        !          1749:          aggregate->metric_set = 0;
        !          1750:          aggregate->metric_out = aggregate->metric;
        !          1751:          aggregate->tag_out    = aggregate->tag;
        !          1752:          memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
        !          1753: 
        !          1754:          /* Apply output filters.*/
        !          1755:          ret = ripng_outgoing_filter (p, ri);
        !          1756:          if (ret < 0)
        !          1757:            continue;
        !          1758: 
        !          1759:          /* Interface route-map */
        !          1760:          if (ri->routemap[RIPNG_FILTER_OUT])
        !          1761:            {
        !          1762:              int ret;
        !          1763:              struct ripng_info newinfo;
        !          1764: 
        !          1765:              /* let's cast the aggregate structure to ripng_info */
        !          1766:              memset (&newinfo, 0, sizeof (struct ripng_info));
        !          1767:              /* the nexthop is :: */
        !          1768:              newinfo.metric = aggregate->metric;
        !          1769:              newinfo.metric_out = aggregate->metric_out;
        !          1770:              newinfo.tag = aggregate->tag;
        !          1771:              newinfo.tag_out = aggregate->tag_out;
        !          1772: 
        !          1773:              ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], 
        !          1774:                                     (struct prefix *) p, RMAP_RIPNG, 
        !          1775:                                     &newinfo);
        !          1776: 
        !          1777:              if (ret == RMAP_DENYMATCH)
        !          1778:                {
        !          1779:                  if (IS_RIPNG_DEBUG_PACKET)
        !          1780:                    zlog_debug ("RIPng %s/%d is filtered by route-map out",
        !          1781:                               inet6_ntoa (p->prefix), p->prefixlen);
        !          1782:                  continue;
        !          1783:                }
        !          1784: 
        !          1785:              aggregate->metric_out = newinfo.metric_out;
        !          1786:              aggregate->tag_out = newinfo.tag_out;
        !          1787:              if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
        !          1788:                aggregate->nexthop_out = newinfo.nexthop_out;
        !          1789:            }
        !          1790: 
        !          1791:          /* There is no redistribute routemap for the aggregated RTE */
        !          1792: 
        !          1793:          /* Changed route only output. */
        !          1794:          /* XXX, vincent, in order to increase time convergence,
        !          1795:           * it should be announced if a child has changed.
        !          1796:           */
        !          1797:          if (route_type == ripng_changed_route)
        !          1798:            continue;
        !          1799: 
        !          1800:          /* Apply offset-list */
        !          1801:          if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
        !          1802:            ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
        !          1803: 
        !          1804:          if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
        !          1805:            aggregate->metric_out = RIPNG_METRIC_INFINITY;
        !          1806: 
        !          1807:          /* Add RTE to the list */
        !          1808:          ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
        !          1809:        }
        !          1810: 
        !          1811:     }
        !          1812: 
        !          1813:   /* Flush the list */
        !          1814:   ripng_rte_send(ripng_rte_list, ifp, to);
        !          1815:   ripng_rte_free(ripng_rte_list);
        !          1816: }
        !          1817: 
        !          1818: /* Create new RIPng instance and set it to global variable. */
        !          1819: static int
        !          1820: ripng_create (void)
        !          1821: {
        !          1822:   /* ripng should be NULL. */
        !          1823:   assert (ripng == NULL);
        !          1824: 
        !          1825:   /* Allocaste RIPng instance. */
        !          1826:   ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
        !          1827: 
        !          1828:   /* Default version and timer values. */
        !          1829:   ripng->version = RIPNG_V1;
        !          1830:   ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
        !          1831:   ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
        !          1832:   ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
        !          1833:   ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
        !          1834:   
        !          1835:   /* Make buffer.  */
        !          1836:   ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
        !          1837:   ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
        !          1838: 
        !          1839:   /* Initialize RIPng routig table. */
        !          1840:   ripng->table = route_table_init ();
        !          1841:   ripng->route = route_table_init ();
        !          1842:   ripng->aggregate = route_table_init ();
        !          1843:  
        !          1844:   /* Make socket. */
        !          1845:   ripng->sock = ripng_make_socket ();
        !          1846:   if (ripng->sock < 0)
        !          1847:     return ripng->sock;
        !          1848: 
        !          1849:   /* Threads. */
        !          1850:   ripng_event (RIPNG_READ, ripng->sock);
        !          1851:   ripng_event (RIPNG_UPDATE_EVENT, 1);
        !          1852: 
        !          1853:   return 0;
        !          1854: }
        !          1855: 
        !          1856: /* Send RIPng request to the interface. */
        !          1857: int
        !          1858: ripng_request (struct interface *ifp)
        !          1859: {
        !          1860:   struct rte *rte;
        !          1861:   struct ripng_packet ripng_packet;
        !          1862: 
        !          1863:   /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
        !          1864:   if (if_is_loopback(ifp))
        !          1865:     return 0;
        !          1866: 
        !          1867:   /* If interface is down, don't send RIP packet. */
        !          1868:   if (! if_is_up (ifp))
        !          1869:     return 0;
        !          1870: 
        !          1871:   if (IS_RIPNG_DEBUG_EVENT)
        !          1872:     zlog_debug ("RIPng send request to %s", ifp->name);
        !          1873: 
        !          1874:   memset (&ripng_packet, 0, sizeof (ripng_packet));
        !          1875:   ripng_packet.command = RIPNG_REQUEST;
        !          1876:   ripng_packet.version = RIPNG_V1;
        !          1877:   rte = ripng_packet.rte;
        !          1878:   rte->metric = RIPNG_METRIC_INFINITY;
        !          1879: 
        !          1880:   return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet), 
        !          1881:                            NULL, ifp);
        !          1882: }
        !          1883: 
        !          1884: 
        !          1885: static int
        !          1886: ripng_update_jitter (int time)
        !          1887: {
        !          1888:   return ((rand () % (time + 1)) - (time / 2));
        !          1889: }
        !          1890: 
        !          1891: void
        !          1892: ripng_event (enum ripng_event event, int sock)
        !          1893: {
        !          1894:   int jitter = 0;
        !          1895: 
        !          1896:   switch (event)
        !          1897:     {
        !          1898:     case RIPNG_READ:
        !          1899:       if (!ripng->t_read)
        !          1900:        ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
        !          1901:       break;
        !          1902:     case RIPNG_UPDATE_EVENT:
        !          1903:       if (ripng->t_update)
        !          1904:        {
        !          1905:          thread_cancel (ripng->t_update);
        !          1906:          ripng->t_update = NULL;
        !          1907:        }
        !          1908:       /* Update timer jitter. */
        !          1909:       jitter = ripng_update_jitter (ripng->update_time);
        !          1910: 
        !          1911:       ripng->t_update = 
        !          1912:        thread_add_timer (master, ripng_update, NULL, 
        !          1913:                          sock ? 2 : ripng->update_time + jitter);
        !          1914:       break;
        !          1915:     case RIPNG_TRIGGERED_UPDATE:
        !          1916:       if (ripng->t_triggered_interval)
        !          1917:        ripng->trigger = 1;
        !          1918:       else if (! ripng->t_triggered_update)
        !          1919:        ripng->t_triggered_update = 
        !          1920:          thread_add_event (master, ripng_triggered_update, NULL, 0);
        !          1921:       break;
        !          1922:     default:
        !          1923:       break;
        !          1924:     }
        !          1925: }
        !          1926: 
        !          1927: 
        !          1928: /* Print out routes update time. */
        !          1929: static void
        !          1930: ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
        !          1931: {
        !          1932:   time_t clock;
        !          1933:   struct tm *tm;
        !          1934: #define TIME_BUF 25
        !          1935:   char timebuf [TIME_BUF];
        !          1936:   struct thread *thread;
        !          1937:   
        !          1938:   if ((thread = rinfo->t_timeout) != NULL)
        !          1939:     {
        !          1940:       clock = thread_timer_remain_second (thread);
        !          1941:       tm = gmtime (&clock);
        !          1942:       strftime (timebuf, TIME_BUF, "%M:%S", tm);
        !          1943:       vty_out (vty, "%5s", timebuf);
        !          1944:     }
        !          1945:   else if ((thread = rinfo->t_garbage_collect) != NULL)
        !          1946:     {
        !          1947:       clock = thread_timer_remain_second (thread);
        !          1948:       tm = gmtime (&clock);
        !          1949:       strftime (timebuf, TIME_BUF, "%M:%S", tm);
        !          1950:       vty_out (vty, "%5s", timebuf);
        !          1951:     }
        !          1952: }
        !          1953: 
        !          1954: static char *
        !          1955: ripng_route_subtype_print (struct ripng_info *rinfo)
        !          1956: {
        !          1957:   static char str[3];
        !          1958:   memset(str, 0, 3);
        !          1959: 
        !          1960:   if (rinfo->suppress)
        !          1961:     strcat(str, "S");
        !          1962: 
        !          1963:   switch (rinfo->sub_type)
        !          1964:     {
        !          1965:        case RIPNG_ROUTE_RTE:
        !          1966:          strcat(str, "n");
        !          1967:          break;
        !          1968:        case RIPNG_ROUTE_STATIC:
        !          1969:          strcat(str, "s");
        !          1970:          break;
        !          1971:        case RIPNG_ROUTE_DEFAULT:
        !          1972:          strcat(str, "d");
        !          1973:          break;
        !          1974:        case RIPNG_ROUTE_REDISTRIBUTE:
        !          1975:          strcat(str, "r");
        !          1976:          break;
        !          1977:        case RIPNG_ROUTE_INTERFACE:
        !          1978:          strcat(str, "i");
        !          1979:          break;
        !          1980:        default:
        !          1981:          strcat(str, "?");
        !          1982:          break;
        !          1983:     }
        !          1984:  
        !          1985:   return str;
        !          1986: }
        !          1987: 
        !          1988: DEFUN (show_ipv6_ripng,
        !          1989:        show_ipv6_ripng_cmd,
        !          1990:        "show ipv6 ripng",
        !          1991:        SHOW_STR
        !          1992:        IPV6_STR
        !          1993:        "Show RIPng routes\n")
        !          1994: {
        !          1995:   struct route_node *rp;
        !          1996:   struct ripng_info *rinfo;
        !          1997:   struct ripng_aggregate *aggregate;
        !          1998:   struct prefix_ipv6 *p;
        !          1999:   int len;
        !          2000: 
        !          2001:   if (! ripng)
        !          2002:     return CMD_SUCCESS;
        !          2003: 
        !          2004:   /* Header of display. */ 
        !          2005:   vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
        !          2006:           "Sub-codes:%s"
        !          2007:           "      (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
        !          2008:           "      (i) - interface, (a/S) - aggregated/Suppressed%s%s"
        !          2009:           "   Network      Next Hop                      Via     Metric Tag Time%s",
        !          2010:           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
        !          2011:           VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
        !          2012:   
        !          2013:   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
        !          2014:     {
        !          2015:       if ((aggregate = rp->aggregate) != NULL)
        !          2016:        {
        !          2017:          p = (struct prefix_ipv6 *) &rp->p;
        !          2018: 
        !          2019: #ifdef DEBUG
        !          2020:          len = vty_out (vty, "R(a) %d/%d %s/%d ",
        !          2021:                         aggregate->count, aggregate->suppress,
        !          2022:                         inet6_ntoa (p->prefix), p->prefixlen);
        !          2023: #else
        !          2024:          len = vty_out (vty, "R(a) %s/%d ", 
        !          2025:                         inet6_ntoa (p->prefix), p->prefixlen);
        !          2026: #endif /* DEBUG */
        !          2027:          vty_out (vty, "%s", VTY_NEWLINE);
        !          2028:          vty_out (vty, "%*s", 18, " ");
        !          2029: 
        !          2030:          vty_out (vty, "%*s", 28, " ");
        !          2031:          vty_out (vty, "self      %2d  %3d%s", aggregate->metric,
        !          2032:                   aggregate->tag,
        !          2033:                   VTY_NEWLINE);
        !          2034:        }
        !          2035: 
        !          2036:       if ((rinfo = rp->info) != NULL)
        !          2037:        {
        !          2038:          p = (struct prefix_ipv6 *) &rp->p;
        !          2039: 
        !          2040: #ifdef DEBUG
        !          2041:          len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
        !          2042:                         zebra_route_char(rinfo->type),
        !          2043:                         ripng_route_subtype_print(rinfo),
        !          2044:                         rinfo->suppress,
        !          2045:                         inet6_ntoa (p->prefix), p->prefixlen);
        !          2046: #else
        !          2047:          len = vty_out (vty, "%c(%s) %s/%d ",
        !          2048:                         zebra_route_char(rinfo->type),
        !          2049:                         ripng_route_subtype_print(rinfo),
        !          2050:                         inet6_ntoa (p->prefix), p->prefixlen);
        !          2051: #endif /* DEBUG */
        !          2052:          vty_out (vty, "%s", VTY_NEWLINE);
        !          2053:          vty_out (vty, "%*s", 18, " ");
        !          2054:          len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
        !          2055: 
        !          2056:          len = 28 - len;
        !          2057:          if (len > 0)
        !          2058:            len = vty_out (vty, "%*s", len, " ");
        !          2059: 
        !          2060:          /* from */
        !          2061:          if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && 
        !          2062:            (rinfo->sub_type == RIPNG_ROUTE_RTE))
        !          2063:          {
        !          2064:            len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
        !          2065:          } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
        !          2066:          {
        !          2067:            len = vty_out (vty, "kill");
        !          2068:          } else
        !          2069:            len = vty_out (vty, "self");
        !          2070: 
        !          2071:          len = 9 - len;
        !          2072:          if (len > 0)
        !          2073:            vty_out (vty, "%*s", len, " ");
        !          2074: 
        !          2075:          vty_out (vty, " %2d  %3d  ",
        !          2076:                   rinfo->metric, rinfo->tag);
        !          2077: 
        !          2078:          /* time */
        !          2079:          if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && 
        !          2080:            (rinfo->sub_type == RIPNG_ROUTE_RTE))
        !          2081:          {
        !          2082:            /* RTE from remote RIP routers */
        !          2083:            ripng_vty_out_uptime (vty, rinfo);
        !          2084:          } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
        !          2085:          {
        !          2086:            /* poisonous reversed routes (gc) */
        !          2087:            ripng_vty_out_uptime (vty, rinfo);
        !          2088:          }
        !          2089: 
        !          2090:          vty_out (vty, "%s", VTY_NEWLINE);
        !          2091:        }
        !          2092:     }
        !          2093: 
        !          2094:   return CMD_SUCCESS;
        !          2095: }
        !          2096: 
        !          2097: DEFUN (show_ipv6_ripng_status,
        !          2098:        show_ipv6_ripng_status_cmd,
        !          2099:        "show ipv6 ripng status",
        !          2100:        SHOW_STR
        !          2101:        IPV6_STR
        !          2102:        "Show RIPng routes\n"
        !          2103:        "IPv6 routing protocol process parameters and statistics\n")
        !          2104: {
        !          2105:   struct listnode *node;
        !          2106:   struct interface *ifp;
        !          2107: 
        !          2108:   if (! ripng)
        !          2109:     return CMD_SUCCESS;
        !          2110: 
        !          2111:   vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
        !          2112:   vty_out (vty, "  Sending updates every %ld seconds with +/-50%%,",
        !          2113:            ripng->update_time);
        !          2114:   vty_out (vty, " next due in %lu seconds%s",
        !          2115:            thread_timer_remain_second (ripng->t_update),
        !          2116:            VTY_NEWLINE);
        !          2117:   vty_out (vty, "  Timeout after %ld seconds,", ripng->timeout_time);
        !          2118:   vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
        !          2119:            VTY_NEWLINE);
        !          2120: 
        !          2121:   /* Filtering status show. */
        !          2122:   config_show_distribute (vty);
        !          2123: 
        !          2124:   /* Default metric information. */
        !          2125:   vty_out (vty, "  Default redistribution metric is %d%s",
        !          2126:            ripng->default_metric, VTY_NEWLINE);
        !          2127: 
        !          2128:   /* Redistribute information. */
        !          2129:   vty_out (vty, "  Redistributing:");
        !          2130:   ripng_redistribute_write (vty, 0);
        !          2131:   vty_out (vty, "%s", VTY_NEWLINE);
        !          2132: 
        !          2133:   vty_out (vty, "  Default version control: send version %d,", ripng->version);
        !          2134:   vty_out (vty, " receive version %d %s", ripng->version,
        !          2135:            VTY_NEWLINE);
        !          2136: 
        !          2137:   vty_out (vty, "    Interface        Send  Recv%s", VTY_NEWLINE);
        !          2138: 
        !          2139:   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
        !          2140:     {
        !          2141:       struct ripng_interface *ri;
        !          2142:       
        !          2143:       ri = ifp->info;
        !          2144: 
        !          2145:       if (ri->enable_network || ri->enable_interface)
        !          2146:        {
        !          2147: 
        !          2148:          vty_out (vty, "    %-17s%-3d   %-3d%s", ifp->name,
        !          2149:                   ripng->version,
        !          2150:                   ripng->version,
        !          2151:                   VTY_NEWLINE);
        !          2152:        }
        !          2153:     }
        !          2154: 
        !          2155:   vty_out (vty, "  Routing for Networks:%s", VTY_NEWLINE);
        !          2156:   ripng_network_write (vty, 0);
        !          2157: 
        !          2158:   vty_out (vty, "  Routing Information Sources:%s", VTY_NEWLINE);
        !          2159:   vty_out (vty, "    Gateway          BadPackets BadRoutes  Distance Last Update%s", VTY_NEWLINE);
        !          2160:   ripng_peer_display (vty);
        !          2161: 
        !          2162:   return CMD_SUCCESS;  
        !          2163: }
        !          2164: 
        !          2165: DEFUN (router_ripng,
        !          2166:        router_ripng_cmd,
        !          2167:        "router ripng",
        !          2168:        "Enable a routing process\n"
        !          2169:        "Make RIPng instance command\n")
        !          2170: {
        !          2171:   int ret;
        !          2172: 
        !          2173:   vty->node = RIPNG_NODE;
        !          2174: 
        !          2175:   if (!ripng)
        !          2176:     {
        !          2177:       ret = ripng_create ();
        !          2178: 
        !          2179:       /* Notice to user we couldn't create RIPng. */
        !          2180:       if (ret < 0)
        !          2181:        {
        !          2182:          zlog_warn ("can't create RIPng");
        !          2183:          return CMD_WARNING;
        !          2184:        }
        !          2185:     }
        !          2186: 
        !          2187:   return CMD_SUCCESS;
        !          2188: }
        !          2189: 
        !          2190: DEFUN (no_router_ripng,
        !          2191:        no_router_ripng_cmd,
        !          2192:        "no router ripng",
        !          2193:        NO_STR
        !          2194:        "Enable a routing process\n"
        !          2195:        "Make RIPng instance command\n")
        !          2196: {
        !          2197:   if(ripng)
        !          2198:     ripng_clean();
        !          2199:   return CMD_SUCCESS;
        !          2200: }
        !          2201: 
        !          2202: DEFUN (ripng_route,
        !          2203:        ripng_route_cmd,
        !          2204:        "route IPV6ADDR",
        !          2205:        "Static route setup\n"
        !          2206:        "Set static RIPng route announcement\n")
        !          2207: {
        !          2208:   int ret;
        !          2209:   struct prefix_ipv6 p;
        !          2210:   struct route_node *rp;
        !          2211: 
        !          2212:   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
        !          2213:   if (ret <= 0)
        !          2214:     {
        !          2215:       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
        !          2216:       return CMD_WARNING;
        !          2217:     }
        !          2218:   apply_mask_ipv6 (&p);
        !          2219: 
        !          2220:   rp = route_node_get (ripng->route, (struct prefix *) &p);
        !          2221:   if (rp->info)
        !          2222:     {
        !          2223:       vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
        !          2224:       route_unlock_node (rp);
        !          2225:       return CMD_WARNING;
        !          2226:     }
        !          2227:   rp->info = (void *)1;
        !          2228: 
        !          2229:   ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
        !          2230: 
        !          2231:   return CMD_SUCCESS;
        !          2232: }
        !          2233: 
        !          2234: DEFUN (no_ripng_route,
        !          2235:        no_ripng_route_cmd,
        !          2236:        "no route IPV6ADDR",
        !          2237:        NO_STR
        !          2238:        "Static route setup\n"
        !          2239:        "Delete static RIPng route announcement\n")
        !          2240: {
        !          2241:   int ret;
        !          2242:   struct prefix_ipv6 p;
        !          2243:   struct route_node *rp;
        !          2244: 
        !          2245:   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
        !          2246:   if (ret <= 0)
        !          2247:     {
        !          2248:       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
        !          2249:       return CMD_WARNING;
        !          2250:     }
        !          2251:   apply_mask_ipv6 (&p);
        !          2252: 
        !          2253:   rp = route_node_lookup (ripng->route, (struct prefix *) &p);
        !          2254:   if (! rp)
        !          2255:     {
        !          2256:       vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
        !          2257:       return CMD_WARNING;
        !          2258:     }
        !          2259: 
        !          2260:   ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
        !          2261:   route_unlock_node (rp);
        !          2262: 
        !          2263:   rp->info = NULL;
        !          2264:   route_unlock_node (rp);
        !          2265: 
        !          2266:   return CMD_SUCCESS;
        !          2267: }
        !          2268: 
        !          2269: DEFUN (ripng_aggregate_address,
        !          2270:        ripng_aggregate_address_cmd,
        !          2271:        "aggregate-address X:X::X:X/M",
        !          2272:        "Set aggregate RIPng route announcement\n"
        !          2273:        "Aggregate network\n")
        !          2274: {
        !          2275:   int ret;
        !          2276:   struct prefix p;
        !          2277:   struct route_node *node;
        !          2278: 
        !          2279:   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
        !          2280:   if (ret <= 0)
        !          2281:     {
        !          2282:       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
        !          2283:       return CMD_WARNING;
        !          2284:     }
        !          2285: 
        !          2286:   /* Check aggregate alredy exist or not. */
        !          2287:   node = route_node_get (ripng->aggregate, &p);
        !          2288:   if (node->info)
        !          2289:     {
        !          2290:       vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
        !          2291:       route_unlock_node (node);
        !          2292:       return CMD_WARNING;
        !          2293:     }
        !          2294:   node->info = (void *)1;
        !          2295: 
        !          2296:   ripng_aggregate_add (&p);
        !          2297: 
        !          2298:   return CMD_SUCCESS;
        !          2299: }
        !          2300: 
        !          2301: DEFUN (no_ripng_aggregate_address,
        !          2302:        no_ripng_aggregate_address_cmd,
        !          2303:        "no aggregate-address X:X::X:X/M",
        !          2304:        NO_STR
        !          2305:        "Delete aggregate RIPng route announcement\n"
        !          2306:        "Aggregate network")
        !          2307: {
        !          2308:   int ret;
        !          2309:   struct prefix p;
        !          2310:   struct route_node *rn;
        !          2311: 
        !          2312:   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
        !          2313:   if (ret <= 0)
        !          2314:     {
        !          2315:       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
        !          2316:       return CMD_WARNING;
        !          2317:     }
        !          2318: 
        !          2319:   rn = route_node_lookup (ripng->aggregate, &p);
        !          2320:   if (! rn)
        !          2321:     {
        !          2322:       vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
        !          2323:       return CMD_WARNING;
        !          2324:     }
        !          2325:   route_unlock_node (rn);
        !          2326:   rn->info = NULL;
        !          2327:   route_unlock_node (rn);
        !          2328: 
        !          2329:   ripng_aggregate_delete (&p);
        !          2330: 
        !          2331:   return CMD_SUCCESS;
        !          2332: }
        !          2333: 
        !          2334: DEFUN (ripng_default_metric,
        !          2335:        ripng_default_metric_cmd,
        !          2336:        "default-metric <1-16>",
        !          2337:        "Set a metric of redistribute routes\n"
        !          2338:        "Default metric\n")
        !          2339: {
        !          2340:   if (ripng)
        !          2341:     {
        !          2342:       ripng->default_metric = atoi (argv[0]);
        !          2343:     }
        !          2344:   return CMD_SUCCESS;
        !          2345: }
        !          2346: 
        !          2347: DEFUN (no_ripng_default_metric,
        !          2348:        no_ripng_default_metric_cmd,
        !          2349:        "no default-metric",
        !          2350:        NO_STR
        !          2351:        "Set a metric of redistribute routes\n"
        !          2352:        "Default metric\n")
        !          2353: {
        !          2354:   if (ripng)
        !          2355:     {
        !          2356:       ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
        !          2357:     }
        !          2358:   return CMD_SUCCESS;
        !          2359: }
        !          2360: 
        !          2361: ALIAS (no_ripng_default_metric,
        !          2362:        no_ripng_default_metric_val_cmd,
        !          2363:        "no default-metric <1-16>",
        !          2364:        NO_STR
        !          2365:        "Set a metric of redistribute routes\n"
        !          2366:        "Default metric\n")
        !          2367: 
        !          2368: #if 0
        !          2369: /* RIPng update timer setup. */
        !          2370: DEFUN (ripng_update_timer,
        !          2371:        ripng_update_timer_cmd,
        !          2372:        "update-timer SECOND",
        !          2373:        "Set RIPng update timer in seconds\n"
        !          2374:        "Seconds\n")
        !          2375: {
        !          2376:   unsigned long update;
        !          2377:   char *endptr = NULL;
        !          2378: 
        !          2379:   update = strtoul (argv[0], &endptr, 10);
        !          2380:   if (update == ULONG_MAX || *endptr != '\0')
        !          2381:     {
        !          2382:       vty_out (vty, "update timer value error%s", VTY_NEWLINE);
        !          2383:       return CMD_WARNING;
        !          2384:     }
        !          2385: 
        !          2386:   ripng->update_time = update;
        !          2387: 
        !          2388:   ripng_event (RIPNG_UPDATE_EVENT, 0);
        !          2389:   return CMD_SUCCESS;
        !          2390: }
        !          2391: 
        !          2392: DEFUN (no_ripng_update_timer,
        !          2393:        no_ripng_update_timer_cmd,
        !          2394:        "no update-timer SECOND",
        !          2395:        NO_STR
        !          2396:        "Unset RIPng update timer in seconds\n"
        !          2397:        "Seconds\n")
        !          2398: {
        !          2399:   ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
        !          2400:   ripng_event (RIPNG_UPDATE_EVENT, 0);
        !          2401:   return CMD_SUCCESS;
        !          2402: }
        !          2403: 
        !          2404: /* RIPng timeout timer setup. */
        !          2405: DEFUN (ripng_timeout_timer,
        !          2406:        ripng_timeout_timer_cmd,
        !          2407:        "timeout-timer SECOND",
        !          2408:        "Set RIPng timeout timer in seconds\n"
        !          2409:        "Seconds\n")
        !          2410: {
        !          2411:   unsigned long timeout;
        !          2412:   char *endptr = NULL;
        !          2413: 
        !          2414:   timeout = strtoul (argv[0], &endptr, 10);
        !          2415:   if (timeout == ULONG_MAX || *endptr != '\0')
        !          2416:     {
        !          2417:       vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
        !          2418:       return CMD_WARNING;
        !          2419:     }
        !          2420: 
        !          2421:   ripng->timeout_time = timeout;
        !          2422: 
        !          2423:   return CMD_SUCCESS;
        !          2424: }
        !          2425: 
        !          2426: DEFUN (no_ripng_timeout_timer,
        !          2427:        no_ripng_timeout_timer_cmd,
        !          2428:        "no timeout-timer SECOND",
        !          2429:        NO_STR
        !          2430:        "Unset RIPng timeout timer in seconds\n"
        !          2431:        "Seconds\n")
        !          2432: {
        !          2433:   ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
        !          2434:   return CMD_SUCCESS;
        !          2435: }
        !          2436: 
        !          2437: /* RIPng garbage timer setup. */
        !          2438: DEFUN (ripng_garbage_timer,
        !          2439:        ripng_garbage_timer_cmd,
        !          2440:        "garbage-timer SECOND",
        !          2441:        "Set RIPng garbage timer in seconds\n"
        !          2442:        "Seconds\n")
        !          2443: {
        !          2444:   unsigned long garbage;
        !          2445:   char *endptr = NULL;
        !          2446: 
        !          2447:   garbage = strtoul (argv[0], &endptr, 10);
        !          2448:   if (garbage == ULONG_MAX || *endptr != '\0')
        !          2449:     {
        !          2450:       vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
        !          2451:       return CMD_WARNING;
        !          2452:     }
        !          2453: 
        !          2454:   ripng->garbage_time = garbage;
        !          2455: 
        !          2456:   return CMD_SUCCESS;
        !          2457: }
        !          2458: 
        !          2459: DEFUN (no_ripng_garbage_timer,
        !          2460:        no_ripng_garbage_timer_cmd,
        !          2461:        "no garbage-timer SECOND",
        !          2462:        NO_STR
        !          2463:        "Unset RIPng garbage timer in seconds\n"
        !          2464:        "Seconds\n")
        !          2465: {
        !          2466:   ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
        !          2467:   return CMD_SUCCESS;
        !          2468: }
        !          2469: #endif /* 0 */
        !          2470: 
        !          2471: DEFUN (ripng_timers,
        !          2472:        ripng_timers_cmd,
        !          2473:        "timers basic <0-65535> <0-65535> <0-65535>",
        !          2474:        "RIPng timers setup\n"
        !          2475:        "Basic timer\n"
        !          2476:        "Routing table update timer value in second. Default is 30.\n"
        !          2477:        "Routing information timeout timer. Default is 180.\n"
        !          2478:        "Garbage collection timer. Default is 120.\n")
        !          2479: {
        !          2480:   unsigned long update;
        !          2481:   unsigned long timeout;
        !          2482:   unsigned long garbage;
        !          2483:   char *endptr = NULL;
        !          2484: 
        !          2485:   update = strtoul (argv[0], &endptr, 10);
        !          2486:   if (update == ULONG_MAX || *endptr != '\0')
        !          2487:     {
        !          2488:       vty_out (vty, "update timer value error%s", VTY_NEWLINE);
        !          2489:       return CMD_WARNING;
        !          2490:     }
        !          2491:   
        !          2492:   timeout = strtoul (argv[1], &endptr, 10);
        !          2493:   if (timeout == ULONG_MAX || *endptr != '\0')
        !          2494:     {
        !          2495:       vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
        !          2496:       return CMD_WARNING;
        !          2497:     }
        !          2498:   
        !          2499:   garbage = strtoul (argv[2], &endptr, 10);
        !          2500:   if (garbage == ULONG_MAX || *endptr != '\0')
        !          2501:     {
        !          2502:       vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
        !          2503:       return CMD_WARNING;
        !          2504:     }
        !          2505: 
        !          2506:   /* Set each timer value. */
        !          2507:   ripng->update_time = update;
        !          2508:   ripng->timeout_time = timeout;
        !          2509:   ripng->garbage_time = garbage;
        !          2510: 
        !          2511:   /* Reset update timer thread. */
        !          2512:   ripng_event (RIPNG_UPDATE_EVENT, 0);
        !          2513: 
        !          2514:   return CMD_SUCCESS;
        !          2515: }
        !          2516: 
        !          2517: DEFUN (no_ripng_timers,
        !          2518:        no_ripng_timers_cmd,
        !          2519:        "no timers basic",
        !          2520:        NO_STR
        !          2521:        "RIPng timers setup\n"
        !          2522:        "Basic timer\n")
        !          2523: {
        !          2524:   /* Set each timer value to the default. */
        !          2525:   ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
        !          2526:   ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
        !          2527:   ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
        !          2528: 
        !          2529:   /* Reset update timer thread. */
        !          2530:   ripng_event (RIPNG_UPDATE_EVENT, 0);
        !          2531: 
        !          2532:   return CMD_SUCCESS;
        !          2533: }
        !          2534: 
        !          2535: ALIAS (no_ripng_timers,
        !          2536:        no_ripng_timers_val_cmd,
        !          2537:        "no timers basic <0-65535> <0-65535> <0-65535>",
        !          2538:        NO_STR
        !          2539:        "RIPng timers setup\n"
        !          2540:        "Basic timer\n"
        !          2541:        "Routing table update timer value in second. Default is 30.\n"
        !          2542:        "Routing information timeout timer. Default is 180.\n"
        !          2543:        "Garbage collection timer. Default is 120.\n")
        !          2544: 
        !          2545: DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
        !          2546:        "show ipv6 protocols",
        !          2547:        SHOW_STR
        !          2548:        IPV6_STR
        !          2549:        "Routing protocol information")
        !          2550: {
        !          2551:   if (! ripng)
        !          2552:     return CMD_SUCCESS;
        !          2553: 
        !          2554:   vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
        !          2555:   
        !          2556:   vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
        !          2557:           ripng->update_time, 0,
        !          2558:           VTY_NEWLINE);
        !          2559: 
        !          2560:   vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
        !          2561:           ripng->timeout_time,
        !          2562:           ripng->garbage_time,
        !          2563:           VTY_NEWLINE);
        !          2564: 
        !          2565:   vty_out (vty, "Outgoing update filter list for all interfaces is not set");
        !          2566:   vty_out (vty, "Incoming update filter list for all interfaces is not set");
        !          2567: 
        !          2568:   return CMD_SUCCESS;
        !          2569: }
        !          2570: 
        !          2571: /* Please be carefull to use this command. */
        !          2572: DEFUN (ripng_default_information_originate,
        !          2573:        ripng_default_information_originate_cmd,
        !          2574:        "default-information originate",
        !          2575:        "Default route information\n"
        !          2576:        "Distribute default route\n")
        !          2577: {
        !          2578:   struct prefix_ipv6 p;
        !          2579: 
        !          2580:   if (! ripng ->default_information) {
        !          2581:     ripng->default_information = 1;
        !          2582: 
        !          2583:     str2prefix_ipv6 ("::/0", &p);
        !          2584:     ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
        !          2585:   }
        !          2586: 
        !          2587:   return CMD_SUCCESS;
        !          2588: }
        !          2589: 
        !          2590: DEFUN (no_ripng_default_information_originate,
        !          2591:        no_ripng_default_information_originate_cmd,
        !          2592:        "no default-information originate",
        !          2593:        NO_STR
        !          2594:        "Default route information\n"
        !          2595:        "Distribute default route\n")
        !          2596: {
        !          2597:   struct prefix_ipv6 p;
        !          2598: 
        !          2599:   if (ripng->default_information) {
        !          2600:     ripng->default_information = 0;
        !          2601: 
        !          2602:     str2prefix_ipv6 ("::/0", &p);
        !          2603:     ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
        !          2604:   }
        !          2605: 
        !          2606:   return CMD_SUCCESS;
        !          2607: }
        !          2608: 
        !          2609: /* RIPng configuration write function. */
        !          2610: static int
        !          2611: ripng_config_write (struct vty *vty)
        !          2612: {
        !          2613:   int ripng_network_write (struct vty *, int);
        !          2614:   void ripng_redistribute_write (struct vty *, int);
        !          2615:   int write = 0;
        !          2616:   struct route_node *rp;
        !          2617: 
        !          2618:   if (ripng)
        !          2619:     {
        !          2620: 
        !          2621:       /* RIPng router. */
        !          2622:       vty_out (vty, "router ripng%s", VTY_NEWLINE);
        !          2623: 
        !          2624:       if (ripng->default_information)
        !          2625:        vty_out (vty, " default-information originate%s", VTY_NEWLINE);
        !          2626: 
        !          2627:       ripng_network_write (vty, 1);
        !          2628: 
        !          2629:       /* RIPng default metric configuration */
        !          2630:       if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
        !          2631:         vty_out (vty, " default-metric %d%s",
        !          2632:                 ripng->default_metric, VTY_NEWLINE);
        !          2633: 
        !          2634:       ripng_redistribute_write (vty, 1);
        !          2635: 
        !          2636:       /* RIP offset-list configuration. */
        !          2637:       config_write_ripng_offset_list (vty);
        !          2638:       
        !          2639:       /* RIPng aggregate routes. */
        !          2640:       for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
        !          2641:        if (rp->info != NULL)
        !          2642:          vty_out (vty, " aggregate-address %s/%d%s", 
        !          2643:                   inet6_ntoa (rp->p.u.prefix6),
        !          2644:                   rp->p.prefixlen, 
        !          2645: 
        !          2646:                   VTY_NEWLINE);
        !          2647: 
        !          2648:       /* RIPng static routes. */
        !          2649:       for (rp = route_top (ripng->route); rp; rp = route_next (rp))
        !          2650:        if (rp->info != NULL)
        !          2651:          vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
        !          2652:                   rp->p.prefixlen,
        !          2653:                   VTY_NEWLINE);
        !          2654: 
        !          2655:       /* RIPng timers configuration. */
        !          2656:       if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
        !          2657:          ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
        !          2658:          ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
        !          2659:        {
        !          2660:          vty_out (vty, " timers basic %ld %ld %ld%s",
        !          2661:                   ripng->update_time,
        !          2662:                   ripng->timeout_time,
        !          2663:                   ripng->garbage_time,
        !          2664:                   VTY_NEWLINE);
        !          2665:        }
        !          2666: #if 0
        !          2667:       if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
        !          2668:        vty_out (vty, " update-timer %d%s", ripng->update_time,
        !          2669:                 VTY_NEWLINE);
        !          2670:       if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
        !          2671:        vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
        !          2672:                 VTY_NEWLINE);
        !          2673:       if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
        !          2674:        vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
        !          2675:                 VTY_NEWLINE);
        !          2676: #endif /* 0 */
        !          2677: 
        !          2678:       write += config_write_distribute (vty);
        !          2679: 
        !          2680:       write += config_write_if_rmap (vty);
        !          2681: 
        !          2682:       write++;
        !          2683:     }
        !          2684:   return write;
        !          2685: }
        !          2686: 
        !          2687: /* RIPng node structure. */
        !          2688: static struct cmd_node cmd_ripng_node =
        !          2689: {
        !          2690:   RIPNG_NODE,
        !          2691:   "%s(config-router)# ",
        !          2692:   1,
        !          2693: };
        !          2694: 
        !          2695: static void
        !          2696: ripng_distribute_update (struct distribute *dist)
        !          2697: {
        !          2698:   struct interface *ifp;
        !          2699:   struct ripng_interface *ri;
        !          2700:   struct access_list *alist;
        !          2701:   struct prefix_list *plist;
        !          2702: 
        !          2703:   if (! dist->ifname)
        !          2704:     return;
        !          2705: 
        !          2706:   ifp = if_lookup_by_name (dist->ifname);
        !          2707:   if (ifp == NULL)
        !          2708:     return;
        !          2709: 
        !          2710:   ri = ifp->info;
        !          2711: 
        !          2712:   if (dist->list[DISTRIBUTE_IN])
        !          2713:     {
        !          2714:       alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
        !          2715:       if (alist)
        !          2716:        ri->list[RIPNG_FILTER_IN] = alist;
        !          2717:       else
        !          2718:        ri->list[RIPNG_FILTER_IN] = NULL;
        !          2719:     }
        !          2720:   else
        !          2721:     ri->list[RIPNG_FILTER_IN] = NULL;
        !          2722: 
        !          2723:   if (dist->list[DISTRIBUTE_OUT])
        !          2724:     {
        !          2725:       alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
        !          2726:       if (alist)
        !          2727:        ri->list[RIPNG_FILTER_OUT] = alist;
        !          2728:       else
        !          2729:        ri->list[RIPNG_FILTER_OUT] = NULL;
        !          2730:     }
        !          2731:   else
        !          2732:     ri->list[RIPNG_FILTER_OUT] = NULL;
        !          2733: 
        !          2734:   if (dist->prefix[DISTRIBUTE_IN])
        !          2735:     {
        !          2736:       plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
        !          2737:       if (plist)
        !          2738:        ri->prefix[RIPNG_FILTER_IN] = plist;
        !          2739:       else
        !          2740:        ri->prefix[RIPNG_FILTER_IN] = NULL;
        !          2741:     }
        !          2742:   else
        !          2743:     ri->prefix[RIPNG_FILTER_IN] = NULL;
        !          2744: 
        !          2745:   if (dist->prefix[DISTRIBUTE_OUT])
        !          2746:     {
        !          2747:       plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
        !          2748:       if (plist)
        !          2749:        ri->prefix[RIPNG_FILTER_OUT] = plist;
        !          2750:       else
        !          2751:        ri->prefix[RIPNG_FILTER_OUT] = NULL;
        !          2752:     }
        !          2753:   else
        !          2754:     ri->prefix[RIPNG_FILTER_OUT] = NULL;
        !          2755: }
        !          2756: 
        !          2757: void
        !          2758: ripng_distribute_update_interface (struct interface *ifp)
        !          2759: {
        !          2760:   struct distribute *dist;
        !          2761: 
        !          2762:   dist = distribute_lookup (ifp->name);
        !          2763:   if (dist)
        !          2764:     ripng_distribute_update (dist);
        !          2765: }
        !          2766: 
        !          2767: /* Update all interface's distribute list. */
        !          2768: static void
        !          2769: ripng_distribute_update_all (struct prefix_list *notused)
        !          2770: {
        !          2771:   struct interface *ifp;
        !          2772:   struct listnode *node;
        !          2773: 
        !          2774:   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
        !          2775:     ripng_distribute_update_interface (ifp);
        !          2776: }
        !          2777: 
        !          2778: static void
        !          2779: ripng_distribute_update_all_wrapper (struct access_list *notused)
        !          2780: {
        !          2781:   ripng_distribute_update_all(NULL);
        !          2782: }
        !          2783: 
        !          2784: /* delete all the added ripng routes. */
        !          2785: void
        !          2786: ripng_clean()
        !          2787: {
        !          2788:   int i;
        !          2789:   struct route_node *rp;
        !          2790:   struct ripng_info *rinfo;
        !          2791: 
        !          2792:   if (ripng) {
        !          2793:     /* Clear RIPng routes */
        !          2794:     for (rp = route_top (ripng->table); rp; rp = route_next (rp)) {
        !          2795:       if ((rinfo = rp->info) != NULL) {
        !          2796:         if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
        !          2797:             (rinfo->sub_type == RIPNG_ROUTE_RTE))
        !          2798:           ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
        !          2799:                                    &rinfo->nexthop, rinfo->metric);
        !          2800: 
        !          2801:         RIPNG_TIMER_OFF (rinfo->t_timeout);
        !          2802:         RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
        !          2803: 
        !          2804:         rp->info = NULL;
        !          2805:         route_unlock_node (rp);
        !          2806: 
        !          2807:         ripng_info_free(rinfo);
        !          2808:       }
        !          2809:     }
        !          2810: 
        !          2811:     /* Cancel the RIPng timers */
        !          2812:     RIPNG_TIMER_OFF (ripng->t_update);
        !          2813:     RIPNG_TIMER_OFF (ripng->t_triggered_update);
        !          2814:     RIPNG_TIMER_OFF (ripng->t_triggered_interval);
        !          2815: 
        !          2816:     /* Cancel the read thread */
        !          2817:     if (ripng->t_read) {
        !          2818:       thread_cancel (ripng->t_read);
        !          2819:       ripng->t_read = NULL;
        !          2820:     }
        !          2821: 
        !          2822:     /* Close the RIPng socket */
        !          2823:     if (ripng->sock >= 0) {
        !          2824:       close(ripng->sock);
        !          2825:       ripng->sock = -1;
        !          2826:     }
        !          2827: 
        !          2828:     /* Static RIPng route configuration. */
        !          2829:     for (rp = route_top (ripng->route); rp; rp = route_next (rp))
        !          2830:       if (rp->info) {
        !          2831:         rp->info = NULL;
        !          2832:         route_unlock_node (rp);
        !          2833:     }
        !          2834: 
        !          2835:     /* RIPng aggregated prefixes */
        !          2836:     for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
        !          2837:       if (rp->info) {
        !          2838:           rp->info = NULL;
        !          2839:           route_unlock_node (rp);
        !          2840:     }
        !          2841: 
        !          2842:     for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
        !          2843:       if (ripng->route_map[i].name)
        !          2844:         free (ripng->route_map[i].name);
        !          2845: 
        !          2846:     XFREE (MTYPE_ROUTE_TABLE, ripng->table);
        !          2847:     XFREE (MTYPE_ROUTE_TABLE, ripng->route);
        !          2848:     XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
        !          2849: 
        !          2850:     XFREE (MTYPE_RIPNG, ripng);
        !          2851:     ripng = NULL;
        !          2852:   } /* if (ripng) */
        !          2853: 
        !          2854:   ripng_clean_network();
        !          2855:   ripng_passive_interface_clean ();
        !          2856:   ripng_offset_clean ();
        !          2857:   ripng_interface_clean ();
        !          2858:   ripng_redistribute_clean ();
        !          2859: }
        !          2860: 
        !          2861: /* Reset all values to the default settings. */
        !          2862: void
        !          2863: ripng_reset ()
        !          2864: {
        !          2865:   /* Call ripd related reset functions. */
        !          2866:   ripng_debug_reset ();
        !          2867:   ripng_route_map_reset ();
        !          2868: 
        !          2869:   /* Call library reset functions. */
        !          2870:   vty_reset ();
        !          2871:   access_list_reset ();
        !          2872:   prefix_list_reset ();
        !          2873: 
        !          2874:   distribute_list_reset ();
        !          2875: 
        !          2876:   ripng_interface_reset ();
        !          2877: 
        !          2878:   ripng_zclient_reset ();
        !          2879: }
        !          2880: 
        !          2881: static void
        !          2882: ripng_if_rmap_update (struct if_rmap *if_rmap)
        !          2883: {
        !          2884:   struct interface *ifp;
        !          2885:   struct ripng_interface *ri;
        !          2886:   struct route_map *rmap;
        !          2887: 
        !          2888:   ifp = if_lookup_by_name (if_rmap->ifname);
        !          2889:   if (ifp == NULL)
        !          2890:     return;
        !          2891: 
        !          2892:   ri = ifp->info;
        !          2893: 
        !          2894:   if (if_rmap->routemap[IF_RMAP_IN])
        !          2895:     {
        !          2896:       rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
        !          2897:       if (rmap)
        !          2898:        ri->routemap[IF_RMAP_IN] = rmap;
        !          2899:       else
        !          2900:        ri->routemap[IF_RMAP_IN] = NULL;
        !          2901:     }
        !          2902:   else
        !          2903:     ri->routemap[RIPNG_FILTER_IN] = NULL;
        !          2904: 
        !          2905:   if (if_rmap->routemap[IF_RMAP_OUT])
        !          2906:     {
        !          2907:       rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
        !          2908:       if (rmap)
        !          2909:        ri->routemap[IF_RMAP_OUT] = rmap;
        !          2910:       else
        !          2911:        ri->routemap[IF_RMAP_OUT] = NULL;
        !          2912:     }
        !          2913:   else
        !          2914:     ri->routemap[RIPNG_FILTER_OUT] = NULL;
        !          2915: }
        !          2916: 
        !          2917: void
        !          2918: ripng_if_rmap_update_interface (struct interface *ifp)
        !          2919: {
        !          2920:   struct if_rmap *if_rmap;
        !          2921: 
        !          2922:   if_rmap = if_rmap_lookup (ifp->name);
        !          2923:   if (if_rmap)
        !          2924:     ripng_if_rmap_update (if_rmap);
        !          2925: }
        !          2926: 
        !          2927: static void
        !          2928: ripng_routemap_update_redistribute (void)
        !          2929: {
        !          2930:   int i;
        !          2931: 
        !          2932:   if (ripng)
        !          2933:     {
        !          2934:       for (i = 0; i < ZEBRA_ROUTE_MAX; i++) 
        !          2935:        {
        !          2936:          if (ripng->route_map[i].name)
        !          2937:            ripng->route_map[i].map = 
        !          2938:              route_map_lookup_by_name (ripng->route_map[i].name);
        !          2939:        }
        !          2940:     }
        !          2941: }
        !          2942: 
        !          2943: static void
        !          2944: ripng_routemap_update (const char *unused)
        !          2945: {
        !          2946:   struct interface *ifp;
        !          2947:   struct listnode *node;
        !          2948: 
        !          2949:   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
        !          2950:     ripng_if_rmap_update_interface (ifp);
        !          2951: 
        !          2952:   ripng_routemap_update_redistribute ();
        !          2953: }
        !          2954: 
        !          2955: /* Initialize ripng structure and set commands. */
        !          2956: void
        !          2957: ripng_init ()
        !          2958: {
        !          2959:   /* Randomize. */
        !          2960:   srand (time (NULL));
        !          2961: 
        !          2962:   /* Install RIPNG_NODE. */
        !          2963:   install_node (&cmd_ripng_node, ripng_config_write);
        !          2964: 
        !          2965:   /* Install ripng commands. */
        !          2966:   install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
        !          2967:   install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
        !          2968: 
        !          2969:   install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
        !          2970:   install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
        !          2971: 
        !          2972:   install_element (CONFIG_NODE, &router_ripng_cmd);
        !          2973:   install_element (CONFIG_NODE, &no_router_ripng_cmd);
        !          2974: 
        !          2975:   install_default (RIPNG_NODE);
        !          2976:   install_element (RIPNG_NODE, &ripng_route_cmd);
        !          2977:   install_element (RIPNG_NODE, &no_ripng_route_cmd);
        !          2978:   install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
        !          2979:   install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
        !          2980: 
        !          2981:   install_element (RIPNG_NODE, &ripng_default_metric_cmd);
        !          2982:   install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
        !          2983:   install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
        !          2984: 
        !          2985:   install_element (RIPNG_NODE, &ripng_timers_cmd);
        !          2986:   install_element (RIPNG_NODE, &no_ripng_timers_cmd);
        !          2987:   install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
        !          2988: #if 0
        !          2989:   install_element (RIPNG_NODE, &ripng_update_timer_cmd);
        !          2990:   install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
        !          2991:   install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
        !          2992:   install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
        !          2993:   install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
        !          2994:   install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
        !          2995: #endif /* 0 */
        !          2996: 
        !          2997:   install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
        !          2998:   install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
        !          2999: 
        !          3000:   ripng_if_init ();
        !          3001:   ripng_debug_init ();
        !          3002: 
        !          3003:   /* Access list install. */
        !          3004:   access_list_init ();
        !          3005:   access_list_add_hook (ripng_distribute_update_all_wrapper);
        !          3006:   access_list_delete_hook (ripng_distribute_update_all_wrapper);
        !          3007: 
        !          3008:   /* Prefix list initialize.*/
        !          3009:   prefix_list_init ();
        !          3010:   prefix_list_add_hook (ripng_distribute_update_all);
        !          3011:   prefix_list_delete_hook (ripng_distribute_update_all);
        !          3012: 
        !          3013:   /* Distribute list install. */
        !          3014:   distribute_list_init (RIPNG_NODE);
        !          3015:   distribute_list_add_hook (ripng_distribute_update);
        !          3016:   distribute_list_delete_hook (ripng_distribute_update);
        !          3017: 
        !          3018:   /* Route-map for interface. */
        !          3019:   ripng_route_map_init ();
        !          3020:   ripng_offset_init ();
        !          3021: 
        !          3022:   route_map_add_hook (ripng_routemap_update);
        !          3023:   route_map_delete_hook (ripng_routemap_update);
        !          3024: 
        !          3025:   if_rmap_init (RIPNG_NODE);
        !          3026:   if_rmap_hook_add (ripng_if_rmap_update);
        !          3027:   if_rmap_hook_delete (ripng_if_rmap_update);
        !          3028: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>