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