#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; }