
  /*
   *  Object %name    : %
   *  State           :  %state%
   *  Creation date   :  Mon Mar 07 10:50:52 2005
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief A brief description of this module
   *
   *  \version CRYS_RC4.c#1:csrc:1
   *  \author adams
   *  \remarks Copyright (C) 2004 by Discretix Technologies Ltd.
   *           All Rights reserved
   */



/************* Include Files ****************/
#include <linux/module.h>
#include <linux/mm.h>
#include "CRYS_RC4.h"
#include "CRYS_RC4_error.h"
#include "error.h"
#include "host_op_code.h"
#include "SEPDriver.h"
#include "gen.h"

/************************ Defines ******************************/



/************************ Enums ******************************/


/************************ Macros ******************************/

/* this macro is required to remove compilers warnings if the RC4 is not supported */


/************************ Public Functions ******************************/

/**
 * @brief This function is used to initialize the RC4 machine.
 *        To operate the RC4 machine, this should be the first function called.      
 *
 * @param[in] ContextID_ptr - A pointer to the RC4 context buffer that is allocated by the user 
 *                       and is used for the RC4 machine operation.
 *
 * @param[in] Key_ptr -  A pointer to the user's key buffer.
 *
 * @param[in] KeySize - The size of the KEY in bytes.
 *
 * @return CRYSError_t - CRYS_OK,
 *                       CRYS_RC4_INVALID_USER_CONTEXT_POINTER_ERROR,
 *                       CRYS_RC4_ILLEGAL_KEY_SIZE_ERROR,
 *                       CRYS_RC4_INVALID_KEY_POINTER_ERROR
 */

