3 * Copyright (C) 2000 Robert Olsson.
4 * Swedish University of Agricultural Sciences
6 * This file is part of GNU Zebra.
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 * This work includes work with the following copywrite:
26 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
31 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
32 * for reviewing and tests.
40 #include "sockunion.h"
45 #include "zebra_memory.h"
48 #include "connected.h"
54 #include "lib_errors.h"
56 #include "zebra/interface.h"
57 #include "zebra/rtadv.h"
58 #include "zebra/rib.h"
59 #include "zebra/zserv.h"
60 #include "zebra/redistribute.h"
61 #include "zebra/irdp.h"
62 #include <netinet/ip_icmp.h>
66 #include "sockunion.h"
71 extern struct zebra_privs_t zserv_privs
;
73 struct thread
*t_irdp_raw
;
75 /* Timer interval of irdp. */
76 int irdp_timer_interval
= IRDP_DEFAULT_INTERVAL
;
78 int irdp_sock_init(void)
84 if (zserv_privs
.change(ZPRIVS_RAISE
))
85 zlog_ferr(LIB_ERR_PRIVILEGES
,
86 "irdp_sock_init: could not raise privs, %s",
87 safe_strerror(errno
));
89 sock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
92 if (zserv_privs
.change(ZPRIVS_LOWER
))
93 zlog_ferr(LIB_ERR_PRIVILEGES
,
94 "irdp_sock_init: could not lower privs, %s",
95 safe_strerror(errno
));
98 zlog_warn("IRDP: can't create irdp socket %s",
99 safe_strerror(save_errno
));
104 ret
= setsockopt(sock
, IPPROTO_IP
, IP_TTL
, (void *)&i
, sizeof(i
));
106 zlog_warn("IRDP: can't do irdp sockopt %s",
107 safe_strerror(errno
));
112 ret
= setsockopt_ifindex(AF_INET
, sock
, 1);
114 zlog_warn("IRDP: can't do irdp sockopt %s",
115 safe_strerror(errno
));
121 thread_add_read(zebrad
.master
, irdp_read_raw
, NULL
, sock
, &t_irdp_raw
);
127 static int get_pref(struct irdp_interface
*irdp
, struct prefix
*p
)
129 struct listnode
*node
;
132 /* Use default preference or use the override pref */
134 if (irdp
->AdvPrefList
== NULL
)
135 return irdp
->Preference
;
137 for (ALL_LIST_ELEMENTS_RO(irdp
->AdvPrefList
, node
, adv
))
138 if (p
->u
.prefix4
.s_addr
== adv
->ip
.s_addr
)
141 return irdp
->Preference
;
144 /* Make ICMP Router Advertisement Message. */
145 static int make_advertisement_packet(struct interface
*ifp
, struct prefix
*p
,
148 struct zebra_if
*zi
= ifp
->info
;
149 struct irdp_interface
*irdp
= zi
->irdp
;
154 pref
= get_pref(irdp
, p
);
156 stream_putc(s
, ICMP_ROUTERADVERT
); /* Type. */
157 stream_putc(s
, 0); /* Code. */
158 stream_putw(s
, 0); /* Checksum. */
159 stream_putc(s
, 1); /* Num address. */
160 stream_putc(s
, 2); /* Address Entry Size. */
162 if (irdp
->flags
& IF_SHUTDOWN
)
165 stream_putw(s
, irdp
->Lifetime
);
167 stream_putl(s
, htonl(p
->u
.prefix4
.s_addr
)); /* Router address. */
168 stream_putl(s
, pref
);
170 /* in_cksum return network byte order value */
172 checksum
= in_cksum(s
->data
, size
);
173 stream_putw_at(s
, 2, htons(checksum
));
178 static void irdp_send(struct interface
*ifp
, struct prefix
*p
, struct stream
*s
)
180 struct zebra_if
*zi
= ifp
->info
;
181 struct irdp_interface
*irdp
= zi
->irdp
;
182 char buf
[PREFIX_STRLEN
];
188 if (!(ifp
->flags
& IFF_UP
))
191 if (irdp
->flags
& IF_BROADCAST
)
192 dst
= INADDR_BROADCAST
;
194 dst
= htonl(INADDR_ALLHOSTS_GROUP
);
196 if (irdp
->flags
& IF_DEBUG_MESSAGES
)
197 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
198 ifp
->name
, prefix2str(p
, buf
, sizeof buf
),
199 irdp
->flags
& IF_SHUTDOWN
? 0 : irdp
->Lifetime
,
202 send_packet(ifp
, s
, dst
, p
, ttl
);
205 static void irdp_advertisement(struct interface
*ifp
, struct prefix
*p
)
209 make_advertisement_packet(ifp
, p
, s
);
210 irdp_send(ifp
, p
, s
);
214 int irdp_send_thread(struct thread
*t_advert
)
217 struct interface
*ifp
= THREAD_ARG(t_advert
);
218 struct zebra_if
*zi
= ifp
->info
;
219 struct irdp_interface
*irdp
= zi
->irdp
;
221 struct listnode
*node
, *nnode
;
222 struct connected
*ifc
;
227 irdp
->flags
&= ~IF_SOLICIT
;
230 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nnode
, ifc
)) {
233 if (p
->family
!= AF_INET
)
236 irdp_advertisement(ifp
, p
);
240 tmp
= irdp
->MaxAdvertInterval
- irdp
->MinAdvertInterval
;
241 timer
= random() % (tmp
+ 1);
242 timer
= irdp
->MinAdvertInterval
+ timer
;
244 if (irdp
->irdp_sent
< MAX_INITIAL_ADVERTISEMENTS
245 && timer
> MAX_INITIAL_ADVERT_INTERVAL
)
246 timer
= MAX_INITIAL_ADVERT_INTERVAL
;
248 if (irdp
->flags
& IF_DEBUG_MISC
)
249 zlog_debug("IRDP: New timer for %s set to %u\n", ifp
->name
,
252 irdp
->t_advertise
= NULL
;
253 thread_add_timer(zebrad
.master
, irdp_send_thread
, ifp
, timer
,
258 void irdp_advert_off(struct interface
*ifp
)
260 struct zebra_if
*zi
= ifp
->info
;
261 struct irdp_interface
*irdp
= zi
->irdp
;
262 struct listnode
*node
, *nnode
;
264 struct connected
*ifc
;
270 if (irdp
->t_advertise
)
271 thread_cancel(irdp
->t_advertise
);
272 irdp
->t_advertise
= NULL
;
275 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nnode
, ifc
)) {
278 /* Output some packets with Lifetime 0
279 we should add a wait...
282 for (i
= 0; i
< IRDP_LAST_ADVERT_MESSAGES
; i
++) {
284 irdp_advertisement(ifp
, p
);
290 void process_solicit(struct interface
*ifp
)
292 struct zebra_if
*zi
= ifp
->info
;
293 struct irdp_interface
*irdp
= zi
->irdp
;
299 /* When SOLICIT is active we reject further incoming solicits
300 this keeps down the answering rate so we don't have think
301 about DoS attacks here. */
303 if (irdp
->flags
& IF_SOLICIT
)
306 irdp
->flags
|= IF_SOLICIT
;
307 if (irdp
->t_advertise
)
308 thread_cancel(irdp
->t_advertise
);
309 irdp
->t_advertise
= NULL
;
311 timer
= (random() % MAX_RESPONSE_DELAY
) + 1;
313 irdp
->t_advertise
= NULL
;
314 thread_add_timer(zebrad
.master
, irdp_send_thread
, ifp
, timer
,
318 static int irdp_finish(void)
321 struct interface
*ifp
;
323 struct irdp_interface
*irdp
;
325 zlog_info("IRDP: Received shutdown notification.");
327 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
)
328 FOR_ALL_INTERFACES (vrf
, ifp
) {
337 if (irdp
->flags
& IF_ACTIVE
) {
338 irdp
->flags
|= IF_SHUTDOWN
;
339 irdp_advert_off(ifp
);
345 static int irdp_init(struct thread_master
*master
)
349 hook_register(frr_early_fini
, irdp_finish
);
353 static int irdp_module_init(void)
355 hook_register(frr_late_init
, irdp_init
);
359 FRR_MODULE_SETUP(.name
= "zebra_irdp", .version
= FRR_VERSION
,
360 .description
= "zebra IRDP module", .init
= irdp_module_init
, )