#ifndef	_LLC_ENCAP_C_
#define	_LLC_ENCAP_C_
/*****************************************************************************
 *                            Intel Proprietary
 *
 * Copyright (c) 1998-2002 By Intel Corporation.  All rights reserved.  
 * No part of this program or publication may be reproduced, transmitted,
 * transcribed, stored in a retrieval system, or translated into any language
 * or computer language in any form or by any means, electronic, mechanical,
 * magnetic, optical, chemical, manual, or otherwise, without the prior
 * written permission of:
 *                        Intel Corporation
 *                        2200 Mission College Blvd.
 *                        Santa Clara, CA  95052-8119
 *****************************************************************************/

/**
 *****************************************************************************
 * @ingroup LlcEncap
 * File:  llc_encap.c 
 * @description
 *    Implements LLC/SNAP encapsulation for IPv4 packets  
 *	  functional pipeline as well as Pool-Of-Threads Meter. The traffic
 *    It does the following.
 *                   1. Add the 8-byte LLC/SNAP header to start of
 *                      packet payload.
 *                   2. Update sop buffer meta-data due to 1.
 *                   3. Update sop buffer cell count due to 1 and
 *                      additional ATM cell consideration for 8-byte
 *                      trailer.
 *                   4. Compute packet cell count.
 *                   5. Update vcq# for the packet if necessary.
 *                   6. Optionally fetch outgoing VPI/VCI information
 *                      for the packet in the sop buffer meta-data.
 *
 *    Change History:
 *    02/March/2003    Created     Shreekanth Patel     Creation
 *    10/April/2003    Modified    Shreekanth Patel     Modified
 *****************************************************************************/

/*****************************************************************************
 *
 * Contents:
 *        Definitions of following exported functions
 *            LlcEncap()
 *****************************************************************************/

#include "dl_system.h"
#include <dl_buf.c>
#include <ixp_sram.c>
#include <dl_meta.c>
#include "dl_meta.h"
#include "dl_pkt_proc.h"
#include "llc_encap.h"

extern dl_buf_handle_t 	dlBufHandle;		/* The current buffer handle. */
extern dl_buf_handle_t 	dlEopBufHandle;		/* For large packets, this is 
											 * the last buffer in the chain. 
											 */
extern dl_meta_t dlMeta;				    /* Pkt Meta data */
extern __declspec(gp_reg) int dlNextBlock; 	/* Next block to process packet.*/
extern int dlExceptionCode;
extern volatile __declspec(gp_reg) hdr_cache_handle_t dlHdrHandle;

/** 
 ****************************************************************************
 * @ingroup LlcEncap
 * LLC SNAP header encapsulation API function.
 *
 * @description
 *			This API adds the LLC/SNAP header to the packet.
 *			It uses the next hop ID as an index into the table containing
 *			layer-2 LLC/SNAP header, VPI-VCI info and VC queue number.
 *			This header encapsulation is done only for ATM cells carrying 
 *			IP packets, null encapsulation is done for MPLS packets.
 *
 *			Since an additional header is added to the packet, the offset,
 *			packet size, SOP buffer size and SOP cell count in the meta data
 *			are updated.
 *			If an additional ATM cell needs to be added to accomodate the 
 *			8-byte trailer, it adds one byte to EOP buffer size. This ensures
 *			that the EOP buffer is freed by the Tx block only after the 
 *			additional cell is transmitted.
 *			
 *			The block also computes the cell count of the entire packet to be
 *			sent to QM
 *
 *			As a compile time option, the block will read VPI-VCI info from the 
 *			layer-2 table and store it in flow_id field of meta data.
 *
 * @context
 *    It is called from the dispatch loop of the pipeline.
 *
 * @return 	LLC_ENCAP_SUCCESS/IX_EXCEPTION/IX_NULL                                                    
 ***************************************************************************/
