b77a4ca8dc5afd4621f06e8076dc6861d1cede90
[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 #ifdef LTE_L2_MEAS_RLC
498    MsgLen              rlcSduSz;  /*Holds length of Rlc Sdu*/
499 #endif /* LTE_L2_MEAS */
500
501    amUl = &RLC_AMUL;
502
503    numPduToProcess = RLC_MIN(pduInfo->numPdu, RGU_MAX_PDU);
504    DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: numPdu[%d],numPduToProcess[%d] UEID:%d CELLID:%d",
505             numPdu, numPduToProcess, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
506
507    while (numPdu < numPduToProcess)
508    {
509       discFlg = FALSE;
510       pdu = pduInfo->mBuf[numPdu++];
511
512       if (! pdu)
513       {
514
515          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmProcessPdus: Null Pdu UEID:%d CELLID:%d",
516             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
517          gCb->genSts.errorPdusRecv++;
518          break;
519       }
520 #ifndef RGL_SPECIFIC_CHANGES
521 #ifndef TENB_ACC
522 #ifndef LTE_PAL_ENB
523       MsgLen len;
524       ODU_GET_MSG_LEN(pdu, &len);
525       ulrate_rgu += len;
526 #endif
527 #endif
528 #endif      
529       /* Extract AM PDU/SEG header Info */
530       RLC_MEM_ZERO(&amHdr, sizeof(RlcAmHdr));
531       /* Avoided the allocation of amHdr and sending
532          a single pointer */
533       if (rlcAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
534       {
535          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",
536             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
537          ODU_PUT_MSG_BUF(pdu);
538          gCb->genSts.errorPdusRecv++;
539          continue;
540       }
541       /* Check if its a control PDU */
542       if (amHdr.dc == 0)
543       {
544          rlcAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
545          ODU_PUT_MSG_BUF(pdu);
546          continue;
547       }
548       if((amHdr.si == RLC_SI_LAST_SEG) && (!amHdr.so))
549       {
550          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmProcessPdus: Dropping PDU because SO can't be zero\
551             for last segment sn:%u UEID:%d CELLID:%d", amHdr.sn, rbCb->rlcId.ueId,
552             rbCb->rlcId.cellId);
553          ODU_PUT_MSG_BUF(pdu);
554          continue;
555       }
556 #ifndef RGL_SPECIFIC_CHANGES
557 #ifdef LTE_TDD
558 #ifndef TENB_ACC
559 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
560 #ifndef LTE_PAL_ENB
561     /* Changed the condition to TRUE from ROK  */
562       if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
563       {
564          uint32_t rlculdrop;
565          rlculdrop++;
566          ODU_PUT_MSG_BUF(pdu);
567          continue;
568       }
569 #endif
570 #else
571 #ifndef LTE_PAL_ENB
572       /*ccpu00142274 - UL memory based flow control*/
573       if(isMemThreshReached(rlcCb[0]->init.region) != ROK)
574       {
575          uint32_t rlculdrop;
576          rlculdrop++;
577          ODU_PUT_MSG_BUF(pdu);
578          continue;
579       }
580 #endif
581 #endif
582 #endif
583 #endif
584 #endif
585
586 #ifdef T2K_TRIGGER_RLC_REEST
587       if(drpRlcDrbPack > 1000)
588       {
589          if(rbCb->rlcId.rbType == CM_LTE_DRB)
590          {
591             ODU_PUT_MSG_BUF(pdu);
592             continue;
593          }
594       }
595       drpRlcDrbPack++;
596 #endif
597       /* Reordering data PDU */
598       sn = amHdr.sn;
599       if (rlcAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
600       {
601          RlcAmRecBuf      *recBuf;
602          bool   tmrRunning;
603          RlcSn   tVrMr;
604          RlcSn   mrxNextHighestRcvd;
605
606 #ifdef LTE_L2_MEAS
607          rlcUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
608 #endif /* LTE_L2_MEAS */
609
610          /* Update rxNextHighestRcvd */
611          MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
612          MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
613          if (mSn >= mrxNextHighestRcvd)
614          {
615             amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask)); 
616
617             DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
618                amUl->rxNextHighestRcvd, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
619          }
620          
621          recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
622          if ((NULLP != recBuf) && ( recBuf->allRcvd))
623          {
624             /* deliver the reassembled RLC SDU to upper layer, 
625                But not removed from the table */
626             rlcAmmUlReassembleSdus(gCb, rbCb, recBuf);
627             recBuf->isDelvUpperLayer = TRUE;
628
629             MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
630             
631             /* Update rxHighestStatus */
632             if (sn == amUl->rxHighestStatus)
633             {
634                tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
635
636                recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
637                /* Scan through till the upper edge of the window */
638                MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
639                while (mSn <= tVrMr)
640                {
641                   if ((NULLP == recBuf) || (!recBuf->allRcvd))
642                   {
643                      DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: Updated rxHighestStatus:%d "
644                            "UEID:%d CELLID:%d",
645                            tSn,
646                            rbCb->rlcId.ueId,
647                            rbCb->rlcId.cellId);
648
649                      amUl->rxHighestStatus = tSn;
650                      break;
651                   }
652                   tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
653                   recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn); 
654                   mSn++;
655                }
656             }
657
658
659             /* Update rxNext */
660             if (sn == amUl->rxNext)
661             {
662                tSn = sn;
663                recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
664                MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
665                /* Scan through till the upper edge of the window */
666                while (mSn <= tVrMr)
667                {
668                   if ((NULLP != recBuf) && (recBuf->allRcvd) &&
669                       (TRUE == recBuf->isDelvUpperLayer))
670                   {
671                      /* RecBuf should remove from table 
672                         since PDU is already sent to upper layer */
673                       recBuf->isDelvUpperLayer = FALSE;
674                       rlcUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
675                   }
676                   else
677                   {
678                      amUl->rxNext = tSn;
679                      amUl->vrMr = (amUl->rxNext + (RLC_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
680                      break;
681                   }
682                   tSn = (tSn + 1) & (amUl->snModMask); 
683                   recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
684                   mSn++;
685                }
686             }
687          }
688
689          /* Check if reAsmblTmr is running and update rxNextStatusTrig accordingly */
690          tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
691          if (tmrRunning)
692          {
693             Bool snInWin = RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
694             /* spec 38.322v15.3.0 - 5.2.3.2.3 */
695             if((amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
696                                              (amUl->rxNextStatusTrig != amUl->vrMr) )||
697                (amUl->rxNextStatusTrig == amUl->rxNext && recBuf &&recBuf->noMissingSeg))
698             {
699                rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
700                tmrRunning = FALSE;
701                DU_LOG("\nINFO  --> RLC_UL: rlcAmmProcessPdus: Stopped ReAssembly Timer rxNextStatusTigger = %d"
702                  "rxNextReassembly = %d", amUl->rxNextStatusTrig, amUl->rxNext);
703             }
704          }
705
706          if (!tmrRunning)
707          {
708             /* spec 38.322v15.3.0 - 5.2.3.2.3 */
709             if((amUl->rxNextHighestRcvd > amUl->rxNext) || ((amUl->rxNextHighestRcvd == amUl->rxNext) &&
710                (recBuf && (!recBuf->noMissingSeg))))
711             {
712                rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
713                amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
714
715                DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmProcessPdus: Updated rxNextStatusTrig = %d" 
716                   "UEID:%d CELLID:%d", amUl->rxNextStatusTrig, rbCb->rlcId.ueId,
717                   rbCb->rlcId.cellId);
718             }
719          }
720       }
721       else
722       {
723          discFlg = TRUE;
724          gRlcStats.amRlcStats.numULPdusDiscarded++;
725       }
726
727       if (amHdr.p)
728       {
729          rlcAmmTriggerStatus(gCb,rbCb, sn, discFlg);
730       }
731    }
732
733 #ifdef LTE_L2_MEAS
734    rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
735 #endif /* LTE_L2_MEAS */
736    gCb->genSts.pdusRecv += pduInfo->numPdu;
737    if (amUl->gatherStaPduInfo)
738    {
739       rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
740    }
741
742    return;
743 }
744
745
746 /**
747  * @brief Private handler to extract header Information of the PDU
748  *
749  * @details
750  *    This function extracts the header elements of the PDU and store them
751  *    in db for future reference.
752  *
753  *    fByte - is the first byte removed from the PDU as part of calling
754  *            functions
755  *
756  * @param[in]  gCb     RLC instance control block
757  * @param[in]  rbCb    Uplink RB control block
758  * @param[in]  pdu     Received PDU
759  * @param[out] amHdr   Pointer to the extracted AM header
760  * @param[out] fByte   First byte removed from the PDU
761  *
762  * @return S16
763  *     -# ROK
764  *     -# RFAILED
765  *
766  */
767 static uint8_t rlcAmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcAmHdr *amHdr, uint8_t *fByte)
768 {
769    uint8_t    snByte;
770    RlcSn      sn = 0;
771    MsgLen     pduSz;
772    RlcExtHdr  hdrInfo;
773
774    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
775
776    /* Extract fixed part of the header */
777    ODU_GET_MSG_LEN(pdu,&pduSz);
778    ODU_REM_PRE_MSG(fByte, pdu);
779    amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
780    if (RLC_CNTRL_PDU == amHdr->dc)
781    {
782    //DU_LOG ("\nINFO  -->  RLC_UL : ++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
783       return ROK;
784    }
785
786    amHdr->p  = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
787
788    amHdr->si = (*fByte & RLC_SI_POS)   >> RLC_SI_SHT;
789
790    /* 12 BIT SN */
791    if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
792    {
793       ODU_REM_PRE_MSG(&snByte, pdu);
794       sn = (RlcSn)(((*fByte & RLC_SN_POS_12BIT) << RLC_BYTE_LEN ) | snByte);
795       amHdr->sn = sn;
796    }
797    else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
798    {
799       ODU_REM_PRE_MSG(&snByte, pdu);
800       sn = (RlcSn)(((*fByte & RLC_SN_POS_18BIT) << RLC_BYTE_LEN ) | snByte);
801
802       ODU_REM_PRE_MSG(&snByte, pdu);
803       sn = ((sn << RLC_BYTE_LEN) | snByte);
804
805       amHdr->sn = sn;
806    }
807    if ((amHdr->si != 0) && (amHdr->si != RLC_SI_FIRST_SEG))
808    {
809       hdrInfo.len = RLC_SO_LEN_5GNR;
810       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
811       amHdr->so = hdrInfo.val;
812       pduSz -= 2;
813    }
814
815    return ROK;
816 }
817
818 #ifdef OLD
819 /**
820  * @brief Private handler to extract header Information of the PDU
821  *
822  * @details
823  *    This function extracts the header elements of the PDU and store them
824  *    in db for future reference.
825  *
826  *    fByte - is the first byte removed from the PDU as part of calling
827  *            functions
828  *
829  * @param[in]  gCb     RLC instance control block
830  * @param[in]  rbCb    Uplink RB control block
831  * @param[in]  pdu     Received PDU
832  * @param[out] amHdr   Pointer to the extracted AM header
833  * @param[out] fByte   First byte removed from the PDU
834  *
835  * @return S16
836  *     -# ROK
837  *     -# RFAILED
838  *
839  */
840 static S16 rlcAmmExtractHdrOld(RlcCb *gCb,Buffer *pdu,RlcAmHdr *amHdr,uint8_t *fByte)
841 {
842    uint8_t         e;
843    uint8_t         snByte;
844    uint16_t        sn;
845    MsgLen     pduSz;
846    MsgLen     totalSz = 0;
847    RlcExtHdr   hdrInfo;
848
849    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
850
851    /* Extract fixed part of the header */
852    SFndLenMsg(pdu,&pduSz);
853    SRemPreMsg(fByte, pdu);
854    amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
855    if (RLC_CNTRL_PDU == amHdr->dc)
856    {
857       return ROK;
858    }
859    /* kw002.201 : Changed the extraction of hdr elements to avoid */
860    /*             function calls                                  */
861    amHdr->rf = (*fByte & RLC_RF_POS)   >> RLC_RF_SHT;
862    amHdr->p  = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
863    amHdr->fi = (*fByte & RLC_FI_POS)   >> RLC_FI_SHT;
864    e = amHdr->e  = (*fByte & RLC_E_POS)>> RLC_E_SHT;
865     
866    SRemPreMsg(&snByte, pdu);
867    sn = (uint16_t)(((*fByte & RLC_SN_POS) << RLC_BYTE_LEN ) | snByte);
868    amHdr->sn = sn;
869    if (amHdr->rf == 1)
870    {
871       /* Extract extn part of the header */
872       hdrInfo.len = RLC_LSF_LEN;
873       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
874       amHdr->lsf = (uint8_t)hdrInfo.val;
875
876       hdrInfo.len = RLC_SO_LEN;
877       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
878       amHdr->so = hdrInfo.val;
879       pduSz -= 2;
880    }
881
882    amHdr->numLi = 0;
883    /* Extract LIs */
884    while (e && (amHdr->numLi < RLC_MAX_UL_LI))
885    {
886       hdrInfo.len = RLC_E_LEN;
887       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
888       e = amHdr->e = (uint8_t)hdrInfo.val;
889
890       /* Extract LI value*/
891       hdrInfo.len = RLC_LI_LEN;
892       rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
893       /* li = hdrInfo.val;*/
894
895       /* check if LI is zero */
896       if (! hdrInfo.val)
897       {
898          DU_LOG("\nERROR  -->  RLC_UL : Received LI as 0");
899          return RFAILED;
900       }
901
902       /* store the extracted  LI value */
903       amHdr->li[amHdr->numLi++] = hdrInfo.val;
904       totalSz += hdrInfo.val;  /* incrment the size by LI value */
905    }
906
907    /*ccpu00122597:PDU is dropped if liCnt exceeds RLC_MAX_LI*/
908    if(e && (amHdr->numLi >= RLC_MAX_UL_LI))
909    {
910       DU_LOG("\nERROR  -->  RLC_UL : LI Count [%u] exceeds Max LI Count[%u]", 
911             amHdr->numLi, RLC_MAX_UL_LI);
912       return RFAILED;
913    }
914
915    /*                                first 2 bytes + Add one for  Odd LI*/
916    pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
917
918    if ( totalSz >= pduSz )
919    {   
920       DU_LOG("\nERROR  -->  RLC_UL : SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
921                amHdr->sn, totalSz, pduSz);
922       return RFAILED;
923    }
924
925    return ROK;
926 }
927 #endif
928
929 /**
930  * @brief Private handler to process the status PDU
931  *
932  * @details
933  *    Private handler invokded by rlcAmmProcessPdus to process the
934  *    control PDU (status report) received from its peer RLC entity.
935  *
936  *        - Decode the values from the received control pdu
937  *        - Create a RlcUdxStaPdu structure, copy the values onto it and
938  *          send it to the DL instance for further processing
939  *
940  * @param[in]  gCb       RLC instance control block
941  * @param[in]  rbCb      Uplink RB control block
942  * @param[in]  cntrlPdu  Control PDU received from MAC
943  * @param[in]  fByte     First byte already removed from the STATUS PDU
944  *
945  *  @return  Void
946  *
947  */
948 static void rlcAmmUlHndlStatusPdu(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *cntrlPdu, uint8_t *fByte)
949 {
950    uint8_t          e1;
951    RlcExtHdr        hdrInfo;
952    RlcUdxStaPdu     *pStaPdu;
953    RlcUdxUlSapCb    *sapCb;
954    uint8_t          e3; /* NACK RANGE : 5GNR */
955    uint32_t         snLen;
956    uint32_t         snRange;
957    uint32_t         resrvdBitsAckSn=0;
958    uint32_t         resrvdBitsNackSn=0;
959
960    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
961
962    /* Extract the Control PDU */
963    hdrInfo.hdr  = (*fByte << 1);
964    hdrInfo.pLen = 4;
965
966    /* D/C has been shifted in the calling function */
967    if (hdrInfo.hdr & 0xE0)
968    {
969       DU_LOG("\nINFO  -->  RLC_UL : rlcAmmUlHndlStatusPdu: Reserved value for CPT received UEID:%d \
970          CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
971       return;
972    }
973
974    sapCb = RLC_GET_UDX_SAP(gCb);
975
976    RLC_ALLOC_SHRABL_BUF(sapCb->pst.region, 
977                        sapCb->pst.pool, 
978                        pStaPdu, 
979                        sizeof(RlcUdxStaPdu));
980
981 #if (ERRCLASS & ERRCLS_ADD_RES)
982    /* Memory allocation failure can not be expected  */
983    if(!pStaPdu)
984    {
985      return;
986    }
987 #endif   
988
989    if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
990    {
991       snLen = 12;
992       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
993       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
994    }
995    else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
996    {
997       snLen = 18;
998       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
999       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
1000    }
1001    else
1002    {
1003       snLen = RLC_SN_LEN;
1004       resrvdBitsAckSn = 0;
1005       resrvdBitsAckSn = 0;
1006    }
1007
1008    pStaPdu->nackCnt = 0;
1009    /* For CPT */
1010    hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
1011
1012    /* ACK Sn */
1013    hdrInfo.len = snLen;
1014    rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1015    pStaPdu->ackSn = hdrInfo.val;
1016
1017    //DU_LOG ("\nINFO  -->  RLC_UL : ++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n",  pStaPdu->ackSn);
1018    /* Check if NACK Exists */
1019    hdrInfo.len = RLC_E1_LEN;
1020    rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1021    e1 = (uint8_t)hdrInfo.val;
1022    DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1023       pStaPdu->ackSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1024
1025    /* Extract the Reserved Bits after ACK SN field */
1026    hdrInfo.len = resrvdBitsAckSn;
1027    rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1028
1029    /* If NACK exists in control PDU */
1030    /* For ACKs and NACKs */
1031    while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
1032    {
1033       hdrInfo.len = snLen;
1034       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1035       pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1036
1037       hdrInfo.len = RLC_E1_LEN;
1038       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1039       e1 = (uint8_t)hdrInfo.val;
1040
1041       /* Extract e2 */
1042       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1043          already present*/
1044       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1045       /*  e2 = (uint8_t) hdrInfo.val;*/
1046
1047       /* Store e2 value */
1048       pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
1049
1050       /* Extract e3 : 5GNR */
1051       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1052          already present*/
1053       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1054       e3 = (uint8_t) hdrInfo.val;
1055
1056       /* Extract Reserved Bits after NACK SN */
1057       hdrInfo.len = resrvdBitsNackSn;
1058       rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1059
1060       /* Test for resegmentation */
1061       if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1062       {
1063          hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1064          rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1065          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1066
1067          rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1068          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = hdrInfo.val;
1069
1070          DU_LOG("\nDEBUG  -->  RLC_UL : rlcAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1071             "UEID:%d CELLID:%d", pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1072             pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd, rbCb->rlcId.ueId,
1073             rbCb->rlcId.cellId);
1074       }                                                                
1075       else
1076       {
1077          hdrInfo.len = 0;
1078          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1079          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = 0;
1080
1081       }
1082       /* NACK RANGE Field is SET */
1083       if (e3)
1084       {
1085          /* Extract NACK range field */
1086          hdrInfo.len = RLC_NACK_RANGE_LEN;
1087          rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1088          snRange = (uint8_t)hdrInfo.val;
1089
1090          pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1091
1092       }
1093       pStaPdu->nackCnt++;
1094    }
1095
1096    gRlcStats.amRlcStats.numULStaPduRcvd++;
1097    gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1098
1099    /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1100       to the last NACK SN + 1 and discard the original ACK_SN*/
1101    if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
1102    {
1103       pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1104    }
1105
1106
1107    /* Parse & send Status PDU to RLC-DL */
1108    rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1109
1110    return;
1111 }
1112
1113 /**
1114  * @brief Private handler to release all stored segments
1115  *
1116  * @details
1117  *    Private handler invokded by rlcAmmUlPlacePduInRecBuf to release the
1118  *    stored segements in case a complete PDU is received later.
1119  *
1120  * @param[in]  gCb      RLC instance control block
1121  * @param[in]  recBuf   Buffer that stores a received PDU or segments
1122  *
1123  * @return  Void
1124  *
1125  */
1126 static void rlcAmmUlRlsAllSegs(RlcCb *gCb, RlcAmRecBuf *recBuf)
1127 {
1128    RlcSeg *seg;
1129
1130    RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1131    while (seg != NULLP)
1132    {
1133       ODU_PUT_MSG_BUF(seg->seg);
1134       cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1135       RLC_FREE(gCb,seg, sizeof(RlcSeg));
1136       RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1137    }
1138
1139    return;
1140 }
1141
1142 /**
1143  * @brief Private handler to store the received segment
1144  *
1145  * @details
1146  *    Private handler invokded by rlcAmmUlPlacePduInRecBuf to add a received
1147  *    segment in reception buffer of a RBCB.
1148  *    - It is responsible for detecting duplicate segments
1149  *    - Adding it at appropriate position in the received buffer
1150  *    - Calling ExpByteSeg to set expSo field in the receiver buffer
1151  *
1152  * @param[in]  gCb      RLC instance control block
1153  * @param[in]  rbCb     Radio Bearer Contro Block
1154  * @param[in]  amHdr    AM Header received
1155  * @param[in]  pdu      Buffer received other than the headers
1156  * @param[in]  pduSz    size of the PDU buffer received
1157  *
1158  * @return  Bool
1159  *   -#TRUE  Successful insertion into the receiver buffer
1160  *   -#FALSE Possibly a duplicate segment
1161  */
1162 static bool rlcAmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu, uint16_t pduSz)
1163 {
1164    RlcAmRecBuf   *recBuf = NULLP;
1165    RlcSeg        *seg;
1166    RlcSeg        *tseg;
1167    uint16_t      soEnd;       /* Holds the SoEnd of received segment */
1168    uint16_t      expSo = 0;   /* Expected SO */
1169
1170    soEnd = amHdr->so + pduSz - 1;
1171    recBuf =  rlcUtlGetRecBuf(RLC_AMUL.recBufLst, amHdr->sn);
1172
1173    if (NULLP == recBuf)
1174    {
1175       RLC_ALLOC(gCb,recBuf, sizeof(RlcAmRecBuf));
1176 #if (ERRCLASS & ERRCLS_ADD_RES)
1177       if (recBuf == NULLP)
1178       {
1179          DU_LOG("\nERROR  -->  RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1180             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1181
1182          ODU_PUT_MSG_BUF(pdu);
1183          return FALSE;
1184       }
1185 #endif /* ERRCLASS & ERRCLS_RES */
1186       rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, amHdr->sn);
1187    }
1188    else
1189    {
1190       if (recBuf->allRcvd == TRUE)
1191       {
1192          ODU_PUT_MSG_BUF(pdu);
1193          return FALSE;
1194       }
1195    }
1196                         
1197    recBuf->isDelvUpperLayer = FALSE;
1198    /* kw003.201 - Move past the segments that are different than the */
1199    /*             one received.                                      */
1200    RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1201    while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1202    {
1203       expSo = seg->amHdr.so + seg->segSz;
1204       RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1205    }
1206
1207    /* The received segment should start after the end of previous seg */
1208    if (expSo > amHdr->so)
1209    {
1210       /* This is a duplicate segment */
1211       gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1212       ODU_PUT_MSG_BUF(pdu);
1213       return FALSE;
1214    }
1215
1216    if ((seg) && (seg->amHdr.so <= soEnd))
1217    {
1218       /* This is a duplicate segment */
1219       gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1220       ODU_PUT_MSG_BUF(pdu);
1221       return FALSE;
1222    }
1223
1224    /* If we have come this far, we have to add this segment to the   */
1225    /* reception buffer as we either have eliminated duplicates or    */
1226    /* have found none.                                               */
1227    RLC_ALLOC_WC(gCb,tseg, sizeof(RlcSeg));
1228 #if (ERRCLASS & ERRCLS_ADD_RES)
1229    if (tseg == NULLP)
1230    {
1231       DU_LOG("\nERROR  -->  RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1232          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1233       ODU_PUT_MSG_BUF(pdu);
1234       return FALSE;
1235    }
1236 #endif /* ERRCLASS & ERRCLS_RES */
1237
1238    tseg->seg = pdu;
1239    tseg->segSz = pduSz;
1240    RLC_MEM_CPY(&tseg->amHdr, amHdr, sizeof(RlcAmHdr));
1241    recBuf->amHdr.si = amHdr->si;
1242    recBuf->amHdr.sn = amHdr->sn;
1243    tseg->soEnd = soEnd;
1244    if (seg == NULLP)
1245    {
1246       cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1247    }
1248    else
1249    {
1250       recBuf->segLst.crnt = &seg->lstEnt;
1251       cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1252    }
1253    tseg->lstEnt.node = (PTR)tseg;
1254    rlcAmmUpdExpByteSeg(gCb,&RLC_AMUL,tseg);
1255
1256    return TRUE;
1257 }
1258
1259 /**
1260  * @brief Private handler to place the PDU in the reception buffer
1261  *
1262  * @details
1263  *    This function checks if the received PDU's SN falls within the
1264  *    receiving window, after which it places the same in the reception
1265  *    buffer if its not a duplicate.
1266  *
1267  * @param[in]  gCb   RLC instance control block
1268  * @param[in]  pdu   Received PDU
1269  * @param[in]  rbCb  Uplink AM Radio Bearer
1270  * @param[out] amUl  AM UL Info
1271  *
1272  * @return Bool
1273  *     -# TRUE
1274  *     -# FALSE
1275  *
1276  */
1277 static bool rlcAmmUlPlacePduInRecBuf(RlcCb *gCb, Buffer *pdu, RlcUlRbCb *rbCb, RlcAmHdr *amHdr)
1278 {
1279    RlcSn     sn;
1280    MsgLen   pduSz;
1281    RlcAmUl   *amUl = &(rbCb->m.amUl);
1282
1283    sn = amHdr->sn;
1284    SFndLenMsg(pdu, &pduSz);
1285
1286    gCb->genSts.bytesRecv += pduSz;
1287    gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz; 
1288    if (!RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1289    {
1290       gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1291       DU_LOG("\nERROR  -->  RLC_UL : rlcAmmUlPlacePduInRecBuf: SN  %d outside the window"
1292          "UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1293
1294       gCb->genSts.unexpPdusRecv++;
1295       ODU_PUT_MSG_BUF(pdu);
1296       return FALSE;
1297    }
1298
1299    if (amHdr->si == 0)
1300    {
1301       RlcAmRecBuf *recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1302
1303       /* We received a complete PDU. Either we already have it, in which */
1304       /* case we just ignore the new PDU and discard it. Otherwise,      */
1305       /* store the received PDU in the reception buffer                  */
1306       if (NULLP == recBuf)
1307       {
1308          RLC_ALLOC(gCb, recBuf, sizeof(RlcAmRecBuf));
1309 #if (ERRCLASS & ERRCLS_ADD_RES)
1310          if (recBuf == NULLP)
1311          {
1312             DU_LOG("\nERROR  -->  RLC_UL : rlcAmmUlPlacePduInRecBuf: Memory allocation failed \
1313                UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1314             ODU_PUT_MSG_BUF(pdu);
1315             return FALSE;
1316          }
1317 #endif /* ERRCLASS & ERRCLS_RES */
1318          rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, sn);
1319       }
1320       else if (recBuf->allRcvd != TRUE)
1321       {
1322          rlcAmmUlRlsAllSegs(gCb,recBuf);
1323       }
1324       else
1325       {
1326          gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1327          gCb->genSts.unexpPdusRecv++;
1328          ODU_PUT_MSG_BUF(pdu);
1329          return FALSE;
1330       }
1331       recBuf->isDelvUpperLayer = FALSE;
1332       recBuf->pdu = pdu;
1333       recBuf->pduSz = pduSz;
1334       recBuf->allRcvd = TRUE;
1335       gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1336       RLC_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(RlcAmHdr));
1337       return TRUE;
1338    }
1339    else
1340    {
1341       /* We received a segment. We need to add that to the existing */
1342       /* segments, if any.                                          */
1343       return (rlcAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1344    }
1345 }
1346
1347 /**
1348  * @brief Private handler to trigger status report
1349  *
1350  * @details
1351  *    Private handler invokded by rlcAmmProcessPdus to check if the
1352  *    status report need to be sent, and update the status trigger
1353  *    flag accordingly based on status prohibit timer.
1354  *
1355  *    - Check if the received pdu's sn is less than rxHighestStatus, set the
1356  *      staTrg flag.
1357  *    - If staProhTmr is not running, calculate cntrlBo, else it'll be
1358  *      updated at the expiry of staProhTmr.
1359  *    - Expiry of reAsmblTmr also will set staTrg flag.
1360  *
1361  * @param[in]  gCb       RLC instance control block
1362  * @param[in]  rbCb      Uplink RB control block
1363  * @param[in]  sn        Sequence number of the pdu based on which to check if
1364  *                       status needs to be triggered
1365  * @param[in]  discFlg   Whether this pdu was discarded or not
1366  *
1367  * @return  Void
1368  *
1369  */
1370 static void rlcAmmTriggerStatus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcSn sn, bool discFlg)
1371 {
1372    bool     tmrRunning;
1373    RlcSn     tSn;
1374    RlcSn     tVrMr;
1375    RlcSn     trxHighestStatus;
1376    RlcAmUl   *amUl = &(rbCb->m.amUl);
1377
1378    MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1379    MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1380    MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1381
1382    /* kw005.201 Product CR ccpu00117114       *
1383     * The "=" in the 2nd condition is removed */
1384    if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1385    {
1386       DU_LOG("\nINFO  -->  RLC_UL : rlcAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1387          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1388
1389       amUl->staTrg = TRUE;
1390       amUl->gatherStaPduInfo = FALSE;
1391
1392       /* Check if staProhTmr is running */
1393       tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1394
1395       if (!tmrRunning)
1396       {
1397          amUl->gatherStaPduInfo = TRUE;
1398       }
1399    }
1400
1401    return;
1402 }
1403
1404 /**
1405  * @brief Private handler to reassemble from a segment or a PDU
1406  *
1407  * @details
1408  *    Private handler invokded by kwAmmReassembleSdus with either a
1409  *    PDU or a segment of a PDU. This is also called in the case of
1410  *    reestablishment and hence out of sequence joining is also to
1411  *    be supported
1412  *
1413  *
1414  * @param[in]  gCb     RLC instance control block
1415  * @param[in]  rbCb    Uplink RB control block
1416  * @param[in]  amHdr   AM header received for this segment/PDU
1417  * @param[in]  pdu     PDU to be reassembled
1418  *
1419  * @return  Void
1420  *
1421  */
1422 static void rlcAmmProcPduOrSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu)
1423 {
1424
1425    if ((RLC_AMUL.expSn != amHdr->sn) || (RLC_AMUL.expSo != amHdr->so))
1426    {
1427       /* Release the existing partial SDU as we have PDUs or */
1428       /* segments that are out of sequence                   */
1429       rbCb->m.amUl.isOutOfSeq = TRUE;
1430       ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1431    }
1432
1433    if (amHdr->si == RLC_SI_FIRST_SEG)
1434    {/* first Segment of the SDU */
1435       if (RLC_AMUL.partialSdu != NULLP)
1436       { /* Some old SDU may be present */
1437          ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1438       }
1439       RLC_AMUL.partialSdu = pdu;
1440       pdu = NULLP;
1441    }
1442    else if(amHdr->si == RLC_SI_MID_SEG)
1443    {/* Middle or last segment of the SUD */
1444       ODU_CAT_MSG(RLC_AMUL.partialSdu,pdu, M1M2);
1445       ODU_PUT_MSG_BUF(pdu);
1446       pdu = NULLP;
1447    }
1448    else if (amHdr->si ==  RLC_SI_LAST_SEG)
1449    {
1450       ODU_CAT_MSG(pdu,RLC_AMUL.partialSdu,M2M1);
1451       ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1452    }
1453
1454    if (pdu != NULLP)
1455    {
1456       RLC_AMUL.partialSdu = NULLP;
1457       rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
1458    }
1459
1460    return;
1461 }
1462
1463 /**
1464  *
1465  * @brief Private handler to reassemble SDUs
1466  *
1467  * @details
1468  *    Private handler invokded by rlcAmmProcessPdus with the PDU
1469  *    from the reception buffer in sequence to reassemble SDUs and
1470  *    send it to PDCP.
1471  *
1472  *        - With the stored header info, FI and LSF segment / concatenate
1473  *          PDUs or byte segments of PDUs to get the associated SDU.
1474  *
1475  * @param[in]  rbCb     RB control block
1476  * @param[in]  pdu      PDU to be reassembled
1477  *
1478  *  @return  S16
1479  *      -# ROK
1480  *      -# RFAILED
1481  *
1482  */
1483 static uint8_t rlcAmmUlReassembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmRecBuf *recBuf)
1484 {
1485    RlcSeg        *seg;
1486
1487    //if (recBuf->amHdr.rf == 0)
1488    if (recBuf->amHdr.si == 0)
1489    {
1490       /* This is a PDU */
1491       rlcAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1492       /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1493       recBuf->pdu = NULLP;
1494       RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1495       RLC_AMUL.expSo = 0;
1496    }
1497    else
1498    {
1499       /* This is a set of segments */
1500       RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1501       RLC_AMUL.expSn = recBuf->amHdr.sn;
1502       RLC_AMUL.expSo = 0;
1503       while(seg)
1504       {
1505          rlcAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1506          RLC_AMUL.expSo = seg->soEnd + 1;
1507
1508          cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1509          RLC_FREE(gCb, seg, sizeof(RlcSeg));
1510
1511          RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1512       }
1513       RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1514       RLC_AMUL.expSo = 0;
1515    }
1516
1517    return ROK;
1518 }
1519
1520 /**
1521  * @brief   Handler to process the re-establishment request received from UIM
1522  *
1523  * @param[in] gCb         RLC instance control block
1524  * @param[in] rlcId       RLC identifier
1525  * @param[in] sendReEst   Whether to send back restablishment complete or not
1526  * @param[in] rbCb        Uplink RB control block
1527  *
1528  * @return  Void
1529  *
1530  */
1531 Void rlcAmmUlReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcUlRbCb  *rbCb)
1532 {
1533    RlcSn   sn;
1534    RlcSn   mSn;
1535    RlcSn   mVrMr;
1536
1537 #ifndef KW_PDCP
1538    RlcKwuSapCb *rlcKwuSap;
1539 #endif
1540    RlcAmRecBuf   *recBuf = NULLP;
1541
1542    sn = RLC_AMUL.rxNext;
1543
1544    MODAMR(RLC_AMUL.vrMr, mVrMr, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1545    MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1546
1547    /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1548    while (mSn < mVrMr)
1549    {
1550       recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1551       if (NULLP != recBuf)
1552       {
1553          if (recBuf->allRcvd == TRUE)
1554          {
1555             rlcAmmUlReassembleSdus(gCb,rbCb, recBuf);
1556          }
1557          else
1558          {
1559             /* Remove PDU and segments */
1560             if(recBuf->pdu)
1561             {
1562                ODU_PUT_MSG_BUF(recBuf->pdu);
1563             }
1564             /* Release all the segments*/
1565             rlcAmmUlRlsAllSegs(gCb,recBuf);
1566          }
1567          rlcUtlDelRecBuf(RLC_AMUL.recBufLst, recBuf, gCb);
1568       }
1569       sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1570       MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1571    }
1572    /* Discard remaining PDUs and bytesegments in recBuf */
1573
1574    /* Stop all timers and reset variables */
1575    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1576    {
1577        rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1578    }
1579    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1580    {
1581        rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1582    }
1583
1584    RLC_AMUL.rxNext  = 0;
1585    RLC_AMUL.rxNextHighestRcvd  = 0;
1586    RLC_AMUL.rxNextStatusTrig  = 0;
1587    rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1588    RLC_AMUL.rxHighestStatus = 0;
1589    RLC_AMUL.staTrg  = FALSE;
1590    RLC_AMUL.gatherStaPduInfo = FALSE;
1591    RLC_AMUL.expSn = 0;
1592    RLC_AMUL.expSo = 0;
1593    if (RLC_AMUL.partialSdu != NULLP)
1594    {
1595      ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1596    }
1597    rlcKwuSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
1598
1599    if(sendReEst)
1600    {
1601       RlcUiKwuReEstCmpInd(&rlcKwuSap->pst, rlcKwuSap->suId, rlcId);
1602       rbCb->m.amUl.isOutOfSeq = FALSE;
1603    }
1604
1605    return;
1606 }
1607
1608 /**
1609  * @brief  Handler for reorder timer expiry
1610  *
1611  * @details
1612  *    This function is used to handle events upon expiry of reorder timer
1613  *
1614  *  @param[in] gCb   RLC instance control block
1615  *  @param[in] rbCb  RB control block
1616  *
1617  *  @return  Void
1618  *
1619  */
1620
1621 Void rlcAmmReAsmblTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1622 {
1623    RlcAmUl *amUl = &(rbCb->m.amUl);
1624    RlcSn sn;
1625    RlcSn mSn;
1626    RlcSn mVrMr;
1627    RlcSn mrxHighestStatus;
1628    RlcSn mrxNextHighestRcvd;
1629    Bool tmrRunning = FALSE;
1630    RlcAmRecBuf   *recBuf = NULLP;
1631
1632    /* Update rxHighestStatus */
1633    sn = amUl->rxNextStatusTrig;
1634
1635    MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1636    MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1637    recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1638
1639    while (mSn < mVrMr)
1640    {
1641       if ((recBuf == NULLP) ||
1642           ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1643       {
1644          amUl->rxHighestStatus = sn;
1645          amUl->staTrg = TRUE;
1646          amUl->gatherStaPduInfo = FALSE;
1647
1648          /* Check if staProhTmr is running */
1649          tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1650
1651          if (!tmrRunning)
1652          {
1653             gRlcStats.amRlcStats.numULReAsmblTimerExpires++;
1654             amUl->gatherStaPduInfo = TRUE;
1655             rlcAmmUlAssembleCntrlInfo(gCb, rbCb);
1656          }
1657
1658          break;
1659       }
1660       sn = (sn + 1) & (amUl->snModMask); 
1661       MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1662    }
1663
1664    /* Update rxNextStatusTrig */
1665    MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1666    MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1667    /* spec 38.322v15.3.0 - 5.2.3.2.4 */
1668    if((mrxNextHighestRcvd > mrxHighestStatus) || ((mrxNextHighestRcvd == mrxHighestStatus) &&
1669       ((recBuf) &&  !(recBuf->noMissingSeg))))
1670    {
1671       rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1672       amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1673    }
1674
1675    return;
1676 } /* rlcAmmReAsmblTmrExp */
1677
1678 /**
1679  * @brief  Handler for status prohibit timer expiry
1680  *
1681  * @details
1682  *    This function is used to handle events upon expiry of status prohibit
1683  *    timer
1684  *
1685  *  @param[in] gCb   RLC instance control block
1686  *  @param[in] rbCb   RB control block
1687  *
1688  *  @return  Void
1689  *
1690  */
1691
1692 Void rlcAmmStaProTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1693 {
1694    RlcAmUl *amUl = &(rbCb->m.amUl);
1695
1696    amUl->gatherStaPduInfo = FALSE;
1697
1698    if (amUl->staTrg == TRUE)
1699    {
1700       amUl->gatherStaPduInfo = TRUE;
1701       /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
1702       rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
1703    }
1704
1705    return;
1706 } /* rlcAmmStaProTmrExp */
1707
1708 /**
1709  * @brief  Handler to extract an element of AM Header
1710  *
1711  * @details
1712  *    This function is used to extract an element of AM header.
1713  *
1714  * @param[in]     pdu      The pdu to be decoded
1715  * @param[in,out] hdrInfo  Container to hold the decoded info
1716  *
1717  * @return Void
1718  *
1719  */
1720
1721 static void rlcAmmExtractElmnt(RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo)
1722 {
1723    uint8_t   hdr;
1724    uint8_t   pLen = hdrInfo->pLen;
1725    uint8_t   len  = (uint8_t)hdrInfo->len;
1726    uint32_t  val;
1727    uint8_t   tHdr;
1728    uint8_t   fLen;
1729    uint8_t   rLen;
1730    /* uint8_t   rLen1 = 0; */
1731    uint16_t  tVal;
1732
1733    hdr = hdrInfo->hdr;
1734
1735    if (pLen == 0)
1736    {
1737       ODU_REM_PRE_MSG(&hdr, pdu);
1738       pLen = 8;
1739    }
1740    tHdr = hdr;
1741    if (len <= 8)
1742    {
1743       val = tHdr >> (RLC_BYTE_LEN - (len));
1744       hdr =  hdr << len;
1745       pLen -= len;
1746    }
1747    else /*if (len > 8) */
1748    {
1749       fLen = pLen;
1750       val = tHdr;
1751       val = val >> (RLC_BYTE_LEN - fLen);
1752       val = val << (len - fLen);
1753       rLen = len - fLen;
1754       ODU_REM_PRE_MSG(&hdr, pdu);
1755       tHdr = hdr;
1756       if (rLen <= 8)
1757       {
1758          hdr = hdr >> (RLC_BYTE_LEN - rLen);
1759          val = val | hdr;
1760          hdr = tHdr << rLen;
1761          pLen = (RLC_BYTE_LEN - rLen);
1762       }
1763       else
1764       {
1765         rLen = rLen - RLC_BYTE_LEN;
1766         tVal = hdr;
1767         tVal = tVal << rLen;
1768         val = val | tVal;
1769
1770         ODU_REM_PRE_MSG(&hdr, pdu);
1771         tHdr = hdr;
1772         hdr = hdr >> (RLC_BYTE_LEN - rLen);
1773         val = val | hdr;
1774         hdr = tHdr << rLen;
1775         pLen = (RLC_BYTE_LEN - rLen);
1776       }
1777    }
1778
1779    hdrInfo->pLen = pLen;
1780    hdrInfo->hdr = hdr;
1781    hdrInfo->val = val;
1782
1783    return;
1784 }
1785
1786 /**
1787  * @brief  Handler to updated expected byte seg
1788  *
1789  * @details
1790  *    This function is used to update expected byte segment. The next segment
1791  *    expected is indicated by the SO of the segment which is expected. Intially
1792  *    the segment with SO 0 is expected and then in order. When all the segments
1793  *    are received (which would happen when an expected SO is encountered
1794  *    with LSF set) the allRcvd flag is set to TRUE
1795  *
1796  * @param[in]  gCb   RLC instance control block
1797  * @param[in]  amUl  AM Uplink Control Block
1798  * @param[in]  seg   Newly received segment
1799  *
1800  * @return Void
1801  *
1802  */
1803
1804 static void rlcAmmUpdExpByteSeg(RlcCb *gCb, RlcAmUl *amUl, RlcSeg *seg)
1805 {
1806    uint16_t  newExpSo; /* The new expected SO */
1807    RlcSn     sn = seg->amHdr.sn;
1808    bool      lstRcvd=FALSE;
1809    RlcAmRecBuf *recBuf = NULLP;
1810    
1811    recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1812    if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
1813    {
1814       return;
1815    }
1816    recBuf->noMissingSeg = FALSE;
1817    newExpSo   = seg->soEnd + 1;
1818    recBuf->expSo = newExpSo;
1819    if(seg->amHdr.si == RLC_SI_LAST_SEG)
1820    {  
1821       lstRcvd = TRUE;
1822    } 
1823    /* kw003.201 - This should update seg with the one after newSeg */
1824    RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1825    while(seg)
1826    {
1827       /* keep going ahead as long as the expectedSo match with the header so
1828          else store the expSo for later checking again */
1829       if(seg->amHdr.si == RLC_SI_LAST_SEG)
1830       {  
1831          lstRcvd = TRUE;
1832       } 
1833       if (seg->amHdr.so == newExpSo)
1834       {
1835          newExpSo = seg->soEnd + 1;
1836          recBuf->expSo = newExpSo;
1837          RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1838       }
1839       else
1840       {
1841          recBuf->expSo = newExpSo;
1842          return;
1843       }
1844    }
1845    if (lstRcvd == TRUE)
1846    {
1847       recBuf->allRcvd = TRUE;
1848       gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1849    }
1850    recBuf->noMissingSeg = TRUE;
1851    return;
1852 }
1853
1854 /**
1855  * @brief
1856  *   Function to release/free the Acknowledged Mode Module  RbCb buffers
1857  *
1858  * @details
1859  *   This primitive Frees the AM RbCb transmission Buffer, retransmission
1860  *   Buffer and reciption Buffers
1861  *
1862  * @param [in]   gCb   - RLC instance Control Block
1863  * @param [in]   rbCb  - RB Control Block
1864  *
1865  * @return   void
1866  */
1867 Void rlcAmmFreeUlRbCb(RlcCb       *gCb,RlcUlRbCb   *rbCb)
1868 {
1869    RlcSn         curSn = 0;           /* Sequence number of PDU */
1870    RlcSn         windSz;              /* PDU window size */
1871    RlcAmRecBuf *recBuf = NULLP;
1872
1873    windSz  =  (RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
1874
1875    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1876    {
1877       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1878    }
1879    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1880    {
1881       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1882    }
1883
1884
1885    /* on the first loop winSz is always greater than zero
1886     while( ( curSn < windSz ) hence changing to do while */
1887    do
1888    {
1889       recBuf = rlcUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
1890       if ( recBuf != NULLP )
1891       {
1892          if (recBuf->pdu != NULLP)
1893          {
1894             ODU_PUT_MSG_BUF(recBuf->pdu);
1895          }
1896          /* Release all the segments */
1897          rlcAmmUlRlsAllSegs(gCb,recBuf);
1898          rlcUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
1899       }
1900       curSn++;
1901    }while ( curSn < windSz );
1902
1903 #ifndef LTE_TDD 
1904       RLC_FREE(gCb,rbCb->m.amUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
1905       rbCb->m.amUl.recBufLst = NULLP;
1906 #endif
1907
1908    if(rbCb->m.amUl.partialSdu != NULLP)
1909    {
1910       ODU_PUT_MSG_BUF(rbCb->m.amUl.partialSdu);
1911    }
1912    return;
1913 } /* rlcAmmFreeUlRbCb */
1914
1915
1916 /*@}*/
1917
1918 \f
1919 /********************************************************************30**
1920
1921          End of file
1922 **********************************************************************/