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