/**
 * ============================================================================
 * = 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 - library primitives
 *
 * = FILENAME
 *      ix_cc_ipv4_library.c
 *
 * = DESCRIPTION
 *      The file defines library interface functions.
 *
 * = AUTHOR
 *       Govindan Nair
 *       govindan.nair@intel.com
 *
 * = AKNOWLEDGEMENTS
 *      
 *
 * = CREATION TIME
 *      07/09/2002
 *
 * = CHANGE HISTORY
 *
 * ============================================================================
 */


#define IX_ERROR_FILE_IDENT "$Id: ix_cc_ipv4_library.c,v 1.21 2003/11/01 03:10:59 rranjeet Exp $";



/**
 * System defined include files
 */


/**
 * User defined include files
 */

#include "ix_cc_error.h"
#include "ix_rm.h"
#include "ix_ossl.h"
#include "ix_netmacros.h"
#include "cc/ix_cc_rtmv4.h"

#include "ix_cc.h"
#include "bindings.h"
#include "ipv4_fwder_uc.h"
#include "cc/ix_cc_ipv4.h"
#include "cc/ipv4/internal/ix_cc_ipv4_msg_handler.h"
#include "cc/ipv4/internal/ix_cc_ipv4_prop.h"
#include "cc/ipv4/internal/ix_cc_ipv4_init.h"
#include "cc/ipv4/internal/icmp.h"






/**
 * Preprocessor symbols and Macros used in this file
 */

/**
 * Type definitions whose scope is limited to this file
 */

extern ix_uint16 g_IcmpSleepTime;
extern ix_uint16 g_IcmpQueueDrain;
extern ix_uint16 g_IcmpQueueDepth;
extern ix_cc_ipv4_context* g_pIpv4Context;

/**
 * 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_add_route
 *
 * DESCRIPTION:This library primitive helps to add a route in RTM. 
 * This API internally calls ix_cc_rtmv4_add_route API of RTM core component to add route in RTM database.
 * 
 * @Param:  - IN arg_IpAddr: network IP address identifying the route.
 * @Param:  - IN arg_NetMask: network mask for the route.
 * @Param:  - IN arg_NextHopId: next hop identifier for route.
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_ENTRY_NOT_FOUND - invalid next hop identifier
 * IX_CC_ERROR_DUPLICATE_ROUTE - route was already added to this NHID
 * IX_CC_ERROR_CONFLICTING_ROUTE - route was already added to another NHID
 * IX_CC_IPV4_ERROR_RTM - RTM internal failure
 * 
 */

ix_error ix_cc_ipv4_add_route(ix_uint32 arg_IpAddr,
                              ix_uint32 arg_NetMask,
                              ix_cc_rtmv4_nhid arg_NextHopId,
                              void *arg_pContext
                             )
{
    ix_error err = IX_SUCCESS;

    IX_ERROR_C(ix_cc_rtmv4_add_route(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                arg_IpAddr,
                                arg_NetMask,
                                arg_NextHopId), err);
    if(err != IX_SUCCESS)
    {
        switch(IX_ERROR_GET_CODE(err))
        {
            case IX_CC_ERROR_ENTRY_NOT_FOUND:
            case IX_CC_ERROR_DUPLICATE_ENTRY:
            case IX_CC_ERROR_CONFLICTING_ENTRY:
		return err;

            default:
            	return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM);
        }/* switch (err) */
    }/* end if (err != IX_SUCCESS) */     

   

    return err;

} /* end ix_cc_ipv4_add_route */





/**
 * NAME: ix_cc_ipv4_delete_route
 *
 * DESCRIPTION: This library primitive helps to delete a route from RTM. 
 * This API internally calls ix_cc_rtmv4_delete_route API of RTM core component to delete route from RTM database.
 * 
 * @Param:  - IN arg_IpAddr: network IP address identifying the route
 *
 * @Param:  - IN arg_NetMask: network mask for the route
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_ENTRY_NOT_FOUND - entry not found in RTM
 * IX_CC_IPV4_ERROR_RTM - RTM internal failure
 * 
 */

ix_error ix_cc_ipv4_delete_route(ix_uint32 arg_IpAddr,
                                 ix_uint32 arg_NetMask,
                                 void *arg_pContext
                                )
{

    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;


    IX_ERROR_C(ix_cc_rtmv4_delete_route(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                        arg_IpAddr,
                                        arg_NetMask),err);

    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        if(errCode == IX_CC_ERROR_ENTRY_NOT_FOUND)
        {
            return err;
        }/* end if (err == IX_CC_ERROR_ENTRY_NOT_FOUND) */
        else
        {
 	    return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM); 
        }/* end else(err == IX_CC_ERROR_ENTRY_NOT_FOUND) */
    }/* end if (err != IX_SUCCESS) */     

   
    return err;

} /* end ix_cc_ipv4_delete_route */



