blob: 56e41840281335c4a9f04d140511fd56b7a02350 [file] [log] [blame]
hassoca776982004-06-12 14:33:05 +00001/*
2 *
3 * Copyright (C) 2000 Robert Olsson.
4 * Swedish University of Agricultural Sciences
5 *
6 * This file is part of GNU Zebra.
7 *
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.
12 *
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.
17 *
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.
22 */
23
24/*
25 * This work includes work with the following copywrite:
26 *
27 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
28 *
29 */
30
31/*
32 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
33 * for reviewing and tests.
34 */
35
36
37#include <zebra.h>
38
39#ifdef HAVE_IRDP
40
41#include "if.h"
42#include "vty.h"
43#include "sockunion.h"
44#include "prefix.h"
45#include "command.h"
46#include "memory.h"
47#include "stream.h"
48#include "ioctl.h"
49#include "connected.h"
50#include "log.h"
51#include "zclient.h"
52#include "thread.h"
hasso25dac852004-07-13 03:06:51 +000053#include "privs.h"
hassoca776982004-06-12 14:33:05 +000054#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>
61
62#include "if.h"
63#include "sockunion.h"
64#include "log.h"
65
66/* GLOBAL VARS */
67
hasso25dac852004-07-13 03:06:51 +000068extern struct zebra_privs_t zserv_privs;
69
hassoca776982004-06-12 14:33:05 +000070/* Master of threads. */
71extern struct zebra_t zebrad;
72struct thread *t_irdp_raw;
73
74/* Timer interval of irdp. */
75int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
76
77int irdp_read_raw(struct thread *r);
78int in_cksum (void *ptr, int nbytes);
79extern int irdp_sock;
80void send_packet(struct interface *ifp,
81 struct stream *s,
82 u_int32_t dst,
83 struct prefix *p,
84 u_int32_t ttl);
85
86void irdp_if_init ();
87
88char *
89inet_2a(u_int32_t a, char *b)
90{
91 sprintf(b, "%u.%u.%u.%u",
92 (a ) & 0xFF,
93 (a>> 8) & 0xFF,
94 (a>>16) & 0xFF,
95 (a>>24) & 0xFF);
96 return b;
97}
98
99int
100irdp_sock_init (void)
101{
102 int ret, i;
103
hasso25dac852004-07-13 03:06:51 +0000104 if ( zserv_privs.change (ZPRIVS_RAISE) )
105 zlog_err ("irdp_sock_init: could not raise privs, %s",
106 strerror (errno) );
107
hassoca776982004-06-12 14:33:05 +0000108 irdp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
hasso25dac852004-07-13 03:06:51 +0000109
110 if ( zserv_privs.change (ZPRIVS_LOWER) )
111 zlog_err ("irdp_sock_init: could not lower privs, %s",
112 strerror (errno) );
113
hassoca776982004-06-12 14:33:05 +0000114 if (irdp_sock < 0) {
115 zlog_warn ("IRDP: can't create irdp socket %s", strerror(errno));
116 return irdp_sock;
117 };
118
119 i = 1;
120 ret = setsockopt (irdp_sock, IPPROTO_IP, IP_TTL,
121 (void *) &i, sizeof (i));
122 if (ret < 0) {
123 zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
124 return ret;
125 };
126
127 i = 1;
128 ret = setsockopt (irdp_sock, IPPROTO_IP, IP_PKTINFO,
129 (void *) &i, sizeof (i));
130 if (ret < 0) {
131 zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
132 return ret;
133 };
134
135 t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
136
137 return irdp_sock;
138}
139
140
141int get_pref(struct irdp_interface *irdp, struct prefix *p)
142{
143 listnode node;
144 struct Adv *adv;
145
146 /* Use default preference or use the override pref */
147
148 if( irdp->AdvPrefList == NULL ) return irdp->Preference;
149
150 for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) {
151 adv = getdata (node);
152 if( p->u.prefix4.s_addr == adv->ip.s_addr )
153 return adv->pref;
154 }
155 return irdp->Preference;
156}
157
158/* Make ICMP Router Advertisement Message. */
159int make_advertisement_packet (struct interface *ifp,
160 struct prefix *p,
161 struct stream *s)
162{
163 struct zebra_if *zi=ifp->info;
164 struct irdp_interface *irdp=&zi->irdp;
165 int size;
166 int pref;
167 u_int16_t checksum;
168
169 pref = get_pref(irdp, p);
170
171 stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
172 stream_putc (s, 0); /* Code. */
173 stream_putw (s, 0); /* Checksum. */
174 stream_putc (s, 1); /* Num address. */
175 stream_putc (s, 2); /* Address Entry Size. */
176
177 if(irdp->flags & IF_SHUTDOWN)
178 stream_putw (s, 0);
179 else
180 stream_putw (s, irdp->Lifetime);
181
182 stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
183 stream_putl (s, pref);
184
185 /* in_cksum return network byte order value */
186 size = 16;
187 checksum = in_cksum (s->data, size);
188 stream_putw_at (s, 2, htons(checksum));
189
190 return size;
191}
192
193void irdp_send(struct interface *ifp,
194 struct prefix *p,
195 struct stream *s)
196{
197 struct zebra_if *zi=ifp->info;
198 struct irdp_interface *irdp=&zi->irdp;
199 u_int32_t dst;
200 u_int32_t ttl=1;
201
202 if (! (ifp->flags & IFF_UP)) return;
203
204 if (irdp->flags & IF_BROADCAST)
205 dst =INADDR_BROADCAST ;
206 else
207 dst = htonl(INADDR_ALLHOSTS_GROUP);
208
209 if(irdp->flags & IF_DEBUG_MESSAGES)
210 zlog_warn("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d",
211 ifp->name,
212 inet_ntoa(p->u.prefix4),
213 p->prefixlen,
214 irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
215 get_pref(irdp, p));
216
217 send_packet (ifp, s, dst, p, ttl);
218}
219
220void irdp_advertisement (struct interface *ifp,
221 struct prefix *p)
222{
223 struct stream *s;
224 s = stream_new (128);
225 make_advertisement_packet (ifp, p, s);
226 irdp_send(ifp, p, s);
227}
228
229int irdp_send_thread(struct thread *t_advert)
230{
231 u_int32_t timer, tmp;
232 struct interface *ifp = THREAD_ARG (t_advert);
233 struct zebra_if *zi=ifp->info;
234 struct irdp_interface *irdp=&zi->irdp;
235 struct prefix *p;
236 listnode node;
237 struct connected *ifc;
238
239 irdp->flags &= ~IF_SOLICIT;
240
241 if(ifp->connected)
242 for (node = listhead (ifp->connected); node; nextnode (node)) {
243 ifc = getdata (node);
244
245 p = ifc->address;
246
247 irdp_advertisement(ifp, p);
248 irdp->irdp_sent++;
249
250 }
251
252 tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
253 timer = (random () % tmp ) + 1;
254 timer = irdp->MinAdvertInterval + timer;
255
256 if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
257 timer > MAX_INITIAL_ADVERT_INTERVAL )
258 timer= MAX_INITIAL_ADVERT_INTERVAL;
259
260 if(irdp->flags & IF_DEBUG_MISC)
261 zlog_warn("IRDP: New timer for %s set to %u\n", ifp->name, timer);
262
263 irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
264 return 0;
265}
266
267void irdp_advert_off(struct interface *ifp)
268{
269 struct zebra_if *zi=ifp->info;
270 struct irdp_interface *irdp=&zi->irdp;
271 listnode node;
272 int i;
273 struct connected *ifc;
274 struct prefix *p;
275
276 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
277 irdp->t_advertise = NULL;
278
279 if(ifp->connected)
280 for (node = listhead (ifp->connected); node; nextnode (node)) {
281 ifc = getdata (node);
282
283 p = ifc->address;
284
285 /* Output some packets with Lifetime 0
286 we should add a wait...
287 */
288
289 for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) {
290
291 irdp->irdp_sent++;
292 irdp_advertisement(ifp, p);
293 }
294 }
295}
296
297
298void process_solicit (struct interface *ifp)
299{
300 struct zebra_if *zi=ifp->info;
301 struct irdp_interface *irdp=&zi->irdp;
302 u_int32_t timer;
303
304 /* When SOLICIT is active we reject further incoming solicits
305 this keeps down the answering rate so we don't have think
306 about DoS attacks here. */
307
308 if( irdp->flags & IF_SOLICIT) return;
309
310 irdp->flags |= IF_SOLICIT;
311 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
312 irdp->t_advertise = NULL;
313
314 timer = (random () % MAX_RESPONSE_DELAY) + 1;
315
316 irdp->t_advertise = thread_add_timer(zebrad.master,
317 irdp_send_thread,
318 ifp,
319 timer);
320}
321
322void irdp_finish()
323{
324
325 listnode node;
326 struct interface *ifp;
327 struct zebra_if *zi;
328 struct irdp_interface *irdp;
329
330 zlog_warn("IRDP: Received shutdown notification.");
331
332 for (node = listhead (iflist); node; node = nextnode (node))
333 {
334 ifp = getdata(node);
335 zi= ifp->info;
336 if(! zi) continue;
337 irdp = &zi->irdp;
338 if(!irdp) continue;
339
340 if(irdp->flags & IF_ACTIVE ) {
341 irdp->flags |= IF_SHUTDOWN;
342 irdp_advert_off(ifp);
343 }
344 }
345}
346
347void irdp_init()
348{
349 irdp_sock_init();
350 irdp_if_init ();
351}
352
353
354
355#endif /* HAVE_IRDP */
356
357
358
359