#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;istSFList[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;nClsidIndexstActivePhsRulesList[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;nClsidIndexstActivePhsRulesList[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;istSFList[i]; S_CLASSIFIER_TABLE *pstClassifierRulesTable = stServiceFlowEntry.pstClassifierTable; if(pstClassifierRulesTable) { for(j=0;jstActivePhsRulesList[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;istSFList[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;istActivePhsRulesList[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;istActivePhsRulesList[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;ipstServiceFlowPhsRulesTable->stSFList[i]; if(stServFlowEntry.bUsed) { for(j=0;jstActivePhsRulesList[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;ku8PHSFLength;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;ku8PHSMLength;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; }