blob: a09053d6e8d4c75cd8f43df1601216ae9fc43894 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Router advertisement
2 * Copyright (C) 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#include "memory.h"
25#include "sockopt.h"
26#include "thread.h"
27#include "if.h"
28#include "log.h"
29#include "prefix.h"
30#include "linklist.h"
31#include "command.h"
pauledd7c242003-06-04 13:59:38 +000032#include "privs.h"
paul718e3742002-12-13 20:15:29 +000033
34#include "zebra/interface.h"
35#include "zebra/rtadv.h"
36#include "zebra/debug.h"
paul537d8ea2003-08-27 06:45:32 +000037#include "zebra/rib.h"
gdt4b5e1352003-12-03 17:54:34 +000038#include "zebra/zserv.h"
paul718e3742002-12-13 20:15:29 +000039
pauledd7c242003-06-04 13:59:38 +000040extern struct zebra_privs_t zserv_privs;
41
paul718e3742002-12-13 20:15:29 +000042#if defined (HAVE_IPV6) && defined (RTADV)
43
hassofa2b17e2004-03-04 17:45:00 +000044#ifdef OPEN_BSD
45#include <netinet/icmp6.h>
46#endif
47
paul718e3742002-12-13 20:15:29 +000048/* If RFC2133 definition is used. */
49#ifndef IPV6_JOIN_GROUP
50#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
51#endif
52#ifndef IPV6_LEAVE_GROUP
53#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
54#endif
55
56#define ALLNODE "ff02::1"
57#define ALLROUTER "ff02::2"
58
paulb21b19c2003-06-15 01:28:29 +000059extern struct zebra_t zebrad;
60
paul718e3742002-12-13 20:15:29 +000061enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ};
62
63void rtadv_event (enum rtadv_event, int);
64
65int if_join_all_router (int, struct interface *);
66int if_leave_all_router (int, struct interface *);
67
68/* Structure which hold status of router advertisement. */
69struct rtadv
70{
71 int sock;
72
73 int adv_if_count;
74
75 struct thread *ra_read;
76 struct thread *ra_timer;
77};
78
79struct rtadv *rtadv = NULL;
80
81struct rtadv *
82rtadv_new ()
83{
84 struct rtadv *new;
85 new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
86 memset (new, 0, sizeof (struct rtadv));
87 return new;
88}
89
90void
91rtadv_free (struct rtadv *rtadv)
92{
93 XFREE (MTYPE_TMP, rtadv);
94}
95
96int
97rtadv_recv_packet (int sock, u_char *buf, int buflen,
98 struct sockaddr_in6 *from, unsigned int *ifindex,
99 int *hoplimit)
100{
101 int ret;
102 struct msghdr msg;
103 struct iovec iov;
104 struct cmsghdr *cmsgptr;
105 struct in6_addr dst;
106
107 char adata[1024];
108
109 /* Fill in message and iovec. */
110 msg.msg_name = (void *) from;
111 msg.msg_namelen = sizeof (struct sockaddr_in6);
112 msg.msg_iov = &iov;
113 msg.msg_iovlen = 1;
114 msg.msg_control = (void *) adata;
115 msg.msg_controllen = sizeof adata;
116 iov.iov_base = buf;
117 iov.iov_len = buflen;
118
119 /* If recvmsg fail return minus value. */
120 ret = recvmsg (sock, &msg, 0);
121 if (ret < 0)
122 return ret;
123
124 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
125 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
126 {
127 /* I want interface index which this packet comes from. */
128 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
129 cmsgptr->cmsg_type == IPV6_PKTINFO)
130 {
131 struct in6_pktinfo *ptr;
132
133 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
134 *ifindex = ptr->ipi6_ifindex;
135 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
136 }
137
138 /* Incoming packet's hop limit. */
139 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
140 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
141 *hoplimit = *((int *) CMSG_DATA (cmsgptr));
142 }
143 return ret;
144}
145
146#define RTADV_MSG_SIZE 4096
147
148/* Send router advertisement packet. */
149void
150rtadv_send_packet (int sock, struct interface *ifp)
151{
152 struct msghdr msg;
153 struct iovec iov;
154 struct cmsghdr *cmsgptr;
155 struct in6_pktinfo *pkt;
156 struct sockaddr_in6 addr;
pauledd7c242003-06-04 13:59:38 +0000157#ifdef HAVE_SOCKADDR_DL
paul718e3742002-12-13 20:15:29 +0000158 struct sockaddr_dl *sdl;
159#endif /* HAVE_SOCKADDR_DL */
160 char adata [sizeof (struct cmsghdr) + sizeof (struct in6_pktinfo)];
161 unsigned char buf[RTADV_MSG_SIZE];
162 struct nd_router_advert *rtadv;
163 int ret;
164 int len = 0;
165 struct zebra_if *zif;
166 u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
167 listnode node;
168
169 /* Logging of packet. */
170 if (IS_ZEBRA_DEBUG_PACKET)
171 zlog_info ("Router advertisement send to %s", ifp->name);
172
173 /* Fill in sockaddr_in6. */
174 memset (&addr, 0, sizeof (struct sockaddr_in6));
175 addr.sin6_family = AF_INET6;
176#ifdef SIN6_LEN
177 addr.sin6_len = sizeof (struct sockaddr_in6);
178#endif /* SIN6_LEN */
179 addr.sin6_port = htons (IPPROTO_ICMPV6);
180 memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
181
182 /* Fetch interface information. */
183 zif = ifp->info;
184
185 /* Make router advertisement message. */
186 rtadv = (struct nd_router_advert *) buf;
187
188 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
189 rtadv->nd_ra_code = 0;
190 rtadv->nd_ra_cksum = 0;
191
192 rtadv->nd_ra_curhoplimit = 64;
193 rtadv->nd_ra_flags_reserved = 0;
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 rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
199 rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
200 rtadv->nd_ra_retransmit = htonl (0);
201
202 len = sizeof (struct nd_router_advert);
203
204 /* Fill in prefix. */
205 for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node))
206 {
207 struct nd_opt_prefix_info *pinfo;
208 struct rtadv_prefix *rprefix;
209
210 rprefix = getdata (node);
211
212 pinfo = (struct nd_opt_prefix_info *) (buf + len);
213
214 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
215 pinfo->nd_opt_pi_len = 4;
216 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
217
218 pinfo->nd_opt_pi_flags_reserved = 0;
219 if (rprefix->AdvOnLinkFlag)
220 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
221 if (rprefix->AdvAutonomousFlag)
222 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
223
224 pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
225 pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
226 pinfo->nd_opt_pi_reserved2 = 0;
227
228 memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
229 sizeof (struct in6_addr));
230
231#ifdef DEBUG
232 {
233 u_char buf[INET6_ADDRSTRLEN];
234
hasso3e31cde2004-05-18 11:58:59 +0000235 zlog_info ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix,
236 buf, INET6_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +0000237
238 }
239#endif /* DEBUG */
240
241 len += sizeof (struct nd_opt_prefix_info);
242 }
243
244 /* Hardware address. */
245#ifdef HAVE_SOCKADDR_DL
246 sdl = &ifp->sdl;
247 if (sdl != NULL && sdl->sdl_alen != 0)
248 {
249 buf[len++] = ND_OPT_SOURCE_LINKADDR;
250 buf[len++] = (sdl->sdl_alen + 2) >> 3;
251
252 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
253 len += sdl->sdl_alen;
254 }
255#else
256 if (ifp->hw_addr_len != 0)
257 {
258 buf[len++] = ND_OPT_SOURCE_LINKADDR;
259 buf[len++] = (ifp->hw_addr_len + 2) >> 3;
260
261 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
262 len += ifp->hw_addr_len;
263 }
264#endif /* HAVE_SOCKADDR_DL */
265
266 msg.msg_name = (void *) &addr;
267 msg.msg_namelen = sizeof (struct sockaddr_in6);
268 msg.msg_iov = &iov;
269 msg.msg_iovlen = 1;
270 msg.msg_control = (void *) adata;
271 msg.msg_controllen = sizeof adata;
272 iov.iov_base = buf;
273 iov.iov_len = len;
274
275 cmsgptr = (struct cmsghdr *)adata;
276 cmsgptr->cmsg_len = sizeof adata;
277 cmsgptr->cmsg_level = IPPROTO_IPV6;
278 cmsgptr->cmsg_type = IPV6_PKTINFO;
279 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
280 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
281 pkt->ipi6_ifindex = ifp->ifindex;
282
283 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000284 if (ret < 0)
285 {
286 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
287 errno, strerror(errno));
288 }
paul718e3742002-12-13 20:15:29 +0000289}
290
291int
292rtadv_timer (struct thread *thread)
293{
294 listnode node;
295 struct interface *ifp;
296 struct zebra_if *zif;
297
298 rtadv->ra_timer = NULL;
299 rtadv_event (RTADV_TIMER, 1);
300
301 for (node = listhead (iflist); node; nextnode (node))
302 {
303 ifp = getdata (node);
304
305 if (if_is_loopback (ifp))
306 continue;
307
308 zif = ifp->info;
309
310 if (zif->rtadv.AdvSendAdvertisements)
311 if (--zif->rtadv.AdvIntervalTimer <= 0)
312 {
313 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
314 rtadv_send_packet (rtadv->sock, ifp);
315 }
316 }
317 return 0;
318}
319
320void
321rtadv_process_solicit (struct interface *ifp)
322{
323 zlog_info ("Router solicitation received on %s", ifp->name);
324
325 rtadv_send_packet (rtadv->sock, ifp);
326}
327
328void
329rtadv_process_advert ()
330{
331 zlog_info ("Router advertisement received");
332}
333
334void
335rtadv_process_packet (u_char *buf, int len, unsigned int ifindex, int hoplimit)
336{
337 struct icmp6_hdr *icmph;
338 struct interface *ifp;
339 struct zebra_if *zif;
340
341 /* Interface search. */
342 ifp = if_lookup_by_index (ifindex);
343 if (ifp == NULL)
344 {
345 zlog_warn ("Unknown interface index: %d", ifindex);
346 return;
347 }
348
349 if (if_is_loopback (ifp))
350 return;
351
352 /* Check interface configuration. */
353 zif = ifp->info;
354 if (! zif->rtadv.AdvSendAdvertisements)
355 return;
356
357 /* ICMP message length check. */
358 if (len < sizeof (struct icmp6_hdr))
359 {
360 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
361 return;
362 }
363
364 icmph = (struct icmp6_hdr *) buf;
365
366 /* ICMP message type check. */
367 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
368 icmph->icmp6_type != ND_ROUTER_ADVERT)
369 {
370 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
371 return;
372 }
373
374 /* Hoplimit check. */
375 if (hoplimit >= 0 && hoplimit != 255)
376 {
377 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
378 hoplimit);
379 return;
380 }
381
382 /* Check ICMP message type. */
383 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
384 rtadv_process_solicit (ifp);
385 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
386 rtadv_process_advert ();
387
388 return;
389}
390
391int
392rtadv_read (struct thread *thread)
393{
394 int sock;
395 int len;
396 u_char buf[RTADV_MSG_SIZE];
397 struct sockaddr_in6 from;
398 unsigned int ifindex;
399 int hoplimit = -1;
400
401 sock = THREAD_FD (thread);
402 rtadv->ra_read = NULL;
403
404 /* Register myself. */
405 rtadv_event (RTADV_READ, sock);
406
407 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
408
409 if (len < 0)
410 {
411 zlog_warn ("router solicitation recv failed: %s.", strerror (errno));
412 return len;
413 }
414
415 rtadv_process_packet (buf, len, ifindex, hoplimit);
416
417 return 0;
418}
419
420int
421rtadv_make_socket (void)
422{
423 int sock;
424 int ret;
425 struct icmp6_filter filter;
426
pauledd7c242003-06-04 13:59:38 +0000427 if ( zserv_privs.change (ZPRIVS_RAISE) )
428 zlog_err ("rtadv_make_socket: could not raise privs, %s",
429 strerror (errno) );
430
paul718e3742002-12-13 20:15:29 +0000431 sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
432
pauledd7c242003-06-04 13:59:38 +0000433 if ( zserv_privs.change (ZPRIVS_LOWER) )
434 zlog_err ("rtadv_make_socket: could not lower privs, %s",
435 strerror (errno) );
436
paul718e3742002-12-13 20:15:29 +0000437 /* When we can't make ICMPV6 socket simply back. Router
438 advertisement feature will not be supported. */
439 if (sock < 0)
440 return -1;
441
442 ret = setsockopt_ipv6_pktinfo (sock, 1);
443 if (ret < 0)
444 return ret;
paul718e3742002-12-13 20:15:29 +0000445 ret = setsockopt_ipv6_multicast_loop (sock, 0);
446 if (ret < 0)
447 return ret;
448 ret = setsockopt_ipv6_unicast_hops (sock, 255);
449 if (ret < 0)
450 return ret;
451 ret = setsockopt_ipv6_multicast_hops (sock, 255);
452 if (ret < 0)
453 return ret;
454 ret = setsockopt_ipv6_hoplimit (sock, 1);
455 if (ret < 0)
456 return ret;
457
458 ICMP6_FILTER_SETBLOCKALL(&filter);
459 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
460 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
461
462 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
463 sizeof (struct icmp6_filter));
464 if (ret < 0)
465 {
466 zlog_info ("ICMP6_FILTER set fail: %s", strerror (errno));
467 return ret;
468 }
469
470 return sock;
471}
472
473struct rtadv_prefix *
474rtadv_prefix_new ()
475{
476 struct rtadv_prefix *new;
477
478 new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
479 memset (new, 0, sizeof (struct rtadv_prefix));
480
481 return new;
482}
483
484void
485rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
486{
487 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
488}
489
490struct rtadv_prefix *
491rtadv_prefix_lookup (list rplist, struct prefix *p)
492{
493 listnode node;
494 struct rtadv_prefix *rprefix;
495
496 for (node = listhead (rplist); node; node = nextnode (node))
497 {
498 rprefix = getdata (node);
499 if (prefix_same (&rprefix->prefix, p))
500 return rprefix;
501 }
502 return NULL;
503}
504
505struct rtadv_prefix *
506rtadv_prefix_get (list rplist, struct prefix *p)
507{
508 struct rtadv_prefix *rprefix;
509
510 rprefix = rtadv_prefix_lookup (rplist, p);
511 if (rprefix)
512 return rprefix;
513
514 rprefix = rtadv_prefix_new ();
515 memcpy (&rprefix->prefix, p, sizeof (struct prefix));
516 listnode_add (rplist, rprefix);
517
518 return rprefix;
519}
520
521void
522rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
523{
524 struct rtadv_prefix *rprefix;
525
526 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
527
528 /* Set parameters. */
529 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
530 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
531 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
532 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
533}
534
535int
536rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
537{
538 struct rtadv_prefix *rprefix;
539
540 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
541 if (rprefix != NULL)
542 {
543 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
544 rtadv_prefix_free (rprefix);
545 return 1;
546 }
547 else
548 return 0;
549}
550
551DEFUN (ipv6_nd_suppress_ra,
552 ipv6_nd_suppress_ra_cmd,
553 "ipv6 nd suppress-ra",
hasso3e31cde2004-05-18 11:58:59 +0000554 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000555 "Neighbor discovery\n"
556 "Suppress Router Advertisement\n")
557{
558 struct interface *ifp;
559 struct zebra_if *zif;
560
561 ifp = vty->index;
562 zif = ifp->info;
563
564 if (if_is_loopback (ifp))
565 {
566 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
567 return CMD_WARNING;
568 }
569
570 if (zif->rtadv.AdvSendAdvertisements)
571 {
572 zif->rtadv.AdvSendAdvertisements = 0;
573 zif->rtadv.AdvIntervalTimer = 0;
574 rtadv->adv_if_count--;
575
576 if_leave_all_router (rtadv->sock, ifp);
577
578 if (rtadv->adv_if_count == 0)
579 rtadv_event (RTADV_STOP, 0);
580 }
581
582 return CMD_SUCCESS;
583}
584
paul718e3742002-12-13 20:15:29 +0000585DEFUN (no_ipv6_nd_suppress_ra,
586 no_ipv6_nd_suppress_ra_cmd,
587 "no ipv6 nd suppress-ra",
588 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000589 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000590 "Neighbor discovery\n"
591 "Suppress Router Advertisement\n")
592{
593 struct interface *ifp;
594 struct zebra_if *zif;
595
596 ifp = vty->index;
597 zif = ifp->info;
598
599 if (if_is_loopback (ifp))
600 {
601 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
602 return CMD_WARNING;
603 }
604
605 if (! zif->rtadv.AdvSendAdvertisements)
606 {
607 zif->rtadv.AdvSendAdvertisements = 1;
608 zif->rtadv.AdvIntervalTimer = 0;
609 rtadv->adv_if_count++;
610
611 if_join_all_router (rtadv->sock, ifp);
612
613 if (rtadv->adv_if_count == 1)
614 rtadv_event (RTADV_START, rtadv->sock);
615 }
616
617 return CMD_SUCCESS;
618}
619
paul718e3742002-12-13 20:15:29 +0000620DEFUN (ipv6_nd_ra_interval,
621 ipv6_nd_ra_interval_cmd,
622 "ipv6 nd ra-interval SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000623 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000624 "Neighbor discovery\n"
625 "Router Advertisement interval\n"
626 "Router Advertisement interval in seconds\n")
627{
628 int interval;
629 struct interface *ifp;
630 struct zebra_if *zif;
631
632 ifp = (struct interface *) vty->index;
633 zif = ifp->info;
634
635 interval = atoi (argv[0]);
636
637 if (interval < 0)
638 {
639 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
640 return CMD_WARNING;
641 }
642
643 zif->rtadv.MaxRtrAdvInterval = interval;
644 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
645 zif->rtadv.AdvIntervalTimer = 0;
646
647 return CMD_SUCCESS;
648}
649
650DEFUN (no_ipv6_nd_ra_interval,
651 no_ipv6_nd_ra_interval_cmd,
652 "no ipv6 nd ra-interval",
653 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000654 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000655 "Neighbor discovery\n"
656 "Router Advertisement interval\n")
657{
658 struct interface *ifp;
659 struct zebra_if *zif;
660
661 ifp = (struct interface *) vty->index;
662 zif = ifp->info;
663
664 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
665 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
666 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
667
668 return CMD_SUCCESS;
669}
670
671DEFUN (ipv6_nd_ra_lifetime,
672 ipv6_nd_ra_lifetime_cmd,
673 "ipv6 nd ra-lifetime SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000674 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000675 "Neighbor discovery\n"
676 "Router lifetime\n"
677 "Router lifetime in seconds\n")
678{
679 int lifetime;
680 struct interface *ifp;
681 struct zebra_if *zif;
682
683 ifp = (struct interface *) vty->index;
684 zif = ifp->info;
685
686 lifetime = atoi (argv[0]);
687
688 if (lifetime < 0 || lifetime > 0xffff)
689 {
690 vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
691 return CMD_WARNING;
692 }
693
694 zif->rtadv.AdvDefaultLifetime = lifetime;
695
696 return CMD_SUCCESS;
697}
698
699DEFUN (no_ipv6_nd_ra_lifetime,
700 no_ipv6_nd_ra_lifetime_cmd,
701 "no ipv6 nd ra-lifetime",
702 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000703 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000704 "Neighbor discovery\n"
705 "Router lifetime\n")
706{
707 struct interface *ifp;
708 struct zebra_if *zif;
709
710 ifp = (struct interface *) vty->index;
711 zif = ifp->info;
712
713 zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
714
715 return CMD_SUCCESS;
716}
717
718DEFUN (ipv6_nd_reachable_time,
719 ipv6_nd_reachable_time_cmd,
720 "ipv6 nd reachable-time MILLISECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000721 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000722 "Neighbor discovery\n"
723 "Reachable time\n"
724 "Reachable time in milliseconds\n")
725{
726 u_int32_t rtime;
727 struct interface *ifp;
728 struct zebra_if *zif;
729
730 ifp = (struct interface *) vty->index;
731 zif = ifp->info;
732
733 rtime = (u_int32_t) atol (argv[0]);
734
735 if (rtime > RTADV_MAX_REACHABLE_TIME)
736 {
737 vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
738 return CMD_WARNING;
739 }
740
741 zif->rtadv.AdvReachableTime = rtime;
742
743 return CMD_SUCCESS;
744}
745
746DEFUN (no_ipv6_nd_reachable_time,
747 no_ipv6_nd_reachable_time_cmd,
748 "no ipv6 nd reachable-time",
749 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000750 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000751 "Neighbor discovery\n"
752 "Reachable time\n")
753{
754 struct interface *ifp;
755 struct zebra_if *zif;
756
757 ifp = (struct interface *) vty->index;
758 zif = ifp->info;
759
760 zif->rtadv.AdvReachableTime = 0;
761
762 return CMD_SUCCESS;
763}
764
765DEFUN (ipv6_nd_managed_config_flag,
766 ipv6_nd_managed_config_flag_cmd,
767 "ipv6 nd managed-config-flag",
hasso3e31cde2004-05-18 11:58:59 +0000768 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000769 "Neighbor discovery\n"
770 "Managed address configuration flag\n")
771{
772 struct interface *ifp;
773 struct zebra_if *zif;
774
775 ifp = (struct interface *) vty->index;
776 zif = ifp->info;
777
778 zif->rtadv.AdvManagedFlag = 1;
779
780 return CMD_SUCCESS;
781}
782
783DEFUN (no_ipv6_nd_managed_config_flag,
784 no_ipv6_nd_managed_config_flag_cmd,
785 "no ipv6 nd managed-config-flag",
786 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000787 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000788 "Neighbor discovery\n"
789 "Managed address configuration flag\n")
790{
791 struct interface *ifp;
792 struct zebra_if *zif;
793
794 ifp = (struct interface *) vty->index;
795 zif = ifp->info;
796
797 zif->rtadv.AdvManagedFlag = 0;
798
799 return CMD_SUCCESS;
800}
801
802DEFUN (ipv6_nd_other_config_flag,
803 ipv6_nd_other_config_flag_cmd,
804 "ipv6 nd other-config-flag",
hasso3e31cde2004-05-18 11:58:59 +0000805 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000806 "Neighbor discovery\n"
807 "Other statefull configuration flag\n")
808{
809 struct interface *ifp;
810 struct zebra_if *zif;
811
812 ifp = (struct interface *) vty->index;
813 zif = ifp->info;
814
815 zif->rtadv.AdvOtherConfigFlag = 1;
816
817 return CMD_SUCCESS;
818}
819
820DEFUN (no_ipv6_nd_other_config_flag,
821 no_ipv6_nd_other_config_flag_cmd,
822 "no ipv6 nd other-config-flag",
823 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000824 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000825 "Neighbor discovery\n"
826 "Other statefull configuration flag\n")
827{
828 struct interface *ifp;
829 struct zebra_if *zif;
830
831 ifp = (struct interface *) vty->index;
832 zif = ifp->info;
833
834 zif->rtadv.AdvOtherConfigFlag = 0;
835
836 return CMD_SUCCESS;
837}
838
hasso3e31cde2004-05-18 11:58:59 +0000839DEFUN (ipv6_nd_prefix,
840 ipv6_nd_prefix_cmd,
841 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
842 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
843 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000844 "Neighbor discovery\n"
845 "Prefix information\n"
846 "IPv6 prefix\n"
847 "Valid lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +0000848 "Infinite valid lifetime\n"
paul718e3742002-12-13 20:15:29 +0000849 "Preferred lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +0000850 "Infinite preferred lifetime\n"
851 "Do not use prefix for onlink determination\n"
852 "Do not use prefix for autoconfiguration\n")
paul718e3742002-12-13 20:15:29 +0000853{
854 int i;
855 int ret;
hasso3e31cde2004-05-18 11:58:59 +0000856 int cursor = 1;
paul718e3742002-12-13 20:15:29 +0000857 struct interface *ifp;
858 struct zebra_if *zebra_if;
859 struct rtadv_prefix rp;
860
861 ifp = (struct interface *) vty->index;
862 zebra_if = ifp->info;
863
864 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
865 if (!ret)
866 {
867 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
868 return CMD_WARNING;
869 }
hasso3e31cde2004-05-18 11:58:59 +0000870 rp.AdvOnLinkFlag = 1;
871 rp.AdvAutonomousFlag = 1;
872 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
873 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
paul718e3742002-12-13 20:15:29 +0000874
hasso3e31cde2004-05-18 11:58:59 +0000875 if (argc > 1)
paul718e3742002-12-13 20:15:29 +0000876 {
hasso3e31cde2004-05-18 11:58:59 +0000877 if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0)
paul718e3742002-12-13 20:15:29 +0000878 {
hasso3e31cde2004-05-18 11:58:59 +0000879 if ( strncmp (argv[1], "i", 1) == 0)
880 rp.AdvValidLifetime = UINT32_MAX;
881 else
882 rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
883 (char **)NULL, 10);
884
885 if ( strncmp (argv[2], "i", 1) == 0)
886 rp.AdvPreferredLifetime = UINT32_MAX;
887 else
888 rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
889 (char **)NULL, 10);
890
891 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
892 {
893 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
894 return CMD_WARNING;
895 }
896 cursor = cursor + 2;
paul718e3742002-12-13 20:15:29 +0000897 }
hasso3e31cde2004-05-18 11:58:59 +0000898 if (argc > cursor)
paul718e3742002-12-13 20:15:29 +0000899 {
hasso3e31cde2004-05-18 11:58:59 +0000900 for (i = cursor; i < argc; i++)
901 {
902 if (strncmp (argv[i], "of", 2) == 0)
903 rp.AdvOnLinkFlag = 0;
904 if (strncmp (argv[i], "no", 2) == 0)
905 rp.AdvAutonomousFlag = 0;
906 }
paul718e3742002-12-13 20:15:29 +0000907 }
908 }
909
910 rtadv_prefix_set (zebra_if, &rp);
911
912 return CMD_SUCCESS;
913}
914
hasso3e31cde2004-05-18 11:58:59 +0000915ALIAS (ipv6_nd_prefix,
916 ipv6_nd_prefix_val_rev_cmd,
917 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
918 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
919 "Interface IPv6 config commands\n"
920 "Neighbor discovery\n"
921 "Prefix information\n"
922 "IPv6 prefix\n"
923 "Valid lifetime in seconds\n"
924 "Infinite valid lifetime\n"
925 "Preferred lifetime in seconds\n"
926 "Infinite preferred lifetime\n"
927 "Do not use prefix for autoconfiguration\n"
928 "Do not use prefix for onlink determination\n")
929
930ALIAS (ipv6_nd_prefix,
931 ipv6_nd_prefix_val_noauto_cmd,
932 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
933 "(<0-4294967295>|infinite) (no-autoconfig|)",
934 "Interface IPv6 config commands\n"
935 "Neighbor discovery\n"
936 "Prefix information\n"
937 "IPv6 prefix\n"
938 "Valid lifetime in seconds\n"
939 "Infinite valid lifetime\n"
940 "Preferred lifetime in seconds\n"
941 "Infinite preferred lifetime\n"
942 "Do not use prefix for autoconfigurationn")
943
944ALIAS (ipv6_nd_prefix,
945 ipv6_nd_prefix_val_offlink_cmd,
946 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
947 "(<0-4294967295>|infinite) (off-link|)",
948 "Interface IPv6 config commands\n"
949 "Neighbor discovery\n"
950 "Prefix information\n"
951 "IPv6 prefix\n"
952 "Valid lifetime in seconds\n"
953 "Infinite valid lifetime\n"
954 "Preferred lifetime in seconds\n"
955 "Infinite preferred lifetime\n"
956 "Do not use prefix for onlink determination\n")
957
958ALIAS (ipv6_nd_prefix,
959 ipv6_nd_prefix_val_cmd,
960 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
961 "(<0-4294967295>|infinite)",
962 "Interface IPv6 config commands\n"
963 "Neighbor discovery\n"
964 "Prefix information\n"
965 "IPv6 prefix\n"
966 "Valid lifetime in seconds\n"
967 "Infinite valid lifetime\n"
968 "Preferred lifetime in seconds\n"
969 "Infinite preferred lifetime\n")
970
971ALIAS (ipv6_nd_prefix,
972 ipv6_nd_prefix_noval_cmd,
973 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
974 "Interface IPv6 config commands\n"
975 "Neighbor discovery\n"
976 "Prefix information\n"
977 "IPv6 prefix\n"
978 "Do not use prefix for autoconfiguration\n"
979 "Do not use prefix for onlink determination\n")
980
981ALIAS (ipv6_nd_prefix,
982 ipv6_nd_prefix_noval_rev_cmd,
983 "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
984 "Interface IPv6 config commands\n"
985 "Neighbor discovery\n"
986 "Prefix information\n"
987 "IPv6 prefix\n"
988 "Do not use prefix for onlink determination\n"
989 "Do not use prefix for autoconfiguration\n")
990
991ALIAS (ipv6_nd_prefix,
992 ipv6_nd_prefix_noval_noauto_cmd,
993 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
994 "Interface IPv6 config commands\n"
995 "Neighbor discovery\n"
996 "Prefix information\n"
997 "IPv6 prefix\n"
998 "Do not use prefix for autoconfiguration\n")
999
1000ALIAS (ipv6_nd_prefix,
1001 ipv6_nd_prefix_noval_offlink_cmd,
1002 "ipv6 nd prefix X:X::X:X/M (off-link|)",
1003 "Interface IPv6 config commands\n"
1004 "Neighbor discovery\n"
1005 "Prefix information\n"
1006 "IPv6 prefix\n"
1007 "Do not use prefix for onlink determination\n")
1008
1009ALIAS (ipv6_nd_prefix,
1010 ipv6_nd_prefix_prefix_cmd,
1011 "ipv6 nd prefix X:X::X:X/M",
1012 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001013 "Neighbor discovery\n"
1014 "Prefix information\n"
1015 "IPv6 prefix\n")
1016
hasso3e31cde2004-05-18 11:58:59 +00001017DEFUN (no_ipv6_nd_prefix,
1018 no_ipv6_nd_prefix_cmd,
1019 "no ipv6 nd prefix IPV6PREFIX",
paul718e3742002-12-13 20:15:29 +00001020 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001021 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001022 "Neighbor discovery\n"
1023 "Prefix information\n"
1024 "IPv6 prefix\n")
1025{
1026 int ret;
1027 struct interface *ifp;
1028 struct zebra_if *zebra_if;
1029 struct rtadv_prefix rp;
1030
1031 ifp = (struct interface *) vty->index;
1032 zebra_if = ifp->info;
1033
1034 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
1035 if (!ret)
1036 {
1037 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1038 return CMD_WARNING;
1039 }
1040
1041 ret = rtadv_prefix_reset (zebra_if, &rp);
1042 if (!ret)
1043 {
1044 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1045 return CMD_WARNING;
1046 }
1047
1048 return CMD_SUCCESS;
1049}
1050
1051/* Write configuration about router advertisement. */
1052void
1053rtadv_config_write (struct vty *vty, struct interface *ifp)
1054{
1055 struct zebra_if *zif;
1056 listnode node;
1057 struct rtadv_prefix *rprefix;
1058 u_char buf[INET6_ADDRSTRLEN];
1059
1060 if (! rtadv)
1061 return;
1062
1063 zif = ifp->info;
1064
1065 if (! if_is_loopback (ifp))
1066 {
1067 if (zif->rtadv.AdvSendAdvertisements)
1068 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1069 else
1070 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1071 }
1072
1073 if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL)
1074 vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval,
1075 VTY_NEWLINE);
1076
1077 if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
1078 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1079 VTY_NEWLINE);
1080
1081 if (zif->rtadv.AdvReachableTime)
1082 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1083 VTY_NEWLINE);
1084
1085 if (zif->rtadv.AdvManagedFlag)
1086 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1087
1088 if (zif->rtadv.AdvOtherConfigFlag)
1089 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1090
1091 for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node))
1092 {
1093 rprefix = getdata (node);
hasso3e31cde2004-05-18 11:58:59 +00001094 vty_out (vty, " ipv6 nd prefix %s/%d",
paul718e3742002-12-13 20:15:29 +00001095 inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6,
1096 buf, INET6_ADDRSTRLEN),
hasso3e31cde2004-05-18 11:58:59 +00001097 rprefix->prefix.prefixlen);
1098 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1099 (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1100 {
1101 if (rprefix->AdvValidLifetime == UINT32_MAX)
1102 vty_out (vty, " infinite");
1103 else
1104 vty_out (vty, " %u", rprefix->AdvValidLifetime);
1105 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1106 vty_out (vty, " infinite");
1107 else
1108 vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1109 }
1110 if (!rprefix->AdvOnLinkFlag)
1111 vty_out (vty, " off-link");
1112 if (!rprefix->AdvAutonomousFlag)
1113 vty_out (vty, " no-autoconfig");
paul718e3742002-12-13 20:15:29 +00001114 vty_out (vty, "%s", VTY_NEWLINE);
1115 }
1116}
1117
paul718e3742002-12-13 20:15:29 +00001118
1119void
1120rtadv_event (enum rtadv_event event, int val)
1121{
1122 switch (event)
1123 {
1124 case RTADV_START:
1125 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001126 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001127 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001128 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
1129 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001130 break;
1131 case RTADV_STOP:
1132 if (rtadv->ra_timer)
1133 {
1134 thread_cancel (rtadv->ra_timer);
1135 rtadv->ra_timer = NULL;
1136 }
1137 if (rtadv->ra_read)
1138 {
1139 thread_cancel (rtadv->ra_read);
1140 rtadv->ra_read = NULL;
1141 }
1142 break;
1143 case RTADV_TIMER:
1144 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001145 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
1146 val);
paul718e3742002-12-13 20:15:29 +00001147 break;
1148 case RTADV_READ:
1149 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001150 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001151 break;
1152 default:
1153 break;
1154 }
1155 return;
1156}
1157
1158void
1159rtadv_init ()
1160{
1161 int sock;
1162
1163 sock = rtadv_make_socket ();
1164 if (sock < 0)
1165 return;
1166
1167 rtadv = rtadv_new ();
1168 rtadv->sock = sock;
1169
1170 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1171 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
paul718e3742002-12-13 20:15:29 +00001172 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1173 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1174 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1175 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1176 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1177 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1178 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1179 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1180 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1181 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001182 install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
1183 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1184 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1185 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
1186 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1187 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1188 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1189 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1190 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
1191 install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1192 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
paul718e3742002-12-13 20:15:29 +00001193}
1194
1195int
1196if_join_all_router (int sock, struct interface *ifp)
1197{
1198 int ret;
1199
1200 struct ipv6_mreq mreq;
1201
1202 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1203 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1204 mreq.ipv6mr_interface = ifp->ifindex;
1205
1206 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1207 (char *) &mreq, sizeof mreq);
1208 if (ret < 0)
1209 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
1210
1211 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1212
1213 return 0;
1214}
1215
1216int
1217if_leave_all_router (int sock, struct interface *ifp)
1218{
1219 int ret;
1220
1221 struct ipv6_mreq mreq;
1222
1223 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1224 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1225 mreq.ipv6mr_interface = ifp->ifindex;
1226
1227 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1228 (char *) &mreq, sizeof mreq);
1229 if (ret < 0)
1230 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno));
1231
1232 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1233
1234 return 0;
1235}
1236
1237#else
1238void
1239rtadv_init ()
1240{
1241 /* Empty.*/;
1242}
1243#endif /* RTADV && HAVE_IPV6 */