/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 *  Description.
 *  =====================================================================
 *  User defined command functions for the CLI.      
 *
 *  Edit    Date/Ver    Edit Description
 *  ================    =================================================
 *
 *
 */
#include <stdlib.h>
#include <tx_api.h>
#include <gpiomux_def.h>
#include <bsp_api.h>
#include <boardParams.h>
#include <narmapi.h>
#include <cliapi.h>
#include <iam_netos.hh>
#include "iam.hh"
#include <sysaccess.h>
#include "clicmd.h"

#define MAX_IPADDRESS_LENGTH    15

static int  checkIpAddress(char *buffer);
int cli_bad_option(int fd, char *bad_option);
int cli_parse_set_network_parms(int fd, int n, char *args[], NaIamParams_t *interface);
void rebootSubmit(int fd, int wait);

static char *cli_set_network_options[] =
    {
        "ip",
        "submask",
        "gateway",
        "dhcp",
		"dhcpv6",
		"staticv6",
		"ipv6",
		"prefix",
        NULL
    };

static char *cli_set_password_options[] =
    {
        "oldpassword",
        "newpassword",
        NULL
    };

static char *cli_reboot_options[] =
    {
        "wait",
        NULL
    };

static char *cli_set_network_on_off[] =
    {
        "on",
        "off",
        NULL
    };

#define NOT_USED                0

static TX_TIMER resetTimer;

static char * ifnames[] = {"eth0", "wln0"};


/*
 *
 *  Function: int cli_show_network_help(int fd, int n, char *args[])
 *
 *  Description:
 *
 *      This function is called to display help for the setnetwork command.
 *
 *  Parameters:
 *
 *      fd       Interface file descriptor. 
 *      n        The number of arguments to parse
 *      args     The arguments to parse
 *
 *  Return Values:
 *
 *      0          Success
 *
 */
int cli_show_network_help(int fd, int n, char *args[]) {
    naCliPrintf(fd, "\r\n\r\nsyntax: setnetwork\r\n\r\n");
    naCliPrintf(fd, "\r\n");
    return 0;
}

