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