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