int cli_show_network(int fd, int n, char *args[]) {
    devBoardParamsType nvParams;
    NaIamParams_t *interface = NULL;
    char *ipv6_addr;
    char ipv6Address[MAX_IP_ADDR_STR_LEN];
	NaIamIfIpCfg_t config;
    char addr[16];
	NaIamStatus_t status;
    int i, cnt, idx, if_idx;

	if (n)
	{
		naCliPrintf(fd, "\r\nerror: Invalid syntax\r\n");
		return 0;
	}
    /* Read current settings. */
    customizeReadDevBoardParams(&nvParams);

	for (if_idx = 0; if_idx < asizeof(ifnames); if_idx++)
	{
		/* Extract the configuration structure from the NVRAM structure.  There should be a configuration */
		/* network settings that is configured.  If not, then fails. */
		for (idx=0; idx < NA_IAM_INTERFACE_MAX; idx++)
		{
			if (nvParams.iamParamsInfo.iamParams[idx].isConfigValid)
			{
				interface = &nvParams.iamParamsInfo.iamParams[idx];
				if (interface && strcmp(interface->ifname, ifnames[if_idx]) == 0)
					break;
			}
		}

		if (interface == NULL)
		{
			naCliPrintf(fd, "\r\nError: Network %s is not configured!\r\n", ifnames[if_idx]);
			continue;
		}

		status = customizeIamGetIfconfig(interface->ifname, &config); 

	/* we want to show the syntax of setnetwork instead of the settings */    
		if (interface->staticParams.isEnabled) 
		{ /* static address */
			naCliPrintf(fd, "%-30s: %s\r\n", "Interface", interface->ifname);
			naCliPrintf(fd, "%-30s: %s\r\n", "DHCPv4", "Disabled");
			NAInet_toa(interface->staticParams.IPV4_ADDR(ipAddress), addr);
			naCliPrintf(fd, "%-30s: %s\r\n", "IP Address", addr);
			NAInet_toa(interface->staticParams.subnetMask, addr);
			naCliPrintf(fd, "%-30s: %s\r\n", "Subnet Mask", addr);
			NAInet_toa(interface->staticParams.IPV4_ADDR(gateway), addr);
			naCliPrintf(fd, "%-30s: %s\r\n", "Gateway", addr);
		} 
		else 
		{ /* DHCP */
        	naCliPrintf(fd, "%-30s: %s\r\n", "Interface", interface->ifname);
			naCliPrintf(fd, "%-30s: %s\r\n", "DHCPv4", "Enabled");

			if (status == NA_IAM_STATUS_SUCCESS)
			{
				NAInet_toa(config.addrV4[0].IPV4_ADDR(ipAddress), addr);
				naCliPrintf(fd, "%-30s: %s\r\n", "IP v4 Address", addr);
                 
				if (config.addrV4[0].IPV4_ADDR(ipAddress))
				{
					NAInet_toa(config.addrV4[0].subnet.ipv4SubnetMask, addr);
					naCliPrintf(fd, "%-30s: %s\r\n", "Subnet Mask", addr);

					NAInet_toa(config.IPV4_ADDR(defaultV4Gateway), addr);
					naCliPrintf(fd, "%-30s: %s\r\n", "Gateway", addr);
				}
			}
		}

		if (status == NA_IAM_STATUS_SUCCESS)
		{
			if (interface->staticParams.ipv6IsEnabled & NA_IAM_STATICV6_ENABLED)
			{
				ipv6_addr = (char *)&interface->staticParams.ipv6Address.addr.ipv6.sin6_addr;

				/* Convert v6 address to ASCII. */
				inet_ntop(AF_INET6, ipv6_addr, ipv6Address, MAX_IP_ADDR_STR_LEN);
				naCliPrintf(fd, "%-30s: %s, prefixlen %d\r\n", "IPv6 Static Address", ipv6Address, interface->staticParams.ipv6PrefixLen);
			}
			else
				naCliPrintf(fd, "%-30s: %s\r\n", "IPv6 Static Address", "Disabled");

			if (interface->staticParams.ipv6IsEnabled & NA_IAM_DHCPV6_ENABLED)
			{
				if (config.dhcpV6.method == NA_IAM_METHOD_DHCPV6)
				{
					ipv6_addr = (char *)&config.dhcpV6.ipAddress.addr.ipv6.sin6_addr;

					/* Convert v6 address to ASCII. */
					inet_ntop(AF_INET6, ipv6_addr, ipv6Address, MAX_IP_ADDR_STR_LEN);
					naCliPrintf(fd, "%-30s: %s\r\n", "DHCPv6 Address", ipv6Address);
				}
				else
					naCliPrintf(fd, "%-30s: %s\r\n", "DHCPv6", "Enabled");
			}
			else
				naCliPrintf(fd, "%-30s: %s\r\n", "DHCPv6", "Disabled");

			cnt = 0;

			for (i = 0; i < NA_MAX_HOMES_PER_IF; i++)
			{
				if (config.autoCfgV6[i].method != NA_IAM_METHOD_NONE)
				{ 
					ipv6_addr = (char *)&config.autoCfgV6[i].ipAddress.addr.ipv6.sin6_addr;

					/* Convert v6 address to ASCII. */
					inet_ntop(AF_INET6, ipv6_addr, ipv6Address, MAX_IP_ADDR_STR_LEN);
					cnt++;
					if (cnt == 1)
					{
						naCliPrintf(fd, "%-30s: %s\r\n", "IPv6 Autoconfigured Address", ipv6Address);
					}
					else
					{
						naCliPrintf(fd, "%-30s: %s\r\n", " ", ipv6Address, ipv6Address);
					}
				}
			}
		}
		naCliPrintf(fd, "\r\n");
	}

    return 0;
}
/*
 *
 *  Function: int cli_set_network_help(int fd, int n, char *args[])
 *
 *  Description:
 *
 *      This function is called to display help for the setnetwork command.
 *
 *  Parameters:
 *
 *      fd       Interface file descriptor. 
 *      n        The number of arguments to parse
 *      args     The arguments to parse
 *
 *  Return Values:
 *
 *      0          Success
 *
 */
int cli_set_network_help(int fd, int n, char *args[]) {
    naCliPrintf(fd, "\r\n\r\nsyntax: setnetwork <ifname> [options...]\r\n\r\n");
    naCliPrintf(fd, "Use shownetwork to show the current network interface.\r\n\r\n");
    naCliPrintf(fd, "options:\r\n\r\n");
    naCliPrintf(fd, "   ip = (IPv4 address)\r\n");
    naCliPrintf(fd, "   submask = (subnet mask)\r\n");
    naCliPrintf(fd, "   gateway = (gateway ipaddr)\r\n");
    naCliPrintf(fd, "   dhcp = (on|off)\r\n");
	naCliPrintf(fd, "   dhcpv6 = (on|off)\r\n");
	naCliPrintf(fd, "   staticv6 = (on|off)\r\n");
	naCliPrintf(fd, "   ipv6 = (IPv6 address)\r\n");
	naCliPrintf(fd, "   prefix = (IPv6 prefix length)\r\n");
    naCliPrintf(fd, "\r\n");

    return 0;
}

