/**
 * ============================================================================
 * = 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-2002 Intel Corporation. All rights reserved.
 *
 * = PRODUCT
 *      Intel(r) IXA SDK 3.0 for the IXP2X00 Network Processor, Release 5
 *
 * = FILENAME
 *      ix_cc_eth_hdlr.c
 *
 * = DESCRIPTION
 *      This file defines various message and packet handler routines for level-1 system.
 *
 * = CHANGE HISTORY
 *      11/22/2002 - Created.
 *
 * ============================================================================
 * $Id: ix_cc_eth_rx_hdlr.c,v 1.11 2003/04/07 22:29:55 ktseng Exp $
 */

/**
 * System defined include files required.
 */

#include "ix_ossl.h"
/**
 * User defined include files required.
 */
#include "ix_cc_error.h"

#include "ix_types.h"
#include "ix_error.h"
#include "ix_cc.h"
#include "bindings.h"
#include "ix_cc_properties.h"

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


#ifndef IX_EXCLUDE_CCI
#include "ix_cci.h"
#endif

#include "cc/ix_cc_msup.h"
#include "cc/ix_cc_eth_rx.h"
#include "cc/internal/ix_cc_eth_rx_internal.h"



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


/**
 * Pre-processor symbols and macros used in this file.
 */


/**
 * Extern function prototypes and variables
 */



/**
 * Static function prototypes
 */



/**
 * function definitions.
 */


/**
 * NAME: ix_cc_eth_rx_msg_handler
 * 
 * DESCRIPTION: This function is the common message handler routine for
 *              Ethernet Rx CC. Ethernet Rx Core component receives messages from
 *				other core components 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: arg_Msg - IN - buffer handle embedding information for the message
 * passed in arg_UserData.
 * @Param: arg_UserData - IN - message type
 * @Param: arg_pContext - IN - pointer to Ethernet Rx 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_eth_rx_init function.
 * 
 * 
 * @Return: IX_SUCCESS if successful or a valid ix_error for failure.
 */