/**
 * NAME: ix_cc_ipv4_update_route
 *
 * DESCRIPTION:This library primitive helps to update a route in RTM. 
 * This API internally calls ix_cc_rtmv4_update_route API of RTM core component to 
 * update a route in RTM database. 
 * 
 * @Param:  - IN arg_IpAddr: network IP address for the route to be updated
 * @Param:  - IN arg_NetMask: network mask for the route to be updated
 * @Param:  - IN arg_NextHopId: hop identifier for route to be updated
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_ENTRY_NOT_FOUND - invalid next hop identifier/route
 * IX_CC_IPV4_ERROR_INVALID_MASK - invalid netmask
 * IX_CC_ERROR_CONFLICTING_ENTRY - route was already added to another NHID
 * IX_CC_IPV4_ERROR_RTM - RTM internal failure
 * 
 */

ix_error ix_cc_ipv4_update_route(ix_uint32 arg_IpAddr,
                              ix_uint32 arg_NetMask,
                              ix_cc_rtmv4_nhid arg_NextHopId,
                              void *arg_pContext
                             )
{
    ix_error err = IX_SUCCESS;

    IX_ERROR_C(ix_cc_rtmv4_update_route(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                        arg_IpAddr,
                                       arg_NetMask,
                                       arg_NextHopId), err);
    if(err != IX_SUCCESS)
    {
        switch(IX_ERROR_GET_CODE(err))
        {
            case IX_CC_ERROR_ENTRY_NOT_FOUND:
            case IX_CC_ERROR_CONFLICTING_ENTRY:
		return err;
            case IX_CC_RTMV4_ERROR_INVALID_MASK:
            	return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_INVALID_MASK);
            default:
            	return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM);
        }/* switch (err) */
    }/* end if (err != IX_SUCCESS) */ 

    return err;

} /* end ix_cc_ipv4_update_route */





/**
 * NAME: ix_cc_ipv4_lookup_route
 *
 * DESCRIPTION: This primitive helps a client to look up routing information for
 * a given IP address. This internally call ix_cc_rtmv4_lookup to get lookup result from RTM.
 * 
 * @Param:  - IN arg_IpAddr: network IP address to be looked up.
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT arg_pNextHopInfo - next hop information result for the given IP address
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null pinter
 * IX_CC_IPV4_ERROR_RTM - RTM internal error
 * 
 */

ix_error ix_cc_ipv4_lookup_route(ix_uint32 arg_IpAddr,
                                 ix_cc_rtmv4_next_hop_info* arg_pNextHopInfo,
                                 void *arg_pContext
                                )
{
    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;
    

    IX_ERROR_C(ix_cc_rtmv4_lookup(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                   arg_IpAddr,
                                   arg_pNextHopInfo),err);


    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        if(errCode == IX_CC_ERROR_NULL)
        {
            return err;
        }/* end if (err == IX_CC_ERROR_NULL) */
        else
        {
            return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM); 
        }/* end else(err == IX_CC_ERROR_NULL) */
    }/* end if (err != IX_SUCCESS) */     

 
    return err;

} /* end ix_cc_ipv4_lookup_route */




/**
 * NAME: ix_cc_ipv4_purge_routes
 *
 * DESCRIPTION: This primitive helps a client to remove all routes from RTM.
 * 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null pointer
 * IX_CC_ERROR_ALIGN - pointer not aligned properly
 * IX_CC_IPV4_ERROR_RTM - RTM failure
 */

ix_error ix_cc_ipv4_purge_routes(void *arg_pContext)
{
    IX_ERROR_CR(ix_cc_rtmv4_purge_routes(((ix_cc_ipv4_context*)arg_pContext)->hRtm));
    
    /* Add invalid routes */
   IX_ERROR_CR(_ix_cc_ipv4_add_invalid_routes());

    return IX_SUCCESS;
} /* end ix_cc_ipv4_purge_routes */




/**
 * NAME: ix_cc_ipv4_dump_routes
 *
 * DESCRIPTION: This primitive helps to dump all routes of RTM in memory
 * Client shall use IX_CC_RTMV4_DUMP_ROUTE_SIZE to determine how many bytes to allocate.
 * 
 * @Param:  - IN arg_pBuffer - pointer to a block of memory where routes are to be stored.
 * @Param:  - IN arg_Size - size of buffer in bytes.
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null pointer
 * IX_CC_ERROR_ALIGN - pointer not aligned properly
 * IX_CC_ERROR_FULL -  buffer is too small
 */