/*
*
*  Function: int cli_set_network(int fd, int n, char *args[])
*
*  Description:
*
*      This function is called when a setnetwork command is typed into the cli.
*
*  Parameters:
*
*      fd       Interface file descriptor. 
*      n        The number of arguments to parse
*      args     The arguments to parse
*
*  Return Values:
*
*      <0         failure
*      0          Success
*
*/
int cli_set_network(int fd, int n, char *args[]) {
    devBoardParamsType nvParams;
    NaIamParams_t *interface = NULL;
    int status = 0;
    int idx, if_idx;

	    /* If no parameters show current values. */
    if (n == 0) {
        /* show the syntax */
        cli_set_network_help(fd, n, args);
        return 0;
    }
	if (n != 2)
	{
		naCliPrintf(fd, "\r\nerror: Invalid syntax\r\n");
		return 0;
	}
	for (if_idx = 0; if_idx < asizeof(ifnames); if_idx++)
	{
		if (strcmp(ifnames[if_idx], args[0]) == 0)
			break;
	}
	if (if_idx >=  asizeof(ifnames))
	{
		naCliPrintf(fd, "\r\nerror: Invalid interface name\r\n");
		return 0;
	}
	for (if_idx = 0; if_idx < asizeof(ifnames); if_idx++)
	{
		if (strcmp(ifnames[if_idx], args[0]) == 0)
			break;
	}

    /* Read current settings. */
    customizeReadDevBoardParams(&nvParams);

    /* Extract the configuration structure from the NVRAM structure.  There should be a configuration */
    /* network settings that is configured.  If not, then fails. */
    for (idx=0; idx < NA_IAM_INTERFACE_MAX; idx++)
    {
        if (nvParams.iamParamsInfo.iamParams[idx].isConfigValid)
        {
            interface = &nvParams.iamParamsInfo.iamParams[idx];
			if (interface && strcmp(interface->ifname,ifnames[if_idx]) == 0)
				break;
        }
    }

    if (interface == NULL)
    {
        naCliPrintf(fd, "\r\n\r\nError - No network interface %s is found!\r\n", ifnames[if_idx]);
        return 0;
    }

    /* Parse the arguments and set the values into interface*/
    status = cli_parse_set_network_parms(fd, n-1, &args[1], interface);

    if (status == 0)
    {
        /* Save settings. */
        status = customizeWriteDevBoardParams(&nvParams);

        if (status != BP_SUCCESS) {
            naCliPrintf(fd, "\r\n\r\nCritical error saving network settings!\r\n");
        } else {
            naCliPrintf(fd, "\r\n\r\nSettings have been saved.\r\n");
        }
    }

    return 0;
}

/*
 *
 *  Function: int cli_parse_set_network_parms(int fd, int n, char *args[], NaIamCfg_t *interface)
 *
 *  Description:
 *
 *      This function parses the supplied parameters and sets the values referenced by interface.
 *
 *  Parameters:
 *
 *      fd         Interface file descriptor. 
 *      n          The number of arguments to parse
 *      args       The arguments to parse
 *      interface  An Interface Address Manager configuration structure
 *
 *  Return Values:
 *
 *      <0         failure
 *      0          Success
 *
 */
