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 Låås at Swedish University of Agricultural Sciences
32 * for reviewing and tests.
42 #include "sockunion.h"
47 #include "zebra_memory.h"
50 #include "connected.h"
55 #include "zebra/interface.h"
56 #include "zebra/rtadv.h"
57 #include "zebra/rib.h"
58 #include "zebra/zserv.h"
59 #include "zebra/redistribute.h"
60 #include "zebra/irdp.h"
61 #include <netinet/ip_icmp.h>
65 #include "sockunion.h"
70 extern struct zebra_privs_t zserv_privs
;
72 struct thread
*t_irdp_raw
;
74 /* Timer interval of irdp. */
75 int irdp_timer_interval
= IRDP_DEFAULT_INTERVAL
;
84 if ( zserv_privs
.change (ZPRIVS_RAISE
) )
85 zlog_err ("irdp_sock_init: could not raise privs, %s",
86 safe_strerror (errno
) );
88 sock
= socket (AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
91 if ( zserv_privs
.change (ZPRIVS_LOWER
) )
92 zlog_err ("irdp_sock_init: could not lower privs, %s",
93 safe_strerror (errno
) );
96 zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno
));
101 ret
= setsockopt (sock
, IPPROTO_IP
, IP_TTL
,
102 (void *) &i
, sizeof (i
));
104 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno
));
109 ret
= setsockopt_ifindex (AF_INET
, sock
, 1);
111 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno
));
117 thread_add_read(zebrad
.master
, irdp_read_raw
, NULL
, sock
, &t_irdp_raw
);
124 get_pref(struct irdp_interface
*irdp
, struct prefix
*p
)
126 struct listnode
*node
;
129 /* Use default preference or use the override pref */
131 if( irdp
->AdvPrefList
== NULL
)
132 return irdp
->Preference
;
134 for (ALL_LIST_ELEMENTS_RO (irdp
->AdvPrefList
, node
, adv
))
135 if( p
->u
.prefix4
.s_addr
== adv
->ip
.s_addr
)
138 return irdp
->Preference
;
141 /* Make ICMP Router Advertisement Message. */
143 make_advertisement_packet (struct interface
*ifp
,
147 struct zebra_if
*zi
=ifp
->info
;
148 struct irdp_interface
*irdp
=&zi
->irdp
;
153 pref
= get_pref(irdp
, p
);
155 stream_putc (s
, ICMP_ROUTERADVERT
); /* Type. */
156 stream_putc (s
, 0); /* Code. */
157 stream_putw (s
, 0); /* Checksum. */
158 stream_putc (s
, 1); /* Num address. */
159 stream_putc (s
, 2); /* Address Entry Size. */
161 if(irdp
->flags
& IF_SHUTDOWN
)
164 stream_putw (s
, irdp
->Lifetime
);
166 stream_putl (s
, htonl(p
->u
.prefix4
.s_addr
)); /* Router address. */
167 stream_putl (s
, pref
);
169 /* in_cksum return network byte order value */
171 checksum
= in_cksum (s
->data
, size
);
172 stream_putw_at (s
, 2, htons(checksum
));
178 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
];
186 if (! (ifp
->flags
& IFF_UP
)) return;
188 if (irdp
->flags
& IF_BROADCAST
)
189 dst
=INADDR_BROADCAST
;
191 dst
= htonl(INADDR_ALLHOSTS_GROUP
);
193 if(irdp
->flags
& IF_DEBUG_MESSAGES
)
194 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
196 prefix2str(p
, buf
, sizeof buf
),
197 irdp
->flags
& IF_SHUTDOWN
? 0 : irdp
->Lifetime
,
200 send_packet (ifp
, s
, dst
, p
, ttl
);
203 static void irdp_advertisement (struct interface
*ifp
, struct prefix
*p
)
206 s
= stream_new (128);
207 make_advertisement_packet (ifp
, p
, s
);
208 irdp_send(ifp
, p
, s
);
212 int irdp_send_thread(struct thread
*t_advert
)
214 u_int32_t timer
, tmp
;
215 struct interface
*ifp
= THREAD_ARG (t_advert
);
216 struct zebra_if
*zi
=ifp
->info
;
217 struct irdp_interface
*irdp
=&zi
->irdp
;
219 struct listnode
*node
, *nnode
;
220 struct connected
*ifc
;
222 irdp
->flags
&= ~IF_SOLICIT
;
225 for (ALL_LIST_ELEMENTS (ifp
->connected
, node
, nnode
, ifc
))
229 if (p
->family
!= AF_INET
)
232 irdp_advertisement(ifp
, p
);
236 tmp
= irdp
->MaxAdvertInterval
-irdp
->MinAdvertInterval
;
237 timer
= (random () % tmp
) + 1;
238 timer
= irdp
->MinAdvertInterval
+ timer
;
240 if(irdp
->irdp_sent
< MAX_INITIAL_ADVERTISEMENTS
&&
241 timer
> MAX_INITIAL_ADVERT_INTERVAL
)
242 timer
= MAX_INITIAL_ADVERT_INTERVAL
;
244 if(irdp
->flags
& IF_DEBUG_MISC
)
245 zlog_debug("IRDP: New timer for %s set to %u\n", ifp
->name
, timer
);
247 irdp
->t_advertise
= NULL
;
248 thread_add_timer(zebrad
.master
, irdp_send_thread
, ifp
, timer
,
253 void irdp_advert_off(struct interface
*ifp
)
255 struct zebra_if
*zi
=ifp
->info
;
256 struct irdp_interface
*irdp
=&zi
->irdp
;
257 struct listnode
*node
, *nnode
;
259 struct connected
*ifc
;
262 if(irdp
->t_advertise
) thread_cancel(irdp
->t_advertise
);
263 irdp
->t_advertise
= NULL
;
266 for (ALL_LIST_ELEMENTS (ifp
->connected
, node
, nnode
, ifc
))
270 /* Output some packets with Lifetime 0
271 we should add a wait...
274 for(i
=0; i
< IRDP_LAST_ADVERT_MESSAGES
; i
++)
277 irdp_advertisement(ifp
, p
);
283 void process_solicit (struct interface
*ifp
)
285 struct zebra_if
*zi
=ifp
->info
;
286 struct irdp_interface
*irdp
=&zi
->irdp
;
289 /* When SOLICIT is active we reject further incoming solicits
290 this keeps down the answering rate so we don't have think
291 about DoS attacks here. */
293 if( irdp
->flags
& IF_SOLICIT
) return;
295 irdp
->flags
|= IF_SOLICIT
;
296 if(irdp
->t_advertise
) thread_cancel(irdp
->t_advertise
);
297 irdp
->t_advertise
= NULL
;
299 timer
= (random () % MAX_RESPONSE_DELAY
) + 1;
301 irdp
->t_advertise
= NULL
;
302 thread_add_timer(zebrad
.master
, irdp_send_thread
, ifp
, timer
,
309 struct listnode
*node
, *nnode
;
310 struct interface
*ifp
;
312 struct irdp_interface
*irdp
;
314 zlog_info("IRDP: Received shutdown notification.");
316 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
)
317 for (ALL_LIST_ELEMENTS (vrf
->iflist
, node
, nnode
, ifp
))
327 if (irdp
->flags
& IF_ACTIVE
)
329 irdp
->flags
|= IF_SHUTDOWN
;
330 irdp_advert_off(ifp
);
335 #endif /* HAVE_IRDP */