ix_error ix_cc_ipv4_dump_routes(char* arg_pBuffer,
                                ix_uint32 arg_Size,
                                void *arg_pContext
                               )
{

    if(arg_pBuffer == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                                  ("Null Pointer: arg_pNextHopInfo"));
 
    }/* end if (err != IX_SUCCESS) */  
 
    IX_ERROR_CR(ix_cc_rtmv4_dump_routes(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                        arg_pBuffer,
                                        arg_Size));
    return IX_SUCCESS;
} /* end ix_cc_ipv4_dump_routes */







/**
 * NAME: ix_cc_ipv4_add_next_hop
 *
 * DESCRIPTION: This primitive helps a client to add next hop information to RTM database.
 * Client needs to add next hop to RTM in order to add routes referring to that next hop. 
 * 
 * 
 * @Param:  - IN arg_NextHopId: identifier of next hop to be added.
 * @Param:  - IN arg_pNextHopData: defined by RTM
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT  none 
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - invalid pointer
 * IX_CC_ERROR_DUPLICATE_ENTRY - next hop was already added to this NHID
 * IX_CC_ERROR_CONFLICTING_ENTRY - next hop was already added to another NHID
 * IX_CC_IPV4_ERROR_RTM - RTM internal failure
 * IX_CC_IPV4_ERROR_INVALID_NH_INFO - invalid next hop information
 */

ix_error ix_cc_ipv4_add_next_hop(
                               ix_cc_rtmv4_nhid arg_NextHopId,
                               ix_cc_rtmv4_next_hop_info* arg_pNextHopInfo,
                               void *arg_pContext)
{
    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;
    
    if(arg_pNextHopInfo == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                                  ("Null Pointer: arg_pNextHopInfo"));
 
    }/* end if(arg_pNextHopInfo == NULL) */     
 
    IX_ERROR_C(ix_cc_rtmv4_add_next_hop(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                        arg_NextHopId,
                                        arg_pNextHopInfo),
                                        err);

    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        switch(errCode)
        {
            case IX_CC_RTMV4_ERROR_INVALID_NH_INFO:
                return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_INVALID_NH_INFO);
                break;
            case IX_CC_ERROR_DUPLICATE_ENTRY:
            case IX_CC_ERROR_CONFLICTING_ENTRY:
                return err;
                break;
            default:
                return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM);
                break;

        }/* switch (err) */
    }/* end if (err != IX_SUCCESS) */     

    return err;
} /* end ix_cc_ipv4_add_next_hop */





/**
 * NAME: ix_cc_ipv4_delete_next_hop
 *
 * DESCRIPTION: This primitive helps a client to delete next hop information from RTM database. 
 * Client needs to remove all routes associated with next hop before calling this primitive. 
 * If not, client gets an error.This API internally calls ix_cc_rtmv4_delete_next_hop API of RTM
 * to delete next hop information from RTM.
 * 
 * @Param:  - IN arg_NextHopId: identifier of next hop to be removed.
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT -none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_RTM - RTM internal failure
 * IX_CC_ERROR_ENTRY_NOT_FOUND - invalid next hop id
 * IX_CC_IPV4_ERROR_NEXT_HOP_ID_IN_USE -next hop id is in use
 */

ix_error ix_cc_ipv4_delete_next_hop(ix_cc_rtmv4_nhid arg_NextHopId,
                                    void *arg_pContext)
{
    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;


    IX_ERROR_C(ix_cc_rtmv4_delete_next_hop(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                      arg_NextHopId),
                                      err);

    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        switch(errCode)
        {
            case IX_CC_ERROR_ENTRY_NOT_FOUND:
                return err;
                break;
            case IX_CC_RTMV4_ERROR_NHID_IN_USE:
                return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_NEXT_HOP_ID_IN_USE);
                break;
            default:
                return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM);
                break;

        }/* switch (err) */
    }/* end if (err != IX_SUCCESS) */     

    return err;

} /* end ix_cc_ipv4_delete_next_hop */



/**
 * NAME: ix_cc_ipv4_update_next_hop
 *
 * DESCRIPTION: This primitive helps a client to update next hop information to RTM database.
 * 
 * @Param:  - IN arg_NextHopId: identifier of next hop to be updated.
 * @Param:  - IN arg_pNextHopInfo: next hop information to be updated
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT  none 
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - invalid pointer
 * IX_CC_IPV4_ERROR_RTM - RTM internal failure
 * IX_CC_IPV4_ERROR_INVALID_NH_INFO - invalid next hop information
 * IX_CC_ERROR_ENTRY_NOT_FOUND - invalid next hop id
 */

