| /* |
| * IS-IS Rout(e)ing protocol - isis_misc.h |
| * Miscellanous routines |
| * |
| * Copyright (C) 2001,2002 Sampo Saaristo |
| * Tampere University of Technology |
| * Institute of Communications Engineering |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public Licenseas published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * This program is distributed in the hope that it will be useful,but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| */ |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <time.h> |
| #include <ctype.h> |
| #include <zebra.h> |
| #include <sys/utsname.h> |
| |
| #include "stream.h" |
| #include "vty.h" |
| #include "hash.h" |
| #include "if.h" |
| #include "command.h" |
| |
| #include "isisd/dict.h" |
| #include "isisd/isis_constants.h" |
| #include "isisd/isis_common.h" |
| #include "isisd/isis_circuit.h" |
| #include "isisd/isisd.h" |
| #include "isisd/isis_misc.h" |
| |
| #include "isisd/isis_tlv.h" |
| #include "isisd/isis_lsp.h" |
| #include "isisd/isis_constants.h" |
| #include "isisd/isis_adjacency.h" |
| |
| /* |
| * This converts the isonet to its printable format |
| */ |
| char * isonet_print (u_char *from, int len) { |
| int i = 0; |
| char *pos = isonet; |
| |
| if(!from) |
| return "unknown"; |
| |
| while (i < len) { |
| if (i & 1) { |
| sprintf ( pos, "%02x", *(from + i)); |
| pos += 2; |
| } else { |
| if (i == (len - 1)) { /* No dot at the end of address */ |
| sprintf ( pos, "%02x", *(from + i)); |
| pos += 2; |
| } else { |
| sprintf ( pos, "%02x.", *(from + i)); |
| pos += 3; |
| } |
| } |
| i++; |
| } |
| *(pos) = '\0'; |
| return isonet; |
| } |
| |
| /* |
| * Returns 0 on error, length of buff on ok |
| * extract dot from the dotted str, and insert all the number in a buff |
| */ |
| int |
| dotformat2buff (u_char *buff, u_char *dotted) |
| { |
| int dotlen, len = 0; |
| u_char *pos = dotted; |
| u_char number[3]; |
| int nextdotpos = 2; |
| |
| number[2] = '\0'; |
| dotlen = strlen(dotted); |
| if (dotlen > 50) { |
| /* this can't be an iso net, its too long */ |
| return 0; |
| } |
| |
| while ( (pos - dotted) < dotlen && len < 20 ) { |
| if (*pos == '.') { |
| /* we expect the . at 2, and than every 5 */ |
| if ((pos - dotted) != nextdotpos) { |
| len = 0; |
| break; |
| } |
| nextdotpos += 5; |
| pos++; |
| continue; |
| } |
| /* we must have at least two chars left here */ |
| if (dotlen - (pos - dotted) < 2) { |
| len = 0; |
| break; |
| } |
| |
| if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos+1)))){ |
| memcpy (number, pos ,2); |
| pos+=2; |
| } else { |
| len = 0; |
| break; |
| } |
| |
| *(buff + len) = (char)strtol(number, NULL, 16); |
| len++; |
| } |
| |
| return len; |
| } |
| /* |
| * conversion of XXXX.XXXX.XXXX to memory |
| */ |
| int |
| sysid2buff (u_char *buff, u_char *dotted) |
| { |
| int len = 0; |
| u_char *pos = dotted; |
| u_char number[3]; |
| |
| number[2] = '\0'; |
| // surely not a sysid_string if not 14 length |
| if (strlen(dotted) != 14) { |
| return 0; |
| } |
| |
| while ( len < ISIS_SYS_ID_LEN ) { |
| if (*pos == '.') { |
| /* the . is not positioned correctly */ |
| if (((pos - dotted) !=4) && ((pos - dotted) != 9)) { |
| len = 0; |
| break; |
| } |
| pos++; |
| continue; |
| } |
| if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos+1)))){ |
| memcpy (number, pos ,2); |
| pos+=2; |
| } else { |
| len = 0; |
| break; |
| } |
| |
| *(buff + len) = (char)strtol(number, NULL, 16); |
| len++; |
| } |
| |
| return len; |
| |
| } |
| |
| /* |
| * converts the nlpids struct (filled by TLV #129) |
| * into a string |
| */ |
| |
| char * |
| nlpid2string (struct nlpids *nlpids) { |
| char *pos = nlpidstring; |
| int i; |
| |
| for (i=0;i<nlpids->count;i++) { |
| switch (nlpids->nlpids[i]) { |
| case NLPID_IP: |
| pos += sprintf (pos, "IPv4"); |
| break; |
| case NLPID_IPV6: |
| pos += sprintf (pos, "IPv6"); |
| break; |
| case NLPID_SNAP: |
| pos += sprintf (pos, "SNAP"); |
| break; |
| case NLPID_CLNP: |
| pos += sprintf (pos, "CLNP"); |
| break; |
| case NLPID_ESIS: |
| pos += sprintf (pos, "ES-IS"); |
| break; |
| default: |
| pos += sprintf (pos, "unknown"); |
| break; |
| } |
| if (nlpids->count-i>1) |
| pos += sprintf (pos, ", "); |
| |
| } |
| |
| *(pos) = '\0'; |
| |
| return nlpidstring; |
| } |
| |
| /* |
| * supports the given af ? |
| */ |
| int |
| speaks (struct nlpids *nlpids, int family) |
| { |
| int i, speaks = 0; |
| |
| if (nlpids == (struct nlpids*)NULL) |
| return speaks; |
| for (i = 0;i < nlpids->count; i++) { |
| if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP) |
| speaks = 1; |
| if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6) |
| speaks = 1; |
| } |
| |
| return speaks; |
| } |
| |
| |
| /* |
| * Returns 0 on error, IS-IS Circuit Type on ok |
| */ |
| int |
| string2circuit_t (u_char *str) |
| { |
| |
| if (!str) |
| return 0; |
| |
| if (!strcmp(str,"level-1")) |
| return IS_LEVEL_1; |
| |
| if (!strcmp(str,"level-2-only") || !strcmp(str,"level-2")) |
| return IS_LEVEL_2; |
| |
| if (!strcmp(str,"level-1-2")) |
| return IS_LEVEL_1_AND_2; |
| |
| return 0; |
| } |
| |
| const char * |
| circuit_t2string (int circuit_t) |
| { |
| switch (circuit_t) { |
| case IS_LEVEL_1: |
| return "L1"; |
| case IS_LEVEL_2: |
| return "L2"; |
| case IS_LEVEL_1_AND_2: |
| return "L1L2"; |
| default: |
| return "??"; |
| } |
| |
| return NULL; /* not reached */ |
| } |
| |
| const char * |
| syst2string (int type) |
| { |
| switch (type) { |
| case ISIS_SYSTYPE_ES: |
| return "ES"; |
| case ISIS_SYSTYPE_IS: |
| return "IS"; |
| case ISIS_SYSTYPE_L1_IS: |
| return "1"; |
| case ISIS_SYSTYPE_L2_IS: |
| return "2"; |
| default: |
| return "??"; |
| } |
| |
| return NULL; /* not reached */ |
| } |
| |
| /* |
| * Print functions - we print to static vars |
| */ |
| char * |
| snpa_print (u_char *from) |
| { |
| int i = 0; |
| u_char *pos = snpa; |
| |
| if(!from) |
| return "unknown"; |
| |
| while (i < ETH_ALEN - 1) { |
| if (i & 1) { |
| sprintf ( pos, "%02x.", *(from + i)); |
| pos += 3; |
| } else { |
| sprintf ( pos, "%02x", *(from + i)); |
| pos += 2; |
| |
| } |
| i++; |
| } |
| |
| sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); |
| pos += 2; |
| *(pos) = '\0'; |
| |
| return snpa; |
| } |
| |
| char * |
| sysid_print (u_char *from) |
| { |
| int i = 0; |
| char *pos = sysid; |
| |
| if(!from) |
| return "unknown"; |
| |
| while (i < ISIS_SYS_ID_LEN - 1) { |
| if (i & 1) { |
| sprintf ( pos, "%02x.", *(from + i)); |
| pos += 3; |
| } else { |
| sprintf ( pos, "%02x", *(from + i)); |
| pos += 2; |
| |
| } |
| i++; |
| } |
| |
| sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); |
| pos += 2; |
| *(pos) = '\0'; |
| |
| return sysid; |
| } |
| |
| char * |
| rawlspid_print (u_char *from) |
| { |
| char *pos = lspid; |
| if(!from) |
| return "unknown"; |
| memcpy(pos, sysid_print(from), 15); |
| pos += 14; |
| sprintf (pos, ".%02x", LSP_PSEUDO_ID(from)); |
| pos += 3; |
| sprintf (pos, "-%02x", LSP_FRAGMENT(from)); |
| pos += 3; |
| |
| *(pos) = '\0'; |
| |
| return lspid; |
| } |
| |
| char * |
| time2string (u_int32_t time) { |
| char *pos = datestring; |
| u_int32_t rest; |
| |
| if (time==0) |
| return "-"; |
| |
| if(time/SECS_PER_YEAR) |
| pos += sprintf (pos, "%uY",time/SECS_PER_YEAR); |
| rest=time%SECS_PER_YEAR; |
| if(rest/SECS_PER_MONTH) |
| pos += sprintf (pos, "%uM",rest/SECS_PER_MONTH); |
| rest=rest%SECS_PER_MONTH; |
| if(rest/SECS_PER_WEEK) |
| pos += sprintf (pos, "%uw",rest/SECS_PER_WEEK); |
| rest=rest%SECS_PER_WEEK; |
| if(rest/SECS_PER_DAY) |
| pos += sprintf (pos, "%ud",rest/SECS_PER_DAY); |
| rest=rest%SECS_PER_DAY; |
| if(rest/SECS_PER_HOUR) |
| pos += sprintf (pos, "%uh",rest/SECS_PER_HOUR); |
| rest=rest%SECS_PER_HOUR; |
| if(rest/SECS_PER_MINUTE) |
| pos += sprintf (pos, "%um",rest/SECS_PER_MINUTE); |
| rest=rest%SECS_PER_MINUTE; |
| if(rest) |
| pos += sprintf (pos, "%us",rest); |
| |
| *(pos) = 0; |
| |
| return datestring; |
| } |
| |
| /* |
| * routine to decrement a timer by a random |
| * number |
| * |
| * first argument is the timer and the second is |
| * the jitter |
| */ |
| unsigned long |
| isis_jitter (unsigned long timer, unsigned long jitter) |
| { |
| int j,k; |
| |
| if (jitter>=100) |
| return timer; |
| |
| if (timer == 1) |
| return timer; |
| /* |
| * randomizing just the percent value provides |
| * no good random numbers - hence the spread |
| * to RANDOM_SPREAD (100000), which is ok as |
| * most IS-IS timers are no longer than 16 bit |
| */ |
| |
| j = 1 + (int) ((RANDOM_SPREAD * rand()) / (RAND_MAX + 1.0 )); |
| |
| k = timer - (timer * (100 - jitter))/100; |
| |
| timer = timer - (k * j / RANDOM_SPREAD); |
| |
| return timer; |
| } |
| |
| struct in_addr |
| newprefix2inaddr (u_char *prefix_start, u_char prefix_masklen) |
| { |
| memset(&new_prefix, 0, sizeof (new_prefix)); |
| memcpy(&new_prefix, prefix_start, (prefix_masklen & 0x3F) ? |
| ((((prefix_masklen & 0x3F)-1)>>3)+1) : 0); |
| return new_prefix; |
| } |
| |
| /* |
| * Returns host.name if any, otherwise |
| * it returns the system hostname. |
| */ |
| const char * |
| unix_hostname(void) |
| { |
| static struct utsname names; |
| const char *hostname; |
| extern struct host host; |
| |
| hostname = host.name; |
| if (!hostname) { |
| uname(&names); |
| hostname = names.nodename; |
| } |
| |
| return hostname; |
| } |