]> git.proxmox.com Git - mirror_frr.git/blob - zebra/rtadv.c
8f4b37780a6dd22dc196e11ab5edee8316469082
[mirror_frr.git] / zebra / rtadv.c
1 /* 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"
32
33 #include "zebra/interface.h"
34 #include "zebra/rtadv.h"
35 #include "zebra/debug.h"
36
37 #if defined (HAVE_IPV6) && defined (RTADV)
38
39 /* If RFC2133 definition is used. */
40 #ifndef IPV6_JOIN_GROUP
41 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
42 #endif
43 #ifndef IPV6_LEAVE_GROUP
44 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
45 #endif
46
47 #define ALLNODE "ff02::1"
48 #define ALLROUTER "ff02::2"
49
50 enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ};
51
52 void rtadv_event (enum rtadv_event, int);
53
54 int if_join_all_router (int, struct interface *);
55 int if_leave_all_router (int, struct interface *);
56 \f
57 /* Structure which hold status of router advertisement. */
58 struct rtadv
59 {
60 int sock;
61
62 int adv_if_count;
63
64 struct thread *ra_read;
65 struct thread *ra_timer;
66 };
67
68 struct rtadv *rtadv = NULL;
69 \f
70 struct rtadv *
71 rtadv_new ()
72 {
73 struct rtadv *new;
74 new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
75 memset (new, 0, sizeof (struct rtadv));
76 return new;
77 }
78
79 void
80 rtadv_free (struct rtadv *rtadv)
81 {
82 XFREE (MTYPE_TMP, rtadv);
83 }
84
85 int
86 rtadv_recv_packet (int sock, u_char *buf, int buflen,
87 struct sockaddr_in6 *from, unsigned int *ifindex,
88 int *hoplimit)
89 {
90 int ret;
91 struct msghdr msg;
92 struct iovec iov;
93 struct cmsghdr *cmsgptr;
94 struct in6_addr dst;
95
96 char adata[1024];
97
98 /* Fill in message and iovec. */
99 msg.msg_name = (void *) from;
100 msg.msg_namelen = sizeof (struct sockaddr_in6);
101 msg.msg_iov = &iov;
102 msg.msg_iovlen = 1;
103 msg.msg_control = (void *) adata;
104 msg.msg_controllen = sizeof adata;
105 iov.iov_base = buf;
106 iov.iov_len = buflen;
107
108 /* If recvmsg fail return minus value. */
109 ret = recvmsg (sock, &msg, 0);
110 if (ret < 0)
111 return ret;
112
113 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
114 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
115 {
116 /* I want interface index which this packet comes from. */
117 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
118 cmsgptr->cmsg_type == IPV6_PKTINFO)
119 {
120 struct in6_pktinfo *ptr;
121
122 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
123 *ifindex = ptr->ipi6_ifindex;
124 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
125 }
126
127 /* Incoming packet's hop limit. */
128 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
129 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
130 *hoplimit = *((int *) CMSG_DATA (cmsgptr));
131 }
132 return ret;
133 }
134
135 #define RTADV_MSG_SIZE 4096
136
137 /* Send router advertisement packet. */
138 void
139 rtadv_send_packet (int sock, struct interface *ifp)
140 {
141 struct msghdr msg;
142 struct iovec iov;
143 struct cmsghdr *cmsgptr;
144 struct in6_pktinfo *pkt;
145 struct sockaddr_in6 addr;
146 #if HAVE_SOCKADDR_DL
147 struct sockaddr_dl *sdl;
148 #endif /* HAVE_SOCKADDR_DL */
149 char adata [sizeof (struct cmsghdr) + sizeof (struct in6_pktinfo)];
150 unsigned char buf[RTADV_MSG_SIZE];
151 struct nd_router_advert *rtadv;
152 int ret;
153 int len = 0;
154 struct zebra_if *zif;
155 u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
156 listnode node;
157
158 /* Logging of packet. */
159 if (IS_ZEBRA_DEBUG_PACKET)
160 zlog_info ("Router advertisement send to %s", ifp->name);
161
162 /* Fill in sockaddr_in6. */
163 memset (&addr, 0, sizeof (struct sockaddr_in6));
164 addr.sin6_family = AF_INET6;
165 #ifdef SIN6_LEN
166 addr.sin6_len = sizeof (struct sockaddr_in6);
167 #endif /* SIN6_LEN */
168 addr.sin6_port = htons (IPPROTO_ICMPV6);
169 memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
170
171 /* Fetch interface information. */
172 zif = ifp->info;
173
174 /* Make router advertisement message. */
175 rtadv = (struct nd_router_advert *) buf;
176
177 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
178 rtadv->nd_ra_code = 0;
179 rtadv->nd_ra_cksum = 0;
180
181 rtadv->nd_ra_curhoplimit = 64;
182 rtadv->nd_ra_flags_reserved = 0;
183 if (zif->rtadv.AdvManagedFlag)
184 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
185 if (zif->rtadv.AdvOtherConfigFlag)
186 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
187 rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
188 rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
189 rtadv->nd_ra_retransmit = htonl (0);
190
191 len = sizeof (struct nd_router_advert);
192
193 /* Fill in prefix. */
194 for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node))
195 {
196 struct nd_opt_prefix_info *pinfo;
197 struct rtadv_prefix *rprefix;
198
199 rprefix = getdata (node);
200
201 pinfo = (struct nd_opt_prefix_info *) (buf + len);
202
203 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
204 pinfo->nd_opt_pi_len = 4;
205 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
206
207 pinfo->nd_opt_pi_flags_reserved = 0;
208 if (rprefix->AdvOnLinkFlag)
209 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
210 if (rprefix->AdvAutonomousFlag)
211 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
212
213 pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
214 pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
215 pinfo->nd_opt_pi_reserved2 = 0;
216
217 memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
218 sizeof (struct in6_addr));
219
220 #ifdef DEBUG
221 {
222 u_char buf[INET6_ADDRSTRLEN];
223
224 zlog_info ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, buf, INET6_ADDRSTRLEN));
225
226 }
227 #endif /* DEBUG */
228
229 len += sizeof (struct nd_opt_prefix_info);
230 }
231
232 /* Hardware address. */
233 #ifdef HAVE_SOCKADDR_DL
234 sdl = &ifp->sdl;
235 if (sdl != NULL && sdl->sdl_alen != 0)
236 {
237 buf[len++] = ND_OPT_SOURCE_LINKADDR;
238 buf[len++] = (sdl->sdl_alen + 2) >> 3;
239
240 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
241 len += sdl->sdl_alen;
242 }
243 #else
244 if (ifp->hw_addr_len != 0)
245 {
246 buf[len++] = ND_OPT_SOURCE_LINKADDR;
247 buf[len++] = (ifp->hw_addr_len + 2) >> 3;
248
249 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
250 len += ifp->hw_addr_len;
251 }
252 #endif /* HAVE_SOCKADDR_DL */
253
254 msg.msg_name = (void *) &addr;
255 msg.msg_namelen = sizeof (struct sockaddr_in6);
256 msg.msg_iov = &iov;
257 msg.msg_iovlen = 1;
258 msg.msg_control = (void *) adata;
259 msg.msg_controllen = sizeof adata;
260 iov.iov_base = buf;
261 iov.iov_len = len;
262
263 cmsgptr = (struct cmsghdr *)adata;
264 cmsgptr->cmsg_len = sizeof adata;
265 cmsgptr->cmsg_level = IPPROTO_IPV6;
266 cmsgptr->cmsg_type = IPV6_PKTINFO;
267 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
268 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
269 pkt->ipi6_ifindex = ifp->ifindex;
270
271 ret = sendmsg (sock, &msg, 0);
272 if (ret <0)
273 perror ("sendmsg");
274 }
275
276 int
277 rtadv_timer (struct thread *thread)
278 {
279 listnode node;
280 struct interface *ifp;
281 struct zebra_if *zif;
282
283 rtadv->ra_timer = NULL;
284 rtadv_event (RTADV_TIMER, 1);
285
286 for (node = listhead (iflist); node; nextnode (node))
287 {
288 ifp = getdata (node);
289
290 if (if_is_loopback (ifp))
291 continue;
292
293 zif = ifp->info;
294
295 if (zif->rtadv.AdvSendAdvertisements)
296 if (--zif->rtadv.AdvIntervalTimer <= 0)
297 {
298 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
299 rtadv_send_packet (rtadv->sock, ifp);
300 }
301 }
302 return 0;
303 }
304
305 void
306 rtadv_process_solicit (struct interface *ifp)
307 {
308 zlog_info ("Router solicitation received on %s", ifp->name);
309
310 rtadv_send_packet (rtadv->sock, ifp);
311 }
312
313 void
314 rtadv_process_advert ()
315 {
316 zlog_info ("Router advertisement received");
317 }
318
319 void
320 rtadv_process_packet (u_char *buf, int len, unsigned int ifindex, int hoplimit)
321 {
322 struct icmp6_hdr *icmph;
323 struct interface *ifp;
324 struct zebra_if *zif;
325
326 /* Interface search. */
327 ifp = if_lookup_by_index (ifindex);
328 if (ifp == NULL)
329 {
330 zlog_warn ("Unknown interface index: %d", ifindex);
331 return;
332 }
333
334 if (if_is_loopback (ifp))
335 return;
336
337 /* Check interface configuration. */
338 zif = ifp->info;
339 if (! zif->rtadv.AdvSendAdvertisements)
340 return;
341
342 /* ICMP message length check. */
343 if (len < sizeof (struct icmp6_hdr))
344 {
345 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
346 return;
347 }
348
349 icmph = (struct icmp6_hdr *) buf;
350
351 /* ICMP message type check. */
352 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
353 icmph->icmp6_type != ND_ROUTER_ADVERT)
354 {
355 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
356 return;
357 }
358
359 /* Hoplimit check. */
360 if (hoplimit >= 0 && hoplimit != 255)
361 {
362 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
363 hoplimit);
364 return;
365 }
366
367 /* Check ICMP message type. */
368 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
369 rtadv_process_solicit (ifp);
370 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
371 rtadv_process_advert ();
372
373 return;
374 }
375
376 int
377 rtadv_read (struct thread *thread)
378 {
379 int sock;
380 int len;
381 u_char buf[RTADV_MSG_SIZE];
382 struct sockaddr_in6 from;
383 unsigned int ifindex;
384 int hoplimit = -1;
385
386 sock = THREAD_FD (thread);
387 rtadv->ra_read = NULL;
388
389 /* Register myself. */
390 rtadv_event (RTADV_READ, sock);
391
392 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
393
394 if (len < 0)
395 {
396 zlog_warn ("router solicitation recv failed: %s.", strerror (errno));
397 return len;
398 }
399
400 rtadv_process_packet (buf, len, ifindex, hoplimit);
401
402 return 0;
403 }
404
405 int
406 rtadv_make_socket (void)
407 {
408 int sock;
409 int ret;
410 struct icmp6_filter filter;
411
412 sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
413
414 /* When we can't make ICMPV6 socket simply back. Router
415 advertisement feature will not be supported. */
416 if (sock < 0)
417 return -1;
418
419 ret = setsockopt_ipv6_pktinfo (sock, 1);
420 if (ret < 0)
421 return ret;
422 ret = setsockopt_ipv6_checksum (sock, 2);
423 if (ret < 0)
424 return ret;
425 ret = setsockopt_ipv6_multicast_loop (sock, 0);
426 if (ret < 0)
427 return ret;
428 ret = setsockopt_ipv6_unicast_hops (sock, 255);
429 if (ret < 0)
430 return ret;
431 ret = setsockopt_ipv6_multicast_hops (sock, 255);
432 if (ret < 0)
433 return ret;
434 ret = setsockopt_ipv6_hoplimit (sock, 1);
435 if (ret < 0)
436 return ret;
437
438 ICMP6_FILTER_SETBLOCKALL(&filter);
439 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
440 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
441
442 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
443 sizeof (struct icmp6_filter));
444 if (ret < 0)
445 {
446 zlog_info ("ICMP6_FILTER set fail: %s", strerror (errno));
447 return ret;
448 }
449
450 return sock;
451 }
452 \f
453 struct rtadv_prefix *
454 rtadv_prefix_new ()
455 {
456 struct rtadv_prefix *new;
457
458 new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
459 memset (new, 0, sizeof (struct rtadv_prefix));
460
461 return new;
462 }
463
464 void
465 rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
466 {
467 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
468 }
469
470 struct rtadv_prefix *
471 rtadv_prefix_lookup (list rplist, struct prefix *p)
472 {
473 listnode node;
474 struct rtadv_prefix *rprefix;
475
476 for (node = listhead (rplist); node; node = nextnode (node))
477 {
478 rprefix = getdata (node);
479 if (prefix_same (&rprefix->prefix, p))
480 return rprefix;
481 }
482 return NULL;
483 }
484
485 struct rtadv_prefix *
486 rtadv_prefix_get (list rplist, struct prefix *p)
487 {
488 struct rtadv_prefix *rprefix;
489
490 rprefix = rtadv_prefix_lookup (rplist, p);
491 if (rprefix)
492 return rprefix;
493
494 rprefix = rtadv_prefix_new ();
495 memcpy (&rprefix->prefix, p, sizeof (struct prefix));
496 listnode_add (rplist, rprefix);
497
498 return rprefix;
499 }
500
501 void
502 rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
503 {
504 struct rtadv_prefix *rprefix;
505
506 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
507
508 /* Set parameters. */
509 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
510 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
511 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
512 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
513 }
514
515 int
516 rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
517 {
518 struct rtadv_prefix *rprefix;
519
520 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
521 if (rprefix != NULL)
522 {
523 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
524 rtadv_prefix_free (rprefix);
525 return 1;
526 }
527 else
528 return 0;
529 }
530
531 DEFUN (ipv6_nd_suppress_ra,
532 ipv6_nd_suppress_ra_cmd,
533 "ipv6 nd suppress-ra",
534 IP_STR
535 "Neighbor discovery\n"
536 "Suppress Router Advertisement\n")
537 {
538 struct interface *ifp;
539 struct zebra_if *zif;
540
541 ifp = vty->index;
542 zif = ifp->info;
543
544 if (if_is_loopback (ifp))
545 {
546 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
547 return CMD_WARNING;
548 }
549
550 if (zif->rtadv.AdvSendAdvertisements)
551 {
552 zif->rtadv.AdvSendAdvertisements = 0;
553 zif->rtadv.AdvIntervalTimer = 0;
554 rtadv->adv_if_count--;
555
556 if_leave_all_router (rtadv->sock, ifp);
557
558 if (rtadv->adv_if_count == 0)
559 rtadv_event (RTADV_STOP, 0);
560 }
561
562 return CMD_SUCCESS;
563 }
564
565 ALIAS (ipv6_nd_suppress_ra,
566 no_ipv6_nd_send_ra_cmd,
567 "no ipv6 nd send-ra",
568 NO_STR
569 IP_STR
570 "Neighbor discovery\n"
571 "Send Router Advertisement\n")
572
573 DEFUN (no_ipv6_nd_suppress_ra,
574 no_ipv6_nd_suppress_ra_cmd,
575 "no ipv6 nd suppress-ra",
576 NO_STR
577 IP_STR
578 "Neighbor discovery\n"
579 "Suppress Router Advertisement\n")
580 {
581 struct interface *ifp;
582 struct zebra_if *zif;
583
584 ifp = vty->index;
585 zif = ifp->info;
586
587 if (if_is_loopback (ifp))
588 {
589 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
590 return CMD_WARNING;
591 }
592
593 if (! zif->rtadv.AdvSendAdvertisements)
594 {
595 zif->rtadv.AdvSendAdvertisements = 1;
596 zif->rtadv.AdvIntervalTimer = 0;
597 rtadv->adv_if_count++;
598
599 if_join_all_router (rtadv->sock, ifp);
600
601 if (rtadv->adv_if_count == 1)
602 rtadv_event (RTADV_START, rtadv->sock);
603 }
604
605 return CMD_SUCCESS;
606 }
607
608 ALIAS (no_ipv6_nd_suppress_ra,
609 ipv6_nd_send_ra_cmd,
610 "ipv6 nd send-ra",
611 IP_STR
612 "Neighbor discovery\n"
613 "Send Router Advertisement\n")
614
615 DEFUN (ipv6_nd_ra_interval,
616 ipv6_nd_ra_interval_cmd,
617 "ipv6 nd ra-interval SECONDS",
618 IP_STR
619 "Neighbor discovery\n"
620 "Router Advertisement interval\n"
621 "Router Advertisement interval in seconds\n")
622 {
623 int interval;
624 struct interface *ifp;
625 struct zebra_if *zif;
626
627 ifp = (struct interface *) vty->index;
628 zif = ifp->info;
629
630 interval = atoi (argv[0]);
631
632 if (interval < 0)
633 {
634 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
635 return CMD_WARNING;
636 }
637
638 zif->rtadv.MaxRtrAdvInterval = interval;
639 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
640 zif->rtadv.AdvIntervalTimer = 0;
641
642 return CMD_SUCCESS;
643 }
644
645 DEFUN (no_ipv6_nd_ra_interval,
646 no_ipv6_nd_ra_interval_cmd,
647 "no ipv6 nd ra-interval",
648 NO_STR
649 IP_STR
650 "Neighbor discovery\n"
651 "Router Advertisement interval\n")
652 {
653 struct interface *ifp;
654 struct zebra_if *zif;
655
656 ifp = (struct interface *) vty->index;
657 zif = ifp->info;
658
659 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
660 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
661 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
662
663 return CMD_SUCCESS;
664 }
665
666 DEFUN (ipv6_nd_ra_lifetime,
667 ipv6_nd_ra_lifetime_cmd,
668 "ipv6 nd ra-lifetime SECONDS",
669 IP_STR
670 "Neighbor discovery\n"
671 "Router lifetime\n"
672 "Router lifetime in seconds\n")
673 {
674 int lifetime;
675 struct interface *ifp;
676 struct zebra_if *zif;
677
678 ifp = (struct interface *) vty->index;
679 zif = ifp->info;
680
681 lifetime = atoi (argv[0]);
682
683 if (lifetime < 0 || lifetime > 0xffff)
684 {
685 vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
686 return CMD_WARNING;
687 }
688
689 zif->rtadv.AdvDefaultLifetime = lifetime;
690
691 return CMD_SUCCESS;
692 }
693
694 DEFUN (no_ipv6_nd_ra_lifetime,
695 no_ipv6_nd_ra_lifetime_cmd,
696 "no ipv6 nd ra-lifetime",
697 NO_STR
698 IP_STR
699 "Neighbor discovery\n"
700 "Router lifetime\n")
701 {
702 struct interface *ifp;
703 struct zebra_if *zif;
704
705 ifp = (struct interface *) vty->index;
706 zif = ifp->info;
707
708 zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
709
710 return CMD_SUCCESS;
711 }
712
713 DEFUN (ipv6_nd_reachable_time,
714 ipv6_nd_reachable_time_cmd,
715 "ipv6 nd reachable-time MILLISECONDS",
716 IP_STR
717 "Neighbor discovery\n"
718 "Reachable time\n"
719 "Reachable time in milliseconds\n")
720 {
721 u_int32_t rtime;
722 struct interface *ifp;
723 struct zebra_if *zif;
724
725 ifp = (struct interface *) vty->index;
726 zif = ifp->info;
727
728 rtime = (u_int32_t) atol (argv[0]);
729
730 if (rtime > RTADV_MAX_REACHABLE_TIME)
731 {
732 vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
733 return CMD_WARNING;
734 }
735
736 zif->rtadv.AdvReachableTime = rtime;
737
738 return CMD_SUCCESS;
739 }
740
741 DEFUN (no_ipv6_nd_reachable_time,
742 no_ipv6_nd_reachable_time_cmd,
743 "no ipv6 nd reachable-time",
744 NO_STR
745 IP_STR
746 "Neighbor discovery\n"
747 "Reachable time\n")
748 {
749 struct interface *ifp;
750 struct zebra_if *zif;
751
752 ifp = (struct interface *) vty->index;
753 zif = ifp->info;
754
755 zif->rtadv.AdvReachableTime = 0;
756
757 return CMD_SUCCESS;
758 }
759
760 DEFUN (ipv6_nd_managed_config_flag,
761 ipv6_nd_managed_config_flag_cmd,
762 "ipv6 nd managed-config-flag",
763 IP_STR
764 "Neighbor discovery\n"
765 "Managed address configuration flag\n")
766 {
767 struct interface *ifp;
768 struct zebra_if *zif;
769
770 ifp = (struct interface *) vty->index;
771 zif = ifp->info;
772
773 zif->rtadv.AdvManagedFlag = 1;
774
775 return CMD_SUCCESS;
776 }
777
778 DEFUN (no_ipv6_nd_managed_config_flag,
779 no_ipv6_nd_managed_config_flag_cmd,
780 "no ipv6 nd managed-config-flag",
781 NO_STR
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 = 0;
793
794 return CMD_SUCCESS;
795 }
796
797 DEFUN (ipv6_nd_other_config_flag,
798 ipv6_nd_other_config_flag_cmd,
799 "ipv6 nd other-config-flag",
800 IP_STR
801 "Neighbor discovery\n"
802 "Other statefull configuration flag\n")
803 {
804 struct interface *ifp;
805 struct zebra_if *zif;
806
807 ifp = (struct interface *) vty->index;
808 zif = ifp->info;
809
810 zif->rtadv.AdvOtherConfigFlag = 1;
811
812 return CMD_SUCCESS;
813 }
814
815 DEFUN (no_ipv6_nd_other_config_flag,
816 no_ipv6_nd_other_config_flag_cmd,
817 "no ipv6 nd other-config-flag",
818 NO_STR
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 = 0;
830
831 return CMD_SUCCESS;
832 }
833
834 DEFUN (ipv6_nd_prefix_advertisement,
835 ipv6_nd_prefix_advertisement_cmd,
836 "ipv6 nd prefix-advertisement IPV6PREFIX VALID PREFERRED [onlink] [autoconfig]",
837 IP_STR
838 "Neighbor discovery\n"
839 "Prefix information\n"
840 "IPv6 prefix\n"
841 "Valid lifetime in seconds\n"
842 "Preferred lifetime in seconds\n"
843 "On link flag\n"
844 "Autonomous address-configuration flag\n")
845 {
846 int i;
847 int ret;
848 struct interface *ifp;
849 struct zebra_if *zebra_if;
850 struct rtadv_prefix rp;
851
852 ifp = (struct interface *) vty->index;
853 zebra_if = ifp->info;
854
855 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
856 if (!ret)
857 {
858 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
859 return CMD_WARNING;
860 }
861
862 if (argc == 1)
863 {
864 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
865 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
866 rp.AdvOnLinkFlag = 1;
867 rp.AdvAutonomousFlag = 1;
868 }
869 else
870 {
871 rp.AdvValidLifetime = (u_int32_t) atol (argv[1]);
872 rp.AdvPreferredLifetime = (u_int32_t) atol (argv[2]);
873 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
874 {
875 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
876 return CMD_WARNING;
877 }
878
879 rp.AdvOnLinkFlag = 0;
880 rp.AdvAutonomousFlag = 0;
881 for (i = 3; i < argc; i++)
882 {
883 if (! strcmp (argv[i], "onlink"))
884 rp.AdvOnLinkFlag = 1;
885 else if (! strcmp (argv[i], "autoconfig"))
886 rp.AdvAutonomousFlag = 1;
887 }
888 }
889
890 rtadv_prefix_set (zebra_if, &rp);
891
892 return CMD_SUCCESS;
893 }
894
895 ALIAS (ipv6_nd_prefix_advertisement,
896 ipv6_nd_prefix_advertisement_no_val_cmd,
897 "ipv6 nd prefix-advertisement IPV6PREFIX",
898 IP_STR
899 "Neighbor discovery\n"
900 "Prefix information\n"
901 "IPv6 prefix\n")
902
903 DEFUN (no_ipv6_nd_prefix_advertisement,
904 no_ipv6_nd_prefix_advertisement_cmd,
905 "no ipv6 nd prefix-advertisement IPV6PREFIX",
906 NO_STR
907 IP_STR
908 "Neighbor discovery\n"
909 "Prefix information\n"
910 "IPv6 prefix\n")
911 {
912 int ret;
913 struct interface *ifp;
914 struct zebra_if *zebra_if;
915 struct rtadv_prefix rp;
916
917 ifp = (struct interface *) vty->index;
918 zebra_if = ifp->info;
919
920 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
921 if (!ret)
922 {
923 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
924 return CMD_WARNING;
925 }
926
927 ret = rtadv_prefix_reset (zebra_if, &rp);
928 if (!ret)
929 {
930 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
931 return CMD_WARNING;
932 }
933
934 return CMD_SUCCESS;
935 }
936
937 /* Write configuration about router advertisement. */
938 void
939 rtadv_config_write (struct vty *vty, struct interface *ifp)
940 {
941 struct zebra_if *zif;
942 listnode node;
943 struct rtadv_prefix *rprefix;
944 u_char buf[INET6_ADDRSTRLEN];
945
946 if (! rtadv)
947 return;
948
949 zif = ifp->info;
950
951 if (! if_is_loopback (ifp))
952 {
953 if (zif->rtadv.AdvSendAdvertisements)
954 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
955 else
956 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
957 }
958
959 if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL)
960 vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval,
961 VTY_NEWLINE);
962
963 if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
964 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
965 VTY_NEWLINE);
966
967 if (zif->rtadv.AdvReachableTime)
968 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
969 VTY_NEWLINE);
970
971 if (zif->rtadv.AdvManagedFlag)
972 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
973
974 if (zif->rtadv.AdvOtherConfigFlag)
975 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
976
977 for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node))
978 {
979 rprefix = getdata (node);
980 vty_out (vty, " ipv6 nd prefix-advertisement %s/%d %d %d",
981 inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6,
982 buf, INET6_ADDRSTRLEN),
983 rprefix->prefix.prefixlen,
984 rprefix->AdvValidLifetime,
985 rprefix->AdvPreferredLifetime);
986 if (rprefix->AdvOnLinkFlag)
987 vty_out (vty, " onlink");
988 if (rprefix->AdvAutonomousFlag)
989 vty_out (vty, " autoconfig");
990 vty_out (vty, "%s", VTY_NEWLINE);
991 }
992 }
993
994 extern struct thread_master *master;
995
996 void
997 rtadv_event (enum rtadv_event event, int val)
998 {
999 switch (event)
1000 {
1001 case RTADV_START:
1002 if (! rtadv->ra_read)
1003 rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val);
1004 if (! rtadv->ra_timer)
1005 rtadv->ra_timer = thread_add_event (master, rtadv_timer, NULL, 0);
1006 break;
1007 case RTADV_STOP:
1008 if (rtadv->ra_timer)
1009 {
1010 thread_cancel (rtadv->ra_timer);
1011 rtadv->ra_timer = NULL;
1012 }
1013 if (rtadv->ra_read)
1014 {
1015 thread_cancel (rtadv->ra_read);
1016 rtadv->ra_read = NULL;
1017 }
1018 break;
1019 case RTADV_TIMER:
1020 if (! rtadv->ra_timer)
1021 rtadv->ra_timer = thread_add_timer (master, rtadv_timer, NULL, val);
1022 break;
1023 case RTADV_READ:
1024 if (! rtadv->ra_read)
1025 rtadv->ra_read = thread_add_read (master, rtadv_read, NULL, val);
1026 break;
1027 default:
1028 break;
1029 }
1030 return;
1031 }
1032
1033 void
1034 rtadv_init ()
1035 {
1036 int sock;
1037
1038 sock = rtadv_make_socket ();
1039 if (sock < 0)
1040 return;
1041
1042 rtadv = rtadv_new ();
1043 rtadv->sock = sock;
1044
1045 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1046 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
1047 install_element (INTERFACE_NODE, &ipv6_nd_send_ra_cmd);
1048 install_element (INTERFACE_NODE, &no_ipv6_nd_send_ra_cmd);
1049 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1050 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1051 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1052 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1053 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1054 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1055 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1056 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1057 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1058 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
1059 install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_cmd);
1060 install_element (INTERFACE_NODE, &ipv6_nd_prefix_advertisement_no_val_cmd);
1061 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_advertisement_cmd);
1062 }
1063
1064 int
1065 if_join_all_router (int sock, struct interface *ifp)
1066 {
1067 int ret;
1068
1069 struct ipv6_mreq mreq;
1070
1071 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1072 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1073 mreq.ipv6mr_interface = ifp->ifindex;
1074
1075 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1076 (char *) &mreq, sizeof mreq);
1077 if (ret < 0)
1078 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
1079
1080 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1081
1082 return 0;
1083 }
1084
1085 int
1086 if_leave_all_router (int sock, struct interface *ifp)
1087 {
1088 int ret;
1089
1090 struct ipv6_mreq mreq;
1091
1092 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1093 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1094 mreq.ipv6mr_interface = ifp->ifindex;
1095
1096 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1097 (char *) &mreq, sizeof mreq);
1098 if (ret < 0)
1099 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", strerror (errno));
1100
1101 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1102
1103 return 0;
1104 }
1105
1106 #else
1107 void
1108 rtadv_init ()
1109 {
1110 /* Empty.*/;
1111 }
1112 #endif /* RTADV && HAVE_IPV6 */