| #include "headers.h" | |
| static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid, B_UINT16 uiClsId, struct bcm_phs_table *psServiceFlowTable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI); | |
| static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid, B_UINT16 uiClsId, struct bcm_phs_entry *pstServiceFlowEntry, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI); | |
| static UINT CreateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, enum bcm_phs_classifier_context eClsContext, B_UINT8 u8AssociatedPHSI); | |
| static UINT UpdateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_entry *pstClassifierEntry, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI); | |
| static BOOLEAN ValidatePHSRuleComplete(struct bcm_phs_rule *psPhsRule); | |
| static BOOLEAN DerefPhsRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule); | |
| static UINT GetClassifierEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_classifier_entry **ppstClassifierEntry); | |
| static UINT GetPhsRuleEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_rule **ppstPhsRule); | |
| static void free_phs_serviceflow_rules(struct bcm_phs_table *psServiceFlowRulesTable); | |
| static int phs_compress(struct bcm_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, | |
| struct bcm_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 suppresses the header by invoking PHS exported compress routine. | |
| * The header data after suppression is copied back to the NDIS_PACKET. | |
| * | |
| * Input parameters: IN struct bcm_mini_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 occurred. | |
| */ | |
| int PHSTransmit(struct bcm_mini_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.ucaHdrSuppressionInBuf; | |
| /* Pointer to PHS OUT Hdr Buffer */ | |
| PUCHAR pucPHSPktHdrOutBuf = Adapter->stPhsTxContextInfo.ucaHdrSuppressionOutBuf; | |
| 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 suppression | |
| * 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 Suppress 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(struct bcm_mini_adapter *Adapter, | |
| USHORT usVcid, | |
| struct sk_buff *packet, | |
| UINT *punPacketLen, | |
| UCHAR *pucEthernetHdr, | |
| UINT bHeaderSuppressionEnabled) | |
| { | |
| u32 nStandardPktHdrLen = 0; | |
| u32 nTotalsuppressedPktHdrBytes = 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, | |
| &nTotalsuppressedPktHdrBytes, | |
| &nStandardPktHdrLen); | |
| BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nSuppressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x", | |
| nTotalsuppressedPktHdrBytes, nStandardPktHdrLen); | |
| if (ulPhsStatus != STATUS_PHS_COMPRESSED) { | |
| skb_pull(packet, 1); | |
| return STATUS_SUCCESS; | |
| } else { | |
| TotalBytesAdded = nStandardPktHdrLen - nTotalsuppressedPktHdrBytes - 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) | |
| { | |
| struct bcm_mini_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 successful. | |
| * FALSE -If allocation of memory fails. | |
| */ | |
| int phs_init(struct bcm_phs_extension *pPhsdeviceExtension, struct bcm_mini_adapter *Adapter) | |
| { | |
| int i; | |
| struct bcm_phs_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(struct bcm_phs_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++) { | |
| struct bcm_phs_entry sServiceFlow = pstServiceFlowTable->stSFList[i]; | |
| sServiceFlow.pstClassifierTable = kzalloc(sizeof(struct bcm_phs_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 Successful"); | |
| return STATUS_SUCCESS; | |
| } | |
| int PhsCleanup(IN struct bcm_phs_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 struct bcm_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 struct bcm_phs_rule *psPhsRule, | |
| IN B_UINT8 u8AssociatedPHSI) | |
| { | |
| ULONG lStatus = 0; | |
| UINT nSFIndex = 0; | |
| struct bcm_phs_entry *pstServiceFlowEntry = NULL; | |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); | |
| struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_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; | |
| struct bcm_phs_entry *pstServiceFlowEntry = NULL; | |
| struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL; | |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); | |
| struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_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(struct bcm_phs_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; | |
| struct bcm_phs_entry *pstServiceFlowEntry = NULL; | |
| struct bcm_phs_classifier_entry *pstClassifierEntry = NULL; | |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); | |
| struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_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(struct bcm_phs_classifier_entry)); | |
| } | |
| nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable, | |
| uiClsId, eOldClassifierRuleContext, &pstClassifierEntry); | |
| if ((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) { | |
| kfree(pstClassifierEntry->pstPhsRule); | |
| memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_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; | |
| struct bcm_phs_entry *pstServiceFlowEntry = NULL; | |
| struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL; | |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); | |
| struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_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(struct bcm_phs_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(struct bcm_phs_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; | |
| struct bcm_phs_entry *pstServiceFlowEntry = NULL; | |
| struct bcm_phs_classifier_entry *pstClassifierEntry = NULL; | |
| struct bcm_phs_rule *pstPhsRule = NULL; | |
| ULONG lStatus = 0; | |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); | |
| struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_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; | |
| struct bcm_phs_entry *pstServiceFlowEntry = NULL; | |
| struct bcm_phs_rule *pstPhsRule = NULL; | |
| UINT phsi; | |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); | |
| struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_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(struct bcm_phs_table *psServiceFlowRulesTable) | |
| { | |
| int i, j; | |
| struct bcm_mini_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++) { | |
| struct bcm_phs_entry stServiceFlowEntry = psServiceFlowRulesTable->stSFList[i]; | |
| struct bcm_phs_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 struct bcm_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 struct bcm_phs_table *psServiceFlowTable, | |
| IN B_UINT16 uiVcid, | |
| struct bcm_phs_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 struct bcm_phs_classifier_table *pstClassifierTable, | |
| IN B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, | |
| OUT struct bcm_phs_classifier_entry **ppstClassifierEntry) | |
| { | |
| int i; | |
| struct bcm_phs_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 struct bcm_phs_classifier_table *pstClassifierTable, | |
| IN B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext, | |
| OUT struct bcm_phs_rule **ppstPhsRule) | |
| { | |
| int i; | |
| struct bcm_phs_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 struct bcm_phs_table *psServiceFlowTable, | |
| struct bcm_phs_rule *psPhsRule, | |
| B_UINT8 u8AssociatedPHSI) | |
| { | |
| struct bcm_phs_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 struct bcm_phs_entry *pstServiceFlowEntry, | |
| struct bcm_phs_rule *psPhsRule, | |
| B_UINT8 u8AssociatedPHSI) | |
| { | |
| struct bcm_phs_classifier_entry *pstClassifierEntry = NULL; | |
| UINT uiStatus = PHS_SUCCESS; | |
| UINT nClassifierIndex = 0; | |
| struct bcm_phs_classifier_table *psaClassifiertable = NULL; | |
| struct bcm_mini_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, | |
| struct bcm_phs_classifier_table *psaClassifiertable, | |
| struct bcm_phs_rule *psPhsRule, | |
| enum bcm_phs_classifier_context eClsContext, | |
| B_UINT8 u8AssociatedPHSI) | |
| { | |
| UINT iClassifierIndex = 0; | |
| BOOLEAN bFreeEntryFound = FALSE; | |
| struct bcm_phs_classifier_entry *psClassifierRules = NULL; | |
| UINT nStatus = PHS_SUCCESS; | |
| struct bcm_mini_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(struct bcm_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(struct bcm_phs_rule)); | |
| } else | |
| nStatus = UpdateClassifierPHSRule(uiClsId, psClassifierRules, | |
| psaClassifiertable, psPhsRule, u8AssociatedPHSI); | |
| return nStatus; | |
| } | |
| static UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId, | |
| IN struct bcm_phs_classifier_entry *pstClassifierEntry, | |
| struct bcm_phs_classifier_table *psaClassifiertable, | |
| struct bcm_phs_rule *psPhsRule, | |
| B_UINT8 u8AssociatedPHSI) | |
| { | |
| struct bcm_phs_rule *pstAddPhsRule = NULL; | |
| UINT nPhsRuleIndex = 0; | |
| BOOLEAN bPHSRuleOrphaned = FALSE; | |
| struct bcm_mini_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(struct bcm_phs_rule), GFP_KERNEL); | |
| if (NULL == pstClassifierEntry->pstPhsRule) | |
| return ERR_PHSRULE_MEMALLOC_FAIL; | |
| } | |
| memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(struct bcm_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, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_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(struct bcm_phs_extension *pDeviceExtension) | |
| { | |
| int i, j, k, l; | |
| struct bcm_mini_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++) { | |
| struct bcm_phs_entry stServFlowEntry = | |
| pDeviceExtension->pstServiceFlowPhsRulesTable->stSFList[i]; | |
| if (stServFlowEntry.bUsed) { | |
| for (j = 0; j < MAX_PHSRULE_PER_SF; j++) { | |
| for (l = 0; l < 2; l++) { | |
| struct bcm_phs_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, | |
| struct bcm_phs_rule *decomp_phs_rules, | |
| UINT *header_size) | |
| { | |
| int phss, size = 0; | |
| struct bcm_phs_rule *tmp_memb; | |
| int bit, i = 0; | |
| unsigned char *phsf, *phsm; | |
| int in_buf_len = *header_size - 1; | |
| struct bcm_mini_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(struct bcm_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 suppress = 0; | |
| struct bcm_mini_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++; | |
| suppress = verify_suppress_phsf(in_buf, out_buf, phs_rule->u8PHSF, | |
| phs_rule->u8PHSM, phs_rule->u8PHSS, | |
| phs_rule->u8PHSV, new_header_size); | |
| if (suppress == 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 suppress; | |
| } | |
| /* | |
| * 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; | |
| struct bcm_mini_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; | |
| } |