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