/*****************************************************************************
* wanpipemon.c	Cisco HDLC Monitor
*
* Author:       Nenad Corbic <ncorbic@sangoma.com>	
*
* Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
*
*		This program is free software; you can redistribute it and/or
*		modify it under the terms of the GNU General Public License
*		as published by the Free Software Foundation; either version
*		2 of the License, or (at your option) any later version.
* ----------------------------------------------------------------------------
*
* Dec 05, 2001  Alex Feldman    Added T1/E1 Statistics.
* Nov 07, 2000  Nenad Corbic    Added Keyboard Led Debugging Commands.
* Mar 14, 2000  Nenad Corbic	Added API support. No IP addresses needed.
* Sep 21, 1999  Nenad Corbic    Changed the input parameters, hearders
*                               data types. More user friendly.
* Aug 06, 1998	David Fong	Initial version based on ppipemon
*****************************************************************************/

/******************************************************************************
 * 			INCLUDE FILES					      *
 *****************************************************************************/
#include <stdio.h>
#include <stddef.h>	/* offsetof(), etc. */
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#if defined(__LINUX__)
# include <linux/version.h>
# include <linux/types.h>
# include <linux/if_packet.h>
# include <linux/if_wanpipe.h>
# include <linux/if_ether.h>
# include <linux/wanpipe_defines.h>
# include <linux/wanpipe_cfg.h>
# include <linux/wanpipe.h>
# include <linux/sdla_chdlc.h>
#else
# include <wanpipe_defines.h>
# include <wanpipe_cfg.h>
# include <wanpipe.h>
# include <sdla_chdlc.h>
#endif
#include "fe_lib.h"
#include "wanpipemon.h"


/******************************************************************************
 * 			DEFINES/MACROS					      *
 *****************************************************************************/
#if LINUX_VERSION_CODE >= 0x020100
#define LINUX_2_1
#endif

#define TIMEOUT 1
#define MDATALEN MAX_LGTH_UDP_MGNT_PKT
#define MAX_TRACE_BUF ((MDATALEN+200)*2)


#define BANNER(str)  banner(str,0)
/******************************************************************************
 * 			TYPEDEF/STRUCTURE				      *
 *****************************************************************************/

/******************************************************************************
 * 			GLOBAL VARIABLES				      *
 *****************************************************************************/
/* The ft1_lib needs these global variables */
static int gfail;
extern char*	progname;

/******************************************************************************
 * 			FUNCTION PROTOTYPES				      *
 *****************************************************************************/
static void error( void );

/* Command routines */
static void modem( void );
static void global_stats( void );
static void comm_stats( void );
static void read_code_version( void );
static void chdlc_configuration( void );
static void link_status( void );
static void operational_stats( void );
static void slarp_stats( void );
static void line_trace( int trace_mode, int trace_sub_type);
static void chdlc_router_up_time( void );
static void flush_operational_stats( void );
static void flush_global_stats( void );
static void flush_comm_stats( void );
static void set_FT1_monitor_status( unsigned char);
static void read_ft1_op_stats( void );
static void read_ft1_te1_56k_config( void );
static void ft1_usage (void);
static void chdlc_reset_adapter (void);


static char *gui_main_menu[]={
"chdlc_card_stats_menu","Card Status",
"chdlc_card_config_menu","Card Configuration",
"chdlc_stats_menu", "Card Statistics",
"chdlc_trace_menu", "Trace Data",
"csudsu_menu", "CSU DSU Config/Stats",
"chdlc_flush_menu","Flush Statistics",
"."
};


static char *chdlc_card_stats_menu[]={
"xm","Modem Status",
"xl","Link Status",
"xcv","Read Code Version",
"xru","Display Router UP time",
"."
};
	
static char *chdlc_card_config_menu[]={
"crc","Read Configuration\n",
"creset","Reset Adapter\n",
"."
};

static char *chdlc_stats_menu[]={
"sg","Global Statistics",
"sc","Communication Error Statistics",
"so","Operational Statistics",
"ss","SLARP and CDP Statistics",
"."
};

static char *chdlc_trace_menu[]={
"ti","Trace and Interpret ALL frames",
"tip","Trace and Interpret PROTOCOL frames only",
"tid","Trace and Interpret DATA frames only",
"tr","Trace ALL frames, in RAW format",
"trp","Trace PROTOCOL frames only, in RAW format",
"trd","Trace DATA frames only, in RAW format",
"."
};

#if 0
static char *chdlc_csudsu_menu[]={
"Tv","View Status",
"Ts","Self Test",
"Tl","Line Loop Test",
"Td","Digital Loop Test",
"Tr","Remote Test",
"To","Operational Mode",
"Tp","Operational stats (FT1)",
"Tf", "Flush operational stats (FT1)",
"Tset", "Set FT1 configuration",
"Tread","Read CSU/DSU config (FT1/T1/E1)",  
"Tallb","E Line Loopback (T1/E1)",  
"Tdllb","D Line Loopback (T1/E1)",  
"Taplb","E Payload Loopback (T1/E1)",  
"Tdplb","D Payload Loopback (T1/E1)",  
"Tadlb","E Diag Digital Loopback (T1/E1)",  
"Tddlb","D Diag Digital Loopback (T1/E1)",  
"Tsalb","Send Loopback Activate Code (T1/E1)",  
"Tsdlb","Send Loopback Deactive Code (T1/E1)",  
"Ta","Read T1/E1/56K alrams",
"."
};
#endif

static char *chdlc_flush_menu[]={
"fg","Flush Global Statistics",
"fc","Flush Communication Error Statistics",
"fo","Flush Operational Statistics",
"fs","Flush SLARP and CDP Statistics",
"fp","Flush T1/E1 performance monitoring counters",
"."
};


static struct cmd_menu_lookup_t gui_cmd_menu_lookup[]={
	{"chdlc_card_stats_menu",chdlc_card_stats_menu},
	{"chdlc_card_config_menu",chdlc_card_config_menu},
	{"chdlc_stats_menu",chdlc_stats_menu},
	{"chdlc_trace_menu",chdlc_trace_menu},
	{"csudsu_menu",csudsu_menu},
	{"chdlc_flush_menu",chdlc_flush_menu},
	{".",NULL}
};


char ** CHDLCget_main_menu(int *len)
{
	int i=0;
	while(strcmp(gui_main_menu[i],".") != 0){
		i++;
	}
	*len=i/2;
	return gui_main_menu;
}

char ** CHDLCget_cmd_menu(char *cmd_name,int *len)
{
	int i=0,j=0;
	char **cmd_menu=NULL;
	
	while(gui_cmd_menu_lookup[i].cmd_menu_ptr != NULL){
		if (strcmp(cmd_name,gui_cmd_menu_lookup[i].cmd_menu_name) == 0){
			cmd_menu=gui_cmd_menu_lookup[i].cmd_menu_ptr;
			while (strcmp(cmd_menu[j],".") != 0){
				j++;
			}
			break;
		}
		i++;
	}
	*len=j/2;
	return cmd_menu;
}



