/**
 * ============================================================================
 * = 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 - dynamic properties table management
 *
 * = FILENAME
 *      ix_cc_ipv4_prop.c
 *
 * = DESCRIPTION
 *      The file defines dynamic properties table management interface functions.
 *
 * = AUTHOR
 *       Govindan Nair
 *       govindan.nair@intel.com
 *
 * = AKNOWLEDGEMENTS
 *      
 *
 * = CREATION TIME
 *      07/10/2002
 *
 * = CHANGE HISTORY
 *
 * ============================================================================
 */


#define IX_ERROR_FILE_IDENT "$Id: ix_cc_ipv4_prop.c,v 1.10 2003/04/23 20:39:28 ktseng 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 "ix_cc_properties.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_prop.h"
#include "cc/ipv4/internal/ix_cc_ipv4_dbcast.h"





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

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

/**
 * Variable declarations global to this file only. Externs are followed by 
 * static variables.
 */
extern ix_cc_ipv4_context* g_pIpv4Context;
extern ix_cc_ipv4_registry_data g_Ipv4RegistryData;
/** 
 * Extern function prototypes.
 */


/** 
 * Static function prototypes.
 */


/** 
 * Function definitions.
 */


/**
 * NAME: _ix_cc_ipv4_prop_get_port_ip_address
 *
 * DESCRIPTION: This primitive will be used to get IP address of a port
 *           .
 * 
 * @Param:  - IN arg_BladeId - blade number of ip address to be retrieved
 * @Param:  - IN arg_PortId - port number of ip address to be retrieved
 *
 * @Param:  - OUT arg_pIpAddress - IP address of given blade and port
 *
 * @Return: IX_SUCCESS if successfull or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM - invalid blade/port number
 * IX_CC_ERROR_ENTRY_NOT_FOUND - no data in location
 */

ix_error _ix_cc_ipv4_get_port_ip_address(
                                        ix_uint16 arg_BladeId,
                                        ix_uint16 arg_PortId, 
                                        ix_uint32 *arg_pIpAddr
                                       )
{


    ix_uint32 keyIndex;

    /* Validate Port and blade Ids */
    if((arg_BladeId > MAX_NUMBER_OF_BLADES - 1) ||
      (arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1))
    {
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM,
                                ("Invalid Blade Id % or Port Id %d",arg_BladeId,arg_PortId));
    }/* endif ((arg_BladeId > MAX_NUMBER_OF_BLADES - 1) ||
      (arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1))
      */

    /* Calculate keyIndex from Blade and Port Id */
    /* 6 bits for Blade Id(totally 64 blades) and each blade can have upto 16 ports */
    /* 4 bits to store portIds */
    keyIndex = (arg_BladeId << 4) | arg_PortId;
     
    /* store ipAddr from dynamic property table to arg_pIpAddr */
    if(g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr == 0)
    {
        *arg_pIpAddr = 0;
        return IX_ERROR_WARNING(IX_CC_ERROR_ENTRY_NOT_FOUND,
                                ("No Ip Address in location"));
    }
    else
    {
        *arg_pIpAddr = IX_NTOH32(g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr);
    }
    
    return IX_SUCCESS;
}/* end _ix_cc_ipv4_get_port_ip_address */



/**
 * NAME: _ix_cc_ipv4_prop_get_port_status
 *
 * DESCRIPTION: This primitive will be used to get status of local port
 *           .
 * 
 * @Param:  - IN arg_PortId - port number of status to be retrieved
 *
 * @Param:  - OUT arg_pPortStatus - status value of given port
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM - invalid port number
 * 
 */

ix_error _ix_cc_ipv4_get_port_status(
                                    ix_uint16 arg_PortId, 
                                    ix_uint32* arg_pPortStatus
                                   )
{
    ix_uint32 currentValue;
    ix_cc_ipv4_mb_ctrl* pData;

    /* Initialize arg_pPrortStatus with disable */
    *arg_pPortStatus = IX_CC_IPV4_DISABLE_PORT_STATUS;

    /* Validate Port Id */
    if(arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1)
    {
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM,
                                ("Invalid Port Id"));
    }/* endif (arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1)
      */

    pData = g_pIpv4Context->pMbCbBase;
