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