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