home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ee.lbl.gov
/
2014.05.ftp.ee.lbl.gov.tar
/
ftp.ee.lbl.gov
/
mrdebug.tar.Z
/
mrdebug.tar
/
user.c
< prev
Wrap
C/C++ Source or Header
|
1993-10-25
|
26KB
|
845 lines
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
#include "types.h"
#include "mrhash.h"
#include "data_struct_proto.h"
#include "build_adj_proto.h"
#include "dist_vect_proto.h"
#include "user_proto.h"
/********* EXTERNAL REFERENCES ***********/
extern int verbose;
extern int reverse_path;
extern int disable_ifc(Network *net, NAME frm_name, NAME to_name, FILE *out );
/****************************************************************
FUNCTION: parse_user_input( Network *net, NAME source, NAME dest )
DESCRIPTION:
This function requests user input and resets the appropriate
variables for the next tree printout.
********************************************************************/
int parse_user_input( Network *net, NAME source, NAME dest, long *max_thresh,
Ifc_list *subnets, FILE **out )
{
char cur_input[MAXLINE],
other[MAXLINE],
other2[MAXLINE];
char ans;
int args;
long number, number2;
Node *node1;
HENTRY_t *ht_entry_p;
Interface *cur_ifc = NULL;
NAME frm_name, to_name;
Change_item *cur_change;
FILE *net_out;
if( verbose )
{
printf( "\n\nCurrent source: %s\n", source );
printf( "Current destination: %s\n", dest );
printf( "\nEnter command: ");
}
else
printf( "\n> ");
strcpy( frm_name, "\0" );
strcpy( to_name, "\0" );
if( gets( cur_input ) == NULL )
{
printf( "\n");
exit(0);
}
ans = NULL;
args = sscanf( cur_input, "%c%s%s", &ans, &frm_name, &to_name );
switch( ans )
{
case 's':
/*
** Specify a new source for the multicast
*/
if( args == 2 )
strcpy( source, frm_name );
else
{
printf( "Enter the name of the source interface: ");
gets( cur_input );
sscanf( cur_input, "%s", source );
}
return FIND_TREE;
break;
case 'd':
/*
** Specify a new destination for the multicast
*/
if( args == 2 )
strcpy( dest, frm_name );
else
{
printf( "Enter the name of the destination interface: ");
gets( cur_input );
sscanf( cur_input, "%s", dest );
}
return FALSE;
break;
case 'o':
if( *out != stdout )
fclose( *out );
if( args == 1 )
{
printf( "Enter the name of the output file (and a to append): ");
gets( cur_input );
args = sscanf( cur_input, "%s%s", frm_name, to_name );
args++;
}
if( args > 2 && to_name[0] == 'a' )
{
strcpy( to_name, "a" );
if( verbose )
printf( "\nOutput will be appended to file %s\n", frm_name );
}
else if( args > 1 )
{
strcpy( to_name, "w" );
if( verbose )
printf( "\nOutput will be written to file %s\n", frm_name );
}
if( args >= 2 )
{
if( !(*out = fopen( frm_name, to_name )))
{
printf( "Unable to open %s output will go to the terminal\n",
frm_name );
*out = stdout;
}
}
else
{
if( verbose )
printf( "\nOutput will be printed to the terminal\n");
*out = stdout;
}
break;
case 't':
case 'u':
/*
** Print the multicast tree or unreachables for the current source.
** Take into account the ttl if specified.
*/
*max_thresh = -1;
if( args >= 3 )
{
strcpy( source, frm_name );
sscanf( to_name, "#%ld", max_thresh );
}
else if( args == 2 )
{
if( frm_name[0] == '#' )
sscanf( frm_name, "#%ld", max_thresh );
else
strcpy( source, frm_name );
}
if( ans == 't' )
return PRINT_TREE;
else
return PRINT_UNREACH;
break;
case 'p':
/*
** Print the multicast path from the current source to
** the current destination.
*/
if( args == 3 )
{
strcpy( source, frm_name );
strcpy( dest, to_name );
}
else if( args == 2 )
strcpy( dest, frm_name );
return PRINT_PATH;
break;
case 'l':
/*
** Reverse the direction of the metric used in calculating
** trees and paths.
*/
if( reverse_path )
reverse_path = FALSE;
else
reverse_path = TRUE;
if( verbose )
{
if( reverse_path )
printf( "Now using the forward direction metrics\n");
else
printf( "Now using the reverse direction metrics\n");
}
return FIND_TREE;
break;
case 'e':
/*
** Print out explanatory text defining the output formats
*/
explain_output( stdout );
break;
case 'n':
/*
** Print out the adjacency list for a specified node
*/
if( args < 2 )
{
printf( "Enter interface name: " );
gets( cur_input );
sscanf( cur_input, "%s", frm_name );
}
ht_entry_p = find_actual_name( net, frm_name, subnets );
if( ht_entry_p != NULL )
print_node( net, ht_entry_p->index, *out );
break;
case 'h':
/*
** Print the history of changes made to the network starting
** with the most recent and going back. If an argument is
** supplied, then only print that many changes.
*/
number = -1;
if( args > 1 )
sscanf( frm_name, "%ld", &number );
print_changes( &net->changes, number, *out );
break;
case 'r':
/*
** Disable a tunnel or interface, the type is determined
** based on the number of input arguments supplied. 1
** implies a subnet interface and 2 imply the tunnel between
** the specified interfaces.
*/
if( args > 1 )
args--;
else
{
printf( "Specify interface to be removed or two for a tunnel: ");
gets( cur_input );
args = sscanf( cur_input, "%s%s", frm_name, to_name );
}
if( args < 1 || args > 2 )
{
printf( "\nIncorrect input specified\n");
return FALSE;
break;
}
if( args == 2 )
{/*
** Disable the specified tunnel
*/
ht_entry_p = find_actual_name( net, frm_name, subnets );
strcpy( frm_name, ht_entry_p->key_p );
ht_entry_p = find_actual_name( net, to_name, subnets );
strcpy( to_name, ht_entry_p->key_p );
if( !disable_ifc( net, frm_name, to_name, *out ) )
return FALSE;
else
{
cur_change = push_change( &net->changes, DISABLE_TUNNEL, frm_name, to_name );
return FIND_TREE;
}
}
if( args == 1 )
{/*
** Disable the specified interface and all tunnels associated
** with it.
*/
ht_entry_p = find_actual_name( net, frm_name, subnets );
strcpy( frm_name, ht_entry_p->key_p );
if( ht_entry_p != NULL )
{
node1 = &(net->adj_list[ht_entry_p->index]);
cur_ifc = find_name( &node1->interfaces, frm_name );
}
if( cur_ifc == NULL )
{
printf( "\nInterface %s not found\n", frm_name );
return FALSE;
}
cur_change = push_change( &net->changes, DISABLE_IFC, frm_name, "\0" );
for( ; cur_ifc != NULL; cur_ifc = cur_ifc->next )
{
if( !(strcmp( cur_ifc->name, frm_name)))
disable_ifc( net, frm_name, cur_ifc->to_name, *out );
else
return FIND_TREE;
}
return FIND_TREE;
}
break;
case 'a':
/*
** Add a tunnel or interface. If the tunnel already
** exists, it is simply reenabled. When a subnet interface
** is added, a search for all interfaces on the subnet is
** undertaken and edges to and from all such interfaces are added.
*/
if( args > 1 )
args--;
else
{
/*printf( "Warning only known interfaces can be specified\n");*/
printf( "Enter interface to add or two for a tunnel:");
gets( cur_input );
args = sscanf( cur_input, "%s%s", frm_name, to_name );
}
if( args < 1 || args > 2 )
{
printf( "\nInvalid input specified\n");
return FALSE;
break;
}
ht_entry_p = find_actual_name( net, frm_name, subnets );
if( ht_entry_p != NULL )
if( !compare_names( ht_entry_p->key_p, frm_name ) &&
(net->adj_list[ht_entry_p->index].type & SUBNET) )
ht_entry_p = NULL;
if( ht_entry_p == NULL )
{
if( !add_new_node( net, frm_name, subnets ))
return FALSE;
else
ht_entry_p = find_actual_name( net, frm_name, subnets );
}
strcpy( frm_name, ht_entry_p->key_p );
node1 = &(net->adj_list[ht_entry_p->index]);
cur_ifc = find_name( &node1->interfaces, frm_name );
if( args == 2 )
{
ht_entry_p = find_actual_name( net, to_name, subnets );
if( ht_entry_p != NULL )
if( !compare_names( ht_entry_p->key_p, to_name ) &&
(net->adj_list[ht_entry_p->index].type & SUBNET))
ht_entry_p = NULL;
if( ht_entry_p == NULL )
{
if( !add_new_node( net, to_name, subnets ))
return FALSE;
else
ht_entry_p = find_actual_name( net, to_name, subnets );
}
strcpy( to_name, ht_entry_p->key_p );
cur_ifc = find_ifc( net, cur_ifc, frm_name, to_name );
if( cur_ifc != NULL )
{
printf( "\nenabling interface from %s to %s\n", frm_name, to_name );
if( *out != stdout )
fprintf(*out, "\nenabling interface from %s to %s\n", frm_name, to_name );
cur_ifc->type &= ~(DOWN|DISABLED);
}
else
{
printf( "Enter edge characteristics in [] separated by /'s: ");
gets( other );
printf( "\nAdding edge %s to %s as %s \n", frm_name, to_name, other );
if( *out != stdout )
fprintf(*out, "\nAdding edge %s to %s as %s \n", frm_name, to_name, other );
strcpy( other2, other );
add_ifc( net, frm_name, to_name, other, FALSE);
}
cur_ifc = find_ifc( net, NULL, to_name, frm_name );
if( cur_ifc != NULL )
{
printf( "enabling edge from %s to %s\n", to_name, frm_name );
if( *out != stdout )
fprintf( *out,"enabling edge from %s to %s\n", to_name, frm_name );
cur_ifc->type &= ~(DOWN|DISABLED);
}
else
{
ht_entry_p = lookup_htable( &net->name_map, to_name );
printf( "Adding edge %s to %s as %s\n", to_name, frm_name, other2 );
if( *out != stdout )
fprintf(*out, "Adding edge %s to %s as %s\n", to_name, frm_name, other2 );
add_ifc( net, to_name, frm_name, other2, FALSE );
}
cur_change = push_change( &net->changes, ADD_TUNNEL, frm_name, to_name );
}
else if( args == 1 )
{
cur_change = push_change( &net->changes, ADD_IFC, frm_name, "\0" );
add_subnet_conn( net, cur_ifc, frm_name, *out );
}
return FIND_TREE;
break;
case 'c':
/*
** Change a metric or threshold for a tunnel or a
** subnet interface.
*/
if( args == 1 )
{
printf( "Specify interface to be changed or two for a tunnel: ");
gets( cur_input );
args = sscanf( cur_input, "%s%s", frm_name, to_name );
args++;
}
if( args < 2 || args > 3 )
{
printf( "\nIncorrect input specified\n");
return FALSE;
break;
}
if( args == 3 )
{/*
** The interface to be changed is a tunnel
*/
ht_entry_p = find_actual_name( net, frm_name, subnets );
strcpy( frm_name, ht_entry_p->key_p );
ht_entry_p = find_actual_name( net, to_name, subnets );
strcpy( to_name, ht_entry_p->key_p );
cur_ifc = find_ifc( net, NULL, frm_name, to_name );
}
if( args == 2 )
{/*
** The interface to be changed is a subnet interface
*/
ht_entry_p = find_actual_name( net, frm_name, subnets );
strcpy( frm_name, ht_entry_p->key_p );
if( ht_entry_p == NULL )
{
printf( "\nInvalid interface name specified %s\n", frm_name );
cur_ifc = NULL;
}
else
{
node1 = &(net->adj_list[ht_entry_p->index]);
cur_ifc = find_conn_subnet( &node1->interfaces, frm_name );
if( cur_ifc != NULL )
strcpy( to_name, cur_ifc->to_name );
else
printf( "\nInvalid interface name specified %s\n", frm_name );
}
}
if( cur_ifc != NULL )
{
printf( "Current metric = %ld and threshold = %ld\n",
cur_ifc->metric, cur_ifc->threshold);
printf( "Enter new metric and new threshold: ");
gets( cur_input );
args = sscanf( cur_input, "%ld%ld", &number, &number2 );
if( args >= 1 )
{/*
** Changing the metric for this interface
*/
cur_change = push_change( &net->changes, CHANGE_METRIC,
frm_name, to_name );
cur_change->val1 = cur_ifc->metric;
cur_change->val2 = number;
printf( "\nChanging metric of %s %s from %ld to %ld\n", frm_name,
to_name, cur_change->val1, cur_change->val2);
if( *out != stdout )
fprintf(*out, "\nChanging metric of %s %s from %ld to %ld\n", frm_name,
to_name, cur_change->val1, cur_change->val2 );
cur_ifc->metric = number;
}
else
printf( "\nNo new values specified\n");
if( args == 2 )
{/*
** Changing the threshold for this interface
*/
cur_change = push_change( &net->changes, CHANGE_THRESH,
frm_name, to_name );
cur_change->val1 = cur_ifc->threshold;
cur_change->val2 = number2;
printf( "Changing threshold of %s %s from %ld to %ld\n", frm_name,
to_name, cur_change->val1, cur_change->val2);
if( *out != stdout )
fprintf(*out, "Changing threshold of %s %s from %ld to %ld\n", frm_name,
to_name, cur_change->val1, cur_change->val2);
cur_ifc->threshold = number2;
}
}
return FIND_TREE;
break;
case 'v':
/*
** This option is used to toggle the verbose mode of the program
*/
if( verbose )
verbose = FALSE;
else
verbose = TRUE;
return FALSE;
break;
case 'w':
if( args == 1 )
{
printf( "Enter the name of the network file to write: ");
gets( cur_input );
args = sscanf( cur_input, "%s", frm_name );
args++;
}
else if( args > 1 )
{
if( verbose )
printf( "\nNetwork description will be written to file %s\n", frm_name );
}
if( args >= 2 )
{
if( !(net_out = fopen( frm_name, "w" )))
printf( "Unable to open %s for output\n", frm_name );
else
print_network( net_out, net );
}
return FALSE;
break;
case 'q':
/*
** Exit the program
*/
return DONE;
break;
case '?':
printf( "Command Options:\n");
printf( "\ts. Specify a new source\n");
printf( "\td. Specify a new destination\n" );
printf( "\to. Specify a new output file\n" );
printf( "\tt. Print source tree ( #ttl can be specified as an argument)\n");
printf( "\tp. Print path from source to destination\n");
printf( "\tu. Print unreachable interfaces\n" );
printf( "\tn. Print the adjacency list for a node\n" );
printf( "\th. Print the change history\n" );
printf( "\tl. Change the link metric direction used\n");
printf( "\te. Explain output symbols\n" );
printf( "\tr. Remove a tunnel or interface from the network\n" );
printf( "\ta. Add a tunnel or interface to the network\n" );
printf( "\tc. Change a metric and threshold\n" );
printf( "\tv. Toggle verbose mode\n" );
printf( "\tw. Write the current network to a network input file\n" );
printf( "\tq. Quit this program\n" );
printf( "\t?. Print this list\n" );
return FALSE;
break;
default:
printf( "\nInvalid command, use ? to get commands\n");
return FALSE;
break;
}
return 0;
}
/**************************************************************************
FUNCTION: disable_ifc( net, cur_ifc, frm_name, to_name )
DESCRIPTION:
This function removes an edge from the network by changing the
type fields of its forward and backward interfaces to disabled.
This function is only called for tunnels.
**************************************************************************/
int disable_ifc( Network *net, NAME frm_name, NAME to_name, FILE *out )
{
Interface *cur_ifc;
cur_ifc = find_ifc( net, NULL, frm_name, to_name );
if( cur_ifc != NULL )
{
printf( "\ndisabling interface from %s to %s\n", frm_name, to_name );
if( out != stdout )
fprintf(out, "\ndisabling interface from %s to %s\n", frm_name, to_name );
cur_ifc->type |= DISABLED;
}
else
{
printf( "\nInterface %s to %s not found\n", frm_name, to_name );
return FALSE;
}
cur_ifc = find_ifc( net, NULL, to_name, frm_name );
if( cur_ifc != NULL )
{
printf( "disabling interface from %s to %s\n", to_name, frm_name );
if( out != stdout )
fprintf(out,"disabling interface from %s to %s\n", to_name, frm_name );
cur_ifc->type |= DISABLED;
}
else
{
printf( "Backward interface not found\n");
return FALSE;
}
return TRUE;
}
/***********************************************************************
FUNCTION: add_subnet_conn( net, ifc, frm_name )
DESCRIPTION:
This function enables all interface edges with the specified name
and it also enables the backward edges. This includes the subnet
connection and all tunnels.
*********************************************************************/
void add_subnet_conn( Network *net, Interface *frm_ifc, NAME frm_name, FILE *out )
{
Interface *back_ifc;
for( ;frm_ifc != NULL; frm_ifc = frm_ifc->next )
{/*
** If this is the last interface with this name, then we are done.
*/
if( strcmp( frm_ifc->name, frm_name ))
return;
/*
** Enable the forward interface
*/
frm_ifc->type &= ~(DOWN | DISABLED);
printf( "\nEnabling interface %s to %s\n", frm_name, frm_ifc->to_name );
if( out != stdout )
fprintf( out, "\nEnabling interface %s to %s\n", frm_name, frm_ifc->to_name );
/*
** Now to enable the backward interface
*/
back_ifc = find_ifc( net, NULL, frm_ifc->to_name, frm_ifc->name );
if( back_ifc != NULL )
{
printf( "Enabling interface from %s to %s\n", back_ifc->name,
frm_name );
if( out != stdout )
fprintf(out, "Enabling interface from %s to %s\n", back_ifc->name,
frm_name );
back_ifc->type &= ~(DOWN|DISABLED);
}
else
printf( "backward interface not found\n");
}
}
/*******************************************************************
FUNCTION: push_change( Change_stack *stack, u_long type, NAME frm_name, NAME to_name )
DESCRIPTION:
This function pushes a network change onto a stack for later
retrieval. It returns a pointer to the change.
**********************************************************************/
Change_item *push_change( Change_stack *stack, u_long type, NAME frm_name, NAME to_name )
{
Change_item *cur_change;
cur_change = (Change_item *)calloc(1, sizeof(Change_item));
cur_change->type = type;
strcpy( cur_change->frm_name, frm_name );
strcpy( cur_change->to_name, to_name );
if( stack->number == 0 )
{
stack->last = cur_change;
cur_change->next = NULL;
}
else
{
cur_change->next = stack->last;
stack->last = cur_change;
}
stack->number++;
return cur_change;
}
/*********************************************************************
FUNCTION: extract_change( Change_stack *stack, u_long type, NAME frm_name,
NAME to_name )
DESCRIPTION:
This function finds the specified change and returns it. It
also removes it from the stack.
**********************************************************************/
Change_item *extract_change( Change_stack *stack, u_long type, NAME frm_name,
NAME to_name )
{
Change_item *cur_chng, *prev_chng;
cur_chng = stack->last;
if( cur_chng->type == type && !(strcmp( frm_name, cur_chng->frm_name ))
&& !(strcmp( to_name, cur_chng->to_name )))
{
stack->last = cur_chng->next;
stack->number--;
return cur_chng;
}
prev_chng = cur_chng;
for( cur_chng = cur_chng->next; cur_chng != NULL; cur_chng = cur_chng->next )
{
if( cur_chng->type == type && !(strcmp( frm_name, cur_chng->frm_name ))
&& !(strcmp( to_name, cur_chng->to_name )))
{
prev_chng->next = cur_chng->next;
stack->number--;
return cur_chng;
}
prev_chng = cur_chng;
}
return NULL;
}
/*****************************************************************************
FUNCTION: print_changes( Change_stack *stack, long number, FILE *out )
DESCRIPTION:
This function prints out the last 'number' changes made to the
network. It prints them starting from the most recent.
***************************************************************************/
void print_changes( Change_stack *stack, long number, FILE *out )
{
Change_item *cur_chng;
long i, cur_num;
fprintf( out, "\nPrinting change history most recent first:\n" );
if( number < 0 || number > stack->number )
number = stack->number;
cur_num = stack->number;
for( i = 0, cur_chng = stack->last; i < number; i++, cur_num-- )
{
switch( cur_chng->type )
{
case DISABLE_IFC:
fprintf(out, "\t%ld. Disabled interface %s\n", cur_num, cur_chng->frm_name );
break;
case DISABLE_TUNNEL:
fprintf( out,"\t%ld. Disabled tunnel %s %s\n", cur_num, cur_chng->frm_name, cur_chng->to_name );
break;
case ADD_IFC:
fprintf(out, "\t%ld. Added interface %s\n", cur_num, cur_chng->frm_name );
break;
case ADD_TUNNEL:
fprintf(out, "\t%ld. Added tunnel %s %s\n", cur_num, cur_chng->frm_name, cur_chng->to_name );
break;
case CHANGE_METRIC:
fprintf(out, "\t%ld. Changed metric of %s %s from %ld to %ld\n", cur_num,
cur_chng->frm_name, cur_chng->to_name, cur_chng->val1, cur_chng->val2);
break;
case CHANGE_THRESH:
fprintf(out, "\t%ld. Changed threshold of %s %s from %ld to %ld\n", cur_num,
cur_chng->frm_name, cur_chng->to_name, cur_chng->val1, cur_chng->val2);
break;
}
cur_chng = cur_chng->next;
}
return;
}
/**************************************************************************
FUNCTION: explain_output( FILE *out )
DESCRIPTION:
Print a description of the output formats for each of the
options.
***************************************************************************/
void explain_output( FILE *out )
{
fprintf(out, "\nSource trees and paths:\n");
fprintf(out, "\tinterface, tree level/metric to here/ttl to reach\n");
fprintf(out, "\t- Indentation indicates tree level\n");
fprintf( out, "\t- A destination is SUSPECT if the tunnel was only specified\n");
fprintf(out, "\t in one direction in the input file, and the interface appeared\n");
fprintf(out, "\t with a ? in the input file\n");
fprintf(out, "\t- A metric of -1 indicates the message will be sent to this\n");
fprintf(out, "\t router along this path, but it is not from the parent interface\n");
fprintf(out, "\t- The unreachable interfaces list: down means\n");
fprintf(out, "\t the entire subnet interface is down\n\n");
fprintf(out, "Adjacency list (n option):\n");
fprintf(out, "\t- All equivalent interfaces at a site are printed.\n");
fprintf(out, "\t- Mask defines subnet mask for address resolution\n");
fprintf(out, "\t- m/t lists the current metric and threshold for the interface\n");
fprintf(out, "\tType field:\n");
fprintf(out, "\t\tLow Byte (1st) gives interface type:\n");
fprintf(out, "\t\t\tTunnel = 1, Querier = 2, Srcrt = 4, Subnet = 8\n");
fprintf(out, "\t\t2nd Byte gives interface internal information:\n");
fprintf(out, "\t\t\tAssumed = 1 (this interface was assumed to be a tunnel)\n");
fprintf(out, "\t\t3rd Byte gives current interface status:\n");
fprintf(out, "\t\t\tDown = 1, Disabled = 2, Suspect = 4\n");
fprintf(out, "\t\t5th Byte gives multicast routing information:\n");
fprintf(out, "\t\t\tLeaf = 1, Child = 2, Parent = 4\n" );
fprintf(out, "\t\t\t(for explanation see S. Deering's thesis)\n");
return;
}
/****************************************************************************
FUNCTION: print_network()
DESCRIPTION:
This function writes the current network description to a file
for later input to the mrdebug program. It allows changes to
the network to be saved.
****************************************************************************/
void print_network( FILE *net_out, Network *net )
{
long v;
Interface *cur_ifc;
char *last_name;
for( v = 0; v < net->no_nodes; v++ )
{
last_name = NULL;
if( !(net->adj_list[v].type & SUBNET))
{
for( cur_ifc = net->adj_list[v].interfaces.first; cur_ifc != NULL;
cur_ifc = cur_ifc->next )
{
if( last_name != NULL && strcmp( last_name, cur_ifc->name ))
{/*
** There are at least two different interface names
** at this site so print out an equivalence line.
*/
fprintf( net_out, "= %s %s\n", last_name, cur_ifc->name );
}
last_name = cur_ifc->name;
if( cur_ifc->type & SUBNET )
fprintf( net_out, "> %s 0.0.0.0 [%ld/%ld", cur_ifc->name,
cur_ifc->metric, cur_ifc->threshold );
else
fprintf( net_out, "> %s %s [%ld/%ld", cur_ifc->name, cur_ifc->to_name,
cur_ifc->metric, cur_ifc->threshold );
if( cur_ifc->type & QUERIER )
fprintf( net_out, "/querier" );
if( cur_ifc->type & TUNNEL )
fprintf( net_out, "/tunnel" );
if( cur_ifc->type & SRCRT )
fprintf( net_out, "/srcrt" );
if( cur_ifc->type & (DOWN | DISABLED))
fprintf( net_out, "/down" );
fprintf( net_out, "]\n" );
}
}
}
fclose( net_out );
}