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
31 --rlcUmmReAssembleSdus
36 **********************************************************************/
39 * @brief RLC Unacknowledged Mode downlink module
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 */
51 #include "kw.h" /* RLC layer */
57 /* header/extern include files (.x) */
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 */
64 #include "kw.x" /* RLC layer */
68 #define RLC_MODULE (RLC_DBGMASK_UM | RLC_DBGMASK_DL)
70 /* variables for logging :declared in BRDCM cl */
72 uint32_t dldrops_kwu_um;
78 static Void rlcUmmCreatePdu ARGS ((RlcCb *gCb,
82 KwPduInfo *datReqPduInfo));
84 /** @addtogroup ummode */
88 * @brief Handler to queue a SDU in the SDU queue, update BO and report
89 * it to the lower layer.
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
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
104 void rlcUmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReqInfo *datReq, Buffer *mBuf)
106 MsgLen len; /* SDU buffer length */
107 RlcSdu *sdu; /* SDU */
109 RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
111 RLC_ALLOC_WC(gCb, sdu, (Size)sizeof(RlcSdu));
112 #if (ERRCLASS & ERRCLS_ADD_RES)
115 DU_LOG("\nERROR --> RLC DL : Memory allocation failed in rlcUmmQSdu for UEID:%d CELLID:%d",\
118 ODU_PUT_MSG_BUF(mBuf);
121 #endif /* ERRCLASS & ERRCLS_ADD_RES */
123 /* Discard new changes starts */
124 rlcUtlGetCurrTime(&sdu->arrTime);
125 /* Discard new changes ends */
126 ODU_GET_MSG_LEN(mBuf,&len);
131 sdu->mode.um.sduId = datReq->sduId;
132 sdu->mode.um.isSegmented = FALSE;
133 #ifndef RGL_SPECIFIC_CHANGES
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;
147 if(!rlcDlUtlIsReestInProgress(rbCb))
149 rlcUtlSendDedLcBoStatus(gCb, rbCb, rbCb->m.umDl.bo, 0, FALSE,0);
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))
158 rlcCb.rlcL2Cb.numActUe[rbCb->qci]++;
167 * @brief Handler to form PDU(s) and update the BO.
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.
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
181 * -# ROK In case of success
182 * -# RFAILED If allocation of Sdu fails
184 void rlcUmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *datReq)
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 */
196 /* kw005.201 added support for L2 Measurement */
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;
205 RlclchInfo lchInfo = {0};
206 uint32_t segSduCnt = 0;
209 int16_t timeDiff = 0;
213 pduInfo = &(datReq->pduInfo);
214 pduSz = datReq->pduSz;
217 contSduLst.numSdus = 0;
218 contSduLst.lcId = rbCb->lch.lChId;
219 oldBo = rbCb->m.umDl.bo;
220 lchInfo.lcId = rbCb->lch.lChId;
224 /* Discard new changes starts */
225 rlcUtlGetCurrTime(&curTime);
228 while ((pduSz > 0) && (rbCb->m.umDl.sduQ.count > 0) && (pduInfo->numPdu < RLC_MAX_PDU))
230 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,firstNode);
231 sdu = (RlcSdu *)(firstNode->node);
233 if ((sdu->mode.um.isSegmented == FALSE) && (rbCb->discTmrInt > 0) &&
234 (rbCb->rlcId.rbType == CM_LTE_DRB))
236 timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime);
238 if (timeDiff >= rbCb->discTmrInt)
241 RLC_UPD_L2_DL_DISC_SDU_STS(gCb, rbCb);
243 rbCb->m.umDl.bo -= sdu->sduSz;
244 RLC_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
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
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)
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);
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;
268 /*Estimate MAC Hdr based on calculated rlcPduSz */
269 macHdrSz = (rlcPduSz > 255 ) ? RLC_MAC_HDR_SZ3 : RLC_MAC_HDR_SZ2;
271 if(macHdrSz != RLC_MAC_HDR_SZ2)
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;
279 if(sdu->mode.um.isSegmented == FALSE)
281 /* RLC SDU is estimated to be segmented first time */
282 if(rlcSduSz < sdu->sduSz)
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;
293 pduSz -= (rlcHdrSz + macHdrSz);
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.
304 -# Remove SDU from the Queue.
306 if (sdu->sduSz <= pduSz)
313 rbCb->m.umDl.bo -= sdu->sduSz;
314 rbCb->m.umDl.bo -= RLC_MAX_HDRSZ;
318 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
320 if(sdu->mode.um.isSegmented)
322 *sduIdx = dlIpThPut->lastSduIdx;
326 RLC_GETSDUIDX(*sduIdx);
329 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
330 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
331 sdu->mode.um.sduId, newIdx);
333 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
335 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
336 lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
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))
348 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
350 lchInfo.arvlTime[lchInfo.numSdus] = sdu->arrTime;
354 #endif /* LTE_L2_MEAS */
356 if(sdu->mode.um.isSegmented)
358 umHdr.si = RLC_SI_LAST_SEG;
359 umHdr.so = sdu->actSz - sdu->sduSz;
360 sdu->mode.um.isSegmented = FALSE;
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);
372 /* Segmentation scenario :
373 If size of SDU is greater than PDU size
374 -# Allocate memory and Segment the Sdu.
376 -# Add segment to the PDU
377 -# Set the second bit of the segmentation info.
378 -# Create the complete PDU and place in pduInfo.
384 ODU_SEGMENT_MSG(sdu->mBuf,pduSz,&remSdu);
387 if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb, rbCb))
389 if(sdu->mode.um.isSegmented)
391 *sduIdx = dlIpThPut->lastSduIdx;
395 RLC_GETSDUIDX(*sduIdx);
398 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
399 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
400 sdu->mode.um.sduId, newIdx);
402 if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
404 if(sdu->actSz == sdu->sduSz)
410 if(sdu->mode.um.isSegmented)
412 umHdr.si = RLC_SI_MID_SEG;
413 umHdr.so = sdu->actSz - sdu->sduSz;
417 umHdr.si = RLC_SI_FIRST_SEG;
419 sdu->mode.um.isSegmented = TRUE;
423 rbCb->m.umDl.bo -= pduSz;
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 */
432 rlcUmmCreatePdu(gCb, rbCb, pdu, &umHdr, pduInfo);
435 /* kw005.201 added support for L2 Measurement */
437 #ifdef LTE_L2_MEAS_RLC
438 if((rbCb->rbL2Cb.measOn) &&
439 (rbCb->m.umDl.sduQ.count == 0) &&
442 if(--(rbCb->ueCb->numActRb[rbCb->qci]) == 0)
444 rlcCb.rlcL2Cb.numActUe[rbCb->qci]--;
447 #endif /* 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))
453 RlcL2MeasTb *l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
455 /* Fix Klock warning */
456 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP) &&
457 (l2MeasTb->numLchInfo < RLC_MAX_ACTV_DRB))
459 memcpy( &l2MeasTb->lchInfo[l2MeasTb->numLchInfo], &lchInfo, sizeof(RlclchInfo));
460 l2MeasTb->numLchInfo++;
462 l2MeasTb->txSegSduCnt += segSduCnt;
464 *totMacGrant -= (oldBo - rbCb->m.umDl.bo);
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)
472 datReq->boRep.oldestSduArrTime =
473 ((RlcSdu *)(rbCb->m.umDl.sduQ.first->node))->arrTime;
479 * @brief Handler to process the re-establishment request received from i
483 * This function does the following functions :
484 * Remove all the SDUs in the SDU queue.
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
496 Void rlcDlUmmReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcDlRbCb *rbCb)
498 /* The re-establishment indication is sent from the UL only */
500 rlcUmmFreeDlRbCb(gCb, rbCb);
502 rbCb->m.umDl.txNext = 0;
504 /* this would have been set when re-establishment was triggered
506 rlcDlUtlResetReestInProgress(rbCb);
511 * @brief Handler to create the header and complete a PDU.
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
519 * @param[in] gCb RLC instance control block
520 * @param[in,out] rbCb RB control block
522 * @param[in] umHdr UM mode header
523 * @param[out] datReqPduInfo Holder in which to copy the created PDU pointer
527 static void rlcUmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr, KwPduInfo *datReqPduInfo)
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 */
533 /* stats updated before for bytes sent before adding RLC headers */
534 rlcUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
536 /* If SI = 0, 1 byte header conatining SI/R */
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)
547 hdr[idx++] = (umHdr->si << 6) | sn;
551 hdr[idx++] = (umHdr->si << 6) | (sn >> 8);
552 hdr[idx++] = sn & 0xff ;
555 /* Add SO for middle and last segments*/
556 if((umHdr->si == RLC_SI_MID_SEG) | (umHdr->si == RLC_SI_LAST_SEG))
558 hdr[idx++] = (umHdr->so >> 8);
559 hdr[idx++] = umHdr->so & 0xff;
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;
568 /* add the header to the beginning of the pdu */
569 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx, pdu);
571 datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
576 * @brief Handler to discard a SDU.
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.
586 * @param[in] rbCb RB control block
587 * @param[in] sduId SDU ID of the SDU to be discarded
591 Void rlcUmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId)
593 CmLList *tmpNode; /* Temporary Node in SDU queue */
594 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
598 RlcSdu *sdu = (RlcSdu *)tmpNode->node;
600 if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
602 /* kw005.201 added support for L2 Measurement */
603 RLC_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
604 gCb->genSts.numSduDisc++;
614 * function to free/release the UnAcknowledged mode RBCB buffers
617 * This primitive Frees the Unacknowldged Mode RbCb sdu queue
619 * @param [in] gCb - RLC instance control block
620 * @param [in] rbCb - RB Control Block
624 Void rlcUmmFreeDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb)
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);
632 } /* rlcUmmFreeDlRbCb */
634 /********************************************************************30**
636 **********************************************************************/