ix_error ix_cc_ipv4_update_next_hop(
                               ix_cc_rtmv4_nhid arg_NextHopId,
                               ix_cc_rtmv4_next_hop_info* arg_pNextHopInfo,
                               void *arg_pContext)
{
    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;
    
    if(arg_pNextHopInfo == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                                  ("Null Pointer: arg_pNextHopInfo"));
 
    }/* end if(arg_pNextHopInfo == NULL) */     
 
    IX_ERROR_C(ix_cc_rtmv4_update_next_hop(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                        arg_NextHopId,
                                        arg_pNextHopInfo),
                                        err);

    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        switch(errCode)
        {
            case IX_CC_RTMV4_ERROR_INVALID_NH_INFO:
                return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_INVALID_NH_INFO);
                break;
            case IX_CC_ERROR_ENTRY_NOT_FOUND:
                return err;
                break;
            default:
                return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM);
                break;

        }/* switch (err) */
    }/* end if (err != IX_SUCCESS) */     

    return err;
} /* end ix_cc_ipv4_update_next_hop */



/**
 * NAME: ix_cc_ipv4_get_next_hop
 *
 * DESCRIPTION:This library primitive helps to retrieve next hop information from RTM.
 * This API internally calls ix_cc_rtmv4_get_next_hop API of RTM core component to 
 * retrieve next hop information. 
 * 
 * @Param:  - IN arg_NextHopId: Identifier of the next hop information to be retrieved from RTM.
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT arg_pNextHopInfo: Result will be placed into this structure
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_RTM - RTM internal failure
 * IX_CC_ERROR_ENTRY_NOT_FOUND - invalid next hop id
 * IX_CC_ERROR_NULL - null pointer
 */

ix_error ix_cc_ipv4_get_next_hop(ix_cc_rtmv4_nhid arg_NextHopId,
                                 ix_cc_rtmv4_next_hop_info* arg_pNextHopInfo,
                                 void *arg_pContext
                                )
{
    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;

    if(arg_pNextHopInfo == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                                  ("Null Pointer: arg_pNextHopInfo"));
 
    }/* end if(arg_pNextHopInfo == NULL) */     

    IX_ERROR_C(ix_cc_rtmv4_get_next_hop(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                   arg_NextHopId,
                                   arg_pNextHopInfo),
                                   err);

  
    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        if(errCode == IX_CC_ERROR_ENTRY_NOT_FOUND)
        {
            return err;
        }/* end if (err == IX_CC_RTMV4_ERROR_INVALID_NHID) */
        else
        {
            return IX_ERROR_SET_CODE(err, IX_CC_IPV4_ERROR_RTM);
 
        }/* end else(err == IX_CC_RTMV4_ERROR_INVALID_NHID) */
    }/* end if (err != IX_SUCCESS) */     
    return err;
} /* end ix_cc_ipv4_get_next_hop */


/**
 * NAME: ix_cc_ipv4_purge_rtm
 *
 * DESCRIPTION: This primitive helps a client to remove all routes and next hops from RTM database.
 * 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_RTM - RTM failure
 * 
 */

ix_error ix_cc_ipv4_purge_rtm(void *arg_pContext)
{

    IX_ERROR_CRT(ix_cc_rtmv4_purge(((ix_cc_ipv4_context*)arg_pContext)->hRtm),
                 IX_CC_IPV4_ERROR_RTM, 0);

    /* Add reserved next hops */
    IX_ERROR_CR(_ix_cc_ipv4_add_reserved_next_hops());

    /* Add invalid routes */
    IX_ERROR_CR(_ix_cc_ipv4_add_invalid_routes());

    return IX_SUCCESS;
} /* end ix_cc_ipv4_purge_rtm */


/**
 * NAME: ix_cc_ipv4_dump_next_hops
 *
 * DESCRIPTION: This API internally calls ix_cc_rtmv4_dump_next_hop API of RTM core component. 
 * Client shall use IX_CC_RTMV4_DUMP_NEXT_HOP_SIZE to determine how many bytes to allocate.
 * 
 * @Param:  - IN arg_pBuffer - pointer to a block of memory where next hops are to be stored.
 * @Param:  - IN arg_Size - size of buffer in bytes
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null pointer
 * IX_CC_ERROR_ALIGN - pointer not aligned properly
 * IX_CC_ERROR_FULL -  buffer is too small
 * 
 */

ix_error ix_cc_ipv4_dump_next_hops(char* arg_pBuffer,
                                   ix_uint32 arg_Size,
                                   void *arg_pContext
                                  )
{
    if(arg_pBuffer == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL, ("Null pointer: arg_pBuffer"));
    }/* end if (err != IX_SUCCESS) */     

 
    IX_ERROR_CR(ix_cc_rtmv4_dump_next_hops(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                     arg_pBuffer,
                                     arg_Size));
      return IX_SUCCESS;
} /* end ix_cc_ipv4_dump_next_hops */



