/* 
 *            Copyright (c) 1998-2000 by NETsilicon Inc.
 *
 *  This software is copyrighted by and is the sole property of 
 *  NETsilicon.  All rights, title, ownership, or other interests
 *  in the software remain the property of NETsilicon.  This
 *  software may only be used in accordance with the corresponding
 *  license agreement.  Any unauthorized use, duplication, transmission,  
 *  distribution, or disclosure of this software is expressly forbidden.
 *
 *  This Copyright notice may not be removed or modified without prior
 *  written consent of NETsilicon.
 *
 *  NETsilicon, reserves the right to modify this software
 *  without notice.
 *
 *  NETsilicon
 *  411 Waverley Oaks Road                  USA 781.647.1234
 *  Suite 227                               http://www.netsilicon.com
 *  Waltham, MA 02452                       AmericaSales@netsilicon.com
 *
 *************************************************************************
 *
 *     Module Name: starttcp.c
 *         Version: 1.00
 *   Original Date: 09/17/99    
 *          Author: Charles Gordon, Frank McConough, Don Cassidy
 *        Language: Ansi C
 * Compile Options: 
 * Compile defines: 
 *       Libraries: 
 *    Link Options: 
 *
 *    Entry Points: 
 *
 * Description.
 * =======================================================================
 * This file contains the entry point for the TCP/IP stack
 * under NET+OS.  It also contains some basic utility routines and the
 * IP polling routines that drive the stack.
 *                                                                        
 *                                                                        
 * Edit Date/Ver   Edit Description
 * ==============  ===================================================
 *  09-17-99  CHG   Integrated latest code dump of main.c from InterNiche
 *                  that fixes some bugs in SNMP and adds support for 
 *                  DHCP client.
 *  10-01-99  CHG   Changed startup routine to use NVRAM or DHCP to get
 *                  IP parameters.
 *                  Startup routines will also call expressInit() once
 *                  IP has started and an IP address has been set.
 *                  Removed code that set Ethernet MAC address.  That's done
 *                  in BoardInit() now.
 *  04-17-02   SW   Support for GNU TOOLS
 *  07-23-02  PMJ   Support for serial com port select capability.
 *  08-07-02  PMJ   Reorganized to support POSIX functions ttyname() and isatty().
 *  12-17-02  LZ    Moved the following code to bsproot.c, before calling dialog code.
 *                  GNU libc stdio routings call isatty() -- please refer to netos_serl.c
 *                       watchThisFileDescriptor ( "/com/0", 0);
 *                       watchThisFileDescriptor ( "/com/1", 1);
 *  02/12/03 JZW & ESUN		Added ping/arp feature to this module, based
 *                              on customer request (ESUN wrote it, JZW
 *                              ported it to V6 tip)
 *  03/24/03 JZW     Moved the include of Efe_def.h to the top of the list
 *                   because when NETOS_DEBUG is set, it includes dbprintf.h
 *                   which includes stdlib.h. Stdlib.h MUST come before
 *                   std.h to forestall the (in)famous abs redefinition
 *                   compiler warning
 *  03/25/03 JZW     getErrno added to a couple of printf statements to ensure
 *                   that adequate information is available during debugging
 *  05/16/03 JZW     replaced all c++-style comments with c-style comments
 *                   eliminates compiler warnings
 *  06/07/04 GAC     Add code to start wireless network interface
 *
 */
#include "time.h"
#include "npttypes.h"
#include "Efe_def.h"
#include "select.h"
#include "sockapi.h"
#include "std.h"
#include "md5.h"
#include "netdev.h"
#include "reg_def.h"
#include "boardParams.h"
#include "tx_api.h"
#include "bsp.h"
#include "ace.h"
#include "ace_params.h"
#include "aceCallbacks.h"
#include "starttcp.h"
#include "errhndlr.h"
#include "narmapi.h"   /* 5/20/03 */
#include "ddi.h"
#include "serParam.h"
#include "config.h"
#include "naadddev.h"
#ifdef BSP_ARM9
#include "mctimer.h"
#endif

#if BSP_WANT_PPP
    #include "nappp.h"
#endif

#if BSP_WANT_WPA
    #include "wpa_api.h"
