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