<JIRA ID: ODUHIGH-390 : Ul throughput per SNSSAI (KPI)>
[o-du/l2.git] / src / 5gnrrlc / rlc_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:    rlc_amm_ul.c
36
37 *********************************************************************21*/
38
39 /* header include files (.h) */
40 #include "common_def.h"
41 #include "lkw.h"           /* LKW defines */
42 #include "ckw.h"           /* CKW defines */
43 #include "kwu.h"           /* KWU defines */
44 #include "rgu.h"           /* RGU defines */
45 #include "rlc_err.h"        /* Err defines */
46 #include "rlc_env.h"        /* RLC environment options */
47
48 /* extern (.x) include files */
49 #include "lkw.x"           /* LKW */
50 #include "ckw.x"           /* CKW */
51 #include "kwu.x"           /* KWU */
52 #include "rgu.x"           /* RGU */
53
54 #include "rlc_utils.h"            /* RLC defines */
55 #include "rlc_dl_ul_inf.h"
56 #include "rlc_ul.h"
57 /* Variable for logging, declared in cl */
58 #ifndef RGL_SPECIFIC_CHANGES
59 #ifndef TENB_ACC
60 #ifndef LTE_PAL_ENB
61 uint32_t ulrate_rgu;
62 #endif
63 #endif
64 #endif
65 #ifndef RGL_SPECIFIC_CHANGES
66 #ifndef TENB_ACC
67 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
68 #ifndef LTE_PAL_ENB
69 uint32_t isMemThreshReached(Region region);
70 #endif
71 #else
72 #ifndef LTE_PAL_ENB
73 uint32_t  isMemThreshReached(Region region);
74 #endif
75 #endif
76 #endif
77 #endif
78 /** @file gp_amm_ul.c
79 @brief RLC Acknowledged Mode Uplink Module
80 **/
81 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_UL) /* for debugging purpose */
82
83 /* private function declarations */
84
85 static void rlcAmmUlAssembleCntrlInfo ARGS ((RlcCb *gCb, RlcUlRbCb *rbCb));
86
87 static uint8_t rlcAmmExtractHdr ARGS ((RlcCb *gCb,
88                                 RlcUlRbCb   *rbCb,
89                                 Buffer *pdu,
90                                 RlcAmHdr *amHdr,
91                                 uint8_t *fByte));
92
93 static bool rlcAmmUlPlacePduInRecBuf ARGS ((RlcCb *gCb,
94                                      Buffer *pdu,
95                                      RlcUlRbCb *rbCb,
96                                      RlcAmHdr *amHdr));
97
98 static void rlcAmmTriggerStatus ARGS ((RlcCb *gCb,
99                                 RlcUlRbCb *rbCb,
100                                 RlcSn sn,
101                                 bool discFlg));
102
103 static uint8_t  rlcAmmUlReassembleSdus ARGS ((RlcCb *gCb,
104                                      RlcUlRbCb *rbCb,
105                                      RlcAmRecBuf *recBuf));
106
107 static Void rlcAmmProcPduOrSeg ARGS ((RlcCb *gCb,
108                                       RlcUlRbCb *rbCb,
109                                       RlcAmHdr *amHdr,
110                                       Buffer *pdu));
111
112 static Void rlcAmmUpdExpByteSeg ARGS ((RlcCb *gCb,RlcAmUl *amUl, RlcSeg* newSeg));
113
114 static Void rlcAmmExtractElmnt ARGS ((RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo));
115
116 static Void rlcAmmUlHndlStatusPdu ARGS ((RlcCb *gCb,
117                                          RlcUlRbCb *rbCb,
118                                          Buffer *cntrlPdu,
119                                          uint8_t *fByte));
120
121 /******************************************************************************
122
123   AM Module contains the following funcitons:
124
125   -  rlcAmmProcessSdus
126      -  rlcAmmUlAssembleCntrlInfo
127      -  rlcResegRetxPdus
128      -  rlcAssembleSdus
129      -  kwChkandSetPoll
130   -  rlcAmmProcessPdus
131      -  rlcAmmUlHndlStatusPdu
132      -  rlcAmmTriggerStatus
133      -  rlcAmmUlReassembleSdus
134
135 *******************************************************************************/
136 /** @addtogroup ammode */
137 /*@{*/
138
139 /**
140  * @brief   Private function to fill NACK information in status Pdu as per 5GNR
141  *
142  * @param[in]   rbCb       Ul RbCb
143  * @param[in]   sn         Sequence number of the PDU for which the NACK
144  * @param[in]   isSegment  TRUE means NACK for segment; FALSE for PDU
145  * @param[in]   soStart    SOStart
146  * @param[in]   soEnd      SOEnd
147  * @param[out]  statusPdu  status Pdu holder to be filled
148  * @param[in]   prevNackSn It holds previous nack Sn
149  *
150  * @return  S16
151  *    The number of bytes required to encode this NACK information
152  *
153  */
154 static uint8_t rlcAmmUlSetNackInfo(RlcUlRbCb *rbCb, RlcSn sn, bool isSegment, \
155    uint16_t soStart, uint16_t soEnd, RlcUdxDlStaPdu *statusPdu, RlcSn *prevNackSn)
156 {
157    RlcNackInfo   *nackInfo = (statusPdu->nackInfo + statusPdu->nackCount);
158    uint16_t       sizeToBeEncd = 0; /* Status PDu size to be encoded */
159
160    /* In following cases we should increment the nackCnt & fill new NACK_SN info:
161     *    1) First NACK_SN of the statusdPdu
162     *    2) NACK_SN is not continuous with previous
163     *    3) NACK_SN is same as previuos but segments are not continuous
164     *    4) NACK_SN is continuous with previous but previous NACK_SN segments
165     *       are not missing in sequence till end
166     */
167    if((*prevNackSn == 0xffffffff) || ((((*prevNackSn) + 1) & RLC_AMUL.snModMask) != sn) ||
168          (((*prevNackSn) == sn) && (((nackInfo->soEnd + 1) != soStart))) ||
169          ((nackInfo->isSegment) && (((*prevNackSn) + 1) == sn) && (nackInfo->soEnd != RLC_ALL_BYTES_MISSING)))
170    {
171       if(nackInfo->nackRange)
172       {
173          if((nackInfo->soEnd) && (!nackInfo->soStart))
174          {
175             /*First nack_sn of this nackRange not segmented but last is segmented */
176             sizeToBeEncd = 5; /*32 for soStart and soEnd and 8 for nackRange */ 
177          }
178          else
179          {
180             /*First nack_sn of this nackRange was segmented */
181             sizeToBeEncd = 1; /*8 for nackRange */ 
182          }
183       }
184
185       if(*prevNackSn != 0xffffffff)
186       {
187          /* Increment nackCount as this sn is continous */
188          statusPdu->nackCount++;
189          nackInfo = statusPdu->nackInfo + statusPdu->nackCount;
190       }
191
192       nackInfo->sn = sn;
193       nackInfo->isSegment = isSegment;
194       nackInfo->soStart = soStart;
195       nackInfo->soEnd   = soEnd;
196       nackInfo->nackRange = 0;
197
198       if(isSegment)
199       {
200          sizeToBeEncd += ((RLC_AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?6:7); /* NACK,E1,E2,Sostart,SoEnd */
201       }
202       else
203       {
204          sizeToBeEncd += ((RLC_AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?2:3); /* NACK,E1,E2 */
205       }
206    }
207    else
208    {
209       if(!(nackInfo->nackRange))
210       {
211          nackInfo->nackRange++;
212       }
213       /* This case means there are continuous SNs/Segments. If it is the next
214        * Sn then increment nackRnage. if same SN but different segment then
215        * dont increment nackRange */
216       if((((*prevNackSn) + 1) & RLC_AMUL.snModMask) == sn)
217       {
218          nackInfo->nackRange++;
219       }
220
221       /* If NackRange is reached to max value then increment statusPdu->nackCount*/
222       if(nackInfo->nackRange == 255)
223       {
224          statusPdu->nackCount++;
225          if(nackInfo->isSegment)
226          {
227             sizeToBeEncd = 1; /* return only nackRangeSize*/
228          }
229          else if (isSegment)
230          {
231             /* First SN was not segmented of this nackRange but last SN is segmented */
232             sizeToBeEncd = 5; /* return size of soSatrt + soEnd + nackRnage */
233          }
234       }
235
236       if(isSegment)
237       {
238          nackInfo->isSegment = isSegment;
239          nackInfo->soEnd = soEnd;
240       }
241       else if(nackInfo->isSegment)
242       {
243          nackInfo->soEnd = RLC_ALL_BYTES_MISSING;
244       }
245       else
246       {
247          nackInfo->soStart = 0;
248          nackInfo->soEnd =   0;
249       }
250
251    }
252    *prevNackSn = sn;
253
254    return (sizeToBeEncd);
255 }
256
257 /**
258  * @brief   Private handler to gather information required to create the STATUS
259  *          PDU
260  *
261  * @details
262  *    Scans the reception buffer and copies information to the UdxDlStaPdu
263  *    structure about SN's  and segments not yet received. This data is
264  *    sent to the DL instance so that it can create an appropriate (depending
265  *    on the grants from MAC) STATUS PDU and send it to MAC.
266  *
267  * @param[in]  gCb      RLC instance control block
268  * @param[in]  rbCb     Uplink RB control block
269  *
270  * @return  Void
271  *
272  */
273 static void rlcAmmUlAssembleCntrlInfo(RlcCb *gCb, RlcUlRbCb *rbCb)
274 {
275    RlcUdxDlStaPdu   *pStatusPdu;
276    RlcNackInfo      *nackInfo;
277    RlcSn            sn;                /* sequence number */
278    RlcSn            mSn;               /* Mod val of sequence number */
279    RlcSn            rxHighestStatus;              /* Mod val of rxHighestStatus */
280    RlcSeg           *seg;              /* pdu segment */
281    uint16_t         nackCnt = 0;       /* Index for staPdu */
282    uint16_t         seqSo;             /* segmment offset */
283    RlcUdxUlSapCb    *sapCb;
284    uint16_t         staPduEncSize = 3; /* size that would be of the encoded
285                                           STATUS PDU, it is in bits; 15 for
286                                           first fixed part of STATUS PDU */
287    RlcAmRecBuf      *recBuf = NULLP;
288    RlcSn            prevNackSn = 0xffffffff;
289
290    sapCb = RLC_GET_UDX_SAP(gCb);
291
292    RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
293                        sapCb->pst.pool,
294                        pStatusPdu, 
295                        sizeof(RlcUdxDlStaPdu)); 
296
297 #if (ERRCLASS & ERRCLS_ADD_RES)
298    /* Memory allocation failure can not be expected  */
299    if(!pStatusPdu)
300    {
301      return;
302    }
303 #endif
304
305    sn = RLC_AMUL.rxNext;
306    MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
307    MODAMR(RLC_AMUL.rxHighestStatus, rxHighestStatus, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
308    
309    recBuf =  rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
310
311    while (mSn < rxHighestStatus )
312    {
313       /* For missing PDUs */
314       if ((NULLP  == recBuf) && nackCnt < RLC_MAX_NACK_CNT )
315       {
316          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing PDU's SN = %d UEID:%d \
317             CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
318          staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
319                                              sn,
320                                              FALSE, /* isSegment */
321                                              0,     /* SOStart */
322                                              0,     /* SOEnd */
323                                              pStatusPdu,
324                                              &prevNackSn);
325       }
326       else if (recBuf && (recBuf->pdu == NULLP) &&
327                (recBuf->segLst.count > 0))
328       {
329          /* Scan through the byte segments of PDU and add this sn
330             with soStart and soEnd info to staPdu */
331
332          seqSo  = 0;
333          RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
334          while (seg != NULLP && nackCnt < RLC_MAX_NACK_CNT)
335          {
336             /* For missing byte segments */
337             if (seg->amHdr.so != seqSo)
338             {
339                staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
340                                                    sn,
341                                                    TRUE,
342                                                    seqSo,
343                                                    seg->amHdr.so - 1,
344                                                    pStatusPdu,
345                                                    &prevNackSn);
346
347                DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing byte segment's" 
348                   " SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
349                DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d \
350                    UEID:%d CELLID:%d", seqSo, seg->amHdr.so - 1, rbCb->rlcId.ueId,
351                    rbCb->rlcId.cellId);
352             }
353
354             seqSo = seg->soEnd + 1;
355             RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
356          }
357
358          /* Check if the last segment is missing */
359          RLC_LLIST_LAST_SEG(recBuf->segLst, seg);
360          if ((seg != NULLP) &&
361              (seg->amHdr.si != RLC_SI_LAST_SEG && nackCnt < RLC_MAX_NACK_CNT))
362          {
363             staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
364                                                 sn,
365                                                 TRUE,
366                                                 seqSo,
367                                                 RLC_ALL_BYTES_MISSING,
368                                                 pStatusPdu,
369                                                 &prevNackSn);
370
371             DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing (last) byte " 
372                "segment's SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId,
373                rbCb->rlcId.cellId);
374             DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d\
375                UEID:%d CELLID:%d", seqSo, RLC_ALL_BYTES_MISSING, rbCb->rlcId.ueId,
376                rbCb->rlcId.cellId);
377          }
378       }
379       
380
381       sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
382       MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
383       
384       /* Get the received Buffer the updated/next SN */
385       recBuf =  rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
386
387       /* Find the next missing sequence number if nackCnt reaches maximum and
388          still Reordering window has some missing AMDPDUs / AMDPDU segments. The
389          next missing sequence number will be considered as the ack sequnece
390          number in the status pdu.*/
391       if((nackCnt == RLC_MAX_NACK_CNT) &&
392           ((recBuf == NULLP) ||
393             ((recBuf->pdu == NULLP) &&
394              (recBuf->segLst.count > 0))))
395       {
396          break;
397       }
398    }
399  
400    /*Unfortunately i have write below peice of code here because kwAmmsetNackInfo()
401     * don't know that this is the last nackSn with nackRange*/
402    nackInfo = &(pStatusPdu->nackInfo[pStatusPdu->nackCount]);
403    if(nackInfo->nackRange)
404    {
405       if((nackInfo->soEnd) && (!nackInfo->soStart))
406       {
407          /*First nack_sn of this nackRange not segmented but last is segmented */
408          staPduEncSize += 5; /*32 for soStart and soEnd and 8 for nackRange */ 
409       }
410       else
411       {
412          /*First nack_sn of this nackRange was segmented */
413          staPduEncSize += 1; /*8 for nackRange */ 
414       }
415    }
416    /* nackCount is used as an index to nackInfo array but in status Pdu it
417     * should be equal to number nackInfo that are filled. hence incrementing by 1*/
418    if(prevNackSn != 0xffffffff)
419    {
420       pStatusPdu->nackCount++;
421    }
422    /* Update ACK SN with the last sn for which feedback is not assembled */
423    if ( mSn == rxHighestStatus)
424    {
425       pStatusPdu->ackSn = RLC_AMUL.rxHighestStatus;
426    }
427    else
428    {
429       pStatusPdu->ackSn = sn;
430    }
431
432    DU_LOG("\nINFO  -->  RLC_UL : rlcAmmUlAssembleCntrlInfo: ACK PDU's SN = %d"
433        "UEID:%d CELLID:%d", pStatusPdu->ackSn, rbCb->rlcId.ueId,
434        rbCb->rlcId.cellId);
435
436    pStatusPdu->controlBo = staPduEncSize; /*Its already in bytes */
437
438    RLC_AMUL.staTrg = FALSE;
439    RLC_AMUL.gatherStaPduInfo = FALSE;
440
441
442    if (rlcUlUdxStaPduReq(&sapCb->pst,
443                         sapCb->spId,
444                         &rbCb->rlcId,
445                         pStatusPdu) != ROK)
446    {
447       DU_LOG("\nERROR  -->  RLC_UL : rlcAmmUlAssembleCntrlInfo: Failed to Send Sta Pdu UEID:%d \
448          CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
449       RLC_FREE_SHRABL_BUF_WC(sapCb->pst.region,
450                             sapCb->pst.pool,
451                             pStatusPdu, 
452                             sizeof(RlcUdxDlStaPdu));
453    }
454
455    return;
456 }
457
458 #ifdef XEON_SPECIFIC_CHANGES
459 uint32_t  gRlcDatIndUL;
460 #endif
461
462 #ifdef T2K_TRIGGER_RLC_REEST
463 uint32_t drpRlcDrbPack;
464 #endif
465 /**
466  * @brief Handler to process the PDUs received from MAC and send it to PDCP
467  *
468  * @details
469  *    This function is invoked by UTL with the PDU(s) received from MAC.
470  *    It reorders the received data PDUs and trigger status report as
471  *    needed. Reassembles the SDUs in sequence and send it to PDCP.
472  *    It also processes the control PDU
473  *
474  * @param[in]  gCb      RLC instance control block
475  * @param[in]  rbCb     RB control block
476  * @param[out] pduInfo  PDU Info received from MAC
477  *
478  *  @return Void
479  *
480  */
481 #ifdef LTE_L2_MEAS
482 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
483 #else
484 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
485 #endif
486 {
487    Buffer    *pdu;
488    RlcAmUl    *amUl;
489    RlcAmHdr   amHdr;
490    uint8_t    numPdu = 0;
491    uint8_t    numPduToProcess;
492    RlcSn      sn;
493    RlcSn      tSn;
494    RlcSn      mSn;
495    uint8_t    fByte;
496    bool      discFlg;
497    RlcTptPerSnssai *snssaiTputNode = NULLP;
498    MsgLen     pduSz = 0;  /*Holds length of Rlc Sdu*/
499
500    amUl = &RLC_AMUL;
501
502    numPduToProcess = RLC_MIN(pduInfo->numPdu, RGU_MAX_PDU);
503    DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: numPdu[%d],numPduToProcess[%d] UEID:%d CELLID:%d",
504          numPdu, numPduToProcess, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
505
506    while (numPdu < numPduToProcess)
507    {
508       discFlg = FALSE;
509       pdu = pduInfo->mBuf[numPdu++];
510       snssaiTputNode = NULLP;
511       if (! pdu)
512       {
513
514          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmProcessPdus: Null Pdu UEID:%d CELLID:%d",
515                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
516          gCb->genSts.errorPdusRecv++;
517          break;
518       }
519 #ifndef RGL_SPECIFIC_CHANGES
520 #ifndef TENB_ACC
521 #ifndef LTE_PAL_ENB
522       MsgLen len;
523       ODU_GET_MSG_LEN(pdu, &len);
524       ulrate_rgu += len;
525 #endif
526 #endif
527 #endif      
528       /* Extract AM PDU/SEG header Info */
529       RLC_MEM_ZERO(&amHdr, sizeof(RlcAmHdr));
530       /* Avoided the allocation of amHdr and sending
531          a single pointer */
532       if (rlcAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
533       {
534          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",
535                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
536          ODU_PUT_MSG_BUF(pdu);
537          gCb->genSts.errorPdusRecv++;
538          continue;
539       }
540       /* Check if its a control PDU */
541       if (amHdr.dc == 0)
542       {
543          rlcAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
544          ODU_PUT_MSG_BUF(pdu);
545          continue;
546       }
547       if((amHdr.si == RLC_SI_LAST_SEG) && (!amHdr.so))
548       {
549          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmProcessPdus: Dropping PDU because SO can't be zero\
550                for last segment sn:%u UEID:%d CELLID:%d", amHdr.sn, rbCb->rlcId.ueId,
551                rbCb->rlcId.cellId);
552          ODU_PUT_MSG_BUF(pdu);
553          continue;
554       }
555 #ifndef RGL_SPECIFIC_CHANGES
556 #ifdef LTE_TDD
557 #ifndef TENB_ACC
558 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
559 #ifndef LTE_PAL_ENB
560       /* Changed the condition to TRUE from ROK  */
561       if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
562       {
563          uint32_t rlculdrop;
564          rlculdrop++;
565          ODU_PUT_MSG_BUF(pdu);
566          continue;
567       }
568 #endif
569 #else
570 #ifndef LTE_PAL_ENB
571       /*ccpu00142274 - UL memory based flow control*/
572       if(isMemThreshReached(rlcCb[0]->init.region) != ROK)
573       {
574          uint32_t rlculdrop;
575          rlculdrop++;
576          ODU_PUT_MSG_BUF(pdu);
577          continue;
578       }
579 #endif
580 #endif
581 #endif
582 #endif
583 #endif
584
585 #ifdef T2K_TRIGGER_RLC_REEST
586       if(drpRlcDrbPack > 1000)
587       {
588          if(rbCb->rlcId.rbType == CM_LTE_DRB)
589          {
590             ODU_PUT_MSG_BUF(pdu);
591             continue;
592          }
593       }
594       drpRlcDrbPack++;
595 #endif
596       /* Reordering data PDU */
597       sn = amHdr.sn;
598       if (rlcAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
599       {
600          RlcAmRecBuf      *recBuf;
601          bool   tmrRunning;
602          RlcSn   tVrMr;
603          RlcSn   mrxNextHighestRcvd;
604
605 #ifdef LTE_L2_MEAS
606          rlcUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
607 #endif /* LTE_L2_MEAS */
608
609          if(rbCb->snssai)
610          {
611             snssaiTputNode = rlcHandleSnssaiTputlist(gCb, rbCb->snssai, SEARCH, DIR_UL);
612             if(snssaiTputNode != NULLP)
613             {
614                ODU_GET_MSG_LEN(pdu, &pduSz);
615                snssaiTputNode->dataVol += (uint64_t)pduSz;
616                DU_LOG("\nINFO   -->  RLC_UL: SNSSAI AMM_UL List PduLen:%d, lcId:%d, total :%ld",\
617                      pduSz, rbCb->lch.lChId, snssaiTputNode->dataVol);
618             }
619          }
620          /* Update rxNextHighestRcvd */
621          MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
622          MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
623          if (mSn >= mrxNextHighestRcvd)
624          {
625             amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask)); 
626
627             DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
628                   amUl->rxNextHighestRcvd, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
629          }
630
631          recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
632          if ((NULLP != recBuf) && ( recBuf->allRcvd))
633          {
634             /* deliver the reassembled RLC SDU to upper layer, 
635                But not removed from the table */
636             rlcAmmUlReassembleSdus(gCb, rbCb, recBuf);
637             recBuf->isDelvUpperLayer = TRUE;
638
639             MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
640
641             /* Update rxHighestStatus */
642             if (sn == amUl->rxHighestStatus)
643             {
644                tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
645
646                recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
647                /* Scan through till the upper edge of the window */
648                MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
649                while (mSn <= tVrMr)
650                {
651                   if ((NULLP == recBuf) || (!recBuf->allRcvd))
652                   {
653                      DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: Updated rxHighestStatus:%d "
654                            "UEID:%d CELLID:%d",
655                            tSn,
656                            rbCb->rlcId.ueId,
657                            rbCb->rlcId.cellId);
658
659                      amUl->rxHighestStatus = tSn;
660                      break;
661                   }
662                   tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
663                   recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn); 
664                   mSn++;
665                }
666             }
667
668
669             /* Update rxNext */
670             if (sn == amUl->rxNext)
671             {
672                tSn = sn;
673                recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
674                MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
675                /* Scan through till the upper edge of the window */
676                while (mSn <= tVrMr)
677                {
678                   if ((NULLP != recBuf) && (recBuf->allRcvd) &&
679                         (TRUE == recBuf->isDelvUpperLayer))
680                   {
681                      /* RecBuf should remove from table 
682                         since PDU is already sent to upper layer */
683                      recBuf->isDelvUpperLayer = FALSE;
684                      rlcUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
685                   }
686                   else
687                   {
688                      amUl->rxNext = tSn;
689                      amUl->vrMr = (amUl->rxNext + (RLC_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
690                      break;
691                   }
692                   tSn = (tSn + 1) & (amUl->snModMask); 
693                   recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
694                   mSn++;
695                }
696             }
697          }
698
699          /* Check if reAsmblTmr is running and update rxNextStatusTrig accordingly */
700          tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
701          if (tmrRunning)
702          {
703             Bool snInWin = RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
704             /* spec 38.322v15.3.0 - 5.2.3.2.3 */
705             if((amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
706                      (amUl->rxNextStatusTrig != amUl->vrMr) )||
707                   (amUl->rxNextStatusTrig == amUl->rxNext && recBuf &&recBuf->noMissingSeg))
708             {
709                rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
710                tmrRunning = FALSE;
711                DU_LOG("\nINFO  --> RLC_UL: rlcAmmProcessPdus: Stopped ReAssembly Timer rxNextStatusTigger = %d"
712                      "rxNextReassembly = %d", amUl->rxNextStatusTrig, amUl->rxNext);
713             }
714          }
715
716          if (!tmrRunning)
717          {
718             /* spec 38.322v15.3.0 - 5.2.3.2.3 */
719             if((amUl->rxNextHighestRcvd > amUl->rxNext) || ((amUl->rxNextHighestRcvd == amUl->rxNext) &&
720                      (recBuf && (!recBuf->noMissingSeg))))
721             {
722                rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
723                amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
724
725                DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: Updated rxNextStatusTrig = %d" 
726                      "UEID:%d CELLID:%d", amUl->rxNextStatusTrig, rbCb->rlcId.ueId,
727                      rbCb->rlcId.cellId);
728             }
729          }
730       }
731       else
732       {
733          discFlg = TRUE;
734          gRlcStats.amRlcStats.numULPdusDiscarded++;
735       }
736
737       if (amHdr.p)
738       {
739          rlcAmmTriggerStatus(gCb,rbCb, sn, discFlg);
740       }
741    }
742
743 #ifdef LTE_L2_MEAS
744    rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
745 #endif /* LTE_L2_MEAS */
746    gCb->genSts.pdusRecv += pduInfo->numPdu;
747    if (amUl->gatherStaPduInfo)
748    {
749       rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
750    }
751
752    return;
753 }
754
755
756 /**
757  * @brief Private handler to extract header Information of the PDU
758  *
759  * @details
760  *    This function extracts the header elements of the PDU and store them
761  *    in db for future reference.
762  *
763  *    fByte - is the first byte removed from the PDU as part of calling
764  *            functions
765  *
766  * @param[in]  gCb     RLC instance control block
767  * @param[in]  rbCb    Uplink RB control block
768  * @param[in]  pdu     Received PDU
769  * @param[out] amHdr   Pointer to the extracted AM header
770  * @param[out] fByte   First byte removed from the PDU
771  *
772  * @return S16
773  *     -# ROK
774  *     -# RFAILED
775  *
776  */
777 static uint8_t rlcAmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcAmHdr *amHdr, uint8_t *fByte)
778 {
779    uint8_t    snByte;
780    RlcSn      sn = 0;
781    MsgLen     pduSz;
782    RlcExtHdr  hdrInfo;
783
784    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
785
786    /* Extract fixed part of the header */
787    ODU_GET_MSG_LEN(pdu,&pduSz);
788    ODU_REM_PRE_MSG(fByte, pdu);
789    amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
790    if (RLC_CNTRL_PDU == amHdr->dc)
791    {
792    //DU_LOG ("\nINFO  -->  RLC_UL : ++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
793       return ROK;
794    }
795
796    amHdr->p  = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
797
798    amHdr->si = (*fByte & RLC_SI_POS)   >> RLC_SI_SHT;
799
800    /* 12 BIT SN */
801    if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
802    {
803       ODU_REM_PRE_MSG(&snByte, pdu);
804       sn = (RlcSn)(((*fByte & RLC_SN_POS_12BIT) << RLC_BYTE_LEN ) | snByte);
805       amHdr->sn = sn;
806    }
807    else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
808    {
809       ODU_REM_PRE_MSG(&snByte, pdu);
810       sn = (RlcSn)(((*fByte & RLC_SN_POS_18BIT) << RLC_BYTE_LEN ) | snByte);
811
812       ODU_REM_PRE_MSG(&snByte, pdu);
813       sn = ((sn << RLC_BYTE_LEN) | snByte);
814
815       amHdr->sn = sn;
816    }
817    if ((amHdr->si != 0) && (amHdr->si != RLC_SI_FIRST_SEG))
818    {
819       hdrInfo.len = RLC_SO_LEN_5GNR;
820       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
821       amHdr->so = hdrInfo.val;
822       pduSz -= 2;
823    }
824
825    return ROK;
826 }
827
828 #ifdef OLD
829 /**
830  * @brief Private handler to extract header Information of the PDU
831  *
832  * @details
833  *    This function extracts the header elements of the PDU and store them
834  *    in db for future reference.
835  *
836  *    fByte - is the first byte removed from the PDU as part of calling
837  *            functions
838  *
839  * @param[in]  gCb     RLC instance control block
840  * @param[in]  rbCb    Uplink RB control block
841  * @param[in]  pdu     Received PDU
842  * @param[out] amHdr   Pointer to the extracted AM header
843  * @param[out] fByte   First byte removed from the PDU
844  *
845  * @return S16
846  *     -# ROK
847  *     -# RFAILED
848  *
849  */
850 static S16 rlcAmmExtractHdrOld(RlcCb *gCb,Buffer *pdu,RlcAmHdr *amHdr,uint8_t *fByte)
851 {
852    uint8_t         e;
853    uint8_t         snByte;
854    uint16_t        sn;
855    MsgLen     pduSz;
856    MsgLen     totalSz = 0;
857    RlcExtHdr   hdrInfo;
858
859    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
860
861    /* Extract fixed part of the header */
862    SFndLenMsg(pdu,&pduSz);
863    SRemPreMsg(fByte, pdu);
864    amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
865    if (RLC_CNTRL_PDU == amHdr->dc)
866    {
867       return ROK;
868    }
869    /* kw002.201 : Changed the extraction of hdr elements to avoid */
870    /*             function calls                                  */
871    amHdr->rf = (*fByte & RLC_RF_POS)   >> RLC_RF_SHT;
872    amHdr->p  = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
873    amHdr->fi = (*fByte & RLC_FI_POS)   >> RLC_FI_SHT;
874    e = amHdr->e  = (*fByte & RLC_E_POS)>> RLC_E_SHT;
875     
876    SRemPreMsg(&snByte, pdu);
877    sn = (uint16_t)(((*fByte & RLC_SN_POS) << RLC_BYTE_LEN ) | snByte);
878    amHdr->sn = sn;
879    if (amHdr->rf == 1)
880    {
881       /* Extract extn part of the header */
882       hdrInfo.len = RLC_LSF_LEN;
883       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
884       amHdr->lsf = (uint8_t)hdrInfo.val;
885
886       hdrInfo.len = RLC_SO_LEN;
887       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
888       amHdr->so = hdrInfo.val;
889       pduSz -= 2;
890    }
891
892    amHdr->numLi = 0;
893    /* Extract LIs */
894    while (e && (amHdr->numLi < RLC_MAX_UL_LI))
895    {
896       hdrInfo.len = RLC_E_LEN;
897       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
898       e = amHdr->e = (uint8_t)hdrInfo.val;
899
900       /* Extract LI value*/
901       hdrInfo.len = RLC_LI_LEN;
902       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
903       /* li = hdrInfo.val;*/
904
905       /* check if LI is zero */
906       if (! hdrInfo.val)
907       {
908          DU_LOG("\nERROR  -->  RLC_UL : Received LI as 0");
909          return RFAILED;
910       }
911
912       /* store the extracted  LI value */
913       amHdr->li[amHdr->numLi++] = hdrInfo.val;
914       totalSz += hdrInfo.val;  /* incrment the size by LI value */
915    }
916
917    /*ccpu00122597:PDU is dropped if liCnt exceeds RLC_MAX_LI*/
918    if(e && (amHdr->numLi >= RLC_MAX_UL_LI))
919    {
920       DU_LOG("\nERROR  -->  RLC_UL : LI Count [%u] exceeds Max LI Count[%u]", 
921             amHdr->numLi, RLC_MAX_UL_LI);
922       return RFAILED;
923    }
924
925    /*                                first 2 bytes + Add one for  Odd LI*/
926    pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
927
928    if ( totalSz >= pduSz )
929    {   
930       DU_LOG("\nERROR  -->  RLC_UL : SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
931                amHdr->sn, totalSz, pduSz);
932       return RFAILED;
933    }
934
935    return ROK;
936 }
937 #endif
938
939 /**
940  * @brief Private handler to process the status PDU
941  *
942  * @details
943  *    Private handler invokded by rlcAmmProcessPdus to process the
944  *    control PDU (status report) received from its peer RLC entity.
945  *
946  *        - Decode the values from the received control pdu
947  *        - Create a RlcUdxStaPdu structure, copy the values onto it and
948  *          send it to the DL instance for further processing
949  *
950  * @param[in]  gCb       RLC instance control block
951  * @param[in]  rbCb      Uplink RB control block
952  * @param[in]  cntrlPdu  Control PDU received from MAC
953  * @param[in]  fByte     First byte already removed from the STATUS PDU
954  *
955  *  @return  Void
956  *
957  */
958 static void rlcAmmUlHndlStatusPdu(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *cntrlPdu, uint8_t *fByte)
959 {
960    uint8_t          e1;
961    RlcExtHdr        hdrInfo;
962    RlcUdxStaPdu     *pStaPdu;
963    RlcUdxUlSapCb    *sapCb;
964    uint8_t          e3; /* NACK RANGE : 5GNR */
965    uint32_t         snLen;
966    uint32_t         snRange;
967    uint32_t         resrvdBitsAckSn=0;
968    uint32_t         resrvdBitsNackSn=0;
969
970    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
971
972    /* Extract the Control PDU */
973    hdrInfo.hdr  = (*fByte << 1);
974    hdrInfo.pLen = 4;
975
976    /* D/C has been shifted in the calling function */
977    if (hdrInfo.hdr & 0xE0)
978    {
979       DU_LOG("\nINFO  -->  RLC_UL : rlcAmmUlHndlStatusPdu: Reserved value for CPT received UEID:%d \
980          CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
981       return;
982    }
983
984    sapCb = RLC_GET_UDX_SAP(gCb);
985
986    RLC_ALLOC_SHRABL_BUF(sapCb->pst.region, 
987                        sapCb->pst.pool, 
988                        pStaPdu, 
989                        sizeof(RlcUdxStaPdu));
990
991 #if (ERRCLASS & ERRCLS_ADD_RES)
992    /* Memory allocation failure can not be expected  */
993    if(!pStaPdu)
994    {
995      return;
996    }
997 #endif   
998
999    if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1000    {
1001       snLen = 12;
1002       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
1003       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
1004    }
1005    else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
1006    {
1007       snLen = 18;
1008       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
1009       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
1010    }
1011    else
1012    {
1013       snLen = RLC_SN_LEN;
1014       resrvdBitsAckSn = 0;
1015       resrvdBitsAckSn = 0;
1016    }
1017
1018    pStaPdu->nackCnt = 0;
1019    /* For CPT */
1020    hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
1021
1022    /* ACK Sn */
1023    hdrInfo.len = snLen;
1024    rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1025    pStaPdu->ackSn = hdrInfo.val;
1026
1027    //DU_LOG ("\nINFO  -->  RLC_UL : ++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n",  pStaPdu->ackSn);
1028    /* Check if NACK Exists */
1029    hdrInfo.len = RLC_E1_LEN;
1030    rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1031    e1 = (uint8_t)hdrInfo.val;
1032    DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1033       pStaPdu->ackSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1034
1035    /* Extract the Reserved Bits after ACK SN field */
1036    hdrInfo.len = resrvdBitsAckSn;
1037    rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1038
1039    /* If NACK exists in control PDU */
1040    /* For ACKs and NACKs */
1041    while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
1042    {
1043       hdrInfo.len = snLen;
1044       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1045       pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1046
1047       hdrInfo.len = RLC_E1_LEN;
1048       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1049       e1 = (uint8_t)hdrInfo.val;
1050
1051       /* Extract e2 */
1052       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1053          already present*/
1054       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1055       /*  e2 = (uint8_t) hdrInfo.val;*/
1056
1057       /* Store e2 value */
1058       pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
1059
1060       /* Extract e3 : 5GNR */
1061       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1062          already present*/
1063       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1064       e3 = (uint8_t) hdrInfo.val;
1065
1066       /* Extract Reserved Bits after NACK SN */
1067       hdrInfo.len = resrvdBitsNackSn;
1068       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1069
1070       /* Test for resegmentation */
1071       if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1072       {
1073          hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1074          rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1075          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1076
1077          rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1078          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = hdrInfo.val;
1079
1080          DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1081             "UEID:%d CELLID:%d", pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1082             pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd, rbCb->rlcId.ueId,
1083             rbCb->rlcId.cellId);
1084       }                                                                
1085       else
1086       {
1087          hdrInfo.len = 0;
1088          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1089          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = 0;
1090
1091       }
1092       /* NACK RANGE Field is SET */
1093       if (e3)
1094       {
1095          /* Extract NACK range field */
1096          hdrInfo.len = RLC_NACK_RANGE_LEN;
1097          rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1098          snRange = (uint8_t)hdrInfo.val;
1099
1100          pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1101
1102       }
1103       pStaPdu->nackCnt++;
1104    }
1105
1106    gRlcStats.amRlcStats.numULStaPduRcvd++;
1107    gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1108
1109    /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1110       to the last NACK SN + 1 and discard the original ACK_SN*/
1111    if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
1112    {
1113       pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1114    }
1115
1116
1117    /* Parse & send Status PDU to RLC-DL */
1118    rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1119
1120    return;
1121 }
1122
1123 /**
1124  * @brief Private handler to release all stored segments
1125  *
1126  * @details
1127  *    Private handler invokded by rlcAmmUlPlacePduInRecBuf to release the
1128  *    stored segements in case a complete PDU is received later.
1129  *
1130  * @param[in]  gCb      RLC instance control block
1131  * @param[in]  recBuf   Buffer that stores a received PDU or segments
1132  *
1133  * @return  Void
1134  *
1135  */
1136 static void rlcAmmUlRlsAllSegs(RlcCb *gCb, RlcAmRecBuf *recBuf)
1137 {
1138    RlcSeg *seg;
1139
1140    RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1141    while (seg != NULLP)
1142    {
1143       ODU_PUT_MSG_BUF(seg->seg);
1144       cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1145       RLC_FREE(gCb,seg, sizeof(RlcSeg));
1146       RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1147    }
1148
1149    return;
1150 }
1151
1152 /**
1153  * @brief Private handler to store the received segment
1154  *
1155  * @details
1156  *    Private handler invokded by rlcAmmUlPlacePduInRecBuf to add a received
1157  *    segment in reception buffer of a RBCB.
1158  *    - It is responsible for detecting duplicate segments
1159  *    - Adding it at appropriate position in the received buffer
1160  *    - Calling ExpByteSeg to set expSo field in the receiver buffer
1161  *
1162  * @param[in]  gCb      RLC instance control block
1163  * @param[in]  rbCb     Radio Bearer Contro Block
1164  * @param[in]  amHdr    AM Header received
1165  * @param[in]  pdu      Buffer received other than the headers
1166  * @param[in]  pduSz    size of the PDU buffer received
1167  *
1168  * @return  Bool
1169  *   -#TRUE  Successful insertion into the receiver buffer
1170  *   -#FALSE Possibly a duplicate segment
1171  */
1172 static bool rlcAmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu, uint16_t pduSz)
1173 {
1174    RlcAmRecBuf   *recBuf = NULLP;
1175    RlcSeg        *seg;
1176    RlcSeg        *tseg;
1177    uint16_t      soEnd;       /* Holds the SoEnd of received segment */
1178    uint16_t      expSo = 0;   /* Expected SO */
1179
1180    soEnd = amHdr->so + pduSz - 1;
1181    recBuf =  rlcUtlGetRecBuf(RLC_AMUL.recBufLst, amHdr->sn);
1182
1183    if (NULLP == recBuf)
1184    {
1185       RLC_ALLOC(gCb,recBuf, sizeof(RlcAmRecBuf));
1186 #if (ERRCLASS & ERRCLS_ADD_RES)
1187       if (recBuf == NULLP)
1188       {
1189          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1190             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1191
1192          ODU_PUT_MSG_BUF(pdu);
1193          return FALSE;
1194       }
1195 #endif /* ERRCLASS & ERRCLS_RES */
1196       rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, amHdr->sn);
1197    }
1198    else
1199    {
1200       if (recBuf->allRcvd == TRUE)
1201       {
1202          ODU_PUT_MSG_BUF(pdu);
1203          return FALSE;
1204       }
1205    }
1206                         
1207    recBuf->isDelvUpperLayer = FALSE;
1208    /* kw003.201 - Move past the segments that are different than the */
1209    /*             one received.                                      */
1210    RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1211    while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1212    {
1213       expSo = seg->amHdr.so + seg->segSz;
1214       RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1215    }
1216
1217    /* The received segment should start after the end of previous seg */
1218    if (expSo > amHdr->so)
1219    {
1220       /* This is a duplicate segment */
1221       gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1222       ODU_PUT_MSG_BUF(pdu);
1223       return FALSE;
1224    }
1225
1226    if ((seg) && (seg->amHdr.so <= soEnd))
1227    {
1228       /* This is a duplicate segment */
1229       gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1230       ODU_PUT_MSG_BUF(pdu);
1231       return FALSE;
1232    }
1233
1234    /* If we have come this far, we have to add this segment to the   */
1235    /* reception buffer as we either have eliminated duplicates or    */
1236    /* have found none.                                               */
1237    RLC_ALLOC_WC(gCb,tseg, sizeof(RlcSeg));
1238 #if (ERRCLASS & ERRCLS_ADD_RES)
1239    if (tseg == NULLP)
1240    {
1241       DU_LOG("\nERROR  -->  RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1242          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1243       ODU_PUT_MSG_BUF(pdu);
1244       return FALSE;
1245    }
1246 #endif /* ERRCLASS & ERRCLS_RES */
1247
1248    tseg->seg = pdu;
1249    tseg->segSz = pduSz;
1250    RLC_MEM_CPY(&tseg->amHdr, amHdr, sizeof(RlcAmHdr));
1251    recBuf->amHdr.si = amHdr->si;
1252    recBuf->amHdr.sn = amHdr->sn;
1253    tseg->soEnd = soEnd;
1254    if (seg == NULLP)
1255    {
1256       cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1257    }
1258    else
1259    {
1260       recBuf->segLst.crnt = &seg->lstEnt;
1261       cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1262    }
1263    tseg->lstEnt.node = (PTR)tseg;
1264    rlcAmmUpdExpByteSeg(gCb,&RLC_AMUL,tseg);
1265
1266    return TRUE;
1267 }
1268
1269 /**
1270  * @brief Private handler to place the PDU in the reception buffer
1271  *
1272  * @details
1273  *    This function checks if the received PDU's SN falls within the
1274  *    receiving window, after which it places the same in the reception
1275  *    buffer if its not a duplicate.
1276  *
1277  * @param[in]  gCb   RLC instance control block
1278  * @param[in]  pdu   Received PDU
1279  * @param[in]  rbCb  Uplink AM Radio Bearer
1280  * @param[out] amUl  AM UL Info
1281  *
1282  * @return Bool
1283  *     -# TRUE
1284  *     -# FALSE
1285  *
1286  */
1287 static bool rlcAmmUlPlacePduInRecBuf(RlcCb *gCb, Buffer *pdu, RlcUlRbCb *rbCb, RlcAmHdr *amHdr)
1288 {
1289    RlcSn     sn;
1290    MsgLen   pduSz;
1291    RlcAmUl   *amUl = &(rbCb->m.amUl);
1292
1293    sn = amHdr->sn;
1294    SFndLenMsg(pdu, &pduSz);
1295
1296    gCb->genSts.bytesRecv += pduSz;
1297    gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz; 
1298    if (!RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1299    {
1300       gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1301       DU_LOG("\nERROR  -->  RLC_UL : rlcAmmUlPlacePduInRecBuf: SN  %d outside the window"
1302          "UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1303
1304       gCb->genSts.unexpPdusRecv++;
1305       ODU_PUT_MSG_BUF(pdu);
1306       return FALSE;
1307    }
1308
1309    if (amHdr->si == 0)
1310    {
1311       RlcAmRecBuf *recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1312
1313       /* We received a complete PDU. Either we already have it, in which */
1314       /* case we just ignore the new PDU and discard it. Otherwise,      */
1315       /* store the received PDU in the reception buffer                  */
1316       if (NULLP == recBuf)
1317       {
1318          RLC_ALLOC(gCb, recBuf, sizeof(RlcAmRecBuf));
1319 #if (ERRCLASS & ERRCLS_ADD_RES)
1320          if (recBuf == NULLP)
1321          {
1322             DU_LOG("\nERROR  -->  RLC_UL : rlcAmmUlPlacePduInRecBuf: Memory allocation failed \
1323                UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1324             ODU_PUT_MSG_BUF(pdu);
1325             return FALSE;
1326          }
1327 #endif /* ERRCLASS & ERRCLS_RES */
1328          rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, sn);
1329       }
1330       else if (recBuf->allRcvd != TRUE)
1331       {
1332          rlcAmmUlRlsAllSegs(gCb,recBuf);
1333       }
1334       else
1335       {
1336          gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1337          gCb->genSts.unexpPdusRecv++;
1338          ODU_PUT_MSG_BUF(pdu);
1339          return FALSE;
1340       }
1341       recBuf->isDelvUpperLayer = FALSE;
1342       recBuf->pdu = pdu;
1343       recBuf->pduSz = pduSz;
1344       recBuf->allRcvd = TRUE;
1345       gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1346       RLC_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(RlcAmHdr));
1347       return TRUE;
1348    }
1349    else
1350    {
1351       /* We received a segment. We need to add that to the existing */
1352       /* segments, if any.                                          */
1353       return (rlcAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1354    }
1355 }
1356
1357 /**
1358  * @brief Private handler to trigger status report
1359  *
1360  * @details
1361  *    Private handler invokded by rlcAmmProcessPdus to check if the
1362  *    status report need to be sent, and update the status trigger
1363  *    flag accordingly based on status prohibit timer.
1364  *
1365  *    - Check if the received pdu's sn is less than rxHighestStatus, set the
1366  *      staTrg flag.
1367  *    - If staProhTmr is not running, calculate cntrlBo, else it'll be
1368  *      updated at the expiry of staProhTmr.
1369  *    - Expiry of reAsmblTmr also will set staTrg flag.
1370  *
1371  * @param[in]  gCb       RLC instance control block
1372  * @param[in]  rbCb      Uplink RB control block
1373  * @param[in]  sn        Sequence number of the pdu based on which to check if
1374  *                       status needs to be triggered
1375  * @param[in]  discFlg   Whether this pdu was discarded or not
1376  *
1377  * @return  Void
1378  *
1379  */
1380 static void rlcAmmTriggerStatus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcSn sn, bool discFlg)
1381 {
1382    bool     tmrRunning;
1383    RlcSn     tSn;
1384    RlcSn     tVrMr;
1385    RlcSn     trxHighestStatus;
1386    RlcAmUl   *amUl = &(rbCb->m.amUl);
1387
1388    MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1389    MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1390    MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1391
1392    /* kw005.201 Product CR ccpu00117114       *
1393     * The "=" in the 2nd condition is removed */
1394    if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1395    {
1396       DU_LOG("\nINFO  -->  RLC_UL : rlcAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1397          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1398
1399       amUl->staTrg = TRUE;
1400       amUl->gatherStaPduInfo = FALSE;
1401
1402       /* Check if staProhTmr is running */
1403       tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1404
1405       if (!tmrRunning)
1406       {
1407          amUl->gatherStaPduInfo = TRUE;
1408       }
1409    }
1410
1411    return;
1412 }
1413
1414 /**
1415  * @brief Private handler to reassemble from a segment or a PDU
1416  *
1417  * @details
1418  *    Private handler invokded by kwAmmReassembleSdus with either a
1419  *    PDU or a segment of a PDU. This is also called in the case of
1420  *    reestablishment and hence out of sequence joining is also to
1421  *    be supported
1422  *
1423  *
1424  * @param[in]  gCb     RLC instance control block
1425  * @param[in]  rbCb    Uplink RB control block
1426  * @param[in]  amHdr   AM header received for this segment/PDU
1427  * @param[in]  pdu     PDU to be reassembled
1428  *
1429  * @return  Void
1430  *
1431  */
1432 static void rlcAmmProcPduOrSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu)
1433 {
1434
1435    if ((RLC_AMUL.expSn != amHdr->sn) || (RLC_AMUL.expSo != amHdr->so))
1436    {
1437       /* Release the existing partial SDU as we have PDUs or */
1438       /* segments that are out of sequence                   */
1439       rbCb->m.amUl.isOutOfSeq = TRUE;
1440       ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1441    }
1442
1443    if (amHdr->si == RLC_SI_FIRST_SEG)
1444    {/* first Segment of the SDU */
1445       if (RLC_AMUL.partialSdu != NULLP)
1446       { /* Some old SDU may be present */
1447          ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1448       }
1449       RLC_AMUL.partialSdu = pdu;
1450       pdu = NULLP;
1451    }
1452    else if(amHdr->si == RLC_SI_MID_SEG)
1453    {/* Middle or last segment of the SUD */
1454       ODU_CAT_MSG(RLC_AMUL.partialSdu,pdu, M1M2);
1455       ODU_PUT_MSG_BUF(pdu);
1456       pdu = NULLP;
1457    }
1458    else if (amHdr->si ==  RLC_SI_LAST_SEG)
1459    {
1460       ODU_CAT_MSG(pdu,RLC_AMUL.partialSdu,M2M1);
1461       ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1462    }
1463
1464    if (pdu != NULLP)
1465    {
1466       RLC_AMUL.partialSdu = NULLP;
1467       rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
1468    }
1469
1470    return;
1471 }
1472
1473 /**
1474  *
1475  * @brief Private handler to reassemble SDUs
1476  *
1477  * @details
1478  *    Private handler invokded by rlcAmmProcessPdus with the PDU
1479  *    from the reception buffer in sequence to reassemble SDUs and
1480  *    send it to PDCP.
1481  *
1482  *        - With the stored header info, FI and LSF segment / concatenate
1483  *          PDUs or byte segments of PDUs to get the associated SDU.
1484  *
1485  * @param[in]  rbCb     RB control block
1486  * @param[in]  pdu      PDU to be reassembled
1487  *
1488  *  @return  S16
1489  *      -# ROK
1490  *      -# RFAILED
1491  *
1492  */
1493 static uint8_t rlcAmmUlReassembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmRecBuf *recBuf)
1494 {
1495    RlcSeg        *seg;
1496
1497    //if (recBuf->amHdr.rf == 0)
1498    if (recBuf->amHdr.si == 0)
1499    {
1500       /* This is a PDU */
1501       rlcAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1502       /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1503       recBuf->pdu = NULLP;
1504       RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1505       RLC_AMUL.expSo = 0;
1506    }
1507    else
1508    {
1509       /* This is a set of segments */
1510       RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1511       RLC_AMUL.expSn = recBuf->amHdr.sn;
1512       RLC_AMUL.expSo = 0;
1513       while(seg)
1514       {
1515          rlcAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1516          RLC_AMUL.expSo = seg->soEnd + 1;
1517
1518          cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1519          RLC_FREE(gCb, seg, sizeof(RlcSeg));
1520
1521          RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1522       }
1523       RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1524       RLC_AMUL.expSo = 0;
1525    }
1526
1527    return ROK;
1528 }
1529
1530 /**
1531  * @brief   Handler to process the re-establishment request received from UIM
1532  *
1533  * @param[in] gCb         RLC instance control block
1534  * @param[in] rlcId       RLC identifier
1535  * @param[in] sendReEst   Whether to send back restablishment complete or not
1536  * @param[in] rbCb        Uplink RB control block
1537  *
1538  * @return  Void
1539  *
1540  */
1541 Void rlcAmmUlReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcUlRbCb  *rbCb)
1542 {
1543    RlcSn   sn;
1544    RlcSn   mSn;
1545    RlcSn   mVrMr;
1546
1547 #ifndef KW_PDCP
1548    RlcKwuSapCb *rlcKwuSap;
1549 #endif
1550    RlcAmRecBuf   *recBuf = NULLP;
1551
1552    sn = RLC_AMUL.rxNext;
1553
1554    MODAMR(RLC_AMUL.vrMr, mVrMr, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1555    MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1556
1557    /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1558    while (mSn < mVrMr)
1559    {
1560       recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1561       if (NULLP != recBuf)
1562       {
1563          if (recBuf->allRcvd == TRUE)
1564          {
1565             rlcAmmUlReassembleSdus(gCb,rbCb, recBuf);
1566          }
1567          else
1568          {
1569             /* Remove PDU and segments */
1570             if(recBuf->pdu)
1571             {
1572                ODU_PUT_MSG_BUF(recBuf->pdu);
1573             }
1574             /* Release all the segments*/
1575             rlcAmmUlRlsAllSegs(gCb,recBuf);
1576          }
1577          rlcUtlDelRecBuf(RLC_AMUL.recBufLst, recBuf, gCb);
1578       }
1579       sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1580       MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1581    }
1582    /* Discard remaining PDUs and bytesegments in recBuf */
1583
1584    /* Stop all timers and reset variables */
1585    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1586    {
1587        rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1588    }
1589    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1590    {
1591        rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1592    }
1593
1594    RLC_AMUL.rxNext  = 0;
1595    RLC_AMUL.rxNextHighestRcvd  = 0;
1596    RLC_AMUL.rxNextStatusTrig  = 0;
1597    rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1598    RLC_AMUL.rxHighestStatus = 0;
1599    RLC_AMUL.staTrg  = FALSE;
1600    RLC_AMUL.gatherStaPduInfo = FALSE;
1601    RLC_AMUL.expSn = 0;
1602    RLC_AMUL.expSo = 0;
1603    if (RLC_AMUL.partialSdu != NULLP)
1604    {
1605      ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1606    }
1607    rlcKwuSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
1608
1609    if(sendReEst)
1610    {
1611       RlcUiKwuReEstCmpInd(&rlcKwuSap->pst, rlcKwuSap->suId, rlcId);
1612       rbCb->m.amUl.isOutOfSeq = FALSE;
1613    }
1614
1615    return;
1616 }
1617
1618 /**
1619  * @brief  Handler for reorder timer expiry
1620  *
1621  * @details
1622  *    This function is used to handle events upon expiry of reorder timer
1623  *
1624  *  @param[in] gCb   RLC instance control block
1625  *  @param[in] rbCb  RB control block
1626  *
1627  *  @return  Void
1628  *
1629  */
1630
1631 Void rlcAmmReAsmblTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1632 {
1633    RlcAmUl *amUl = &(rbCb->m.amUl);
1634    RlcSn sn;
1635    RlcSn mSn;
1636    RlcSn mVrMr;
1637    RlcSn mrxHighestStatus;
1638    RlcSn mrxNextHighestRcvd;
1639    Bool tmrRunning = FALSE;
1640    RlcAmRecBuf   *recBuf = NULLP;
1641
1642    /* Update rxHighestStatus */
1643    sn = amUl->rxNextStatusTrig;
1644
1645    MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1646    MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1647    recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1648
1649    while (mSn < mVrMr)
1650    {
1651       if ((recBuf == NULLP) ||
1652           ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1653       {
1654          amUl->rxHighestStatus = sn;
1655          amUl->staTrg = TRUE;
1656          amUl->gatherStaPduInfo = FALSE;
1657
1658          /* Check if staProhTmr is running */
1659          tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1660
1661          if (!tmrRunning)
1662          {
1663             gRlcStats.amRlcStats.numULReAsmblTimerExpires++;
1664             amUl->gatherStaPduInfo = TRUE;
1665             rlcAmmUlAssembleCntrlInfo(gCb, rbCb);
1666          }
1667
1668          break;
1669       }
1670       sn = (sn + 1) & (amUl->snModMask); 
1671       MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1672    }
1673
1674    /* Update rxNextStatusTrig */
1675    MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1676    MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1677    /* spec 38.322v15.3.0 - 5.2.3.2.4 */
1678    if((mrxNextHighestRcvd > mrxHighestStatus) || ((mrxNextHighestRcvd == mrxHighestStatus) &&
1679       ((recBuf) &&  !(recBuf->noMissingSeg))))
1680    {
1681       rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1682       amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1683    }
1684
1685    return;
1686 } /* rlcAmmReAsmblTmrExp */
1687
1688 /**
1689  * @brief  Handler for status prohibit timer expiry
1690  *
1691  * @details
1692  *    This function is used to handle events upon expiry of status prohibit
1693  *    timer
1694  *
1695  *  @param[in] gCb   RLC instance control block
1696  *  @param[in] rbCb   RB control block
1697  *
1698  *  @return  Void
1699  *
1700  */
1701
1702 Void rlcAmmStaProTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1703 {
1704    RlcAmUl *amUl = &(rbCb->m.amUl);
1705
1706    amUl->gatherStaPduInfo = FALSE;
1707
1708    if (amUl->staTrg == TRUE)
1709    {
1710       amUl->gatherStaPduInfo = TRUE;
1711       /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
1712       rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
1713    }
1714
1715    return;
1716 } /* rlcAmmStaProTmrExp */
1717
1718 /**
1719  * @brief  Handler to extract an element of AM Header
1720  *
1721  * @details
1722  *    This function is used to extract an element of AM header.
1723  *
1724  * @param[in]     pdu      The pdu to be decoded
1725  * @param[in,out] hdrInfo  Container to hold the decoded info
1726  *
1727  * @return Void
1728  *
1729  */
1730
1731 static void rlcAmmExtractElmnt(RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo)
1732 {
1733    uint8_t   hdr;
1734    uint8_t   pLen = hdrInfo->pLen;
1735    uint8_t   len  = (uint8_t)hdrInfo->len;
1736    uint32_t  val;
1737    uint8_t   tHdr;
1738    uint8_t   fLen;
1739    uint8_t   rLen;
1740    /* uint8_t   rLen1 = 0; */
1741    uint16_t  tVal;
1742
1743    hdr = hdrInfo->hdr;
1744
1745    if (pLen == 0)
1746    {
1747       ODU_REM_PRE_MSG(&hdr, pdu);
1748       pLen = 8;
1749    }
1750    tHdr = hdr;
1751    if (len <= 8)
1752    {
1753       val = tHdr >> (RLC_BYTE_LEN - (len));
1754       hdr =  hdr << len;
1755       pLen -= len;
1756    }
1757    else /*if (len > 8) */
1758    {
1759       fLen = pLen;
1760       val = tHdr;
1761       val = val >> (RLC_BYTE_LEN - fLen);
1762       val = val << (len - fLen);
1763       rLen = len - fLen;
1764       ODU_REM_PRE_MSG(&hdr, pdu);
1765       tHdr = hdr;
1766       if (rLen <= 8)
1767       {
1768          hdr = hdr >> (RLC_BYTE_LEN - rLen);
1769          val = val | hdr;
1770          hdr = tHdr << rLen;
1771          pLen = (RLC_BYTE_LEN - rLen);
1772       }
1773       else
1774       {
1775         rLen = rLen - RLC_BYTE_LEN;
1776         tVal = hdr;
1777         tVal = tVal << rLen;
1778         val = val | tVal;
1779
1780         ODU_REM_PRE_MSG(&hdr, pdu);
1781         tHdr = hdr;
1782         hdr = hdr >> (RLC_BYTE_LEN - rLen);
1783         val = val | hdr;
1784         hdr = tHdr << rLen;
1785         pLen = (RLC_BYTE_LEN - rLen);
1786       }
1787    }
1788
1789    hdrInfo->pLen = pLen;
1790    hdrInfo->hdr = hdr;
1791    hdrInfo->val = val;
1792
1793    return;
1794 }
1795
1796 /**
1797  * @brief  Handler to updated expected byte seg
1798  *
1799  * @details
1800  *    This function is used to update expected byte segment. The next segment
1801  *    expected is indicated by the SO of the segment which is expected. Intially
1802  *    the segment with SO 0 is expected and then in order. When all the segments
1803  *    are received (which would happen when an expected SO is encountered
1804  *    with LSF set) the allRcvd flag is set to TRUE
1805  *
1806  * @param[in]  gCb   RLC instance control block
1807  * @param[in]  amUl  AM Uplink Control Block
1808  * @param[in]  seg   Newly received segment
1809  *
1810  * @return Void
1811  *
1812  */
1813
1814 static void rlcAmmUpdExpByteSeg(RlcCb *gCb, RlcAmUl *amUl, RlcSeg *seg)
1815 {
1816    uint16_t  newExpSo; /* The new expected SO */
1817    RlcSn     sn = seg->amHdr.sn;
1818    bool      lstRcvd=FALSE;
1819    RlcAmRecBuf *recBuf = NULLP;
1820    
1821    recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1822    if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
1823    {
1824       return;
1825    }
1826    recBuf->noMissingSeg = FALSE;
1827    newExpSo   = seg->soEnd + 1;
1828    recBuf->expSo = newExpSo;
1829    if(seg->amHdr.si == RLC_SI_LAST_SEG)
1830    {  
1831       lstRcvd = TRUE;
1832    } 
1833    /* kw003.201 - This should update seg with the one after newSeg */
1834    RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1835    while(seg)
1836    {
1837       /* keep going ahead as long as the expectedSo match with the header so
1838          else store the expSo for later checking again */
1839       if(seg->amHdr.si == RLC_SI_LAST_SEG)
1840       {  
1841          lstRcvd = TRUE;
1842       } 
1843       if (seg->amHdr.so == newExpSo)
1844       {
1845          newExpSo = seg->soEnd + 1;
1846          recBuf->expSo = newExpSo;
1847          RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1848       }
1849       else
1850       {
1851          recBuf->expSo = newExpSo;
1852          return;
1853       }
1854    }
1855    if (lstRcvd == TRUE)
1856    {
1857       recBuf->allRcvd = TRUE;
1858       gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1859    }
1860    recBuf->noMissingSeg = TRUE;
1861    return;
1862 }
1863
1864 /**
1865  * @brief
1866  *   Function to release/free the Acknowledged Mode Module  RbCb buffers
1867  *
1868  * @details
1869  *   This primitive Frees the AM RbCb transmission Buffer, retransmission
1870  *   Buffer and reciption Buffers
1871  *
1872  * @param [in]   gCb   - RLC instance Control Block
1873  * @param [in]   rbCb  - RB Control Block
1874  *
1875  * @return   void
1876  */
1877 Void rlcAmmFreeUlRbCb(RlcCb       *gCb,RlcUlRbCb   *rbCb)
1878 {
1879    RlcSn         curSn = 0;           /* Sequence number of PDU */
1880    RlcSn         windSz;              /* PDU window size */
1881    RlcAmRecBuf *recBuf = NULLP;
1882
1883    windSz  =  (RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
1884
1885    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1886    {
1887       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1888    }
1889    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1890    {
1891       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1892    }
1893
1894    RLC_FREE(gCb,rbCb->snssai, sizeof (Snssai));
1895
1896    /* on the first loop winSz is always greater than zero
1897     while( ( curSn < windSz ) hence changing to do while */
1898    do
1899    {
1900       recBuf = rlcUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
1901       if ( recBuf != NULLP )
1902       {
1903          if (recBuf->pdu != NULLP)
1904          {
1905             ODU_PUT_MSG_BUF(recBuf->pdu);
1906          }
1907          /* Release all the segments */
1908          rlcAmmUlRlsAllSegs(gCb,recBuf);
1909          rlcUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
1910       }
1911       curSn++;
1912    }while ( curSn < windSz );
1913
1914 #ifndef LTE_TDD 
1915       RLC_FREE(gCb,rbCb->m.amUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
1916       rbCb->m.amUl.recBufLst = NULLP;
1917 #endif
1918
1919    if(rbCb->m.amUl.partialSdu != NULLP)
1920    {
1921       ODU_PUT_MSG_BUF(rbCb->m.amUl.partialSdu);
1922    }
1923    return;
1924 } /* rlcAmmFreeUlRbCb */
1925
1926
1927 /*@}*/
1928
1929 \f
1930 /********************************************************************30**
1931
1932          End of file
1933 **********************************************************************/