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 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 "kw_env.h" /* RLC environment options */
51 #include "kw.h" /* RLC layer */
56 /* header/extern include files (.x) */
58 #include "ckw.x" /* RRC layer */
59 #include "kwu.x" /* RLC service user */
60 #include "lkw.x" /* LM Interface */
61 #include "rgu.x" /* MAC later */
63 #include "kw.x" /* RLC layer */
66 #define RLC_MODULE (RLC_DBGMASK_UM | RLC_DBGMASK_UL)
68 static uint8_t rlcUmmExtractHdr ARGS ((RlcCb *gCb,
73 uint8_t rlcUmmReAssembleSdus ARGS ((RlcCb *gCb,
75 RlcUmRecBuf *umRecBuf));
78 bool rlcUmmAddRcvdSeg ARGS ((RlcCb *gCb,
84 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf);
90 uint32_t isMemThreshReached(Region region);
94 * @brief Finds and sets the next VR(UR) depending on the
95 * passed sequence number
98 * Finds the next VR(UR) depending on the passed SN. Updates VR(UR) to
99 * the SN of the first UMD PDU with SN >= _nextSn that has not been received
101 * @param[in] umUl pointer to Um mode uplink control block
102 * @param[in] nextSn Sequence number after which the VR(UR) is to set to
106 static void rlcUmmFindNextVRUR (RlcUmUl* umUl, RlcSn nextSn)
108 RlcSn ur = RLC_UM_GET_VALUE(umUl->vrUr, *umUl);
110 RlcSn nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
112 while (ur < nextSnToCompare)
114 if (!(umUl->recBuf[nextSn])) /* if the buffer is empty, SN not received */
119 nextSn = (nextSn + 1) & umUl->modBitMask;
120 nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
125 * @brief Checks whether a sequence number is within the
126 * re-ordering window or not
128 * @param[in] sn Sequence Number to be checked
129 * @param[in] umUl pointer to Um mode uplink control block
137 static int16_t rlcUmmCheckSnInReordWindow (RlcSn sn, const RlcUmUl* const umUl)
139 return (RLC_UM_GET_VALUE(sn, *umUl) < RLC_UM_GET_VALUE(umUl->vrUh, *umUl));
145 * @brief Handler to updated expected byte seg
148 * This function is used to update expected byte segment. The next segment
149 * expected is indicated by the SO of the segment which is expected. Intially
150 * the segment with SO 0 is expected and then in order. When all the segments
151 * are received (which would happen when an expected SO is encountered
152 * with LSF set) the allRcvd flag is set to TRUE
154 * @param[in] gCb RLC instance control block
155 * @param[in] umUl AM Uplink Control Block
156 * @param[in] seg Newly received segment
162 void rlcUmmUpdExpByteSeg(RlcCb *gCb, RlcUmUl *umUl, RlcUmSeg *seg)
164 uint16_t newExpSo; /* The new expected SO */
165 RlcSn sn = seg->umHdr.sn;
167 RlcUmRecBuf *recBuf = NULLP;
169 recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst, sn);
170 if ((recBuf == NULLP) || (recBuf && (seg->umHdr.so != recBuf->expSo)))
174 recBuf->noMissingSeg = FALSE;
175 newExpSo = seg->soEnd + 1;
176 recBuf->expSo = newExpSo;
177 if(seg->umHdr.si == RLC_SI_LAST_SEG)
181 RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
184 /* keep going ahead as long as the expectedSo match with the header so
185 else store the expSo for later checking again */
186 if(seg->umHdr.si == RLC_SI_LAST_SEG)
190 if (seg->umHdr.so == newExpSo)
192 newExpSo = seg->soEnd + 1;
193 recBuf->expSo = newExpSo;
194 RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
198 recBuf->expSo = newExpSo;
204 recBuf->allSegRcvd = TRUE;
206 recBuf->noMissingSeg = TRUE;
211 * @brief Private handler to store the received segment
214 * Private handler invokded by rlcUmmUlPlacePduInRecBuf to add a received
215 * segment in reception buffer of a RBCB.
216 * - It is responsible for detecting duplicate segments
217 * - Adding it at appropriate position in the received buffer
218 * - Calling ExpByteSeg to set expSo field in the receiver buffer
220 * @param[in] gCb RLC instance control block
221 * @param[in] rbCb Radio Bearer Contro Block
222 * @param[in] umHdr UM Header received
223 * @param[in] pdu Buffer received other than the headers
224 * @param[in] pduSz size of the PDU buffer received
227 * -#TRUE Successful insertion into the receiver buffer
228 * -#FALSE Possibly a duplicate segment
231 bool rlcUmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu, uint16_t pduSz)
233 RlcUmRecBuf *recBuf = NULLP;
236 uint16_t soEnd; /* Holds the SoEnd of received segment */
237 uint16_t expSo = 0; /* Expected SO */
239 soEnd = umHdr->so + pduSz - 1;
240 recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, umHdr->sn);
244 RLC_ALLOC(gCb,recBuf, sizeof(RlcUmRecBuf));
247 DU_LOG("\nERROR --> RLC_UL : Failed to allocate memory to recv buf for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
248 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
250 ODU_PUT_MSG_BUF(pdu);
253 rlcUtlStoreUmRecBuf(RLC_UMUL.recBufLst, recBuf, umHdr->sn);
257 if (recBuf->allSegRcvd == TRUE)
259 ODU_PUT_MSG_BUF(pdu);
264 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
265 while ((seg != NULLP) && (seg->umHdr.so < umHdr->so))
267 expSo = seg->umHdr.so + seg->segSz;
268 RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
271 if (expSo > umHdr->so)
273 DU_LOG("\nDEBUG --> RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
274 /* This is a duplicate segment */
275 ODU_PUT_MSG_BUF(pdu);
279 if ((seg) && (seg->umHdr.so <= soEnd))
281 DU_LOG("\nDEBUG --> RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
282 /* This is a duplicate segment */
283 ODU_PUT_MSG_BUF(pdu);
287 /* If we have come this far, we have to add this segment to the */
288 /* reception buffer as we either have eliminated duplicates or */
289 /* have found none. */
290 RLC_ALLOC_WC(gCb, tseg, sizeof(RlcUmSeg));
293 DU_LOG("\nERROR --> RLC_UL : Failed to allocate memory to segment for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
294 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
295 ODU_PUT_MSG_BUF(pdu);
301 RLC_MEM_CPY(&tseg->umHdr, umHdr, sizeof(RlcUmHdr));
302 RLC_MEM_CPY(&recBuf->umHdr, umHdr, sizeof(RlcUmHdr));
303 recBuf->sn = umHdr->sn;
307 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
311 recBuf->segLst.crnt = &seg->lstEnt;
312 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
314 tseg->lstEnt.node = (PTR)tseg;
315 rlcUmmUpdExpByteSeg(gCb, &RLC_UMUL, tseg);
320 * @brief Private handler to release all stored segments
323 * Private handler invokded by rlcUmmRelAllSegs to release the
324 * stored segements in case a complete PDU is received later.
326 * @param[in] gCb RLC instance control block
327 * @param[in] recBuf Buffer that stores a received PDU or segments
332 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf)
336 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
339 ODU_PUT_MSG_BUF(seg->seg);
340 cmLListDelFrm(&(recBuf->segLst), &(seg->lstEnt));
341 RLC_FREE(gCb, seg, sizeof(RlcUmSeg));
342 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
349 * @brief Private handler to reassemble from a segment or a PDU
352 * Private handler invokded by rlcUmmReAssembleSdus with either a
353 * PDU or a segment of a PDU. This is also called in the case of
354 * reestablishment and hence out of sequence joining is also to
358 * @param[in] gCb RLC instance control block
359 * @param[in] rbCb Uplink RB control block
360 * @param[in] umHdr UM header received for this segment/PDU
361 * @param[in] pdu PDU to be reassembled
367 uint8_t rlcUmmProcSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu)
370 if ((RLC_UMUL.expSn != umHdr->sn) || (RLC_UMUL.expSo != umHdr->so))
372 /* Release the existing SDU as we have PDUs or */
373 /* segments that are out of sequence */
374 DU_LOG("\nDEBUG --> RLC_UL : Received Segments are out of sequence in rlcUmmProcSeg()");
375 ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
379 if (umHdr->si == RLC_SI_FIRST_SEG)
380 {/* first Segment of the SDU */
381 if (RLC_UMUL.assembleSdu != NULLP)
382 { /* Some old SDU may be present */
383 ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
385 RLC_UMUL.assembleSdu = pdu;
388 else if(umHdr->si == RLC_SI_MID_SEG)
389 {/* Middle Segment of the SDU */
390 ODU_CAT_MSG(RLC_UMUL.assembleSdu,pdu, M1M2);
391 ODU_PUT_MSG_BUF(pdu);
394 else if(umHdr->si == RLC_SI_LAST_SEG)
396 ODU_CAT_MSG(pdu, RLC_UMUL.assembleSdu, M2M1);
397 ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
402 RLC_UMUL.assembleSdu = NULLP;
403 rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
410 * @brief Private handler to reassemble SDUs
413 * Private handler invokded by rlcUmmProcessPdus with the PDU
414 * from the reception buffer in sequence to reassemble SDUs and
417 * - With the stored header info, FI and LSF segment / concatenate
418 * PDUs or byte segments of PDUs to get the associated SDU.
420 * @param[in] rbCb RB control block
421 * @param[in] pdu PDU to be reassembled
428 uint8_t rlcUmmReAssembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmRecBuf *recBuf)
432 /* This is a set of segments */
433 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
434 RLC_UMUL.expSn = recBuf->sn;
438 if(rlcUmmProcSeg(gCb, rbCb, &seg->umHdr, seg->seg) == RFAILED)
440 rlcUmmRelAllSegs(gCb, recBuf);
443 RLC_UMUL.expSo = seg->soEnd + 1;
444 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
445 RLC_FREE(gCb, seg, sizeof(RlcSeg));
446 RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
448 RLC_UMUL.expSn = (recBuf->umHdr.sn + 1) & (RLC_UMUL.modBitMask);
456 * @brief Handler to process the Data Indication from the lower layer
457 * and send the PDUs to re-assembly unit.
460 * This function processes the PDUs received from the lower layer
461 * re-orders them and sends them one after the other in sequence
462 * to the re-assembly unit.
464 * @param[in] gCb RLC Instance control block
465 * @param[in] rbCb RB control block
466 * @param[in] pduInfo Pdu information
470 /* kw005.201 added support for L2 Measurement */
472 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
474 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
477 RlcSn *vrUh; /* vr(uh) */
478 RlcSn *vrUr; /* vr(ur) */
479 RlcSn *vrUx; /* vr(ux) */
480 uint16_t curSn; /* Current Sequence Number */
481 uint32_t pduCount; /* PDU count */
482 uint32_t count; /* Loop counter */
483 RlcUmRecBuf **recBuf; /* UM Reception Buffer */
485 bool tmrRunning; /* Boolean for checking Tmr */
489 /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */
490 pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU;
492 vrUh = &(rbCb->m.umUl.vrUh);
493 vrUr = &(rbCb->m.umUl.vrUr);
494 vrUx = &(rbCb->m.umUl.vrUx);
495 recBuf = (rbCb->m.umUl.recBuf);
497 while (count < pduCount)
502 Buffer *pdu = pduInfo->mBuf[count];
503 RlcUmRecBuf *tmpRecBuf;
504 gCb->genSts.pdusRecv++;
505 #ifndef RGL_SPECIFIC_CHANGES
510 ODU_GET_MSG_LEN(pdu, &len);
515 /* create a buffer to be later inserted into the reception buffer */
516 RLC_ALLOC_WC(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
517 #if (ERRCLASS & ERRCLS_ADD_RES)
518 if (tmpRecBuf == NULLP)
520 DU_LOG("\nRLC : rlcUmmProcessPdus: Memory allocation failed UEID:%d CELLID:%d",\
521 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
522 ODU_PUT_MSG_BUF(pdu);
525 #endif /* ERRCLASS & ERRCLS_ADD_RES */
526 /* ccpu00142274 - UL memory based flow control*/
527 #ifndef RGL_SPECIFIC_CHANGES
530 /* Changed the condition to TRUE from ROK */
531 #ifndef XEON_SPECIFIC_CHANGES
532 if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
536 ODU_PUT_MSG_BUF(pdu);
537 RLC_FREE(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
538 /*Fix for CR ccpu00144030: If threshhold is hit then also count
539 *should be incrmented */
547 /* get the pdu header */
548 if (rlcUmmExtractHdr(gCb, rbCb, pdu, &(tmpRecBuf->umHdr)))
550 DU_LOG("\nRLC : rlcUmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",\
551 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
553 /* Header extraction is a problem.
554 * log an error and free the allocated memory */
556 RLC_FREE(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
557 ODU_PUT_MSG_BUF(pdu);
559 /* kw005.201 ccpu00117318, updating the statistics */
560 gCb->genSts.errorPdusRecv++;
565 /*TODO 1.Extract Hdr */
566 /* 2.Add Seg into Reception Buffer */
567 /* 3.If All Seg Recvd in Reception buffer list */
568 /* 4.Step 3 is true call Assemble Sdus */
570 curSn = tmpRecBuf->umHdr.sn;
572 /* Check if the PDU should be discarded or not */
573 ur = RLC_UM_GET_VALUE(RLC_UMUL.vrUr, RLC_UMUL);
574 uh = RLC_UM_GET_VALUE(RLC_UMUL.vrUh, RLC_UMUL);
575 seqNum = RLC_UM_GET_VALUE(curSn, RLC_UMUL);
577 if (((ur < seqNum) && (seqNum < uh) && (RLC_UMUL.recBuf[curSn])) ||
580 /* PDU needs to be discarded */
581 DU_LOG("\nRLC : rlcUmmProcessPdus: Received a duplicate pdu with sn %d \
582 UEID:%d CELLID:%d", curSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
584 ODU_PUT_MSG_BUF(pdu);
585 RLC_FREE(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
587 /* kw005.201 ccpu00117318, updating the statistics */
588 gCb->genSts.unexpPdusRecv++;
592 /* kw005.201 added support for L2 Measurement */
595 /* kw006.201 ccpu00120058, reduced code complexity by adding new function */
596 rlcUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt);
600 recBuf[curSn] = tmpRecBuf;
602 recBuf[curSn]->pdu = pdu;
603 ODU_GET_MSG_LEN(pdu,&(recBuf[curSn]->pduSz));
604 /* kw005.201 ccpu00117318, updating the statistics */
605 gCb->genSts.bytesRecv += recBuf[curSn]->pduSz;
607 if (!rlcUmmCheckSnInReordWindow(curSn,&RLC_UMUL))
608 { /* currSn is outside re-ordering window */
609 *vrUh = (curSn + 1) & RLC_UMUL.modBitMask;
611 /* re-assemble all pdus outside the modified re-ordering window */
612 /* the first SN is VR(UR) */
613 if (!rlcUmmCheckSnInReordWindow(*vrUr,&RLC_UMUL))
615 /* TODO : should it be VR(UR) + 1 ?... check, earlier it was so */
616 RlcSn sn = *vrUr; /* SN's which need to be re-assembled */
617 RlcSn lowerEdge; /* to hold the lower-edge of the
618 re-ordering window */
620 /* The new value ov VR(UR) is the lower end of the window i
621 * and SN's still this value need to be re-assembled */
623 *vrUr = (*vrUh - RLC_UMUL.umWinSz) & RLC_UMUL.modBitMask;
624 lowerEdge = RLC_UM_GET_VALUE(*vrUr ,RLC_UMUL);
626 while (RLC_UM_GET_VALUE(sn, RLC_UMUL) < lowerEdge)
631 rlcUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
633 RLC_FREE(gCb,recBuf[sn],sizeof(RlcUmRecBuf));
636 sn = (sn + 1) & RLC_UMUL.modBitMask;
643 RlcSn tSn = RLC_UM_GET_VALUE(sn,RLC_UMUL);
646 /* set VR(UR) to next SN > current VR(UR) which is not received */
647 RlcSn nextVrUr = (*vrUr + 1) & RLC_UMUL.modBitMask;
648 rlcUmmFindNextVRUR(&RLC_UMUL, nextVrUr);
650 /* re-assemble SDUs with SN < Vr(UR) */
651 tVrUr = RLC_UM_GET_VALUE(*vrUr,RLC_UMUL);
652 while (recBuf[sn] && tSn < tVrUr)
655 rlcUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
657 RLC_FREE(gCb,recBuf[sn],sizeof(RlcUmRecBuf));
659 sn = (sn + 1) & RLC_UMUL.modBitMask;
660 tSn = RLC_UM_GET_VALUE(sn, RLC_UMUL);
664 tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, RLC_EVT_UMUL_REORD_TMR);
668 RlcSn tVrUx = RLC_UM_GET_VALUE(*vrUx, RLC_UMUL);
669 RlcSn tVrUr = RLC_UM_GET_VALUE(*vrUr ,RLC_UMUL);
671 RlcSn tVrUh = RLC_UM_GET_VALUE(*vrUh, RLC_UMUL);
673 S16 ret = rlcUmmCheckSnInReordWindow(*vrUx, &RLC_UMUL);
675 if ( (tVrUx <= tVrUr) || ((!ret) && (tVrUx != tVrUh)))
677 rlcStopTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
684 if (RLC_UM_GET_VALUE(*vrUh, RLC_UMUL) > RLC_UM_GET_VALUE(*vrUr, RLC_UMUL))
686 rlcStartTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
691 }/* end while count < pduCount */
693 rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
694 #endif /* LTE_L2_MEAS */
699 * @brief Handler to process the re-establishment request received
700 * from the upper layer.
703 * This function does the following functions :
704 * - If direction of the RB is downlink :
705 * Remove all the SDUs in the SDU queue.
706 * - If direction of the RB is uplink :
707 * Call rlcUmmReAssembleSdus() for each PDU with SN < VR(UH)
709 * @param[in] gCb RLC Instance control block
710 * @param[in] rlcID Identity of the RLC entity for which
711 * re-establishment is to be done
712 * @param[in] rbCb RB control block for which re-establishment
717 Void rlcUmmUlReEstablish
726 RlcUmRecBuf **recBuf; /* UM Reception Buffer */
727 RlcKwuSapCb *rlcKwSap; /* KWU SAP Information */
729 curSn = rbCb->m.umUl.vrUr;
730 vrUh = RLC_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl);
731 recBuf = rbCb->m.umUl.recBuf;
733 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR))
735 rlcStopTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
738 while (RLC_UM_GET_VALUE(curSn,rbCb->m.umUl) < vrUh)
740 if ( recBuf[curSn] != NULLP )
743 rlcUmmReAssembleSdus(gCb,rbCb,recBuf[curSn]);
745 RLC_FREE(gCb,recBuf[curSn],sizeof(RlcUmRecBuf));
746 recBuf[curSn] = NULLP;
748 curSn = (curSn + 1) & rbCb->m.umUl.modBitMask;
750 rbCb->m.umUl.vrUr = 0;
751 rbCb->m.umUl.vrUh = 0;
752 rbCb->m.umUl.vrUx = 0;
754 rlcKwSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
756 /* In the UM Mode always send reestablish-indication to Upper Latyer*/
757 RlcUiKwuReEstCmpInd(&rlcKwSap->pst, rlcKwSap->suId, *rlcId);
763 * @brief Handler to extract the header from a PDU
766 * This function is used to extract the header of a PDU and store it
767 * along with the PDU buffer.The sequence number,framing info
768 * and LIs are extracted by this function.
770 * @param[in] gCb RLC Instance control block
771 * @param[in] rbCb Rb Control block for which the pdu is received
772 * @param[in] pdu PDU buffer
773 * @param[out] umHdr UM header to be filled after extraction
779 static uint8_t rlcUmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr)
781 uint8_t e; /* Extension Bit */
782 Data dst[2]; /* Destination Buffer */
783 int32_t totalSz; /* Sum of LIs */
784 MsgLen pduSz; /* PDU size */
785 #if (ERRCLASS & ERRCLS_DEBUG)
786 uint8_t ret; /* Return Value */
789 ODU_GET_MSG_LEN(pdu,&pduSz);
791 if ( rbCb->m.umUl.snLen == 1)
793 #if (ERRCLASS & ERRCLS_DEBUG)
794 ret = ODU_REM_PRE_MSG(dst,pdu);
797 DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for 5 bit SN \
798 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
802 ODU_REM_PRE_MSG(dst,pdu);
805 umHdr->sn = (dst[0]) & 0x1F;
806 umHdr->fi = (dst[0]) >> 6;
807 e = (dst[0]>>5) & 0x01;
811 /* snLen - sequnce length will be 10 bits requiring 2 bytes */
812 #if (ERRCLASS & ERRCLS_DEBUG)
813 ret = ODU_REM_PRE_MSG_MULT(dst,2,pdu);
816 DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG_MULT Failed for 10 bits SN \
817 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
821 ODU_REM_PRE_MSG_MULT(dst,2,pdu);
825 /* kw005.201 R9 Upgrade 3gpp spec 36.322 ver9.3.0 CR0082 *
826 * Removed the "if" condition for checking the reserved field *
827 * Added mask 0x03 for extracting the FI field. */
829 umHdr->fi = ( (dst[0] ) >> 3) & 0x03;
830 e = ( (dst[0] ) >> 2) & 0x01;
831 umHdr->sn = ( dst[0] & 0x03) << 8;
838 while(e && umHdr->numLi < RLC_MAX_UL_LI )
840 #if (ERRCLASS & ERRCLS_DEBUG)
841 ret = ODU_REM_PRE_MSG_MULT(dst,2,pdu);
844 DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG_MULT Failed UEID:%d CELLID:%d",\
845 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
849 ODU_REM_PRE_MSG_MULT(dst,2,pdu);
851 umHdr->li[umHdr->numLi] = ((dst[0]) & 0x7F) << 4;
852 umHdr->li[umHdr->numLi] |= dst[1] >> 4;
853 if ( 0 == umHdr->li[umHdr->numLi] )
855 DU_LOG("\nRLC : rlcUmmExtractHdr : Received LI as 0 UEID:%d CELLID:%d",
856 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
859 totalSz += umHdr->li[umHdr->numLi];
860 if ( pduSz <= totalSz )
862 DU_LOG("\nRLC : rlcUmmExtractHdr : SN [%d]: UEID:%d CELLID:%d",\
863 umHdr->sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
864 DU_LOG("\nRLC : rlcUmmExtractHdr : Corrupted PDU as TotSz[%d] PduSz[%d] \
865 UEID:%d CELLID:%d ", totalSz, pduSz, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
866 return RFAILED; /* the situation where in the PDU size
867 is something that does not match with
873 e = ((dst[0]) & 0x80) >> 7;
875 if ( e && umHdr->numLi < RLC_MAX_UL_LI)
877 uint8_t tmp = ((dst[1]) & 0x08) >> 3;
878 umHdr->li[umHdr->numLi] = ( dst[1] & 0x07) << 8;
881 #if (ERRCLASS & ERRCLS_DEBUG)
882 ret = ODU_REM_PRE_MSG(dst,pdu);
885 DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed UEID:%d CELLID:%d",
886 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
890 ODU_REM_PRE_MSG(dst,pdu);
892 umHdr->li[umHdr->numLi] |= ( dst[0] ); /* The first byte lies in
893 the first 8 bits.We want
894 them in the last 8 bits */
895 if ( 0 == umHdr->li[umHdr->numLi] )
897 DU_LOG("\nRLC : rlcUmmExtractHdr :Received LI as 0 UEID:%d CELLID:%d",
898 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
901 totalSz += umHdr->li[umHdr->numLi];
907 return RFAILED; /* the situation where in the PDU size is
908 something that does not match with the
914 } /* while(e && umHdr->numLi < RLC_MAX_LI ) */
917 /* PDU was constructed with LIs that exceeded RLC_MAX_LI */
924 * @brief Handles expiry of re-ordering timer
926 * @param[in] gCb RLC Instance control block
927 * @param[in] rbCb Rb Control block for which re-order timer expired
931 Void rlcUmmReOrdTmrExp
937 RlcSn prevVrUr; /* prevVrUr */
938 prevVrUr = RLC_UMUL.vrUr;
940 /* set VR(UR) to SN >= VR(UX) that has not been received */
941 rlcUmmFindNextVRUR(&RLC_UMUL, RLC_UMUL.vrUx);
943 while (RLC_UM_GET_VALUE(prevVrUr,RLC_UMUL) <
944 RLC_UM_GET_VALUE(RLC_UMUL.vrUr,RLC_UMUL))
946 if (RLC_UMUL.recBuf[prevVrUr])
949 rlcUmmReAssembleSdus(gCb, rbCb, RLC_UMUL.recBuf[prevVrUr]);
951 if(RLC_UMUL.recBuf[prevVrUr]->pdu != NULLP) /* RLC mem leak fix */
953 ODU_PUT_MSG_BUF(RLC_UMUL.recBuf[prevVrUr]->pdu);
955 RLC_FREE(gCb, RLC_UMUL.recBuf[prevVrUr], sizeof(RlcUmRecBuf));
956 RLC_UMUL.recBuf[prevVrUr] = NULLP;
959 prevVrUr = (prevVrUr + 1) & rbCb->m.umUl.modBitMask;
962 if (RLC_UM_GET_VALUE(RLC_UMUL.vrUh, RLC_UMUL) >
963 RLC_UM_GET_VALUE(RLC_UMUL.vrUr, RLC_UMUL))
965 rlcStartTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
966 RLC_UMUL.vrUx = RLC_UMUL.vrUh;
972 * Function to release/free the UnAcknowledged Mode Module RbCb buffers
975 * This primitive Frees the UM RbCb transmission Buffer, retransmission
976 * Buffer and reciption Buffers
978 * @param [in] gCb - RLC instance Control Block
979 * @param [in] rbCb - RB Control Block
984 Void rlcUmmFreeUlRbCb
990 RlcSn curSn = 0; /* sequence number of PDU */
991 RlcSn windSz; /* PDU window size */
992 RlcUmRecBuf **umRecBuf; /* UM module receive buffer */
994 windSz = rbCb->m.umUl.umWinSz << 1;
996 umRecBuf = rbCb->m.umUl.recBuf;
998 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR))
1000 rlcStopTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
1002 while (curSn < windSz)
1004 if (umRecBuf[curSn] != NULLP)
1006 ODU_PUT_MSG_BUF(umRecBuf[curSn]->pdu);
1007 umRecBuf[curSn]->pdu = NULLP;
1009 RLC_FREE(gCb, umRecBuf[curSn], sizeof(RlcUmRecBuf));
1010 umRecBuf[curSn] = NULLP;
1014 RLC_FREE(gCb,rbCb->m.umUl.recBuf, (windSz ) * sizeof(RlcUmRecBuf*));
1015 rbCb->m.umUl.recBuf = NULLP;
1020 /********************************************************************30**
1022 **********************************************************************/