#endif

extern unsigned int eth_isr_timer_cnt;
/* new functional prototypes added 5/20/03 */
extern void osdep_init (void);
extern void    t_clock(void);
extern int so_initialize (void);


/* function prototypes */
static int serialSelectInit(void);









TX_THREAD timer_task;
TX_THREAD thrdSlct;
TX_EVENT_FLAGS_GROUP evntSelect;

#define STACK_SIZE 4096
char    timer_stack[STACK_SIZE];
char    slctStack[STACK_SIZE];


extern int ip_configured;


#ifdef FAST_IP_ENABLED
extern void fastip_ip_down(void);
extern void fastip_ip_up(void);
#endif
/************************************************************************
*                                                                       *
*  Function : netosInterfaceUp                                          *
*                                                                       *
*  Description :                                                        *
*       This function is used to support functions within bsproot.c.    *
*       This function is called when an interface is brought up using   *
*       ll_config, and sets ip_configured to IP_STATE_CONFIGURED.  All  *
*       other interface status changes are registered through DHCP      *
*       callbacks.                                                      *
*                                                                       *
*  Parameters : None.                                                   *
*                                                                       *
*  Return : None.                                                       *
*                                                                       *
************************************************************************/
void netosInterfaceUp(void)
{
#ifdef FAST_IP_ENABLED    
    fastip_ip_up();                 /* Update IP addr for Fast IP */
#endif
    ip_configured = IP_STATE_CONFIGURED;
}




void tSelect(unsigned long unused)
{
    int err;
    extern int sockLocalfd[2];
    extern struct sockaddr_in sockLocalfsin;

    while(true)
    {
        /* Suspend waiting for select timer to kick us off */
        err = tx_event_flags_get(&evntSelect, 1, TX_AND_CLEAR, &unused, TX_WAIT_FOREVER);

        err = sendto (sockLocalfd[1], (char *)&err, 1, 0, &sockLocalfsin, sizeof(struct sockaddr_in) );
        if (err < 0)
        {
#ifdef _NETARM_DEBUG
            printf ("sendto fail - error %d\n", getErrno());
#endif
	    
        }
    }
}

/*
 * This routine calls the Fusion clock routine t_clock() about once every 10 milliseconds.
 * It is used for timing within the TCP/IP stack.
 *
 *
 * param   unused      unused parameter required by ThreadX
 */
void timer_proc(unsigned long unused)
{
    #define TICKS_PER_MILL      ((BSP_TICKS_PER_SECOND + 500)/1000)
    #define MILLS_PER_TICK      (1000/BSP_TICKS_PER_SECOND)
    
    NA_UNUSED_PARAM(unused);
    
    while(1)
    {
        if (MILLS_PER_TICK >= MIN_MILLS_PER_FUSION_TICK)
        {
            tx_thread_sleep(1);
        }
        else if (MILLS_PER_TICK)
        {
            tx_thread_sleep(MIN_MILLS_PER_FUSION_TICK/MILLS_PER_TICK);
        }
        else
        {
            tx_thread_sleep(TICKS_PER_MILL * MIN_MILLS_PER_FUSION_TICK);
        }
        t_clock();
    }
}



int watchThisFileDescriptor (char *filename, int ourDescriptors)
{
    int i;
    extern int NAserialComPortFds[];

    for (i = 0; i < MAX_DEV; i ++)
    {
        /*  find the com file descriptor   */
        if (strcmp (filename, deviceTable[i].name) == 0)
	    {
            NAserialComPortFds[ourDescriptors] = i + DDI_BIT;
            return 0;
        }
    }

    return -1;
}


#if BSP_WANT_WIRELESS
/*
 *  Function: int wireless_init(void)
 *
 *  Description:
 *
 *      Install the wireless driver into the TCP/IP stack, set 
 *		wireless parameters, and initialize the WPA application.
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *       0	Success
 *		-1	Error installing driver
 *		-2	Error getting wireless parameters
 *		-3	Error setting wireless parameters
 *		-4	Error starting WPA application
 */