ix_error ix_cc_eth_rx_msg_handler(
				  ix_buffer_handle arg_Msg, 
				  ix_uint32 arg_UserData,
				  void *arg_pContext)
{
  
	void *pMsgData;
	ix_error err1 = IX_SUCCESS;
	ix_error result;
    ix_error err;
	void *pContext;
    void *pRetMsg = NULL;
    ix_uint32 msgRetLength = 0;
	ix_cc_properties_msg *ccPropMsg;  
  
  
	/* Check whether arg_pContext is invalid */
	if (arg_pContext == (void *)NULL)
    {
		err1 = IX_ERROR_WARNING(IX_CC_ERROR_NULL,
			    ("NULL argument"));
		goto funcRet;
    }
  
	/* Get the message sent by the helper function */
	IX_ERROR_CT(ix_cc_msup_extract_msg(arg_Msg, &pMsgData, &pContext),
              err1,
              IX_CC_ETH_RX_ERROR_MSUP_EXTRACT_MSG, 
              IX_ERROR_LEVEL_WARNING);
	if (err1 != IX_SUCCESS)
    {
		/* Free the ix_buffer (ignore the return code from ix_rm_buffer_free_chain) */
		ix_rm_buffer_free_chain(arg_Msg);
		return(err1);
    }
  
  
	/* Process the message */
	switch(arg_UserData)
	{
		/* This case is to handle microblock counters request */
		case (IX_CC_ETH_RX_MSG_GET_STATISTICS_INFO): 
		{
#ifndef MICROBLOCK_COUNTERS

                    result = IX_ERROR_WARNING(IX_CC_ERROR_UNIMPL,
                                              ("The supported feature is disabled."));

                    /* Send back the result */
                    IX_ERROR_CT(ix_cc_msup_send_reply_msg(pContext,
                                                          (void *)0, 
                                                          0,
                                                          result),
                                err1,
                                IX_CC_ETH_RX_ERROR_MSUP_SEND_REPLY, 
                                IX_ERROR_LEVEL_WARNING);

#else

			ix_cc_eth_rx_statistics_info entity;
			ix_uint32 index;
			ix_cc_eth_rx_statistics_info_data buffer;
			ix_uint32 numCountersReturned;
	
			/* Retrieve embedded information */
			entity = ((ix_cc_eth_rx_statistics_info_context *)pMsgData)->entity;
			index = ((ix_cc_eth_rx_statistics_info_context *)pMsgData)->index;
			
			/* Obtain the number of counters to be returned */
			if (entity == IX_CC_ETH_RX_ALL_MICROBLOCK_COUNTERS)
			{
				
				numCountersReturned = ETH_RX_NUM_COUNTERS_PER_PORT;
			}
			else /* for all single counters */
			{
				numCountersReturned = 1;
			}
			/*
			* Check for the ranges of the arg_Entity and arg_Index moved to 
			* ix_cc_eth_rx_get_statistics_info.
			*/
	
			{
			ix_uint64 dataBuffer[numCountersReturned];
			/* Invoke the corresponding library API */
			buffer.dataLength = sizeof(dataBuffer);
			buffer.pDataBuffer = (void *)dataBuffer;
			result = ix_cc_eth_rx_get_statistics_info(entity,
						    index, 
						    &buffer,
						    arg_pContext); 
			/*4th arg-argContext. This is used by the lib API ix_cc_eth_rx_get_statistics_info
			when it tries to get the value of 64 bit counters 
            (context has  a pointer to the linked list of counters, 
			index is used to get to it. */
	  

			/* Send back the result */
			IX_ERROR_CT(ix_cc_msup_send_reply_msg(pContext,
						(void *)dataBuffer, 
						sizeof(dataBuffer),
						result),
		      err1,
		      IX_CC_ETH_RX_ERROR_MSUP_SEND_REPLY, 
		      IX_ERROR_LEVEL_WARNING);
			}

#endif /* MICROBLOCK_COUNTERS */

		break; 	
		}
    
		/*get interface state case */          
		case IX_CC_ETH_RX_MSG_GET_INTERFACE_STATE:
		{
	
			ix_uint32 portId;
			ix_cc_eth_rx_if_state ifState;
	
			/* Retrieve embedded information */
			portId = ((ix_cc_eth_rx_if_state_context *)pMsgData)->portId;
	
			/* Invoke the corresponding library API */
			result = ix_cc_eth_rx_get_interface_state(portId,
						  &ifState,
						  arg_pContext);
	
			/* Send back the result */
			IX_ERROR_CT(ix_cc_msup_send_reply_msg(pContext,
					      (void *)&ifState, 
					      sizeof(ix_cc_eth_rx_if_state),
					      result),
		    err1,
		    IX_CC_ETH_RX_ERROR_MSUP_SEND_REPLY, 
		    IX_ERROR_LEVEL_WARNING);
			break;
		}
      
		/*case for update state; will be sent by stack for Property update for interface state*/
		case IX_CC_COMMON_MSG_ID_PROP_UPDATE:
		/*portId and property is sent in the property structure*/
		{
			
			ccPropMsg = (ix_cc_properties_msg*)pMsgData;
			/*Make sure the blade id is our local blade id */
			if (ccPropMsg->propData.blade_id != ((ix_cc_eth_rx_ctl_blk *)arg_pContext)->bladeId)
			{
				/* Free the ix_buffer */
				ix_rm_buffer_free_chain(arg_Msg);
				
#ifdef ETH_DEBUG
				ix_ossl_message_log("Blade id received does not match with local blade id.\n");
#endif
				/*We do not do anything*/
				return IX_SUCCESS;
			}
			/* Invoke the corresponding library API - set_property */
			IX_ERROR_C(ix_cc_eth_rx_set_property(ccPropMsg->propID, 
					     &(ccPropMsg->propData),
					     arg_pContext),
		   				err1); 
			break;
		}

        /* MAC Filtering table related message */
        case IX_CC_ETH_RX_MSG_ADD_MAC_ADDR:
        {
            ix_cc_eth_rx_add_mac_addr_data *pData = 
              (ix_cc_eth_rx_add_mac_addr_data*)pMsgData;
            err = ix_cc_eth_rx_add_mac_addr(
                  pData->destMac,
                  pData->portNum,arg_pContext);
            /* send return message, length and retrieved context to message support library */
            IX_ERROR_CT(ix_cc_msup_send_reply_msg(pContext,
						pRetMsg, 
						msgRetLength,
						err),
		      err1,
		      IX_CC_ETH_RX_ERROR_MSUP_SEND_REPLY, 
		      IX_ERROR_LEVEL_WARNING);
			

            break;
        }
        case IX_CC_ETH_RX_MSG_DELETE_MAC_ADDR:
        {
            ix_cc_eth_rx_delete_mac_addr_data *pData = 
             (ix_cc_eth_rx_delete_mac_addr_data*) pMsgData;
            err = ix_cc_eth_rx_del_mac_addr(pData->destMac,
                   arg_pContext);
            /* send return message, length and retrieved context to message support library */
            IX_ERROR_CT(ix_cc_msup_send_reply_msg(pContext,
						pRetMsg, 
						msgRetLength,
						err),
		      err1,
		      IX_CC_ETH_RX_ERROR_MSUP_SEND_REPLY, 
		      IX_ERROR_LEVEL_WARNING);
			
            break;
        }
        case IX_CC_ETH_RX_MSG_LOOKUP_PORT:
        {
            ix_uint32 msgRetData=0;
            ix_cc_eth_rx_lookup_port_data *pData = 
            (ix_cc_eth_rx_lookup_port_data*)pMsgData;
            msgRetLength = sizeof(ix_uint32);

            err = ix_cc_eth_rx_lookup_port(pData->destMac,
            &msgRetData,arg_pContext);
            pRetMsg = (void*)&msgRetData;
            /* send return message, length and retrieved context
            to message support library */
            IX_ERROR_CT(ix_cc_msup_send_reply_msg(pContext,
						pRetMsg, 
						msgRetLength,
						err),
		      err1,
		      IX_CC_ETH_RX_ERROR_MSUP_SEND_REPLY, 
		      IX_ERROR_LEVEL_WARNING);
			
            break;
        }
         
		default :
			err1 = IX_ERROR_WARNING(IX_CC_ERROR_UNDEFINED_MSG, 
			    ("Undefined message type"));
			break;
      
	}  
  
 funcRet:
    /* This is the function exiting point.  Free the ix_buffer here */
    ix_rm_buffer_free_chain(arg_Msg);
	
    pMsgData = NULL;      
    
    /* Always return the first error encountered */
    if (err1 != IX_SUCCESS)
	{
        /* Ignore the return code from ix_rm_buffer_free_chain.
        Just return the first error */
        return err1;
    }
  
			
    return IX_SUCCESS;
}      
/* ix_cc_eth_rx_msg_handler */