/******************************************************************************
 * 			FUNCTION DEFINITION				      *
 *****************************************************************************/
int CHDLCConfig(void)
{
	char codeversion[10];
	unsigned char x=0;
   
	protocol_cb_size = sizeof(wan_mgmt_t) + 
			   sizeof(wan_cmd_t) + 
			   sizeof(wan_trace_info_t) + 1;
	wan_udp.wan_udphdr_command= READ_CHDLC_CONFIGURATION;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	while (++x < 4) {
		DO_COMMAND(wan_udp); 
		if (wan_udp.wan_udphdr_return_code == 0x00){
			break;
		}
		if (wan_udp.wan_udphdr_return_code == 0xaa){
			printf("Error: Command timeout occurred\n"); 
			return(WAN_FALSE);
		}

		if (wan_udp.wan_udphdr_return_code == 0xCC){ 
			return(WAN_FALSE);
		}
		wan_udp.wan_udphdr_return_code = 0xaa;
	}

	if (x >= 4) return(WAN_FALSE);

	if (wan_udp.wan_udphdr_data_len == sizeof(CHDLC_CONFIGURATION_STRUCT)) {
		is_508 = WAN_TRUE;
	} else {
		is_508 = WAN_FALSE;
	} 
   
	strlcpy(codeversion, "?.??", 10);
   
	wan_udp.wan_udphdr_command = READ_CHDLC_CODE_VERSION;
	wan_udp.wan_udphdr_data_len = 0;
	wan_udp.wan_udphdr_return_code = 0xaa;
	DO_COMMAND(wan_udp);
	if (wan_udp.wan_udphdr_return_code == 0) {
		wan_udp.wan_udphdr_data[wan_udp.wan_udphdr_data_len] = 0;
		strlcpy(codeversion, (char*)wan_udp.wan_udphdr_data,10);
	}
	
	return(WAN_TRUE);
}; 

void CHDLC_set_FT1_mode( void )
{
	for(;;){ 
		wan_udp.wan_udphdr_command= SET_FT1_MODE;
		wan_udp.wan_udphdr_data_len = 0;
		wan_udp.wan_udphdr_return_code = 0xaa;
		DO_COMMAND(wan_udp);
		if (wan_udp.wan_udphdr_return_code == 0){
			break;
		}
	}
} /* set_FT1_mode */

void CHDLC_read_FT1_status( void )
{

	wan_udp.wan_udphdr_command= CPIPE_FT1_READ_STATUS;
	wan_udp.wan_udphdr_data_len = 0;
	wan_udp.wan_udphdr_return_code = 0xaa;
	DO_COMMAND(wan_udp); 
	if(wan_udp.wan_udphdr_return_code == 0) {
		par_port_A_byte = wan_udp.wan_udphdr_data[0];
		par_port_B_byte = wan_udp.wan_udphdr_data[1];

		if(!(par_port_A_byte & PP_A_RT_NOT_RED)) {
			FT1_LED.RT_red ++;
		}
		if(!(par_port_A_byte & PP_A_RT_NOT_GREEN)) {
			FT1_LED.RT_green ++;
 		}
		if((par_port_A_byte & (PP_A_RT_NOT_GREEN | PP_A_RT_NOT_RED))
			== (PP_A_RT_NOT_GREEN | PP_A_RT_NOT_RED)) {
			FT1_LED.RT_off ++;
		}
 		if(!(par_port_A_byte & PP_A_LL_NOT_RED)) {
			FT1_LED.LL_red ++;
		}
		else {
			FT1_LED.LL_off ++;
		}
		if(!(par_port_A_byte & PP_A_DL_NOT_RED)) {
			FT1_LED.DL_red ++;
		}
		else {
			FT1_LED.DL_off ++;
		}
		if(!(par_port_B_byte & PP_B_RxD_NOT_GREEN)) {
			FT1_LED.RxD_green ++;
		}
		if(!(par_port_B_byte & PP_B_TxD_NOT_GREEN)) {
			FT1_LED.TxD_green ++;
		}
		if(!(par_port_B_byte & PP_B_ERR_NOT_GREEN)) {
			FT1_LED.ERR_green ++;
		}
		if(!(par_port_B_byte & PP_B_ERR_NOT_RED)) {
			FT1_LED.ERR_red ++;
		}
		if((par_port_B_byte & (PP_B_ERR_NOT_GREEN | PP_B_ERR_NOT_RED))
			== (PP_B_ERR_NOT_GREEN | PP_B_ERR_NOT_RED)) {
			FT1_LED.ERR_off ++;
		}
		if(!(par_port_B_byte & PP_B_INS_NOT_RED)) {
			FT1_LED.INS_red ++;
		}
		if(!(par_port_B_byte & PP_B_INS_NOT_GREEN)) {
			FT1_LED.INS_green ++;
		}
		if((par_port_B_byte & (PP_B_INS_NOT_GREEN | PP_B_INS_NOT_RED))
			== (PP_B_INS_NOT_GREEN | PP_B_INS_NOT_RED)) {
			FT1_LED.INS_off ++;
		}
		if(!(par_port_B_byte & PP_B_ST_NOT_GREEN)) {
			FT1_LED.ST_green ++;
		}
		if(!(par_port_B_byte & PP_B_ST_NOT_RED)) {
			FT1_LED.ST_red ++;
		}
		if((par_port_B_byte & (PP_B_ST_NOT_GREEN | PP_B_ST_NOT_RED))
			== (PP_B_ST_NOT_GREEN | PP_B_ST_NOT_RED)) {
			FT1_LED.ST_off ++;
		}
	}
} /* read_FT1_status */
 


static void error( void ) 
{
	printf("Error: Command failed!\n");

}; /* error */


static void global_stats (void)
{
	GLOBAL_STATS_STRUCT* global_stats;
	wan_udp.wan_udphdr_command= READ_GLOBAL_STATISTICS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0 ) {
		BANNER("GLOBAL STATISTICS");
		global_stats = (GLOBAL_STATS_STRUCT *)&wan_udp.wan_udphdr_data[0];
		printf("Times application did not respond to IRQ: %u",
			global_stats->app_IRQ_timeout_count);
	} else {
		error();
	}
};  /* global stats */

static void flush_global_stats (void)
{
	wan_udp.wan_udphdr_command= FLUSH_GLOBAL_STATISTICS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code != 0 ) error();
};  /* flush global stats */

static void modem( void )
{
	unsigned char cts_dcd;
	wan_udp.wan_udphdr_command= READ_MODEM_STATUS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0 ) {
		BANNER("MODEM STATUS");
		memcpy(&cts_dcd, &wan_udp.wan_udphdr_data[0],1);
		printf("DCD: ");
		(cts_dcd & 0x08) ? printf("High\n") : printf("Low\n");
		printf("CTS: ");
		(cts_dcd & 0x20) ? printf("High\n") : printf("Low\n");
	} else {
		error();
	}
}; /* modem */


