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 --rlcUmUlReAssembleSdus
36 **********************************************************************/
39 * @brief RLC Unacknowledged Mode uplink 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 */
51 /* header/extern include files (.x) */
53 #include "ckw.x" /* RRC layer */
54 #include "kwu.x" /* RLC service user */
55 #include "lkw.x" /* LM Interface */
56 #include "rgu.x" /* MAC later */
58 #include "rlc_utils.h" /* RLC layer */
62 #define RLC_MODULE (RLC_DBGMASK_UM | RLC_DBGMASK_UL)
64 static uint8_t rlcUmmExtractHdr ARGS ((RlcCb *gCb,
69 uint8_t rlcUmmReAssembleSdus ARGS ((RlcCb *gCb,
71 RlcUmRecBuf *umRecBuf));
73 bool rlcUmmAddRcvdSeg ARGS ((RlcCb *gCb,
79 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf);
83 uint32_t isMemThreshReached(Region region);
87 * @brief Finds and sets the next VR(UR) depending on the
88 * passed sequence number
91 * Finds the next VR(UR) depending on the passed SN. Updates VR(UR) to
92 * the SN of the first UMD PDU with SN >= _nextSn that has not been reassembled
94 * @param[in] umUl pointer to Um mode uplink control block
95 * @param[in] nextSn Sequence number after which the VR(UR) is to set to
99 static void rlcUmmFindRxNextReassembly (RlcCb *gCb, RlcUmUl* umUl, RlcSn nextSn)
101 RlcSn ur = RLC_UM_GET_VALUE(umUl->vrUr, *umUl);
102 RlcSn prevRxNextReassembly = umUl->vrUr;
104 RlcSn nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
105 RlcUmRecBuf *recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,nextSn);
106 RlcUmRecBuf *prevRecBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,prevRxNextReassembly);
107 while (ur < nextSnToCompare)
109 if((ur + 1) == nextSnToCompare)
111 if ((recBuf == NULLP) || (!(recBuf->allSegRcvd))) /* if the buffer is empty, SN not received */
116 rlcUmmRelAllSegs(gCb, prevRecBuf);
117 rlcUtlDelUmRecBuf(gCb, umUl->recBufLst, prevRecBuf);
125 rlcUmmRelAllSegs(gCb, prevRecBuf);
126 rlcUtlDelUmRecBuf(gCb, umUl->recBufLst, prevRecBuf);
129 prevRecBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,nextSn);
130 nextSn = (nextSn + 1) & umUl->modBitMask;
131 nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
132 recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,nextSn);
137 ur = RLC_UM_GET_VALUE(umUl->vrUr, *umUl);
140 rlcUmmRelAllSegs(gCb, prevRecBuf);
141 rlcUtlDelUmRecBuf(gCb, umUl->recBufLst, prevRecBuf);
143 prevRecBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,umUl->vrUr);
149 * @brief Checks whether a sequence number is within the
150 * re-assembly window or not
152 * @param[in] sn Sequence Number to be checked
153 * @param[in] umUl pointer to Um mode uplink control block
161 static int16_t rlcUmmCheckSnInReassemblyWindow (RlcSn sn, const RlcUmUl* const umUl)
163 return (RLC_UM_GET_VALUE(sn, *umUl) < RLC_UM_GET_VALUE(umUl->vrUh, *umUl));
167 * @brief Handler to updated expected byte seg
170 * This function is used to update expected byte segment. The next segment
171 * expected is indicated by the SO of the segment which is expected. Intially
172 * the segment with SO 0 is expected and then in order. When all the segments
173 * are received (which would happen when an expected SO is encountered
174 * with LSF set) the allRcvd flag is set to TRUE
176 * @param[in] gCb RLC instance control block
177 * @param[in] umUl AM Uplink Control Block
178 * @param[in] seg Newly received segment
184 void rlcUmmUpdExpByteSeg(RlcCb *gCb, RlcUmUl *umUl, RlcUmSeg *seg)
186 uint16_t newExpSo; /* The new expected SO */
187 RlcSn sn = seg->umHdr.sn;
189 RlcUmRecBuf *recBuf = NULLP;
191 recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst, sn);
192 if ((recBuf == NULLP) || (recBuf && (seg->umHdr.so != recBuf->expSo)))
196 recBuf->noMissingSeg = FALSE;
197 newExpSo = seg->soEnd + 1;
198 recBuf->expSo = newExpSo;
199 if(seg->umHdr.si == RLC_SI_LAST_SEG)
203 RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
206 /* keep going ahead as long as the expectedSo match with the header so
207 else store the expSo for later checking again */
208 if(seg->umHdr.si == RLC_SI_LAST_SEG)
212 if (seg->umHdr.so == newExpSo)
214 newExpSo = seg->soEnd + 1;
215 recBuf->expSo = newExpSo;
216 RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
220 recBuf->expSo = newExpSo;
226 recBuf->allSegRcvd = TRUE;
228 recBuf->noMissingSeg = TRUE;
233 * @brief Private handler to store the received segment
236 * Private handler invokded by rlcUmmUlPlacePduInRecBuf to add a received
237 * segment in reception buffer of a RBCB.
238 * - It is responsible for detecting duplicate segments
239 * - Adding it at appropriate position in the received buffer
240 * - Calling ExpByteSeg to set expSo field in the receiver buffer
242 * @param[in] gCb RLC instance control block
243 * @param[in] rbCb Radio Bearer Contro Block
244 * @param[in] umHdr UM Header received
245 * @param[in] pdu Buffer received other than the headers
246 * @param[in] pduSz size of the PDU buffer received
249 * -#TRUE Successful insertion into the receiver buffer
250 * -#FALSE Possibly a duplicate segment
253 bool rlcUmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu, uint16_t pduSz)
255 RlcUmRecBuf *recBuf = NULLP;
258 uint16_t soEnd; /* Holds the SoEnd of received segment */
259 uint16_t expSo = 0; /* Expected SO */
261 soEnd = umHdr->so + pduSz - 1;
262 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, umHdr->sn);
266 RLC_ALLOC(gCb,recBuf, sizeof(RlcUmRecBuf));
269 DU_LOG("\nERROR --> RLC_UL : Failed to allocate memory to recv buf for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
270 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
272 ODU_PUT_MSG_BUF(pdu);
275 rlcUtlStoreUmRecBuf(RLC_UMUL.recBufLst, recBuf, umHdr->sn);
279 if (recBuf->allSegRcvd == TRUE)
281 ODU_PUT_MSG_BUF(pdu);
286 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
287 while ((seg != NULLP) && (seg->umHdr.so < umHdr->so))
289 expSo = seg->umHdr.so + seg->segSz;
290 RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
293 if (expSo > umHdr->so)
295 DU_LOG("\nDEBUG --> RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
296 /* This is a duplicate segment */
297 ODU_PUT_MSG_BUF(pdu);
301 if ((seg) && (seg->umHdr.so <= soEnd))
303 DU_LOG("\nDEBUG --> RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
304 /* This is a duplicate segment */
305 ODU_PUT_MSG_BUF(pdu);
309 /* If we have come this far, we have to add this segment to the */
310 /* reception buffer as we either have eliminated duplicates or */
311 /* have found none. */
312 RLC_ALLOC_WC(gCb, tseg, sizeof(RlcUmSeg));
315 DU_LOG("\nERROR --> RLC_UL : Failed to allocate memory to segment for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
316 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
317 ODU_PUT_MSG_BUF(pdu);
323 RLC_MEM_CPY(&tseg->umHdr, umHdr, sizeof(RlcUmHdr));
324 RLC_MEM_CPY(&recBuf->umHdr, umHdr, sizeof(RlcUmHdr));
325 recBuf->sn = umHdr->sn;
329 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
333 recBuf->segLst.crnt = &seg->lstEnt;
334 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
336 tseg->lstEnt.node = (PTR)tseg;
337 rlcUmmUpdExpByteSeg(gCb, &RLC_UMUL, tseg);
342 * @brief Private handler to release all stored segments
345 * Private handler invokded by rlcUmmRelAllSegs to release the
346 * stored segements in case a complete PDU is received later.
348 * @param[in] gCb RLC instance control block
349 * @param[in] recBuf Buffer that stores a received PDU or segments
354 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf)
358 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
361 ODU_PUT_MSG_BUF(seg->seg);
362 cmLListDelFrm(&(recBuf->segLst), &(seg->lstEnt));
363 RLC_FREE(gCb, seg, sizeof(RlcUmSeg));
364 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
371 * @brief Private handler to reassemble from a segment or a PDU
374 * Private handler invokded by rlcUmmReAssembleSdus with either a
375 * PDU or a segment of a PDU. This is also called in the case of
376 * reestablishment and hence out of sequence joining is also to
380 * @param[in] gCb RLC instance control block
381 * @param[in] rbCb Uplink RB control block
382 * @param[in] umHdr UM header received for this segment/PDU
383 * @param[in] pdu PDU to be reassembled
389 uint8_t rlcUmmProcSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu)
392 if ((RLC_UMUL.expSn != umHdr->sn) || (RLC_UMUL.expSo != umHdr->so))
394 /* Release the existing SDU as we have PDUs or */
395 /* segments that are out of sequence */
396 DU_LOG("\nDEBUG --> RLC_UL : Received Segments are out of sequence in rlcUmmProcSeg()");
397 ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
401 if (umHdr->si == RLC_SI_FIRST_SEG)
402 {/* first Segment of the SDU */
403 if (RLC_UMUL.assembleSdu != NULLP)
404 { /* Some old SDU may be present */
405 ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
407 RLC_UMUL.assembleSdu = pdu;
410 else if(umHdr->si == RLC_SI_MID_SEG)
411 {/* Middle Segment of the SDU */
412 ODU_CAT_MSG(RLC_UMUL.assembleSdu,pdu, M1M2);
413 ODU_PUT_MSG_BUF(pdu);
416 else if(umHdr->si == RLC_SI_LAST_SEG)
418 ODU_CAT_MSG(pdu, RLC_UMUL.assembleSdu, M2M1);
419 ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
424 RLC_UMUL.assembleSdu = NULLP;
425 rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
432 * @brief Private handler to reassemble SDUs
435 * Private handler invokded by rlcUmmProcessPdus with the PDU
436 * from the reception buffer in sequence to reassemble SDUs and
439 * - With the stored header info, FI and LSF segment / concatenate
440 * PDUs or byte segments of PDUs to get the associated SDU.
442 * @param[in] rbCb RB control block
443 * @param[in] pdu PDU to be reassembled
450 uint8_t rlcUmmReAssembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmRecBuf *recBuf)
454 /* This is a set of segments */
455 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
456 RLC_UMUL.expSn = recBuf->sn;
460 if(rlcUmmProcSeg(gCb, rbCb, &seg->umHdr, seg->seg) == RFAILED)
462 rlcUmmRelAllSegs(gCb, recBuf);
465 RLC_UMUL.expSo = seg->soEnd + 1;
466 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
467 RLC_FREE(gCb, seg, sizeof(RlcSeg));
468 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
470 RLC_UMUL.expSn = (recBuf->umHdr.sn + 1) & (RLC_UMUL.modBitMask);
476 * @brief Handler to process the Data Indication from the lower layer
477 * and send the PDUs to re-assembly unit.
480 * This function processes the PDUs received from the lower layer
481 * re-orders them and sends them one after the other in sequence
482 * to the re-assembly unit.
484 * @param[in] gCb RLC Instance control block
485 * @param[in] rbCb RB control block
486 * @param[in] pduInfo Pdu information
490 /* kw005.201 added support for L2 Measurement */
492 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
494 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
497 RlcSn *vrUh; /* vr(uh) */
498 RlcSn *vrUr; /* vr(ur) */
499 RlcSn *vrUx; /* vr(ux) */
500 uint16_t curSn; /* Current Sequence Number */
501 uint32_t pduCount; /* PDU count */
502 uint32_t count; /* Loop counter */
503 RlcUmRecBuf *recBuf; /* UM Reception Buffer */
504 RlcUmHdr umHdr; /* Um header*/
505 bool tmrRunning; /* Boolean for checking Tmr */
506 MsgLen pduSz; /* Pdu Size */
507 RlcSn tRxNextReassembly;
508 RlcSn tRxNextReassemblyNxt;
509 RlcSn tRxNextHighest;
513 /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */
514 pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU;
516 vrUh = &(rbCb->m.umUl.vrUh);
517 vrUr = &(rbCb->m.umUl.vrUr);
518 vrUx = &(rbCb->m.umUl.vrUx);
520 while (count < pduCount)
524 Buffer *pdu = pduInfo->mBuf[count];
526 gCb->genSts.pdusRecv++;
527 #ifndef RGL_SPECIFIC_CHANGES
532 ODU_GET_MSG_LEN(pdu, &len);
537 /* ccpu00142274 - UL memory based flow control*/
538 #ifndef RGL_SPECIFIC_CHANGES
541 /* Changed the condition to TRUE from ROK */
542 #ifndef XEON_SPECIFIC_CHANGES
543 if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
547 ODU_PUT_MSG_BUF(pdu);
555 /* get the pdu header */
556 if (rlcUmmExtractHdr(gCb, rbCb, pdu, &umHdr))
558 DU_LOG("\nERROR --> RLC_UL: rlcUmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",\
559 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
560 ODU_PUT_MSG_BUF(pdu);
562 gCb->genSts.errorPdusRecv++;
566 /* Check if the PDU should be delivered to upper layer */
569 rlcUtlSendUlDataToDu(gCb, rbCb, pdu);
570 ODU_PUT_MSG_BUF(pdu);
577 /* Check if the PDU should be discarded or not */
578 ur = RLC_UM_GET_VALUE(RLC_UMUL.vrUr, RLC_UMUL);
579 seqNum = RLC_UM_GET_VALUE(curSn, RLC_UMUL);
583 /* PDU needs to be discarded */
584 DU_LOG("\nINFO --> RLC_UL: rlcUmmProcessPdus: Received an unexpected pdu with sn %d \
585 UEID:%d CELLID:%d", curSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
587 ODU_PUT_MSG_BUF(pdu);
589 gCb->genSts.unexpPdusRecv++;
594 rlcUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt);
597 ODU_GET_MSG_LEN(pdu, &pduSz);
598 /* Place sdu segment into recption buffer */
599 if(rlcUmmAddRcvdSeg(gCb, rbCb, &umHdr, pdu, pduSz) == TRUE)
601 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, umHdr.sn);
604 DU_LOG("\nERROR --> RLC_UL: rlcUmmProcessPdus: recBuf is NULLP UEID:%d CELLID:%d", \
605 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
606 ODU_PUT_MSG_BUF(pdu);
611 /* If all bytes segments of curSn are received, deliver assembled SDU to upper layer */
612 if(recBuf != NULLP && recBuf->allSegRcvd)
614 rlcUmmReAssembleSdus(gCb, rbCb, recBuf);
615 DU_LOG("\nDEBUG --> RLC_UL: rlcUmmProcessPdus: Assembled the Sdus for sn = %d UEID:%d CELLID:%d",\
616 umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
618 /* if curSn is same as the RX_NEXT_Reassembly */
621 /* set RX_NEXT_Reassembly to next SN > current RX_NEXT_Reassembly which is not reassembled yet */
622 RlcSn nextVrUr = (*vrUr + 1) & RLC_UMUL.modBitMask;
623 rlcUmmFindRxNextReassembly(gCb, &RLC_UMUL, nextVrUr);
626 /* If curSn is outside re-assembly window */
627 else if (!rlcUmmCheckSnInReassemblyWindow(curSn,&RLC_UMUL))
629 DU_LOG("\nDEBUG --> RLC_UL: rlcUmmProcessPdus: curent sn is outSide the re-Assembly window. \
630 sn = %d UEID:%d CELLID:%d", umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
632 /* update RX_NEXT_Highest */
633 *vrUh = (curSn + 1) & RLC_UMUL.modBitMask;
635 /* Discard all pdus outside the modified re-assembly window */
636 if (!rlcUmmCheckSnInReassemblyWindow(*vrUr,&RLC_UMUL))
638 RlcSn sn = *vrUr; /* Stores SNs which need to be discarded. First SN is VR(UR) */
639 RlcSn lowerEdge; /* to hold the lower-edge of the re-assembly window */
642 /* Set RX_NEXT_Reassembly to next SN >= (RX_NEXT_Highest - windowSize) that has not been reassembled yet */
643 *vrUr = (*vrUh - RLC_UMUL.umWinSz) & RLC_UMUL.modBitMask;
645 packetCount = (lowerEdge - sn) & RLC_UMUL.modBitMask;
649 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, sn);
652 rlcUmmRelAllSegs(gCb, recBuf);
653 rlcUtlDelUmRecBuf(gCb, RLC_UMUL.recBufLst, recBuf);
655 sn = (sn + 1) & RLC_UMUL.modBitMask;
658 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, *vrUr);
659 if (recBuf != NULLP && recBuf->allSegRcvd)
661 /* set rxNextReassembly to next SN > current rxNextReassembly which is not received */
662 RlcSn nextRxNextReassembly = (*vrUr + 1) & RLC_UMUL.modBitMask;
663 rlcUmmFindRxNextReassembly(gCb ,&RLC_UMUL, nextRxNextReassembly);
668 tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
669 tRxNextReassembly = RLC_UM_GET_VALUE(*vrUr ,RLC_UMUL);
670 tRxNextReassemblyNxt = (*vrUr + 1) & rbCb->m.umUl.modBitMask;
671 tRxNextHighest = RLC_UM_GET_VALUE(*vrUh, RLC_UMUL);
672 tRxNextReassemblyNxt = RLC_UM_GET_VALUE(tRxNextReassemblyNxt ,RLC_UMUL);
674 /* If reassemby timer is running */
677 RlcSn tRxTimerTigger = RLC_UM_GET_VALUE(*vrUx, RLC_UMUL);
678 uint8_t ret = rlcUmmCheckSnInReassemblyWindow(*vrUx, &RLC_UMUL);
679 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst,*vrUr);
681 if ((tRxTimerTigger <= tRxNextReassembly) || ((!ret) && (tRxTimerTigger != tRxNextHighest)) ||
682 (tRxNextHighest == tRxNextReassemblyNxt && recBuf && recBuf->noMissingSeg))
684 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
686 DU_LOG("\nINFO --> RLC_UL: rlcUmmProcessPdus: Stopped ReAssembly Timer rxTimerTigger = %d \
687 rxNextReassembly = %d rxNextHighest = %d ", tRxTimerTigger, tRxNextReassembly, tRxNextHighest);
691 /* If Reassembly timer is not running */
694 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, curSn);
695 if ((tRxNextHighest > tRxNextReassemblyNxt) || ((tRxNextHighest == tRxNextReassemblyNxt)
696 && (recBuf && (!recBuf->noMissingSeg))))
698 DU_LOG("\nDEBUG --> RLC_UL: rlcUmmProcessPdus: Start ReAssembly Timer tRxNextReassemblyNxt = %d \
699 tRxNextHighest %d", tRxNextReassemblyNxt, tRxNextHighest);
700 rlcStartTmr(gCb, (PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
707 DU_LOG("\nERROR --> RLC_UL: rlcUmmProcessPdus:Failed to assemble the PDU for SN = %d UEID:%d CELLID:%d",\
708 umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
712 }/* end while count < pduCount */
714 rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
715 #endif /* LTE_L2_MEAS */
720 * @brief Handler to process the re-establishment request received
721 * from the upper layer.
724 * This function does the following functions :
725 * - If direction of the RB is downlink :
726 * Remove all the SDUs in the SDU queue.
727 * - If direction of the RB is uplink :
728 * Call rlcUmUlReAssembleSdus() for each PDU with SN < VR(UH)
730 * @param[in] gCb RLC Instance control block
731 * @param[in] rlcID Identity of the RLC entity for which
732 * re-establishment is to be done
733 * @param[in] rbCb RB control block for which re-establishment
738 Void rlcUmmUlReEstablish
747 RlcUmRecBuf *recBuf; /* UM Reception Buffer */
748 RlcKwuSapCb *rlcKwSap; /* KWU SAP Information */
750 curSn = rbCb->m.umUl.vrUr;
751 vrUh = RLC_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl);
753 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR))
755 rlcStopTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR);
758 while (RLC_UM_GET_VALUE(curSn, rbCb->m.umUl) < vrUh)
760 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, curSn);
761 if ( recBuf != NULLP )
763 if(recBuf->allRcvd == TRUE)
765 rlcUmmReAssembleSdus(gCb,rbCb,recBuf);
769 /* Remove PDU and segments */
772 ODU_PUT_MSG_BUF(recBuf->pdu);
774 /* Release all the segments*/
775 rlcUmmRelAllSegs(gCb,recBuf);
777 rlcUtlDelUmRecBuf(gCb, RLC_UMUL.recBufLst, recBuf);
779 curSn = (curSn + 1) & rbCb->m.umUl.modBitMask;
781 rbCb->m.umUl.vrUr = 0;
782 rbCb->m.umUl.vrUh = 0;
783 rbCb->m.umUl.vrUx = 0;
785 rlcKwSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
787 /* In the UM Mode always send reestablish-indication to Upper Latyer*/
788 RlcUiKwuReEstCmpInd(&rlcKwSap->pst, rlcKwSap->suId, *rlcId);
794 * @brief Handler to extract the header from a PDU
797 * This function is used to extract the header of a PDU and store it
798 * along with the PDU buffer.The sequence number, segmentation info
799 * and segmentation offset are extracted by this function.
801 * @param[in] gCb RLC Instance control block
802 * @param[in] rbCb Rb Control block for which the pdu is received
803 * @param[in] pdu PDU buffer
804 * @param[out] umHdr UM header to be filled after extraction
810 static uint8_t rlcUmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr)
812 Data dst[2]; /* Destination Buffer */
813 uint8_t ret; /* Return Value */
815 memset(umHdr, 0, sizeof(RlcUmHdr));
817 ret = ODU_REM_PRE_MSG(dst,pdu);
820 DU_LOG("\nERROR --> RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for SI\
821 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
824 umHdr->si = (dst[0]) >> 6;
826 /* If SI = 0, the RLC PDU contains complete RLC SDU. Header extraction complete.
827 * No other fields present in header */
831 /* If SI != 0, one SDU segment is present in RLC PDU. Hence extracting SN */
832 if (rbCb->m.umUl.snLen == RLC_UM_CFG_6BIT_SN_LEN)
834 /* Extractin 6-bit SN */
835 umHdr->sn = (dst[0]) & 0x3F;
839 /* Extracting 12 bits SN */
840 umHdr->sn = (dst[0]) & 0x0F;
841 ret = ODU_REM_PRE_MSG(dst,pdu);
844 DU_LOG("\nERROR --> RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for SN\
845 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
848 umHdr->sn = (umHdr->sn << 8) | dst[0];
851 /* SO field is present for middle and last segments of SDU, not present for first segment */
852 if((umHdr->si == RLC_SI_LAST_SEG) || (umHdr->si == RLC_SI_MID_SEG))
854 ret = ODU_REM_PRE_MSG_MULT(dst,2,pdu);
857 DU_LOG("\nERROR --> RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG_MULT Failed for 16 bits SO \
858 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
862 umHdr->so = (umHdr->so << 8) | dst[1];
868 * @brief Handles expiry of re-assembly timer
870 * @param[in] gCb RLC Instance control block
871 * @param[in] rbCb Rb Control block for which re-assembly timer expired
875 void rlcUmmReAsmblTmrExp
881 RlcSn tRxNextHighest;
882 RlcSn tRxNextReassembly;
885 DU_LOG("\nINFO --> RLC_UL: rlcUmmReAsmblTmrExp: UM Re-assembly timer expired");
887 /* set VR(UR) to SN >= VR(UX) that has not been reassembled */
888 rlcUmmFindRxNextReassembly(gCb, &RLC_UMUL, RLC_UMUL.vrUx);
890 tRxNextHighest = RLC_UM_GET_VALUE(RLC_UMUL.vrUh, RLC_UMUL);
891 tRxNextReassembly = (RLC_UMUL.vrUr + 1) & rbCb->m.umUl.modBitMask;
892 tRxNextReassembly = RLC_UM_GET_VALUE(tRxNextReassembly, RLC_UMUL);
893 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst,RLC_UMUL.vrUr);
894 if ((tRxNextHighest > tRxNextReassembly) || ((tRxNextHighest == tRxNextReassembly) &&
895 ((recBuf) && !(recBuf->noMissingSeg))))
897 rlcStartTmr(gCb, (PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
898 RLC_UMUL.vrUx = RLC_UMUL.vrUh;
904 * Function to release/free the UnAcknowledged Mode Module RbCb buffers
907 * This primitive Frees the UM RbCb transmission Buffer, retransmission
908 * Buffer and reciption Buffers
910 * @param [in] gCb - RLC instance Control Block
911 * @param [in] rbCb - RB Control Block
916 Void rlcUmmFreeUlRbCb
922 RlcSn curSn = 0; /* Sequence number of PDU */
923 RlcUmRecBuf *recBuf = NULLP;
925 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR))
927 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
932 recBuf = rlcUtlGetUmRecBuf(rbCb->m.umUl.recBufLst, curSn);
933 if ( recBuf != NULLP )
935 if (recBuf->pdu != NULLP)
937 ODU_PUT_MSG_BUF(recBuf->pdu);
939 /* Release all the segments */
940 rlcUmmRelAllSegs(gCb,recBuf);
941 rlcUtlDelUmRecBuf(gCb, rbCb->m.umUl.recBufLst, recBuf);
944 }while ( curSn < RLC_RCV_BUF_BIN_SIZE);
946 RLC_FREE(gCb,rbCb->snssai, sizeof (Snssai));
947 RLC_FREE(gCb,rbCb->m.umUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
948 rbCb->m.umUl.recBufLst = NULLP;
950 if(rbCb->m.umUl.assembleSdu != NULLP)
952 ODU_PUT_MSG_BUF(rbCb->m.umUl.assembleSdu);
955 } /* rlcAmmFreeUlRbCb */
957 /********************************************************************30**
959 **********************************************************************/