/**
 * ============================================================================
 * = 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) 2002 Intel Corporation. All rights reserved.
 *
 * = PRODUCT
 *      Intel(r) IXA SDK 3.0 for the IXP2000 Network Processor
 *
 *
 *      
 *
 * = MODULE
 *      IPv4 Forwarder Core Component
 *
 * = FILENAME
 *      header_validation.c
 *
 * = DESCRIPTION
 *      This file contains the implementation
 *      of IP header validation and address
 *      validation functions according to
 *      RFC1812 
 *
 *
 *
 *
 * = CREATION TIME
 *      8/09/2002 11:56:24 PM
 *
 * = CHANGE HISTORY
 *
 * ============================================================================
 */

#define IX_ERROR_FILE_IDENT "$Id: header_validation.c,v 1.22 2003/11/17 19:47:24 rranjeet Exp $"


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

/**
 * User defined include files required.
 */
#include "ix_cc_error.h"
#include "cc/ipv4/internal/header_validation.h"



/**
 * Function definitions.
 */

/**
 * NAME: _ix_cc_ipv4_IPheader_validate
 *
 * DESCRIPTION: This function validates the IP header 
 *              according to RFC1812 Section 5.2.2 
 * 
 * @Param:  - IN  arg_pIpHdr - a pointer to IPv4 header
 *		  arg_hBuffer - a buffer containing the packet
 *                              with IP header
 * @Param:  - INOUT  None
 * @Param:  - OUT arg_pDropped - value to tell whether the packet
 *				should be dropped or forwarded  
 *
 * @Return: IX_SUCCESS if successful or a valid ix_error token
 *             for failure.
 * Error codes: IX_CC_IPV4_ERROR_INVALID_HEADER
 *              IX_CC_ERROR_INTERNAL
 */
ix_error _ix_cc_ipv4_IPheader_validate(
			ix_cc_ipv4_header *arg_pIpHdr,
			ix_buffer_handle arg_hBuffer,
                        ix_uint32 *arg_pDropped)
{
	ix_uint16 len;
	ix_error err = IX_SUCCESS;
	ix_hw_buffer_meta *pHwMeta;
    *arg_pDropped = 0;

	/* Extract meta data from buffer */
	err = ix_rm_buffer_get_meta( arg_hBuffer, (void **)&pHwMeta);
    if (err)
    {
        goto drop;
                
    }
	/* Extract packet size from meta data */
	len = IX_NTOH16(IX_RM_MEM_UINT16_READ(&pHwMeta->m_PacketSize));

    if (arg_pIpHdr->version != 4)
    {
        /*Invalid IP version */
        goto drop;
    }
    if (arg_pIpHdr->headerLength < MIN_IP_LEN/4 )
    {
        /*Invalid IP header length */
        goto drop;
    }

    /* Note that arg_pIpHdr->totalLength is 16 bits value ***/
    /* It will be represented in network byte order **/
    /** To access it in network byte order, we need to use ntohs **/
    if ((IX_NTOH16(arg_pIpHdr->totalLength )) < (arg_pIpHdr->headerLength *4))
    {
        /*Invalid IP total length field */
        goto drop;
    }
    if(_ix_cc_ipv4_calculate_checksum( (ix_uint8 *)arg_pIpHdr,  
                                       (arg_pIpHdr->headerLength * 4)) != 0)
    {
        /*Invalid IP checksum */
        goto drop;
    }
    if (IX_NTOH16(arg_pIpHdr->totalLength) > len)
    {
        goto drop;	/* packet corrupted */
    }
    return IX_SUCCESS;

drop:
    *arg_pDropped = 1;
    
    /* need to delete this buffer */
    return IX_SUCCESS;

}


/**
 * NAME:_ix_cc_ipv4_validate_IP_addresses 
 *
 * DESCRIPTION: This function checks the Destination
 *           IP address and Source IP address in the
 *           given buffer to make sure
 *           that they do not contain any unrouteable
 *           addresses according to RFC1812 
 *           Section 4.2.2.11 
 * 
 * @Param:  - IN  arg_pIpHdr - a pointer to IPv4 header
 *		  arg_hBuffer - a buffer containing the packet
 *                              with IP header
 * @Param:  - INOUT  None
 * @Param:  - OUT arg_pDropped - value to tell whether the packet
 *				should be dropped or forwarded  
 *
 * @Return: IX_SUCCESS if successful or a valid ix_error token
 *             for failure.
 * Error codes: IX_CCI_ERR_SEND_FAIL
 *              IX_CC_ERROR_INTERNAL
 */