static void comm_stats (void)
{
	COMMS_ERROR_STATS_STRUCT* comm_stats;
	wan_udp.wan_udphdr_command= READ_COMMS_ERROR_STATS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0 ) {
	 	BANNER("COMMUNICATION ERROR STATISTICS");

		comm_stats = (COMMS_ERROR_STATS_STRUCT *)&wan_udp.wan_udphdr_data[0];

		printf("                        Number of receiver overrun errors:  %u\n", comm_stats->Rx_overrun_err_count);
		printf("                            Number of receiver CRC errors:  %u\n", comm_stats->CRC_err_count);
		printf("                          Number of abort frames received:  %u\n", comm_stats->Rx_abort_count);
		printf("                        Number of times receiver disabled:  %u\n", comm_stats->Rx_dis_pri_bfrs_full_count);
		printf(" Number of transmitted abort frames (missed Tx interrupt):  %u\n", comm_stats->sec_Tx_abort_msd_Tx_int_count);
		printf("                             Number of transmit underruns:  %u\n", comm_stats->missed_Tx_und_int_count);
		printf("                       Number of abort frames transmitted:  %u\n", comm_stats->sec_Tx_abort_count);
		printf("                        Number of times DCD changed state:  %u\n", comm_stats->DCD_state_change_count);
		printf("                        Number of times CTS changed state:  %u\n", comm_stats->CTS_state_change_count);
	} else {
		error();
	}
}; /* comm_stats */


static void flush_comm_stats( void ) 
{
	wan_udp.wan_udphdr_command= FLUSH_COMMS_ERROR_STATS;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code != 0) error();
}; /* flush_comm_stats */


static void read_code_version (void)
{
	wan_udp.wan_udphdr_command= READ_CHDLC_CODE_VERSION; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0) {
		unsigned char version[10];
		BANNER("CODE VERSION");
		memcpy(version,&wan_udp.wan_udphdr_data,wan_udp.wan_udphdr_data_len);
		version[wan_udp.wan_udphdr_data_len] = '\0';
		printf("Cisco HDLC Code version: %s\n", version);
	}
}; /* read code version */

static void chdlc_configuration (void)
{
	CHDLC_CONFIGURATION_STRUCT *chdlc_cfg;
	wan_udp.wan_udphdr_command = READ_CHDLC_CONFIGURATION; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0) {
		chdlc_cfg = (CHDLC_CONFIGURATION_STRUCT *)&wan_udp.wan_udphdr_data[0];
		BANNER("CHDLC CONFIGURATION");

		printf("Baud rate: %u", chdlc_cfg->baud_rate);

		printf("\nLine configuration: ");
		     switch (chdlc_cfg->line_config_options) {
			case INTERFACE_LEVEL_V35:
				printf("V.35");
				break;
			case INTERFACE_LEVEL_RS232:
				printf("RS-232");
				break;
		     }

		printf("\n\nLink State depends on:");
		     if (chdlc_cfg->CHDLC_protocol_options & IGNORE_DCD_FOR_LINK_STAT)
			     printf ("\n\t\t\tDCD:  NO");
		     else
			     printf ("\n\t\t\tDCD:  YES");
		     
		     if (chdlc_cfg->CHDLC_protocol_options & IGNORE_CTS_FOR_LINK_STAT)
			     printf ("\n\t\t\tCTS:  NO\n");
		     else	
			     printf ("\n\t\t\tCTS:  YES\n");
		     
		     if (chdlc_cfg->CHDLC_protocol_options & IGNORE_KPALV_FOR_LINK_STAT)
			     printf ("\tKeepalive Reception:  NO\n");
		     else
			     printf ("\tKeepalive Reception:  YES\n");

		printf("\n\n                 Maximum data field length:  %u",
			chdlc_cfg->max_CHDLC_data_field_length);

		printf(  "\n          Keepalive transmit interval (ms):  %u",
			chdlc_cfg->transmit_keepalive_timer);

		printf(  "\nExpected keepalive reception interval (ms):  %u",
			chdlc_cfg->receive_keepalive_timer);
		
		printf(  "\n       Keepalive reception error tolerance:  %u",
			chdlc_cfg->keepalive_error_tolerance);

		printf(  "\n      SLARP request transmit interval (ms):  %u",
			chdlc_cfg->SLARP_request_timer);
		
	} else {
		error();
	}
}; /* chdlc_configuration */

static void chdlc_reset_adapter (void)
{

	wan_udp.wan_udphdr_command= DISABLE_CHDLC_COMMUNICATIONS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code != 0){
		printf("Failed to Disable Comm rc=0x%X\n",
				wan_udp.wan_udphdr_return_code);
		return;
	}

	wan_udp.wan_udphdr_command= RESET_ESCC; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code != 0){

		printf("Failed to Reset Comm rc=0x%X\n",
				wan_udp.wan_udphdr_return_code);

		wan_udp.wan_udphdr_command= ENABLE_CHDLC_COMMUNICATIONS; 
		wan_udp.wan_udphdr_return_code = 0xaa;
		wan_udp.wan_udphdr_data_len = 0;
		DO_COMMAND(wan_udp);

		return;
	}

	
	wan_udp.wan_udphdr_command= ENABLE_CHDLC_COMMUNICATIONS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code != 0){
		printf("Failed to Enable Comm rc=0x%X\n",
				wan_udp.wan_udphdr_return_code);
		return;
	}

	printf("Comm reset successful\n");

	return;
}

static void link_status (void)
{
	CHDLC_LINK_STATUS_STRUCT *status;
	wan_udp.wan_udphdr_command= READ_CHDLC_LINK_STATUS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0) {
		
		BANNER("LINK STATUS");	
	
		status = (CHDLC_LINK_STATUS_STRUCT *)&wan_udp.wan_udphdr_data[0];

		printf("                          Link status:  ");
		     switch (status->CHDLC_link_status) {
			case CHDLC_LINK_INACTIVE:
				printf("Inactive\n");
				break;
			case CHDLC_LINK_ACTIVE:
				printf("Active\n");
				break;
		     }

		printf("Available data frames for application:  %u\n",
			status->no_Data_frms_for_app);

		printf("                      Receiver status:  ");
		     if (status->receiver_status & 0x01)
			printf("Disabled due to flow control restrictions\n");
		     else printf("Enabled\n");
	} else {
		error();
	}
}; /* Link Status */		


