]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/bcm/PHSModule.c
Merge remote-tracking branch 'staging/staging-next'
[karo-tx-linux.git] / drivers / staging / bcm / PHSModule.c
1 #include "headers.h"
2
3 static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid, B_UINT16 uiClsId, struct bcm_phs_table *psServiceFlowTable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
4
5 static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid, B_UINT16  uiClsId, struct bcm_phs_entry *pstServiceFlowEntry, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
6
7 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);
8
9 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);
10
11 static BOOLEAN ValidatePHSRuleComplete(struct bcm_phs_rule *psPhsRule);
12
13 static BOOLEAN DerefPhsRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule);
14
15 static UINT GetClassifierEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_classifier_entry **ppstClassifierEntry);
16
17 static UINT GetPhsRuleEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_rule **ppstPhsRule);
18
19 static void free_phs_serviceflow_rules(struct bcm_phs_table *psServiceFlowRulesTable);
20
21 static int phs_compress(struct bcm_phs_rule *phs_members, unsigned char *in_buf,
22                         unsigned char *out_buf, unsigned int *header_size, UINT *new_header_size);
23
24 static int verify_suppress_phsf(unsigned char *in_buffer, unsigned char *out_buffer,
25                                 unsigned char *phsf, unsigned char *phsm, unsigned int phss, unsigned int phsv, UINT *new_header_size);
26
27 static int phs_decompress(unsigned char *in_buf, unsigned char *out_buf,
28                         struct bcm_phs_rule *phs_rules, UINT *header_size);
29
30 static ULONG PhsCompress(void *pvContext,
31                         B_UINT16 uiVcid,
32                         B_UINT16 uiClsId,
33                         void *pvInputBuffer,
34                         void *pvOutputBuffer,
35                         UINT *pOldHeaderSize,
36                         UINT *pNewHeaderSize);
37
38 static ULONG PhsDeCompress(void *pvContext,
39                         B_UINT16 uiVcid,
40                         void *pvInputBuffer,
41                         void *pvOutputBuffer,
42                         UINT *pInHeaderSize,
43                         UINT *pOutHeaderSize);
44
45 #define IN
46 #define OUT
47
48 /*
49  * Function: PHSTransmit
50  * Description: This routine handle PHS(Payload Header Suppression for Tx path.
51  *      It extracts a fragment of the NDIS_PACKET containing the header
52  *      to be suppressed. It then suppresses the header by invoking PHS exported compress routine.
53  *      The header data after suppression is copied back to the NDIS_PACKET.
54  *
55  * Input parameters: IN struct bcm_mini_adapter *Adapter         - Miniport Adapter Context
56  *      IN Packet - NDIS packet containing data to be transmitted
57  *      IN USHORT Vcid - vcid pertaining to connection on which the packet is being sent.Used to
58  *              identify PHS rule to be applied.
59  *      B_UINT16 uiClassifierRuleID - Classifier Rule ID
60  *      BOOLEAN bHeaderSuppressionEnabled - indicates if header suprression is enabled for SF.
61  *
62  * Return:      STATUS_SUCCESS - If the send was successful.
63  *      Other  - If an error occurred.
64  */
65
66 int PHSTransmit(struct bcm_mini_adapter *Adapter,
67                 struct sk_buff **pPacket,
68                 USHORT Vcid,
69                 B_UINT16 uiClassifierRuleID,
70                 BOOLEAN bHeaderSuppressionEnabled,
71                 UINT *PacketLen,
72                 UCHAR bEthCSSupport)
73 {
74         /* PHS Sepcific */
75         UINT unPHSPktHdrBytesCopied = 0;
76         UINT unPhsOldHdrSize = 0;
77         UINT unPHSNewPktHeaderLen = 0;
78         /* Pointer to PHS IN Hdr Buffer */
79         PUCHAR pucPHSPktHdrInBuf = Adapter->stPhsTxContextInfo.ucaHdrSuppressionInBuf;
80         /* Pointer to PHS OUT Hdr Buffer */
81         PUCHAR pucPHSPktHdrOutBuf = Adapter->stPhsTxContextInfo.ucaHdrSuppressionOutBuf;
82         UINT usPacketType;
83         UINT BytesToRemove = 0;
84         BOOLEAN bPHSI = 0;
85         LONG ulPhsStatus = 0;
86         UINT numBytesCompressed = 0;
87         struct sk_buff *newPacket = NULL;
88         struct sk_buff *Packet = *pPacket;
89
90         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "In PHSTransmit");
91
92         if (!bEthCSSupport)
93                 BytesToRemove = ETH_HLEN;
94         /*
95          * Accumulate the header upto the size we support suppression
96          * from NDIS packet
97          */
98
99         usPacketType = ((struct ethhdr *)(Packet->data))->h_proto;
100
101         pucPHSPktHdrInBuf = Packet->data + BytesToRemove;
102         /* considering data after ethernet header */
103         if ((*PacketLen - BytesToRemove) < MAX_PHS_LENGTHS)
104                 unPHSPktHdrBytesCopied = (*PacketLen - BytesToRemove);
105         else
106                 unPHSPktHdrBytesCopied = MAX_PHS_LENGTHS;
107
108         if ((unPHSPktHdrBytesCopied > 0) &&
109                 (unPHSPktHdrBytesCopied <= MAX_PHS_LENGTHS)) {
110
111                 /*
112                  * Step 2 Suppress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
113                  * Suppress only if IP Header and PHS Enabled For the Service Flow
114                  */
115                 if (((usPacketType == ETHERNET_FRAMETYPE_IPV4) ||
116                                 (usPacketType == ETHERNET_FRAMETYPE_IPV6)) &&
117                         (bHeaderSuppressionEnabled)) {
118
119                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nTrying to PHS Compress Using Classifier rule 0x%X", uiClassifierRuleID);
120                         unPHSNewPktHeaderLen = unPHSPktHdrBytesCopied;
121                         ulPhsStatus = PhsCompress(&Adapter->stBCMPhsContext,
122                                                 Vcid,
123                                                 uiClassifierRuleID,
124                                                 pucPHSPktHdrInBuf,
125                                                 pucPHSPktHdrOutBuf,
126                                                 &unPhsOldHdrSize,
127                                                 &unPHSNewPktHeaderLen);
128                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nPHS Old header Size : %d New Header Size  %d\n", unPhsOldHdrSize, unPHSNewPktHeaderLen);
129
130                         if (unPHSNewPktHeaderLen == unPhsOldHdrSize) {
131
132                                 if (ulPhsStatus == STATUS_PHS_COMPRESSED)
133                                         bPHSI = *pucPHSPktHdrOutBuf;
134
135                                 ulPhsStatus = STATUS_PHS_NOCOMPRESSION;
136                         }
137
138                         if (ulPhsStatus == STATUS_PHS_COMPRESSED) {
139
140                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "PHS Sending packet Compressed");
141
142                                 if (skb_cloned(Packet)) {
143                                         newPacket = skb_copy(Packet, GFP_ATOMIC);
144
145                                         if (newPacket == NULL)
146                                                 return STATUS_FAILURE;
147
148                                         dev_kfree_skb(Packet);
149                                         *pPacket = Packet = newPacket;
150                                         pucPHSPktHdrInBuf = Packet->data  + BytesToRemove;
151                                 }
152
153                                 numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen + PHSI_LEN);
154
155                                 memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
156                                 memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
157                                 skb_pull(Packet, numBytesCompressed);
158
159                                 return STATUS_SUCCESS;
160                         } else {
161                                 /* if one byte headroom is not available, increase it through skb_cow */
162                                 if (!(skb_headroom(Packet) > 0)) {
163
164                                         if (skb_cow(Packet, 1)) {
165                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "SKB Cow Failed\n");
166                                                 return STATUS_FAILURE;
167                                         }
168                                 }
169                                 skb_push(Packet, 1);
170
171                                 /*
172                                  * CAUTION: The MAC Header is getting corrupted
173                                  * here for IP CS - can be saved by copying 14
174                                  * Bytes.  not needed .... hence corrupting it.
175                                  */
176                                 *(Packet->data + BytesToRemove) = bPHSI;
177                                 return STATUS_SUCCESS;
178                         }
179                 } else {
180
181                         if (!bHeaderSuppressionEnabled)
182                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nHeader Suppression Disabled For SF: No PHS\n");
183
184                         return STATUS_SUCCESS;
185                 }
186         }
187
188         /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"PHSTransmit : Dumping data packet After PHS"); */
189         return STATUS_SUCCESS;
190 }
191
192 int PHSReceive(struct bcm_mini_adapter *Adapter,
193         USHORT usVcid,
194         struct sk_buff *packet,
195         UINT *punPacketLen,
196         UCHAR *pucEthernetHdr,
197         UINT bHeaderSuppressionEnabled)
198 {
199         u32 nStandardPktHdrLen = 0;
200         u32 nTotalsuppressedPktHdrBytes = 0;
201         int ulPhsStatus = 0;
202         PUCHAR pucInBuff = NULL;
203         UINT TotalBytesAdded = 0;
204
205         if (!bHeaderSuppressionEnabled) {
206                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nPhs Disabled for incoming packet");
207                 return ulPhsStatus;
208         }
209
210         pucInBuff = packet->data;
211
212         /* Restore PHS suppressed header */
213         nStandardPktHdrLen = packet->len;
214         ulPhsStatus = PhsDeCompress(&Adapter->stBCMPhsContext,
215                                 usVcid,
216                                 pucInBuff,
217                                 Adapter->ucaPHSPktRestoreBuf,
218                                 &nTotalsuppressedPktHdrBytes,
219                                 &nStandardPktHdrLen);
220
221         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nSuppressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x",
222                         nTotalsuppressedPktHdrBytes, nStandardPktHdrLen);
223
224         if (ulPhsStatus != STATUS_PHS_COMPRESSED) {
225                 skb_pull(packet, 1);
226                 return STATUS_SUCCESS;
227         } else {
228                 TotalBytesAdded = nStandardPktHdrLen - nTotalsuppressedPktHdrBytes - PHSI_LEN;
229
230                 if (TotalBytesAdded) {
231                         if (skb_headroom(packet) >= (SKB_RESERVE_ETHERNET_HEADER + TotalBytesAdded))
232                                 skb_push(packet, TotalBytesAdded);
233                         else {
234                                 if (skb_cow(packet, skb_headroom(packet) + TotalBytesAdded)) {
235                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "cow failed in receive\n");
236                                         return STATUS_FAILURE;
237                                 }
238
239                                 skb_push(packet, TotalBytesAdded);
240                         }
241                 }
242
243                 memcpy(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen);
244         }
245
246         return STATUS_SUCCESS;
247 }
248
249 void DumpFullPacket(UCHAR *pBuf, UINT nPktLen)
250 {
251         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
252
253         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dumping Data Packet");
254         BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, pBuf, nPktLen);
255 }
256
257 /*
258  * Procedure:   phs_init
259  *
260  * Description: This routine is responsible for allocating memory for classifier and
261  * PHS rules.
262  *
263  * Arguments:
264  * pPhsdeviceExtension - ptr to Device extension containing PHS Classifier rules and PHS Rules , RX, TX buffer etc
265  *
266  * Returns:
267  * TRUE(1)      -If allocation of memory was successful.
268  * FALSE        -If allocation of memory fails.
269  */
270 int phs_init(struct bcm_phs_extension *pPhsdeviceExtension, struct bcm_mini_adapter *Adapter)
271 {
272         int i;
273         struct bcm_phs_table *pstServiceFlowTable;
274
275         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nPHS:phs_init function");
276
277         if (pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
278                 return -EINVAL;
279
280         pPhsdeviceExtension->pstServiceFlowPhsRulesTable = kzalloc(sizeof(struct bcm_phs_table), GFP_KERNEL);
281
282         if (!pPhsdeviceExtension->pstServiceFlowPhsRulesTable) {
283                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed");
284                 return -ENOMEM;
285         }
286
287         pstServiceFlowTable = pPhsdeviceExtension->pstServiceFlowPhsRulesTable;
288         for (i = 0; i < MAX_SERVICEFLOWS; i++) {
289                 struct bcm_phs_entry sServiceFlow = pstServiceFlowTable->stSFList[i];
290                 sServiceFlow.pstClassifierTable = kzalloc(sizeof(struct bcm_phs_classifier_table), GFP_KERNEL);
291                 if (!sServiceFlow.pstClassifierTable) {
292                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
293                         free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
294                         pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
295                         return -ENOMEM;
296                 }
297         }
298
299         pPhsdeviceExtension->CompressedTxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
300         if (pPhsdeviceExtension->CompressedTxBuffer == NULL) {
301                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
302                 free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
303                 pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
304                 return -ENOMEM;
305         }
306
307         pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
308         if (pPhsdeviceExtension->UnCompressedRxBuffer == NULL) {
309                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
310                 kfree(pPhsdeviceExtension->CompressedTxBuffer);
311                 free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
312                 pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
313                 return -ENOMEM;
314         }
315
316         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successful");
317         return STATUS_SUCCESS;
318 }
319
320 int PhsCleanup(IN struct bcm_phs_extension *pPHSDeviceExt)
321 {
322         if (pPHSDeviceExt->pstServiceFlowPhsRulesTable) {
323                 free_phs_serviceflow_rules(pPHSDeviceExt->pstServiceFlowPhsRulesTable);
324                 pPHSDeviceExt->pstServiceFlowPhsRulesTable = NULL;
325         }
326
327         kfree(pPHSDeviceExt->CompressedTxBuffer);
328         pPHSDeviceExt->CompressedTxBuffer = NULL;
329
330         kfree(pPHSDeviceExt->UnCompressedRxBuffer);
331         pPHSDeviceExt->UnCompressedRxBuffer = NULL;
332
333         return 0;
334 }
335
336 /*
337  * PHS functions
338  * PhsUpdateClassifierRule
339  *
340  * Routine Description:
341  *   Exported function to add or modify a PHS Rule.
342  *
343  * Arguments:
344  *      IN void* pvContext - PHS Driver Specific Context
345  *      IN B_UINT16 uiVcid    - The Service Flow ID for which the PHS rule applies
346  *      IN B_UINT16  uiClsId   - The Classifier ID within the Service Flow for which the PHS rule applies.
347  *      IN struct bcm_phs_rule *psPhsRule - The PHS Rule strcuture to be added to the PHS Rule table.
348  *
349  * Return Value:
350  *
351  * 0 if successful,
352  * >0 Error.
353  */
354 ULONG PhsUpdateClassifierRule(IN void *pvContext,
355                         IN B_UINT16 uiVcid ,
356                         IN B_UINT16 uiClsId   ,
357                         IN struct bcm_phs_rule *psPhsRule,
358                         IN B_UINT8 u8AssociatedPHSI)
359 {
360         ULONG lStatus = 0;
361         UINT nSFIndex = 0;
362         struct bcm_phs_entry *pstServiceFlowEntry = NULL;
363         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
364         struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
365
366         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "PHS With Corr2 Changes\n");
367
368         if (pDeviceExtension == NULL) {
369                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "Invalid Device Extension\n");
370                 return ERR_PHS_INVALID_DEVICE_EXETENSION;
371         }
372
373         if (u8AssociatedPHSI == 0)
374                 return ERR_PHS_INVALID_PHS_RULE;
375
376         /* Retrieve the SFID Entry Index for requested Service Flow */
377         nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
378                                 uiVcid, &pstServiceFlowEntry);
379
380         if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
381                 /* This is a new SF. Create a mapping entry for this */
382                 lStatus = CreateSFToClassifierRuleMapping(uiVcid, uiClsId,
383                                                         pDeviceExtension->pstServiceFlowPhsRulesTable, psPhsRule, u8AssociatedPHSI);
384                 return lStatus;
385         }
386
387         /* SF already Exists Add PHS Rule to existing SF */
388         lStatus = CreateClassiferToPHSRuleMapping(uiVcid, uiClsId,
389                                                 pstServiceFlowEntry, psPhsRule, u8AssociatedPHSI);
390
391         return lStatus;
392 }
393
394 /*
395  * PhsDeletePHSRule
396  *
397  * Routine Description:
398  *   Deletes the specified phs Rule within Vcid
399  *
400  * Arguments:
401  *      IN void* pvContext - PHS Driver Specific Context
402  *      IN B_UINT16  uiVcid    - The Service Flow ID for which the PHS rule applies
403  *      IN B_UINT8  u8PHSI   - the PHS Index identifying PHS rule to be deleted.
404  *
405  * Return Value:
406  *
407  * 0 if successful,
408  * >0 Error.
409  */
410 ULONG PhsDeletePHSRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT8 u8PHSI)
411 {
412         ULONG lStatus = 0;
413         UINT nSFIndex = 0, nClsidIndex = 0;
414         struct bcm_phs_entry *pstServiceFlowEntry = NULL;
415         struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL;
416         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
417         struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
418
419         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "======>\n");
420
421         if (pDeviceExtension) {
422                 /* Retrieve the SFID Entry Index for requested Service Flow */
423                 nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry);
424
425                 if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
426                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
427                         return ERR_SF_MATCH_FAIL;
428                 }
429
430                 pstClassifierRulesTable = pstServiceFlowEntry->pstClassifierTable;
431                 if (pstClassifierRulesTable) {
432                         for (nClsidIndex = 0; nClsidIndex < MAX_PHSRULE_PER_SF; nClsidIndex++) {
433                                 if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule) {
434                                         if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI) {
435
436                                                 if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
437                                                         pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
438
439                                                 if (0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
440                                                         kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
441
442                                                 memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0,
443                                                         sizeof(struct bcm_phs_classifier_entry));
444                                         }
445                                 }
446                         }
447                 }
448         }
449         return lStatus;
450 }
451
452 /*
453  * PhsDeleteClassifierRule
454  *
455  * Routine Description:
456  *    Exported function to Delete a PHS Rule for the SFID,CLSID Pair.
457  *
458  * Arguments:
459  *      IN void* pvContext - PHS Driver Specific Context
460  *      IN B_UINT16  uiVcid    - The Service Flow ID for which the PHS rule applies
461  *      IN B_UINT16  uiClsId   - The Classifier ID within the Service Flow for which the PHS rule applies.
462  *
463  * Return Value:
464  *
465  * 0 if successful,
466  * >0 Error.
467  */
468 ULONG PhsDeleteClassifierRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT16 uiClsId)
469 {
470         ULONG lStatus = 0;
471         UINT nSFIndex = 0, nClsidIndex = 0;
472         struct bcm_phs_entry *pstServiceFlowEntry = NULL;
473         struct bcm_phs_classifier_entry *pstClassifierEntry = NULL;
474         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
475         struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
476
477         if (pDeviceExtension) {
478                 /* Retrieve the SFID Entry Index for requested Service Flow */
479                 nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry);
480                 if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
481                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
482                         return ERR_SF_MATCH_FAIL;
483                 }
484
485                 nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
486                                                 uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry);
487
488                 if ((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) {
489                         if (pstClassifierEntry->pstPhsRule) {
490                                 if (pstClassifierEntry->pstPhsRule->u8RefCnt)
491                                         pstClassifierEntry->pstPhsRule->u8RefCnt--;
492
493                                 if (0 == pstClassifierEntry->pstPhsRule->u8RefCnt)
494                                         kfree(pstClassifierEntry->pstPhsRule);
495                         }
496                         memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_classifier_entry));
497                 }
498
499                 nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
500                                                 uiClsId, eOldClassifierRuleContext, &pstClassifierEntry);
501
502                 if ((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) {
503                         kfree(pstClassifierEntry->pstPhsRule);
504                         memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_classifier_entry));
505                 }
506         }
507         return lStatus;
508 }
509
510 /*
511  * PhsDeleteSFRules
512  *
513  * Routine Description:
514  *    Exported function to Delete a all PHS Rules for the SFID.
515  *
516  * Arguments:
517  *      IN void* pvContext - PHS Driver Specific Context
518  *      IN B_UINT16 uiVcid   - The Service Flow ID for which the PHS rules need to be deleted
519  *
520  * Return Value:
521  *
522  * 0 if successful,
523  * >0 Error.
524  */
525 ULONG PhsDeleteSFRules(IN void *pvContext, IN B_UINT16 uiVcid)
526 {
527         ULONG lStatus = 0;
528         UINT nSFIndex = 0, nClsidIndex = 0;
529         struct bcm_phs_entry *pstServiceFlowEntry = NULL;
530         struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL;
531         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
532         struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
533
534         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "====>\n");
535
536         if (pDeviceExtension) {
537                 /* Retrieve the SFID Entry Index for requested Service Flow */
538                 nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
539                                         uiVcid, &pstServiceFlowEntry);
540                 if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
541                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
542                         return ERR_SF_MATCH_FAIL;
543                 }
544
545                 pstClassifierRulesTable = pstServiceFlowEntry->pstClassifierTable;
546                 if (pstClassifierRulesTable) {
547                         for (nClsidIndex = 0; nClsidIndex < MAX_PHSRULE_PER_SF; nClsidIndex++) {
548                                 if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule) {
549
550                                         if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
551                                                 pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
552
553                                         if (0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
554                                                 kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
555
556                                         pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule = NULL;
557                                 }
558                                 memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(struct bcm_phs_classifier_entry));
559                                 if (pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule) {
560
561                                         if (pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
562                                                 pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
563
564                                         if (0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
565                                                 kfree(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule);
566
567                                         pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule = NULL;
568                                 }
569                                 memset(&pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex], 0, sizeof(struct bcm_phs_classifier_entry));
570                         }
571                 }
572                 pstServiceFlowEntry->bUsed = FALSE;
573                 pstServiceFlowEntry->uiVcid = 0;
574         }
575
576         return lStatus;
577 }
578
579 /*
580  * PhsCompress
581  *
582  * Routine Description:
583  *    Exported function to compress the data using PHS.
584  *
585  * Arguments:
586  *      IN void* pvContext - PHS Driver Specific Context.
587  *      IN B_UINT16 uiVcid    - The Service Flow ID to which current packet header compression applies.
588  *      IN UINT  uiClsId   - The Classifier ID to which current packet header compression applies.
589  *      IN void *pvInputBuffer - The Input buffer containg packet header data
590  *      IN void *pvOutputBuffer - The output buffer returned by this function after PHS
591  *      IN UINT *pOldHeaderSize  - The actual size of the header before PHS
592  *      IN UINT *pNewHeaderSize - The new size of the header after applying PHS
593  *
594  * Return Value:
595  *
596  * 0 if successful,
597  * >0 Error.
598  */
599 static ULONG PhsCompress(IN void *pvContext,
600                 IN B_UINT16 uiVcid,
601                 IN B_UINT16 uiClsId,
602                 IN void *pvInputBuffer,
603                 OUT void *pvOutputBuffer,
604                 OUT UINT *pOldHeaderSize,
605                 OUT UINT *pNewHeaderSize)
606 {
607         UINT nSFIndex = 0, nClsidIndex = 0;
608         struct bcm_phs_entry *pstServiceFlowEntry = NULL;
609         struct bcm_phs_classifier_entry *pstClassifierEntry = NULL;
610         struct bcm_phs_rule *pstPhsRule = NULL;
611         ULONG lStatus = 0;
612         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
613         struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
614
615         if (pDeviceExtension == NULL) {
616                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "Invalid Device Extension\n");
617                 lStatus = STATUS_PHS_NOCOMPRESSION;
618                 return lStatus;
619         }
620
621         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "Suppressing header\n");
622
623         /* Retrieve the SFID Entry Index for requested Service Flow */
624         nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
625                                 uiVcid, &pstServiceFlowEntry);
626         if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
627                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "SFID Match Failed\n");
628                 lStatus = STATUS_PHS_NOCOMPRESSION;
629                 return lStatus;
630         }
631
632         nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
633                                         uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry);
634
635         if (nClsidIndex == PHS_INVALID_TABLE_INDEX) {
636                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "No PHS Rule Defined For Classifier\n");
637                 lStatus =  STATUS_PHS_NOCOMPRESSION;
638                 return lStatus;
639         }
640
641         /* get rule from SF id,Cls ID pair and proceed */
642         pstPhsRule = pstClassifierEntry->pstPhsRule;
643         if (!ValidatePHSRuleComplete(pstPhsRule)) {
644                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "PHS Rule Defined For Classifier But Not Complete\n");
645                 lStatus = STATUS_PHS_NOCOMPRESSION;
646                 return lStatus;
647         }
648
649         /* Compress Packet */
650         lStatus = phs_compress(pstPhsRule, (PUCHAR)pvInputBuffer,
651                         (PUCHAR)pvOutputBuffer, pOldHeaderSize, pNewHeaderSize);
652
653         if (lStatus == STATUS_PHS_COMPRESSED) {
654                 pstPhsRule->PHSModifiedBytes += *pOldHeaderSize - *pNewHeaderSize - 1;
655                 pstPhsRule->PHSModifiedNumPackets++;
656         } else
657                 pstPhsRule->PHSErrorNumPackets++;
658
659         return lStatus;
660 }
661
662 /*
663  * PhsDeCompress
664  *
665  * Routine Description:
666  *    Exported function to restore the packet header in Rx path.
667  *
668  * Arguments:
669  *      IN void* pvContext - PHS Driver Specific Context.
670  *      IN B_UINT16 uiVcid    - The Service Flow ID to which current packet header restoration applies.
671  *      IN  void *pvInputBuffer - The Input buffer containg suppressed packet header data
672  *      OUT void *pvOutputBuffer - The output buffer returned by this function after restoration
673  *      OUT UINT *pHeaderSize   - The packet header size after restoration is returned in this parameter.
674  *
675  * Return Value:
676  *
677  * 0 if successful,
678  * >0 Error.
679  */
680 static ULONG PhsDeCompress(IN void *pvContext,
681                 IN B_UINT16 uiVcid,
682                 IN void *pvInputBuffer,
683                 OUT void *pvOutputBuffer,
684                 OUT UINT *pInHeaderSize,
685                 OUT UINT *pOutHeaderSize)
686 {
687         UINT nSFIndex = 0, nPhsRuleIndex = 0;
688         struct bcm_phs_entry *pstServiceFlowEntry = NULL;
689         struct bcm_phs_rule *pstPhsRule = NULL;
690         UINT phsi;
691         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
692         struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
693
694         *pInHeaderSize = 0;
695         if (pDeviceExtension == NULL) {
696                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "Invalid Device Extension\n");
697                 return ERR_PHS_INVALID_DEVICE_EXETENSION;
698         }
699
700         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "Restoring header\n");
701
702         phsi = *((unsigned char *)(pvInputBuffer));
703         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "PHSI To Be Used For restore : %x\n", phsi);
704         if (phsi == UNCOMPRESSED_PACKET)
705                 return STATUS_PHS_NOCOMPRESSION;
706
707         /* Retrieve the SFID Entry Index for requested Service Flow */
708         nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
709                                 uiVcid, &pstServiceFlowEntry);
710         if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
711                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "SFID Match Failed During Lookup\n");
712                 return ERR_SF_MATCH_FAIL;
713         }
714
715         nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable, phsi,
716                                         eActiveClassifierRuleContext, &pstPhsRule);
717         if (nPhsRuleIndex == PHS_INVALID_TABLE_INDEX) {
718                 /* Phs Rule does not exist in  active rules table. Lets try in the old rules table. */
719                 nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable,
720                                                 phsi, eOldClassifierRuleContext, &pstPhsRule);
721                 if (nPhsRuleIndex == PHS_INVALID_TABLE_INDEX)
722                         return ERR_PHSRULE_MATCH_FAIL;
723         }
724
725         *pInHeaderSize = phs_decompress((PUCHAR)pvInputBuffer,
726                                         (PUCHAR)pvOutputBuffer, pstPhsRule, pOutHeaderSize);
727
728         pstPhsRule->PHSModifiedBytes += *pOutHeaderSize - *pInHeaderSize - 1;
729
730         pstPhsRule->PHSModifiedNumPackets++;
731         return STATUS_PHS_COMPRESSED;
732 }
733
734 /*
735  * Procedure:   free_phs_serviceflow_rules
736  *
737  * Description: This routine is responsible for freeing memory allocated for PHS rules.
738  *
739  * Arguments:
740  * rules        - ptr to S_SERVICEFLOW_TABLE structure.
741  *
742  * Returns:
743  * Does not return any value.
744  */
745 static void free_phs_serviceflow_rules(struct bcm_phs_table *psServiceFlowRulesTable)
746 {
747         int i, j;
748         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
749
750         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "=======>\n");
751
752         if (psServiceFlowRulesTable) {
753                 for (i = 0; i < MAX_SERVICEFLOWS; i++) {
754                         struct bcm_phs_entry stServiceFlowEntry = psServiceFlowRulesTable->stSFList[i];
755                         struct bcm_phs_classifier_table *pstClassifierRulesTable = stServiceFlowEntry.pstClassifierTable;
756
757                         if (pstClassifierRulesTable) {
758                                 for (j = 0; j < MAX_PHSRULE_PER_SF; j++) {
759                                         if (pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule) {
760
761                                                 if (pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt)
762                                                         pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt--;
763
764                                                 if (0 == pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt)
765                                                         kfree(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule);
766
767                                                 pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule = NULL;
768                                         }
769
770                                         if (pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule) {
771
772                                                 if (pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt)
773                                                         pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt--;
774
775                                                 if (0 == pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt)
776                                                         kfree(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule);
777
778                                                 pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL;
779                                         }
780                                 }
781                                 kfree(pstClassifierRulesTable);
782                                 stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL;
783                         }
784                 }
785         }
786
787         kfree(psServiceFlowRulesTable);
788         psServiceFlowRulesTable = NULL;
789 }
790
791 static BOOLEAN ValidatePHSRuleComplete(IN struct bcm_phs_rule *psPhsRule)
792 {
793         if (psPhsRule) {
794                 if (!psPhsRule->u8PHSI) {
795                         /* PHSI is not valid */
796                         return FALSE;
797                 }
798
799                 if (!psPhsRule->u8PHSS) {
800                         /* PHSS Is Undefined */
801                         return FALSE;
802                 }
803
804                 /* Check if PHSF is defines for the PHS Rule */
805                 if (!psPhsRule->u8PHSFLength) /* If any part of PHSF is valid then Rule contains valid PHSF */
806                         return FALSE;
807
808                 return TRUE;
809         } else
810                 return FALSE;
811 }
812
813 UINT GetServiceFlowEntry(IN struct bcm_phs_table *psServiceFlowTable,
814                         IN B_UINT16 uiVcid,
815                         struct bcm_phs_entry **ppstServiceFlowEntry)
816 {
817         int i;
818
819         for (i = 0; i < MAX_SERVICEFLOWS; i++) {
820                 if (psServiceFlowTable->stSFList[i].bUsed) {
821                         if (psServiceFlowTable->stSFList[i].uiVcid == uiVcid) {
822                                 *ppstServiceFlowEntry = &psServiceFlowTable->stSFList[i];
823                                 return i;
824                         }
825                 }
826         }
827
828         *ppstServiceFlowEntry = NULL;
829         return PHS_INVALID_TABLE_INDEX;
830 }
831
832 static UINT GetClassifierEntry(IN struct bcm_phs_classifier_table *pstClassifierTable,
833                         IN B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext,
834                         OUT struct bcm_phs_classifier_entry **ppstClassifierEntry)
835 {
836         int  i;
837         struct bcm_phs_classifier_entry *psClassifierRules = NULL;
838
839         for (i = 0; i < MAX_PHSRULE_PER_SF; i++) {
840
841                 if (eClsContext == eActiveClassifierRuleContext)
842                         psClassifierRules = &pstClassifierTable->stActivePhsRulesList[i];
843                 else
844                         psClassifierRules = &pstClassifierTable->stOldPhsRulesList[i];
845
846                 if (psClassifierRules->bUsed) {
847                         if (psClassifierRules->uiClassifierRuleId == uiClsid) {
848                                 *ppstClassifierEntry = psClassifierRules;
849                                 return i;
850                         }
851                 }
852         }
853
854         *ppstClassifierEntry = NULL;
855         return PHS_INVALID_TABLE_INDEX;
856 }
857
858 static UINT GetPhsRuleEntry(IN struct bcm_phs_classifier_table *pstClassifierTable,
859                         IN B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext,
860                         OUT struct bcm_phs_rule **ppstPhsRule)
861 {
862         int  i;
863         struct bcm_phs_classifier_entry *pstClassifierRule = NULL;
864
865         for (i = 0; i < MAX_PHSRULE_PER_SF; i++) {
866                 if (eClsContext == eActiveClassifierRuleContext)
867                         pstClassifierRule = &pstClassifierTable->stActivePhsRulesList[i];
868                 else
869                         pstClassifierRule = &pstClassifierTable->stOldPhsRulesList[i];
870
871                 if (pstClassifierRule->bUsed) {
872                         if (pstClassifierRule->u8PHSI == uiPHSI) {
873                                 *ppstPhsRule = pstClassifierRule->pstPhsRule;
874                                 return i;
875                         }
876                 }
877         }
878
879         *ppstPhsRule = NULL;
880         return PHS_INVALID_TABLE_INDEX;
881 }
882
883 static UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid, IN B_UINT16  uiClsId,
884                                 IN struct bcm_phs_table *psServiceFlowTable,
885                                 struct bcm_phs_rule *psPhsRule,
886                                 B_UINT8 u8AssociatedPHSI)
887 {
888         struct bcm_phs_classifier_table *psaClassifiertable = NULL;
889         UINT uiStatus = 0;
890         int iSfIndex;
891         BOOLEAN bFreeEntryFound = FALSE;
892
893         /* Check for a free entry in SFID table */
894         for (iSfIndex = 0; iSfIndex < MAX_SERVICEFLOWS; iSfIndex++) {
895                 if (!psServiceFlowTable->stSFList[iSfIndex].bUsed) {
896                         bFreeEntryFound = TRUE;
897                         break;
898                 }
899         }
900
901         if (!bFreeEntryFound)
902                 return ERR_SFTABLE_FULL;
903
904         psaClassifiertable = psServiceFlowTable->stSFList[iSfIndex].pstClassifierTable;
905         uiStatus = CreateClassifierPHSRule(uiClsId, psaClassifiertable, psPhsRule,
906                                         eActiveClassifierRuleContext, u8AssociatedPHSI);
907         if (uiStatus == PHS_SUCCESS) {
908                 /* Add entry at free index to the SF */
909                 psServiceFlowTable->stSFList[iSfIndex].bUsed = TRUE;
910                 psServiceFlowTable->stSFList[iSfIndex].uiVcid = uiVcid;
911         }
912
913         return uiStatus;
914 }
915
916 static UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
917                                 IN B_UINT16 uiClsId,
918                                 IN struct bcm_phs_entry *pstServiceFlowEntry,
919                                 struct bcm_phs_rule *psPhsRule,
920                                 B_UINT8 u8AssociatedPHSI)
921 {
922         struct bcm_phs_classifier_entry *pstClassifierEntry = NULL;
923         UINT uiStatus = PHS_SUCCESS;
924         UINT nClassifierIndex = 0;
925         struct bcm_phs_classifier_table *psaClassifiertable = NULL;
926         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
927
928         psaClassifiertable = pstServiceFlowEntry->pstClassifierTable;
929
930         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "==>");
931
932         /* Check if the supplied Classifier already exists */
933         nClassifierIndex = GetClassifierEntry(
934                 pstServiceFlowEntry->pstClassifierTable,
935                 uiClsId,
936                 eActiveClassifierRuleContext,
937                 &pstClassifierEntry);
938
939         if (nClassifierIndex == PHS_INVALID_TABLE_INDEX) {
940                 /*
941                  * The Classifier doesn't exist. So its a new classifier being added.
942                  * Add new entry to associate PHS Rule to the Classifier
943                  */
944
945                 uiStatus = CreateClassifierPHSRule(uiClsId, psaClassifiertable,
946                                                 psPhsRule,
947                                                 eActiveClassifierRuleContext,
948                                                 u8AssociatedPHSI);
949                 return uiStatus;
950         }
951
952         /*
953          * The Classifier exists.The PHS Rule for this classifier
954          * is being modified
955          */
956
957         if (pstClassifierEntry->u8PHSI == psPhsRule->u8PHSI) {
958                 if (pstClassifierEntry->pstPhsRule == NULL)
959                         return ERR_PHS_INVALID_PHS_RULE;
960
961                 /*
962                  * This rule already exists if any fields are changed for this PHS
963                  * rule update them.
964                  */
965                 /* If any part of PHSF is valid then we update PHSF */
966                 if (psPhsRule->u8PHSFLength) {
967                         /* update PHSF */
968                         memcpy(pstClassifierEntry->pstPhsRule->u8PHSF,
969                                 psPhsRule->u8PHSF, MAX_PHS_LENGTHS);
970                 }
971
972                 if (psPhsRule->u8PHSFLength) {
973                         /* update PHSFLen */
974                         pstClassifierEntry->pstPhsRule->u8PHSFLength = psPhsRule->u8PHSFLength;
975                 }
976
977                 if (psPhsRule->u8PHSMLength) {
978                         /* update PHSM */
979                         memcpy(pstClassifierEntry->pstPhsRule->u8PHSM,
980                                 psPhsRule->u8PHSM, MAX_PHS_LENGTHS);
981                 }
982
983                 if (psPhsRule->u8PHSMLength) {
984                         /* update PHSM Len */
985                         pstClassifierEntry->pstPhsRule->u8PHSMLength =
986                                 psPhsRule->u8PHSMLength;
987                 }
988
989                 if (psPhsRule->u8PHSS) {
990                         /* update PHSS */
991                         pstClassifierEntry->pstPhsRule->u8PHSS = psPhsRule->u8PHSS;
992                 }
993
994                 /* update PHSV */
995                 pstClassifierEntry->pstPhsRule->u8PHSV = psPhsRule->u8PHSV;
996         } else {
997                 /* A new rule is being set for this classifier. */
998                 uiStatus = UpdateClassifierPHSRule(uiClsId, pstClassifierEntry,
999                                                 psaClassifiertable, psPhsRule, u8AssociatedPHSI);
1000         }
1001
1002         return uiStatus;
1003 }
1004
1005 static UINT CreateClassifierPHSRule(IN B_UINT16  uiClsId,
1006                                 struct bcm_phs_classifier_table *psaClassifiertable,
1007                                 struct bcm_phs_rule *psPhsRule,
1008                                 enum bcm_phs_classifier_context eClsContext,
1009                                 B_UINT8 u8AssociatedPHSI)
1010 {
1011         UINT iClassifierIndex = 0;
1012         BOOLEAN bFreeEntryFound = FALSE;
1013         struct bcm_phs_classifier_entry *psClassifierRules = NULL;
1014         UINT nStatus = PHS_SUCCESS;
1015         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
1016
1017         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "Inside CreateClassifierPHSRule");
1018
1019         if (psaClassifiertable == NULL)
1020                 return ERR_INVALID_CLASSIFIERTABLE_FOR_SF;
1021
1022         if (eClsContext == eOldClassifierRuleContext) {
1023                 /*
1024                  * If An Old Entry for this classifier ID already exists in the
1025                  * old rules table replace it.
1026                  */
1027
1028                 iClassifierIndex =
1029                         GetClassifierEntry(psaClassifiertable, uiClsId,
1030                                         eClsContext, &psClassifierRules);
1031
1032                 if (iClassifierIndex != PHS_INVALID_TABLE_INDEX) {
1033                         /*
1034                          * The Classifier already exists in the old rules table
1035                          * Lets replace the old classifier with the new one.
1036                          */
1037                         bFreeEntryFound = TRUE;
1038                 }
1039         }
1040
1041         if (!bFreeEntryFound) {
1042                 /* Continue to search for a free location to add the rule */
1043                 for (iClassifierIndex = 0; iClassifierIndex <
1044                              MAX_PHSRULE_PER_SF; iClassifierIndex++) {
1045                         if (eClsContext == eActiveClassifierRuleContext)
1046                                 psClassifierRules = &psaClassifiertable->stActivePhsRulesList[iClassifierIndex];
1047                         else
1048                                 psClassifierRules = &psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
1049
1050                         if (!psClassifierRules->bUsed) {
1051                                 bFreeEntryFound = TRUE;
1052                                 break;
1053                         }
1054                 }
1055         }
1056
1057         if (!bFreeEntryFound) {
1058
1059                 if (eClsContext == eActiveClassifierRuleContext)
1060                         return ERR_CLSASSIFIER_TABLE_FULL;
1061                 else {
1062                         /* Lets replace the oldest rule if we are looking in old Rule table */
1063                         if (psaClassifiertable->uiOldestPhsRuleIndex >= MAX_PHSRULE_PER_SF)
1064                                 psaClassifiertable->uiOldestPhsRuleIndex = 0;
1065
1066                         iClassifierIndex = psaClassifiertable->uiOldestPhsRuleIndex;
1067                         psClassifierRules = &psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
1068
1069                         (psaClassifiertable->uiOldestPhsRuleIndex)++;
1070                 }
1071         }
1072
1073         if (eClsContext == eOldClassifierRuleContext) {
1074
1075                 if (psClassifierRules->pstPhsRule == NULL) {
1076
1077                         psClassifierRules->pstPhsRule = kmalloc(sizeof(struct bcm_phs_rule), GFP_KERNEL);
1078
1079                         if (NULL == psClassifierRules->pstPhsRule)
1080                                 return ERR_PHSRULE_MEMALLOC_FAIL;
1081                 }
1082
1083                 psClassifierRules->bUsed = TRUE;
1084                 psClassifierRules->uiClassifierRuleId = uiClsId;
1085                 psClassifierRules->u8PHSI = psPhsRule->u8PHSI;
1086                 psClassifierRules->bUnclassifiedPHSRule = psPhsRule->bUnclassifiedPHSRule;
1087
1088                 /* Update The PHS rule */
1089                 memcpy(psClassifierRules->pstPhsRule, psPhsRule, sizeof(struct bcm_phs_rule));
1090         } else
1091                 nStatus = UpdateClassifierPHSRule(uiClsId, psClassifierRules,
1092                                                 psaClassifiertable, psPhsRule, u8AssociatedPHSI);
1093
1094         return nStatus;
1095 }
1096
1097 static UINT UpdateClassifierPHSRule(IN B_UINT16  uiClsId,
1098                                 IN struct bcm_phs_classifier_entry *pstClassifierEntry,
1099                                 struct bcm_phs_classifier_table *psaClassifiertable,
1100                                 struct bcm_phs_rule *psPhsRule,
1101                                 B_UINT8 u8AssociatedPHSI)
1102 {
1103         struct bcm_phs_rule *pstAddPhsRule = NULL;
1104         UINT nPhsRuleIndex = 0;
1105         BOOLEAN bPHSRuleOrphaned = FALSE;
1106         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
1107
1108         psPhsRule->u8RefCnt = 0;
1109
1110         /* Step 1 Deref Any Exisiting PHS Rule in this classifier Entry */
1111         bPHSRuleOrphaned = DerefPhsRule(uiClsId, psaClassifiertable,
1112                                         pstClassifierEntry->pstPhsRule);
1113
1114         /* Step 2 Search if there is a PHS Rule with u8AssociatedPHSI in Classifier table for this SF */
1115         nPhsRuleIndex = GetPhsRuleEntry(psaClassifiertable, u8AssociatedPHSI,
1116                                         eActiveClassifierRuleContext, &pstAddPhsRule);
1117         if (PHS_INVALID_TABLE_INDEX == nPhsRuleIndex) {
1118
1119                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAdding New PHSRuleEntry For Classifier");
1120
1121                 if (psPhsRule->u8PHSI == 0) {
1122                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nError PHSI is Zero\n");
1123                         return ERR_PHS_INVALID_PHS_RULE;
1124                 }
1125
1126                 /* Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId */
1127                 if (FALSE == bPHSRuleOrphaned) {
1128
1129                         pstClassifierEntry->pstPhsRule = kmalloc(sizeof(struct bcm_phs_rule), GFP_KERNEL);
1130                         if (NULL == pstClassifierEntry->pstPhsRule)
1131                                 return ERR_PHSRULE_MEMALLOC_FAIL;
1132                 }
1133                 memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(struct bcm_phs_rule));
1134         } else {
1135                 /* Step 2.b PHS Rule  Exists Tie uiClsId with the existing PHS Rule */
1136                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule");
1137                 if (bPHSRuleOrphaned) {
1138                         kfree(pstClassifierEntry->pstPhsRule);
1139                         pstClassifierEntry->pstPhsRule = NULL;
1140                 }
1141                 pstClassifierEntry->pstPhsRule = pstAddPhsRule;
1142         }
1143
1144         pstClassifierEntry->bUsed = TRUE;
1145         pstClassifierEntry->u8PHSI = pstClassifierEntry->pstPhsRule->u8PHSI;
1146         pstClassifierEntry->uiClassifierRuleId = uiClsId;
1147         pstClassifierEntry->pstPhsRule->u8RefCnt++;
1148         pstClassifierEntry->bUnclassifiedPHSRule = pstClassifierEntry->pstPhsRule->bUnclassifiedPHSRule;
1149
1150         return PHS_SUCCESS;
1151 }
1152
1153 static BOOLEAN DerefPhsRule(IN B_UINT16  uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule)
1154 {
1155         if (pstPhsRule == NULL)
1156                 return FALSE;
1157
1158         if (pstPhsRule->u8RefCnt)
1159                 pstPhsRule->u8RefCnt--;
1160
1161         if (0 == pstPhsRule->u8RefCnt) {
1162                 /*
1163                  * if(pstPhsRule->u8PHSI)
1164                  * Store the currently active rule into the old rules list
1165                  * CreateClassifierPHSRule(uiClsId,psaClassifiertable,pstPhsRule,eOldClassifierRuleContext,pstPhsRule->u8PHSI);
1166                  */
1167                 return TRUE;
1168         } else
1169                 return FALSE;
1170 }
1171
1172 void DumpPhsRules(struct bcm_phs_extension *pDeviceExtension)
1173 {
1174         int i, j, k, l;
1175         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
1176
1177         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n Dumping PHS Rules :\n");
1178
1179         for (i = 0; i < MAX_SERVICEFLOWS; i++) {
1180
1181                 struct bcm_phs_entry stServFlowEntry =
1182                         pDeviceExtension->pstServiceFlowPhsRulesTable->stSFList[i];
1183                 if (stServFlowEntry.bUsed) {
1184
1185                         for (j = 0; j < MAX_PHSRULE_PER_SF; j++) {
1186
1187                                 for (l = 0; l < 2; l++) {
1188                                         struct bcm_phs_classifier_entry stClsEntry;
1189
1190                                         if (l == 0) {
1191                                                 stClsEntry = stServFlowEntry.pstClassifierTable->stActivePhsRulesList[j];
1192                                                 if (stClsEntry.bUsed)
1193                                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Active PHS Rule :\n");
1194                                         } else {
1195                                                 stClsEntry = stServFlowEntry.pstClassifierTable->stOldPhsRulesList[j];
1196                                                 if (stClsEntry.bUsed)
1197                                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Old PHS Rule :\n");
1198                                         }
1199
1200                                         if (stClsEntry.bUsed) {
1201                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n VCID  : %#X", stServFlowEntry.uiVcid);
1202                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n ClassifierID  : %#X", stClsEntry.uiClassifierRuleId);
1203                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSRuleID  : %#X", stClsEntry.u8PHSI);
1204                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n****************PHS Rule********************\n");
1205                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSI  : %#X", stClsEntry.pstPhsRule->u8PHSI);
1206                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSFLength : %#X ", stClsEntry.pstPhsRule->u8PHSFLength);
1207                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSF : ");
1208
1209                                                 for (k = 0 ; k < stClsEntry.pstPhsRule->u8PHSFLength; k++)
1210                                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X  ", stClsEntry.pstPhsRule->u8PHSF[k]);
1211                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSMLength  : %#X", stClsEntry.pstPhsRule->u8PHSMLength);
1212                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSM :");
1213
1214                                                 for (k = 0; k < stClsEntry.pstPhsRule->u8PHSMLength; k++)
1215                                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X  ", stClsEntry.pstPhsRule->u8PHSM[k]);
1216                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSS : %#X ", stClsEntry.pstPhsRule->u8PHSS);
1217                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSV  : %#X", stClsEntry.pstPhsRule->u8PHSV);
1218                                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n********************************************\n");
1219                                         }
1220                                 }
1221                         }
1222                 }
1223         }
1224 }
1225
1226 /*
1227  * Procedure:   phs_decompress
1228  *
1229  * Description: This routine restores the static fields within the packet.
1230  *
1231  * Arguments:
1232  *      in_buf                  - ptr to incoming packet buffer.
1233  *      out_buf                 - ptr to output buffer where the suppressed header is copied.
1234  *      decomp_phs_rules - ptr to PHS rule.
1235  *      header_size             - ptr to field which holds the phss or phsf_length.
1236  *
1237  * Returns:
1238  *      size -The number of bytes of dynamic fields present with in the incoming packet
1239  *                      header.
1240  *      0       -If PHS rule is NULL.If PHSI is 0 indicateing packet as uncompressed.
1241  */
1242 static int phs_decompress(unsigned char *in_buf,
1243                 unsigned char *out_buf,
1244                 struct bcm_phs_rule *decomp_phs_rules,
1245                 UINT *header_size)
1246 {
1247         int phss, size = 0;
1248         struct bcm_phs_rule *tmp_memb;
1249         int bit, i = 0;
1250         unsigned char *phsf, *phsm;
1251         int in_buf_len = *header_size - 1;
1252         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
1253
1254         in_buf++;
1255
1256         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "====>\n");
1257         *header_size = 0;
1258
1259         if ((decomp_phs_rules == NULL))
1260                 return 0;
1261
1262         tmp_memb = decomp_phs_rules;
1263         /*
1264          * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phs_decompress PHSI 1  %d",phsi));
1265          * header_size = tmp_memb->u8PHSFLength;
1266          */
1267         phss = tmp_memb->u8PHSS;
1268         phsf = tmp_memb->u8PHSF;
1269         phsm = tmp_memb->u8PHSM;
1270
1271         if (phss > MAX_PHS_LENGTHS)
1272                 phss = MAX_PHS_LENGTHS;
1273
1274         /*
1275          * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:
1276          * In phs_decompress PHSI  %d phss %d index %d",phsi,phss,index));
1277          */
1278         while ((phss > 0) && (size < in_buf_len)) {
1279                 bit = ((*phsm << i) & SUPPRESS);
1280
1281                 if (bit == SUPPRESS) {
1282                         *out_buf = *phsf;
1283                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nDECOMP:In phss  %d phsf %d ouput %d",
1284                                         phss, *phsf, *out_buf);
1285                 } else {
1286                         *out_buf = *in_buf;
1287                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nDECOMP:In phss  %d input %d ouput %d",
1288                                         phss, *in_buf, *out_buf);
1289                         in_buf++;
1290                         size++;
1291                 }
1292                 out_buf++;
1293                 phsf++;
1294                 phss--;
1295                 i++;
1296                 *header_size = *header_size + 1;
1297
1298                 if (i > MAX_NO_BIT) {
1299                         i = 0;
1300                         phsm++;
1301                 }
1302         }
1303
1304         return size;
1305 }
1306
1307 /*
1308  * Procedure:   phs_compress
1309  *
1310  * Description: This routine suppresses the static fields within the packet.Before
1311  * that it will verify the fields to be suppressed with the corresponding fields in the
1312  * phsf. For verification it checks the phsv field of PHS rule. If set and verification
1313  * succeeds it suppresses the field.If any one static field is found different none of
1314  * the static fields are suppressed then the packet is sent as uncompressed packet with
1315  * phsi=0.
1316  *
1317  * Arguments:
1318  *      phs_rule - ptr to PHS rule.
1319  *      in_buf          - ptr to incoming packet buffer.
1320  *      out_buf         - ptr to output buffer where the suppressed header is copied.
1321  *      header_size     - ptr to field which holds the phss.
1322  *
1323  * Returns:
1324  *      size-The number of bytes copied into the output buffer i.e dynamic fields
1325  *      0       -If PHS rule is NULL.If PHSV field is not set.If the verification fails.
1326  */
1327 static int phs_compress(struct bcm_phs_rule *phs_rule,
1328                         unsigned char *in_buf,
1329                         unsigned char *out_buf,
1330                         UINT *header_size,
1331                         UINT *new_header_size)
1332 {
1333         unsigned char *old_addr = out_buf;
1334         int suppress = 0;
1335         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
1336
1337         if (phs_rule == NULL) {
1338                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nphs_compress(): phs_rule null!");
1339                 *out_buf = ZERO_PHSI;
1340                 return STATUS_PHS_NOCOMPRESSION;
1341         }
1342
1343         if (phs_rule->u8PHSS <= *new_header_size)
1344                 *header_size = phs_rule->u8PHSS;
1345         else
1346                 *header_size = *new_header_size;
1347
1348         /* To copy PHSI */
1349         out_buf++;
1350         suppress = verify_suppress_phsf(in_buf, out_buf, phs_rule->u8PHSF,
1351                                         phs_rule->u8PHSM, phs_rule->u8PHSS,
1352                                         phs_rule->u8PHSV, new_header_size);
1353
1354         if (suppress == STATUS_PHS_COMPRESSED) {
1355                 *old_addr = (unsigned char)phs_rule->u8PHSI;
1356                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In phs_compress phsi %d", phs_rule->u8PHSI);
1357         } else {
1358                 *old_addr = ZERO_PHSI;
1359                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In phs_compress PHSV Verification failed");
1360         }
1361
1362         return suppress;
1363 }
1364
1365 /*
1366  * Procedure:   verify_suppress_phsf
1367  *
1368  * Description: This routine verifies the fields of the packet and if all the
1369  * static fields are equal it adds the phsi of that PHS rule.If any static
1370  * field differs it woun't suppress any field.
1371  *
1372  * Arguments:
1373  * rules_set    - ptr to classifier_rules.
1374  * in_buffer    - ptr to incoming packet buffer.
1375  * out_buffer   - ptr to output buffer where the suppressed header is copied.
1376  * phsf                 - ptr to phsf.
1377  * phsm                 - ptr to phsm.
1378  * phss                 - variable holding phss.
1379  *
1380  * Returns:
1381  *      size-The number of bytes copied into the output buffer i.e dynamic fields.
1382  *      0       -Packet has failed the verification.
1383  */
1384 static int verify_suppress_phsf(unsigned char *in_buffer,
1385                                 unsigned char *out_buffer,
1386                                 unsigned char *phsf,
1387                                 unsigned char *phsm,
1388                                 unsigned int phss,
1389                                 unsigned int phsv,
1390                                 UINT *new_header_size)
1391 {
1392         unsigned int size = 0;
1393         int bit, i = 0;
1394         struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
1395
1396         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In verify_phsf PHSM - 0x%X", *phsm);
1397
1398         if (phss > (*new_header_size))
1399                 phss = *new_header_size;
1400
1401         while (phss > 0) {
1402                 bit = ((*phsm << i) & SUPPRESS);
1403                 if (bit == SUPPRESS) {
1404                         if (*in_buffer != *phsf) {
1405                                 if (phsv == VERIFY) {
1406                                         BCM_DEBUG_PRINT(Adapter,
1407                                                         DBG_TYPE_OTHERS,
1408                                                         PHS_SEND,
1409                                                         DBG_LVL_ALL,
1410                                                         "\nCOMP:In verify_phsf failed for field  %d buf  %d phsf %d",
1411                                                         phss,
1412                                                         *in_buffer,
1413                                                         *phsf);
1414                                         return STATUS_PHS_NOCOMPRESSION;
1415                                 }
1416                         } else
1417                                 BCM_DEBUG_PRINT(Adapter,
1418                                                 DBG_TYPE_OTHERS,
1419                                                 PHS_SEND,
1420                                                 DBG_LVL_ALL,
1421                                                 "\nCOMP:In verify_phsf success for field  %d buf  %d phsf %d",
1422                                                 phss,
1423                                                 *in_buffer,
1424                                                 *phsf);
1425                 } else {
1426                         *out_buffer = *in_buffer;
1427                         BCM_DEBUG_PRINT(Adapter,
1428                                         DBG_TYPE_OTHERS,
1429                                         PHS_SEND,
1430                                         DBG_LVL_ALL,
1431                                         "\nCOMP:In copying_header input %d  out %d",
1432                                         *in_buffer,
1433                                         *out_buffer);
1434                         out_buffer++;
1435                         size++;
1436                 }
1437
1438                 in_buffer++;
1439                 phsf++;
1440                 phss--;
1441                 i++;
1442
1443                 if (i > MAX_NO_BIT) {
1444                         i = 0;
1445                         phsm++;
1446                 }
1447         }
1448         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In verify_phsf success");
1449         *new_header_size = size;
1450         return STATUS_PHS_COMPRESSED;
1451 }