]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* Router advertisement |
7cee1bb1 | 2 | * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com> |
718e3744 | 3 | * 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" | |
edd7c245 | 33 | #include "privs.h" |
718e3744 | 34 | |
35 | #include "zebra/interface.h" | |
36 | #include "zebra/rtadv.h" | |
37 | #include "zebra/debug.h" | |
537d8ea9 | 38 | #include "zebra/rib.h" |
4b5e1359 | 39 | #include "zebra/zserv.h" |
718e3744 | 40 | |
edd7c245 | 41 | extern struct zebra_privs_t zserv_privs; |
42 | ||
718e3744 | 43 | #if defined (HAVE_IPV6) && defined (RTADV) |
44 | ||
fa2b17e3 | 45 | #ifdef OPEN_BSD |
46 | #include <netinet/icmp6.h> | |
47 | #endif | |
48 | ||
718e3744 | 49 | /* 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 | ||
b21b19c5 | 60 | extern struct zebra_t zebrad; |
61 | ||
7cee1bb1 | 62 | enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, |
63 | RTADV_TIMER_MSEC, RTADV_READ}; | |
718e3744 | 64 | |
a1ac18c4 | 65 | static void rtadv_event (enum rtadv_event, int); |
718e3744 | 66 | |
a1ac18c4 | 67 | static int if_join_all_router (int, struct interface *); |
68 | static int if_leave_all_router (int, struct interface *); | |
718e3744 | 69 | \f |
70 | /* Structure which hold status of router advertisement. */ | |
71 | struct rtadv | |
72 | { | |
73 | int sock; | |
74 | ||
75 | int adv_if_count; | |
7cee1bb1 | 76 | int adv_msec_if_count; |
718e3744 | 77 | |
78 | struct thread *ra_read; | |
79 | struct thread *ra_timer; | |
80 | }; | |
81 | ||
82 | struct rtadv *rtadv = NULL; | |
83 | \f | |
a1ac18c4 | 84 | static struct rtadv * |
85 | rtadv_new (void) | |
718e3744 | 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 | ||
a1ac18c4 | 93 | static void |
718e3744 | 94 | rtadv_free (struct rtadv *rtadv) |
95 | { | |
96 | XFREE (MTYPE_TMP, rtadv); | |
97 | } | |
98 | ||
a1ac18c4 | 99 | static int |
718e3744 | 100 | rtadv_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 | ||
b99760ab | 127 | for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL; |
718e3744 | 128 | 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. */ | |
a1ac18c4 | 152 | static void |
718e3744 | 153 | rtadv_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; | |
edd7c245 | 160 | #ifdef HAVE_SOCKADDR_DL |
718e3744 | 161 | struct sockaddr_dl *sdl; |
162 | #endif /* HAVE_SOCKADDR_DL */ | |
57492d56 | 163 | static void *adata = NULL; |
718e3744 | 164 | unsigned char buf[RTADV_MSG_SIZE]; |
165 | struct nd_router_advert *rtadv; | |
166 | int ret; | |
167 | int len = 0; | |
168 | struct zebra_if *zif; | |
1eb8ef25 | 169 | struct rtadv_prefix *rprefix; |
718e3744 | 170 | u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; |
52dc7ee6 | 171 | struct listnode *node; |
718e3744 | 172 | |
57492d56 | 173 | /* |
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 | ||
718e3744 | 188 | /* Logging of packet. */ |
189 | if (IS_ZEBRA_DEBUG_PACKET) | |
b6178002 | 190 | zlog_debug ("Router advertisement send to %s", ifp->name); |
718e3744 | 191 | |
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; | |
7cee1bb1 | 217 | if (zif->rtadv.AdvHomeAgentFlag) |
218 | rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT; | |
718e3744 | 219 | 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 | ||
7cee1bb1 | 225 | 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 | ||
718e3744 | 248 | /* Fill in prefix. */ |
1eb8ef25 | 249 | for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) |
718e3744 | 250 | { |
251 | struct nd_opt_prefix_info *pinfo; | |
718e3744 | 252 | |
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; | |
7cee1bb1 | 264 | if (rprefix->AdvRouterAddressFlag) |
265 | pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR; | |
718e3744 | 266 | |
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 | ||
b6178002 | 278 | zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, |
3e31cded | 279 | buf, INET6_ADDRSTRLEN)); |
718e3744 | 280 | |
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; | |
f841e02e | 314 | msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); |
57492d56 | 315 | msg.msg_flags = 0; |
718e3744 | 316 | iov.iov_base = buf; |
317 | iov.iov_len = len; | |
318 | ||
b99760ab | 319 | cmsgptr = ZCMSG_FIRSTHDR(&msg); |
57492d56 | 320 | cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); |
718e3744 | 321 | cmsgptr->cmsg_level = IPPROTO_IPV6; |
322 | cmsgptr->cmsg_type = IPV6_PKTINFO; | |
80893817 | 323 | |
718e3744 | 324 | 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); | |
9ccabd1c | 329 | if (ret < 0) |
330 | { | |
331 | zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n", | |
6099b3b5 | 332 | errno, safe_strerror(errno)); |
9ccabd1c | 333 | } |
718e3744 | 334 | } |
335 | ||
a1ac18c4 | 336 | static int |
718e3744 | 337 | rtadv_timer (struct thread *thread) |
338 | { | |
1eb8ef25 | 339 | struct listnode *node, *nnode; |
718e3744 | 340 | struct interface *ifp; |
341 | struct zebra_if *zif; | |
7cee1bb1 | 342 | int period; |
718e3744 | 343 | |
344 | rtadv->ra_timer = NULL; | |
7cee1bb1 | 345 | 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 | } | |
718e3744 | 355 | |
1eb8ef25 | 356 | for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) |
718e3744 | 357 | { |
718e3744 | 358 | if (if_is_loopback (ifp)) |
359 | continue; | |
360 | ||
361 | zif = ifp->info; | |
362 | ||
363 | if (zif->rtadv.AdvSendAdvertisements) | |
7cee1bb1 | 364 | { |
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 | } | |
718e3744 | 372 | } |
373 | return 0; | |
374 | } | |
375 | ||
a1ac18c4 | 376 | static void |
718e3744 | 377 | rtadv_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 | ||
a1ac18c4 | 384 | static void |
385 | rtadv_process_advert (void) | |
718e3744 | 386 | { |
387 | zlog_info ("Router advertisement received"); | |
388 | } | |
389 | ||
a1ac18c4 | 390 | static void |
fce954f8 | 391 | rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit) |
718e3744 | 392 | { |
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 | ||
a1ac18c4 | 447 | static int |
718e3744 | 448 | rtadv_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 | { | |
6099b3b5 | 467 | zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno)); |
718e3744 | 468 | return len; |
469 | } | |
470 | ||
fce954f8 | 471 | rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit); |
718e3744 | 472 | |
473 | return 0; | |
474 | } | |
475 | ||
a1ac18c4 | 476 | static int |
718e3744 | 477 | rtadv_make_socket (void) |
478 | { | |
479 | int sock; | |
480 | int ret; | |
481 | struct icmp6_filter filter; | |
482 | ||
edd7c245 | 483 | if ( zserv_privs.change (ZPRIVS_RAISE) ) |
484 | zlog_err ("rtadv_make_socket: could not raise privs, %s", | |
6099b3b5 | 485 | safe_strerror (errno) ); |
edd7c245 | 486 | |
718e3744 | 487 | sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); |
488 | ||
edd7c245 | 489 | if ( zserv_privs.change (ZPRIVS_LOWER) ) |
490 | zlog_err ("rtadv_make_socket: could not lower privs, %s", | |
6099b3b5 | 491 | safe_strerror (errno) ); |
edd7c245 | 492 | |
718e3744 | 493 | /* 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); | |
718e3744 | 499 | if (ret < 0) |
500 | return ret; | |
501 | 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 | { | |
6099b3b5 | 522 | zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno)); |
718e3744 | 523 | return ret; |
524 | } | |
525 | ||
526 | return sock; | |
527 | } | |
528 | \f | |
a1ac18c4 | 529 | static struct rtadv_prefix * |
718e3744 | 530 | rtadv_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 | ||
a1ac18c4 | 540 | static void |
718e3744 | 541 | rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix) |
542 | { | |
543 | XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix); | |
544 | } | |
545 | ||
a1ac18c4 | 546 | static struct rtadv_prefix * |
52dc7ee6 | 547 | rtadv_prefix_lookup (struct list *rplist, struct prefix *p) |
718e3744 | 548 | { |
52dc7ee6 | 549 | struct listnode *node; |
718e3744 | 550 | struct rtadv_prefix *rprefix; |
551 | ||
1eb8ef25 | 552 | for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix)) |
553 | if (prefix_same (&rprefix->prefix, p)) | |
554 | return rprefix; | |
718e3744 | 555 | return NULL; |
556 | } | |
557 | ||
a1ac18c4 | 558 | static struct rtadv_prefix * |
52dc7ee6 | 559 | rtadv_prefix_get (struct list *rplist, struct prefix *p) |
718e3744 | 560 | { |
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 | ||
a1ac18c4 | 574 | static void |
718e3744 | 575 | rtadv_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; | |
7cee1bb1 | 586 | rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag; |
718e3744 | 587 | } |
588 | ||
a1ac18c4 | 589 | static int |
718e3744 | 590 | rtadv_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 | ||
605 | DEFUN (ipv6_nd_suppress_ra, | |
606 | ipv6_nd_suppress_ra_cmd, | |
607 | "ipv6 nd suppress-ra", | |
3e31cded | 608 | "Interface IPv6 config commands\n" |
718e3744 | 609 | "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 | ||
718e3744 | 639 | DEFUN (no_ipv6_nd_suppress_ra, |
640 | no_ipv6_nd_suppress_ra_cmd, | |
641 | "no ipv6 nd suppress-ra", | |
642 | NO_STR | |
3e31cded | 643 | "Interface IPv6 config commands\n" |
718e3744 | 644 | "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 | ||
7cee1bb1 | 674 | DEFUN (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 | ||
718e3744 | 710 | DEFUN (ipv6_nd_ra_interval, |
711 | ipv6_nd_ra_interval_cmd, | |
712 | "ipv6 nd ra-interval SECONDS", | |
3e31cded | 713 | "Interface IPv6 config commands\n" |
718e3744 | 714 | "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 | ||
7cee1bb1 | 727 | if (interval <= 0) |
718e3744 | 728 | { |
729 | vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE); | |
730 | return CMD_WARNING; | |
731 | } | |
732 | ||
7cee1bb1 | 733 | if (zif->rtadv.MaxRtrAdvInterval % 1000) |
734 | rtadv->adv_msec_if_count--; | |
735 | ||
736 | /* convert to milliseconds */ | |
737 | interval = interval * 1000; | |
738 | ||
718e3744 | 739 | zif->rtadv.MaxRtrAdvInterval = interval; |
740 | zif->rtadv.MinRtrAdvInterval = 0.33 * interval; | |
741 | zif->rtadv.AdvIntervalTimer = 0; | |
742 | ||
743 | return CMD_SUCCESS; | |
744 | } | |
745 | ||
746 | DEFUN (no_ipv6_nd_ra_interval, | |
747 | no_ipv6_nd_ra_interval_cmd, | |
748 | "no ipv6 nd ra-interval", | |
749 | NO_STR | |
3e31cded | 750 | "Interface IPv6 config commands\n" |
718e3744 | 751 | "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 | ||
7cee1bb1 | 760 | if (zif->rtadv.MaxRtrAdvInterval % 1000) |
761 | rtadv->adv_msec_if_count--; | |
762 | ||
718e3744 | 763 | 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 | ||
770 | DEFUN (ipv6_nd_ra_lifetime, | |
771 | ipv6_nd_ra_lifetime_cmd, | |
772 | "ipv6 nd ra-lifetime SECONDS", | |
3e31cded | 773 | "Interface IPv6 config commands\n" |
718e3744 | 774 | "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 | ||
798 | DEFUN (no_ipv6_nd_ra_lifetime, | |
799 | no_ipv6_nd_ra_lifetime_cmd, | |
800 | "no ipv6 nd ra-lifetime", | |
801 | NO_STR | |
3e31cded | 802 | "Interface IPv6 config commands\n" |
718e3744 | 803 | "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 | ||
817 | DEFUN (ipv6_nd_reachable_time, | |
818 | ipv6_nd_reachable_time_cmd, | |
819 | "ipv6 nd reachable-time MILLISECONDS", | |
3e31cded | 820 | "Interface IPv6 config commands\n" |
718e3744 | 821 | "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 | ||
845 | DEFUN (no_ipv6_nd_reachable_time, | |
846 | no_ipv6_nd_reachable_time_cmd, | |
847 | "no ipv6 nd reachable-time", | |
848 | NO_STR | |
3e31cded | 849 | "Interface IPv6 config commands\n" |
718e3744 | 850 | "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 | ||
7cee1bb1 | 864 | DEFUN (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 | ||
892 | DEFUN (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 | ||
911 | DEFUN (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 | ||
939 | DEFUN (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 | ||
718e3744 | 958 | DEFUN (ipv6_nd_managed_config_flag, |
959 | ipv6_nd_managed_config_flag_cmd, | |
960 | "ipv6 nd managed-config-flag", | |
3e31cded | 961 | "Interface IPv6 config commands\n" |
718e3744 | 962 | "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 | ||
976 | DEFUN (no_ipv6_nd_managed_config_flag, | |
977 | no_ipv6_nd_managed_config_flag_cmd, | |
978 | "no ipv6 nd managed-config-flag", | |
979 | NO_STR | |
3e31cded | 980 | "Interface IPv6 config commands\n" |
718e3744 | 981 | "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 | ||
7cee1bb1 | 995 | DEFUN (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 | ||
1013 | DEFUN (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 | ||
1032 | DEFUN (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 | ||
1050 | DEFUN (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 | ||
718e3744 | 1069 | DEFUN (ipv6_nd_other_config_flag, |
1070 | ipv6_nd_other_config_flag_cmd, | |
1071 | "ipv6 nd other-config-flag", | |
3e31cded | 1072 | "Interface IPv6 config commands\n" |
718e3744 | 1073 | "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 | ||
1087 | DEFUN (no_ipv6_nd_other_config_flag, | |
1088 | no_ipv6_nd_other_config_flag_cmd, | |
1089 | "no ipv6 nd other-config-flag", | |
1090 | NO_STR | |
3e31cded | 1091 | "Interface IPv6 config commands\n" |
718e3744 | 1092 | "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 | ||
3e31cded | 1106 | DEFUN (ipv6_nd_prefix, |
1107 | ipv6_nd_prefix_cmd, | |
1108 | "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " | |
7cee1bb1 | 1109 | "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)", |
3e31cded | 1110 | "Interface IPv6 config commands\n" |
718e3744 | 1111 | "Neighbor discovery\n" |
1112 | "Prefix information\n" | |
1113 | "IPv6 prefix\n" | |
1114 | "Valid lifetime in seconds\n" | |
3e31cded | 1115 | "Infinite valid lifetime\n" |
718e3744 | 1116 | "Preferred lifetime in seconds\n" |
3e31cded | 1117 | "Infinite preferred lifetime\n" |
1118 | "Do not use prefix for onlink determination\n" | |
7cee1bb1 | 1119 | "Do not use prefix for autoconfiguration\n" |
1120 | "Set Router Address flag\n") | |
718e3744 | 1121 | { |
1122 | int i; | |
1123 | int ret; | |
3e31cded | 1124 | int cursor = 1; |
718e3744 | 1125 | 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 | } | |
3e31cded | 1138 | rp.AdvOnLinkFlag = 1; |
1139 | rp.AdvAutonomousFlag = 1; | |
7cee1bb1 | 1140 | rp.AdvRouterAddressFlag = 0; |
3e31cded | 1141 | rp.AdvValidLifetime = RTADV_VALID_LIFETIME; |
1142 | rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; | |
718e3744 | 1143 | |
3e31cded | 1144 | if (argc > 1) |
718e3744 | 1145 | { |
3e31cded | 1146 | if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0) |
718e3744 | 1147 | { |
3e31cded | 1148 | 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; | |
718e3744 | 1166 | } |
3e31cded | 1167 | if (argc > cursor) |
718e3744 | 1168 | { |
3e31cded | 1169 | 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; | |
7cee1bb1 | 1175 | if (strncmp (argv[i], "ro", 2) == 0) |
1176 | rp.AdvRouterAddressFlag = 1; | |
3e31cded | 1177 | } |
718e3744 | 1178 | } |
1179 | } | |
1180 | ||
1181 | rtadv_prefix_set (zebra_if, &rp); | |
1182 | ||
1183 | return CMD_SUCCESS; | |
1184 | } | |
1185 | ||
7cee1bb1 | 1186 | ALIAS (ipv6_nd_prefix, |
1187 | 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 | ||
3e31cded | 1201 | ALIAS (ipv6_nd_prefix, |
1202 | 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 | ||
7cee1bb1 | 1216 | ALIAS (ipv6_nd_prefix, |
1217 | 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 | ||
3e31cded | 1232 | ALIAS (ipv6_nd_prefix, |
1233 | 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" | |
7cee1bb1 | 1244 | "Do not use prefix for autoconfiguration") |
3e31cded | 1245 | |
1246 | ALIAS (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 | ||
7cee1bb1 | 1260 | ALIAS (ipv6_nd_prefix, |
1261 | 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 | ||
3e31cded | 1274 | ALIAS (ipv6_nd_prefix, |
1275 | 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 | ||
1287 | ALIAS (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 | ||
1297 | ALIAS (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 | ||
1307 | ALIAS (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 | ||
1316 | ALIAS (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 | ||
7cee1bb1 | 1325 | ALIAS (ipv6_nd_prefix, |
1326 | 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 | ||
3e31cded | 1334 | ALIAS (ipv6_nd_prefix, |
1335 | ipv6_nd_prefix_prefix_cmd, | |
1336 | "ipv6 nd prefix X:X::X:X/M", | |
1337 | "Interface IPv6 config commands\n" | |
718e3744 | 1338 | "Neighbor discovery\n" |
1339 | "Prefix information\n" | |
1340 | "IPv6 prefix\n") | |
1341 | ||
3e31cded | 1342 | DEFUN (no_ipv6_nd_prefix, |
1343 | no_ipv6_nd_prefix_cmd, | |
1344 | "no ipv6 nd prefix IPV6PREFIX", | |
718e3744 | 1345 | NO_STR |
3e31cded | 1346 | "Interface IPv6 config commands\n" |
718e3744 | 1347 | "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 | } | |
718e3744 | 1375 | /* Write configuration about router advertisement. */ |
1376 | void | |
1377 | rtadv_config_write (struct vty *vty, struct interface *ifp) | |
1378 | { | |
1379 | struct zebra_if *zif; | |
52dc7ee6 | 1380 | struct listnode *node; |
718e3744 | 1381 | struct rtadv_prefix *rprefix; |
1382 | u_char buf[INET6_ADDRSTRLEN]; | |
7cee1bb1 | 1383 | int interval; |
718e3744 | 1384 | |
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 | ||
7cee1bb1 | 1398 | |
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, | |
718e3744 | 1406 | 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 | ||
1eb8ef25 | 1422 | for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) |
718e3744 | 1423 | { |
3e31cded | 1424 | vty_out (vty, " ipv6 nd prefix %s/%d", |
718e3744 | 1425 | inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6, |
c9e52be3 | 1426 | (char *) buf, INET6_ADDRSTRLEN), |
3e31cded | 1427 | 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"); | |
7cee1bb1 | 1444 | if (rprefix->AdvRouterAddressFlag) |
1445 | vty_out (vty, " router-address"); | |
718e3744 | 1446 | vty_out (vty, "%s", VTY_NEWLINE); |
1447 | } | |
1448 | } | |
1449 | ||
718e3744 | 1450 | |
a1ac18c4 | 1451 | static void |
718e3744 | 1452 | rtadv_event (enum rtadv_event event, int val) |
1453 | { | |
1454 | switch (event) | |
1455 | { | |
1456 | case RTADV_START: | |
1457 | if (! rtadv->ra_read) | |
b21b19c5 | 1458 | rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); |
718e3744 | 1459 | if (! rtadv->ra_timer) |
3e31cded | 1460 | rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer, |
1461 | NULL, 0); | |
718e3744 | 1462 | 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) | |
3e31cded | 1477 | rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL, |
1478 | val); | |
718e3744 | 1479 | break; |
7cee1bb1 | 1480 | 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; | |
718e3744 | 1485 | case RTADV_READ: |
1486 | if (! rtadv->ra_read) | |
b21b19c5 | 1487 | rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); |
718e3744 | 1488 | break; |
1489 | default: | |
1490 | break; | |
1491 | } | |
1492 | return; | |
1493 | } | |
1494 | ||
1495 | void | |
a1ac18c4 | 1496 | rtadv_init (void) |
718e3744 | 1497 | { |
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); | |
718e3744 | 1509 | install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); |
7cee1bb1 | 1510 | install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd); |
718e3744 | 1511 | 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); | |
7cee1bb1 | 1520 | 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); | |
3e31cded | 1528 | install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd); |
7cee1bb1 | 1529 | install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd); |
1530 | install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd); | |
3e31cded | 1531 | 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); | |
7cee1bb1 | 1534 | install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd); |
3e31cded | 1535 | 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); | |
7cee1bb1 | 1540 | install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd); |
3e31cded | 1541 | install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd); |
1542 | install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd); | |
718e3744 | 1543 | } |
1544 | ||
a1ac18c4 | 1545 | static int |
718e3744 | 1546 | if_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) | |
6099b3b5 | 1559 | zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno)); |
718e3744 | 1560 | |
1561 | zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name); | |
1562 | ||
1563 | return 0; | |
1564 | } | |
1565 | ||
a1ac18c4 | 1566 | static int |
718e3744 | 1567 | if_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) | |
6099b3b5 | 1580 | zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno)); |
718e3744 | 1581 | |
1582 | zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name); | |
1583 | ||
1584 | return 0; | |
1585 | } | |
1586 | ||
1587 | #else | |
1588 | void | |
a1ac18c4 | 1589 | rtadv_init (void) |
718e3744 | 1590 | { |
1591 | /* Empty.*/; | |
1592 | } | |
1593 | #endif /* RTADV && HAVE_IPV6 */ |