/*-------------------------------------------------------------------- */
void efss_createfilecb( char *name, unsigned int length, unsigned char *pData,
                       EFSFUN pllDestroyFun, unsigned int MemMgrArg )
{
    FILEHEADER *pfh;

    /* Allocate the file header structure */
    pfh = mmAlloc( sizeof(FILEHEADER) );
    if( !pfh )
        return;

    pfh->Type = HTYPE_EFSFILEHEADER;

    /* Record the filename, size, and data pointer */
    strncpy( pfh->Filename, name, EFSS_FILENAME_MAX-1 );
    pfh->Filename[EFSS_FILENAME_MAX-1] = 0;
    pfh->Length     = length;
    pfh->RefCount   = 0;
    pfh->pData      = pData;
    pfh->Flags      = 0;
    pfh->pMemMgrCallback = pllDestroyFun;
    pfh->MemMgrArg = MemMgrArg;

    llEnter();

    /* Put it in our list */
    pfh->pNext = pRoot;
    pRoot      = pfh;

    llExit();

}
/*-------------------------------------------------------------------- */
EFSS_FILE *efss_fopen( char *name, char *mode )
{
    FILEHEADER *pfh;
    FILEPTR    *pf;

    /* Verify the read mode */
    if( stricmp( mode, "rb" ) )
        return(0);

    llEnter();

    pfh = efss_findfile( name );

    if( !pfh )
    {
        llExit();
        return(0);
    }

    /* Allocate the file header structure */
    pf = mmAlloc( sizeof(FILEPTR) );
    if( !pf )
    {
        llExit();
        return(0);
    }

    pf->Type = HTYPE_EFSFILEPOINTER;
    pf->pfh = pfh;
    pf->Pos = 0;

    pfh->RefCount++;

    llExit();

    return( pf );
}
/*-------------------------------------------------------------------- */
void efss_destroyfile( char *name )
{
    FILEHEADER *pfh;

    llEnter();

    pfh = efss_findfile( name );
    if( !pfh )
        goto dest_exit;

    if( !pfh->RefCount )
        efss_internal_remove( pfh );
    else
        pfh->Flags |= EFSFLG_DESTROY_PENDING;

dest_exit:
    llExit();

}
/*-------------------------------------------------------------------- */
int efss_fclose( EFSS_FILE *stream )
{
    FILEPTR *pf     = (FILEPTR *)stream;
    FILEHEADER *pfh = pf->pfh;

    llEnter();

    /* Zap type for debug */
    pf->Type = 0;
    mmFree( pf );

    pfh->RefCount--;

    if( !pfh->RefCount && (pfh->Flags & EFSFLG_DESTROY_PENDING) )
        efss_internal_remove( pfh );

    llExit();

    return(0);
}
/*-------------------------------------------------------------------- */
EFSFUN efss_loadfunction( char *name )
{
    FILEHEADER *pfh;
    EFSFUN     pFun = 0;

    llEnter();

    pfh = efss_findfile( name );
    if( pfh ) {
        /* CQ7924 fix. To eliminate compiler warning. */
        unsigned int temp;

        temp = (unsigned int) pfh->pData;
        pFun = (EFSFUN) temp;
    }

    llExit();

    return( pFun );
}
/*
 *  ======== netCloseHook ========
 *  NDK network close hook used to de-initialize IPv6
 */