static void operational_stats (void)
{
	CHDLC_OPERATIONAL_STATS_STRUCT *stats;
	wan_udp.wan_udphdr_command= READ_CHDLC_OPERATIONAL_STATS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0) {
		BANNER("OPERATIONAL STATISTICS");
		stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)&wan_udp.wan_udphdr_data[0];
 
		printf(    "             Number of frames transmitted:   %u",stats->Data_frames_Tx_count);
		printf(  "\n              Number of bytes transmitted:   %u",stats->Data_bytes_Tx_count);
		printf(  "\n                      Transmit Throughput:   %u",stats->Data_Tx_throughput);
		printf(  "\n Transmit frames discarded (length error):   %u",stats->Tx_Data_discard_lgth_err_count);

		printf("\n\n                Number of frames received:   %u",stats->Data_frames_Rx_count);
		printf(  "\n                 Number of bytes received:   %u",stats->Data_bytes_Rx_count);
		printf(  "\n                       Receive Throughput:   %u",stats->Data_Rx_throughput);
		printf(  "\n    Received frames discarded (too short):   %u",stats->Rx_Data_discard_short_count);
		printf(  "\n     Received frames discarded (too long):   %u",stats->Rx_Data_discard_long_count);
		printf(  "\nReceived frames discarded (link inactive):   %u",stats->Rx_Data_discard_inactive_count);


		printf("\n\nIncoming frames with format errors");
		printf(  "\n               Frames of excessive length:   %u", stats->Rx_frms_too_long_count);	
		printf(  "\n                  Incomplete Cisco Header:   %u", stats->Rx_frm_incomp_CHDLC_hdr_count);
		printf(  "\n          Invalid Cisco HDLC link address:   %u", stats->Rx_invalid_CHDLC_addr_count);
		printf(  "\n               Invalid Cisco HDLC control:   %u", stats->Rx_invalid_CHDLC_ctrl_count);
		printf(  "\n            Invalid Cisco HDLC frame type:   %u", stats->Rx_invalid_CHDLC_type_count);

		printf("\n\nCisco HDLC link active/inactive and loopback statistics");
		printf(  "\n                           Times that the link went active:   %u", stats->link_active_count);	
		printf(  "\n         Times that the link went inactive (modem failure):   %u", stats->link_inactive_modem_count);
		printf(  "\n     Times that the link went inactive (keepalive failure):   %u", stats->link_inactive_keepalive_count);
		printf(  "\n                                         link looped count:   %u", stats->link_looped_count);
	} else {
		error();
	}
} /* Operational_stats */


static void flush_operational_stats( void ) 
{
	wan_udp.wan_udphdr_command= FLUSH_CHDLC_OPERATIONAL_STATS;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code != 0 ) {
		error();
	}

}; /* flush_operational_stats */

static void slarp_stats (void)
{
	CHDLC_OPERATIONAL_STATS_STRUCT *stats;
	wan_udp.wan_udphdr_command= READ_CHDLC_OPERATIONAL_STATS; 
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0) {
		BANNER("SLARP STATISTICS");
		stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)&wan_udp.wan_udphdr_data[0];

		printf("\n SLARP frame transmission/reception statistics");
		printf(  "\n       SLARP request packets transmitted:   %u",
 stats->CHDLC_SLARP_REQ_Tx_count);
		printf(  "\n          SLARP request packets received:   %u",
 stats->CHDLC_SLARP_REQ_Rx_count);
		printf("\n\n         SLARP Reply packets transmitted:   %u",
 stats->CHDLC_SLARP_REPLY_Tx_count);
		printf(  "\n            SLARP Reply packets received:   %u",
 stats->CHDLC_SLARP_REPLY_Rx_count);
		printf("\n\n     SLARP keepalive packets transmitted:   %u",
 stats->CHDLC_SLARP_KPALV_Tx_count);
		printf(  "\n        SLARP keepalive packets received:   %u",
 stats->CHDLC_SLARP_KPALV_Rx_count);

		printf(  "\n\nIncoming SLARP Packets with format errors");
		printf(  "\n                      Invalid SLARP Code:   %u", stats->Rx_SLARP_invalid_code_count);
		printf(  "\n                Replies with bad IP addr:   %u", stats->Rx_SLARP_Reply_bad_IP_addr);
		printf(  "\n                Replies with bad netmask:   %u",stats->Rx_SLARP_Reply_bad_netmask);
		printf(  "\n\nSLARP timeout/retry statistics");
		printf(  "\n                  SLARP Request timeouts:   %u",stats->SLARP_Request_TO_count);
		printf(  "\n            keepalive reception timeouts:   %u",stats->SLARP_Rx_keepalive_TO_count);

		printf("\n\nCisco Discovery Protocol frames");
		printf(  "\n                             Transmitted:   %u", stats->CHDLC_CDP_Tx_count);
		printf(  "\n                                Received:   %u", stats->CHDLC_CDP_Rx_count);

	} else {
		error();
	}

} /* slarp_stats */


int CHDLCDisableTrace(void)
{
	wan_udp.wan_udphdr_command= CPIPE_DISABLE_TRACING;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);
	return 0;
}

