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