INLINE unsigned int 
LlcEncap (__declspec(local_mem, aligned(32)) unsigned int *pktHdr)
{

	/*  
	 * register declarations 
	 */
	__declspec (gp_reg) unsigned int correct_packetCellCount; 
	__declspec (gp_reg) unsigned int noAddnCell_packetCellCount; 
	__declspec (gp_reg) unsigned int original_packetCellCount;
	__declspec (gp_reg) unsigned int cellCountVcqNum;
	__declspec (gp_reg) unsigned int diff_packetCellCount;

	/*   
	 * Allocate 4 lw's to read the next hop entry for the packet. 
	 */
	__declspec (sram_read_reg) llc_table_entry_t llcSnapEntry;


	/*
	 * Check if packet is meant for this block
	 */
	if (dlNextBlock != BID_LLC_ENCAP)
		return IX_NULL;

	/*
	 * Compute original packet cell count.
	 */
#if 0	/* Not required since we are not taking the difference in Cell Count */
	original_packetCellCount = LlcEncap_ComputePacketCellCount (NO_ADDN_CELL);
#endif /* #if 0 */

	/*
	 * Read next hop entry for the packet, index is nextHopId
	 */
	LlcEncap_ReadNextHopEntry (&llcSnapEntry);

    /* 
	 * Do LLC Encapsulation and VPI-VCI lookup only in case of IPv4 Packets.
	 * For MPLS packets we only update VCQ# and Cell count
	 */
	if (dlMeta.headerType != PKT_PROTO_MPLS)
	{
#ifdef LOOKUP_VPI_VCI
		/*
		 * Optionally read & store outgoing VPI/VCI in the flow id field.
		 */
		dlMeta.flowId = llcSnapEntry.llc_hdr.outVpiVci;
#endif /* LOOKUP_VPI_VCI */

#ifdef ADD_L2_ENCAP
		/* 
		 * Check if LLC/SNAP needs to added to payload.
		 */
		if (llcSnapEntry.value[2] != 0xFFFFFFFF)
		{
			/* 
			 * Add LLC/SNAP header to start of payload.
			 */
			LlcEncap_AddLlcToPayload (pktHdr, &llcSnapEntry);

			/*
			 * Buffer Meta-data Update is being done in dl_source
			 * so no need to do it here
			 */
			/* LlcEncap_UpdateMetaData (); */
		} 
		else	/* (i.e. if llcSnapEntry.value[2] == 0xFFFFFFFF) */
		{
			/*
			 * Invalid header value
			 */
			dlExceptionCode = LLC_ENCAP_EXCEPTION_INVALID_HDR_VALUE;
			dlNextBlock = IX_EXCEPTION;
			return IX_EXCEPTION;
		}
#endif /* ADD_L2_ENCAP */
	}
	else
	{
		/* Make top of the stack label as NULL for MPLS over ATM case */
		*(pktHdr + dlHdrHandle.hdrOffset) = *(pktHdr + dlHdrHandle.hdrOffset) & 0xFFF;
	} /* if (dlMeta.headerType != PKT_PROTO_MPLS) */ 

	/*
	 * Compute VCQ#, packet cell count and update
	 * sop buffer cell count if necessary.
	 */

	/*
	 * Compute packet cell count without taking ADDN_CELL into account.
	 */
	noAddnCell_packetCellCount = LlcEncap_ComputePacketCellCount(
																     NO_ADDN_CELL
																	 );

	/*
	 * Compute correct packet cell count.
	 */
	correct_packetCellCount = LlcEncap_ComputePacketCellCount(
																ADDN_CELL
																);

	/*
	 * If (correct_packetCellCount - noAddnCell_packetCellCount) == 1
	 * increment eop buffer size by 1. This implies an additional cell needs
	 * to be scheduled.
	 * We increment eop buffer size so that the AAL5 transmit block does not
	 * free this buffer until the additional cell dequeue request comes in.
	 */
	if ((correct_packetCellCount - noAddnCell_packetCellCount) == 1)
	{
		/*
		 * If EOP Buf handle is not NULL, update cell count by one
		 */
		if (dlEopBufHandle.value != IX_NULL)
		{
			dlEopBufHandle.value = dlEopBufHandle.value | (1 << 16); 
		}
		else
		{
			/* 
			 * Since EOP buffer handle is NULL,
			 * Update SOP buffer size by one
			 */
			dlMeta.bufferSize += 1;
		} 
	}

	/* 
	 * Compute vcq and store it in the return value.
	 * This value will be stored in the scratch ring msg passed to OM
	 */
	if (llcSnapEntry.llc_hdr.vcqNum != 0xFFFF)
	{

		cellCountVcqNum = llcSnapEntry.llc_hdr.vcqNum;
	}

	/*  
	 * Store packet cell count in the return value.
	 * Also if needed, update buffer cell count in SOP handle.
	 */
    cellCountVcqNum = cellCountVcqNum | (correct_packetCellCount << 18);
	 
	 /* 
	  * Not required since we are not taking the difference in Cell Count
	  */
#if 0	
	/* 
	 * The difference between correct_packetCellCount and 
	 * original_packetCellCount is the number of cells that need
	 * to be added to the sop buffer cell count so that the sum of cell
	 * counts in all buffers of this packet equals the packet cell count.
	 */
	diff_packetCellCount = correct_packetCellCount - original_packetCellCount;

	/* 
 	 * Update the sop buffer cell count.
	 * For IPv4 Packets we take "diff_packetCellCount"
	 * But for MPLS, since PacketSize in Meta data is already updated
	 * diff_packetCellCount for MPLS is always zero
	 */
    if (diff_packetCellCount)
        dlBufHandle.value = (dlBufHandle.value) + (diff_packetCellCount << 24);
#endif	/* #if 0 */

    dlBufHandle.value = (dlBufHandle.value) + ((correct_packetCellCount - 1 ) << 24);

	/* 
	 * Update Next Block Id
	 */
	dlNextBlock = BID_LLC_ENCAP_NEXT1;

	return cellCountVcqNum;
}

#endif /* _LLC_ENCAP_C_ */