/**
 * ============================================================================
 * = COPYRIGHT
 *              INTEL CORPORATION PROPRIETARY INFORMATION
 *   This software is supplied under the terms of a license agreement or
 *   nondisclosure agreement with Intel Corporation and may not be copied 
 *   or disclosed except in accordance with the terms in that agreement.
 *      Copyright (C) 2000-2001 Intel Corporation. All rights reserved.
 *
 * = PRODUCT
 *      Intel(r) IXA SDK 3.0 for the IXP2000 Network Processor, Release 5
 *
 * = LIBRARY
 *      
 *
 * = MODULE
 *      IPv4 Forwarder Core Component - message handler
 *
 * = FILENAME
 *      ix_cc_ipv4_msg_handler.c
 *
 * = DESCRIPTION
 *      The file defines message handler interface functions.
 *
 * = AUTHOR
 *       Govindan Nair
 *       govindan.nair@intel.com
 *
 * = AKNOWLEDGEMENTS
 *      
 *
 * = CREATION TIME
 *      07/01/2002
 *
 * = CHANGE HISTORY
 *
 * ============================================================================
 */



#define IX_ERROR_FILE_IDENT "$Id: ix_cc_ipv4_msg_handler.c,v 1.17 2002/10/11 19:38:12 gnair1 Exp $";

/**
 * System defined include files
 */

/**
 * User defined include files
 */

#include "ix_cc_error.h"
#include "ix_ossl.h"
#include "ix_rm.h"

#include "ix_cc.h"
#include "ix_cc_macros.h"
#include "ix_cc_properties.h"

#include "cc/ix_cc_rtmv4.h"
#include "cc/ix_cc_msup.h"

#include "bindings.h"

#include "cc/ix_cc_ipv4.h"
#include "cc/ipv4/internal/ix_cc_ipv4_init.h"
#include "cc/ipv4/internal/ix_cc_ipv4_msg_handler.h"

/**
 * Preprocessor symbols and Macros used in this file
 */
/* Flag fornot to send report to msg support lib*/
#define IX_CC_IPV4_SEND_NO_RESPONSE 1 

/**
 * Type definitions whose scope is limited to this file
 */
typedef union ix_u_cc_ipv4_msg_handler_return_data
{
    ix_cc_rtmv4_next_hop_info nextHopInfo;
    ix_cc_ipv4_dump_data dumpData;
    ix_cc_ipv4_stats_data statsData;
    ix_uint16 icmpData;
} ix_cc_ipv4_msg_handler_return_data;

/**
 * Variable declarations global to this file only. Externs are followed by 
 * static variables.
 */

/** 
 * Extern function prototypes.
 */


/** 
 * Static function prototypes.
 */


/** 
 * Function definitions.
 */


/**
 * NAME: ix_cc_ipv4_msg_handler
 *
 * DESCRIPTION: This primitive is the message handler function for IPv4 Forwarder
 * core component. IPV4 Forwarder core component receives messages from other core component
 * through this message handler function and internally it calls appropriate library function
 * to process the message. This message handler shall be used to update dynamic properties.
 * 
 * @Param:  - IN arg_hDataToken - buffer handle embedding information for the message
 * passed in arg_UserData.
 *
 * @Param:  - IN  arg_UserData - message type
 *
 * @Param:  - IN - arg_pComponentContext: pointer to IPv4 Forwarder core component context 
 * that will be passed to the core component when a message arrives. This context was defined
 * by the core component and passed to core components infrastructure through 
 * ix_cc_ipv4_init function.
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null argument
 * IX_CC_ERROR_UNDEFINED_MSG - un supported message
 * IX_CC_IPV4_ERROR_MSG_LIBRARY - error from message support library
 * IX_CC_IPV4_ERROR_BUFFER_FREE - error from RM for freeing buffer
 */