static void line_trace(int trace_mode, int trace_subtype)
{
	unsigned int num_frames;
	unsigned short curr_pos = 0;
	wan_trace_pkt_t *trace_pkt;
	unsigned int i;
	int recv_buff = sizeof(wan_udp_hdr_t)+ 100;
	fd_set ready;
	struct timeval to;
 	wp_trace_output_iface_t trace_iface;
   
	memset(&trace_iface,0,sizeof(wp_trace_output_iface_t));

	setsockopt( sock, SOL_SOCKET, SO_RCVBUF, &recv_buff, sizeof(int) );

	/* Disable trace to ensure that the buffers are flushed */
	wan_udp.wan_udphdr_command= CPIPE_DISABLE_TRACING;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);

	wan_udp.wan_udphdr_command= CPIPE_ENABLE_TRACING;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	wan_udp.wan_udphdr_data[0]=0;
	if(trace_mode == TRACE_PROT){
		wan_udp.wan_udphdr_data_len = 1;
		wan_udp.wan_udphdr_data[0] |= TRACE_SLARP_FRAMES | TRACE_CDP_FRAMES; 
		printf("Tracing Protocol only %X\n",wan_udp.wan_udphdr_data[0]);
	}else if(trace_mode == TRACE_DATA){
		wan_udp.wan_udphdr_data_len = 1;
		wan_udp.wan_udphdr_data[0] = TRACE_DATA_FRAMES; 
	}else{
		wan_udp.wan_udphdr_data_len = 1;
		wan_udp.wan_udphdr_data[0] |= TRACE_SLARP_FRAMES | 
			      TRACE_DATA_FRAMES | 
			       TRACE_CDP_FRAMES;
	}

	DO_COMMAND(wan_udp);

	if (wan_udp.wan_udphdr_return_code == 0) { 
		printf("Starting trace...(Press ENTER to exit)\n");
		fflush(stdout);
	} else if(wan_udp.wan_udphdr_return_code == 0xCD ) {
		printf("Cannot Enable Line Tracing from Underneath.\n");
		fflush(stdout);
		return;
	}else if (wan_udp.wan_udphdr_return_code == 0x01 ) {
		printf("Starting trace...(although it's already enabled!)\n");
		printf("Press ENTER to exit.\n");
		fflush(stdout);
	}else{
		printf("Failed to Enable Line Tracing. Return code: 0x%02X\n", 
			wan_udp.wan_udphdr_return_code );
		fflush(stdout);
		return;
	}

	to.tv_sec = 0;
	to.tv_usec = 0;
	for(;;) {
		FD_ZERO(&ready);
		FD_SET(0,&ready);
		fflush(stdout);
	
		if(select(1,&ready, NULL, NULL, &to)) {
			break;
		} /* if */

		wan_udp.wan_udphdr_command = CPIPE_GET_TRACE_INFO;
		wan_udp.wan_udphdr_return_code = 0xaa;
		wan_udp.wan_udphdr_data_len = 0;
		DO_COMMAND(wan_udp);

		if (wan_udp.wan_udphdr_return_code == 0 && wan_udp.wan_udphdr_data_len) { 
		     num_frames = wan_udp.wan_udphdr_chdlc_num_frames;

		 	for ( i = 0; i < num_frames; i++) {
				trace_pkt= (wan_trace_pkt_t *)(&wan_udp.wan_udphdr_data[0] + curr_pos);

#if 0
				if (annexg_trace){
		
					if (trace_pkt->real_length > wan_udp.wan_udphdr_data_len){
						break;		
					}
					curr_pos += sizeof(wan_trace_pkt_t);
				
					if (trace_pkt->data_avail) {
						curr_pos += trace_pkt->real_length -1;
				
						decode_pkt(trace_pkt->data,
						  	   trace_pkt->real_length,
					 		   trace_pkt->status,
							   trace_pkt->time_stamp,
						   	0);
					}
					goto trace_skip;
				}
#endif

				/*  frame type */
				trace_iface.status=0;
				if (trace_pkt->status & 0x01) {
					trace_iface.status|=WP_TRACE_OUTGOING;
				} else {
					if (trace_pkt->status & 0x10) { 
						trace_iface.status|=WP_TRACE_ABORT;
					} else if (trace_pkt->status & 0x20) {
						trace_iface.status|=WP_TRACE_CRC;
					} else if (trace_pkt->status & 0x40) {
						trace_iface.status|=WP_TRACE_OVERRUN;
					}
				}
			
				trace_iface.len = trace_pkt->real_length;
				trace_iface.timestamp = trace_pkt->time_stamp;
				trace_iface.sec = trace_pkt->sec;
				trace_iface.usec = trace_pkt->usec;

				if (trace_pkt->real_length > wan_udp.wan_udphdr_data_len){
					break;		
				}
			
				/* first update curr_pos */
				curr_pos += sizeof(wan_trace_pkt_t);
			
				if (trace_pkt->data_avail == 0) {
					printf("the frame data is not available" );
					printf("\n");
					goto trace_skip;
				}

				/* update curr_pos again */
				curr_pos += trace_pkt->real_length;

				trace_iface.trace_all_data=trace_all_data;
				trace_iface.data=(unsigned char*)&trace_pkt->data[0];
				trace_iface.link_type = 104;
			
				if (pcap_output){
					trace_iface.type=WP_OUT_TRACE_PCAP;
				}else if (raw_data) {
					trace_iface.type=WP_OUT_TRACE_RAW;
				}else{
					trace_iface.type=WP_OUT_TRACE_INTERP;
				}

				trace_iface.sub_type = trace_subtype;

				wp_trace_output(&trace_iface);
trace_skip:
			     	fflush(stdout);
		
			} //for
		} //if

		curr_pos = 0;

		if (!wan_udp.wan_udphdr_chdlc_ismoredata){
			to.tv_sec = 0;
			to.tv_usec = WAN_TRACE_DELAY;
		}else{
			to.tv_sec = 0;
			to.tv_usec = 0;
		}
	}
	
	wan_udp.wan_udphdr_command= CPIPE_DISABLE_TRACING;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 0;
	DO_COMMAND(wan_udp);
}; /* line_trace */

//CORBA
int CHDLCUsage(void)
{
#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
	printf("%s: Wanpipe Cisco-HDLC Debugging Utility\n\n", progname);
#else
	printf("%s: Wanpipe HDLC Debugging Utility\n\n", progname);
#endif
	printf("Usage:\n");
	printf("-----\n\n");
	printf("wanpipemon -i <ip-address or interface name> -u <port> -c <command>\n\n");
	printf("\tOption -i: \n");
	printf("\t\tWanpipe remote IP address must be supplied\n");
#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
	printf("\t\t<or> Wanpipe network interface name (ex: wp1_chdlc)\n");   
#else
	printf("\t\t<or> Wanpipe network interface name (ex: hdlc0)\n");   
#endif
	printf("\tOption -u: (Optional, default: 9000)\n");
#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
	printf("\t\tWanpipe UDPPORT specified in /etc/wanpipe/wanpipe#.conf\n");
#else
	printf("\t\tWanpipe UDPPORT specified in /etc/wanpipe/ifcfg-hdlcN\n");
#endif
	printf("\tOption -full: (Optional, trace option)\n");
	printf("\t\tDisplay raw packets in full: default trace pkt len=25bytes\n");
	printf("\tOption -c: \n");
	printf("\t\tCommand is split into two parts:\n"); 
	printf("\t\t\tFirst letter is a command and the rest are options:\n"); 
	printf("\t\t\tex: xm = View Modem Status\n\n");
	printf("\tSupported Commands: x=status : s=statistics : t=trace \n");
	printf("\t                    c=config : T=FT1 stats  : f=flush\n\n");
	printf("\tCommand:  Options:   Description \n");	
	printf("\t-------------------------------- \n\n");    
	printf("\tCard Status\n");
	printf("\t   x         m       Modem Status\n");
	printf("\t             l       Link Status\n");
	printf("\t             cv      Read Code Version\n");
	printf("\t             ru      Display Router UP time\n");
	printf("\tCard Configuration\n");
	printf("\t   c         rc      Read CHDLC Configuration\n");
	printf("\tCard Statistics\n");
	printf("\t   s         g       Global Statistics\n");
	printf("\t             c       Communication Error Statistics\n");
	printf("\t             o       Operational Statistics\n");
	printf("\t             s       SLARP and CDP Statistics\n");
	printf("\tTrace Data \n");
#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
	printf("\t   t         i       Trace and Interpret ALL frames\n");
	printf("\t             ip      Trace and Interpret PROTOCOL frames only\n");
	printf("\t             id      Trace and Interpret DATA frames only\n");
	printf("\t             r       Trace ALL frames, in RAW format\n");
	printf("\t             rp      Trace PROTOCOL frames only, in RAW format\n");
	printf("\t             rd      Trace DATA frames only, in RAW format\n");
#else
	printf("\t   t         r       Trace ALL frames, in RAW format\n");
#endif
	printf("\tFT1/T1/E1/56K Configuration/Statistics\n");
	printf("\t   T         v       View Status (S508/FT1 or S5143/FT1)\n");
	printf("\t             s       Self Test (S508/FT1 or S5143/FT1)\n");
	printf("\t             l       Line Loop Test (S508/FT1 or S5143/FT1)\n");
	printf("\t             d       Digital Loop Test (S508/FT1 or S5143/FT1)\n");
	printf("\t             r       Remote Test (S508/FT1 or S5143/FT1)\n");
	printf("\t             o       Operational Mode (S508/FT1 or S5143/FT1)\n");
	printf("\t             p       FT1 CSU/DSU operational statistics (S508/FT1 or S5143/FT1)\n");
	printf("\t             f       Flush FT1 CSU/DSU operational statistcs (S508/FT1 or S5143/FT1)\n");
	printf("\t             set <Opt> Set CSU/DSU configuration\n");
	printf("\t             read      Read CSU/DSU configuration (FT1/T1/E1 card)\n");  
	printf("\t             allb    Active Line Loopback mode (T1/E1 card only)\n");  
	printf("\t             dllb    Deactive Line Loopback mode (T1/E1 card only)\n");  
	printf("\t             aplb    Active Payload Loopback mode (T1/E1 card only)\n");  
	printf("\t             dplb    Deactive Payload Loopback mode (T1/E1 card only)\n");  
	printf("\t             adlb    Active Diagnostic Digital Loopback mode (T1/E1 card only)\n");  
	printf("\t             ddlb    Deactive Diagnostic Digital Loopback mode (T1/E1 card only)\n");  
	printf("\t             salb    Send Loopback Activate Code (T1/E1 card only)\n");  
	printf("\t             sdlb    Send Loopback Deactive Code (T1/E1 card only)\n");  
	printf("\t             a       Read T1/E1/56K alarms.\n");  
	printf("\tFlush Statistics\n");
	printf("\t   f         g       Flush Global Statistics\n");
	printf("\t             c       Flush Communication Error Statistics\n");
	printf("\t             o       Flush Operational Statistics\n");
	printf("\t             s       Flush SLARP and CDP Statistics\n");
	printf("\t             p       Flush T1/E1 performance monitoring counters\n");
	printf("\tExamples:\n");
	printf("\t--------\n\n");
#if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC)
	printf("\tex: wanpipemon -i wp1_chdlc0 -u 9000 -c xm :View Modem Status \n");
	printf("\tex: wanpipemon -i wp1_chdlc0 -c Tset       :View Help for CSU/DSU Setup\n");
	printf("\tex: wanpipemon -i 201.1.1.2 -u 9000 -c ti  :Trace and Interpret ALL frames\n\n");
#else
	printf("\tex: %s -i hdlc0 -u 9000 -c xm :View Modem Status \n", progname);
	printf("\tex: %s -i hdlc0 -c Tset       :View Help for CSU/DSU Setup\n", progname);
	printf("\tex: %s -i 201.1.1.2 -u 9000 -c ti  :Trace and Interpret ALL frames\n\n", progname);
#endif
	return 0;
}




