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