+ fix minor regression in OSPF sending buffer adjustment logic
[jleu-quagga.git] / zebra / irdp_main.c
blob5510669927a6b515266cae2a8eb1bce927dce156
1 /*
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
11 * later version.
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
21 * 02111-1307, USA.
24 /*
25 * This work includes work with the following copywrite:
27 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
31 /*
32 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
33 * for reviewing and tests.
37 #include <zebra.h>
39 #ifdef HAVE_IRDP
41 #include "if.h"
42 #include "vty.h"
43 #include "sockunion.h"
44 #include "sockopt.h"
45 #include "prefix.h"
46 #include "command.h"
47 #include "memory.h"
48 #include "stream.h"
49 #include "ioctl.h"
50 #include "connected.h"
51 #include "log.h"
52 #include "zclient.h"
53 #include "thread.h"
54 #include "privs.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>
63 #include "if.h"
64 #include "sockunion.h"
65 #include "log.h"
67 /* GLOBAL VARS */
69 extern struct zebra_privs_t zserv_privs;
71 /* Master of threads. */
72 extern struct zebra_t zebrad;
73 struct thread *t_irdp_raw;
75 /* Timer interval of irdp. */
76 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
78 int irdp_read_raw(struct thread *r);
79 int in_cksum (void *ptr, int nbytes);
80 void send_packet(struct interface *ifp,
81 struct stream *s,
82 u_int32_t dst,
83 struct prefix *p,
84 u_int32_t ttl);
86 char *
87 inet_2a(u_int32_t a, char *b)
89 sprintf(b, "%u.%u.%u.%u",
90 (a ) & 0xFF,
91 (a>> 8) & 0xFF,
92 (a>>16) & 0xFF,
93 (a>>24) & 0xFF);
94 return b;
97 int
98 irdp_sock_init (void)
100 int ret, i;
101 int save_errno;
102 int sock;
104 if ( zserv_privs.change (ZPRIVS_RAISE) )
105 zlog_err ("irdp_sock_init: could not raise privs, %s",
106 safe_strerror (errno) );
108 sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
109 save_errno = errno;
111 if ( zserv_privs.change (ZPRIVS_LOWER) )
112 zlog_err ("irdp_sock_init: could not lower privs, %s",
113 safe_strerror (errno) );
115 if (sock < 0) {
116 zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
117 return sock;
120 i = 1;
121 ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
122 (void *) &i, sizeof (i));
123 if (ret < 0) {
124 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
125 close(sock);
126 return ret;
129 ret = setsockopt_ifindex (AF_INET, sock, 1);
130 if (ret < 0) {
131 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
132 close(sock);
133 return ret;
136 t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock);
138 return sock;
142 static int
143 get_pref(struct irdp_interface *irdp, struct prefix *p)
145 struct listnode *node;
146 struct Adv *adv;
148 /* Use default preference or use the override pref */
150 if( irdp->AdvPrefList == NULL )
151 return irdp->Preference;
153 for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
154 if( p->u.prefix4.s_addr == adv->ip.s_addr )
155 return adv->pref;
157 return irdp->Preference;
160 /* Make ICMP Router Advertisement Message. */
161 static int
162 make_advertisement_packet (struct interface *ifp,
163 struct prefix *p,
164 struct stream *s)
166 struct zebra_if *zi=ifp->info;
167 struct irdp_interface *irdp=&zi->irdp;
168 int size;
169 int pref;
170 u_int16_t checksum;
172 pref = get_pref(irdp, p);
174 stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
175 stream_putc (s, 0); /* Code. */
176 stream_putw (s, 0); /* Checksum. */
177 stream_putc (s, 1); /* Num address. */
178 stream_putc (s, 2); /* Address Entry Size. */
180 if(irdp->flags & IF_SHUTDOWN)
181 stream_putw (s, 0);
182 else
183 stream_putw (s, irdp->Lifetime);
185 stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
186 stream_putl (s, pref);
188 /* in_cksum return network byte order value */
189 size = 16;
190 checksum = in_cksum (s->data, size);
191 stream_putw_at (s, 2, htons(checksum));
193 return size;
196 static void
197 irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
199 struct zebra_if *zi=ifp->info;
200 struct irdp_interface *irdp=&zi->irdp;
201 u_int32_t dst;
202 u_int32_t ttl=1;
204 if (! (ifp->flags & IFF_UP)) return;
206 if (irdp->flags & IF_BROADCAST)
207 dst =INADDR_BROADCAST ;
208 else
209 dst = htonl(INADDR_ALLHOSTS_GROUP);
211 if(irdp->flags & IF_DEBUG_MESSAGES)
212 zlog_debug("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d",
213 ifp->name,
214 inet_ntoa(p->u.prefix4),
215 p->prefixlen,
216 irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
217 get_pref(irdp, p));
219 send_packet (ifp, s, dst, p, ttl);
222 static void irdp_advertisement (struct interface *ifp, struct prefix *p)
224 struct stream *s;
225 s = stream_new (128);
226 make_advertisement_packet (ifp, p, s);
227 irdp_send(ifp, p, s);
228 stream_free (s);
231 int irdp_send_thread(struct thread *t_advert)
233 u_int32_t timer, tmp;
234 struct interface *ifp = THREAD_ARG (t_advert);
235 struct zebra_if *zi=ifp->info;
236 struct irdp_interface *irdp=&zi->irdp;
237 struct prefix *p;
238 struct listnode *node, *nnode;
239 struct connected *ifc;
241 irdp->flags &= ~IF_SOLICIT;
243 if(ifp->connected)
244 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
246 p = ifc->address;
248 if (p->family != AF_INET)
249 continue;
251 irdp_advertisement(ifp, p);
252 irdp->irdp_sent++;
255 tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
256 timer = (random () % tmp ) + 1;
257 timer = irdp->MinAdvertInterval + timer;
259 if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
260 timer > MAX_INITIAL_ADVERT_INTERVAL )
261 timer= MAX_INITIAL_ADVERT_INTERVAL;
263 if(irdp->flags & IF_DEBUG_MISC)
264 zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
266 irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
267 return 0;
270 void irdp_advert_off(struct interface *ifp)
272 struct zebra_if *zi=ifp->info;
273 struct irdp_interface *irdp=&zi->irdp;
274 struct listnode *node, *nnode;
275 int i;
276 struct connected *ifc;
277 struct prefix *p;
279 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
280 irdp->t_advertise = NULL;
282 if(ifp->connected)
283 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
285 p = ifc->address;
287 /* Output some packets with Lifetime 0
288 we should add a wait...
291 for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++)
293 irdp->irdp_sent++;
294 irdp_advertisement(ifp, p);
300 void process_solicit (struct interface *ifp)
302 struct zebra_if *zi=ifp->info;
303 struct irdp_interface *irdp=&zi->irdp;
304 u_int32_t timer;
306 /* When SOLICIT is active we reject further incoming solicits
307 this keeps down the answering rate so we don't have think
308 about DoS attacks here. */
310 if( irdp->flags & IF_SOLICIT) return;
312 irdp->flags |= IF_SOLICIT;
313 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
314 irdp->t_advertise = NULL;
316 timer = (random () % MAX_RESPONSE_DELAY) + 1;
318 irdp->t_advertise = thread_add_timer(zebrad.master,
319 irdp_send_thread,
320 ifp,
321 timer);
324 void irdp_finish()
327 struct listnode *node, *nnode;
328 struct interface *ifp;
329 struct zebra_if *zi;
330 struct irdp_interface *irdp;
332 zlog_info("IRDP: Received shutdown notification.");
334 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
336 zi = ifp->info;
338 if (!zi)
339 continue;
340 irdp = &zi->irdp;
341 if (!irdp)
342 continue;
344 if (irdp->flags & IF_ACTIVE )
346 irdp->flags |= IF_SHUTDOWN;
347 irdp_advert_off(ifp);
352 #endif /* HAVE_IRDP */