/*    currentValue = IX_NTOH32(IX_IPV4_MEM_UINT32_READ(&pData->portForward)); */
    currentValue = IX_IPV4_MEM_UINT32_READ(&pData->portForward);
    currentValue = IX_NTOH32(currentValue);
    *arg_pPortStatus = (currentValue >> arg_PortId) & 1;
   
    return IX_SUCCESS;
}/* end _ix_cc_ipv4_get_port_status */



/**
 * NAME: _ix_cc_ipv4_property_update_port_status
 *
 * DESCRIPTION: This primitive will be used to set status of local port
 *           .
 * 
 * @Param:  - IN arg_PortId - port number 
 * @Param:  - IN arg_pPortStatus - status value of given port
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM - invalid port number
 * 
 */

ix_error _ix_cc_ipv4_property_update_port_status(
                                    ix_uint16 arg_PortId, 
                                    ix_uint32 arg_PortStatus
                                   )
{

    ix_uint32 portMask;
    ix_cc_ipv4_mb_ctrl* pData;
    ix_uint32 data;
    
    /* Validate Port Id */
    if(arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1)
    {
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM,
                                ("Invalid Port Id"));
    }/* endif (arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1)
      */

    portMask = 1 << (ix_uint32)arg_PortId;

    /* Calucate Port mask to set port status from pMbCbBase */
    pData = g_pIpv4Context->pMbCbBase;
    data = IX_IPV4_MEM_UINT32_READ(&pData->portForward);
    data = IX_NTOH32(data);
     
    if(arg_PortStatus == IX_CC_IPV4_ENABLE_PORT_STATUS)
    {
        data |= portMask;
    }/* end if (arg_PortStatus == IX_CC_IPV4_ENABLE_PORT_STATUS) */
    else
    {
        data &= ~portMask;
    }/*endelse (arg_PortStatus == IX_CC_IPV4_ENABLE_PORT_STATUS) */
    data = IX_HTON32(data);
    ix_ossl_mutex_lock(g_pIpv4Context->ipv4Mutex,IX_OSSL_MUTEX_LOCK);
    IX_IPV4_MEM_UINT32_WRITE(&pData->portForward,data);
    ix_ossl_mutex_unlock(g_pIpv4Context->ipv4Mutex);
   
    return IX_SUCCESS;
}/* end ix_cc_ipv4_property_update_port_status */



/**
 * NAME: _ix_cc_ipv4_property_update_ip_address
 *
 * DESCRIPTION: This primitive will be used to add/delete ip address and 
 * net mask in dynamic property table and directed broadcast table
 *           
 * 
 * @Param:  - IN arg_PropId - property id : add/delete ip address
 * @Param:  - IN arg_BladeId - blade number
 * @Param:  - IN arg_PordId - port number
 * @Param:  - IN arg_IpAddr - ip address of port
 * @Param:  - IN arg_SubnetMask - sunnet mask of port
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM - invalid blade/port number 
 * 
 */

ix_error _ix_cc_ipv4_property_update_ip_address(
                                               ix_uint16 arg_PropId,
                                               ix_uint16 arg_BladeId,
                                               ix_uint16 arg_PortId,
                                               ix_uint32 arg_IpAddr,
                                               ix_uint32 arg_SubnetMask
                                              )

