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
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * This work includes work with the following copywrite:
27 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
32 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
33 * for reviewing and tests.
43 #include "sockunion.h"
49 #include "connected.h"
54 #include "zebra/interface.h"
55 #include "zebra/rtadv.h"
56 #include "zebra/rib.h"
57 #include "zebra/zserv.h"
58 #include "zebra/redistribute.h"
59 #include "zebra/irdp.h"
60 #include <netinet/ip_icmp.h>
63 #include "sockunion.h"
68 extern struct zebra_privs_t zserv_privs
;
70 /* Master of threads. */
71 extern struct zebra_t zebrad
;
72 struct thread
*t_irdp_raw
;
74 /* Timer interval of irdp. */
75 int irdp_timer_interval
= IRDP_DEFAULT_INTERVAL
;
77 int irdp_read_raw(struct thread
*r
);
78 int in_cksum (void *ptr
, int nbytes
);
80 void send_packet(struct interface
*ifp
,
89 inet_2a(u_int32_t a
, char *b
)
91 sprintf(b
, "%u.%u.%u.%u",
100 irdp_sock_init (void)
104 if ( zserv_privs
.change (ZPRIVS_RAISE
) )
105 zlog_err ("irdp_sock_init: could not raise privs, %s",
108 irdp_sock
= socket (AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
110 if ( zserv_privs
.change (ZPRIVS_LOWER
) )
111 zlog_err ("irdp_sock_init: could not lower privs, %s",
115 zlog_warn ("IRDP: can't create irdp socket %s", strerror(errno
));
120 ret
= setsockopt (irdp_sock
, IPPROTO_IP
, IP_TTL
,
121 (void *) &i
, sizeof (i
));
123 zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno
));
127 ret
= setsockopt_pktinfo (AF_INET
, irdp_sock
, 1);
129 zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno
));
133 t_irdp_raw
= thread_add_read (zebrad
.master
, irdp_read_raw
, NULL
, irdp_sock
);
139 int get_pref(struct irdp_interface
*irdp
, struct prefix
*p
)
141 struct listnode
*node
;
144 /* Use default preference or use the override pref */
146 if( irdp
->AdvPrefList
== NULL
)
147 return irdp
->Preference
;
149 LIST_LOOP (irdp
->AdvPrefList
, adv
, node
)
150 if( p
->u
.prefix4
.s_addr
== adv
->ip
.s_addr
)
153 return irdp
->Preference
;
156 /* Make ICMP Router Advertisement Message. */
157 int make_advertisement_packet (struct interface
*ifp
,
161 struct zebra_if
*zi
=ifp
->info
;
162 struct irdp_interface
*irdp
=&zi
->irdp
;
167 pref
= get_pref(irdp
, p
);
169 stream_putc (s
, ICMP_ROUTERADVERT
); /* Type. */
170 stream_putc (s
, 0); /* Code. */
171 stream_putw (s
, 0); /* Checksum. */
172 stream_putc (s
, 1); /* Num address. */
173 stream_putc (s
, 2); /* Address Entry Size. */
175 if(irdp
->flags
& IF_SHUTDOWN
)
178 stream_putw (s
, irdp
->Lifetime
);
180 stream_putl (s
, htonl(p
->u
.prefix4
.s_addr
)); /* Router address. */
181 stream_putl (s
, pref
);
183 /* in_cksum return network byte order value */
185 checksum
= in_cksum (s
->data
, size
);
186 stream_putw_at (s
, 2, htons(checksum
));
191 void irdp_send(struct interface
*ifp
,
195 struct zebra_if
*zi
=ifp
->info
;
196 struct irdp_interface
*irdp
=&zi
->irdp
;
200 if (! (ifp
->flags
& IFF_UP
)) return;
202 if (irdp
->flags
& IF_BROADCAST
)
203 dst
=INADDR_BROADCAST
;
205 dst
= htonl(INADDR_ALLHOSTS_GROUP
);
207 if(irdp
->flags
& IF_DEBUG_MESSAGES
)
208 zlog_warn("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d",
210 inet_ntoa(p
->u
.prefix4
),
212 irdp
->flags
& IF_SHUTDOWN
? 0 : irdp
->Lifetime
,
215 send_packet (ifp
, s
, dst
, p
, ttl
);
218 void irdp_advertisement (struct interface
*ifp
,
222 s
= stream_new (128);
223 make_advertisement_packet (ifp
, p
, s
);
224 irdp_send(ifp
, p
, s
);
227 int irdp_send_thread(struct thread
*t_advert
)
229 u_int32_t timer
, tmp
;
230 struct interface
*ifp
= THREAD_ARG (t_advert
);
231 struct zebra_if
*zi
=ifp
->info
;
232 struct irdp_interface
*irdp
=&zi
->irdp
;
234 struct listnode
*node
;
235 struct connected
*ifc
;
237 irdp
->flags
&= ~IF_SOLICIT
;
240 LIST_LOOP (ifp
->connected
, ifc
, node
)
243 irdp_advertisement(ifp
, p
);
247 tmp
= irdp
->MaxAdvertInterval
-irdp
->MinAdvertInterval
;
248 timer
= (random () % tmp
) + 1;
249 timer
= irdp
->MinAdvertInterval
+ timer
;
251 if(irdp
->irdp_sent
< MAX_INITIAL_ADVERTISEMENTS
&&
252 timer
> MAX_INITIAL_ADVERT_INTERVAL
)
253 timer
= MAX_INITIAL_ADVERT_INTERVAL
;
255 if(irdp
->flags
& IF_DEBUG_MISC
)
256 zlog_warn("IRDP: New timer for %s set to %u\n", ifp
->name
, timer
);
258 irdp
->t_advertise
= thread_add_timer(zebrad
.master
, irdp_send_thread
, ifp
, timer
);
262 void irdp_advert_off(struct interface
*ifp
)
264 struct zebra_if
*zi
=ifp
->info
;
265 struct irdp_interface
*irdp
=&zi
->irdp
;
266 struct listnode
*node
;
268 struct connected
*ifc
;
271 if(irdp
->t_advertise
) thread_cancel(irdp
->t_advertise
);
272 irdp
->t_advertise
= NULL
;
275 LIST_LOOP (ifp
->connected
, ifc
, node
)
279 /* Output some packets with Lifetime 0
280 we should add a wait...
283 for(i
=0; i
< IRDP_LAST_ADVERT_MESSAGES
; i
++)
286 irdp_advertisement(ifp
, p
);
292 void process_solicit (struct interface
*ifp
)
294 struct zebra_if
*zi
=ifp
->info
;
295 struct irdp_interface
*irdp
=&zi
->irdp
;
298 /* When SOLICIT is active we reject further incoming solicits
299 this keeps down the answering rate so we don't have think
300 about DoS attacks here. */
302 if( irdp
->flags
& IF_SOLICIT
) return;
304 irdp
->flags
|= IF_SOLICIT
;
305 if(irdp
->t_advertise
) thread_cancel(irdp
->t_advertise
);
306 irdp
->t_advertise
= NULL
;
308 timer
= (random () % MAX_RESPONSE_DELAY
) + 1;
310 irdp
->t_advertise
= thread_add_timer(zebrad
.master
,
319 struct listnode
*node
;
320 struct interface
*ifp
;
322 struct irdp_interface
*irdp
;
324 zlog_warn("IRDP: Received shutdown notification.");
326 for (node
= listhead (iflist
); node
; node
= nextnode (node
))
337 if (irdp
->flags
& IF_ACTIVE
)
339 irdp
->flags
|= IF_SHUTDOWN
;
340 irdp_advert_off(ifp
);
351 #endif /* HAVE_IRDP */