1/*
2 * Interface related function for RIPng.
3 * Copyright (C) 1998 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "linklist.h"
26#include "if.h"
27#include "prefix.h"
28#include "memory.h"
29#include "network.h"
30#include "filter.h"
31#include "log.h"
32#include "stream.h"
33#include "zclient.h"
34#include "command.h"
35#include "table.h"
36#include "thread.h"
37#include "privs.h"
38
39#include "ripngd/ripngd.h"
40#include "ripngd/ripng_debug.h"
41
42/* If RFC2133 definition is used. */
43#ifndef IPV6_JOIN_GROUP
44#define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP
45#endif
46#ifndef IPV6_LEAVE_GROUP
47#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
48#endif
49
50extern struct zebra_privs_t ripngd_privs;
51
52/* Static utility function. */
53static void ripng_enable_apply (struct interface *);
54static void ripng_passive_interface_apply (struct interface *);
55static int ripng_enable_if_lookup (const char *);
56static int ripng_enable_network_lookup2 (struct connected *);
57static void ripng_enable_apply_all (void);
58
59/* Join to the all rip routers multicast group. */
60static int
61ripng_multicast_join (struct interface *ifp)
62{
63  int ret;
64  struct ipv6_mreq mreq;
65  int save_errno;
66
67  if (if_is_up (ifp) && if_is_multicast (ifp)) {
68    memset (&mreq, 0, sizeof (mreq));
69    inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
70    mreq.ipv6mr_interface = ifp->ifindex;
71
72    /*
73     * NetBSD 1.6.2 requires root to join groups on gif(4).
74     * While this is bogus, privs are available and easy to use
75     * for this call as a workaround.
76     */
77    if (ripngd_privs.change (ZPRIVS_RAISE))
78      zlog_err ("ripng_multicast_join: could not raise privs");
79
80    ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
81		      (char *) &mreq, sizeof (mreq));
82    save_errno = errno;
83
84    if (ripngd_privs.change (ZPRIVS_LOWER))
85      zlog_err ("ripng_multicast_join: could not lower privs");
86
87    if (ret < 0 && save_errno == EADDRINUSE)
88      {
89	/*
90	 * Group is already joined.  This occurs due to sloppy group
91	 * management, in particular declining to leave the group on
92	 * an interface that has just gone down.
93	 */
94	zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name);
95	return 0;		/* not an error */
96      }
97
98    if (ret < 0)
99      zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s",
100      		 safe_strerror (save_errno));
101
102    if (IS_RIPNG_DEBUG_EVENT)
103      zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name);
104
105    if (ret < 0)
106      return -1;
107  }
108  return 0;
109}
110
111/* Leave from the all rip routers multicast group. */
112static int
113ripng_multicast_leave (struct interface *ifp)
114{
115  int ret;
116  struct ipv6_mreq mreq;
117
118  if (if_is_up (ifp) && if_is_multicast (ifp)) {
119    memset (&mreq, 0, sizeof (mreq));
120    inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
121    mreq.ipv6mr_interface = ifp->ifindex;
122
123    ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
124		      (char *) &mreq, sizeof (mreq));
125    if (ret < 0)
126      zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", safe_strerror (errno));
127
128    if (IS_RIPNG_DEBUG_EVENT)
129      zlog_debug ("RIPng %s leave from all-rip-routers multicast group",
130	         ifp->name);
131
132    if (ret < 0)
133      return -1;
134  }
135
136  return 0;
137}
138
139/* How many link local IPv6 address could be used on the interface ? */
140static int
141ripng_if_ipv6_lladdress_check (struct interface *ifp)
142{
143  struct listnode *nn;
144  struct connected *connected;
145  int count = 0;
146
147  for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected))
148    {
149      struct prefix *p;
150      p = connected->address;
151
152      if ((p->family == AF_INET6) &&
153          IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6))
154        count++;
155    }
156
157  return count;
158}
159
160static int
161ripng_if_down (struct interface *ifp)
162{
163  struct route_node *rp;
164  struct ripng_info *rinfo;
165  struct ripng_interface *ri;
166
167  if (ripng)
168    {
169      for (rp = route_top (ripng->table); rp; rp = route_next (rp))
170	if ((rinfo = rp->info) != NULL)
171	  {
172	    /* Routes got through this interface. */
173	    if (rinfo->ifindex == ifp->ifindex
174		&& rinfo->type == ZEBRA_ROUTE_RIPNG
175		&& rinfo->sub_type == RIPNG_ROUTE_RTE)
176	      {
177		ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p,
178					 &rinfo->nexthop,
179					 rinfo->ifindex);
180
181		ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
182					   (struct prefix_ipv6 *)&rp->p,
183					   rinfo->ifindex);
184	      }
185	    else
186	      {
187		/* All redistributed routes got through this interface,
188		 * but the static and system ones are kept. */
189		if ((rinfo->ifindex == ifp->ifindex) &&
190		    (rinfo->type != ZEBRA_ROUTE_STATIC) &&
191		    (rinfo->type != ZEBRA_ROUTE_SYSTEM))
192		  ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
193					     (struct prefix_ipv6 *) &rp->p,
194					     rinfo->ifindex);
195	      }
196	  }
197    }
198
199  ri = ifp->info;
200
201  if (ri->running)
202   {
203     if (IS_RIPNG_DEBUG_EVENT)
204       zlog_debug ("turn off %s", ifp->name);
205
206     /* Leave from multicast group. */
207     ripng_multicast_leave (ifp);
208
209     ri->running = 0;
210   }
211
212  return 0;
213}
214
215/* Inteface link up message processing. */
216int
217ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length)
218{
219  struct stream *s;
220  struct interface *ifp;
221
222  /* zebra_interface_state_read() updates interface structure in iflist. */
223  s = zclient->ibuf;
224  ifp = zebra_interface_state_read (s);
225
226  if (ifp == NULL)
227    return 0;
228
229  if (IS_RIPNG_DEBUG_ZEBRA)
230    zlog_debug ("interface up %s index %d flags %llx metric %d mtu %d",
231	       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
232	       ifp->metric, ifp->mtu6);
233
234  /* Check if this interface is RIPng enabled or not. */
235  ripng_enable_apply (ifp);
236
237  /* Check for a passive interface. */
238  ripng_passive_interface_apply (ifp);
239
240  /* Apply distribute list to the all interface. */
241  ripng_distribute_update_interface (ifp);
242
243  return 0;
244}
245
246/* Inteface link down message processing. */
247int
248ripng_interface_down (int command, struct zclient *zclient,
249		      zebra_size_t length)
250{
251  struct stream *s;
252  struct interface *ifp;
253
254  /* zebra_interface_state_read() updates interface structure in iflist. */
255  s = zclient->ibuf;
256  ifp = zebra_interface_state_read (s);
257
258  if (ifp == NULL)
259    return 0;
260
261  ripng_if_down (ifp);
262
263  if (IS_RIPNG_DEBUG_ZEBRA)
264    zlog_debug ("interface down %s index %d flags %#llx metric %d mtu %d",
265		ifp->name, ifp->ifindex,
266		(unsigned long long) ifp->flags, ifp->metric, ifp->mtu6);
267
268  return 0;
269}
270
271/* Inteface addition message from zebra. */
272int
273ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length)
274{
275  struct interface *ifp;
276
277  ifp = zebra_interface_add_read (zclient->ibuf);
278
279  if (IS_RIPNG_DEBUG_ZEBRA)
280    zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d",
281		ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
282		ifp->metric, ifp->mtu6);
283
284  /* Check is this interface is RIP enabled or not.*/
285  ripng_enable_apply (ifp);
286
287  /* Apply distribute list to the interface. */
288  ripng_distribute_update_interface (ifp);
289
290  /* Check interface routemap. */
291  ripng_if_rmap_update_interface (ifp);
292
293  return 0;
294}
295
296int
297ripng_interface_delete (int command, struct zclient *zclient,
298			zebra_size_t length)
299{
300  struct interface *ifp;
301  struct stream *s;
302
303  s = zclient->ibuf;
304  /*  zebra_interface_state_read() updates interface structure in iflist */
305  ifp = zebra_interface_state_read(s);
306
307  if (ifp == NULL)
308    return 0;
309
310  if (if_is_up (ifp)) {
311    ripng_if_down(ifp);
312  }
313
314  zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d",
315            ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
316	    ifp->metric, ifp->mtu6);
317
318  /* To support pseudo interface do not free interface structure.  */
319  /* if_delete(ifp); */
320  ifp->ifindex = IFINDEX_INTERNAL;
321
322  return 0;
323}
324
325void
326ripng_interface_clean (void)
327{
328  struct listnode *node, *nnode;
329  struct interface *ifp;
330  struct ripng_interface *ri;
331
332  for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
333    {
334      ri = ifp->info;
335
336      ri->enable_network = 0;
337      ri->enable_interface = 0;
338      ri->running = 0;
339
340      if (ri->t_wakeup)
341        {
342          thread_cancel (ri->t_wakeup);
343          ri->t_wakeup = NULL;
344        }
345    }
346}
347
348void
349ripng_interface_reset (void)
350{
351  struct listnode *node;
352  struct interface *ifp;
353  struct ripng_interface *ri;
354
355  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
356    {
357      ri = ifp->info;
358
359      ri->enable_network = 0;
360      ri->enable_interface = 0;
361      ri->running = 0;
362
363      ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
364      ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON;
365
366      ri->list[RIPNG_FILTER_IN] = NULL;
367      ri->list[RIPNG_FILTER_OUT] = NULL;
368
369      ri->prefix[RIPNG_FILTER_IN] = NULL;
370      ri->prefix[RIPNG_FILTER_OUT] = NULL;
371
372      if (ri->t_wakeup)
373        {
374          thread_cancel (ri->t_wakeup);
375          ri->t_wakeup = NULL;
376        }
377
378      ri->passive = 0;
379    }
380}
381
382static void
383ripng_apply_address_add (struct connected *ifc) {
384  struct prefix_ipv6 address;
385  struct prefix *p;
386
387  if (!ripng)
388    return;
389
390  if (! if_is_up(ifc->ifp))
391    return;
392
393  p = ifc->address;
394
395  memset (&address, 0, sizeof (address));
396  address.family = p->family;
397  address.prefix = p->u.prefix6;
398  address.prefixlen = p->prefixlen;
399  apply_mask_ipv6(&address);
400
401  /* Check if this interface is RIP enabled or not
402     or  Check if this address's prefix is RIP enabled */
403  if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) ||
404      (ripng_enable_network_lookup2(ifc) >= 0))
405    ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
406                           &address, ifc->ifp->ifindex, NULL);
407
408}
409
410int
411ripng_interface_address_add (int command, struct zclient *zclient,
412			     zebra_size_t length)
413{
414  struct connected *c;
415  struct prefix *p;
416
417  c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
418                                    zclient->ibuf);
419
420  if (c == NULL)
421    return 0;
422
423  p = c->address;
424
425  if (p->family == AF_INET6)
426    {
427      struct ripng_interface *ri = c->ifp->info;
428
429      if (IS_RIPNG_DEBUG_ZEBRA)
430	zlog_debug ("RIPng connected address %s/%d add",
431		   inet6_ntoa(p->u.prefix6),
432		   p->prefixlen);
433
434      /* Check is this prefix needs to be redistributed. */
435      ripng_apply_address_add(c);
436
437      /* Let's try once again whether the interface could be activated */
438      if (!ri->running) {
439        /* Check if this interface is RIP enabled or not.*/
440        ripng_enable_apply (c->ifp);
441
442        /* Apply distribute list to the interface. */
443        ripng_distribute_update_interface (c->ifp);
444
445        /* Check interface routemap. */
446        ripng_if_rmap_update_interface (c->ifp);
447      }
448
449    }
450
451  return 0;
452}
453
454static void
455ripng_apply_address_del (struct connected *ifc) {
456  struct prefix_ipv6 address;
457  struct prefix *p;
458
459  if (!ripng)
460    return;
461
462  if (! if_is_up(ifc->ifp))
463    return;
464
465  p = ifc->address;
466
467  memset (&address, 0, sizeof (address));
468  address.family = p->family;
469  address.prefix = p->u.prefix6;
470  address.prefixlen = p->prefixlen;
471  apply_mask_ipv6(&address);
472
473  ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
474                            &address, ifc->ifp->ifindex);
475}
476
477int
478ripng_interface_address_delete (int command, struct zclient *zclient,
479				zebra_size_t length)
480{
481  struct connected *ifc;
482  struct prefix *p;
483  char buf[INET6_ADDRSTRLEN];
484
485  ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE,
486                                      zclient->ibuf);
487
488  if (ifc)
489    {
490      p = ifc->address;
491
492      if (p->family == AF_INET6)
493	{
494	  if (IS_RIPNG_DEBUG_ZEBRA)
495	    zlog_debug ("RIPng connected address %s/%d delete",
496		       inet_ntop (AF_INET6, &p->u.prefix6, buf,
497				  INET6_ADDRSTRLEN),
498		       p->prefixlen);
499
500	  /* Check wether this prefix needs to be removed. */
501	  ripng_apply_address_del(ifc);
502	}
503      connected_free (ifc);
504    }
505
506  return 0;
507}
508
509/* RIPng enable interface vector. */
510vector ripng_enable_if;
511
512/* RIPng enable network table. */
513struct route_table *ripng_enable_network;
514
515/* Lookup RIPng enable network. */
516/* Check wether the interface has at least a connected prefix that
517 * is within the ripng_enable_network table. */
518static int
519ripng_enable_network_lookup_if (struct interface *ifp)
520{
521  struct listnode *node;
522  struct connected *connected;
523  struct prefix_ipv6 address;
524
525  for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
526    {
527      struct prefix *p;
528      struct route_node *node;
529
530      p = connected->address;
531
532      if (p->family == AF_INET6)
533        {
534          address.family = AF_INET6;
535          address.prefix = p->u.prefix6;
536          address.prefixlen = IPV6_MAX_BITLEN;
537
538          node = route_node_match (ripng_enable_network,
539                                   (struct prefix *)&address);
540          if (node)
541            {
542              route_unlock_node (node);
543              return 1;
544            }
545        }
546    }
547  return -1;
548}
549
550/* Check wether connected is within the ripng_enable_network table. */
551static int
552ripng_enable_network_lookup2 (struct connected *connected)
553{
554  struct prefix_ipv6 address;
555  struct prefix *p;
556
557  p = connected->address;
558
559  if (p->family == AF_INET6) {
560    struct route_node *node;
561
562    address.family = p->family;
563    address.prefix = p->u.prefix6;
564    address.prefixlen = IPV6_MAX_BITLEN;
565
566    /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */
567    node = route_node_match (ripng_enable_network,
568                             (struct prefix *)&address);
569
570    if (node) {
571      route_unlock_node (node);
572      return 1;
573    }
574  }
575
576  return -1;
577}
578
579/* Add RIPng enable network. */
580static int
581ripng_enable_network_add (struct prefix *p)
582{
583  struct route_node *node;
584
585  node = route_node_get (ripng_enable_network, p);
586
587  if (node->info)
588    {
589      route_unlock_node (node);
590      return -1;
591    }
592  else
593    node->info = (char *) "enabled";
594
595  /* XXX: One should find a better solution than a generic one */
596  ripng_enable_apply_all();
597
598  return 1;
599}
600
601/* Delete RIPng enable network. */
602static int
603ripng_enable_network_delete (struct prefix *p)
604{
605  struct route_node *node;
606
607  node = route_node_lookup (ripng_enable_network, p);
608  if (node)
609    {
610      node->info = NULL;
611
612      /* Unlock info lock. */
613      route_unlock_node (node);
614
615      /* Unlock lookup lock. */
616      route_unlock_node (node);
617
618      return 1;
619    }
620  return -1;
621}
622
623/* Lookup function. */
624static int
625ripng_enable_if_lookup (const char *ifname)
626{
627  unsigned int i;
628  char *str;
629
630  for (i = 0; i < vector_active (ripng_enable_if); i++)
631    if ((str = vector_slot (ripng_enable_if, i)) != NULL)
632      if (strcmp (str, ifname) == 0)
633	return i;
634  return -1;
635}
636
637/* Add interface to ripng_enable_if. */
638static int
639ripng_enable_if_add (const char *ifname)
640{
641  int ret;
642
643  ret = ripng_enable_if_lookup (ifname);
644  if (ret >= 0)
645    return -1;
646
647  vector_set (ripng_enable_if, strdup (ifname));
648
649  ripng_enable_apply_all();
650
651  return 1;
652}
653
654/* Delete interface from ripng_enable_if. */
655static int
656ripng_enable_if_delete (const char *ifname)
657{
658  int index;
659  char *str;
660
661  index = ripng_enable_if_lookup (ifname);
662  if (index < 0)
663    return -1;
664
665  str = vector_slot (ripng_enable_if, index);
666  free (str);
667  vector_unset (ripng_enable_if, index);
668
669  ripng_enable_apply_all();
670
671  return 1;
672}
673
674/* Wake up interface. */
675static int
676ripng_interface_wakeup (struct thread *t)
677{
678  struct interface *ifp;
679  struct ripng_interface *ri;
680
681  /* Get interface. */
682  ifp = THREAD_ARG (t);
683
684  ri = ifp->info;
685  ri->t_wakeup = NULL;
686
687  /* Join to multicast group. */
688  if (ripng_multicast_join (ifp) < 0) {
689    zlog_err ("multicast join failed, interface %s not running", ifp->name);
690    return 0;
691  }
692
693  /* Set running flag. */
694  ri->running = 1;
695
696  /* Send RIP request to the interface. */
697  ripng_request (ifp);
698
699  return 0;
700}
701
702static void
703ripng_connect_set (struct interface *ifp, int set)
704{
705  struct listnode *node, *nnode;
706  struct connected *connected;
707  struct prefix_ipv6 address;
708
709  for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
710    {
711      struct prefix *p;
712      p = connected->address;
713
714      if (p->family != AF_INET6)
715        continue;
716
717      address.family = AF_INET6;
718      address.prefix = p->u.prefix6;
719      address.prefixlen = p->prefixlen;
720      apply_mask_ipv6 (&address);
721
722      if (set) {
723        /* Check once more wether this prefix is within a "network IF_OR_PREF" one */
724        if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) ||
725            (ripng_enable_network_lookup2(connected) >= 0))
726          ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
727                                  &address, connected->ifp->ifindex, NULL);
728      } else {
729        ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
730                                   &address, connected->ifp->ifindex);
731        if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT))
732          ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE,
733                                  &address, connected->ifp->ifindex, NULL);
734      }
735    }
736}
737
738/* Check RIPng is enabed on this interface. */
739void
740ripng_enable_apply (struct interface *ifp)
741{
742  int ret;
743  struct ripng_interface *ri = NULL;
744
745  /* Check interface. */
746  if (! if_is_up (ifp))
747    return;
748
749  ri = ifp->info;
750
751  /* Is this interface a candidate for RIPng ? */
752  ret = ripng_enable_network_lookup_if (ifp);
753
754  /* If the interface is matched. */
755  if (ret > 0)
756    ri->enable_network = 1;
757  else
758    ri->enable_network = 0;
759
760  /* Check interface name configuration. */
761  ret = ripng_enable_if_lookup (ifp->name);
762  if (ret >= 0)
763    ri->enable_interface = 1;
764  else
765    ri->enable_interface = 0;
766
767  /* any candidate interface MUST have a link-local IPv6 address */
768  if ((! ripng_if_ipv6_lladdress_check (ifp)) &&
769      (ri->enable_network || ri->enable_interface)) {
770    ri->enable_network = 0;
771    ri->enable_interface = 0;
772    zlog_warn("Interface %s does not have any link-local address",
773              ifp->name);
774  }
775
776  /* Update running status of the interface. */
777  if (ri->enable_network || ri->enable_interface)
778    {
779	{
780	  if (IS_RIPNG_DEBUG_EVENT)
781	    zlog_debug ("RIPng turn on %s", ifp->name);
782
783	  /* Add interface wake up thread. */
784	  if (! ri->t_wakeup)
785	    ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup,
786					     ifp, 1);
787
788	  ripng_connect_set (ifp, 1);
789	}
790    }
791  else
792    {
793      if (ri->running)
794	{
795	  /* Might as well clean up the route table as well
796	   * ripng_if_down sets to 0 ri->running, and displays "turn off %s"
797	   **/
798	  ripng_if_down(ifp);
799
800	  ripng_connect_set (ifp, 0);
801	}
802    }
803}
804
805/* Set distribute list to all interfaces. */
806static void
807ripng_enable_apply_all (void)
808{
809  struct interface *ifp;
810  struct listnode *node;
811
812  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
813    ripng_enable_apply (ifp);
814}
815
816/* Clear all network and neighbor configuration */
817void
818ripng_clean_network ()
819{
820  unsigned int i;
821  char *str;
822  struct route_node *rn;
823
824  /* ripng_enable_network */
825  for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn))
826    if (rn->info) {
827      rn->info = NULL;
828      route_unlock_node(rn);
829    }
830
831  /* ripng_enable_if */
832  for (i = 0; i < vector_active (ripng_enable_if); i++)
833    if ((str = vector_slot (ripng_enable_if, i)) != NULL) {
834      free (str);
835      vector_slot (ripng_enable_if, i) = NULL;
836    }
837}
838
839/* Vector to store passive-interface name. */
840vector Vripng_passive_interface;
841
842/* Utility function for looking up passive interface settings. */
843static int
844ripng_passive_interface_lookup (const char *ifname)
845{
846  unsigned int i;
847  char *str;
848
849  for (i = 0; i < vector_active (Vripng_passive_interface); i++)
850    if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
851      if (strcmp (str, ifname) == 0)
852	return i;
853  return -1;
854}
855
856void
857ripng_passive_interface_apply (struct interface *ifp)
858{
859  int ret;
860  struct ripng_interface *ri;
861
862  ri = ifp->info;
863
864  ret = ripng_passive_interface_lookup (ifp->name);
865  if (ret < 0)
866    ri->passive = 0;
867  else
868    ri->passive = 1;
869}
870
871static void
872ripng_passive_interface_apply_all (void)
873{
874  struct interface *ifp;
875  struct listnode *node;
876
877  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
878    ripng_passive_interface_apply (ifp);
879}
880
881/* Passive interface. */
882static int
883ripng_passive_interface_set (struct vty *vty, const char *ifname)
884{
885  if (ripng_passive_interface_lookup (ifname) >= 0)
886    return CMD_WARNING;
887
888  vector_set (Vripng_passive_interface, strdup (ifname));
889
890  ripng_passive_interface_apply_all ();
891
892  return CMD_SUCCESS;
893}
894
895static int
896ripng_passive_interface_unset (struct vty *vty, const char *ifname)
897{
898  int i;
899  char *str;
900
901  i = ripng_passive_interface_lookup (ifname);
902  if (i < 0)
903    return CMD_WARNING;
904
905  str = vector_slot (Vripng_passive_interface, i);
906  free (str);
907  vector_unset (Vripng_passive_interface, i);
908
909  ripng_passive_interface_apply_all ();
910
911  return CMD_SUCCESS;
912}
913
914/* Free all configured RIP passive-interface settings. */
915void
916ripng_passive_interface_clean (void)
917{
918  unsigned int i;
919  char *str;
920
921  for (i = 0; i < vector_active (Vripng_passive_interface); i++)
922    if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
923      {
924	free (str);
925	vector_slot (Vripng_passive_interface, i) = NULL;
926      }
927  ripng_passive_interface_apply_all ();
928}
929
930/* Write RIPng enable network and interface to the vty. */
931int
932ripng_network_write (struct vty *vty, int config_mode)
933{
934  unsigned int i;
935  const char *ifname;
936  struct route_node *node;
937  char buf[BUFSIZ];
938
939  /* Write enable network. */
940  for (node = route_top (ripng_enable_network); node; node = route_next (node))
941    if (node->info)
942      {
943	struct prefix *p = &node->p;
944	vty_out (vty, "%s%s/%d%s",
945		 config_mode ? " network " : "    ",
946		 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
947		 p->prefixlen,
948		 VTY_NEWLINE);
949
950      }
951
952  /* Write enable interface. */
953  for (i = 0; i < vector_active (ripng_enable_if); i++)
954    if ((ifname = vector_slot (ripng_enable_if, i)) != NULL)
955      vty_out (vty, "%s%s%s",
956	       config_mode ? " network " : "    ",
957	       ifname,
958	       VTY_NEWLINE);
959
960  /* Write passive interface. */
961  if (config_mode)
962    for (i = 0; i < vector_active (Vripng_passive_interface); i++)
963      if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
964        vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
965
966  return 0;
967}
968
969/* RIPng enable on specified interface or matched network. */
970DEFUN (ripng_network,
971       ripng_network_cmd,
972       "network IF_OR_ADDR",
973       "RIPng enable on specified interface or network.\n"
974       "Interface or address")
975{
976  int ret;
977  struct prefix p;
978
979  ret = str2prefix (argv[0], &p);
980
981  /* Given string is IPv6 network or interface name. */
982  if (ret)
983    ret = ripng_enable_network_add (&p);
984  else
985    ret = ripng_enable_if_add (argv[0]);
986
987  if (ret < 0)
988    {
989      vty_out (vty, "There is same network configuration %s%s", argv[0],
990	       VTY_NEWLINE);
991      return CMD_WARNING;
992    }
993
994  return CMD_SUCCESS;
995}
996
997/* RIPng enable on specified interface or matched network. */
998DEFUN (no_ripng_network,
999       no_ripng_network_cmd,
1000       "no network IF_OR_ADDR",
1001       NO_STR
1002       "RIPng enable on specified interface or network.\n"
1003       "Interface or address")
1004{
1005  int ret;
1006  struct prefix p;
1007
1008  ret = str2prefix (argv[0], &p);
1009
1010  /* Given string is interface name. */
1011  if (ret)
1012    ret = ripng_enable_network_delete (&p);
1013  else
1014    ret = ripng_enable_if_delete (argv[0]);
1015
1016  if (ret < 0)
1017    {
1018      vty_out (vty, "can't find network %s%s", argv[0],
1019	       VTY_NEWLINE);
1020      return CMD_WARNING;
1021    }
1022
1023  return CMD_SUCCESS;
1024}
1025
1026DEFUN (ipv6_ripng_split_horizon,
1027       ipv6_ripng_split_horizon_cmd,
1028       "ipv6 ripng split-horizon",
1029       IPV6_STR
1030       "Routing Information Protocol\n"
1031       "Perform split horizon\n")
1032{
1033  struct interface *ifp;
1034  struct ripng_interface *ri;
1035
1036  ifp = vty->index;
1037  ri = ifp->info;
1038
1039  ri->split_horizon = RIPNG_SPLIT_HORIZON;
1040  return CMD_SUCCESS;
1041}
1042
1043DEFUN (ipv6_ripng_split_horizon_poisoned_reverse,
1044       ipv6_ripng_split_horizon_poisoned_reverse_cmd,
1045       "ipv6 ripng split-horizon poisoned-reverse",
1046       IPV6_STR
1047       "Routing Information Protocol\n"
1048       "Perform split horizon\n"
1049       "With poisoned-reverse\n")
1050{
1051  struct interface *ifp;
1052  struct ripng_interface *ri;
1053
1054  ifp = vty->index;
1055  ri = ifp->info;
1056
1057  ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE;
1058  return CMD_SUCCESS;
1059}
1060
1061DEFUN (no_ipv6_ripng_split_horizon,
1062       no_ipv6_ripng_split_horizon_cmd,
1063       "no ipv6 ripng split-horizon",
1064       NO_STR
1065       IPV6_STR
1066       "Routing Information Protocol\n"
1067       "Perform split horizon\n")
1068{
1069  struct interface *ifp;
1070  struct ripng_interface *ri;
1071
1072  ifp = vty->index;
1073  ri = ifp->info;
1074
1075  ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
1076  return CMD_SUCCESS;
1077}
1078
1079ALIAS (no_ipv6_ripng_split_horizon,
1080       no_ipv6_ripng_split_horizon_poisoned_reverse_cmd,
1081       "no ipv6 ripng split-horizon poisoned-reverse",
1082       NO_STR
1083       IPV6_STR
1084       "Routing Information Protocol\n"
1085       "Perform split horizon\n"
1086       "With poisoned-reverse\n")
1087
1088DEFUN (ripng_passive_interface,
1089       ripng_passive_interface_cmd,
1090       "passive-interface IFNAME",
1091       "Suppress routing updates on an interface\n"
1092       "Interface name\n")
1093{
1094  return ripng_passive_interface_set (vty, argv[0]);
1095}
1096
1097DEFUN (no_ripng_passive_interface,
1098       no_ripng_passive_interface_cmd,
1099       "no passive-interface IFNAME",
1100       NO_STR
1101       "Suppress routing updates on an interface\n"
1102       "Interface name\n")
1103{
1104  return ripng_passive_interface_unset (vty, argv[0]);
1105}
1106
1107static struct ripng_interface *
1108ri_new (void)
1109{
1110  struct ripng_interface *ri;
1111  ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
1112
1113  /* Set default split-horizon behavior.  If the interface is Frame
1114     Relay or SMDS is enabled, the default value for split-horizon is
1115     off.  But currently Zebra does detect Frame Relay or SMDS
1116     interface.  So all interface is set to split horizon.  */
1117  ri->split_horizon_default = RIPNG_SPLIT_HORIZON;
1118  ri->split_horizon = ri->split_horizon_default;
1119
1120  return ri;
1121}
1122
1123static int
1124ripng_if_new_hook (struct interface *ifp)
1125{
1126  ifp->info = ri_new ();
1127  return 0;
1128}
1129
1130/* Called when interface structure deleted. */
1131static int
1132ripng_if_delete_hook (struct interface *ifp)
1133{
1134  XFREE (MTYPE_IF, ifp->info);
1135  ifp->info = NULL;
1136  return 0;
1137}
1138
1139/* Configuration write function for ripngd. */
1140static int
1141interface_config_write (struct vty *vty)
1142{
1143  struct listnode *node;
1144  struct interface *ifp;
1145  struct ripng_interface *ri;
1146  int write = 0;
1147
1148  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
1149    {
1150      ri = ifp->info;
1151
1152      /* Do not display the interface if there is no
1153       * configuration about it.
1154       **/
1155      if ((!ifp->desc) &&
1156          (ri->split_horizon == ri->split_horizon_default))
1157        continue;
1158
1159      vty_out (vty, "interface %s%s", ifp->name,
1160	       VTY_NEWLINE);
1161      if (ifp->desc)
1162	vty_out (vty, " description %s%s", ifp->desc,
1163		 VTY_NEWLINE);
1164
1165      /* Split horizon. */
1166      if (ri->split_horizon != ri->split_horizon_default)
1167	{
1168          switch (ri->split_horizon) {
1169          case RIPNG_SPLIT_HORIZON:
1170            vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE);
1171            break;
1172          case RIPNG_SPLIT_HORIZON_POISONED_REVERSE:
1173            vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s",
1174                          VTY_NEWLINE);
1175            break;
1176          case RIPNG_NO_SPLIT_HORIZON:
1177          default:
1178            vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE);
1179            break;
1180          }
1181	}
1182
1183      vty_out (vty, "!%s", VTY_NEWLINE);
1184
1185      write++;
1186    }
1187  return write;
1188}
1189
1190/* ripngd's interface node. */
1191static struct cmd_node interface_node =
1192{
1193  INTERFACE_NODE,
1194  "%s(config-if)# ",
1195  1 /* VTYSH */
1196};
1197
1198/* Initialization of interface. */
1199void
1200ripng_if_init ()
1201{
1202  /* Interface initialize. */
1203  iflist = list_new ();
1204  if_add_hook (IF_NEW_HOOK, ripng_if_new_hook);
1205  if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook);
1206
1207  /* RIPng enable network init. */
1208  ripng_enable_network = route_table_init ();
1209
1210  /* RIPng enable interface init. */
1211  ripng_enable_if = vector_init (1);
1212
1213  /* RIPng passive interface. */
1214  Vripng_passive_interface = vector_init (1);
1215
1216  /* Install interface node. */
1217  install_node (&interface_node, interface_config_write);
1218
1219  /* Install commands. */
1220  install_element (CONFIG_NODE, &interface_cmd);
1221  install_element (CONFIG_NODE, &no_interface_cmd);
1222  install_default (INTERFACE_NODE);
1223  install_element (INTERFACE_NODE, &interface_desc_cmd);
1224  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
1225
1226  install_element (RIPNG_NODE, &ripng_network_cmd);
1227  install_element (RIPNG_NODE, &no_ripng_network_cmd);
1228  install_element (RIPNG_NODE, &ripng_passive_interface_cmd);
1229  install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd);
1230
1231  install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
1232  install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd);
1233  install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd);
1234  install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd);
1235}
1236