{
    ix_uint32 keyIndex;
    ix_uint32 srcDBCastAddr;

    /* Validate input arguments */
    if((arg_BladeId > MAX_NUMBER_OF_BLADES - 1) ||
      (arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1))
    {
        return IX_ERROR_WARNING(IX_CC_IPV4_ERROR_INVALID_INPUT_PARAM,
                                ("Invalid Blade Id or Port Id"));
    }/* endif (arg_BladeId > MAX_NUMBER_OF_BLADES - 1) ||
      (arg_PortId > MAX_NUMBER_OF_PORTS_PER_BLADE - 1))
      */

    /* Calculate keyIndex from blade and Port Id */
    /* 6 bits for Blade Id(totally 64 blades) and each blade can have upto 16 ports */
    /* 4 bits to store portIds */
    keyIndex = (arg_BladeId << 4) | arg_PortId;    

    /* Calculate source directed broadcast address based on current ip address,
       subnet mask. Delete directed broadcast address from table and 
       Add new source directed broadcast to table if bladeId is local*/
    if(arg_BladeId == g_Ipv4RegistryData.localBladeId)
    {
        if(g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr != 0)
        {
            /* calculate {netId,-1} */
            srcDBCastAddr = g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr | ~g_pIpv4Context->ipv4PropTable[keyIndex].netMask;
            IX_ERROR_CR(_ix_cc_ipv4_delete_source_broadcast(srcDBCastAddr)); 
            /* calculate {netId,0} */
            srcDBCastAddr = g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr & g_pIpv4Context->ipv4PropTable[keyIndex].netMask;
            IX_ERROR_CR(_ix_cc_ipv4_delete_source_broadcast(srcDBCastAddr)); 
        }/* end if ipaddress != 0 */
        if(arg_PropId == IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4)
        {
            /* calculate {netId, -1} */   
            srcDBCastAddr = arg_IpAddr | ~arg_SubnetMask;
            IX_ERROR_CR(_ix_cc_ipv4_add_source_broadcast(srcDBCastAddr));
            /* calculate {netId, 0} */
            srcDBCastAddr = arg_IpAddr & arg_SubnetMask;
            IX_ERROR_CR(_ix_cc_ipv4_add_source_broadcast(srcDBCastAddr));
        }/* end for add in dbcast table */

    }/* end if(arg_BladeId == g_pIpv4Context->localBladeId) */

    if(arg_PropId == IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4)
    {
        /* store ipAddr and netMask to  dynamic property table */
        ix_ossl_mutex_lock(g_pIpv4Context->ipv4Mutex,IX_OSSL_WAIT_FOREVER);
        g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr =  arg_IpAddr;
        g_pIpv4Context->ipv4PropTable[keyIndex].netMask = arg_SubnetMask; 
        ix_ossl_mutex_unlock(g_pIpv4Context->ipv4Mutex);
        
        IpTrace(2, "Adding route %d.%d.%d.%d 255.255.255.255\n",
                (ix_uint8)(arg_IpAddr >> 24), (ix_uint8)(arg_IpAddr >> 16 & 0xff),
                (ix_uint8)((arg_IpAddr >> 8) & 0xff), (ix_uint8)(arg_IpAddr & 0xff));
        ix_cc_rtmv4_add_route(g_pIpv4Context->hRtm, arg_IpAddr, 0xffffffff,
                              IX_CC_IPV4_NH_LOCAL);
    }
    if(arg_PropId == IX_CC_SET_PROPERTY_DEL_INTERFACE_IPV4)
    {
        arg_IpAddr = g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr;
        IpTrace(2, "Deleting route %d.%d.%d.%d 255.255.255.255\n",
                (ix_uint8)(arg_IpAddr >> 24), (ix_uint8)((arg_IpAddr >> 16) & 0xff),
                (ix_uint8)((arg_IpAddr >> 8) & 0xff), (ix_uint8)(arg_IpAddr & 0xff));
        ix_cc_rtmv4_delete_route(g_pIpv4Context->hRtm, arg_IpAddr, 0xffffffff);
        
        ix_ossl_mutex_lock(g_pIpv4Context->ipv4Mutex,IX_OSSL_WAIT_FOREVER);
        g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr =  0;
        g_pIpv4Context->ipv4PropTable[keyIndex].netMask = 0;
        ix_ossl_mutex_unlock(g_pIpv4Context->ipv4Mutex);
    }
    return IX_SUCCESS;    
}/* end _ix_cc_ipv4_property_update_ip_address */


/**
 * NAME: _ix_cc_ipv4_prop_table_lookup_ip_address
 *
 * DESCRIPTION: This primitive will be used to lookup ip address
 * in dynamic property table
 *           
 * @Param:  - IN arg_IpAddr - ip address(non zero) to be searched in table.
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_ENTRY_NOT_FOUND - no entry in table 
 * 
 */

ix_error _ix_cc_ipv4_prop_table_lookup_ip_address(ix_uint32 arg_IpAddr)
{
    ix_uint32 keyIndex;
    ix_uint32 ipAddr;
    
    /* Convert the IP address into network byte order */   
    ipAddr = IX_HTON32(arg_IpAddr);
    for(keyIndex = 0; keyIndex < TOTAL_NUMBER_OF_PORTS; keyIndex++)
    {
        if(g_pIpv4Context->ipv4PropTable[keyIndex].ipAddr == ipAddr)
        {
            return IX_SUCCESS;
        }/* end if */
    }/* end of table search */

    return IX_ERROR_WARNING(IX_CC_ERROR_ENTRY_NOT_FOUND,("no entry in table"));
}/* end _ix_cc_ipv4_prop_table_lookup_ip_address */


