Added a new Flag ODU_LWR_MAC_DEBUG in the code
[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    DU_LOG("\nRLC: rlcAssembleSdus: BO after assembly = %d UEID:%d CELLID:%d",
2136       amDl->bo, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2137    return;
2138 }
2139
2140 /**
2141  * @brief Private handler to check if the poll bit needs to be set for data PDU
2142  *
2143  * @details
2144  *    Its a private function called by kwProcessSdus, to checks if the 
2145  *    polling bit needs to be set for any RLC data PDU and updates the 
2146  *    same.
2147  *    - For the new PDUs, if the counters exceed the configured 
2148  *      pduWoPoll/byteWoPoll values, return poll bit.
2149  *    - For the PDUs/portion of PDUs, if the SDU list / retxBuf is 
2150  *      empty, return poll bit.
2151  *    - Update the pollPdu, pollByte counters and Poll_SN; start staProhTmr 
2152  *
2153  * @param[in]  rCb      RLC instance control block
2154  * @param[in]  rbCb     RB control block 
2155  * @param[in]  newPdu   Flag to indicate if its a new AMD PDU. 
2156  * @param[in]  bufSz    Length of the PDU
2157  *
2158  * @return  Bool 
2159  *      -# 1 - To set the poll bit
2160  *      -# 0 - Poll bit is not set
2161  *
2162  */
2163 bool rlcAmmDlCheckAndSetPoll(RlcCb *gCb, RlcDlRbCb *rbCb, bool newPdu, MsgLen bufSz)
2164
2165    bool     pollBit = FALSE;
2166    RlcAmDl   *amDl = &(rbCb->m.amDl);
2167
2168    /* If it's a new PDU increment PDU without poll and bytes without poll
2169     and check if they cross the configured number of poll pdu and poll bytes*/ 
2170    if (newPdu)
2171    {
2172       amDl->pduWoPoll++;
2173       /* Patch kw004.201 */
2174       amDl->byteWoPoll += bufSz;
2175
2176      if (((amDl->pollPdu != -1) && (amDl->pduWoPoll >= amDl->pollPdu)) || 
2177          ((amDl->pollByte != -1) && (amDl->byteWoPoll >= amDl->pollByte))) 
2178      {
2179         pollBit = TRUE;
2180      }
2181    }
2182
2183    /* Check if both tx/retx buffer are empty or if tx window is stalled */
2184    if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) ||
2185        RLC_AM_IS_TRANS_WIN_STALLED(amDl))
2186    {
2187       pollBit = TRUE;
2188    }
2189    
2190    if (pollBit)
2191    {
2192       amDl->pduWoPoll  = 0;
2193       amDl->byteWoPoll = 0;
2194
2195       amDl->pollSn = (amDl->txNext - 1) & amDl->snModMask;
2196
2197       DU_LOG("\nRLC: rlcAmmDlCheckAndSetPoll: Poll SN = %d UEID:%d CELLID:%d", 
2198          amDl->pollSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
2199
2200       /* kw005.201: Fix for poll retransmission timer. 
2201        * Timer is stopped if it is already running and 
2202        * then starting the timer. Fixes crs 
2203        * ccpu00117216 and ccpu00118284 .
2204        * */
2205       if( TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMDL_POLL_RETX_TMR) )
2206       {
2207          rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
2208       }
2209
2210       rlcStartTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
2211    }
2212
2213    return (pollBit);
2214 }
2215
2216 /**
2217  * @brief Private handler to create AMD PDU 
2218  *
2219  * @details
2220  *    This function constructs header and concatenate it with the data for
2221  *    the PDU. It also updates the txBuf with the created PDU.
2222  *
2223  * @param[in]  gCB         RLC instance control block
2224  * @param[in]  rbCb        Downlink RB control block
2225  * @param[in]  amHdr       AM header
2226  * @param[in]  RlcDlPduInfo Pointer to PduInfo
2227  * @param[in]  pdu         PDU buffer 
2228  *
2229  *  @return  Void
2230  *
2231  */
2232 void rlcAmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcAmHdr *amHdr,
2233 RlcDlPduInfo *pduInfo, Buffer *pdu)
2234 {
2235    uint8_t   hdr[RLC_MAX_HDRSZ];
2236    uint16_t  idx;
2237    RlcTx     *txBuf;
2238    MsgLen    pduSz;
2239    RlcAmDl   *amDl = &(rbCb->m.amDl);
2240
2241    /* Update sn */
2242    amHdr->sn = amDl->txNext;
2243
2244    /*5GNR RLC: Increment txNext only if no segmentation of it is a last segment */
2245    if((!amHdr->si) || (amHdr->si == RLC_SI_LAST_SEG))
2246    {
2247       //printf("\n 5GNRLOG: no segment/last seg SDU with lcId %d Sn %u txNext %u So %u\n",
2248       //          rbCb->lch.lChId, amHdr->sn, amDl->txNext, amHdr->so);
2249       amDl->txNext = (amDl->txNext + 1) & amDl->snModMask;
2250    }
2251
2252    /* Update hdr Info */
2253    ODU_GET_MSG_LEN(pdu, &pduSz);
2254
2255    /* passing newPDU = TRUE*/
2256    amHdr->p = rlcAmmDlCheckAndSetPoll(gCb,rbCb, TRUE, pduSz);
2257
2258    /* Construct header with the available hdr Info, set isSegment to FALSE */
2259    rlcConstructAmHdr(amHdr, hdr, amDl->snLen, &idx);
2260
2261    /* Concatenate hdr and data */
2262    ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx+1, pdu);
2263    
2264    txBuf = rlcUtlGetTxBuf(amDl->txBufLst, amHdr->sn);
2265    rlcCpyMsg(gCb,pdu,&(pduInfo->pdu));
2266    pduInfo->pduSz = pduSz;
2267    pduInfo->hdrSz = idx+1;
2268
2269    /*Update estHdrSz. deduct current hdrSz */
2270     amDl->estHdrSz -= pduInfo->hdrSz;
2271     /* Reestimate estHdrSz for mid and last seg */
2272     if(amHdr->si & 0x1)
2273     {
2274        amDl->estHdrSz += ((amHdr->si == RLC_SI_MID_SEG)? pduInfo->hdrSz : (pduInfo->hdrSz + 2));
2275     }
2276
2277    cmLListAdd2Tail(&txBuf->pduLst, &pduInfo->lstEnt);
2278    pduInfo->lstEnt.node = (PTR)pduInfo;
2279
2280    gCb->genSts.bytesSent += pduSz;
2281    
2282    return;
2283 }
2284
2285 /**
2286  * @brief Private handler to remove the retx PDU from the rbCb
2287  *
2288  * @details
2289  *    This function releases a retx PDU stored on DL portion of rbCb.
2290  *    It also updates the BO if wtForAck flag is not set which implies
2291  *    that it is not sent out yet.
2292  *
2293  * @param[in]  gCb        RLC instance control block
2294  * @param[in]  retx       retransmit PDU to be removed
2295  * @param[in]  rbCb       Radio Bearer Control Block
2296  *
2297  * @return Void 
2298  *
2299  */
2300 #ifdef ANSI
2301 PRIVATE Void rlcRemRetxPdu
2302 (  
2303 RlcCb          *gCb,
2304 RlcDlRbCb      *rbCb,
2305 RlcRetx        *retx
2306 )
2307 #else
2308 PRIVATE Void rlcRemRetxPdu(gCb, rbCb, retx)
2309 RlcCb          *gCb;
2310 RlcDlRbCb      *rbCb;
2311 RlcRetx        *retx;
2312 #endif
2313 {
2314    TRC2(rlcRemRetxPdu)
2315
2316    cmLListDelFrm(&AMDL.retxLst, &retx->lstEnt); 
2317
2318    if( AMDL.retxLst.count == 0)
2319    {
2320       AMDL.nxtRetx = NULLP;
2321    }
2322
2323    if(retx->pendingReTrans == TRUE)
2324    {
2325       AMDL.retxBo -= retx->segSz;
2326       AMDL.estHdrSz -= retx->hdrSz;
2327    }
2328
2329    rlcUtlAddReTxPduToBeFreedQueue(gCb, retx);
2330    rlcUtlRaiseDlCleanupEvent(gCb);
2331
2332    RETVOID;
2333 }
2334
2335 /**
2336  * @brief Private handler to mark a retx PDU for further retransmission
2337  *
2338  * @details
2339  *    This function sets a retx PDU that has not been ACKed in the   
2340  *    received Status PDU for futher retransmission. If the retransmission
2341  *    limit is reached, it releases the retx PDU and informs the higher
2342  *    layers about the same.
2343  *
2344  * @param[in]  gCb        RLC instance control block 
2345  * @param[in]  retx       retransmit PDU to be removed
2346  * @param[in]  rbCb       Radio Bearer Control Block
2347  *
2348  * @return Void 
2349  *
2350  */
2351 #ifdef ANSI
2352 PRIVATE Void rlcAmmDlMarkPduForReTx
2353 (
2354 RlcCb          *gCb,
2355 RlcDlRbCb      *rbCb,
2356 RlcRetx        *retx
2357 )
2358 #else
2359 PRIVATE Void rlcAmmDlMarkPduForReTx(*gCb, rbCb, retx)
2360 RlcCb          *gCb;
2361 RlcDlRbCb      *rbCb;
2362 RlcRetx        *retx;
2363 #endif
2364 {
2365    TRC2(rlcAmmDlMarkPduForReTx)
2366    if (AMDL.maxReTxReached == TRUE)
2367    {
2368       RETVOID;
2369    }
2370   
2371    if(retx->pendingReTrans == FALSE)
2372    {
2373       retx->pendingReTrans = TRUE;
2374       ++retx->retxCnt;
2375
2376       AMDL.retxBo   += retx->segSz;
2377       AMDL.estHdrSz += retx->hdrSz;
2378
2379       if (retx->retxCnt > AMDL.maxRetx)
2380       {
2381          /* RLC_DL_MAX_RETX fix */
2382          /* Marking the RB stalled for DL scheduling. This is to avoid unnecessary */
2383          /* preparation of RLC PDUs and adding the same to Tx Buffer */
2384          /* This condition is to avoid sending StaIndication more than once */
2385          if (TRUE != rbCb->m.amDl.maxReTxReached)
2386          {
2387             rbCb->m.amDl.maxReTxReached = TRUE;
2388             rbCb->m.amDl.bo = 0;
2389             rbCb->m.amDl.cntrlBo = 0;
2390             rbCb->m.amDl.retxBo = 0;
2391             /* Sending BO update to SCH */
2392             rlcUtlSendDedLcBoStatus(gCb, rbCb, 0,0,0,0);
2393             rlcAmmSndStaInd(gCb, rbCb, retx);
2394             gRlcStats.amRlcStats.numDLMaxRetx++;
2395          }
2396
2397          rlcRemRetxPdu(gCb,rbCb, retx);
2398          
2399          RETVOID;
2400       }
2401
2402
2403       if (AMDL.nxtRetx == NULLP)
2404       {
2405          AMDL.nxtRetx = retx;
2406       }
2407
2408       gRlcStats.amRlcStats.numDLRetransPdus++;
2409    }
2410
2411
2412    RETVOID;
2413 }
2414
2415 /**
2416  * @brief Private handler to check if SDU is completely deliverd and
2417  *        send higher layers data confirmation
2418  *
2419  * @details 
2420  *    This function sends higher layers data confirmation for SDUs which
2421  *    have been successfully delivered to the peer RLC entity.
2422  *
2423  * @param[in]  gCb      RLC instance control block
2424  * @param[in]  rbCb     Radio Bearer Control Block
2425  * @param[in]  sduLst   List of SDUs that were part of the PDU
2426  * @param[in]  numSdu   Number of SDUs in the list
2427  *
2428  * @return Void 
2429  *
2430  */
2431 #ifdef ANSI
2432 PRIVATE Void rlcAmmDlCheckIsSDUDelivered
2433 (
2434 RlcCb            *gCb,
2435 RlcDlRbCb        *rbCb,
2436 RlcSduMap        *sduMap,
2437 KwuDatCfmInfo   **datCfm
2438 )
2439 #else
2440 PRIVATE Void rlcAmmDlCheckIsSDUDelivered(gCb, rbCb, sduMap, datCfm)
2441 RlcCb            *gCb;
2442 RlcDlRbCb        *rbCb;
2443 RlcSduMap        *sduMap;
2444 KwuDatCfmInfo   **datCfm;
2445 #endif
2446 {
2447    RlcSdu *sdu;
2448    
2449    TRC2(rlcAmmDlCheckIsSDUDelivered)
2450    
2451    sdu = sduMap->sdu;
2452
2453    sdu->mode.am.rcvdSz += sduMap->sduSz;
2454
2455    /* send a dat cfm if all the bytes of the sdu have been received */
2456    if (sdu->mode.am.rcvdSz == sdu->actSz)
2457    {
2458       /* Send DatCfm for this sdu */
2459       if((*datCfm)->numSduIds < KWU_MAX_DAT_CFM)
2460       {
2461          (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2462       }
2463       else
2464       {
2465          /* This is an error that should never happen, we should resize
2466           * the #define to a larger value or check why we need to 
2467           * send so many confirms in one go
2468           * Confrims to PDCP are being dropped in this case
2469           */
2470          RlcKwuSapCb    *rlckwuSap;
2471          rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2472          RlcUiKwuDatCfm(&rlckwuSap->pst, rlckwuSap->suId, *datCfm);
2473
2474          RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, *datCfm, sizeof(KwuDatCfmInfo));
2475
2476 #if (ERRCLASS & ERRCLS_ADD_RES)
2477          if (*datCfm == NULLP)
2478          {
2479             RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
2480                   "Memory allocation failed UEID:%d CELLID:%d",
2481                   rbCb->rlcId.ueId,
2482                   rbCb->rlcId.cellId);
2483             RETVOID;
2484          }
2485 #endif /* ERRCLASS & ERRCLS_RES */
2486
2487          (*datCfm)->numSduIds = 0;
2488          (*datCfm)->rlcId = rbCb->rlcId;
2489          /* ccpu00135618: say total 1026 sduIds to copy the 1025 sduId after
2490           * new allocation of datCfm */
2491          (*datCfm)->sduIds[(*datCfm)->numSduIds++] = sdu->mode.am.sduId;
2492       }
2493
2494       /* Remove SDU from the sduQ */
2495       cmLListDelFrm(&AMDL.sduQ, &sdu->lstEnt);
2496       rlcUtlAddSduToBeFreedQueue(gCb, sdu);
2497       rlcUtlRaiseDlCleanupEvent(gCb);
2498    }
2499
2500    RETVOID;
2501
2502
2503 /**
2504  * @brief Private handler to mark a PDU successful.
2505  *
2506  * @details
2507  *    This function is called when we receive a STATUS pdu that marks
2508  *    a PDU as successful. It releases the PDU from RLC entity and 
2509  *    informs PDCP of successful SDUs delivered as a result of this PDU.
2510  *
2511  * @param[in]  gCb        RLC instance control block  
2512  * @param[in]  rbCb       Radio Bearer Control Block
2513  * @param[in]  sn         SN that is successfully delivered to the peer 
2514  *
2515  * @return Void 
2516  *
2517  */
2518 #ifdef ANSI
2519 PRIVATE Void rlcAmmDlProcessSuccessfulTxPdu
2520 (
2521 RlcCb            *gCb,
2522 RlcDlRbCb        *rbCb,
2523 RlcSn            sn,
2524 KwuDatCfmInfo   **datCfm
2525 )
2526 #else
2527 PRIVATE Void rlcAmmDlProcessSuccessfulTxPdu(gCb, rbCb, sn, datCfm)
2528 RlcCb            *gCb;
2529 RlcDlRbCb        *rbCb;
2530 RlcSn            sn;
2531 KwuDatCfmInfo   **datCfm;
2532 #endif
2533 {
2534    TRC2(rlcAmmDlProcessSuccessfulTxPdu)
2535    CmLList *pduNode;
2536   
2537    RlcTx *txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
2538    
2539    if (txBuf == NULLP)
2540    {
2541            RETVOID;
2542    }
2543    pduNode = txBuf->pduLst.first;
2544    while(pduNode)
2545    {
2546       RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(pduNode->node);
2547       rlcAmmDlCheckIsSDUDelivered(gCb,
2548                               rbCb,  
2549                               &(pduInfo->sduMap), 
2550                               datCfm);
2551       pduNode = pduNode->next;
2552    }
2553    
2554    rlcUtlAddTxPduToBeFreedQueue(gCb, txBuf);
2555    rlcUtlRaiseDlCleanupEvent(gCb);
2556    /* so that it is not processed again */
2557    rlcUtlRemovTxBuf(AMDL.txBufLst, txBuf, gCb);
2558
2559    RETVOID;
2560 }
2561
2562 /**
2563  * @brief  Handler to send Status Indication to PDCP
2564  *
2565  * @details
2566  *    This function is used to send status indication to PDCP when the 
2567  *    maximum retransmission threshold value is reached for a PDU.
2568  * 
2569  * @param[in] gCb    RLC instance control block
2570  * @param[in] rbCb   RB control block 
2571  * @param[in] retx   The PDU/segment that failed max re-transmissions
2572  *
2573  * @return  Void
2574  *
2575  */
2576 #ifdef ANSI
2577 PRIVATE Void rlcAmmSndStaInd
2578 (
2579 RlcCb       *gCb,
2580 RlcDlRbCb   *rbCb,
2581 RlcRetx     *retx
2582 )
2583 #else
2584 PRIVATE Void rlcAmmSndStaInd(gCb, rbCb, retx)
2585 RlcCb       *gCb;
2586 RlcDlRbCb   *rbCb;
2587 RlcRetx     *retx;
2588 #endif
2589 {
2590    KwuStaIndInfo   *staInd;
2591    RlcKwuSapCb      *rlckwuSap;
2592
2593    TRC2(rlcAmmSndStaInd);
2594
2595
2596    /* Sap control block */
2597    rlckwuSap = gCb->u.dlCb->rlcKwuDlSap + RLC_UI_PDCP;
2598
2599    /* Allocate memory for staInd Info */
2600    RLC_SHRABL_STATIC_BUF_ALLOC(rlckwuSap->pst.region, rlckwuSap->pst.pool, staInd, sizeof(KwuStaIndInfo));
2601
2602 #if (ERRCLASS & ERRCLS_ADD_RES)
2603    if (staInd == NULLP)
2604    {
2605       RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId, 
2606             "Memory allocation failed UEID:%d CELLID:%d",
2607             rbCb->rlcId.ueId,
2608             rbCb->rlcId.cellId);
2609       RETVOID;
2610    }
2611 #endif /* ERRCLASS & ERRCLS_RES */
2612
2613    /* Fill staInd Info */ 
2614    RLC_MEM_CPY(&staInd->rlcId, &rbCb->rlcId, sizeof(CmLteRlcId));    
2615    
2616    staInd->numSdu = 1;
2617    staInd->sduId[0] = retx->sduMap.sdu->mode.am.sduId;
2618
2619 #ifdef KW_PDCP
2620 #else
2621    RlcUiKwuStaInd(&rlckwuSap->pst, rlckwuSap->suId, staInd);
2622 #endif /* KW_PDCP */
2623
2624    RETVOID;
2625 }
2626
2627 /**
2628  * @brief  Handler to get the next node to be retransmitted from retxLst
2629  *
2630  * @details
2631  *    This function is used to get the next node to be retransmitted 
2632  *    from the retxLst
2633  *            
2634  *  @param[in] gCb     RLC instance control block 
2635  *  @param[in] retx    The PDU/segment after which to find a node to be 
2636  *                     retransmitted
2637  *
2638  *  @return  Void 
2639  *
2640  */
2641 void rlcGetNxtRetx(RlcCb *gCb, RlcRetx **retx)
2642 {
2643    CmLList *tNode;
2644
2645    do
2646    {
2647       tNode = &((*retx)->lstEnt);
2648       tNode = tNode->next;
2649       
2650       if (tNode)
2651       {
2652          *retx = (RlcRetx *)tNode->node;
2653       }
2654       else
2655       {
2656          *retx = NULLP;
2657          RETVOID;
2658       }
2659    }while((*retx)->pendingReTrans == FALSE);
2660
2661    return;
2662 }
2663
2664 /**
2665  * @brief  Handler to process the re-establishment request received from UIM
2666  *
2667  * @param[in]  gCb         RLC instance control block
2668  * @param[in]  rlcId       Identity of the RB in the UE/Cell for which 
2669  *                         re-establishment is to be done
2670  * @param[in]  rbCb        Downlink RB control block (rbCb is freed in this
2671  *                         function)
2672  *
2673  * @return  Void 
2674  *
2675  */
2676 #ifdef ANSI
2677 Void rlcAmmDlReEstablish
2678 (
2679 RlcCb         *gCb,
2680 CmLteRlcId   rlcId,
2681 RlcDlRbCb     *rbCb
2682 )
2683 #else
2684 Void rlcAmmDlReEstablish(gCb, rlcId, rbCb)
2685 RlcCb         *gCb;
2686 CmLteRlcId   rlcId;
2687 RlcDlRbCb     *rbCb;
2688 #endif
2689 {
2690    /* create a new AM DL RB, reset it and replace in the UeCb*/
2691    RlcDlUeCb   *ueCb;
2692    RlcDlRbCb   *resetRb;
2693    RlcAmDl* newAmDl;
2694    RlcAmDl* oldAmDl;
2695    RLC_ALLOC(gCb, resetRb, sizeof(RlcDlRbCb));
2696    
2697    /* ccpu00135170 Removing KLOCK warning */
2698    if(resetRb == NULLP)
2699    {
2700       RETVOID;
2701    }
2702
2703    RLC_MEM_CPY(resetRb, rbCb, sizeof(RlcDlRbCb));
2704    RLC_MEM_SET(&resetRb->m.amDl, 0 , sizeof(RlcAmDl));
2705
2706 /* AGHOSH changes start */
2707    /* restore the old AM values */
2708    newAmDl = &resetRb->m.amDl;
2709    oldAmDl = &rbCb->m.amDl;
2710
2711    newAmDl->pollPdu = oldAmDl->pollPdu;
2712    newAmDl->pollByte = oldAmDl->pollByte;
2713    newAmDl->maxRetx = oldAmDl->maxRetx;
2714    newAmDl->snLen   = oldAmDl->snLen;
2715    newAmDl->snModMask   = oldAmDl->snModMask;
2716    newAmDl->pollRetxTmrInt = oldAmDl->pollRetxTmrInt;
2717    rbCb->boUnRprtdCnt = (U32)0;
2718    rbCb->lastRprtdBoToMac = (U32)0;
2719    cmInitTimers(&(resetRb->m.amDl.pollRetxTmr), 1); 
2720 /* AGHOSH changes end */
2721  
2722    if (ROK != rlcDbmFetchDlUeCb(gCb,rlcId.ueId, rlcId.cellId, &ueCb))
2723    {
2724       RLOG_ARG2(L_ERROR,DBG_CELLID, rlcId.cellId,
2725                "UeId [%d]: UeCb not found RBID;%d",
2726                rlcId.ueId,
2727                rlcId.rbId);
2728       RETVOID;
2729    }
2730    
2731    if(rlcId.rbType == CM_LTE_SRB)
2732    {
2733       ueCb->srbCb[rlcId.rbId] = resetRb;
2734    }
2735    else
2736    {
2737       ueCb->drbCb[rlcId.rbId] = resetRb;
2738    }
2739    /* update into the logical channel array also */
2740    ueCb->lCh[rbCb->lch.lChId - 1].dlRbCb = resetRb;
2741  
2742    if((resetRb->rlcId.rbType == CM_LTE_SRB)
2743                 &&(resetRb->rlcId.rbId == 1))
2744    {
2745       /* To stop the traffic on SRB2 and other DRBs*/
2746       rlcDlUtlSetReestInProgressForAllRBs(gCb, ueCb);
2747    }
2748    else 
2749    {
2750       rlcDlUtlSetReestInProgressForRB(gCb, resetRb);      
2751    }
2752
2753    /* allocate the TX array again */
2754 #ifndef  LTE_TDD
2755    U32 hashIndex;
2756    RLC_ALLOC(gCb,
2757                    resetRb->m.amDl.txBufLst,
2758                    (RLC_TX_BUF_BIN_SIZE * sizeof(CmLListCp)));
2759    for(hashIndex = 0; hashIndex < RLC_TX_BUF_BIN_SIZE; hashIndex++)
2760    {
2761            cmLListInit(&(resetRb->m.amDl.txBufLst[hashIndex]));
2762    }
2763 #endif
2764    /* send the old rb of deletion */
2765    rlcAmmFreeDlRbCb(gCb,rbCb); 
2766
2767
2768    /* TODO: for now we are re-settting the re-establishment flag here
2769       this needs to be fixed
2770       There should be a proper intreface to resume the RBs */
2771    if(rlcId.rbType == CM_LTE_SRB)
2772    {
2773       rlcDlUtlResetReestInProgress(ueCb->srbCb[rlcId.rbId]);
2774    }
2775    else
2776    {
2777       rlcDlUtlResetReestInProgress(ueCb->drbCb[rlcId.rbId]);
2778    }      
2779       
2780    RETVOID;
2781 }
2782
2783 /**
2784  * @brief  Handler to discard a SDU.
2785  *
2786  * @details
2787  *    This function is used to discard a SDU after receiving
2788  *    the Discard Request from UIM. The SDU is discarded if its 
2789  *    available and is not mapped to any PDU yet.
2790  *   
2791  * @param[in] gCb     RLC instance control block
2792  * @param[in] rbCb    RB control block 
2793  * @param[in] sduId   Sdu ID of the SDU to be discarded
2794  *
2795  *  @return  S16
2796  *     -# ROK      In case of successful discard
2797  *     -# RFAILED  In case the SDU is not found or already mapped
2798  */
2799 #ifdef ANSI
2800 S16 rlcAmmDiscSdu
2801 (
2802 RlcCb       *gCb,
2803 RlcDlRbCb   *rbCb,
2804 U32        sduId 
2805 )
2806 #else
2807 S16 rlcAmmDiscSdu(gCb, rbCb, sduId)
2808 RlcCb       *gCb;
2809 RlcDlRbCb   *rbCb;  
2810 U32        sduId; 
2811 #endif
2812 {
2813    TRC2(rlcAmmDiscSdu);
2814    return (RFAILED);
2815
2816
2817 /**
2818  * @brief  Handler for Poll retransmit timer expiry
2819  *
2820  * @details
2821  *    This function is used to handle events upon expiry of Poll 
2822  *    retransmit timer.
2823  *  
2824  * @param[in] gCb    RLC instance control block
2825  * @param[in] rbCb   Downlink RB control block 
2826  *
2827  * @return  Void 
2828  */
2829 #ifdef ANSI
2830 Void rlcAmmPollRetxTmrExp
2831 (
2832 RlcCb       *gCb,
2833 RlcDlRbCb   *rbCb
2834 )
2835 #else
2836 Void rlcAmmPollRetxTmrExp(gCb, rbCb)
2837 RlcCb       *gCb;
2838 RlcDlRbCb   *rbCb;
2839 #endif
2840 {
2841    RlcRetx        *retx; 
2842    RlcAmDl        *amDl = &(rbCb->m.amDl);
2843    RlcSn          sn;
2844    RlcTx          *txBuf;
2845    TRC2(rlcAmmPollRetxTmrExp);
2846
2847    
2848    /* kw003.201 - Correcting the logic for determmining whether to do   */
2849    /*             any transmission of PDU. As per the spec section      */
2850    /*             5.2.2.3, if there is any to transmit or retransmit,   */
2851    /*             do nothing. Else, pick up the VT(S) -1 for retx       */
2852    /*             We have nothing to transmit if window is stalled or   */
2853    /*             there are no SDUs to be transmitted or if there are   */
2854    /*             PDUs to be retransmitted.                             */
2855    if(CM_LTE_SRB == rbCb->rlcId.rbType)
2856    {
2857       gRlcStats.amRlcStats.numDLPollTimerExpiresSrb++;
2858    }
2859    else
2860    {
2861       gRlcStats.amRlcStats.numDLPollTimerExpiresDrb++;
2862    }
2863
2864    if (((amDl->nxtTx == NULLP) && (amDl->nxtRetx == NULLP)) || 
2865         RLC_AM_IS_TRANS_WIN_STALLED(amDl)) 
2866    {
2867       sn = (amDl->txNext - 1) & amDl->snModMask;
2868       txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
2869
2870       if (txBuf != NULLP)
2871       {
2872          rlcAmmDlMoveFrmTxtoRetxBuffer(gCb,amDl, &retx, sn); 
2873          
2874          if (AMDL.nxtRetx == NULLP)
2875          {
2876             AMDL.nxtRetx = retx;
2877          }
2878          
2879          rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);         
2880          RETVOID;
2881       }
2882       /* Get the last node in retxLst */
2883       RLC_LLIST_LAST_RETX(amDl->retxLst, retx);
2884
2885       /* Unset wtForAck flag for the NACK PDUs */ 
2886       if (retx != NULLP)
2887       {
2888          rlcAmmDlMarkPduForReTx(gCb, rbCb, retx);
2889          rlcAmmSendDedLcBoStatus(gCb, rbCb, &AMDL);         
2890       }
2891    }
2892
2893    RETVOID;
2894
2895
2896 /**
2897  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
2898  *         NACK PDU.
2899  *
2900  * @details 
2901  *    This function is used to handle ACKs for the PDUs remaining after the 
2902  *    last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and 
2903  *    sends DatCfm to PDCP for the same.
2904  *
2905  * @param[in]  gCb         RLC instance control block
2906  * @param[in]  rbCb        Downlink Radio Bearer control block
2907  * @param[in]  mAckSn      The ACK SN after doing the base modulus
2908  * @param[in]  rextNode    Next node in the re-transmission buffer          
2909  *
2910  * @return  Void
2911  *
2912  */
2913
2914 #ifdef ANSI
2915 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForAckSn
2916 (
2917 RlcCb            *gCb,
2918 RlcDlRbCb        *rbCb,
2919 RlcSn            mAckSn,
2920 CmLList         *retxNode,
2921 KwuDatCfmInfo   **datCfm
2922 )
2923 #else
2924 PRIVATE Void rlcAmmDlUpdateTxAndReTxBufForAckSn(gCb, rbCb, mAckSn, retxNode, datCfm)
2925 RlcCb            *gCb;
2926 RlcDlRbCb        *rbCb;
2927 RlcSn            mAckSn;
2928 CmLList         *retxNode;
2929 KwuDatCfmInfo   **datCfm;
2930 #endif
2931 {
2932    RlcSn    mSn;
2933    RlcSn    sn;
2934    RlcRetx  *retx;
2935    RlcTx    *txBuf;
2936
2937    TRC2(rlcAmmDlUpdateTxAndReTxBufForAckSn);
2938
2939    /* Remove pdus/segs from retxLst */ 
2940    while (retxNode)
2941    {
2942       retx = (RlcRetx *)(retxNode->node);
2943       retxNode = retxNode->next;
2944       MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2945       if (mSn < mAckSn) 
2946       {
2947          rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
2948       }
2949    }
2950
2951    /* For the remaining; pdus not acknowldeged by the NACK_SN but being
2952       acknowledged by the ACK_SN*/
2953    /* start from the starting of the transmission window and remove till just
2954       before ACK_SN*/
2955    mSn = 0;       /* same as MODAMT(AMDL.txNextAck, mSn, AMDL.txNextAck);*/
2956    sn = AMDL.txNextAck;
2957    while(mSn < mAckSn)
2958    {
2959       txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
2960       if (txBuf != NULLP)
2961       {
2962          RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId, 
2963                  "rlcAmmDlUpdateTxAndReTxBufForAckSn: ACK for PDU "
2964                  "with sn = %ld UEID:%ld CELLID:%ld",
2965                  sn,
2966                  rbCb->rlcId.ueId,
2967                  rbCb->rlcId.cellId);
2968
2969          rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
2970       }
2971       
2972       sn = (sn + 1) & AMDL.snModMask;
2973       MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
2974    }
2975
2976    RETVOID;
2977 }
2978
2979 /**
2980  * @brief  Handler to update Acks for the remaining PDUs after the last accessed
2981  *         NACK PDU.
2982  *
2983  * @details 
2984  *    This function is used to handle ACKs for the PDUs remaining after the 
2985  *    last accessed NACK PDU, It updates the txBuf/retxBuf for the ACKs and 
2986  *    sends DatCfm to PDCP for the same.
2987  *
2988  * @param[in]  gCb         RLC instance control block
2989  * @param[in]  rbCb        Downlink Radio Bearer control block
2990  * @param[in]  mAckSn      The ACK SN after doing the base modulus
2991  * @param[in]  rextNode    Next node in the re-transmission buffer          
2992  *
2993  * @return  Void
2994  *
2995  */
2996 #ifdef ANSI
2997 PRIVATE Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn
2998 (
2999 RlcCb            *gCb,
3000 RlcDlRbCb        *rbCb,
3001 RlcSn            sn,
3002 RlcSn            mNackSn,
3003 CmLList         **retxNode,
3004 KwuDatCfmInfo   **datCfm
3005 )
3006 #else
3007 PRIVATE Void rlcAmmDlUpdTxAndReTxBufForLessThanNackSn(gCb, rbCb, sn, mNackSn, retxNode, datCfm)
3008 RlcCb            *gCb;
3009 RlcDlRbCb        *rbCb;
3010 RlcSn            sn;
3011 RlcSn            mNackSn;
3012 CmLList         **retxNode;
3013 KwuDatCfmInfo   **datCfm;
3014 #endif
3015 {
3016    RlcSn    mSn;
3017    RlcRetx  *retx;
3018    RlcTx    *txBuf=NULLP;
3019
3020    TRC2(rlcAmmDlUpdTxAndReTxBufForLessThanNackSn);
3021
3022    while (*retxNode)
3023    {
3024       retx = (RlcRetx *)((*retxNode)->node);
3025       MODAMT(retx->amHdr.sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3026       if (mSn < mNackSn)
3027       {
3028          (*retxNode) = (*retxNode)->next;
3029          rlcAmmDlProcessSuccessfulReTx(gCb,rbCb, retx, datCfm);
3030       }
3031       else
3032       {
3033          break;
3034       }
3035    }
3036
3037    /* Remove all pdus with SN < NACK_SN from the transmission buffer */ 
3038    MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3039    while (mSn < mNackSn)
3040    {
3041       /* this if check seems redundant,why should mSn ever be mTxSn 
3042          (which actually is VT(A) */
3043       txBuf = rlcUtlGetTxBuf(AMDL.txBufLst, sn);
3044       if ((txBuf != NULLP)) 
3045       {
3046          RLOG_ARG3(L_DEBUG,DBG_RBID, rbCb->rlcId.rbId, 
3047                "rlcHndlStaRsp: Handle ACK (sn = %d) UEID:%d CELLID:%d",
3048                sn,
3049                rbCb->rlcId.ueId,
3050                rbCb->rlcId.cellId);
3051
3052          /* Remove pdus from txBuf */
3053          rlcAmmDlProcessSuccessfulTxPdu(gCb,rbCb, sn, datCfm);
3054       }
3055
3056       sn = (sn + 1) & AMDL.snModMask;
3057       MODAMT(sn, mSn, AMDL.txNextAck,AMDL.snModMask);
3058    }
3059    
3060    RETVOID;
3061 }
3062
3063
3064 /**
3065  * @brief  Handler to form construct AM header
3066  *
3067  * @details 
3068  *    This function is used to construct am header with the available header
3069  *    elements.
3070  *
3071  * @param[in] gCb    RLC instance control block
3072  * @param[in] amHdr  AM Header
3073  * @param[in] isSeg  Check for Segmentation of PDU
3074  * @param[in] hdr    Header field
3075  * @param[in] idx    Index
3076  *  
3077  * @return Void            
3078  *
3079  */
3080 void rlcConstructAmHdr(RlcAmHdr *amHdr, uint8_t *hdr, uint8_t snLen, uint16_t *idx)
3081 {
3082    *idx = 0;
3083     hdr[0] = RLC_DATA_BITMASK;
3084     
3085     hdr[0] = hdr[0] | (amHdr->p << 6);
3086     hdr[0] = hdr[0] | ((amHdr->si & 0x3) << 4);
3087    if(snLen == RLC_AM_CFG_12BIT_SN_LEN)
3088    {
3089       hdr[0] = hdr[0] | (U8)((amHdr->sn & 0xF00) >> 8);
3090       hdr[1] =  (U8)(amHdr->sn & 0x0FF);
3091       (*idx)++;
3092    }
3093    else
3094    {
3095       hdr[0] = hdr[0] | (U8)((amHdr->sn & 0x30000) >> 16);
3096       hdr[1] =  (U8)((amHdr->sn & 0xFF00) >> 8);
3097       (*idx)++;
3098       hdr[2] =  (U8)(amHdr->sn & 0xFF);
3099       (*idx)++;
3100    }
3101     
3102    if ((amHdr->si == RLC_SI_MID_SEG) || (amHdr->si == RLC_SI_LAST_SEG))                                      
3103    {
3104       (*idx)++;
3105       hdr[(*idx)] = (U8)((amHdr->so & 0xFF00)>> 8);
3106       (*idx)++;
3107       hdr[(*idx)] = (U8)(amHdr->so & 0xFF);
3108    }                                                        
3109
3110    return;
3111 }
3112
3113 /**
3114  * @brief  This function adds a retx PDU to list of retx PDUs
3115  *
3116  * @details
3117  *    kw003.201 - Poll expiry may cause an SN to be added to retx 
3118  *                out of sequence and hence all additions to retx 
3119  *                must validate that they are added in sequence   
3120  *
3121  * @param[in] amDl   AM Downlink Control Block
3122  * @param[in] retx   Retransmit PDU
3123  * 
3124  * @return Void
3125  *            
3126  */
3127 #ifdef ANSI
3128 PRIVATE Void rlcAmmAddPduToRetxLst
3129 (
3130 RlcAmDl   *amDl,
3131 RlcRetx   *retx
3132 )
3133 #else
3134 PRIVATE Void rlcAmmAddPduToRetxLst(amDl, retx)
3135 RlcAmDl   *amDl;
3136 RlcRetx   *retx;
3137 #endif
3138 {
3139    CmLList   *node;
3140    RlcRetx    *tRetx;
3141    RlcSn      tMSn;
3142    RlcSn      retxMSn;
3143    
3144    TRC2(rlcAmmAddPduToRetxLst);
3145  
3146    node = amDl->retxLst.last;
3147    MODAMT(retx->amHdr.sn, retxMSn, amDl->txNextAck,amDl->snModMask);
3148    while(node != NULLP)
3149    {
3150       tRetx = (RlcRetx *)(node->node);
3151       MODAMT(tRetx->amHdr.sn, tMSn, amDl->txNextAck,amDl->snModMask);
3152       if (tMSn > retxMSn)
3153       {
3154          node = node->prev;
3155       }
3156       else
3157       {
3158          break;
3159       }
3160    }
3161    if (node)
3162    {
3163       amDl->retxLst.crnt = node;
3164       cmLListInsAfterCrnt(&amDl->retxLst, &retx->lstEnt);
3165       retx->lstEnt.node = (PTR)retx;
3166    }
3167    else
3168    {
3169       amDl->retxLst.crnt = amDl->retxLst.first;
3170       cmLListInsCrnt(&amDl->retxLst, &retx->lstEnt);
3171       retx->lstEnt.node = (PTR)retx;
3172    }
3173
3174    if (amDl->nxtRetx == NULLP)
3175    {
3176       amDl->nxtRetx = retx;
3177    }
3178
3179    RETVOID;
3180 }
3181
3182 /**
3183  * @brief Handler to Move the PDU from txBuf to re-transmission buffer 
3184  *
3185  * @details
3186  *    This function is used to move the PDU from the txBuf to re-transmit buffer
3187  *
3188  * @param[in]  gCb         RLC instance control block
3189  * @param[in]  amDl        AM Downlink Control Block 
3190  * @param[in]  retx        node in the reTx buffer to be moved to, allocated by
3191  *                         this function
3192  * @param[in]  sn          SN in the tx buffer which needs to be moved
3193  * 
3194  * @return Void
3195  *            
3196  */
3197
3198 #ifdef ANSI
3199 PRIVATE Void rlcAmmDlMoveFrmTxtoRetxBuffer
3200 (
3201 RlcCb          *gCb,
3202 RlcAmDl        *amDl,
3203 RlcRetx        **retx,
3204 RlcSn          sn
3205 )
3206 #else
3207 PRIVATE Void rlcAmmDlMoveFrmTxtoRetxBuffer(gCb, amDl, retx, sn)
3208 RlcCb          *gCb;
3209 RlcAmDl        *amDl;
3210 RlcRetx        **retx;
3211 RlcSn          sn; 
3212 #endif
3213 {
3214    RlcTx* txBuf = rlcUtlGetTxBuf(amDl->txBufLst, sn);
3215    TRC2(rlcAmmDlMoveFrmTxtoRetxBuffer);
3216
3217    if (txBuf == NULLP)
3218    {
3219            RETVOID;
3220    }
3221    while(txBuf->pduLst.first)
3222    {
3223       RlcDlPduInfo *pduInfo = (RlcDlPduInfo *)(txBuf->pduLst.first->node);
3224       RLC_ALLOC_WC(gCb,*retx, sizeof(RlcRetx));
3225
3226 #if (ERRCLASS & ERRCLS_ADD_RES)
3227       if (*retx == NULLP)
3228       {
3229               RLOG0(L_FATAL, "Memory allocation failed");
3230               RETVOID;
3231       }
3232 #endif /* ERRCLASS & ERRCLS_RES */
3233
3234       /* Move Sdu byte segment from TX buf to retx buf*/
3235       rlcAmmDlMoveSduByteSegFrmTxtoRetxBuffer(gCb, 
3236             amDl, 
3237             retx, 
3238             pduInfo);
3239       
3240       /* Delete node from the txBuf Pdu lst */
3241       cmLListDelFrm(&txBuf->pduLst, txBuf->pduLst.first);
3242       RLC_FREE_WC(gCb, pduInfo, sizeof(RlcDlPduInfo));
3243    }
3244    /* Remove PDU from txBuf */
3245    rlcUtlDelTxBuf(amDl->txBufLst, txBuf,gCb); 
3246    
3247    RETVOID;
3248 }
3249
3250
3251
3252 /*
3253  * @brief
3254  *    function to free/release the Acknowledged mode RBCB buffers
3255  *
3256  * @details
3257  *    This primitive Frees the Acknowledged Mode RbCb transmission Buffer,
3258  *    retransmission Buffer and reciption Buffers
3259  *
3260  * @param [in]   gCb    - RLC instance control block
3261  * @param [in]   rbCb   - Downlink RB Control Block
3262  *
3263  * @return Void
3264  */
3265 #ifdef ANSI
3266 Void rlcAmmFreeDlRbCb
3267 (
3268 RlcCb       *gCb,
3269 RlcDlRbCb   *rbCb
3270 )
3271 #else
3272 Void rlcAmmFreeDlRbCb(gCb,rbCb)
3273 RlcCb       *gCb;
3274 RlcDlRbCb   *rbCb;
3275 #endif
3276 {
3277    /* stop the re-transmission timer */
3278    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMDL_POLL_RETX_TMR))
3279    {
3280       rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMDL_POLL_RETX_TMR);
3281    }
3282
3283    /* store the entire Rb pointer */      
3284    rbCb->rlsLnk.node = (PTR)rbCb;
3285    cmLListAdd2Tail(&gCb->u.dlCb->toBeFreed.rbLst, &rbCb->rlsLnk);
3286
3287    /* the sdu queue */
3288    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.amDl.sduQ));
3289
3290    rlcUtlRaiseDlCleanupEvent(gCb);
3291    
3292    RETVOID;
3293 }
3294
3295 /**
3296  * @brief  Handler to create STATUS Pdu
3297  *
3298  * @details
3299  *    This function is used to create status pdu 
3300  *
3301  * @param[in] gCb        RLC instance control block
3302  * @param[in] rbCb       Downlink RB control block
3303  * @param[in] rlcDatReq   The data to be passed to MAC
3304  *
3305  * @return Void
3306  *
3307  */
3308 void rlcAmmCreateStatusPdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *rlcDatReq)
3309 {
3310     RlcSn          sn;                      /* sequence number */
3311     RlcSn          ack_sn;                  /* Ack sequence number */
3312     Buffer        *mBuf;           /* control pdu buffer */
3313     MsgLen        cntrlPduSz;          /* control pdu size */
3314     uint8_t       cntrlPdu[RLC_MAX_CNTRL_FIELDS];   /* control pdu to be added to mBuf */
3315     RlcUdxDlStaPdu   *pStaPdu;
3316     uint16_t         bytesToEncode = 0; /* bytes required to encode the STATUS PDU */
3317     uint16_t         encIdx = 0;
3318     uint16_t         prevEncIdx = 0;
3319     RlcNackInfo      *rlcNackInfo;
3320     uint16_t         nkCnt = 0;
3321
3322     pStaPdu = AMDL.pStaPdu;
3323
3324
3325     /* D/C| CPT| */
3326     /* 0 - Control
3327        1 - Data */
3328     cntrlPdu[0] = 0x00;
3329     cntrlPdu[2] = 0x00;
3330
3331     /* ACK SN Field will be set in the end based on available Grant */
3332
3333     encIdx = bytesToEncode = 3; /* Num Octets before NACK SN info encoding*/
3334
3335     ack_sn = pStaPdu->ackSn;
3336
3337     if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3338     {
3339
3340        /* If alteast one NACK SN Info then set the E1 field */
3341        if (pStaPdu->nackCount)
3342        {
3343           /* 12 BIT SN CASE:
3344              In Third Octet:
3345              7  6 5 4 3 2 1 0
3346              E1 R R R R R R R 
3347            */
3348           cntrlPdu[2] = 0x80;
3349        }
3350
3351        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3352        {           
3353           sn = pStaPdu->nackInfo[nkCnt].sn;
3354
3355           rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3356
3357           bytesToEncode += 2; /* 2 Octets for NACK SN */
3358
3359           /* Check if E2 : isSegment is set */
3360           if (rlcNackInfo->isSegment)
3361           {
3362              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3363           }
3364
3365           /* Check if E3 : nackRange is set */
3366           if (rlcNackInfo->nackRange)
3367           {
3368              bytesToEncode += 1; /* 1 Octet: NACK range */
3369           }
3370
3371           /* Check if this NACK info can be accomodated in the Grant */
3372           if( rlcDatReq->pduSz >= bytesToEncode)
3373           {
3374              /* If there is a NACK SN before this then set its 
3375                 E1 bit */
3376              if(prevEncIdx)
3377              {
3378                 /* NACKSN  E1 E2 E3 R */
3379                 cntrlPdu[prevEncIdx + 1] |= 0x8;
3380              }
3381
3382              /* 12 BIT Nack SN encode */
3383              cntrlPdu[encIdx] = (sn & 0xFF0) >> 4;
3384
3385              /* Next Octet */
3386              cntrlPdu[encIdx + 1] = (sn & 0xF) << 4;
3387
3388              if (rlcNackInfo->isSegment)
3389              {
3390                 /*Set E2 Bit */
3391                 cntrlPdu[encIdx + 1] |= 0x4;
3392
3393
3394                 /* Add soStart and soEnd */
3395                 /* SOstart */
3396                 cntrlPdu[encIdx + 2] = (rlcNackInfo->soStart) >> 8; 
3397                 cntrlPdu[encIdx + 3] = rlcNackInfo->soStart & 0xFF;
3398
3399                 /* SOend */
3400                 cntrlPdu[encIdx + 4] = (rlcNackInfo->soEnd) >> 8;
3401                 cntrlPdu[encIdx + 5] = rlcNackInfo->soEnd & 0xFF;
3402              }
3403
3404              if (rlcNackInfo->nackRange)
3405              {
3406                 /*Set E3 Bit */
3407                 cntrlPdu[encIdx + 1] |= 0x2;
3408                 if(rlcNackInfo->isSegment)
3409                 {
3410                    cntrlPdu[encIdx + 6] = rlcNackInfo->nackRange;
3411                 }
3412                 else
3413                 {
3414                    cntrlPdu[encIdx + 2] = rlcNackInfo->nackRange;
3415                 }
3416              }
3417
3418              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3419           }
3420           /* Set ACK SN now */
3421           else
3422           {
3423              ack_sn = rlcNackInfo->sn;
3424
3425              /* Not even one nack can be accomodated */
3426              if (nkCnt == 0)
3427              {
3428                cntrlPdu[2] = 0x0;
3429              }
3430
3431              break;
3432           }
3433
3434           prevEncIdx = encIdx;
3435           encIdx = bytesToEncode;
3436
3437        }/* Loop is done for the NackCount */
3438
3439         /* set ACK SN */
3440        {
3441
3442           DU_LOG("\nRLC: rlcAssembleCntrlInfo: ACK PDU's SN = %d"\
3443              "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
3444
3445           cntrlPdu[0] |= (ack_sn & 0xF00)>> 8; 
3446           cntrlPdu[1] =  (U8)ack_sn;
3447        }
3448
3449     }
3450     else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3451     {
3452        /* If alteast one NACK SN Info then set the E1 field */
3453        if (pStaPdu->nackCount)
3454        {
3455           /* 12 BIT SN CASE:
3456              In Third Octet:
3457              7  6 5 4 3 2 1 0
3458              ACKSN       E1 R 
3459            */
3460           cntrlPdu[2] = 0x2;
3461        }
3462
3463        for(nkCnt = 0;nkCnt < pStaPdu->nackCount; nkCnt++)
3464        {           
3465           sn = pStaPdu->nackInfo[nkCnt].sn;
3466
3467           rlcNackInfo = &(pStaPdu->nackInfo[nkCnt]);
3468
3469           bytesToEncode += 3; /* 3 Octets for NACK SN */
3470
3471           /* Check if E2 : isSegment is set */
3472           if (rlcNackInfo->isSegment)
3473           {
3474              bytesToEncode += 4; /* 4 Octets: SOstart, SOend */ 
3475           }
3476
3477           /* Check if E3 : nackRange is set */
3478           if (rlcNackInfo->nackRange)
3479           {
3480              bytesToEncode += 1; /* 1 Octet: NACK range */
3481           }
3482
3483           /* Check if this NACK info can be accomodated in the Grant */
3484           if( rlcDatReq->pduSz >= bytesToEncode)
3485           {
3486              /* If there is a NACK SN before this then set its 
3487                 E1 bit */
3488              if(prevEncIdx)
3489              {
3490                 /* NACKSN  E1 E2 E3 R R R */
3491                 cntrlPdu[prevEncIdx + 2] |= 0x20;
3492              }
3493
3494              /* 18 BIT Nack SN encode */
3495              cntrlPdu[encIdx] = (U8)((sn & 0x3FC00) >> 10);
3496
3497              /* Next Octet */
3498              cntrlPdu[encIdx + 1] = (U8)((sn & 0x3FC) >> 2);
3499
3500              /* Next Octet */
3501              cntrlPdu[encIdx + 2] = (U8)((sn & 0x3)<< 6);
3502
3503              if (rlcNackInfo->isSegment)
3504              {
3505                 /* NACKSN  E1 E2 E3 R R R */
3506                 /*Set E2 Bit */
3507                 cntrlPdu[encIdx + 2] |= 0x10;
3508
3509
3510                 /* Add soStart and soEnd */
3511                 /* SOstart */
3512                 cntrlPdu[encIdx + 3] = (rlcNackInfo->soStart) >> 8;
3513                 cntrlPdu[encIdx + 4] = (U8)rlcNackInfo->soStart;
3514
3515                 /* SOend */
3516                 cntrlPdu[encIdx + 5] = (rlcNackInfo->soEnd) >> 8; 
3517                 cntrlPdu[encIdx + 6] = (U8)(rlcNackInfo->soEnd);
3518              }
3519
3520              if (rlcNackInfo->nackRange)
3521              {
3522                 /* NACKSN  E1 E2 E3 R R R */
3523                 /*Set E3 Bit */
3524                 cntrlPdu[encIdx + 2] |= 0x08;
3525
3526                 if (rlcNackInfo->isSegment)
3527                 {
3528                    cntrlPdu[encIdx + 7] = rlcNackInfo->nackRange;
3529                 }
3530                 else
3531                 {
3532                    cntrlPdu[encIdx + 3] = rlcNackInfo->nackRange;
3533                 }
3534              }
3535
3536              gRlcStats.amRlcStats.numDLNacksInStaPdu++;
3537           }
3538           /* Set ACK SN now */
3539           else
3540           {
3541              ack_sn = rlcNackInfo->sn;
3542
3543              /* Not even one nack can be accomodated */
3544              if (nkCnt == 0)
3545              {
3546                cntrlPdu[2] &= 0xFD;
3547              }
3548
3549              break;
3550           }
3551
3552           prevEncIdx = encIdx;
3553           encIdx = bytesToEncode;
3554
3555        }/* Loop is done for the NackCount */
3556    
3557        /* set ACK SN */
3558        {
3559
3560           DU_LOG("\nRLC: rlcAssembleCntrlInfo: ACK PDU's SN = %d"
3561              "UEID:%d CELLID:%d", ack_sn, rbCb->rlcId.ueId,rbCb->rlcId.cellId);
3562
3563           cntrlPdu[0] |=  (ack_sn & 0x3C000) >> 14;
3564           cntrlPdu[1] =  (ack_sn & 0x3FC0) >> 6;
3565           cntrlPdu[2] |= (ack_sn & 0x3F)<< 2;
3566        }
3567
3568     }
3569     else
3570     {
3571        /* ERROR Log */
3572        DU_LOG("\nRLC: rlcAssembleCntrlInfo:Conf SN LEN  %d  is INVALID !!!! \
3573           UEID:%d CELLID:%d", rbCb->m.amDl.snLen, rbCb->rlcId.ueId,
3574           rbCb->rlcId.cellId);
3575     }
3576
3577
3578 #ifndef L2_OPTMZ
3579     SGetMsg(RLC_GET_MEM_REGION(gCb), RLC_GET_MEM_POOL(gCb),&mBuf);
3580 #else
3581     mBuf = (Buffer *)rlcAmmStaPduList[rlcAmmStaPduListCnt++];
3582     SResetMBuf(mBuf);
3583     if(rlcAmmStaPduListCnt > 511)
3584        rlcAmmStaPduListCnt = 0;
3585 #endif
3586
3587     cntrlPduSz = encIdx;
3588     ODU_ADD_POST_MSG_MULT(cntrlPdu, cntrlPduSz, mBuf);
3589
3590     rlcDatReq->pduSz -= cntrlPduSz;
3591     /* Add mBuf to AMDL.mBuf */
3592     AMDL.mBuf = mBuf;
3593  
3594     return;
3595 }
3596
3597 #ifdef RLC_STA_PROC_IN_MAC/* RLC Status PDU Processing */
3598
3599 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3600       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu);
3601
3602 #ifdef ANSI
3603 PRIVATE Void rgAmmExtractElmnt
3604 (
3605 RlcCb       *gCb,
3606 Buffer     *pdu,
3607 RlcExtHdr   *hdrInfo
3608 )
3609 #else
3610 PRIVATE Void rgAmmExtractElmnt(gCb, pdu, hdrInfo)
3611 RlcCb       *gCb;
3612 Buffer     *pdu;
3613 RlcExtHdr   *hdrInfo;
3614 #endif
3615 {
3616    U8   hdr;
3617    U8   pLen = hdrInfo->pLen;
3618    U8   len  = (U8)hdrInfo->len;
3619    U16  val;
3620    U8   tHdr;
3621    U8   fLen;
3622    U8   rLen;
3623    /* U8   rLen1 = 0; */
3624    U16  tVal;
3625
3626    TRC2(rlcAmmExtractElmnt);
3627
3628    hdr = hdrInfo->hdr;
3629
3630    if (pLen == 0)
3631    {
3632       SRemPreMsg(&hdr, pdu);
3633       pLen = 8;
3634    }
3635    tHdr = hdr;
3636    if (len <= 8)
3637    {
3638       val = tHdr >> (RLC_BYTE_LEN - (len));
3639       hdr =  hdr << len;
3640       pLen -= len;
3641    }
3642    else /*if (len > 8) */
3643    {
3644       fLen = pLen;
3645       val = tHdr;
3646       val = val >> (RLC_BYTE_LEN - fLen);
3647       val = val << (len - fLen);
3648       rLen = len - fLen;
3649       SRemPreMsg(&hdr, pdu);
3650       tHdr = hdr;
3651       if (rLen <= 8)
3652       {
3653          hdr = hdr >> (RLC_BYTE_LEN - rLen);
3654          val = val | hdr;
3655          hdr = tHdr << rLen;
3656          pLen = (RLC_BYTE_LEN - rLen);
3657       }
3658       else
3659       {
3660         rLen = rLen - RLC_BYTE_LEN;
3661         tVal = hdr;
3662         tVal = tVal << rLen;
3663         val = val | tVal;
3664
3665         SRemPreMsg(&hdr, pdu);
3666         tHdr = hdr;
3667         hdr = hdr >> (RLC_BYTE_LEN - rLen);
3668         val = val | hdr;
3669         hdr = tHdr << rLen;
3670         pLen = (RLC_BYTE_LEN - rLen);
3671       }
3672    }
3673
3674    hdrInfo->pLen = pLen;
3675    hdrInfo->hdr = hdr;
3676    hdrInfo->val = val;
3677
3678    RETVOID;
3679 }
3680
3681
3682
3683
3684 #ifdef ANSI
3685 PRIVATE Void rgAmmUlHndlStatusPdu
3686 (
3687 Pst        *udxPst,
3688 SuId       suId,
3689 RlcCb       *gCb,
3690 RlcDlRbCb   *rbCb,
3691 Buffer     *cntrlPdu,
3692 U8         *fByte
3693 )
3694 #else
3695 PRIVATE Void rgAmmUlHndlStatusPdu(udxPst,suId,gCb, rbCb, cntrlPdu, fByte)
3696 Pst        *udxPst;
3697 SuId       suId;
3698 RlcCb       *gCb;
3699 RlcDlRbCb   *rbCb;
3700 Buffer     *cntrlPdu;
3701 U8         *fByte;
3702 #endif
3703 {
3704    U8             e1;
3705    RlcExtHdr       hdrInfo;
3706    RlcUdxStaPdu    *pStaPdu;
3707    U8             e3; /* NACK RANGE : 5GNR */
3708    U32            snLen;
3709    U32            snRange;
3710    U32            resrvdBitsAckSn;
3711    U32            resrvdBitsNackSn;
3712
3713
3714    TRC2(rgAmmUlHndlStatusPdu)
3715
3716    RLCDBGP_BRIEF(gCb, "rgAmmUlHndlStatusPdu(rbCb, cntrlPdu, fByte) \n");
3717
3718    RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
3719
3720    /* Extract the Control PDU */
3721    hdrInfo.hdr  = (*fByte << 1);
3722    hdrInfo.pLen = 4;
3723
3724    /* D/C has been shifted in the calling function */
3725    if (hdrInfo.hdr & 0xE0)
3726    {
3727       RLCDBGP_ERROR(gCb, "rgAmmUlHndlStatusPdu: Reserved value for CPT received \n");
3728       RETVOID;
3729    }
3730
3731    RLC_ALLOC_SHRABL_BUF(udxPst->region, 
3732                        udxPst->pool, 
3733                        pStaPdu, 
3734                        sizeof(RlcUdxStaPdu));
3735
3736 #if (ERRCLASS & ERRCLS_ADD_RES)
3737    /* Memory allocation failure can not be expected  */
3738    if(!pStaPdu)
3739    {
3740      RETVOID;
3741    }
3742 #endif   
3743
3744    if (rbCb->m.amDl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
3745    {
3746       snLen = 12;
3747       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
3748       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
3749    }
3750    else if (rbCb->m.amDl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
3751    {
3752       snLen = 18;
3753       resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
3754       resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
3755    }
3756    else
3757    {
3758       snLen = RLC_SN_LEN;
3759       resrvdBitsAckSn = 0;
3760       resrvdBitsAckSn = 0;
3761    }
3762
3763    pStaPdu->nackCnt = 0;
3764    /* For CPT */
3765    hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
3766
3767    /* ACK Sn */
3768    hdrInfo.len = RLC_SN_LEN;
3769    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3770    pStaPdu->ackSn = hdrInfo.val;
3771
3772    /* Check if NACK Exists */
3773    hdrInfo.len = RLC_E1_LEN;
3774    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3775    e1 = (U8)hdrInfo.val;
3776    RLCDBGP_DETAIL(gCb, "rgAmmUlHndlStatusPdu: ACK SN = %d \n", pStaPdu->ackSn);
3777
3778    /* Extract the Reserved Bits after ACK SN field */
3779    hdrInfo.len = resrvdBitsAckSn;
3780    rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3781
3782
3783    /* If NACK exists in control PDU */
3784    /* For ACKs and NACKs */
3785    while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
3786    {
3787       hdrInfo.len = snLen;
3788       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3789       pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
3790
3791       hdrInfo.len = RLC_E1_LEN;
3792       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3793       e1 = (U8)hdrInfo.val;
3794
3795       /* Extract e2 */
3796       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3797          already present*/
3798       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3799       /*  e2 = (U8) hdrInfo.val;*/
3800
3801       /* Store e2 value */
3802       pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
3803
3804       /* Extract e3 : 5GNR */
3805       /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
3806          already present*/
3807       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3808       e3 = (U8) hdrInfo.val;
3809
3810       /* Extract Reserved Bits after NACK SN */
3811       hdrInfo.len = resrvdBitsNackSn;
3812       rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3813
3814       /* Test for resegmentation */
3815       if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
3816       {
3817          hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
3818          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3819          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
3820
3821          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3822          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = hdrInfo.val;
3823
3824          RLCDBGP_DETAIL(gCb,
3825                        "rgAmmUlHndlStatusPdu: soStart and soEnd = %d %d \n",
3826                        pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
3827                        pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd);
3828       }
3829       else
3830       {
3831          hdrInfo.len = 0;
3832          pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
3833          pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd   = 0;
3834
3835       }
3836       /* NACK RANGE Field is SET */
3837       if (e3)
3838       {
3839          /* Extract NACK range field */
3840          hdrInfo.len = RLC_NACK_RANGE_LEN;
3841          rgAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
3842          snRange = (U8)hdrInfo.val;
3843
3844          pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
3845
3846       }
3847       pStaPdu->nackCnt++;
3848    }
3849
3850    gRlcStats.amRlcStats.numULStaPduRcvd++;
3851    gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
3852
3853    /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
3854       to the last NACK SN + 1 and discard the original ACK_SN*/
3855    if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
3856    {
3857       pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & amDl->snModMask;
3858    }
3859
3860
3861    /* Parse & send Status PDU to RLC-DL */
3862    //rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
3863    rlcUlUdxStaUpdReq(udxPst, suId, &rbCb->rlcId, pStaPdu);
3864
3865    RETVOID;
3866 }
3867
3868 S16 rlcProcDlStatusPdu(Pst *udxPst,SuId suId,
3869       CmLteCellId cellId,CmLteRnti rnti,CmLteLcId lcId,Buffer *rlcSdu)
3870 {
3871    RlcDlRbCb      *rbCb = NULLP;   
3872    RlcDlUeCb      *ueCb = NULLP; 
3873    U8        fByte;
3874    U8        temp;
3875    S16       retVal = RFAILED;
3876    RlcCb      *gCb;
3877    Pst       dlRlcPst = *udxPst;
3878
3879    gCb = RLC_GET_RLCCB(1); /* DL RLC instance */
3880
3881    if( ROK != rlcDbmFetchDlUeCb(gCb,rnti,cellId,&(ueCb)))
3882    {
3883      printf("\n RLC UECb Not found...\n");
3884      return RFAILED;
3885    }
3886
3887
3888    rbCb = ueCb->lCh[lcId - 1].dlRbCb;
3889
3890    /* Skip if mode is not AM */
3891    if((rbCb ==  NULLP) || (rbCb->mode != CM_LTE_MODE_AM))
3892    {
3893       return RFAILED;
3894    }
3895
3896    if(ROK != SExamMsg((Data *)(&fByte),
3897             rlcSdu, 0))
3898    {
3899       printf("\n Failure in Rlc Hdr SExamMsg\n");
3900       return RFAILED;
3901    }
3902
3903    if(RLC_CNTRL_PDU == ((fByte & RLC_DC_POS) >> RLC_DC_SHT))
3904    {
3905       SRemPreMsg(&temp, rlcSdu);
3906       dlRlcPst.selector = 1;/* LWLC*/
3907       rgAmmUlHndlStatusPdu(&dlRlcPst,suId,gCb, rbCb, rlcSdu, &fByte);
3908       retVal = ROK;
3909    }
3910
3911    return (retVal);
3912 }
3913
3914
3915 #endif
3916
3917
3918 /*@}*/
3919
3920 \f  
3921 /********************************************************************30**
3922   
3923          End of file
3924 **********************************************************************/