int cli_parse_set_network_parms(int fd, int n, char *args[], NaIamParams_t *interface) {
    char *equal_separator = "=";
    char *result1[4];
    int i;
    int option_count;

    /* look at each parameter. */
    for (i=0; i < n; i++) {
        /* split up the current option result1[0] holds the option and */
        /* result1[1] holds the value. */
        option_count = naCliSplitStr(args[i], result1, 4, equal_separator);

        if ((option_count != 2) || (result1[1] == NULL)) {
            return cli_bad_option(fd, args[i]);
        }

        /* process the current option */
        switch (naCliWhichOp(result1[0], cli_set_network_options)) {
        case CLI_SET_NETWORK_OPTION_IP:

            /* result1[1] is an IP address */
            if (checkIpAddress(result1[1])) {
                /* set the static IP address portion of the interface. */
                interface->staticParams.IPV4_ADDR(ipAddress) = NAInet_addr(result1[1]);
            } else {
                return cli_bad_option(fd, result1[1]);
            }
            break;

        case CLI_SET_NETWORK_OPTION_SUBMASK:

            /* result1[1] is an IP SubMask */
            if (checkIpAddress(result1[1])) {
                /* set the static IP subnet mask portion of the interface. */
                interface->staticParams.subnetMask = NAInet_addr(result1[1]);
            } else {
                return cli_bad_option(fd, result1[1]);
            }

            break;

        case CLI_SET_NETWORK_OPTION_GATEWAY:

            /* result1[1] is the IP address of the gateway */
            if (checkIpAddress(result1[1])) {
                /* set the static IP address for the gateway portion of the interface. */
                interface->staticParams.IPV4_ADDR(gateway) = NAInet_addr(result1[1]);
            } else {
                return cli_bad_option(fd, result1[1]);
            }

            break;

        case CLI_SET_NETWORK_OPTION_DHCP:

            switch (naCliWhichOp(result1[1], cli_set_network_on_off)) {
            case CLI_SET_NETWORK_OPTION_ON:
                /*
                 * Disable the static configuration to make IAM get an address from the network.
                 * The protocols actually used by IAM are determined by the settings stored
                 * in NVRAM.
                 */
                interface->staticParams.isEnabled = FALSE;
				interface->dhcpParams.isEnabled = TRUE;
				
                break;

            case CLI_SET_NETWORK_OPTION_OFF:
                /*
                 * Enabling the static configuration will cause IAM to ignore the settings used
                 * for DHCP, BOOTP, et al on the same interface.
                 */
                interface->staticParams.isEnabled = TRUE;
                break;

            default:
                return cli_bad_option(fd, result1[1]);
            }

            break;

			case CLI_SET_NETWORK_OPTION_DHCPV6:
				switch (naCliWhichOp(result1[1], cli_set_network_on_off)) {
				case CLI_SET_NETWORK_OPTION_ON:
					interface->staticParams.ipv6IsEnabled |= NA_IAM_DHCPV6_ENABLED;
					break;

				case CLI_SET_NETWORK_OPTION_OFF:
					interface->staticParams.ipv6IsEnabled &= ~NA_IAM_DHCPV6_ENABLED;
					break;

				default:
					return cli_bad_option(fd, result1[1]);
				}
				break;

			case CLI_SET_NETWORK_OPTION_STATICV6:
				switch (naCliWhichOp(result1[1], cli_set_network_on_off)) {
				case CLI_SET_NETWORK_OPTION_ON:
					interface->staticParams.ipv6IsEnabled |= NA_IAM_STATICV6_ENABLED;
					break;

				case CLI_SET_NETWORK_OPTION_OFF:
					interface->staticParams.ipv6IsEnabled &= ~NA_IAM_STATICV6_ENABLED;
					break;

				default:
					return cli_bad_option(fd, result1[1]);
				}
				break;

			case CLI_SET_NETWORK_OPTION_PREFIX:
			{
				int num = atoi(result1[1]);
				if (num >= 0 && num <= 128)
				{
					interface->staticParams.ipv6PrefixLen = (WORD8) num;
				}
				else	
				{
					naCliPrintf(fd, "IPv6 network prefix length must be between 0 and 128\r\n");
					return cli_bad_option(fd, result1[1]);
				}
			}
			break;

			case CLI_SET_NETWORK_OPTION_IPV6:
			{
				struct sockaddr_storage ipv6addr;
				if (inet_pton(AF_INET6, result1[1], &ipv6addr.addr.ipv6.sin6_addr) == 1) 
				{
					ipv6addr.ss_family = AF_INET6;
					ipv6addr.ss_len = sizeof(struct sockaddr_in6);

					if (naValidateIpv6Information(&ipv6addr, interface->staticParams.ipv6PrefixLen) == 0)
					{
						interface->staticParams.ipv6Address = ipv6addr;
					}
					else
					if (naValidateIpv6Information(&ipv6addr, 64) == 0)
					{
						interface->staticParams.ipv6Address = ipv6addr;
						interface->staticParams.ipv6PrefixLen = 64;
						naCliPrintf(fd, "IPv6 network prefix length defauled to 64\r\n");
					}
					else
					{
						naCliPrintf(fd, "Invalid IPv6 address / prefix length combination\r\n");
						return cli_bad_option(fd, result1[1]);
					}
				}
				else
				{
					naCliPrintf(fd, "Invalid IPv6 address\r\n");
					return cli_bad_option(fd, result1[1]);
				}
			}
			break;

        default:
            return cli_bad_option(fd, args[i]);
        }
    }

    return 0;
}

