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