f7ef2bfce5df1ea04f03e793788b4c644326d0ec
[o-du/l2.git] / src / 5gnrrlc / kw_amm_ul.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
5 #   Licensed under the Apache License, Version 2.0 (the "License");            #
6 #   you may not use this file except in compliance with the License.           #
7 #   You may obtain a copy of the License at                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
11 #   Unless required by applicable law or agreed to in writing, software        #
12 #   distributed under the License is distributed on an "AS IS" BASIS,          #
13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #   See the License for the specific language governing permissions and        #
15 #   limitations under the License.                                             #
16 ################################################################################
17 *******************************************************************************/
18
19 /********************************************************************20**
20
21         Name:    RLC - AM module file
22
23         Type:    C source file
24
25         Desc:    Source code for Acknowledged Mode Module functions such as,
26
27                  Transmission of data/control PDUs
28                  Retransmission (Feedback in terms of status)
29                  Polling
30                  Assemble SDUs
31                  Reception - reordering
32                  Duplicate detection for byte segments
33                  Reassemble SDUs
34
35         File:    kw_amm_ul.c
36
37 *********************************************************************21*/
38 static const char* RLOG_MODULE_NAME="AMM";
39 static int RLOG_MODULE_ID=2048;
40 static int RLOG_FILE_ID=190;
41
42 /* header include files (.h) */
43 #include "envopt.h"        /* environment options */
44 #include "envdep.h"        /* environment dependent */
45 #include "envind.h"        /* environment independent */
46
47 #include "gen.h"           /* general */
48 #include "ssi.h"           /* system services */
49 #include "cm5.h"           /* common timer defines */
50 #include "cm_tkns.h"       /* common tokens defines */
51 #include "cm_mblk.h"       /* common memory allocation library defines */
52 #include "cm_llist.h"      /* common link list  defines  */
53 #include "cm_hash.h"       /* common hash list  defines */
54 #include "cm_lte.h"        /* common LTE defines */
55 #include "lkw.h"           /* LKW defines */
56 #include "ckw.h"           /* CKW defines */
57 #include "kwu.h"           /* KWU defines */
58 #include "rgu.h"           /* RGU defines */
59 #include "kw_udx.h"
60 #include "kw_err.h"        /* Err defines */
61 #include "kw_env.h"        /* RLC environment options */
62
63 #include "kw.h"            /* RLC defines */
64 #include "kw_ul.h"
65
66 /* extern (.x) include files */
67 #include "gen.x"           /* general */
68 #include "ssi.x"           /* system services */
69
70 #include "cm5.x"           /* common timer library */
71 #include "cm_tkns.x"       /* common tokens */
72 #include "cm_mblk.x"       /* common memory allocation */
73 #include "cm_llist.x"      /* common link list */
74 #include "cm_hash.x"       /* common hash list */
75 #include "cm_lte.x"        /* common LTE includes */
76 #include "cm_lib.x"        /* common memory allocation library */
77 #include "lkw.x"           /* LKW */
78 #include "ckw.x"           /* CKW */
79 #include "kwu.x"           /* KWU */
80 #include "rgu.x"           /* RGU */
81
82 #include "kw.x"
83 #include "kw_ul.x"
84 #include "kw_udx.x"
85
86 /* Variable for logging, declared in cl */
87 #ifndef RGL_SPECIFIC_CHANGES
88 #ifndef TENB_ACC
89 #ifndef LTE_PAL_ENB
90 extern U32 ulrate_rgu;
91 #endif
92 #endif
93 #endif
94 #ifndef RGL_SPECIFIC_CHANGES
95 #ifndef TENB_ACC
96 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
97 #ifndef LTE_PAL_ENB
98 extern U32 isMemThreshReached(Region region);
99 #endif
100 #else
101 #ifndef LTE_PAL_ENB
102 extern U32  isMemThreshReached(Region region);
103 #endif
104 #endif
105 #endif
106 #endif
107 /** @file gp_amm_ul.c
108 @brief RLC Acknowledged Mode Uplink Module
109 **/
110 #define KW_MODULE (KW_DBGMASK_AM | KW_DBGMASK_UL) /* for debugging purpose */
111
112 /* private function declarations */
113
114 PRIVATE Void kwAmmUlAssembleCntrlInfo ARGS ((KwCb *gCb, KwUlRbCb *rbCb));
115
116 PRIVATE S16 kwAmmExtractHdr ARGS ((KwCb *gCb,
117                                 KwUlRbCb   *rbCb,
118                                 Buffer *pdu,
119                                 KwAmHdr *amHdr,
120                                 U8 *fByte));
121
122 PRIVATE Bool kwAmmUlPlacePduInRecBuf ARGS ((KwCb *gCb,
123                                             Buffer *pdu,
124                                             KwUlRbCb *rbCb,
125                                             KwAmHdr *amHdr));
126
127 PRIVATE Void kwAmmTriggerStatus ARGS ((KwCb *gCb,
128                                     KwUlRbCb *rbCb,
129                                     KwSn sn,
130                                     Bool discFlg));
131
132 PRIVATE S16  kwAmmUlReassembleSdus ARGS ((KwCb *gCb,
133                                      KwUlRbCb *rbCb,
134                                      KwAmRecBuf *recBuf));
135
136 PRIVATE Void kwAmmProcPduOrSeg ARGS ((KwCb *gCb,
137                                       KwUlRbCb *rbCb,
138                                       KwAmHdr *amHdr,
139                                       Buffer *pdu));
140
141 PRIVATE Void kwAmmUpdExpByteSeg ARGS ((KwCb *gCb,KwAmUl *amUl, KwSeg* newSeg));
142
143 PRIVATE Void kwAmmExtractElmnt ARGS ((KwCb *gCb, Buffer *pdu, KwExtHdr *hdrInfo));
144
145 PRIVATE Void kwAmmUlHndlStatusPdu ARGS ((KwCb *gCb,
146                                          KwUlRbCb *rbCb,
147                                          Buffer *cntrlPdu,
148                                          U8 *fByte));
149
150 /******************************************************************************
151
152   AM Module contains the following funcitons:
153
154   -  kwAmmProcessSdus
155      -  kwAmmUlAssembleCntrlInfo
156      -  kwResegRetxPdus
157      -  kwAssembleSdus
158      -  kwChkandSetPoll
159   -  kwAmmProcessPdus
160      -  kwAmmUlHndlStatusPdu
161      -  kwAmmTriggerStatus
162      -  kwAmmUlReassembleSdus
163
164 *******************************************************************************/
165 /** @addtogroup ammode */
166 /*@{*/
167
168 /**
169  * @brief   Private function to fill NACK information in status Pdu as per 5GNR
170  *
171  * @param[in]   rbCb       Ul RbCb
172  * @param[in]   sn         Sequence number of the PDU for which the NACK
173  * @param[in]   isSegment  TRUE means NACK for segment; FALSE for PDU
174  * @param[in]   soStart    SOStart
175  * @param[in]   soEnd      SOEnd
176  * @param[out]  statusPdu  status Pdu holder to be filled
177  * @param[in]   prevNackSn It holds previous nack Sn
178  *
179  * @return  S16
180  *    The number of bytes required to encode this NACK information
181  *
182  */
183 #ifdef ANSI
184 PRIVATE S16 kwAmmUlSetNackInfo
185 (
186 KwUlRbCb      *rbCb,
187 KwSn          sn,
188 Bool          isSegment,
189 U16           soStart,
190 U16           soEnd,
191 KwUdxDlStaPdu *statusPdu,
192 KwSn          *prevNackSn
193 )
194 #else
195 PRIVATE S16 kwAmmUlSetNackInfo(rbCb, sn, isSegment, soStart, statusPdu, prevNackSn)
196 KwUlRbCb      *rbCb;
197 KwSn          sn;
198 Bool          isSegment;
199 U16           soStart;
200 U16           soEnd;
201 KwUdxDlStaPdu *statusPdu,
202 KwSn          *prevNackSn;
203 #endif
204 {
205    KwNackInfo   *nackInfo = (statusPdu->nackInfo + statusPdu->nackCount);
206    S16           sizeToBeEncd = 0; /* Status PDu size to be encoded */
207
208    TRC2(kwAmmUlSetNackInfo)
209
210       /* In following cases we should increment the nackCnt & fill new NACK_SN info:
211        *    1) First NACK_SN of the statusdPdu
212        *    2) NACK_SN is not continuous with previous
213        *    3) NACK_SN is same as previuos but segments are not continuous
214        *    4) NACK_SN is continuous with previous but previous NACK_SN segments
215        *       are not missing in sequence till end
216        */
217       if((*prevNackSn == 0xffffffff) || ((((*prevNackSn) + 1) & AMUL.snModMask) != sn) ||
218             (((*prevNackSn) == sn) && (((nackInfo->soEnd + 1) != soStart))) ||
219             ((nackInfo->isSegment) && (((*prevNackSn) + 1) == sn) && (nackInfo->soEnd != KW_ALL_BYTES_MISSING)))
220       {
221          if(nackInfo->nackRange)
222          {
223             if((nackInfo->soEnd) && (!nackInfo->soStart))
224             {
225                /*First nack_sn of this nackRange not segmented but last is segmented */
226                sizeToBeEncd = 5; /*32 for soStart and soEnd and 8 for nackRange */ 
227             }
228             else
229             {
230                /*First nack_sn of this nackRange was segmented */
231                sizeToBeEncd = 1; /*8 for nackRange */ 
232             }
233          }
234
235          if(*prevNackSn != 0xffffffff)
236          {
237             /* Increment nackCount as this sn is continous */
238             statusPdu->nackCount++;
239             nackInfo = statusPdu->nackInfo + statusPdu->nackCount;
240          }
241
242          nackInfo->sn = sn;
243          nackInfo->isSegment = isSegment;
244          nackInfo->soStart = soStart;
245          nackInfo->soEnd   = soEnd;
246          nackInfo->nackRange = 0;
247
248          if(isSegment)
249          {
250             sizeToBeEncd += ((AMUL.snLen == KW_AM_CFG_12BIT_SN_LEN)?6:7); /* NACK,E1,E2,Sostart,SoEnd */
251          }
252          else
253          {
254             sizeToBeEncd += ((AMUL.snLen == KW_AM_CFG_12BIT_SN_LEN)?2:3); /* NACK,E1,E2 */
255          }
256       }
257       else
258       {
259          if(!(nackInfo->nackRange))
260          {
261             nackInfo->nackRange++;
262          }
263          /* This case means there are continuous SNs/Segments. If it is the next
264           * Sn then increment nackRnage. if same SN but different segment then
265           * dont increment nackRange */
266          if((((*prevNackSn) + 1) & AMUL.snModMask) == sn)
267          {
268             nackInfo->nackRange++;
269          }
270
271          /* If NackRange is reached to max value then increment statusPdu->nackCount*/
272          if(nackInfo->nackRange == 255)
273          {
274             statusPdu->nackCount++;
275             if(nackInfo->isSegment)
276             {
277                sizeToBeEncd = 1; /* return only nackRangeSize*/
278             }
279             else if (isSegment)
280             {
281                /* First SN was not segmented of this nackRange but last SN is segmented */
282                sizeToBeEncd = 5; /* return size of soSatrt + soEnd + nackRnage */
283             }
284          }
285
286          if(isSegment)
287          {
288             nackInfo->isSegment = isSegment;
289             nackInfo->soEnd = soEnd;
290          }
291          else if(nackInfo->isSegment)
292          {
293             nackInfo->soEnd = KW_ALL_BYTES_MISSING;
294          }
295          else
296          {
297             nackInfo->soStart = 0;
298             nackInfo->soEnd =   0;
299          }
300
301       }
302    *prevNackSn = sn;
303
304    RETVALUE(sizeToBeEncd);
305 }
306
307 /**
308  * @brief   Private handler to gather information required to create the STATUS
309  *          PDU
310  *
311  * @details
312  *    Scans the reception buffer and copies information to the UdxDlStaPdu
313  *    structure about SN's  and segments not yet received. This data is
314  *    sent to the DL instance so that it can create an appropriate (depending
315  *    on the grants from MAC) STATUS PDU and send it to MAC.
316  *
317  * @param[in]  gCb      RLC instance control block
318  * @param[in]  rbCb     Uplink RB control block
319  *
320  * @return  Void
321  *
322  */
323 #ifdef ANSI
324 PRIVATE Void kwAmmUlAssembleCntrlInfo
325 (
326 KwCb       *gCb,
327 KwUlRbCb   *rbCb
328 )
329 #else
330 PRIVATE Void kwAmmUlAssembleCntrlInfo(gCb, rbCb)
331 KwCb       *gCb;
332 KwUlRbCb   *rbCb;
333 #endif
334 {
335    KwUdxDlStaPdu   *pStatusPdu;
336    KwNackInfo      *nackInfo;
337    KwSn            sn;                /* sequence number */
338    KwSn            mSn;               /* Mod val of sequence number */
339    KwSn            rxHighestStatus;              /* Mod val of rxHighestStatus */
340    KwSeg           *seg;              /* pdu segment */
341    U16             nackCnt = 0;       /* Index for staPdu */
342    U16             seqSo;             /* segmment offset */
343    KwUdxUlSapCb    *sapCb;
344    U16             staPduEncSize = 3; /* size that would be of the encoded
345                                           STATUS PDU, it is in bits; 15 for
346                                           first fixed part of STATUS PDU */
347    KwAmRecBuf      *recBuf = NULLP;
348    KwSn            prevNackSn = 0xffffffff;
349
350    TRC2(kwAmmUlAssembleCntrlInfo)
351
352
353    sapCb = KW_GET_UDX_SAP(gCb);
354
355    KW_ALLOC_SHRABL_BUF(sapCb->pst.region,
356                        sapCb->pst.pool,
357                        pStatusPdu, 
358                        sizeof(KwUdxDlStaPdu)); 
359
360 #if (ERRCLASS & ERRCLS_ADD_RES)
361    /* Memory allocation failure can not be expected  */
362    if(!pStatusPdu)
363    {
364      RETVOID;
365    }
366 #endif
367
368    sn = AMUL.rxNext;
369    MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
370    MODAMR(AMUL.rxHighestStatus, rxHighestStatus, AMUL.rxNext, AMUL.snModMask);
371    
372    recBuf =  kwUtlGetRecBuf(AMUL.recBufLst, sn);
373
374    while (mSn < rxHighestStatus )
375    {
376       /* For missing PDUs */
377       if ((NULLP  == recBuf) && nackCnt < KW_MAX_NACK_CNT )
378       {
379          RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, 
380                   "Missing PDU's SN = %d UEID:%d CELLID:%d", 
381                   sn,
382                   rbCb->rlcId.ueId,
383                   rbCb->rlcId.cellId);
384          staPduEncSize += kwAmmUlSetNackInfo(rbCb,
385                                              sn,
386                                              FALSE, /* isSegment */
387                                              0,     /* SOStart */
388                                              0,     /* SOEnd */
389                                              pStatusPdu,
390                                              &prevNackSn);
391       }
392       else if (recBuf && (recBuf->pdu == NULLP) &&
393                (recBuf->segLst.count > 0))
394       {
395          /* Scan through the byte segments of PDU and add this sn
396             with soStart and soEnd info to staPdu */
397
398          seqSo  = 0;
399          KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
400          while (seg != NULLP && nackCnt < KW_MAX_NACK_CNT)
401          {
402             /* For missing byte segments */
403             if (seg->amHdr.so != seqSo)
404             {
405                staPduEncSize += kwAmmUlSetNackInfo(rbCb,
406                                                    sn,
407                                                    TRUE,
408                                                    seqSo,
409                                                    seg->amHdr.so - 1,
410                                                    pStatusPdu,
411                                                    &prevNackSn);
412
413                RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
414                              "Missing byte segment's" 
415                              " SN:%d UEID:%d CELLID:%d",
416                              sn,
417                              rbCb->rlcId.ueId,
418                              rbCb->rlcId.cellId);
419                RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
420                              "soStart and soEnd = %d, %d UEID:%d CELLID:%d",
421                              seqSo,
422                              seg->amHdr.so - 1,
423                              rbCb->rlcId.ueId,
424                              rbCb->rlcId.cellId);
425             }
426
427             seqSo = seg->soEnd + 1;
428             KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
429          }
430
431          /* Check if the last segment is missing */
432          KW_LLIST_LAST_SEG(recBuf->segLst, seg);
433          if ((seg != NULLP) &&
434              (seg->amHdr.si != KW_SI_LAST_SEG && nackCnt < KW_MAX_NACK_CNT))
435          {
436             staPduEncSize += kwAmmUlSetNackInfo(rbCb,
437                                                 sn,
438                                                 TRUE,
439                                                 seqSo,
440                                                 KW_ALL_BYTES_MISSING,
441                                                 pStatusPdu,
442                                                 &prevNackSn);
443
444             RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
445                           "kwAmmUlAssembleCntrlInfo: Missing (last) byte " 
446                           "segment's SN:%d UEID:%d CELLID:%d",
447                           sn,
448                           rbCb->rlcId.ueId,
449                           rbCb->rlcId.cellId);
450             RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
451                           "soStart and soEnd = %d, %d UEID:%d CELLID:%d",
452                           seqSo,
453                           KW_ALL_BYTES_MISSING,
454                           rbCb->rlcId.ueId,
455                           rbCb->rlcId.cellId);
456          }
457       }
458       
459
460       sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
461       MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
462       
463       /* Get the received Buffer the updated/next SN */
464       recBuf =  kwUtlGetRecBuf(AMUL.recBufLst, sn);
465
466       /* Find the next missing sequence number if nackCnt reaches maximum and
467          still Reordering window has some missing AMDPDUs / AMDPDU segments. The
468          next missing sequence number will be considered as the ack sequnece
469          number in the status pdu.*/
470       if((nackCnt == KW_MAX_NACK_CNT) &&
471           ((recBuf == NULLP) ||
472             ((recBuf->pdu == NULLP) &&
473              (recBuf->segLst.count > 0))))
474       {
475          break;
476       }
477    }
478  
479    /*Unfortunately i have write below peice of code here because kwAmmsetNackInfo()
480     * don't know that this is the last nackSn with nackRange*/
481    nackInfo = &(pStatusPdu->nackInfo[pStatusPdu->nackCount]);
482    if(nackInfo->nackRange)
483    {
484       if((nackInfo->soEnd) && (!nackInfo->soStart))
485       {
486          /*First nack_sn of this nackRange not segmented but last is segmented */
487          staPduEncSize += 5; /*32 for soStart and soEnd and 8 for nackRange */ 
488       }
489       else
490       {
491          /*First nack_sn of this nackRange was segmented */
492          staPduEncSize += 1; /*8 for nackRange */ 
493       }
494    }
495    /* nackCount is used as an index to nackInfo array but in status Pdu it
496     * should be equal to number nackInfo that are filled. hence incrementing by 1*/
497    if(prevNackSn != 0xffffffff)
498    {
499       pStatusPdu->nackCount++;
500    }
501    /* Update ACK SN with the last sn for which feedback is not assembled */
502    if ( mSn == rxHighestStatus)
503    {
504       pStatusPdu->ackSn = AMUL.rxHighestStatus;
505    }
506    else
507    {
508       pStatusPdu->ackSn = sn;
509    }
510
511    RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
512             "kwAmmUlAssembleCntrlInfo: ACK PDU's SN = %d"
513             "UEID:%d CELLID:%d",
514             pStatusPdu->ackSn,
515             rbCb->rlcId.ueId,
516             rbCb->rlcId.cellId);
517
518    pStatusPdu->controlBo = staPduEncSize; /*Its already in bytes */
519
520    AMUL.staTrg = FALSE;
521    AMUL.gatherStaPduInfo = FALSE;
522
523
524    if (KwUlUdxStaPduReq(&sapCb->pst,
525                         sapCb->spId,
526                         &rbCb->rlcId,
527                         pStatusPdu) != ROK)
528    {
529       RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
530                "Failed to Send Sta Pdu UEID:%d CELLID:%d",
531                rbCb->rlcId.ueId,
532                rbCb->rlcId.cellId);
533       KW_FREE_SHRABL_BUF_WC(sapCb->pst.region,
534                             sapCb->pst.pool,
535                             pStatusPdu, 
536                             sizeof(KwUdxDlStaPdu));
537    }
538
539    RETVOID;
540 }
541
542 #ifdef XEON_SPECIFIC_CHANGES
543 extern U32  gRlcDatIndUL;
544 #endif
545
546 #ifdef T2K_TRIGGER_RLC_REEST
547 PUBLIC U32 drpRlcDrbPack;
548 #endif
549 /**
550  * @brief Handler to process the PDUs received from MAC and send it to PDCP
551  *
552  * @details
553  *    This function is invoked by UTL with the PDU(s) received from MAC.
554  *    It reorders the received data PDUs and trigger status report as
555  *    needed. Reassembles the SDUs in sequence and send it to PDCP.
556  *    It also processes the control PDU
557  *
558  * @param[in]  gCb      RLC instance control block
559  * @param[in]  rbCb     RB control block
560  * @param[out] pduInfo  PDU Info received from MAC
561  *
562  *  @return Void
563  *
564  */
565 #ifdef LTE_L2_MEAS
566 #ifdef ANSI
567 PUBLIC Void kwAmmProcessPdus
568 (
569 KwCb                    *gCb,
570 KwUlRbCb                *rbCb,
571 KwPduInfo               *pduInfo,
572 U32                     ttiCnt
573 )
574 #else
575 PUBLIC Void kwAmmProcessPdus(gCb, rbCb, pduInfo, ulTimeInfo)
576 KwCb                    *gCb;
577 KwUlRbCb                *rbCb;
578 KwPduInfo               *pduInfo;
579 U32                     ttiCnt;
580 #endif
581 #else
582 #ifdef ANSI
583 PUBLIC Void kwAmmProcessPdus
584 (
585 KwCb        *gCb,
586 KwUlRbCb    *rbCb,
587 KwPduInfo   *pduInfo
588 )
589 #else
590 PUBLIC Void kwAmmProcessPdus(gCb, rbCb, pduInfo)
591 KwCb        *gCb;
592 KwUlRbCb    *rbCb;
593 KwPduInfo   *pduInfo;
594 #endif
595 #endif
596 {
597    Buffer    *pdu;
598    KwAmUl    *amUl;
599    KwAmHdr   amHdr;
600    U8        numPdu = 0;
601    U8        numPduToProcess;
602    KwSn      sn;
603    KwSn      tSn;
604    KwSn      mSn;
605    U8        fByte;
606    Bool      discFlg;
607 #ifdef LTE_L2_MEAS_RLC
608    MsgLen              rlcSduSz;  /*Holds length of Rlc Sdu*/
609 #endif /* LTE_L2_MEAS */
610
611    TRC2(kwAmmProcessPdus)
612
613
614    amUl = &AMUL;
615
616    numPduToProcess = KW_MIN(pduInfo->numPdu, RGU_MAX_PDU);
617    RLOG_ARG4(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
618             "numPdu[%ld],numPduToProcess[%ld] UEID:%ld CELLID:%ld",
619             numPdu,
620             numPduToProcess,
621             rbCb->rlcId.ueId,
622             rbCb->rlcId.cellId);
623
624    //printf ("++++++++++++  5GNRLOG numPduToProcess %d \n", numPduToProcess);
625    while (numPdu < numPduToProcess)
626    {
627    //printf ("++++++++++++  5GNRLOG processing pdu  %d \n", numPdu);
628       discFlg = FALSE;
629       pdu = pduInfo->mBuf[numPdu++];
630
631       if (! pdu)
632       {
633
634          RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
635                   "Null Pdu UEID:%d CELLID:%d",
636                   rbCb->rlcId.ueId,
637                   rbCb->rlcId.cellId);
638          gCb->genSts.errorPdusRecv++;
639          break;
640       }
641 #ifndef RGL_SPECIFIC_CHANGES
642 #ifndef TENB_ACC
643 #ifndef LTE_PAL_ENB
644       MsgLen len;
645       SFndLenMsg(pdu, &len);
646       ulrate_rgu += len;
647 #endif
648 #endif
649 #endif      
650       /* Extract AM PDU/SEG header Info */
651       KW_MEM_ZERO(&amHdr, sizeof(KwAmHdr));
652       /* Avoided the allocation of amHdr and sending
653          a single pointer */
654       if (kwAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
655       {
656          RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
657                   "Header Extraction Failed UEID:%d CELLID:%d",
658                   rbCb->rlcId.ueId,
659                   rbCb->rlcId.cellId);
660          KW_FREE_BUF(pdu);
661          gCb->genSts.errorPdusRecv++;
662          continue;
663       }
664       /* Check if its a control PDU */
665       if (amHdr.dc == 0)
666       {
667          kwAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
668          KW_FREE_BUF(pdu);
669          continue;
670       }
671       if((amHdr.si == KW_SI_LAST_SEG) && (!amHdr.so))
672       {
673          RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
674                "kwAmmProcessPdus: Dropping PDU because SO can't be zero for last segment sn:%u "
675                "UEID:%d CELLID:%d",
676                amHdr.sn,
677                rbCb->rlcId.ueId,
678                rbCb->rlcId.cellId);
679          KW_FREE_BUF(pdu);
680          continue;
681       }
682 #ifndef RGL_SPECIFIC_CHANGES
683 #ifdef LTE_TDD
684 #ifndef TENB_ACC
685 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
686 #ifndef LTE_PAL_ENB
687     /* Changed the condition to TRUE from ROK  */
688       if(isMemThreshReached(kwCb[0]->init.region) == TRUE)
689       {
690          extern U32 rlculdrop;
691          rlculdrop++;
692          KW_FREE_BUF(pdu);
693          continue;
694       }
695 #endif
696 #else
697 #ifndef LTE_PAL_ENB
698       /*ccpu00142274 - UL memory based flow control*/
699       if(isMemThreshReached(kwCb[0]->init.region) != ROK)
700       {
701          extern U32 rlculdrop;
702          rlculdrop++;
703          KW_FREE_BUF(pdu);
704          continue;
705       }
706 #endif
707 #endif
708 #endif
709 #endif
710 #endif
711
712 #ifdef T2K_TRIGGER_RLC_REEST
713       if(drpRlcDrbPack > 1000)
714       {
715          if(rbCb->rlcId.rbType == CM_LTE_DRB)
716          {
717             KW_FREE_BUF(pdu);
718             continue;
719          }
720       }
721       drpRlcDrbPack++;
722 #endif
723       /* Reordering data PDU */
724       sn = amHdr.sn;
725       if (kwAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
726       {
727          KwAmRecBuf      *recBuf;
728          Bool   tmrRunning;
729          KwSn   tVrMr;
730          KwSn   mrxNextHighestRcvd;
731
732 #ifdef LTE_L2_MEAS
733          kwUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
734 #endif /* LTE_L2_MEAS */
735
736          /* Update rxNextHighestRcvd */
737          MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
738          MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
739          if (mSn >= mrxNextHighestRcvd)
740          {
741             amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask)); 
742
743             RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
744                   "kwAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
745                   amUl->rxNextHighestRcvd,
746                   rbCb->rlcId.ueId,
747                   rbCb->rlcId.cellId);
748          }
749          
750          recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
751          if ((NULLP != recBuf) && ( recBuf->allRcvd))
752          {
753             /* deliver the reassembled RLC SDU to upper layer, 
754                But not removed from the table */
755             kwAmmUlReassembleSdus(gCb, rbCb, recBuf);
756             recBuf->isDelvUpperLayer = TRUE;
757
758             MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
759             
760             /* Update rxHighestStatus */
761             if (sn == amUl->rxHighestStatus)
762             {
763                tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
764
765                recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
766                /* Scan through till the upper edge of the window */
767                MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
768                while (mSn <= tVrMr)
769                {
770                   if ((NULLP == recBuf) || (!recBuf->allRcvd))
771                   {
772                      RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
773                            "kwAmmProcessPdus: Updated rxHighestStatus:%d "
774                            "UEID:%d CELLID:%d",
775                            tSn,
776                            rbCb->rlcId.ueId,
777                            rbCb->rlcId.cellId);
778
779                      amUl->rxHighestStatus = tSn;
780                      break;
781                   }
782                   tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
783                   recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn); 
784                   mSn++;
785                }
786             }
787
788
789             /* Update rxNext */
790             if (sn == amUl->rxNext)
791             {
792                tSn = sn;
793                recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
794                MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
795                /* Scan through till the upper edge of the window */
796                while (mSn <= tVrMr)
797                {
798                   if ((NULLP != recBuf) && (recBuf->allRcvd) &&
799                       (TRUE == recBuf->isDelvUpperLayer))
800                   {
801                      /* RecBuf should remove from table 
802                         since PDU is already sent to upper layer */
803                       recBuf->isDelvUpperLayer = FALSE;
804                       kwUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
805                   }
806                   else
807                   {
808                      amUl->rxNext = tSn;
809                      amUl->vrMr = (amUl->rxNext + (KW_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
810                      break;
811                   }
812                   tSn = (tSn + 1) & (amUl->snModMask); 
813                   recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
814                   mSn++;
815                }
816             }
817          }
818
819          /* Check if reOrdTmr is running and update rxNextStatusTrig accordingly */
820          tmrRunning = kwChkTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
821          if (tmrRunning)
822          {
823             Bool snInWin = KW_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
824
825             if ( (amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
826                                              (amUl->rxNextStatusTrig != amUl->vrMr) ) )
827             {
828                kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
829                tmrRunning = FALSE;
830             }
831          }
832
833          if (!tmrRunning)
834          {
835             if (amUl->rxNextHighestRcvd > amUl->rxNext)
836             {
837                kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
838                amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
839
840                RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
841                         "kwAmmProcessPdus: Updated rxNextStatusTrig = %d UEID:%d CELLID:%d",
842                         amUl->rxNextStatusTrig,
843                         rbCb->rlcId.ueId,
844                         rbCb->rlcId.cellId);
845             }
846          }
847       }
848       else
849       {
850          discFlg = TRUE;
851          gRlcStats.amRlcStats.numULPdusDiscarded++;
852       }
853
854       if (amHdr.p)
855       {
856          kwAmmTriggerStatus(gCb,rbCb, sn, discFlg);
857       }
858    }
859
860 #ifdef LTE_L2_MEAS
861    kwUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
862 #endif /* LTE_L2_MEAS */
863    gCb->genSts.pdusRecv += pduInfo->numPdu;
864    if (amUl->gatherStaPduInfo)
865    {
866       kwAmmUlAssembleCntrlInfo(gCb,rbCb);
867    }
868
869    RETVOID;
870 }
871
872
873 /**
874  * @brief Private handler to extract header Information of the PDU
875  *
876  * @details
877  *    This function extracts the header elements of the PDU and store them
878  *    in db for future reference.
879  *
880  *    fByte - is the first byte removed from the PDU as part of calling
881  *            functions
882  *
883  * @param[in]  gCb     RLC instance control block
884  * @param[in]  rbCb    Uplink RB control block
885  * @param[in]  pdu     Received PDU
886  * @param[out] amHdr   Pointer to the extracted AM header
887  * @param[out] fByte   First byte removed from the PDU
888  *
889  * @return S16
890  *     -# ROK
891  *     -# RFAILED
892  *
893  */
894 #ifdef ANSI
895 PRIVATE S16 kwAmmExtractHdr
896 (
897 KwCb       *gCb,
898 KwUlRbCb   *rbCb,
899 Buffer     *pdu,
900 KwAmHdr    *amHdr,
901 U8         *fByte
902 )
903 #else
904 PRIVATE S16 kwAmmExtractHdr(gCb, rbCb, pdu, amHdr, fByte)
905 KwCb       *gCb;
906 KwUlRbCb   *rbCb;
907 Buffer     *pdu;
908 KwAmHdr    *amHdr;
909 U8         *fByte;
910 #endif
911 {
912    U8         snByte;
913    KwSn        sn = 0;
914    MsgLen     pduSz;
915    KwExtHdr   hdrInfo;
916
917    TRC2(kwAmmExtractHdr)
918
919
920    KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
921
922    /* Extract fixed part of the header */
923    SFndLenMsg(pdu,&pduSz);
924    SRemPreMsg(fByte, pdu);
925    amHdr->dc = (*fByte & KW_DC_POS) >> KW_DC_SHT;
926    if (KW_CNTRL_PDU == amHdr->dc)
927    {
928    //printf ("++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
929       RETVALUE(ROK);
930    }
931
932    amHdr->p  = (*fByte & KW_POLL_POS) >> KW_POLL_SHT;
933
934    amHdr->si = (*fByte & KW_SI_POS)   >> KW_SI_SHT;
935
936    /* 12 BIT SN */
937    if (rbCb->m.amUl.snLen == KW_AM_CFG_12BIT_SN_LEN)
938    {
939       SRemPreMsg(&snByte, pdu);
940       sn = (KwSn)(((*fByte & KW_SN_POS_12BIT) << KW_BYTE_LEN ) | snByte);
941       amHdr->sn = sn;
942    }
943    else if (rbCb->m.amUl.snLen == KW_AM_CFG_18BIT_SN_LEN)
944    {
945       SRemPreMsg(&snByte, pdu);
946       sn = (KwSn)(((*fByte & KW_SN_POS_18BIT) << KW_BYTE_LEN ) | snByte);
947
948       SRemPreMsg(&snByte, pdu);
949       sn = ((sn << KW_BYTE_LEN) | snByte);
950
951       amHdr->sn = sn;
952    }
953    if ((amHdr->si != 0) && (amHdr->si != 0x01))
954    {
955       hdrInfo.len = KW_SO_LEN_5GNR;
956       kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
957       amHdr->so = hdrInfo.val;
958       pduSz -= 2;
959    }
960
961    //printf ("++++++++++++ 5GNRLOG HDR extracted DATA : sn %d  \n", sn);
962    RETVALUE(ROK);
963 }
964
965 #ifdef OLD
966 /**
967  * @brief Private handler to extract header Information of the PDU
968  *
969  * @details
970  *    This function extracts the header elements of the PDU and store them
971  *    in db for future reference.
972  *
973  *    fByte - is the first byte removed from the PDU as part of calling
974  *            functions
975  *
976  * @param[in]  gCb     RLC instance control block
977  * @param[in]  rbCb    Uplink RB control block
978  * @param[in]  pdu     Received PDU
979  * @param[out] amHdr   Pointer to the extracted AM header
980  * @param[out] fByte   First byte removed from the PDU
981  *
982  * @return S16
983  *     -# ROK
984  *     -# RFAILED
985  *
986  */
987 #ifdef ANSI
988 PRIVATE S16 kwAmmExtractHdrOld
989 (
990 KwCb       *gCb,
991 Buffer     *pdu,
992 KwAmHdr    *amHdr,
993 U8         *fByte
994 )
995 #else
996 PRIVATE S16 kwAmmExtractHdrOld(gCb, pdu, amHdr, fByte)
997 KwCb       *gCb;
998 Buffer     *pdu;
999 KwAmHdr    *amHdr;
1000 U8         *fByte;
1001 #endif
1002 {
1003    U8         e;
1004    U8         snByte;
1005    U16        sn;
1006    MsgLen     pduSz;
1007    MsgLen     totalSz = 0;
1008    KwExtHdr   hdrInfo;
1009
1010    TRC2(kwAmmExtractHdrOld)
1011
1012
1013    KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
1014
1015    /* Extract fixed part of the header */
1016    SFndLenMsg(pdu,&pduSz);
1017    SRemPreMsg(fByte, pdu);
1018    amHdr->dc = (*fByte & KW_DC_POS) >> KW_DC_SHT;
1019    if (KW_CNTRL_PDU == amHdr->dc)
1020    {
1021       RETVALUE(ROK);
1022    }
1023    /* kw002.201 : Changed the extraction of hdr elements to avoid */
1024    /*             function calls                                  */
1025    amHdr->rf = (*fByte & KW_RF_POS)   >> KW_RF_SHT;
1026    amHdr->p  = (*fByte & KW_POLL_POS) >> KW_POLL_SHT;
1027    amHdr->fi = (*fByte & KW_FI_POS)   >> KW_FI_SHT;
1028    e = amHdr->e  = (*fByte & KW_E_POS)>> KW_E_SHT;
1029
1030    SRemPreMsg(&snByte, pdu);
1031    sn = (U16)(((*fByte & KW_SN_POS) << KW_BYTE_LEN ) | snByte);
1032    amHdr->sn = sn;
1033    if (amHdr->rf == 1)
1034    {
1035       /* Extract extn part of the header */
1036       hdrInfo.len = KW_LSF_LEN;
1037       kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1038       amHdr->lsf = (U8)hdrInfo.val;
1039
1040       hdrInfo.len = KW_SO_LEN;
1041       kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1042       amHdr->so = hdrInfo.val;
1043       pduSz -= 2;
1044    }
1045
1046    amHdr->numLi = 0;
1047    /* Extract LIs */
1048    while (e && (amHdr->numLi < KW_MAX_UL_LI))
1049    {
1050       hdrInfo.len = KW_E_LEN;
1051       kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1052       e = amHdr->e = (U8)hdrInfo.val;
1053
1054       /* Extract LI value*/
1055       hdrInfo.len = KW_LI_LEN;
1056       kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1057       /* li = hdrInfo.val;*/
1058
1059       /* check if LI is zero */
1060       if (! hdrInfo.val)
1061       {
1062          RLOG0(L_ERROR, "Received LI as 0");
1063          RETVALUE(RFAILED);
1064       }
1065
1066       /* store the extracted  LI value */
1067       amHdr->li[amHdr->numLi++] = hdrInfo.val;
1068       totalSz += hdrInfo.val;  /* incrment the size by LI value */
1069    }
1070
1071    /*ccpu00122597:PDU is dropped if liCnt exceeds KW_MAX_LI*/
1072    if(e && (amHdr->numLi >= KW_MAX_UL_LI))
1073    {
1074       RLOG2(L_ERROR,"LI Count [%u] exceeds Max LI Count[%u]", 
1075             amHdr->numLi, KW_MAX_UL_LI);
1076       RETVALUE(RFAILED);
1077    }
1078
1079    /*                                first 2 bytes + Add one for  Odd LI*/
1080    pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
1081
1082    if ( totalSz >= pduSz )
1083    {   
1084       RLOG3(L_ERROR,"SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
1085                amHdr->sn, totalSz, pduSz);
1086       RETVALUE(RFAILED);
1087    }
1088
1089    RETVALUE(ROK);
1090 }
1091 #endif
1092
1093 /**
1094  * @brief Private handler to process the status PDU
1095  *
1096  * @details
1097  *    Private handler invokded by kwAmmProcessPdus to process the
1098  *    control PDU (status report) received from its peer RLC entity.
1099  *
1100  *        - Decode the values from the received control pdu
1101  *        - Create a KwUdxStaPdu structure, copy the values onto it and
1102  *          send it to the DL instance for further processing
1103  *
1104  * @param[in]  gCb       RLC instance control block
1105  * @param[in]  rbCb      Uplink RB control block
1106  * @param[in]  cntrlPdu  Control PDU received from MAC
1107  * @param[in]  fByte     First byte already removed from the STATUS PDU
1108  *
1109  *  @return  Void
1110  *
1111  */
1112 #ifdef ANSI
1113 PRIVATE Void kwAmmUlHndlStatusPdu
1114 (
1115 KwCb       *gCb,
1116 KwUlRbCb   *rbCb,
1117 Buffer     *cntrlPdu,
1118 U8         *fByte
1119 )
1120 #else
1121 PRIVATE Void kwAmmUlHndlStatusPdu(gCb, rbCb, cntrlPdu, fByte)
1122 KwCb       *gCb;
1123 KwUlRbCb   *rbCb;
1124 Buffer     *cntrlPdu;
1125 U8         *fByte;
1126 #endif
1127 {
1128    U8             e1;
1129    KwExtHdr       hdrInfo;
1130    KwUdxStaPdu    *pStaPdu;
1131    KwUdxUlSapCb   *sapCb;
1132    U8             e3; /* NACK RANGE : 5GNR */
1133    U32            snLen;
1134    U32            snRange;
1135    U32            resrvdBitsAckSn=0;
1136    U32            resrvdBitsNackSn=0;
1137
1138    TRC2(kwAmmUlHndlStatusPdu)
1139
1140
1141    KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
1142
1143    /* Extract the Control PDU */
1144    hdrInfo.hdr  = (*fByte << 1);
1145    hdrInfo.pLen = 4;
1146
1147    /* D/C has been shifted in the calling function */
1148    if (hdrInfo.hdr & 0xE0)
1149    {
1150       RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
1151                "Reserved value for CPT received UEID:%d CELLID:%d",
1152                rbCb->rlcId.ueId,
1153                rbCb->rlcId.cellId);
1154
1155       RETVOID;
1156    }
1157
1158    sapCb = KW_GET_UDX_SAP(gCb);
1159
1160    KW_ALLOC_SHRABL_BUF(sapCb->pst.region, 
1161                        sapCb->pst.pool, 
1162                        pStaPdu, 
1163                        sizeof(KwUdxStaPdu));
1164
1165 #if (ERRCLASS & ERRCLS_ADD_RES)
1166    /* Memory allocation failure can not be expected  */
1167    if(!pStaPdu)
1168    {
1169      RETVOID;
1170    }
1171 #endif   
1172
1173    if (rbCb->m.amUl.snLen == KW_AM_CFG_12BIT_SN_LEN)
1174    {
1175       snLen = 12;
1176       resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_12BITS;
1177       resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_12BITS;
1178    }
1179    else if (rbCb->m.amUl.snLen == KW_AM_CFG_18BIT_SN_LEN)
1180    {
1181       snLen = 18;
1182       resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_18BITS;
1183       resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_18BITS;
1184    }
1185    else
1186    {
1187       snLen = KW_SN_LEN;
1188       resrvdBitsAckSn = 0;
1189       resrvdBitsAckSn = 0;
1190    }
1191
1192    pStaPdu->nackCnt = 0;
1193    /* For CPT */
1194    hdrInfo.hdr = hdrInfo.hdr << KW_CPT_LEN;
1195
1196    /* ACK Sn */
1197    hdrInfo.len = snLen;
1198    kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1199    pStaPdu->ackSn = hdrInfo.val;
1200
1201    //printf ("++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n",  pStaPdu->ackSn);
1202    /* Check if NACK Exists */
1203    hdrInfo.len = KW_E1_LEN;
1204    kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1205    e1 = (U8)hdrInfo.val;
1206    RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
1207             "kwAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1208             pStaPdu->ackSn,
1209             rbCb->rlcId.ueId,
1210             rbCb->rlcId.cellId);
1211
1212    /* Extract the Reserved Bits after ACK SN field */
1213    hdrInfo.len = resrvdBitsAckSn;
1214    kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1215
1216    /* If NACK exists in control PDU */
1217    /* For ACKs and NACKs */
1218    while (e1 && (pStaPdu->nackCnt < KW_MAX_NACK_CNT))
1219    {
1220       hdrInfo.len = snLen;
1221       kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1222       pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1223
1224       hdrInfo.len = KW_E1_LEN;
1225       kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1226       e1 = (U8)hdrInfo.val;
1227
1228       /* Extract e2 */
1229       /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
1230          already present*/
1231       kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1232       /*  e2 = (U8) hdrInfo.val;*/
1233
1234       /* Store e2 value */
1235       pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
1236
1237       /* Extract e3 : 5GNR */
1238       /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
1239          already present*/
1240       kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1241       e3 = (U8) hdrInfo.val;
1242
1243       /* Extract Reserved Bits after NACK SN */
1244       hdrInfo.len = resrvdBitsNackSn;
1245       kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1246
1247       /* Test for resegmentation */
1248       if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1249       {
1250          hdrInfo.len = KW_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1251          kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1252          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1253
1254          kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1255          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = hdrInfo.val;
1256
1257          RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1258                        "kwAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1259                        "UEID:%d CELLID:%d",
1260                        pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1261                        pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd,      
1262                        rbCb->rlcId.ueId,
1263                        rbCb->rlcId.cellId);
1264       }                                                                
1265       else
1266       {
1267          hdrInfo.len = 0;
1268          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1269          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = 0;
1270
1271       }
1272       /* NACK RANGE Field is SET */
1273       if (e3)
1274       {
1275          /* Extract NACK range field */
1276          hdrInfo.len = KW_NACK_RANGE_LEN;
1277          kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1278          snRange = (U8)hdrInfo.val;
1279
1280          pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1281
1282       }
1283       pStaPdu->nackCnt++;
1284    }
1285
1286    gRlcStats.amRlcStats.numULStaPduRcvd++;
1287    gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1288
1289    /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1290       to the last NACK SN + 1 and discard the original ACK_SN*/
1291    if(pStaPdu->nackCnt == KW_MAX_NACK_CNT)
1292    {
1293       pStaPdu->ackSn = (pStaPdu->nackInfo[KW_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1294    }
1295
1296
1297    /* Parse & send Status PDU to RLC-DL */
1298    KwUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1299
1300    RETVOID;
1301 }
1302
1303 /**
1304  * @brief Private handler to release all stored segments
1305  *
1306  * @details
1307  *    Private handler invokded by kwAmmUlPlacePduInRecBuf to release the
1308  *    stored segements in case a complete PDU is received later.
1309  *
1310  * @param[in]  gCb      RLC instance control block
1311  * @param[in]  recBuf   Buffer that stores a received PDU or segments
1312  *
1313  * @return  Void
1314  *
1315  */
1316 #ifdef ANSI
1317 PRIVATE Void kwAmmUlRlsAllSegs
1318 (
1319 KwCb         *gCb,
1320 KwAmRecBuf   *recBuf
1321 )
1322 #else
1323 PRIVATE Void kwAmmUlRlsAllSegs(gCb,recBuf)
1324 KwCb         *gCb;
1325 KwAmRecBuf   *recBuf;
1326 #endif
1327 {
1328    KwSeg *seg;
1329
1330    TRC2(kwAmmUlRlsAllSegs)
1331
1332    KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1333    while (seg != NULLP)
1334    {
1335       KW_FREE_BUF_WC(seg->seg);
1336       cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1337       KW_FREE_WC(gCb,seg, sizeof(KwSeg));
1338       KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1339    }
1340
1341    RETVOID;
1342 }
1343
1344 /**
1345  * @brief Private handler to store the received segment
1346  *
1347  * @details
1348  *    Private handler invokded by kwAmmUlPlacePduInRecBuf to add a received
1349  *    segment in reception buffer of a RBCB.
1350  *    - It is responsible for detecting duplicate segments
1351  *    - Adding it at appropriate position in the received buffer
1352  *    - Calling ExpByteSeg to set expSo field in the receiver buffer
1353  *
1354  * @param[in]  gCb      RLC instance control block
1355  * @param[in]  rbCb     Radio Bearer Contro Block
1356  * @param[in]  amHdr    AM Header received
1357  * @param[in]  pdu      Buffer received other than the headers
1358  * @param[in]  pduSz    size of the PDU buffer received
1359  *
1360  * @return  Bool
1361  *   -#TRUE  Successful insertion into the receiver buffer
1362  *   -#FALSE Possibly a duplicate segment
1363  */
1364 #ifdef ANSI
1365 PRIVATE Bool kwAmmAddRcvdSeg
1366 (
1367 KwCb       *gCb,
1368 KwUlRbCb   *rbCb,
1369 KwAmHdr    *amHdr,
1370 Buffer     *pdu,
1371 U16        pduSz
1372 )
1373 #else
1374 PRIVATE Bool kwAmmAddRcvdSeg(gCb, rbCb, amHdr, pdu, pduSz)
1375 KwCb       *gCb;
1376 KwUlRbCb   *rbCb;
1377 KwAmHdr    *amHdr;
1378 Buffer     *pdu;
1379 U16        pduSz;
1380 #endif
1381 {
1382    KwAmRecBuf   *recBuf = NULLP;
1383    KwSeg        *seg;
1384    KwSeg        *tseg;
1385    U16          soEnd;       /* Holds the SoEnd of received segment */
1386    U16          expSo = 0;   /* Expected SO */
1387
1388    TRC2(kwAmmAddRcvdSeg)
1389
1390    soEnd = amHdr->so + pduSz - 1;
1391    recBuf =  kwUtlGetRecBuf(AMUL.recBufLst, amHdr->sn);
1392
1393    if (NULLP == recBuf)
1394    {
1395       KW_ALLOC(gCb,recBuf, sizeof(KwAmRecBuf));
1396 #if (ERRCLASS & ERRCLS_ADD_RES)
1397       if (recBuf == NULLP)
1398       {
1399          RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1400                   "Memory allocation failed UEID:%d CELLID:%d",
1401                   rbCb->rlcId.ueId,
1402                   rbCb->rlcId.cellId);
1403
1404          KW_FREE_BUF(pdu);
1405          RETVALUE(FALSE);
1406       }
1407 #endif /* ERRCLASS & ERRCLS_RES */
1408       kwUtlStoreRecBuf(AMUL.recBufLst, recBuf, amHdr->sn);
1409    }
1410    else
1411    {
1412       if (recBuf->allRcvd == TRUE)
1413       {
1414          KW_FREE_BUF(pdu);
1415          RETVALUE(FALSE);
1416       }
1417    }
1418                         
1419    recBuf->isDelvUpperLayer = FALSE;
1420    /* kw003.201 - Move past the segments that are different than the */
1421    /*             one received.                                      */
1422    KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1423    while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1424    {
1425       expSo = seg->amHdr.so + seg->segSz;
1426       KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
1427    }
1428
1429    /* The received segment should start after the end of previous seg */
1430    if (expSo > amHdr->so)
1431    {
1432       /* This is a duplicate segment */
1433       gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1434       KW_FREE_BUF(pdu);
1435       RETVALUE(FALSE);
1436    }
1437
1438    if ((seg) && (seg->amHdr.so <= soEnd))
1439    {
1440       /* This is a duplicate segment */
1441       gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1442       KW_FREE_BUF(pdu);
1443       RETVALUE(FALSE);
1444    }
1445
1446    /* If we have come this far, we have to add this segment to the   */
1447    /* reception buffer as we either have eliminated duplicates or    */
1448    /* have found none.                                               */
1449    KW_ALLOC_WC(gCb,tseg, sizeof(KwSeg));
1450 #if (ERRCLASS & ERRCLS_ADD_RES)
1451    if (tseg == NULLP)
1452    {
1453       RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
1454                "Memory allocation failed UEID:%d CELLID:%d",
1455                rbCb->rlcId.ueId,
1456                rbCb->rlcId.cellId);
1457       KW_FREE_BUF(pdu);
1458       RETVALUE(FALSE);
1459    }
1460 #endif /* ERRCLASS & ERRCLS_RES */
1461
1462    tseg->seg = pdu;
1463    tseg->segSz = pduSz;
1464    KW_MEM_CPY(&tseg->amHdr, amHdr, sizeof(KwAmHdr));
1465    recBuf->amHdr.si = amHdr->si;
1466    recBuf->amHdr.sn = amHdr->sn;
1467    tseg->soEnd = soEnd;
1468    if (seg == NULLP)
1469    {
1470       cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1471    }
1472    else
1473    {
1474       recBuf->segLst.crnt = &seg->lstEnt;
1475       cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1476    }
1477    tseg->lstEnt.node = (PTR)tseg;
1478    kwAmmUpdExpByteSeg(gCb,&AMUL,tseg);
1479
1480    RETVALUE(TRUE);
1481 }
1482
1483 /**
1484  * @brief Private handler to place the PDU in the reception buffer
1485  *
1486  * @details
1487  *    This function checks if the received PDU's SN falls within the
1488  *    receiving window, after which it places the same in the reception
1489  *    buffer if its not a duplicate.
1490  *
1491  * @param[in]  gCb   RLC instance control block
1492  * @param[in]  pdu   Received PDU
1493  * @param[in]  rbCb  Uplink AM Radio Bearer
1494  * @param[out] amUl  AM UL Info
1495  *
1496  * @return Bool
1497  *     -# TRUE
1498  *     -# FALSE
1499  *
1500  */
1501 #ifdef ANSI
1502 PRIVATE Bool kwAmmUlPlacePduInRecBuf
1503 (
1504 KwCb       *gCb,
1505 Buffer     *pdu,
1506 KwUlRbCb   *rbCb,
1507 KwAmHdr    *amHdr
1508 )
1509 #else
1510 PRIVATE Bool kwAmmUlPlacePduInRecBuf(gCb, pdu, rbCb, amHdr)
1511 KwCb       *gCb;
1512 Buffer     *pdu;
1513 KwUlRbCb   *rbCb;
1514 KwAmHdr    *amHdr;
1515 #endif
1516 {
1517    KwSn     sn;
1518    MsgLen   pduSz;
1519    KwAmUl   *amUl = &(rbCb->m.amUl);
1520
1521    TRC2(kwAmmUlPlacePduInRecBuf)
1522
1523
1524    sn = amHdr->sn;
1525    SFndLenMsg(pdu, &pduSz);
1526
1527    gCb->genSts.bytesRecv += pduSz;
1528    gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz; 
1529    if (!KW_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1530    {
1531       gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1532       RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
1533                     "kwAmmUlPlacePduInRecBuf: SN  %d outside the window"
1534                     "UEID:%d CELLID:%d",
1535                     sn,
1536                     rbCb->rlcId.ueId,
1537                     rbCb->rlcId.cellId);
1538
1539       gCb->genSts.unexpPdusRecv++;
1540       KW_FREE_BUF(pdu);
1541       RETVALUE(FALSE);
1542    }
1543
1544    if (amHdr->si == 0)
1545    {
1546       KwAmRecBuf *recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
1547
1548       /* We received a complete PDU. Either we already have it, in which */
1549       /* case we just ignore the new PDU and discard it. Otherwise,      */
1550       /* store the received PDU in the reception buffer                  */
1551       if (NULLP == recBuf)
1552       {
1553          KW_ALLOC(gCb, recBuf, sizeof(KwAmRecBuf));
1554 #if (ERRCLASS & ERRCLS_ADD_RES)
1555          if (recBuf == NULLP)
1556          {
1557             RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1558                      "Memory allocation failed UEID:%d CELLID:%d",
1559                      rbCb->rlcId.ueId,
1560                      rbCb->rlcId.cellId);
1561             KW_FREE_BUF(pdu);
1562             RETVALUE(FALSE);
1563          }
1564 #endif /* ERRCLASS & ERRCLS_RES */
1565          kwUtlStoreRecBuf(AMUL.recBufLst, recBuf, sn);
1566       }
1567       else if (recBuf->allRcvd != TRUE)
1568       {
1569          kwAmmUlRlsAllSegs(gCb,recBuf);
1570       }
1571       else
1572       {
1573          gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1574          gCb->genSts.unexpPdusRecv++;
1575          KW_FREE_BUF(pdu);
1576          RETVALUE(FALSE);
1577       }
1578       recBuf->isDelvUpperLayer = FALSE;
1579       recBuf->pdu = pdu;
1580       recBuf->pduSz = pduSz;
1581       recBuf->allRcvd = TRUE;
1582       gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1583       KW_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(KwAmHdr));
1584       RETVALUE(TRUE);
1585    }
1586    else
1587    {
1588       /* We received a segment. We need to add that to the existing */
1589       /* segments, if any.                                          */
1590       RETVALUE(kwAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1591    }
1592 }
1593
1594 /**
1595  * @brief Private handler to trigger status report
1596  *
1597  * @details
1598  *    Private handler invokded by kwAmmProcessPdus to check if the
1599  *    status report need to be sent, and update the status trigger
1600  *    flag accordingly based on status prohibit timer.
1601  *
1602  *    - Check if the received pdu's sn is less than rxHighestStatus, set the
1603  *      staTrg flag.
1604  *    - If staProhTmr is not running, calculate cntrlBo, else it'll be
1605  *      updated at the expiry of staProhTmr.
1606  *    - Expiry of reOrdTmr also will set staTrg flag.
1607  *
1608  * @param[in]  gCb       RLC instance control block
1609  * @param[in]  rbCb      Uplink RB control block
1610  * @param[in]  sn        Sequence number of the pdu based on which to check if
1611  *                       status needs to be triggered
1612  * @param[in]  discFlg   Whether this pdu was discarded or not
1613  *
1614  * @return  Void
1615  *
1616  */
1617 #ifdef ANSI
1618 PRIVATE Void kwAmmTriggerStatus
1619 (
1620 KwCb       *gCb,
1621 KwUlRbCb   *rbCb,
1622 KwSn       sn,
1623 Bool       discFlg
1624 )
1625 #else
1626 PRIVATE Void kwAmmTriggerStatus(gCb,rbCb, sn, discFlg)
1627 KwCb       *gCb;
1628 KwUlRbCb   *rbCb;
1629 KwSn       sn;
1630 Bool       discFlg;
1631 #endif
1632 {
1633    Bool     tmrRunning;
1634    KwSn     tSn;
1635    KwSn     tVrMr;
1636    KwSn     trxHighestStatus;
1637    KwAmUl   *amUl = &(rbCb->m.amUl);
1638
1639    TRC2(kwAmmTriggerStatus)
1640
1641
1642    MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1643    MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1644    MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1645
1646    /* kw005.201 Product CR ccpu00117114       *
1647     * The "=" in the 2nd condition is removed */
1648    if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1649    {
1650       RLOG_ARG2(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
1651                "kwAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1652                      rbCb->rlcId.ueId,
1653                      rbCb->rlcId.cellId);
1654
1655       amUl->staTrg = TRUE;
1656       amUl->gatherStaPduInfo = FALSE;
1657
1658       /* Check if staProhTmr is running */
1659       tmrRunning = kwChkTmr(gCb,(PTR) rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1660
1661       if (!tmrRunning)
1662       {
1663          amUl->gatherStaPduInfo = TRUE;
1664       }
1665    }
1666
1667    RETVOID;
1668 }
1669
1670 /**
1671  * @brief Private handler to reassemble from a segment or a PDU
1672  *
1673  * @details
1674  *    Private handler invokded by kwAmmReassembleSdus with either a
1675  *    PDU or a segment of a PDU. This is also called in the case of
1676  *    reestablishment and hence out of sequence joining is also to
1677  *    be supported
1678  *
1679  *
1680  * @param[in]  gCb     RLC instance control block
1681  * @param[in]  rbCb    Uplink RB control block
1682  * @param[in]  amHdr   AM header received for this segment/PDU
1683  * @param[in]  pdu     PDU to be reassembled
1684  *
1685  * @return  Void
1686  *
1687  */
1688 #ifdef ANSI
1689 PRIVATE Void kwAmmProcPduOrSeg
1690 (
1691 KwCb       *gCb,
1692 KwUlRbCb   *rbCb,
1693 KwAmHdr    *amHdr,
1694 Buffer     *pdu
1695 )
1696 #else
1697 PRIVATE Void kwAmmProcPduOrSeg(gCb, rbCb, amHdr, pdu)
1698 KwCb       *gCb;
1699 KwUlRbCb   *rbCb;
1700 KwAmHdr    *amHdr;
1701 Buffer     *pdu;
1702 #endif
1703 {
1704
1705    TRC2(kwAmmProcPduOrSeg)
1706
1707    if ((AMUL.expSn != amHdr->sn) || (AMUL.expSo != amHdr->so))
1708    {
1709       /* Release the existing partial SDU as we have PDUs or */
1710       /* segments that are out of sequence                   */
1711       rbCb->m.amUl.isOutOfSeq = TRUE;
1712       KW_FREE_BUF(AMUL.partialSdu);
1713    }
1714
1715    //if (amHdr->fi & KW_FI_FIRST_SEG)
1716    if (amHdr->si == 0x01)
1717    {/* first Segment of the SDU */
1718       if (AMUL.partialSdu != NULLP)
1719       { /* Some old SDU may be present */
1720          KW_FREE_BUF_WC(AMUL.partialSdu);
1721       }
1722       AMUL.partialSdu = pdu;
1723       pdu = NULLP;
1724    }
1725    else if(amHdr->si == 0x03)
1726    {/* Middle or last segment of the SUD */
1727       SCatMsg(AMUL.partialSdu,pdu, M1M2);
1728       KW_FREE_BUF_WC(pdu);
1729       pdu = NULLP;
1730    }
1731    else if (amHdr->si ==  0x02)
1732    {
1733       SCatMsg(pdu,AMUL.partialSdu,M2M1);
1734       KW_FREE_BUF_WC(AMUL.partialSdu);
1735    }
1736
1737    if (pdu != NULLP)
1738    {
1739       AMUL.partialSdu = NULLP;
1740       kwUtlSndDatInd(gCb,rbCb, pdu);
1741    }
1742
1743    RETVOID;
1744 }
1745
1746 /**
1747  *
1748  * @brief Private handler to reassemble SDUs
1749  *
1750  * @details
1751  *    Private handler invokded by kwAmmProcessPdus with the PDU
1752  *    from the reception buffer in sequence to reassemble SDUs and
1753  *    send it to PDCP.
1754  *
1755  *        - With the stored header info, FI and LSF segment / concatenate
1756  *          PDUs or byte segments of PDUs to get the associated SDU.
1757  *
1758  * @param[in]  rbCb     RB control block
1759  * @param[in]  pdu      PDU to be reassembled
1760  *
1761  *  @return  S16
1762  *      -# ROK
1763  *      -# RFAILED
1764  *
1765  */
1766 #ifdef ANSI
1767 PRIVATE S16 kwAmmUlReassembleSdus
1768 (
1769 KwCb         *gCb,
1770 KwUlRbCb     *rbCb,
1771 KwAmRecBuf   *recBuf
1772 )
1773 #else
1774 PRIVATE S16 kwAmmUlReassembleSdus(gCb, rbCb, recBuf)
1775 KwCb         *gCb;
1776 KwUlRbCb     *rbCb;
1777 KwAmRecBuf   *recBuf;
1778 #endif
1779 {
1780    KwSeg        *seg;
1781
1782    TRC2(kwAmmUlReassembleSdus)
1783    //if (recBuf->amHdr.rf == 0)
1784    if (recBuf->amHdr.si == 0)
1785    {
1786       /* This is a PDU */
1787       kwAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1788       /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1789       recBuf->pdu = NULLP;
1790       AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1791       AMUL.expSo = 0;
1792    }
1793    else
1794    {
1795       /* This is a set of segments */
1796       KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1797       AMUL.expSn = recBuf->amHdr.sn;
1798       AMUL.expSo = 0;
1799       while(seg)
1800       {
1801          kwAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1802          AMUL.expSo = seg->soEnd + 1;
1803
1804          cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1805          KW_FREE_WC(gCb, seg, sizeof(KwSeg));
1806
1807          KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1808       }
1809       AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1810       AMUL.expSo = 0;
1811    }
1812
1813    RETVALUE(ROK);
1814 }
1815
1816 /**
1817  * @brief   Handler to process the re-establishment request received from UIM
1818  *
1819  * @param[in] gCb         RLC instance control block
1820  * @param[in] rlcId       RLC identifier
1821  * @param[in] sendReEst   Whether to send back restablishment complete or not
1822  * @param[in] rbCb        Uplink RB control block
1823  *
1824  * @return  Void
1825  *
1826  */
1827 #ifdef ANSI
1828 PUBLIC Void kwAmmUlReEstablish
1829 (
1830 KwCb         *gCb,
1831 CmLteRlcId   rlcId,
1832 Bool         sendReEst,
1833 KwUlRbCb     *rbCb
1834 )
1835 #else
1836 PUBLIC Void kwAmmUlReEstablish(gCb, rlcId, sendReEst, rbCb)
1837 KwCb         *gCb;
1838 CmLteRlcId   rlcId;
1839 Bool         sendReEst;
1840 KwUlRbCb     *rbCb;
1841 #endif
1842 {
1843    KwSn   sn;
1844    KwSn   mSn;
1845    KwSn   mVrMr;
1846
1847 #ifndef KW_PDCP
1848    KwKwuSapCb *kwKwSap;
1849 #endif
1850    KwAmRecBuf   *recBuf = NULLP;
1851
1852    TRC2(kwAmmUlReEstablish);
1853
1854
1855    sn = AMUL.rxNext;
1856
1857    MODAMR(AMUL.vrMr, mVrMr, AMUL.rxNext, AMUL.snModMask);
1858    MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1859
1860    /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1861    while (mSn < mVrMr)
1862    {
1863       recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
1864       if (NULLP != recBuf)
1865       {
1866          if (recBuf->allRcvd == TRUE)
1867          {
1868             kwAmmUlReassembleSdus(gCb,rbCb, recBuf);
1869          }
1870          else
1871          {
1872             /* Remove PDU and segments */
1873             if(recBuf->pdu)
1874             {
1875                KW_FREE_BUF_WC(recBuf->pdu);
1876             }
1877             /* Release all the segments*/
1878             kwAmmUlRlsAllSegs(gCb,recBuf);
1879          }
1880          kwUtlDelRecBuf(AMUL.recBufLst, recBuf, gCb);
1881       }
1882       sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1883       MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1884    }
1885    /* Discard remaining PDUs and bytesegments in recBuf */
1886
1887    /* Stop all timers and reset variables */
1888    if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_REORD_TMR))
1889    {
1890        kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
1891    }
1892    if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_STA_PROH_TMR))
1893    {
1894        kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1895    }
1896
1897    AMUL.rxNext  = 0;
1898    AMUL.rxNextHighestRcvd  = 0;
1899    AMUL.rxNextStatusTrig  = 0;
1900    rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + KW_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1901    AMUL.rxHighestStatus = 0;
1902    AMUL.staTrg  = FALSE;
1903    AMUL.gatherStaPduInfo = FALSE;
1904    AMUL.expSn = 0;
1905    AMUL.expSo = 0;
1906    if (AMUL.partialSdu != NULLP)
1907    {
1908      KW_FREE_BUF(AMUL.partialSdu);
1909    }
1910    kwKwSap = gCb->u.ulCb->kwuUlSap + KW_UI_PDCP;
1911
1912    if(sendReEst)
1913    {
1914       KwUiKwuReEstCmpInd(&kwKwSap->pst, kwKwSap->suId, rlcId);
1915       rbCb->m.amUl.isOutOfSeq = FALSE;
1916    }
1917
1918    RETVOID;
1919 }
1920
1921 /**
1922  * @brief  Handler for reorder timer expiry
1923  *
1924  * @details
1925  *    This function is used to handle events upon expiry of reorder timer
1926  *
1927  *  @param[in] gCb   RLC instance control block
1928  *  @param[in] rbCb  RB control block
1929  *
1930  *  @return  Void
1931  *
1932  */
1933
1934 #ifdef ANSI
1935 PUBLIC Void kwAmmReOrdTmrExp
1936 (
1937 KwCb        *gCb,
1938 KwUlRbCb    *rbCb
1939 )
1940 #else
1941 PUBLIC Void kwAmmReOrdTmrExp(rbCb)
1942 KwCb        *gCb;
1943 KwUlRbCb    *rbCb;
1944 #endif
1945 {
1946    KwAmUl *amUl = &(rbCb->m.amUl);
1947    KwSn sn;
1948    KwSn mSn;
1949    KwSn mVrMr;
1950    KwSn mrxHighestStatus;
1951    KwSn mrxNextHighestRcvd;
1952    Bool tmrRunning = FALSE;
1953    KwAmRecBuf   *recBuf = NULLP;
1954
1955    TRC2(kwAmmReOrdTmrExp);
1956
1957
1958    /* Update rxHighestStatus */
1959    sn = amUl->rxNextStatusTrig;
1960
1961    MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1962    MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1963    recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
1964
1965    while (mSn < mVrMr)
1966    {
1967       if ((recBuf == NULLP) ||
1968           ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1969       {
1970          amUl->rxHighestStatus = sn;
1971          amUl->staTrg = TRUE;
1972          amUl->gatherStaPduInfo = FALSE;
1973
1974          /* Check if staProhTmr is running */
1975          tmrRunning = kwChkTmr(gCb,(PTR) rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1976
1977          if (!tmrRunning)
1978          {
1979             gRlcStats.amRlcStats.numULReOrdTimerExpires++;
1980             amUl->gatherStaPduInfo = TRUE;
1981             kwAmmUlAssembleCntrlInfo(gCb, rbCb);
1982          }
1983
1984          break;
1985       }
1986       sn = (sn + 1) & (amUl->snModMask); 
1987       MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1988    }
1989
1990    /* Update rxNextStatusTrig */
1991    MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1992    MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1993    if (mrxNextHighestRcvd > mrxHighestStatus)
1994    {
1995       kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
1996       amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1997    }
1998
1999    RETVOID;
2000 } /* kwAmmReOrdTmrExp */
2001
2002 /**
2003  * @brief  Handler for status prohibit timer expiry
2004  *
2005  * @details
2006  *    This function is used to handle events upon expiry of status prohibit
2007  *    timer
2008  *
2009  *  @param[in] gCb   RLC instance control block
2010  *  @param[in] rbCb   RB control block
2011  *
2012  *  @return  Void
2013  *
2014  */
2015
2016 #ifdef ANSI
2017 PUBLIC Void kwAmmStaProTmrExp
2018 (
2019 KwCb        *gCb,
2020 KwUlRbCb    *rbCb
2021 )
2022 #else
2023 PUBLIC Void kwAmmStaProTmrExp(gCb, rbCb)
2024 KwCb        *gCb;
2025 KwUlRbCb    *rbCb;
2026 #endif
2027 {
2028    KwAmUl *amUl = &(rbCb->m.amUl);
2029
2030    TRC2(kwAmmStaProTmrExp);
2031
2032
2033    amUl->gatherStaPduInfo = FALSE;
2034
2035    if (amUl->staTrg == TRUE)
2036    {
2037       amUl->gatherStaPduInfo = TRUE;
2038       /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
2039       kwAmmUlAssembleCntrlInfo(gCb,rbCb);
2040    }
2041
2042    RETVOID;
2043 } /* kwAmmStaProTmrExp */
2044
2045 /**
2046  * @brief  Handler to extract an element of AM Header
2047  *
2048  * @details
2049  *    This function is used to extract an element of AM header.
2050  *
2051  * @param[in]     pdu      The pdu to be decoded
2052  * @param[in,out] hdrInfo  Container to hold the decoded info
2053  *
2054  * @return Void
2055  *
2056  */
2057
2058 #ifdef ANSI
2059 PRIVATE Void kwAmmExtractElmnt
2060 (
2061 KwCb       *gCb,
2062 Buffer     *pdu,
2063 KwExtHdr   *hdrInfo
2064 )
2065 #else
2066 PRIVATE Void kwAmmExtractElmnt(gCb, pdu, hdrInfo)
2067 KwCb       *gCb;
2068 Buffer     *pdu;
2069 KwExtHdr   *hdrInfo;
2070 #endif
2071 {
2072    U8   hdr;
2073    U8   pLen = hdrInfo->pLen;
2074    U8   len  = (U8)hdrInfo->len;
2075    U32  val;
2076    U8   tHdr;
2077    U8   fLen;
2078    U8   rLen;
2079    /* U8   rLen1 = 0; */
2080    U16  tVal;
2081
2082    TRC2(kwAmmExtractElmnt);
2083
2084    hdr = hdrInfo->hdr;
2085
2086    if (pLen == 0)
2087    {
2088       SRemPreMsg(&hdr, pdu);
2089       pLen = 8;
2090    }
2091    tHdr = hdr;
2092    if (len <= 8)
2093    {
2094       val = tHdr >> (KW_BYTE_LEN - (len));
2095       hdr =  hdr << len;
2096       pLen -= len;
2097    }
2098    else /*if (len > 8) */
2099    {
2100       fLen = pLen;
2101       val = tHdr;
2102       val = val >> (KW_BYTE_LEN - fLen);
2103       val = val << (len - fLen);
2104       rLen = len - fLen;
2105       SRemPreMsg(&hdr, pdu);
2106       tHdr = hdr;
2107       if (rLen <= 8)
2108       {
2109          hdr = hdr >> (KW_BYTE_LEN - rLen);
2110          val = val | hdr;
2111          hdr = tHdr << rLen;
2112          pLen = (KW_BYTE_LEN - rLen);
2113       }
2114       else
2115       {
2116         rLen = rLen - KW_BYTE_LEN;
2117         tVal = hdr;
2118         tVal = tVal << rLen;
2119         val = val | tVal;
2120
2121         SRemPreMsg(&hdr, pdu);
2122         tHdr = hdr;
2123         hdr = hdr >> (KW_BYTE_LEN - rLen);
2124         val = val | hdr;
2125         hdr = tHdr << rLen;
2126         pLen = (KW_BYTE_LEN - rLen);
2127       }
2128    }
2129
2130    hdrInfo->pLen = pLen;
2131    hdrInfo->hdr = hdr;
2132    hdrInfo->val = val;
2133
2134    RETVOID;
2135 }
2136
2137 /**
2138  * @brief  Handler to updated expected byte seg
2139  *
2140  * @details
2141  *    This function is used to update expected byte segment. The next segment
2142  *    expected is indicated by the SO of the segment which is expected. Intially
2143  *    the segment with SO 0 is expected and then in order. When all the segments
2144  *    are received (which would happen when an expected SO is encountered
2145  *    with LSF set) the allRcvd flag is set to TRUE
2146  *
2147  * @param[in]  gCb   RLC instance control block
2148  * @param[in]  amUl  AM Uplink Control Block
2149  * @param[in]  seg   Newly received segment
2150  *
2151  * @return Void
2152  *
2153  */
2154
2155 #ifdef ANSI
2156 PRIVATE Void kwAmmUpdExpByteSeg
2157 (
2158 KwCb     *gCb,
2159 KwAmUl   *amUl,
2160 KwSeg    *seg
2161 )
2162 #else
2163 PRIVATE Void kwAmmUpdExpByteSeg(gCb, amUl, seg)
2164 KwCb     *gCb;
2165 KwAmUl   *amUl;
2166 KwSeg    *seg;
2167 #endif
2168 {
2169    U16    newExpSo; /* The new expected SO */
2170    KwSn   sn = seg->amHdr.sn;
2171    Bool   lstRcvd=FALSE;
2172    KwAmRecBuf *recBuf = NULLP;
2173    
2174    TRC2(kwAmmUpdExpByteSeg);
2175
2176
2177    recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
2178    if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
2179    {
2180       RETVOID;
2181    }
2182
2183    newExpSo   = seg->soEnd + 1;
2184    recBuf->expSo = newExpSo;
2185    //lstRcvd = seg->amHdr.lsf;
2186    if(seg->amHdr.si == 0x2)
2187    {  
2188       lstRcvd = TRUE;
2189    } 
2190    /* kw003.201 - This should update seg with the one after newSeg */
2191    KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
2192    while(seg)
2193    {
2194       /* keep going ahead as long as the expectedSo match with the header so
2195          else store the expSo for later checking again */
2196       if(seg->amHdr.si == 0x2)
2197       {  
2198          lstRcvd = TRUE;
2199       } 
2200       if (seg->amHdr.so == newExpSo)
2201       {
2202          newExpSo = seg->soEnd + 1;
2203          recBuf->expSo = newExpSo;
2204          //lstRcvd = seg->amHdr.lsf;
2205          KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
2206       }
2207       else
2208       {
2209          recBuf->expSo = newExpSo;
2210          RETVOID;
2211       }
2212    }
2213    if (lstRcvd == TRUE)
2214    {
2215       recBuf->allRcvd = TRUE;
2216       gRlcStats.amRlcStats.numRlcAmCellSduRx++;
2217    }
2218
2219    RETVOID;
2220 }
2221
2222 /**
2223  * @brief
2224  *   Function to release/free the Acknowledged Mode Module  RbCb buffers
2225  *
2226  * @details
2227  *   This primitive Frees the AM RbCb transmission Buffer, retransmission
2228  *   Buffer and reciption Buffers
2229  *
2230  * @param [in]   gCb   - RLC instance Control Block
2231  * @param [in]   rbCb  - RB Control Block
2232  *
2233  * @return   void
2234  */
2235 #ifdef ANSI
2236 PUBLIC Void kwAmmFreeUlRbCb
2237 (
2238 KwCb       *gCb,
2239 KwUlRbCb   *rbCb
2240 )
2241 #else
2242 PUBLIC Void kwAmmFreeUlRbCb(gCb,rbCb)
2243 KwCb       *gCb;
2244 KwUlRbCb   *rbCb;
2245 #endif
2246 {
2247    KwSn         curSn = 0;           /* Sequence number of PDU */
2248    KwSn         windSz;              /* PDU window size */
2249    KwAmRecBuf *recBuf = NULLP;
2250
2251    TRC2(kwAmmFreeUlRbCb)
2252
2253
2254    windSz  =  (KW_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
2255
2256    if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_REORD_TMR))
2257    {
2258       kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
2259    }
2260    if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_STA_PROH_TMR))
2261    {
2262       kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_STA_PROH_TMR);
2263    }
2264
2265
2266    /* on the first loop winSz is always greater than zero
2267     while( ( curSn < windSz ) hence changing to do while */
2268    do
2269    {
2270       recBuf = kwUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
2271       if ( recBuf != NULLP )
2272       {
2273          if (recBuf->pdu != NULLP)
2274          {
2275             KW_FREE_BUF_WC(recBuf->pdu);
2276          }
2277          /* Release all the segments */
2278          kwAmmUlRlsAllSegs(gCb,recBuf);
2279          kwUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
2280       }
2281       curSn++;
2282    }while ( curSn < windSz );
2283
2284 #ifndef LTE_TDD 
2285       KW_FREE_WC(gCb,rbCb->m.amUl.recBufLst, (KW_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
2286       rbCb->m.amUl.recBufLst = NULLP;
2287 #endif
2288
2289    if(rbCb->m.amUl.partialSdu != NULLP)
2290    {
2291       KW_FREE_BUF_WC(rbCb->m.amUl.partialSdu);
2292    }
2293    RETVOID;
2294 } /* kwAmmFreeUlRbCb */
2295
2296
2297 /*@}*/
2298
2299 \f
2300 /********************************************************************30**
2301
2302          End of file
2303 **********************************************************************/