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 "rlc_env.h" /* RLC environment options */
55 /* header/extern include files (.x) */
57 #include "ckw.x" /* RRC layer */
58 #include "kwu.x" /* RLC service user */
59 #include "lkw.x" /* LM Interface */
60 #include "rgu.x" /* MAC later */
62 #include "rlc_utils.h" /* RLC layer */
63 #include "rlc_dl_ul_inf.h"
66 #define RLC_MODULE (RLC_DBGMASK_UM | RLC_DBGMASK_DL)
68 /* variables for logging :declared in BRDCM cl */
70 uint32_t dldrops_kwu_um;
76 static Void rlcUmmCreatePdu ARGS ((RlcCb *gCb,
80 KwPduInfo *datReqPduInfo));
82 /** @addtogroup ummode */
86 * @brief Handler to queue a SDU in the SDU queue, update BO and report
87 * it to the lower layer.
90 * This function is used to queue the received SDU in the
91 * SDU queue maintained in the radio bearer control block.
92 * After queuing the SDU, BO is updated and is reported
95 * @param[in] gCb RLC Instance control block
96 * @param[in] rbCb RB control block
97 * @param[in] datReq Ptr to the datReq sent from PDCP
98 * @param[in] mBuf Sdu data
102 void rlcUmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReqInfo *datReq, Buffer *mBuf)
104 MsgLen len; /* SDU buffer length */
105 RlcSdu *sdu; /* SDU */
107 RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
109 RLC_ALLOC_WC(gCb, sdu, (Size)sizeof(RlcSdu));
110 #if (ERRCLASS & ERRCLS_ADD_RES)
113 DU_LOG("\nERROR --> RLC DL : Memory allocation failed in rlcUmmQSdu for UEID:%d CELLID:%d",\
116 ODU_PUT_MSG_BUF(mBuf);
119 #endif /* ERRCLASS & ERRCLS_ADD_RES */
121 /* Discard new changes starts */
122 rlcUtlGetCurrTime(&sdu->arrTime);
123 /* Discard new changes ends */
124 ODU_GET_MSG_LEN(mBuf,&len);
129 sdu->mode.um.sduId = datReq->sduId;
130 sdu->mode.um.isSegmented = FALSE;
131 #ifndef RGL_SPECIFIC_CHANGES
140 rbCb->m.umDl.bo += len;
141 rbCb->m.umDl.bo += RLC_MAX_HDRSZ;
142 cmLListAdd2Tail(&(rbCb->m.umDl.sduQ), &sdu->lstEnt);
143 sdu->lstEnt.node = (PTR)sdu;
145 if(!rlcDlUtlIsReestInProgress(rbCb))
147 rlcUtlSendDedLcBoStatus(gCb, rbCb, rbCb->m.umDl.bo, 0, FALSE,0);
150 /* kw005.201 added support for L2 Measurement */
151 #ifdef LTE_L2_MEAS_RLC
152 /* Update numActUe if it is not active */
153 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
154 (rbCb->ueCb->numActRb[rbCb->qci]++ == 0))
156 rlcCb.rlcL2Cb.numActUe[rbCb->qci]++;
165 * @brief Handler to form PDU(s) and update the BO.
168 * -# This function forms pdu(s) from the SDU(s) in the
169 * SDU queue and returns them.
170 * -# This function also updates the BO along with the
171 * along with the estimated Header size.
173 * @param[in] rbCb RB control block
174 * @param[out] pduInfo Pdu Info to be filled and the PDU size to be
175 * formed and the updated BO
176 * @param[in] pduSz The size for which PDUs have to constructed
179 * -# ROK In case of success
180 * -# RFAILED If allocation of Sdu fails
182 void rlcUmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *datReq)
184 CmLList *firstNode; /* First Node in SDU queue */
185 Buffer *pdu; /* Buffer for holding the formed PDU */
186 KwPduInfo *pduInfo; /* PDU Info pointer */
187 int16_t pduSz; /* PDU Size to be constructed */
188 RlcUmHdr umHdr; /* Header */
194 /* kw005.201 added support for L2 Measurement */
196 RlcContSduLst contSduLst; /*Contained sduLst */
197 int32_t dataVol = rbCb->m.umDl.bo;
198 uint32_t* totMacGrant= &(datReq->totMacGrant);
199 RlcL2MeasDlIpTh *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
200 uint8_t *sduIdx = &dlIpThPut->lastSduIdx;
203 RlclchInfo lchInfo = {0};
204 uint32_t segSduCnt = 0;
207 int16_t timeDiff = 0;
211 pduInfo = &(datReq->pduInfo);
212 pduSz = datReq->pduSz;
215 contSduLst.numSdus = 0;
216 contSduLst.lcId = rbCb->lch.lChId;
217 oldBo = rbCb->m.umDl.bo;
218 lchInfo.lcId = rbCb->lch.lChId;
222 /* Discard new changes starts */
223 rlcUtlGetCurrTime(&curTime);
226 while ((pduSz > 0) && (rbCb->m.umDl.sduQ.count > 0) && (pduInfo->numPdu < RLC_MAX_PDU))
228 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,firstNode);
229 sdu = (RlcSdu *)(firstNode->node);
231 if ((sdu->mode.um.isSegmented == FALSE) && (rbCb->discTmrInt > 0) &&
232 (rbCb->rlcId.rbType == CM_LTE_DRB))
234 timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime);
236 if (timeDiff >= rbCb->discTmrInt)
239 RLC_UPD_L2_DL_DISC_SDU_STS(gCb, rbCb);
241 rbCb->m.umDl.bo -= sdu->sduSz;
242 RLC_REMOVE_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
249 /* When forming a new PDU, pdu == NULLP
250 -# Eliminate MAC header size for each pdu
251 -# Substract the fixed header length based on SN length
253 /* account for the RLC header size
254 minimum header size will be 1 , if Sdu is not segmented */
255 rlcHdrSz = RLC_MIN_HDRSZ;
256 if(sdu->mode.um.isSegmented)
258 /* value of rbCb->m.umDl.snLen will be 1 for 6 bit SN and 2 for 12 bit SN and 2 bytes of SO */
259 rlcHdrSz = (rbCb->m.umDl.snLen + 2);
261 macHdrSz = RLC_MAC_HDR_SZ2; /*Minimum MacHdr size */
262 rlcSduSz = sdu->sduSz;
263 rlcPduSz = ((rlcSduSz + rlcHdrSz) < (pduSz - macHdrSz))? (rlcSduSz + rlcHdrSz) : (pduSz - macHdrSz);
264 rlcSduSz = rlcPduSz - rlcHdrSz;
266 /*Estimate MAC Hdr based on calculated rlcPduSz */
267 macHdrSz = (rlcPduSz > 255 ) ? RLC_MAC_HDR_SZ3 : RLC_MAC_HDR_SZ2;
269 if(macHdrSz != RLC_MAC_HDR_SZ2)
271 rlcSduSz = sdu->sduSz;
272 rlcPduSz = ((rlcSduSz + rlcHdrSz) < (pduSz - macHdrSz))? (rlcSduSz + rlcHdrSz) : (pduSz - macHdrSz);
273 rlcSduSz = rlcPduSz - rlcHdrSz;
274 macHdrSz = (rlcPduSz > 255 ) ? RLC_MAC_HDR_SZ3 : RLC_MAC_HDR_SZ2;
277 if(sdu->mode.um.isSegmented == FALSE)
279 /* RLC SDU is estimated to be segmented first time */
280 if(rlcSduSz < sdu->sduSz)
282 rlcHdrSz = rbCb->m.umDl.snLen;
283 rlcSduSz = sdu->sduSz;
284 rlcPduSz = ((rlcSduSz + rlcHdrSz) < (pduSz - macHdrSz))? (rlcSduSz + rlcHdrSz) : (pduSz - macHdrSz);
285 rlcSduSz = rlcPduSz - rlcHdrSz;
286 /*Estimate MAC Hdr based on calculated rlcPduSz */
287 macHdrSz = (rlcPduSz > 255 ) ? RLC_MAC_HDR_SZ3 : RLC_MAC_HDR_SZ2;
291 pduSz -= (rlcHdrSz + macHdrSz);
298 /* No Segmentation scenario :
299 If SDU size is less than or equal to the requested PDU size
300 -# Allocate memory and copy SDU into it.
302 -# Remove SDU from the Queue.
304 if (sdu->sduSz <= pduSz)
311 rbCb->m.umDl.bo -= sdu->sduSz;
312 rbCb->m.umDl.bo -= RLC_MAX_HDRSZ;
316 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
318 if(sdu->mode.um.isSegmented)
320 *sduIdx = dlIpThPut->lastSduIdx;
324 RLC_GETSDUIDX(*sduIdx);
327 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
328 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
329 sdu->mode.um.sduId, newIdx);
331 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
333 lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime;
334 lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
339 /* kw005.201 added support for L2 Measurement */
340 #ifdef LTE_L2_MEAS_RLC
341 rlcUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
342 if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_DL_DELAY) ||
343 (rbCb->rbL2Cb.measOn & LKW_L2MEAS_UU_LOSS))
346 if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
348 lchInfo.arvlTime[lchInfo.numSdus] = sdu->arrTime;
352 #endif /* LTE_L2_MEAS */
354 if(sdu->mode.um.isSegmented)
356 umHdr.si = RLC_SI_LAST_SEG;
357 umHdr.so = sdu->actSz - sdu->sduSz;
358 sdu->mode.um.isSegmented = FALSE;
365 rlcUmmCreatePdu(gCb, rbCb, pdu, &umHdr, pduInfo);
366 RLC_REMOVE_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu); /* kw003.201 */
367 rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
370 /* Segmentation scenario :
371 If size of SDU is greater than PDU size
372 -# Allocate memory and Segment the Sdu.
374 -# Add segment to the PDU
375 -# Set the second bit of the segmentation info.
376 -# Create the complete PDU and place in pduInfo.
382 ODU_SEGMENT_MSG(sdu->mBuf,pduSz,&remSdu);
385 if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb, rbCb))
387 if(sdu->mode.um.isSegmented)
389 *sduIdx = dlIpThPut->lastSduIdx;
393 RLC_GETSDUIDX(*sduIdx);
396 rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
397 rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz,
398 sdu->mode.um.sduId, newIdx);
400 if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
402 if(sdu->actSz == sdu->sduSz)
408 if(sdu->mode.um.isSegmented)
410 umHdr.si = RLC_SI_MID_SEG;
411 umHdr.so = sdu->actSz - sdu->sduSz;
415 umHdr.si = RLC_SI_FIRST_SEG;
417 sdu->mode.um.isSegmented = TRUE;
421 rbCb->m.umDl.bo -= pduSz;
425 /* kw005.201 added support for L2 Measurement */
426 #ifdef LTE_L2_MEAS_RLC
427 rlcUtlUpdSduSnMap(rbCb, sdu, datReq, FALSE);
428 #endif /* LTE_L2_MEAS */
430 rlcUmmCreatePdu(gCb, rbCb, pdu, &umHdr, pduInfo);
433 /* kw005.201 added support for L2 Measurement */
435 #ifdef LTE_L2_MEAS_RLC
436 if((rbCb->rbL2Cb.measOn) &&
437 (rbCb->m.umDl.sduQ.count == 0) &&
440 if(--(rbCb->ueCb->numActRb[rbCb->qci]) == 0)
442 rlcCb.rlcL2Cb.numActUe[rbCb->qci]--;
445 #endif /* LTE_L2_MEAS */
447 rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
448 /* Need to check into optimizing this code : TODO */
449 if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && (lchInfo.numSdus != 0))
451 RlcL2MeasTb *l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
453 /* Fix Klock warning */
454 if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP) &&
455 (l2MeasTb->numLchInfo < RLC_MAX_ACTV_DRB))
457 memcpy( &l2MeasTb->lchInfo[l2MeasTb->numLchInfo], &lchInfo, sizeof(RlclchInfo));
458 l2MeasTb->numLchInfo++;
460 l2MeasTb->txSegSduCnt += segSduCnt;
462 *totMacGrant -= (oldBo - rbCb->m.umDl.bo);
465 datReq->boRep.bo = rbCb->m.umDl.bo;
466 datReq->boRep.estHdrSz = 0;
467 datReq->boRep.staPduPrsnt = FALSE;
468 if (rbCb->m.umDl.sduQ.count > 0)
470 datReq->boRep.oldestSduArrTime =
471 ((RlcSdu *)(rbCb->m.umDl.sduQ.first->node))->arrTime;
477 * @brief Handler to process the re-establishment request received from i
481 * This function does the following functions :
482 * Remove all the SDUs in the SDU queue.
484 * @param[in] gCb RLC Instance control block
485 * @param[in] rlcID Identity of the RLC entity for which
486 * re-establishment is to be done
487 * @param[in] sendReEst Whether to send re-establishment complete
488 * indication to upper layer or not
489 * @param[in] rbCb RB control block for which re-establishment
494 Void rlcDlUmmReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcDlRbCb *rbCb)
496 /* The re-establishment indication is sent from the UL only */
498 rlcUmmFreeDlRbCb(gCb, rbCb);
500 rbCb->m.umDl.txNext = 0;
502 /* this would have been set when re-establishment was triggered
504 rlcDlUtlResetReestInProgress(rbCb);
509 * @brief Handler to create the header and complete a PDU.
512 * This function is used to create the header of a PDU and concatenate it
513 * with the data part of the PDU.
514 * Also updates the statistics
515 * Sets the passed pdu to NULLP
517 * @param[in] gCb RLC instance control block
518 * @param[in,out] rbCb RB control block
520 * @param[in] umHdr UM mode header
521 * @param[out] datReqPduInfo Holder in which to copy the created PDU pointer
525 static void rlcUmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr, KwPduInfo *datReqPduInfo)
527 RlcSn sn; /* Sequence Number */
528 uint8_t hdr[RLC_MAX_HDRSZ]; /* Stores header */
529 uint32_t idx = 0; /* To index to the hdr array */
531 /* stats updated before for bytes sent before adding RLC headers */
532 rlcUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
534 /* If SI = 0, 1 byte header conatining SI/R */
541 /* Add SN based on SN length */
542 sn = rbCb->m.umDl.txNext;
543 if (rbCb->m.umDl.snLen == RLC_UM_CFG_6BIT_SN_LEN)
545 hdr[idx++] = (umHdr->si << 6) | sn;
549 hdr[idx++] = (umHdr->si << 6) | (sn >> 8);
550 hdr[idx++] = sn & 0xff ;
553 /* Add SO for middle and last segments*/
554 if((umHdr->si == RLC_SI_MID_SEG) | (umHdr->si == RLC_SI_LAST_SEG))
556 hdr[idx++] = (umHdr->so >> 8);
557 hdr[idx++] = umHdr->so & 0xff;
560 /* Increment TX_Next if this is last segment of current SDU */
561 if(umHdr->si == RLC_SI_LAST_SEG)
562 rbCb->m.umDl.txNext = (rbCb->m.umDl.txNext + 1) & rbCb->m.umDl.modBitMask;
566 /* add the header to the beginning of the pdu */
567 ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx, pdu);
569 datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
574 * @brief Handler to discard a SDU.
577 * This function is used to discard a SDU after receiving
578 * the Discard Request from the upper layer.The SDU is discarded if
579 * it is present and is not mapped to any PDU yet.
580 * The discards coming from the upper layer would be coming in
581 * sequence according to the sduId, so we should find the sduId at the
582 * head of the sduQ. Discards if there is a match else does nothing.
584 * @param[in] rbCb RB control block
585 * @param[in] sduId SDU ID of the SDU to be discarded
589 Void rlcUmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId)
591 CmLList *tmpNode; /* Temporary Node in SDU queue */
592 CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
596 RlcSdu *sdu = (RlcSdu *)tmpNode->node;
598 if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
600 /* kw005.201 added support for L2 Measurement */
601 RLC_REMOVE_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
602 gCb->genSts.numSduDisc++;
612 * function to free/release the UnAcknowledged mode RBCB buffers
615 * This primitive Frees the Unacknowldged Mode RbCb sdu queue
617 * @param [in] gCb - RLC instance control block
618 * @param [in] rbCb - RB Control Block
622 Void rlcUmmFreeDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb)
625 /* cat the SDU queue to the to be freed list */
626 RLC_FREE (gCb,rbCb->snssai, sizeof (Snssai));
627 cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.umDl.sduQ));
628 rlcUtlRaiseDlCleanupEvent(gCb);
631 } /* rlcUmmFreeDlRbCb */
633 /********************************************************************30**
635 **********************************************************************/