1/* Router advertisement
2 * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com>
3 * Copyright (C) 1999 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 "memory.h"
26#include "sockopt.h"
27#include "thread.h"
28#include "if.h"
29#include "log.h"
30#include "prefix.h"
31#include "linklist.h"
32#include "command.h"
33#include "privs.h"
34
35#include "zebra/interface.h"
36#include "zebra/rtadv.h"
37#include "zebra/debug.h"
38#include "zebra/rib.h"
39#include "zebra/zserv.h"
40
41extern struct zebra_privs_t zserv_privs;
42
43#if defined (HAVE_IPV6) && defined (RTADV)
44
45#ifdef OPEN_BSD
46#include <netinet/icmp6.h>
47#endif
48
49/* If RFC2133 definition is used. */
50#ifndef IPV6_JOIN_GROUP
51#define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP
52#endif
53#ifndef IPV6_LEAVE_GROUP
54#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
55#endif
56
57#define ALLNODE   "ff02::1"
58#define ALLROUTER "ff02::2"
59
60extern struct zebra_t zebrad;
61
62enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER,
63		  RTADV_TIMER_MSEC, RTADV_READ};
64
65static void rtadv_event (enum rtadv_event, int);
66
67static int if_join_all_router (int, struct interface *);
68static int if_leave_all_router (int, struct interface *);
69
70/* Structure which hold status of router advertisement. */
71struct rtadv
72{
73  int sock;
74
75  int adv_if_count;
76  int adv_msec_if_count;
77
78  struct thread *ra_read;
79  struct thread *ra_timer;
80};
81
82struct rtadv *rtadv = NULL;
83
84static struct rtadv *
85rtadv_new (void)
86{
87  return XCALLOC (MTYPE_TMP, sizeof (struct rtadv));
88}
89
90static int
91rtadv_recv_packet (int sock, u_char *buf, int buflen,
92		   struct sockaddr_in6 *from, unsigned int *ifindex,
93		   int *hoplimit)
94{
95  int ret;
96  struct msghdr msg;
97  struct iovec iov;
98  struct cmsghdr  *cmsgptr;
99  struct in6_addr dst;
100
101  char adata[1024];
102
103  /* Fill in message and iovec. */
104  msg.msg_name = (void *) from;
105  msg.msg_namelen = sizeof (struct sockaddr_in6);
106  msg.msg_iov = &iov;
107  msg.msg_iovlen = 1;
108  msg.msg_control = (void *) adata;
109  msg.msg_controllen = sizeof adata;
110  iov.iov_base = buf;
111  iov.iov_len = buflen;
112
113  /* If recvmsg fail return minus value. */
114  ret = recvmsg (sock, &msg, 0);
115  if (ret < 0)
116    return ret;
117
118  for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
119       cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
120    {
121      /* I want interface index which this packet comes from. */
122      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
123	  cmsgptr->cmsg_type == IPV6_PKTINFO)
124	{
125	  struct in6_pktinfo *ptr;
126
127	  ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
128	  *ifindex = ptr->ipi6_ifindex;
129	  memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
130        }
131
132      /* Incoming packet's hop limit. */
133      if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
134	  cmsgptr->cmsg_type == IPV6_HOPLIMIT)
135	{
136	  int *hoptr = (int *) CMSG_DATA (cmsgptr);
137	  *hoplimit = *hoptr;
138	}
139    }
140  return ret;
141}
142
143#define RTADV_MSG_SIZE 4096
144
145/* Send router advertisement packet. */
146static void
147rtadv_send_packet (int sock, struct interface *ifp)
148{
149  struct msghdr msg;
150  struct iovec iov;
151  struct cmsghdr  *cmsgptr;
152  struct in6_pktinfo *pkt;
153  struct sockaddr_in6 addr;
154#ifdef HAVE_STRUCT_SOCKADDR_DL
155  struct sockaddr_dl *sdl;
156#endif /* HAVE_STRUCT_SOCKADDR_DL */
157  static void *adata = NULL;
158  unsigned char buf[RTADV_MSG_SIZE];
159  struct nd_router_advert *rtadv;
160  int ret;
161  int len = 0;
162  struct zebra_if *zif;
163  struct rtadv_prefix *rprefix;
164  u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
165  struct listnode *node;
166  u_int16_t pkt_RouterLifetime;
167
168  /*
169   * Allocate control message bufffer.  This is dynamic because
170   * CMSG_SPACE is not guaranteed not to call a function.  Note that
171   * the size will be different on different architectures due to
172   * differing alignment rules.
173   */
174  if (adata == NULL)
175    {
176      /* XXX Free on shutdown. */
177      adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)));
178
179      if (adata == NULL)
180	zlog_err("rtadv_send_packet: can't malloc control data\n");
181    }
182
183  /* Logging of packet. */
184  if (IS_ZEBRA_DEBUG_PACKET)
185    zlog_debug ("Router advertisement send to %s", ifp->name);
186
187  /* Fill in sockaddr_in6. */
188  memset (&addr, 0, sizeof (struct sockaddr_in6));
189  addr.sin6_family = AF_INET6;
190#ifdef SIN6_LEN
191  addr.sin6_len = sizeof (struct sockaddr_in6);
192#endif /* SIN6_LEN */
193  addr.sin6_port = htons (IPPROTO_ICMPV6);
194  IPV6_ADDR_COPY (&addr.sin6_addr, all_nodes_addr);
195
196  /* Fetch interface information. */
197  zif = ifp->info;
198
199  /* Make router advertisement message. */
200  rtadv = (struct nd_router_advert *) buf;
201
202  rtadv->nd_ra_type = ND_ROUTER_ADVERT;
203  rtadv->nd_ra_code = 0;
204  rtadv->nd_ra_cksum = 0;
205
206  rtadv->nd_ra_curhoplimit = 64;
207
208  /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
209  rtadv->nd_ra_flags_reserved =
210    zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference;
211  rtadv->nd_ra_flags_reserved <<= 3;
212
213  if (zif->rtadv.AdvManagedFlag)
214    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
215  if (zif->rtadv.AdvOtherConfigFlag)
216    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
217  if (zif->rtadv.AdvHomeAgentFlag)
218    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
219  /* Note that according to Neighbor Discovery (RFC 4861 [18]),
220   * AdvDefaultLifetime is by default based on the value of
221   * MaxRtrAdvInterval.  AdvDefaultLifetime is used in the Router Lifetime
222   * field of Router Advertisements.  Given that this field is expressed
223   * in seconds, a small MaxRtrAdvInterval value can result in a zero
224   * value for this field.  To prevent this, routers SHOULD keep
225   * AdvDefaultLifetime in at least one second, even if the use of
226   * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
227  pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ?
228    zif->rtadv.AdvDefaultLifetime :
229    MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
230  rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime);
231  rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
232  rtadv->nd_ra_retransmit = htonl (0);
233
234  len = sizeof (struct nd_router_advert);
235
236  /* If both the Home Agent Preference and Home Agent Lifetime are set to
237   * their default values specified above, this option SHOULD NOT be
238   * included in the Router Advertisement messages sent by this home
239   * agent. -- RFC6275, 7.4 */
240  if
241  (
242    zif->rtadv.AdvHomeAgentFlag &&
243    (zif->rtadv.HomeAgentPreference || zif->rtadv.HomeAgentLifetime != -1)
244  )
245    {
246      struct nd_opt_homeagent_info *ndopt_hai =
247	(struct nd_opt_homeagent_info *)(buf + len);
248      ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
249      ndopt_hai->nd_opt_hai_len = 1;
250      ndopt_hai->nd_opt_hai_reserved = 0;
251      ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference);
252      /* 16-bit unsigned integer.  The lifetime associated with the home
253       * agent in units of seconds.  The default value is the same as the
254       * Router Lifetime, as specified in the main body of the Router
255       * Advertisement.  The maximum value corresponds to 18.2 hours.  A
256       * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
257      ndopt_hai->nd_opt_hai_lifetime = htons
258      (
259        zif->rtadv.HomeAgentLifetime != -1 ?
260        zif->rtadv.HomeAgentLifetime :
261        MAX (1, pkt_RouterLifetime) /* 0 is OK for RL, but not for HAL*/
262      );
263      len += sizeof(struct nd_opt_homeagent_info);
264    }
265
266  if (zif->rtadv.AdvIntervalOption)
267    {
268      struct nd_opt_adv_interval *ndopt_adv =
269	(struct nd_opt_adv_interval *)(buf + len);
270      ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
271      ndopt_adv->nd_opt_ai_len = 1;
272      ndopt_adv->nd_opt_ai_reserved = 0;
273      ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval);
274      len += sizeof(struct nd_opt_adv_interval);
275    }
276
277  /* Fill in prefix. */
278  for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
279    {
280      struct nd_opt_prefix_info *pinfo;
281
282      pinfo = (struct nd_opt_prefix_info *) (buf + len);
283
284      pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
285      pinfo->nd_opt_pi_len = 4;
286      pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
287
288      pinfo->nd_opt_pi_flags_reserved = 0;
289      if (rprefix->AdvOnLinkFlag)
290	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
291      if (rprefix->AdvAutonomousFlag)
292	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
293      if (rprefix->AdvRouterAddressFlag)
294	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
295
296      pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
297      pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
298      pinfo->nd_opt_pi_reserved2 = 0;
299
300      IPV6_ADDR_COPY (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix);
301
302#ifdef DEBUG
303      {
304	u_char buf[INET6_ADDRSTRLEN];
305
306	zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix,
307	           buf, INET6_ADDRSTRLEN));
308
309      }
310#endif /* DEBUG */
311
312      len += sizeof (struct nd_opt_prefix_info);
313    }
314
315  /* Hardware address. */
316#ifdef HAVE_STRUCT_SOCKADDR_DL
317  sdl = &ifp->sdl;
318  if (sdl != NULL && sdl->sdl_alen != 0)
319    {
320      buf[len++] = ND_OPT_SOURCE_LINKADDR;
321
322      /* Option length should be rounded up to next octet if
323         the link address does not end on an octet boundary. */
324      buf[len++] = (sdl->sdl_alen + 9) >> 3;
325
326      memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
327      len += sdl->sdl_alen;
328
329      /* Pad option to end on an octet boundary. */
330      memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7);
331      len += -(sdl->sdl_alen + 2) & 0x7;
332    }
333#else
334  if (ifp->hw_addr_len != 0)
335    {
336      buf[len++] = ND_OPT_SOURCE_LINKADDR;
337
338      /* Option length should be rounded up to next octet if
339         the link address does not end on an octet boundary. */
340      buf[len++] = (ifp->hw_addr_len + 9) >> 3;
341
342      memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
343      len += ifp->hw_addr_len;
344
345      /* Pad option to end on an octet boundary. */
346      memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
347      len += -(ifp->hw_addr_len + 2) & 0x7;
348    }
349#endif /* HAVE_STRUCT_SOCKADDR_DL */
350
351  /* MTU */
352  if (zif->rtadv.AdvLinkMTU)
353    {
354      struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len);
355      opt->nd_opt_mtu_type = ND_OPT_MTU;
356      opt->nd_opt_mtu_len = 1;
357      opt->nd_opt_mtu_reserved = 0;
358      opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU);
359      len += sizeof (struct nd_opt_mtu);
360    }
361
362  msg.msg_name = (void *) &addr;
363  msg.msg_namelen = sizeof (struct sockaddr_in6);
364  msg.msg_iov = &iov;
365  msg.msg_iovlen = 1;
366  msg.msg_control = (void *) adata;
367  msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
368  msg.msg_flags = 0;
369  iov.iov_base = buf;
370  iov.iov_len = len;
371
372  cmsgptr = ZCMSG_FIRSTHDR(&msg);
373  cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
374  cmsgptr->cmsg_level = IPPROTO_IPV6;
375  cmsgptr->cmsg_type = IPV6_PKTINFO;
376
377  pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
378  memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
379  pkt->ipi6_ifindex = ifp->ifindex;
380
381  ret = sendmsg (sock, &msg, 0);
382  if (ret < 0)
383    {
384      zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
385		errno, safe_strerror(errno));
386    }
387}
388
389static int
390rtadv_timer (struct thread *thread)
391{
392  struct listnode *node, *nnode;
393  struct interface *ifp;
394  struct zebra_if *zif;
395  int period;
396
397  rtadv->ra_timer = NULL;
398  if (rtadv->adv_msec_if_count == 0)
399    {
400      period = 1000; /* 1 s */
401      rtadv_event (RTADV_TIMER, 1 /* 1 s */);
402    }
403  else
404    {
405      period = 10; /* 10 ms */
406      rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */);
407    }
408
409  for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
410    {
411      if (if_is_loopback (ifp) || ! if_is_operative (ifp))
412	continue;
413
414      zif = ifp->info;
415
416      if (zif->rtadv.AdvSendAdvertisements)
417	{
418	  zif->rtadv.AdvIntervalTimer -= period;
419	  if (zif->rtadv.AdvIntervalTimer <= 0)
420	    {
421	      /* FIXME: using MaxRtrAdvInterval each time isn't what section
422	         6.2.4 of RFC4861 tells to do. */
423	      zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
424	      rtadv_send_packet (rtadv->sock, ifp);
425	    }
426	}
427    }
428  return 0;
429}
430
431static void
432rtadv_process_solicit (struct interface *ifp)
433{
434  zlog_info ("Router solicitation received on %s", ifp->name);
435
436  rtadv_send_packet (rtadv->sock, ifp);
437}
438
439static void
440rtadv_process_advert (void)
441{
442  zlog_info ("Router advertisement received");
443}
444
445static void
446rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit)
447{
448  struct icmp6_hdr *icmph;
449  struct interface *ifp;
450  struct zebra_if *zif;
451
452  /* Interface search. */
453  ifp = if_lookup_by_index (ifindex);
454  if (ifp == NULL)
455    {
456      zlog_warn ("Unknown interface index: %d", ifindex);
457      return;
458    }
459
460  if (if_is_loopback (ifp))
461    return;
462
463  /* Check interface configuration. */
464  zif = ifp->info;
465  if (! zif->rtadv.AdvSendAdvertisements)
466    return;
467
468  /* ICMP message length check. */
469  if (len < sizeof (struct icmp6_hdr))
470    {
471      zlog_warn ("Invalid ICMPV6 packet length: %d", len);
472      return;
473    }
474
475  icmph = (struct icmp6_hdr *) buf;
476
477  /* ICMP message type check. */
478  if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
479      icmph->icmp6_type != ND_ROUTER_ADVERT)
480    {
481      zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
482      return;
483    }
484
485  /* Hoplimit check. */
486  if (hoplimit >= 0 && hoplimit != 255)
487    {
488      zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
489		 hoplimit);
490      return;
491    }
492
493  /* Check ICMP message type. */
494  if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
495    rtadv_process_solicit (ifp);
496  else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
497    rtadv_process_advert ();
498
499  return;
500}
501
502static int
503rtadv_read (struct thread *thread)
504{
505  int sock;
506  int len;
507  u_char buf[RTADV_MSG_SIZE];
508  struct sockaddr_in6 from;
509  unsigned int ifindex = 0;
510  int hoplimit = -1;
511
512  sock = THREAD_FD (thread);
513  rtadv->ra_read = NULL;
514
515  /* Register myself. */
516  rtadv_event (RTADV_READ, sock);
517
518  len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
519
520  if (len < 0)
521    {
522      zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno));
523      return len;
524    }
525
526  rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit);
527
528  return 0;
529}
530
531static int
532rtadv_make_socket (void)
533{
534  int sock;
535  int ret;
536  struct icmp6_filter filter;
537
538  if ( zserv_privs.change (ZPRIVS_RAISE) )
539       zlog_err ("rtadv_make_socket: could not raise privs, %s",
540                  safe_strerror (errno) );
541
542  sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
543
544  if ( zserv_privs.change (ZPRIVS_LOWER) )
545       zlog_err ("rtadv_make_socket: could not lower privs, %s",
546       			 safe_strerror (errno) );
547
548  /* When we can't make ICMPV6 socket simply back.  Router
549     advertisement feature will not be supported. */
550  if (sock < 0)
551    return -1;
552
553  ret = setsockopt_ipv6_pktinfo (sock, 1);
554  if (ret < 0)
555    return ret;
556  ret = setsockopt_ipv6_multicast_loop (sock, 0);
557  if (ret < 0)
558    return ret;
559  ret = setsockopt_ipv6_unicast_hops (sock, 255);
560  if (ret < 0)
561    return ret;
562  ret = setsockopt_ipv6_multicast_hops (sock, 255);
563  if (ret < 0)
564    return ret;
565  ret = setsockopt_ipv6_hoplimit (sock, 1);
566  if (ret < 0)
567    return ret;
568
569  ICMP6_FILTER_SETBLOCKALL(&filter);
570  ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
571  ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
572
573  ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
574		    sizeof (struct icmp6_filter));
575  if (ret < 0)
576    {
577      zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno));
578      return ret;
579    }
580
581  return sock;
582}
583
584static struct rtadv_prefix *
585rtadv_prefix_new (void)
586{
587  return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
588}
589
590static void
591rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
592{
593  XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
594}
595
596static struct rtadv_prefix *
597rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p)
598{
599  struct listnode *node;
600  struct rtadv_prefix *rprefix;
601
602  for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix))
603    if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p))
604      return rprefix;
605  return NULL;
606}
607
608static struct rtadv_prefix *
609rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *p)
610{
611  struct rtadv_prefix *rprefix;
612
613  rprefix = rtadv_prefix_lookup (rplist, p);
614  if (rprefix)
615    return rprefix;
616
617  rprefix = rtadv_prefix_new ();
618  memcpy (&rprefix->prefix, p, sizeof (struct prefix_ipv6));
619  listnode_add (rplist, rprefix);
620
621  return rprefix;
622}
623
624static void
625rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
626{
627  struct rtadv_prefix *rprefix;
628
629  rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
630
631  /* Set parameters. */
632  rprefix->AdvValidLifetime = rp->AdvValidLifetime;
633  rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
634  rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
635  rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
636  rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
637}
638
639static int
640rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
641{
642  struct rtadv_prefix *rprefix;
643
644  rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
645  if (rprefix != NULL)
646    {
647      listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
648      rtadv_prefix_free (rprefix);
649      return 1;
650    }
651  else
652    return 0;
653}
654
655DEFUN (ipv6_nd_suppress_ra,
656       ipv6_nd_suppress_ra_cmd,
657       "ipv6 nd suppress-ra",
658       "Interface IPv6 config commands\n"
659       "Neighbor discovery\n"
660       "Suppress Router Advertisement\n")
661{
662  struct interface *ifp;
663  struct zebra_if *zif;
664
665  ifp = vty->index;
666  zif = ifp->info;
667
668  if (if_is_loopback (ifp))
669    {
670      vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
671      return CMD_WARNING;
672    }
673
674  if (zif->rtadv.AdvSendAdvertisements)
675    {
676      zif->rtadv.AdvSendAdvertisements = 0;
677      zif->rtadv.AdvIntervalTimer = 0;
678      rtadv->adv_if_count--;
679
680      if_leave_all_router (rtadv->sock, ifp);
681
682      if (rtadv->adv_if_count == 0)
683	rtadv_event (RTADV_STOP, 0);
684    }
685
686  return CMD_SUCCESS;
687}
688
689DEFUN (no_ipv6_nd_suppress_ra,
690       no_ipv6_nd_suppress_ra_cmd,
691       "no ipv6 nd suppress-ra",
692       NO_STR
693       "Interface IPv6 config commands\n"
694       "Neighbor discovery\n"
695       "Suppress Router Advertisement\n")
696{
697  struct interface *ifp;
698  struct zebra_if *zif;
699
700  ifp = vty->index;
701  zif = ifp->info;
702
703  if (if_is_loopback (ifp))
704    {
705      vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
706      return CMD_WARNING;
707    }
708
709  if (! zif->rtadv.AdvSendAdvertisements)
710    {
711      zif->rtadv.AdvSendAdvertisements = 1;
712      zif->rtadv.AdvIntervalTimer = 0;
713      rtadv->adv_if_count++;
714
715      if_join_all_router (rtadv->sock, ifp);
716
717      if (rtadv->adv_if_count == 1)
718	rtadv_event (RTADV_START, rtadv->sock);
719    }
720
721  return CMD_SUCCESS;
722}
723
724DEFUN (ipv6_nd_ra_interval_msec,
725       ipv6_nd_ra_interval_msec_cmd,
726       "ipv6 nd ra-interval msec <70-1800000>",
727       "Interface IPv6 config commands\n"
728       "Neighbor discovery\n"
729       "Router Advertisement interval\n"
730       "Router Advertisement interval in milliseconds\n")
731{
732  unsigned interval;
733  struct interface *ifp = (struct interface *) vty->index;
734  struct zebra_if *zif = ifp->info;
735
736  VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000);
737  if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000))
738  {
739    vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
740    return CMD_WARNING;
741  }
742
743  if (zif->rtadv.MaxRtrAdvInterval % 1000)
744    rtadv->adv_msec_if_count--;
745
746  if (interval % 1000)
747    rtadv->adv_msec_if_count++;
748
749  zif->rtadv.MaxRtrAdvInterval = interval;
750  zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
751  zif->rtadv.AdvIntervalTimer = 0;
752
753  return CMD_SUCCESS;
754}
755
756DEFUN (ipv6_nd_ra_interval,
757       ipv6_nd_ra_interval_cmd,
758       "ipv6 nd ra-interval <1-1800>",
759       "Interface IPv6 config commands\n"
760       "Neighbor discovery\n"
761       "Router Advertisement interval\n"
762       "Router Advertisement interval in seconds\n")
763{
764  unsigned interval;
765  struct interface *ifp = (struct interface *) vty->index;
766  struct zebra_if *zif = ifp->info;
767
768  VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800);
769  if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime))
770  {
771    vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
772    return CMD_WARNING;
773  }
774
775  if (zif->rtadv.MaxRtrAdvInterval % 1000)
776    rtadv->adv_msec_if_count--;
777
778  /* convert to milliseconds */
779  interval = interval * 1000;
780
781  zif->rtadv.MaxRtrAdvInterval = interval;
782  zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
783  zif->rtadv.AdvIntervalTimer = 0;
784
785  return CMD_SUCCESS;
786}
787
788DEFUN (no_ipv6_nd_ra_interval,
789       no_ipv6_nd_ra_interval_cmd,
790       "no ipv6 nd ra-interval",
791       NO_STR
792       "Interface IPv6 config commands\n"
793       "Neighbor discovery\n"
794       "Router Advertisement interval\n")
795{
796  struct interface *ifp;
797  struct zebra_if *zif;
798
799  ifp = (struct interface *) vty->index;
800  zif = ifp->info;
801
802  if (zif->rtadv.MaxRtrAdvInterval % 1000)
803    rtadv->adv_msec_if_count--;
804
805  zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
806  zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
807  zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
808
809  return CMD_SUCCESS;
810}
811
812ALIAS (no_ipv6_nd_ra_interval,
813       no_ipv6_nd_ra_interval_val_cmd,
814       "no ipv6 nd ra-interval <1-1800>",
815       NO_STR
816       "Interface IPv6 config commands\n"
817       "Neighbor discovery\n"
818       "Router Advertisement interval\n")
819
820ALIAS (no_ipv6_nd_ra_interval,
821       no_ipv6_nd_ra_interval_msec_val_cmd,
822       "no ipv6 nd ra-interval msec <1-1800000>",
823       NO_STR
824       "Interface IPv6 config commands\n"
825       "Neighbor discovery\n"
826       "Router Advertisement interval\n"
827       "Router Advertisement interval in milliseconds\n")
828
829DEFUN (ipv6_nd_ra_lifetime,
830       ipv6_nd_ra_lifetime_cmd,
831       "ipv6 nd ra-lifetime <0-9000>",
832       "Interface IPv6 config commands\n"
833       "Neighbor discovery\n"
834       "Router lifetime\n"
835       "Router lifetime in seconds (0 stands for a non-default gw)\n")
836{
837  int lifetime;
838  struct interface *ifp;
839  struct zebra_if *zif;
840
841  ifp = (struct interface *) vty->index;
842  zif = ifp->info;
843
844  VTY_GET_INTEGER_RANGE ("router lifetime", lifetime, argv[0], 0, 9000);
845
846  /* The value to be placed in the Router Lifetime field
847   * of Router Advertisements sent from the interface,
848   * in seconds.  MUST be either zero or between
849   * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
850  if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval))
851    {
852      vty_out (vty, "This ra-lifetime would conflict with configured ra-interval%s", VTY_NEWLINE);
853      return CMD_WARNING;
854    }
855
856  zif->rtadv.AdvDefaultLifetime = lifetime;
857
858  return CMD_SUCCESS;
859}
860
861DEFUN (no_ipv6_nd_ra_lifetime,
862       no_ipv6_nd_ra_lifetime_cmd,
863       "no ipv6 nd ra-lifetime",
864       NO_STR
865       "Interface IPv6 config commands\n"
866       "Neighbor discovery\n"
867       "Router lifetime\n")
868{
869  struct interface *ifp;
870  struct zebra_if *zif;
871
872  ifp = (struct interface *) vty->index;
873  zif = ifp->info;
874
875  zif->rtadv.AdvDefaultLifetime = -1;
876
877  return CMD_SUCCESS;
878}
879
880ALIAS (no_ipv6_nd_ra_lifetime,
881       no_ipv6_nd_ra_lifetime_val_cmd,
882       "no ipv6 nd ra-lifetime <0-9000>",
883       NO_STR
884       "Interface IPv6 config commands\n"
885       "Neighbor discovery\n"
886       "Router lifetime\n"
887       "Router lifetime in seconds (0 stands for a non-default gw)\n")
888
889DEFUN (ipv6_nd_reachable_time,
890       ipv6_nd_reachable_time_cmd,
891       "ipv6 nd reachable-time <1-3600000>",
892       "Interface IPv6 config commands\n"
893       "Neighbor discovery\n"
894       "Reachable time\n"
895       "Reachable time in milliseconds\n")
896{
897  struct interface *ifp = (struct interface *) vty->index;
898  struct zebra_if *zif = ifp->info;
899  VTY_GET_INTEGER_RANGE ("reachable time", zif->rtadv.AdvReachableTime, argv[0], 1, RTADV_MAX_REACHABLE_TIME);
900  return CMD_SUCCESS;
901}
902
903DEFUN (no_ipv6_nd_reachable_time,
904       no_ipv6_nd_reachable_time_cmd,
905       "no ipv6 nd reachable-time",
906       NO_STR
907       "Interface IPv6 config commands\n"
908       "Neighbor discovery\n"
909       "Reachable time\n")
910{
911  struct interface *ifp;
912  struct zebra_if *zif;
913
914  ifp = (struct interface *) vty->index;
915  zif = ifp->info;
916
917  zif->rtadv.AdvReachableTime = 0;
918
919  return CMD_SUCCESS;
920}
921
922ALIAS (no_ipv6_nd_reachable_time,
923       no_ipv6_nd_reachable_time_val_cmd,
924       "no ipv6 nd reachable-time <1-3600000>",
925       NO_STR
926       "Interface IPv6 config commands\n"
927       "Neighbor discovery\n"
928       "Reachable time\n"
929       "Reachable time in milliseconds\n")
930
931DEFUN (ipv6_nd_homeagent_preference,
932       ipv6_nd_homeagent_preference_cmd,
933       "ipv6 nd home-agent-preference <0-65535>",
934       "Interface IPv6 config commands\n"
935       "Neighbor discovery\n"
936       "Home Agent preference\n"
937       "preference value (default is 0, least preferred)\n")
938{
939  struct interface *ifp = (struct interface *) vty->index;
940  struct zebra_if *zif = ifp->info;
941  VTY_GET_INTEGER_RANGE ("home agent preference", zif->rtadv.HomeAgentPreference, argv[0], 0, 65535);
942  return CMD_SUCCESS;
943}
944
945DEFUN (no_ipv6_nd_homeagent_preference,
946       no_ipv6_nd_homeagent_preference_cmd,
947       "no ipv6 nd home-agent-preference",
948       NO_STR
949       "Interface IPv6 config commands\n"
950       "Neighbor discovery\n"
951       "Home Agent preference\n")
952{
953  struct interface *ifp;
954  struct zebra_if *zif;
955
956  ifp = (struct interface *) vty->index;
957  zif = ifp->info;
958
959  zif->rtadv.HomeAgentPreference = 0;
960
961  return CMD_SUCCESS;
962}
963
964ALIAS (no_ipv6_nd_homeagent_preference,
965       no_ipv6_nd_homeagent_preference_val_cmd,
966       "no ipv6 nd home-agent-preference <0-65535>",
967       NO_STR
968       "Interface IPv6 config commands\n"
969       "Neighbor discovery\n"
970       "Home Agent preference\n"
971       "preference value (default is 0, least preferred)\n")
972
973DEFUN (ipv6_nd_homeagent_lifetime,
974       ipv6_nd_homeagent_lifetime_cmd,
975       "ipv6 nd home-agent-lifetime <0-65520>",
976       "Interface IPv6 config commands\n"
977       "Neighbor discovery\n"
978       "Home Agent lifetime\n"
979       "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
980{
981  struct interface *ifp = (struct interface *) vty->index;
982  struct zebra_if *zif = ifp->info;
983  VTY_GET_INTEGER_RANGE ("home agent lifetime", zif->rtadv.HomeAgentLifetime, argv[0], 0, RTADV_MAX_HALIFETIME);
984  return CMD_SUCCESS;
985}
986
987DEFUN (no_ipv6_nd_homeagent_lifetime,
988       no_ipv6_nd_homeagent_lifetime_cmd,
989       "no ipv6 nd home-agent-lifetime",
990       NO_STR
991       "Interface IPv6 config commands\n"
992       "Neighbor discovery\n"
993       "Home Agent lifetime\n")
994{
995  struct interface *ifp;
996  struct zebra_if *zif;
997
998  ifp = (struct interface *) vty->index;
999  zif = ifp->info;
1000
1001  zif->rtadv.HomeAgentLifetime = -1;
1002
1003  return CMD_SUCCESS;
1004}
1005
1006ALIAS (no_ipv6_nd_homeagent_lifetime,
1007       no_ipv6_nd_homeagent_lifetime_val_cmd,
1008       "no ipv6 nd home-agent-lifetime <0-65520>",
1009       NO_STR
1010       "Interface IPv6 config commands\n"
1011       "Neighbor discovery\n"
1012       "Home Agent lifetime\n"
1013       "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1014
1015DEFUN (ipv6_nd_managed_config_flag,
1016       ipv6_nd_managed_config_flag_cmd,
1017       "ipv6 nd managed-config-flag",
1018       "Interface IPv6 config commands\n"
1019       "Neighbor discovery\n"
1020       "Managed address configuration flag\n")
1021{
1022  struct interface *ifp;
1023  struct zebra_if *zif;
1024
1025  ifp = (struct interface *) vty->index;
1026  zif = ifp->info;
1027
1028  zif->rtadv.AdvManagedFlag = 1;
1029
1030  return CMD_SUCCESS;
1031}
1032
1033DEFUN (no_ipv6_nd_managed_config_flag,
1034       no_ipv6_nd_managed_config_flag_cmd,
1035       "no ipv6 nd managed-config-flag",
1036       NO_STR
1037       "Interface IPv6 config commands\n"
1038       "Neighbor discovery\n"
1039       "Managed address configuration flag\n")
1040{
1041  struct interface *ifp;
1042  struct zebra_if *zif;
1043
1044  ifp = (struct interface *) vty->index;
1045  zif = ifp->info;
1046
1047  zif->rtadv.AdvManagedFlag = 0;
1048
1049  return CMD_SUCCESS;
1050}
1051
1052DEFUN (ipv6_nd_homeagent_config_flag,
1053       ipv6_nd_homeagent_config_flag_cmd,
1054       "ipv6 nd home-agent-config-flag",
1055       "Interface IPv6 config commands\n"
1056       "Neighbor discovery\n"
1057       "Home Agent configuration flag\n")
1058{
1059  struct interface *ifp;
1060  struct zebra_if *zif;
1061
1062  ifp = (struct interface *) vty->index;
1063  zif = ifp->info;
1064
1065  zif->rtadv.AdvHomeAgentFlag = 1;
1066
1067  return CMD_SUCCESS;
1068}
1069
1070DEFUN (no_ipv6_nd_homeagent_config_flag,
1071       no_ipv6_nd_homeagent_config_flag_cmd,
1072       "no ipv6 nd home-agent-config-flag",
1073       NO_STR
1074       "Interface IPv6 config commands\n"
1075       "Neighbor discovery\n"
1076       "Home Agent configuration flag\n")
1077{
1078  struct interface *ifp;
1079  struct zebra_if *zif;
1080
1081  ifp = (struct interface *) vty->index;
1082  zif = ifp->info;
1083
1084  zif->rtadv.AdvHomeAgentFlag = 0;
1085
1086  return CMD_SUCCESS;
1087}
1088
1089DEFUN (ipv6_nd_adv_interval_config_option,
1090       ipv6_nd_adv_interval_config_option_cmd,
1091       "ipv6 nd adv-interval-option",
1092       "Interface IPv6 config commands\n"
1093       "Neighbor discovery\n"
1094       "Advertisement Interval Option\n")
1095{
1096  struct interface *ifp;
1097  struct zebra_if *zif;
1098
1099  ifp = (struct interface *) vty->index;
1100  zif = ifp->info;
1101
1102  zif->rtadv.AdvIntervalOption = 1;
1103
1104  return CMD_SUCCESS;
1105}
1106
1107DEFUN (no_ipv6_nd_adv_interval_config_option,
1108       no_ipv6_nd_adv_interval_config_option_cmd,
1109       "no ipv6 nd adv-interval-option",
1110       NO_STR
1111       "Interface IPv6 config commands\n"
1112       "Neighbor discovery\n"
1113       "Advertisement Interval Option\n")
1114{
1115  struct interface *ifp;
1116  struct zebra_if *zif;
1117
1118  ifp = (struct interface *) vty->index;
1119  zif = ifp->info;
1120
1121  zif->rtadv.AdvIntervalOption = 0;
1122
1123  return CMD_SUCCESS;
1124}
1125
1126DEFUN (ipv6_nd_other_config_flag,
1127       ipv6_nd_other_config_flag_cmd,
1128       "ipv6 nd other-config-flag",
1129       "Interface IPv6 config commands\n"
1130       "Neighbor discovery\n"
1131       "Other statefull configuration flag\n")
1132{
1133  struct interface *ifp;
1134  struct zebra_if *zif;
1135
1136  ifp = (struct interface *) vty->index;
1137  zif = ifp->info;
1138
1139  zif->rtadv.AdvOtherConfigFlag = 1;
1140
1141  return CMD_SUCCESS;
1142}
1143
1144DEFUN (no_ipv6_nd_other_config_flag,
1145       no_ipv6_nd_other_config_flag_cmd,
1146       "no ipv6 nd other-config-flag",
1147       NO_STR
1148       "Interface IPv6 config commands\n"
1149       "Neighbor discovery\n"
1150       "Other statefull configuration flag\n")
1151{
1152  struct interface *ifp;
1153  struct zebra_if *zif;
1154
1155  ifp = (struct interface *) vty->index;
1156  zif = ifp->info;
1157
1158  zif->rtadv.AdvOtherConfigFlag = 0;
1159
1160  return CMD_SUCCESS;
1161}
1162
1163DEFUN (ipv6_nd_prefix,
1164       ipv6_nd_prefix_cmd,
1165       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1166       "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)",
1167       "Interface IPv6 config commands\n"
1168       "Neighbor discovery\n"
1169       "Prefix information\n"
1170       "IPv6 prefix\n"
1171       "Valid lifetime in seconds\n"
1172       "Infinite valid lifetime\n"
1173       "Preferred lifetime in seconds\n"
1174       "Infinite preferred lifetime\n"
1175       "Do not use prefix for onlink determination\n"
1176       "Do not use prefix for autoconfiguration\n"
1177       "Set Router Address flag\n")
1178{
1179  int i;
1180  int ret;
1181  int cursor = 1;
1182  struct interface *ifp;
1183  struct zebra_if *zebra_if;
1184  struct rtadv_prefix rp;
1185
1186  ifp = (struct interface *) vty->index;
1187  zebra_if = ifp->info;
1188
1189  ret = str2prefix_ipv6 (argv[0], &rp.prefix);
1190  if (!ret)
1191    {
1192      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1193      return CMD_WARNING;
1194    }
1195  apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
1196  rp.AdvOnLinkFlag = 1;
1197  rp.AdvAutonomousFlag = 1;
1198  rp.AdvRouterAddressFlag = 0;
1199  rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1200  rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
1201
1202  if (argc > 1)
1203    {
1204      if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0)
1205	{
1206	  if ( strncmp (argv[1], "i", 1) == 0)
1207	    rp.AdvValidLifetime = UINT32_MAX;
1208	  else
1209	    rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
1210		(char **)NULL, 10);
1211
1212	  if ( strncmp (argv[2], "i", 1) == 0)
1213	    rp.AdvPreferredLifetime = UINT32_MAX;
1214	  else
1215	    rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
1216		(char **)NULL, 10);
1217
1218	  if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
1219	    {
1220	      vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
1221	      return CMD_WARNING;
1222	    }
1223	  cursor = cursor + 2;
1224	}
1225      if (argc > cursor)
1226	{
1227	  for (i = cursor; i < argc; i++)
1228	    {
1229	      if (strncmp (argv[i], "of", 2) == 0)
1230		rp.AdvOnLinkFlag = 0;
1231	      if (strncmp (argv[i], "no", 2) == 0)
1232		rp.AdvAutonomousFlag = 0;
1233	      if (strncmp (argv[i], "ro", 2) == 0)
1234		rp.AdvRouterAddressFlag = 1;
1235	    }
1236	}
1237    }
1238
1239  rtadv_prefix_set (zebra_if, &rp);
1240
1241  return CMD_SUCCESS;
1242}
1243
1244ALIAS (ipv6_nd_prefix,
1245       ipv6_nd_prefix_val_nortaddr_cmd,
1246       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1247       "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
1248       "Interface IPv6 config commands\n"
1249       "Neighbor discovery\n"
1250       "Prefix information\n"
1251       "IPv6 prefix\n"
1252       "Valid lifetime in seconds\n"
1253       "Infinite valid lifetime\n"
1254       "Preferred lifetime in seconds\n"
1255       "Infinite preferred lifetime\n"
1256       "Do not use prefix for onlink determination\n"
1257       "Do not use prefix for autoconfiguration\n")
1258
1259ALIAS (ipv6_nd_prefix,
1260       ipv6_nd_prefix_val_rev_cmd,
1261       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1262       "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
1263       "Interface IPv6 config commands\n"
1264       "Neighbor discovery\n"
1265       "Prefix information\n"
1266       "IPv6 prefix\n"
1267       "Valid lifetime in seconds\n"
1268       "Infinite valid lifetime\n"
1269       "Preferred lifetime in seconds\n"
1270       "Infinite preferred lifetime\n"
1271       "Do not use prefix for autoconfiguration\n"
1272       "Do not use prefix for onlink determination\n")
1273
1274ALIAS (ipv6_nd_prefix,
1275       ipv6_nd_prefix_val_rev_rtaddr_cmd,
1276       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1277       "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)",
1278       "Interface IPv6 config commands\n"
1279       "Neighbor discovery\n"
1280       "Prefix information\n"
1281       "IPv6 prefix\n"
1282       "Valid lifetime in seconds\n"
1283       "Infinite valid lifetime\n"
1284       "Preferred lifetime in seconds\n"
1285       "Infinite preferred lifetime\n"
1286       "Do not use prefix for autoconfiguration\n"
1287       "Do not use prefix for onlink determination\n"
1288       "Set Router Address flag\n")
1289
1290ALIAS (ipv6_nd_prefix,
1291       ipv6_nd_prefix_val_noauto_cmd,
1292       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1293       "(<0-4294967295>|infinite) (no-autoconfig|)",
1294       "Interface IPv6 config commands\n"
1295       "Neighbor discovery\n"
1296       "Prefix information\n"
1297       "IPv6 prefix\n"
1298       "Valid lifetime in seconds\n"
1299       "Infinite valid lifetime\n"
1300       "Preferred lifetime in seconds\n"
1301       "Infinite preferred lifetime\n"
1302       "Do not use prefix for autoconfiguration")
1303
1304ALIAS (ipv6_nd_prefix,
1305       ipv6_nd_prefix_val_offlink_cmd,
1306       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1307       "(<0-4294967295>|infinite) (off-link|)",
1308       "Interface IPv6 config commands\n"
1309       "Neighbor discovery\n"
1310       "Prefix information\n"
1311       "IPv6 prefix\n"
1312       "Valid lifetime in seconds\n"
1313       "Infinite valid lifetime\n"
1314       "Preferred lifetime in seconds\n"
1315       "Infinite preferred lifetime\n"
1316       "Do not use prefix for onlink determination\n")
1317
1318ALIAS (ipv6_nd_prefix,
1319       ipv6_nd_prefix_val_rtaddr_cmd,
1320       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1321       "(<0-4294967295>|infinite) (router-address|)",
1322       "Interface IPv6 config commands\n"
1323       "Neighbor discovery\n"
1324       "Prefix information\n"
1325       "IPv6 prefix\n"
1326       "Valid lifetime in seconds\n"
1327       "Infinite valid lifetime\n"
1328       "Preferred lifetime in seconds\n"
1329       "Infinite preferred lifetime\n"
1330       "Set Router Address flag\n")
1331
1332ALIAS (ipv6_nd_prefix,
1333       ipv6_nd_prefix_val_cmd,
1334       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1335       "(<0-4294967295>|infinite)",
1336       "Interface IPv6 config commands\n"
1337       "Neighbor discovery\n"
1338       "Prefix information\n"
1339       "IPv6 prefix\n"
1340       "Valid lifetime in seconds\n"
1341       "Infinite valid lifetime\n"
1342       "Preferred lifetime in seconds\n"
1343       "Infinite preferred lifetime\n")
1344
1345ALIAS (ipv6_nd_prefix,
1346       ipv6_nd_prefix_noval_cmd,
1347       "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
1348       "Interface IPv6 config commands\n"
1349       "Neighbor discovery\n"
1350       "Prefix information\n"
1351       "IPv6 prefix\n"
1352       "Do not use prefix for autoconfiguration\n"
1353       "Do not use prefix for onlink determination\n")
1354
1355ALIAS (ipv6_nd_prefix,
1356       ipv6_nd_prefix_noval_rev_cmd,
1357       "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
1358       "Interface IPv6 config commands\n"
1359       "Neighbor discovery\n"
1360       "Prefix information\n"
1361       "IPv6 prefix\n"
1362       "Do not use prefix for onlink determination\n"
1363       "Do not use prefix for autoconfiguration\n")
1364
1365ALIAS (ipv6_nd_prefix,
1366       ipv6_nd_prefix_noval_noauto_cmd,
1367       "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
1368       "Interface IPv6 config commands\n"
1369       "Neighbor discovery\n"
1370       "Prefix information\n"
1371       "IPv6 prefix\n"
1372       "Do not use prefix for autoconfiguration\n")
1373
1374ALIAS (ipv6_nd_prefix,
1375       ipv6_nd_prefix_noval_offlink_cmd,
1376       "ipv6 nd prefix X:X::X:X/M (off-link|)",
1377       "Interface IPv6 config commands\n"
1378       "Neighbor discovery\n"
1379       "Prefix information\n"
1380       "IPv6 prefix\n"
1381       "Do not use prefix for onlink determination\n")
1382
1383ALIAS (ipv6_nd_prefix,
1384       ipv6_nd_prefix_noval_rtaddr_cmd,
1385       "ipv6 nd prefix X:X::X:X/M (router-address|)",
1386       "Interface IPv6 config commands\n"
1387       "Neighbor discovery\n"
1388       "Prefix information\n"
1389       "IPv6 prefix\n"
1390       "Set Router Address flag\n")
1391
1392ALIAS (ipv6_nd_prefix,
1393       ipv6_nd_prefix_prefix_cmd,
1394       "ipv6 nd prefix X:X::X:X/M",
1395       "Interface IPv6 config commands\n"
1396       "Neighbor discovery\n"
1397       "Prefix information\n"
1398       "IPv6 prefix\n")
1399
1400DEFUN (no_ipv6_nd_prefix,
1401       no_ipv6_nd_prefix_cmd,
1402       "no ipv6 nd prefix IPV6PREFIX",
1403       NO_STR
1404       "Interface IPv6 config commands\n"
1405       "Neighbor discovery\n"
1406       "Prefix information\n"
1407       "IPv6 prefix\n")
1408{
1409  int ret;
1410  struct interface *ifp;
1411  struct zebra_if *zebra_if;
1412  struct rtadv_prefix rp;
1413
1414  ifp = (struct interface *) vty->index;
1415  zebra_if = ifp->info;
1416
1417  ret = str2prefix_ipv6 (argv[0], &rp.prefix);
1418  if (!ret)
1419    {
1420      vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1421      return CMD_WARNING;
1422    }
1423  apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
1424
1425  ret = rtadv_prefix_reset (zebra_if, &rp);
1426  if (!ret)
1427    {
1428      vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1429      return CMD_WARNING;
1430    }
1431
1432  return CMD_SUCCESS;
1433}
1434
1435DEFUN (ipv6_nd_router_preference,
1436       ipv6_nd_router_preference_cmd,
1437       "ipv6 nd router-preference (high|medium|low)",
1438       "Interface IPv6 config commands\n"
1439       "Neighbor discovery\n"
1440       "Default router preference\n"
1441       "High default router preference\n"
1442       "Low default router preference\n"
1443       "Medium default router preference (default)\n")
1444{
1445  struct interface *ifp;
1446  struct zebra_if *zif;
1447  int i = 0;
1448
1449  ifp = (struct interface *) vty->index;
1450  zif = ifp->info;
1451
1452  while (0 != rtadv_pref_strs[i])
1453    {
1454      if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0)
1455	{
1456	  zif->rtadv.DefaultPreference = i;
1457	  return CMD_SUCCESS;
1458	}
1459      i++;
1460    }
1461
1462  return CMD_ERR_NO_MATCH;
1463}
1464
1465DEFUN (no_ipv6_nd_router_preference,
1466       no_ipv6_nd_router_preference_cmd,
1467       "no ipv6 nd router-preference",
1468       NO_STR
1469       "Interface IPv6 config commands\n"
1470       "Neighbor discovery\n"
1471       "Default router preference\n")
1472{
1473  struct interface *ifp;
1474  struct zebra_if *zif;
1475
1476  ifp = (struct interface *) vty->index;
1477  zif = ifp->info;
1478
1479  zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */
1480
1481  return CMD_SUCCESS;
1482}
1483
1484ALIAS (no_ipv6_nd_router_preference,
1485       no_ipv6_nd_router_preference_val_cmd,
1486       "no ipv6 nd router-preference (high|medium|low)",
1487       NO_STR
1488       "Interface IPv6 config commands\n"
1489       "Neighbor discovery\n"
1490       "Default router preference\n"
1491       "High default router preference\n"
1492       "Low default router preference\n"
1493       "Medium default router preference (default)\n")
1494
1495DEFUN (ipv6_nd_mtu,
1496       ipv6_nd_mtu_cmd,
1497       "ipv6 nd mtu <1-65535>",
1498       "Interface IPv6 config commands\n"
1499       "Neighbor discovery\n"
1500       "Advertised MTU\n"
1501       "MTU in bytes\n")
1502{
1503  struct interface *ifp = (struct interface *) vty->index;
1504  struct zebra_if *zif = ifp->info;
1505  VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535);
1506  return CMD_SUCCESS;
1507}
1508
1509DEFUN (no_ipv6_nd_mtu,
1510       no_ipv6_nd_mtu_cmd,
1511       "no ipv6 nd mtu",
1512       NO_STR
1513       "Interface IPv6 config commands\n"
1514       "Neighbor discovery\n"
1515       "Advertised MTU\n")
1516{
1517  struct interface *ifp = (struct interface *) vty->index;
1518  struct zebra_if *zif = ifp->info;
1519  zif->rtadv.AdvLinkMTU = 0;
1520  return CMD_SUCCESS;
1521}
1522
1523ALIAS (no_ipv6_nd_mtu,
1524       no_ipv6_nd_mtu_val_cmd,
1525       "no ipv6 nd mtu <1-65535>",
1526       NO_STR
1527       "Interface IPv6 config commands\n"
1528       "Neighbor discovery\n"
1529       "Advertised MTU\n"
1530       "MTU in bytes\n")
1531
1532/* Write configuration about router advertisement. */
1533void
1534rtadv_config_write (struct vty *vty, struct interface *ifp)
1535{
1536  struct zebra_if *zif;
1537  struct listnode *node;
1538  struct rtadv_prefix *rprefix;
1539  u_char buf[INET6_ADDRSTRLEN];
1540  int interval;
1541
1542  if (! rtadv)
1543    return;
1544
1545  zif = ifp->info;
1546
1547  if (! if_is_loopback (ifp))
1548    {
1549      if (zif->rtadv.AdvSendAdvertisements)
1550	vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1551      else
1552	vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1553    }
1554
1555
1556  interval = zif->rtadv.MaxRtrAdvInterval;
1557  if (interval % 1000)
1558    vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval,
1559	     VTY_NEWLINE);
1560  else
1561    if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1562      vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
1563	     VTY_NEWLINE);
1564
1565  if (zif->rtadv.AdvIntervalOption)
1566    vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE);
1567
1568  if (zif->rtadv.AdvDefaultLifetime != -1)
1569    vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1570	     VTY_NEWLINE);
1571
1572  if (zif->rtadv.HomeAgentPreference)
1573    vty_out (vty, " ipv6 nd home-agent-preference %u%s",
1574	     zif->rtadv.HomeAgentPreference, VTY_NEWLINE);
1575
1576  if (zif->rtadv.HomeAgentLifetime != -1)
1577    vty_out (vty, " ipv6 nd home-agent-lifetime %u%s",
1578	     zif->rtadv.HomeAgentLifetime, VTY_NEWLINE);
1579
1580  if (zif->rtadv.AdvHomeAgentFlag)
1581    vty_out (vty, " ipv6 nd home-agent-config-flag%s", VTY_NEWLINE);
1582
1583  if (zif->rtadv.AdvReachableTime)
1584    vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1585	     VTY_NEWLINE);
1586
1587  if (zif->rtadv.AdvManagedFlag)
1588    vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1589
1590  if (zif->rtadv.AdvOtherConfigFlag)
1591    vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1592
1593  if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
1594    vty_out (vty, " ipv6 nd router-preference %s%s",
1595	     rtadv_pref_strs[zif->rtadv.DefaultPreference],
1596	     VTY_NEWLINE);
1597
1598  if (zif->rtadv.AdvLinkMTU)
1599    vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE);
1600
1601  for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
1602    {
1603      vty_out (vty, " ipv6 nd prefix %s/%d",
1604	       inet_ntop (AF_INET6, &rprefix->prefix.prefix,
1605			  (char *) buf, INET6_ADDRSTRLEN),
1606	       rprefix->prefix.prefixlen);
1607      if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1608	  (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1609	{
1610	  if (rprefix->AdvValidLifetime == UINT32_MAX)
1611	    vty_out (vty, " infinite");
1612	  else
1613	    vty_out (vty, " %u", rprefix->AdvValidLifetime);
1614	  if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1615	    vty_out (vty, " infinite");
1616	  else
1617	    vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1618	}
1619      if (!rprefix->AdvOnLinkFlag)
1620	vty_out (vty, " off-link");
1621      if (!rprefix->AdvAutonomousFlag)
1622	vty_out (vty, " no-autoconfig");
1623      if (rprefix->AdvRouterAddressFlag)
1624	vty_out (vty, " router-address");
1625      vty_out (vty, "%s", VTY_NEWLINE);
1626    }
1627}
1628
1629
1630static void
1631rtadv_event (enum rtadv_event event, int val)
1632{
1633  switch (event)
1634    {
1635    case RTADV_START:
1636      if (! rtadv->ra_read)
1637	rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
1638      if (! rtadv->ra_timer)
1639	rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
1640	                                    NULL, 0);
1641      break;
1642    case RTADV_STOP:
1643      if (rtadv->ra_timer)
1644	{
1645	  thread_cancel (rtadv->ra_timer);
1646	  rtadv->ra_timer = NULL;
1647	}
1648      if (rtadv->ra_read)
1649	{
1650	  thread_cancel (rtadv->ra_read);
1651	  rtadv->ra_read = NULL;
1652	}
1653      break;
1654    case RTADV_TIMER:
1655      if (! rtadv->ra_timer)
1656	rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
1657	                                    val);
1658      break;
1659    case RTADV_TIMER_MSEC:
1660      if (! rtadv->ra_timer)
1661	rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer,
1662					    NULL, val);
1663      break;
1664    case RTADV_READ:
1665      if (! rtadv->ra_read)
1666	rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
1667      break;
1668    default:
1669      break;
1670    }
1671  return;
1672}
1673
1674void
1675rtadv_init (void)
1676{
1677  int sock;
1678
1679  sock = rtadv_make_socket ();
1680  if (sock < 0)
1681    return;
1682
1683  rtadv = rtadv_new ();
1684  rtadv->sock = sock;
1685
1686  install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1687  install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
1688  install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1689  install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
1690  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1691  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd);
1692  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd);
1693  install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1694  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1695  install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd);
1696  install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1697  install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1698  install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd);
1699  install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1700  install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1701  install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1702  install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
1703  install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1704  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1705  install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1706  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
1707  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd);
1708  install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1709  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
1710  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd);
1711  install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
1712  install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
1713  install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
1714  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd);
1715  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd);
1716  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1717  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1718  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
1719  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd);
1720  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1721  install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1722  install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1723  install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1724  install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
1725  install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
1726  install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1727  install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
1728  install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
1729  install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
1730  install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd);
1731  install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd);
1732  install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
1733  install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd);
1734}
1735
1736static int
1737if_join_all_router (int sock, struct interface *ifp)
1738{
1739  int ret;
1740
1741  struct ipv6_mreq mreq;
1742
1743  memset (&mreq, 0, sizeof (struct ipv6_mreq));
1744  inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1745  mreq.ipv6mr_interface = ifp->ifindex;
1746
1747  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1748		    (char *) &mreq, sizeof mreq);
1749  if (ret < 0)
1750    zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno));
1751
1752  zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1753
1754  return 0;
1755}
1756
1757static int
1758if_leave_all_router (int sock, struct interface *ifp)
1759{
1760  int ret;
1761
1762  struct ipv6_mreq mreq;
1763
1764  memset (&mreq, 0, sizeof (struct ipv6_mreq));
1765  inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1766  mreq.ipv6mr_interface = ifp->ifindex;
1767
1768  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1769		    (char *) &mreq, sizeof mreq);
1770  if (ret < 0)
1771    zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno));
1772
1773  zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1774
1775  return 0;
1776}
1777
1778#else
1779void
1780rtadv_init (void)
1781{
1782  /* Empty.*/;
1783}
1784#endif /* RTADV && HAVE_IPV6 */
1785