blob: 83c3e777a23cc903df7b2fd8d771df49f3378fb7 [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
paula1ac18c2005-06-28 17:17:12 +000065static void rtadv_event (enum rtadv_event, int);
paul718e3742002-12-13 20:15:29 +000066
paula1ac18c2005-06-28 17:17:12 +000067static int if_join_all_router (int, struct interface *);
68static int if_leave_all_router (int, struct interface *);
paul718e3742002-12-13 20:15:29 +000069
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
paula1ac18c2005-06-28 17:17:12 +000084static struct rtadv *
85rtadv_new (void)
paul718e3742002-12-13 20:15:29 +000086{
87 struct rtadv *new;
88 new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
89 memset (new, 0, sizeof (struct rtadv));
90 return new;
91}
92
paula1ac18c2005-06-28 17:17:12 +000093static void
paul718e3742002-12-13 20:15:29 +000094rtadv_free (struct rtadv *rtadv)
95{
96 XFREE (MTYPE_TMP, rtadv);
97}
98
paula1ac18c2005-06-28 17:17:12 +000099static int
paul718e3742002-12-13 20:15:29 +0000100rtadv_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. */
paula1ac18c2005-06-28 17:17:12 +0000152static void
paul718e3742002-12-13 20:15:29 +0000153rtadv_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;
paul1eb8ef22005-04-07 07:30:20 +0000169 struct rtadv_prefix *rprefix;
paul718e3742002-12-13 20:15:29 +0000170 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 +0000171 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000172
gdt57492d52004-08-11 18:06:38 +0000173 /*
174 * Allocate control message bufffer. This is dynamic because
175 * CMSG_SPACE is not guaranteed not to call a function. Note that
176 * the size will be different on different architectures due to
177 * differing alignment rules.
178 */
179 if (adata == NULL)
180 {
181 /* XXX Free on shutdown. */
182 adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)));
183
184 if (adata == NULL)
185 zlog_err("rtadv_send_packet: can't malloc control data\n");
186 }
187
paul718e3742002-12-13 20:15:29 +0000188 /* Logging of packet. */
189 if (IS_ZEBRA_DEBUG_PACKET)
ajsb6178002004-12-07 21:12:56 +0000190 zlog_debug ("Router advertisement send to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +0000191
192 /* Fill in sockaddr_in6. */
193 memset (&addr, 0, sizeof (struct sockaddr_in6));
194 addr.sin6_family = AF_INET6;
195#ifdef SIN6_LEN
196 addr.sin6_len = sizeof (struct sockaddr_in6);
197#endif /* SIN6_LEN */
198 addr.sin6_port = htons (IPPROTO_ICMPV6);
199 memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr));
200
201 /* Fetch interface information. */
202 zif = ifp->info;
203
204 /* Make router advertisement message. */
205 rtadv = (struct nd_router_advert *) buf;
206
207 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
208 rtadv->nd_ra_code = 0;
209 rtadv->nd_ra_cksum = 0;
210
211 rtadv->nd_ra_curhoplimit = 64;
212 rtadv->nd_ra_flags_reserved = 0;
213 if (zif->rtadv.AdvManagedFlag)
214 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
215 if (zif->rtadv.AdvOtherConfigFlag)
216 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
vincent7cee1bb2005-03-25 13:08:53 +0000217 if (zif->rtadv.AdvHomeAgentFlag)
218 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
paul718e3742002-12-13 20:15:29 +0000219 rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
220 rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
221 rtadv->nd_ra_retransmit = htonl (0);
222
223 len = sizeof (struct nd_router_advert);
224
vincent7cee1bb2005-03-25 13:08:53 +0000225 if (zif->rtadv.AdvHomeAgentFlag)
226 {
227 struct nd_opt_homeagent_info *ndopt_hai =
228 (struct nd_opt_homeagent_info *)(buf + len);
229 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
230 ndopt_hai->nd_opt_hai_len = 1;
231 ndopt_hai->nd_opt_hai_reserved = 0;
232 ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference);
233 ndopt_hai->nd_opt_hai_lifetime = htons(zif->rtadv.HomeAgentLifetime);
234 len += sizeof(struct nd_opt_homeagent_info);
235 }
236
237 if (zif->rtadv.AdvIntervalOption)
238 {
239 struct nd_opt_adv_interval *ndopt_adv =
240 (struct nd_opt_adv_interval *)(buf + len);
241 ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
242 ndopt_adv->nd_opt_ai_len = 1;
243 ndopt_adv->nd_opt_ai_reserved = 0;
244 ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval);
245 len += sizeof(struct nd_opt_adv_interval);
246 }
247
paul718e3742002-12-13 20:15:29 +0000248 /* Fill in prefix. */
paul1eb8ef22005-04-07 07:30:20 +0000249 for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
paul718e3742002-12-13 20:15:29 +0000250 {
251 struct nd_opt_prefix_info *pinfo;
paul718e3742002-12-13 20:15:29 +0000252
253 pinfo = (struct nd_opt_prefix_info *) (buf + len);
254
255 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
256 pinfo->nd_opt_pi_len = 4;
257 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
258
259 pinfo->nd_opt_pi_flags_reserved = 0;
260 if (rprefix->AdvOnLinkFlag)
261 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
262 if (rprefix->AdvAutonomousFlag)
263 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
vincent7cee1bb2005-03-25 13:08:53 +0000264 if (rprefix->AdvRouterAddressFlag)
265 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
paul718e3742002-12-13 20:15:29 +0000266
267 pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
268 pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
269 pinfo->nd_opt_pi_reserved2 = 0;
270
271 memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6,
272 sizeof (struct in6_addr));
273
274#ifdef DEBUG
275 {
276 u_char buf[INET6_ADDRSTRLEN];
277
ajsb6178002004-12-07 21:12:56 +0000278 zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix,
hasso3e31cde2004-05-18 11:58:59 +0000279 buf, INET6_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +0000280
281 }
282#endif /* DEBUG */
283
284 len += sizeof (struct nd_opt_prefix_info);
285 }
286
287 /* Hardware address. */
288#ifdef HAVE_SOCKADDR_DL
289 sdl = &ifp->sdl;
290 if (sdl != NULL && sdl->sdl_alen != 0)
291 {
292 buf[len++] = ND_OPT_SOURCE_LINKADDR;
293 buf[len++] = (sdl->sdl_alen + 2) >> 3;
294
295 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
296 len += sdl->sdl_alen;
297 }
298#else
299 if (ifp->hw_addr_len != 0)
300 {
301 buf[len++] = ND_OPT_SOURCE_LINKADDR;
302 buf[len++] = (ifp->hw_addr_len + 2) >> 3;
303
304 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
305 len += ifp->hw_addr_len;
306 }
307#endif /* HAVE_SOCKADDR_DL */
308
309 msg.msg_name = (void *) &addr;
310 msg.msg_namelen = sizeof (struct sockaddr_in6);
311 msg.msg_iov = &iov;
312 msg.msg_iovlen = 1;
313 msg.msg_control = (void *) adata;
gdtf841e022004-08-11 19:20:01 +0000314 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
gdt57492d52004-08-11 18:06:38 +0000315 msg.msg_flags = 0;
paul718e3742002-12-13 20:15:29 +0000316 iov.iov_base = buf;
317 iov.iov_len = len;
318
ajsb99760a2005-01-04 16:24:43 +0000319 cmsgptr = ZCMSG_FIRSTHDR(&msg);
gdt57492d52004-08-11 18:06:38 +0000320 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
paul718e3742002-12-13 20:15:29 +0000321 cmsgptr->cmsg_level = IPPROTO_IPV6;
322 cmsgptr->cmsg_type = IPV6_PKTINFO;
gdt80893812004-08-11 15:58:00 +0000323
paul718e3742002-12-13 20:15:29 +0000324 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
325 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
326 pkt->ipi6_ifindex = ifp->ifindex;
327
328 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000329 if (ret < 0)
330 {
331 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
ajs6099b3b2004-11-20 02:06:59 +0000332 errno, safe_strerror(errno));
gdt9ccabd12004-01-06 18:23:02 +0000333 }
paul718e3742002-12-13 20:15:29 +0000334}
335
paula1ac18c2005-06-28 17:17:12 +0000336static int
paul718e3742002-12-13 20:15:29 +0000337rtadv_timer (struct thread *thread)
338{
paul1eb8ef22005-04-07 07:30:20 +0000339 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000340 struct interface *ifp;
341 struct zebra_if *zif;
vincent7cee1bb2005-03-25 13:08:53 +0000342 int period;
paul718e3742002-12-13 20:15:29 +0000343
344 rtadv->ra_timer = NULL;
vincent7cee1bb2005-03-25 13:08:53 +0000345 if (rtadv->adv_msec_if_count == 0)
346 {
347 period = 1000; /* 1 s */
348 rtadv_event (RTADV_TIMER, 1 /* 1 s */);
349 }
350 else
351 {
352 period = 10; /* 10 ms */
353 rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */);
354 }
paul718e3742002-12-13 20:15:29 +0000355
paul1eb8ef22005-04-07 07:30:20 +0000356 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
paul718e3742002-12-13 20:15:29 +0000357 {
paul718e3742002-12-13 20:15:29 +0000358 if (if_is_loopback (ifp))
359 continue;
360
361 zif = ifp->info;
362
363 if (zif->rtadv.AdvSendAdvertisements)
vincent7cee1bb2005-03-25 13:08:53 +0000364 {
365 zif->rtadv.AdvIntervalTimer -= period;
366 if (zif->rtadv.AdvIntervalTimer <= 0)
367 {
368 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
369 rtadv_send_packet (rtadv->sock, ifp);
370 }
371 }
paul718e3742002-12-13 20:15:29 +0000372 }
373 return 0;
374}
375
paula1ac18c2005-06-28 17:17:12 +0000376static void
paul718e3742002-12-13 20:15:29 +0000377rtadv_process_solicit (struct interface *ifp)
378{
379 zlog_info ("Router solicitation received on %s", ifp->name);
380
381 rtadv_send_packet (rtadv->sock, ifp);
382}
383
paula1ac18c2005-06-28 17:17:12 +0000384static void
385rtadv_process_advert (void)
paul718e3742002-12-13 20:15:29 +0000386{
387 zlog_info ("Router advertisement received");
388}
389
paula1ac18c2005-06-28 17:17:12 +0000390static void
hassofce954f2004-10-07 20:29:24 +0000391rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit)
paul718e3742002-12-13 20:15:29 +0000392{
393 struct icmp6_hdr *icmph;
394 struct interface *ifp;
395 struct zebra_if *zif;
396
397 /* Interface search. */
398 ifp = if_lookup_by_index (ifindex);
399 if (ifp == NULL)
400 {
401 zlog_warn ("Unknown interface index: %d", ifindex);
402 return;
403 }
404
405 if (if_is_loopback (ifp))
406 return;
407
408 /* Check interface configuration. */
409 zif = ifp->info;
410 if (! zif->rtadv.AdvSendAdvertisements)
411 return;
412
413 /* ICMP message length check. */
414 if (len < sizeof (struct icmp6_hdr))
415 {
416 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
417 return;
418 }
419
420 icmph = (struct icmp6_hdr *) buf;
421
422 /* ICMP message type check. */
423 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
424 icmph->icmp6_type != ND_ROUTER_ADVERT)
425 {
426 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
427 return;
428 }
429
430 /* Hoplimit check. */
431 if (hoplimit >= 0 && hoplimit != 255)
432 {
433 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
434 hoplimit);
435 return;
436 }
437
438 /* Check ICMP message type. */
439 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
440 rtadv_process_solicit (ifp);
441 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
442 rtadv_process_advert ();
443
444 return;
445}
446
paula1ac18c2005-06-28 17:17:12 +0000447static int
paul718e3742002-12-13 20:15:29 +0000448rtadv_read (struct thread *thread)
449{
450 int sock;
451 int len;
452 u_char buf[RTADV_MSG_SIZE];
453 struct sockaddr_in6 from;
454 unsigned int ifindex;
455 int hoplimit = -1;
456
457 sock = THREAD_FD (thread);
458 rtadv->ra_read = NULL;
459
460 /* Register myself. */
461 rtadv_event (RTADV_READ, sock);
462
463 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
464
465 if (len < 0)
466 {
ajs6099b3b2004-11-20 02:06:59 +0000467 zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000468 return len;
469 }
470
hassofce954f2004-10-07 20:29:24 +0000471 rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit);
paul718e3742002-12-13 20:15:29 +0000472
473 return 0;
474}
475
paula1ac18c2005-06-28 17:17:12 +0000476static int
paul718e3742002-12-13 20:15:29 +0000477rtadv_make_socket (void)
478{
479 int sock;
480 int ret;
481 struct icmp6_filter filter;
482
pauledd7c242003-06-04 13:59:38 +0000483 if ( zserv_privs.change (ZPRIVS_RAISE) )
484 zlog_err ("rtadv_make_socket: could not raise privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000485 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000486
paul718e3742002-12-13 20:15:29 +0000487 sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
488
pauledd7c242003-06-04 13:59:38 +0000489 if ( zserv_privs.change (ZPRIVS_LOWER) )
490 zlog_err ("rtadv_make_socket: could not lower privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000491 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000492
paul718e3742002-12-13 20:15:29 +0000493 /* When we can't make ICMPV6 socket simply back. Router
494 advertisement feature will not be supported. */
495 if (sock < 0)
496 return -1;
497
498 ret = setsockopt_ipv6_pktinfo (sock, 1);
499 if (ret < 0)
500 return ret;
paul718e3742002-12-13 20:15:29 +0000501 ret = setsockopt_ipv6_multicast_loop (sock, 0);
502 if (ret < 0)
503 return ret;
504 ret = setsockopt_ipv6_unicast_hops (sock, 255);
505 if (ret < 0)
506 return ret;
507 ret = setsockopt_ipv6_multicast_hops (sock, 255);
508 if (ret < 0)
509 return ret;
510 ret = setsockopt_ipv6_hoplimit (sock, 1);
511 if (ret < 0)
512 return ret;
513
514 ICMP6_FILTER_SETBLOCKALL(&filter);
515 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
516 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
517
518 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
519 sizeof (struct icmp6_filter));
520 if (ret < 0)
521 {
ajs6099b3b2004-11-20 02:06:59 +0000522 zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000523 return ret;
524 }
525
526 return sock;
527}
528
paula1ac18c2005-06-28 17:17:12 +0000529static struct rtadv_prefix *
paul718e3742002-12-13 20:15:29 +0000530rtadv_prefix_new ()
531{
532 struct rtadv_prefix *new;
533
534 new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
535 memset (new, 0, sizeof (struct rtadv_prefix));
536
537 return new;
538}
539
paula1ac18c2005-06-28 17:17:12 +0000540static void
paul718e3742002-12-13 20:15:29 +0000541rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
542{
543 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
544}
545
paula1ac18c2005-06-28 17:17:12 +0000546static struct rtadv_prefix *
hasso52dc7ee2004-09-23 19:18:23 +0000547rtadv_prefix_lookup (struct list *rplist, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000548{
hasso52dc7ee2004-09-23 19:18:23 +0000549 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000550 struct rtadv_prefix *rprefix;
551
paul1eb8ef22005-04-07 07:30:20 +0000552 for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix))
553 if (prefix_same (&rprefix->prefix, p))
554 return rprefix;
paul718e3742002-12-13 20:15:29 +0000555 return NULL;
556}
557
paula1ac18c2005-06-28 17:17:12 +0000558static struct rtadv_prefix *
hasso52dc7ee2004-09-23 19:18:23 +0000559rtadv_prefix_get (struct list *rplist, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000560{
561 struct rtadv_prefix *rprefix;
562
563 rprefix = rtadv_prefix_lookup (rplist, p);
564 if (rprefix)
565 return rprefix;
566
567 rprefix = rtadv_prefix_new ();
568 memcpy (&rprefix->prefix, p, sizeof (struct prefix));
569 listnode_add (rplist, rprefix);
570
571 return rprefix;
572}
573
paula1ac18c2005-06-28 17:17:12 +0000574static void
paul718e3742002-12-13 20:15:29 +0000575rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
576{
577 struct rtadv_prefix *rprefix;
578
579 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
580
581 /* Set parameters. */
582 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
583 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
584 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
585 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
vincent7cee1bb2005-03-25 13:08:53 +0000586 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
paul718e3742002-12-13 20:15:29 +0000587}
588
paula1ac18c2005-06-28 17:17:12 +0000589static int
paul718e3742002-12-13 20:15:29 +0000590rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
591{
592 struct rtadv_prefix *rprefix;
593
594 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
595 if (rprefix != NULL)
596 {
597 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
598 rtadv_prefix_free (rprefix);
599 return 1;
600 }
601 else
602 return 0;
603}
604
605DEFUN (ipv6_nd_suppress_ra,
606 ipv6_nd_suppress_ra_cmd,
607 "ipv6 nd suppress-ra",
hasso3e31cde2004-05-18 11:58:59 +0000608 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000609 "Neighbor discovery\n"
610 "Suppress Router Advertisement\n")
611{
612 struct interface *ifp;
613 struct zebra_if *zif;
614
615 ifp = vty->index;
616 zif = ifp->info;
617
618 if (if_is_loopback (ifp))
619 {
620 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
621 return CMD_WARNING;
622 }
623
624 if (zif->rtadv.AdvSendAdvertisements)
625 {
626 zif->rtadv.AdvSendAdvertisements = 0;
627 zif->rtadv.AdvIntervalTimer = 0;
628 rtadv->adv_if_count--;
629
630 if_leave_all_router (rtadv->sock, ifp);
631
632 if (rtadv->adv_if_count == 0)
633 rtadv_event (RTADV_STOP, 0);
634 }
635
636 return CMD_SUCCESS;
637}
638
paul718e3742002-12-13 20:15:29 +0000639DEFUN (no_ipv6_nd_suppress_ra,
640 no_ipv6_nd_suppress_ra_cmd,
641 "no ipv6 nd suppress-ra",
642 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000643 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000644 "Neighbor discovery\n"
645 "Suppress Router Advertisement\n")
646{
647 struct interface *ifp;
648 struct zebra_if *zif;
649
650 ifp = vty->index;
651 zif = ifp->info;
652
653 if (if_is_loopback (ifp))
654 {
655 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
656 return CMD_WARNING;
657 }
658
659 if (! zif->rtadv.AdvSendAdvertisements)
660 {
661 zif->rtadv.AdvSendAdvertisements = 1;
662 zif->rtadv.AdvIntervalTimer = 0;
663 rtadv->adv_if_count++;
664
665 if_join_all_router (rtadv->sock, ifp);
666
667 if (rtadv->adv_if_count == 1)
668 rtadv_event (RTADV_START, rtadv->sock);
669 }
670
671 return CMD_SUCCESS;
672}
673
vincent7cee1bb2005-03-25 13:08:53 +0000674DEFUN (ipv6_nd_ra_interval_msec,
675 ipv6_nd_ra_interval_msec_cmd,
676 "ipv6 nd ra-interval msec MILLISECONDS",
677 "Interface IPv6 config commands\n"
678 "Neighbor discovery\n"
679 "Router Advertisement interval\n"
680 "Router Advertisement interval in milliseconds\n")
681{
682 int interval;
683 struct interface *ifp;
684 struct zebra_if *zif;
685
686 ifp = (struct interface *) vty->index;
687 zif = ifp->info;
688
689 interval = atoi (argv[0]);
690
691 if (interval <= 0)
692 {
693 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
694 return CMD_WARNING;
695 }
696
697 if (zif->rtadv.MaxRtrAdvInterval % 1000)
698 rtadv->adv_msec_if_count--;
699
700 if (interval % 1000)
701 rtadv->adv_msec_if_count++;
702
703 zif->rtadv.MaxRtrAdvInterval = interval;
704 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
705 zif->rtadv.AdvIntervalTimer = 0;
706
707 return CMD_SUCCESS;
708}
709
paul718e3742002-12-13 20:15:29 +0000710DEFUN (ipv6_nd_ra_interval,
711 ipv6_nd_ra_interval_cmd,
712 "ipv6 nd ra-interval SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000713 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000714 "Neighbor discovery\n"
715 "Router Advertisement interval\n"
716 "Router Advertisement interval in seconds\n")
717{
718 int interval;
719 struct interface *ifp;
720 struct zebra_if *zif;
721
722 ifp = (struct interface *) vty->index;
723 zif = ifp->info;
724
725 interval = atoi (argv[0]);
726
vincent7cee1bb2005-03-25 13:08:53 +0000727 if (interval <= 0)
paul718e3742002-12-13 20:15:29 +0000728 {
729 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
730 return CMD_WARNING;
731 }
732
vincent7cee1bb2005-03-25 13:08:53 +0000733 if (zif->rtadv.MaxRtrAdvInterval % 1000)
734 rtadv->adv_msec_if_count--;
735
736 /* convert to milliseconds */
737 interval = interval * 1000;
738
paul718e3742002-12-13 20:15:29 +0000739 zif->rtadv.MaxRtrAdvInterval = interval;
740 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
741 zif->rtadv.AdvIntervalTimer = 0;
742
743 return CMD_SUCCESS;
744}
745
746DEFUN (no_ipv6_nd_ra_interval,
747 no_ipv6_nd_ra_interval_cmd,
748 "no ipv6 nd ra-interval",
749 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000750 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000751 "Neighbor discovery\n"
752 "Router Advertisement interval\n")
753{
754 struct interface *ifp;
755 struct zebra_if *zif;
756
757 ifp = (struct interface *) vty->index;
758 zif = ifp->info;
759
vincent7cee1bb2005-03-25 13:08:53 +0000760 if (zif->rtadv.MaxRtrAdvInterval % 1000)
761 rtadv->adv_msec_if_count--;
762
paul718e3742002-12-13 20:15:29 +0000763 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
764 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
765 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
766
767 return CMD_SUCCESS;
768}
769
770DEFUN (ipv6_nd_ra_lifetime,
771 ipv6_nd_ra_lifetime_cmd,
772 "ipv6 nd ra-lifetime SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000773 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000774 "Neighbor discovery\n"
775 "Router lifetime\n"
776 "Router lifetime in seconds\n")
777{
778 int lifetime;
779 struct interface *ifp;
780 struct zebra_if *zif;
781
782 ifp = (struct interface *) vty->index;
783 zif = ifp->info;
784
785 lifetime = atoi (argv[0]);
786
787 if (lifetime < 0 || lifetime > 0xffff)
788 {
789 vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
790 return CMD_WARNING;
791 }
792
793 zif->rtadv.AdvDefaultLifetime = lifetime;
794
795 return CMD_SUCCESS;
796}
797
798DEFUN (no_ipv6_nd_ra_lifetime,
799 no_ipv6_nd_ra_lifetime_cmd,
800 "no ipv6 nd ra-lifetime",
801 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000802 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000803 "Neighbor discovery\n"
804 "Router lifetime\n")
805{
806 struct interface *ifp;
807 struct zebra_if *zif;
808
809 ifp = (struct interface *) vty->index;
810 zif = ifp->info;
811
812 zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
813
814 return CMD_SUCCESS;
815}
816
817DEFUN (ipv6_nd_reachable_time,
818 ipv6_nd_reachable_time_cmd,
819 "ipv6 nd reachable-time MILLISECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000820 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000821 "Neighbor discovery\n"
822 "Reachable time\n"
823 "Reachable time in milliseconds\n")
824{
825 u_int32_t rtime;
826 struct interface *ifp;
827 struct zebra_if *zif;
828
829 ifp = (struct interface *) vty->index;
830 zif = ifp->info;
831
832 rtime = (u_int32_t) atol (argv[0]);
833
834 if (rtime > RTADV_MAX_REACHABLE_TIME)
835 {
836 vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
837 return CMD_WARNING;
838 }
839
840 zif->rtadv.AdvReachableTime = rtime;
841
842 return CMD_SUCCESS;
843}
844
845DEFUN (no_ipv6_nd_reachable_time,
846 no_ipv6_nd_reachable_time_cmd,
847 "no ipv6 nd reachable-time",
848 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000849 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000850 "Neighbor discovery\n"
851 "Reachable time\n")
852{
853 struct interface *ifp;
854 struct zebra_if *zif;
855
856 ifp = (struct interface *) vty->index;
857 zif = ifp->info;
858
859 zif->rtadv.AdvReachableTime = 0;
860
861 return CMD_SUCCESS;
862}
863
vincent7cee1bb2005-03-25 13:08:53 +0000864DEFUN (ipv6_nd_homeagent_preference,
865 ipv6_nd_homeagent_preference_cmd,
866 "ipv6 nd home-agent-preference PREFERENCE",
867 "Interface IPv6 config commands\n"
868 "Neighbor discovery\n"
869 "Home Agent preference\n"
870 "Home Agent preference value 0..65535\n")
871{
872 u_int32_t hapref;
873 struct interface *ifp;
874 struct zebra_if *zif;
875
876 ifp = (struct interface *) vty->index;
877 zif = ifp->info;
878
879 hapref = (u_int32_t) atol (argv[0]);
880
881 if (hapref > 65535)
882 {
883 vty_out (vty, "Invalid Home Agent preference%s", VTY_NEWLINE);
884 return CMD_WARNING;
885 }
886
887 zif->rtadv.HomeAgentPreference = hapref;
888
889 return CMD_SUCCESS;
890}
891
892DEFUN (no_ipv6_nd_homeagent_preference,
893 no_ipv6_nd_homeagent_preference_cmd,
894 "no ipv6 nd home-agent-preference",
895 NO_STR
896 "Interface IPv6 config commands\n"
897 "Neighbor discovery\n"
898 "Home Agent preference\n")
899{
900 struct interface *ifp;
901 struct zebra_if *zif;
902
903 ifp = (struct interface *) vty->index;
904 zif = ifp->info;
905
906 zif->rtadv.HomeAgentPreference = 0;
907
908 return CMD_SUCCESS;
909}
910
911DEFUN (ipv6_nd_homeagent_lifetime,
912 ipv6_nd_homeagent_lifetime_cmd,
913 "ipv6 nd home-agent-lifetime SECONDS",
914 "Interface IPv6 config commands\n"
915 "Neighbor discovery\n"
916 "Home Agent lifetime\n"
917 "Home Agent lifetime in seconds\n")
918{
919 u_int32_t ha_ltime;
920 struct interface *ifp;
921 struct zebra_if *zif;
922
923 ifp = (struct interface *) vty->index;
924 zif = ifp->info;
925
926 ha_ltime = (u_int32_t) atol (argv[0]);
927
928 if (ha_ltime > RTADV_MAX_HALIFETIME)
929 {
930 vty_out (vty, "Invalid Home Agent Lifetime time%s", VTY_NEWLINE);
931 return CMD_WARNING;
932 }
933
934 zif->rtadv.HomeAgentLifetime = ha_ltime;
935
936 return CMD_SUCCESS;
937}
938
939DEFUN (no_ipv6_nd_homeagent_lifetime,
940 no_ipv6_nd_homeagent_lifetime_cmd,
941 "no ipv6 nd home-agent-lifetime",
942 NO_STR
943 "Interface IPv6 config commands\n"
944 "Neighbor discovery\n"
945 "Home Agent lifetime\n")
946{
947 struct interface *ifp;
948 struct zebra_if *zif;
949
950 ifp = (struct interface *) vty->index;
951 zif = ifp->info;
952
953 zif->rtadv.HomeAgentLifetime = 0;
954
955 return CMD_SUCCESS;
956}
957
paul718e3742002-12-13 20:15:29 +0000958DEFUN (ipv6_nd_managed_config_flag,
959 ipv6_nd_managed_config_flag_cmd,
960 "ipv6 nd managed-config-flag",
hasso3e31cde2004-05-18 11:58:59 +0000961 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000962 "Neighbor discovery\n"
963 "Managed address configuration flag\n")
964{
965 struct interface *ifp;
966 struct zebra_if *zif;
967
968 ifp = (struct interface *) vty->index;
969 zif = ifp->info;
970
971 zif->rtadv.AdvManagedFlag = 1;
972
973 return CMD_SUCCESS;
974}
975
976DEFUN (no_ipv6_nd_managed_config_flag,
977 no_ipv6_nd_managed_config_flag_cmd,
978 "no ipv6 nd managed-config-flag",
979 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000980 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000981 "Neighbor discovery\n"
982 "Managed address configuration flag\n")
983{
984 struct interface *ifp;
985 struct zebra_if *zif;
986
987 ifp = (struct interface *) vty->index;
988 zif = ifp->info;
989
990 zif->rtadv.AdvManagedFlag = 0;
991
992 return CMD_SUCCESS;
993}
994
vincent7cee1bb2005-03-25 13:08:53 +0000995DEFUN (ipv6_nd_homeagent_config_flag,
996 ipv6_nd_homeagent_config_flag_cmd,
997 "ipv6 nd home-agent-config-flag",
998 "Interface IPv6 config commands\n"
999 "Neighbor discovery\n"
1000 "Home Agent configuration flag\n")
1001{
1002 struct interface *ifp;
1003 struct zebra_if *zif;
1004
1005 ifp = (struct interface *) vty->index;
1006 zif = ifp->info;
1007
1008 zif->rtadv.AdvHomeAgentFlag = 1;
1009
1010 return CMD_SUCCESS;
1011}
1012
1013DEFUN (no_ipv6_nd_homeagent_config_flag,
1014 no_ipv6_nd_homeagent_config_flag_cmd,
1015 "no ipv6 nd home-agent-config-flag",
1016 NO_STR
1017 "Interface IPv6 config commands\n"
1018 "Neighbor discovery\n"
1019 "Home Agent configuration flag\n")
1020{
1021 struct interface *ifp;
1022 struct zebra_if *zif;
1023
1024 ifp = (struct interface *) vty->index;
1025 zif = ifp->info;
1026
1027 zif->rtadv.AdvHomeAgentFlag = 0;
1028
1029 return CMD_SUCCESS;
1030}
1031
1032DEFUN (ipv6_nd_adv_interval_config_option,
1033 ipv6_nd_adv_interval_config_option_cmd,
1034 "ipv6 nd adv-interval-option",
1035 "Interface IPv6 config commands\n"
1036 "Neighbor discovery\n"
1037 "Advertisement Interval Option\n")
1038{
1039 struct interface *ifp;
1040 struct zebra_if *zif;
1041
1042 ifp = (struct interface *) vty->index;
1043 zif = ifp->info;
1044
1045 zif->rtadv.AdvIntervalOption = 1;
1046
1047 return CMD_SUCCESS;
1048}
1049
1050DEFUN (no_ipv6_nd_adv_interval_config_option,
1051 no_ipv6_nd_adv_interval_config_option_cmd,
1052 "no ipv6 nd adv-interval-option",
1053 NO_STR
1054 "Interface IPv6 config commands\n"
1055 "Neighbor discovery\n"
1056 "Advertisement Interval Option\n")
1057{
1058 struct interface *ifp;
1059 struct zebra_if *zif;
1060
1061 ifp = (struct interface *) vty->index;
1062 zif = ifp->info;
1063
1064 zif->rtadv.AdvIntervalOption = 0;
1065
1066 return CMD_SUCCESS;
1067}
1068
paul718e3742002-12-13 20:15:29 +00001069DEFUN (ipv6_nd_other_config_flag,
1070 ipv6_nd_other_config_flag_cmd,
1071 "ipv6 nd other-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001072 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001073 "Neighbor discovery\n"
1074 "Other statefull configuration flag\n")
1075{
1076 struct interface *ifp;
1077 struct zebra_if *zif;
1078
1079 ifp = (struct interface *) vty->index;
1080 zif = ifp->info;
1081
1082 zif->rtadv.AdvOtherConfigFlag = 1;
1083
1084 return CMD_SUCCESS;
1085}
1086
1087DEFUN (no_ipv6_nd_other_config_flag,
1088 no_ipv6_nd_other_config_flag_cmd,
1089 "no ipv6 nd other-config-flag",
1090 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001091 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001092 "Neighbor discovery\n"
1093 "Other statefull configuration flag\n")
1094{
1095 struct interface *ifp;
1096 struct zebra_if *zif;
1097
1098 ifp = (struct interface *) vty->index;
1099 zif = ifp->info;
1100
1101 zif->rtadv.AdvOtherConfigFlag = 0;
1102
1103 return CMD_SUCCESS;
1104}
1105
hasso3e31cde2004-05-18 11:58:59 +00001106DEFUN (ipv6_nd_prefix,
1107 ipv6_nd_prefix_cmd,
1108 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
vincent7cee1bb2005-03-25 13:08:53 +00001109 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)",
hasso3e31cde2004-05-18 11:58:59 +00001110 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001111 "Neighbor discovery\n"
1112 "Prefix information\n"
1113 "IPv6 prefix\n"
1114 "Valid lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001115 "Infinite valid lifetime\n"
paul718e3742002-12-13 20:15:29 +00001116 "Preferred lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001117 "Infinite preferred lifetime\n"
1118 "Do not use prefix for onlink determination\n"
vincent7cee1bb2005-03-25 13:08:53 +00001119 "Do not use prefix for autoconfiguration\n"
1120 "Set Router Address flag\n")
paul718e3742002-12-13 20:15:29 +00001121{
1122 int i;
1123 int ret;
hasso3e31cde2004-05-18 11:58:59 +00001124 int cursor = 1;
paul718e3742002-12-13 20:15:29 +00001125 struct interface *ifp;
1126 struct zebra_if *zebra_if;
1127 struct rtadv_prefix rp;
1128
1129 ifp = (struct interface *) vty->index;
1130 zebra_if = ifp->info;
1131
1132 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
1133 if (!ret)
1134 {
1135 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1136 return CMD_WARNING;
1137 }
hasso3e31cde2004-05-18 11:58:59 +00001138 rp.AdvOnLinkFlag = 1;
1139 rp.AdvAutonomousFlag = 1;
vincent7cee1bb2005-03-25 13:08:53 +00001140 rp.AdvRouterAddressFlag = 0;
hasso3e31cde2004-05-18 11:58:59 +00001141 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1142 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
paul718e3742002-12-13 20:15:29 +00001143
hasso3e31cde2004-05-18 11:58:59 +00001144 if (argc > 1)
paul718e3742002-12-13 20:15:29 +00001145 {
hasso3e31cde2004-05-18 11:58:59 +00001146 if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0)
paul718e3742002-12-13 20:15:29 +00001147 {
hasso3e31cde2004-05-18 11:58:59 +00001148 if ( strncmp (argv[1], "i", 1) == 0)
1149 rp.AdvValidLifetime = UINT32_MAX;
1150 else
1151 rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
1152 (char **)NULL, 10);
1153
1154 if ( strncmp (argv[2], "i", 1) == 0)
1155 rp.AdvPreferredLifetime = UINT32_MAX;
1156 else
1157 rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
1158 (char **)NULL, 10);
1159
1160 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
1161 {
1162 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
1163 return CMD_WARNING;
1164 }
1165 cursor = cursor + 2;
paul718e3742002-12-13 20:15:29 +00001166 }
hasso3e31cde2004-05-18 11:58:59 +00001167 if (argc > cursor)
paul718e3742002-12-13 20:15:29 +00001168 {
hasso3e31cde2004-05-18 11:58:59 +00001169 for (i = cursor; i < argc; i++)
1170 {
1171 if (strncmp (argv[i], "of", 2) == 0)
1172 rp.AdvOnLinkFlag = 0;
1173 if (strncmp (argv[i], "no", 2) == 0)
1174 rp.AdvAutonomousFlag = 0;
vincent7cee1bb2005-03-25 13:08:53 +00001175 if (strncmp (argv[i], "ro", 2) == 0)
1176 rp.AdvRouterAddressFlag = 1;
hasso3e31cde2004-05-18 11:58:59 +00001177 }
paul718e3742002-12-13 20:15:29 +00001178 }
1179 }
1180
1181 rtadv_prefix_set (zebra_if, &rp);
1182
1183 return CMD_SUCCESS;
1184}
1185
hasso3e31cde2004-05-18 11:58:59 +00001186ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001187 ipv6_nd_prefix_val_nortaddr_cmd,
1188 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1189 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
1190 "Interface IPv6 config commands\n"
1191 "Neighbor discovery\n"
1192 "Prefix information\n"
1193 "IPv6 prefix\n"
1194 "Valid lifetime in seconds\n"
1195 "Infinite valid lifetime\n"
1196 "Preferred lifetime in seconds\n"
1197 "Infinite preferred lifetime\n"
1198 "Do not use prefix for onlink determination\n"
1199 "Do not use prefix for autoconfiguration\n")
1200
1201ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001202 ipv6_nd_prefix_val_rev_cmd,
1203 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1204 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
1205 "Interface IPv6 config commands\n"
1206 "Neighbor discovery\n"
1207 "Prefix information\n"
1208 "IPv6 prefix\n"
1209 "Valid lifetime in seconds\n"
1210 "Infinite valid lifetime\n"
1211 "Preferred lifetime in seconds\n"
1212 "Infinite preferred lifetime\n"
1213 "Do not use prefix for autoconfiguration\n"
1214 "Do not use prefix for onlink determination\n")
1215
1216ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001217 ipv6_nd_prefix_val_rev_rtaddr_cmd,
1218 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1219 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)",
1220 "Interface IPv6 config commands\n"
1221 "Neighbor discovery\n"
1222 "Prefix information\n"
1223 "IPv6 prefix\n"
1224 "Valid lifetime in seconds\n"
1225 "Infinite valid lifetime\n"
1226 "Preferred lifetime in seconds\n"
1227 "Infinite preferred lifetime\n"
1228 "Do not use prefix for autoconfiguration\n"
1229 "Do not use prefix for onlink determination\n"
1230 "Set Router Address flag\n")
1231
1232ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001233 ipv6_nd_prefix_val_noauto_cmd,
1234 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1235 "(<0-4294967295>|infinite) (no-autoconfig|)",
1236 "Interface IPv6 config commands\n"
1237 "Neighbor discovery\n"
1238 "Prefix information\n"
1239 "IPv6 prefix\n"
1240 "Valid lifetime in seconds\n"
1241 "Infinite valid lifetime\n"
1242 "Preferred lifetime in seconds\n"
1243 "Infinite preferred lifetime\n"
vincent7cee1bb2005-03-25 13:08:53 +00001244 "Do not use prefix for autoconfiguration")
hasso3e31cde2004-05-18 11:58:59 +00001245
1246ALIAS (ipv6_nd_prefix,
1247 ipv6_nd_prefix_val_offlink_cmd,
1248 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1249 "(<0-4294967295>|infinite) (off-link|)",
1250 "Interface IPv6 config commands\n"
1251 "Neighbor discovery\n"
1252 "Prefix information\n"
1253 "IPv6 prefix\n"
1254 "Valid lifetime in seconds\n"
1255 "Infinite valid lifetime\n"
1256 "Preferred lifetime in seconds\n"
1257 "Infinite preferred lifetime\n"
1258 "Do not use prefix for onlink determination\n")
1259
1260ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001261 ipv6_nd_prefix_val_rtaddr_cmd,
1262 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1263 "(<0-4294967295>|infinite) (router-address|)",
1264 "Interface IPv6 config commands\n"
1265 "Neighbor discovery\n"
1266 "Prefix information\n"
1267 "IPv6 prefix\n"
1268 "Valid lifetime in seconds\n"
1269 "Infinite valid lifetime\n"
1270 "Preferred lifetime in seconds\n"
1271 "Infinite preferred lifetime\n"
1272 "Set Router Address flag\n")
1273
1274ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001275 ipv6_nd_prefix_val_cmd,
1276 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1277 "(<0-4294967295>|infinite)",
1278 "Interface IPv6 config commands\n"
1279 "Neighbor discovery\n"
1280 "Prefix information\n"
1281 "IPv6 prefix\n"
1282 "Valid lifetime in seconds\n"
1283 "Infinite valid lifetime\n"
1284 "Preferred lifetime in seconds\n"
1285 "Infinite preferred lifetime\n")
1286
1287ALIAS (ipv6_nd_prefix,
1288 ipv6_nd_prefix_noval_cmd,
1289 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
1290 "Interface IPv6 config commands\n"
1291 "Neighbor discovery\n"
1292 "Prefix information\n"
1293 "IPv6 prefix\n"
1294 "Do not use prefix for autoconfiguration\n"
1295 "Do not use prefix for onlink determination\n")
1296
1297ALIAS (ipv6_nd_prefix,
1298 ipv6_nd_prefix_noval_rev_cmd,
1299 "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
1300 "Interface IPv6 config commands\n"
1301 "Neighbor discovery\n"
1302 "Prefix information\n"
1303 "IPv6 prefix\n"
1304 "Do not use prefix for onlink determination\n"
1305 "Do not use prefix for autoconfiguration\n")
1306
1307ALIAS (ipv6_nd_prefix,
1308 ipv6_nd_prefix_noval_noauto_cmd,
1309 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
1310 "Interface IPv6 config commands\n"
1311 "Neighbor discovery\n"
1312 "Prefix information\n"
1313 "IPv6 prefix\n"
1314 "Do not use prefix for autoconfiguration\n")
1315
1316ALIAS (ipv6_nd_prefix,
1317 ipv6_nd_prefix_noval_offlink_cmd,
1318 "ipv6 nd prefix X:X::X:X/M (off-link|)",
1319 "Interface IPv6 config commands\n"
1320 "Neighbor discovery\n"
1321 "Prefix information\n"
1322 "IPv6 prefix\n"
1323 "Do not use prefix for onlink determination\n")
1324
1325ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001326 ipv6_nd_prefix_noval_rtaddr_cmd,
1327 "ipv6 nd prefix X:X::X:X/M (router-address|)",
1328 "Interface IPv6 config commands\n"
1329 "Neighbor discovery\n"
1330 "Prefix information\n"
1331 "IPv6 prefix\n"
1332 "Set Router Address flag\n")
1333
1334ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001335 ipv6_nd_prefix_prefix_cmd,
1336 "ipv6 nd prefix X:X::X:X/M",
1337 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001338 "Neighbor discovery\n"
1339 "Prefix information\n"
1340 "IPv6 prefix\n")
1341
hasso3e31cde2004-05-18 11:58:59 +00001342DEFUN (no_ipv6_nd_prefix,
1343 no_ipv6_nd_prefix_cmd,
1344 "no ipv6 nd prefix IPV6PREFIX",
paul718e3742002-12-13 20:15:29 +00001345 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001346 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001347 "Neighbor discovery\n"
1348 "Prefix information\n"
1349 "IPv6 prefix\n")
1350{
1351 int ret;
1352 struct interface *ifp;
1353 struct zebra_if *zebra_if;
1354 struct rtadv_prefix rp;
1355
1356 ifp = (struct interface *) vty->index;
1357 zebra_if = ifp->info;
1358
1359 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix);
1360 if (!ret)
1361 {
1362 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1363 return CMD_WARNING;
1364 }
1365
1366 ret = rtadv_prefix_reset (zebra_if, &rp);
1367 if (!ret)
1368 {
1369 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1370 return CMD_WARNING;
1371 }
1372
1373 return CMD_SUCCESS;
1374}
paul718e3742002-12-13 20:15:29 +00001375/* Write configuration about router advertisement. */
1376void
1377rtadv_config_write (struct vty *vty, struct interface *ifp)
1378{
1379 struct zebra_if *zif;
hasso52dc7ee2004-09-23 19:18:23 +00001380 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001381 struct rtadv_prefix *rprefix;
1382 u_char buf[INET6_ADDRSTRLEN];
vincent7cee1bb2005-03-25 13:08:53 +00001383 int interval;
paul718e3742002-12-13 20:15:29 +00001384
1385 if (! rtadv)
1386 return;
1387
1388 zif = ifp->info;
1389
1390 if (! if_is_loopback (ifp))
1391 {
1392 if (zif->rtadv.AdvSendAdvertisements)
1393 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1394 else
1395 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1396 }
1397
vincent7cee1bb2005-03-25 13:08:53 +00001398
1399 interval = zif->rtadv.MaxRtrAdvInterval;
1400 if (interval % 1000)
1401 vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval,
1402 VTY_NEWLINE);
1403 else
1404 if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1405 vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
paul718e3742002-12-13 20:15:29 +00001406 VTY_NEWLINE);
1407
1408 if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
1409 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1410 VTY_NEWLINE);
1411
1412 if (zif->rtadv.AdvReachableTime)
1413 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1414 VTY_NEWLINE);
1415
1416 if (zif->rtadv.AdvManagedFlag)
1417 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1418
1419 if (zif->rtadv.AdvOtherConfigFlag)
1420 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1421
paul1eb8ef22005-04-07 07:30:20 +00001422 for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
paul718e3742002-12-13 20:15:29 +00001423 {
hasso3e31cde2004-05-18 11:58:59 +00001424 vty_out (vty, " ipv6 nd prefix %s/%d",
paul718e3742002-12-13 20:15:29 +00001425 inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6,
hassoc9e52be2004-09-26 16:09:34 +00001426 (char *) buf, INET6_ADDRSTRLEN),
hasso3e31cde2004-05-18 11:58:59 +00001427 rprefix->prefix.prefixlen);
1428 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1429 (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1430 {
1431 if (rprefix->AdvValidLifetime == UINT32_MAX)
1432 vty_out (vty, " infinite");
1433 else
1434 vty_out (vty, " %u", rprefix->AdvValidLifetime);
1435 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1436 vty_out (vty, " infinite");
1437 else
1438 vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1439 }
1440 if (!rprefix->AdvOnLinkFlag)
1441 vty_out (vty, " off-link");
1442 if (!rprefix->AdvAutonomousFlag)
1443 vty_out (vty, " no-autoconfig");
vincent7cee1bb2005-03-25 13:08:53 +00001444 if (rprefix->AdvRouterAddressFlag)
1445 vty_out (vty, " router-address");
paul718e3742002-12-13 20:15:29 +00001446 vty_out (vty, "%s", VTY_NEWLINE);
1447 }
1448}
1449
paul718e3742002-12-13 20:15:29 +00001450
paula1ac18c2005-06-28 17:17:12 +00001451static void
paul718e3742002-12-13 20:15:29 +00001452rtadv_event (enum rtadv_event event, int val)
1453{
1454 switch (event)
1455 {
1456 case RTADV_START:
1457 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001458 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001459 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001460 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
1461 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001462 break;
1463 case RTADV_STOP:
1464 if (rtadv->ra_timer)
1465 {
1466 thread_cancel (rtadv->ra_timer);
1467 rtadv->ra_timer = NULL;
1468 }
1469 if (rtadv->ra_read)
1470 {
1471 thread_cancel (rtadv->ra_read);
1472 rtadv->ra_read = NULL;
1473 }
1474 break;
1475 case RTADV_TIMER:
1476 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001477 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
1478 val);
paul718e3742002-12-13 20:15:29 +00001479 break;
vincent7cee1bb2005-03-25 13:08:53 +00001480 case RTADV_TIMER_MSEC:
1481 if (! rtadv->ra_timer)
1482 rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer,
1483 NULL, val);
1484 break;
paul718e3742002-12-13 20:15:29 +00001485 case RTADV_READ:
1486 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001487 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001488 break;
1489 default:
1490 break;
1491 }
1492 return;
1493}
1494
1495void
paula1ac18c2005-06-28 17:17:12 +00001496rtadv_init (void)
paul718e3742002-12-13 20:15:29 +00001497{
1498 int sock;
1499
1500 sock = rtadv_make_socket ();
1501 if (sock < 0)
1502 return;
1503
1504 rtadv = rtadv_new ();
1505 rtadv->sock = sock;
1506
1507 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1508 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
paul718e3742002-12-13 20:15:29 +00001509 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001510 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
paul718e3742002-12-13 20:15:29 +00001511 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1512 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1513 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1514 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1515 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1516 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1517 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1518 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1519 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001520 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1521 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1522 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1523 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
1524 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1525 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
1526 install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
1527 install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001528 install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001529 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd);
1530 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001531 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1532 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1533 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001534 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001535 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1536 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1537 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1538 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1539 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001540 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001541 install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1542 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
paul718e3742002-12-13 20:15:29 +00001543}
1544
paula1ac18c2005-06-28 17:17:12 +00001545static int
paul718e3742002-12-13 20:15:29 +00001546if_join_all_router (int sock, struct interface *ifp)
1547{
1548 int ret;
1549
1550 struct ipv6_mreq mreq;
1551
1552 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1553 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1554 mreq.ipv6mr_interface = ifp->ifindex;
1555
1556 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1557 (char *) &mreq, sizeof mreq);
1558 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001559 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001560
1561 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1562
1563 return 0;
1564}
1565
paula1ac18c2005-06-28 17:17:12 +00001566static int
paul718e3742002-12-13 20:15:29 +00001567if_leave_all_router (int sock, struct interface *ifp)
1568{
1569 int ret;
1570
1571 struct ipv6_mreq mreq;
1572
1573 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1574 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1575 mreq.ipv6mr_interface = ifp->ifindex;
1576
1577 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1578 (char *) &mreq, sizeof mreq);
1579 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001580 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001581
1582 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1583
1584 return 0;
1585}
1586
1587#else
1588void
paula1ac18c2005-06-28 17:17:12 +00001589rtadv_init (void)
paul718e3742002-12-13 20:15:29 +00001590{
1591 /* Empty.*/;
1592}
1593#endif /* RTADV && HAVE_IPV6 */