ix_error ix_cc_ipv4_msg_handler(
                                ix_buffer_handle arg_hDataToken,  
                                ix_uint32 arg_UserData,
                                void* arg_pContext
                                )
{

    ix_error err = IX_SUCCESS;
    void *pContext = NULL;
    void *pMsg = NULL;
    void *pRetMsg = NULL;
    ix_cc_ipv4_msg_handler_return_data msgRetData;
    ix_uint32 msgRetLength = 0;
    ix_uint32 noResponse = 0;  

    
    /* Validate arg_pContext */
    if(arg_pContext == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                                   ("arg_pContext is NULL"));
    }/* end if(arg_pContext == NULL) */

    if((arg_UserData < IX_CC_COMMON_MSG_ID_FIRST) ||
       (arg_UserData >= IX_CC_IPV4_MSG_LAST))
    {
    
        return IX_ERROR_WARNING(IX_CC_ERROR_UNDEFINED_MSG,
                                  ("Invalid Message Type"));
    }/* end if */

    IX_MSUP_EXTRACT_MSG(arg_hDataToken,&pMsg,&pContext);

    if((arg_UserData != IX_CC_IPV4_MSG_PURGE_ROUTES) &&
       (arg_UserData != IX_CC_IPV4_MSG_DUMP_ROUTES) && 
       (arg_UserData != IX_CC_IPV4_MSG_PURGE_RTM) &&
       (arg_UserData != IX_CC_IPV4_MSG_DUMP_NEXT_HOPS) &&
       (arg_UserData != IX_CC_IPV4_MSG_GET_SLEEP_TIME) &&
       (arg_UserData != IX_CC_IPV4_MSG_GET_QUEUE_DEPTH) &&
       (arg_UserData != IX_CC_IPV4_MSG_GET_PACKETS_TO_DRAIN) &&
       (arg_UserData != IX_CC_IPV4_MSG_GET_STATISTICS)) 
    {
        if(pMsg == NULL)
        {
            return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                                      ("Invalid Buffer"));
        }/* end if(pContext == NULL) */
    }/* end if */
    
    /* Check for route messages, next hop message, icmp messages and statistics message*/
    switch(arg_UserData)
    {
        case IX_CC_COMMON_MSG_ID_PROP_UPDATE: 
        {
            ix_cc_properties_msg* pData = (ix_cc_properties_msg*)pMsg;
            noResponse = IX_CC_IPV4_SEND_NO_RESPONSE;
            if(((pData->propID & IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4) == IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4) ||
               ((pData->propID & IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4) == IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4) ||   
               ((pData->propID & IX_CC_SET_PROPERTY_PHYSICAL_IF_STATUS) == IX_CC_SET_PROPERTY_PHYSICAL_IF_STATUS))
            {
                err = ix_cc_ipv4_set_property(pData->propID,&pData->propData,arg_pContext); 
            }/* end if propId */
            else
            {
                err = IX_ERROR_WARNING(IX_CC_ERROR_UNDEFINED_MSG,
                                       ("Invalid Message Type"));
 
            }/*end if invalid propId*/

            break;
        }
        /* RTM routes related message */
        case IX_CC_IPV4_MSG_ADD_ROUTE:
        {
            ix_cc_ipv4_add_route_data* pData = (ix_cc_ipv4_add_route_data*)pMsg;
	    err = ix_cc_ipv4_add_route(pData->ipAddr,pData->netMask,pData->nextHopId,arg_pContext);
            break;
        }
        case IX_CC_IPV4_MSG_DELETE_ROUTE:
        {
            ix_cc_ipv4_delete_route_data* pData = (ix_cc_ipv4_delete_route_data*) pMsg;
            err = ix_cc_ipv4_delete_route(pData->ipAddr,pData->netMask,arg_pContext);
            break;
        }
        case IX_CC_IPV4_MSG_UPDATE_ROUTE:
        {
            ix_cc_ipv4_add_route_data* pData = (ix_cc_ipv4_add_route_data*)pMsg;
	    err = ix_cc_ipv4_update_route(pData->ipAddr,pData->netMask,pData->nextHopId,arg_pContext);
            break;
        }
        case IX_CC_IPV4_MSG_LOOKUP_ROUTE:
        {
            ix_uint32* pData = (ix_uint32*)pMsg;
            msgRetLength = sizeof(ix_cc_rtmv4_next_hop_info);
            err = ix_cc_ipv4_lookup_route(*pData,&msgRetData.nextHopInfo,arg_pContext);
            pRetMsg = (void*)&msgRetData.nextHopInfo;
            break;
        }
        case IX_CC_IPV4_MSG_PURGE_ROUTES:
       	    err = ix_cc_ipv4_purge_routes(arg_pContext);
            noResponse = IX_CC_IPV4_SEND_NO_RESPONSE;
            break;
        case IX_CC_IPV4_MSG_DUMP_ROUTES:
            /* Allocate memory for data */
        {
            ix_cc_rtmv4_statistics data;
            ix_uint32 value;
            err = ix_cc_rtmv4_get_statistics(((ix_cc_ipv4_context*)arg_pContext)->hRtm,&data);
            if(err == IX_SUCCESS)
            {
                value = data.numberOfRoutes;
                value = IX_CC_RTMV4_DUMP_ROUTE_SIZE(value);
                msgRetData.dumpData.size = value;
                msgRetData.dumpData.pBuffer = (char *)ix_ossl_malloc(msgRetData.dumpData.size);
                if(msgRetData.dumpData.pBuffer != NULL)
                {
                    msgRetLength = sizeof(ix_cc_ipv4_dump_data);
                    err = ix_cc_ipv4_dump_routes(msgRetData.dumpData.pBuffer,msgRetData.dumpData.size,arg_pContext);
                    pRetMsg = (void*)&msgRetData.dumpData;
                }
                else
                {
                    err = IX_ERROR_WARNING(IX_CC_ERROR_OOM,
                                           ("No memory to dump routes"));

                }
            }/* end if statistics*/
            break;
        }
        /* RTM next hop related messages */
        case IX_CC_IPV4_MSG_ADD_NEXT_HOP:
        {
            ix_cc_ipv4_add_next_hop_data* pData = (ix_cc_ipv4_add_next_hop_data*)pMsg;
	    err = ix_cc_ipv4_add_next_hop(pData->nextHopId,&pData->nextHopInfo,arg_pContext);
            break;
        }
        case IX_CC_IPV4_MSG_DELETE_NEXT_HOP:
        {
            ix_cc_rtmv4_nhid* pData = (ix_cc_rtmv4_nhid*)pMsg;
            err = ix_cc_ipv4_delete_next_hop(*pData,arg_pContext);
            break;
        }
        case IX_CC_IPV4_MSG_UPDATE_NEXT_HOP:
        {
            ix_cc_ipv4_add_next_hop_data* pData = (ix_cc_ipv4_add_next_hop_data*)pMsg;
	    err = ix_cc_ipv4_update_next_hop(pData->nextHopId,&pData->nextHopInfo,arg_pContext);
            break;
        }
        case IX_CC_IPV4_MSG_GET_NEXT_HOP:
        {
            ix_cc_rtmv4_nhid* pData = (ix_cc_rtmv4_nhid*)pMsg;
            msgRetLength = sizeof(ix_cc_rtmv4_next_hop_info);
            err = ix_cc_ipv4_get_next_hop(*pData,&msgRetData.nextHopInfo,arg_pContext);
            pRetMsg = (void*)&msgRetData.nextHopInfo;
            break;
        }
        case IX_CC_IPV4_MSG_PURGE_RTM:
       	    err = ix_cc_ipv4_purge_rtm(arg_pContext);
            noResponse = IX_CC_IPV4_SEND_NO_RESPONSE;
            break;
        case IX_CC_IPV4_MSG_DUMP_NEXT_HOPS:
        {
            ix_cc_rtmv4_statistics data;
            err = ix_cc_rtmv4_get_statistics(((ix_cc_ipv4_context*)arg_pContext)->hRtm,&data);
            if(err == IX_SUCCESS)
            {
                msgRetData.dumpData.size = data.numberOfNextHops;
                msgRetData.dumpData.size = IX_CC_RTMV4_DUMP_NEXT_HOP_SIZE(msgRetData.dumpData.size);
                msgRetData.dumpData.pBuffer = (char *)ix_ossl_malloc(msgRetData.dumpData.size);
                if(msgRetData.dumpData.pBuffer != NULL)
                {
                    msgRetLength = sizeof(ix_cc_ipv4_dump_data);
                    err = ix_cc_ipv4_dump_next_hops(msgRetData.dumpData.pBuffer,msgRetData.dumpData.size,arg_pContext);
                    pRetMsg = (void*)&msgRetData.dumpData;
                }
                else
                {
                    err = IX_ERROR_WARNING(IX_CC_ERROR_OOM,
                                           ("No memory to dump next hops"));

                }
            }/* end if statistics*/
            break;
        }
        case IX_CC_IPV4_MSG_SET_MTU:
        {
            ix_cc_ipv4_set_mtu_data* pData = (ix_cc_ipv4_set_mtu_data*)pMsg;
            err = ix_cc_ipv4_set_mtu(pData->nextHopId,pData->mtu,arg_pContext);
            break;
        }
        case IX_CC_IPV4_MSG_SET_FLAGS:
        {
            ix_cc_ipv4_set_flags_data* pData = (ix_cc_ipv4_set_flags_data*)pMsg;
            err = ix_cc_ipv4_set_flags(pData->nextHopId,pData->flags,arg_pContext);
            break;
        }
        /* ICMP related messages */
        case IX_CC_IPV4_MSG_GET_SLEEP_TIME: 
            msgRetLength = sizeof(ix_uint16);
            err = ix_cc_ipv4_get_sleep_time(&msgRetData.icmpData,arg_pContext);
            pRetMsg = (void*)&msgRetData.icmpData;
            break; 
        case IX_CC_IPV4_MSG_SET_SLEEP_TIME:
        { 
            ix_uint16 *pData = (ix_uint16*)pMsg;
            err = ix_cc_ipv4_set_sleep_time(*pData,arg_pContext);
            noResponse = IX_CC_IPV4_SEND_NO_RESPONSE;
            break;
        }
        case IX_CC_IPV4_MSG_GET_QUEUE_DEPTH: 
            msgRetLength = sizeof(ix_uint16);
            err = ix_cc_ipv4_get_queue_depth(&msgRetData.icmpData,arg_pContext);
            pRetMsg = (void*)&msgRetData.icmpData;
            break; 
        case IX_CC_IPV4_MSG_GET_PACKETS_TO_DRAIN: 
            msgRetLength = sizeof(ix_uint16);
            err = ix_cc_ipv4_get_packets_to_drain(&msgRetData.icmpData,arg_pContext);
            pRetMsg = (void*)&msgRetData.icmpData;
            break; 
        case IX_CC_IPV4_MSG_SET_PACKETS_TO_DRAIN: 
        {
            ix_uint16 *pData = (ix_uint16*)pMsg;
            err = ix_cc_ipv4_set_packets_to_drain(*pData,arg_pContext);
            noResponse = IX_CC_IPV4_SEND_NO_RESPONSE;
            break; 
        }
        case IX_CC_IPV4_MSG_GET_STATISTICS: 
        {
            msgRetLength = sizeof(ix_cc_ipv4_stats_data);
            err = ix_cc_ipv4_get_statistics(&msgRetData.statsData,arg_pContext);
            pRetMsg = (void*)&msgRetData.statsData;
            break; 
        }
        default:
           IX_ERROR_CRT(ix_rm_buffer_free_chain(arg_hDataToken),IX_CC_IPV4_ERROR_BUFFER_FREE,0);  
           return IX_ERROR_WARNING(IX_CC_ERROR_UNDEFINED_MSG,
                                     ("Invalid Message Type"));
           break;
    }/* end switch(arg_UserData) */


    if(noResponse == IX_CC_IPV4_SEND_NO_RESPONSE)
    {
        IX_ERROR_CRT(ix_rm_buffer_free_chain(arg_hDataToken),IX_CC_IPV4_ERROR_BUFFER_FREE,0);  
        return IX_SUCCESS;
    }/* end if no need to send message to msg support lib*/


    /* send return message, length and retrieved context to message support library */
    err = ix_cc_msup_send_reply_msg(pContext,pRetMsg,msgRetLength,err);
    if(err != IX_SUCCESS)
    {
        err = IX_ERROR_WARNING(IX_CC_IPV4_ERROR_MSG_LIBRARY,
                                   ("Send reply message failed"));
    }/* endif (err != IX_SUCCESS) */

    IX_ERROR_CRT(ix_rm_buffer_free_chain(arg_hDataToken),IX_CC_IPV4_ERROR_BUFFER_FREE,0);
    return err;

} /* end ix_cc_ipv4_msg_handler */