ix_error _ix_cc_ipv4_validate_IP_addresses( 
                             ix_cc_ipv4_header *arg_pIpHdr, 
                             ix_buffer_handle arg_hBuffer,
                             ix_uint32 *arg_pDropped )
{
    

    
    
    
    ix_uint32 localDeliv = 0;
    ix_uint32 sip;
    ix_uint32 dip;
    ix_error err;    
    
    *arg_pDropped = 0;
    sip =  IX_NTOH32(arg_pIpHdr->sourceAddress);
    dip =  IX_NTOH32(arg_pIpHdr->destAddress);
    
    
        
    /** Check to make sure that source address is not {0,0}*/
    /**Check to make sure that sip is not loopback address **/
    /* Check to make sure that sip  is not class D(0xe0000000) and not class E***/
    /* Check to make sure that sip is not multicast (224.x.x.x) **/
    /* Check to make sure that sip is not limited broadcast **/
    /* Check if dip is loopback, then we need to drop the packet **/
    /** Check if dip is 240.0.0.0 (class E)and if dip is not 255.255.255.255 **/
    
#ifdef RFC1812_SHOULD
    if  ((sip & 0xffffffff ) == 0         ||
        ( sip & 0xff000000 ) == 0x7f000000 ||
        ( sip & 0xff000000 ) == 0xff000000 ||
        ( sip & 0xf0000000 ) == 0xf0000000 ||
        ( sip & 0xf0000000 ) == 0xe0000000 ||
        ( sip & 0xffffffff ) == 0xffffffff ||
        ( dip & 0xff000000 ) == 0x7f000000 ||
        ( dip & 0xffffffff ) == 0          ||
        ( ( dip & 0xf0000000 ) == 0xf0000000 
            && ( dip & 0xffffffff ) != 0xffffffff ) )
    {
        /* silently drop */
        /*bad address */
        *arg_pDropped = 1;
        /* free buffer chain */
        ix_rm_buffer_free_chain(arg_hBuffer);
    }
    /* If dip is 255.255.255.255 ie. limited broadcast, then 
    *it is meant for local delvery **/
    /** If dip is multicast, then it is meant for local delivery **/
    
	
    else if ( ( dip & 0xffffffff ) == 0xffffffff ||
            ( dip & 0xf0000000 ) == 0xe0000000) 
           
    {
        localDeliv = 1;
    }

#endif /* RFC1812_SHOULD */

#ifdef INCLUDE_BCAST_CHECK
    /* Directed broadcast check **/
    /**
     *Addresses of type {<netid>, 0}
     * {<netid>, -1}
     * {0, <hostid>}
     * {-1, <hostid>}
     **/
    
    err = _ix_cc_ipv4_lookup_source_broadcast(sip);
    if ( err == IX_SUCCESS)
    {
        /*Failed prefix check */
        *arg_pDropped = 1;
        /* Free buffer chain */
        ix_rm_buffer_free_chain(arg_hBuffer);
    }
#endif /* INCLUDE_BCAST_CHECK */

    
    if ( localDeliv )
    {
        
        /*Local delivery - send through high priority queue*/
        err = ix_rm_message_send(
            IX_CC_IPV4_PKT_HIGH_PRIORITY_STKDRV_OUTPUT,
            arg_hBuffer, 0);
        if (err)
        {
            /** Free the buffer and return error to caller **/
            ix_rm_buffer_free_chain(arg_hBuffer);
            return IX_ERROR_CHAIN(err, IX_CC_ERROR_SEND_FAIL,0, 
            ("Failed to send packet to next target\n"));

        }     
        /* This is a special case for local delivery */
        /* Do not want to free buffer chain */
        *arg_pDropped = 1;

	
    }
    return IX_SUCCESS;
}

