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