]> git.proxmox.com Git - mirror_frr.git/blob - zebra/irdp.c
Initial revision
[mirror_frr.git] / zebra / irdp.c
1 /* ICMP Router Discovery Messages
2 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #include <zebra.h>
23
24 #include <netinet/ip_icmp.h>
25
26 #include "if.h"
27 #include "stream.h"
28 #include "memory.h"
29 #include "command.h"
30 #include "log.h"
31 #include "sockunion.h"
32 #include "sockopt.h"
33
34 #include "zebra/irdp.h"
35
36 /* Default does nothing. */
37 int irdp_mode = IRDP_NONE;
38
39 /* Timer interval of irdp. */
40 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
41
42 /* Max solicitations */
43 int max_solicitations = MAX_SOLICITATIONS;
44
45 #define IRDP_SOLICIT_PACKET_SIZE 8
46
47 static struct irdp *irdp_head = NULL;
48
49 extern int in_cksum (void *ptr, int nbytes);
50
51 char *icmp_type_str[] =
52 {
53 "Echo Reply",
54 "ICMP 1",
55 "ICMP 2",
56 "Dest Unreachable",
57 "Source Quench",
58 "Redirect",
59 "ICMP 6",
60 "ICMP 7",
61 "Echo",
62 "Router Advertise",
63 "Router Solicitation",
64 "Time Exceeded",
65 "Parameter Problem",
66 "Timestamp",
67 "Timestamp Reply",
68 "Info Request",
69 "Info Reply",
70 "Netmask Request",
71 "Netmask Reply",
72 };
73
74 char *
75 icmp_type (int type)
76 {
77 if (type < 0 || type >= (sizeof icmp_type_str / sizeof (char *))) {
78 return "OUT-OF-RANGE";
79 }
80 return icmp_type_str [type];
81 }
82
83 /* */
84 void
85 irdp_add_interface ()
86 {
87 ;
88 }
89
90 /* */
91 void
92 irdp_delete_interface ()
93 {
94
95 }
96
97 struct irdp *
98 irdp_route_new ()
99 {
100 struct irdp *new = XMALLOC (0, sizeof (struct irdp));
101 memset (new, 0, sizeof (struct irdp));
102 return new;
103 }
104
105 void
106 irdp_route_free (struct irdp *route)
107 {
108 XFREE (0, route);
109 }
110
111 void
112 route_delete ()
113 {
114
115 }
116
117 void
118 route_init ()
119 {
120
121 }
122
123 void
124 route_add (struct in_addr addr, unsigned long pref)
125 {
126 struct irdp *new = irdp_route_new();
127
128 new->prefix = addr;
129 new->pref = pref;
130
131 printf ("address %s\n", inet_ntoa (new->prefix));
132 printf ("pref %ld\n", new->pref);
133 }
134
135 void
136 route_age (int time)
137 {
138 struct irdp *p;
139
140 for (p = irdp_head; p != NULL; p = p->next) {
141 if (p->timer < time) {
142 /* fire */
143 } else {
144 p->timer -= time;
145 }
146 }
147 }
148
149 #define FLAG_TEST(a) ((ifp->flags & (a)) == (a))
150
151 void
152 send_multicast (struct interface *ifp, int sock, struct stream *s, int size)
153 {
154 struct sockaddr_in sin;
155 struct in_addr addr;
156 int nbytes;
157 struct connected *connected;
158 listnode node;
159
160 for (node = listhead (ifp->connected); node; nextnode (node))
161 {
162 connected = getdata (node);
163 }
164
165 if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
166 addr, 0, ifp->ifindex) < 0)
167 {
168 perror ("setsockopt");
169 exit (1);
170 }
171
172 sin.sin_addr.s_addr = htonl (INADDR_ALLRTRS_GROUP);
173 sin.sin_family = AF_INET;
174
175 nbytes = sendto (sock, s->data, size, 0,
176 (struct sockaddr *) &sin, sizeof (struct sockaddr));
177
178 if (nbytes != size)
179 {
180 perror ("sendto");
181 exit (1);
182 }
183 }
184
185 void
186 send_broadcast ()
187 {
188 struct sockaddr_in sin;
189
190 printf ("broadcast\n");
191 inet_aton ("255.255.255.255", &sin.sin_addr);
192 }
193
194 void
195 irdp_send_solicit (int sock, struct stream *s, int size)
196 {
197 struct interface *ifp;
198 listnode node;
199
200 for (node = listhead (iflist); node; nextnode (node))
201 {
202 ifp = getdata (node);
203 if (FLAG_TEST (IFF_UP | IFF_MULTICAST))
204 {
205 send_multicast (ifp, sock, s, size);
206 }
207 else if (FLAG_TEST (IFF_UP | IFF_BROADCAST))
208 {
209 send_broadcast ();
210 }
211 }
212 }
213
214 int
215 ipv4_multicast_join (int sock,
216 struct in_addr group,
217 struct in_addr ifa,
218 unsigned int ifindex)
219 {
220 int ret;
221
222 ret = setsockopt_multicast_ipv4 (sock, IP_ADD_MEMBERSHIP,
223 ifa, group.saddr, ifindex);
224
225 if (ret < 0)
226 zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP");
227
228 return ret;
229 }
230
231 /* multicast packet recieve socket */
232 int
233 irdp_multicast_socket (int sock, struct in_addr group)
234 {
235 struct interface *ifp;
236 listnode node;
237 struct in_addr addr;
238
239 for (node = listhead (iflist); node; nextnode (node))
240 {
241 ifp = getdata (node);
242
243 if ((ifp->flags & IFF_UP) && (ifp->flags & IFF_MULTICAST))
244 {
245 ipv4_multicast_join (sock, group, addr, ifp->ifindex);
246 }
247 }
248 return 0;
249 }
250
251 struct
252 {
253 u_char type;
254 u_char code;
255 u_int16_t checksum;
256 u_char number;
257 u_char entry;
258 u_int16_t lifetime;
259 } radv;
260
261 void
262 irdp_set (int sock)
263 {
264 struct in_addr irdp_group;
265
266 switch (irdp_mode)
267 {
268 case IRDP_HOST:
269 irdp_group.s_addr = htonl (INADDR_ALLHOSTS_GROUP);
270 break;
271 case IRDP_ROUTER:
272 irdp_group.s_addr = htonl (INADDR_ALLRTRS_GROUP);
273 break;
274 case IRDP_NONE:
275 default:
276 return;
277 }
278 irdp_multicast_socket (sock, irdp_group);
279 }
280
281 /* Make ICMP Router Solicitation Message. */
282 int
283 make_solicit_packet (struct stream *s)
284 {
285 int size;
286 int checksum;
287
288 stream_putc (s, ICMP_ROUTERSOLICIT); /* Type. */
289 stream_putc (s, 0); /* Code. */
290 stream_putw (s, 0); /* Checksum. */
291 stream_putl (s, 0); /* Reserved. */
292
293 /* in_cksum return network byte order value */
294 size = IRDP_SOLICIT_PACKET_SIZE;
295 checksum = in_cksum (s->data, size);
296 stream_putw_at (s, checksum, 2);
297
298 return IRDP_SOLICIT_PACKET_SIZE;
299 }
300
301 void
302 irdp_solicit (int sock)
303 {
304 struct stream *s;
305
306 s = stream_new (IRDP_SOLICIT_PACKET_SIZE);
307 make_solicit_packet (s);
308 irdp_send_solicit (sock, s, IRDP_SOLICIT_PACKET_SIZE);
309 }
310
311 #define ICMP_MINLEN 8
312
313 /* check validity of the packet */
314 int
315 irdp_valid_check (char *packet, size_t size, struct sockaddr_in *from)
316 {
317 struct icmp *icmp;
318
319 icmp = (struct icmp *) packet;
320
321 if (in_cksum (packet, size)) {
322 zlog_warn ("ICMP %s packet from %s: Bad checksum, silently ignored",
323 icmp_type (icmp->icmp_type),
324 inet_ntoa (from->sin_addr));
325 return -1;
326 }
327
328 if (icmp->icmp_code != 0) {
329 zlog_warn ("ICMP %s packet from %s: Bad ICMP type code, silently ignored",
330 icmp_type (icmp->icmp_type),
331 inet_ntoa (from->sin_addr));
332 return -1;
333 }
334
335 if (size < ICMP_MINLEN) {
336 zlog_warn ("ICMP %s packet from %s: IMCP message length is short",
337 icmp_type (icmp->icmp_type),
338 inet_ntoa (from->sin_addr));
339 return -1;
340 }
341 return 0;
342 }
343
344 int
345 irdp_solicit_recv (struct stream *s, int size, struct sockaddr_in *from)
346 {
347 if (irdp_valid_check (s->data, size, from)) {
348 return 1;
349 }
350 return 0;
351 }
352
353 void
354 irdp_advert_recv (struct stream *s, int size, struct sockaddr_in *from)
355 {
356 int i;
357 struct in_addr addr;
358 long pref;
359
360 if (irdp_valid_check (s->data, size, from) < 0) {
361 return;
362 }
363
364 radv.type = stream_getc (s);
365 radv.code = stream_getc (s);
366 radv.checksum = stream_getw (s);
367 radv.number = stream_getc (s);
368 radv.entry = stream_getc (s);
369 radv.lifetime = stream_getw (s);
370
371 printf ("type : %s\n", icmp_type (radv.type));
372 printf ("number: %d\n", radv.number);
373 printf ("entry: %d\n", radv.entry);
374 printf ("lifetime: %d\n", radv.entry);
375
376 for (i = 0; i < radv.number; i++)
377 {
378 addr.s_addr = stream_getl (s);
379 pref = stream_getl (s);
380 route_add (addr, ntohl (pref));
381 }
382 /* Packet size check is needed at here. */
383 }
384
385 void
386 irdp_packet_process (char *buf, int size, struct sockaddr_in *from)
387 {
388 struct ip *ip;
389 struct icmp *icmp;
390 int hlen;
391 struct stream *s = NULL;
392
393 ip = (struct ip *)buf;
394 hlen = ip->ip_hl << 2;
395
396 if (size < hlen + ICMP_MINLEN)
397 zlog_err ("ICMP relpy length is short\n");
398
399 icmp = (struct icmp *)(buf + hlen);
400
401 stream_forward (s, hlen);
402
403 switch (icmp->icmp_type)
404 {
405 case ICMP_ROUTERADVERT:
406 irdp_advert_recv (s, size - hlen, from);
407 break;
408 case ICMP_ROUTERSOLICIT:
409 irdp_solicit_recv (s, size - hlen, from);
410 break;
411 }
412 }
413
414 /* Make socket for ICMP Router Discovery. */
415 int
416 irdp_make_socket ()
417 {
418 int sock;
419 struct protoent *pent;
420
421 if ((pent = getprotobyname ("icmp")) == NULL) {
422 perror ("getprotobyname");
423 exit (1);
424 }
425
426 if ((sock = socket (AF_INET, SOCK_RAW, pent->p_proto)) < 0)
427 {
428 perror ("socket");
429 exit (1);
430 }
431
432 return sock;
433 }
434
435 /* recv routine */
436 int
437 irdp_recv (int sock)
438 {
439 #define PACKET_BUF 4096
440 int nbytes;
441 struct sockaddr_in from;
442 int fromlen;
443 char buf[PACKET_BUF];
444
445 fromlen = sizeof (from);
446 nbytes = recvfrom (sock, (char *)buf, PACKET_BUF, 0,
447 (struct sockaddr *)&from, &fromlen);
448
449 if (nbytes < 0)
450 {
451 perror ("recvfrom");
452 exit (1);
453 }
454
455 irdp_packet_process (buf, nbytes, &from);
456
457 return 0;
458 }
459
460 /* irdp packet recv loop */
461 void
462 irdp_loop (int sock)
463 {
464 while (1)
465 {
466 irdp_recv (sock);
467 }
468 }
469 \f
470 DEFUN (ip_irdp,
471 ip_irdp_cmd,
472 "ip irdp",
473 IP_STR
474 "ICMP Router discovery on this interface\n")
475 {
476 return CMD_SUCCESS;
477 }
478
479 DEFUN (ip_irdp_multicast,
480 ip_irdp_multicast_cmd,
481 "ip irdp multicast",
482 IP_STR
483 "ICMP Router discovery on this interface\n"
484 "Send IRDP advertisement to the multicast address\n")
485 {
486 return CMD_SUCCESS;
487 }
488
489 DEFUN (ip_irdp_holdtime,
490 ip_irdp_holdtime_cmd,
491 "ip irdp holdtime <0-9000>",
492 IP_STR
493 "ICMP Router discovery on this interface\n"
494 "Set holdtime value\n"
495 "Holdtime value in seconds. Default is 1800 seconds\n")
496 {
497 return CMD_SUCCESS;
498 }
499
500 DEFUN (ip_irdp_maxadvertinterval,
501 ip_irdp_maxadvertinterval_cmd,
502 "ip irdp maxadvertinterval (0|<4-1800>)",
503 IP_STR
504 "ICMP Router discovery on this interface\n"
505 "Set maximum time between advertisement\n"
506 "Maximum advertisement interval in seconds\n")
507 {
508 return CMD_SUCCESS;
509 }
510
511 DEFUN (ip_irdp_minadvertinterval,
512 ip_irdp_minadvertinterval_cmd,
513 "ip irdp minadvertinterval <3-1800>",
514 IP_STR
515 "ICMP Router discovery on this interface\n"
516 "Set minimum time between advertisement\n"
517 "Minimum advertisement interval in seconds\n")
518 {
519 return CMD_SUCCESS;
520 }
521
522 DEFUN (ip_irdp_preference,
523 ip_irdp_preference_cmd,
524 /* "ip irdp preference <-2147483648-2147483647>", */
525 "ip irdp preference <0-2147483647>",
526 IP_STR
527 "ICMP Router discovery on this interface\n"
528 "Set default preference level for this interface\n"
529 "Preference level\n")
530 {
531 return CMD_SUCCESS;
532 }
533
534 #if 0
535 DEFUN (ip_irdp_address,
536 ip_irdp_address_cmd,
537 "ip irdp address A.B.C.D",
538 IP_STR
539 "ICMP Router discovery on this interface\n"
540 "Specify IRDP address and preference to proxy-advertise\n"
541 "Set IRDP address for proxy-advertise\n")
542 {
543 return CMD_SUCCESS;
544 }
545 #endif /* 0 */
546
547 DEFUN (ip_irdp_address_preference,
548 ip_irdp_address_preference_cmd,
549 "ip irdp address A.B.C.D <0-2147483647>",
550 IP_STR
551 "ICMP Router discovery on this interface\n"
552 "Specify IRDP address and preference to proxy-advertise\n"
553 "Set IRDP address for proxy-advertise\n"
554 "Preference level\n")
555 {
556 return CMD_SUCCESS;
557 }
558 \f
559 void
560 irdp_init ()
561 {
562 install_element (INTERFACE_NODE, &ip_irdp_cmd);
563 install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd);
564 install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd);
565 install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd);
566 install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd);
567 install_element (INTERFACE_NODE, &ip_irdp_preference_cmd);
568 install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd);
569 }