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