/**
 * NAME: ix_cc_ipv4_set_mtu
 *
 * DESCRIPTION: This primitive helps client to update MTU for a given next hop. 
 * Before calling this, client needs to call ix_cc_ipv4_add_next_hop to add next hop 
 * identifier in RTM database. The validity of MTU shall be done by the client.
 * 
 * @Param:  - IN arg_NextHopId: identifier of next hop.
 * @Param:  - IN arg_Mtu: new maximum transmission unit for the given next hop.
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 *
 * IX_CC_IPV4_ERROR_RTM - RTM failure
 * IX_CC_ERROR_ENTRY_NOT_FOUND - invalid next hop id 
 * IX_CC_IPV4_ERROR_INVALID_NH_INFO - invalid mtu
 */

ix_error ix_cc_ipv4_set_mtu(ix_cc_rtmv4_nhid arg_NextHopId,
                            ix_uint32 arg_Mtu,
                            void *arg_pContext
                           )
{
    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;


    err = ix_cc_rtmv4_set_mtu(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                              arg_NextHopId,
                              arg_Mtu);
                             

  
    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        switch(errCode)
        {
            case IX_CC_ERROR_ENTRY_NOT_FOUND:
            return err;
            break;
            case IX_CC_RTMV4_ERROR_INVALID_NH_INFO:
            return IX_ERROR_SET_CODE(err,IX_CC_IPV4_ERROR_INVALID_NH_INFO);
            break;
            default:
            return IX_ERROR_SET_CODE(err,IX_CC_IPV4_ERROR_RTM);
            break; 
        }/* end switch(err) */
    }/* end if (err != IX_SUCCESS) */     
    return err;

} /* end ix_cc_ipv4_set_mtu  */





/**
 * NAME: ix_cc_ipv4_set_flags
 *
 * DESCRIPTION:This primitive helps client to update flags for a given next hop.
 * Before calling this primitive, client needs to call ix_cc_ipv4_add_next_hop to 
 * add next hop identifier in RTM database. 
 * 
 * @Param:  - IN arg_NextHopId: identifier of next hop.
 * @Param:  - IN arg_Flags: new flags for the given next hop 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_RTM - RTM failure
 * IX_CC_ERROR_ENTRY_NOT_FOUND - invalid next hop id 
 * IX_CC_IPV4_ERROR_INVALID_FLAGS - invalid flags 
 * 
 */

ix_error ix_cc_ipv4_set_flags(ix_cc_rtmv4_nhid arg_NextHopId,
                              ix_uint32 arg_Flags,
                              void *arg_pContext
                             )
{
    ix_uint32 errCode;
    ix_error err = IX_SUCCESS;



    if((arg_Flags !=IPV4_NH_FLAGS_LOCAL_BIT) &&
      (arg_Flags !=IPV4_NH_FLAGS_DOWN_BIT) &&
      (arg_Flags !=IPV4_NH_FLAGS_DROP_BIT) &&
      (arg_Flags !=IPV4_NH_FLAGS_BROADCAST_BIT) &&
      (arg_Flags !=IPV4_NH_FLAGS_MULTICAST_BIT))
    {
        err = IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_FLAGS,
                                       ("Invalid flags"));
        return err;
    }/* end if flags bit */


    err = ix_cc_rtmv4_set_flags(((ix_cc_ipv4_context*)arg_pContext)->hRtm,
                                arg_NextHopId,
                                arg_Flags);

  
    if(err != IX_SUCCESS)
    {
        errCode = IX_ERROR_GET_CODE(err);
        if(errCode == IX_CC_ERROR_ENTRY_NOT_FOUND)
        {
            return err;
        }/* end if (err == IX_CC_RTMV4_ERROR_INVALID_NHID) */
        else
        {
            return IX_ERROR_SET_CODE(err,IX_CC_IPV4_ERROR_RTM); 
        }/* end else(err == IX_CC_RTMV4_ERROR_INVALID_NHID) */
    }/* end if (err != IX_SUCCESS) */     
    return err;

} /* end ix_cc_ipv4_set_flags */



/**
 * NAME: ix_cc_ipv4_get_sleep_time
 *
 * DESCRIPTION: This library primitive helps to retrieve the number of seconds 
 * between when the event will fire causing the ICMP messages to be dequeued and sent. 
 * The lower the value of arg_pSleepTime, the more frequently the ICMP messages will be 
 * dequeued and sent.  
 * 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT arg_pSleepTime: ICMP sleep period 
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null pointer
 * 
 */

ix_error ix_cc_ipv4_get_sleep_time(ix_uint16* arg_pSleepTime,
                                   void *arg_pContext)
{
    
    if(arg_pSleepTime == NULL)
    {
  
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                               ("Invalid Pointer: arg_pSleepTime")); 
    }/* end if (arg_pSleepTime == NULL) */

    *arg_pSleepTime = g_IcmpSleepTime;
 
    return IX_SUCCESS;

} /* end ix_cc_ipv4_get_sleep_time  */



