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"
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 /* Master of threads. */
73 extern struct zebra_t zebrad;
74 struct thread *t_irdp_raw;
76 /* Timer interval of irdp. */
77 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
86 if ( zserv_privs.change (ZPRIVS_RAISE) )
87 zlog_err ("irdp_sock_init: could not raise privs, %s",
88 safe_strerror (errno) );
90 sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
93 if ( zserv_privs.change (ZPRIVS_LOWER) )
94 zlog_err ("irdp_sock_init: could not lower privs, %s",
95 safe_strerror (errno) );
98 zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
103 ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
104 (void *) &i, sizeof (i));
106 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
111 ret = setsockopt_ifindex (AF_INET, sock, 1);
113 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
118 t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock);
125 get_pref(struct irdp_interface *irdp, struct prefix *p)
127 struct listnode *node;
130 /* Use default preference or use the override pref */
132 if( irdp->AdvPrefList == NULL )
133 return irdp->Preference;
135 for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
136 if( p->u.prefix4.s_addr == adv->ip.s_addr )
139 return irdp->Preference;
142 /* Make ICMP Router Advertisement Message. */
144 make_advertisement_packet (struct interface *ifp,
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));
179 irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
181 struct zebra_if *zi=ifp->info;
182 struct irdp_interface *irdp=&zi->irdp;
183 char buf[PREFIX_STRLEN];
187 if (! (ifp->flags & IFF_UP)) return;
189 if (irdp->flags & IF_BROADCAST)
190 dst =INADDR_BROADCAST ;
192 dst = htonl(INADDR_ALLHOSTS_GROUP);
194 if(irdp->flags & IF_DEBUG_MESSAGES)
195 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
197 prefix2str(p, buf, sizeof buf),
198 irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
201 send_packet (ifp, s, dst, p, ttl);
204 static void irdp_advertisement (struct interface *ifp, struct prefix *p)
207 s = stream_new (128);
208 make_advertisement_packet (ifp, p, s);
209 irdp_send(ifp, p, s);
213 int irdp_send_thread(struct thread *t_advert)
215 u_int32_t timer, tmp;
216 struct interface *ifp = THREAD_ARG (t_advert);
217 struct zebra_if *zi=ifp->info;
218 struct irdp_interface *irdp=&zi->irdp;
220 struct listnode *node, *nnode;
221 struct connected *ifc;
223 irdp->flags &= ~IF_SOLICIT;
226 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
230 if (p->family != AF_INET)
233 irdp_advertisement(ifp, p);
237 tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
238 timer = (random () % tmp ) + 1;
239 timer = irdp->MinAdvertInterval + timer;
241 if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
242 timer > MAX_INITIAL_ADVERT_INTERVAL )
243 timer= MAX_INITIAL_ADVERT_INTERVAL;
245 if(irdp->flags & IF_DEBUG_MISC)
246 zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
248 irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
252 void irdp_advert_off(struct interface *ifp)
254 struct zebra_if *zi=ifp->info;
255 struct irdp_interface *irdp=&zi->irdp;
256 struct listnode *node, *nnode;
258 struct connected *ifc;
261 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
262 irdp->t_advertise = NULL;
265 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
269 /* Output some packets with Lifetime 0
270 we should add a wait...
273 for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++)
276 irdp_advertisement(ifp, p);
282 void process_solicit (struct interface *ifp)
284 struct zebra_if *zi=ifp->info;
285 struct irdp_interface *irdp=&zi->irdp;
288 /* When SOLICIT is active we reject further incoming solicits
289 this keeps down the answering rate so we don't have think
290 about DoS attacks here. */
292 if( irdp->flags & IF_SOLICIT) return;
294 irdp->flags |= IF_SOLICIT;
295 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
296 irdp->t_advertise = NULL;
298 timer = (random () % MAX_RESPONSE_DELAY) + 1;
300 irdp->t_advertise = thread_add_timer(zebrad.master,
309 struct listnode *node, *nnode;
310 struct interface *ifp;
312 struct irdp_interface *irdp;
314 zlog_info("IRDP: Received shutdown notification.");
316 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
326 if (irdp->flags & IF_ACTIVE )
328 irdp->flags |= IF_SHUTDOWN;
329 irdp_advert_off(ifp);
334 #endif /* HAVE_IRDP */