1bc8ef5440b458d696fb7e9eb80de086ddb8c073
[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    /*5GNR: value of RLC_AM_PDU_FIXED_HDRSZ will be 2 or 3 depending on SN Size*/
1636    if(amDl->snLen == RLC_AM_CFG_12BIT_SN_LEN)
1637    {
1638       fixedHdrSz   = RLC_AM_PDU_12BIT_SN_HDRSZ;
1639    }
1640    else
1641    {
1642       fixedHdrSz   = RLC_AM_PDU_18BIT_SN_HDRSZ;
1643    }
1644
1645    while ((macGrntSz > fixedHdrSz) && (sdu != NULLP) &&
1646           (rlcDatReq->pduInfo.numPdu < RLC_MAX_PDU) && 
1647           (numNewPdu < RLC_MAX_NEW_DL_PDU))
1648    {
1649 #ifdef LTE_L2_MEAS   
1650       isSduSegmented = sdu->mode.am.isSegmented;
1651 #endif
1652       /* Discard new changes starts */
1653       if ((sdu->mode.am.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && \
1654             (rbCb->rlcId.rbType == CM_LTE_DRB))
1655       {
1656          //leftAmSdus[rbCb->qci]--;
1657          timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime); 
1658          if (timeDiff > rbCb->discTmrInt)
1659          {
1660             CmLList* nxtNode;
1661             /*starting Task*/
1662             SStartTask(&startTime, PID_RLC_AMM_DISC_SDUS);
1663 #ifdef LTE_L2_MEAS 
1664             RLC_UPD_L2_DL_DISC_SDU_STS(gCb,rbCb);
1665             /* TODO need to send disc cfm to pdcp */
1666 #endif
1667             /* Update bo for boReport */
1668             amDl->bo -= sdu->sduSz;
1669
1670             /* Get next sdu for assembly */
1671             nxtNode = sdu->lstEnt.next;
1672
1673             /* store the info for sending it to PDCP */
1674             if(discSduInfo->numSduIds > 500)
1675             {
1676                DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleSdus: This is a big error, we shouldn't be here"
1677                   "UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1678                break;
1679             }
1680
1681             discSduInfo->sduIds[discSduInfo->numSduIds] = sdu->mode.am.sduId;
1682             discSduInfo->numSduIds++;
1683
1684             cmLListDelFrm(&amDl->sduQ, &sdu->lstEnt);
1685
1686             rlcUtlAddSduToBeFreedQueue(gCb, sdu);
1687             rlcUtlRaiseDlCleanupEvent(gCb);
1688
1689             /* We need to restore the crnt in the linked list which
1690              * would have become NULL in the DelFrm above */
1691             amDl->sduQ.crnt = nxtNode;
1692
1693             if(nxtNode)
1694                sdu = (RlcSdu*)nxtNode->node;
1695             else
1696                sdu = NULLP;
1697
1698             /*stopping Task*/
1699             ODU_STOP_TASK(startTime, PID_RLC_AMM_DISC_SDUS);
1700             continue;
1701          }
1702       }
1703       nxtTxUpd = FALSE;
1704
1705 #ifdef LTE_L2_MEAS
1706       newIdx = FALSE;
1707 #endif
1708       /** kw003.201 - Check for window stall when you are
1709        *  creating a new PDU
1710        */
1711       if (RLC_AM_IS_TRANS_WIN_STALLED(amDl))
1712       {
1713          //int *a = NULLP;
1714          DU_LOG("\nINFO  -->  RLC_DL : Window stalled  \n");
1715          gRlcStats.amRlcStats.numRlcAmCellWinStall++;
1716          //*a = 10;
1717          break;
1718       }
1719
1720       hdrEstmt = fixedHdrSz; 
1721
1722       if (sdu->mode.am.isSegmented)
1723       {
1724          /* Adding two byte for SO */
1725          hdrEstmt += 2;
1726       } 
1727       /* Eliminate MAC header */
1728       /* ccpu00135743 : Fix for MAC Hdr size calculation */
1729       /*5GNR: value of mac hdr length field changed to 8/16bits  */
1730       pduSz = RLC_MIN(macGrntSz, (sdu->sduSz + hdrEstmt));
1731       hdrEstmt += (pduSz < 255) ? RLC_MAC_HDR_SZ2 : RLC_MAC_HDR_SZ3;
1732
1733       macGrntSz -= hdrEstmt;
1734       /* kw005.201 Check for PDU Size is large enough.
1735        * Fix for ccpu00118973 
1736        * */
1737       if(macGrntSz <= 0)
1738       {
1739          break;
1740       }
1741
1742       /* Dont create new txBuf for segmented SDU */
1743       if (!sdu->mode.am.isSegmented)
1744       {
1745          /* Update txBuf */
1746          RLC_ALLOC_WC(gCb,txBuf, sizeof(RlcTx));
1747
1748          cmLListInit(&txBuf->pduLst);
1749
1750 #if (ERRCLASS & ERRCLS_ADD_RES)
1751          if (txBuf == NULLP)
1752          {
1753             uint32_t avblMem = 0;
1754             SRegInfoShow(gCb->init.region, &avblMem);
1755             DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1756                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1757             return;
1758          }
1759 #endif /* ERRCLASS & ERRCLS_RES */
1760
1761          rlcUtlStoreTxBuf(amDl->txBufLst, txBuf, amDl->txNext);
1762       }
1763       else
1764       {
1765          txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amDl->txNext);
1766       }
1767
1768       RLC_ALLOC_WC(gCb,pduInfo, sizeof(RlcDlPduInfo));
1769 #if (ERRCLASS & ERRCLS_ADD_RES)
1770       if (pduInfo == NULLP)
1771       {
1772          uint32_t avblMem = 0;
1773          SRegInfoShow(gCb->init.region, &avblMem);
1774          DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleSdus: Memory allocation failed UEID:%d CELLID:%d",
1775             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1776          return;
1777       }
1778 #endif /* ERRCLASS & ERRCLS_RES */
1779
1780       /*Initialize DL segment structure */
1781       pduInfo->lstEnt.next = NULLP;
1782       pduInfo->lstEnt.prev = NULLP;
1783       pduInfo->lstEnt.node = NULLP;
1784
1785       pduInfo->pdu = NULLP;
1786       pduInfo->amHdr.dc = 0;
1787       pduInfo->amHdr.p = 0;
1788       pduInfo->amHdr.si = 0;
1789       pduInfo->amHdr.so = 0;
1790
1791       pduInfo->amHdr.sn = amDl->txNext;
1792
1793       if (macGrntSz >= sdu->sduSz)
1794       {
1795          pdu = sdu->mBuf;     
1796          sdu->mBuf = NULLP; 
1797          /* Update Framing Info */
1798          if (sdu->mode.am.isSegmented) 
1799          {
1800             /*5GNR RLC_DL : SN should be same for all segment of a SDU*/
1801             pduInfo->amHdr.sn = sdu->mode.am.sn;
1802             pduInfo->amHdr.si = RLC_SI_LAST_SEG; /* binary 10 */
1803             pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1804             sdu->mode.am.isSegmented = FALSE;
1805
1806
1807             gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1808             //DU_LOG("\nINFO  -->  RLC_DL : 5GNRLOG: last segment of lcId %d SduId %u So %u macGrntSz\
1809             %u sduActSz %u sdu->sduSz %u\n",
1810             //          rbCb->lch.lChId, sdu->mode.am.sduId, pduInfo->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1811          }
1812          else
1813          {
1814             gRlcStats.amRlcStats.numRlcAmCellSduTx++;
1815          }
1816          amHdr          = &pduInfo->amHdr; 
1817          /* Create PDU with hdr and data */
1818          rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1819
1820          //DU_LOG("\nINFO  -->  Segmentation not required case: numPdu %d pdu  %p \n",rlcDatReq->pduInfo.numPdu, pdu);
1821
1822 #ifdef LTE_L2_MEAS_RLC
1823          rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, TRUE);
1824 #endif /*  LTE_L2_MEAS */
1825
1826          /* kw005.201 ccpu00117318, updating the statistics */
1827          rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
1828 #ifdef LTE_L2_MEAS
1829          if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
1830          {
1831             if(isSduSegmented)
1832             {
1833                *sduIdx    = dlIpThPut->lastSduIdx;
1834             }
1835             else
1836             {
1837                RLC_GETSDUIDX(*sduIdx);
1838                newIdx = TRUE;
1839             }
1840             rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1841             rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
1842                   sdu->mode.am.sduId, newIdx);
1843             /* Update the arrival time for each SDU */
1844             /* ccpu00143043 */
1845             if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
1846             {
1847                lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
1848                lchInfo.numSdus++;
1849             }
1850          }
1851 #endif
1852          sduMap.sduSz    = sdu->sduSz;
1853       }
1854       else 
1855       {
1856          /* Segmentation
1857           * Allocate buffer for next PDU
1858           * Remove the segmented portion from SDUQ 
1859           * Calculate the hdr with LI for SDU */
1860
1861          Buffer  *remSeg = NULLP;
1862
1863          //DU_LOG("\nINFO  -->  SDU segmentation case: numPdu %d pdu %p \n", rlcDatReq->pduInfo.numPdu, pdu);
1864 #ifdef LTE_L2_MEAS
1865          if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb,rbCb) ||
1866                RLC_MEAS_IS_DL_DELAY_MEAS_ON_FOR_RB(gCb,rbCb) || 
1867                RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb) )
1868          {
1869             /* If actual size of the sdu is equal to msgLen
1870              * then it is first segment of the SDU */
1871             if(sdu->actSz == sdu->sduSz)
1872             {
1873                RLC_GETSDUIDX(*sduIdx);
1874                newIdx = TRUE;
1875             }
1876             else
1877             {
1878                *sduIdx    = dlIpThPut->lastSduIdx;
1879             }
1880             rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
1881             rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
1882                   sdu->mode.am.sduId, newIdx);
1883             if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
1884             {
1885                /* If actual size of the sdu is equal to msgLen
1886                 * then it is first segment of the SDU */
1887                if(sdu->actSz == sdu->sduSz)
1888                {
1889                   segSduCnt++;
1890                }
1891             }
1892          }
1893 #endif
1894
1895          /* Segment the SDU to the size of the PDU and update header Info */
1896          ODU_SEGMENT_MSG(sdu->mBuf, macGrntSz, &remSeg);
1897          pdu = sdu->mBuf;      
1898          sdu->mBuf = remSeg;
1899
1900          /* Update SI and SN */
1901          if (sdu->mode.am.isSegmented) 
1902          {
1903             /*5GNR RLC_DL : SN should be same for all segment of a SDU.
1904              * Sdu was already segmented and segmenting again*/
1905             pduInfo->amHdr.sn = sdu->mode.am.sn;
1906             pduInfo->amHdr.si = RLC_SI_MID_SEG; /* binary 11 */
1907             pduInfo->amHdr.so = sdu->actSz - sdu->sduSz;
1908
1909             //DU_LOG("\nINFO  -->  RLC_DL : 5GNRLOG: mid segment of lcId %d SduId %u So %u macGrntSz %u sduActSz\
1910             %u sdu->sduSz %u\n",
1911             //         rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1912          }
1913          else
1914          {
1915             /*5GNR RLC_DL : This means it is the first*/
1916             pduInfo->amHdr.si = RLC_SI_FIRST_SEG; /* binary 01 */
1917             /*5GNR_RLC_DL : Store SN so that in sub-seqent SDU segments will use this SN*/
1918             sdu->mode.am.sn = pduInfo->amHdr.sn;
1919             pduInfo->amHdr.so = 0;
1920
1921             //DU_LOG("\nINFO  -->   RLC_DL : 5GNRLOG: First segment of lcId %d SduId %u So\
1922             %u macGrntSz %u sduActSz %u sdu->sduSz %u\n", 
1923             //         rbCb->lch.lChId, sdu->mode.am.sduId, txBuf->amHdr.so, macGrntSz, sdu->actSz, sdu->sduSz);
1924          }
1925
1926          amHdr = &pduInfo->amHdr; 
1927          /* Create PDU with hdr and data */
1928          rlcAmmCreatePdu(gCb,rbCb, amHdr, pduInfo, pdu);
1929
1930          sdu->mode.am.isSegmented = TRUE;
1931          sdu->sduSz -= macGrntSz;
1932          sduMap.sduSz = macGrntSz;
1933
1934 #ifdef LTE_L2_MEAS_RLC
1935          rlcUtlUpdSduSnMap(rbCb, sdu, rlcDatReq, FALSE);
1936 #endif /*  LTE_L2_MEAS */
1937
1938          amDl->nxtTx = sdu;
1939          nxtTxUpd    = TRUE;
1940       }
1941
1942       /* Update bo for boReport */
1943       amDl->bo -= sduMap.sduSz;
1944
1945       sduMap.sdu = sdu;
1946
1947       /* Update pduInfo */
1948       rlcDatReq->pduInfo.mBuf[rlcDatReq->pduInfo.numPdu] = pdu; 
1949       rlcDatReq->pduInfo.numPdu++;
1950       numNewPdu++;
1951       /* kw005.201 ccpu00117318, updating the statistics */
1952       gCb->genSts.pdusSent++;
1953       gRlcStats.amRlcStats.numRlcAmCellSduBytesTx = gRlcStats.amRlcStats.numRlcAmCellSduBytesTx + sduMap.sduSz;
1954       /* Update the RLC Tx buffer with the new PDU info */
1955       RLC_MEM_CPY(&pduInfo->sduMap, &sduMap, sizeof(RlcSduMap));
1956       pdu = NULLP;
1957
1958       macGrntSz -= sduMap.sduSz;
1959       /* Get next sdu for assembly */
1960       RLC_LLIST_NEXT_SDU(amDl->sduQ, sdu);
1961
1962    } /*End of pduSz loop */
1963
1964    rlcDatReq->pduSz = macGrntSz;
1965    /* Updating nxtTx to sdu in the Q */
1966    if (!nxtTxUpd)
1967       amDl->nxtTx = sdu;
1968
1969 #ifdef LTE_L2_MEAS
1970    if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && 
1971          (rbCb->rlcId.rbType == CM_LTE_DRB))
1972    {
1973       numSdus = 0;
1974       currSduIdx = 0;
1975       l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
1976       rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
1977       if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP))
1978       {
1979          for (lchIdx = 0; ((lchIdx < l2MeasTb->numLchInfo)
1980                   && (lchIdx < RLC_MAX_ACTV_DRB )); lchIdx++)
1981          {
1982             if (l2MeasTb->lchInfo[lchIdx].lcId == rbCb->lch.lChId)
1983             {
1984                /* Lch Info already added in Retx procedure */
1985                break;
1986             }
1987          }
1988          if (lchIdx < RLC_MAX_ACTV_DRB)
1989          {
1990             if (lchIdx == l2MeasTb->numLchInfo)
1991             {
1992                l2MeasTb->lchInfo[lchIdx].lcId = rbCb->lch.lChId;
1993                l2MeasTb->lchInfo[lchIdx].numSdus = 0;
1994                l2MeasTb->numLchInfo++;
1995             }
1996             dstLchInfo = &l2MeasTb->lchInfo[lchIdx];
1997             currSduIdx = l2MeasTb->lchInfo[lchIdx].numSdus;
1998             while ((numSdus < lchInfo.numSdus) && (currSduIdx < RLC_L2MEAS_SDUIDX)) 
1999             {
2000                dstLchInfo->sduInfo[currSduIdx].arvlTime = lchInfo.sduInfo[numSdus].arvlTime;
2001                dstLchInfo->sduInfo[currSduIdx].isRetxPdu = FALSE;
2002                numSdus++;
2003                currSduIdx++;
2004             }
2005             l2MeasTb->lchInfo[lchIdx].numSdus += numSdus;
2006          }
2007       }
2008       /* Fix Klock warning */
2009       if(l2MeasTb != NULLP)
2010       {
2011          l2MeasTb->txSegSduCnt += segSduCnt;
2012       }
2013    }
2014    *totMacGrant -= (oldBo - amDl->bo);
2015 #endif
2016
2017    if(discSduInfo->numSduIds != 0)
2018    {
2019       /* Sap control block */
2020       RlcUiKwuDiscSduCfm(&rlckwuSap->pst, rlckwuSap->suId, discSduInfo);
2021    }
2022    else
2023    {
2024       RLC_SHRABL_STATIC_BUF_FREE(rlckwuSap->pst.region, rlckwuSap->pst.pool, discSduInfo, sizeof(KwuDiscSduInfo));
2025    }
2026
2027    DU_LOG("\nDEBUG  -->  RLC_DL : rlcAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2028       amDl->bo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2029    return;
2030 }
2031
2032 /**
2033  * @brief Private handler to check if the poll bit needs to be set for data PDU
2034  *
2035  * @details
2036  *    Its a private function called by kwProcessSdus, to checks if the 
2037  *    polling bit needs to be set for any RLC data PDU and updates the 
2038  *    same.
2039  *    - For the new PDUs, if the counters exceed the configured 
2040  *      pduWoPoll/byteWoPoll values, return poll bit.
2041  *    - For the PDUs/portion of PDUs, if the SDU list / retxBuf is 
2042  *      empty, return poll bit.
2043  *    - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr 
2044  *
2045  * @param[in]  rCb      RLC instance control block
2046  * @param[in]  rbCb     RB control block 
2047  * @param[in]  newPdu   Flag to indicate if its a new AMD PDU. 
2048  * @param[in]  bufSz    Length of the PDU
2049  *
2050  * @return  Bool 
2051  *      -# 1 - To set the poll bit
2052  *      -# 0 - Poll bit is not set
2053  *
2054  */
2055 static bool rlcAmmDlCheckAndSetPoll(RlcCb *gCb, RlcDlRbCb *rbCb, bool newPdu, MsgLen bufSz)
2056
2057    bool     pollBit = FALSE;
2058    RlcAmDl   *amDl = &(rbCb->m.amDl);
2059
2060    /* If it's a new PDU increment PDU without poll and bytes without poll
2061     and check if they cross the configured number of poll pdu and poll bytes*/ 
2062    if (newPdu)
2063    {
2064       amDl->pduWoPoll++;
2065       /* Patch kw004.201 */
2066       amDl->byteWoPoll += bufSz;
2067
2068      if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) || 
2069          ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte))) 
2070      {
2071         pollBit = TRUE;
2072      }
2073    }
2074
2075    /* Check if both tx/retx buffer are empty or if tx window is stalled */
2076    if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2077        RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2078    {
2079       pollBit = TRUE;
2080    }
2081    
2082    if (pollBit)
2083    {
2084       amDl->pduWoPoll  = 0;
2085       amDl->byteWoPoll = 0;
2086
2087       amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2088
2089       DU_LOG("\nINFO  -->  RLC_DL : rlcAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d", 
2090          amDl->pollSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2091
2092       /* kw005.201: Fix for poll retransmission timer. 
2093        * Timer is stopped if it is already running and 
2094        * then starting the timer. Fixes crs 
2095        * ccpu00117216 and ccpu00118284 .
2096        * */
2097       if( TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR) )
2098       {
2099          rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2100       }
2101
2102       rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
2103    }
2104
2105    return (pollBit);
2106 }
2107
2108 /**
2109  * @brief Private handler to create AMD PDU 
2110  *
2111  * @details
2112  *    This function constructs header and concatenate it with the data for
2113  *    the PDU. It also updates the txBuf with the created PDU.
2114  *
2115  * @param[in]  gCB         RLC instance control block
2116  * @param[in]  rbCb        Downlink RB control block
2117  * @param[in]  amHdr       AM header
2118  * @param[in]  RlcDlPduInfo Pointer to PduInfo
2119  * @param[in]  pdu         PDU buffer 
2120  *
2121  *  @return  Void
2122  *
2123  */
2124 static void rlcAmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmHdr *amHdr,
2125 RlcDlPduInfo *pduInfo, Buffer *pdu)
2126 {
2127    uint8_t   hdr[RLC_MAX_HDRSZ];
2128    uint16_t  idx;
2129    RlcTx     *txBuf;
2130    MsgLen    pduSz;
2131    RlcAmDl   *amDl = &(rbCb->m.amDl);
2132
2133    /* Update sn */
2134    amHdr->sn = amDl->txNext;
2135
2136    /*5GNR RLC_DL : Increment txNext only if no segmentation of it is a last segment */
2137    if((!amHdr->si) || (amHdr->si == RLC_SI_LAST_SEG))
2138    {
2139       //DU_LOG("\nINFO  -->  RLC_DL : 5GNRLOG: no segment/last seg SDU with lcId %d Sn %u txNext %u So %u\n",
2140       //          rbCb->lch.lChId, amHdr->sn, amDl->txNext, amHdr->so);
2141       amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2142    }
2143
2144    /* Update hdr Info */
2145    ODU_GET_MSG_LEN(pdu, &pduSz);
2146
2147    /* passing newPDU = TRUE*/
2148    amHdr->p = rlcAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2149
2150    /* Construct header with the available hdr Info, set isSegment to FALSE */
2151    rlcConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2152
2153    /* Concatenate hdr and data */
2154    ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx+1, pdu);
2155    
2156    txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2157    rlcCpyMsg(gCb,pdu,&(pduInfo->pdu));
2158    pduInfo->pduSz = pduSz;
2159    pduInfo->hdrSz = idx+1;
2160
2161    /*Update estHdrSz. deduct current hdrSz */
2162     amDl->estHdrSz -= pduInfo->hdrSz;
2163     /* Reestimate estHdrSz for mid and last seg */
2164     if(amHdr->si & 0x1)
2165     {
2166        amDl->estHdrSz += ((amHdr->si == RLC_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2167     }
2168
2169    cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2170    pduInfo->lstEnt.node = (PTR)pduInfo;
2171
2172    gCb->genSts.bytesSent += pduSz;
2173    
2174    return;
2175 }
2176
2177 /**
2178  * @brief Private handler to remove the retx PDU from the rbCb
2179  *
2180  * @details
2181  *    This function releases a retx PDU stored on DL portion of rbCb.
2182  *    It also updates the BO if wtForAck flag is not set which implies
2183  *    that it is not sent out yet.
2184  *
2185  * @param[in]  gCb        RLC instance control block
2186  * @param[in]  retx       retransmit PDU to be removed
2187  * @param[in]  rbCb       Radio Bearer Control Block
2188  *
2189  * @return Void 
2190  *
2191  */
2192 static Void rlcRemRetxPdu(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2193 {
2194    cmLListDelFrm(&RLC_AMDL.retxLst, &retx->lstEnt); 
2195
2196    if( RLC_AMDL.retxLst.count == 0)
2197    {
2198       RLC_AMDL.nxtRetx = NULLP;
2199    }
2200
2201    if(retx->pendingReTrans == TRUE)
2202    {
2203       RLC_AMDL.retxBo -= retx->segSz;
2204       RLC_AMDL.estHdrSz -= retx->hdrSz;
2205    }
2206
2207    rlcUtlAddReTxPduToBeFreedQueue(gCb, retx);
2208    rlcUtlRaiseDlCleanupEvent(gCb);
2209
2210    return;
2211 }
2212
2213 /**
2214  * @brief Private handler to mark a retx PDU for further retransmission
2215  *
2216  * @details
2217  *    This function sets a retx PDU that has not been ACKed in the   
2218  *    received Status PDU for futher retransmission. If the retransmission
2219  *    limit is reached, it releases the retx PDU and informs the higher
2220  *    layers about the same.
2221  *
2222  * @param[in]  gCb        RLC instance control block 
2223  * @param[in]  retx       retransmit PDU to be removed
2224  * @param[in]  rbCb       Radio Bearer Control Block
2225  *
2226  * @return Void 
2227  *
2228  */
2229 static Void rlcAmmDlMarkPduForReTx(RlcCb *gCb,RlcDlRbCb *rbCb,RlcRetx *retx)
2230 {
2231    if (RLC_AMDL.maxReTxReached == TRUE)
2232    {
2233       return;
2234    }
2235   
2236    if(retx->pendingReTrans == FALSE)
2237    {
2238       retx->pendingReTrans = TRUE;
2239       ++retx->retxCnt;
2240
2241       RLC_AMDL.retxBo   += retx->segSz;
2242       RLC_AMDL.estHdrSz += retx->hdrSz;
2243
2244       if (retx->retxCnt > RLC_AMDL.maxRetx)
2245       {
2246          /* RLC_DL_MAX_RETX fix */
2247          /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2248          /* preparation of RLC PDUs and adding the same to Tx Buffer */
2249          /* This condition is to avoid sending StaIndication more than once */
2250          if (TRUE != rbCb->m.amDl.maxReTxReached)
2251          {
2252             rbCb->m.amDl.maxReTxReached = TRUE;
2253             rbCb->m.amDl.bo = 0;
2254             rbCb->m.amDl.cntrlBo = 0;
2255             rbCb->m.amDl.retxBo = 0;
2256             /* Sending BO update to SCH */
2257             rlcUtlSendDedLcBoStatus(gCb, rbCb, 0,0,0,0);
2258             rlcAmmSndStaInd(gCb, rbCb, retx);
2259             gRlcStats.amRlcStats.numDLMaxRetx++;
2260          }
2261
2262          rlcRemRetxPdu(gCb,rbCb, retx);
2263          
2264          return;
2265       }
2266
2267
2268       if (RLC_AMDL.nxtRetx == NULLP)
2269       {
2270          RLC_AMDL.nxtRetx = retx;
2271       }
2272
2273       gRlcStats.amRlcStats.numDLRetransPdus++;
2274    }
2275
2276
2277    return;
2278 }
2279
2280 /**
2281  * @brief Private handler to check if SDU is completely deliverd and
2282  *        send higher layers data confirmation
2283  *
2284  * @details 
2285  *    This function sends higher layers data confirmation for SDUs which
2286  *    have been successfully delivered to the peer RLC entity.
2287  *
2288  * @param[in]  gCb      RLC instance control block
2289  * @param[in]  rbCb     Radio Bearer Control Block
2290  * @param[in]  sduLst   List of SDUs that were part of the PDU
2291  * @param[in]  numSdu   Number of SDUs in the list
2292  *
2293  * @return Void 
2294  *
2295  */
2296 static Void rlcAmmDlCheckIsSDUDelivered
2297 (
2298 RlcCb            *gCb,
2299 RlcDlRbCb        *rbCb,
2300 RlcSduMap        *sduMap,
2301 KwuDatCfmInfo    **datCfm
2302 )
2303 {
2304    RlcSdu *sdu;
2305    
2306    sdu = sduMap->sdu;
2307
2308    sdu->mode.am.rcvdSz += sduMap->sduSz;
2309
2310    /* send a dat cfm if all the bytes of the sdu have been received */
2311    if (sdu->mode.am.rcvdSz == sdu->actSz)
2312    {
2313       /* Send DatCfm for this sdu */
2314       if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2315       {
2316          (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2317       }
2318       else
2319       {
2320          /* This is an error that should never happen, we should resize
2321           * the #define to a larger value or check why we need to 
2322           * send so many confirms in one go
2323           * Confrims to PDCP are being dropped in this case
2324           */
2325          RlcKwuSapCb    *rlckwuSap;
2326          rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2327          RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, *datCfm);
2328
2329          RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2330
2331 #if (ERRCLASS & ERRCLS_ADD_RES)
2332          if (*datCfm == NULLP)
2333          {
2334             DU_LOG("\nERROR  -->  RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2335                   rbCb->rlcId.ueId,
2336                   rbCb->rlcId.cellId);
2337             return;
2338          }
2339 #endif /* ERRCLASS & ERRCLS_RES */
2340
2341          (*datCfm)->numSduIds = 0;
2342          (*datCfm)->rlcId = rbCb->rlcId;
2343          /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2344           * new allocation of datCfm */
2345          (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2346       }
2347
2348       /* Remove SDU from the sduQ */
2349       cmLListDelFrm(&RLC_AMDL.sduQ, &sdu->lstEnt);
2350       rlcUtlAddSduToBeFreedQueue(gCb, sdu);
2351       rlcUtlRaiseDlCleanupEvent(gCb);
2352    }
2353
2354    return;
2355
2356
2357 /**
2358  * @brief Private handler to mark a PDU successful.
2359  *
2360  * @details
2361  *    This function is called when we receive a STATUS pdu that marks
2362  *    a PDU as successful. It releases the PDU from RLC entity and 
2363  *    informs PDCP of successful SDUs delivered as a result of this PDU.
2364  *
2365  * @param[in]  gCb        RLC instance control block  
2366  * @param[in]  rbCb       Radio Bearer Control Block
2367  * @param[in]  sn         SN that is successfully delivered to the peer 
2368  *
2369  * @return Void 
2370  *
2371  */
2372 static Void rlcAmmDlProcessSuccessfulTxPdu
2373 (
2374 RlcCb            *gCb,
2375 RlcDlRbCb        *rbCb,
2376 RlcSn            sn,
2377 KwuDatCfmInfo    **datCfm
2378 )
2379 {
2380    CmLList *pduNode;
2381   
2382    RlcTx *txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2383    
2384    if (txBuf == NULLP)
2385    {
2386            return;
2387    }
2388    pduNode = txBuf->pduLst.first;
2389    while(pduNode)
2390    {
2391       RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2392       rlcAmmDlCheckIsSDUDelivered(gCb,
2393                               rbCb,  
2394                               &(pduInfo->sduMap), 
2395                               datCfm);
2396       pduNode = pduNode->next;
2397    }
2398    
2399    rlcUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2400    rlcUtlRaiseDlCleanupEvent(gCb);
2401    /* so that it is not processed again */
2402    rlcUtlRemovTxBuf(RLC_AMDL.txBufLst, txBuf, gCb);
2403
2404    return;
2405 }
2406
2407 /**
2408  * @brief  Handler to send Status Indication to PDCP
2409  *
2410  * @details
2411  *    This function is used to send status indication to PDCP when the 
2412  *    maximum retransmission threshold value is reached for a PDU.
2413  * 
2414  * @param[in] gCb    RLC instance control block
2415  * @param[in] rbCb   RB control block 
2416  * @param[in] retx   The PDU/segment that failed max re-transmissions
2417  *
2418  * @return  Void
2419  *
2420  */
2421 static Void rlcAmmSndStaInd
2422 (
2423 RlcCb       *gCb,
2424 RlcDlRbCb   *rbCb,
2425 RlcRetx     *retx
2426 )
2427 {
2428    KwuStaIndInfo   *staInd;
2429    RlcKwuSapCb      *rlckwuSap;
2430
2431    /* Sap control block */
2432    rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2433
2434    /* Allocate memory for staInd Info */
2435    RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2436
2437 #if (ERRCLASS & ERRCLS_ADD_RES)
2438    if (staInd == NULLP)
2439    {
2440       DU_LOG("\nERROR  -->  RLC_DL : Memory allocation failed UEID:%d CELLID:%d",
2441             rbCb->rlcId.ueId,
2442             rbCb->rlcId.cellId);
2443       return;
2444    }
2445 #endif /* ERRCLASS & ERRCLS_RES */
2446
2447    /* Fill staInd Info */ 
2448    RLC_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));    
2449    
2450    staInd->numSdu = 1;
2451    staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2452
2453 #ifdef KW_PDCP
2454 #else
2455    RlcUiKwuStaInd(&rlckwuSap->pst, rlckwuSap->suId, staInd);
2456 #endif /* KW_PDCP */
2457
2458    return;
2459 }
2460
2461 /**
2462  * @brief  Handler to get the next node to be retransmitted from retxLst
2463  *
2464  * @details
2465  *    This function is used to get the next node to be retransmitted 
2466  *    from the retxLst
2467  *            
2468  *  @param[in] gCb     RLC instance control block 
2469  *  @param[in] retx    The PDU/segment after which to find a node to be 
2470  *                     retransmitted
2471  *
2472  *  @return  Void 
2473  *
2474  */
2475 static void rlcGetNxtRetx(RlcCb *gCb, RlcRetx **retx)
2476 {
2477    CmLList *tNode;
2478
2479    do
2480    {
2481       tNode = &((*retx)->lstEnt);
2482       tNode = tNode->next;
2483       
2484       if (tNode)
2485       {
2486          *retx = (RlcRetx *)tNode->node;
2487       }
2488       else
2489       {
2490          *retx = NULLP;
2491          return;
2492       }
2493    }while((*retx)->pendingReTrans == FALSE);
2494
2495    return;
2496 }
2497
2498 /**
2499  * @brief  Handler to process the re-establishment request received from UIM
2500  *
2501  * @param[in]  gCb         RLC instance control block
2502  * @param[in]  rlcId       Identity of the RB in the UE/Cell for which 
2503  *                         re-establishment is to be done
2504  * @param[in]  rbCb        Downlink RB control block (rbCb is freed in this
2505  *                         function)
2506  *
2507  * @return  Void 
2508  *
2509  */
2510 Void rlcAmmDlReEstablish
2511 (
2512 RlcCb         *gCb,
2513 CmLteRlcId   rlcId,
2514 RlcDlRbCb     *rbCb
2515 )
2516 {
2517    /* create a new AM DL RB, reset it and replace in the UeCb*/
2518    RlcDlUeCb   *ueCb;
2519    RlcDlRbCb   *resetRb;
2520    RlcAmDl* newAmDl;
2521    RlcAmDl* oldAmDl;
2522    RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2523    
2524    /* ccpu00135170 Removing KLOCK warning */
2525    if(resetRb == NULLP)
2526    {
2527       return;
2528    }
2529
2530    RLC_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2531    RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(RlcAmDl));
2532
2533 /* AGHOSH changes start */
2534    /* restore the old AM values */
2535    newAmDl = &resetRb->m.amDl;
2536    oldAmDl = &rbCb->m.amDl;
2537
2538    newAmDl->pollPdu = oldAmDl->pollPdu;
2539    newAmDl->pollByte = oldAmDl->pollByte;
2540    newAmDl->maxRetx = oldAmDl->maxRetx;
2541    newAmDl->snLen   = oldAmDl->snLen;
2542    newAmDl->snModMask   = oldAmDl->snModMask;
2543    newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2544    rbCb->boUnRprtdCnt = (uint32_t)0;
2545    rbCb->lastRprtdBoToMac = (uint32_t)0;
2546    cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1); 
2547 /* AGHOSH changes end */
2548  
2549    if (ROK != rlcDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2550    {
2551       DU_LOG("\nERROR  -->  RLC_DL : UeId [%d]: UeCb not found RBID;%d",
2552                rlcId.ueId,
2553                rlcId.rbId);
2554       return;
2555    }
2556    
2557    if(rlcId.rbType == CM_LTE_SRB)
2558    {
2559       ueCb->srbCb[rlcId.rbId] = resetRb;
2560    }
2561    else
2562    {
2563       ueCb->drbCb[rlcId.rbId] = resetRb;
2564    }
2565    /* update into the logical channel array also */
2566    ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2567  
2568    if((resetRb->rlcId.rbType == CM_LTE_SRB)
2569                 &&(resetRb->rlcId.rbId == 1))
2570    {
2571       /* To stop the traffic on SRB2 and other DRBs*/
2572       rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2573    }
2574    else 
2575    {
2576       rlcDlUtlSetReestInProgressForRB(gCb, resetRb);      
2577    }
2578
2579    /* allocate the TX array again */
2580 #ifndef  LTE_TDD
2581    uint32_t hashIndex;
2582    RLC_ALLOC(gCb,
2583                    resetRb->m.amDl.txBufLst,
2584                    (RLC_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2585    for(hashIndex = 0; hashIndex < RLC_TX_BUF_BIN_SIZE; hashIndex++)
2586    {
2587            cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2588    }
2589 #endif
2590    /* send the old rb of deletion */
2591    rlcAmmFreeDlRbCb(gCb,rbCb); 
2592
2593
2594    /* TODO: for now we are re-settting the re-establishment flag here
2595       this needs to be fixed
2596       There should be a proper intreface to resume the RBs */
2597    if(rlcId.rbType == CM_LTE_SRB)
2598    {
2599       rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2600    }
2601    else
2602    {
2603       rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2604    }      
2605       
2606    return;
2607 }
2608
2609 /**
2610  * @brief  Handler to discard a SDU.
2611  *
2612  * @details
2613  *    This function is used to discard a SDU after receiving
2614  *    the Discard Request from UIM. The SDU is discarded if its 
2615  *    available and is not mapped to any PDU yet.
2616  *   
2617  * @param[in] gCb     RLC instance control block
2618  * @param[in] rbCb    RB control block 
2619  * @param[in] sduId   Sdu ID of the SDU to be discarded
2620  *
2621  *  @return  S16
2622  *     -# ROK      In case of successful discard
2623  *     -# RFAILED  In case the SDU is not found or already mapped
2624  */
2625 S16 rlcAmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId )
2626 {
2627    return (RFAILED);
2628
2629
2630 /**
2631  * @brief  Handler for Poll retransmit timer expiry
2632  *
2633  * @details
2634  *    This function is used to handle events upon expiry of Poll 
2635  *    retransmit timer.
2636  *  
2637  * @param[in] gCb    RLC instance control block
2638  * @param[in] rbCb   Downlink RB control block 
2639  *
2640  * @return  Void 
2641  */
2642 Void rlcAmmPollRetxTmrExp(RlcCb *gCb,RlcDlRbCb *rbCb)
2643 {
2644    RlcRetx        *retx; 
2645    RlcAmDl        *amDl = &(rbCb->m.amDl);
2646    RlcSn          sn;
2647    RlcTx          *txBuf;
2648
2649    /* kw003.201 - Correcting the logic for determmining whether to do   */
2650    /*             any transmission of PDU. As per the spec section      */
2651    /*             5.2.2.3, if there is any to transmit or retransmit,   */
2652    /*             do nothing. Else, pick up the VT(S) -1 for retx       */
2653    /*             We have nothing to transmit if window is stalled or   */
2654    /*             there are no SDUs to be transmitted or if there are   */
2655    /*             PDUs to be retransmitted.                             */
2656    if(CM_LTE_SRB == rbCb->rlcId.rbType)
2657    {
2658       gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
2659    }
2660    else
2661    {
2662       gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
2663    }
2664
2665    if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) || 
2666         RLC_AM_IS_TRANS_WIN_STALLED(amDl)) 
2667    {
2668       sn = (amDl->txNext - 1) & amDl->snModMask;
2669       txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2670
2671       if (txBuf != NULLP)
2672       {
2673          rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn); 
2674          
2675          if (RLC_AMDL.nxtRetx == NULLP)
2676          {
2677             RLC_AMDL.nxtRetx = retx;
2678          }
2679          
2680          rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);         
2681          return;
2682       }
2683       /* Get the last node in retxLst */
2684       RLC_LLIST_LAST_RETX(amDl->retxLst, retx);
2685
2686       /* Unset wtForAck flag for the NACK PDUs */ 
2687       if (retx != NULLP)
2688       {
2689          rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
2690          rlcAmmSendDedLcBoStatus(gCb, rbCb, &RLC_AMDL);         
2691       }
2692    }
2693
2694    return;
2695
2696
2697 /**
2698  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
2699  *         NACK PDU.
2700  *
2701  * @details 
2702  *    This function is used to handle ACKs for the PDUs remaining after the 
2703  *    last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and 
2704  *    sends DatCfm to PDCP for the same.
2705  *
2706  * @param[in]  gCb         RLC instance control block
2707  * @param[in]  rbCb        Downlink Radio Bearer control block
2708  * @param[in]  mAckSn      The ACK SN after doing the base modulus
2709  * @param[in]  rextNode    Next node in the re-transmission buffer          
2710  *
2711  * @return  Void
2712  *
2713  */
2714
2715 static Void rlcAmmDlUpdateTxAndReTxBufForAckSn
2716 (
2717 RlcCb            *gCb,
2718 RlcDlRbCb        *rbCb,
2719 RlcSn            mAckSn,
2720 CmLList         *retxNode,
2721 KwuDatCfmInfo   **datCfm
2722 )
2723 {
2724    RlcSn    mSn;
2725    RlcSn    sn;
2726    RlcRetx  *retx;
2727    RlcTx    *txBuf;
2728
2729    /* Remove pdus/segs from retxLst */ 
2730    while (retxNode)
2731    {
2732       retx = (RlcRetx *)(retxNode->node);
2733       retxNode = retxNode->next;
2734       MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2735       if (mSn < mAckSn) 
2736       {
2737          rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2738       }
2739    }
2740
2741    /* For the remaining; pdus not acknowldeged by the NACK_SN but being
2742       acknowledged by the ACK_SN*/
2743    /* start from the starting of the transmission window and remove till just
2744       before ACK_SN*/
2745    mSn = 0;       /* same as MODAMT(RLC_AMDL.txNextAck, mSn, RLC_AMDL.txNextAck);*/
2746    sn = RLC_AMDL.txNextAck;
2747    while(mSn < mAckSn)
2748    {
2749       txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2750       if (txBuf != NULLP)
2751       {
2752          
2753          DU_LOG("\nDEBUG  -->  RLC_DL : rlcAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
2754                  "with sn = %d UEID:%d CELLID:%d",
2755                  sn,
2756                  rbCb->rlcId.ueId,
2757                  rbCb->rlcId.cellId);
2758
2759          rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2760       }
2761       
2762       sn = (sn + 1) & RLC_AMDL.snModMask;
2763       MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2764    }
2765
2766    return;
2767 }
2768
2769 /**
2770  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
2771  *         NACK PDU.
2772  *
2773  * @details 
2774  *    This function is used to handle ACKs for the PDUs remaining after the 
2775  *    last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and 
2776  *    sends DatCfm to PDCP for the same.
2777  *
2778  * @param[in]  gCb         RLC instance control block
2779  * @param[in]  rbCb        Downlink Radio Bearer control block
2780  * @param[in]  mAckSn      The ACK SN after doing the base modulus
2781  * @param[in]  rextNode    Next node in the re-transmission buffer          
2782  *
2783  * @return  Void
2784  *
2785  */
2786 static Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn
2787 (
2788 RlcCb            *gCb,
2789 RlcDlRbCb        *rbCb,
2790 RlcSn            sn,
2791 RlcSn            mNackSn,
2792 CmLList         **retxNode,
2793 KwuDatCfmInfo   **datCfm
2794 )
2795 {
2796    RlcSn    mSn;
2797    RlcRetx  *retx;
2798    RlcTx    *txBuf=NULLP;
2799
2800    while (*retxNode)
2801    {
2802       retx = (RlcRetx *)((*retxNode)->node);
2803       MODAMT(retx->amHdr.sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2804       if (mSn < mNackSn)
2805       {
2806          (*retxNode) = (*retxNode)->next;
2807          rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2808       }
2809       else
2810       {
2811          break;
2812       }
2813    }
2814
2815    /* Remove all pdus with SN < NACK_SN from the transmission buffer */ 
2816    MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2817    while (mSn < mNackSn)
2818    {
2819       /* this if check seems redundant,why should mSn ever be mTxSn 
2820          (which actually is VT(A) */
2821       txBuf = rlcUtlGetTxBuf(RLC_AMDL.txBufLst, sn);
2822       if ((txBuf != NULLP)) 
2823       {
2824          DU_LOG("\nDEBUG  -->  RLC_DL : rlcHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
2825                sn,
2826                rbCb->rlcId.ueId,
2827                rbCb->rlcId.cellId);
2828
2829          /* Remove pdus from txBuf */
2830          rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2831       }
2832
2833       sn = (sn + 1) & RLC_AMDL.snModMask;
2834       MODAMT(sn, mSn, RLC_AMDL.txNextAck,RLC_AMDL.snModMask);
2835    }
2836    
2837    return;
2838 }
2839
2840
2841 /**
2842  * @brief  Handler to form construct AM header
2843  *
2844  * @details 
2845  *    This function is used to construct am header with the available header
2846  *    elements.
2847  *
2848  * @param[in] gCb    RLC instance control block
2849  * @param[in] amHdr  AM Header
2850  * @param[in] isSeg  Check for Segmentation of PDU
2851  * @param[in] hdr    Header field
2852  * @param[in] idx    Index
2853  *  
2854  * @return Void            
2855  *
2856  */
2857 static void rlcConstructAmHdr(RlcAmHdr *amHdr, uint8_t *hdr, uint8_t snLen, uint16_t *idx)
2858 {
2859    *idx = 0;
2860     hdr[0] = RLC_DATA_BITMASK;
2861     
2862     hdr[0] = hdr[0] | (amHdr->p << 6);
2863     hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
2864    if(snLen == RLC_AM_CFG_12BIT_SN_LEN)
2865    {
2866       hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0xF00) >> 8);
2867       hdr[1] =  (uint8_t)(amHdr->sn & 0x0FF);
2868       (*idx)++;
2869    }
2870    else
2871    {
2872       hdr[0] = hdr[0] | (uint8_t)((amHdr->sn & 0x30000) >> 16);
2873       hdr[1] =  (uint8_t)((amHdr->sn & 0xFF00) >> 8);
2874       (*idx)++;
2875       hdr[2] =  (uint8_t)(amHdr->sn & 0xFF);
2876       (*idx)++;
2877    }
2878     
2879    if ((amHdr->si == RLC_SI_MID_SEG) || (amHdr->si == RLC_SI_LAST_SEG))                                      
2880    {
2881       (*idx)++;
2882       hdr[(*idx)] = (uint8_t)((amHdr->so & 0xFF00)>> 8);
2883       (*idx)++;
2884       hdr[(*idx)] = (uint8_t)(amHdr->so & 0xFF);
2885    }                                                        
2886
2887    return;
2888 }
2889
2890 /**
2891  * @brief  This function adds a retx PDU to list of retx PDUs
2892  *
2893  * @details
2894  *    kw003.201 - Poll expiry may cause an SN to be added to retx 
2895  *                out of sequence and hence all additions to retx 
2896  *                must validate that they are added in sequence   
2897  *
2898  * @param[in] amDl   AM Downlink Control Block
2899  * @param[in] retx   Retransmit PDU
2900  * 
2901  * @return Void
2902  *            
2903  */
2904 static Void rlcAmmAddPduToRetxLst(RlcAmDl *amDl,RlcRetx *retx)
2905 {
2906    CmLList   *node;
2907    RlcRetx    *tRetx;
2908    RlcSn      tMSn;
2909    RlcSn      retxMSn;
2910    
2911    node = amDl->retxLst.last;
2912    MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
2913    while(node != NULLP)
2914    {
2915       tRetx = (RlcRetx *)(node->node);
2916       MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
2917       if (tMSn > retxMSn)
2918       {
2919          node = node->prev;
2920       }
2921       else
2922       {
2923          break;
2924       }
2925    }
2926    if (node)
2927    {
2928       amDl->retxLst.crnt = node;
2929       cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
2930       retx->lstEnt.node = (PTR)retx;
2931    }
2932    else
2933    {
2934       amDl->retxLst.crnt = amDl->retxLst.first;
2935       cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
2936       retx->lstEnt.node = (PTR)retx;
2937    }
2938
2939    if (amDl->nxtRetx == NULLP)
2940    {
2941       amDl->nxtRetx = retx;
2942    }
2943
2944    return;
2945 }
2946
2947 /**
2948  * @brief Handler to Move the PDU from txBuf to re-transmission buffer 
2949  *
2950  * @details
2951  *    This function is used to move the PDU from the txBuf to re-transmit buffer
2952  *
2953  * @param[in]  gCb         RLC instance control block
2954  * @param[in]  amDl        AM Downlink Control Block 
2955  * @param[in]  retx        node in the reTx buffer to be moved to, allocated by
2956  *                         this function
2957  * @param[in]  sn          SN in the tx buffer which needs to be moved
2958  * 
2959  * @return Void
2960  *            
2961  */
2962
2963 static Void rlcAmmDlMoveFrmTxtoRetxBuffer
2964 (
2965 RlcCb          *gCb,
2966 RlcAmDl        *amDl,
2967 RlcRetx        **retx,
2968 RlcSn          sn
2969 )
2970 {
2971    RlcTx* txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2972
2973    if (txBuf == NULLP)
2974    {
2975            return;
2976    }
2977    while(txBuf->pduLst.first)
2978    {
2979       RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
2980       RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
2981
2982 #if (ERRCLASS & ERRCLS_ADD_RES)
2983       if (*retx == NULLP)
2984       {
2985               DU_LOG("\nERROR  -->  RLC_DL : Memory allocation failed");
2986               return;
2987       }
2988 #endif /* ERRCLASS & ERRCLS_RES */
2989
2990       /* Move Sdu byte segment from TX buf to retx buf*/
2991       rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, 
2992             amDl, 
2993             retx, 
2994             pduInfo);
2995       
2996       /* Delete node from the txBuf Pdu lst */
2997       cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
2998       RLC_FREE(gCb, pduInfo, sizeof(RlcDlPduInfo));
2999    }
3000    /* Remove PDU from txBuf */
3001    rlcUtlDelTxBuf(amDl->txBufLst, txBuf,gCb); 
3002    
3003    return;
3004 }
3005
3006
3007
3008 /*
3009  * @brief
3010  *    function to free/release the Acknowledged mode RBCB buffers
3011  *
3012  * @details
3013  *    This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3014  *    retransmission Buffer and reciption Buffers
3015  *
3016  * @param [in]   gCb    - RLC instance control block
3017  * @param [in]   rbCb   - Downlink RB Control Block
3018  *
3019  * @return Void
3020  */
3021 Void rlcAmmFreeDlRbCb(RlcCb  *gCb,RlcDlRbCb  *rbCb)
3022 {
3023    /* stop the re-transmission timer */
3024    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMDL_POLL_RETX_TMR))
3025    {
3026       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMDL_POLL_RETX_TMR);
3027    }
3028
3029    /* store the entire Rb pointer */      
3030    rbCb->rlsLnk.node = (PTR)rbCb;
3031    cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3032
3033    /* the sdu queue */
3034    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3035
3036    rlcUtlRaiseDlCleanupEvent(gCb);
3037    
3038    return;
3039 }
3040
3041 /**
3042  * @brief  Handler to create STATUS Pdu
3043  *
3044  * @details
3045  *    This function is used to create status pdu 
3046  *
3047  * @param[in] gCb        RLC instance control block
3048  * @param[in] rbCb       Downlink RB control block
3049  * @param[in] rlcDatReq   The data to be passed to MAC
3050  *
3051  * @return Void
3052  *
3053  */
3054 static void rlcAmmCreateStatusPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
3055 {
3056     RlcSn          sn;                      /* sequence number */
3057     RlcSn          ack_sn;                  /* Ack sequence number */
3058     Buffer        *mBuf;           /* control pdu buffer */
3059     MsgLen        cntrlPduSz;          /* control pdu size */
3060     uint8_t       cntrlPdu[RLC_MAX_CNTRL_FIELDS];   /* control pdu to be added to mBuf */
3061     RlcUdxDlStaPdu   *pStaPdu;
3062     uint16_t         bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3063     uint16_t         encIdx = 0;
3064     uint16_t         prevEncIdx = 0;
3065     RlcNackInfo      *rlcNackInfo;
3066     uint16_t         nkCnt = 0;
3067
3068     pStaPdu = RLC_AMDL.pStaPdu;
3069
3070
3071     /* D/C| CPT| */
3072     /* 0 - Control
3073        1 - Data */
3074     cntrlPdu[0] = 0x00;
3075     cntrlPdu[2] = 0x00;
3076
3077     /* ACK SN Field will be set in the end based on available Grant */
3078
3079     encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3080
3081     ack_sn = pStaPdu->ackSn;
3082
3083     if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3084     {
3085
3086        /* If alteast one NACK SN Info then set the E1 field */
3087        if (pStaPdu->nackCount)
3088        {
3089           /* 12 BIT SN CASE:
3090              In Third Octet:
3091              7  6 5 4 3 2 1 0
3092              E1 R R R R R R R 
3093            */
3094           cntrlPdu[2] = 0x80;
3095        }
3096
3097        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3098        {           
3099           sn = pStaPdu->nackInfo[nkCnt].sn;
3100
3101           rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3102
3103           bytesToEncode += 2; /* 2 Octets for NACK SN */
3104
3105           /* Check if E2 : isSegment is set */
3106           if (rlcNackInfo->isSegment)
3107           {
3108              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3109           }
3110
3111           /* Check if E3 : nackRange is set */
3112           if (rlcNackInfo->nackRange)
3113           {
3114              bytesToEncode += 1; /* 1 Octet: NACK range */
3115           }
3116
3117           /* Check if this NACK info can be accomodated in the Grant */
3118           if( rlcDatReq->pduSz >= bytesToEncode)
3119           {
3120              /* If there is a NACK SN before this then set its 
3121                 E1 bit */
3122              if(prevEncIdx)
3123              {
3124                 /* NACKSN  E1 E2 E3 R */
3125                 cntrlPdu[prevEncIdx + 1] |= 0x8;
3126              }
3127
3128              /* 12 BIT Nack SN encode */
3129              cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3130
3131              /* Next Octet */
3132              cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3133
3134              if (rlcNackInfo->isSegment)
3135              {
3136                 /*Set E2 Bit */
3137                 cntrlPdu[encIdx + 1] |= 0x4;
3138
3139
3140                 /* Add soStart and soEnd */
3141                 /* SOstart */
3142                 cntrlPdu[encIdx + 2] = (rlcNackInfo->soStart) >> 8; 
3143                 cntrlPdu[encIdx + 3] = rlcNackInfo->soStart & 0xFF;
3144
3145                 /* SOend */
3146                 cntrlPdu[encIdx + 4] = (rlcNackInfo->soEnd) >> 8;
3147                 cntrlPdu[encIdx + 5] = rlcNackInfo->soEnd & 0xFF;
3148              }
3149
3150              if (rlcNackInfo->nackRange)
3151              {
3152                 /*Set E3 Bit */
3153                 cntrlPdu[encIdx + 1] |= 0x2;
3154                 if(rlcNackInfo->isSegment)
3155                 {
3156                    cntrlPdu[encIdx + 6] = rlcNackInfo->nackRange;
3157                 }
3158                 else
3159                 {
3160                    cntrlPdu[encIdx + 2] = rlcNackInfo->nackRange;
3161                 }
3162              }
3163
3164              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3165           }
3166           /* Set ACK SN now */
3167           else
3168           {
3169              ack_sn = rlcNackInfo->sn;
3170
3171              /* Not even one nack can be accomodated */
3172              if (nkCnt == 0)
3173              {
3174                cntrlPdu[2] = 0x0;
3175              }
3176
3177              break;
3178           }
3179
3180           prevEncIdx = encIdx;
3181           encIdx = bytesToEncode;
3182
3183        }/* Loop is done for the NackCount */
3184
3185         /* set ACK SN */
3186        {
3187
3188           DU_LOG("\nINFO  -->  RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"\
3189              "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
3190
3191           cntrlPdu[0] |= (ack_sn & 0xF00)>> 8; 
3192           cntrlPdu[1] =  (uint8_t)ack_sn;
3193        }
3194
3195     }
3196     else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3197     {
3198        /* If alteast one NACK SN Info then set the E1 field */
3199        if (pStaPdu->nackCount)
3200        {
3201           /* 12 BIT SN CASE:
3202              In Third Octet:
3203              7  6 5 4 3 2 1 0
3204              ACKSN       E1 R 
3205            */
3206           cntrlPdu[2] = 0x2;
3207        }
3208
3209        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3210        {           
3211           sn = pStaPdu->nackInfo[nkCnt].sn;
3212
3213           rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3214
3215           bytesToEncode += 3; /* 3 Octets for NACK SN */
3216
3217           /* Check if E2 : isSegment is set */
3218           if (rlcNackInfo->isSegment)
3219           {
3220              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3221           }
3222
3223           /* Check if E3 : nackRange is set */
3224           if (rlcNackInfo->nackRange)
3225           {
3226              bytesToEncode += 1; /* 1 Octet: NACK range */
3227           }
3228
3229           /* Check if this NACK info can be accomodated in the Grant */
3230           if( rlcDatReq->pduSz >= bytesToEncode)
3231           {
3232              /* If there is a NACK SN before this then set its 
3233                 E1 bit */
3234              if(prevEncIdx)
3235              {
3236                 /* NACKSN  E1 E2 E3 R R R */
3237                 cntrlPdu[prevEncIdx + 2] |= 0x20;
3238              }
3239
3240              /* 18 BIT Nack SN encode */
3241              cntrlPdu[encIdx] = (uint8_t)((sn & 0x3FC00) >> 10);
3242
3243              /* Next Octet */
3244              cntrlPdu[encIdx + 1] = (uint8_t)((sn & 0x3FC) >> 2);
3245
3246              /* Next Octet */
3247              cntrlPdu[encIdx + 2] = (uint8_t)((sn & 0x3)<< 6);
3248
3249              if (rlcNackInfo->isSegment)
3250              {
3251                 /* NACKSN  E1 E2 E3 R R R */
3252                 /*Set E2 Bit */
3253                 cntrlPdu[encIdx + 2] |= 0x10;
3254
3255
3256                 /* Add soStart and soEnd */
3257                 /* SOstart */
3258                 cntrlPdu[encIdx + 3] = (rlcNackInfo->soStart) >> 8;
3259                 cntrlPdu[encIdx + 4] = (uint8_t)rlcNackInfo->soStart;
3260
3261                 /* SOend */
3262                 cntrlPdu[encIdx + 5] = (rlcNackInfo->soEnd) >> 8; 
3263                 cntrlPdu[encIdx + 6] = (uint8_t)(rlcNackInfo->soEnd);
3264              }
3265
3266              if (rlcNackInfo->nackRange)
3267              {
3268                 /* NACKSN  E1 E2 E3 R R R */
3269                 /*Set E3 Bit */
3270                 cntrlPdu[encIdx + 2] |= 0x08;
3271
3272                 if (rlcNackInfo->isSegment)
3273                 {
3274                    cntrlPdu[encIdx + 7] = rlcNackInfo->nackRange;
3275                 }
3276                 else
3277                 {
3278                    cntrlPdu[encIdx + 3] = rlcNackInfo->nackRange;
3279                 }
3280              }
3281
3282              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3283           }
3284           /* Set ACK SN now */
3285           else
3286           {
3287              ack_sn = rlcNackInfo->sn;
3288
3289              /* Not even one nack can be accomodated */
3290              if (nkCnt == 0)
3291              {
3292                cntrlPdu[2] &= 0xFD;
3293              }
3294
3295              break;
3296           }
3297
3298           prevEncIdx = encIdx;
3299           encIdx = bytesToEncode;
3300
3301        }/* Loop is done for the NackCount */
3302    
3303        /* set ACK SN */
3304        {
3305
3306           DU_LOG("\nINFO  -->  RLC_DL : rlcAssembleCntrlInfo: ACK PDU's SN = %d"
3307              "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId,rbCb->rlcId.cellId);
3308
3309           cntrlPdu[0] |=  (ack_sn & 0x3C000) >> 14;
3310           cntrlPdu[1] =  (ack_sn & 0x3FC0) >> 6;
3311           cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3312        }
3313
3314     }
3315     else
3316     {
3317        /* ERROR Log */
3318        DU_LOG("\nERROR  -->  RLC_DL : rlcAssembleCntrlInfo:Conf SN LEN  %d  is INVALID !!!! \
3319           UEID:%d CELLID:%d", rbCb->m.amDl.snLen, rbCb->rlcId.ueId,
3320           rbCb->rlcId.cellId);
3321     }
3322
3323
3324 #ifndef L2_OPTMZ
3325     SGetMsg(RLC_GET_MEM_REGION(gCb), RLC_GET_MEM_POOL(gCb),&mBuf);
3326 #else
3327     mBuf = (Buffer *)rlcAmmStaPduList[rlcAmmStaPduListCnt++];
3328     SResetMBuf(mBuf);
3329     if(rlcAmmStaPduListCnt > 511)
3330        rlcAmmStaPduListCnt = 0;
3331 #endif
3332
3333     cntrlPduSz = encIdx;
3334     ODU_ADD_POST_MSG_MULT(cntrlPdu, cntrlPduSz, mBuf);
3335
3336     rlcDatReq->pduSz -= cntrlPduSz;
3337     /* Add mBuf to RLC_AMDL.mBuf */
3338     RLC_AMDL.mBuf = mBuf;
3339  
3340     return;
3341 }
3342
3343 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3344
3345 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3346       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3347
3348 static Void rgAmmExtractElmnt(RlcCb *gCb,Buffer *pdu,RlcExtHdr *hdrInfo)
3349 {
3350    uint8_t   hdr;
3351    uint8_t   pLen = hdrInfo->pLen;
3352    uint8_t   len  = (uint8_t)hdrInfo->len;
3353    uint16_t  val;
3354    uint8_t   tHdr;
3355    uint8_t   fLen;
3356    uint8_t   rLen;
3357    /* uint8_t   rLen1 = 0; */
3358    uint16_t  tVal;
3359
3360    hdr = hdrInfo->hdr;
3361
3362    if (pLen == 0)
3363    {
3364       SRemPreMsg(&hdr, pdu);
3365       pLen = 8;
3366    }
3367    tHdr = hdr;
3368    if (len <= 8)
3369    {
3370       val = tHdr >> (RLC_BYTE_LEN - (len));
3371       hdr =  hdr << len;
3372       pLen -= len;
3373    }
3374    else /*if (len > 8) */
3375    {
3376       fLen = pLen;
3377       val = tHdr;
3378       val = val >> (RLC_BYTE_LEN - fLen);
3379       val = val << (len - fLen);
3380       rLen = len - fLen;
3381       SRemPreMsg(&hdr, pdu);
3382       tHdr = hdr;
3383       if (rLen <= 8)
3384       {
3385          hdr = hdr >> (RLC_BYTE_LEN - rLen);
3386          val = val | hdr;
3387          hdr = tHdr << rLen;
3388          pLen = (RLC_BYTE_LEN - rLen);
3389       }
3390       else
3391       {
3392         rLen = rLen - RLC_BYTE_LEN;
3393         tVal = hdr;
3394         tVal = tVal << rLen;
3395         val = val | tVal;
3396
3397         SRemPreMsg(&hdr, pdu);
3398         tHdr = hdr;
3399         hdr = hdr >> (RLC_BYTE_LEN - rLen);
3400         val = val | hdr;
3401         hdr = tHdr << rLen;
3402         pLen = (RLC_BYTE_LEN - rLen);
3403       }
3404    }
3405
3406    hdrInfo->pLen = pLen;
3407    hdrInfo->hdr = hdr;
3408    hdrInfo->val = val;
3409
3410    return;
3411 }
3412
3413
3414
3415
3416 static Void rgAmmUlHndlStatusPdu
3417 (
3418 Pst        *udxPst,
3419 SuId       suId,
3420 RlcCb      *gCb,
3421 RlcDlRbCb  *rbCb,
3422 Buffer     *cntrlPdu,
3423 uint8_t    *fByte
3424 )
3425 {
3426    uint8_t             e1;
3427    RlcExtHdr       hdrInfo;
3428    RlcUdxStaPdu    *pStaPdu;
3429    uint8_t             e3; /* NACK RANGE : 5GNR */
3430    uint32_t            snLen;
3431    uint32_t            snRange;
3432    uint32_t            resrvdBitsAckSn;
3433    uint32_t            resrvdBitsNackSn;
3434
3435    RLCDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3436
3437    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
3438
3439    /* Extract the Control PDU */
3440    hdrInfo.hdr  = (*fByte << 1);
3441    hdrInfo.pLen = 4;
3442
3443    /* D/C has been shifted in the calling function */
3444    if (hdrInfo.hdr & 0xE0)
3445    {
3446       RLCDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3447       return;
3448    }
3449
3450    RLC_ALLOC_SHRABL_BUF(udxPst->region, 
3451                        udxPst->pool, 
3452                        pStaPdu, 
3453                        sizeof(RlcUdxStaPdu));
3454
3455 #if (ERRCLASS & ERRCLS_ADD_RES)
3456    /* Memory allocation failure can not be expected  */
3457    if(!pStaPdu)
3458    {
3459      return;
3460    }
3461 #endif   
3462
3463    if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3464    {
3465       snLen = 12;
3466       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
3467       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
3468    }
3469    else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3470    {
3471       snLen = 18;
3472       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
3473       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
3474    }
3475    else
3476    {
3477       snLen = RLC_SN_LEN;
3478       resrvdBitsAckSn = 0;
3479       resrvdBitsAckSn = 0;
3480    }
3481
3482    pStaPdu->nackCnt = 0;
3483    /* For CPT */
3484    hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
3485
3486    /* ACK Sn */
3487    hdrInfo.len = RLC_SN_LEN;
3488    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3489    pStaPdu->ackSn = hdrInfo.val;
3490
3491    /* Check if NACK Exists */
3492    hdrInfo.len = RLC_E1_LEN;
3493    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3494    e1 = (uint8_t)hdrInfo.val;
3495    RLCDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
3496
3497    /* Extract the Reserved Bits after ACK SN field */
3498    hdrInfo.len = resrvdBitsAckSn;
3499    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3500
3501
3502    /* If NACK exists in control PDU */
3503    /* For ACKs and NACKs */
3504    while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
3505    {
3506       hdrInfo.len = snLen;
3507       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3508       pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
3509
3510       hdrInfo.len = RLC_E1_LEN;
3511       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3512       e1 = (uint8_t)hdrInfo.val;
3513
3514       /* Extract e2 */
3515       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3516          already present*/
3517       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3518       /*  e2 = (uint8_t) hdrInfo.val;*/
3519
3520       /* Store e2 value */
3521       pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
3522
3523       /* Extract e3 : 5GNR */
3524       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3525          already present*/
3526       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3527       e3 = (uint8_t) hdrInfo.val;
3528
3529       /* Extract Reserved Bits after NACK SN */
3530       hdrInfo.len = resrvdBitsNackSn;
3531       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3532
3533       /* Test for resegmentation */
3534       if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
3535       {
3536          hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
3537          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3538          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
3539
3540          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3541          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = hdrInfo.val;
3542
3543          RLCDBGP_DETAIL(gCb,
3544                        "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
3545                        pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
3546                        pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
3547       }
3548       else
3549       {
3550          hdrInfo.len = 0;
3551          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
3552          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = 0;
3553
3554       }
3555       /* NACK RANGE Field is SET */
3556       if (e3)
3557       {
3558          /* Extract NACK range field */
3559          hdrInfo.len = RLC_NACK_RANGE_LEN;
3560          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3561          snRange = (uint8_t)hdrInfo.val;
3562
3563          pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
3564
3565       }
3566       pStaPdu->nackCnt++;
3567    }
3568
3569    gRlcStats.amRlcStats.numULStaPduRcvd++;
3570    gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
3571
3572    /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
3573       to the last NACK SN + 1 and discard the original ACK_SN*/
3574    if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
3575    {
3576       pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
3577    }
3578
3579
3580    /* Parse & send Status PDU to RLC-DL */
3581    //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
3582    rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
3583
3584    return;
3585 }
3586
3587 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3588       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
3589 {
3590    RlcDlRbCb      *rbCb = NULLP;   
3591    RlcDlUeCb      *ueCb = NULLP; 
3592    uint8_t        fByte;
3593    uint8_t        temp;
3594    S16       retVal = RFAILED;
3595    RlcCb      *gCb;
3596    Pst       dlRlcPst = *udxPst;
3597
3598    gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
3599
3600    if( ROK != rlcDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
3601    {
3602      DU_LOG("\nERROR  -->  RLC_DL : RLC UECb Not found...\n");
3603      return RFAILED;
3604    }
3605
3606
3607    rbCb = ueCb->lCh[lcId - 1].dlRbCb;
3608
3609    /* Skip if mode is not AM */
3610    if((rbCb ==  NULLP) || (rbCb->mode != RLC_MODE_AM))
3611    {
3612       return RFAILED;
3613    }
3614
3615    if(ROK != SExamMsg((Data *)(&fByte),
3616             rlcSdu, 0))
3617    {
3618       DU_LOG("\nERROR  -->  RLC_DL : Failure in Rlc Hdr SExamMsg\n");
3619       return RFAILED;
3620    }
3621
3622    if(RLC_CNTRL_PDU == ((fByte & RLC_DC_POS) >> RLC_DC_SHT))
3623    {
3624       SRemPreMsg(&temp, rlcSdu);
3625       dlRlcPst.selector = 1;/* LWLC*/
3626       rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
3627       retVal = ROK;
3628    }
3629
3630    return (retVal);
3631 }
3632
3633
3634 #endif
3635
3636
3637 /*@}*/
3638
3639 \f  
3640 /********************************************************************30**
3641   
3642          End of file
3643 **********************************************************************/