CEXPORT_C CRYSError_t  CRYS_RC4_Init(CRYS_RC4UserContext_t*   ContextID_ptr,
                                     DxUint8_t*               Key_ptr, 
                                     DxUint32_t               KeySizeInBytes)
{
  /* the Error identifier */
  CRYSError_t   Error; 
  
  /* offset */
  DxUint32_t    sramOffset;
  
  /* read parameter */
  DxUint32_t    messageParam[2];
  
  /* max length */
  DxUint32_t    maxLength;
  
   
  /*-----------------------------
      CODE
  -------------------------------*/
  Error = CRYS_OK;

                  
  #ifndef CRYS_NO_RC4_SUPPORT                                      
      
  /* ............... checking the parameters validity ................... */
   
  /* if the users context ID pointer is DX_NULL return an error */
  if( ContextID_ptr == DX_NULL )
  {
    Error = CRYS_RC4_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }   
            
  /* If the Keys size in invalid return an error */
  if( KeySizeInBytes == 0 || KeySizeInBytes > CRYS_RC4_MAX_KEY_SIZE_IN_BYTES)  
  {   
    Error = CRYS_RC4_ILLEGAL_KEY_SIZE_ERROR;
    goto end_function;
  }   
     
  /* If the the key pointer is not validity */
  if( Key_ptr == DX_NULL )
  {
    Error = CRYS_RC4_INVALID_KEY_POINTER_ERROR;
    goto end_function;
  }
  
  /* lock access to the SEP */
  SEPDriver_Lock();
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RC4_INIT_OP_CODE;
  messageParam[1] = KeySizeInBytes;
  
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam , 
                           sizeof(DxUint32_t) * 2,
                           sizeof(DxUint32_t) * 2,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
    
  /* send key */
  maxLength = ((KeySizeInBytes + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_WriteParamater((DxUint32_t)Key_ptr , 
                            KeySizeInBytes ,
                            maxLength, 
                            &sramOffset , 
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  Error = SEPDriver_POLL_FOR_REPONSE();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /*-------------------
    start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_RC4_INIT_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
   
  /* read the context */
  maxLength = ((sizeof(CRYS_RC4UserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_ReadParamater((DxUint32_t)ContextID_ptr,
                          sizeof(CRYS_RC4UserContext_t),
                          maxLength,
                          &sramOffset,
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                                           
  /* ...................... end of function ................................ */   

end_function_unlock:   

  /* lock access to the SEP */
  SEPDriver_Unlock();
  
                       
end_function:

  return Error;   
  
  #endif /*CRYS_NO_RC4_SUPPORT*/
   
}/* END OF CRYS_RC4_Init */

EXPORT_SYMBOL(CRYS_RC4_Init);                  		     

/**
 * @brief This function is used to process a stream on the RC4 machine.
 *        This function should be called after the CRYS_RS4_Init. 
 *      
 *
 * @param[in] ContextID_ptr - A pointer to the RC4 context buffer allocated by the user 
 *                       that is used for the RC4 machine operation. This should be the 
 *                       same context as was used for the previous call of this session.
 *
 * @param[in] DataIn_ptr - The pointer to the buffer of the input data to the RC4. 
 *                   The pointer's value does not need to be word-aligned.
 *
 * @param[in] DataInSize - The size of the input data.
 *
 * @param[in,out] DataOut_ptr - The pointer to the buffer of the output data from the RC4. 
 *                        The pointer's value does not need to be word-aligned.  
 *
 * @return CRYSError_t - CRYS_OK,
 *                       CRYS_RC4_INVALID_USER_CONTEXT_POINTER_ERROR,
 *                       CRYS_RC4_USER_CONTEXT_CORRUPTED_ERROR,
 *                       CRYS_RC4_DATA_IN_POINTER_INVALID_ERROR,
 *                       CRYS_RC4_DATA_OUT_POINTER_INVALID_ERROR,
 *                       CRYS_RC4_DATA_OUT_DATA_IN_OVERLAP_ERROR,
 *                       CRYS_RC4_DATA_SIZE_ILLEGAL
 */
 CEXPORT_C CRYSError_t  CRYS_RC4_Stream(CRYS_RC4UserContext_t*    ContextID_ptr,   
                                        DxUint8_t*                DataIn_ptr,                                  
                                        DxUint32_t                DataInSize,
                                        DxUint8_t*                DataOut_ptr)
{                                
  /* the Error identifier */
  CRYSError_t   Error;
  
  /* address of the first table in the input list */
  DxUint32_t    firstInputLLITableAddr;
  
  /* address of the first table in the output list */
  DxUint32_t    firstOutputLLITableAddr;
  
  /* number of entries in the first input tables */
  DxUint32_t    numInTableEntries;
  
  /* number of entries in the first input tables */
  DxUint32_t    numOutTableEntries;
  
  /* size of data in the first table */
  DxUint32_t    firstTableSize;
  
  /* offset */
  DxUint32_t    sramOffset;
  
  /* read parameter */
  DxUint32_t    messageParam[7];
  
  /* max length */
  DxUint32_t    maxLength;
   
   
  /*-----------------------------
      CODE
  --------------------------------*/
  Error = CRYS_OK;
                
  #ifndef CRYS_NO_RC4_SUPPORT                                      
    
  /* ............... checking the parameters validity ................... */
  
  /* if the users context ID pointer is DX_NULL return an error */
  if( ContextID_ptr == DX_NULL )
  {
    Error = CRYS_RC4_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }   
   
  /* if the users Data In pointer is illegal return an error */
  if( DataIn_ptr == DX_NULL )
  {
    Error = CRYS_RC4_DATA_IN_POINTER_INVALID_ERROR;
    goto end_function;
  }     
  
  /* if the users Data Out pointer is illegal return an error */
  if( DataOut_ptr == DX_NULL )
  {
    Error = CRYS_RC4_DATA_OUT_POINTER_INVALID_ERROR;
    goto end_function;
  }
   
  /* checking that there is no overlapping between the data input and data out put buffer
    except the inplace case that is legal */
  if( DataIn_ptr != DataOut_ptr )
  {
    /* checking the case that the input buffer is in a higher address then the output buffer */
    if ( DataIn_ptr > DataOut_ptr )
    {
      /* if after adding the size to the data out pointer it is larger then the data in pointer 
          return the overlap error */
      if( DataOut_ptr + DataInSize > DataIn_ptr )   
      {
        Error = CRYS_RC4_DATA_OUT_DATA_IN_OVERLAP_ERROR; 
        goto end_function;
      }
    }/* end of DataIn_ptr > DataOut_ptr */   
          
    /* checking the case that the output buffer is in a higher address then the input buffer */      
    else
    {
     /* if after adding the size to the data in pointer it is larger then the data out pointer 
        return the overlap error */
      if( DataIn_ptr + DataInSize > DataOut_ptr )   
      {
        Error = CRYS_RC4_DATA_OUT_DATA_IN_OVERLAP_ERROR; 
        goto end_function;
      }
         
    }/* end of DataOut_ptr > DataIn_ptr */   
      
  }/* end of DataIn_ptr != DataOut_ptr case */   

  /* if the data size is zero return error */
  if( DataInSize == 0 )
  {
    Error = CRYS_RC4_DATA_SIZE_ILLEGAL;
    goto end_function;
  }         

  /* lock access to the SEP */
  SEPDriver_Lock();
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
   Error = SEPDriver_PrepareSymDMATables((DxUint32_t)DataIn_ptr,
                                         (DxUint32_t)DataOut_ptr,
                                         DataInSize,
                                         0x1,/*RC$ is bytes stream */
                                         &firstInputLLITableAddr,
                                         &firstOutputLLITableAddr,
                                         &numInTableEntries,
                                         &numOutTableEntries,
                                         &firstTableSize); 
                                    
   if(Error != DX_OK)
   {
      goto end_function_unlock;
   }
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RC4_STREAM_OP_CODE;
  messageParam[1] = firstInputLLITableAddr;
  messageParam[2] = numInTableEntries;
  messageParam[3] = firstOutputLLITableAddr;
  messageParam[4] = numOutTableEntries;
  messageParam[5] = firstTableSize;
   
   /* send the message to SEP */
   sramOffset = 0;
   
   /* start the message */
   SEPDriver_StartMessage(&sramOffset);
  
   
   /* send message */
   Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 6,
                            sizeof(DxUint32_t) * 6,
                            &sramOffset, 
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send context */
   maxLength = ((sizeof(CRYS_RC4UserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_WriteParamater((DxUint32_t)ContextID_ptr , 
                            sizeof(CRYS_RC4UserContext_t) ,
                            maxLength, 
                            &sramOffset , 
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* end message */
   SEPDriver_EndMessage(sramOffset);
            
   /* wait for the response */
   Error = SEPDriver_POLL_FOR_REPONSE();
   if(Error != DX_OK)
   {
     goto end_function_unlock;
   }
   
   /*-------------------
      start reading message from the SEP 
   ---------------------*/ 
   
   /* free the tables */
   Error = SEPDriver_FreeDMATables();
   if(Error)
   {
      goto end_function_unlock;
   }
   
   /* start the message */
   Error = SEPDriver_StartIncomingMessage(&sramOffset);
   if(Error)
   {
    goto end_function_unlock;
   }
   
   /* read opcode + status  */
   Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                           sizeof(DxUint32_t) * 2,
                           sizeof(DxUint32_t) * 2, 
                           &sramOffset,
                           DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* check the opcode */
   if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_RC4_STREAM_OP_CODE)
   {
      Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
      goto end_function_unlock;
   }
   
   /* check the status */
   if(messageParam[1] != CRYS_OK)
   {
      Error = messageParam[1];
      goto end_function_unlock;
   }
   
   /* read the context */
   maxLength = ((sizeof(CRYS_RC4UserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_ReadParamater((DxUint32_t)ContextID_ptr,
                           sizeof(CRYS_RC4UserContext_t),
                           maxLength,
                           &sramOffset,
                           DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }

end_function_unlock:   

  /* lock access to the SEP */
  SEPDriver_Unlock();
  
                       
end_function:

  return Error; 

  #endif /*CRYS_NO_RC4_SUPPORT*/

}/* END OF CRYS_RC4_Stream */

EXPORT_SYMBOL(CRYS_RC4_Stream);


/**
 * @brief This function is used to end the RC4 processing session.
 *        It is the last function called for the RC4 process.
 *      
 *
 * @param[in] ContextID_ptr - A pointer to the RC4 context buffer allocated by the user that
 *                       is used for the RC4 machine operation. This should be the 
 *                       same context as was used for the previous call of this session.
 *
 *
 * @return CRYSError_t -  CRYS_OK, 
 *                        CRYS_RC4_INVALID_USER_CONTEXT_POINTER_ERROR,
 *                        CRYS_RC4_USER_CONTEXT_CORRUPTED_ERROR
 */
 CEXPORT_C CRYSError_t  CRYS_RC4_Free(CRYS_RC4UserContext_t  *ContextID_ptr )
 {
  /* The return error identifier */
  CRYSError_t   Error;
  

  /*--------------------------
      CODE
  ----------------------------*/
  
  Error = CRYS_OK;
                   
  #ifndef CRYS_NO_RC4_SUPPORT                                      
 
  /* ............... checking the parameters validity ................... */
   
  /* if the users context ID pointer is DX_NULL return an error */
  if( ContextID_ptr == DX_NULL )
  {
    Error = CRYS_RC4_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  } 
   
   
  /* .............. clearing the users context .......................... */
  /* -------------------------------------------------------------------- */
   
  memset( ContextID_ptr , 0 , sizeof(CRYS_RC4UserContext_t) );   

  /* ................. end of function ..................................... */
  /* ----------------------------------------------------------------------- */
    
end_function:
   
   return Error;   

   #endif /*CRYS_NO_RC4_SUPPORT*/
 
}/* END OF CRYS_RC4_Free */

EXPORT_SYMBOL(CRYS_RC4_Free);

/**
 * \brief This function provides a RC4 function for processing data.
 *
 * The function allocates an internal RC4 Context, and initializes the RC4 Context with the
 * cryptographic attributes that are needed for the RC4 cryptographic operation. Next the
 * function loads the engine with the initializing values, and then processes the data,
 * returning the processed data in the output buffer. Finally, the function frees the
 * internally allocated context.
 *
 * @param[in] Key_ptr -  A pointer to the user's key buffer.
 *
 * @param[in] KeySize - The size of the KEY in bytes.
 *
 * @param[in] DataIn_ptr - The pointer to the buffer of the input data to the RC4. 
 *                   The pointer's value does not need to be word-aligned.
 *
 * @param[in] DataInSize - The size of the input data.
 *
 * @param[in,out] The pointer to the buffer of the output data from the RC4.
 *                The pointer's value does not need to be word-aligned. The size of this buffer
 *                must be the same as the DataIn buffer.  
 *
 * @return CRYSError_t -  On success the function returns the value CRYS_OK, 
 *				and on failure a value from CRYS_RC4_error.h
 *
 */
CEXPORT_C CRYSError_t CRYS_RC4  (DxUint8_t*     Key_ptr, 
                            	   DxUint32_t     KeySizeInBytes,
                                 DxUint8_t*     DataIn_ptr,                                  
                                 DxUint32_t     DataInSize,
                                 DxUint8_t*     DataOut_ptr)  
{                         
  /* The return error identifier */
  CRYSError_t   Error;
  
  /* address of the first table in the input list */
  DxUint32_t    firstInputLLITableAddr;
  
  /* address of the first table in the output list */
  DxUint32_t    firstOutputLLITableAddr;
  
  /* number of entries in the first input tables */
  DxUint32_t    numInTableEntries;
  
  /* number of entries in the first output tables */
  DxUint32_t    numOutTableEntries;
  
  /* first table data size */
  DxUint32_t    firstTableSize;

  /* offset */
  DxUint32_t    sramOffset;
  
  /* read parameter */
  DxUint32_t    messageParam[8];
  
  /* max length */
  DxUint32_t    maxLength;
  
   
  /*---------------------------------
      CODE
  ----------------------------------*/
  Error = CRYS_OK;
               
  #ifndef CRYS_NO_RC4_SUPPORT 
  
  /* if the users Data In pointer is illegal return an error */
  if( DataIn_ptr == DX_NULL )
  {
    Error = CRYS_RC4_DATA_IN_POINTER_INVALID_ERROR;
    goto end_function;
  }     
  
  /* if the users Data Out pointer is illegal return an error */
  if( DataOut_ptr == DX_NULL )
  {
    Error = CRYS_RC4_DATA_OUT_POINTER_INVALID_ERROR;
    goto end_function;
  }
   
  /* checking that there is no overlapping between the data input and data out put buffer
    except the inplace case that is legal */
  if( DataIn_ptr != DataOut_ptr )
  {
    /* checking the case that the input buffer is in a higher address then the output buffer */
    if ( DataIn_ptr > DataOut_ptr )
    {
      /* if after adding the size to the data out pointer it is larger then the data in pointer 
          return the overlap error */
      if( DataOut_ptr + DataInSize > DataIn_ptr )   
      {
        Error = CRYS_RC4_DATA_OUT_DATA_IN_OVERLAP_ERROR; 
        goto end_function;
      }
    }/* end of DataIn_ptr > DataOut_ptr */   
          
    /* checking the case that the output buffer is in a higher address then the input buffer */      
    else
    {
     /* if after adding the size to the data in pointer it is larger then the data out pointer 
        return the overlap error */
      if( DataIn_ptr + DataInSize > DataOut_ptr )   
      {
        Error = CRYS_RC4_DATA_OUT_DATA_IN_OVERLAP_ERROR; 
        goto end_function;
      }
         
    }/* end of DataOut_ptr > DataIn_ptr */   
      
  }/* end of DataIn_ptr != DataOut_ptr case */   

  /* if the data size is zero return error */
  if( DataInSize == 0 )
  {
    Error = CRYS_RC4_DATA_SIZE_ILLEGAL;
    goto end_function;
  }
  
  /* lock access to the SEP */
  SEPDriver_Lock();
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/

   /* prepare LLI table */
   Error = SEPDriver_PrepareSymDMATables((DxUint32_t)DataIn_ptr,
                                         (DxUint32_t)DataOut_ptr,
                                         DataInSize,
                                         CRYS_AES_BLOCK_SIZE_IN_BYTES,
                                         &firstInputLLITableAddr,
                                         &firstOutputLLITableAddr,
                                         &numInTableEntries,
                                         &numOutTableEntries,
                                         &firstTableSize);                                    
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RC4_OP_CODE;
  messageParam[1] = firstInputLLITableAddr;
  messageParam[2] = numInTableEntries;
  messageParam[3] = firstOutputLLITableAddr;
  messageParam[4] = numOutTableEntries;
  messageParam[5] = firstTableSize;
  messageParam[6] = KeySizeInBytes;
  
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam , 
                           sizeof(DxUint32_t) * 7,
                           sizeof(DxUint32_t) * 7,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
     
  /* send key */
  maxLength = ((KeySizeInBytes + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_WriteParamater((DxUint32_t)Key_ptr , 
                           KeySizeInBytes ,
                           maxLength, 
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
     
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  Error = SEPDriver_POLL_FOR_REPONSE();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /*-------------------
    start reading message from the SEP 
  ---------------------*/
   
  /* free the tables */
  Error = SEPDriver_FreeDMATables();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }

  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_RC4_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
   
                                           
  /* ...................... end of function ................................ */   

end_function_unlock:   

  /* lock access to the SEP */
  SEPDriver_Unlock();
  
                       
end_function:

  return Error;                                        

  #endif /*CRYS_NO_RC4_SUPPORT*/

}/* END OF CRYS_RC4 */

EXPORT_SYMBOL(CRYS_RC4);


