www.usr.com/support/gpl/USR9108_release1.5.tar.gz
[bcm963xx.git] / userapps / opensource / zebra / 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 #ifdef BRCM_CMD_SUPPORT
563   install_element (INTERFACE_NODE, &ip_irdp_cmd);
564   install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd);
565   install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd);
566   install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd);
567   install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd);
568   install_element (INTERFACE_NODE, &ip_irdp_preference_cmd);
569   install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd);
570 #endif
571 }