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