blob: 7ded4c8033fb502e503575646c444982dcaf472d [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 */
gdt57492d52004-08-11 18:06:38 +0000160 static void *adata = NULL;
paul718e3742002-12-13 20:15:29 +0000161 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
gdt57492d52004-08-11 18:06:38 +0000169 /*
170 * Allocate control message bufffer. This is dynamic because
171 * CMSG_SPACE is not guaranteed not to call a function. Note that
172 * the size will be different on different architectures due to
173 * differing alignment rules.
174 */
175 if (adata == NULL)
176 {
177 /* XXX Free on shutdown. */
178 adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)));
179
180 if (adata == NULL)
181 zlog_err("rtadv_send_packet: can't malloc control data\n");
182 }
183
paul718e3742002-12-13 20:15:29 +0000184 /* Logging of packet. */
185 if (IS_ZEBRA_DEBUG_PACKET)
186 zlog_info ("Router advertisement send to %s", ifp->name);
187
188 /* Fill in sockaddr_in6. */
189 memset (&addr, 0, sizeof (struct sockaddr_in6));
190 addr.sin6_family = AF_INET6;
191#ifdef SIN6_LEN
192 addr.sin6_len = sizeof (struct sockaddr_in6);
193#endif /* SIN6_LEN */
194 addr.sin6_port = htons (IPPROTO_ICMPV6);
195 memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
196
197 /* Fetch interface information. */
198 zif = ifp->info;
199
200 /* Make router advertisement message. */
201 rtadv = (struct nd_router_advert *) buf;
202
203 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
204 rtadv->nd_ra_code = 0;
205 rtadv->nd_ra_cksum = 0;
206
207 rtadv->nd_ra_curhoplimit = 64;
208 rtadv->nd_ra_flags_reserved = 0;
209 if (zif->rtadv.AdvManagedFlag)
210 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
211 if (zif->rtadv.AdvOtherConfigFlag)
212 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
213 rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
214 rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
215 rtadv->nd_ra_retransmit = htonl (0);
216
217 len = sizeof (struct nd_router_advert);
218
219 /* Fill in prefix. */
220 for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node))
221 {
222 struct nd_opt_prefix_info *pinfo;
223 struct rtadv_prefix *rprefix;
224
225 rprefix = getdata (node);
226
227 pinfo = (struct nd_opt_prefix_info *) (buf + len);
228
229 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
230 pinfo->nd_opt_pi_len = 4;
231 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
232
233 pinfo->nd_opt_pi_flags_reserved = 0;
234 if (rprefix->AdvOnLinkFlag)
235 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
236 if (rprefix->AdvAutonomousFlag)
237 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
238
239 pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
240 pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
241 pinfo->nd_opt_pi_reserved2 = 0;
242
243 memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
244 sizeof (struct in6_addr));
245
246#ifdef DEBUG
247 {
248 u_char buf[INET6_ADDRSTRLEN];
249
hasso3e31cde2004-05-18 11:58:59 +0000250 zlog_info ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix,
251 buf, INET6_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +0000252
253 }
254#endif /* DEBUG */
255
256 len += sizeof (struct nd_opt_prefix_info);
257 }
258
259 /* Hardware address. */
260#ifdef HAVE_SOCKADDR_DL
261 sdl = &ifp->sdl;
262 if (sdl != NULL && sdl->sdl_alen != 0)
263 {
264 buf[len++] = ND_OPT_SOURCE_LINKADDR;
265 buf[len++] = (sdl->sdl_alen + 2) >> 3;
266
267 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
268 len += sdl->sdl_alen;
269 }
270#else
271 if (ifp->hw_addr_len != 0)
272 {
273 buf[len++] = ND_OPT_SOURCE_LINKADDR;
274 buf[len++] = (ifp->hw_addr_len + 2) >> 3;
275
276 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
277 len += ifp->hw_addr_len;
278 }
279#endif /* HAVE_SOCKADDR_DL */
280
281 msg.msg_name = (void *) &addr;
282 msg.msg_namelen = sizeof (struct sockaddr_in6);
283 msg.msg_iov = &iov;
284 msg.msg_iovlen = 1;
285 msg.msg_control = (void *) adata;
gdtf841e022004-08-11 19:20:01 +0000286 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
gdt57492d52004-08-11 18:06:38 +0000287 msg.msg_flags = 0;
paul718e3742002-12-13 20:15:29 +0000288 iov.iov_base = buf;
289 iov.iov_len = len;
290
gdt57492d52004-08-11 18:06:38 +0000291 cmsgptr = CMSG_FIRSTHDR(&msg);
292 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
paul718e3742002-12-13 20:15:29 +0000293 cmsgptr->cmsg_level = IPPROTO_IPV6;
294 cmsgptr->cmsg_type = IPV6_PKTINFO;
gdt80893812004-08-11 15:58:00 +0000295
paul718e3742002-12-13 20:15:29 +0000296 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
297 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
298 pkt->ipi6_ifindex = ifp->ifindex;
299
300 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000301 if (ret < 0)
302 {
303 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
304 errno, strerror(errno));
305 }
paul718e3742002-12-13 20:15:29 +0000306}
307
308int
309rtadv_timer (struct thread *thread)
310{
311 listnode node;
312 struct interface *ifp;
313 struct zebra_if *zif;
314
315 rtadv->ra_timer = NULL;
316 rtadv_event (RTADV_TIMER, 1);
317
318 for (node = listhead (iflist); node; nextnode (node))
319 {
320 ifp = getdata (node);
321
322 if (if_is_loopback (ifp))
323 continue;
324
325 zif = ifp->info;
326
327 if (zif->rtadv.AdvSendAdvertisements)
328 if (--zif->rtadv.AdvIntervalTimer <= 0)
329 {
330 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
331 rtadv_send_packet (rtadv->sock, ifp);
332 }
333 }
334 return 0;
335}
336
337void
338rtadv_process_solicit (struct interface *ifp)
339{
340 zlog_info ("Router solicitation received on %s", ifp->name);
341
342 rtadv_send_packet (rtadv->sock, ifp);
343}
344
345void
346rtadv_process_advert ()
347{
348 zlog_info ("Router advertisement received");
349}
350
351void
352rtadv_process_packet (u_char *buf, int len, unsigned int ifindex, int hoplimit)
353{
354 struct icmp6_hdr *icmph;
355 struct interface *ifp;
356 struct zebra_if *zif;
357
358 /* Interface search. */
359 ifp = if_lookup_by_index (ifindex);
360 if (ifp == NULL)
361 {
362 zlog_warn ("Unknown interface index: %d", ifindex);
363 return;
364 }
365
366 if (if_is_loopback (ifp))
367 return;
368
369 /* Check interface configuration. */
370 zif = ifp->info;
371 if (! zif->rtadv.AdvSendAdvertisements)
372 return;
373
374 /* ICMP message length check. */
375 if (len < sizeof (struct icmp6_hdr))
376 {
377 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
378 return;
379 }
380
381 icmph = (struct icmp6_hdr *) buf;
382
383 /* ICMP message type check. */
384 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
385 icmph->icmp6_type != ND_ROUTER_ADVERT)
386 {
387 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
388 return;
389 }
390
391 /* Hoplimit check. */
392 if (hoplimit >= 0 && hoplimit != 255)
393 {
394 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
395 hoplimit);
396 return;
397 }
398
399 /* Check ICMP message type. */
400 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
401 rtadv_process_solicit (ifp);
402 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
403 rtadv_process_advert ();
404
405 return;
406}
407
408int
409rtadv_read (struct thread *thread)
410{
411 int sock;
412 int len;
413 u_char buf[RTADV_MSG_SIZE];
414 struct sockaddr_in6 from;
415 unsigned int ifindex;
416 int hoplimit = -1;
417
418 sock = THREAD_FD (thread);
419 rtadv->ra_read = NULL;
420
421 /* Register myself. */
422 rtadv_event (RTADV_READ, sock);
423
424 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
425
426 if (len < 0)
427 {
428 zlog_warn ("router solicitation recv failed: %s.", strerror (errno));
429 return len;
430 }
431
432 rtadv_process_packet (buf, len, ifindex, hoplimit);
433
434 return 0;
435}
436
437int
438rtadv_make_socket (void)
439{
440 int sock;
441 int ret;
442 struct icmp6_filter filter;
443
pauledd7c242003-06-04 13:59:38 +0000444 if ( zserv_privs.change (ZPRIVS_RAISE) )
445 zlog_err ("rtadv_make_socket: could not raise privs, %s",
446 strerror (errno) );
447
paul718e3742002-12-13 20:15:29 +0000448 sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
449
pauledd7c242003-06-04 13:59:38 +0000450 if ( zserv_privs.change (ZPRIVS_LOWER) )
451 zlog_err ("rtadv_make_socket: could not lower privs, %s",
452 strerror (errno) );
453
paul718e3742002-12-13 20:15:29 +0000454 /* When we can't make ICMPV6 socket simply back. Router
455 advertisement feature will not be supported. */
456 if (sock < 0)
457 return -1;
458
459 ret = setsockopt_ipv6_pktinfo (sock, 1);
460 if (ret < 0)
461 return ret;
paul718e3742002-12-13 20:15:29 +0000462 ret = setsockopt_ipv6_multicast_loop (sock, 0);
463 if (ret < 0)
464 return ret;
465 ret = setsockopt_ipv6_unicast_hops (sock, 255);
466 if (ret < 0)
467 return ret;
468 ret = setsockopt_ipv6_multicast_hops (sock, 255);
469 if (ret < 0)
470 return ret;
471 ret = setsockopt_ipv6_hoplimit (sock, 1);
472 if (ret < 0)
473 return ret;
474
475 ICMP6_FILTER_SETBLOCKALL(&filter);
476 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
477 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
478
479 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
480 sizeof (struct icmp6_filter));
481 if (ret < 0)
482 {
483 zlog_info ("ICMP6_FILTER set fail: %s", strerror (errno));
484 return ret;
485 }
486
487 return sock;
488}
489
490struct rtadv_prefix *
491rtadv_prefix_new ()
492{
493 struct rtadv_prefix *new;
494
495 new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
496 memset (new, 0, sizeof (struct rtadv_prefix));
497
498 return new;
499}
500
501void
502rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
503{
504 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
505}
506
507struct rtadv_prefix *
508rtadv_prefix_lookup (list rplist, struct prefix *p)
509{
510 listnode node;
511 struct rtadv_prefix *rprefix;
512
513 for (node = listhead (rplist); node; node = nextnode (node))
514 {
515 rprefix = getdata (node);
516 if (prefix_same (&rprefix->prefix, p))
517 return rprefix;
518 }
519 return NULL;
520}
521
522struct rtadv_prefix *
523rtadv_prefix_get (list rplist, struct prefix *p)
524{
525 struct rtadv_prefix *rprefix;
526
527 rprefix = rtadv_prefix_lookup (rplist, p);
528 if (rprefix)
529 return rprefix;
530
531 rprefix = rtadv_prefix_new ();
532 memcpy (&rprefix->prefix, p, sizeof (struct prefix));
533 listnode_add (rplist, rprefix);
534
535 return rprefix;
536}
537
538void
539rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
540{
541 struct rtadv_prefix *rprefix;
542
543 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
544
545 /* Set parameters. */
546 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
547 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
548 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
549 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
550}
551
552int
553rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
554{
555 struct rtadv_prefix *rprefix;
556
557 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
558 if (rprefix != NULL)
559 {
560 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
561 rtadv_prefix_free (rprefix);
562 return 1;
563 }
564 else
565 return 0;
566}
567
568DEFUN (ipv6_nd_suppress_ra,
569 ipv6_nd_suppress_ra_cmd,
570 "ipv6 nd suppress-ra",
hasso3e31cde2004-05-18 11:58:59 +0000571 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000572 "Neighbor discovery\n"
573 "Suppress Router Advertisement\n")
574{
575 struct interface *ifp;
576 struct zebra_if *zif;
577
578 ifp = vty->index;
579 zif = ifp->info;
580
581 if (if_is_loopback (ifp))
582 {
583 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
584 return CMD_WARNING;
585 }
586
587 if (zif->rtadv.AdvSendAdvertisements)
588 {
589 zif->rtadv.AdvSendAdvertisements = 0;
590 zif->rtadv.AdvIntervalTimer = 0;
591 rtadv->adv_if_count--;
592
593 if_leave_all_router (rtadv->sock, ifp);
594
595 if (rtadv->adv_if_count == 0)
596 rtadv_event (RTADV_STOP, 0);
597 }
598
599 return CMD_SUCCESS;
600}
601
paul718e3742002-12-13 20:15:29 +0000602DEFUN (no_ipv6_nd_suppress_ra,
603 no_ipv6_nd_suppress_ra_cmd,
604 "no ipv6 nd suppress-ra",
605 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000606 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000607 "Neighbor discovery\n"
608 "Suppress Router Advertisement\n")
609{
610 struct interface *ifp;
611 struct zebra_if *zif;
612
613 ifp = vty->index;
614 zif = ifp->info;
615
616 if (if_is_loopback (ifp))
617 {
618 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
619 return CMD_WARNING;
620 }
621
622 if (! zif->rtadv.AdvSendAdvertisements)
623 {
624 zif->rtadv.AdvSendAdvertisements = 1;
625 zif->rtadv.AdvIntervalTimer = 0;
626 rtadv->adv_if_count++;
627
628 if_join_all_router (rtadv->sock, ifp);
629
630 if (rtadv->adv_if_count == 1)
631 rtadv_event (RTADV_START, rtadv->sock);
632 }
633
634 return CMD_SUCCESS;
635}
636
paul718e3742002-12-13 20:15:29 +0000637DEFUN (ipv6_nd_ra_interval,
638 ipv6_nd_ra_interval_cmd,
639 "ipv6 nd ra-interval SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000640 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000641 "Neighbor discovery\n"
642 "Router Advertisement interval\n"
643 "Router Advertisement interval in seconds\n")
644{
645 int interval;
646 struct interface *ifp;
647 struct zebra_if *zif;
648
649 ifp = (struct interface *) vty->index;
650 zif = ifp->info;
651
652 interval = atoi (argv[0]);
653
654 if (interval < 0)
655 {
656 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
657 return CMD_WARNING;
658 }
659
660 zif->rtadv.MaxRtrAdvInterval = interval;
661 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
662 zif->rtadv.AdvIntervalTimer = 0;
663
664 return CMD_SUCCESS;
665}
666
667DEFUN (no_ipv6_nd_ra_interval,
668 no_ipv6_nd_ra_interval_cmd,
669 "no ipv6 nd ra-interval",
670 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000671 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000672 "Neighbor discovery\n"
673 "Router Advertisement interval\n")
674{
675 struct interface *ifp;
676 struct zebra_if *zif;
677
678 ifp = (struct interface *) vty->index;
679 zif = ifp->info;
680
681 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
682 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
683 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
684
685 return CMD_SUCCESS;
686}
687
688DEFUN (ipv6_nd_ra_lifetime,
689 ipv6_nd_ra_lifetime_cmd,
690 "ipv6 nd ra-lifetime SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000691 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000692 "Neighbor discovery\n"
693 "Router lifetime\n"
694 "Router lifetime in seconds\n")
695{
696 int lifetime;
697 struct interface *ifp;
698 struct zebra_if *zif;
699
700 ifp = (struct interface *) vty->index;
701 zif = ifp->info;
702
703 lifetime = atoi (argv[0]);
704
705 if (lifetime < 0 || lifetime > 0xffff)
706 {
707 vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
708 return CMD_WARNING;
709 }
710
711 zif->rtadv.AdvDefaultLifetime = lifetime;
712
713 return CMD_SUCCESS;
714}
715
716DEFUN (no_ipv6_nd_ra_lifetime,
717 no_ipv6_nd_ra_lifetime_cmd,
718 "no ipv6 nd ra-lifetime",
719 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000720 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000721 "Neighbor discovery\n"
722 "Router lifetime\n")
723{
724 struct interface *ifp;
725 struct zebra_if *zif;
726
727 ifp = (struct interface *) vty->index;
728 zif = ifp->info;
729
730 zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
731
732 return CMD_SUCCESS;
733}
734
735DEFUN (ipv6_nd_reachable_time,
736 ipv6_nd_reachable_time_cmd,
737 "ipv6 nd reachable-time MILLISECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000738 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000739 "Neighbor discovery\n"
740 "Reachable time\n"
741 "Reachable time in milliseconds\n")
742{
743 u_int32_t rtime;
744 struct interface *ifp;
745 struct zebra_if *zif;
746
747 ifp = (struct interface *) vty->index;
748 zif = ifp->info;
749
750 rtime = (u_int32_t) atol (argv[0]);
751
752 if (rtime > RTADV_MAX_REACHABLE_TIME)
753 {
754 vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
755 return CMD_WARNING;
756 }
757
758 zif->rtadv.AdvReachableTime = rtime;
759
760 return CMD_SUCCESS;
761}
762
763DEFUN (no_ipv6_nd_reachable_time,
764 no_ipv6_nd_reachable_time_cmd,
765 "no ipv6 nd reachable-time",
766 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000767 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000768 "Neighbor discovery\n"
769 "Reachable time\n")
770{
771 struct interface *ifp;
772 struct zebra_if *zif;
773
774 ifp = (struct interface *) vty->index;
775 zif = ifp->info;
776
777 zif->rtadv.AdvReachableTime = 0;
778
779 return CMD_SUCCESS;
780}
781
782DEFUN (ipv6_nd_managed_config_flag,
783 ipv6_nd_managed_config_flag_cmd,
784 "ipv6 nd managed-config-flag",
hasso3e31cde2004-05-18 11:58:59 +0000785 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000786 "Neighbor discovery\n"
787 "Managed address configuration flag\n")
788{
789 struct interface *ifp;
790 struct zebra_if *zif;
791
792 ifp = (struct interface *) vty->index;
793 zif = ifp->info;
794
795 zif->rtadv.AdvManagedFlag = 1;
796
797 return CMD_SUCCESS;
798}
799
800DEFUN (no_ipv6_nd_managed_config_flag,
801 no_ipv6_nd_managed_config_flag_cmd,
802 "no ipv6 nd managed-config-flag",
803 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000804 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000805 "Neighbor discovery\n"
806 "Managed address configuration flag\n")
807{
808 struct interface *ifp;
809 struct zebra_if *zif;
810
811 ifp = (struct interface *) vty->index;
812 zif = ifp->info;
813
814 zif->rtadv.AdvManagedFlag = 0;
815
816 return CMD_SUCCESS;
817}
818
819DEFUN (ipv6_nd_other_config_flag,
820 ipv6_nd_other_config_flag_cmd,
821 "ipv6 nd other-config-flag",
hasso3e31cde2004-05-18 11:58:59 +0000822 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000823 "Neighbor discovery\n"
824 "Other statefull configuration flag\n")
825{
826 struct interface *ifp;
827 struct zebra_if *zif;
828
829 ifp = (struct interface *) vty->index;
830 zif = ifp->info;
831
832 zif->rtadv.AdvOtherConfigFlag = 1;
833
834 return CMD_SUCCESS;
835}
836
837DEFUN (no_ipv6_nd_other_config_flag,
838 no_ipv6_nd_other_config_flag_cmd,
839 "no ipv6 nd other-config-flag",
840 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000841 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000842 "Neighbor discovery\n"
843 "Other statefull configuration flag\n")
844{
845 struct interface *ifp;
846 struct zebra_if *zif;
847
848 ifp = (struct interface *) vty->index;
849 zif = ifp->info;
850
851 zif->rtadv.AdvOtherConfigFlag = 0;
852
853 return CMD_SUCCESS;
854}
855
hasso3e31cde2004-05-18 11:58:59 +0000856DEFUN (ipv6_nd_prefix,
857 ipv6_nd_prefix_cmd,
858 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
859 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
860 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000861 "Neighbor discovery\n"
862 "Prefix information\n"
863 "IPv6 prefix\n"
864 "Valid lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +0000865 "Infinite valid lifetime\n"
paul718e3742002-12-13 20:15:29 +0000866 "Preferred lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +0000867 "Infinite preferred lifetime\n"
868 "Do not use prefix for onlink determination\n"
869 "Do not use prefix for autoconfiguration\n")
paul718e3742002-12-13 20:15:29 +0000870{
871 int i;
872 int ret;
hasso3e31cde2004-05-18 11:58:59 +0000873 int cursor = 1;
paul718e3742002-12-13 20:15:29 +0000874 struct interface *ifp;
875 struct zebra_if *zebra_if;
876 struct rtadv_prefix rp;
877
878 ifp = (struct interface *) vty->index;
879 zebra_if = ifp->info;
880
881 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
882 if (!ret)
883 {
884 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
885 return CMD_WARNING;
886 }
hasso3e31cde2004-05-18 11:58:59 +0000887 rp.AdvOnLinkFlag = 1;
888 rp.AdvAutonomousFlag = 1;
889 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
890 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
paul718e3742002-12-13 20:15:29 +0000891
hasso3e31cde2004-05-18 11:58:59 +0000892 if (argc > 1)
paul718e3742002-12-13 20:15:29 +0000893 {
hasso3e31cde2004-05-18 11:58:59 +0000894 if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0)
paul718e3742002-12-13 20:15:29 +0000895 {
hasso3e31cde2004-05-18 11:58:59 +0000896 if ( strncmp (argv[1], "i", 1) == 0)
897 rp.AdvValidLifetime = UINT32_MAX;
898 else
899 rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
900 (char **)NULL, 10);
901
902 if ( strncmp (argv[2], "i", 1) == 0)
903 rp.AdvPreferredLifetime = UINT32_MAX;
904 else
905 rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
906 (char **)NULL, 10);
907
908 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
909 {
910 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
911 return CMD_WARNING;
912 }
913 cursor = cursor + 2;
paul718e3742002-12-13 20:15:29 +0000914 }
hasso3e31cde2004-05-18 11:58:59 +0000915 if (argc > cursor)
paul718e3742002-12-13 20:15:29 +0000916 {
hasso3e31cde2004-05-18 11:58:59 +0000917 for (i = cursor; i < argc; i++)
918 {
919 if (strncmp (argv[i], "of", 2) == 0)
920 rp.AdvOnLinkFlag = 0;
921 if (strncmp (argv[i], "no", 2) == 0)
922 rp.AdvAutonomousFlag = 0;
923 }
paul718e3742002-12-13 20:15:29 +0000924 }
925 }
926
927 rtadv_prefix_set (zebra_if, &rp);
928
929 return CMD_SUCCESS;
930}
931
hasso3e31cde2004-05-18 11:58:59 +0000932ALIAS (ipv6_nd_prefix,
933 ipv6_nd_prefix_val_rev_cmd,
934 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
935 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
936 "Interface IPv6 config commands\n"
937 "Neighbor discovery\n"
938 "Prefix information\n"
939 "IPv6 prefix\n"
940 "Valid lifetime in seconds\n"
941 "Infinite valid lifetime\n"
942 "Preferred lifetime in seconds\n"
943 "Infinite preferred lifetime\n"
944 "Do not use prefix for autoconfiguration\n"
945 "Do not use prefix for onlink determination\n")
946
947ALIAS (ipv6_nd_prefix,
948 ipv6_nd_prefix_val_noauto_cmd,
949 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
950 "(<0-4294967295>|infinite) (no-autoconfig|)",
951 "Interface IPv6 config commands\n"
952 "Neighbor discovery\n"
953 "Prefix information\n"
954 "IPv6 prefix\n"
955 "Valid lifetime in seconds\n"
956 "Infinite valid lifetime\n"
957 "Preferred lifetime in seconds\n"
958 "Infinite preferred lifetime\n"
959 "Do not use prefix for autoconfigurationn")
960
961ALIAS (ipv6_nd_prefix,
962 ipv6_nd_prefix_val_offlink_cmd,
963 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
964 "(<0-4294967295>|infinite) (off-link|)",
965 "Interface IPv6 config commands\n"
966 "Neighbor discovery\n"
967 "Prefix information\n"
968 "IPv6 prefix\n"
969 "Valid lifetime in seconds\n"
970 "Infinite valid lifetime\n"
971 "Preferred lifetime in seconds\n"
972 "Infinite preferred lifetime\n"
973 "Do not use prefix for onlink determination\n")
974
975ALIAS (ipv6_nd_prefix,
976 ipv6_nd_prefix_val_cmd,
977 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
978 "(<0-4294967295>|infinite)",
979 "Interface IPv6 config commands\n"
980 "Neighbor discovery\n"
981 "Prefix information\n"
982 "IPv6 prefix\n"
983 "Valid lifetime in seconds\n"
984 "Infinite valid lifetime\n"
985 "Preferred lifetime in seconds\n"
986 "Infinite preferred lifetime\n")
987
988ALIAS (ipv6_nd_prefix,
989 ipv6_nd_prefix_noval_cmd,
990 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
991 "Interface IPv6 config commands\n"
992 "Neighbor discovery\n"
993 "Prefix information\n"
994 "IPv6 prefix\n"
995 "Do not use prefix for autoconfiguration\n"
996 "Do not use prefix for onlink determination\n")
997
998ALIAS (ipv6_nd_prefix,
999 ipv6_nd_prefix_noval_rev_cmd,
1000 "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
1001 "Interface IPv6 config commands\n"
1002 "Neighbor discovery\n"
1003 "Prefix information\n"
1004 "IPv6 prefix\n"
1005 "Do not use prefix for onlink determination\n"
1006 "Do not use prefix for autoconfiguration\n")
1007
1008ALIAS (ipv6_nd_prefix,
1009 ipv6_nd_prefix_noval_noauto_cmd,
1010 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
1011 "Interface IPv6 config commands\n"
1012 "Neighbor discovery\n"
1013 "Prefix information\n"
1014 "IPv6 prefix\n"
1015 "Do not use prefix for autoconfiguration\n")
1016
1017ALIAS (ipv6_nd_prefix,
1018 ipv6_nd_prefix_noval_offlink_cmd,
1019 "ipv6 nd prefix X:X::X:X/M (off-link|)",
1020 "Interface IPv6 config commands\n"
1021 "Neighbor discovery\n"
1022 "Prefix information\n"
1023 "IPv6 prefix\n"
1024 "Do not use prefix for onlink determination\n")
1025
1026ALIAS (ipv6_nd_prefix,
1027 ipv6_nd_prefix_prefix_cmd,
1028 "ipv6 nd prefix X:X::X:X/M",
1029 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001030 "Neighbor discovery\n"
1031 "Prefix information\n"
1032 "IPv6 prefix\n")
1033
hasso3e31cde2004-05-18 11:58:59 +00001034DEFUN (no_ipv6_nd_prefix,
1035 no_ipv6_nd_prefix_cmd,
1036 "no ipv6 nd prefix IPV6PREFIX",
paul718e3742002-12-13 20:15:29 +00001037 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001038 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001039 "Neighbor discovery\n"
1040 "Prefix information\n"
1041 "IPv6 prefix\n")
1042{
1043 int ret;
1044 struct interface *ifp;
1045 struct zebra_if *zebra_if;
1046 struct rtadv_prefix rp;
1047
1048 ifp = (struct interface *) vty->index;
1049 zebra_if = ifp->info;
1050
1051 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
1052 if (!ret)
1053 {
1054 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1055 return CMD_WARNING;
1056 }
1057
1058 ret = rtadv_prefix_reset (zebra_if, &rp);
1059 if (!ret)
1060 {
1061 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1062 return CMD_WARNING;
1063 }
1064
1065 return CMD_SUCCESS;
1066}
1067
1068/* Write configuration about router advertisement. */
1069void
1070rtadv_config_write (struct vty *vty, struct interface *ifp)
1071{
1072 struct zebra_if *zif;
1073 listnode node;
1074 struct rtadv_prefix *rprefix;
1075 u_char buf[INET6_ADDRSTRLEN];
1076
1077 if (! rtadv)
1078 return;
1079
1080 zif = ifp->info;
1081
1082 if (! if_is_loopback (ifp))
1083 {
1084 if (zif->rtadv.AdvSendAdvertisements)
1085 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1086 else
1087 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1088 }
1089
1090 if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL)
1091 vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval,
1092 VTY_NEWLINE);
1093
1094 if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
1095 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1096 VTY_NEWLINE);
1097
1098 if (zif->rtadv.AdvReachableTime)
1099 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1100 VTY_NEWLINE);
1101
1102 if (zif->rtadv.AdvManagedFlag)
1103 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1104
1105 if (zif->rtadv.AdvOtherConfigFlag)
1106 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1107
1108 for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node))
1109 {
1110 rprefix = getdata (node);
hasso3e31cde2004-05-18 11:58:59 +00001111 vty_out (vty, " ipv6 nd prefix %s/%d",
paul718e3742002-12-13 20:15:29 +00001112 inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6,
1113 buf, INET6_ADDRSTRLEN),
hasso3e31cde2004-05-18 11:58:59 +00001114 rprefix->prefix.prefixlen);
1115 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1116 (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1117 {
1118 if (rprefix->AdvValidLifetime == UINT32_MAX)
1119 vty_out (vty, " infinite");
1120 else
1121 vty_out (vty, " %u", rprefix->AdvValidLifetime);
1122 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1123 vty_out (vty, " infinite");
1124 else
1125 vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1126 }
1127 if (!rprefix->AdvOnLinkFlag)
1128 vty_out (vty, " off-link");
1129 if (!rprefix->AdvAutonomousFlag)
1130 vty_out (vty, " no-autoconfig");
paul718e3742002-12-13 20:15:29 +00001131 vty_out (vty, "%s", VTY_NEWLINE);
1132 }
1133}
1134
paul718e3742002-12-13 20:15:29 +00001135
1136void
1137rtadv_event (enum rtadv_event event, int val)
1138{
1139 switch (event)
1140 {
1141 case RTADV_START:
1142 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001143 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001144 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001145 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
1146 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001147 break;
1148 case RTADV_STOP:
1149 if (rtadv->ra_timer)
1150 {
1151 thread_cancel (rtadv->ra_timer);
1152 rtadv->ra_timer = NULL;
1153 }
1154 if (rtadv->ra_read)
1155 {
1156 thread_cancel (rtadv->ra_read);
1157 rtadv->ra_read = NULL;
1158 }
1159 break;
1160 case RTADV_TIMER:
1161 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001162 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
1163 val);
paul718e3742002-12-13 20:15:29 +00001164 break;
1165 case RTADV_READ:
1166 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001167 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001168 break;
1169 default:
1170 break;
1171 }
1172 return;
1173}
1174
1175void
1176rtadv_init ()
1177{
1178 int sock;
1179
1180 sock = rtadv_make_socket ();
1181 if (sock < 0)
1182 return;
1183
1184 rtadv = rtadv_new ();
1185 rtadv->sock = sock;
1186
1187 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1188 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
paul718e3742002-12-13 20:15:29 +00001189 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1190 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1191 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1192 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1193 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1194 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1195 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1196 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1197 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1198 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001199 install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
1200 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1201 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1202 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
1203 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1204 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1205 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1206 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1207 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
1208 install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1209 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
paul718e3742002-12-13 20:15:29 +00001210}
1211
1212int
1213if_join_all_router (int sock, struct interface *ifp)
1214{
1215 int ret;
1216
1217 struct ipv6_mreq mreq;
1218
1219 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1220 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1221 mreq.ipv6mr_interface = ifp->ifindex;
1222
1223 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1224 (char *) &mreq, sizeof mreq);
1225 if (ret < 0)
1226 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
1227
1228 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1229
1230 return 0;
1231}
1232
1233int
1234if_leave_all_router (int sock, struct interface *ifp)
1235{
1236 int ret;
1237
1238 struct ipv6_mreq mreq;
1239
1240 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1241 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1242 mreq.ipv6mr_interface = ifp->ifindex;
1243
1244 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1245 (char *) &mreq, sizeof mreq);
1246 if (ret < 0)
1247 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno));
1248
1249 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1250
1251 return 0;
1252}
1253
1254#else
1255void
1256rtadv_init ()
1257{
1258 /* Empty.*/;
1259}
1260#endif /* RTADV && HAVE_IPV6 */