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=240;
43 * @brief RLC Unacknowledged Mode uplink module
46 /* header (.h) include files */
47 #include "envopt.h" /* environment options */
48 #include "envdep.h" /* environment dependent */
49 #include "envind.h" /* environment independent */
51 #include "gen.h" /* general */
52 #include "ssi.h" /* system services interface */
53 #include "cm5.h" /* Timer Functions */
54 #include "cm_lte.h" /* common umts header file */
55 #include "cm_hash.h" /* common hash module file */
56 #include "cm_llist.h" /* common list header file */
57 #include "ckw.h" /* RRC layer */
58 #include "lkw.h" /* RRC layer */
59 #include "kwu.h" /* RLC service user */
60 #include "lkw.h" /* LM Interface */
61 #include "rgu.h" /* MAC layer */
62 #include "kw_env.h" /* RLC environment options */
64 #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 */
86 #define KW_MODULE (KW_DBGMASK_UM | KW_DBGMASK_UL)
88 PRIVATE S16 kwUmmExtractHdr ARGS ((KwCb *gCb,
93 PRIVATE Void kwUmmReAssembleSdus ARGS ((KwCb *gCb,
95 KwUmRecBuf *umRecBuf));
99 extern U32 isMemThreshReached(Region region);
103 * @brief Finds and sets the next VR(UR) depending on the
104 * passed sequence number
107 * Finds the next VR(UR) depending on the passed SN. Updates VR(UR) to
108 * the SN of the first UMD PDU with SN >= _nextSn that has not been received
110 * @param[in] umUl pointer to Um mode uplink control block
111 * @param[in] nextSn Sequence number after which the VR(UR) is to set to
115 PRIVATE Void kwUmmFindNextVRUR (KwUmUl* umUl, KwSn nextSn)
117 KwSn ur = KW_UM_GET_VALUE(umUl->vrUr, *umUl);
119 KwSn nextSnToCompare = KW_UM_GET_VALUE(nextSn,*umUl);
121 while (ur < nextSnToCompare)
123 if (!(umUl->recBuf[nextSn])) /* if the buffer is empty, SN not received */
128 nextSn = (nextSn + 1) & umUl->modBitMask;
129 nextSnToCompare = KW_UM_GET_VALUE(nextSn,*umUl);
134 * @brief Checks whether a sequence number is within the
135 * re-ordering window or not
137 * @param[in] sn Sequence Number to be checked
138 * @param[in] umUl pointer to Um mode uplink control block
146 PRIVATE S16 kwUmmCheckSnInReordWindow (KwSn sn,
147 CONSTANT KwUmUl* CONSTANT umUl)
149 return (KW_UM_GET_VALUE(sn, *umUl) < KW_UM_GET_VALUE(umUl->vrUh, *umUl));
153 * @brief Handler to process the Data Indication from the lower layer
154 * and send the PDUs to re-assembly unit.
157 * This function processes the PDUs received from the lower layer
158 * re-orders them and sends them one after the other in sequence
159 * to the re-assembly unit.
161 * @param[in] gCb RLC Instance control block
162 * @param[in] rbCb RB control block
163 * @param[in] pduInfo Pdu information
167 /* kw005.201 added support for L2 Measurement */
171 PUBLIC Void kwUmmProcessPdus
174 KwUlRbCb *rbCb, /* Rb Control Block */
175 KwPduInfo *pduInfo, /* Pdu data and related information */
176 U32 ttiCnt /* ttiCnt received from MAC */
179 PUBLIC Void kwUmmProcessPdus(rbCb,pduInfo,ttiCnt)
181 KwUlRbCb *rbCb; /* Rb Control Block */
182 KwPduInfo *pduInfo; /* Pdu data and related information */
183 U32 ttiCnt; /* ttiCnt received from MAC */
187 PUBLIC Void kwUmmProcessPdus
190 KwUlRbCb *rbCb, /* Rb Control Block */
191 KwPduInfo *pduInfo /* Pdu data and related information */
194 PUBLIC Void kwUmmProcessPdus(rbCb,pduInfo)
196 KwUlRbCb *rbCb; /* Rb Control Block */
197 KwPduInfo *pduInfo; /* Pdu data and related information */
201 KwSn *vrUh; /* vr(uh) */
202 KwSn *vrUr; /* vr(ur) */
203 KwSn *vrUx; /* vr(ux) */
204 U16 curSn; /* Current Sequence Number */
205 U32 pduCount; /* PDU count */
206 U32 count; /* Loop counter */
207 KwUmRecBuf **recBuf; /* UM Reception Buffer */
209 Bool tmrRunning; /* Boolean for checking Tmr */
210 /* kw005.201 added support for L2 Measurement */
212 TRC2(kwUmmProcessPdus)
217 /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */
218 pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU;
220 vrUh = &(rbCb->m.umUl.vrUh);
221 vrUr = &(rbCb->m.umUl.vrUr);
222 vrUx = &(rbCb->m.umUl.vrUx);
223 recBuf = (rbCb->m.umUl.recBuf);
225 while (count < pduCount)
230 Buffer *pdu = pduInfo->mBuf[count];
231 KwUmRecBuf *tmpRecBuf;
232 gCb->genSts.pdusRecv++;
233 #ifndef RGL_SPECIFIC_CHANGES
236 extern U32 ulrate_rgu;
238 SFndLenMsg(pdu, &len);
243 /* create a buffer to be later inserted into the reception buffer */
244 KW_ALLOC_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
245 #if (ERRCLASS & ERRCLS_ADD_RES)
246 if (tmpRecBuf == NULLP)
248 RLOG_ARG2(L_FATAL, DBG_RBID,rbCb->rlcId.rbId,
249 "Memory allocation failed UEID:%d CELLID:%d",
256 #endif /* ERRCLASS & ERRCLS_ADD_RES */
257 /* ccpu00142274 - UL memory based flow control*/
258 #ifndef RGL_SPECIFIC_CHANGES
261 /* Changed the condition to TRUE from ROK */
262 #ifndef XEON_SPECIFIC_CHANGES
263 if(isMemThreshReached(kwCb[0]->init.region) == TRUE)
265 extern U32 rlculdrop;
268 KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
269 /*Fix for CR ccpu00144030: If threshhold is hit then also count
270 *should be incrmented */
278 /* get the pdu header */
279 if (kwUmmExtractHdr(gCb, rbCb, pdu, &(tmpRecBuf->umHdr)))
281 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
282 "Header Extraction Failed UEID:%d CELLID:%d",
286 /* Header extraction is a problem.
287 * log an error and free the allocated memory */
289 KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
292 /* kw005.201 ccpu00117318, updating the statistics */
293 gCb->genSts.errorPdusRecv++;
296 curSn = tmpRecBuf->umHdr.sn;
298 /* Check if the PDU should be discarded or not */
299 ur = KW_UM_GET_VALUE(KW_UMUL.vrUr, KW_UMUL);
300 uh = KW_UM_GET_VALUE(KW_UMUL.vrUh, KW_UMUL);
301 seqNum = KW_UM_GET_VALUE(curSn, KW_UMUL);
303 if (((ur < seqNum) && (seqNum < uh) && (KW_UMUL.recBuf[curSn])) ||
306 /* PDU needs to be discarded */
307 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
308 "Received a duplicate pdu with sn %d UEID:%d CELLID:%d",
314 KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
316 /* kw005.201 ccpu00117318, updating the statistics */
317 gCb->genSts.unexpPdusRecv++;
321 /* kw005.201 added support for L2 Measurement */
324 /* kw006.201 ccpu00120058, reduced code complexity by adding new function */
325 kwUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt);
329 recBuf[curSn] = tmpRecBuf;
331 recBuf[curSn]->pdu = pdu;
332 SFndLenMsg(pdu,&(recBuf[curSn]->pduSz));
333 /* kw005.201 ccpu00117318, updating the statistics */
334 gCb->genSts.bytesRecv += recBuf[curSn]->pduSz;
336 if (!kwUmmCheckSnInReordWindow(curSn,&KW_UMUL))
337 { /* currSn is outside re-ordering window */
338 *vrUh = (curSn + 1) & KW_UMUL.modBitMask;
340 /* re-assemble all pdus outside the modified re-ordering window */
341 /* the first SN is VR(UR) */
342 if (!kwUmmCheckSnInReordWindow(*vrUr,&KW_UMUL))
344 /* TODO : should it be VR(UR) + 1 ?... check, earlier it was so */
345 KwSn sn = *vrUr; /* SN's which need to be re-assembled */
346 KwSn lowerEdge; /* to hold the lower-edge of the
347 re-ordering window */
349 /* The new value ov VR(UR) is the lower end of the window i
350 * and SN's still this value need to be re-assembled */
352 *vrUr = (*vrUh - KW_UMUL.umWinSz) & KW_UMUL.modBitMask;
353 lowerEdge = KW_UM_GET_VALUE(*vrUr ,KW_UMUL);
355 while (KW_UM_GET_VALUE(sn, KW_UMUL) < lowerEdge)
359 kwUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
360 KW_FREE_WC(gCb,recBuf[sn],sizeof(KwUmRecBuf));
363 sn = (sn + 1) & KW_UMUL.modBitMask;
370 KwSn tSn = KW_UM_GET_VALUE(sn,KW_UMUL);
373 /* set VR(UR) to next SN > current VR(UR) which is not received */
374 KwSn nextVrUr = (*vrUr + 1) & KW_UMUL.modBitMask;
375 kwUmmFindNextVRUR(&KW_UMUL, nextVrUr);
377 /* re-assemble SDUs with SN < Vr(UR) */
378 tVrUr = KW_UM_GET_VALUE(*vrUr,KW_UMUL);
379 while (recBuf[sn] && tSn < tVrUr)
381 kwUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
382 KW_FREE_WC(gCb,recBuf[sn],sizeof(KwUmRecBuf));
384 sn = (sn + 1) & KW_UMUL.modBitMask;
385 tSn = KW_UM_GET_VALUE(sn, KW_UMUL);
389 tmrRunning = kwChkTmr(gCb,(PTR)rbCb, KW_EVT_UMUL_REORD_TMR);
393 KwSn tVrUx = KW_UM_GET_VALUE(*vrUx, KW_UMUL);
394 KwSn tVrUr = KW_UM_GET_VALUE(*vrUr ,KW_UMUL);
396 KwSn tVrUh = KW_UM_GET_VALUE(*vrUh, KW_UMUL);
398 S16 ret = kwUmmCheckSnInReordWindow(*vrUx, &KW_UMUL);
400 if ( (tVrUx <= tVrUr) || ((!ret) && (tVrUx != tVrUh)))
402 kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
409 if (KW_UM_GET_VALUE(*vrUh, KW_UMUL) > KW_UM_GET_VALUE(*vrUr, KW_UMUL))
411 kwStartTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
416 }/* end while count < pduCount */
418 kwUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
419 #endif /* LTE_L2_MEAS */
424 * @brief Handler to reassemble the SDUs and send them to the upper layer.
427 * This function processes the received in-sequence PDU and
428 * re-assembles the SDUs and sends them to the upper layer.
430 * @param[in] gCb RLC Instance control block
431 * @param[in] rbCb RB control block
432 * @param[in] umRecBuf Reception Buffer to be Re-Assembled
437 PRIVATE Void kwUmmReAssembleSdus
444 PRIVATE Void kwUmmReAssembleSdus(gCb,rbCb,umRecBuf)
447 KwUmRecBuf *umRecBuf;
450 U32 liCount; /* LI count */
451 U32 count; /* Loop counter */
452 U8 fi; /* Framing Info */
453 U16 sn; /* Sequence Number of current PDU */
454 MsgLen len; /* PDU Length */
455 Buffer *sdu; /* SDU to be sent to upper layer */
456 Buffer *remPdu; /* Remaining PDU */
457 Buffer **partialSdu; /* Partial SDU */
459 TRC2(kwUmmReAssembleSdus)
462 liCount = umRecBuf->umHdr.numLi;
463 fi = umRecBuf->umHdr.fi;
464 sn = umRecBuf->umHdr.sn;
466 for (count = 0; (count <= liCount);count++)
468 if (count < liCount )
469 len = umRecBuf->umHdr.li[count];
472 if (!(umRecBuf->pdu))
476 SFndLenMsg(umRecBuf->pdu,&len);
479 /* get the sdu out of the pdu */
480 SSegMsg(umRecBuf->pdu,len,&remPdu);
482 umRecBuf->pdu = remPdu;
484 partialSdu = &(rbCb->m.umUl.partialSdu);
485 /* While re-assembling the SDUs, consider the first LI and perform
486 * the following steps.
487 -# If the first bit of FI(Framing Info of 2 bits) is set =>
488 -# The current Data field in the PDU is a segment.
489 So form a SDU only if the
490 rbCb->m.um.umUl.partialSdu exists and the SNs are
492 -# If there are no LIs and the second bit of LI is 1
493 then a partial SDU is formed which would not be sent
496 -# If rbCb->partialSdu is not NULL then flush it off.
497 -# If LI count > 0 or LI count is 0 and second bit
499 The SDU is complete.So send it to upper layer.
501 The SDU is partial and is placed
502 in rbCb->m.um.umUl.partialSdu;
510 (sn == ((rbCb->m.umUl.sn + 1) & rbCb->m.umUl.modBitMask)))
512 SCatMsg(*partialSdu,sdu,M1M2);
514 if (liCount > 0 || !(fi & 1))
516 kwUtlSndDatInd(gCb,rbCb,*partialSdu);
522 /* Partial Sdu stored is not valid now.So free it */
525 KW_FREE_BUF(*partialSdu);
537 KW_FREE_BUF(*partialSdu); /* RLC mem leak fix */
541 if (liCount > 0 || !( fi & 1))
543 kwUtlSndDatInd(gCb,rbCb,sdu);
552 If the SDU pointer has the last Data field of the PDU
553 -# If FI is 1,place the SDU in rbCb->m.um.umDl.partialSdu
554 -# else send the SDU to upper layer.
556 else if (count == liCount)
564 kwUtlSndDatInd(gCb, rbCb, sdu);
568 If the LI is something other than the first one,
569 just send the SDU to the upper layer */
572 kwUtlSndDatInd(gCb, rbCb, sdu);
575 rbCb->m.umUl.sn = sn;
581 * @brief Handler to process the re-establishment request received
582 * from the upper layer.
585 * This function does the following functions :
586 * - If direction of the RB is downlink :
587 * Remove all the SDUs in the SDU queue.
588 * - If direction of the RB is uplink :
589 * Call kwUmmReAssembleSdus() for each PDU with SN < VR(UH)
591 * @param[in] gCb RLC Instance control block
592 * @param[in] rlcID Identity of the RLC entity for which
593 * re-establishment is to be done
594 * @param[in] rbCb RB control block for which re-establishment
600 PUBLIC Void kwUmmUlReEstablish
607 PUBLIC Void kwUmmUlReEstablish(gCb, rlcId, rbCb)
615 KwUmRecBuf **recBuf; /* UM Reception Buffer */
616 KwKwuSapCb *kwKwSap; /* KWU SAP Information */
618 TRC2(kwUmmUlReEstablish)
621 curSn = rbCb->m.umUl.vrUr;
622 vrUh = KW_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl);
623 recBuf = rbCb->m.umUl.recBuf;
625 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR))
627 kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
630 while (KW_UM_GET_VALUE(curSn,rbCb->m.umUl) < vrUh)
632 if ( recBuf[curSn] != NULLP )
634 kwUmmReAssembleSdus(gCb,rbCb,recBuf[curSn]);
635 KW_FREE_WC(gCb,recBuf[curSn],sizeof(KwUmRecBuf));
636 recBuf[curSn] = NULLP;
638 curSn = (curSn + 1) & rbCb->m.umUl.modBitMask;
640 rbCb->m.umUl.vrUr = 0;
641 rbCb->m.umUl.vrUh = 0;
642 rbCb->m.umUl.vrUx = 0;
644 kwKwSap = gCb->u.ulCb->kwuUlSap + KW_UI_PDCP;
646 /* In the UM Mode always send reestablish-indication to Upper Latyer*/
647 KwUiKwuReEstCmpInd(&kwKwSap->pst, kwKwSap->suId, *rlcId);
653 * @brief Handler to extract the header from a PDU
656 * This function is used to extract the header of a PDU and store it
657 * along with the PDU buffer.The sequence number,framing info
658 * and LIs are extracted by this function.
660 * @param[in] gCb RLC Instance control block
661 * @param[in] rbCb Rb Control block for which the pdu is received
662 * @param[in] pdu PDU buffer
663 * @param[out] umHdr UM header to be filled after extraction
670 PRIVATE S16 kwUmmExtractHdr
678 PRIVATE S16 kwUmmExtractHdr(gCb, rbCb, pdu, umHdr)
685 U8 e; /* Extension Bit */
686 Data dst[2]; /* Destination Buffer */
687 S32 totalSz; /* Sum of LIs */
688 MsgLen pduSz; /* PDU size */
689 #if (ERRCLASS & ERRCLS_DEBUG)
690 S16 ret; /* Return Value */
693 TRC3(kwUmmExtractHdr)
696 SFndLenMsg(pdu,&pduSz);
698 if ( rbCb->m.umUl.snLen == 1)
700 #if (ERRCLASS & ERRCLS_DEBUG)
701 ret = SRemPreMsg(dst,pdu);
704 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
705 "SRemPreMsg Failed for 5 bit SN UEID:%d CELLID:%d",
715 umHdr->sn = (dst[0]) & 0x1F;
716 umHdr->fi = (dst[0]) >> 6;
717 e = (dst[0]>>5) & 0x01;
721 /* snLen - sequnce length will be 10 bits requiring 2 bytes */
722 #if (ERRCLASS & ERRCLS_DEBUG)
723 ret = SRemPreMsgMult(dst,2,pdu);
726 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
727 "SRemPreMsgMult Failed for 10 bits SN UEID:%d CELLID:%d",
733 SRemPreMsgMult(dst,2,pdu);
737 /* kw005.201 R9 Upgrade 3gpp spec 36.322 ver9.3.0 CR0082 *
738 * Removed the "if" condition for checking the reserved field *
739 * Added mask 0x03 for extracting the FI field. */
741 umHdr->fi = ( (dst[0] ) >> 3) & 0x03;
742 e = ( (dst[0] ) >> 2) & 0x01;
743 umHdr->sn = ( dst[0] & 0x03) << 8;
750 while(e && umHdr->numLi < KW_MAX_UL_LI )
752 #if (ERRCLASS & ERRCLS_DEBUG)
753 ret = SRemPreMsgMult(dst,2,pdu);
756 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
757 "SRemPreMsgMult Failed UEID:%d CELLID:%d",
763 SRemPreMsgMult(dst,2,pdu);
765 umHdr->li[umHdr->numLi] = ((dst[0]) & 0x7F) << 4;
766 umHdr->li[umHdr->numLi] |= dst[1] >> 4;
767 if ( 0 == umHdr->li[umHdr->numLi] )
769 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
770 "Received LI as 0 UEID:%d CELLID:%d",
775 totalSz += umHdr->li[umHdr->numLi];
776 if ( pduSz <= totalSz )
778 RLOG_ARG3(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
779 "SN [%d]: UEID:%d CELLID:%d",
783 RLOG_ARG4(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
784 "Corrupted PDU as TotSz[%lu] PduSz[%lu] UEID:%d CELLID:%d ",
789 RETVALUE(RFAILED); /* the situation where in the PDU size
790 is something that does not match with
796 e = ((dst[0]) & 0x80) >> 7;
798 if ( e && umHdr->numLi < KW_MAX_UL_LI)
800 U8 tmp = ((dst[1]) & 0x08) >> 3;
801 umHdr->li[umHdr->numLi] = ( dst[1] & 0x07) << 8;
804 #if (ERRCLASS & ERRCLS_DEBUG)
805 ret = SRemPreMsg(dst,pdu);
808 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
809 "SRemPreMsg Failed UEID:%d CELLID:%d",
817 umHdr->li[umHdr->numLi] |= ( dst[0] ); /* The first byte lies in
818 the first 8 bits.We want
819 them in the last 8 bits */
820 if ( 0 == umHdr->li[umHdr->numLi] )
822 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
823 "Received LI as 0 UEID:%d CELLID:%d",
828 totalSz += umHdr->li[umHdr->numLi];
834 RETVALUE(RFAILED); /* the situation where in the PDU size is
835 something that does not match with the
841 } /* while(e && umHdr->numLi < KW_MAX_LI ) */
844 /* PDU was constructed with LIs that exceeded KW_MAX_LI */
851 * @brief Handles expiry of re-ordering timer
853 * @param[in] gCb RLC Instance control block
854 * @param[in] rbCb Rb Control block for which re-order timer expired
859 PUBLIC Void kwUmmReOrdTmrExp
865 PUBLIC Void kwUmmReOrdTmrExp(gCb, rbCb)
870 KwSn prevVrUr; /* prevVrUr */
872 TRC3(kwUmmReOrdTmrExp)
875 prevVrUr = KW_UMUL.vrUr;
877 /* set VR(UR) to SN >= VR(UX) that has not been received */
878 kwUmmFindNextVRUR(&KW_UMUL, KW_UMUL.vrUx);
880 while (KW_UM_GET_VALUE(prevVrUr,KW_UMUL) <
881 KW_UM_GET_VALUE(KW_UMUL.vrUr,KW_UMUL))
883 if (KW_UMUL.recBuf[prevVrUr])
885 kwUmmReAssembleSdus(gCb, rbCb, KW_UMUL.recBuf[prevVrUr]);
886 if(KW_UMUL.recBuf[prevVrUr]->pdu != NULLP) /* RLC mem leak fix */
888 KW_FREE_BUF(KW_UMUL.recBuf[prevVrUr]->pdu);
890 KW_FREE_WC(gCb, KW_UMUL.recBuf[prevVrUr], sizeof(KwUmRecBuf));
891 KW_UMUL.recBuf[prevVrUr] = NULLP;
894 prevVrUr = (prevVrUr + 1) & rbCb->m.umUl.modBitMask;
897 if (KW_UM_GET_VALUE(KW_UMUL.vrUh, KW_UMUL) >
898 KW_UM_GET_VALUE(KW_UMUL.vrUr, KW_UMUL))
900 kwStartTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
901 KW_UMUL.vrUx = KW_UMUL.vrUh;
907 * Function to release/free the UnAcknowledged Mode Module RbCb buffers
910 * This primitive Frees the UM RbCb transmission Buffer, retransmission
911 * Buffer and reciption Buffers
913 * @param [in] gCb - RLC instance Control Block
914 * @param [in] rbCb - RB Control Block
920 PUBLIC Void kwUmmFreeUlRbCb
926 PUBLIC Void kwUmmFreeUlRbCb(gCb,rbCb)
931 KwSn curSn = 0; /* sequence number of PDU */
932 KwSn windSz; /* PDU window size */
933 KwUmRecBuf **umRecBuf; /* UM module receive buffer */
935 TRC2(kwUmmFreeUlRbCb)
938 windSz = rbCb->m.umUl.umWinSz << 1;
940 umRecBuf = rbCb->m.umUl.recBuf;
942 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR))
944 kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
946 while (curSn < windSz)
948 if (umRecBuf[curSn] != NULLP)
950 KW_FREE_BUF_WC(umRecBuf[curSn]->pdu);
951 umRecBuf[curSn]->pdu = NULLP;
953 KW_FREE_WC(gCb, umRecBuf[curSn], sizeof(KwUmRecBuf));
954 umRecBuf[curSn] = NULLP;
958 KW_FREE_WC(gCb,rbCb->m.umUl.recBuf, (windSz ) * sizeof(KwUmRecBuf*));
959 rbCb->m.umUl.recBuf = NULLP;
964 /********************************************************************30**
966 **********************************************************************/