/**
 * NAME: _ix_cc_ipv4_cb_genaral
 *
 * DESCRIPTION: This is a general callback function.Message support library 
 * calls this function to return the status of the requested asynchrouns operation 
 * @Param:  - IN  arg_Result: result of the asynchronous operation
 * @Param:  - IN  arg_pContext: context provided by caller
 * @Param:  - IN  arg_pMsg: return message
 * @Param:  - IN  arg_MsgLength: length of the message
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CALLBACK - user callback returns error message
 * 
 */

ix_error _ix_cc_ipv4_cb_general(ix_error arg_Result,
                               void* arg_pContext,
                               void* arg_pMsg,
                               ix_uint32 arg_MsgLength)
{

    ix_error err = IX_SUCCESS;
 
    ix_cc_ipv4_general_callback_data* pCbData = NULL;
 
    pCbData = (ix_cc_ipv4_general_callback_data*)arg_pContext;
   
    if(pCbData != NULL)
    {
        err = pCbData->pUserCallback(arg_Result,pCbData->pUserContext);
        ix_ossl_free(arg_pContext);
        if(err != IX_SUCCESS)
        {
            return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_CALLBACK,
                                      ("general callback failed"));
        }/* end if (err != IX_SUCCESS) */
    }/* end if(pCbData != NULL) */
       
    return IX_SUCCESS;
}/* _ix_cc_ipv4_cb_general */