/**
 * NAME: ix_cc_ipv4_set_sleep_time
 *
 * DESCRIPTION: This library primitive helps to set the period between events firing to process 
 * the ICMP error message queue. The lower the value of arg_SleepTime, the more frequently
 * the output queue will be processed. The minimum value of arg_SleepTime is 1 sec and 
 * maximum value can be 32sec.
 * 
 * @Param:  - IN arg_SleepTime: the number of seconds to wait between processing
 * the ICMP error message queue.
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_INVALID_SLEEP_TIME - invalid sleep time
 * 
 */

ix_error ix_cc_ipv4_set_sleep_time(ix_uint16 arg_SleepTime,
                                   void *arg_pContext)
{

#ifndef IX_EXCLUDE_CCI
    ix_uint32 eventInterval;
    ix_cc_handle hEventHandle;
#endif
    if((arg_SleepTime < IX_CC_IPV4_ICMP_MIN_SLEEP_TIME) ||
      (arg_SleepTime > IX_CC_IPV4_ICMP_MAX_SLEEP_TIME))
    {
               
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_SLEEP_TIME,
            ("ICMP: ix_cc_ipv4_icmp_set_sleep_time: invalid parameters"));
    }
    ix_ossl_mutex_lock(((ix_cc_ipv4_context*)arg_pContext)->ipv4Mutex,IX_OSSL_WAIT_FOREVER);
    g_IcmpSleepTime = arg_SleepTime;   
    ix_ossl_mutex_unlock(((ix_cc_ipv4_context*)arg_pContext)->ipv4Mutex);

#ifndef IX_EXCLUDE_CCI
    /*Added the following function to fix SCR 4709 */
    hEventHandle = g_pIpv4Context->hEventHandle;
    /* Calculate event interval in milliseconds, data in g_IcmpSleepTime is in seconds */
    eventInterval = arg_SleepTime * IX_CC_IPV4_MILLISECONDS_PER_SECOND;

    IX_ERROR_CRT(ix_cci_change_event(hEventHandle,eventInterval),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);
#endif
   
    return IX_SUCCESS;

} /* end ix_cc_ipv4_set_sleep_time */





/**
 * NAME: ix_cc_ipv4_get_queue_depth
 *
 * DESCRIPTION: This library primitive helps to retrieves the depth of the ICMP error message 
 * queue. That is, the maximum number of ICMP messages that can fit in the queue, not the
 * number of messages currently in the queue.
 * 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT arg_pQueueDepth: the current number of entries that the ICMP error message queue can hold.
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null pointer
 * 
 */

ix_error ix_cc_ipv4_get_queue_depth(ix_uint16* arg_pQueueDepth,
                                    void *arg_pContext)
{
    if(arg_pQueueDepth == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                               ("Invalid pointer: arg_pQueueDepth"));
    }/* end if(arg_pQueueDepth == NULL)  */

    *arg_pQueueDepth = g_IcmpQueueDepth;

    return IX_SUCCESS;

} /* end ix_cc_ipv4_get_queue_depth  */




/**
 * NAME: ix_cc_ipv4_get_packets_to_drain
 *
 * DESCRIPTION:This library primitive helps to retrieve the maximum number of ICMP error messages
 * to send (from the ICMP message queue ) each time the queue processing event fires. 
 * 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT arg_pPacketsToDrain: the maximum number of packets to send each time the 
 * event fires for processing the queue.  
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - invalid pointer
 * 
 */

ix_error ix_cc_ipv4_get_packets_to_drain(ix_uint16* arg_pPacketsToDrain,
                                         void *arg_pContext)
{
    if(arg_pPacketsToDrain == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                               ("Invalid pointer: arg_pPacketsToDrain "));
    }/* end if(arg_pPacketsToDrain == NULL)  */

    *arg_pPacketsToDrain = g_IcmpQueueDrain;

    return IX_SUCCESS;

} /* end ix_cc_ipv4_get_packets_to_drain  */




/**
 * NAME: ix_cc_ipv4_set_packets_to_drain
 *
 * DESCRIPTION: This library primitive helps to set the maximum number of ICMP error messages 
 * to send each time the queue processing event fires. The value of arg_PacketsToDrain
 * must not exceed the depth of the queue.
 * 
 * @Param:  - IN arg_PacketsToDrain: The maximum number of packets to send each time the queue processing
 * event fires. 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_INVALID_PACKETS_TO_DRAIN - invalid value
 * 
 */

ix_error ix_cc_ipv4_set_packets_to_drain(ix_uint16 arg_PacketsToDrain,
                                         void *arg_pContext)
{
    if ((arg_PacketsToDrain < 1) || (arg_PacketsToDrain > g_IcmpQueueDepth))
    {
        
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_PACKETS_TO_DRAIN,
            ("ICMP: ix_cc_ipv4_set_packets_to_drain invalid parameter: %d\n",arg_PacketsToDrain));
        
    }
    ix_ossl_mutex_lock(((ix_cc_ipv4_context*)arg_pContext)->ipv4Mutex,IX_OSSL_WAIT_FOREVER);
    g_IcmpQueueDrain = arg_PacketsToDrain;
    ix_ossl_mutex_unlock(((ix_cc_ipv4_context*)arg_pContext)->ipv4Mutex);
    
    return IX_SUCCESS;

} /* end ix_cc_ipv4_set_packets_to_drain */