static void chdlc_router_up_time( void )
{
     	u_int32_t time;
     
     	wan_udp.wan_udphdr_command= CPIPE_ROUTER_UP_TIME;
	wan_udp.wan_udphdr_return_code = 0xaa;
     	wan_udp.wan_udphdr_data_len = 0;
     	wan_udp.wan_udphdr_data[0] = 0;
     	DO_COMMAND(wan_udp);
    
     	time = *(u_int32_t*)&wan_udp.wan_udphdr_data[0];
	
	BANNER("ROUTER UP TIME");

	
     	if (time < 3600) {
		if (time<60) 
     			printf("    Router UP Time:  %u seconds\n", time);
		else
     			printf("    Router UP Time:  %u minute(s)\n", (time/60));
     	}else
     		printf("    Router UP Time:  %u hour(s)\n", (time/3600));
			
      
}

static void set_FT1_monitor_status( unsigned char status)
{
	gfail = 0;
	
	
	//cb.data[0] = status; 	
	wan_udp.wan_udphdr_command= FT1_MONITOR_STATUS_CTRL;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = 1;
	wan_udp.wan_udphdr_data[0] = status; 	
	DO_COMMAND(wan_udp);
	//if( (cb.wan_udphdr_return_code != 0) && status){
	if ((wan_udp.wan_udphdr_return_code != 0) && status){
		gfail = 1;
		printf("This command is only possible with S508/FT1 board!");
	}
} /* set_FT1_monitor_status */


static void read_ft1_op_stats( void )
{
        fd_set ready;
	struct timeval to;
	unsigned short length;
 
   
	printf("TIME: Time in seconds since the FT1 op stats were last reset\n");
	printf("  ES: Errored Second\n");
	printf(" BSE: Bursty Errored Second\n");
	printf(" SES: Severly Errored Second\n");
	printf(" UAS: Unavailable Second\n");
	printf("LOFC: Loss of Frame Count\n");
	printf(" ESF: ESF Error Count\n");
   
	printf("\nFT1 CSU/DSU Operational Stats...(Press ENTER to exit)\n");
	for(;;){	
		
		
 		
		wan_udp.wan_udphdr_command= READ_FT1_OPERATIONAL_STATS;
		wan_udp.wan_udphdr_return_code = 0xaa;
 		wan_udp.wan_udphdr_data_len = 0;
		DO_COMMAND(wan_udp);

		FD_ZERO(&ready);
		FD_SET(0,&ready);
		to.tv_sec = 0;
		to.tv_usec = 50000;
	
		if(select(1,&ready, NULL, NULL, &to)) {
			break;
		} /* if */
		//if( cb.wan_udphdr_data_len ){
		if (wan_udp.wan_udphdr_data_len ){
			int i=0;
			printf("   TIME    ES   BES   SES   UAS  LOFC    ESF\n");
			//length = cb.wan_udphdr_data_len;
			length = wan_udp.wan_udphdr_data_len;
			while(length){
			
				//printf("%c", cb.data[i]);
				printf("%c", wan_udp.wan_udphdr_data[i]);
				length--;
				i++;
			}
			printf("\n");
		}
	}
}

static unsigned char ft1_usage_buf[]="\n"
"\n"
"---------------------------------------------------------------------------------------\n"
"		\n"
"Usage: wanpipemon -i <int name> -u <udp port> -c Tset <Framing> <Encoding> <LineBuild> \\n"
"                                                    <Channel> <Baudrate> <Clock>\n"
"\n"
"Example: Setup CSU/DSU for T1, ESF, B8ZS:\n"
"	    wanpipemon -i chdlc0 -u 9000 -c Tset 0 0 0 1 1536 0\n"
"---------------------------------------------------------------------------------------\n"
"						    \n"
"FRAMING:        0 = ESF ,       1 = D4\n\\n"
"		Please select one of the above options as specified by\n\\n"
"                your FT1 provider.\n\n"
"\n"
"ENCODING:       0 = B8ZS ,      1 = AMI\n\\n"
"		Please select one of the above options as specified by\n\\n"
"		your FT1 provider.\n\n"
"		\n"
"LINE_BUILD:     0 = CSU: 0db, DSX: 0-133ft\n\\n"
"		1 = DSX: 266-399ft\n\\n"
"		2 = DSX: 399-533ft\n\\n"
"		3 = DSX: 399-533ft\n\\n"
"		4 = DSX: 533-655ft\n\\n"
"		5 = CSU -7dB\n\\n"
"		6 = CSU -15dB\n\\n"
"		7 = CSU -22.5dB\n\\n"
"\n"
"		For WANPIPE FT1 Card setup, select the first option:\n"
"		* CSU 0dB DSX1 0-133ft (option 0)\n"
"\n"
"		For any other setup, select an option as specified by\n"
"		your FT1 provider.\n\n"
"		\n"
"CHANNEL:        Number between 1 to 24.\n"
"		Represents the first active channel.\n"
"		(Default = 1)\n"
"\n"
"		The T1 line consists of 24 channels, each 64 or 56\n"
"		Kbps. If this is a full T1 line, then the first\n"
"		active channel is 1.  Otherwise, set the first\n"
"		active channel as specified by your FT1 provider.\n\n"
"		\n"
"BAUD:           Line baud rate (speed).\n"
"\n"
"		For B8ZS Encoding:\n"
"			Full T1 baud rate is: 1536 Kbps.\n"
"			Each T1 channel runs at: 64 Kbps.\n"
"		For AMI Encoding:\n"
"			Full T1 baud rate is: 1344 Kbps.\n"
"			Each T1 channel runs at: 56 Kbps.\n"
"\n"
"		Enter the speed of your connection in Kbps, as\n"
"		specified by your FT1 provider.\n"
"\n"
"		To calculate your baud rate, find out how many\n"
"		active T1 channels you have.  Then multiply that\n"
"		number to ether 64 (for B8ZS) or 56 (for AMI).\n"
"		Note, that first active channel should be set to\n"
"		1 in most cases.  (Note: CHANNEL option)\n"
"		\n"
"CLOCK:          0 = NORMAL,     1 = MASTER\n"
"\n"
"		Default is always Normal.\n"
"\n"
"		Select clocking options as specified by your FT1\n"
"		provider.\n"
"\n";