/**
 * NAME: _ix_cc_ipv4_cb_lookup_rtm
 *
 * DESCRIPTION: This is a callback function for lookup rtm and get next hop message helpers. Message support library 
 * calls this function to return the status of the requested asynchrouns operation 
 * @Param:  - IN  arg_Result: result of the asynchronous operation
 * @Param:  - IN  arg_pContext: context provided by caller
 * @Param:  - IN  arg_pMsg: return message
 * @Param:  - IN  arg_MsgLength: length of the message
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CALLBACK - user callback returns error message
 * 
 */

ix_error _ix_cc_ipv4_cb_lookup_rtm(ix_error arg_Result,
                                  void* arg_pContext,
                                  void* arg_pMsg,
                                  ix_uint32 arg_MsgLength)
{


    ix_error err = IX_SUCCESS;
 
    ix_cc_ipv4_lookup_callback_data* pCbData = NULL;
    ix_cc_rtmv4_next_hop_info* pNextHopInfo = NULL;



    pCbData = (ix_cc_ipv4_lookup_callback_data*)arg_pContext;
    pNextHopInfo = (ix_cc_rtmv4_next_hop_info*)arg_pMsg;
    
   
    if(pCbData != NULL)
    {
        err = pCbData->pUserCallback(arg_Result,pCbData->pUserContext,pNextHopInfo);
        ix_ossl_free(arg_pContext);
        if(err != IX_SUCCESS)
        {
            return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_CALLBACK,
                                      ("lookup callback failed"));
        }/* end if (err != IX_SUCCESS) */
    }/* end if(pCbData != NULL)*/
       
    return IX_SUCCESS;
}/* _ix_cc_ipv4_cb_lookup_rtm */