static int wireless_init (void)
{
	wln_params params;
	
	/* Install wireless driver */
	if (wln_install (BP_WLN_INTERFACE) != 0)
		return -1;

	/* Retrieve and set wireless network params */
	if (customizeGetWirelessParameters (&params) != 0)
		return -2;
	if (wln_set_params (&params) != 0)
		return -3;

#if BSP_WANT_WPA		
	/* Start WPA application */
	if (wpa_supplicant_init (BP_WLN_INTERFACE, &params) == NULL)
		return -4;
#endif

	return 0;
}
#endif /* BSP_WANT_WIRELESS */

/*
 *
 *  Function: void netosStartTCP(void)
 *
 *  Description:
 *
 *      This routine starts TCP/IP.  It creates the semaphores and threads used by
 *      the TCP/IP stack and then waits for the stack to load.
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */


void netosStartTCP(void)

{
	int result;
#if BSP_WANT_PPP
    int pppDeviceIndex;
	static NADeviceTableEntryType pppEntry[] =
	{
    	{
    	    "ppp0",         /* name */
    	    0,              /* device minor ID */
    	    0,              /* xflags */
    	    0,              /* OEM parameter 0 (not used) */
    	    0,              /* OEM parameter 1 (not used) */
    	    0,              /* OEM parameter 2 (not used) */
    	    0,              /* OEM parameter 3 (not used) */
    	    AF_PPP,         /* family */
    	    ppp_init,       /* initialization function */
    	    ppp_updown,     /* enable/disable function */
    	    ppp_scomm,      /* create link layer headers function */
    	    ppp_start,      /* transmit function */
    	    noent_ioctl     /* no ioctl function */
    	},
    	{
    	    "ppp1",         /* name */
    	    1,              /* device minor ID */
    	    0,              /* xflags */
    	    0,              /* OEM parameter 0 (not used) */
    	    0,              /* OEM parameter 1 (not used) */
    	    0,              /* OEM parameter 2 (not used) */
    	    0,              /* OEM parameter 3 (not used) */
    	    AF_PPP,         /* family */
    	    ppp_init,       /* initialization function */
    	    ppp_updown,     /* enable/disable function */
    	    ppp_scomm,      /* create link layer headers function */
    	    ppp_start,      /* transmit function */
    	    noent_ioctl     /* no ioctl function */
    	}
    };
#endif
    /* initialize osdeps variables */
    osdep_init();
    
    /* initialize fusion */
    if(so_initialize())
    {
	
#ifdef _NETARM_DEBUG
        printf("netosStartTCP: error running so_initialize\n");
#endif
	
    }

#if BSP_WANT_PPP___
    for (pppDeviceIndex = 0; pppDeviceIndex < asizeof(pppEntry); pppDeviceIndex++)
    {
        if (NAAddDeviceToTcpipDeviceTable(&pppEntry[pppDeviceIndex]) == FALSE)
        {
            customizeErrorHandler(ERROR_PPP, ERROR_PPP_UNABLE_TO_ADD_DEVICE);
        }
    }
#endif
        
    /* start fusion clock */
    tx_thread_create(&timer_task, "timer task", timer_proc, 0, &timer_stack[0], STACK_SIZE, 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
    
#if BSP_WANT_PPP
    for (pppDeviceIndex = 0; pppDeviceIndex < asizeof(pppEntry); pppDeviceIndex++)
    {
        if (NAAddDeviceToTcpipDeviceTable(&pppEntry[pppDeviceIndex]) == FALSE)
        {
            customizeErrorHandler(ERROR_PPP, ERROR_PPP_UNABLE_TO_ADD_DEVICE);
        }
    }
#endif
        
#if BSP_WANT_WIRELESS
	/* Intialize wireless network interface */
	result = wireless_init();
#ifdef _NETARM_DEBUG
	if (result != 0)
		printf("netosStartTCP: Wireless interface not started: %d\n", result);
#endif
#endif

    result = customizeStartAce();

	if (result != 0)
    {
        customizeErrorHandler(ERROR_ACE_FAILURE, ERROR_ACE_FAILED);
    }
        
	serialSelectInit();

    /* Wait some time for network input to create randomness */
    if (NABspStartupDelay && narm_read_reg (NARM_GSSR_REG, NARM_GSSR_ADDR, rev) >= NETA20UM)
    {
        tx_thread_sleep(NABspStartupDelay * NABspTicksPerSecond);
    }
}

static int serialSelectInit(void)
{
	extern int sockLocalfd[2];
    extern struct sockaddr_in sockLocalfsin;
    int ioption;
	int err;

    sockLocalfd[0] = socket (AF_INET, SOCK_DGRAM, 0);
    if (sockLocalfd[0] < 0)
    {

#ifdef _NETARM_DEBUG
        printf("netosStartTCP: error openning select socket 0.\n");
#endif
	
        return -1;
    }

    memset((void *)&sockLocalfsin, 0, sizeof(sockLocalfsin));
    sockLocalfsin.sin_family  = AF_INET;
    err = bind (sockLocalfd[0], &sockLocalfsin, sizeof (struct sockaddr_in));
    if (err < 0)
    {

#ifdef _NETARM_DEBUG
        printf("netosStartTCP: error binding select socket 0. Error %d\n",
		getErrno());
#endif
	
        return -1;
    }

    ioption = sizeof (struct sockaddr_in);
    err = getsockname (sockLocalfd[0], &sockLocalfsin, &ioption);
    if (err < 0)
    {

#ifdef _NETARM_DEBUG
        printf("netosStartTCP: error getting sockname on select socket 0.\n");
#endif

	return -1;
    }

    ioption = 1;
    err = setsockopt (sockLocalfd[0], SOL_SOCKET, SO_NBIO, (char *)&ioption, sizeof(int));
    if (err < 0)
    {

#ifdef _NETARM_DEBUG
        printf("netosStartTCP: error setting select socket 0 to non-blocking. Error %d\n",
		 getErrno());
#endif

	return-1;
    }

    sockLocalfd[1] = socket (AF_INET, SOCK_DGRAM, 0);
    if (sockLocalfd[1] < 0)
    {
#ifdef _NETARM_DEBUG
        printf("netosStartTCP: error openning select socket 1. Error %d\n",
		getErrno());
#endif
	
	return -1;
    }

    /*  complete the setup of the sockaddr_in structure */
    sockLocalfsin.sin_addr.s_addr = NAInet_addr("127.0.0.1");

    err = tx_event_flags_create(&evntSelect, "Select Event");
    if (err < 0)
    {
#ifdef _NETARM_DEBUG
        printf("netosStartTCP: select event create failure\n");
#endif

	return -1;
    }

    err = tx_thread_create (&thrdSlct, "Select task", tSelect, 0, &slctStack[0], STACK_SIZE, 16, 16, 1, TX_AUTO_START);
    if (err < 0)
    {

#ifdef _NETARM_DEBUG
        printf("netosStartTCP: select thread failure\n");
#endif
	return -1;
    }
	return 0;
}

unsigned NA_Rand(void)
{
   static unsigned int t = 0;
   MD5_CTX mdContext;

   MD5Init(&mdContext);   /* initialize MD5 */

   if (t == 0)
   {
#ifdef BSP_ARM9
       MCGetTimerCounter (THREADX_TIMER, (unsigned long *)&t);
#else
       /* For NET+50 get Ethernet MAC random number, anf MD5 it*/
       if (narm_read_reg (NARM_GSSR_REG, NARM_GSSR_ADDR, rev) < NETA20UM)   /* NET+50,40,15,20 */
       {
           t = *NARM_EFE_TRNG50_ADDR;
       }
       else
       {
           /* get current timer 1 count and MD5 it */
           t = *NARM_T1SR_ADDR;
       }
#endif
   }

   /* First hash the residue    */
   MD5Update(&mdContext, (unsigned char *)&t, sizeof(int));

#if !defined(BSP_WANT_ETHERNET) || BSP_WANT_ETHERNET
   /* get timer 1 count at the time of last Ethernet Receive and MD5 it */
   MD5Update(&mdContext, (unsigned char *)&eth_isr_timer_cnt, sizeof(int));

   /* Md5 Ethernet statistics */
   MD5Update(&mdContext, (unsigned char *)&eth_stats.received[0] , sizeof(eth_stats.received[0]));
#endif

   MD5Final(&mdContext);

   t = *(unsigned int *) mdContext.digest;
   return t;
}






