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