/* dhcpsSampleHook.c - Sample DHCP server storage routine */

/* Copyright 1984 - 1997 Wind River Systems, Inc. */
#include "copyright_wrs.h"

/*
modification history
____________________
01b,29apr97,spm  written.
*/

/*
DESCRIPTION
This code demonstrates one possible method of implementing the permanent
storage needed by the DHCP server. It uses a SCSI device with a bus ID of 2 
and a LUN of 0 with a DOS file system which spans the full device.
*/

#include "vxWorks.h"
#include "scsiLib.h"
#include "dosFsLib.h"

#include "stdio.h"    /* for sprintf() */
#include "stdlib.h"   /* for atoi() */

/* DHCP include files */

#include "dhcp/dhcp.h"
#include "dhcp/common.h"
#include "dhcpsLib.h"

BOOL myFsInit = FALSE;
BOOL myFileInit = FALSE;
BOOL endOfData = FALSE;

SCSI_PHYS_DEV * 	pPhysDev;
BLK_DEV * 		pBlkDev;
DOS_VOL_DESC * 		pVolDesc;
DOS_VOL_CONFIG 		configStruct;

int 			myWriteDesc;
int 			myReadDesc;

STATUS sampleLeaseStorageHook 
    (
    int op, 		/* lease operation */
    char *recData, 	/* record of active lease */
    int dataLen		/* length of record data */
    )
    {
    int result;
    int offset;
    int length;
    char delim;
    char buffer [10];

    switch (op)
        {
        case DHCPS_STORAGE_START:

            /* Prepare to store and retrieve records of active leases. */

            if (myFsInit == FALSE)
                {
                /* Set up the BLK_DEV structure to access the SCSI device. */

                pPhysDev = scsiPhysDevCreate (pSysScsiCtrl, 2, 0, 0, NONE,
                                              0, 0, 0);
                if (pPhysDev == NULL)
                    return (ERROR);

                pBlkDev = scsiBlkDevCreate (pPhysDev, 0, 0);
                if (pBlkDev == NULL)
                    return (ERROR);

                /*
                 * Initialize dosFs volume configuration structure.
                 * (Depends on disk type and capacity - see Programmer's Guide).
                 */

                result = dosFsConfigInit (&configStruct, 0xff, 4, 1, 1, 30,
                                          112, 0, 0);
                if (result == ERROR)
                    return (ERROR);

                /* Access an existing DOS file system. */

                pVolDesc = dosFsDevInit ("DEV1:", pBlkDev, &configStruct);
                if (pVolDesc == NULL)
                    return (ERROR);                
                myFsInit = TRUE;
                }

            if (myFileInit == FALSE)
                {
                myWriteDesc = open ("DEV1:leases.dat", O_WRONLY, 0);
                if (myWriteDesc == ERROR)    /* Try to create file. */
                    {
                    myWriteDesc = creat ("DEV1:leases.dat", O_WRONLY);
                    endOfData = TRUE;
                    }

                if (myWriteDesc == ERROR)
                    return (ERROR);
                
                myReadDesc = open ("DEV1:leases.dat", O_RDONLY, 0);
                if (myReadDesc == ERROR)
                    return (ERROR);
     
                myFileInit = TRUE;  
                }
             break;

        case DHCPS_STORAGE_WRITE:

            /* Store active leases. Return ERROR if START operation failed. */

            if (myFsInit == FALSE || myFileInit == FALSE)
                return (ERROR);

            /* Store the length for later retrieval by READ operation. */

            sprintf (buffer, "%d:", dataLen);
            result = write (myWriteDesc, buffer, strlen (buffer));
            if (result != strlen (buffer))
                return (ERROR);
            
            /* Store the record of the lease. */

            result = write (myWriteDesc, recData, dataLen);
            if (result != dataLen)
                return (ERROR);

            /*
             * Force write to file - each operation must be independent,
             * so can't rely on close() call in the DHCPS_STORAGE_STOP code.
             */

            result = ioctl (myWriteDesc, FIOFLUSH, 0);
            if (result == ERROR)
                return (ERROR);
 
            endOfData = FALSE;     /* Data available. */
            break;

        case DHCPS_STORAGE_READ:

             /* 
              * Retrieve active leases. Return ERROR if START failed or if 
              * no data is available.
              */
                       
            if (myFsInit == FALSE || myFileInit == FALSE)
                return (ERROR);

             if (endOfData == TRUE)
                 return (ERROR);

             offset = 0;

             while (offset < 10)
                 {
                 result = read (myReadDesc, &delim, 1);

                 if (result == 0)      /* Unexpected end-of-file. */
                     {
                     endOfData = TRUE;
                     return (ERROR); 
                     }

                 if (result == ERROR)
                     return (ERROR);

                 if (delim == ':')
                     break;

                 buffer [offset++] = delim;
                 }

             if (offset == 10)       /* Buffer overflow - bad file format. */
                 return (ERROR);
             else
                 buffer [offset] = '\0';
            
             length = atoi (buffer);
            
             result = read (myReadDesc, recData, length);
             if (result == 0)      /* Unexpected end-of-file. */
                 {
                 endOfData = TRUE;
                 return (ERROR); 
                 }
             if (result == ERROR)
                 return (ERROR);
             if (result != length)
                 return (ERROR);

             break;

        case DHCPS_STORAGE_CLEAR:

             myFileInit = FALSE;
             endOfData = TRUE;

             /* Remove and recreate underlying file. */
            
             close (myWriteDesc);

             close (myReadDesc);

             result = remove ("DEV1:/leases.dat");
             if (result == ERROR)
                 return (ERROR);

             myWriteDesc = creat ("DEV1:/leases.dat", O_WRONLY);
             if (myWriteDesc == ERROR)
                 return (ERROR);
                
             myReadDesc = open ("DEV1:/leases.dat", O_RDONLY, 0);
             if (myReadDesc == ERROR)
                 return (ERROR);

             myFileInit = TRUE;

             break;

        case DHCPS_STORAGE_STOP:

             myFileInit = FALSE;
             endOfData = FALSE;
             close (myWriteDesc);
             close (myReadDesc);
             break;

        default:
             break;
        }
    return (OK);
    }

