[Epic-ID: ODUHIGH-488][Task-ID: ODUHIGH-498] Fix in DL data flow and trace alignment
[o-du/l2.git] / src / 5gnrrlc / rlc_amm_dl.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 DL module file
22     
23         Type:    C source file
24   
25         Desc:    Source code for Acknowledged Mode Module functions such as, 
26
27                  Transmission of data/control PDUs 
28                  Retransmission (Feedback in terms of status)
29                  Polling
30                  Assemble SDUs
31                  Reception - reordering
32                  Duplicate detection for byte segments
33                  Reassemble SDUs
34                   
35         File:   rlc_amm_dl.c 
36   
37 *********************************************************************21*/
38 /* header include files (.h) */
39 #include "common_def.h"
40 #include "lkw.h"           /* LKW defines */
41 #include "ckw.h"           /* CKW defines */
42 #include "kwu.h"           /* KWU defines */
43 #include "rgu.h"           /* RGU defines */
44 #include "rlc_err.h"        /* Err defines */
45 #include "rlc_env.h"        /* RLC environment options */
46
47 /* extern (.x) include files */
48 #include "lkw.x"           /* LKW */
49 #include "ckw.x"           /* CKW */
50 #include "kwu.x"           /* KWU */
51 #include "rgu.x"           /* RGU */
52
53 #include "rlc_utils.h"            /* RLC defines */
54 #include "rlc_dl_ul_inf.h"
55 #include "rlc_dl.h"
56
57 //UDAY
58 #ifdef L2_OPTMZ
59 uint32_t rlcAmmStaPduList[512];
60 uint32_t rlcAmmStaPduListCnt = 0;
61 #endif
62
63
64 /** @file gp_amm_dl.c
65 @brief RLC Acknowledged Mode Downlink Module
66 **/
67 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_DL)
68
69 uint32_t rlcStatusPduCnt, rlcStatusAckCnt, rlcStatusNcnt, rlcSduSndCnt;
70
71 /* local defines */
72
73 /* local externs */
74
75 /* forward references */
76 Void rlcAmmDlHndlStatusPdu ARGS ((RlcCb  *gCb,
77                                         RlcDlRbCb  *rbCb,
78                                         RlcUdxStaPdu *pStaPdu));
79
80 /* public variable declarations */
81
82 /* This structure holds all the global structs we need. */
83
84 /* private variable declarations */
85
86 #define RLC_AM_REMOVE_HDR(_gCb, _rbCb, _retx) do { \
87   if ((_retx)->yetToConst == FALSE) \
88   {\
89      Buffer    *_pduInfo; \
90      SSegMsg((_retx)->seg, (_retx)->hdrSz, &_pduInfo); \
91      ODU_PUT_MSG_BUF((_retx)->seg); \
92      (_retx)->seg = _pduInfo; \
93   }\
94   (_rbCb)->m.amDl.estHdrSz -= retx->hdrSz;\
95 } while(0)
96
97 /* private function declarations */
98
99 static Void  rlcResegRetxPdus ARGS ((RlcCb *gCb,
100                                      RlcDlRbCb *rbCb, 
101                                      RlcDatReq *rlcDatReq));
102
103 static Void rlcRemRetxPdu ARGS ((RlcCb *gCb, 
104                                  RlcDlRbCb *rbCb, 
105                                  RlcRetx *retx));
106
107 static Void rlcAmmCreateStatusPdu ARGS ((RlcCb *gCb, 
108                                          RlcDlRbCb *rbCb,
109                                          RlcDatReq *rlcDatReq));
110
111 static Void rlcAmmDlMarkPduForReTx ARGS ((RlcCb *gCb,
112                                           RlcDlRbCb *rbCb,
113                                           RlcRetx *retx));
114
115 static Void rlcAmmDlProcessSuccessfulTxPdu ARGS((RlcCb *gCb, 
116                                                  RlcDlRbCb *rbCb,
117                                                  RlcSn  sn,
118                                                  KwuDatCfmInfo **datCfm));
119
120 static Void rlcAmmDlSetTxNextAck ARGS((RlcAmDl *amDl, RlcSn sn));
121
122 static Void rlcAmmDlCheckAndStopPollTmr ARGS((RlcCb *gCb,
123                                               RlcDlRbCb *rbCb,
124                                               RlcSn mAckSn));
125
126 static Void  rlcAssembleSdus ARGS ((RlcCb *gCb,
127                                     RlcDlRbCb *rbCb, 
128                                     RlcDatReq *rlcDatReq));
129
130 static bool rlcAmmDlCheckAndSetPoll ARGS ((RlcCb *gCb,
131                                            RlcDlRbCb *rbCb, 
132                                            bool newPdu, 
133                                            MsgLen bufSz));
134
135 static Void rlcAmmCreatePdu ARGS ((RlcCb *gCb,
136                                    RlcDlRbCb *rbCb, 
137                                    RlcAmHdr *amHdr, 
138                                    RlcDlPduInfo *pduInfo,
139                                    Buffer *pdu));
140
141 static Void rlcAmmSndStaInd ARGS ((RlcCb *gCb,RlcDlRbCb *rbCb, RlcRetx *retx));
142
143 static Void rlcGetNxtRetx ARGS ((RlcCb *gCb, RlcRetx **retx));
144
145 static Void rlcConstructAmHdr ARGS ((RlcAmHdr *amHdr, 
146                                      uint8_t *hdr,
147                                      uint8_t  snLen,
148                                      uint16_t *idx));
149
150 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn ARGS ((RlcCb *gCb,
151                                                       RlcDlRbCb *rbCb, 
152                                                       RlcSn mAckSn,
153                                                       CmLList *retx,
154                                                       KwuDatCfmInfo **datCfm));
155
156 static Void rlcAmmDlMoveFrmTxtoRetxBuffer ARGS ((RlcCb *gCb,
157                                                  RlcAmDl *amDl, 
158                                                  RlcRetx **retx, 
159                                                  RlcSn sn));
160  
161 static Void rlcAmmDlCheckIsSDUDelivered ARGS((RlcCb *gCb,
162                                               RlcDlRbCb *rbCb, 
163                                               RlcSduMap *sduMap, 
164                                               KwuDatCfmInfo **datCfm));
165
166 static Void rlcAmmAddPduToRetxLst ARGS((RlcAmDl   *amDl,
167                                         RlcRetx   *retx));
168
169 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer ARGS(
170 (
171 RlcCb          *gCb,
172 RlcAmDl        *amDl,
173 RlcRetx        **retx,
174 RlcDlPduInfo   *pduInfo
175 ));
176
177 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf ARGS(
178 (
179 RlcCb          *gCb,
180 RlcDlRbCb      *rbCb,
181 RlcNackInfo    *nackSnInfo,
182 RlcRetx        **retx,
183 KwuDatCfmInfo **datCfm
184 ));
185
186 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn ARGS(
187 (
188  RlcCb          *gCb,
189  RlcDlRbCb      *rbCb,
190  RlcNackInfo    *nackSnInfo,
191  CmLList       **retxNode,
192  KwuDatCfmInfo **datCfm
193  ));
194
195 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx ARGS(
196 (
197 RlcAmDl        *amDl,
198 RlcNackInfo    *nackInfo,
199 CmLList       *retxNode,
200 RlcNackInfo    *nackSnInfo,
201 uint8_t            idx
202 ));
203
204 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn ARGS(
205 (
206 RlcCb            *gCb,
207 RlcDlRbCb        *rbCb,
208 RlcSn            sn,
209 RlcSn            mNackSn,
210 CmLList         **retxNode,
211 KwuDatCfmInfo   **datCfm
212 ));
213 /*****************************************************************************
214
215   AM Module contains the following funcitons:
216
217   -  rlcAmmQSdu 
218   -  rlcAmmProcessSdus
219      -  rlcAmmDlAssembleCntrlInfo
220      -  rlcResegRetxPdus
221      -  rlcAssembleSdus
222      -  rlcAmmDlCheckAndSetPoll
223   -  rlcAmmProcessPdus
224      -  rlcDlmHndlStaRsp
225      -  kwTriggerStatus
226      -  kwReassembleSdus
227    
228 *******************************************************************************/
229 /** @addtogroup ammode */
230 /*@{*/
231
232 /**
233  * @brief Function to send a Status Response to MAC for a dedicated logical
234  *        channel
235  *       
236  * @details
237  *    Function calculates the current bo and send a Status response for the
238  *    dedicated logical channel if the bo is non zero
239  *
240  * @param[in] gCb    RLC instance control block
241  * @param[in] rbCb   Radio Bearer control block
242  * @param[in] amDl   AM downlink control block
243  * 
244  * @return  Void
245 */
246 void rlcAmmSendDedLcBoStatus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmDl *amDl)
247 {
248    int32_t bo = rlcAmmCalculateBo(amDl);
249
250    if(bo)
251    {
252       rlcUtlSendDedLcBoStatus(gCb, rbCb, bo, amDl->estHdrSz, \
253          amDl->cntrlBo ?TRUE:FALSE,amDl->cntrlBo);
254    }
255    
256    return;
257 }
258
259 /**
260  * @brief Function to check if the pollSn is acked and stop the poll timer
261  *
262  * @param[in] gCb      RLC instance control block
263  * @param[in] rbCb     Radio Bearer control block
264  * @param[in] mAckSn   The last received ACKSN. The base modulus value should
265  *                     be passed
266  * 
267  * @return  Void
268 */
269 static Void rlcAmmDlCheckAndStopPollTmr(RlcCb *gCb,RlcDlRbCb *rbCb,RlcSn mAckSn)
270 {
271    RlcSn mPollSn;                                                   
272                                                                    
273    MODAMT(rbCb->m.amDl.pollSn, mPollSn, rbCb->m.amDl.txNextAck,rbCb->m.amDl.snModMask);      
274                                                                    
275    if (mPollSn <= mAckSn)                                        
276    {                                                               
277       if (rlcChkTmr(gCb, (PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR))    
278       {                                                            
279          rlcStopTmr(gCb, (PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);    
280       }                                                            
281    }
282
283    return;
284 }
285
286 /**
287  * @brief Function to set VT(A) and VT(MS). Calculates the VT(MS) from VT(A)
288  *
289  * @param[in,out] amDl    AM downlink control block
290  * @param[in]sn           Sequence number to be set as VT(A)
291  * 
292  * @return  Void
293 */
294 static Void rlcAmmDlSetTxNextAck(RlcAmDl *amDl,RlcSn sn)
295 {
296    amDl->txNextAck = sn;
297    
298    return;
299 }
300
301 /**
302  * @brief Function to process a successfully re-transmitted PDU/segment
303  *       
304  * @details
305  *    Checks if the SDU has been completely delivered or not. Removes the PDU
306  *    from the re-transmission buffer
307  *
308  * @param[in] gCb    RLC instance control block
309  * @param[in] rbCb   Downlink Radio Bearer control block
310  * @param[in] retx   The PDU/segment which was successfully re-transmitted
311  * 
312  * @return  Void
313 */
314 static Void rlcAmmDlProcessSuccessfulReTx
315 (
316 RlcCb            *gCb,
317 RlcDlRbCb        *rbCb,
318 RlcRetx          *retx,
319 KwuDatCfmInfo    **datCfm
320 )
321 {
322    rlcAmmDlCheckIsSDUDelivered(gCb, rbCb, &(retx->sduMap), datCfm);
323    
324    rlcRemRetxPdu(gCb, rbCb, retx);
325
326    return;
327 }
328
329 /**
330  * @brief Handler to Move the PDU from txBuf to re-transmission buffer 
331  *
332  * @details
333  *    This function is used to move the PDU from the txBuf to re-transmit buffer
334  *
335  * @param[in]RlcCb   *gCb           RLC instance control block
336  * @param[in]RlcAmDl *amDl          AM Downlink Control Block 
337  * @param[in]RlcRetx **retx         node in the reTx buffer to be moved to, allocated by
338  *                                 this function
339  * @param[in]RlcDlPduInfo *pduInfo  TX PDU which needs to be moved
340  * 
341  * @return Void
342  *            
343  */
344
345 static Void rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer
346 (
347 RlcCb          *gCb,
348 RlcAmDl        *amDl,
349 RlcRetx        **retx,
350 RlcDlPduInfo   *pduInfo
351 )
352 {
353
354    RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
355
356 #if (ERRCLASS & ERRCLS_ADD_RES)
357    if (*retx == NULLP)
358    {
359            DU_LOG("\nERROR  -->  RLC_DL : Memory allocation failed");
360            return;
361    }
362 #endif /* ERRCLASS & ERRCLS_RES */
363
364    (*retx)->seg = pduInfo->pdu;
365    (*retx)->segSz = pduInfo->pduSz;
366    /* MS_FIX for DL stall */
367    (*retx)->soEnd = (pduInfo->amHdr.so + pduInfo->pduSz - 1);
368
369    (*retx)->hdrSz = pduInfo->hdrSz;
370    (*retx)->retxCnt = 1;
371    (*retx)->yetToConst = 0;
372    (*retx)->pendingReTrans = TRUE;
373
374    /* initialize the list pointer to 0 instead of memset */
375    (*retx)->lstEnt.next = 0;
376    (*retx)->lstEnt.prev = 0;
377    /* copy the sdu maps */
378    RLC_MEM_CPY(&((*retx)->sduMap), 
379                    &pduInfo->sduMap, 
380                    sizeof(RlcSduMap));
381
382    RLC_MEM_CPY(&((*retx)->amHdr), &pduInfo->amHdr, sizeof(RlcAmHdr));
383    rlcAmmAddPduToRetxLst(amDl, (*retx));
384
385    /* Update the BO appropriately */
386    amDl->retxBo   += (*retx)->segSz;
387    amDl->estHdrSz += (*retx)->hdrSz;
388
389    gRlcStats.amRlcStats.numDLRetransPdus++;
390
391    return;
392 } /*rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer */
393
394 /**
395  * @brief Function to handle Status of Sdu byte segment for a nackSn 
396  *
397  * @details
398  *    This function is used to move the PDU from the txBuf to re-transmit buffer
399  *
400  * @param[in]RlcCb       *gCb          RLC instance control block
401  * @param[in]RlcDlRbCb   *rbCb         AM Downlink Control Block 
402  * @param[in]RlcNackInfo *nackSnInfo   Nack Information of a NACK_SN 
403  * @param[in]RlcRetx     **retx        node in the reTx buffer to be moved to, allocated by
404  *                                    this function
405  * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
406  * 
407  * @return Void
408  *            
409  */
410
411 static Void rlcAmmDlHndlStatus4SduByteSegInTxBuf
412 (
413 RlcCb          *gCb,
414 RlcDlRbCb      *rbCb,
415 RlcNackInfo    *nackSnInfo,
416 RlcRetx        **retx,
417 KwuDatCfmInfo ** datCfm
418 )
419 {
420    RlcTx    *txBuf=NULLP;
421    CmLList *lnk;
422    CmLList *nextLnk;
423
424    txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, nackSnInfo->sn);
425    if (txBuf == NULLP)
426    {
427            return;
428    }
429    lnk = txBuf->pduLst.first;
430    while(lnk)
431    {
432       RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(lnk->node);
433       RlcSn        pduSoEnd = (pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1);
434
435       /* If So of Sdu byte segment(pduInfo/seg) is < status pdu
436          soStart that means it's ACKED*/
437       if(pduSoEnd < nackSnInfo->soStart) 
438       {
439          rlcAmmDlCheckIsSDUDelivered(gCb,
440                rbCb,  
441                &(pduInfo->sduMap), 
442                datCfm);
443
444       }
445       else if (pduSoEnd <= nackSnInfo->soEnd)
446       {
447          /* Move Sdu byte segment from TX buf to retx buf*/
448          rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, 
449                &rbCb->m.amDl, 
450                retx, 
451                pduInfo);
452       }
453       else
454       {
455          lnk = lnk->next;
456          continue;
457       }
458       nextLnk = lnk->next;
459       /* Delete node from the txBuf Pdu lst */
460       cmLListDelFrm(&txBuf->pduLst, lnk);
461       RLC_FREE(gCb, pduInfo, sizeof(RlcDlPduInfo));
462       lnk = nextLnk;
463    }
464    if(!txBuf->pduLst.count)
465    {
466       /*No more Sdu byte segment are left. Hence delete txBuf*/
467       rlcUtlDelTxBuf(RLC_AMDL.txBufLst, txBuf,gCb);
468    }
469
470    return;
471 }
472
473 /**
474  * @brief Function to handle Status of Sdu byte segment for a nackSn 
475  *
476  * @details
477  *    This function is used to move the PDU from the txBuf to re-transmit buffer
478  *
479  * @param[in]RlcCb   *gCb            RLC instance control block
480  * @param[in]RlcDlRbCb *rbCb         AM Downlink Control Block 
481  * @param[in]RlcNackInfo *nackSnInfo Nack Information of a NACK_SN
482  * @param[in]RlcRetx **retx          node in the reTx buffer to be moved to, allocated by
483  *                                  this function
484  * @param[in]KwuDatCfmInfo **datCfm Ptr to datCfm
485  * 
486  * @return Void
487  *            
488  */
489 static Void rlcAmmDlUpdateTxAndReTxBufForNackSn
490 (
491 RlcCb          *gCb,
492 RlcDlRbCb      *rbCb,
493 RlcNackInfo    *nackSnInfo,
494 CmLList        **retxNode,
495 KwuDatCfmInfo **datCfm
496 )
497 {
498    RlcTx    *txBuf;
499    RlcRetx  *retx;
500
501    /* Now process the NACK_SN received. Now the NACK_SN is    */
502    /* either the first element of RETX or is in TX array      */
503    /* To remove the remaining acks from the pdu byte segments */
504
505    /* if the NACK_SN is in the transmit buffer, move it to the re-
506          transmit buffer */
507    txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, nackSnInfo->sn);
508    if (txBuf != NULLP)
509    {
510       if(nackSnInfo->isSegment)
511       {
512          /* Go through all the AMD PDUs of a particular SN
513             and check if segment is ACKED if yes then mark succesfully sent,
514             if segment is NACKed then move it to to retx lst */
515          rlcAmmDlHndlStatus4SduByteSegInTxBuf(gCb, rbCb, nackSnInfo, &retx, datCfm);
516       }
517       else
518       {
519          /*e2= 0 and e3= 0: Move complete PDU from TX buf to retx buf*/
520          rlcAmmDlMoveFrmTxtoRetxBuffer(gCb, 
521                &rbCb->m.amDl, 
522                &retx, 
523                nackSnInfo->sn);
524       } 
525
526 #if (ERRCLASS & ERRCLS_ADD_RES)
527       if(retx)
528 #endif
529       {
530               (*retxNode) = retx->lstEnt.next;
531       }
532
533       return;
534    }
535
536    /* process the pdus/segments in the re-transmit buffer with 
537       this NACK_SN */
538    while (*retxNode)
539    {
540       retx = (RlcRetx *)((*retxNode)->node);
541       if (retx->amHdr.sn != nackSnInfo->sn)
542       {
543          break;
544       }
545       if ((nackSnInfo->isSegment) &&
546             ((retx->soEnd < nackSnInfo->soStart) /*|| (retx->amHdr.so > soEnd)*/))
547       {
548          DU_LOG( "\nDEBUG  -->  RLC_DL : rlcHndlStaRsp: Handle ACK for byte segment, Its "
549                "sn = %d UEID:%d CELLID:%d",
550                nackSnInfo->sn, 
551                rbCb->rlcId.ueId,
552                rbCb->rlcId.cellId);
553          DU_LOG("\nDEBUG  -->  RLC_DL : soStart and soEnd = %d, %d, UEID:%d CELLID:%d",
554                retx->amHdr.so, retx->soEnd, 
555                rbCb->rlcId.ueId,
556                rbCb->rlcId.cellId);
557
558          (*retxNode) = (*retxNode)->next;
559          rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
560       }
561       else if((!nackSnInfo->isSegment) || (retx->soEnd <= nackSnInfo->soEnd))
562       {
563          /* This case covers the NACKED segments and also the case */
564          /* when there are segments and the entire SN is nacked.   */
565          /* This case also covers the case of nonsegmented retx PDU*/
566
567          (*retxNode) = (*retxNode)->next;
568          /* Mark the retx PDU we found for further retransmission  */
569          rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
570       }
571       else
572       { 
573          /* If we are here that means this segment and segments after this are ACKed*/
574          break;
575       }
576    } /* end of retxNode while loop*/
577    return;
578 }
579
580 /**
581  * @brief Function to get nack Sn information from nackRange index 
582  *
583  * @details
584  *    This function is used to get nack Sn information from nackRange index
585  *
586 * @param[in]RlcAmDl        *amDl,
587 * @param[in]RlcUdxStaPdu   *StaPdu,
588 * @param[in]RlcNackInfo    *nackSnInfo,
589 * @param[in]RlcRetx        *retx;
590 * @param[in]RlcSn          sn, 
591 * @param[in]uint8_t            idx
592  * 
593  * @return Void
594  *            
595  */
596 static Void RlcDlAmmGetNackSnInfoFrmNackRangeIdx
597 (
598 RlcAmDl        *amDl,
599 RlcNackInfo    *nackInfo,
600 CmLList        *retxNode,
601 RlcNackInfo    *nackSnInfo,
602 uint8_t        idx
603 )
604 {
605    RlcTx     *txBuf;
606    RlcRetx   *retx;
607    CmLList  *node;
608
609    nackSnInfo->isSegment = FALSE;
610
611    if((!nackInfo->isSegment) || (!idx && nackSnInfo->nackRange && (!nackInfo->soStart)))
612    {
613       nackSnInfo->soStart = 0;
614       nackSnInfo->soEnd = 0;
615       return;
616    }
617    txBuf = rlcUtlGetTxBuf(amDl->txBufLst, nackSnInfo->sn);
618    if(txBuf != NULLP)
619    {
620       node = txBuf->pduLst.first;
621       while(node)
622       {
623          RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(node->node);
624          uint16_t         pduSoEnd = pduInfo->amHdr.so + pduInfo->sduMap.sduSz - 1; 
625          if((!idx) && (pduInfo->amHdr.so == nackInfo->soStart))
626          {
627             nackSnInfo->isSegment = TRUE;
628             nackSnInfo->soStart = pduInfo->amHdr.so;
629             nackSnInfo->soEnd = pduSoEnd;
630             break;
631          }
632          else if((idx == nackSnInfo->nackRange - 1) && \
633                (pduSoEnd == nackInfo->soEnd))
634          {
635             nackSnInfo->isSegment = TRUE;
636             nackSnInfo->soStart = pduInfo->amHdr.so;
637             nackSnInfo->soEnd = pduSoEnd;
638             break;
639          }
640          node = node->next;
641       }
642    }
643    if(!nackSnInfo->isSegment)
644    { 
645       while (retxNode)
646       {
647          retx = (RlcRetx *)(retxNode->node);
648          if(retx->amHdr.sn != nackSnInfo->sn)
649          {
650             break;
651          }
652          if((!idx) && (retx->amHdr.so == nackInfo->soStart))
653          {
654             nackSnInfo->isSegment = TRUE;
655             nackSnInfo->soStart = retx->amHdr.so;
656             nackSnInfo->soEnd = retx->soEnd;
657             break;
658          }
659          else if((idx == nackSnInfo->nackRange - 1) && \
660                (retx->soEnd == nackInfo->soEnd))
661          {
662             nackSnInfo->isSegment = TRUE;
663             nackSnInfo->soStart = retx->amHdr.so;
664             nackSnInfo->soEnd = retx->soEnd;
665             break;
666          }
667          retxNode = retxNode->next;
668       }
669    }
670 }
671
672 /**
673  * @brief Function to update transmission buffers and send confimations to
674  *        PDCP on the reception of Status PDU
675  *
676  * @details
677  *    First processes the NACKs received
678  *    -# Removes the pdus which are acked by each of the NACK SN from the
679  *       transmission and re-transmission buffer
680  *    -# If NACKed SN in in the transmisson buffer, moves it to re-transmission
681  *       buffer
682  *    -# Removes PDU segments of the NACKed SN which have been successfully 
683  *       received by the other end. For the un-successful ones, marks them for
684  *       re-transmission
685  *    -# When PDUs/segments are removed from the buffer, indicates to upper
686  *       layer if the SDU is completely delivered
687  *    -# Removes the PDUs/segments which are acked by the ACK_SN but not by the
688  *       NACK_SNs
689  *
690  * @param[in] gCb         RLC Instance control block
691  * @param[in] rbCb        Downlink Radio Bearer control block
692  * @param[in] pStaPdu     The decoded Status Pdu
693  * 
694  * @return  Void
695 */
696 Void rlcAmmDlHndlStatusPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcUdxStaPdu *pStaPdu)
697 {
698    RlcSn      mAckSn;
699    S32       oldRetxBo;
700    CmLList   *retxNode;
701    KwuDatCfmInfo* datCfm; 
702    RlcKwuSapCb    *rlckwuSap;
703    RlcSn       mTxNext;
704
705    rlcStatusPduCnt++;
706
707    rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
708    /* store the re-transmission bo, to check if it changes due to the
709       processing of the status pdu */
710    oldRetxBo = RLC_AMDL.retxBo;
711
712    /* Allocate memory for datCfm Info */
713    RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
714
715 #if (ERRCLASS & ERRCLS_ADD_RES)
716    if (datCfm == NULLP)
717    {
718       DU_LOG("\nERROR  -->  RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
719                rbCb->rlcId.ueId,
720                rbCb->rlcId.cellId);
721       RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
722       return;
723    }
724 #endif /* ERRCLASS & ERRCLS_RES */
725
726    datCfm->numSduIds = 0;
727    datCfm->rlcId = rbCb->rlcId;
728
729    MODAMT(pStaPdu->ackSn, mAckSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
730    MODAMT(RLC_AMDL.txNext,mTxNext, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
731
732    if(mAckSn > mTxNext)
733    {
734       DU_LOG("\nERROR  -->  RLC_DL : Invalid ACK SN = %d received. Current Vta =%d"
735                "UEID:%d CELLID:%d", 
736                pStaPdu->ackSn,
737                RLC_AMDL.txNextAck,
738                rbCb->rlcId.ueId,
739                rbCb->rlcId.cellId);
740 /*      RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo)); */
741       RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
742       return;
743    }
744  
745    /* Venki - stopping the poll retx timer */
746    /*Stop PollRetx Tmr */
747    rlcAmmDlCheckAndStopPollTmr(gCb, rbCb, mAckSn);
748
749    /* Set the first node in retx list to retxNode */
750    retxNode = RLC_AMDL.retxLst.first;
751
752    /* If NACK exists in control PDU */
753    if (pStaPdu->nackCnt)
754    {
755       RlcSn   sn;
756       RlcNackInfo nackSnInfo;
757       RlcSn   mNackSn;
758       RlcSn   txNextAck;
759       RlcSn   transWinStartSn = RLC_AMDL.txNextAck; /*used to track the SN from which 
760                                            to start processing the transmission
761                                            buffer */
762       uint32_t    idx = 0;
763
764       /* if any NACKs then txNextAck should be equal to the first NACK_SN*/
765       txNextAck = pStaPdu->nackInfo[0].sn;
766
767       rlcStatusNcnt += pStaPdu->nackCnt;
768
769       /* For NACKs */
770       while (idx < pStaPdu->nackCnt)
771       {
772          nackSnInfo.isSegment = pStaPdu->nackInfo[idx].isSegment;
773          nackSnInfo.nackRange = pStaPdu->nackInfo[idx].nackRange;
774          nackSnInfo.sn = pStaPdu->nackInfo[idx].sn;
775          
776          DU_LOG("\nDEBUG  -->  RLC_DL : rlcHndlStaRsp: NACK SN = %d UEID:%d CELLID:%d",
777                   nackSnInfo.sn,
778                   rbCb->rlcId.ueId,
779                   rbCb->rlcId.cellId);
780
781          nackSnInfo.soStart = pStaPdu->nackInfo[idx].soStart;
782          nackSnInfo.soEnd   = pStaPdu->nackInfo[idx].soEnd;
783
784          /* e2 is used as a boolean indicating presence of SOStart or SOEnd */
785
786          sn = transWinStartSn;
787
788          /* move transWinStartSn to nackSnInfo.sn + 1, as the pdu's before that
789             will be removed from the buffer */
790          transWinStartSn = (nackSnInfo.sn + (nackSnInfo.nackRange ?\
791                   (nackSnInfo.nackRange - 1) : 0) + 1) & RLC_AMDL.snModMask;
792         
793         /* Clear the acked SNs from the retx list */
794          MODAMT(nackSnInfo.sn, mNackSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
795
796          if ((mNackSn > mAckSn) || (mNackSn >= mTxNext))
797          {
798             /* Erroneous NACK_SN, we should raise an error towards L3 */
799             DU_LOG("\nERROR  -->  RLC_DL : Status Pdu is not correct UEID:%d CELLID:%d",
800                      rbCb->rlcId.ueId,
801                      rbCb->rlcId.cellId);
802             RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
803             return;
804          }
805
806          /* clear all the SNs < NACK_SN from re-transmission list */   
807          rlcAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn,
808                                                  &retxNode, &datCfm);
809          
810          if(!nackSnInfo.nackRange)
811          {
812             rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo, &retxNode, &datCfm);
813             gRlcStats.amRlcStats.numRlcAmCellNackRx++;
814          }
815          else
816          {
817             uint8_t idx1 = 0;
818             /* Update issegment, soStart, soEnd ,sn  in nackSnInfo and handle
819              * nack sn*/
820             do
821             {
822                RlcDlAmmGetNackSnInfoFrmNackRangeIdx(&RLC_AMDL, &pStaPdu->nackInfo[idx],
823                                                    retxNode, &nackSnInfo, idx1);
824                
825                rlcAmmDlUpdateTxAndReTxBufForNackSn(gCb, rbCb, &nackSnInfo,
826                                                   &retxNode, &datCfm);
827                nackSnInfo.sn = ((nackSnInfo.sn + 1) & (RLC_AMDL.snModMask)); 
828                gRlcStats.amRlcStats.numRlcAmCellNackRx++;
829
830             }while((++idx1) < (nackSnInfo.nackRange));
831          }
832
833          idx++;
834       } /* End of nackCnt while loop */
835
836       /* Remove the PDUs with are further acked by the ACK_SN after taking
837          care of all the NACK_SN related acknowledgments*/
838       rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
839
840       /* Update txNextAck */
841       rlcAmmDlSetTxNextAck(&RLC_AMDL,txNextAck);
842    }
843    else
844    {
845      rlcStatusAckCnt++;
846       /* For All ACKs */
847       DU_LOG("\nDEBUG  -->  RLC_DL : rlcHndlStaRsp: Received All ACKS UEID:%d CELLID:%d",
848                rbCb->rlcId.ueId,
849                rbCb->rlcId.cellId);
850
851       /* For the remaining ACKs  after last nackSn */
852       rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb,rbCb, mAckSn, retxNode, &datCfm);
853       
854       /* update txNextAck */
855       rlcAmmDlSetTxNextAck(&RLC_AMDL, pStaPdu->ackSn); 
856    }
857
858    if(datCfm->numSduIds != 0)
859    {
860       if(datCfm->numSduIds > 1024)
861       {
862          DU_LOG("\nDEBUG  -->  RLC_DL : Sending [%u] SDU Cfms to PDCP & [%u] lost for"
863                   "UEID:%d CELLID:%d",
864                   datCfm->numSduIds, 
865                   datCfm->numSduIds-1024,
866                   rbCb->rlcId.ueId,
867                   rbCb->rlcId.cellId);
868          datCfm->numSduIds = 1024;
869       }
870       rlcSduSndCnt += datCfm->numSduIds;
871       /* Sap control block */
872       RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, datCfm);
873    }
874    else
875    {
876       RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, datCfm, sizeof(KwuDatCfmInfo));
877    }
878
879    /* Fix for memory corruption */
880    RLC_LLIST_FIRST_RETX(RLC_AMDL.retxLst, RLC_AMDL.nxtRetx);
881    /* BO update, if retransmission BO has changed. RLC_AMDL.retxBo would have
882       canged inside the above called functions */
883    if (oldRetxBo != RLC_AMDL.retxBo)
884    {
885       rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
886    }
887
888    return;
889 }
890
891 /**
892  * @brief Function to calculate the current buffer occupancy
893  *
894  * @details 
895  *    Function to calculate the current bo depending on the control, 
896  *          re-transmit, transmit bo's and the state of the transmit window. 
897  *          If the transmit window is stalled, then the transmit bo is not 
898  *          taken into account
899  *
900  * @param[in] amDl AM mode donwlink control block 
901  *
902  *  @return S16
903  *      Calculated bo
904 */
905 S32 rlcAmmCalculateBo(RlcAmDl *amDl)
906 {
907    S32 bo;
908
909    /* Make sure non of the bo's are negative */      
910    if (amDl->bo < 0) 
911    {   
912       amDl->bo = 0;                         
913    }
914    
915    if (amDl->cntrlBo < 0) 
916    {
917       amDl->cntrlBo = 0;               
918    }
919    
920    if (amDl->retxBo < 0) 
921    {
922       amDl->retxBo = 0;                 
923    }
924
925    bo = amDl->cntrlBo + amDl->retxBo;
926
927    /* if window is not stalled then add the transmit bo also */
928    if (! RLC_AM_IS_TRANS_WIN_STALLED(amDl)) 
929    {
930       bo += amDl->bo;
931    }
932    
933    return bo;
934 }
935 uint32_t kwRxSdu;
936
937 /**
938  * @brief Handler to queue the SDUs received from PDCP
939  *       
940  * @details
941  *    This function is invoked by UIM to queue the SDU received from PDCP in the
942  *    SDU queue of the corresponding RbCb. It also updates the BO and report the
943  *    same to MAC.
944  *    -  Allocate memory for and assign received buffer to the SDU
945  *    -  Add SDU in the sduQ of RlcAmDl 
946  *    -  Calculate bo with the buffer received
947  *    -  Accumulate bo with retransmission bo and control pdu's bo if available
948  *    -  Estimate the header size for the bo; Fill in StaRspInfo and send it 
949  *       to MAC
950  *
951  * @param[in] gCb     RLC Instance control block
952  * @param[in] rbCb    RB control block 
953  * @param[in] mBuf    Sdu to be queued
954  * @param[in] datReq  Ptr to the datReq sent from PDCP
955  *
956  * @return Void
957  *      -# void
958 */
959 void rlcAmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *mBuf, RlcDatReqInfo *datReq)
960 {
961    RlcSdu       *sdu;
962 #ifdef LTE_L2_MEAS
963 #ifndef L2_L3_SPLIT
964 #ifdef TENB_STATS
965    uint32_t         rlcWinSz; 
966 #endif
967 #endif
968 #endif
969
970    /* Allocate sdu */
971    RLC_ALLOC_WC(gCb,sdu, sizeof(RlcSdu)); 
972
973 #if (ERRCLASS & ERRCLS_ADD_RES)
974    if (sdu == NULLP)
975    {
976       DU_LOG("\nERROR  -->  RLC_DL : rlcAmmQSdu : Memory allocation failed UEID:%d CELLID:%d",\
977          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
978       return;
979    }
980 #endif /* ERRCLASS & ERRCLS_RES */
981
982    RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
983    /* Discard new changes starts */
984    rlcUtlGetCurrTime(&sdu->arrTime);
985    /* Discard new changes ends */
986    /* Assign values to sdu */
987    ODU_GET_MSG_LEN(mBuf, &sdu->sduSz);
988
989    sdu->mBuf = mBuf;
990    sdu->actSz = sdu->sduSz;
991    sdu->mode.am.sduId = datReq->sduId;
992    /* initialize values for AM mode to 0 */
993    sdu->mode.am.rcvdSz = 0;
994    sdu->mode.am.isSegmented = 0;
995 #ifndef RGL_SPECIFIC_CHANGES
996 #ifdef MSPD
997 {
998 uint32_t dlrate_kwu;
999 dlrate_kwu += sdu->sduSz;
1000 }
1001 #endif
1002 #endif   
1003    /* Update nxtTx to point to the added sdu if this is the first SDU in the
1004     * queue */
1005    if (RLC_AMDL.nxtTx == NULLP)
1006    {
1007       DU_LOG("\nDEBUG  -->  RLC_DL : rlcAmmQSdu: Received SDU will be transmitted next \
1008          UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1009       RLC_AMDL.nxtTx = sdu;
1010    }
1011
1012    /* Add sdu to the sdu list */
1013    cmLListAdd2Tail(&RLC_AMDL.sduQ, &sdu->lstEnt);
1014    sdu->lstEnt.node = (PTR)sdu;
1015 #ifdef LTE_L2_MEAS
1016 #ifndef L2_L3_SPLIT
1017 #ifdef TENB_STATS
1018    if (rbCb->ueCb->tenbStats)
1019    {
1020       if (RLC_AMDL.sduQ.count > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ)
1021       {
1022          rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxPktsInSduQ = RLC_AMDL.sduQ.count;
1023       }
1024       rlcWinSz = RLC_AM_TRANS_WIN_SIZE(&RLC_AMDL);
1025       if (rlcWinSz > rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz)
1026       {
1027          rbCb->ueCb->tenbStats->stats.nonPersistent.rlc.dlMaxWindowSz = rlcWinSz;
1028       }
1029    }
1030 #endif
1031 #endif
1032 #endif
1033    /* Update BO and estimate header size for the current BO */ 
1034    RLC_AMDL.bo = RLC_AMDL.bo + sdu->sduSz;
1035   if(RLC_AMDL.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1036   {
1037      RLC_AMDL.estHdrSz += 2;
1038   }
1039   else
1040   {
1041      RLC_AMDL.estHdrSz += 3;
1042   }
1043 #ifdef LTE_L2_MEAS_RLC
1044    /* Update numActUe if it is not active */
1045    if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
1046       (rbCb->ueCb->numActRb[rbCb->qci] == 0))
1047    {
1048       rbCb->ueCb->numActRb[rbCb->qci]++;
1049       gCb.rlcL2Cb.numActUe[rbCb->qci]++;
1050    }
1051 #endif
1052
1053    if(!rlcDlUtlIsReestInProgress(rbCb))
1054    {
1055       rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);
1056    }
1057
1058    return;
1059
1060
1061 /**
1062  *
1063  * @brief Private handler to construct control PDU
1064  *
1065  * @details
1066  *    This function sets the pduSz correctly after eliminating the fixed
1067  *    header sizes and the MAC header size. It copies the already prepared
1068  *    STATUS PDU to the data to be sent to MAC.
1069  *
1070  * @param[in]  gCb        RLC instance control block
1071  * @param[in]  rbCb       Downlink RB control block 
1072  * @param[in]  kwdatReq   DatReq to be sent to MAC 
1073  *
1074  *  @return Void 
1075  *
1076  */
1077 static void rlcAmmDlAssembleCntrlInfo(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1078 {
1079    RlcUdxDlSapCb   *sapCb;
1080    MsgLen         macHdrEstmt;
1081
1082    macHdrEstmt = (rbCb->m.amDl.cntrlBo < 256) ?
1083                   RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1084    /* Eliminate fixed hdr size (14bits including ACK_SN) */
1085    if (rlcDatReq->pduSz >= (RLC_CNTRL_PDU_FIXED_HDRSZ + macHdrEstmt))
1086    {
1087       /* Check the TB size whether it is sufficcient enough to fit the 
1088          status Pdu into it otherwise make arrangement such that it can fit 
1089          into in a way of possible NACks*/
1090       /* ccpu00135743 : fix for MAC Hdr size calc */ 
1091       rlcDatReq->pduSz -= macHdrEstmt;
1092       
1093       /* Create the status Pdu with the required NACKs */
1094       rlcAmmCreateStatusPdu(gCb,rbCb,rlcDatReq);
1095
1096       sapCb = RLC_GET_DL_SAPCB(gCb, rbCb);
1097       rlcDlUdxStaProhTmrStart(&(gCb->u.dlCb->udxDlSap->pst), 
1098                              sapCb->suId, &(rbCb->rlcId));
1099           
1100       /* Update number of pdus in pduInfo */
1101       rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = RLC_AMDL.mBuf; 
1102       rlcDatReq->pduInfo.numPdu++;
1103       gRlcStats.amRlcStats.numDLStaPduSent++;
1104
1105       RLC_FREE_SHRABL_BUF(gCb->u.dlCb->udxDlSap->pst.region, 
1106                          gCb->u.dlCb->udxDlSap->pst.pool,
1107                          RLC_AMDL.pStaPdu,
1108                          sizeof(RlcUdxDlStaPdu));
1109
1110       RLC_AMDL.pStaPdu = NULLP;
1111       RLC_AMDL.mBuf = NULLP;
1112       gRlcStats.amRlcStats.numDLStaPduSent++;
1113    }
1114
1115    return;
1116 }
1117
1118 /**
1119  * @brief Handler to form the PDUs with the size indicated by MAC
1120  *
1121  * @details
1122  *    This function is invoked by UTL with the PDU size indicated by 
1123  *    MAC (after eliminating MAC header size). It assembles control 
1124  *    Info / data (New SDUs / Retx PDUs), check if polling needs to be 
1125  *    set for the data PDU and returns PDU(s) and updated BO with 
1126  *    estimated header size to be sent to MAC.
1127  *
1128  *    - Check if the control BO is available and call rlcAssembleCntrlInfo 
1129  *      to assemble control Information
1130  *    - Check if the pdu size is available to form PDUs from retransmission 
1131  *      buffer and call rlcResegRetxPdus
1132  *    - Check if the pdu size is available and assemble SDUs from sduQ 
1133  *      if exist, using rlcAssembleSdus
1134  *    - PDU Info and bo are filled in and then sent to MAC from the 
1135  *      utility function
1136  *
1137  * @param[in]  gCb          RLC instance control block
1138  * @param[in]  rbCb         RB control block 
1139  * @param[in]  kwdatReq     DatReq to be sent to MAC 
1140  * @param[in]  fillCtrlPdu  Indicates whether cntrl PDU to be filled or not 
1141  *
1142  * @return Void
1143  *
1144  */
1145 void rlcAmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq, bool fillCtrlPdu)
1146 {
1147    /* Assemble control information. fillCtrlPdu parameter check is added for CA
1148     * It is used to force cntrl Pdu scheduling on PCell. for Non CA case this
1149     * flag will always be TRUE. In CA case, for PCELL it is TRUE and for SCEll
1150     * it is FALSE */ 
1151
1152    if ((RLC_AMDL.cntrlBo != 0) 
1153 #ifdef LTE_ADV
1154         && (fillCtrlPdu)
1155 #endif
1156                                )
1157    {
1158       rlcDatReq->boRep.staPduPrsnt = TRUE;
1159       rlcDatReq->boRep.staPduBo = RLC_AMDL.cntrlBo;
1160
1161       if (RLC_AMDL.pStaPdu != NULLP)
1162       {
1163          rlcAmmDlAssembleCntrlInfo (gCb, rbCb, rlcDatReq);
1164       }
1165       else
1166       {
1167          DU_LOG("\nERROR  -->  RLC_DL : rlcAmmProcessSdus: Miscomputation of control Bo. \
1168             UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1169       }
1170       RLC_AMDL.cntrlBo = 0;
1171    }   
1172
1173    /* Retransmit PDUs /portions of PDUs available in retxLst */
1174    if ((rlcDatReq->pduSz > 0) && (RLC_AMDL.nxtRetx != NULLP))
1175    {
1176       rlcResegRetxPdus (gCb,rbCb, rlcDatReq);
1177    }
1178
1179    /* Assemble SDUs to form new PDUs */ 
1180    if ((rlcDatReq->pduSz > 0) && (RLC_AMDL.nxtTx != 0))
1181    {
1182       rlcAssembleSdus(gCb,rbCb, rlcDatReq); 
1183    }
1184   
1185    if (RLC_AMDL.nxtRetx != NULLP)
1186    {
1187       rlcDatReq->boRep.oldestSduArrTime = RLC_AMDL.nxtRetx->sduMap.sdu->arrTime;
1188    }
1189    else if (RLC_AMDL.nxtTx != NULLP)
1190    {
1191       rlcDatReq->boRep.oldestSduArrTime = RLC_AMDL.nxtTx->arrTime;
1192    }
1193    /* Accumulate bo */
1194    rlcDatReq->boRep.bo = rlcAmmCalculateBo(&RLC_AMDL);
1195    rlcDatReq->boRep.staPduBo = RLC_AMDL.cntrlBo;
1196
1197    /* Hdr estimation is moved to kwAmmCreatePDu */
1198    rlcDatReq->boRep.estHdrSz = RLC_AMDL.estHdrSz;
1199
1200    if(rlcDatReq->pduSz > 0)
1201    {
1202       gRlcStats.amRlcStats.numDLBytesUnused += rlcDatReq->pduSz;
1203    }
1204    return;
1205
1206
1207 /**
1208  * @brief Private handler split a PDU/segment into two
1209  *
1210  * @details
1211  *    Its a private function called by kwResegRetxPdu to split a segment
1212  *    or a retransmit PDU into two segments splitting at the passed size.
1213  *    This function is called only for those PDUs that dont have any LIs.
1214  *
1215  * @param[in]     gCb    RLC instance control block
1216  * @param[in]     rbCb   RB control block 
1217  * @param[in,out] crnt   The PDU to be split, first part of split pdu remians
1218  *                       in this
1219  * @param[out]    next   The second part of the split pdu
1220  * @param[in]     size   The size witin crnt, at which to split   
1221  *
1222  * @return  Void
1223  *
1224  */
1225 static void rlcSplitPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcRetx *crnt, RlcRetx *next, uint16_t size)
1226 {
1227    uint8_t        si;
1228    RlcAmDl        *amDl = &RLC_AMDL;
1229
1230    /* Set the SN for the new segment */
1231    next->amHdr.sn = crnt->amHdr.sn;
1232
1233    /* Set the protocol specific fields appropriately */
1234    si = crnt->amHdr.si;
1235    crnt->amHdr.si = si | RLC_SI_FIRST_SEG;
1236    next->amHdr.si = si | RLC_SI_LAST_SEG;
1237    
1238    crnt->amHdr.p   = 0;
1239
1240    /* Update seg size */
1241    next->segSz = crnt->segSz - size;
1242    crnt->segSz = size;
1243
1244    /* Set the SO fields appropriately */
1245    /* MS_FIX for DL stall */
1246    next->soEnd = crnt->soEnd;
1247
1248    /* Set the SO fields appropriately */
1249    /* SO of next will be after the end of current */
1250    next->amHdr.so = crnt->amHdr.so + crnt->segSz;
1251    /* SO End of current will be one less than the start of next */
1252    crnt->soEnd = next->amHdr.so - 1;
1253    
1254    /* intialize the other fields in the amHdr of next to 0 */
1255    next->amHdr.p = 0;
1256    next->amHdr.dc = 0;
1257    
1258    /* This macro is called for No LI case - one SDU */
1259    /* Update the size of SDU in each node's sduMap  */
1260    next->sduMap.sdu = crnt->sduMap.sdu;
1261    crnt->sduMap.sduSz = crnt->segSz;
1262    next->sduMap.sduSz = next->segSz;
1263
1264    /* Segment the payload into two parts based on the size passed */
1265    ODU_SEGMENT_MSG(crnt->seg, size, &next->seg);
1266    next->retxCnt     = crnt->retxCnt;
1267    next->yetToConst  = TRUE;
1268    next->pendingReTrans    = crnt->pendingReTrans;
1269
1270    /* Compute the header size and update the BO appropriately */
1271    if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1272    {
1273       next->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1274       if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1275       {
1276          crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1277       }
1278       else
1279       {
1280          crnt->hdrSz = RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1281       }
1282    }
1283    else
1284    {
1285       next->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1286       if(crnt->amHdr.si == RLC_SI_FIRST_SEG)
1287       {
1288          crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1289       }
1290       else
1291       {
1292          crnt->hdrSz = RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1293       }
1294    }
1295
1296    /* Add the next to the retx list */
1297    RLC_AMDL.retxLst.crnt = &crnt->lstEnt;
1298    CM_LLIST_INS_AFT_CRNT(RLC_AMDL.retxLst, next); 
1299    RLC_AMDL.nxtRetx = next;
1300    amDl->estHdrSz += next->hdrSz;
1301    
1302    return;
1303 }
1304
1305 /**
1306  * @brief Private handler to retransmit PDUs or PDU segments
1307  *
1308  * @details
1309  *    Its a private function called by kwProcessSdus, to create the 
1310  *    PDUs / its segments from the retransmission buffer available in RbCb.
1311  *       
1312  *    - Eliminate the fixed header size and MAC header size while 
1313  *      forming PDUs/segments
1314  *    - While pdusize is available and retxBuf has data (pdu or portion 
1315  *      of pdu) to be sent, form the pdu as it is if it matches with the 
1316  *      pdusize else segment the PDUs/portion of PDUs
1317  *    - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit as 
1318  *      required 
1319  *    - Concatenate data and header info and fill pduInfo 
1320  *    - Update retxCnt and send indication to PDCP if it reaches maxRetx 
1321  *      threshold
1322  *
1323  * @param[in]  gCb       RLC instance control block
1324  * @param[in]  rbCb      RB control block
1325  * @param[in]  kwdatReq  DatReq to be sent to MAC 
1326  *
1327  * @return  Void
1328  *
1329  */
1330 static void rlcResegRetxPdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1331 {
1332    RlcAmDl   *amDl;
1333    RlcRetx   *retx;
1334    uint8_t   hdr[RLC_MAX_HDRSZ];
1335    uint16_t  idx; 
1336    Buffer   *pdu;
1337    MsgLen   pduSz; 
1338 #ifdef LTE_L2_MEAS
1339    uint16_     sduIdx;
1340    RlcL2MeasTb *l2MeasTb;
1341    RlclchInfo  *lchInfo;
1342    uint8_t     numSdus;
1343 #endif
1344
1345    amDl  = &RLC_AMDL;
1346 #ifdef LTE_L2_MEAS
1347    /* TODO : This shoould be taken care in new Trasmissions */
1348    /* This lchInfo should be retrieved there */
1349    l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1350    if (l2MeasTb == NULLP)
1351    {
1352       return;
1353    }
1354    /* TODO : This lcid needs to be searched in case of normal Tx */
1355    /* In retx here, its fine as this will be higher priority */
1356    lchInfo = &l2MeasTb->lchInfo[l2MeasTb->numLchInfo];
1357    if (l2MeasTb->numLchInfo >= RLC_MAX_ACTV_DRB)
1358    {
1359       return;
1360    }
1361    l2MeasTb->numLchInfo++;
1362    lchInfo->lcId = rbCb->lch.lChId;
1363    lchInfo->numSdus = 0;
1364 #endif
1365
1366    while ((rlcDatReq->pduSz > 0) && (amDl->nxtRetx != NULLP)&&
1367           (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU))
1368    {
1369       uint16_t tmpSz;
1370       
1371       retx = amDl->nxtRetx;
1372       /* kw003.201 : Add header size to seg size to determine if the      */
1373       /*             the segment can be completed within the allocation   */
1374       /* kw003.201 - Eliminate MAC Header Size based on bites needed      */
1375       tmpSz = RLC_MIN((retx->segSz + retx->hdrSz), rlcDatReq->pduSz);
1376       pduSz = (retx->segSz + retx->hdrSz);
1377       /* 5GNR_RLC_DL : length field in 5GNR MAC Hdr is 8/16 btis*/
1378       rlcDatReq->pduSz -= (tmpSz < 255) ?  RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1379
1380       /* kw003.201 - We should have at least one more than basic header */
1381       if (rlcDatReq->pduSz <= retx->hdrSz)
1382       {
1383          return;
1384       }
1385       rlcGetNxtRetx(gCb, &(amDl->nxtRetx));
1386
1387       /* Send retx buf without segmentation */
1388       if (rlcDatReq->pduSz >= pduSz)
1389       {
1390          uint8_t pollBit;
1391          
1392          DU_LOG("\nINFO  -->  RLC_DL : rlcResegRetxPdus: Send retx buf without segmentation "
1393             "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1394
1395          if (retx->yetToConst)
1396          {
1397             /* Construct hdr with the available hdr values */ 
1398             rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1399             /* Add header to the pdu/segment */
1400             ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1401             retx->yetToConst = FALSE;
1402          } 
1403
1404          /* kw003.201 - Check if poll bit needs to be set. Retx size does */
1405          /* not affect the poll bit so it is being passed as zero         */ 
1406          pollBit = rlcAmmDlCheckAndSetPoll(gCb,rbCb, FALSE, 0);
1407          RLC_UPD_POLL_BIT(gCb, retx, pollBit);
1408
1409          rlcDatReq->pduSz  -= pduSz;
1410          RLC_AMDL.estHdrSz    -= retx->hdrSz;
1411 #ifdef LTE_L2_MEAS   
1412
1413          if (rbCb->rlcId.rbType == CM_LTE_DRB)
1414          {
1415             numSdus = 0;
1416             for (sduIdx = lchInfo->numSdus ; 
1417                   ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX)) ; 
1418                   sduIdx++, numSdus++)
1419             {
1420                lchInfo->sduInfo[sduIdx].arvlTime = retx->sduMap[numSdus].sdu->arrTime;
1421                lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE; /* TODO : for later use */
1422             }
1423             lchInfo->numSdus += numSdus;
1424          }
1425 #endif
1426       }
1427       else
1428       {
1429          RlcRetx *tNode;
1430          
1431          /* Segment this pdu / portion of pdu. Insert this segment into */
1432          /* retxLst and update offset                                   */
1433          DU_LOG("\nINFO  -->  RLC_DL : rlcResegRetxPdus: Segment retx buf UEID:%d CELLID:%d",
1434             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1435
1436          /* Eliminate fixed header size if the pdu is segmented for the */
1437          /* first time                                                  */
1438          if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1439          {
1440             if(retx->amHdr.si < RLC_SI_LAST_SEG)
1441             {
1442                rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITHOUT_SO_HDRSZ;
1443             }
1444             else
1445             {
1446                rlcDatReq->pduSz -= RLC_AM_SEG_12BIT_SN_WITH_SO_HDRSZ;
1447             }
1448          }
1449          else
1450          {
1451             if(retx->amHdr.si < RLC_SI_LAST_SEG)
1452             {
1453                rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITHOUT_SO_HDRSZ;
1454             }
1455             else
1456             {
1457                rlcDatReq->pduSz -= RLC_AM_SEG_18BIT_SN_WITH_SO_HDRSZ;
1458             }
1459          }
1460          if (rlcDatReq->pduSz <= 0)
1461          {
1462             return;
1463          }
1464
1465          /* Allocate memory for tracking a new segment */
1466          RLC_ALLOC_WC(gCb,tNode, sizeof(RlcRetx)); 
1467 #if (ERRCLASS & ERRCLS_ADD_RES)
1468          if (tNode == NULLP)
1469          {
1470             DU_LOG("\nERROR  -->  RLC_DL : rlcResegRetxPdus: Memory allocation failed UEID:%d CELLID:%d",
1471                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1472             return;
1473          }
1474 #endif /* ERRCLASS & ERRCLS_RES */
1475
1476          /* initialize the list pointer to 0 instead of memset */
1477          tNode->lstEnt.next = 0;
1478          tNode->lstEnt.prev = 0;
1479          
1480          /* Segment header and data */
1481          RLC_AM_REMOVE_HDR(gCb, rbCb, retx);
1482
1483          /* kw003.201 - Split the payload and update other fields */
1484          rlcSplitPdu(gCb,rbCb, retx, tNode, rlcDatReq->pduSz); 
1485
1486 #ifdef LTE_L2_MEAS
1487          numSdus = 0;
1488          /* ccpu00143043 */
1489          sduIdx = lchInfo->numSdus;
1490          for (numSdus = 0, sduIdx = lchInfo->numSdus; 
1491               ((numSdus < retx->numSdu) && (sduIdx < RLC_L2MEAS_SDUIDX));
1492               numSdus++, sduIdx++)
1493          {
1494             lchInfo->sduInfo[sduIdx].arvlTime = 
1495                   retx->sduMap[numSdus].sdu->arrTime;
1496             lchInfo->sduInfo[sduIdx].isRetxPdu = TRUE;
1497          }
1498          lchInfo->numSdus = sduIdx;
1499          if ((retx->amHdr.lsf == 0) && (lchInfo->numSdus > 0))
1500          {
1501             lchInfo->numSdus--;
1502          }
1503 #endif
1504          /* Construct hdr with the available hdr values */
1505          rlcConstructAmHdr(&retx->amHdr, hdr, amDl->snLen, &idx);
1506          ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx + 1, retx->seg);
1507
1508          retx->hdrSz = idx + 1;
1509
1510          /* Poll bit need not be set for this seg, since its second  */
1511          /* half remains in retxLst                                  */
1512          RLC_UPD_POLL_BIT(gCb, retx, FALSE);
1513          retx->yetToConst = FALSE;
1514          rlcDatReq->pduSz = 0; 
1515       }
1516
1517       rlcCpyMsg(gCb,retx->seg, &pdu);
1518
1519       /* Update pduInfo */
1520       rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu;
1521       rlcDatReq->pduInfo.numPdu++;
1522       /* kw005.201 ccpu00117318, updating the statistics */
1523       gCb->genSts.pdusRetx += 1;
1524       gRlcStats.amRlcStats.numRlcAmCellRetxPdu++;
1525       retx->soEnd = retx->amHdr.so + retx->segSz - 1;
1526       retx->pendingReTrans    = FALSE;
1527       amDl->retxBo -= retx->segSz;
1528    }
1529 #ifndef ALIGN_64BIT
1530    DU_LOG("\nINFO  -->  RLC_DL : rlcResegRetxPdus: retxBo after resegmentation = %ld"
1531       "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1532 #else
1533    DU_LOG("\nINFO  -->  RLC_DL : rlcResegRetxPdus: retxBo after resegmentation = %d "
1534       "UEID:%d CELLID:%d", amDl->retxBo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1535 #endif
1536
1537    return;
1538 }
1539
1540
1541 /**
1542  * @brief Private handler to assemble SDUs to form new data PDU(s)
1543  *
1544  * @details
1545  *    Its a private function called by kwProcessSdus, to create the new data 
1546  *    PDUs from the SDU queue of RbCb.
1547  *
1548  *    - While pdusize is available, segment/concatenate SDUs or else if it
1549  *      matches the pdu size form PDUs accordingly.
1550  *    - RLC header and MAC header size are eliminated while forming the PDUs
1551  *    - Call rlcAmmDlCheckAndSetPoll function to check and set the poll bit 
1552  *      as required 
1553  *    - Concatenate data and header info and fill pduInfo  
1554  *
1555  * @param[in]  rbCb     RB control block
1556  * @param[in]  kwdatReq DatReq to be sent to MAC 
1557  *
1558  * @return  Void 
1559  *
1560  */
1561 static void rlcAssembleSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
1562 {
1563    Buffer          *pdu         = NULLP;
1564    MsgLen          macGrntSz    = rlcDatReq->pduSz;
1565    RlcAmDl          *amDl        = &RLC_AMDL;
1566    RlcSdu           *sdu         = amDl->nxtTx;
1567    RlcSduMap        sduMap;
1568    bool            nxtTxUpd     = FALSE;
1569    KwuDiscSduInfo  *discSduInfo = NULLP;
1570    RlcKwuSapCb* rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
1571 #ifdef LTE_L2_MEAS
1572    RlcContSduLst     contSduLst;  /*Contained sduLst */
1573    int32_t           dataVol    = amDl->bo;
1574    uint32_t          *totMacGrant = &rlcDatReq->totMacGrant;
1575    RlcL2MeasDlIpTh   *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
1576    uint8_t           *sduIdx    = &dlIpThPut->lastSduIdx;
1577    bool             newIdx;
1578    bool             isSduSegmented;
1579    int32_t          oldBo;
1580    RlclchInfo        lchInfo;
1581    RlclchInfo        *dstLchInfo;
1582    uint32_t          segSduCnt = 0;
1583    uint32_t          lchIdx;
1584    uint32_t          numSdus = 0;
1585    uint32_t          currSduIdx = 0;
1586    RlcL2MeasTb       *l2MeasTb;
1587 #endif
1588    /* Discard new changes starts */
1589    Ticks                timeDiff = 0;
1590    Ticks                curTime  = 0;
1591    uint8_t              numNewPdu = 0;
1592    RlcTx                 *txBuf = NULLP;
1593    /* Discard new changes ends */
1594    volatile uint32_t    startTime = 0;
1595    uint32_t             hdrEstmt;
1596    uint32_t             fixedHdrSz;
1597    uint32_t             pduSz;
1598    RlcAmHdr              *amHdr = NULLP;
1599    RlcDlPduInfo          *pduInfo = NULLP;
1600
1601 #ifdef LTE_L2_MEAS   
1602    contSduLst.numSdus = 0; 
1603    contSduLst.lcId = rbCb->lch.lChId;
1604    oldBo = amDl->bo;
1605    lchInfo.lcId = rbCb->lch.lChId;
1606    lchInfo.numSdus = 0;
1607 #endif
1608    /* Discard new changes starts */
1609    /* Allocate memory for discSdu Info */
1610    RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region,
1611                               rlckwuSap->pst.pool,
1612                               discSduInfo, 
1613                               sizeof(KwuDiscSduInfo));
1614
1615 #if (ERRCLASS & ERRCLS_ADD_RES)
1616    if (discSduInfo == NULLP)
1617    {
1618       DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1619          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1620       return;
1621    }
1622 #endif /* ERRCLASS & ERRCLS_RES */
1623
1624    discSduInfo->numSduIds = 0;
1625    discSduInfo->rlcId = rbCb->rlcId;
1626
1627    rlcUtlGetCurrTime(&curTime);
1628    amDl->sduQ.crnt =  &sdu->lstEnt;
1629    /* Eliminate fixed header size */
1630    if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1631    {
1632       fixedHdrSz   = RLC_AM_PDU_12BIT_SN_HDRSZ;
1633    }
1634    else
1635    {
1636       fixedHdrSz   = RLC_AM_PDU_18BIT_SN_HDRSZ;
1637    }
1638
1639    while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1640           (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU) && 
1641           (numNewPdu < RLC_MAX_NEW_DL_PDU))
1642    {
1643 #ifdef LTE_L2_MEAS   
1644       isSduSegmented = sdu->mode.am.isSegmented;
1645 #endif
1646       /* Discard new changes starts */
1647       if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1648             (rbCb->rlcId.rbType == CM_LTE_DRB))
1649       {
1650          timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime); 
1651          if (timeDiff > rbCb->discTmrInt)
1652          {
1653             CmLList* nxtNode;
1654             /*starting Task*/
1655             SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1656 #ifdef LTE_L2_MEAS 
1657             RLC_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1658             /* TODO need to send disc cfm to pdcp */
1659 #endif
1660             /* Update bo for boReport */
1661             amDl->bo -= sdu->sduSz;
1662
1663             /* Get next sdu for assembly */
1664             nxtNode = sdu->lstEnt.next;
1665
1666             /* store the info for sending it to PDCP */
1667             if(discSduInfo->numSduIds > 500)
1668             {
1669                DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleSdus: This is a big error, we shouldn't be here"
1670                   "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1671                break;
1672             }
1673
1674             discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1675             discSduInfo->numSduIds++;
1676
1677             cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1678
1679             rlcUtlAddSduToBeFreedQueue(gCb, sdu);
1680             rlcUtlRaiseDlCleanupEvent(gCb);
1681
1682             /* We need to restore the crnt in the linked list which
1683              * would have become NULL in the DelFrm above */
1684             amDl->sduQ.crnt = nxtNode;
1685
1686             if(nxtNode)
1687                sdu = (RlcSdu*)nxtNode->node;
1688             else
1689                sdu = NULLP;
1690
1691             /*stopping Task*/
1692             ODU_STOP_TASK(startTime, PID_RLC_AMM_DISC_SDUS);
1693             continue;
1694          }
1695       }
1696       nxtTxUpd = FALSE;
1697
1698 #ifdef LTE_L2_MEAS
1699       newIdx = FALSE;
1700 #endif
1701       /** Check for window stall when you are creating a new PDU */
1702       if (RLC_AM_IS_TRANS_WIN_STALLED(amDl))
1703       {
1704          DU_LOG("\nINFO  -->  RLC_DL : Window stalled  \n");
1705          gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1706          break;
1707       }
1708
1709       hdrEstmt = fixedHdrSz; 
1710
1711       if (sdu->mode.am.isSegmented)
1712       {
1713          /* Adding two byte for SO */
1714          hdrEstmt += 2;
1715       } 
1716       /* Eliminate MAC header */
1717       pduSz = RLC_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1718       hdrEstmt += (pduSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1719
1720       macGrntSz -= hdrEstmt;
1721       /* Check for PDU Size is large enough */
1722       if(macGrntSz <= 0)
1723       {
1724          break;
1725       }
1726
1727       /* Dont create new txBuf for segmented SDU */
1728       if (!sdu->mode.am.isSegmented)
1729       {
1730          /* Update txBuf */
1731          RLC_ALLOC_WC(gCb,txBuf, sizeof(RlcTx));
1732
1733          cmLListInit(&txBuf->pduLst);
1734
1735 #if (ERRCLASS & ERRCLS_ADD_RES)
1736          if (txBuf == NULLP)
1737          {
1738             uint32_t avblMem = 0;
1739             SRegInfoShow(gCb->init.region, &avblMem);
1740             DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1741                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1742             return;
1743          }
1744 #endif /* ERRCLASS & ERRCLS_RES */
1745
1746          rlcUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
1747       }
1748       else
1749       {
1750          txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
1751       }
1752
1753       RLC_ALLOC_WC(gCb,pduInfo, sizeof(RlcDlPduInfo));
1754 #if (ERRCLASS & ERRCLS_ADD_RES)
1755       if (pduInfo == NULLP)
1756       {
1757          uint32_t avblMem = 0;
1758          SRegInfoShow(gCb->init.region, &avblMem);
1759          DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1760             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1761          return;
1762       }
1763 #endif /* ERRCLASS & ERRCLS_RES */
1764
1765       /*Initialize DL segment structure */
1766       pduInfo->lstEnt.next = NULLP;
1767       pduInfo->lstEnt.prev = NULLP;
1768       pduInfo->lstEnt.node = NULLP;
1769
1770       pduInfo->pdu = NULLP;
1771       pduInfo->amHdr.dc = 0;
1772       pduInfo->amHdr.p = 0;
1773       pduInfo->amHdr.si = 0;
1774       pduInfo->amHdr.so = 0;
1775
1776       pduInfo->amHdr.sn = amDl->txNext;
1777
1778       /* No Segmentation scenario :
1779        *  If SDU size is less than or equal to the requested PDU size
1780        * - Allocate memory and copy SDU into it.
1781        * -# Update BO
1782        * -# Remove SDU from the Queue.
1783        */
1784       if (macGrntSz >= sdu->sduSz)
1785       {
1786          pdu = sdu->mBuf;     
1787          sdu->mBuf = NULLP; 
1788          /* Update Framing Info */
1789          if (sdu->mode.am.isSegmented) 
1790          {
1791             /*5GNR RLC_DL : SN should be same for all segment of a SDU*/
1792             pduInfo->amHdr.sn = sdu->mode.am.sn;
1793             pduInfo->amHdr.si = RLC_SI_LAST_SEG; /* binary 10 */
1794             pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1795             sdu->mode.am.isSegmented = FALSE;
1796
1797             gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1798          }
1799          else
1800          {
1801             gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1802          }
1803          amHdr          = &pduInfo->amHdr; 
1804          /* Create PDU with hdr and data */
1805          rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1806
1807 #ifdef LTE_L2_MEAS_RLC
1808          rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, TRUE);
1809 #endif /*  LTE_L2_MEAS */
1810
1811          /* kw005.201 ccpu00117318, updating the statistics */
1812          rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
1813 #ifdef LTE_L2_MEAS
1814          if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
1815          {
1816             if(isSduSegmented)
1817             {
1818                *sduIdx    = dlIpThPut->lastSduIdx;
1819             }
1820             else
1821             {
1822                RLC_GETSDUIDX(*sduIdx);
1823                newIdx = TRUE;
1824             }
1825             rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1826             rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
1827                   sdu->mode.am.sduId, newIdx);
1828             /* Update the arrival time for each SDU */
1829             if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
1830             {
1831                lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
1832                lchInfo.numSdus++;
1833             }
1834          }
1835 #endif
1836          sduMap.sduSz    = sdu->sduSz;
1837       }
1838       else 
1839       {
1840          /* Segmentation
1841           * Allocate buffer for next PDU
1842           * Remove the segmented portion from SDUQ 
1843           * Calculate the hdr with LI for SDU */
1844
1845          Buffer  *remSeg = NULLP;
1846
1847 #ifdef LTE_L2_MEAS
1848          if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
1849                RLC_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) || 
1850                RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
1851          {
1852             /* If actual size of the sdu is equal to msgLen
1853              * then it is first segment of the SDU */
1854             if(sdu->actSz == sdu->sduSz)
1855             {
1856                RLC_GETSDUIDX(*sduIdx);
1857                newIdx = TRUE;
1858             }
1859             else
1860             {
1861                *sduIdx    = dlIpThPut->lastSduIdx;
1862             }
1863             rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1864             rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
1865                   sdu->mode.am.sduId, newIdx);
1866             if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
1867             {
1868                /* If actual size of the sdu is equal to msgLen
1869                 * then it is first segment of the SDU */
1870                if(sdu->actSz == sdu->sduSz)
1871                {
1872                   segSduCnt++;
1873                }
1874             }
1875          }
1876 #endif
1877
1878          /* Segment the SDU to the size of the PDU and update header Info */
1879          ODU_SEGMENT_MSG(sdu->mBuf, macGrntSz, &remSeg);
1880          pdu = sdu->mBuf;      
1881          sdu->mBuf = remSeg;
1882
1883          /* Update SI and SN */
1884          if (sdu->mode.am.isSegmented) 
1885          {
1886             /*5GNR RLC_DL : SN should be same for all segment of a SDU.
1887              * Sdu was already segmented and segmenting again*/
1888             pduInfo->amHdr.sn = sdu->mode.am.sn;
1889             pduInfo->amHdr.si = RLC_SI_MID_SEG; /* binary 11 */
1890             pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1891          }
1892          else
1893          {
1894             /*5GNR RLC_DL : This means it is the first*/
1895             pduInfo->amHdr.si = RLC_SI_FIRST_SEG; /* binary 01 */
1896             /*5GNR_RLC_DL : Store SN so that in sub-seqent SDU segments will use this SN*/
1897             sdu->mode.am.sn = pduInfo->amHdr.sn;
1898             pduInfo->amHdr.so = 0;
1899
1900          }
1901
1902          amHdr = &pduInfo->amHdr; 
1903          /* Create PDU with hdr and data */
1904          rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1905
1906          sdu->mode.am.isSegmented = TRUE;
1907          sdu->sduSz -= macGrntSz;
1908          sduMap.sduSz = macGrntSz;
1909
1910 #ifdef LTE_L2_MEAS_RLC
1911          rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, FALSE);
1912 #endif /*  LTE_L2_MEAS */
1913
1914          amDl->nxtTx = sdu;
1915          nxtTxUpd    = TRUE;
1916       }
1917
1918       /* Update bo for boReport */
1919       amDl->bo -= sduMap.sduSz;
1920
1921       sduMap.sdu = sdu;
1922
1923       /* Update pduInfo */
1924       rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu; 
1925       rlcDatReq->pduInfo.numPdu++;
1926       numNewPdu++;
1927       /* kw005.201 ccpu00117318, updating the statistics */
1928       gCb->genSts.pdusSent++;
1929       gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
1930       /* Update the RLC Tx buffer with the new PDU info */
1931       RLC_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(RlcSduMap));
1932       pdu = NULLP;
1933
1934       macGrntSz -= sduMap.sduSz;
1935       /* Get next sdu for assembly */
1936       RLC_LLIST_NEXT_SDU(amDl->sduQ, sdu);
1937
1938    } /*End of pduSz loop */
1939
1940    rlcDatReq->pduSz = macGrntSz;
1941    /* Updating nxtTx to sdu in the Q */
1942    if (!nxtTxUpd)
1943       amDl->nxtTx = sdu;
1944
1945 #ifdef LTE_L2_MEAS
1946    if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && 
1947          (rbCb->rlcId.rbType == CM_LTE_DRB))
1948    {
1949       numSdus = 0;
1950       currSduIdx = 0;
1951       l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1952       rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
1953       if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
1954       {
1955          for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
1956                   && (lchIdx < RLC_MAX_ACTV_DRB )); lchIdx++)
1957          {
1958             if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
1959             {
1960                /* Lch Info already added in Retx procedure */
1961                break;
1962             }
1963          }
1964          if (lchIdx < RLC_MAX_ACTV_DRB)
1965          {
1966             if (lchIdx == l2MeasTb->numLchInfo)
1967             {
1968                l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
1969                l2MeasTb->lchInfo[lchIdx].numSdus = 0;
1970                l2MeasTb->numLchInfo++;
1971             }
1972             dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
1973             currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
1974             while ((numSdus < lchInfo.numSdus) && (currSduIdx < RLC_L2MEAS_SDUIDX)) 
1975             {
1976                dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
1977                dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
1978                numSdus++;
1979                currSduIdx++;
1980             }
1981             l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
1982          }
1983       }
1984       /* Fix Klock warning */
1985       if(l2MeasTb != NULLP)
1986       {
1987          l2MeasTb->txSegSduCnt += segSduCnt;
1988       }
1989    }
1990    *totMacGrant -= (oldBo - amDl->bo);
1991 #endif
1992
1993    if(discSduInfo->numSduIds != 0)
1994    {
1995       /* Sap control block */
1996       RlcUiKwuDiscSduCfm(&rlckwuSap->pst, rlckwuSap->suId, discSduInfo);
1997    }
1998    else
1999    {
2000       RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2001    }
2002
2003    DU_LOG("\nDEBUG  -->  RLC_DL : rlcAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2004       amDl->bo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2005    return;
2006 }
2007
2008 /**
2009  * @brief Private handler to check if the poll bit needs to be set for data PDU
2010  *
2011  * @details
2012  *    Its a private function called by kwProcessSdus, to checks if the 
2013  *    polling bit needs to be set for any RLC data PDU and updates the 
2014  *    same.
2015  *    - For the new PDUs, if the counters exceed the configured 
2016  *      pduWoPoll/byteWoPoll values, return poll bit.
2017  *    - For the PDUs/portion of PDUs, if the SDU list / retxBuf is 
2018  *      empty, return poll bit.
2019  *    - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr 
2020  *
2021  * @param[in]  rCb      RLC instance control block
2022  * @param[in]  rbCb     RB control block 
2023  * @param[in]  newPdu   Flag to indicate if its a new AMD PDU. 
2024  * @param[in]  bufSz    Length of the PDU
2025  *
2026  * @return  Bool 
2027  *      -# 1 - To set the poll bit
2028  *      -# 0 - Poll bit is not set
2029  *
2030  */
2031 static bool rlcAmmDlCheckAndSetPoll(RlcCb *gCb, RlcDlRbCb *rbCb, bool newPdu, MsgLen bufSz)
2032
2033    bool     pollBit = FALSE;
2034    RlcAmDl   *amDl = &(rbCb->m.amDl);
2035
2036    /* If it's a new PDU increment PDU without poll and bytes without poll
2037     and check if they cross the configured number of poll pdu and poll bytes*/ 
2038    if (newPdu)
2039    {
2040       amDl->pduWoPoll++;
2041       /* Patch kw004.201 */
2042       amDl->byteWoPoll += bufSz;
2043
2044      if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) || 
2045          ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte))) 
2046      {
2047         pollBit = TRUE;
2048      }
2049    }
2050
2051    /* Check if both tx/retx buffer are empty or if tx window is stalled */
2052    if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2053        RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2054    {
2055       pollBit = TRUE;
2056    }
2057    
2058    if (pollBit)
2059    {
2060       amDl->pduWoPoll  = 0;
2061       amDl->byteWoPoll = 0;
2062
2063       amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2064
2065       DU_LOG("\nINFO   -->  RLC_DL : rlcAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d", 
2066          amDl->pollSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2067
2068       /* kw005.201: Fix for poll retransmission timer. 
2069        * Timer is stopped if it is already running and 
2070        * then starting the timer. Fixes crs 
2071        * ccpu00117216 and ccpu00118284 .
2072        * */
2073       if( TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR) )
2074       {
2075          rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2076       }
2077
2078       rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2079    }
2080
2081    return (pollBit);
2082 }
2083
2084 /**
2085  * @brief Private handler to create AMD PDU 
2086  *
2087  * @details
2088  *    This function constructs header and concatenate it with the data for
2089  *    the PDU. It also updates the txBuf with the created PDU.
2090  *
2091  * @param[in]  gCB         RLC instance control block
2092  * @param[in]  rbCb        Downlink RB control block
2093  * @param[in]  amHdr       AM header
2094  * @param[in]  RlcDlPduInfo Pointer to PduInfo
2095  * @param[in]  pdu         PDU buffer 
2096  *
2097  *  @return  Void
2098  *
2099  */
2100 static void rlcAmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmHdr *amHdr,
2101 RlcDlPduInfo *pduInfo, Buffer *pdu)
2102 {
2103    uint8_t   hdr[RLC_MAX_HDRSZ];
2104    uint16_t  idx;
2105    RlcTx     *txBuf;
2106    MsgLen    pduSz;
2107    RlcAmDl   *amDl = &(rbCb->m.amDl);
2108
2109    /* Update sn */
2110    amHdr->sn = amDl->txNext;
2111    /*5GNR RLC_DL : Increment txNext only if no segmentation of it is a last segment */
2112    if((!amHdr->si) || (amHdr->si == RLC_SI_LAST_SEG))
2113    {
2114       amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2115    }
2116
2117    /* Update hdr Info */
2118    ODU_GET_MSG_LEN(pdu, &pduSz);
2119
2120    /* passing newPDU = TRUE*/
2121    amHdr->p = rlcAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2122
2123    /* Construct header with the available hdr Info, set isSegment to FALSE */
2124    rlcConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2125
2126    /* Concatenate hdr and data */
2127    ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx+1, pdu);
2128    
2129    txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2130    rlcCpyMsg(gCb,pdu,&(pduInfo->pdu));
2131    pduInfo->pduSz = pduSz;
2132    pduInfo->hdrSz = idx+1;
2133
2134    /*Update estHdrSz. deduct current hdrSz */
2135     amDl->estHdrSz -= pduInfo->hdrSz;
2136     /* Reestimate estHdrSz for mid and last seg */
2137     if(amHdr->si & 0x1)
2138     {
2139        amDl->estHdrSz += ((amHdr->si == RLC_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2140     }
2141
2142    cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2143    pduInfo->lstEnt.node = (PTR)pduInfo;
2144
2145    gCb->genSts.bytesSent += pduSz;
2146    
2147    return;
2148 }
2149
2150 /**
2151  * @brief Private handler to remove the retx PDU from the rbCb
2152  *
2153  * @details
2154  *    This function releases a retx PDU stored on DL portion of rbCb.
2155  *    It also updates the BO if wtForAck flag is not set which implies
2156  *    that it is not sent out yet.
2157  *
2158  * @param[in]  gCb        RLC instance control block
2159  * @param[in]  retx       retransmit PDU to be removed
2160  * @param[in]  rbCb       Radio Bearer Control Block
2161  *
2162  * @return Void 
2163  *
2164  */
2165 static Void rlcRemRetxPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2166 {
2167    cmLListDelFrm(&RLC_AMDL.retxLst, &retx->lstEnt); 
2168
2169    if( RLC_AMDL.retxLst.count == 0)
2170    {
2171       RLC_AMDL.nxtRetx = NULLP;
2172    }
2173
2174    if(retx->pendingReTrans == TRUE)
2175    {
2176       RLC_AMDL.retxBo -= retx->segSz;
2177       RLC_AMDL.estHdrSz -= retx->hdrSz;
2178    }
2179
2180    rlcUtlAddReTxPduToBeFreedQueue(gCb, retx);
2181    rlcUtlRaiseDlCleanupEvent(gCb);
2182
2183    return;
2184 }
2185
2186 /**
2187  * @brief Private handler to mark a retx PDU for further retransmission
2188  *
2189  * @details
2190  *    This function sets a retx PDU that has not been ACKed in the   
2191  *    received Status PDU for futher retransmission. If the retransmission
2192  *    limit is reached, it releases the retx PDU and informs the higher
2193  *    layers about the same.
2194  *
2195  * @param[in]  gCb        RLC instance control block 
2196  * @param[in]  retx       retransmit PDU to be removed
2197  * @param[in]  rbCb       Radio Bearer Control Block
2198  *
2199  * @return Void 
2200  *
2201  */
2202 static Void rlcAmmDlMarkPduForReTx(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2203 {
2204    if (RLC_AMDL.maxReTxReached == TRUE)
2205    {
2206       return;
2207    }
2208   
2209    if(retx->pendingReTrans == FALSE)
2210    {
2211       retx->pendingReTrans = TRUE;
2212       ++retx->retxCnt;
2213
2214       RLC_AMDL.retxBo   += retx->segSz;
2215       RLC_AMDL.estHdrSz += retx->hdrSz;
2216
2217       if (retx->retxCnt > RLC_AMDL.maxRetx)
2218       {
2219          /* RLC_DL_MAX_RETX fix */
2220          /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2221          /* preparation of RLC PDUs and adding the same to Tx Buffer */
2222          /* This condition is to avoid sending StaIndication more than once */
2223          if (TRUE != rbCb->m.amDl.maxReTxReached)
2224          {
2225             rbCb->m.amDl.maxReTxReached = TRUE;
2226             rbCb->m.amDl.bo = 0;
2227             rbCb->m.amDl.cntrlBo = 0;
2228             rbCb->m.amDl.retxBo = 0;
2229             /* Sending BO update to SCH */
2230             rlcUtlSendDedLcBoStatus(gCb, rbCb, 0,0,0,0);
2231             rlcAmmSndStaInd(gCb, rbCb, retx);
2232             gRlcStats.amRlcStats.numDLMaxRetx++;
2233          }
2234
2235          rlcRemRetxPdu(gCb,rbCb, retx);
2236          
2237          return;
2238       }
2239
2240
2241       if (RLC_AMDL.nxtRetx == NULLP)
2242       {
2243          RLC_AMDL.nxtRetx = retx;
2244       }
2245
2246       gRlcStats.amRlcStats.numDLRetransPdus++;
2247    }
2248
2249
2250    return;
2251 }
2252
2253 /**
2254  * @brief Private handler to check if SDU is completely deliverd and
2255  *        send higher layers data confirmation
2256  *
2257  * @details 
2258  *    This function sends higher layers data confirmation for SDUs which
2259  *    have been successfully delivered to the peer RLC entity.
2260  *
2261  * @param[in]  gCb      RLC instance control block
2262  * @param[in]  rbCb     Radio Bearer Control Block
2263  * @param[in]  sduLst   List of SDUs that were part of the PDU
2264  * @param[in]  numSdu   Number of SDUs in the list
2265  *
2266  * @return Void 
2267  *
2268  */
2269 static Void rlcAmmDlCheckIsSDUDelivered
2270 (
2271 RlcCb            *gCb,
2272 RlcDlRbCb        *rbCb,
2273 RlcSduMap        *sduMap,
2274 KwuDatCfmInfo    **datCfm
2275 )
2276 {
2277    RlcSdu *sdu;
2278    
2279    sdu = sduMap->sdu;
2280
2281    sdu->mode.am.rcvdSz += sduMap->sduSz;
2282
2283    /* send a dat cfm if all the bytes of the sdu have been received */
2284    if (sdu->mode.am.rcvdSz == sdu->actSz)
2285    {
2286       /* Send DatCfm for this sdu */
2287       if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2288       {
2289          (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2290       }
2291       else
2292       {
2293          /* This is an error that should never happen, we should resize
2294           * the #define to a larger value or check why we need to 
2295           * send so many confirms in one go
2296           * Confrims to PDCP are being dropped in this case
2297           */
2298          RlcKwuSapCb    *rlckwuSap;
2299          rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2300          RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, *datCfm);
2301
2302          RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2303
2304 #if (ERRCLASS & ERRCLS_ADD_RES)
2305          if (*datCfm == NULLP)
2306          {
2307             DU_LOG("\nERROR  -->  RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2308                   rbCb->rlcId.ueId,
2309                   rbCb->rlcId.cellId);
2310             return;
2311          }
2312 #endif /* ERRCLASS & ERRCLS_RES */
2313
2314          (*datCfm)->numSduIds = 0;
2315          (*datCfm)->rlcId = rbCb->rlcId;
2316          /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2317           * new allocation of datCfm */
2318          (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2319       }
2320
2321       /* Remove SDU from the sduQ */
2322       cmLListDelFrm(&RLC_AMDL.sduQ, &sdu->lstEnt);
2323       rlcUtlAddSduToBeFreedQueue(gCb, sdu);
2324       rlcUtlRaiseDlCleanupEvent(gCb);
2325    }
2326
2327    return;
2328
2329
2330 /**
2331  * @brief Private handler to mark a PDU successful.
2332  *
2333  * @details
2334  *    This function is called when we receive a STATUS pdu that marks
2335  *    a PDU as successful. It releases the PDU from RLC entity and 
2336  *    informs PDCP of successful SDUs delivered as a result of this PDU.
2337  *
2338  * @param[in]  gCb        RLC instance control block  
2339  * @param[in]  rbCb       Radio Bearer Control Block
2340  * @param[in]  sn         SN that is successfully delivered to the peer 
2341  *
2342  * @return Void 
2343  *
2344  */
2345 static Void rlcAmmDlProcessSuccessfulTxPdu
2346 (
2347 RlcCb            *gCb,
2348 RlcDlRbCb        *rbCb,
2349 RlcSn            sn,
2350 KwuDatCfmInfo    **datCfm
2351 )
2352 {
2353    CmLList *pduNode;
2354   
2355    RlcTx *txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2356    
2357    if (txBuf == NULLP)
2358    {
2359            return;
2360    }
2361    pduNode = txBuf->pduLst.first;
2362    while(pduNode)
2363    {
2364       RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2365       rlcAmmDlCheckIsSDUDelivered(gCb,
2366                               rbCb,  
2367                               &(pduInfo->sduMap), 
2368                               datCfm);
2369       pduNode = pduNode->next;
2370    }
2371    
2372    rlcUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2373    rlcUtlRaiseDlCleanupEvent(gCb);
2374    /* so that it is not processed again */
2375    rlcUtlRemovTxBuf(RLC_AMDL.txBufLst, txBuf, gCb);
2376
2377    return;
2378 }
2379
2380 /**
2381  * @brief  Handler to send Status Indication to PDCP
2382  *
2383  * @details
2384  *    This function is used to send status indication to PDCP when the 
2385  *    maximum retransmission threshold value is reached for a PDU.
2386  * 
2387  * @param[in] gCb    RLC instance control block
2388  * @param[in] rbCb   RB control block 
2389  * @param[in] retx   The PDU/segment that failed max re-transmissions
2390  *
2391  * @return  Void
2392  *
2393  */
2394 static Void rlcAmmSndStaInd
2395 (
2396 RlcCb       *gCb,
2397 RlcDlRbCb   *rbCb,
2398 RlcRetx     *retx
2399 )
2400 {
2401    KwuStaIndInfo   *staInd;
2402    RlcKwuSapCb      *rlckwuSap;
2403
2404    /* Sap control block */
2405    rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2406
2407    /* Allocate memory for staInd Info */
2408    RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2409
2410 #if (ERRCLASS & ERRCLS_ADD_RES)
2411    if (staInd == NULLP)
2412    {
2413       DU_LOG("\nERROR  -->  RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2414             rbCb->rlcId.ueId,
2415             rbCb->rlcId.cellId);
2416       return;
2417    }
2418 #endif /* ERRCLASS & ERRCLS_RES */
2419
2420    /* Fill staInd Info */ 
2421    RLC_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));    
2422    
2423    staInd->numSdu = 1;
2424    staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2425
2426 #ifdef KW_PDCP
2427 #else
2428    RlcUiKwuStaInd(&rlckwuSap->pst, rlckwuSap->suId, staInd);
2429 #endif /* KW_PDCP */
2430
2431    return;
2432 }
2433
2434 /**
2435  * @brief  Handler to get the next node to be retransmitted from retxLst
2436  *
2437  * @details
2438  *    This function is used to get the next node to be retransmitted 
2439  *    from the retxLst
2440  *            
2441  *  @param[in] gCb     RLC instance control block 
2442  *  @param[in] retx    The PDU/segment after which to find a node to be 
2443  *                     retransmitted
2444  *
2445  *  @return  Void 
2446  *
2447  */
2448 static void rlcGetNxtRetx(RlcCb *gCb, RlcRetx **retx)
2449 {
2450    CmLList *tNode;
2451
2452    do
2453    {
2454       tNode = &((*retx)->lstEnt);
2455       tNode = tNode->next;
2456       
2457       if (tNode)
2458       {
2459          *retx = (RlcRetx *)tNode->node;
2460       }
2461       else
2462       {
2463          *retx = NULLP;
2464          return;
2465       }
2466    }while((*retx)->pendingReTrans == FALSE);
2467
2468    return;
2469 }
2470
2471 /**
2472  * @brief  Handler to process the re-establishment request received from UIM
2473  *
2474  * @param[in]  gCb         RLC instance control block
2475  * @param[in]  rlcId       Identity of the RB in the UE/Cell for which 
2476  *                         re-establishment is to be done
2477  * @param[in]  rbCb        Downlink RB control block (rbCb is freed in this
2478  *                         function)
2479  *
2480  * @return  Void 
2481  *
2482  */
2483 Void rlcAmmDlReEstablish
2484 (
2485 RlcCb         *gCb,
2486 CmLteRlcId   rlcId,
2487 RlcDlRbCb     *rbCb
2488 )
2489 {
2490    /* create a new AM DL RB, reset it and replace in the UeCb*/
2491    RlcDlUeCb   *ueCb;
2492    RlcDlRbCb   *resetRb;
2493    RlcAmDl* newAmDl;
2494    RlcAmDl* oldAmDl;
2495    RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2496    
2497    /* ccpu00135170 Removing KLOCK warning */
2498    if(resetRb == NULLP)
2499    {
2500       return;
2501    }
2502
2503    RLC_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2504    RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(RlcAmDl));
2505
2506 /* AGHOSH changes start */
2507    /* restore the old AM values */
2508    newAmDl = &resetRb->m.amDl;
2509    oldAmDl = &rbCb->m.amDl;
2510
2511    newAmDl->pollPdu = oldAmDl->pollPdu;
2512    newAmDl->pollByte = oldAmDl->pollByte;
2513    newAmDl->maxRetx = oldAmDl->maxRetx;
2514    newAmDl->snLen   = oldAmDl->snLen;
2515    newAmDl->snModMask   = oldAmDl->snModMask;
2516    newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2517    rbCb->boUnRprtdCnt = (uint32_t)0;
2518    rbCb->lastRprtdBoToMac = (uint32_t)0;
2519    cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1); 
2520 /* AGHOSH changes end */
2521  
2522    if (ROK != rlcDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2523    {
2524       DU_LOG("\nERROR  -->  RLC_DL : UeId [%d]: UeCb not found RBID;%d",
2525                rlcId.ueId,
2526                rlcId.rbId);
2527       return;
2528    }
2529    
2530    if(rlcId.rbType == CM_LTE_SRB)
2531    {
2532       ueCb->srbCb[rlcId.rbId] = resetRb;
2533    }
2534    else
2535    {
2536       ueCb->drbCb[rlcId.rbId] = resetRb;
2537    }
2538    /* update into the logical channel array also */
2539    ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2540  
2541    if((resetRb->rlcId.rbType == CM_LTE_SRB)
2542                 &&(resetRb->rlcId.rbId == 1))
2543    {
2544       /* To stop the traffic on SRB2 and other DRBs*/
2545       rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2546    }
2547    else 
2548    {
2549       rlcDlUtlSetReestInProgressForRB(gCb, resetRb);      
2550    }
2551
2552    /* allocate the TX array again */
2553 #ifndef  LTE_TDD
2554    uint32_t hashIndex;
2555    RLC_ALLOC(gCb,
2556                    resetRb->m.amDl.txBufLst,
2557                    (RLC_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2558    for(hashIndex = 0; hashIndex < RLC_TX_BUF_BIN_SIZE; hashIndex++)
2559    {
2560            cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2561    }
2562 #endif
2563    /* send the old rb of deletion */
2564    rlcAmmFreeDlRbCb(gCb,rbCb); 
2565
2566
2567    /* TODO: for now we are re-settting the re-establishment flag here
2568       this needs to be fixed
2569       There should be a proper intreface to resume the RBs */
2570    if(rlcId.rbType == CM_LTE_SRB)
2571    {
2572       rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2573    }
2574    else
2575    {
2576       rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2577    }      
2578       
2579    return;
2580 }
2581
2582 /**
2583  * @brief  Handler to discard a SDU.
2584  *
2585  * @details
2586  *    This function is used to discard a SDU after receiving
2587  *    the Discard Request from UIM. The SDU is discarded if its 
2588  *    available and is not mapped to any PDU yet.
2589  *   
2590  * @param[in] gCb     RLC instance control block
2591  * @param[in] rbCb    RB control block 
2592  * @param[in] sduId   Sdu ID of the SDU to be discarded
2593  *
2594  *  @return  S16
2595  *     -# ROK      In case of successful discard
2596  *     -# RFAILED  In case the SDU is not found or already mapped
2597  */
2598 S16 rlcAmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId )
2599 {
2600    return (RFAILED);
2601
2602
2603 /**
2604  * @brief  Handler for Poll retransmit timer expiry
2605  *
2606  * @details
2607  *    This function is used to handle events upon expiry of Poll 
2608  *    retransmit timer.
2609  *  
2610  * @param[in] gCb    RLC instance control block
2611  * @param[in] rbCb   Downlink RB control block 
2612  *
2613  * @return  Void 
2614  */
2615 Void rlcAmmPollRetxTmrExp(RlcCb *gCb,RlcDlRbCb *rbCb)
2616 {
2617    RlcRetx        *retx; 
2618    RlcAmDl        *amDl = &(rbCb->m.amDl);
2619    RlcSn          sn;
2620    RlcTx          *txBuf;
2621
2622    /* kw003.201 - Correcting the logic for determmining whether to do   */
2623    /*             any transmission of PDU. As per the spec section      */
2624    /*             5.2.2.3, if there is any to transmit or retransmit,   */
2625    /*             do nothing. Else, pick up the VT(S) -1 for retx       */
2626    /*             We have nothing to transmit if window is stalled or   */
2627    /*             there are no SDUs to be transmitted or if there are   */
2628    /*             PDUs to be retransmitted.                             */
2629    if(CM_LTE_SRB == rbCb->rlcId.rbType)
2630    {
2631       gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
2632    }
2633    else
2634    {
2635       gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
2636    }
2637
2638    if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) || 
2639         RLC_AM_IS_TRANS_WIN_STALLED(amDl)) 
2640    {
2641       sn = (amDl->txNext - 1) & amDl->snModMask;
2642       txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2643
2644       if (txBuf != NULLP)
2645       {
2646          rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn); 
2647          
2648          if (RLC_AMDL.nxtRetx == NULLP)
2649          {
2650             RLC_AMDL.nxtRetx = retx;
2651          }
2652          
2653          rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);         
2654          return;
2655       }
2656       /* Get the last node in retxLst */
2657       RLC_LLIST_LAST_RETX(amDl->retxLst, retx);
2658
2659       /* Unset wtForAck flag for the NACK PDUs */ 
2660       if (retx != NULLP)
2661       {
2662          rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
2663          rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);         
2664       }
2665    }
2666
2667    return;
2668
2669
2670 /**
2671  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
2672  *         NACK PDU.
2673  *
2674  * @details 
2675  *    This function is used to handle ACKs for the PDUs remaining after the 
2676  *    last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and 
2677  *    sends DatCfm to PDCP for the same.
2678  *
2679  * @param[in]  gCb         RLC instance control block
2680  * @param[in]  rbCb        Downlink Radio Bearer control block
2681  * @param[in]  mAckSn      The ACK SN after doing the base modulus
2682  * @param[in]  rextNode    Next node in the re-transmission buffer          
2683  *
2684  * @return  Void
2685  *
2686  */
2687
2688 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn
2689 (
2690 RlcCb            *gCb,
2691 RlcDlRbCb        *rbCb,
2692 RlcSn            mAckSn,
2693 CmLList         *retxNode,
2694 KwuDatCfmInfo   **datCfm
2695 )
2696 {
2697    RlcSn    mSn;
2698    RlcSn    sn;
2699    RlcRetx  *retx;
2700    RlcTx    *txBuf;
2701
2702    /* Remove pdus/segs from retxLst */ 
2703    while (retxNode)
2704    {
2705       retx = (RlcRetx *)(retxNode->node);
2706       retxNode = retxNode->next;
2707       MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2708       if (mSn < mAckSn) 
2709       {
2710          rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2711       }
2712    }
2713
2714    /* For the remaining; pdus not acknowldeged by the NACK_SN but being
2715       acknowledged by the ACK_SN*/
2716    /* start from the starting of the transmission window and remove till just
2717       before ACK_SN*/
2718    mSn = 0;       /* same as MODAMT(RLC_AMDL.txNextAck, mSn, RLC_AMDL.txNextAck);*/
2719    sn = RLC_AMDL.txNextAck;
2720    while(mSn < mAckSn)
2721    {
2722       txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2723       if (txBuf != NULLP)
2724       {
2725          
2726          DU_LOG("\nDEBUG  -->  RLC_DL : rlcAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
2727                  "with sn = %d UEID:%d CELLID:%d",
2728                  sn,
2729                  rbCb->rlcId.ueId,
2730                  rbCb->rlcId.cellId);
2731
2732          rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2733       }
2734       
2735       sn = (sn + 1) & RLC_AMDL.snModMask;
2736       MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2737    }
2738
2739    return;
2740 }
2741
2742 /**
2743  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
2744  *         NACK PDU.
2745  *
2746  * @details 
2747  *    This function is used to handle ACKs for the PDUs remaining after the 
2748  *    last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and 
2749  *    sends DatCfm to PDCP for the same.
2750  *
2751  * @param[in]  gCb         RLC instance control block
2752  * @param[in]  rbCb        Downlink Radio Bearer control block
2753  * @param[in]  mAckSn      The ACK SN after doing the base modulus
2754  * @param[in]  rextNode    Next node in the re-transmission buffer          
2755  *
2756  * @return  Void
2757  *
2758  */
2759 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn
2760 (
2761 RlcCb            *gCb,
2762 RlcDlRbCb        *rbCb,
2763 RlcSn            sn,
2764 RlcSn            mNackSn,
2765 CmLList         **retxNode,
2766 KwuDatCfmInfo   **datCfm
2767 )
2768 {
2769    RlcSn    mSn;
2770    RlcRetx  *retx;
2771    RlcTx    *txBuf=NULLP;
2772
2773    while (*retxNode)
2774    {
2775       retx = (RlcRetx *)((*retxNode)->node);
2776       MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2777       if (mSn < mNackSn)
2778       {
2779          (*retxNode) = (*retxNode)->next;
2780          rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2781       }
2782       else
2783       {
2784          break;
2785       }
2786    }
2787
2788    /* Remove all pdus with SN < NACK_SN from the transmission buffer */ 
2789    MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2790    while (mSn < mNackSn)
2791    {
2792       /* this if check seems redundant,why should mSn ever be mTxSn 
2793          (which actually is VT(A) */
2794       txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2795       if ((txBuf != NULLP)) 
2796       {
2797          DU_LOG("\nDEBUG  -->  RLC_DL : rlcHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
2798                sn,
2799                rbCb->rlcId.ueId,
2800                rbCb->rlcId.cellId);
2801
2802          /* Remove pdus from txBuf */
2803          rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2804       }
2805
2806       sn = (sn + 1) & RLC_AMDL.snModMask;
2807       MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2808    }
2809    
2810    return;
2811 }
2812
2813
2814 /**
2815  * @brief  Handler to form construct AM header
2816  *
2817  * @details 
2818  *    This function is used to construct am header with the available header
2819  *    elements.
2820  *
2821  * @param[in] gCb    RLC instance control block
2822  * @param[in] amHdr  AM Header
2823  * @param[in] isSeg  Check for Segmentation of PDU
2824  * @param[in] hdr    Header field
2825  * @param[in] idx    Index
2826  *  
2827  * @return Void            
2828  *
2829  */
2830 static void rlcConstructAmHdr(RlcAmHdr *amHdr, uint8_t *hdr, uint8_t snLen, uint16_t *idx)
2831 {
2832    *idx = 0;
2833     hdr[0] = RLC_DATA_BITMASK;
2834     
2835     hdr[0] = hdr[0] | (amHdr->p << 6);
2836     hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
2837    if(snLen == RLC_AM_CFG_12BIT_SN_LEN)
2838    {
2839       hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0xF00) >> 8);
2840       hdr[1] =  (uint8_t)(amHdr->sn & 0x0FF);
2841       (*idx)++;
2842    }
2843    else
2844    {
2845       hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0x30000) >> 16);
2846       hdr[1] =  (uint8_t)((amHdr->sn & 0xFF00) >> 8);
2847       (*idx)++;
2848       hdr[2] =  (uint8_t)(amHdr->sn & 0xFF);
2849       (*idx)++;
2850    }
2851     
2852    if ((amHdr->si == RLC_SI_MID_SEG) || (amHdr->si == RLC_SI_LAST_SEG))                                      
2853    {
2854       (*idx)++;
2855       hdr[(*idx)] = (uint8_t)((amHdr->so & 0xFF00)>> 8);
2856       (*idx)++;
2857       hdr[(*idx)] = (uint8_t)(amHdr->so & 0xFF);
2858    }                                                        
2859
2860    return;
2861 }
2862
2863 /**
2864  * @brief  This function adds a retx PDU to list of retx PDUs
2865  *
2866  * @details
2867  *    kw003.201 - Poll expiry may cause an SN to be added to retx 
2868  *                out of sequence and hence all additions to retx 
2869  *                must validate that they are added in sequence   
2870  *
2871  * @param[in] amDl   AM Downlink Control Block
2872  * @param[in] retx   Retransmit PDU
2873  * 
2874  * @return Void
2875  *            
2876  */
2877 static Void rlcAmmAddPduToRetxLst(RlcAmDl *amDl,RlcRetx *retx)
2878 {
2879    CmLList   *node;
2880    RlcRetx    *tRetx;
2881    RlcSn      tMSn;
2882    RlcSn      retxMSn;
2883    
2884    node = amDl->retxLst.last;
2885    MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
2886    while(node != NULLP)
2887    {
2888       tRetx = (RlcRetx *)(node->node);
2889       MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
2890       if (tMSn > retxMSn)
2891       {
2892          node = node->prev;
2893       }
2894       else
2895       {
2896          break;
2897       }
2898    }
2899    if (node)
2900    {
2901       amDl->retxLst.crnt = node;
2902       cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
2903       retx->lstEnt.node = (PTR)retx;
2904    }
2905    else
2906    {
2907       amDl->retxLst.crnt = amDl->retxLst.first;
2908       cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
2909       retx->lstEnt.node = (PTR)retx;
2910    }
2911
2912    if (amDl->nxtRetx == NULLP)
2913    {
2914       amDl->nxtRetx = retx;
2915    }
2916
2917    return;
2918 }
2919
2920 /**
2921  * @brief Handler to Move the PDU from txBuf to re-transmission buffer 
2922  *
2923  * @details
2924  *    This function is used to move the PDU from the txBuf to re-transmit buffer
2925  *
2926  * @param[in]  gCb         RLC instance control block
2927  * @param[in]  amDl        AM Downlink Control Block 
2928  * @param[in]  retx        node in the reTx buffer to be moved to, allocated by
2929  *                         this function
2930  * @param[in]  sn          SN in the tx buffer which needs to be moved
2931  * 
2932  * @return Void
2933  *            
2934  */
2935
2936 static Void rlcAmmDlMoveFrmTxtoRetxBuffer
2937 (
2938 RlcCb          *gCb,
2939 RlcAmDl        *amDl,
2940 RlcRetx        **retx,
2941 RlcSn          sn
2942 )
2943 {
2944    RlcTx* txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2945
2946    if (txBuf == NULLP)
2947    {
2948            return;
2949    }
2950    while(txBuf->pduLst.first)
2951    {
2952       RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
2953
2954       /* Move Sdu byte segment from TX buf to retx buf*/
2955       rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, 
2956             amDl, 
2957             retx, 
2958             pduInfo);
2959       
2960       /* Delete node from the txBuf Pdu lst */
2961       cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
2962       RLC_FREE(gCb, pduInfo, sizeof(RlcDlPduInfo));
2963    }
2964    /* Remove PDU from txBuf */
2965    rlcUtlDelTxBuf(amDl->txBufLst, txBuf,gCb); 
2966    
2967    return;
2968 }
2969
2970
2971
2972 /*
2973  * @brief
2974  *    function to free/release the Acknowledged mode RBCB buffers
2975  *
2976  * @details
2977  *    This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
2978  *    retransmission Buffer and reciption Buffers
2979  *
2980  * @param [in]   gCb    - RLC instance control block
2981  * @param [in]   rbCb   - Downlink RB Control Block
2982  *
2983  * @return Void
2984  */
2985 Void rlcAmmFreeDlRbCb(RlcCb  *gCb,RlcDlRbCb  *rbCb)
2986 {
2987    /* stop the re-transmission timer */
2988    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR))
2989    {
2990       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2991    }
2992
2993    /* store the entire Rb pointer */      
2994    rbCb->rlsLnk.node = (PTR)rbCb;
2995    cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
2996
2997    /* the sdu queue */
2998    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
2999
3000    rlcUtlRaiseDlCleanupEvent(gCb);
3001    
3002    return;
3003 }
3004
3005 /**
3006  * @brief  Handler to create STATUS Pdu
3007  *
3008  * @details
3009  *    This function is used to create status pdu 
3010  *
3011  * @param[in] gCb        RLC instance control block
3012  * @param[in] rbCb       Downlink RB control block
3013  * @param[in] rlcDatReq   The data to be passed to MAC
3014  *
3015  * @return Void
3016  *
3017  */
3018 static void rlcAmmCreateStatusPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
3019 {
3020     RlcSn          sn;                      /* sequence number */
3021     RlcSn          ack_sn;                  /* Ack sequence number */
3022     Buffer        *mBuf;           /* control pdu buffer */
3023     MsgLen        cntrlPduSz;          /* control pdu size */
3024     uint8_t       cntrlPdu[RLC_MAX_CNTRL_FIELDS];   /* control pdu to be added to mBuf */
3025     RlcUdxDlStaPdu   *pStaPdu;
3026     uint16_t         bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3027     uint16_t         encIdx = 0;
3028     uint16_t         prevEncIdx = 0;
3029     RlcNackInfo      *rlcNackInfo;
3030     uint16_t         nkCnt = 0;
3031
3032     pStaPdu = RLC_AMDL.pStaPdu;
3033
3034
3035     /* D/C| CPT| */
3036     /* 0 - Control
3037        1 - Data */
3038     cntrlPdu[0] = 0x00;
3039     cntrlPdu[2] = 0x00;
3040
3041     /* ACK SN Field will be set in the end based on available Grant */
3042
3043     encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3044
3045     ack_sn = pStaPdu->ackSn;
3046
3047     if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3048     {
3049
3050        /* If alteast one NACK SN Info then set the E1 field */
3051        if (pStaPdu->nackCount)
3052        {
3053           /* 12 BIT SN CASE:
3054              In Third Octet:
3055              7  6 5 4 3 2 1 0
3056              E1 R R R R R R R 
3057            */
3058           cntrlPdu[2] = 0x80;
3059        }
3060
3061        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3062        {           
3063           sn = pStaPdu->nackInfo[nkCnt].sn;
3064
3065           rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3066
3067           bytesToEncode += 2; /* 2 Octets for NACK SN */
3068
3069           /* Check if E2 : isSegment is set */
3070           if (rlcNackInfo->isSegment)
3071           {
3072              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3073           }
3074
3075           /* Check if E3 : nackRange is set */
3076           if (rlcNackInfo->nackRange)
3077           {
3078              bytesToEncode += 1; /* 1 Octet: NACK range */
3079           }
3080
3081           /* Check if this NACK info can be accomodated in the Grant */
3082           if( rlcDatReq->pduSz >= bytesToEncode)
3083           {
3084              /* If there is a NACK SN before this then set its 
3085                 E1 bit */
3086              if(prevEncIdx)
3087              {
3088                 /* NACKSN  E1 E2 E3 R */
3089                 cntrlPdu[prevEncIdx + 1] |= 0x8;
3090              }
3091
3092              /* 12 BIT Nack SN encode */
3093              cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3094
3095              /* Next Octet */
3096              cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3097
3098              if (rlcNackInfo->isSegment)
3099              {
3100                 /*Set E2 Bit */
3101                 cntrlPdu[encIdx + 1] |= 0x4;
3102
3103
3104                 /* Add soStart and soEnd */
3105                 /* SOstart */
3106                 cntrlPdu[encIdx + 2] = (rlcNackInfo->soStart) >> 8; 
3107                 cntrlPdu[encIdx + 3] = rlcNackInfo->soStart & 0xFF;
3108
3109                 /* SOend */
3110                 cntrlPdu[encIdx + 4] = (rlcNackInfo->soEnd) >> 8;
3111                 cntrlPdu[encIdx + 5] = rlcNackInfo->soEnd & 0xFF;
3112              }
3113
3114              if (rlcNackInfo->nackRange)
3115              {
3116                 /*Set E3 Bit */
3117                 cntrlPdu[encIdx + 1] |= 0x2;
3118                 if(rlcNackInfo->isSegment)
3119                 {
3120                    cntrlPdu[encIdx + 6] = rlcNackInfo->nackRange;
3121                 }
3122                 else
3123                 {
3124                    cntrlPdu[encIdx + 2] = rlcNackInfo->nackRange;
3125                 }
3126              }
3127
3128              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3129           }
3130           /* Set ACK SN now */
3131           else
3132           {
3133              ack_sn = rlcNackInfo->sn;
3134
3135              /* Not even one nack can be accomodated */
3136              if (nkCnt == 0)
3137              {
3138                cntrlPdu[2] = 0x0;
3139              }
3140
3141              break;
3142           }
3143
3144           prevEncIdx = encIdx;
3145           encIdx = bytesToEncode;
3146
3147        }/* Loop is done for the NackCount */
3148
3149         /* set ACK SN */
3150        {
3151
3152           DU_LOG("\nINFO  -->  RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"\
3153              "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
3154
3155           cntrlPdu[0] |= (ack_sn & 0xF00)>> 8; 
3156           cntrlPdu[1] =  (uint8_t)ack_sn;
3157        }
3158
3159     }
3160     else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3161     {
3162        /* If alteast one NACK SN Info then set the E1 field */
3163        if (pStaPdu->nackCount)
3164        {
3165           /* 12 BIT SN CASE:
3166              In Third Octet:
3167              7  6 5 4 3 2 1 0
3168              ACKSN       E1 R 
3169            */
3170           cntrlPdu[2] = 0x2;
3171        }
3172
3173        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3174        {           
3175           sn = pStaPdu->nackInfo[nkCnt].sn;
3176
3177           rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3178
3179           bytesToEncode += 3; /* 3 Octets for NACK SN */
3180
3181           /* Check if E2 : isSegment is set */
3182           if (rlcNackInfo->isSegment)
3183           {
3184              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3185           }
3186
3187           /* Check if E3 : nackRange is set */
3188           if (rlcNackInfo->nackRange)
3189           {
3190              bytesToEncode += 1; /* 1 Octet: NACK range */
3191           }
3192
3193           /* Check if this NACK info can be accomodated in the Grant */
3194           if( rlcDatReq->pduSz >= bytesToEncode)
3195           {
3196              /* If there is a NACK SN before this then set its 
3197                 E1 bit */
3198              if(prevEncIdx)
3199              {
3200                 /* NACKSN  E1 E2 E3 R R R */
3201                 cntrlPdu[prevEncIdx + 2] |= 0x20;
3202              }
3203
3204              /* 18 BIT Nack SN encode */
3205              cntrlPdu[encIdx] = (uint8_t)((sn & 0x3FC00) >> 10);
3206
3207              /* Next Octet */
3208              cntrlPdu[encIdx + 1] = (uint8_t)((sn & 0x3FC) >> 2);
3209
3210              /* Next Octet */
3211              cntrlPdu[encIdx + 2] = (uint8_t)((sn & 0x3)<< 6);
3212
3213              if (rlcNackInfo->isSegment)
3214              {
3215                 /* NACKSN  E1 E2 E3 R R R */
3216                 /*Set E2 Bit */
3217                 cntrlPdu[encIdx + 2] |= 0x10;
3218
3219
3220                 /* Add soStart and soEnd */
3221                 /* SOstart */
3222                 cntrlPdu[encIdx + 3] = (rlcNackInfo->soStart) >> 8;
3223                 cntrlPdu[encIdx + 4] = (uint8_t)rlcNackInfo->soStart;
3224
3225                 /* SOend */
3226                 cntrlPdu[encIdx + 5] = (rlcNackInfo->soEnd) >> 8; 
3227                 cntrlPdu[encIdx + 6] = (uint8_t)(rlcNackInfo->soEnd);
3228              }
3229
3230              if (rlcNackInfo->nackRange)
3231              {
3232                 /* NACKSN  E1 E2 E3 R R R */
3233                 /*Set E3 Bit */
3234                 cntrlPdu[encIdx + 2] |= 0x08;
3235
3236                 if (rlcNackInfo->isSegment)
3237                 {
3238                    cntrlPdu[encIdx + 7] = rlcNackInfo->nackRange;
3239                 }
3240                 else
3241                 {
3242                    cntrlPdu[encIdx + 3] = rlcNackInfo->nackRange;
3243                 }
3244              }
3245
3246              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3247           }
3248           /* Set ACK SN now */
3249           else
3250           {
3251              ack_sn = rlcNackInfo->sn;
3252
3253              /* Not even one nack can be accomodated */
3254              if (nkCnt == 0)
3255              {
3256                cntrlPdu[2] &= 0xFD;
3257              }
3258
3259              break;
3260           }
3261
3262           prevEncIdx = encIdx;
3263           encIdx = bytesToEncode;
3264
3265        }/* Loop is done for the NackCount */
3266    
3267        /* set ACK SN */
3268        {
3269
3270           DU_LOG("\nINFO  -->  RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"
3271              "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId,rbCb->rlcId.cellId);
3272
3273           cntrlPdu[0] |=  (ack_sn & 0x3C000) >> 14;
3274           cntrlPdu[1] =  (ack_sn & 0x3FC0) >> 6;
3275           cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3276        }
3277
3278     }
3279     else
3280     {
3281        /* ERROR Log */
3282        DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleCntrlInfo:Conf SN LEN  %d  is INVALID !!!! \
3283           UEID:%d CELLID:%d", rbCb->m.amDl.snLen, rbCb->rlcId.ueId,
3284           rbCb->rlcId.cellId);
3285     }
3286
3287
3288 #ifndef L2_OPTMZ
3289     ODU_GET_MSG_BUF(RLC_MEM_REGION_DL, RLC_POOL, &mBuf);
3290 #else
3291     mBuf = (Buffer *)rlcAmmStaPduList[rlcAmmStaPduListCnt++];
3292     SResetMBuf(mBuf);
3293     if(rlcAmmStaPduListCnt > 511)
3294        rlcAmmStaPduListCnt = 0;
3295 #endif
3296
3297     cntrlPduSz = encIdx;
3298     ODU_ADD_POST_MSG_MULT(cntrlPdu, cntrlPduSz, mBuf);
3299
3300     rlcDatReq->pduSz -= cntrlPduSz;
3301     /* Add mBuf to RLC_AMDL.mBuf */
3302     RLC_AMDL.mBuf = mBuf;
3303  
3304     return;
3305 }
3306
3307 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3308
3309 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3310       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3311
3312 static Void rgAmmExtractElmnt(RlcCb *gCb,Buffer *pdu,RlcExtHdr *hdrInfo)
3313 {
3314    uint8_t   hdr;
3315    uint8_t   pLen = hdrInfo->pLen;
3316    uint8_t   len  = (uint8_t)hdrInfo->len;
3317    uint16_t  val;
3318    uint8_t   tHdr;
3319    uint8_t   fLen;
3320    uint8_t   rLen;
3321    /* uint8_t   rLen1 = 0; */
3322    uint16_t  tVal;
3323
3324    hdr = hdrInfo->hdr;
3325
3326    if (pLen == 0)
3327    {
3328       SRemPreMsg(&hdr, pdu);
3329       pLen = 8;
3330    }
3331    tHdr = hdr;
3332    if (len <= 8)
3333    {
3334       val = tHdr >> (RLC_BYTE_LEN - (len));
3335       hdr =  hdr << len;
3336       pLen -= len;
3337    }
3338    else /*if (len > 8) */
3339    {
3340       fLen = pLen;
3341       val = tHdr;
3342       val = val >> (RLC_BYTE_LEN - fLen);
3343       val = val << (len - fLen);
3344       rLen = len - fLen;
3345       SRemPreMsg(&hdr, pdu);
3346       tHdr = hdr;
3347       if (rLen <= 8)
3348       {
3349          hdr = hdr >> (RLC_BYTE_LEN - rLen);
3350          val = val | hdr;
3351          hdr = tHdr << rLen;
3352          pLen = (RLC_BYTE_LEN - rLen);
3353       }
3354       else
3355       {
3356         rLen = rLen - RLC_BYTE_LEN;
3357         tVal = hdr;
3358         tVal = tVal << rLen;
3359         val = val | tVal;
3360
3361         SRemPreMsg(&hdr, pdu);
3362         tHdr = hdr;
3363         hdr = hdr >> (RLC_BYTE_LEN - rLen);
3364         val = val | hdr;
3365         hdr = tHdr << rLen;
3366         pLen = (RLC_BYTE_LEN - rLen);
3367       }
3368    }
3369
3370    hdrInfo->pLen = pLen;
3371    hdrInfo->hdr = hdr;
3372    hdrInfo->val = val;
3373
3374    return;
3375 }
3376
3377
3378
3379
3380 static Void rgAmmUlHndlStatusPdu
3381 (
3382 Pst        *udxPst,
3383 SuId       suId,
3384 RlcCb      *gCb,
3385 RlcDlRbCb  *rbCb,
3386 Buffer     *cntrlPdu,
3387 uint8_t    *fByte
3388 )
3389 {
3390    uint8_t             e1;
3391    RlcExtHdr       hdrInfo;
3392    RlcUdxStaPdu    *pStaPdu;
3393    uint8_t             e3; /* NACK RANGE : 5GNR */
3394    uint32_t            snLen;
3395    uint32_t            snRange;
3396    uint32_t            resrvdBitsAckSn;
3397    uint32_t            resrvdBitsNackSn;
3398
3399    RLCDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3400
3401    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
3402
3403    /* Extract the Control PDU */
3404    hdrInfo.hdr  = (*fByte << 1);
3405    hdrInfo.pLen = 4;
3406
3407    /* D/C has been shifted in the calling function */
3408    if (hdrInfo.hdr & 0xE0)
3409    {
3410       RLCDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3411       return;
3412    }
3413
3414    RLC_ALLOC_SHRABL_BUF(udxPst->region, 
3415                        udxPst->pool, 
3416                        pStaPdu, 
3417                        sizeof(RlcUdxStaPdu));
3418
3419 #if (ERRCLASS & ERRCLS_ADD_RES)
3420    /* Memory allocation failure can not be expected  */
3421    if(!pStaPdu)
3422    {
3423      return;
3424    }
3425 #endif   
3426
3427    if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3428    {
3429       snLen = 12;
3430       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
3431       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
3432    }
3433    else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3434    {
3435       snLen = 18;
3436       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
3437       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
3438    }
3439    else
3440    {
3441       snLen = RLC_SN_LEN;
3442       resrvdBitsAckSn = 0;
3443       resrvdBitsAckSn = 0;
3444    }
3445
3446    pStaPdu->nackCnt = 0;
3447    /* For CPT */
3448    hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
3449
3450    /* ACK Sn */
3451    hdrInfo.len = RLC_SN_LEN;
3452    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3453    pStaPdu->ackSn = hdrInfo.val;
3454
3455    /* Check if NACK Exists */
3456    hdrInfo.len = RLC_E1_LEN;
3457    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3458    e1 = (uint8_t)hdrInfo.val;
3459    RLCDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
3460
3461    /* Extract the Reserved Bits after ACK SN field */
3462    hdrInfo.len = resrvdBitsAckSn;
3463    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3464
3465
3466    /* If NACK exists in control PDU */
3467    /* For ACKs and NACKs */
3468    while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
3469    {
3470       hdrInfo.len = snLen;
3471       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3472       pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
3473
3474       hdrInfo.len = RLC_E1_LEN;
3475       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3476       e1 = (uint8_t)hdrInfo.val;
3477
3478       /* Extract e2 */
3479       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3480          already present*/
3481       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3482       /*  e2 = (uint8_t) hdrInfo.val;*/
3483
3484       /* Store e2 value */
3485       pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
3486
3487       /* Extract e3 : 5GNR */
3488       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3489          already present*/
3490       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3491       e3 = (uint8_t) hdrInfo.val;
3492
3493       /* Extract Reserved Bits after NACK SN */
3494       hdrInfo.len = resrvdBitsNackSn;
3495       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3496
3497       /* Test for resegmentation */
3498       if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
3499       {
3500          hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
3501          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3502          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
3503
3504          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3505          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = hdrInfo.val;
3506
3507          RLCDBGP_DETAIL(gCb,
3508                        "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
3509                        pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
3510                        pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
3511       }
3512       else
3513       {
3514          hdrInfo.len = 0;
3515          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
3516          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = 0;
3517
3518       }
3519       /* NACK RANGE Field is SET */
3520       if (e3)
3521       {
3522          /* Extract NACK range field */
3523          hdrInfo.len = RLC_NACK_RANGE_LEN;
3524          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3525          snRange = (uint8_t)hdrInfo.val;
3526
3527          pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
3528
3529       }
3530       pStaPdu->nackCnt++;
3531    }
3532
3533    gRlcStats.amRlcStats.numULStaPduRcvd++;
3534    gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
3535
3536    /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
3537       to the last NACK SN + 1 and discard the original ACK_SN*/
3538    if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
3539    {
3540       pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
3541    }
3542
3543
3544    /* Parse & send Status PDU to RLC-DL */
3545    //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
3546    rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
3547
3548    return;
3549 }
3550
3551 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3552       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
3553 {
3554    RlcDlRbCb      *rbCb = NULLP;   
3555    RlcDlUeCb      *ueCb = NULLP; 
3556    uint8_t        fByte;
3557    uint8_t        temp;
3558    S16       retVal = RFAILED;
3559    RlcCb      *gCb;
3560    Pst       dlRlcPst = *udxPst;
3561
3562    gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
3563
3564    if( ROK != rlcDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
3565    {
3566      DU_LOG("\nERROR  -->  RLC_DL : RLC UECb Not found...\n");
3567      return RFAILED;
3568    }
3569
3570
3571    rbCb = ueCb->lCh[lcId - 1].dlRbCb;
3572
3573    /* Skip if mode is not AM */
3574    if((rbCb ==  NULLP) || (rbCb->mode != RLC_MODE_AM))
3575    {
3576       return RFAILED;
3577    }
3578
3579    if(ROK != SExamMsg((Data *)(&fByte),
3580             rlcSdu, 0))
3581    {
3582       DU_LOG("\nERROR  -->  RLC_DL : Failure in Rlc Hdr SExamMsg\n");
3583       return RFAILED;
3584    }
3585
3586    if(RLC_CNTRL_PDU == ((fByte & RLC_DC_POS) >> RLC_DC_SHT))
3587    {
3588       SRemPreMsg(&temp, rlcSdu);
3589       dlRlcPst.selector = 1;/* LWLC*/
3590       rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
3591       retVal = ROK;
3592    }
3593
3594    return (retVal);
3595 }
3596
3597
3598 #endif
3599
3600
3601 /*@}*/
3602
3603 \f  
3604 /********************************************************************30**
3605   
3606          End of file
3607 **********************************************************************/