void netCloseHook()
{
    int status = 0;
    int dev_index = 1;

    /* Enter the kernel Mode. */
    llEnter ();
    status = IPv6InterfaceDeInit(dev_index);
    llExit ();

    /* Were we able to deinitialize the stack? */
    if (status < 0) {
        System_printf(
                "Error: Unable to de-initialize the IPv6 stack on device %d\n",
                dev_index);
    }
    else {
        System_printf("IPv6 stack has been deinitialized on %d\n", dev_index);
    }
}
/** 
 *  @b Description
 *  @n  
 *      The function creates a V6 Daemon.
 *
 *  @param[in]  Type
 *      This is the type of socket being opened through the daemon. In
 *      the case of IPv6 the following types are supported
 *          - SOCK_STREAM
 *              Use this for TCP Sockets.
 *          - SOCK_DGRAM
 *              Use this for UDP Sockets.
 *  @param[in]  LocalAddress
 *      This is the Local Address to which the socket will be bound to.
 *      In most cases this is typically passed as IPV6_UNSPECIFIED_ADDRESS
 *  @param[in]  LocalPort
 *      This is the Local Port to serve (cannot be NULL)
 *  @param[in]  pCb
 *      Call back function which is to be invoked.
 *  @param[in]  Priority
 *      Priority of new task to create for callback function 
 *  @param[in]  StackSize
 *      Stack size of new task to create for callback function
 *  @param[in]  Argument
 *      Argument (besides socket) to pass to callback function
 *  @param[in]  MaxSpawn
 *      Maximum number of callback function instances (must be 1 for UDP)
 *
 *  @retval
 *      Success - Handle to the spawned Daemon.
 *  @retval
 *      Error   - 0
 */
