blob: c98b11cf162fda0fa1ba848375a7118507217d0b [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
235 zlog_info ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, buf, INET6_ADDRSTRLEN));
236
237 }
238#endif /* DEBUG */
239
240 len += sizeof (struct nd_opt_prefix_info);
241 }
242
243 /* Hardware address. */
244#ifdef HAVE_SOCKADDR_DL
245 sdl = &ifp->sdl;
246 if (sdl != NULL && sdl->sdl_alen != 0)
247 {
248 buf[len++] = ND_OPT_SOURCE_LINKADDR;
249 buf[len++] = (sdl->sdl_alen + 2) >> 3;
250
251 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
252 len += sdl->sdl_alen;
253 }
254#else
255 if (ifp->hw_addr_len != 0)
256 {
257 buf[len++] = ND_OPT_SOURCE_LINKADDR;
258 buf[len++] = (ifp->hw_addr_len + 2) >> 3;
259
260 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
261 len += ifp->hw_addr_len;
262 }
263#endif /* HAVE_SOCKADDR_DL */
264
265 msg.msg_name = (void *) &addr;
266 msg.msg_namelen = sizeof (struct sockaddr_in6);
267 msg.msg_iov = &iov;
268 msg.msg_iovlen = 1;
269 msg.msg_control = (void *) adata;
270 msg.msg_controllen = sizeof adata;
271 iov.iov_base = buf;
272 iov.iov_len = len;
273
274 cmsgptr = (struct cmsghdr *)adata;
275 cmsgptr->cmsg_len = sizeof adata;
276 cmsgptr->cmsg_level = IPPROTO_IPV6;
277 cmsgptr->cmsg_type = IPV6_PKTINFO;
278 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
279 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
280 pkt->ipi6_ifindex = ifp->ifindex;
281
282 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000283 if (ret < 0)
284 {
285 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
286 errno, strerror(errno));
287 }
paul718e3742002-12-13 20:15:29 +0000288}
289
290int
291rtadv_timer (struct thread *thread)
292{
293 listnode node;
294 struct interface *ifp;
295 struct zebra_if *zif;
296
297 rtadv->ra_timer = NULL;
298 rtadv_event (RTADV_TIMER, 1);
299
300 for (node = listhead (iflist); node; nextnode (node))
301 {
302 ifp = getdata (node);
303
304 if (if_is_loopback (ifp))
305 continue;
306
307 zif = ifp->info;
308
309 if (zif->rtadv.AdvSendAdvertisements)
310 if (--zif->rtadv.AdvIntervalTimer <= 0)
311 {
312 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
313 rtadv_send_packet (rtadv->sock, ifp);
314 }
315 }
316 return 0;
317}
318
319void
320rtadv_process_solicit (struct interface *ifp)
321{
322 zlog_info ("Router solicitation received on %s", ifp->name);
323
324 rtadv_send_packet (rtadv->sock, ifp);
325}
326
327void
328rtadv_process_advert ()
329{
330 zlog_info ("Router advertisement received");
331}
332
333void
334rtadv_process_packet (u_char *buf, int len, unsigned int ifindex, int hoplimit)
335{
336 struct icmp6_hdr *icmph;
337 struct interface *ifp;
338 struct zebra_if *zif;
339
340 /* Interface search. */
341 ifp = if_lookup_by_index (ifindex);
342 if (ifp == NULL)
343 {
344 zlog_warn ("Unknown interface index: %d", ifindex);
345 return;
346 }
347
348 if (if_is_loopback (ifp))
349 return;
350
351 /* Check interface configuration. */
352 zif = ifp->info;
353 if (! zif->rtadv.AdvSendAdvertisements)
354 return;
355
356 /* ICMP message length check. */
357 if (len < sizeof (struct icmp6_hdr))
358 {
359 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
360 return;
361 }
362
363 icmph = (struct icmp6_hdr *) buf;
364
365 /* ICMP message type check. */
366 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
367 icmph->icmp6_type != ND_ROUTER_ADVERT)
368 {
369 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
370 return;
371 }
372
373 /* Hoplimit check. */
374 if (hoplimit >= 0 && hoplimit != 255)
375 {
376 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
377 hoplimit);
378 return;
379 }
380
381 /* Check ICMP message type. */
382 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
383 rtadv_process_solicit (ifp);
384 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
385 rtadv_process_advert ();
386
387 return;
388}
389
390int
391rtadv_read (struct thread *thread)
392{
393 int sock;
394 int len;
395 u_char buf[RTADV_MSG_SIZE];
396 struct sockaddr_in6 from;
397 unsigned int ifindex;
398 int hoplimit = -1;
399
400 sock = THREAD_FD (thread);
401 rtadv->ra_read = NULL;
402
403 /* Register myself. */
404 rtadv_event (RTADV_READ, sock);
405
406 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
407
408 if (len < 0)
409 {
410 zlog_warn ("router solicitation recv failed: %s.", strerror (errno));
411 return len;
412 }
413
414 rtadv_process_packet (buf, len, ifindex, hoplimit);
415
416 return 0;
417}
418
419int
420rtadv_make_socket (void)
421{
422 int sock;
423 int ret;
424 struct icmp6_filter filter;
425
pauledd7c242003-06-04 13:59:38 +0000426 if ( zserv_privs.change (ZPRIVS_RAISE) )
427 zlog_err ("rtadv_make_socket: could not raise privs, %s",
428 strerror (errno) );
429
paul718e3742002-12-13 20:15:29 +0000430 sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
431
pauledd7c242003-06-04 13:59:38 +0000432 if ( zserv_privs.change (ZPRIVS_LOWER) )
433 zlog_err ("rtadv_make_socket: could not lower privs, %s",
434 strerror (errno) );
435
paul718e3742002-12-13 20:15:29 +0000436 /* When we can't make ICMPV6 socket simply back. Router
437 advertisement feature will not be supported. */
438 if (sock < 0)
439 return -1;
440
441 ret = setsockopt_ipv6_pktinfo (sock, 1);
442 if (ret < 0)
443 return ret;
paul718e3742002-12-13 20:15:29 +0000444 ret = setsockopt_ipv6_multicast_loop (sock, 0);
445 if (ret < 0)
446 return ret;
447 ret = setsockopt_ipv6_unicast_hops (sock, 255);
448 if (ret < 0)
449 return ret;
450 ret = setsockopt_ipv6_multicast_hops (sock, 255);
451 if (ret < 0)
452 return ret;
453 ret = setsockopt_ipv6_hoplimit (sock, 1);
454 if (ret < 0)
455 return ret;
456
457 ICMP6_FILTER_SETBLOCKALL(&filter);
458 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
459 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
460
461 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
462 sizeof (struct icmp6_filter));
463 if (ret < 0)
464 {
465 zlog_info ("ICMP6_FILTER set fail: %s", strerror (errno));
466 return ret;
467 }
468
469 return sock;
470}
471
472struct rtadv_prefix *
473rtadv_prefix_new ()
474{
475 struct rtadv_prefix *new;
476
477 new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
478 memset (new, 0, sizeof (struct rtadv_prefix));
479
480 return new;
481}
482
483void
484rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
485{
486 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
487}
488
489struct rtadv_prefix *
490rtadv_prefix_lookup (list rplist, struct prefix *p)
491{
492 listnode node;
493 struct rtadv_prefix *rprefix;
494
495 for (node = listhead (rplist); node; node = nextnode (node))
496 {
497 rprefix = getdata (node);
498 if (prefix_same (&rprefix->prefix, p))
499 return rprefix;
500 }
501 return NULL;
502}
503
504struct rtadv_prefix *
505rtadv_prefix_get (list rplist, struct prefix *p)
506{
507 struct rtadv_prefix *rprefix;
508
509 rprefix = rtadv_prefix_lookup (rplist, p);
510 if (rprefix)
511 return rprefix;
512
513 rprefix = rtadv_prefix_new ();
514 memcpy (&rprefix->prefix, p, sizeof (struct prefix));
515 listnode_add (rplist, rprefix);
516
517 return rprefix;
518}
519
520void
521rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
522{
523 struct rtadv_prefix *rprefix;
524
525 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
526
527 /* Set parameters. */
528 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
529 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
530 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
531 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
532}
533
534int
535rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
536{
537 struct rtadv_prefix *rprefix;
538
539 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
540 if (rprefix != NULL)
541 {
542 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
543 rtadv_prefix_free (rprefix);
544 return 1;
545 }
546 else
547 return 0;
548}
549
550DEFUN (ipv6_nd_suppress_ra,
551 ipv6_nd_suppress_ra_cmd,
552 "ipv6 nd suppress-ra",
553 IP_STR
554 "Neighbor discovery\n"
555 "Suppress Router Advertisement\n")
556{
557 struct interface *ifp;
558 struct zebra_if *zif;
559
560 ifp = vty->index;
561 zif = ifp->info;
562
563 if (if_is_loopback (ifp))
564 {
565 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
566 return CMD_WARNING;
567 }
568
569 if (zif->rtadv.AdvSendAdvertisements)
570 {
571 zif->rtadv.AdvSendAdvertisements = 0;
572 zif->rtadv.AdvIntervalTimer = 0;
573 rtadv->adv_if_count--;
574
575 if_leave_all_router (rtadv->sock, ifp);
576
577 if (rtadv->adv_if_count == 0)
578 rtadv_event (RTADV_STOP, 0);
579 }
580
581 return CMD_SUCCESS;
582}
583
584ALIAS (ipv6_nd_suppress_ra,
585 no_ipv6_nd_send_ra_cmd,
586 "no ipv6 nd send-ra",
587 NO_STR
588 IP_STR
589 "Neighbor discovery\n"
590 "Send Router Advertisement\n")
591
592DEFUN (no_ipv6_nd_suppress_ra,
593 no_ipv6_nd_suppress_ra_cmd,
594 "no ipv6 nd suppress-ra",
595 NO_STR
596 IP_STR
597 "Neighbor discovery\n"
598 "Suppress Router Advertisement\n")
599{
600 struct interface *ifp;
601 struct zebra_if *zif;
602
603 ifp = vty->index;
604 zif = ifp->info;
605
606 if (if_is_loopback (ifp))
607 {
608 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
609 return CMD_WARNING;
610 }
611
612 if (! zif->rtadv.AdvSendAdvertisements)
613 {
614 zif->rtadv.AdvSendAdvertisements = 1;
615 zif->rtadv.AdvIntervalTimer = 0;
616 rtadv->adv_if_count++;
617
618 if_join_all_router (rtadv->sock, ifp);
619
620 if (rtadv->adv_if_count == 1)
621 rtadv_event (RTADV_START, rtadv->sock);
622 }
623
624 return CMD_SUCCESS;
625}
626
627ALIAS (no_ipv6_nd_suppress_ra,
628 ipv6_nd_send_ra_cmd,
629 "ipv6 nd send-ra",
630 IP_STR
631 "Neighbor discovery\n"
632 "Send Router Advertisement\n")
633
634DEFUN (ipv6_nd_ra_interval,
635 ipv6_nd_ra_interval_cmd,
636 "ipv6 nd ra-interval SECONDS",
637 IP_STR
638 "Neighbor discovery\n"
639 "Router Advertisement interval\n"
640 "Router Advertisement interval in seconds\n")
641{
642 int interval;
643 struct interface *ifp;
644 struct zebra_if *zif;
645
646 ifp = (struct interface *) vty->index;
647 zif = ifp->info;
648
649 interval = atoi (argv[0]);
650
651 if (interval < 0)
652 {
653 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
654 return CMD_WARNING;
655 }
656
657 zif->rtadv.MaxRtrAdvInterval = interval;
658 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
659 zif->rtadv.AdvIntervalTimer = 0;
660
661 return CMD_SUCCESS;
662}
663
664DEFUN (no_ipv6_nd_ra_interval,
665 no_ipv6_nd_ra_interval_cmd,
666 "no ipv6 nd ra-interval",
667 NO_STR
668 IP_STR
669 "Neighbor discovery\n"
670 "Router Advertisement interval\n")
671{
672 struct interface *ifp;
673 struct zebra_if *zif;
674
675 ifp = (struct interface *) vty->index;
676 zif = ifp->info;
677
678 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
679 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
680 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
681
682 return CMD_SUCCESS;
683}
684
685DEFUN (ipv6_nd_ra_lifetime,
686 ipv6_nd_ra_lifetime_cmd,
687 "ipv6 nd ra-lifetime SECONDS",
688 IP_STR
689 "Neighbor discovery\n"
690 "Router lifetime\n"
691 "Router lifetime in seconds\n")
692{
693 int lifetime;
694 struct interface *ifp;
695 struct zebra_if *zif;
696
697 ifp = (struct interface *) vty->index;
698 zif = ifp->info;
699
700 lifetime = atoi (argv[0]);
701
702 if (lifetime < 0 || lifetime > 0xffff)
703 {
704 vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
705 return CMD_WARNING;
706 }
707
708 zif->rtadv.AdvDefaultLifetime = lifetime;
709
710 return CMD_SUCCESS;
711}
712
713DEFUN (no_ipv6_nd_ra_lifetime,
714 no_ipv6_nd_ra_lifetime_cmd,
715 "no ipv6 nd ra-lifetime",
716 NO_STR
717 IP_STR
718 "Neighbor discovery\n"
719 "Router lifetime\n")
720{
721 struct interface *ifp;
722 struct zebra_if *zif;
723
724 ifp = (struct interface *) vty->index;
725 zif = ifp->info;
726
727 zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
728
729 return CMD_SUCCESS;
730}
731
732DEFUN (ipv6_nd_reachable_time,
733 ipv6_nd_reachable_time_cmd,
734 "ipv6 nd reachable-time MILLISECONDS",
735 IP_STR
736 "Neighbor discovery\n"
737 "Reachable time\n"
738 "Reachable time in milliseconds\n")
739{
740 u_int32_t rtime;
741 struct interface *ifp;
742 struct zebra_if *zif;
743
744 ifp = (struct interface *) vty->index;
745 zif = ifp->info;
746
747 rtime = (u_int32_t) atol (argv[0]);
748
749 if (rtime > RTADV_MAX_REACHABLE_TIME)
750 {
751 vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
752 return CMD_WARNING;
753 }
754
755 zif->rtadv.AdvReachableTime = rtime;
756
757 return CMD_SUCCESS;
758}
759
760DEFUN (no_ipv6_nd_reachable_time,
761 no_ipv6_nd_reachable_time_cmd,
762 "no ipv6 nd reachable-time",
763 NO_STR
764 IP_STR
765 "Neighbor discovery\n"
766 "Reachable time\n")
767{
768 struct interface *ifp;
769 struct zebra_if *zif;
770
771 ifp = (struct interface *) vty->index;
772 zif = ifp->info;
773
774 zif->rtadv.AdvReachableTime = 0;
775
776 return CMD_SUCCESS;
777}
778
779DEFUN (ipv6_nd_managed_config_flag,
780 ipv6_nd_managed_config_flag_cmd,
781 "ipv6 nd managed-config-flag",
782 IP_STR
783 "Neighbor discovery\n"
784 "Managed address configuration flag\n")
785{
786 struct interface *ifp;
787 struct zebra_if *zif;
788
789 ifp = (struct interface *) vty->index;
790 zif = ifp->info;
791
792 zif->rtadv.AdvManagedFlag = 1;
793
794 return CMD_SUCCESS;
795}
796
797DEFUN (no_ipv6_nd_managed_config_flag,
798 no_ipv6_nd_managed_config_flag_cmd,
799 "no ipv6 nd managed-config-flag",
800 NO_STR
801 IP_STR
802 "Neighbor discovery\n"
803 "Managed address configuration flag\n")
804{
805 struct interface *ifp;
806 struct zebra_if *zif;
807
808 ifp = (struct interface *) vty->index;
809 zif = ifp->info;
810
811 zif->rtadv.AdvManagedFlag = 0;
812
813 return CMD_SUCCESS;
814}
815
816DEFUN (ipv6_nd_other_config_flag,
817 ipv6_nd_other_config_flag_cmd,
818 "ipv6 nd other-config-flag",
819 IP_STR
820 "Neighbor discovery\n"
821 "Other statefull configuration flag\n")
822{
823 struct interface *ifp;
824 struct zebra_if *zif;
825
826 ifp = (struct interface *) vty->index;
827 zif = ifp->info;
828
829 zif->rtadv.AdvOtherConfigFlag = 1;
830
831 return CMD_SUCCESS;
832}
833
834DEFUN (no_ipv6_nd_other_config_flag,
835 no_ipv6_nd_other_config_flag_cmd,
836 "no ipv6 nd other-config-flag",
837 NO_STR
838 IP_STR
839 "Neighbor discovery\n"
840 "Other statefull configuration flag\n")
841{
842 struct interface *ifp;
843 struct zebra_if *zif;
844
845 ifp = (struct interface *) vty->index;
846 zif = ifp->info;
847
848 zif->rtadv.AdvOtherConfigFlag = 0;
849
850 return CMD_SUCCESS;
851}
852
853DEFUN (ipv6_nd_prefix_advertisement,
854 ipv6_nd_prefix_advertisement_cmd,
855 "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]",
856 IP_STR
857 "Neighbor discovery\n"
858 "Prefix information\n"
859 "IPv6 prefix\n"
860 "Valid lifetime in seconds\n"
861 "Preferred lifetime in seconds\n"
862 "On link flag\n"
863 "Autonomous address-configuration flag\n")
864{
865 int i;
866 int ret;
867 struct interface *ifp;
868 struct zebra_if *zebra_if;
869 struct rtadv_prefix rp;
870
871 ifp = (struct interface *) vty->index;
872 zebra_if = ifp->info;
873
874 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
875 if (!ret)
876 {
877 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
878 return CMD_WARNING;
879 }
880
881 if (argc == 1)
882 {
883 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
884 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
885 rp.AdvOnLinkFlag = 1;
886 rp.AdvAutonomousFlag = 1;
887 }
888 else
889 {
890 rp.AdvValidLifetime = (u_int32_t) atol (argv[1]);
891 rp.AdvPreferredLifetime = (u_int32_t) atol (argv[2]);
892 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
893 {
894 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
895 return CMD_WARNING;
896 }
897
898 rp.AdvOnLinkFlag = 0;
899 rp.AdvAutonomousFlag = 0;
900 for (i = 3; i < argc; i++)
901 {
902 if (! strcmp (argv[i], "onlink"))
903 rp.AdvOnLinkFlag = 1;
904 else if (! strcmp (argv[i], "autoconfig"))
905 rp.AdvAutonomousFlag = 1;
906 }
907 }
908
909 rtadv_prefix_set (zebra_if, &rp);
910
911 return CMD_SUCCESS;
912}
913
914ALIAS (ipv6_nd_prefix_advertisement,
915 ipv6_nd_prefix_advertisement_no_val_cmd,
916 "ipv6 nd prefix-advertisement IPV6PREFIX",
917 IP_STR
918 "Neighbor discovery\n"
919 "Prefix information\n"
920 "IPv6 prefix\n")
921
922DEFUN (no_ipv6_nd_prefix_advertisement,
923 no_ipv6_nd_prefix_advertisement_cmd,
924 "no ipv6 nd prefix-advertisement IPV6PREFIX",
925 NO_STR
926 IP_STR
927 "Neighbor discovery\n"
928 "Prefix information\n"
929 "IPv6 prefix\n")
930{
931 int ret;
932 struct interface *ifp;
933 struct zebra_if *zebra_if;
934 struct rtadv_prefix rp;
935
936 ifp = (struct interface *) vty->index;
937 zebra_if = ifp->info;
938
939 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
940 if (!ret)
941 {
942 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
943 return CMD_WARNING;
944 }
945
946 ret = rtadv_prefix_reset (zebra_if, &rp);
947 if (!ret)
948 {
949 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
950 return CMD_WARNING;
951 }
952
953 return CMD_SUCCESS;
954}
955
956/* Write configuration about router advertisement. */
957void
958rtadv_config_write (struct vty *vty, struct interface *ifp)
959{
960 struct zebra_if *zif;
961 listnode node;
962 struct rtadv_prefix *rprefix;
963 u_char buf[INET6_ADDRSTRLEN];
964
965 if (! rtadv)
966 return;
967
968 zif = ifp->info;
969
970 if (! if_is_loopback (ifp))
971 {
972 if (zif->rtadv.AdvSendAdvertisements)
973 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
974 else
975 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
976 }
977
978 if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL)
979 vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval,
980 VTY_NEWLINE);
981
982 if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
983 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
984 VTY_NEWLINE);
985
986 if (zif->rtadv.AdvReachableTime)
987 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
988 VTY_NEWLINE);
989
990 if (zif->rtadv.AdvManagedFlag)
991 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
992
993 if (zif->rtadv.AdvOtherConfigFlag)
994 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
995
996 for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node))
997 {
998 rprefix = getdata (node);
999 vty_out (vty, " ipv6 nd prefix-advertisement %s/%d %d %d",
1000 inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6,
1001 buf, INET6_ADDRSTRLEN),
1002 rprefix->prefix.prefixlen,
1003 rprefix->AdvValidLifetime,
1004 rprefix->AdvPreferredLifetime);
1005 if (rprefix->AdvOnLinkFlag)
1006 vty_out (vty, " onlink");
1007 if (rprefix->AdvAutonomousFlag)
1008 vty_out (vty, " autoconfig");
1009 vty_out (vty, "%s", VTY_NEWLINE);
1010 }
1011}
1012
paul718e3742002-12-13 20:15:29 +00001013
1014void
1015rtadv_event (enum rtadv_event event, int val)
1016{
1017 switch (event)
1018 {
1019 case RTADV_START:
1020 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001021 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001022 if (! rtadv->ra_timer)
paulb21b19c2003-06-15 01:28:29 +00001023 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer, NULL, 0);
paul718e3742002-12-13 20:15:29 +00001024 break;
1025 case RTADV_STOP:
1026 if (rtadv->ra_timer)
1027 {
1028 thread_cancel (rtadv->ra_timer);
1029 rtadv->ra_timer = NULL;
1030 }
1031 if (rtadv->ra_read)
1032 {
1033 thread_cancel (rtadv->ra_read);
1034 rtadv->ra_read = NULL;
1035 }
1036 break;
1037 case RTADV_TIMER:
1038 if (! rtadv->ra_timer)
paulb21b19c2003-06-15 01:28:29 +00001039 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL, val);
paul718e3742002-12-13 20:15:29 +00001040 break;
1041 case RTADV_READ:
1042 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001043 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001044 break;
1045 default:
1046 break;
1047 }
1048 return;
1049}
1050
1051void
1052rtadv_init ()
1053{
1054 int sock;
1055
1056 sock = rtadv_make_socket ();
1057 if (sock < 0)
1058 return;
1059
1060 rtadv = rtadv_new ();
1061 rtadv->sock = sock;
1062
1063 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1064 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
1065 install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd);
1066 install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd);
1067 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1068 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1069 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1070 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1071 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1072 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1073 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1074 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1075 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1076 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
1077 install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd);
1078 install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd);
1079 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd);
1080}
1081
1082int
1083if_join_all_router (int sock, struct interface *ifp)
1084{
1085 int ret;
1086
1087 struct ipv6_mreq mreq;
1088
1089 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1090 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1091 mreq.ipv6mr_interface = ifp->ifindex;
1092
1093 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1094 (char *) &mreq, sizeof mreq);
1095 if (ret < 0)
1096 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
1097
1098 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1099
1100 return 0;
1101}
1102
1103int
1104if_leave_all_router (int sock, struct interface *ifp)
1105{
1106 int ret;
1107
1108 struct ipv6_mreq mreq;
1109
1110 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1111 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1112 mreq.ipv6mr_interface = ifp->ifindex;
1113
1114 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1115 (char *) &mreq, sizeof mreq);
1116 if (ret < 0)
1117 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno));
1118
1119 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1120
1121 return 0;
1122}
1123
1124#else
1125void
1126rtadv_init ()
1127{
1128 /* Empty.*/;
1129}
1130#endif /* RTADV && HAVE_IPV6 */