1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
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 #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
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 *******************************************************************************/
19 /**********************************************************************
25 Desc: Source code for RLC Unacknowledged mode assembly and
26 reassembly.This file contains following functions
36 **********************************************************************/
37 static const char* RLOG_MODULE_NAME="RLC";
38 static int RLOG_MODULE_ID=2048;
39 static int RLOG_FILE_ID=239;
42 * @brief RLC Unacknowledged Mode downlink module
45 /* header (.h) include files */
46 #include "envopt.h" /* environment options */
47 #include "envdep.h" /* environment dependent */
48 #include "envind.h" /* environment independent */
50 #include "gen.h" /* general */
51 #include "ssi.h" /* system services interface */
52 #include "cm5.h" /* Timer Functions */
53 #include "cm_lte.h" /* common umts header file */
54 #include "cm_hash.h" /* common hash module file */
55 #include "cm_llist.h" /* common list header file */
56 #include "ckw.h" /* RRC layer */
57 #include "lkw.h" /* RRC layer */
58 #include "kwu.h" /* RLC service user */
59 #include "lkw.h" /* LM Interface */
60 #include "rgu.h" /* MAC layer */
61 #include "kw_env.h" /* RLC environment options */
63 #include "kw.h" /* RLC layer */
69 /* header/extern include files (.x) */
71 #include "gen.x" /* general */
72 #include "ssi.x" /* system services interface */
73 #include "cm_lib.x" /* common library */
74 #include "cm5.x" /* Timer Functions */
75 #include "cm_hash.x" /* common hash module */
76 #include "cm_lte.x" /* common umts file */
77 #include "cm_llist.x" /* common list header file */
78 #include "ckw.x" /* RRC layer */
79 #include "kwu.x" /* RLC service user */
80 #include "lkw.x" /* LM Interface */
81 #include "rgu.x" /* MAC later */
83 #include "kw.x" /* RLC layer */
87 #define KW_MODULE (KW_DBGMASK_UM | KW_DBGMASK_DL)
89 /* variables for logging :declared in BRDCM cl */
91 extern U32 dldrops_kwu_um;
93 extern U32 buffer_occ;
94 extern U32 dlrate_kwu;
97 PRIVATE Void kwUmmEstHdrSz ARGS ((KwUmDl *umUl));
99 PRIVATE Void kwUmmCreatePdu ARGS ((KwCb *gCb,
103 KwPduInfo *datReqPduInfo));
105 /** @addtogroup ummode */
109 * @brief Handler to queue a SDU in the SDU queue, update BO and report
110 * it to the lower layer.
113 * This function is used to queue the received SDU in the
114 * SDU queue maintained in the radio bearer control block.
115 * After queuing the SDU, BO is updated and is reported
116 * to the lower layer.
118 * @param[in] gCb RLC Instance control block
119 * @param[in] rbCb RB control block
120 * @param[in] datReq Ptr to the datReq sent from PDCP
121 * @param[in] mBuf Sdu data
126 PUBLIC Void kwUmmQSdu
130 KwuDatReqInfo *datReq,
134 PUBLIC Void kwUmmQSdu(gCb,rbCb,datReq,mBuf)
137 KwuDatReqInfo *datReq;
141 MsgLen len; /* SDU buffer length */
142 KwSdu *sdu; /* SDU */
146 KW_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
148 KW_ALLOC_WC(gCb, sdu, (Size)sizeof(KwSdu));
149 #if (ERRCLASS & ERRCLS_ADD_RES)
152 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
153 "Memory allocation failed UEID:%d CELLID:%d",
159 #endif /* ERRCLASS & ERRCLS_ADD_RES */
161 /* Discard new changes starts */
162 kwUtlGetCurrTime(&sdu->arrTime);
163 /* Discard new changes ends */
164 SFndLenMsg(mBuf,&len);
169 sdu->mode.um.sduId = datReq->sduId;
170 sdu->mode.um.isSegmented = FALSE;
171 #ifndef RGL_SPECIFIC_CHANGES
180 rbCb->m.umDl.bo += len;
182 cmLListAdd2Tail(&(rbCb->m.umDl.sduQ), &sdu->lstEnt);
183 sdu->lstEnt.node = (PTR)sdu;
185 kwUmmEstHdrSz(&rbCb->m.umDl);
187 if(!kwDlUtlIsReestInProgress(rbCb))
189 kwUtlSndDStaRsp(gCb,rbCb,rbCb->m.umDl.bo,rbCb->m.umDl.estHdrSz,FALSE,0);
192 /* kw005.201 added support for L2 Measurement */
193 #ifdef LTE_L2_MEAS_RLC
194 /* Update numActUe if it is not active */
195 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
196 (rbCb->ueCb->numActRb[rbCb->qci]++ == 0))
198 kwCb.kwL2Cb.numActUe[rbCb->qci]++;
207 * @brief Handler to form PDU(s) and update the BO.
210 * -# This function forms pdu(s) from the SDU(s) in the
211 * SDU queue and returns them.
212 * -# This function also updates the BO along with the
213 * along with the estimated Header size.
215 * @param[in] rbCb RB control block
216 * @param[out] pduInfo Pdu Info to be filled and the PDU size to be
217 * formed and the updated BO
218 * @param[in] pduSz The size for which PDUs have to constructed
221 * -# ROK In case of success
222 * -# RFAILED If allocation of Sdu fails
225 PUBLIC Void kwUmmProcessSdus
232 PUBLIC Void kwUmmProcessSdus(gCb, rbCb, datReq)
238 CmLList *firstNode; /* First Node in SDU queue */
239 U8 fi=0; /* Framing Info */
240 Buffer *pdu; /* Buffer for holding the formed PDU */
241 KwPduInfo *pduInfo; /* PDU Info pointer */
242 S16 pduSz; /* PDU Size to be constructed */
244 /* kw005.201 added support for L2 Measurement */
246 KwContSduLst contSduLst; /*Contained sduLst */
247 S32 dataVol = rbCb->m.umDl.bo;
248 U32* totMacGrant= &(datReq->totMacGrant);
249 KwL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
250 U8 *sduIdx = &dlIpThPut->lastSduIdx;
253 KwlchInfo lchInfo = {0};
261 TRC2(kwUmmProcessSdus)
266 pduInfo = &(datReq->pduInfo);
267 pduSz = datReq->pduSz;
270 contSduLst.numSdus = 0;
271 contSduLst.lcId = rbCb->lch.lChId;
272 oldBo = rbCb->m.umDl.bo;
273 lchInfo.lcId = rbCb->lch.lChId;
277 /* Discard new changes starts */
278 kwUtlGetCurrTime(&curTime);
281 while ((pduSz > 0) && (rbCb->m.umDl.sduQ.count > 0) &&
282 (rbCb->m.umDl.numLi < KW_MAX_DL_LI) && (pduInfo->numPdu < KW_MAX_PDU))
284 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,firstNode);
285 sdu = (KwSdu *)(firstNode->node);
287 if ((sdu->mode.um.isSegmented == FALSE) && (rbCb->discTmrInt > 0) &&
288 (rbCb->rlcId.rbType == CM_LTE_DRB))
290 timeDiff = KW_TIME_DIFF(curTime,sdu->arrTime);
292 if (timeDiff >= rbCb->discTmrInt)
295 KW_UPD_L2_DL_DISC_SDU_STS(gCb, rbCb);
297 rbCb->m.umDl.bo -= sdu->sduSz;
298 KW_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
302 /* When forming a new PDU, pdu == NULLP
303 -# Eliminate MAC header size for each pdu
304 -# Initialize the li array to 0
305 -# Substract the fixed header length based on SN length
312 KW_RMV_MAC_HDR_SZ(pduSz);
314 /* account for the RLC header size */
315 pduSz -= rbCb->m.umDl.snLen;
317 /* kw005.201 fixing pduSz <= 0 problem, ccpu00119417 */
323 rbCb->m.umDl.numLi = 0;
324 if (sdu->mode.um.isSegmented == TRUE)
334 kwUtlCalcLiForSdu(gCb,rbCb->m.umDl.numLi,sdu->sduSz,&pduSz);
336 /* Exact fit scenario :
337 If the SDU size matches with the PDU size
338 -# Allocate memory equal to PDU size;
340 -# Remove SDu from queue
341 -# Append to already existing PDU portion if present .
342 -# Add Header and create complete PDU and place it in
345 if (sdu->sduSz == pduSz)
354 SCatMsg(pdu, sdu->mBuf, M1M2);
357 rbCb->m.umDl.bo -= pduSz;
361 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
363 if(sdu->mode.um.isSegmented)
365 *sduIdx = dlIpThPut->lastSduIdx;
369 KW_GETSDUIDX(*sduIdx);
372 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
373 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
374 sdu->mode.um.sduId, newIdx);
376 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
378 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
379 lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
384 /* kw005.201 added support for L2 Measurement */
385 #ifdef LTE_L2_MEAS_RLC
386 kwUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
387 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_DL_DELAY) ||
388 (rbCb->rbL2Cb.measOn & LKW_L2MEAS_UU_LOSS))
391 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
393 lchInfo.arvlTime[lchInfo.numSdus] = sdu->arrTime;
397 #endif /* LTE_L2_MEAS */
398 KW_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu); /* kw003.201 */
399 kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
401 kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
405 /* Concatenation scenario :
406 If SDU size is less than the requested PDU size
407 -# Allocate memory and copy SDU into it.
409 -# Remove SDU from the Queue.
410 -# Append to already existing PDU portion if present .
411 -# If the SDU size is greater than 2047 or the number of i
412 LIs reaches max, place it as a separate PDU in pduInfo and
415 place the msglen in li array and continue with the next SDU.
416 -# If the number of PDUs is more than KW_MAX_PDU, return from
417 the function even if pduSize > 0.
419 else if (sdu->sduSz < pduSz)
428 SCatMsg(pdu, sdu->mBuf ,M1M2);
430 rbCb->m.umDl.bo -= sdu->sduSz;
433 /* kw005.201 added support for L2 Measurement */
434 #ifdef LTE_L2_MEAS_RLC
435 kwUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
436 #endif /* LTE_L2_MEAS */
437 if (sdu->sduSz < 2048 && rbCb->m.umDl.numLi < KW_MAX_DL_LI)
439 rbCb->m.umDl.li[(rbCb->m.umDl.numLi)++] = sdu->sduSz;
443 kwUmmCreatePdu(gCb, rbCb, pdu, fi, pduInfo);
446 if ( pduInfo->numPdu == KW_MAX_PDU)
448 /* Could not transmit what MAC asked for because the number
449 * of PDUs to be transmitted has reached maximum. */
450 RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
451 "Maximum Pdu limit has been reached UEID:%d CELLID:%d",
458 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) )
460 if(sdu->mode.um.isSegmented)
462 *sduIdx = dlIpThPut->lastSduIdx;
466 KW_GETSDUIDX(*sduIdx);
469 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
470 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
471 sdu->mode.um.sduId, newIdx);
473 if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
475 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
476 lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
481 KW_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu);
482 /* kw005.201 ccpu00117318, updating the statistics */
483 kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
485 /* Segmentation scenario :
486 If size of SDU is greater than PDU size
487 -# Allocate memory and Segment the Sdu.
489 -# Append to already existing PDU if any.
490 -# Set the second bit of the framing info.
491 -# Create the complete PDU and place in pduInfo.
497 SSegMsg(sdu->mBuf,pduSz,&remSdu);
500 if(KW_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb, rbCb))
502 if(sdu->mode.um.isSegmented)
504 *sduIdx = dlIpThPut->lastSduIdx;
508 KW_GETSDUIDX(*sduIdx);
511 kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
512 kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
513 sdu->mode.um.sduId, newIdx);
515 if(KW_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
517 if(sdu->actSz == sdu->sduSz)
529 SCatMsg(pdu, sdu->mBuf, M1M2);
530 KW_FREE_BUF_WC(sdu->mBuf);
534 rbCb->m.umDl.bo -= pduSz;
535 sdu->mode.um.isSegmented = TRUE;
540 /* kw005.201 added support for L2 Measurement */
541 #ifdef LTE_L2_MEAS_RLC
542 kwUtlUpdSduSnMap(rbCb, sdu, datReq, FALSE);
543 #endif /* LTE_L2_MEAS */
545 kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
548 /* kw005.201 added support for L2 Measurement */
550 #ifdef LTE_L2_MEAS_RLC
551 if((rbCb->rbL2Cb.measOn) &&
552 (rbCb->m.umDl.sduQ.count == 0) &&
555 if(--(rbCb->ueCb->numActRb[rbCb->qci]) == 0)
557 kwCb.kwL2Cb.numActUe[rbCb->qci]--;
560 #endif /* LTE_L2_MEAS */
562 kwUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
563 /* Need to check into optimizing this code : TODO */
564 if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && (lchInfo.numSdus != 0))
566 KwL2MeasTb *l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
568 /* Fix Klock warning */
569 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP) &&
570 (l2MeasTb->numLchInfo < KW_MAX_ACTV_DRB))
572 cmMemcpy((U8 *) &l2MeasTb->lchInfo[l2MeasTb->numLchInfo], (U8 *) &lchInfo, sizeof(KwlchInfo));
573 l2MeasTb->numLchInfo++;
575 l2MeasTb->txSegSduCnt += segSduCnt;
577 *totMacGrant -= (oldBo - rbCb->m.umDl.bo);
580 /* If we have a situation wherein the size requested is greater than the total size of SDUs
581 and a pdu buffer which is not null, this if loop helps to send
582 a non null PDU to the lower layer.
584 if (pduSz > 0 && pdu)
586 if (pduInfo->numPdu != KW_MAX_PDU)
588 rbCb->m.umDl.numLi--;
589 kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
598 kwUmmEstHdrSz(&rbCb->m.umDl);
599 datReq->boRep.bo = rbCb->m.umDl.bo;
600 datReq->boRep.estHdrSz = rbCb->m.umDl.estHdrSz;
601 datReq->boRep.staPduPrsnt = FALSE;
602 if (rbCb->m.umDl.sduQ.count > 0)
604 datReq->boRep.oldestSduArrTime =
605 ((KwSdu *)(rbCb->m.umDl.sduQ.first->node))->arrTime;
611 * @brief Handler to process the re-establishment request received from i
615 * This function does the following functions :
616 * Remove all the SDUs in the SDU queue.
618 * @param[in] gCb RLC Instance control block
619 * @param[in] rlcID Identity of the RLC entity for which
620 * re-establishment is to be done
621 * @param[in] sendReEst Whether to send re-establishment complete
622 * indication to upper layer or not
623 * @param[in] rbCb RB control block for which re-establishment
629 PUBLIC Void kwDlUmmReEstablish
637 PUBLIC Void kwDlUmmReEstablish(gCb, rlcId, rbCb)
644 /* The re-establishment indication is sent from the UL only */
645 TRC2(kwDlUmmReEstablish)
648 kwUmmFreeDlRbCb(gCb, rbCb);
650 rbCb->m.umDl.vtUs = 0;
652 /* this would have been set when re-establishment was triggered
654 kwDlUtlResetReestInProgress(rbCb);
659 * @brief Handler to create the header and complete a PDU.
662 * This function is used to create the header of a PDU and concatenate it
663 * with the data part of the PDU.
664 * Also updates the statistics
665 * Sets the passed pdu to NULLP
667 * @param[in] gCb RLC instance control block
668 * @param[in,out] rbCb RB control block
670 * @param[in] fi Framing Info field
671 * @param[out] datReqPduInfo Holder in which to copy the created PDU pointer
676 PRIVATE Void kwUmmCreatePdu
682 KwPduInfo *datReqPduInfo
685 PRIVATE Void kwUmmCreatePdu(gCb, rbCb, pdu, fi, datReqPduInfo)
690 KwPduInfo *datReqPduInfo
693 KwSn sn; /* Sequence Number */
694 U32 liCount; /* LI count */
695 U8 e = 0; /* Extension Bit */
696 U32 count; /* Loop Counter */
699 /* create a big array to store the header, assuming 3 bytes per 2 L1s
700 * (2 bytes if only a single LI) and 2 bytes for the
702 * size of header = ( NumLi /2 ) * 3 + (NumLi % 2) * 2 + 2;
703 * where NumLi = Number of Length Indicators to be sent
705 U8 hdr[((KW_MAX_DL_LI >> 1) * 3) + ((KW_MAX_DL_LI & 0x01) << 1) + 2];
706 U32 idx = 0; /* To index to the hdr array */
708 /* Note: idx is not checked against crossing the hdr array bound as
709 * liCount will be < KW_MAX_DL_LI and as per the size calculated above;
710 * idx cannot cross the array
716 /* stats updated before for bytes sent before adding RLC headers */
717 kwUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
719 sn = rbCb->m.umDl.vtUs;
720 liCount = rbCb->m.umDl.numLi;
722 if(liCount > KW_MAX_DL_LI)
723 liCount = KW_MAX_DL_LI;
725 /* if there are any LI's then set the first E bit */
731 if (rbCb->m.umDl.snLen == 1)
733 hdr[idx++] = (fi << 6) | (e << 5) | sn;
735 else /* SN length is 2 */
737 /* SN length is 10 bits */
738 hdr[idx] = (fi << 3) | (e << 2) | (sn >> 8);
739 hdr[++idx] = sn & 0xff;
744 for (count = 0;count < liCount;count++)
746 /* In each iteration we try and encode 2 LIs */
747 /* if this is the last LI then e should be 0 */
748 if(count == liCount - 1)
753 /* ccpu00135170 Fixing KLOCK warning */
754 if((idx + 1)>= hdrSz)
758 /* odd LI, 1st , 3rd etc */
759 hdr[idx] = (e << 7) | (rbCb->m.umDl.li[count] >> 4);
760 hdr[++idx] = (rbCb->m.umDl.li[count] & 0xf) << 4;
763 if(count == liCount - 1)
767 else if(count >= liCount)
771 /* ccpu00135170 Fixing KLOCK warning */
772 if((idx + 1)>= hdrSz)
776 /* even one, 2nd , 4th etc LI's, count starts at 0 */
777 hdr[idx] |= ((e << 3) | (rbCb->m.umDl.li[count] >> 8));
778 hdr[++idx] = rbCb->m.umDl.li[count] & 0xff;
782 /* if odd number of L1s increment idx */
788 /* increment VT(US) */
789 rbCb->m.umDl.vtUs = (rbCb->m.umDl.vtUs + 1) & rbCb->m.umDl.modBitMask;
791 /* add the header to the beginning of the pdu */
792 SAddPreMsgMultInOrder(hdr, idx, pdu);
794 datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
799 * @brief Handler to estimate the header size of the RLC SDUs
800 * present in the SDU queue.
803 * This function is used to update the estimated header size variable in RB.
804 * This function is called when a SDU is queued and when a PDU is formed and
805 * sent to the lower layer.
807 * @param[in] umDl UM mode downlink control block
812 PRIVATE Void kwUmmEstHdrSz
817 PRIVATE Void kwUmmEstHdrSz(umDl)
821 /* The header size is estimated as :
822 If sdu count = 0 then 0
823 else sdu count * 2 + 1; the 1 is added for the FI and SN byte;
826 umDl->estHdrSz = (umDl->sduQ.count)?((umDl->sduQ.count << 1) + 1) : 0;
832 * @brief Handler to discard a SDU.
835 * This function is used to discard a SDU after receiving
836 * the Discard Request from the upper layer.The SDU is discarded if
837 * it is present and is not mapped to any PDU yet.
838 * The discards coming from the upper layer would be coming in
839 * sequence according to the sduId, so we should find the sduId at the
840 * head of the sduQ. Discards if there is a match else does nothing.
842 * @param[in] rbCb RB control block
843 * @param[in] sduId SDU ID of the SDU to be discarded
848 PUBLIC Void kwUmmDiscSdu
855 PUBLIC Void kwUmmDiscSdu(gCb,rbCb,sduId)
861 CmLList *tmpNode; /* Temporary Node in SDU queue */
866 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
870 KwSdu *sdu = (KwSdu *)tmpNode->node;
872 if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
874 /* kw005.201 added support for L2 Measurement */
875 KW_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
876 gCb->genSts.numSduDisc++;
886 * function to free/release the UnAcknowledged mode RBCB buffers
889 * This primitive Frees the Unacknowldged Mode RbCb sdu queue
891 * @param [in] gCb - RLC instance control block
892 * @param [in] rbCb - RB Control Block
897 PUBLIC Void kwUmmFreeDlRbCb
903 PUBLIC Void kwUmmFreeDlRbCb(gCb,rbCb)
908 TRC2(kwUmmFreeDlRbCb)
911 /* cat the SDU queue to the to be freed list */
912 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.umDl.sduQ));
913 kwUtlRaiseDlCleanupEvent(gCb);
916 } /* kwUmmFreeDlRbCb */
918 /********************************************************************30**
920 **********************************************************************/