/**
 * NAME: ix_cc_eth_rx_low_priority_pkt_handler
 * 
 * DESCRIPTION: This function is the low priority packet handler routine for
 *              Ethernet Rx CC. 
 * 
 * @Param: arg_hDataBuffer - IN - handle to a buffer which contains exception packets
 *  from Ethernet Rx microblock
 * @Param: arg_ExceptionCode - IN-Exception codes generated by Ethernet
 *         Rx microblock. Valid exception code is IX_NON_IP_PACKET and is
 *         defined in ix_cc_microengines_bindings.h
 * @Param: arg_pContext - IN -  pointer to Ethernet Rx core component context
 * 
 * @Return: IX_SUCCESS if successful or a valid ix_error for failure.
 */  
ix_error ix_cc_eth_rx_low_priority_pkt_handler(
				  ix_buffer_handle arg_hDataBuffer,  
				  ix_uint32 arg_ExceptionCode,
				  void* arg_pContext)
{
  
	ix_error err = IX_SUCCESS;
  
  
#ifdef IX_DEBUG  
	/*If exception code is not  non-IP packet, log a warning*/
	if (arg_ExceptionCode != IX_NON_IP_PACKET)
	{
		ix_rm_buffer_free_chain(arg_hDataBuffer);
		return IX_ERROR_WARNING(IX_CC_ERROR_UNDEFINED_EXCEP,
		       ("undefined exception code"));

    }
#endif
	/*Using only RM as CCI packet_send also uses RM packet_send*/  
	err = ix_rm_packet_send(IX_CC_ETH_RX_COMMON_PKT_OUTPUT, 
			arg_hDataBuffer,0);
	/*we only free buffer if there is a send error*/
	if(err != IX_SUCCESS)
    {
		ix_rm_buffer_free_chain(arg_hDataBuffer);
		err = IX_ERROR_WARNING(IX_CC_ERROR_SEND_FAIL,
		("Unable to send packet in Ethernet Rx low priority packet handler"));
    }/* end if (err != IX_SUCCESS) */     
   
	return err;
}

/**
 * NAME: ix_cc_eth_rx_high_priority_pkt_handler
 * 
 * DESCRIPTION: This function is the high priority packet handler routine for
 *              Ethernet Rx CC for handling ARP packets 
 * 
 * @Param: arg_hDataBuffer - IN - handle to a buffer which contains exception packets
 *  from Ethernet Rx microblock
 * @Param: arg_ExceptionCode - IN - Exception code generated by Ethernet
 *         Rx microblock. Valid exception code is IX_ARP_PACKET and is defined in 
 *           ix_cc_microengines_bindings.h
 * @Param: arg_pContext - IN -  pointer to Ethernet Rx core component context
 * 
 * @Return: IX_SUCCESS if successful or a valid ix_error for failure.
 */  
ix_error ix_cc_eth_rx_high_priority_pkt_handler(
				  ix_buffer_handle arg_hDataBuffer,  
				  ix_uint32 arg_ExceptionCode,
				  void* arg_pContext)
{
  
	ix_error err = IX_SUCCESS;
 
#ifdef IX_DEBUG  
	/*If exception code is not ARP, log a warning*/
	if (arg_ExceptionCode != IX_ARP_PACKET)
	{
		ix_rm_buffer_free_chain(arg_hDataBuffer);
		return IX_ERROR_WARNING(IX_CC_ERROR_UNDEFINED_EXCEP,
		       ("undefined exception code"));

    }
#endif
	/*Using only RM as CCI packet_send also uses RM packet_send*/  
	err = ix_rm_message_send(IX_CC_ETH_RX_ARP_PKT_OUTPUT,
           arg_hDataBuffer,arg_ExceptionCode);
  
	/*we only free buffer if there is a send error*/
	if(err != IX_SUCCESS)
    {
		
		ix_rm_buffer_free_chain(arg_hDataBuffer);
		err = IX_ERROR_WARNING(IX_CC_ERROR_SEND_FAIL,
		("Unable to send packet in Ethernet Rx high priority packet handler"));
    }/* end if (err != IX_SUCCESS) */     
  
 
	return err;
}