/*
 *
 *  Function: cli_set_password_help(int fd, int n, char *args[])
 *
 *  Description:
 *
 *      This function prints the help text for setpassword.
 *
 *  Parameters:
 *
 *      fd         Interface file descriptor. 
 *      n          The number of arguments to parse
 *      args       The arguments to parse
 *
 *  Return Values:
 *
 *      <0         failure
 *      0          Success
 *
 */
int cli_set_password_help(int fd, int n, char *args[]) {
    naCliPrintf(fd, "\r\n\r\nsyntax: setpassword [options...]\r\n\r\n");
    naCliPrintf(fd, "options:\r\n\r\n");
    naCliPrintf(fd, "   old=(old password)\r\n");
    naCliPrintf(fd, "   new=(new password)\r\n");
    naCliPrintf(fd, "\r\n");

    return 0;
}

/*
 *
 *  Function: cli_set_password(int fd, int n, char *args[])
 *
 *  Description:
 *
 *      This function will change the root password.
 *
 *  Parameters:
 *
 *      fd         Interface file descriptor. 
 *      n          The number of arguments to parse
 *      args       The arguments to parse
 *
 *  Return Values:
 *
 *      <0         failure
 *      0          Success
 *
 */
int cli_set_password(int fd, int n, char *args[]) {
    char *equal_separator = "=";
    char *result1[4];
    int i;
    int rc;
    int option_count;
    char *oldPassword;
    char *newPassword;
    char rootPassword[NASYSACC_STRLEN_PASSWORD];
    devBoardParamsType nvParams;

    if (n == 0) {
        cli_set_password_help(fd, n, args);
        return 0;
    }

    if (n != 2) {
        naCliPrintf(fd, "\r\nerror: Incorrect number of options for setpassword: %d\r\n", n);
        return -1;
    }

    /* look at each parameter. */
    for (i=0; i < n; i++) {
        /* split up the current option result1[0] holds the option and */
        /* result1[1] holds the value. */
        option_count = naCliSplitStr(args[i], result1, 4, equal_separator);

        if ((option_count != 2) || (result1[1] == NULL)) {
            return cli_bad_option(fd, args[i]);
        }

        /* process the current option */
        switch (naCliWhichOp(result1[0], cli_set_password_options)) {
        case CLI_SET_PASSWORD_OPTION_OLD:

            /* result1[1] is the old password */
            oldPassword = result1[1];
            // Get the current root password
            rc = NAgetSysAccess("root", &rootPassword[0], NULL);
            if (rc == 0) {
                naCliPrintf(fd, "\r\nerror: User root does not exist.\r\n");
                return -1;
            }

            if (strcmp(oldPassword, rootPassword) != 0) {
                naCliPrintf(fd, "\r\nerror: Old password is not correct.\r\n");
                return -1;
            }

            break;

        case CLI_SET_PASSWORD_OPTION_NEW:

            /* result1[1] is the new password */
            newPassword = result1[1];

            if (strlen(newPassword) > NASYSACC_STRLEN_PASSWORD) {
                naCliPrintf(fd, "\r\nerror: New password too long. Maximum length = %d.\r\n",
                            NASYSACC_STRLEN_PASSWORD);
                return -1;
            }

            break;

        default:
            return cli_bad_option(fd, args[i]);
        }
    }

    /* At this point the old passwrod was correct and the new password is the right length, so
     * go ahead and set the new password.
     */
    rc = NAChangePassword("root", newPassword);
    if (rc == 0) {
        naCliPrintf(fd, "\r\nPassword changed and updated into NVRAM.\r\n");

        /* Read current settings. */
        customizeReadDevBoardParams(&nvParams);

        /*  update the nvParams record  */
        memset (&nvParams.rootPassword, 0, sizeof(nvParams.rootPassword));
        strcpy ((char *)&nvParams.rootPassword, newPassword);

        /* Write current settings. */
        customizeWriteDevBoardParams(&nvParams);

    } else {
        naCliPrintf(fd, "\r\nPassword not changed.\r\n");
    }

    return 0;
}