/**
 * NAME: ix_cc_ipv4_get_statistics
 *
 * DESCRIPTION: This library primitive helps to retrieve statistics report from IPV4 Forwarder 
 * core component. This primitive will give the statistics of IPV4 microblock, RTM and 
 * IPV4 Forwarder core component. Client needs to allocate memory to hold data.
 * 
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT arg_pBuffer: pointer to memory to hold statistics data.
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - null pointer
 * IX_CC_IPV4_ERROR_RTM  - RTM failure
 * IX_CC_ERROR_INTERNAL - internal failure
 */

ix_error ix_cc_ipv4_get_statistics(ix_cc_ipv4_stats_data* arg_pBuffer,
                                   void *arg_pContext)
{
    ix_cc_rtmv4_statistics rtmStats;
    ix_uint32 index;
    ix_uint64 mbStats[IX_CC_IPV4_NUMBER_OF_MB_COUNTERS];
    ix_error err = IX_SUCCESS;

	/* In uCode we have ipv4 statistics per port
    we have to change it in Core Components so that no iligal use of 
    SCRATCH is done. This may be a temporary solution */
    ix_uint32 portIndex;
    ix_uint64 mbCounter;


    if(arg_pBuffer == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                               ("Invalid pointer: arg_pBuffer "));
    }/* end if(arg_pPacketsToDrain == NULL)  */


    /* Fillup buffer with ICMP statistics */
    arg_pBuffer->ipv4CoreInvalidHeaderPkts = g_pIpv4Context->ipv4FwdStats.ipv4CorestatsInvalidHeader;
    /* Fillup buffer with IPv4 Forwarder statistics */
    arg_pBuffer->ipv4CoreInvalidAddressPkts = g_pIpv4Context->ipv4FwdStats.ipv4CorestatsInvalidAddress;
    arg_pBuffer->ipv4CoreRcvdPkts = g_pIpv4Context->ipv4FwdStats.ipv4CorestatsIncomingDatagrams;
    arg_pBuffer->ipv4CoreFwdPkts = g_pIpv4Context->ipv4FwdStats.ipv4CorestatsForwardingAttempted;
    arg_pBuffer->ipv4CoreLocalDeliveryPkts = g_pIpv4Context->ipv4FwdStats.ipv4CorestatsLocalDelivery;
    arg_pBuffer->ipv4CoreNoRoutePkts = g_pIpv4Context->ipv4FwdStats.ipv4CorestatsNorouteFound;
    /* Get RTM statistics */
    err = ix_cc_rtmv4_get_statistics(((ix_cc_ipv4_context*)arg_pContext)->hRtm,&rtmStats);

    if(err != IX_SUCCESS)
    {
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_RTM,
                                ("Failed :ix_cc_rtmv4_get_statistics"));
    }/* end if (err != IX_SUCCESS) */ 
    /* Fillup buffer with RTM statistics */
    arg_pBuffer->ipv4NumberOfRoutes = rtmStats.numberOfRoutes;
    arg_pBuffer->ipv4NumberOfNextHops = rtmStats.numberOfNextHops;
    /* Get microblock statistics */
   
   /* In uCode we have ipv4 statistics per port
   we have to change it in Core Components so that no iligal use of 
   SCRATCH is done. This may be a temporary solution */

    for(index = 0; index < IX_CC_IPV4_NUMBER_OF_MB_COUNTERS;index++)
    {
	mbStats[index] = 0;
    }
	
    for (portIndex = 0; portIndex < MAX_NUMBER_OF_PORTS_PER_BLADE; portIndex++)
    {
	for(index = 0; index < IX_CC_IPV4_NUMBER_OF_MB_COUNTERS;index++)
    	{
    	    err = ix_rm_counter_64bit_get_value(
		((ix_cc_ipv4_context*)arg_pContext)->counter64BitHandle[portIndex].ahCounter64BitHandle[index],
                 &mbCounter);
    
	    mbStats[index] += mbCounter;

	    if(err != IX_SUCCESS)
      	    {
     	       return IX_ERROR_WARNING(IX_CC_ERROR_INTERNAL,
      	                              ("Failed :ix_rm_counter_64bit_get_value"));
       	    }/* end if (err != IX_SUCCESS) */ 
	}/* end for */
    }/* end for */


    /* Fillup buffer with microblock statistics */
    arg_pBuffer->ipv4MbRcvdPkts = mbStats[0];
    arg_pBuffer->ipv4MbFwdPkts = mbStats[1];
    arg_pBuffer->ipv4MbDropPkts = mbStats[2];
    arg_pBuffer->ipv4MbExcpPkts = mbStats[3];
    arg_pBuffer->ipv4MbBadHeaderPkts = mbStats[4];
    arg_pBuffer->ipv4MbBadTotalLengthPkts = mbStats[5];
    arg_pBuffer->ipv4MbBadTTLPkts = mbStats[6];
    arg_pBuffer->ipv4MbNoRoutePkts = mbStats[7];
    arg_pBuffer->ipv4MbLengthTooSmallPkts = mbStats[8];
   
    return IX_SUCCESS;
} /* end ix_cc_ipv4_get_statistics  */