/**
 * NAME: _ix_cc_ipv4_cb_dump_rtm
 *
 * DESCRIPTION: This is a callback function for dump(routes/next hops) message helpers. Message support library 
 * calls this function to return the status of the requested asynchrouns operation 
 * @Param:  - IN  arg_Result: result of the asynchronous operation
 * @Param:  - IN  arg_pContext: context provided by caller
 * @Param:  - IN  arg_pMsg: return message
 * @Param:  - IN  arg_MsgLength: length of the message
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CALLBACK - user callback returns error message
 * 
 */

ix_error _ix_cc_ipv4_cb_dump_rtm(ix_error arg_Result,
                               void* arg_pContext,
                               void* arg_pMsg,
                               ix_uint32 arg_MsgLength)
{

    ix_error err = IX_SUCCESS;
 
    ix_cc_ipv4_dump_callback_data* pCbData = NULL;
    ix_cc_ipv4_dump_data* pDumpData = NULL;


    pCbData = (ix_cc_ipv4_dump_callback_data*)arg_pContext;
    pDumpData = (ix_cc_ipv4_dump_data*)arg_pMsg;
   
    if(pCbData != NULL)
    {
        err = pCbData->pUserCallback(arg_Result,pCbData->pUserContext,pDumpData);
        ix_ossl_free(arg_pContext);
        ix_ossl_free(pDumpData->pBuffer);
        if(err != IX_SUCCESS)
        {
            return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_CALLBACK,
                                      ("dump callback failed"));
        }/* end if (err != IX_SUCCESS) */

    }/* end if (pCbData != NULL)*/
       
    return IX_SUCCESS;
}/* _ix_cc_ipv4_cb_dump_rtm */