/*
 *
 *  Function: cli_reboot_help(int fd, int n, char *args[])
 *
 *  Description:
 *
 *      This function will display the help text for reboot.
 *
 *  Parameters:
 *
 *      fd         Interface file descriptor. 
 *      n          The number of arguments to parse
 *      args       The arguments to parse
 *
 *  Return Values:
 *
 *      <0         failure
 *      0          Success
 *
 */
int cli_reboot_help(int fd, int n, char *args[]) {
    naCliPrintf(fd, "\r\n\r\nsyntax: reboot [options...]\r\n\r\n");
    naCliPrintf(fd, "options:\r\n\r\n");
    naCliPrintf(fd, "   wait=(# seconds)\r\n");
    naCliPrintf(fd, "\r\n");

    return 0;
}

/*
 *
 *  Function: cli_reboot(int fd, int n, char *args[])
 *
 *  Description:
 *
 *      This function handle the reboot command.
 *
 *  Parameters:
 *
 *      fd         Interface file descriptor. 
 *      n          The number of arguments to parse
 *      args       The arguments to parse
 *
 *  Return Values:
 *
 *      <0         failure
 *      0          Success
 *
 */
int cli_reboot(int fd, int n, char *args[]) {
    char *equal_separator = "=";
    char *result1[4];
    int i;
    int option_count;
    int wait = 0;

    if (n > 1) {
        naCliPrintf(fd, "\r\nerror: Incorrect number of options for reboot: %d\r\n", n);
        return -1;
    }

    /* look at each parameter. */
    for (i=0; i < n; i++) {
        /* split up the current option result1[0] holds the option and */
        /* result1[1] holds the value. */
        option_count = naCliSplitStr(args[i], result1, 4, equal_separator);

        if ((option_count != 2) || (result1[1] == NULL)) {
            return cli_bad_option(fd, args[i]);
        }

        /* process the current option */
        switch (naCliWhichOp(result1[0], cli_reboot_options)) {
        case CLI_REBOOT_OPTION_WAIT:

            wait = atoi(result1[1]);
            break;

        default:
            return cli_bad_option(fd, args[i]);
        }
    }

    rebootSubmit(fd, wait);

    return 0;
}

/*
 * This function wraps the function customizeReset so that it can
 * be called from a timer. The function customizeReset performs
 * the actual system reset.
 */
static void reset(ULONG notUsed) {
    NA_UNUSED_PARAM(notUsed);
    customizeReset();   /* reset*/
}

/*
 * This function creates a timer to wait "wait" seconds and then
 * perform a processor reset.
 */
void rebootSubmit(int fd, int wait) {

    naCliPrintf(fd, "Resetting system...");
    if (wait > 0) {
        /* Create a timer that waits (wait * NABspTicksPerSecond) seconds and then calls the
         * function reset
         */
        tx_timer_create (&resetTimer, "Reset Timer", reset, NOT_USED, (wait * NABspTicksPerSecond), NOT_USED, TX_AUTO_ACTIVATE);
    } else {
    	reset(0);
    }
}

/*
 * This function performs some generic error printing.
 */
int cli_bad_option(int fd, char *bad_option) {
    naCliPrintf(fd, "\r\nerror: bad option: %s\r\n", bad_option);
    return -1;
}

/*
 *
 *  Function: static int  checkIpAddress(char *buffer)
 *
 *  Description:
 *
 *      This routine validates an IP address.
 *
 *  Parameters:
 *
 *      buffer    points to the string which contains an IP address in "a.b.c.d" format.
 *
 *  Return Values:
 *
 *      0         invalid
 *      1         valid
 *
 */
static int  checkIpAddress(char *buffer) {
    unsigned int length,i;
    unsigned int j =0;
    unsigned int val;

    length = strlen(buffer);

    if ( (length > MAX_IPADDRESS_LENGTH))
        return 0;
    else {
        for (i=0; i<length; i++) {

            if (buffer[i] =='.') {
                j++;
                if (j > 3)   /* only three '.' allowed */
                    return 0;
            } else if (!(isdigit(buffer[i]))) /* all input char must be numeric */
                return 0;
        }

        for (i = 0; i < 4; i++) {
            if (*buffer != '\0') {
                val = 0;
                while (*buffer != '\0' && *buffer != '.') {
                    val *= 10;
                    val += *buffer - '0';
                    buffer++;
                }
                if (val > 255)
                    return 0;       /* any field should be less than 256 */

                if (*buffer != '\0')
                    buffer++;
            }
        }
    }
    return 1;
}