/**
 * NAME: ix_cc_ipv4_set_property
 *
 * DESCRIPTION: This library primitive helps to set dynamic properties of 
 * IPv4 Forwarder core component. 
 * 
 * @Param:  - IN arg_PropId: Identifier of a property or properties(ORed) to be updated 
 * for a port
 * @Param:  - IN arg_pPropData: pointer to dynamic property data structure
 * @Param:  - IN arg_pContext: pointer to IPv4 context
 *
 * @Param:  - OUT - none
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * IX_CC_ERROR_NUL - invalid pointer
 * IX_ERROR_FULL - table is full
 * IX_CC_ERROR_ENTRY_NOT_FOUND - entry not found in table
 * IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM - inavlid property id
 */

ix_error ix_cc_ipv4_set_property(ix_uint32 arg_PropId,
                                 ix_cc_properties* arg_pPropData,
                                 void *arg_pContext)
{
    ix_uint32 ipAddr;
    ix_uint32 netMask;
    /* Validate arg_pPropData */
    if(arg_pPropData == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                ("Invalid pointer: arg_pPropData"));
    }/* end if (arg_PropData == NULL) */  

    if(((arg_PropId & IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4) != 
       IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4) &&
       ((arg_PropId & IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4) != 
       IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4) &&
       ((arg_PropId & IX_CC_SET_PROPERTY_PHYSICAL_IF_STATUS) != 
       IX_CC_SET_PROPERTY_PHYSICAL_IF_STATUS))
    {
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM,
                ("Invalid property Id"));

    }/* end if invalid property */ 
  
    /* arg_PropId can have multiple properties */  
    if((arg_PropId & IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4) == 
        IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4)
    {
        ix_uint32 loop_var;

        for (loop_var = 0;
             loop_var < arg_pPropData->no_virtual_if;
             loop_var++)
        {
            if (arg_pPropData->ip_prop[loop_var].ip_version
                == IX_CC_IP_VERSION_IPV4)
            {
                /* Convert IP Address into network byte order */
                ipAddr = IX_HTON32(arg_pPropData->ip_prop[loop_var].protocol.ipv4_prop.ipv4_address);
                netMask = IX_HTON32(arg_pPropData->ip_prop[loop_var].protocol.ipv4_prop.ipv4_subnet_mask);
                IX_ERROR_CR(_ix_cc_ipv4_property_update_ip_address(
                                IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4,
                                arg_pPropData->blade_id,
                                arg_pPropData->port_id,
                                ipAddr,
                                netMask));
            }
        }
    }/* end if add ipv4 address */

    if((arg_PropId & IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4) == 
        IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4)
    {
        ix_uint32 loop_var;

        for (loop_var = 0;
             loop_var < arg_pPropData->no_virtual_if;
             loop_var++)
        {
            if (arg_pPropData->ip_prop[loop_var].ip_version
                == IX_CC_IP_VERSION_IPV4)
            {
                /* Convert IP Address into network byte order */
                ipAddr = IX_HTON32(arg_pPropData->ip_prop[loop_var].protocol.ipv4_prop.ipv4_address);
                netMask = IX_HTON32(arg_pPropData->ip_prop[loop_var].protocol.ipv4_prop.ipv4_subnet_mask);
                IX_ERROR_CR(_ix_cc_ipv4_property_update_ip_address(
                                IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4,
                                arg_pPropData->blade_id,
                                arg_pPropData->port_id,
                                ipAddr,
                                netMask));
            }
        }
    }/* end if delete ipv4 address */

    if((arg_PropId & IX_CC_SET_PROPERTY_PHYSICAL_IF_STATUS) == IX_CC_SET_PROPERTY_PHYSICAL_IF_STATUS)
    {
        IX_ERROR_CR(_ix_cc_ipv4_property_update_port_status(arg_pPropData->port_id,
                                                     arg_pPropData->physical_if_state));
    }/* end if delete ipv4 address */
    
    return IX_SUCCESS;
} /* end ix_cc_ipv4_set_property */

