X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=src%2F5gnrrlc%2Fkw_umm_ul.c;fp=src%2F5gnrrlc%2Fkw_umm_ul.c;h=449e1861d4ef21142df16ebf8179c792015dbc66;hb=5625a52ad68f6ad93684e68bbbdbaef0d462cf9a;hp=0000000000000000000000000000000000000000;hpb=59f84608ec15c016958a6e0e0ddd813f376c0925;p=o-du%2Fl2.git diff --git a/src/5gnrrlc/kw_umm_ul.c b/src/5gnrrlc/kw_umm_ul.c new file mode 100755 index 000000000..449e1861d --- /dev/null +++ b/src/5gnrrlc/kw_umm_ul.c @@ -0,0 +1,966 @@ +/******************************************************************************* +################################################################################ +# Copyright (c) [2017-2019] [Radisys] # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +################################################################################ +*******************************************************************************/ + +/********************************************************************** + + Name: LTE-RLC Layer + + Type: C file + + Desc: Source code for RLC Unacknowledged mode assembly and + reassembly.This file contains following functions + + --kwUmmQSdu + --kwUmmProcessSdus + --kwUmmProcessPdus + --kwUmmReAssembleSdus + --kwUmmReEstablish + + File: kw_umm_ul.c + +**********************************************************************/ +static const char* RLOG_MODULE_NAME="RLC"; +static int RLOG_MODULE_ID=2048; +static int RLOG_FILE_ID=240; + +/** + * @file kw_umm_ul.c + * @brief RLC Unacknowledged Mode uplink module +*/ + +/* header (.h) include files */ +#include "envopt.h" /* environment options */ +#include "envdep.h" /* environment dependent */ +#include "envind.h" /* environment independent */ + +#include "gen.h" /* general */ +#include "ssi.h" /* system services interface */ +#include "cm5.h" /* Timer Functions */ +#include "cm_lte.h" /* common umts header file */ +#include "cm_hash.h" /* common hash module file */ +#include "cm_llist.h" /* common list header file */ +#include "ckw.h" /* RRC layer */ +#include "lkw.h" /* RRC layer */ +#include "kwu.h" /* RLC service user */ +#include "lkw.h" /* LM Interface */ +#include "rgu.h" /* MAC layer */ +#include "kw_env.h" /* RLC environment options */ + +#include "kw.h" /* RLC layer */ +#include "kw_err.h" +#include "kw_ul.h" + + +/* header/extern include files (.x) */ + +#include "gen.x" /* general */ +#include "ssi.x" /* system services interface */ +#include "cm_lib.x" /* common library */ +#include "cm5.x" /* Timer Functions */ +#include "cm_hash.x" /* common hash module */ +#include "cm_lte.x" /* common umts file */ +#include "cm_llist.x" /* common list header file */ +#include "ckw.x" /* RRC layer */ +#include "kwu.x" /* RLC service user */ +#include "lkw.x" /* LM Interface */ +#include "rgu.x" /* MAC later */ + +#include "kw.x" /* RLC layer */ +#include "kw_ul.x" + +#define KW_MODULE (KW_DBGMASK_UM | KW_DBGMASK_UL) + +PRIVATE S16 kwUmmExtractHdr ARGS ((KwCb *gCb, + KwUlRbCb *rbCb, + Buffer *pdu, + KwUmHdr *umHdr)); + +PRIVATE Void kwUmmReAssembleSdus ARGS ((KwCb *gCb, + KwUlRbCb *rbCb, + KwUmRecBuf *umRecBuf)); + +#ifndef TENB_ACC +#ifndef LTE_PAL_ENB +extern U32 isMemThreshReached(Region region); +#endif +#endif +/** + * @brief Finds and sets the next VR(UR) depending on the + * passed sequence number + * + * @details + * Finds the next VR(UR) depending on the passed SN. Updates VR(UR) to + * the SN of the first UMD PDU with SN >= _nextSn that has not been received + * + * @param[in] umUl pointer to Um mode uplink control block + * @param[in] nextSn Sequence number after which the VR(UR) is to set to + * + * @return Void +*/ +PRIVATE Void kwUmmFindNextVRUR (KwUmUl* umUl, KwSn nextSn) +{ + KwSn ur = KW_UM_GET_VALUE(umUl->vrUr, *umUl); + + KwSn nextSnToCompare = KW_UM_GET_VALUE(nextSn,*umUl); + + while (ur < nextSnToCompare) + { + if (!(umUl->recBuf[nextSn])) /* if the buffer is empty, SN not received */ + { + umUl->vrUr = nextSn; + break; + } + nextSn = (nextSn + 1) & umUl->modBitMask; + nextSnToCompare = KW_UM_GET_VALUE(nextSn,*umUl); + } +} + +/** + * @brief Checks whether a sequence number is within the + * re-ordering window or not + * + * @param[in] sn Sequence Number to be checked + * @param[in] umUl pointer to Um mode uplink control block + * + * @return S16 + * -# TRUE + * -# FALSE + * + * @return Void +*/ +PRIVATE S16 kwUmmCheckSnInReordWindow (KwSn sn, + CONSTANT KwUmUl* CONSTANT umUl) +{ + return (KW_UM_GET_VALUE(sn, *umUl) < KW_UM_GET_VALUE(umUl->vrUh, *umUl)); +} + +/** + * @brief Handler to process the Data Indication from the lower layer + * and send the PDUs to re-assembly unit. + * + * @details + * This function processes the PDUs received from the lower layer + * re-orders them and sends them one after the other in sequence + * to the re-assembly unit. + * + * @param[in] gCb RLC Instance control block + * @param[in] rbCb RB control block + * @param[in] pduInfo Pdu information + * + * @return Void +*/ +/* kw005.201 added support for L2 Measurement */ +#ifdef LTE_L2_MEAS + +#ifdef ANSI +PUBLIC Void kwUmmProcessPdus +( +KwCb *gCb, +KwUlRbCb *rbCb, /* Rb Control Block */ +KwPduInfo *pduInfo, /* Pdu data and related information */ +U32 ttiCnt /* ttiCnt received from MAC */ +) +#else +PUBLIC Void kwUmmProcessPdus(rbCb,pduInfo,ttiCnt) +KwCb *gCb; +KwUlRbCb *rbCb; /* Rb Control Block */ +KwPduInfo *pduInfo; /* Pdu data and related information */ +U32 ttiCnt; /* ttiCnt received from MAC */ +#endif +#else +#ifdef ANSI +PUBLIC Void kwUmmProcessPdus +( +KwCb *gCb, +KwUlRbCb *rbCb, /* Rb Control Block */ +KwPduInfo *pduInfo /* Pdu data and related information */ +) +#else +PUBLIC Void kwUmmProcessPdus(rbCb,pduInfo) +KwCb *gCb; +KwUlRbCb *rbCb; /* Rb Control Block */ +KwPduInfo *pduInfo; /* Pdu data and related information */ +#endif +#endif +{ + KwSn *vrUh; /* vr(uh) */ + KwSn *vrUr; /* vr(ur) */ + KwSn *vrUx; /* vr(ux) */ + U16 curSn; /* Current Sequence Number */ + U32 pduCount; /* PDU count */ + U32 count; /* Loop counter */ + KwUmRecBuf **recBuf; /* UM Reception Buffer */ + + Bool tmrRunning; /* Boolean for checking Tmr */ +/* kw005.201 added support for L2 Measurement */ + + TRC2(kwUmmProcessPdus) + + + count = 0; + + /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */ + pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU; + + vrUh = &(rbCb->m.umUl.vrUh); + vrUr = &(rbCb->m.umUl.vrUr); + vrUx = &(rbCb->m.umUl.vrUx); + recBuf = (rbCb->m.umUl.recBuf); + + while (count < pduCount) + { + KwSn ur; + KwSn uh; + KwSn seqNum; + Buffer *pdu = pduInfo->mBuf[count]; + KwUmRecBuf *tmpRecBuf; + gCb->genSts.pdusRecv++; +#ifndef RGL_SPECIFIC_CHANGES +#ifndef TENB_ACC +#ifndef LTE_PAL_ENB + extern U32 ulrate_rgu; + MsgLen len; + SFndLenMsg(pdu, &len); + ulrate_rgu += len; +#endif +#endif +#endif + /* create a buffer to be later inserted into the reception buffer */ + KW_ALLOC_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf)); +#if (ERRCLASS & ERRCLS_ADD_RES) + if (tmpRecBuf == NULLP) + { + RLOG_ARG2(L_FATAL, DBG_RBID,rbCb->rlcId.rbId, + "Memory allocation failed UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + SPutMsg(pdu); + + RETVOID; + } +#endif /* ERRCLASS & ERRCLS_ADD_RES */ + /* ccpu00142274 - UL memory based flow control*/ +#ifndef RGL_SPECIFIC_CHANGES +#ifndef TENB_ACC +#ifndef LTE_PAL_ENB + /* Changed the condition to TRUE from ROK */ +#ifndef XEON_SPECIFIC_CHANGES + if(isMemThreshReached(kwCb[0]->init.region) == TRUE) + { + extern U32 rlculdrop; + rlculdrop++; + KW_FREE_BUF(pdu); + KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf)); + /*Fix for CR ccpu00144030: If threshhold is hit then also count + *should be incrmented */ + count++; + continue; + } +#endif +#endif +#endif +#endif + /* get the pdu header */ + if (kwUmmExtractHdr(gCb, rbCb, pdu, &(tmpRecBuf->umHdr))) + { + RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "Header Extraction Failed UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + + /* Header extraction is a problem. + * log an error and free the allocated memory */ + /* ccpu00136940 */ + KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf)); + SPutMsg(pdu); + count++; + /* kw005.201 ccpu00117318, updating the statistics */ + gCb->genSts.errorPdusRecv++; + continue; + } + curSn = tmpRecBuf->umHdr.sn; + + /* Check if the PDU should be discarded or not */ + ur = KW_UM_GET_VALUE(KW_UMUL.vrUr, KW_UMUL); + uh = KW_UM_GET_VALUE(KW_UMUL.vrUh, KW_UMUL); + seqNum = KW_UM_GET_VALUE(curSn, KW_UMUL); + + if (((ur < seqNum) && (seqNum < uh) && (KW_UMUL.recBuf[curSn])) || + (seqNum < ur)) + { + /* PDU needs to be discarded */ + RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, + "Received a duplicate pdu with sn %d UEID:%d CELLID:%d", + curSn, + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + + KW_FREE_BUF(pdu); + KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf)); + count++; + /* kw005.201 ccpu00117318, updating the statistics */ + gCb->genSts.unexpPdusRecv++; + continue; + } + + /* kw005.201 added support for L2 Measurement */ +#ifdef LTE_L2_MEAS + + /* kw006.201 ccpu00120058, reduced code complexity by adding new function */ + kwUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt); + +#endif + + recBuf[curSn] = tmpRecBuf; + + recBuf[curSn]->pdu = pdu; + SFndLenMsg(pdu,&(recBuf[curSn]->pduSz)); + /* kw005.201 ccpu00117318, updating the statistics */ + gCb->genSts.bytesRecv += recBuf[curSn]->pduSz; + + if (!kwUmmCheckSnInReordWindow(curSn,&KW_UMUL)) + { /* currSn is outside re-ordering window */ + *vrUh = (curSn + 1) & KW_UMUL.modBitMask; + + /* re-assemble all pdus outside the modified re-ordering window */ + /* the first SN is VR(UR) */ + if (!kwUmmCheckSnInReordWindow(*vrUr,&KW_UMUL)) + { + /* TODO : should it be VR(UR) + 1 ?... check, earlier it was so */ + KwSn sn = *vrUr; /* SN's which need to be re-assembled */ + KwSn lowerEdge; /* to hold the lower-edge of the + re-ordering window */ + + /* The new value ov VR(UR) is the lower end of the window i + * and SN's still this value need to be re-assembled */ + + *vrUr = (*vrUh - KW_UMUL.umWinSz) & KW_UMUL.modBitMask; + lowerEdge = KW_UM_GET_VALUE(*vrUr ,KW_UMUL); + + while (KW_UM_GET_VALUE(sn, KW_UMUL) < lowerEdge) + { + if (recBuf[sn]) + { + kwUmmReAssembleSdus(gCb,rbCb,recBuf[sn]); + KW_FREE_WC(gCb,recBuf[sn],sizeof(KwUmRecBuf)); + recBuf[sn] = NULLP; + } + sn = (sn + 1) & KW_UMUL.modBitMask; + } + } + } + if (recBuf[*vrUr]) + { + KwSn sn = *vrUr; + KwSn tSn = KW_UM_GET_VALUE(sn,KW_UMUL); + KwSn tVrUr; + + /* set VR(UR) to next SN > current VR(UR) which is not received */ + KwSn nextVrUr = (*vrUr + 1) & KW_UMUL.modBitMask; + kwUmmFindNextVRUR(&KW_UMUL, nextVrUr); + + /* re-assemble SDUs with SN < Vr(UR) */ + tVrUr = KW_UM_GET_VALUE(*vrUr,KW_UMUL); + while (recBuf[sn] && tSn < tVrUr) + { + kwUmmReAssembleSdus(gCb,rbCb,recBuf[sn]); + KW_FREE_WC(gCb,recBuf[sn],sizeof(KwUmRecBuf)); + recBuf[sn] = NULLP; + sn = (sn + 1) & KW_UMUL.modBitMask; + tSn = KW_UM_GET_VALUE(sn, KW_UMUL); + } + } + + tmrRunning = kwChkTmr(gCb,(PTR)rbCb, KW_EVT_UMUL_REORD_TMR); + + if (tmrRunning) + { + KwSn tVrUx = KW_UM_GET_VALUE(*vrUx, KW_UMUL); + KwSn tVrUr = KW_UM_GET_VALUE(*vrUr ,KW_UMUL); + + KwSn tVrUh = KW_UM_GET_VALUE(*vrUh, KW_UMUL); + + S16 ret = kwUmmCheckSnInReordWindow(*vrUx, &KW_UMUL); + + if ( (tVrUx <= tVrUr) || ((!ret) && (tVrUx != tVrUh))) + { + kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR); + tmrRunning = FALSE; + } + } + + if (!tmrRunning) + { + if (KW_UM_GET_VALUE(*vrUh, KW_UMUL) > KW_UM_GET_VALUE(*vrUr, KW_UMUL)) + { + kwStartTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR); + *vrUx = *vrUh; + } + } + count++; + }/* end while count < pduCount */ +#ifdef LTE_L2_MEAS + kwUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt); +#endif /* LTE_L2_MEAS */ + RETVOID; +} + +/** + * @brief Handler to reassemble the SDUs and send them to the upper layer. + * + * @details + * This function processes the received in-sequence PDU and + * re-assembles the SDUs and sends them to the upper layer. + * + * @param[in] gCb RLC Instance control block + * @param[in] rbCb RB control block + * @param[in] umRecBuf Reception Buffer to be Re-Assembled + * + * @return Void +*/ +#ifdef ANSI +PRIVATE Void kwUmmReAssembleSdus +( +KwCb *gCb, +KwUlRbCb *rbCb, +KwUmRecBuf *umRecBuf +) +#else +PRIVATE Void kwUmmReAssembleSdus(gCb,rbCb,umRecBuf) +KwCb *gCb; +KwUlRbCb *rbCb; +KwUmRecBuf *umRecBuf; +#endif +{ + U32 liCount; /* LI count */ + U32 count; /* Loop counter */ + U8 fi; /* Framing Info */ + U16 sn; /* Sequence Number of current PDU */ + MsgLen len; /* PDU Length */ + Buffer *sdu; /* SDU to be sent to upper layer */ + Buffer *remPdu; /* Remaining PDU */ + Buffer **partialSdu; /* Partial SDU */ + + TRC2(kwUmmReAssembleSdus) + + + liCount = umRecBuf->umHdr.numLi; + fi = umRecBuf->umHdr.fi; + sn = umRecBuf->umHdr.sn; + + for (count = 0; (count <= liCount);count++) + { + if (count < liCount ) + len = umRecBuf->umHdr.li[count]; + else + { + if (!(umRecBuf->pdu)) + { + RETVOID; + } + SFndLenMsg(umRecBuf->pdu,&len); + } + + /* get the sdu out of the pdu */ + SSegMsg(umRecBuf->pdu,len,&remPdu); + sdu = umRecBuf->pdu; + umRecBuf->pdu = remPdu; + + partialSdu = &(rbCb->m.umUl.partialSdu); + /* While re-assembling the SDUs, consider the first LI and perform + * the following steps. + -# If the first bit of FI(Framing Info of 2 bits) is set => + -# The current Data field in the PDU is a segment. + So form a SDU only if the + rbCb->m.um.umUl.partialSdu exists and the SNs are + in-sequence. + -# If there are no LIs and the second bit of LI is 1 + then a partial SDU is formed which would not be sent + to the upper layer. + -# else + -# If rbCb->partialSdu is not NULL then flush it off. + -# If LI count > 0 or LI count is 0 and second bit + of FI is not 1 + The SDU is complete.So send it to upper layer. + -# else + The SDU is partial and is placed + in rbCb->m.um.umUl.partialSdu; + */ + + if (0 == count ) + { + if (fi & 2) + { + if ((*partialSdu) && + (sn == ((rbCb->m.umUl.sn + 1) & rbCb->m.umUl.modBitMask))) + { + SCatMsg(*partialSdu,sdu,M1M2); + KW_FREE_BUF(sdu); + if (liCount > 0 || !(fi & 1)) + { + kwUtlSndDatInd(gCb,rbCb,*partialSdu); + *partialSdu = NULLP; + } + } + else + { + /* Partial Sdu stored is not valid now.So free it */ + if (*partialSdu) + { + KW_FREE_BUF(*partialSdu); + *partialSdu = NULLP; + } + + KW_FREE_BUF(sdu); + sdu = NULLP; + } + } + else + { + if (*partialSdu) + { + KW_FREE_BUF(*partialSdu); /* RLC mem leak fix */ + *partialSdu = NULLP; + } + + if (liCount > 0 || !( fi & 1)) + { + kwUtlSndDatInd(gCb,rbCb,sdu); + } + else + { + *partialSdu = sdu; + } + } + } + /* + If the SDU pointer has the last Data field of the PDU + -# If FI is 1,place the SDU in rbCb->m.um.umDl.partialSdu + -# else send the SDU to upper layer. + */ + else if (count == liCount) + { + if (fi & 1) + { + *partialSdu = sdu; + } + else + { + kwUtlSndDatInd(gCb, rbCb, sdu); + } + } + /* + If the LI is something other than the first one, + just send the SDU to the upper layer */ + else + { + kwUtlSndDatInd(gCb, rbCb, sdu); + } + } + rbCb->m.umUl.sn = sn; + + RETVOID; +} + +/** + * @brief Handler to process the re-establishment request received + * from the upper layer. + * + * @details + * This function does the following functions : + * - If direction of the RB is downlink : + * Remove all the SDUs in the SDU queue. + * - If direction of the RB is uplink : + * Call kwUmmReAssembleSdus() for each PDU with SN < VR(UH) + * + * @param[in] gCb RLC Instance control block + * @param[in] rlcID Identity of the RLC entity for which + * re-establishment is to be done + * @param[in] rbCb RB control block for which re-establishment + * is to be done + * + * @return Void +*/ +#ifdef ANSI +PUBLIC Void kwUmmUlReEstablish +( +KwCb *gCb, +CmLteRlcId *rlcId, +KwUlRbCb *rbCb +) +#else +PUBLIC Void kwUmmUlReEstablish(gCb, rlcId, rbCb) +KwCb *gCb; +CmLteRlcId *rlcId; +KwUlRbCb *rbCb; +#endif +{ + KwSn curSn; + KwSn vrUh; + KwUmRecBuf **recBuf; /* UM Reception Buffer */ + KwKwuSapCb *kwKwSap; /* KWU SAP Information */ + + TRC2(kwUmmUlReEstablish) + + + curSn = rbCb->m.umUl.vrUr; + vrUh = KW_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl); + recBuf = rbCb->m.umUl.recBuf; + + if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR)) + { + kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR); + } + + while (KW_UM_GET_VALUE(curSn,rbCb->m.umUl) < vrUh) + { + if ( recBuf[curSn] != NULLP ) + { + kwUmmReAssembleSdus(gCb,rbCb,recBuf[curSn]); + KW_FREE_WC(gCb,recBuf[curSn],sizeof(KwUmRecBuf)); + recBuf[curSn] = NULLP; + } + curSn = (curSn + 1) & rbCb->m.umUl.modBitMask; + } + rbCb->m.umUl.vrUr = 0; + rbCb->m.umUl.vrUh = 0; + rbCb->m.umUl.vrUx = 0; + + kwKwSap = gCb->u.ulCb->kwuUlSap + KW_UI_PDCP; + + /* In the UM Mode always send reestablish-indication to Upper Latyer*/ + KwUiKwuReEstCmpInd(&kwKwSap->pst, kwKwSap->suId, *rlcId); + + RETVOID; +} + +/** + * @brief Handler to extract the header from a PDU + * + * @details + * This function is used to extract the header of a PDU and store it + * along with the PDU buffer.The sequence number,framing info + * and LIs are extracted by this function. + * + * @param[in] gCb RLC Instance control block + * @param[in] rbCb Rb Control block for which the pdu is received + * @param[in] pdu PDU buffer + * @param[out] umHdr UM header to be filled after extraction + * + * @return S16 + * -# TRUE + * -# FALSE +*/ +#ifdef ANSI +PRIVATE S16 kwUmmExtractHdr +( +KwCb *gCb, +KwUlRbCb *rbCb, +Buffer *pdu, +KwUmHdr *umHdr +) +#else +PRIVATE S16 kwUmmExtractHdr(gCb, rbCb, pdu, umHdr) +KwCb *gCb; +KwUlRbCb *rbCb; +Buffer *pdu; +KwUmHdr *umHdr; +#endif +{ + U8 e; /* Extension Bit */ + Data dst[2]; /* Destination Buffer */ + S32 totalSz; /* Sum of LIs */ + MsgLen pduSz; /* PDU size */ +#if (ERRCLASS & ERRCLS_DEBUG) + S16 ret; /* Return Value */ +#endif + + TRC3(kwUmmExtractHdr) + + + SFndLenMsg(pdu,&pduSz); + + if ( rbCb->m.umUl.snLen == 1) + { +#if (ERRCLASS & ERRCLS_DEBUG) + ret = SRemPreMsg(dst,pdu); + if (ret != ROK) + { + RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "SRemPreMsg Failed for 5 bit SN UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + + RETVALUE(RFAILED); + } +#else + SRemPreMsg(dst,pdu); +#endif + pduSz--; + umHdr->sn = (dst[0]) & 0x1F; + umHdr->fi = (dst[0]) >> 6; + e = (dst[0]>>5) & 0x01; + } + else + { + /* snLen - sequnce length will be 10 bits requiring 2 bytes */ +#if (ERRCLASS & ERRCLS_DEBUG) + ret = SRemPreMsgMult(dst,2,pdu); + if (ret != ROK) + { + RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "SRemPreMsgMult Failed for 10 bits SN UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + RETVALUE(RFAILED); + } +#else + SRemPreMsgMult(dst,2,pdu); +#endif + pduSz -= 2; + + /* kw005.201 R9 Upgrade 3gpp spec 36.322 ver9.3.0 CR0082 * + * Removed the "if" condition for checking the reserved field * + * Added mask 0x03 for extracting the FI field. */ + + umHdr->fi = ( (dst[0] ) >> 3) & 0x03; + e = ( (dst[0] ) >> 2) & 0x01; + umHdr->sn = ( dst[0] & 0x03) << 8; + umHdr->sn |= dst[1]; + } + + umHdr->numLi = 0; + + totalSz = 0; + while(e && umHdr->numLi < KW_MAX_UL_LI ) + { +#if (ERRCLASS & ERRCLS_DEBUG) + ret = SRemPreMsgMult(dst,2,pdu); + if (ret != ROK) + { + RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "SRemPreMsgMult Failed UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + RETVALUE(RFAILED); + } +#else + SRemPreMsgMult(dst,2,pdu); +#endif + umHdr->li[umHdr->numLi] = ((dst[0]) & 0x7F) << 4; + umHdr->li[umHdr->numLi] |= dst[1] >> 4; + if ( 0 == umHdr->li[umHdr->numLi] ) + { + RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "Received LI as 0 UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + RETVALUE(RFAILED); + } + totalSz += umHdr->li[umHdr->numLi]; + if ( pduSz <= totalSz ) + { + RLOG_ARG3(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "SN [%d]: UEID:%d CELLID:%d", + umHdr->sn, + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + RLOG_ARG4(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "Corrupted PDU as TotSz[%lu] PduSz[%lu] UEID:%d CELLID:%d ", + totalSz, + pduSz, + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + RETVALUE(RFAILED); /* the situation where in the PDU size + is something that does not match with + the size in LIs*/ + } + umHdr->numLi++; + pduSz -= 2; + + e = ((dst[0]) & 0x80) >> 7; + + if ( e && umHdr->numLi < KW_MAX_UL_LI) + { + U8 tmp = ((dst[1]) & 0x08) >> 3; + umHdr->li[umHdr->numLi] = ( dst[1] & 0x07) << 8; + + +#if (ERRCLASS & ERRCLS_DEBUG) + ret = SRemPreMsg(dst,pdu); + if (ret != ROK) + { + RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "SRemPreMsg Failed UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + RETVALUE(RFAILED); + } +#else + SRemPreMsg(dst,pdu); +#endif + umHdr->li[umHdr->numLi] |= ( dst[0] ); /* The first byte lies in + the first 8 bits.We want + them in the last 8 bits */ + if ( 0 == umHdr->li[umHdr->numLi] ) + { + RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId, + "Received LI as 0 UEID:%d CELLID:%d", + rbCb->rlcId.ueId, + rbCb->rlcId.cellId); + RETVALUE(RFAILED); + } + totalSz += umHdr->li[umHdr->numLi]; + pduSz--; + umHdr->numLi++; + + if (pduSz < totalSz) + { + RETVALUE(RFAILED); /* the situation where in the PDU size is + something that does not match with the + size in LIs*/ + } + + e = tmp; + } + } /* while(e && umHdr->numLi < KW_MAX_LI ) */ + if (e) + { + /* PDU was constructed with LIs that exceeded KW_MAX_LI */ + RETVALUE(RFAILED); + } + RETVALUE(ROK); +} + +/** + * @brief Handles expiry of re-ordering timer + * + * @param[in] gCb RLC Instance control block + * @param[in] rbCb Rb Control block for which re-order timer expired + * + * @return Void +*/ +#ifdef ANSI +PUBLIC Void kwUmmReOrdTmrExp +( +KwCb *gCb, +KwUlRbCb *rbCb +) +#else +PUBLIC Void kwUmmReOrdTmrExp(gCb, rbCb) +KwCb *gCb; +KwUlRbCb *rbCb; +#endif +{ + KwSn prevVrUr; /* prevVrUr */ + + TRC3(kwUmmReOrdTmrExp) + + + prevVrUr = KW_UMUL.vrUr; + + /* set VR(UR) to SN >= VR(UX) that has not been received */ + kwUmmFindNextVRUR(&KW_UMUL, KW_UMUL.vrUx); + + while (KW_UM_GET_VALUE(prevVrUr,KW_UMUL) < + KW_UM_GET_VALUE(KW_UMUL.vrUr,KW_UMUL)) + { + if (KW_UMUL.recBuf[prevVrUr]) + { + kwUmmReAssembleSdus(gCb, rbCb, KW_UMUL.recBuf[prevVrUr]); + if(KW_UMUL.recBuf[prevVrUr]->pdu != NULLP) /* RLC mem leak fix */ + { + KW_FREE_BUF(KW_UMUL.recBuf[prevVrUr]->pdu); + } + KW_FREE_WC(gCb, KW_UMUL.recBuf[prevVrUr], sizeof(KwUmRecBuf)); + KW_UMUL.recBuf[prevVrUr] = NULLP; + } + + prevVrUr = (prevVrUr + 1) & rbCb->m.umUl.modBitMask; + } + + if (KW_UM_GET_VALUE(KW_UMUL.vrUh, KW_UMUL) > + KW_UM_GET_VALUE(KW_UMUL.vrUr, KW_UMUL)) + { + kwStartTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR); + KW_UMUL.vrUx = KW_UMUL.vrUh; + } +} + +/** + * @brief + * Function to release/free the UnAcknowledged Mode Module RbCb buffers + * + * @details + * This primitive Frees the UM RbCb transmission Buffer, retransmission + * Buffer and reciption Buffers + * + * @param [in] gCb - RLC instance Control Block + * @param [in] rbCb - RB Control Block + * + * @return void + */ + +#ifdef ANSI +PUBLIC Void kwUmmFreeUlRbCb +( +KwCb *gCb, +KwUlRbCb *rbCb +) +#else +PUBLIC Void kwUmmFreeUlRbCb(gCb,rbCb) +KwCb *gCb; +KwUlRbCb *rbCb; +#endif +{ + KwSn curSn = 0; /* sequence number of PDU */ + KwSn windSz; /* PDU window size */ + KwUmRecBuf **umRecBuf; /* UM module receive buffer */ + + TRC2(kwUmmFreeUlRbCb) + + + windSz = rbCb->m.umUl.umWinSz << 1; + + umRecBuf = rbCb->m.umUl.recBuf; + + if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR)) + { + kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR); + } + while (curSn < windSz) + { + if (umRecBuf[curSn] != NULLP) + { + KW_FREE_BUF_WC(umRecBuf[curSn]->pdu); + umRecBuf[curSn]->pdu = NULLP; + + KW_FREE_WC(gCb, umRecBuf[curSn], sizeof(KwUmRecBuf)); + umRecBuf[curSn] = NULLP; + } + curSn++; + } + KW_FREE_WC(gCb,rbCb->m.umUl.recBuf, (windSz ) * sizeof(KwUmRecBuf*)); + rbCb->m.umUl.recBuf = NULLP; + RETVOID; +} + + +/********************************************************************30** + End of file +**********************************************************************/