1451 lines · 48.9 KB · C
RawDownload
#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.