HANDLE Daemon6New (uint Type, IP6N LocalAddress, uint LocalPort, int (*pCb)(SOCKET,UINT32),
                   uint Priority, uint StackSize, UINT32 Argument, uint MaxSpawn )
{
    int i;
    DREC *pdr = 0;

    // Sanity check the arguments
    if( Type==SOCK_DGRAM )
        MaxSpawn=1;
    else if( Type!=SOCK_STREAM)
        return(0);

    if( !LocalPort || !pCb || Priority<1 || Priority>15 || !StackSize || !MaxSpawn )
        return(0);

    // We'll borrow the stack's kernel mode for a temp exclusion method
    llEnter();
    if( !hDSem6 )
    {
        hDSem6 = SemCreate( 1 );
        bzero( drec6, sizeof(drec6) );
        RequestedRecords6 = 0;
    }
    llExit();

    // At this point we must have a semaphore
    if( !hDSem6 )
        return(0);

    // Enter our own lock
    SemPend( hDSem6, SEM_FOREVER );

    // Scan the list for a free slot
    for( i=0; i<DAEMON_MAXRECORD; i++ )
        if( !drec6[i].Type && !drec6[i].TasksSpawned )
            break;

    // Break out if no free records
    if(i==DAEMON_MAXRECORD)
        goto errorout;

    // Build the new record
    pdr = &drec6[i];
    pdr->Type           = Type;
    pdr->LocalV6Address = LocalAddress;
    pdr->LocalPort      = LocalPort;
    pdr->pCb            = pCb;
    pdr->Priority       = Priority;
    pdr->StackSize      = StackSize;
    pdr->Argument       = Argument;
    pdr->MaxSpawn       = MaxSpawn;
    pdr->s              = INVALID_SOCKET;

    // If the Deamon task exists, ping it, otherwise create it
    if( hDTask6 )
        fdSelectAbort( hDTask6 );
    else
    {
        hDTask6 = TaskCreate(daemon6,"daemon6",OS_TASKPRINORM,OS_TASKSTKLOW,0,0,0);
        if( hDTask6 )
            fdOpenSession(hDTask6);
        else
        {
            pdr->Type = 0;
            pdr = 0;
            goto errorout;
        }
    }

    RequestedRecords6++;

errorout:
    // Exit our lock
    SemPost( hDSem6 );
    return( pdr );
}
/*------------------------------------------------------------------------- */
int efss_filecheck(char *name, char *user, char *pass, int *prealm)
{
    FILEHEADER *pfh;
    char tstr[EFSS_FILENAME_MAX];
    int  i,realm=0,retflags = 0;

    /* First, see if the file is present */

    llEnter();
    pfh = efss_findfile( name );
    llExit();

    if( !pfh )
        return( EFSS_FC_NOTFOUND );

    /* Next, determine if the file is a "function". */

    /* The method for detecting if a filename represents an executable */
    /* function is determined by this EFS module. It can use any method */
    /* suitable to application developer. */

    /* For this implementation, we assume if the file ends in '.cgi', */
    /* then its a function. */

    i = strlen(name);
    if( i>4 && !stricmp( name+i-4, ".cgi" ) )
        retflags |= EFSS_FC_EXECUTE;


    /* Now do authentication */

    /* The authentication method is determined by this EFS module. */
    /* It can use any method suitable to application developer. */

    /* For this implementation, the authentication scheme works by */
    /* looking for files named %R% in primary subdirectory of the */
    /* requested file, or in the root directory if no subdirectory */
    /* exits. The file contains a single 4 byte int that is the */
    /* authorization realm index. If there is no file, there is no */
    /* authentication. Here, only the first subdir level is */
    /* validated. */

    /* Find the first '/' terminator (if any). */
    /* We must have room for "$R$<NULL>" at the end */
    for( i=0; i<(EFSS_FILENAME_MAX-4); i++ )
    {
        tstr[i] = *(name+i);
        if( tstr[i] == '/' || !tstr[i] )
            break;
    }

    /* Setup the following: */
    /*   tstr   = the primary directory name "mydir/" (null terminated) */
    /*   name+i = the part of the filename following the primary directory */
    /*   Return EFSS_FC_NOTALLOWED on an error */
    if( tstr[i] == '/' )
        tstr[++i]=0;
    else if( !tstr[i] )
    {
        tstr[0] = 0;
        i=0;
    }
    else
    {
        retflags |= EFSS_FC_NOTALLOWED;
        return(retflags);
    }

    /* First of all, it is illegal to request a %R% file */
    if( !stricmp( name+i, "%R%" ) )
    {
        retflags |= EFSS_FC_NOTALLOWED;
        return(retflags);
    }

    /* Look for a realm authentication file */
    /* and read the required realm index */
    strcat( tstr, "%R%" );

    /* (Since we're EFS, we'll cheat and use the internal EFS functions) */
    llEnter();
    pfh = efss_findfile( tstr );
    if( pfh )
        realm = *(int *)pfh->pData;
    llExit();

    /* If there is no realm (or the realm is zero), we're done */
    if( !realm )
        return(retflags);

    /* If we have either a username or password, attempt the validation. */
    if( *user || *pass )
    {
#if 0
        HANDLE  hAcct;
        CI_ACCT CA;
        int     rc;
        int     size;

        /* i == "Found" flag */
        i = 0;

        /* Search for this user account */
        rc = CfgGetEntry( 0, CFGTAG_ACCT, CFGITEM_ACCT_REALM, 1, &hAcct );
        while( rc > 0 )
        {
            /* Read the account data in our CA record */
            size = sizeof(CA);
            rc = CfgEntryGetData( hAcct, &size, (unsigned char *)&CA );

            /* If the read succeeded and the username matches, we're done */
            if( rc > 0 && !strcmp( user, CA.Username ) )
            {
                i = 1;
                CfgEntryDeRef( hAcct );
                break;
            }

            /* Close the current handle on error, or get next handle */
            if( rc <= 0 )
                CfgEntryDeRef( hAcct );
            else
                rc = CfgGetNextEntry( 0, hAcct, &hAcct );
        }

        /* If we found the user, validate the password */
        if( i && !strcmp( pass, CA.Password ) )
        {
            /* See if the user is authorized for this realm */
            if( CA.Flags & (CFG_ACCTFLG_CH1<<(realm-1)) )
                return(retflags);
        }
#endif
    }

    /* Return the non-validated realm index */
    retflags |= EFSS_FC_AUTHFAILED;
    if( prealm )
        *prealm = realm;
    return(retflags);
}