#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 bool ValidatePHSRuleComplete(struct bcm_phs_rule *psPhsRule); static bool 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, bool 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; bool 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);Lines 1–500 of 1451. Load more
#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 bool ValidatePHSRuleComplete(struct bcm_phs_rule *psPhsRule); static bool 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, bool 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; bool 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);