static void ft1_usage (void)
{
	printf("%s\n",ft1_usage_buf);
}



static void set_ft1_config(int argc, char ** argv)
{
	ft1_config_t *ft1_config = (ft1_config_t *)&wan_udp.wan_udphdr_data[0];
	int i=0,found=0;
	
	wan_udp.wan_udphdr_command = SET_FT1_CONFIGURATION;
	wan_udp.wan_udphdr_return_code = 0xaa;
	wan_udp.wan_udphdr_data_len = sizeof(ft1_config_t);

	for (i=0;i<argc;i++){
		if (!strcmp(argv[i],"Tset")){
			i++;
			found=1;
			break;
		}
	}
	
	if (!found){
		printf("Error, failed to find 'Tset' command\n");
		ft1_usage();
		return;
	}
	
	if (argc <= i+5){
		printf("Error, arguments missing: argc %i\n",argc);
		ft1_usage();
		return;
	}
	
	ft1_config->framing_mode   = atoi(argv[i++]);
	ft1_config->encoding_mode  = atoi(argv[i++]);
	ft1_config->line_build_out = atoi(argv[i++]);  
	ft1_config->channel_base   = atoi(argv[i++]);
	ft1_config->baud_rate_kbps = atoi(argv[i++]);
	ft1_config->clock_mode     = atoi(argv[i]);


	if (ft1_config->framing_mode > 1){
		printf("Error: Invalid Framing Mode (0=ESF 1=D4)\n");
		return;
	}
	if (ft1_config->encoding_mode > 1){
		printf("Error: Invalid Encoding Mode (0=B8ZS 1=AMI)\n");
		return;
	}
	if (ft1_config->line_build_out > 7){
		printf("Error: Invalid Line Build Mode (0-7) Default:0\n");
		return;
	}
	if (ft1_config->channel_base > 24){
		printf("Error: Invalid Channel Base (1-24) Default:1 \n");
		return;
	}	
	if ((ft1_config->encoding_mode ==0 && ft1_config->baud_rate_kbps > 1536)||
	    (ft1_config->encoding_mode ==1 && ft1_config->baud_rate_kbps > 1344)){
		printf("Error: Invalid Baud Rate: B8ZS Max=1536KBps; AMI Max=1344KBps\n");
		return;
	}

	if ((ft1_config->encoding_mode ==0 && ft1_config->baud_rate_kbps < 64)||
	    (ft1_config->encoding_mode ==1 && ft1_config->baud_rate_kbps < 56)){
		printf("Error: Invalid Baud Rate: B8ZS Min=64KBps; AMI Max=56KBps\n");
		return;
	}

	if ((ft1_config->encoding_mode ==0 && ft1_config->baud_rate_kbps%64 != 0)||
	    (ft1_config->encoding_mode ==1 && ft1_config->baud_rate_kbps%56 != 0)){
		printf("Error: Invalid Baud Rate: \n");
		printf("       For B8ZS: Baud rate must be a multiple of 64KBps.\n"); 
		printf("       For AMI:  Baud rate must be a multiple of 56KBps.\n");
		return;
	}
	
	if (ft1_config->clock_mode  > 1){
		printf("Error: Invalid Clock Mode: (0=Normal, 1=Master) Default:0\n");
		return;
	}
	
	DO_COMMAND(wan_udp);
	//if (cb.wan_udphdr_return_code == 0){
	if (wan_udp.wan_udphdr_return_code == 0){
		printf("CSU/DSU Configuration Successfull!\n");
		
	//}else if (cb.wan_udphdr_return_code == 0xaa){
	}else if (wan_udp.wan_udphdr_return_code == 0xaa){
		printf("Sangoma Adaptor is not equiped with an onboard CSU/DSU!\n");
		printf("\tCSU/DSU Configuration Failed!\n");
	
	}else{
		//printf("CSU/DSU Configuration Failed: rc %x",cb.wan_udphdr_return_code);
		printf("CSU/DSU Configuration Failed: rc %x",wan_udp.wan_udphdr_return_code);
	}
}


static void read_ft1_te1_56k_config (void)
{
	unsigned char	adapter_type = 0x00;

	/* Read Adapter Type */
	if (get_fe_type(&adapter_type)){
		return;
	}

	switch(adapter_type){
	case WAN_MEDIA_NONE:
		
		wan_udp.wan_udphdr_command = READ_FT1_CONFIGURATION;
		wan_udp.wan_udphdr_return_code = 0xaa;
		wan_udp.wan_udphdr_data_len = 0;

		DO_COMMAND(wan_udp);
		if (wan_udp.wan_udphdr_return_code != 0){
			printf("CSU/DSU Read Configuration Failed");
		}else{
			//ft1_config_t *ft1_config = (ft1_config_t *)&cb.data[0];
			ft1_config_t *ft1_config = (ft1_config_t *)&wan_udp.wan_udphdr_data[0];
			printf("CSU/DSU %s Configuration:\n", if_name);
			printf("\tFraming\t\t%s\n",ft1_config->framing_mode ? "D4" : "ESF");
			printf("\tEncoding\t%s\n",ft1_config->encoding_mode ? "AMI" : "B8ZS");
			printf("\tLine Build\t%i\n",ft1_config->line_build_out);
			printf("\tChannel Base\t%i\n",ft1_config->channel_base);
			printf("\tBaud Rate\t%i\n",ft1_config->baud_rate_kbps);
			printf("\tClock Mode\t%s\n",ft1_config->clock_mode ? "MASTER":"NORMAL");
		}
		break;

	case WAN_MEDIA_T1:
	case WAN_MEDIA_E1:
	case WAN_MEDIA_56K:
		read_te1_56k_config();
		break;
	}
	return;
}


