blob: 4aa2b71a40ebe40a1d5c27b8506443955e18e650 [file] [log] [blame]
#include "headers.h"
static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId,S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
static UINT CreateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI);
static UINT UpdateClassifierPHSRule(B_UINT16 uiClsId,S_CLASSIFIER_ENTRY *pstClassifierEntry,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
static BOOLEAN ValidatePHSRuleComplete(S_PHS_RULE *psPhsRule);
static BOOLEAN DerefPhsRule(B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule);
static UINT GetClassifierEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, S_CLASSIFIER_ENTRY **ppstClassifierEntry);
static UINT GetPhsRuleEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,S_PHS_RULE **ppstPhsRule);
static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable);
static int phs_compress(S_PHS_RULE *phs_members,unsigned char *in_buf,
unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size );
static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size );
static int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\
S_PHS_RULE *phs_rules,UINT *header_size);
static ULONG PhsCompress(void* pvContext,
B_UINT16 uiVcid,
B_UINT16 uiClsId,
void *pvInputBuffer,
void *pvOutputBuffer,
UINT *pOldHeaderSize,
UINT *pNewHeaderSize );
static ULONG PhsDeCompress(void* pvContext,
B_UINT16 uiVcid,
void *pvInputBuffer,
void *pvOutputBuffer,
UINT *pInHeaderSize,
UINT *pOutHeaderSize);
#define IN
#define OUT
/*
Function: PHSTransmit
Description: This routine handle PHS(Payload Header Suppression for Tx path.
It extracts a fragment of the NDIS_PACKET containing the header
to be suppressed.It then supresses the header by invoking PHS exported compress routine.
The header data after supression is copied back to the NDIS_PACKET.
Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context
IN Packet - NDIS packet containing data to be transmitted
IN USHORT Vcid - vcid pertaining to connection on which the packet is being sent.Used to
identify PHS rule to be applied.
B_UINT16 uiClassifierRuleID - Classifier Rule ID
BOOLEAN bHeaderSuppressionEnabled - indicates if header suprression is enabled for SF.
Return: STATUS_SUCCESS - If the send was successful.
Other - If an error occured.
*/
int PHSTransmit(PMINI_ADAPTER Adapter,
struct sk_buff **pPacket,
USHORT Vcid,
B_UINT16 uiClassifierRuleID,
BOOLEAN bHeaderSuppressionEnabled,
UINT *PacketLen,
UCHAR bEthCSSupport)
{
//PHS Sepcific
UINT unPHSPktHdrBytesCopied = 0;
UINT unPhsOldHdrSize = 0;
UINT unPHSNewPktHeaderLen = 0;
/* Pointer to PHS IN Hdr Buffer */
PUCHAR pucPHSPktHdrInBuf =
Adapter->stPhsTxContextInfo.ucaHdrSupressionInBuf;
/* Pointer to PHS OUT Hdr Buffer */
PUCHAR pucPHSPktHdrOutBuf =
Adapter->stPhsTxContextInfo.ucaHdrSupressionOutBuf;
UINT usPacketType;
UINT BytesToRemove=0;
BOOLEAN bPHSI = 0;
LONG ulPhsStatus = 0;
UINT numBytesCompressed = 0;
struct sk_buff *newPacket = NULL;
struct sk_buff *Packet = *pPacket;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "In PHSTransmit");
if(!bEthCSSupport)
BytesToRemove=ETH_HLEN;
/*
Accumulate the header upto the size we support supression
from NDIS packet
*/
usPacketType=((struct ethhdr *)(Packet->data))->h_proto;
pucPHSPktHdrInBuf = Packet->data + BytesToRemove;
//considering data after ethernet header
if((*PacketLen - BytesToRemove) < MAX_PHS_LENGTHS)
{
unPHSPktHdrBytesCopied = (*PacketLen - BytesToRemove);
}
else
{
unPHSPktHdrBytesCopied = MAX_PHS_LENGTHS;
}
if( (unPHSPktHdrBytesCopied > 0 ) &&
(unPHSPktHdrBytesCopied <= MAX_PHS_LENGTHS))
{
// Step 2 Supress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
// Suppress only if IP Header and PHS Enabled For the Service Flow
if(((usPacketType == ETHERNET_FRAMETYPE_IPV4) ||
(usPacketType == ETHERNET_FRAMETYPE_IPV6)) &&
(bHeaderSuppressionEnabled))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nTrying to PHS Compress Using Classifier rule 0x%X",uiClassifierRuleID);
unPHSNewPktHeaderLen = unPHSPktHdrBytesCopied;
ulPhsStatus = PhsCompress(&Adapter->stBCMPhsContext,
Vcid,
uiClassifierRuleID,
pucPHSPktHdrInBuf,
pucPHSPktHdrOutBuf,
&unPhsOldHdrSize,
&unPHSNewPktHeaderLen);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nPHS Old header Size : %d New Header Size %d\n",unPhsOldHdrSize,unPHSNewPktHeaderLen);
if(unPHSNewPktHeaderLen == unPhsOldHdrSize)
{
if( ulPhsStatus == STATUS_PHS_COMPRESSED)
bPHSI = *pucPHSPktHdrOutBuf;
ulPhsStatus = STATUS_PHS_NOCOMPRESSION;
}
if( ulPhsStatus == STATUS_PHS_COMPRESSED)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"PHS Sending packet Compressed");
if(skb_cloned(Packet))
{
newPacket = skb_copy(Packet, GFP_ATOMIC);
if(newPacket == NULL)
return STATUS_FAILURE;
dev_kfree_skb(Packet);
*pPacket = Packet = newPacket;
pucPHSPktHdrInBuf = Packet->data + BytesToRemove;
}
numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen+PHSI_LEN);
memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
skb_pull(Packet, numBytesCompressed);
return STATUS_SUCCESS;
}
else
{
//if one byte headroom is not available, increase it through skb_cow
if(!(skb_headroom(Packet) > 0))
{
if(skb_cow(Packet, 1))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "SKB Cow Failed\n");
return STATUS_FAILURE;
}
}
skb_push(Packet, 1);
// CAUTION: The MAC Header is getting corrupted here for IP CS - can be saved by copying 14 Bytes. not needed .... hence corrupting it.
*(Packet->data + BytesToRemove) = bPHSI;
return STATUS_SUCCESS;
}
}
else
{
if(!bHeaderSuppressionEnabled)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nHeader Suppression Disabled For SF: No PHS\n");
}
return STATUS_SUCCESS;
}
}
//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"PHSTransmit : Dumping data packet After PHS");
return STATUS_SUCCESS;
}
int PHSReceive(PMINI_ADAPTER Adapter,
USHORT usVcid,
struct sk_buff *packet,
UINT *punPacketLen,
UCHAR *pucEthernetHdr,
UINT bHeaderSuppressionEnabled)
{
u32 nStandardPktHdrLen = 0;
u32 nTotalsupressedPktHdrBytes = 0;
int ulPhsStatus = 0;
PUCHAR pucInBuff = NULL ;
UINT TotalBytesAdded = 0;
if(!bHeaderSuppressionEnabled)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nPhs Disabled for incoming packet");
return ulPhsStatus;
}
pucInBuff = packet->data;
//Restore PHS suppressed header
nStandardPktHdrLen = packet->len;
ulPhsStatus = PhsDeCompress(&Adapter->stBCMPhsContext,
usVcid,
pucInBuff,
Adapter->ucaPHSPktRestoreBuf,
&nTotalsupressedPktHdrBytes,
&nStandardPktHdrLen);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nSupressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x",
nTotalsupressedPktHdrBytes,nStandardPktHdrLen);
if(ulPhsStatus != STATUS_PHS_COMPRESSED)
{
skb_pull(packet, 1);
return STATUS_SUCCESS;
}
else
{
TotalBytesAdded = nStandardPktHdrLen - nTotalsupressedPktHdrBytes - PHSI_LEN;
if(TotalBytesAdded)
{
if(skb_headroom(packet) >= (SKB_RESERVE_ETHERNET_HEADER + TotalBytesAdded))
skb_push(packet, TotalBytesAdded);
else
{
if(skb_cow(packet, skb_headroom(packet) + TotalBytesAdded))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "cow failed in receive\n");
return STATUS_FAILURE;
}
skb_push(packet, TotalBytesAdded);
}
}
memcpy(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen);
}
return STATUS_SUCCESS;
}
void DumpFullPacket(UCHAR *pBuf,UINT nPktLen)
{
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,"Dumping Data Packet");
BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,pBuf,nPktLen);
}
//-----------------------------------------------------------------------------
// Procedure: phs_init
//
// Description: This routine is responsible for allocating memory for classifier and
// PHS rules.
//
// Arguments:
// pPhsdeviceExtension - ptr to Device extension containing PHS Classifier rules and PHS Rules , RX, TX buffer etc
//
// Returns:
// TRUE(1) -If allocation of memory was success full.
// FALSE -If allocation of memory fails.
//-----------------------------------------------------------------------------
int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
{
int i;
S_SERVICEFLOW_TABLE *pstServiceFlowTable;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nPHS:phs_init function ");
if(pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
return -EINVAL;
pPhsdeviceExtension->pstServiceFlowPhsRulesTable =
kzalloc(sizeof(S_SERVICEFLOW_TABLE), GFP_KERNEL);
if(!pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed");
return -ENOMEM;
}
pstServiceFlowTable = pPhsdeviceExtension->pstServiceFlowPhsRulesTable;
for(i=0;i<MAX_SERVICEFLOWS;i++)
{
S_SERVICEFLOW_ENTRY sServiceFlow = pstServiceFlowTable->stSFList[i];
sServiceFlow.pstClassifierTable = kzalloc(sizeof(S_CLASSIFIER_TABLE), GFP_KERNEL);
if(!sServiceFlow.pstClassifierTable)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
free_phs_serviceflow_rules(pPhsdeviceExtension->
pstServiceFlowPhsRulesTable);
pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
return -ENOMEM;
}
}
pPhsdeviceExtension->CompressedTxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
if(pPhsdeviceExtension->CompressedTxBuffer == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
return -ENOMEM;
}
pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
if(pPhsdeviceExtension->UnCompressedRxBuffer == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
kfree(pPhsdeviceExtension->CompressedTxBuffer);
free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
return -ENOMEM;
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successfull");
return STATUS_SUCCESS;
}
int PhsCleanup(IN PPHS_DEVICE_EXTENSION pPHSDeviceExt)
{
if(pPHSDeviceExt->pstServiceFlowPhsRulesTable)
{
free_phs_serviceflow_rules(pPHSDeviceExt->pstServiceFlowPhsRulesTable);
pPHSDeviceExt->pstServiceFlowPhsRulesTable = NULL;
}
kfree(pPHSDeviceExt->CompressedTxBuffer);
pPHSDeviceExt->CompressedTxBuffer = NULL;
kfree(pPHSDeviceExt->UnCompressedRxBuffer);
pPHSDeviceExt->UnCompressedRxBuffer = NULL;
return 0;
}
//PHS functions
/*++
PhsUpdateClassifierRule
Routine Description:
Exported function to add or modify a PHS Rule.
Arguments:
IN void* pvContext - PHS Driver Specific Context
IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies.
IN S_PHS_RULE *psPhsRule - The PHS Rule strcuture to be added to the PHS Rule table.
Return Value:
0 if successful,
>0 Error.
--*/
ULONG PhsUpdateClassifierRule(IN void* pvContext,
IN B_UINT16 uiVcid ,
IN B_UINT16 uiClsId ,
IN S_PHS_RULE *psPhsRule,
IN B_UINT8 u8AssociatedPHSI)
{
ULONG lStatus =0;
UINT nSFIndex =0 ;
S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"PHS With Corr2 Changes \n");
if(pDeviceExtension == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"Invalid Device Extension\n");
return ERR_PHS_INVALID_DEVICE_EXETENSION;
}
if(u8AssociatedPHSI == 0)
{
return ERR_PHS_INVALID_PHS_RULE;
}
/* Retrieve the SFID Entry Index for requested Service Flow */
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
uiVcid,&pstServiceFlowEntry);
if(nSFIndex == PHS_INVALID_TABLE_INDEX)
{
/* This is a new SF. Create a mapping entry for this */
lStatus = CreateSFToClassifierRuleMapping(uiVcid, uiClsId,
pDeviceExtension->pstServiceFlowPhsRulesTable, psPhsRule, u8AssociatedPHSI);
return lStatus;
}
/* SF already Exists Add PHS Rule to existing SF */
lStatus = CreateClassiferToPHSRuleMapping(uiVcid, uiClsId,
pstServiceFlowEntry, psPhsRule, u8AssociatedPHSI);
return lStatus;
}
/*++
PhsDeletePHSRule
Routine Description:
Deletes the specified phs Rule within Vcid
Arguments:
IN void* pvContext - PHS Driver Specific Context
IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
IN B_UINT8 u8PHSI - the PHS Index identifying PHS rule to be deleted.
Return Value:
0 if successful,
>0 Error.
--*/
ULONG PhsDeletePHSRule(IN void* pvContext,IN B_UINT16 uiVcid,IN B_UINT8 u8PHSI)
{
ULONG lStatus =0;
UINT nSFIndex =0, nClsidIndex =0 ;
S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
S_CLASSIFIER_TABLE *pstClassifierRulesTable = NULL;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "======>\n");
if(pDeviceExtension)
{
//Retrieve the SFID Entry Index for requested Service Flow
nSFIndex = GetServiceFlowEntry(pDeviceExtension
->pstServiceFlowPhsRulesTable,uiVcid,&pstServiceFlowEntry);
if(nSFIndex == PHS_INVALID_TABLE_INDEX)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
return ERR_SF_MATCH_FAIL;
}
pstClassifierRulesTable=pstServiceFlowEntry->pstClassifierTable;
if(pstClassifierRulesTable)
{
for(nClsidIndex=0;nClsidIndex<MAX_PHSRULE_PER_SF;nClsidIndex++)
{
if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule)
{
if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI) {
if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0,
sizeof(S_CLASSIFIER_ENTRY));
}
}
}
}
}
return lStatus;
}
/*++
PhsDeleteClassifierRule
Routine Description:
Exported function to Delete a PHS Rule for the SFID,CLSID Pair.
Arguments:
IN void* pvContext - PHS Driver Specific Context
IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies.
Return Value:
0 if successful,
>0 Error.
--*/
ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16 uiClsId)
{
ULONG lStatus =0;
UINT nSFIndex =0, nClsidIndex =0 ;
S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
S_CLASSIFIER_ENTRY *pstClassifierEntry = NULL;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
if(pDeviceExtension)
{
//Retrieve the SFID Entry Index for requested Service Flow
nSFIndex = GetServiceFlowEntry(pDeviceExtension
->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry);
if(nSFIndex == PHS_INVALID_TABLE_INDEX)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"SFID Match Failed\n");
return ERR_SF_MATCH_FAIL;
}
nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry);
if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule))
{
if(pstClassifierEntry->pstPhsRule)
{
if(pstClassifierEntry->pstPhsRule->u8RefCnt)
pstClassifierEntry->pstPhsRule->u8RefCnt--;
if(0==pstClassifierEntry->pstPhsRule->u8RefCnt)
kfree(pstClassifierEntry->pstPhsRule);
}
memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY));
}
nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
uiClsId,eOldClassifierRuleContext,&pstClassifierEntry);
if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule))
{
kfree(pstClassifierEntry->pstPhsRule);
memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY));
}
}
return lStatus;
}
/*++
PhsDeleteSFRules
Routine Description:
Exported function to Delete a all PHS Rules for the SFID.
Arguments:
IN void* pvContext - PHS Driver Specific Context
IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rules need to be deleted
Return Value:
0 if successful,
>0 Error.
--*/
ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid)
{
ULONG lStatus =0;
UINT nSFIndex =0, nClsidIndex =0 ;
S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
S_CLASSIFIER_TABLE *pstClassifierRulesTable = NULL;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"====> \n");
if(pDeviceExtension)
{
//Retrieve the SFID Entry Index for requested Service Flow
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
uiVcid,&pstServiceFlowEntry);
if(nSFIndex == PHS_INVALID_TABLE_INDEX)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
return ERR_SF_MATCH_FAIL;
}
pstClassifierRulesTable=pstServiceFlowEntry->pstClassifierTable;
if(pstClassifierRulesTable)
{
for(nClsidIndex=0;nClsidIndex<MAX_PHSRULE_PER_SF;nClsidIndex++)
{
if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule)
{
if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt)
pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt--;
if(0==pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt)
kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
.pstPhsRule = NULL;
}
memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY));
if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule)
{
if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt)
pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt--;
if(0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
.pstPhsRule->u8RefCnt)
kfree(pstClassifierRulesTable
->stOldPhsRulesList[nClsidIndex].pstPhsRule);
pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
.pstPhsRule = NULL;
}
memset(&pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY));
}
}
pstServiceFlowEntry->bUsed = FALSE;
pstServiceFlowEntry->uiVcid = 0;
}
return lStatus;
}
/*++
PhsCompress
Routine Description:
Exported function to compress the data using PHS.
Arguments:
IN void* pvContext - PHS Driver Specific Context.
IN B_UINT16 uiVcid - The Service Flow ID to which current packet header compression applies.
IN UINT uiClsId - The Classifier ID to which current packet header compression applies.
IN void *pvInputBuffer - The Input buffer containg packet header data
IN void *pvOutputBuffer - The output buffer returned by this function after PHS
IN UINT *pOldHeaderSize - The actual size of the header before PHS
IN UINT *pNewHeaderSize - The new size of the header after applying PHS
Return Value:
0 if successful,
>0 Error.
--*/
ULONG PhsCompress(IN void* pvContext,
IN B_UINT16 uiVcid,
IN B_UINT16 uiClsId,
IN void *pvInputBuffer,
OUT void *pvOutputBuffer,
OUT UINT *pOldHeaderSize,
OUT UINT *pNewHeaderSize )
{
UINT nSFIndex =0, nClsidIndex =0 ;
S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
S_CLASSIFIER_ENTRY *pstClassifierEntry = NULL;
S_PHS_RULE *pstPhsRule = NULL;
ULONG lStatus =0;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
PPHS_DEVICE_EXTENSION pDeviceExtension= (PPHS_DEVICE_EXTENSION)pvContext;
if(pDeviceExtension == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Invalid Device Extension\n");
lStatus = STATUS_PHS_NOCOMPRESSION ;
return lStatus;
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Suppressing header \n");
//Retrieve the SFID Entry Index for requested Service Flow
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
uiVcid,&pstServiceFlowEntry);
if(nSFIndex == PHS_INVALID_TABLE_INDEX)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"SFID Match Failed\n");
lStatus = STATUS_PHS_NOCOMPRESSION ;
return lStatus;
}
nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
uiClsId,eActiveClassifierRuleContext,&pstClassifierEntry);
if(nClsidIndex == PHS_INVALID_TABLE_INDEX)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"No PHS Rule Defined For Classifier\n");
lStatus = STATUS_PHS_NOCOMPRESSION ;
return lStatus;
}
//get rule from SF id,Cls ID pair and proceed
pstPhsRule = pstClassifierEntry->pstPhsRule;
if(!ValidatePHSRuleComplete(pstPhsRule))
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"PHS Rule Defined For Classifier But Not Complete\n");
lStatus = STATUS_PHS_NOCOMPRESSION ;
return lStatus;
}
//Compress Packet
lStatus = phs_compress(pstPhsRule,(PUCHAR)pvInputBuffer,
(PUCHAR)pvOutputBuffer, pOldHeaderSize,pNewHeaderSize);
if(lStatus == STATUS_PHS_COMPRESSED)
{
pstPhsRule->PHSModifiedBytes += *pOldHeaderSize - *pNewHeaderSize - 1;
pstPhsRule->PHSModifiedNumPackets++;
}
else
pstPhsRule->PHSErrorNumPackets++;
return lStatus;
}
/*++
PhsDeCompress
Routine Description:
Exported function to restore the packet header in Rx path.
Arguments:
IN void* pvContext - PHS Driver Specific Context.
IN B_UINT16 uiVcid - The Service Flow ID to which current packet header restoration applies.
IN void *pvInputBuffer - The Input buffer containg suppressed packet header data
OUT void *pvOutputBuffer - The output buffer returned by this function after restoration
OUT UINT *pHeaderSize - The packet header size after restoration is returned in this parameter.
Return Value:
0 if successful,
>0 Error.
--*/
ULONG PhsDeCompress(IN void* pvContext,
IN B_UINT16 uiVcid,
IN void *pvInputBuffer,
OUT void *pvOutputBuffer,
OUT UINT *pInHeaderSize,
OUT UINT *pOutHeaderSize )
{
UINT nSFIndex =0, nPhsRuleIndex =0 ;
S_SERVICEFLOW_ENTRY *pstServiceFlowEntry = NULL;
S_PHS_RULE *pstPhsRule = NULL;
UINT phsi;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
PPHS_DEVICE_EXTENSION pDeviceExtension=
(PPHS_DEVICE_EXTENSION)pvContext;
*pInHeaderSize = 0;
if(pDeviceExtension == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"Invalid Device Extension\n");
return ERR_PHS_INVALID_DEVICE_EXETENSION;
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"Restoring header\n");
phsi = *((unsigned char *)(pvInputBuffer));
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"PHSI To Be Used For restore : %x\n",phsi);
if(phsi == UNCOMPRESSED_PACKET )
{
return STATUS_PHS_NOCOMPRESSION;
}
//Retrieve the SFID Entry Index for requested Service Flow
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
uiVcid,&pstServiceFlowEntry);
if(nSFIndex == PHS_INVALID_TABLE_INDEX)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"SFID Match Failed During Lookup\n");
return ERR_SF_MATCH_FAIL;
}
nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable,phsi,
eActiveClassifierRuleContext,&pstPhsRule);
if(nPhsRuleIndex == PHS_INVALID_TABLE_INDEX)
{
//Phs Rule does not exist in active rules table. Lets try in the old rules table.
nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable,
phsi,eOldClassifierRuleContext,&pstPhsRule);
if(nPhsRuleIndex == PHS_INVALID_TABLE_INDEX)
{
return ERR_PHSRULE_MATCH_FAIL;
}
}
*pInHeaderSize = phs_decompress((PUCHAR)pvInputBuffer,
(PUCHAR)pvOutputBuffer,pstPhsRule,pOutHeaderSize);
pstPhsRule->PHSModifiedBytes += *pOutHeaderSize - *pInHeaderSize - 1;
pstPhsRule->PHSModifiedNumPackets++;
return STATUS_PHS_COMPRESSED;
}
//-----------------------------------------------------------------------------
// Procedure: free_phs_serviceflow_rules
//
// Description: This routine is responsible for freeing memory allocated for PHS rules.
//
// Arguments:
// rules - ptr to S_SERVICEFLOW_TABLE structure.
//
// Returns:
// Does not return any value.
//-----------------------------------------------------------------------------
static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
{
int i,j;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "=======>\n");
if(psServiceFlowRulesTable)
{
for(i=0;i<MAX_SERVICEFLOWS;i++)
{
S_SERVICEFLOW_ENTRY stServiceFlowEntry =
psServiceFlowRulesTable->stSFList[i];
S_CLASSIFIER_TABLE *pstClassifierRulesTable =
stServiceFlowEntry.pstClassifierTable;
if(pstClassifierRulesTable)
{
for(j=0;j<MAX_PHSRULE_PER_SF;j++)
{
if(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule)
{
if(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
->u8RefCnt)
pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
->u8RefCnt--;
if(0==pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
->u8RefCnt)
kfree(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule);
pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule = NULL;
}
if(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule)
{
if(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
->u8RefCnt)
pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
->u8RefCnt--;
if(0==pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
->u8RefCnt)
kfree(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule);
pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL;
}
}
kfree(pstClassifierRulesTable);
stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL;
}
}
}
kfree(psServiceFlowRulesTable);
psServiceFlowRulesTable = NULL;
}
static BOOLEAN ValidatePHSRuleComplete(IN S_PHS_RULE *psPhsRule)
{
if(psPhsRule)
{
if(!psPhsRule->u8PHSI)
{
// PHSI is not valid
return FALSE;
}
if(!psPhsRule->u8PHSS)
{
//PHSS Is Undefined
return FALSE;
}
//Check if PHSF is defines for the PHS Rule
if(!psPhsRule->u8PHSFLength) // If any part of PHSF is valid then Rule contains valid PHSF
{
return FALSE;
}
return TRUE;
}
else
{
return FALSE;
}
}
UINT GetServiceFlowEntry(IN S_SERVICEFLOW_TABLE *psServiceFlowTable,
IN B_UINT16 uiVcid,S_SERVICEFLOW_ENTRY **ppstServiceFlowEntry)
{
int i;
for(i=0;i<MAX_SERVICEFLOWS;i++)
{
if(psServiceFlowTable->stSFList[i].bUsed)
{
if(psServiceFlowTable->stSFList[i].uiVcid == uiVcid)
{
*ppstServiceFlowEntry = &psServiceFlowTable->stSFList[i];
return i;
}
}
}
*ppstServiceFlowEntry = NULL;
return PHS_INVALID_TABLE_INDEX;
}
UINT GetClassifierEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
IN B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,
OUT S_CLASSIFIER_ENTRY **ppstClassifierEntry)
{
int i;
S_CLASSIFIER_ENTRY *psClassifierRules = NULL;
for(i=0;i<MAX_PHSRULE_PER_SF;i++)
{
if(eClsContext == eActiveClassifierRuleContext)
{
psClassifierRules = &pstClassifierTable->stActivePhsRulesList[i];
}
else
{
psClassifierRules = &pstClassifierTable->stOldPhsRulesList[i];
}
if(psClassifierRules->bUsed)
{
if(psClassifierRules->uiClassifierRuleId == uiClsid)
{
*ppstClassifierEntry = psClassifierRules;
return i;
}
}
}
*ppstClassifierEntry = NULL;
return PHS_INVALID_TABLE_INDEX;
}
static UINT GetPhsRuleEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
IN B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,
OUT S_PHS_RULE **ppstPhsRule)
{
int i;
S_CLASSIFIER_ENTRY *pstClassifierRule = NULL;
for(i=0;i<MAX_PHSRULE_PER_SF;i++)
{
if(eClsContext == eActiveClassifierRuleContext)
{
pstClassifierRule = &pstClassifierTable->stActivePhsRulesList[i];
}
else
{
pstClassifierRule = &pstClassifierTable->stOldPhsRulesList[i];
}
if(pstClassifierRule->bUsed)
{
if(pstClassifierRule->u8PHSI == uiPHSI)
{
*ppstPhsRule = pstClassifierRule->pstPhsRule;
return i;
}
}
}
*ppstPhsRule = NULL;
return PHS_INVALID_TABLE_INDEX;
}
UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid,IN B_UINT16 uiClsId,
IN S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,
B_UINT8 u8AssociatedPHSI)
{
S_CLASSIFIER_TABLE *psaClassifiertable = NULL;
UINT uiStatus = 0;
int iSfIndex;
BOOLEAN bFreeEntryFound =FALSE;
//Check for a free entry in SFID table
for(iSfIndex=0;iSfIndex < MAX_SERVICEFLOWS;iSfIndex++)
{
if(!psServiceFlowTable->stSFList[iSfIndex].bUsed)
{
bFreeEntryFound = TRUE;
break;
}
}
if(!bFreeEntryFound)
return ERR_SFTABLE_FULL;
psaClassifiertable = psServiceFlowTable->stSFList[iSfIndex].pstClassifierTable;
uiStatus = CreateClassifierPHSRule(uiClsId,psaClassifiertable,psPhsRule,
eActiveClassifierRuleContext,u8AssociatedPHSI);
if(uiStatus == PHS_SUCCESS)
{
//Add entry at free index to the SF
psServiceFlowTable->stSFList[iSfIndex].bUsed = TRUE;
psServiceFlowTable->stSFList[iSfIndex].uiVcid = uiVcid;
}
return uiStatus;
}
UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
IN B_UINT16 uiClsId,IN S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,
S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI)
{
S_CLASSIFIER_ENTRY *pstClassifierEntry = NULL;
UINT uiStatus =PHS_SUCCESS;
UINT nClassifierIndex = 0;
S_CLASSIFIER_TABLE *psaClassifiertable = NULL;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
psaClassifiertable = pstServiceFlowEntry->pstClassifierTable;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "==>");
/* Check if the supplied Classifier already exists */
nClassifierIndex =GetClassifierEntry(
pstServiceFlowEntry->pstClassifierTable,uiClsId,
eActiveClassifierRuleContext,&pstClassifierEntry);
if(nClassifierIndex == PHS_INVALID_TABLE_INDEX)
{
/*
The Classifier doesn't exist. So its a new classifier being added.
Add new entry to associate PHS Rule to the Classifier
*/
uiStatus = CreateClassifierPHSRule(uiClsId,psaClassifiertable,
psPhsRule,eActiveClassifierRuleContext,u8AssociatedPHSI);
return uiStatus;
}
/*
The Classifier exists.The PHS Rule for this classifier
is being modified
*/
if(pstClassifierEntry->u8PHSI == psPhsRule->u8PHSI)
{
if(pstClassifierEntry->pstPhsRule == NULL)
return ERR_PHS_INVALID_PHS_RULE;
/*
This rule already exists if any fields are changed for this PHS
rule update them.
*/
/* If any part of PHSF is valid then we update PHSF */
if(psPhsRule->u8PHSFLength)
{
//update PHSF
memcpy(pstClassifierEntry->pstPhsRule->u8PHSF,
psPhsRule->u8PHSF , MAX_PHS_LENGTHS);
}
if(psPhsRule->u8PHSFLength)
{
//update PHSFLen
pstClassifierEntry->pstPhsRule->u8PHSFLength =
psPhsRule->u8PHSFLength;
}
if(psPhsRule->u8PHSMLength)
{
//update PHSM
memcpy(pstClassifierEntry->pstPhsRule->u8PHSM,
psPhsRule->u8PHSM, MAX_PHS_LENGTHS);
}
if(psPhsRule->u8PHSMLength)
{
//update PHSM Len
pstClassifierEntry->pstPhsRule->u8PHSMLength =
psPhsRule->u8PHSMLength;
}
if(psPhsRule->u8PHSS)
{
//update PHSS
pstClassifierEntry->pstPhsRule->u8PHSS = psPhsRule->u8PHSS;
}
//update PHSV
pstClassifierEntry->pstPhsRule->u8PHSV = psPhsRule->u8PHSV;
}
else
{
/*
A new rule is being set for this classifier.
*/
uiStatus=UpdateClassifierPHSRule( uiClsId, pstClassifierEntry,
psaClassifiertable, psPhsRule, u8AssociatedPHSI);
}
return uiStatus;
}
static UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,
E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI)
{
UINT iClassifierIndex = 0;
BOOLEAN bFreeEntryFound = FALSE;
S_CLASSIFIER_ENTRY *psClassifierRules = NULL;
UINT nStatus = PHS_SUCCESS;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"Inside CreateClassifierPHSRule");
if(psaClassifiertable == NULL)
{
return ERR_INVALID_CLASSIFIERTABLE_FOR_SF;
}
if(eClsContext == eOldClassifierRuleContext)
{
/* If An Old Entry for this classifier ID already exists in the
old rules table replace it. */
iClassifierIndex =
GetClassifierEntry(psaClassifiertable, uiClsId,
eClsContext,&psClassifierRules);
if(iClassifierIndex != PHS_INVALID_TABLE_INDEX)
{
/*
The Classifier already exists in the old rules table
Lets replace the old classifier with the new one.
*/
bFreeEntryFound = TRUE;
}
}
if(!bFreeEntryFound)
{
/*
Continue to search for a free location to add the rule
*/
for(iClassifierIndex = 0; iClassifierIndex <
MAX_PHSRULE_PER_SF; iClassifierIndex++)
{
if(eClsContext == eActiveClassifierRuleContext)
{
psClassifierRules =
&psaClassifiertable->stActivePhsRulesList[iClassifierIndex];
}
else
{
psClassifierRules =
&psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
}
if(!psClassifierRules->bUsed)
{
bFreeEntryFound = TRUE;
break;
}
}
}
if(!bFreeEntryFound)
{
if(eClsContext == eActiveClassifierRuleContext)
{
return ERR_CLSASSIFIER_TABLE_FULL;
}
else
{
//Lets replace the oldest rule if we are looking in old Rule table
if(psaClassifiertable->uiOldestPhsRuleIndex >=
MAX_PHSRULE_PER_SF)
{
psaClassifiertable->uiOldestPhsRuleIndex =0;
}
iClassifierIndex = psaClassifiertable->uiOldestPhsRuleIndex;
psClassifierRules =
&psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
(psaClassifiertable->uiOldestPhsRuleIndex)++;
}
}
if(eClsContext == eOldClassifierRuleContext)
{
if(psClassifierRules->pstPhsRule == NULL)
{
psClassifierRules->pstPhsRule = kmalloc(sizeof(S_PHS_RULE),GFP_KERNEL);
if(NULL == psClassifierRules->pstPhsRule)
return ERR_PHSRULE_MEMALLOC_FAIL;
}
psClassifierRules->bUsed = TRUE;
psClassifierRules->uiClassifierRuleId = uiClsId;
psClassifierRules->u8PHSI = psPhsRule->u8PHSI;
psClassifierRules->bUnclassifiedPHSRule = psPhsRule->bUnclassifiedPHSRule;
/* Update The PHS rule */
memcpy(psClassifierRules->pstPhsRule,
psPhsRule, sizeof(S_PHS_RULE));
}
else
{
nStatus = UpdateClassifierPHSRule(uiClsId,psClassifierRules,
psaClassifiertable,psPhsRule,u8AssociatedPHSI);
}
return nStatus;
}
static UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
IN S_CLASSIFIER_ENTRY *pstClassifierEntry,
S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,
B_UINT8 u8AssociatedPHSI)
{
S_PHS_RULE *pstAddPhsRule = NULL;
UINT nPhsRuleIndex = 0;
BOOLEAN bPHSRuleOrphaned = FALSE;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
psPhsRule->u8RefCnt =0;
/* Step 1 Deref Any Exisiting PHS Rule in this classifier Entry*/
bPHSRuleOrphaned = DerefPhsRule( uiClsId, psaClassifiertable,
pstClassifierEntry->pstPhsRule);
//Step 2 Search if there is a PHS Rule with u8AssociatedPHSI in Classifier table for this SF
nPhsRuleIndex =GetPhsRuleEntry(psaClassifiertable,u8AssociatedPHSI,
eActiveClassifierRuleContext, &pstAddPhsRule);
if(PHS_INVALID_TABLE_INDEX == nPhsRuleIndex)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAdding New PHSRuleEntry For Classifier");
if(psPhsRule->u8PHSI == 0)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nError PHSI is Zero\n");
return ERR_PHS_INVALID_PHS_RULE;
}
//Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId
if(FALSE == bPHSRuleOrphaned)
{
pstClassifierEntry->pstPhsRule = kmalloc(sizeof(S_PHS_RULE), GFP_KERNEL);
if(NULL == pstClassifierEntry->pstPhsRule)
{
return ERR_PHSRULE_MEMALLOC_FAIL;
}
}
memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE));
}
else
{
//Step 2.b PHS Rule Exists Tie uiClsId with the existing PHS Rule
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule");
if(bPHSRuleOrphaned)
{
kfree(pstClassifierEntry->pstPhsRule);
pstClassifierEntry->pstPhsRule = NULL;
}
pstClassifierEntry->pstPhsRule = pstAddPhsRule;
}
pstClassifierEntry->bUsed = TRUE;
pstClassifierEntry->u8PHSI = pstClassifierEntry->pstPhsRule->u8PHSI;
pstClassifierEntry->uiClassifierRuleId = uiClsId;
pstClassifierEntry->pstPhsRule->u8RefCnt++;
pstClassifierEntry->bUnclassifiedPHSRule = pstClassifierEntry->pstPhsRule->bUnclassifiedPHSRule;
return PHS_SUCCESS;
}
static BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule)
{
if(pstPhsRule==NULL)
return FALSE;
if(pstPhsRule->u8RefCnt)
pstPhsRule->u8RefCnt--;
if(0==pstPhsRule->u8RefCnt)
{
/*if(pstPhsRule->u8PHSI)
//Store the currently active rule into the old rules list
CreateClassifierPHSRule(uiClsId,psaClassifiertable,pstPhsRule,eOldClassifierRuleContext,pstPhsRule->u8PHSI);*/
return TRUE;
}
else
{
return FALSE;
}
}
void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension)
{
int i,j,k,l;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n Dumping PHS Rules : \n");
for(i=0;i<MAX_SERVICEFLOWS;i++)
{
S_SERVICEFLOW_ENTRY stServFlowEntry =
pDeviceExtension->pstServiceFlowPhsRulesTable->stSFList[i];
if(stServFlowEntry.bUsed)
{
for(j=0;j<MAX_PHSRULE_PER_SF;j++)
{
for(l=0;l<2;l++)
{
S_CLASSIFIER_ENTRY stClsEntry;
if(l==0)
{
stClsEntry = stServFlowEntry.pstClassifierTable->stActivePhsRulesList[j];
if(stClsEntry.bUsed)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Active PHS Rule : \n");
}
else
{
stClsEntry = stServFlowEntry.pstClassifierTable->stOldPhsRulesList[j];
if(stClsEntry.bUsed)
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Old PHS Rule : \n");
}
if(stClsEntry.bUsed)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n VCID : %#X",stServFlowEntry.uiVcid);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n ClassifierID : %#X",stClsEntry.uiClassifierRuleId);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSRuleID : %#X",stClsEntry.u8PHSI);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n****************PHS Rule********************\n");
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSI : %#X",stClsEntry.pstPhsRule->u8PHSI);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSFLength : %#X ",stClsEntry.pstPhsRule->u8PHSFLength);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSF : ");
for(k=0;k<stClsEntry.pstPhsRule->u8PHSFLength;k++)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ",stClsEntry.pstPhsRule->u8PHSF[k]);
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSMLength : %#X",stClsEntry.pstPhsRule->u8PHSMLength);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSM :");
for(k=0;k<stClsEntry.pstPhsRule->u8PHSMLength;k++)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ",stClsEntry.pstPhsRule->u8PHSM[k]);
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSS : %#X ",stClsEntry.pstPhsRule->u8PHSS);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSV : %#X",stClsEntry.pstPhsRule->u8PHSV);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n********************************************\n");
}
}
}
}
}
}
//-----------------------------------------------------------------------------
// Procedure: phs_decompress
//
// Description: This routine restores the static fields within the packet.
//
// Arguments:
// in_buf - ptr to incoming packet buffer.
// out_buf - ptr to output buffer where the suppressed header is copied.
// decomp_phs_rules - ptr to PHS rule.
// header_size - ptr to field which holds the phss or phsf_length.
//
// Returns:
// size -The number of bytes of dynamic fields present with in the incoming packet
// header.
// 0 -If PHS rule is NULL.If PHSI is 0 indicateing packet as uncompressed.
//-----------------------------------------------------------------------------
int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,
S_PHS_RULE *decomp_phs_rules,UINT *header_size)
{
int phss,size=0;
S_PHS_RULE *tmp_memb;
int bit,i=0;
unsigned char *phsf,*phsm;
int in_buf_len = *header_size-1;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
in_buf++;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"====>\n");
*header_size = 0;
if((decomp_phs_rules == NULL ))
return 0;
tmp_memb = decomp_phs_rules;
//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phs_decompress PHSI 1 %d",phsi));
//*header_size = tmp_memb->u8PHSFLength;
phss = tmp_memb->u8PHSS;
phsf = tmp_memb->u8PHSF;
phsm = tmp_memb->u8PHSM;
if(phss > MAX_PHS_LENGTHS)
phss = MAX_PHS_LENGTHS;
//BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phs_decompress PHSI %d phss %d index %d",phsi,phss,index));
while((phss > 0) && (size < in_buf_len))
{
bit = ((*phsm << i)& SUPPRESS);
if(bit == SUPPRESS)
{
*out_buf = *phsf;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phss %d phsf %d ouput %d",
phss,*phsf,*out_buf);
}
else
{
*out_buf = *in_buf;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phss %d input %d ouput %d",
phss,*in_buf,*out_buf);
in_buf++;
size++;
}
out_buf++;
phsf++;
phss--;
i++;
*header_size=*header_size + 1;
if(i > MAX_NO_BIT)
{
i=0;
phsm++;
}
}
return size;
}
//-----------------------------------------------------------------------------
// Procedure: phs_compress
//
// Description: This routine suppresses the static fields within the packet.Before
// that it will verify the fields to be suppressed with the corresponding fields in the
// phsf. For verification it checks the phsv field of PHS rule. If set and verification
// succeeds it suppresses the field.If any one static field is found different none of
// the static fields are suppressed then the packet is sent as uncompressed packet with
// phsi=0.
//
// Arguments:
// phs_rule - ptr to PHS rule.
// in_buf - ptr to incoming packet buffer.
// out_buf - ptr to output buffer where the suppressed header is copied.
// header_size - ptr to field which holds the phss.
//
// Returns:
// size-The number of bytes copied into the output buffer i.e dynamic fields
// 0 -If PHS rule is NULL.If PHSV field is not set.If the verification fails.
//-----------------------------------------------------------------------------
static int phs_compress(S_PHS_RULE *phs_rule,unsigned char *in_buf
,unsigned char *out_buf,UINT *header_size,UINT *new_header_size)
{
unsigned char *old_addr = out_buf;
int supress = 0;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
if(phs_rule == NULL)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nphs_compress(): phs_rule null!");
*out_buf = ZERO_PHSI;
return STATUS_PHS_NOCOMPRESSION;
}
if(phs_rule->u8PHSS <= *new_header_size)
{
*header_size = phs_rule->u8PHSS;
}
else
{
*header_size = *new_header_size;
}
//To copy PHSI
out_buf++;
supress = verify_suppress_phsf(in_buf,out_buf,phs_rule->u8PHSF,
phs_rule->u8PHSM, phs_rule->u8PHSS, phs_rule->u8PHSV,new_header_size);
if(supress == STATUS_PHS_COMPRESSED)
{
*old_addr = (unsigned char)phs_rule->u8PHSI;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In phs_compress phsi %d",phs_rule->u8PHSI);
}
else
{
*old_addr = ZERO_PHSI;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In phs_compress PHSV Verification failed");
}
return supress;
}
//-----------------------------------------------------------------------------
// Procedure: verify_suppress_phsf
//
// Description: This routine verifies the fields of the packet and if all the
// static fields are equal it adds the phsi of that PHS rule.If any static
// field differs it woun't suppress any field.
//
// Arguments:
// rules_set - ptr to classifier_rules.
// in_buffer - ptr to incoming packet buffer.
// out_buffer - ptr to output buffer where the suppressed header is copied.
// phsf - ptr to phsf.
// phsm - ptr to phsm.
// phss - variable holding phss.
//
// Returns:
// size-The number of bytes copied into the output buffer i.e dynamic fields.
// 0 -Packet has failed the verification.
//-----------------------------------------------------------------------------
static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
unsigned char *phsf,unsigned char *phsm,unsigned int phss,
unsigned int phsv,UINT* new_header_size)
{
unsigned int size=0;
int bit,i=0;
PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf PHSM - 0x%X",*phsm);
if(phss>(*new_header_size))
{
phss=*new_header_size;
}
while(phss > 0)
{
bit = ((*phsm << i)& SUPPRESS);
if(bit == SUPPRESS)
{
if(*in_buffer != *phsf)
{
if(phsv == VERIFY)
{
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf failed for field %d buf %d phsf %d",phss,*in_buffer,*phsf);
return STATUS_PHS_NOCOMPRESSION;
}
}
else
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf success for field %d buf %d phsf %d",phss,*in_buffer,*phsf);
}
else
{
*out_buffer = *in_buffer;
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In copying_header input %d out %d",*in_buffer,*out_buffer);
out_buffer++;
size++;
}
in_buffer++;
phsf++;
phss--;
i++;
if(i > MAX_NO_BIT)
{
i=0;
phsm++;
}
}
BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf success");
*new_header_size = size;
return STATUS_PHS_COMPRESSED;
}