blob: dac6aea1ac1c2b200ddc2038ae44c93013a71d36 [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"
53#include "zebra/interface.h"
54#include "zebra/rtadv.h"
55#include "zebra/rib.h"
56#include "zebra/zserv.h"
57#include "zebra/redistribute.h"
58#include "zebra/irdp.h"
59#include <netinet/ip_icmp.h>
60
61#include "if.h"
62#include "sockunion.h"
63#include "log.h"
64
65/* GLOBAL VARS */
66
67/* Master of threads. */
68extern struct zebra_t zebrad;
69struct thread *t_irdp_raw;
70
71/* Timer interval of irdp. */
72int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
73
74int irdp_read_raw(struct thread *r);
75int in_cksum (void *ptr, int nbytes);
76extern int irdp_sock;
77void send_packet(struct interface *ifp,
78 struct stream *s,
79 u_int32_t dst,
80 struct prefix *p,
81 u_int32_t ttl);
82
83void irdp_if_init ();
84
85char *
86inet_2a(u_int32_t a, char *b)
87{
88 sprintf(b, "%u.%u.%u.%u",
89 (a ) & 0xFF,
90 (a>> 8) & 0xFF,
91 (a>>16) & 0xFF,
92 (a>>24) & 0xFF);
93 return b;
94}
95
96int
97irdp_sock_init (void)
98{
99 int ret, i;
100
101 irdp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
102 if (irdp_sock < 0) {
103 zlog_warn ("IRDP: can't create irdp socket %s", strerror(errno));
104 return irdp_sock;
105 };
106
107 i = 1;
108 ret = setsockopt (irdp_sock, IPPROTO_IP, IP_TTL,
109 (void *) &i, sizeof (i));
110 if (ret < 0) {
111 zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
112 return ret;
113 };
114
115 i = 1;
116 ret = setsockopt (irdp_sock, IPPROTO_IP, IP_PKTINFO,
117 (void *) &i, sizeof (i));
118 if (ret < 0) {
119 zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
120 return ret;
121 };
122
123 t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
124
125 return irdp_sock;
126}
127
128
129int get_pref(struct irdp_interface *irdp, struct prefix *p)
130{
131 listnode node;
132 struct Adv *adv;
133
134 /* Use default preference or use the override pref */
135
136 if( irdp->AdvPrefList == NULL ) return irdp->Preference;
137
138 for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) {
139 adv = getdata (node);
140 if( p->u.prefix4.s_addr == adv->ip.s_addr )
141 return adv->pref;
142 }
143 return irdp->Preference;
144}
145
146/* Make ICMP Router Advertisement Message. */
147int make_advertisement_packet (struct interface *ifp,
148 struct prefix *p,
149 struct stream *s)
150{
151 struct zebra_if *zi=ifp->info;
152 struct irdp_interface *irdp=&zi->irdp;
153 int size;
154 int pref;
155 u_int16_t checksum;
156
157 pref = get_pref(irdp, p);
158
159 stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
160 stream_putc (s, 0); /* Code. */
161 stream_putw (s, 0); /* Checksum. */
162 stream_putc (s, 1); /* Num address. */
163 stream_putc (s, 2); /* Address Entry Size. */
164
165 if(irdp->flags & IF_SHUTDOWN)
166 stream_putw (s, 0);
167 else
168 stream_putw (s, irdp->Lifetime);
169
170 stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
171 stream_putl (s, pref);
172
173 /* in_cksum return network byte order value */
174 size = 16;
175 checksum = in_cksum (s->data, size);
176 stream_putw_at (s, 2, htons(checksum));
177
178 return size;
179}
180
181void irdp_send(struct interface *ifp,
182 struct prefix *p,
183 struct stream *s)
184{
185 struct zebra_if *zi=ifp->info;
186 struct irdp_interface *irdp=&zi->irdp;
187 u_int32_t dst;
188 u_int32_t ttl=1;
189
190 if (! (ifp->flags & IFF_UP)) return;
191
192 if (irdp->flags & IF_BROADCAST)
193 dst =INADDR_BROADCAST ;
194 else
195 dst = htonl(INADDR_ALLHOSTS_GROUP);
196
197 if(irdp->flags & IF_DEBUG_MESSAGES)
198 zlog_warn("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d",
199 ifp->name,
200 inet_ntoa(p->u.prefix4),
201 p->prefixlen,
202 irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
203 get_pref(irdp, p));
204
205 send_packet (ifp, s, dst, p, ttl);
206}
207
208void irdp_advertisement (struct interface *ifp,
209 struct prefix *p)
210{
211 struct stream *s;
212 s = stream_new (128);
213 make_advertisement_packet (ifp, p, s);
214 irdp_send(ifp, p, s);
215}
216
217int irdp_send_thread(struct thread *t_advert)
218{
219 u_int32_t timer, tmp;
220 struct interface *ifp = THREAD_ARG (t_advert);
221 struct zebra_if *zi=ifp->info;
222 struct irdp_interface *irdp=&zi->irdp;
223 struct prefix *p;
224 listnode node;
225 struct connected *ifc;
226
227 irdp->flags &= ~IF_SOLICIT;
228
229 if(ifp->connected)
230 for (node = listhead (ifp->connected); node; nextnode (node)) {
231 ifc = getdata (node);
232
233 p = ifc->address;
234
235 irdp_advertisement(ifp, p);
236 irdp->irdp_sent++;
237
238 }
239
240 tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
241 timer = (random () % tmp ) + 1;
242 timer = irdp->MinAdvertInterval + timer;
243
244 if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
245 timer > MAX_INITIAL_ADVERT_INTERVAL )
246 timer= MAX_INITIAL_ADVERT_INTERVAL;
247
248 if(irdp->flags & IF_DEBUG_MISC)
249 zlog_warn("IRDP: New timer for %s set to %u\n", ifp->name, timer);
250
251 irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
252 return 0;
253}
254
255void irdp_advert_off(struct interface *ifp)
256{
257 struct zebra_if *zi=ifp->info;
258 struct irdp_interface *irdp=&zi->irdp;
259 listnode node;
260 int i;
261 struct connected *ifc;
262 struct prefix *p;
263
264 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
265 irdp->t_advertise = NULL;
266
267 if(ifp->connected)
268 for (node = listhead (ifp->connected); node; nextnode (node)) {
269 ifc = getdata (node);
270
271 p = ifc->address;
272
273 /* Output some packets with Lifetime 0
274 we should add a wait...
275 */
276
277 for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) {
278
279 irdp->irdp_sent++;
280 irdp_advertisement(ifp, p);
281 }
282 }
283}
284
285
286void process_solicit (struct interface *ifp)
287{
288 struct zebra_if *zi=ifp->info;
289 struct irdp_interface *irdp=&zi->irdp;
290 u_int32_t timer;
291
292 /* When SOLICIT is active we reject further incoming solicits
293 this keeps down the answering rate so we don't have think
294 about DoS attacks here. */
295
296 if( irdp->flags & IF_SOLICIT) return;
297
298 irdp->flags |= IF_SOLICIT;
299 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
300 irdp->t_advertise = NULL;
301
302 timer = (random () % MAX_RESPONSE_DELAY) + 1;
303
304 irdp->t_advertise = thread_add_timer(zebrad.master,
305 irdp_send_thread,
306 ifp,
307 timer);
308}
309
310void irdp_finish()
311{
312
313 listnode node;
314 struct interface *ifp;
315 struct zebra_if *zi;
316 struct irdp_interface *irdp;
317
318 zlog_warn("IRDP: Received shutdown notification.");
319
320 for (node = listhead (iflist); node; node = nextnode (node))
321 {
322 ifp = getdata(node);
323 zi= ifp->info;
324 if(! zi) continue;
325 irdp = &zi->irdp;
326 if(!irdp) continue;
327
328 if(irdp->flags & IF_ACTIVE ) {
329 irdp->flags |= IF_SHUTDOWN;
330 irdp_advert_off(ifp);
331 }
332 }
333}
334
335void irdp_init()
336{
337 irdp_sock_init();
338 irdp_if_init ();
339}
340
341
342
343#endif /* HAVE_IRDP */
344
345
346
347