blob: 725965630d1f74d939abf489e5b5db8646e78d7e [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Router advertisement
vincent7cee1bb2005-03-25 13:08:53 +00002 * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com>
paul718e3742002-12-13 20:15:29 +00003 * Copyright (C) 1999 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "memory.h"
26#include "sockopt.h"
27#include "thread.h"
28#include "if.h"
29#include "log.h"
30#include "prefix.h"
31#include "linklist.h"
32#include "command.h"
pauledd7c242003-06-04 13:59:38 +000033#include "privs.h"
paul718e3742002-12-13 20:15:29 +000034
35#include "zebra/interface.h"
36#include "zebra/rtadv.h"
37#include "zebra/debug.h"
paul537d8ea2003-08-27 06:45:32 +000038#include "zebra/rib.h"
gdt4b5e1352003-12-03 17:54:34 +000039#include "zebra/zserv.h"
paul718e3742002-12-13 20:15:29 +000040
pauledd7c242003-06-04 13:59:38 +000041extern struct zebra_privs_t zserv_privs;
42
paul718e3742002-12-13 20:15:29 +000043#if defined (HAVE_IPV6) && defined (RTADV)
44
hassofa2b17e2004-03-04 17:45:00 +000045#ifdef OPEN_BSD
46#include <netinet/icmp6.h>
47#endif
48
paul718e3742002-12-13 20:15:29 +000049/* If RFC2133 definition is used. */
50#ifndef IPV6_JOIN_GROUP
51#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
52#endif
53#ifndef IPV6_LEAVE_GROUP
54#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
55#endif
56
57#define ALLNODE "ff02::1"
58#define ALLROUTER "ff02::2"
59
paulb21b19c2003-06-15 01:28:29 +000060extern struct zebra_t zebrad;
61
vincent7cee1bb2005-03-25 13:08:53 +000062enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER,
63 RTADV_TIMER_MSEC, RTADV_READ};
paul718e3742002-12-13 20:15:29 +000064
65void rtadv_event (enum rtadv_event, int);
66
67int if_join_all_router (int, struct interface *);
68int if_leave_all_router (int, struct interface *);
69
70/* Structure which hold status of router advertisement. */
71struct rtadv
72{
73 int sock;
74
75 int adv_if_count;
vincent7cee1bb2005-03-25 13:08:53 +000076 int adv_msec_if_count;
paul718e3742002-12-13 20:15:29 +000077
78 struct thread *ra_read;
79 struct thread *ra_timer;
80};
81
82struct rtadv *rtadv = NULL;
83
84struct rtadv *
85rtadv_new ()
86{
87 struct rtadv *new;
88 new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
89 memset (new, 0, sizeof (struct rtadv));
90 return new;
91}
92
93void
94rtadv_free (struct rtadv *rtadv)
95{
96 XFREE (MTYPE_TMP, rtadv);
97}
98
99int
100rtadv_recv_packet (int sock, u_char *buf, int buflen,
101 struct sockaddr_in6 *from, unsigned int *ifindex,
102 int *hoplimit)
103{
104 int ret;
105 struct msghdr msg;
106 struct iovec iov;
107 struct cmsghdr *cmsgptr;
108 struct in6_addr dst;
109
110 char adata[1024];
111
112 /* Fill in message and iovec. */
113 msg.msg_name = (void *) from;
114 msg.msg_namelen = sizeof (struct sockaddr_in6);
115 msg.msg_iov = &iov;
116 msg.msg_iovlen = 1;
117 msg.msg_control = (void *) adata;
118 msg.msg_controllen = sizeof adata;
119 iov.iov_base = buf;
120 iov.iov_len = buflen;
121
122 /* If recvmsg fail return minus value. */
123 ret = recvmsg (sock, &msg, 0);
124 if (ret < 0)
125 return ret;
126
ajsb99760a2005-01-04 16:24:43 +0000127 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000128 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
129 {
130 /* I want interface index which this packet comes from. */
131 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
132 cmsgptr->cmsg_type == IPV6_PKTINFO)
133 {
134 struct in6_pktinfo *ptr;
135
136 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
137 *ifindex = ptr->ipi6_ifindex;
138 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
139 }
140
141 /* Incoming packet's hop limit. */
142 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
143 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
144 *hoplimit = *((int *) CMSG_DATA (cmsgptr));
145 }
146 return ret;
147}
148
149#define RTADV_MSG_SIZE 4096
150
151/* Send router advertisement packet. */
152void
153rtadv_send_packet (int sock, struct interface *ifp)
154{
155 struct msghdr msg;
156 struct iovec iov;
157 struct cmsghdr *cmsgptr;
158 struct in6_pktinfo *pkt;
159 struct sockaddr_in6 addr;
pauledd7c242003-06-04 13:59:38 +0000160#ifdef HAVE_SOCKADDR_DL
paul718e3742002-12-13 20:15:29 +0000161 struct sockaddr_dl *sdl;
162#endif /* HAVE_SOCKADDR_DL */
gdt57492d52004-08-11 18:06:38 +0000163 static void *adata = NULL;
paul718e3742002-12-13 20:15:29 +0000164 unsigned char buf[RTADV_MSG_SIZE];
165 struct nd_router_advert *rtadv;
166 int ret;
167 int len = 0;
168 struct zebra_if *zif;
169 u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
hasso52dc7ee2004-09-23 19:18:23 +0000170 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000171
gdt57492d52004-08-11 18:06:38 +0000172 /*
173 * Allocate control message bufffer. This is dynamic because
174 * CMSG_SPACE is not guaranteed not to call a function. Note that
175 * the size will be different on different architectures due to
176 * differing alignment rules.
177 */
178 if (adata == NULL)
179 {
180 /* XXX Free on shutdown. */
181 adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)));
182
183 if (adata == NULL)
184 zlog_err("rtadv_send_packet: can't malloc control data\n");
185 }
186
paul718e3742002-12-13 20:15:29 +0000187 /* Logging of packet. */
188 if (IS_ZEBRA_DEBUG_PACKET)
ajsb6178002004-12-07 21:12:56 +0000189 zlog_debug ("Router advertisement send to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +0000190
191 /* Fill in sockaddr_in6. */
192 memset (&addr, 0, sizeof (struct sockaddr_in6));
193 addr.sin6_family = AF_INET6;
194#ifdef SIN6_LEN
195 addr.sin6_len = sizeof (struct sockaddr_in6);
196#endif /* SIN6_LEN */
197 addr.sin6_port = htons (IPPROTO_ICMPV6);
198 memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
199
200 /* Fetch interface information. */
201 zif = ifp->info;
202
203 /* Make router advertisement message. */
204 rtadv = (struct nd_router_advert *) buf;
205
206 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
207 rtadv->nd_ra_code = 0;
208 rtadv->nd_ra_cksum = 0;
209
210 rtadv->nd_ra_curhoplimit = 64;
211 rtadv->nd_ra_flags_reserved = 0;
212 if (zif->rtadv.AdvManagedFlag)
213 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
214 if (zif->rtadv.AdvOtherConfigFlag)
215 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
vincent7cee1bb2005-03-25 13:08:53 +0000216 if (zif->rtadv.AdvHomeAgentFlag)
217 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
paul718e3742002-12-13 20:15:29 +0000218 rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
219 rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
220 rtadv->nd_ra_retransmit = htonl (0);
221
222 len = sizeof (struct nd_router_advert);
223
vincent7cee1bb2005-03-25 13:08:53 +0000224 if (zif->rtadv.AdvHomeAgentFlag)
225 {
226 struct nd_opt_homeagent_info *ndopt_hai =
227 (struct nd_opt_homeagent_info *)(buf + len);
228 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
229 ndopt_hai->nd_opt_hai_len = 1;
230 ndopt_hai->nd_opt_hai_reserved = 0;
231 ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference);
232 ndopt_hai->nd_opt_hai_lifetime = htons(zif->rtadv.HomeAgentLifetime);
233 len += sizeof(struct nd_opt_homeagent_info);
234 }
235
236 if (zif->rtadv.AdvIntervalOption)
237 {
238 struct nd_opt_adv_interval *ndopt_adv =
239 (struct nd_opt_adv_interval *)(buf + len);
240 ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
241 ndopt_adv->nd_opt_ai_len = 1;
242 ndopt_adv->nd_opt_ai_reserved = 0;
243 ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval);
244 len += sizeof(struct nd_opt_adv_interval);
245 }
246
paul718e3742002-12-13 20:15:29 +0000247 /* Fill in prefix. */
248 for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node))
249 {
250 struct nd_opt_prefix_info *pinfo;
251 struct rtadv_prefix *rprefix;
252
253 rprefix = getdata (node);
254
255 pinfo = (struct nd_opt_prefix_info *) (buf + len);
256
257 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
258 pinfo->nd_opt_pi_len = 4;
259 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
260
261 pinfo->nd_opt_pi_flags_reserved = 0;
262 if (rprefix->AdvOnLinkFlag)
263 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
264 if (rprefix->AdvAutonomousFlag)
265 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
vincent7cee1bb2005-03-25 13:08:53 +0000266 if (rprefix->AdvRouterAddressFlag)
267 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
paul718e3742002-12-13 20:15:29 +0000268
269 pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
270 pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
271 pinfo->nd_opt_pi_reserved2 = 0;
272
273 memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
274 sizeof (struct in6_addr));
275
276#ifdef DEBUG
277 {
278 u_char buf[INET6_ADDRSTRLEN];
279
ajsb6178002004-12-07 21:12:56 +0000280 zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix,
hasso3e31cde2004-05-18 11:58:59 +0000281 buf, INET6_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +0000282
283 }
284#endif /* DEBUG */
285
286 len += sizeof (struct nd_opt_prefix_info);
287 }
288
289 /* Hardware address. */
290#ifdef HAVE_SOCKADDR_DL
291 sdl = &ifp->sdl;
292 if (sdl != NULL && sdl->sdl_alen != 0)
293 {
294 buf[len++] = ND_OPT_SOURCE_LINKADDR;
295 buf[len++] = (sdl->sdl_alen + 2) >> 3;
296
297 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
298 len += sdl->sdl_alen;
299 }
300#else
301 if (ifp->hw_addr_len != 0)
302 {
303 buf[len++] = ND_OPT_SOURCE_LINKADDR;
304 buf[len++] = (ifp->hw_addr_len + 2) >> 3;
305
306 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
307 len += ifp->hw_addr_len;
308 }
309#endif /* HAVE_SOCKADDR_DL */
310
311 msg.msg_name = (void *) &addr;
312 msg.msg_namelen = sizeof (struct sockaddr_in6);
313 msg.msg_iov = &iov;
314 msg.msg_iovlen = 1;
315 msg.msg_control = (void *) adata;
gdtf841e022004-08-11 19:20:01 +0000316 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
gdt57492d52004-08-11 18:06:38 +0000317 msg.msg_flags = 0;
paul718e3742002-12-13 20:15:29 +0000318 iov.iov_base = buf;
319 iov.iov_len = len;
320
ajsb99760a2005-01-04 16:24:43 +0000321 cmsgptr = ZCMSG_FIRSTHDR(&msg);
gdt57492d52004-08-11 18:06:38 +0000322 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
paul718e3742002-12-13 20:15:29 +0000323 cmsgptr->cmsg_level = IPPROTO_IPV6;
324 cmsgptr->cmsg_type = IPV6_PKTINFO;
gdt80893812004-08-11 15:58:00 +0000325
paul718e3742002-12-13 20:15:29 +0000326 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
327 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
328 pkt->ipi6_ifindex = ifp->ifindex;
329
330 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000331 if (ret < 0)
332 {
333 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
ajs6099b3b2004-11-20 02:06:59 +0000334 errno, safe_strerror(errno));
gdt9ccabd12004-01-06 18:23:02 +0000335 }
paul718e3742002-12-13 20:15:29 +0000336}
337
338int
339rtadv_timer (struct thread *thread)
340{
hasso52dc7ee2004-09-23 19:18:23 +0000341 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000342 struct interface *ifp;
343 struct zebra_if *zif;
vincent7cee1bb2005-03-25 13:08:53 +0000344 int period;
paul718e3742002-12-13 20:15:29 +0000345
346 rtadv->ra_timer = NULL;
vincent7cee1bb2005-03-25 13:08:53 +0000347 if (rtadv->adv_msec_if_count == 0)
348 {
349 period = 1000; /* 1 s */
350 rtadv_event (RTADV_TIMER, 1 /* 1 s */);
351 }
352 else
353 {
354 period = 10; /* 10 ms */
355 rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */);
356 }
paul718e3742002-12-13 20:15:29 +0000357
358 for (node = listhead (iflist); node; nextnode (node))
359 {
360 ifp = getdata (node);
361
362 if (if_is_loopback (ifp))
363 continue;
364
365 zif = ifp->info;
366
367 if (zif->rtadv.AdvSendAdvertisements)
vincent7cee1bb2005-03-25 13:08:53 +0000368 {
369 zif->rtadv.AdvIntervalTimer -= period;
370 if (zif->rtadv.AdvIntervalTimer <= 0)
371 {
372 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
373 rtadv_send_packet (rtadv->sock, ifp);
374 }
375 }
paul718e3742002-12-13 20:15:29 +0000376 }
377 return 0;
378}
379
380void
381rtadv_process_solicit (struct interface *ifp)
382{
383 zlog_info ("Router solicitation received on %s", ifp->name);
384
385 rtadv_send_packet (rtadv->sock, ifp);
386}
387
388void
389rtadv_process_advert ()
390{
391 zlog_info ("Router advertisement received");
392}
393
394void
hassofce954f2004-10-07 20:29:24 +0000395rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit)
paul718e3742002-12-13 20:15:29 +0000396{
397 struct icmp6_hdr *icmph;
398 struct interface *ifp;
399 struct zebra_if *zif;
400
401 /* Interface search. */
402 ifp = if_lookup_by_index (ifindex);
403 if (ifp == NULL)
404 {
405 zlog_warn ("Unknown interface index: %d", ifindex);
406 return;
407 }
408
409 if (if_is_loopback (ifp))
410 return;
411
412 /* Check interface configuration. */
413 zif = ifp->info;
414 if (! zif->rtadv.AdvSendAdvertisements)
415 return;
416
417 /* ICMP message length check. */
418 if (len < sizeof (struct icmp6_hdr))
419 {
420 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
421 return;
422 }
423
424 icmph = (struct icmp6_hdr *) buf;
425
426 /* ICMP message type check. */
427 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
428 icmph->icmp6_type != ND_ROUTER_ADVERT)
429 {
430 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
431 return;
432 }
433
434 /* Hoplimit check. */
435 if (hoplimit >= 0 && hoplimit != 255)
436 {
437 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
438 hoplimit);
439 return;
440 }
441
442 /* Check ICMP message type. */
443 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
444 rtadv_process_solicit (ifp);
445 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
446 rtadv_process_advert ();
447
448 return;
449}
450
451int
452rtadv_read (struct thread *thread)
453{
454 int sock;
455 int len;
456 u_char buf[RTADV_MSG_SIZE];
457 struct sockaddr_in6 from;
458 unsigned int ifindex;
459 int hoplimit = -1;
460
461 sock = THREAD_FD (thread);
462 rtadv->ra_read = NULL;
463
464 /* Register myself. */
465 rtadv_event (RTADV_READ, sock);
466
467 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
468
469 if (len < 0)
470 {
ajs6099b3b2004-11-20 02:06:59 +0000471 zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000472 return len;
473 }
474
hassofce954f2004-10-07 20:29:24 +0000475 rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit);
paul718e3742002-12-13 20:15:29 +0000476
477 return 0;
478}
479
480int
481rtadv_make_socket (void)
482{
483 int sock;
484 int ret;
485 struct icmp6_filter filter;
486
pauledd7c242003-06-04 13:59:38 +0000487 if ( zserv_privs.change (ZPRIVS_RAISE) )
488 zlog_err ("rtadv_make_socket: could not raise privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000489 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000490
paul718e3742002-12-13 20:15:29 +0000491 sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
492
pauledd7c242003-06-04 13:59:38 +0000493 if ( zserv_privs.change (ZPRIVS_LOWER) )
494 zlog_err ("rtadv_make_socket: could not lower privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000495 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000496
paul718e3742002-12-13 20:15:29 +0000497 /* When we can't make ICMPV6 socket simply back. Router
498 advertisement feature will not be supported. */
499 if (sock < 0)
500 return -1;
501
502 ret = setsockopt_ipv6_pktinfo (sock, 1);
503 if (ret < 0)
504 return ret;
paul718e3742002-12-13 20:15:29 +0000505 ret = setsockopt_ipv6_multicast_loop (sock, 0);
506 if (ret < 0)
507 return ret;
508 ret = setsockopt_ipv6_unicast_hops (sock, 255);
509 if (ret < 0)
510 return ret;
511 ret = setsockopt_ipv6_multicast_hops (sock, 255);
512 if (ret < 0)
513 return ret;
514 ret = setsockopt_ipv6_hoplimit (sock, 1);
515 if (ret < 0)
516 return ret;
517
518 ICMP6_FILTER_SETBLOCKALL(&filter);
519 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
520 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
521
522 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
523 sizeof (struct icmp6_filter));
524 if (ret < 0)
525 {
ajs6099b3b2004-11-20 02:06:59 +0000526 zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000527 return ret;
528 }
529
530 return sock;
531}
532
533struct rtadv_prefix *
534rtadv_prefix_new ()
535{
536 struct rtadv_prefix *new;
537
538 new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
539 memset (new, 0, sizeof (struct rtadv_prefix));
540
541 return new;
542}
543
544void
545rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
546{
547 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
548}
549
550struct rtadv_prefix *
hasso52dc7ee2004-09-23 19:18:23 +0000551rtadv_prefix_lookup (struct list *rplist, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000552{
hasso52dc7ee2004-09-23 19:18:23 +0000553 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000554 struct rtadv_prefix *rprefix;
555
556 for (node = listhead (rplist); node; node = nextnode (node))
557 {
558 rprefix = getdata (node);
559 if (prefix_same (&rprefix->prefix, p))
560 return rprefix;
561 }
562 return NULL;
563}
564
565struct rtadv_prefix *
hasso52dc7ee2004-09-23 19:18:23 +0000566rtadv_prefix_get (struct list *rplist, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000567{
568 struct rtadv_prefix *rprefix;
569
570 rprefix = rtadv_prefix_lookup (rplist, p);
571 if (rprefix)
572 return rprefix;
573
574 rprefix = rtadv_prefix_new ();
575 memcpy (&rprefix->prefix, p, sizeof (struct prefix));
576 listnode_add (rplist, rprefix);
577
578 return rprefix;
579}
580
581void
582rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
583{
584 struct rtadv_prefix *rprefix;
585
586 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
587
588 /* Set parameters. */
589 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
590 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
591 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
592 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
vincent7cee1bb2005-03-25 13:08:53 +0000593 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
paul718e3742002-12-13 20:15:29 +0000594}
595
596int
597rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
598{
599 struct rtadv_prefix *rprefix;
600
601 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
602 if (rprefix != NULL)
603 {
604 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
605 rtadv_prefix_free (rprefix);
606 return 1;
607 }
608 else
609 return 0;
610}
611
612DEFUN (ipv6_nd_suppress_ra,
613 ipv6_nd_suppress_ra_cmd,
614 "ipv6 nd suppress-ra",
hasso3e31cde2004-05-18 11:58:59 +0000615 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000616 "Neighbor discovery\n"
617 "Suppress Router Advertisement\n")
618{
619 struct interface *ifp;
620 struct zebra_if *zif;
621
622 ifp = vty->index;
623 zif = ifp->info;
624
625 if (if_is_loopback (ifp))
626 {
627 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
628 return CMD_WARNING;
629 }
630
631 if (zif->rtadv.AdvSendAdvertisements)
632 {
633 zif->rtadv.AdvSendAdvertisements = 0;
634 zif->rtadv.AdvIntervalTimer = 0;
635 rtadv->adv_if_count--;
636
637 if_leave_all_router (rtadv->sock, ifp);
638
639 if (rtadv->adv_if_count == 0)
640 rtadv_event (RTADV_STOP, 0);
641 }
642
643 return CMD_SUCCESS;
644}
645
paul718e3742002-12-13 20:15:29 +0000646DEFUN (no_ipv6_nd_suppress_ra,
647 no_ipv6_nd_suppress_ra_cmd,
648 "no ipv6 nd suppress-ra",
649 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000650 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000651 "Neighbor discovery\n"
652 "Suppress Router Advertisement\n")
653{
654 struct interface *ifp;
655 struct zebra_if *zif;
656
657 ifp = vty->index;
658 zif = ifp->info;
659
660 if (if_is_loopback (ifp))
661 {
662 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
663 return CMD_WARNING;
664 }
665
666 if (! zif->rtadv.AdvSendAdvertisements)
667 {
668 zif->rtadv.AdvSendAdvertisements = 1;
669 zif->rtadv.AdvIntervalTimer = 0;
670 rtadv->adv_if_count++;
671
672 if_join_all_router (rtadv->sock, ifp);
673
674 if (rtadv->adv_if_count == 1)
675 rtadv_event (RTADV_START, rtadv->sock);
676 }
677
678 return CMD_SUCCESS;
679}
680
vincent7cee1bb2005-03-25 13:08:53 +0000681DEFUN (ipv6_nd_ra_interval_msec,
682 ipv6_nd_ra_interval_msec_cmd,
683 "ipv6 nd ra-interval msec MILLISECONDS",
684 "Interface IPv6 config commands\n"
685 "Neighbor discovery\n"
686 "Router Advertisement interval\n"
687 "Router Advertisement interval in milliseconds\n")
688{
689 int interval;
690 struct interface *ifp;
691 struct zebra_if *zif;
692
693 ifp = (struct interface *) vty->index;
694 zif = ifp->info;
695
696 interval = atoi (argv[0]);
697
698 if (interval <= 0)
699 {
700 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
701 return CMD_WARNING;
702 }
703
704 if (zif->rtadv.MaxRtrAdvInterval % 1000)
705 rtadv->adv_msec_if_count--;
706
707 if (interval % 1000)
708 rtadv->adv_msec_if_count++;
709
710 zif->rtadv.MaxRtrAdvInterval = interval;
711 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
712 zif->rtadv.AdvIntervalTimer = 0;
713
714 return CMD_SUCCESS;
715}
716
paul718e3742002-12-13 20:15:29 +0000717DEFUN (ipv6_nd_ra_interval,
718 ipv6_nd_ra_interval_cmd,
719 "ipv6 nd ra-interval SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000720 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000721 "Neighbor discovery\n"
722 "Router Advertisement interval\n"
723 "Router Advertisement interval in seconds\n")
724{
725 int interval;
726 struct interface *ifp;
727 struct zebra_if *zif;
728
729 ifp = (struct interface *) vty->index;
730 zif = ifp->info;
731
732 interval = atoi (argv[0]);
733
vincent7cee1bb2005-03-25 13:08:53 +0000734 if (interval <= 0)
paul718e3742002-12-13 20:15:29 +0000735 {
736 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
737 return CMD_WARNING;
738 }
739
vincent7cee1bb2005-03-25 13:08:53 +0000740 if (zif->rtadv.MaxRtrAdvInterval % 1000)
741 rtadv->adv_msec_if_count--;
742
743 /* convert to milliseconds */
744 interval = interval * 1000;
745
paul718e3742002-12-13 20:15:29 +0000746 zif->rtadv.MaxRtrAdvInterval = interval;
747 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
748 zif->rtadv.AdvIntervalTimer = 0;
749
750 return CMD_SUCCESS;
751}
752
753DEFUN (no_ipv6_nd_ra_interval,
754 no_ipv6_nd_ra_interval_cmd,
755 "no ipv6 nd ra-interval",
756 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000757 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000758 "Neighbor discovery\n"
759 "Router Advertisement interval\n")
760{
761 struct interface *ifp;
762 struct zebra_if *zif;
763
764 ifp = (struct interface *) vty->index;
765 zif = ifp->info;
766
vincent7cee1bb2005-03-25 13:08:53 +0000767 if (zif->rtadv.MaxRtrAdvInterval % 1000)
768 rtadv->adv_msec_if_count--;
769
paul718e3742002-12-13 20:15:29 +0000770 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
771 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
772 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
773
774 return CMD_SUCCESS;
775}
776
777DEFUN (ipv6_nd_ra_lifetime,
778 ipv6_nd_ra_lifetime_cmd,
779 "ipv6 nd ra-lifetime SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000780 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000781 "Neighbor discovery\n"
782 "Router lifetime\n"
783 "Router lifetime in seconds\n")
784{
785 int lifetime;
786 struct interface *ifp;
787 struct zebra_if *zif;
788
789 ifp = (struct interface *) vty->index;
790 zif = ifp->info;
791
792 lifetime = atoi (argv[0]);
793
794 if (lifetime < 0 || lifetime > 0xffff)
795 {
796 vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
797 return CMD_WARNING;
798 }
799
800 zif->rtadv.AdvDefaultLifetime = lifetime;
801
802 return CMD_SUCCESS;
803}
804
805DEFUN (no_ipv6_nd_ra_lifetime,
806 no_ipv6_nd_ra_lifetime_cmd,
807 "no ipv6 nd ra-lifetime",
808 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000809 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000810 "Neighbor discovery\n"
811 "Router lifetime\n")
812{
813 struct interface *ifp;
814 struct zebra_if *zif;
815
816 ifp = (struct interface *) vty->index;
817 zif = ifp->info;
818
819 zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
820
821 return CMD_SUCCESS;
822}
823
824DEFUN (ipv6_nd_reachable_time,
825 ipv6_nd_reachable_time_cmd,
826 "ipv6 nd reachable-time MILLISECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000827 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000828 "Neighbor discovery\n"
829 "Reachable time\n"
830 "Reachable time in milliseconds\n")
831{
832 u_int32_t rtime;
833 struct interface *ifp;
834 struct zebra_if *zif;
835
836 ifp = (struct interface *) vty->index;
837 zif = ifp->info;
838
839 rtime = (u_int32_t) atol (argv[0]);
840
841 if (rtime > RTADV_MAX_REACHABLE_TIME)
842 {
843 vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
844 return CMD_WARNING;
845 }
846
847 zif->rtadv.AdvReachableTime = rtime;
848
849 return CMD_SUCCESS;
850}
851
852DEFUN (no_ipv6_nd_reachable_time,
853 no_ipv6_nd_reachable_time_cmd,
854 "no ipv6 nd reachable-time",
855 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000856 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000857 "Neighbor discovery\n"
858 "Reachable time\n")
859{
860 struct interface *ifp;
861 struct zebra_if *zif;
862
863 ifp = (struct interface *) vty->index;
864 zif = ifp->info;
865
866 zif->rtadv.AdvReachableTime = 0;
867
868 return CMD_SUCCESS;
869}
870
vincent7cee1bb2005-03-25 13:08:53 +0000871DEFUN (ipv6_nd_homeagent_preference,
872 ipv6_nd_homeagent_preference_cmd,
873 "ipv6 nd home-agent-preference PREFERENCE",
874 "Interface IPv6 config commands\n"
875 "Neighbor discovery\n"
876 "Home Agent preference\n"
877 "Home Agent preference value 0..65535\n")
878{
879 u_int32_t hapref;
880 struct interface *ifp;
881 struct zebra_if *zif;
882
883 ifp = (struct interface *) vty->index;
884 zif = ifp->info;
885
886 hapref = (u_int32_t) atol (argv[0]);
887
888 if (hapref > 65535)
889 {
890 vty_out (vty, "Invalid Home Agent preference%s", VTY_NEWLINE);
891 return CMD_WARNING;
892 }
893
894 zif->rtadv.HomeAgentPreference = hapref;
895
896 return CMD_SUCCESS;
897}
898
899DEFUN (no_ipv6_nd_homeagent_preference,
900 no_ipv6_nd_homeagent_preference_cmd,
901 "no ipv6 nd home-agent-preference",
902 NO_STR
903 "Interface IPv6 config commands\n"
904 "Neighbor discovery\n"
905 "Home Agent preference\n")
906{
907 struct interface *ifp;
908 struct zebra_if *zif;
909
910 ifp = (struct interface *) vty->index;
911 zif = ifp->info;
912
913 zif->rtadv.HomeAgentPreference = 0;
914
915 return CMD_SUCCESS;
916}
917
918DEFUN (ipv6_nd_homeagent_lifetime,
919 ipv6_nd_homeagent_lifetime_cmd,
920 "ipv6 nd home-agent-lifetime SECONDS",
921 "Interface IPv6 config commands\n"
922 "Neighbor discovery\n"
923 "Home Agent lifetime\n"
924 "Home Agent lifetime in seconds\n")
925{
926 u_int32_t ha_ltime;
927 struct interface *ifp;
928 struct zebra_if *zif;
929
930 ifp = (struct interface *) vty->index;
931 zif = ifp->info;
932
933 ha_ltime = (u_int32_t) atol (argv[0]);
934
935 if (ha_ltime > RTADV_MAX_HALIFETIME)
936 {
937 vty_out (vty, "Invalid Home Agent Lifetime time%s", VTY_NEWLINE);
938 return CMD_WARNING;
939 }
940
941 zif->rtadv.HomeAgentLifetime = ha_ltime;
942
943 return CMD_SUCCESS;
944}
945
946DEFUN (no_ipv6_nd_homeagent_lifetime,
947 no_ipv6_nd_homeagent_lifetime_cmd,
948 "no ipv6 nd home-agent-lifetime",
949 NO_STR
950 "Interface IPv6 config commands\n"
951 "Neighbor discovery\n"
952 "Home Agent lifetime\n")
953{
954 struct interface *ifp;
955 struct zebra_if *zif;
956
957 ifp = (struct interface *) vty->index;
958 zif = ifp->info;
959
960 zif->rtadv.HomeAgentLifetime = 0;
961
962 return CMD_SUCCESS;
963}
964
paul718e3742002-12-13 20:15:29 +0000965DEFUN (ipv6_nd_managed_config_flag,
966 ipv6_nd_managed_config_flag_cmd,
967 "ipv6 nd managed-config-flag",
hasso3e31cde2004-05-18 11:58:59 +0000968 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000969 "Neighbor discovery\n"
970 "Managed address configuration flag\n")
971{
972 struct interface *ifp;
973 struct zebra_if *zif;
974
975 ifp = (struct interface *) vty->index;
976 zif = ifp->info;
977
978 zif->rtadv.AdvManagedFlag = 1;
979
980 return CMD_SUCCESS;
981}
982
983DEFUN (no_ipv6_nd_managed_config_flag,
984 no_ipv6_nd_managed_config_flag_cmd,
985 "no ipv6 nd managed-config-flag",
986 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000987 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000988 "Neighbor discovery\n"
989 "Managed address configuration flag\n")
990{
991 struct interface *ifp;
992 struct zebra_if *zif;
993
994 ifp = (struct interface *) vty->index;
995 zif = ifp->info;
996
997 zif->rtadv.AdvManagedFlag = 0;
998
999 return CMD_SUCCESS;
1000}
1001
vincent7cee1bb2005-03-25 13:08:53 +00001002DEFUN (ipv6_nd_homeagent_config_flag,
1003 ipv6_nd_homeagent_config_flag_cmd,
1004 "ipv6 nd home-agent-config-flag",
1005 "Interface IPv6 config commands\n"
1006 "Neighbor discovery\n"
1007 "Home Agent configuration flag\n")
1008{
1009 struct interface *ifp;
1010 struct zebra_if *zif;
1011
1012 ifp = (struct interface *) vty->index;
1013 zif = ifp->info;
1014
1015 zif->rtadv.AdvHomeAgentFlag = 1;
1016
1017 return CMD_SUCCESS;
1018}
1019
1020DEFUN (no_ipv6_nd_homeagent_config_flag,
1021 no_ipv6_nd_homeagent_config_flag_cmd,
1022 "no ipv6 nd home-agent-config-flag",
1023 NO_STR
1024 "Interface IPv6 config commands\n"
1025 "Neighbor discovery\n"
1026 "Home Agent configuration flag\n")
1027{
1028 struct interface *ifp;
1029 struct zebra_if *zif;
1030
1031 ifp = (struct interface *) vty->index;
1032 zif = ifp->info;
1033
1034 zif->rtadv.AdvHomeAgentFlag = 0;
1035
1036 return CMD_SUCCESS;
1037}
1038
1039DEFUN (ipv6_nd_adv_interval_config_option,
1040 ipv6_nd_adv_interval_config_option_cmd,
1041 "ipv6 nd adv-interval-option",
1042 "Interface IPv6 config commands\n"
1043 "Neighbor discovery\n"
1044 "Advertisement Interval Option\n")
1045{
1046 struct interface *ifp;
1047 struct zebra_if *zif;
1048
1049 ifp = (struct interface *) vty->index;
1050 zif = ifp->info;
1051
1052 zif->rtadv.AdvIntervalOption = 1;
1053
1054 return CMD_SUCCESS;
1055}
1056
1057DEFUN (no_ipv6_nd_adv_interval_config_option,
1058 no_ipv6_nd_adv_interval_config_option_cmd,
1059 "no ipv6 nd adv-interval-option",
1060 NO_STR
1061 "Interface IPv6 config commands\n"
1062 "Neighbor discovery\n"
1063 "Advertisement Interval Option\n")
1064{
1065 struct interface *ifp;
1066 struct zebra_if *zif;
1067
1068 ifp = (struct interface *) vty->index;
1069 zif = ifp->info;
1070
1071 zif->rtadv.AdvIntervalOption = 0;
1072
1073 return CMD_SUCCESS;
1074}
1075
paul718e3742002-12-13 20:15:29 +00001076DEFUN (ipv6_nd_other_config_flag,
1077 ipv6_nd_other_config_flag_cmd,
1078 "ipv6 nd other-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001079 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001080 "Neighbor discovery\n"
1081 "Other statefull configuration flag\n")
1082{
1083 struct interface *ifp;
1084 struct zebra_if *zif;
1085
1086 ifp = (struct interface *) vty->index;
1087 zif = ifp->info;
1088
1089 zif->rtadv.AdvOtherConfigFlag = 1;
1090
1091 return CMD_SUCCESS;
1092}
1093
1094DEFUN (no_ipv6_nd_other_config_flag,
1095 no_ipv6_nd_other_config_flag_cmd,
1096 "no ipv6 nd other-config-flag",
1097 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001098 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001099 "Neighbor discovery\n"
1100 "Other statefull configuration flag\n")
1101{
1102 struct interface *ifp;
1103 struct zebra_if *zif;
1104
1105 ifp = (struct interface *) vty->index;
1106 zif = ifp->info;
1107
1108 zif->rtadv.AdvOtherConfigFlag = 0;
1109
1110 return CMD_SUCCESS;
1111}
1112
hasso3e31cde2004-05-18 11:58:59 +00001113DEFUN (ipv6_nd_prefix,
1114 ipv6_nd_prefix_cmd,
1115 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
vincent7cee1bb2005-03-25 13:08:53 +00001116 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)",
hasso3e31cde2004-05-18 11:58:59 +00001117 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001118 "Neighbor discovery\n"
1119 "Prefix information\n"
1120 "IPv6 prefix\n"
1121 "Valid lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001122 "Infinite valid lifetime\n"
paul718e3742002-12-13 20:15:29 +00001123 "Preferred lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001124 "Infinite preferred lifetime\n"
1125 "Do not use prefix for onlink determination\n"
vincent7cee1bb2005-03-25 13:08:53 +00001126 "Do not use prefix for autoconfiguration\n"
1127 "Set Router Address flag\n")
paul718e3742002-12-13 20:15:29 +00001128{
1129 int i;
1130 int ret;
hasso3e31cde2004-05-18 11:58:59 +00001131 int cursor = 1;
paul718e3742002-12-13 20:15:29 +00001132 struct interface *ifp;
1133 struct zebra_if *zebra_if;
1134 struct rtadv_prefix rp;
1135
1136 ifp = (struct interface *) vty->index;
1137 zebra_if = ifp->info;
1138
1139 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
1140 if (!ret)
1141 {
1142 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1143 return CMD_WARNING;
1144 }
hasso3e31cde2004-05-18 11:58:59 +00001145 rp.AdvOnLinkFlag = 1;
1146 rp.AdvAutonomousFlag = 1;
vincent7cee1bb2005-03-25 13:08:53 +00001147 rp.AdvRouterAddressFlag = 0;
hasso3e31cde2004-05-18 11:58:59 +00001148 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1149 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
paul718e3742002-12-13 20:15:29 +00001150
hasso3e31cde2004-05-18 11:58:59 +00001151 if (argc > 1)
paul718e3742002-12-13 20:15:29 +00001152 {
hasso3e31cde2004-05-18 11:58:59 +00001153 if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0)
paul718e3742002-12-13 20:15:29 +00001154 {
hasso3e31cde2004-05-18 11:58:59 +00001155 if ( strncmp (argv[1], "i", 1) == 0)
1156 rp.AdvValidLifetime = UINT32_MAX;
1157 else
1158 rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
1159 (char **)NULL, 10);
1160
1161 if ( strncmp (argv[2], "i", 1) == 0)
1162 rp.AdvPreferredLifetime = UINT32_MAX;
1163 else
1164 rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
1165 (char **)NULL, 10);
1166
1167 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
1168 {
1169 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
1170 return CMD_WARNING;
1171 }
1172 cursor = cursor + 2;
paul718e3742002-12-13 20:15:29 +00001173 }
hasso3e31cde2004-05-18 11:58:59 +00001174 if (argc > cursor)
paul718e3742002-12-13 20:15:29 +00001175 {
hasso3e31cde2004-05-18 11:58:59 +00001176 for (i = cursor; i < argc; i++)
1177 {
1178 if (strncmp (argv[i], "of", 2) == 0)
1179 rp.AdvOnLinkFlag = 0;
1180 if (strncmp (argv[i], "no", 2) == 0)
1181 rp.AdvAutonomousFlag = 0;
vincent7cee1bb2005-03-25 13:08:53 +00001182 if (strncmp (argv[i], "ro", 2) == 0)
1183 rp.AdvRouterAddressFlag = 1;
hasso3e31cde2004-05-18 11:58:59 +00001184 }
paul718e3742002-12-13 20:15:29 +00001185 }
1186 }
1187
1188 rtadv_prefix_set (zebra_if, &rp);
1189
1190 return CMD_SUCCESS;
1191}
1192
hasso3e31cde2004-05-18 11:58:59 +00001193ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001194 ipv6_nd_prefix_val_nortaddr_cmd,
1195 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1196 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
1197 "Interface IPv6 config commands\n"
1198 "Neighbor discovery\n"
1199 "Prefix information\n"
1200 "IPv6 prefix\n"
1201 "Valid lifetime in seconds\n"
1202 "Infinite valid lifetime\n"
1203 "Preferred lifetime in seconds\n"
1204 "Infinite preferred lifetime\n"
1205 "Do not use prefix for onlink determination\n"
1206 "Do not use prefix for autoconfiguration\n")
1207
1208ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001209 ipv6_nd_prefix_val_rev_cmd,
1210 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1211 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
1212 "Interface IPv6 config commands\n"
1213 "Neighbor discovery\n"
1214 "Prefix information\n"
1215 "IPv6 prefix\n"
1216 "Valid lifetime in seconds\n"
1217 "Infinite valid lifetime\n"
1218 "Preferred lifetime in seconds\n"
1219 "Infinite preferred lifetime\n"
1220 "Do not use prefix for autoconfiguration\n"
1221 "Do not use prefix for onlink determination\n")
1222
1223ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001224 ipv6_nd_prefix_val_rev_rtaddr_cmd,
1225 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1226 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)",
1227 "Interface IPv6 config commands\n"
1228 "Neighbor discovery\n"
1229 "Prefix information\n"
1230 "IPv6 prefix\n"
1231 "Valid lifetime in seconds\n"
1232 "Infinite valid lifetime\n"
1233 "Preferred lifetime in seconds\n"
1234 "Infinite preferred lifetime\n"
1235 "Do not use prefix for autoconfiguration\n"
1236 "Do not use prefix for onlink determination\n"
1237 "Set Router Address flag\n")
1238
1239ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001240 ipv6_nd_prefix_val_noauto_cmd,
1241 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1242 "(<0-4294967295>|infinite) (no-autoconfig|)",
1243 "Interface IPv6 config commands\n"
1244 "Neighbor discovery\n"
1245 "Prefix information\n"
1246 "IPv6 prefix\n"
1247 "Valid lifetime in seconds\n"
1248 "Infinite valid lifetime\n"
1249 "Preferred lifetime in seconds\n"
1250 "Infinite preferred lifetime\n"
vincent7cee1bb2005-03-25 13:08:53 +00001251 "Do not use prefix for autoconfiguration")
hasso3e31cde2004-05-18 11:58:59 +00001252
1253ALIAS (ipv6_nd_prefix,
1254 ipv6_nd_prefix_val_offlink_cmd,
1255 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1256 "(<0-4294967295>|infinite) (off-link|)",
1257 "Interface IPv6 config commands\n"
1258 "Neighbor discovery\n"
1259 "Prefix information\n"
1260 "IPv6 prefix\n"
1261 "Valid lifetime in seconds\n"
1262 "Infinite valid lifetime\n"
1263 "Preferred lifetime in seconds\n"
1264 "Infinite preferred lifetime\n"
1265 "Do not use prefix for onlink determination\n")
1266
1267ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001268 ipv6_nd_prefix_val_rtaddr_cmd,
1269 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1270 "(<0-4294967295>|infinite) (router-address|)",
1271 "Interface IPv6 config commands\n"
1272 "Neighbor discovery\n"
1273 "Prefix information\n"
1274 "IPv6 prefix\n"
1275 "Valid lifetime in seconds\n"
1276 "Infinite valid lifetime\n"
1277 "Preferred lifetime in seconds\n"
1278 "Infinite preferred lifetime\n"
1279 "Set Router Address flag\n")
1280
1281ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001282 ipv6_nd_prefix_val_cmd,
1283 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1284 "(<0-4294967295>|infinite)",
1285 "Interface IPv6 config commands\n"
1286 "Neighbor discovery\n"
1287 "Prefix information\n"
1288 "IPv6 prefix\n"
1289 "Valid lifetime in seconds\n"
1290 "Infinite valid lifetime\n"
1291 "Preferred lifetime in seconds\n"
1292 "Infinite preferred lifetime\n")
1293
1294ALIAS (ipv6_nd_prefix,
1295 ipv6_nd_prefix_noval_cmd,
1296 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
1297 "Interface IPv6 config commands\n"
1298 "Neighbor discovery\n"
1299 "Prefix information\n"
1300 "IPv6 prefix\n"
1301 "Do not use prefix for autoconfiguration\n"
1302 "Do not use prefix for onlink determination\n")
1303
1304ALIAS (ipv6_nd_prefix,
1305 ipv6_nd_prefix_noval_rev_cmd,
1306 "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
1307 "Interface IPv6 config commands\n"
1308 "Neighbor discovery\n"
1309 "Prefix information\n"
1310 "IPv6 prefix\n"
1311 "Do not use prefix for onlink determination\n"
1312 "Do not use prefix for autoconfiguration\n")
1313
1314ALIAS (ipv6_nd_prefix,
1315 ipv6_nd_prefix_noval_noauto_cmd,
1316 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
1317 "Interface IPv6 config commands\n"
1318 "Neighbor discovery\n"
1319 "Prefix information\n"
1320 "IPv6 prefix\n"
1321 "Do not use prefix for autoconfiguration\n")
1322
1323ALIAS (ipv6_nd_prefix,
1324 ipv6_nd_prefix_noval_offlink_cmd,
1325 "ipv6 nd prefix X:X::X:X/M (off-link|)",
1326 "Interface IPv6 config commands\n"
1327 "Neighbor discovery\n"
1328 "Prefix information\n"
1329 "IPv6 prefix\n"
1330 "Do not use prefix for onlink determination\n")
1331
1332ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001333 ipv6_nd_prefix_noval_rtaddr_cmd,
1334 "ipv6 nd prefix X:X::X:X/M (router-address|)",
1335 "Interface IPv6 config commands\n"
1336 "Neighbor discovery\n"
1337 "Prefix information\n"
1338 "IPv6 prefix\n"
1339 "Set Router Address flag\n")
1340
1341ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001342 ipv6_nd_prefix_prefix_cmd,
1343 "ipv6 nd prefix X:X::X:X/M",
1344 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001345 "Neighbor discovery\n"
1346 "Prefix information\n"
1347 "IPv6 prefix\n")
1348
hasso3e31cde2004-05-18 11:58:59 +00001349DEFUN (no_ipv6_nd_prefix,
1350 no_ipv6_nd_prefix_cmd,
1351 "no ipv6 nd prefix IPV6PREFIX",
paul718e3742002-12-13 20:15:29 +00001352 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001353 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001354 "Neighbor discovery\n"
1355 "Prefix information\n"
1356 "IPv6 prefix\n")
1357{
1358 int ret;
1359 struct interface *ifp;
1360 struct zebra_if *zebra_if;
1361 struct rtadv_prefix rp;
1362
1363 ifp = (struct interface *) vty->index;
1364 zebra_if = ifp->info;
1365
1366 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
1367 if (!ret)
1368 {
1369 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1370 return CMD_WARNING;
1371 }
1372
1373 ret = rtadv_prefix_reset (zebra_if, &rp);
1374 if (!ret)
1375 {
1376 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1377 return CMD_WARNING;
1378 }
1379
1380 return CMD_SUCCESS;
1381}
paul718e3742002-12-13 20:15:29 +00001382/* Write configuration about router advertisement. */
1383void
1384rtadv_config_write (struct vty *vty, struct interface *ifp)
1385{
1386 struct zebra_if *zif;
hasso52dc7ee2004-09-23 19:18:23 +00001387 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001388 struct rtadv_prefix *rprefix;
1389 u_char buf[INET6_ADDRSTRLEN];
vincent7cee1bb2005-03-25 13:08:53 +00001390 int interval;
paul718e3742002-12-13 20:15:29 +00001391
1392 if (! rtadv)
1393 return;
1394
1395 zif = ifp->info;
1396
1397 if (! if_is_loopback (ifp))
1398 {
1399 if (zif->rtadv.AdvSendAdvertisements)
1400 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1401 else
1402 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1403 }
1404
vincent7cee1bb2005-03-25 13:08:53 +00001405
1406 interval = zif->rtadv.MaxRtrAdvInterval;
1407 if (interval % 1000)
1408 vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval,
1409 VTY_NEWLINE);
1410 else
1411 if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1412 vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
paul718e3742002-12-13 20:15:29 +00001413 VTY_NEWLINE);
1414
1415 if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
1416 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1417 VTY_NEWLINE);
1418
1419 if (zif->rtadv.AdvReachableTime)
1420 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1421 VTY_NEWLINE);
1422
1423 if (zif->rtadv.AdvManagedFlag)
1424 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1425
1426 if (zif->rtadv.AdvOtherConfigFlag)
1427 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1428
1429 for (node = listhead(zif->rtadv.AdvPrefixList); node; node = nextnode (node))
1430 {
1431 rprefix = getdata (node);
hasso3e31cde2004-05-18 11:58:59 +00001432 vty_out (vty, " ipv6 nd prefix %s/%d",
paul718e3742002-12-13 20:15:29 +00001433 inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6,
hassoc9e52be2004-09-26 16:09:34 +00001434 (char *) buf, INET6_ADDRSTRLEN),
hasso3e31cde2004-05-18 11:58:59 +00001435 rprefix->prefix.prefixlen);
1436 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1437 (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1438 {
1439 if (rprefix->AdvValidLifetime == UINT32_MAX)
1440 vty_out (vty, " infinite");
1441 else
1442 vty_out (vty, " %u", rprefix->AdvValidLifetime);
1443 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1444 vty_out (vty, " infinite");
1445 else
1446 vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1447 }
1448 if (!rprefix->AdvOnLinkFlag)
1449 vty_out (vty, " off-link");
1450 if (!rprefix->AdvAutonomousFlag)
1451 vty_out (vty, " no-autoconfig");
vincent7cee1bb2005-03-25 13:08:53 +00001452 if (rprefix->AdvRouterAddressFlag)
1453 vty_out (vty, " router-address");
paul718e3742002-12-13 20:15:29 +00001454 vty_out (vty, "%s", VTY_NEWLINE);
1455 }
1456}
1457
paul718e3742002-12-13 20:15:29 +00001458
1459void
1460rtadv_event (enum rtadv_event event, int val)
1461{
1462 switch (event)
1463 {
1464 case RTADV_START:
1465 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001466 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001467 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001468 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
1469 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001470 break;
1471 case RTADV_STOP:
1472 if (rtadv->ra_timer)
1473 {
1474 thread_cancel (rtadv->ra_timer);
1475 rtadv->ra_timer = NULL;
1476 }
1477 if (rtadv->ra_read)
1478 {
1479 thread_cancel (rtadv->ra_read);
1480 rtadv->ra_read = NULL;
1481 }
1482 break;
1483 case RTADV_TIMER:
1484 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001485 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
1486 val);
paul718e3742002-12-13 20:15:29 +00001487 break;
vincent7cee1bb2005-03-25 13:08:53 +00001488 case RTADV_TIMER_MSEC:
1489 if (! rtadv->ra_timer)
1490 rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer,
1491 NULL, val);
1492 break;
paul718e3742002-12-13 20:15:29 +00001493 case RTADV_READ:
1494 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001495 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001496 break;
1497 default:
1498 break;
1499 }
1500 return;
1501}
1502
1503void
1504rtadv_init ()
1505{
1506 int sock;
1507
1508 sock = rtadv_make_socket ();
1509 if (sock < 0)
1510 return;
1511
1512 rtadv = rtadv_new ();
1513 rtadv->sock = sock;
1514
1515 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1516 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
paul718e3742002-12-13 20:15:29 +00001517 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001518 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
paul718e3742002-12-13 20:15:29 +00001519 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1520 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1521 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1522 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1523 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1524 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1525 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1526 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1527 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001528 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1529 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1530 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1531 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
1532 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1533 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
1534 install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
1535 install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001536 install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001537 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd);
1538 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001539 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1540 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1541 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001542 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001543 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1544 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1545 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1546 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1547 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001548 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001549 install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1550 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
paul718e3742002-12-13 20:15:29 +00001551}
1552
1553int
1554if_join_all_router (int sock, struct interface *ifp)
1555{
1556 int ret;
1557
1558 struct ipv6_mreq mreq;
1559
1560 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1561 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1562 mreq.ipv6mr_interface = ifp->ifindex;
1563
1564 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1565 (char *) &mreq, sizeof mreq);
1566 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001567 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001568
1569 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1570
1571 return 0;
1572}
1573
1574int
1575if_leave_all_router (int sock, struct interface *ifp)
1576{
1577 int ret;
1578
1579 struct ipv6_mreq mreq;
1580
1581 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1582 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1583 mreq.ipv6mr_interface = ifp->ifindex;
1584
1585 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1586 (char *) &mreq, sizeof mreq);
1587 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001588 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001589
1590 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1591
1592 return 0;
1593}
1594
1595#else
1596void
1597rtadv_init ()
1598{
1599 /* Empty.*/;
1600}
1601#endif /* RTADV && HAVE_IPV6 */