int CHDLCMain(char *command,int argc, char* argv[])
{
	char *opt=&command[1];

	switch(command[0]){

		case 'x':
			if (!strcmp(opt,"m")){	
				modem();
			}else if (!strcmp(opt, "cv")){
				read_code_version();
			}else if (!strcmp(opt,"l")){
				link_status();
			}else if (!strcmp(opt,"ru")){
				chdlc_router_up_time();
			}else{
				printf("ERROR: Invalid Status Command 'x'\n");
				printf("ERROR: Type %s <cr> for help\n\n", progname);
			}
			break;	
		case 's':
			if (!strcmp(opt,"g")){
				global_stats();
			}else if (!strcmp(opt,"c")){
				comm_stats();
			}else if (!strcmp(opt,"o")){
				operational_stats();
			}else if (!strcmp(opt,"s")){
				slarp_stats();
			}else{
				printf("ERROR: Invalid Statistics Command 's'\n");
				printf("ERROR: Type %s <cr> for help\n\n", progname);
			}
			break;
		case 'c':
			if (!strcmp(opt,"rc")){
				chdlc_configuration();
			}else if (!strcmp(opt,"reset")){
				chdlc_reset_adapter();
			}else{
				printf("ERROR: Invalid Configuration Command 'c'\n");
				printf("ERROR: Type %s <cr> for help\n\n", progname);
			}
			break;
		case 't':
			if(!strcmp(opt,"i" )){
				raw_data = WAN_FALSE;
				line_trace(TRACE_ALL, WP_OUT_TRACE_RAW);
			}else if (!strcmp(opt, "ip")){
				raw_data = WAN_FALSE;
				line_trace(TRACE_PROT, WP_OUT_TRACE_RAW);
			}else if (!strcmp(opt, "id")){
				raw_data = WAN_FALSE;
				line_trace(TRACE_DATA, WP_OUT_TRACE_RAW);
			}else if (!strcmp(opt, "r")){
				raw_data = WAN_TRUE;
				line_trace(TRACE_ALL, WP_OUT_TRACE_RAW);
			}else if (!strcmp(opt, "rp")){
				raw_data = WAN_TRUE;
				line_trace(TRACE_PROT, WP_OUT_TRACE_RAW);
			}else if (!strcmp(opt, "rd")){
				raw_data = WAN_TRUE;
				line_trace(TRACE_DATA, WP_OUT_TRACE_RAW);
			
			}else if (!strcmp(opt, "ra")){
				raw_data = WAN_TRUE;
				annexg_trace = WAN_TRUE;
				line_trace(TRACE_ALL, WP_OUT_TRACE_RAW);
			}else{
				printf("ERROR: Invalid Trace Command 't'\n");
				printf("ERROR: Type %s <cr> for help\n\n", progname);
			}
			break;
		case 'f':
			if (!strcmp(opt, "o")){
				flush_operational_stats();
				operational_stats();
			}else if (!strcmp(opt, "s")){
				flush_operational_stats();
				slarp_stats();
			}else if (!strcmp(opt, "g")){
				flush_global_stats();
				global_stats();
			}else if (!strcmp(opt, "c")){
				flush_comm_stats();
				comm_stats();
			}else if (!strcmp(opt, "p")){
				flush_te1_pmon();
			} else{
				printf("ERROR: Invalid Flush Command 'f'\n");
				printf("ERROR: Type %s <cr> for help\n\n", progname);
			}
			break;

		case 'T':
			if (!strcmp(opt, "v")){
				set_FT1_monitor_status(0x01);
				if(!gfail){
					view_FT1_status();
				 }
				set_FT1_monitor_status(0x00);
			}else if (!strcmp(opt, "s")){
				set_FT1_monitor_status(0x01);
				if(!gfail){	 	
					FT1_self_test();
				}
				set_FT1_monitor_status(0x00);
			}else if (!strcmp(opt, "l")){
				set_FT1_monitor_status(0x01);
				if(!gfail){
					FT1_local_loop_mode();
				}
				set_FT1_monitor_status(0x00);
			}else if (!strcmp(opt, "d")){
				set_FT1_monitor_status(0x01);
				if(!gfail){
					FT1_digital_loop_mode();
				}
				set_FT1_monitor_status(0x00);
			}else if (!strcmp(opt, "r")){
				set_FT1_monitor_status(0x01);
				if(!gfail){
					FT1_remote_test();
				}
				set_FT1_monitor_status(0x00);
			}else if (!strcmp(opt, "o")){
				set_FT1_monitor_status(0x01);
				if(!gfail){
					FT1_operational_mode();
				}
				set_FT1_monitor_status(0x00);
			}else if (!strcmp(opt, "p")){
				set_FT1_monitor_status(0x02);
				if(!gfail)
					read_ft1_op_stats();
				set_FT1_monitor_status(0x00);
			}else if (!strcmp(opt, "f")){
				set_FT1_monitor_status(0x04);
				if(!gfail){
					printf("Flushed Operational Statistics\n");
				}else{
					printf("FT1 Flush Failed %i\n",gfail);
				}

			}else if (!strcmp(opt, "set")){
				set_ft1_config(argc, argv);
			}else if (!strcmp(opt,"read")){
				read_ft1_te1_56k_config();
			}else if (!strcmp(opt,"allb")){
				set_lb_modes(WAN_TE1_LINELB_MODE, WAN_TE1_LB_ENABLE);
			}else if (!strcmp(opt,"dllb")){
				set_lb_modes(WAN_TE1_LINELB_MODE, WAN_TE1_LB_DISABLE);
			}else if (!strcmp(opt,"aplb")){
				set_lb_modes(WAN_TE1_PAYLB_MODE, WAN_TE1_LB_ENABLE);
			}else if (!strcmp(opt,"dplb")){
				set_lb_modes(WAN_TE1_PAYLB_MODE, WAN_TE1_LB_DISABLE);
			}else if (!strcmp(opt,"adlb")){
				set_lb_modes(WAN_TE1_DDLB_MODE, WAN_TE1_LB_ENABLE);
			}else if (!strcmp(opt,"ddlb")){
				set_lb_modes(WAN_TE1_DDLB_MODE, WAN_TE1_LB_DISABLE);
			}else if (!strcmp(opt,"salb")){
				set_lb_modes(WAN_TE1_TX_LB_MODE, WAN_TE1_LB_ENABLE);
			}else if (!strcmp(opt,"sdlb")){
				set_lb_modes(WAN_TE1_TX_LB_MODE, WAN_TE1_LB_DISABLE);
			}else if (!strcmp(opt,"a")){
				read_te1_56k_stat();
			} else{
				printf("ERROR: Invalid FT1/T1/E1 Command 'T'\n");
				printf("ERROR: Type %s <cr> for help\n\n", progname);
			} 
			break;

		default:
			printf("ERROR: Invalid Command!\n");
			printf("ERROR: Type %s <cr> for help\n\n", progname);
			break;
	}//switch 
   	printf("\n");
   	fflush(stdout);
   	return 0;
}; //main