/**
 * NAME: _ix_cc_ipv4_cb_icmp
 *
 * DESCRIPTION: This is a callback function for ICMP message helpers. Message support library 
 * calls this function to return the status of the requested asynchrouns operation 
 * @Param:  - IN  arg_Result: result of the asynchronous operation
 * @Param:  - IN  arg_pContext: context provided by caller
 * @Param:  - IN  arg_pMsg: return message
 * @Param:  - IN  arg_MsgLength: length of the message
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CALLBACK - user callback returns error message
 * 
 */

ix_error _ix_cc_ipv4_cb_icmp(ix_error arg_Result,
                                     void* arg_pContext,
                                     void* arg_pMsg,
                                     ix_uint32 arg_MsgLength)
{
    ix_error err = IX_SUCCESS;
    ix_cc_ipv4_icmp_callback_data* pCbData = NULL;
    ix_uint16* pRetData;



    pCbData = (ix_cc_ipv4_icmp_callback_data*)arg_pContext;
    pRetData = (ix_uint16*)arg_pMsg;
   
    if(pCbData != NULL)
    {
        err = pCbData->pUserCallback(arg_Result,pCbData->pUserContext,*pRetData);
        ix_ossl_free(arg_pContext);
        if(err != IX_SUCCESS)
        {        
            return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_CALLBACK,
                                      ("icmp callback failed"));
        }/* end if (err != IX_SUCCESS) */
    }/* end if (pCbData != NULL)*/
       
    return IX_SUCCESS;
}/* _ix_cc_ipv4_cb_icmp */


/**
 * NAME: _ix_cc_ipv4_cb_statistics
 *
 * DESCRIPTION: This is a callback function for statistics message helper. Message support library 
 * calls this function to return the status of the requested asynchrouns operation 
 * @Param:  - IN  arg_Result: result of the asynchronous operation
 * @Param:  - IN  arg_pContext: context provided by caller
 * @Param:  - IN  arg_pMsg: return message
 * @Param:  - IN  arg_MsgLength: length of the message
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CALLBACK - user callback returns error message
 * 
 */

ix_error _ix_cc_ipv4_cb_statistics(ix_error arg_Result,
                                      void* arg_pContext,
                                      void* arg_pMsg,
                                      ix_uint32 arg_MsgLength)
{

    ix_error err = IX_SUCCESS;
 
    ix_cc_ipv4_statistics_callback_data* pCbData = NULL;
    ix_cc_ipv4_stats_data* pStatsData = NULL;


    pCbData = (ix_cc_ipv4_statistics_callback_data*)arg_pContext;
    pStatsData = (ix_cc_ipv4_stats_data*)arg_pMsg;
   
    if(pCbData != NULL)
    {
        err = pCbData->pUserCallback(arg_Result,pCbData->pUserContext,pStatsData);
        ix_ossl_free(arg_pContext);
        if(err != IX_SUCCESS)
        {        
            return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_CALLBACK,
                                      ("statistics callback failed"));
        }/* end if (err != IX_SUCCESS) */    

    }/* end if (pCbData != NULL)*/
       
    return IX_SUCCESS;
}/* _ix_cc_ipv4_cb_statistics */


