Adding new commiter to ODU-High repo
[o-du/l2.git] / src / 5gnrrlc / rlc_umm_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
21      Name:     NR RLC Layer 
22   
23      Type:     C file
24   
25      Desc:     Source code for RLC Unacknowledged mode assembly and
26                reassembly.This file contains following functions
27
28                   --rlcUmmQSdu
29                   --rlcUmmProcessSdus
30                   --rlcUmmProcessPdus
31                   --rlcUmmReAssembleSdus
32                   --kwUmmReEstablish 
33
34      File:     rlc_umm_dl.c
35
36 **********************************************************************/
37 /** 
38  * @file rlc_umm_dl.c
39  * @brief RLC Unacknowledged Mode downlink module
40 */
41
42 /* header (.h) include files */
43 #include "common_def.h"
44 #include "ckw.h"                /* RRC layer */
45 #include "lkw.h"                /* RRC layer */
46 #include "kwu.h"                /* RLC service user */
47 #include "lkw.h"                /* LM Interface */
48 #include "rgu.h"                /* MAC layer */
49 #include "rlc_env.h"             /* RLC environment options */
50 #include "rlc_err.h"
51
52
53
54
55 /* header/extern include files (.x) */
56
57 #include "ckw.x"                /* RRC layer */
58 #include "kwu.x"                /* RLC service user */
59 #include "lkw.x"                /* LM Interface */
60 #include "rgu.x"                /* MAC later */
61
62 #include "rlc_utils.h"                 /* RLC layer */
63 #include "rlc_dl_ul_inf.h"
64 #include "rlc_dl.h"
65
66 #define RLC_MODULE (RLC_DBGMASK_UM | RLC_DBGMASK_DL)
67
68 /* variables for logging :declared in BRDCM cl */
69 #ifndef TENB_ACC
70 uint32_t dldrops_kwu_um;
71 uint32_t dlpkt_um;
72 uint32_t buffer_occ;
73 uint32_t dlrate_kwu;
74 #endif
75
76 static Void rlcUmmCreatePdu ARGS ((RlcCb *gCb,
77                                   RlcDlRbCb *rbCb, 
78                                   Buffer *pdu,
79                                   RlcUmHdr *umHdr,
80                                   KwPduInfo *datReqPduInfo));
81
82 /** @addtogroup ummode */
83 /*@{*/
84
85 /**
86  * @brief  Handler to queue a SDU in the SDU queue, update BO and report 
87  *         it to the lower layer.
88  *       
89  * @details
90  *    This function is used to queue the received SDU in the 
91  *    SDU queue maintained in the radio bearer control block.
92  *    After queuing the SDU, BO is updated and is reported
93  *    to the lower layer. 
94  *
95  * @param[in] gCb      RLC Instance control block
96  * @param[in] rbCb     RB control block 
97  * @param[in] datReq   Ptr to the datReq sent from PDCP
98  * @param[in] mBuf     Sdu data
99  *
100  * @return  Void
101 */  
102 void rlcUmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReqInfo *datReq, Buffer *mBuf)
103 {
104    MsgLen   len;    /* SDU buffer length */
105    RlcSdu    *sdu;   /* SDU */
106
107    RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
108
109    RLC_ALLOC_WC(gCb, sdu, (Size)sizeof(RlcSdu));
110 #if (ERRCLASS & ERRCLS_ADD_RES)
111    if ( sdu == NULLP )
112    {
113       DU_LOG("\nERROR  -->  RLC DL : Memory allocation failed in rlcUmmQSdu for UEID:%d CELLID:%d",\
114                rbCb->rlcId.ueId,
115                rbCb->rlcId.cellId);
116       ODU_PUT_MSG_BUF(mBuf);
117       return;
118    }
119 #endif /* ERRCLASS & ERRCLS_ADD_RES */
120
121 /* Discard new changes starts */
122    rlcUtlGetCurrTime(&sdu->arrTime);
123 /* Discard new changes ends */
124    ODU_GET_MSG_LEN(mBuf,&len);
125
126    sdu->mBuf = mBuf;
127    sdu->sduSz = len;
128    sdu->actSz = len;
129    sdu->mode.um.sduId = datReq->sduId;
130    sdu->mode.um.isSegmented = FALSE;
131 #ifndef RGL_SPECIFIC_CHANGES
132 #ifndef TENB_ACC
133 #ifndef LTE_PAL_ENB
134    {
135          dlrate_kwu += len;
136    }
137 #endif   
138 #endif
139 #endif
140    rbCb->m.umDl.bo += len;
141    rbCb->m.umDl.bo += RLC_MAX_HDRSZ;
142    cmLListAdd2Tail(&(rbCb->m.umDl.sduQ), &sdu->lstEnt);
143    sdu->lstEnt.node = (PTR)sdu;
144
145    if(!rlcDlUtlIsReestInProgress(rbCb))
146    {
147       rlcUtlSendDedLcBoStatus(gCb, rbCb, rbCb->m.umDl.bo, 0, FALSE,0);
148    }
149    
150    /* kw005.201 added support for L2 Measurement */
151 #ifdef LTE_L2_MEAS_RLC
152    /* Update numActUe if it is not active */
153    if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
154       (rbCb->ueCb->numActRb[rbCb->qci]++ == 0))
155    {
156      rlcCb.rlcL2Cb.numActUe[rbCb->qci]++;
157    }
158 #endif
159
160    return;    
161 }
162
163
164 /**
165  * @brief   Handler to form PDU(s) and update the BO. 
166  *       
167  * @details
168  *     -# This function forms pdu(s) from the SDU(s) in the
169  *        SDU queue and returns them.
170  *     -# This function also updates the BO along with the 
171  *        along with the estimated Header size.
172  *
173  * @param[in]  rbCb     RB control block 
174  * @param[out] pduInfo  Pdu Info to be filled and the PDU size to be 
175  *                      formed and the updated BO
176  * @param[in]  pduSz    The size for which PDUs have to constructed
177  *
178  * @return  S16
179  *    -# ROK       In case of success
180  *    -# RFAILED   If allocation of Sdu fails
181 */  
182 void rlcUmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *datReq)
183 {
184    CmLList     *firstNode;   /* First Node in SDU queue */
185    Buffer      *pdu;         /* Buffer for holding the formed PDU */
186    KwPduInfo   *pduInfo;     /* PDU Info pointer */
187    int16_t     pduSz;        /* PDU Size to be constructed */
188    RlcUmHdr    umHdr;        /* Header */
189    uint32_t    rlcHdrSz;
190    uint32_t    rlcSduSz;
191    uint32_t    rlcPduSz;
192    uint32_t    macHdrSz;
193    
194    /* kw005.201 added support for L2 Measurement */
195 #ifdef LTE_L2_MEAS
196    RlcContSduLst         contSduLst;  /*Contained sduLst */
197    int32_t               dataVol    = rbCb->m.umDl.bo;
198    uint32_t*             totMacGrant= &(datReq->totMacGrant);
199    RlcL2MeasDlIpTh       *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
200    uint8_t               *sduIdx    = &dlIpThPut->lastSduIdx;
201    bool                  newIdx = FALSE;
202    int32_t               oldBo;
203    RlclchInfo            lchInfo = {0};
204    uint32_t              segSduCnt = 0;
205 #endif
206    Ticks                curTime  = 0;
207    int16_t              timeDiff = 0;
208    RlcSdu                *sdu;
209
210    pdu = NULLP;
211    pduInfo = &(datReq->pduInfo);
212    pduSz = datReq->pduSz;
213    
214 #ifdef LTE_L2_MEAS   
215    contSduLst.numSdus = 0;
216    contSduLst.lcId = rbCb->lch.lChId;
217    oldBo = rbCb->m.umDl.bo; 
218    lchInfo.lcId = rbCb->lch.lChId;
219    lchInfo.numSdus = 0;
220 #endif
221
222    /* Discard new changes starts */
223    rlcUtlGetCurrTime(&curTime);
224
225    /* ccpu00143043 */
226    while ((pduSz > 0) && (rbCb->m.umDl.sduQ.count > 0) && (pduInfo->numPdu < RLC_MAX_PDU))
227    {
228       CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,firstNode);
229       sdu = (RlcSdu *)(firstNode->node);
230
231       if ((sdu->mode.um.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && 
232             (rbCb->rlcId.rbType == CM_LTE_DRB))
233       {
234          timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime); 
235
236          if (timeDiff >= rbCb->discTmrInt)
237          {
238 #ifdef LTE_L2_MEAS 
239             RLC_UPD_L2_DL_DISC_SDU_STS(gCb, rbCb);
240 #endif
241             rbCb->m.umDl.bo -= sdu->sduSz;
242             RLC_REMOVE_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
243             continue;
244          }
245       }
246 #ifdef LTE_L2_MEAS
247       newIdx = FALSE;
248 #endif
249       /* When forming a new PDU, pdu == NULLP
250            -# Eliminate MAC header size for each pdu
251            -# Substract the fixed header length based on SN length
252       */
253       /* account for the RLC header size
254          minimum header size will be 1 , if Sdu is not segmented */
255       rlcHdrSz = RLC_MIN_HDRSZ;
256       if(sdu->mode.um.isSegmented)
257       {
258          /* value of rbCb->m.umDl.snLen will be 1 for 6 bit SN and 2 for 12 bit SN and 2 bytes of SO */
259          rlcHdrSz = (rbCb->m.umDl.snLen + 2);
260       }
261       macHdrSz = RLC_MAC_HDR_SZ2; /*Minimum MacHdr size */
262       rlcSduSz = sdu->sduSz;
263       rlcPduSz = ((rlcSduSz + rlcHdrSz) < (pduSz - macHdrSz))? (rlcSduSz + rlcHdrSz) : (pduSz - macHdrSz);
264       rlcSduSz = rlcPduSz - rlcHdrSz;
265
266       /*Estimate MAC Hdr based on calculated rlcPduSz */
267       macHdrSz = (rlcPduSz > 255 ) ? RLC_MAC_HDR_SZ3 : RLC_MAC_HDR_SZ2;
268
269       if(macHdrSz != RLC_MAC_HDR_SZ2)
270       {
271           rlcSduSz = sdu->sduSz;
272           rlcPduSz = ((rlcSduSz + rlcHdrSz) < (pduSz - macHdrSz))? (rlcSduSz + rlcHdrSz) : (pduSz - macHdrSz);
273           rlcSduSz = rlcPduSz - rlcHdrSz;
274           macHdrSz = (rlcPduSz > 255 ) ? RLC_MAC_HDR_SZ3 : RLC_MAC_HDR_SZ2;
275       }
276
277       if(sdu->mode.um.isSegmented == FALSE)
278       {
279           /* RLC SDU is estimated to be segmented first time */
280           if(rlcSduSz < sdu->sduSz)
281           {
282               rlcHdrSz = rbCb->m.umDl.snLen;
283               rlcSduSz = sdu->sduSz;
284               rlcPduSz = ((rlcSduSz + rlcHdrSz) < (pduSz - macHdrSz))? (rlcSduSz + rlcHdrSz) : (pduSz - macHdrSz);
285               rlcSduSz = rlcPduSz - rlcHdrSz;
286               /*Estimate MAC Hdr based on calculated rlcPduSz */
287               macHdrSz = (rlcPduSz > 255 ) ? RLC_MAC_HDR_SZ3 : RLC_MAC_HDR_SZ2;
288           }
289       }
290
291       pduSz -= (rlcHdrSz + macHdrSz);
292
293       if(pduSz <= 0)
294       {
295           break;
296       }
297      
298       /* No Segmentation scenario :
299          If SDU size is less than or equal to the requested PDU size
300          -# Allocate memory and copy SDU into it.
301          -# Update BO
302          -# Remove SDU from the Queue.
303       */
304       if (sdu->sduSz <= pduSz)
305       {
306          if (!pdu)
307          {
308             pdu = sdu->mBuf;
309             sdu->mBuf = NULLP;
310          }
311          rbCb->m.umDl.bo -= sdu->sduSz;
312          rbCb->m.umDl.bo -= RLC_MAX_HDRSZ;
313          pduSz -= sdu->sduSz;
314
315 #ifdef LTE_L2_MEAS
316         if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
317         {
318            if(sdu->mode.um.isSegmented)
319            {
320               *sduIdx    = dlIpThPut->lastSduIdx;
321            }
322            else
323            {
324               RLC_GETSDUIDX(*sduIdx);
325               newIdx = TRUE;
326            }
327            rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
328            rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
329                  sdu->mode.um.sduId, newIdx);
330            /* ccpu00143043 */
331            if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
332            {
333               lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
334               lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
335               lchInfo.numSdus++;
336            }
337         }
338 #endif
339 /* kw005.201 added support for L2 Measurement */
340 #ifdef LTE_L2_MEAS_RLC
341          rlcUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
342          if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_DL_DELAY) ||
343                  (rbCb->rbL2Cb.measOn & LKW_L2MEAS_UU_LOSS))
344           {
345              /* ccpu00143043 */
346              if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
347              {
348                 lchInfo.arvlTime[lchInfo.numSdus] = sdu->arrTime; 
349                 lchInfo.numSdus++;
350              }
351           }
352 #endif /*  LTE_L2_MEAS */
353
354          if(sdu->mode.um.isSegmented)
355          {
356              umHdr.si = RLC_SI_LAST_SEG;
357              umHdr.so = sdu->actSz - sdu->sduSz;
358              sdu->mode.um.isSegmented = FALSE;
359          }
360          else
361          {
362               umHdr.si = 0;
363               umHdr.so = 0;
364          }
365          rlcUmmCreatePdu(gCb, rbCb, pdu, &umHdr, pduInfo);
366          RLC_REMOVE_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu); /* kw003.201 */
367          rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
368          pdu = NULLP;
369       }
370       /* Segmentation scenario :
371          If size of SDU is greater than PDU size 
372            -# Allocate memory and Segment the Sdu.
373            -# Update BO
374            -# Add segment to the PDU
375            -# Set the second bit of the segmentation info.
376            -# Create the complete PDU and place in pduInfo.
377       */ 
378       else 
379       {
380          Buffer *remSdu;
381        
382          ODU_SEGMENT_MSG(sdu->mBuf,pduSz,&remSdu);
383         
384 #ifdef LTE_L2_MEAS
385         if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb, rbCb))
386         {
387            if(sdu->mode.um.isSegmented)
388            {
389               *sduIdx    = dlIpThPut->lastSduIdx;
390            }
391            else
392            {
393               RLC_GETSDUIDX(*sduIdx);
394               newIdx = TRUE;
395            }
396            rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
397            rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
398                  sdu->mode.um.sduId, newIdx);
399         }
400         if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
401         {
402            if(sdu->actSz == sdu->sduSz)
403            {
404               segSduCnt++;
405            }
406         }
407 #endif
408          if(sdu->mode.um.isSegmented)
409          {
410             umHdr.si = RLC_SI_MID_SEG;
411             umHdr.so = sdu->actSz - sdu->sduSz;
412          }
413          else
414          {
415             umHdr.si = RLC_SI_FIRST_SEG;
416             umHdr.so = 0;
417             sdu->mode.um.isSegmented = TRUE;
418          }
419          pdu = sdu->mBuf;
420          sdu->sduSz -= pduSz;
421          rbCb->m.umDl.bo -= pduSz;
422          sdu->mBuf = remSdu;
423          pduSz = 0;
424
425 /* kw005.201 added support for L2 Measurement */
426 #ifdef LTE_L2_MEAS_RLC
427          rlcUtlUpdSduSnMap(rbCb, sdu, datReq, FALSE);
428 #endif /*  LTE_L2_MEAS */
429
430          rlcUmmCreatePdu(gCb, rbCb, pdu, &umHdr, pduInfo);
431          pdu = NULLP;
432       }
433 /* kw005.201 added support for L2 Measurement */
434    }
435 #ifdef LTE_L2_MEAS_RLC
436    if((rbCb->rbL2Cb.measOn) && 
437       (rbCb->m.umDl.sduQ.count == 0) && 
438       (dataWasPrsnt))
439    {
440       if(--(rbCb->ueCb->numActRb[rbCb->qci]) == 0)
441       {
442          rlcCb.rlcL2Cb.numActUe[rbCb->qci]--;
443       }
444    }
445 #endif /* LTE_L2_MEAS */
446 #ifdef LTE_L2_MEAS
447    rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
448    /* Need to check into optimizing this code : TODO */
449    if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && (lchInfo.numSdus != 0))
450    {
451       RlcL2MeasTb *l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
452       /* ccpu00143043 */
453       /* Fix Klock warning */
454       if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP) &&
455           (l2MeasTb->numLchInfo < RLC_MAX_ACTV_DRB))
456       {   
457          memcpy( &l2MeasTb->lchInfo[l2MeasTb->numLchInfo],  &lchInfo, sizeof(RlclchInfo));
458          l2MeasTb->numLchInfo++;
459       }
460       l2MeasTb->txSegSduCnt += segSduCnt;
461    }
462    *totMacGrant -= (oldBo - rbCb->m.umDl.bo);
463 #endif 
464
465    datReq->boRep.bo = rbCb->m.umDl.bo;
466    datReq->boRep.estHdrSz = 0;
467    datReq->boRep.staPduPrsnt = FALSE;
468    if (rbCb->m.umDl.sduQ.count > 0)
469    {
470       datReq->boRep.oldestSduArrTime = 
471         ((RlcSdu *)(rbCb->m.umDl.sduQ.first->node))->arrTime;
472    }
473    return; 
474 }
475
476 /**
477  * @brief   Handler to process the re-establishment request received from i
478  *          the upper layer. 
479  *       
480  * @details
481  *     This function does the following functions : 
482  *         Remove all the SDUs in the SDU queue.
483  *
484  * @param[in] gCb        RLC Instance control block
485  * @param[in] rlcID      Identity of the RLC entity for which 
486  *                       re-establishment is to be done
487  * @param[in] sendReEst  Whether to send re-establishment complete 
488  *                       indication to  upper layer or not
489  * @param[in] rbCb       RB control block for which re-establishment 
490  *                       is to be done
491  *
492  * @return  Void
493 */ 
494 Void rlcDlUmmReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcDlRbCb *rbCb)
495 {
496    /* The re-establishment indication is sent from the UL only */
497
498    rlcUmmFreeDlRbCb(gCb, rbCb);
499
500    rbCb->m.umDl.txNext = 0;
501
502    /* this would have been set when re-establishment was triggered
503       for SRB 1 */
504    rlcDlUtlResetReestInProgress(rbCb);
505    
506    return;
507 }
508 /**
509  * @brief   Handler to create the header and complete a PDU.
510  *       
511  * @details
512  *     This function is used to create the header of a PDU and concatenate  it
513  *     with the data part of the PDU.
514  *     Also updates the statistics
515  *     Sets the passed pdu to NULLP
516  *
517  * @param[in]     gCb            RLC instance control block
518  * @param[in,out] rbCb           RB control block 
519  * @param[in]     pdu            PDU  
520  * @param[in]     umHdr          UM mode header
521  * @param[out]    datReqPduInfo  Holder in which to copy the created PDU pointer
522  *
523  * @return  Void
524 */ 
525 static void rlcUmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr, KwPduInfo *datReqPduInfo)
526 {
527    RlcSn     sn;                   /*  Sequence Number */
528    uint8_t   hdr[RLC_MAX_HDRSZ];   /* Stores header */
529    uint32_t  idx = 0;              /* To index to the hdr array */
530    
531    /* stats updated before for bytes sent before adding RLC headers */
532    rlcUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
533          
534    /* If SI = 0, 1 byte header conatining SI/R */
535    if(umHdr->si == 0)
536    {
537       hdr[idx++] = 0;
538    }
539    else
540    {
541       /* Add SN based on SN length */
542       sn = rbCb->m.umDl.txNext;
543       if (rbCb->m.umDl.snLen == RLC_UM_CFG_6BIT_SN_LEN) 
544       {
545          hdr[idx++] = (umHdr->si << 6) | sn;
546       }
547       else
548       {
549          hdr[idx++] = (umHdr->si << 6) | (sn >> 8);
550          hdr[idx++] = sn & 0xff ;
551       }
552
553       /* Add SO for middle and last segments*/
554       if((umHdr->si == RLC_SI_MID_SEG) | (umHdr->si == RLC_SI_LAST_SEG))
555       {
556          hdr[idx++] = (umHdr->so >> 8);
557          hdr[idx++] = umHdr->so & 0xff;
558       }
559
560       /* Increment TX_Next if this is last segment of current SDU */
561       if(umHdr->si == RLC_SI_LAST_SEG)
562          rbCb->m.umDl.txNext = (rbCb->m.umDl.txNext + 1) & rbCb->m.umDl.modBitMask;
563
564    }
565
566    /* add the header to the beginning of the pdu */
567    ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx, pdu);
568
569    datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
570    return;
571 }
572
573 /**
574  * @brief   Handler to discard a SDU.
575  *       
576  * @details
577  *     This function is used to discard a SDU after receiving
578  *     the Discard Request from the upper layer.The SDU is discarded if 
579  *     it is present and is not mapped to any PDU yet. 
580  *     The discards coming from the upper layer would be coming in 
581  *     sequence according to the sduId, so we should find the sduId at the 
582  *     head of the sduQ. Discards if there is a match else does nothing.
583  *
584  * @param[in] rbCb   RB control block 
585  * @param[in] sduId  SDU ID of the SDU to be discarded
586  *
587  * @return  Void
588 */
589 Void rlcUmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId)
590 {
591    CmLList *tmpNode;  /* Temporary Node in SDU queue */
592    CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
593
594    if (tmpNode)
595    {
596       RlcSdu *sdu = (RlcSdu *)tmpNode->node;
597       
598       if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
599       {
600 /* kw005.201 added support for L2 Measurement */
601          RLC_REMOVE_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
602          gCb->genSts.numSduDisc++;         
603       }
604    }
605
606    return;
607 }
608
609 /*
610  *
611  * @brief
612  *    function to free/release the UnAcknowledged mode RBCB buffers
613  *
614  * @details
615  *    This primitive Frees the Unacknowldged Mode RbCb sdu queue
616  *
617  * @param [in]   gCb    - RLC instance control block
618  * @param [in]   rbCb   - RB Control Block
619  *
620  * @return Void
621  */
622 Void rlcUmmFreeDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb)
623 {
624
625    /* cat the SDU queue to the to be freed list */
626    RLC_FREE (gCb,rbCb->snssai, sizeof (Snssai));
627    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.umDl.sduQ));
628    rlcUtlRaiseDlCleanupEvent(gCb);
629
630    return;
631 } /* rlcUmmFreeDlRbCb */
632
633 /********************************************************************30**
634          End of file
635 **********************************************************************/