diff options
author | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2010-09-08 14:46:36 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-09-08 21:15:06 -0700 |
commit | f8942e07a3db9d82e8fb11d3d494876b8bae9ff9 (patch) | |
tree | 2406636a4f9a4ac6b0bfc90e07aefa8b1b18b8ff /drivers/staging/bcm/PHSModule.c | |
parent | 2d2f03b022186e6d7520a758abdea9c04a2969fe (diff) |
staging: Beeceem USB Wimax driver
The Sprint 4G network uses a Wimax dongle with Beecem
chipset. The driver is typical of out of tree drivers, but
maybe useful for people, and the hardware is readily available.
Here is a staging ready version (i.e warts and all)
0. Started with Rel_5.2.7.3P1_USB from Sprint4GDeveloperPack-1.1
1. Consolidated files in staging
2. Remove Dos cr/lf
3. Remove unnecessary ioctl from usbbcm_fops
Applied patches that were in the developer pack, surprising
there were ones for 2.6.35 already.
This is compile tested only, see TODO for what still needs
to be done.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/bcm/PHSModule.c')
-rw-r--r-- | drivers/staging/bcm/PHSModule.c | 1641 |
1 files changed, 1641 insertions, 0 deletions
diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c new file mode 100644 index 00000000000..8ba8489afc2 --- /dev/null +++ b/drivers/staging/bcm/PHSModule.c @@ -0,0 +1,1641 @@ +#include "headers.h" + +#define IN +#define OUT + +void DumpDataPacketHeader(PUCHAR pPkt); + +/* +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)) + { + + + //DumpDataPacketHeader(pucPHSPktHdrInBuf); + + // 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; + + bcm_kfree_skb(Packet); + *pPacket = Packet = newPacket; + pucPHSPktHdrInBuf = Packet->data + BytesToRemove; + } + + numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen+PHSI_LEN); + + OsalMemMove(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN); + OsalMemMove(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 PHSRecieve(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_RECIEVE,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_RECIEVE,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); + } + } + + OsalMemMove(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen); + } + + return STATUS_SUCCESS; +} + +void DumpDataPacketHeader(PUCHAR pPkt) +{ + struct iphdr *iphd = (struct iphdr*)pPkt; + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Phs Send/Recieve : IP Packet Hdr \n"); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"TOS : %x \n",iphd->tos); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Src IP : %x \n",iphd->saddr); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Dest IP : %x \n \n",iphd->daddr); + +} + +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 = + (S_SERVICEFLOW_TABLE*)OsalMemAlloc(sizeof(S_SERVICEFLOW_TABLE), + PHS_MEM_TAG); + + if(pPhsdeviceExtension->pstServiceFlowPhsRulesTable) + { + OsalZeroMemory(pPhsdeviceExtension->pstServiceFlowPhsRulesTable, + sizeof(S_SERVICEFLOW_TABLE)); + } + else + { + 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 = (S_CLASSIFIER_TABLE*)OsalMemAlloc( + sizeof(S_CLASSIFIER_TABLE), PHS_MEM_TAG); + if(sServiceFlow.pstClassifierTable) + { + OsalZeroMemory(sServiceFlow.pstClassifierTable,sizeof(S_CLASSIFIER_TABLE)); + pstServiceFlowTable->stSFList[i].pstClassifierTable = sServiceFlow.pstClassifierTable; + } + else + { + 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 = + OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG); + + 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 = + OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG); + if(pPhsdeviceExtension->UnCompressedRxBuffer == NULL) + { + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed"); + OsalMemFree(pPhsdeviceExtension->CompressedTxBuffer,PHS_BUFFER_SIZE); + 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; + } + + if(pPHSDeviceExt->CompressedTxBuffer) + { + OsalMemFree(pPHSDeviceExt->CompressedTxBuffer,PHS_BUFFER_SIZE); + pPHSDeviceExt->CompressedTxBuffer = NULL; + } + if(pPHSDeviceExt->UnCompressedRxBuffer) + { + OsalMemFree(pPHSDeviceExt->UnCompressedRxBuffer,PHS_BUFFER_SIZE); + 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) + OsalMemFree(pstClassifierRulesTable + ->stActivePhsRulesList[nClsidIndex].pstPhsRule, + sizeof(S_PHS_RULE)); + OsalZeroMemory(&pstClassifierRulesTable + ->stActivePhsRulesList[nClsidIndex], + 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) + OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE)); + + } + OsalZeroMemory(pstClassifierEntry,sizeof(S_CLASSIFIER_ENTRY)); + } + + nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable, + uiClsId,eOldClassifierRuleContext,&pstClassifierEntry); + + if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) + { + if(pstClassifierEntry->pstPhsRule) + //Delete the classifier entry + OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE)); + OsalZeroMemory(pstClassifierEntry,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) + OsalMemFree(pstClassifierRulesTable + ->stActivePhsRulesList[nClsidIndex].pstPhsRule, + sizeof(S_PHS_RULE)); + pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex] + .pstPhsRule = NULL; + } + OsalZeroMemory(&pstClassifierRulesTable + ->stActivePhsRulesList[nClsidIndex],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) + OsalMemFree(pstClassifierRulesTable + ->stOldPhsRulesList[nClsidIndex].pstPhsRule, + sizeof(S_PHS_RULE)); + pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex] + .pstPhsRule = NULL; + } + OsalZeroMemory(&pstClassifierRulesTable + ->stOldPhsRulesList[nClsidIndex], + 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_RECIEVE,DBG_LVL_ALL,"Invalid Device Extension\n"); + return ERR_PHS_INVALID_DEVICE_EXETENSION; + } + + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECIEVE,DBG_LVL_ALL,"Restoring header \n"); + + phsi = *((unsigned char *)(pvInputBuffer)); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECIEVE,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_RECIEVE,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. +//----------------------------------------------------------------------------- + +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) + OsalMemFree(pstClassifierRulesTable->stActivePhsRulesList[j]. + pstPhsRule, sizeof(S_PHS_RULE)); + 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) + OsalMemFree(pstClassifierRulesTable->stOldPhsRulesList[j] + .pstPhsRule,sizeof(S_PHS_RULE)); + pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL; + } + } + OsalMemFree(pstClassifierRulesTable,sizeof(S_CLASSIFIER_TABLE)); + stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL; + } + } + } + + OsalMemFree(psServiceFlowRulesTable,sizeof(S_SERVICEFLOW_TABLE)); + psServiceFlowRulesTable = NULL; +} + + + +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; +} + +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, + |