New upstream release and new maintainer
[quagga-debian.git] / isisd / isis_misc.c
1 /*
2  * IS-IS Rout(e)ing protocol - isis_misc.h
3  *                             Miscellanous routines
4  *
5  * Copyright (C) 2001,2002   Sampo Saaristo
6  *                           Tampere University of Technology      
7  *                           Institute of Communications Engineering
8  *
9  * This program is free software; you can redistribute it and/or modify it 
10  * under the terms of the GNU General Public Licenseas published by the Free 
11  * Software Foundation; either version 2 of the License, or (at your option) 
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,but WITHOUT 
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
17  * more details.
18
19  * You should have received a copy of the GNU General Public License along 
20  * with this program; if not, write to the Free Software Foundation, Inc., 
21  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #include <zebra.h>
25
26 #include "stream.h"
27 #include "vty.h"
28 #include "hash.h"
29 #include "if.h"
30 #include "command.h"
31
32 #include "isisd/dict.h"
33 #include "isisd/isis_constants.h"
34 #include "isisd/isis_common.h"
35 #include "isisd/isis_flags.h"
36 #include "isisd/isis_circuit.h"
37 #include "isisd/isis_csm.h"
38 #include "isisd/isisd.h"
39 #include "isisd/isis_misc.h"
40
41 #include "isisd/isis_tlv.h"
42 #include "isisd/isis_lsp.h"
43 #include "isisd/isis_constants.h"
44 #include "isisd/isis_adjacency.h"
45 #include "isisd/isis_dynhn.h"
46
47 /* staticly assigned vars for printing purposes */
48 struct in_addr new_prefix;
49 /* len of xxxx.xxxx.xxxx + place for #0 termination */
50 char sysid[15];
51 /* len of xxxx.xxxx.xxxx + place for #0 termination */
52 char snpa[15];
53 /* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */
54 char isonet[51];
55 /* + place for #0 termination */
56 /* len of xxxx.xxxx.xxxx.xx.xx + place for #0 termination */
57 char lspid[21];
58 /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
59 char datestring[20];
60 char nlpidstring[30];
61
62 /*
63  * This converts the isonet to its printable format
64  */
65 const char *
66 isonet_print (const u_char * from, int len)
67 {
68   int i = 0;
69   char *pos = isonet;
70
71   if (!from)
72     return "unknown";
73
74   while (i < len)
75     {
76       if (i & 1)
77         {
78           sprintf (pos, "%02x", *(from + i));
79           pos += 2;
80         }
81       else
82         {
83           if (i == (len - 1))
84             {                   /* No dot at the end of address */
85               sprintf (pos, "%02x", *(from + i));
86               pos += 2;
87             }
88           else
89             {
90               sprintf (pos, "%02x.", *(from + i));
91               pos += 3;
92             }
93         }
94       i++;
95     }
96   *(pos) = '\0';
97   return isonet;
98 }
99
100 /*
101  * Returns 0 on error, length of buff on ok
102  * extract dot from the dotted str, and insert all the number in a buff 
103  */
104 int
105 dotformat2buff (u_char * buff, const char * dotted)
106 {
107   int dotlen, len = 0;
108   const char *pos = dotted;
109   u_char number[3];
110   int nextdotpos = 2;
111
112   number[2] = '\0';
113   dotlen = strlen(dotted);
114   if (dotlen > 50)
115     {
116       /* this can't be an iso net, its too long */
117       return 0;
118     }
119
120   while ((pos - dotted) < dotlen && len < 20)
121     {
122       if (*pos == '.')
123         {
124           /* we expect the . at 2, and than every 5 */
125           if ((pos - dotted) != nextdotpos)
126             {
127               len = 0;
128               break;
129             }
130           nextdotpos += 5;
131           pos++;
132           continue;
133         }
134       /* we must have at least two chars left here */
135       if (dotlen - (pos - dotted) < 2)
136         {
137           len = 0;
138           break;
139         }
140
141       if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1))))
142         {
143           memcpy (number, pos, 2);
144           pos += 2;
145         }
146       else
147         {
148           len = 0;
149           break;
150         }
151
152       *(buff + len) = (char) strtol ((char *)number, NULL, 16);
153       len++;
154     }
155
156   return len;
157 }
158
159 /*
160  * conversion of XXXX.XXXX.XXXX to memory
161  */
162 int
163 sysid2buff (u_char * buff, const char * dotted)
164 {
165   int len = 0;
166   const char *pos = dotted;
167   u_char number[3];
168
169   number[2] = '\0';
170   // surely not a sysid_string if not 14 length
171   if (strlen (dotted) != 14)
172     {
173       return 0;
174     }
175
176   while (len < ISIS_SYS_ID_LEN)
177     {
178       if (*pos == '.')
179         {
180           /* the . is not positioned correctly */
181           if (((pos - dotted) != 4) && ((pos - dotted) != 9))
182             {
183               len = 0;
184               break;
185             }
186           pos++;
187           continue;
188         }
189       if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1))))
190         {
191           memcpy (number, pos, 2);
192           pos += 2;
193         }
194       else
195         {
196           len = 0;
197           break;
198         }
199
200       *(buff + len) = (char) strtol ((char *)number, NULL, 16);
201       len++;
202     }
203
204   return len;
205
206 }
207
208 /*
209  * converts the nlpids struct (filled by TLV #129)
210  * into a string
211  */
212
213 char *
214 nlpid2string (struct nlpids *nlpids)
215 {
216   char *pos = nlpidstring;
217   int i;
218
219   for (i = 0; i < nlpids->count; i++)
220     {
221       switch (nlpids->nlpids[i])
222         {
223         case NLPID_IP:
224           pos += sprintf (pos, "IPv4");
225           break;
226         case NLPID_IPV6:
227           pos += sprintf (pos, "IPv6");
228           break;
229         case NLPID_SNAP:
230           pos += sprintf (pos, "SNAP");
231           break;
232         case NLPID_CLNP:
233           pos += sprintf (pos, "CLNP");
234           break;
235         case NLPID_ESIS:
236           pos += sprintf (pos, "ES-IS");
237           break;
238         default:
239           pos += sprintf (pos, "unknown");
240           break;
241         }
242       if (nlpids->count - i > 1)
243         pos += sprintf (pos, ", ");
244
245     }
246
247   *(pos) = '\0';
248
249   return nlpidstring;
250 }
251
252 /*
253  *  supports the given af ?
254  */
255 int
256 speaks (struct nlpids *nlpids, int family)
257 {
258   int i, speaks = 0;
259
260   if (nlpids == (struct nlpids *) NULL)
261     return speaks;
262   for (i = 0; i < nlpids->count; i++)
263     {
264       if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP)
265         speaks = 1;
266       if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6)
267         speaks = 1;
268     }
269
270   return speaks;
271 }
272
273 /*
274  * Returns 0 on error, IS-IS Circuit Type on ok
275  */
276 int
277 string2circuit_t (const char * str)
278 {
279
280   if (!str)
281     return 0;
282
283   if (!strcmp (str, "level-1"))
284     return IS_LEVEL_1;
285
286   if (!strcmp (str, "level-2-only") || !strcmp (str, "level-2"))
287     return IS_LEVEL_2;
288
289   if (!strcmp (str, "level-1-2"))
290     return IS_LEVEL_1_AND_2;
291
292   return 0;
293 }
294
295 const char *
296 circuit_state2string (int state)
297 {
298
299   switch (state)
300     {
301     case C_STATE_INIT:
302       return "Init";
303     case C_STATE_CONF:
304       return "Config";
305     case C_STATE_UP:
306       return "Up";
307     default:
308       return "Unknown";
309     }
310   return NULL;
311 }
312
313 const char *
314 circuit_type2string (int type)
315 {
316
317   switch (type)
318     {
319     case CIRCUIT_T_P2P:
320       return "p2p";
321     case CIRCUIT_T_BROADCAST:
322       return "lan";
323     case CIRCUIT_T_LOOPBACK:
324       return "loopback";
325     default:
326       return "Unknown";
327     }
328   return NULL;
329 }
330
331 const char *
332 circuit_t2string (int circuit_t)
333 {
334   switch (circuit_t)
335     {
336     case IS_LEVEL_1:
337       return "L1";
338     case IS_LEVEL_2:
339       return "L2";
340     case IS_LEVEL_1_AND_2:
341       return "L1L2";
342     default:
343       return "??";
344     }
345
346   return NULL;                  /* not reached */
347 }
348
349 const char *
350 syst2string (int type)
351 {
352   switch (type)
353     {
354     case ISIS_SYSTYPE_ES:
355       return "ES";
356     case ISIS_SYSTYPE_IS:
357       return "IS";
358     case ISIS_SYSTYPE_L1_IS:
359       return "1";
360     case ISIS_SYSTYPE_L2_IS:
361       return "2";
362     default:
363       return "??";
364     }
365
366   return NULL;                  /* not reached */
367 }
368
369 /*
370  * Print functions - we print to static vars
371  */
372 const char *
373 snpa_print (const u_char * from)
374 {
375   int i = 0;
376   u_char *pos = (u_char *)snpa;
377
378   if (!from)
379     return "unknown";
380
381   while (i < ETH_ALEN - 1)
382     {
383       if (i & 1)
384         {
385           sprintf ((char *)pos, "%02x.", *(from + i));
386           pos += 3;
387         }
388       else
389         {
390           sprintf ((char *)pos, "%02x", *(from + i));
391           pos += 2;
392
393         }
394       i++;
395     }
396
397   sprintf ((char *)pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
398   pos += 2;
399   *(pos) = '\0';
400
401   return snpa;
402 }
403
404 const char *
405 sysid_print (const u_char * from)
406 {
407   int i = 0;
408   char *pos = sysid;
409
410   if (!from)
411     return "unknown";
412
413   while (i < ISIS_SYS_ID_LEN - 1)
414     {
415       if (i & 1)
416         {
417           sprintf (pos, "%02x.", *(from + i));
418           pos += 3;
419         }
420       else
421         {
422           sprintf (pos, "%02x", *(from + i));
423           pos += 2;
424
425         }
426       i++;
427     }
428
429   sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
430   pos += 2;
431   *(pos) = '\0';
432
433   return sysid;
434 }
435
436 const char *
437 rawlspid_print (const u_char * from)
438 {
439   char *pos = lspid;
440   if (!from)
441     return "unknown";
442   memcpy (pos, sysid_print (from), 15);
443   pos += 14;
444   sprintf (pos, ".%02x", LSP_PSEUDO_ID (from));
445   pos += 3;
446   sprintf (pos, "-%02x", LSP_FRAGMENT (from));
447   pos += 3;
448
449   *(pos) = '\0';
450
451   return lspid;
452 }
453
454 const char *
455 time2string (u_int32_t time)
456 {
457   char *pos = datestring;
458   u_int32_t rest;
459
460   if (time == 0)
461     return "-";
462
463   if (time / SECS_PER_YEAR)
464     pos += sprintf (pos, "%uY", time / SECS_PER_YEAR);
465   rest = time % SECS_PER_YEAR;
466   if (rest / SECS_PER_MONTH)
467     pos += sprintf (pos, "%uM", rest / SECS_PER_MONTH);
468   rest = rest % SECS_PER_MONTH;
469   if (rest / SECS_PER_WEEK)
470     pos += sprintf (pos, "%uw", rest / SECS_PER_WEEK);
471   rest = rest % SECS_PER_WEEK;
472   if (rest / SECS_PER_DAY)
473     pos += sprintf (pos, "%ud", rest / SECS_PER_DAY);
474   rest = rest % SECS_PER_DAY;
475   if (rest / SECS_PER_HOUR)
476     pos += sprintf (pos, "%uh", rest / SECS_PER_HOUR);
477   rest = rest % SECS_PER_HOUR;
478   if (rest / SECS_PER_MINUTE)
479     pos += sprintf (pos, "%um", rest / SECS_PER_MINUTE);
480   rest = rest % SECS_PER_MINUTE;
481   if (rest)
482     pos += sprintf (pos, "%us", rest);
483
484   *(pos) = 0;
485
486   return datestring;
487 }
488
489 /*
490  * routine to decrement a timer by a random
491  * number
492  *
493  * first argument is the timer and the second is
494  * the jitter
495  */
496 unsigned long
497 isis_jitter (unsigned long timer, unsigned long jitter)
498 {
499   int j, k;
500
501   if (jitter >= 100)
502     return timer;
503
504   if (timer == 1)
505     return timer;
506   /* 
507    * randomizing just the percent value provides
508    * no good random numbers - hence the spread
509    * to RANDOM_SPREAD (100000), which is ok as
510    * most IS-IS timers are no longer than 16 bit
511    */
512
513   j = 1 + (int) ((RANDOM_SPREAD * random ()) / (RAND_MAX + 1.0));
514
515   k = timer - (timer * (100 - jitter)) / 100;
516
517   timer = timer - (k * j / RANDOM_SPREAD);
518
519   return timer;
520 }
521
522 struct in_addr
523 newprefix2inaddr (u_char * prefix_start, u_char prefix_masklen)
524 {
525   memset (&new_prefix, 0, sizeof (new_prefix));
526   memcpy (&new_prefix, prefix_start, (prefix_masklen & 0x3F) ?
527           ((((prefix_masklen & 0x3F) - 1) >> 3) + 1) : 0);
528   return new_prefix;
529 }
530
531 /*
532  * Returns host.name if any, otherwise
533  * it returns the system hostname.
534  */
535 const char *
536 unix_hostname (void)
537 {
538   static struct utsname names;
539   const char *hostname;
540
541   hostname = host.name;
542   if (!hostname)
543     {
544       uname (&names);
545       hostname = names.nodename;
546     }
547
548   return hostname;
549 }
550
551 /*
552  * Returns the dynamic hostname associated with the passed system ID.
553  * If no dynamic hostname found then returns formatted system ID.
554  */
555 const char *
556 print_sys_hostname (const u_char *sysid)
557 {
558   struct isis_dynhn *dyn;
559
560   if (!sysid)
561     return "nullsysid";
562
563   /* For our system ID return our host name */
564   if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
565     return unix_hostname();
566
567   dyn = dynhn_find_by_id (sysid);
568   if (dyn)
569     return (const char *)dyn->name.name;
570
571   return sysid_print (sysid);
572 }
573
574 /*
575  * This function is a generic utility that logs data of given length.
576  * Move this to a shared lib so that any protocol can use it.
577  */
578 void
579 zlog_dump_data (void *data, int len)
580 {
581   int i;
582   unsigned char *p;
583   unsigned char c;
584   char bytestr[4];
585   char addrstr[10];
586   char hexstr[ 16*3 + 5];
587   char charstr[16*1 + 5];
588
589   p = data;
590   memset (bytestr, 0, sizeof(bytestr));
591   memset (addrstr, 0, sizeof(addrstr));
592   memset (hexstr, 0, sizeof(hexstr));
593   memset (charstr, 0, sizeof(charstr));
594
595   for (i = 1; i <= len; i++)
596   {
597     c = *p;
598     if (isalnum (c) == 0)
599       c = '.';
600
601     /* store address for this line */
602     if ((i % 16) == 1)
603       snprintf (addrstr, sizeof(addrstr), "%p", p);
604
605     /* store hex str (for left side) */
606     snprintf (bytestr, sizeof (bytestr), "%02X ", *p);
607     strncat (hexstr, bytestr, sizeof (hexstr) - strlen (hexstr) - 1);
608
609     /* store char str (for right side) */
610     snprintf (bytestr, sizeof (bytestr), "%c", c);
611     strncat (charstr, bytestr, sizeof (charstr) - strlen (charstr) - 1);
612
613     if ((i % 16) == 0)
614     {
615       /* line completed */
616       zlog_debug ("[%8.8s]   %-50.50s  %s", addrstr, hexstr, charstr);
617       hexstr[0] = 0;
618       charstr[0] = 0;
619     }
620     else if ((i % 8) == 0)
621     {
622       /* half line: add whitespaces */
623       strncat (hexstr, "  ", sizeof (hexstr) - strlen (hexstr) - 1);
624       strncat (charstr, " ", sizeof (charstr) - strlen (charstr) - 1);
625     }
626     p++; /* next byte */
627   }
628
629   /* print rest of buffer if not empty */
630   if (strlen (hexstr) > 0)
631     zlog_debug ("[%8.8s]   %-50.50s  %s", addrstr, hexstr, charstr);
632   return;
633 }