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 /********************************************************************20**
21 Name: RLC - AM module file
25 Desc: Source code for Acknowledged Mode Module functions such as,
27 Transmission of data/control PDUs
28 Retransmission (Feedback in terms of status)
31 Reception - reordering
32 Duplicate detection for byte segments
37 *********************************************************************21*/
39 /* header include files (.h) */
40 #include "common_def.h"
41 #include "lkw.h" /* LKW defines */
42 #include "ckw.h" /* CKW defines */
43 #include "kwu.h" /* KWU defines */
44 #include "rgu.h" /* RGU defines */
45 #include "rlc_err.h" /* Err defines */
46 #include "rlc_env.h" /* RLC environment options */
48 /* extern (.x) include files */
49 #include "lkw.x" /* LKW */
50 #include "ckw.x" /* CKW */
51 #include "kwu.x" /* KWU */
52 #include "rgu.x" /* RGU */
54 #include "rlc_utils.h" /* RLC defines */
55 #include "rlc_dl_ul_inf.h"
57 /* Variable for logging, declared in cl */
58 #ifndef RGL_SPECIFIC_CHANGES
65 #ifndef RGL_SPECIFIC_CHANGES
67 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
69 uint32_t isMemThreshReached(Region region);
73 uint32_t isMemThreshReached(Region region);
79 @brief RLC Acknowledged Mode Uplink Module
81 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_UL) /* for debugging purpose */
83 /* private function declarations */
85 static void rlcAmmUlAssembleCntrlInfo ARGS ((RlcCb *gCb, RlcUlRbCb *rbCb));
87 static uint8_t rlcAmmExtractHdr ARGS ((RlcCb *gCb,
93 static bool rlcAmmUlPlacePduInRecBuf ARGS ((RlcCb *gCb,
98 static void rlcAmmTriggerStatus ARGS ((RlcCb *gCb,
103 static uint8_t rlcAmmUlReassembleSdus ARGS ((RlcCb *gCb,
105 RlcAmRecBuf *recBuf));
107 static Void rlcAmmProcPduOrSeg ARGS ((RlcCb *gCb,
112 static Void rlcAmmUpdExpByteSeg ARGS ((RlcCb *gCb,RlcAmUl *amUl, RlcSeg* newSeg));
114 static Void rlcAmmExtractElmnt ARGS ((RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo));
116 static Void rlcAmmUlHndlStatusPdu ARGS ((RlcCb *gCb,
121 /******************************************************************************
123 AM Module contains the following funcitons:
126 - rlcAmmUlAssembleCntrlInfo
131 - rlcAmmUlHndlStatusPdu
132 - rlcAmmTriggerStatus
133 - rlcAmmUlReassembleSdus
135 *******************************************************************************/
136 /** @addtogroup ammode */
140 * @brief Private function to fill NACK information in status Pdu as per 5GNR
142 * @param[in] rbCb Ul RbCb
143 * @param[in] sn Sequence number of the PDU for which the NACK
144 * @param[in] isSegment TRUE means NACK for segment; FALSE for PDU
145 * @param[in] soStart SOStart
146 * @param[in] soEnd SOEnd
147 * @param[out] statusPdu status Pdu holder to be filled
148 * @param[in] prevNackSn It holds previous nack Sn
151 * The number of bytes required to encode this NACK information
154 static uint8_t rlcAmmUlSetNackInfo(RlcUlRbCb *rbCb, RlcSn sn, bool isSegment, \
155 uint16_t soStart, uint16_t soEnd, RlcUdxDlStaPdu *statusPdu, RlcSn *prevNackSn)
157 RlcNackInfo *nackInfo = (statusPdu->nackInfo + statusPdu->nackCount);
158 uint16_t sizeToBeEncd = 0; /* Status PDu size to be encoded */
160 /* In following cases we should increment the nackCnt & fill new NACK_SN info:
161 * 1) First NACK_SN of the statusdPdu
162 * 2) NACK_SN is not continuous with previous
163 * 3) NACK_SN is same as previuos but segments are not continuous
164 * 4) NACK_SN is continuous with previous but previous NACK_SN segments
165 * are not missing in sequence till end
167 if((*prevNackSn == 0xffffffff) || ((((*prevNackSn) + 1) & RLC_AMUL.snModMask) != sn) ||
168 (((*prevNackSn) == sn) && (((nackInfo->soEnd + 1) != soStart))) ||
169 ((nackInfo->isSegment) && (((*prevNackSn) + 1) == sn) && (nackInfo->soEnd != RLC_ALL_BYTES_MISSING)))
171 if(nackInfo->nackRange)
173 if((nackInfo->soEnd) && (!nackInfo->soStart))
175 /*First nack_sn of this nackRange not segmented but last is segmented */
176 sizeToBeEncd = 5; /*32 for soStart and soEnd and 8 for nackRange */
180 /*First nack_sn of this nackRange was segmented */
181 sizeToBeEncd = 1; /*8 for nackRange */
185 if(*prevNackSn != 0xffffffff)
187 /* Increment nackCount as this sn is continous */
188 statusPdu->nackCount++;
189 nackInfo = statusPdu->nackInfo + statusPdu->nackCount;
193 nackInfo->isSegment = isSegment;
194 nackInfo->soStart = soStart;
195 nackInfo->soEnd = soEnd;
196 nackInfo->nackRange = 0;
200 sizeToBeEncd += ((RLC_AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?6:7); /* NACK,E1,E2,Sostart,SoEnd */
204 sizeToBeEncd += ((RLC_AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?2:3); /* NACK,E1,E2 */
209 if(!(nackInfo->nackRange))
211 nackInfo->nackRange++;
213 /* This case means there are continuous SNs/Segments. If it is the next
214 * Sn then increment nackRnage. if same SN but different segment then
215 * dont increment nackRange */
216 if((((*prevNackSn) + 1) & RLC_AMUL.snModMask) == sn)
218 nackInfo->nackRange++;
221 /* If NackRange is reached to max value then increment statusPdu->nackCount*/
222 if(nackInfo->nackRange == 255)
224 statusPdu->nackCount++;
225 if(nackInfo->isSegment)
227 sizeToBeEncd = 1; /* return only nackRangeSize*/
231 /* First SN was not segmented of this nackRange but last SN is segmented */
232 sizeToBeEncd = 5; /* return size of soSatrt + soEnd + nackRnage */
238 nackInfo->isSegment = isSegment;
239 nackInfo->soEnd = soEnd;
241 else if(nackInfo->isSegment)
243 nackInfo->soEnd = RLC_ALL_BYTES_MISSING;
247 nackInfo->soStart = 0;
254 return (sizeToBeEncd);
258 * @brief Private handler to gather information required to create the STATUS
262 * Scans the reception buffer and copies information to the UdxDlStaPdu
263 * structure about SN's and segments not yet received. This data is
264 * sent to the DL instance so that it can create an appropriate (depending
265 * on the grants from MAC) STATUS PDU and send it to MAC.
267 * @param[in] gCb RLC instance control block
268 * @param[in] rbCb Uplink RB control block
273 static void rlcAmmUlAssembleCntrlInfo(RlcCb *gCb, RlcUlRbCb *rbCb)
275 RlcUdxDlStaPdu *pStatusPdu;
276 RlcNackInfo *nackInfo;
277 RlcSn sn; /* sequence number */
278 RlcSn mSn; /* Mod val of sequence number */
279 RlcSn rxHighestStatus; /* Mod val of rxHighestStatus */
280 RlcSeg *seg; /* pdu segment */
281 uint16_t nackCnt = 0; /* Index for staPdu */
282 uint16_t seqSo; /* segmment offset */
283 RlcUdxUlSapCb *sapCb;
284 uint16_t staPduEncSize = 3; /* size that would be of the encoded
285 STATUS PDU, it is in bits; 15 for
286 first fixed part of STATUS PDU */
287 RlcAmRecBuf *recBuf = NULLP;
288 RlcSn prevNackSn = 0xffffffff;
290 sapCb = RLC_GET_UDX_SAP(gCb);
292 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
295 sizeof(RlcUdxDlStaPdu));
297 #if (ERRCLASS & ERRCLS_ADD_RES)
298 /* Memory allocation failure can not be expected */
305 sn = RLC_AMUL.rxNext;
306 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
307 MODAMR(RLC_AMUL.rxHighestStatus, rxHighestStatus, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
309 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
311 while (mSn < rxHighestStatus )
313 /* For missing PDUs */
314 if ((NULLP == recBuf) && nackCnt < RLC_MAX_NACK_CNT )
316 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing PDU's SN = %d UEID:%d \
317 CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
318 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
320 FALSE, /* isSegment */
326 else if (recBuf && (recBuf->pdu == NULLP) &&
327 (recBuf->segLst.count > 0))
329 /* Scan through the byte segments of PDU and add this sn
330 with soStart and soEnd info to staPdu */
333 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
334 while (seg != NULLP && nackCnt < RLC_MAX_NACK_CNT)
336 /* For missing byte segments */
337 if (seg->amHdr.so != seqSo)
339 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
347 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing byte segment's"
348 " SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
349 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d \
350 UEID:%d CELLID:%d", seqSo, seg->amHdr.so - 1, rbCb->rlcId.ueId,
354 seqSo = seg->soEnd + 1;
355 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
358 /* Check if the last segment is missing */
359 RLC_LLIST_LAST_SEG(recBuf->segLst, seg);
360 if ((seg != NULLP) &&
361 (seg->amHdr.si != RLC_SI_LAST_SEG && nackCnt < RLC_MAX_NACK_CNT))
363 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
367 RLC_ALL_BYTES_MISSING,
371 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing (last) byte "
372 "segment's SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId,
374 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d\
375 UEID:%d CELLID:%d", seqSo, RLC_ALL_BYTES_MISSING, rbCb->rlcId.ueId,
381 sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
382 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
384 /* Get the received Buffer the updated/next SN */
385 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
387 /* Find the next missing sequence number if nackCnt reaches maximum and
388 still Reordering window has some missing AMDPDUs / AMDPDU segments. The
389 next missing sequence number will be considered as the ack sequnece
390 number in the status pdu.*/
391 if((nackCnt == RLC_MAX_NACK_CNT) &&
392 ((recBuf == NULLP) ||
393 ((recBuf->pdu == NULLP) &&
394 (recBuf->segLst.count > 0))))
400 /*Unfortunately i have write below peice of code here because kwAmmsetNackInfo()
401 * don't know that this is the last nackSn with nackRange*/
402 nackInfo = &(pStatusPdu->nackInfo[pStatusPdu->nackCount]);
403 if(nackInfo->nackRange)
405 if((nackInfo->soEnd) && (!nackInfo->soStart))
407 /*First nack_sn of this nackRange not segmented but last is segmented */
408 staPduEncSize += 5; /*32 for soStart and soEnd and 8 for nackRange */
412 /*First nack_sn of this nackRange was segmented */
413 staPduEncSize += 1; /*8 for nackRange */
416 /* nackCount is used as an index to nackInfo array but in status Pdu it
417 * should be equal to number nackInfo that are filled. hence incrementing by 1*/
418 if(prevNackSn != 0xffffffff)
420 pStatusPdu->nackCount++;
422 /* Update ACK SN with the last sn for which feedback is not assembled */
423 if ( mSn == rxHighestStatus)
425 pStatusPdu->ackSn = RLC_AMUL.rxHighestStatus;
429 pStatusPdu->ackSn = sn;
432 DU_LOG("\nINFO --> RLC_UL : rlcAmmUlAssembleCntrlInfo: ACK PDU's SN = %d"
433 "UEID:%d CELLID:%d", pStatusPdu->ackSn, rbCb->rlcId.ueId,
436 pStatusPdu->controlBo = staPduEncSize; /*Its already in bytes */
438 RLC_AMUL.staTrg = FALSE;
439 RLC_AMUL.gatherStaPduInfo = FALSE;
442 if (rlcUlUdxStaPduReq(&sapCb->pst,
447 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Failed to Send Sta Pdu UEID:%d \
448 CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
449 RLC_FREE_SHRABL_BUF_WC(sapCb->pst.region,
452 sizeof(RlcUdxDlStaPdu));
458 #ifdef XEON_SPECIFIC_CHANGES
459 uint32_t gRlcDatIndUL;
462 #ifdef T2K_TRIGGER_RLC_REEST
463 uint32_t drpRlcDrbPack;
466 * @brief Handler to process the PDUs received from MAC and send it to PDCP
469 * This function is invoked by UTL with the PDU(s) received from MAC.
470 * It reorders the received data PDUs and trigger status report as
471 * needed. Reassembles the SDUs in sequence and send it to PDCP.
472 * It also processes the control PDU
474 * @param[in] gCb RLC instance control block
475 * @param[in] rbCb RB control block
476 * @param[out] pduInfo PDU Info received from MAC
482 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
484 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
491 uint8_t numPduToProcess;
497 RlcTptPerSnssai *snssaiTputNode = NULLP;
498 MsgLen pduSz = 0; /*Holds length of Rlc Sdu*/
502 numPduToProcess = RLC_MIN(pduInfo->numPdu, RGU_MAX_PDU);
503 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: numPdu[%d],numPduToProcess[%d] UEID:%d CELLID:%d",
504 numPdu, numPduToProcess, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
506 while (numPdu < numPduToProcess)
509 pdu = pduInfo->mBuf[numPdu++];
510 snssaiTputNode = NULLP;
514 DU_LOG("\nERROR --> RLC_UL : rlcAmmProcessPdus: Null Pdu UEID:%d CELLID:%d",
515 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
516 gCb->genSts.errorPdusRecv++;
519 #ifndef RGL_SPECIFIC_CHANGES
523 ODU_GET_MSG_LEN(pdu, &len);
528 /* Extract AM PDU/SEG header Info */
529 RLC_MEM_ZERO(&amHdr, sizeof(RlcAmHdr));
530 /* Avoided the allocation of amHdr and sending
532 if (rlcAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
534 DU_LOG("\nERROR --> RLC_UL : rlcAmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",
535 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
536 ODU_PUT_MSG_BUF(pdu);
537 gCb->genSts.errorPdusRecv++;
540 /* Check if its a control PDU */
543 rlcAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
544 ODU_PUT_MSG_BUF(pdu);
547 if((amHdr.si == RLC_SI_LAST_SEG) && (!amHdr.so))
549 DU_LOG("\nERROR --> RLC_UL : rlcAmmProcessPdus: Dropping PDU because SO can't be zero\
550 for last segment sn:%u UEID:%d CELLID:%d", amHdr.sn, rbCb->rlcId.ueId,
552 ODU_PUT_MSG_BUF(pdu);
555 #ifndef RGL_SPECIFIC_CHANGES
558 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
560 /* Changed the condition to TRUE from ROK */
561 if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
565 ODU_PUT_MSG_BUF(pdu);
571 /*ccpu00142274 - UL memory based flow control*/
572 if(isMemThreshReached(rlcCb[0]->init.region) != ROK)
576 ODU_PUT_MSG_BUF(pdu);
585 #ifdef T2K_TRIGGER_RLC_REEST
586 if(drpRlcDrbPack > 1000)
588 if(rbCb->rlcId.rbType == CM_LTE_DRB)
590 ODU_PUT_MSG_BUF(pdu);
596 /* Reordering data PDU */
598 if (rlcAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
603 RlcSn mrxNextHighestRcvd;
606 rlcUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
607 #endif /* LTE_L2_MEAS */
611 snssaiTputNode = rlcHandleSnssaiTputlist(gCb, rbCb->snssai, SEARCH, DIR_UL);
612 if(snssaiTputNode != NULLP)
614 ODU_GET_MSG_LEN(pdu, &pduSz);
615 snssaiTputNode->dataVol += (uint64_t)pduSz;
616 DU_LOG("\nINFO --> RLC_UL: SNSSAI AMM_UL List PduLen:%d, lcId:%d, total :%ld",\
617 pduSz, rbCb->lch.lChId, snssaiTputNode->dataVol);
620 /* Update rxNextHighestRcvd */
621 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
622 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
623 if (mSn >= mrxNextHighestRcvd)
625 amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask));
627 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
628 amUl->rxNextHighestRcvd, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
631 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
632 if ((NULLP != recBuf) && ( recBuf->allRcvd))
634 /* deliver the reassembled RLC SDU to upper layer,
635 But not removed from the table */
636 rlcAmmUlReassembleSdus(gCb, rbCb, recBuf);
637 recBuf->isDelvUpperLayer = TRUE;
639 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
641 /* Update rxHighestStatus */
642 if (sn == amUl->rxHighestStatus)
644 tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
646 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
647 /* Scan through till the upper edge of the window */
648 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
651 if ((NULLP == recBuf) || (!recBuf->allRcvd))
653 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: Updated rxHighestStatus:%d "
659 amUl->rxHighestStatus = tSn;
662 tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
663 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
670 if (sn == amUl->rxNext)
673 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
674 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
675 /* Scan through till the upper edge of the window */
678 if ((NULLP != recBuf) && (recBuf->allRcvd) &&
679 (TRUE == recBuf->isDelvUpperLayer))
681 /* RecBuf should remove from table
682 since PDU is already sent to upper layer */
683 recBuf->isDelvUpperLayer = FALSE;
684 rlcUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
689 amUl->vrMr = (amUl->rxNext + (RLC_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
692 tSn = (tSn + 1) & (amUl->snModMask);
693 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
699 /* Check if reAsmblTmr is running and update rxNextStatusTrig accordingly */
700 tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
703 Bool snInWin = RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
704 /* spec 38.322v15.3.0 - 5.2.3.2.3 */
705 if((amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
706 (amUl->rxNextStatusTrig != amUl->vrMr) )||
707 (amUl->rxNextStatusTrig == amUl->rxNext && recBuf &&recBuf->noMissingSeg))
709 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
711 DU_LOG("\nINFO --> RLC_UL: rlcAmmProcessPdus: Stopped ReAssembly Timer rxNextStatusTigger = %d"
712 "rxNextReassembly = %d", amUl->rxNextStatusTrig, amUl->rxNext);
718 /* spec 38.322v15.3.0 - 5.2.3.2.3 */
719 if((amUl->rxNextHighestRcvd > amUl->rxNext) || ((amUl->rxNextHighestRcvd == amUl->rxNext) &&
720 (recBuf && (!recBuf->noMissingSeg))))
722 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
723 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
725 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: Updated rxNextStatusTrig = %d"
726 "UEID:%d CELLID:%d", amUl->rxNextStatusTrig, rbCb->rlcId.ueId,
734 gRlcStats.amRlcStats.numULPdusDiscarded++;
739 rlcAmmTriggerStatus(gCb,rbCb, sn, discFlg);
744 rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
745 #endif /* LTE_L2_MEAS */
746 gCb->genSts.pdusRecv += pduInfo->numPdu;
747 if (amUl->gatherStaPduInfo)
749 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
757 * @brief Private handler to extract header Information of the PDU
760 * This function extracts the header elements of the PDU and store them
761 * in db for future reference.
763 * fByte - is the first byte removed from the PDU as part of calling
766 * @param[in] gCb RLC instance control block
767 * @param[in] rbCb Uplink RB control block
768 * @param[in] pdu Received PDU
769 * @param[out] amHdr Pointer to the extracted AM header
770 * @param[out] fByte First byte removed from the PDU
777 static uint8_t rlcAmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcAmHdr *amHdr, uint8_t *fByte)
784 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
786 /* Extract fixed part of the header */
787 ODU_GET_MSG_LEN(pdu,&pduSz);
788 ODU_REM_PRE_MSG(fByte, pdu);
789 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
790 if (RLC_CNTRL_PDU == amHdr->dc)
792 //DU_LOG ("\nINFO --> RLC_UL : ++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
796 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
798 amHdr->si = (*fByte & RLC_SI_POS) >> RLC_SI_SHT;
801 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
803 ODU_REM_PRE_MSG(&snByte, pdu);
804 sn = (RlcSn)(((*fByte & RLC_SN_POS_12BIT) << RLC_BYTE_LEN ) | snByte);
807 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
809 ODU_REM_PRE_MSG(&snByte, pdu);
810 sn = (RlcSn)(((*fByte & RLC_SN_POS_18BIT) << RLC_BYTE_LEN ) | snByte);
812 ODU_REM_PRE_MSG(&snByte, pdu);
813 sn = ((sn << RLC_BYTE_LEN) | snByte);
817 if ((amHdr->si != 0) && (amHdr->si != RLC_SI_FIRST_SEG))
819 hdrInfo.len = RLC_SO_LEN_5GNR;
820 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
821 amHdr->so = hdrInfo.val;
830 * @brief Private handler to extract header Information of the PDU
833 * This function extracts the header elements of the PDU and store them
834 * in db for future reference.
836 * fByte - is the first byte removed from the PDU as part of calling
839 * @param[in] gCb RLC instance control block
840 * @param[in] rbCb Uplink RB control block
841 * @param[in] pdu Received PDU
842 * @param[out] amHdr Pointer to the extracted AM header
843 * @param[out] fByte First byte removed from the PDU
850 static S16 rlcAmmExtractHdrOld(RlcCb *gCb,Buffer *pdu,RlcAmHdr *amHdr,uint8_t *fByte)
859 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
861 /* Extract fixed part of the header */
862 SFndLenMsg(pdu,&pduSz);
863 SRemPreMsg(fByte, pdu);
864 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
865 if (RLC_CNTRL_PDU == amHdr->dc)
869 /* kw002.201 : Changed the extraction of hdr elements to avoid */
871 amHdr->rf = (*fByte & RLC_RF_POS) >> RLC_RF_SHT;
872 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
873 amHdr->fi = (*fByte & RLC_FI_POS) >> RLC_FI_SHT;
874 e = amHdr->e = (*fByte & RLC_E_POS)>> RLC_E_SHT;
876 SRemPreMsg(&snByte, pdu);
877 sn = (uint16_t)(((*fByte & RLC_SN_POS) << RLC_BYTE_LEN ) | snByte);
881 /* Extract extn part of the header */
882 hdrInfo.len = RLC_LSF_LEN;
883 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
884 amHdr->lsf = (uint8_t)hdrInfo.val;
886 hdrInfo.len = RLC_SO_LEN;
887 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
888 amHdr->so = hdrInfo.val;
894 while (e && (amHdr->numLi < RLC_MAX_UL_LI))
896 hdrInfo.len = RLC_E_LEN;
897 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
898 e = amHdr->e = (uint8_t)hdrInfo.val;
900 /* Extract LI value*/
901 hdrInfo.len = RLC_LI_LEN;
902 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
903 /* li = hdrInfo.val;*/
905 /* check if LI is zero */
908 DU_LOG("\nERROR --> RLC_UL : Received LI as 0");
912 /* store the extracted LI value */
913 amHdr->li[amHdr->numLi++] = hdrInfo.val;
914 totalSz += hdrInfo.val; /* incrment the size by LI value */
917 /*ccpu00122597:PDU is dropped if liCnt exceeds RLC_MAX_LI*/
918 if(e && (amHdr->numLi >= RLC_MAX_UL_LI))
920 DU_LOG("\nERROR --> RLC_UL : LI Count [%u] exceeds Max LI Count[%u]",
921 amHdr->numLi, RLC_MAX_UL_LI);
925 /* first 2 bytes + Add one for Odd LI*/
926 pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
928 if ( totalSz >= pduSz )
930 DU_LOG("\nERROR --> RLC_UL : SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
931 amHdr->sn, totalSz, pduSz);
940 * @brief Private handler to process the status PDU
943 * Private handler invokded by rlcAmmProcessPdus to process the
944 * control PDU (status report) received from its peer RLC entity.
946 * - Decode the values from the received control pdu
947 * - Create a RlcUdxStaPdu structure, copy the values onto it and
948 * send it to the DL instance for further processing
950 * @param[in] gCb RLC instance control block
951 * @param[in] rbCb Uplink RB control block
952 * @param[in] cntrlPdu Control PDU received from MAC
953 * @param[in] fByte First byte already removed from the STATUS PDU
958 static void rlcAmmUlHndlStatusPdu(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *cntrlPdu, uint8_t *fByte)
962 RlcUdxStaPdu *pStaPdu;
963 RlcUdxUlSapCb *sapCb;
964 uint8_t e3; /* NACK RANGE : 5GNR */
967 uint32_t resrvdBitsAckSn=0;
968 uint32_t resrvdBitsNackSn=0;
970 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
972 /* Extract the Control PDU */
973 hdrInfo.hdr = (*fByte << 1);
976 /* D/C has been shifted in the calling function */
977 if (hdrInfo.hdr & 0xE0)
979 DU_LOG("\nINFO --> RLC_UL : rlcAmmUlHndlStatusPdu: Reserved value for CPT received UEID:%d \
980 CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
984 sapCb = RLC_GET_UDX_SAP(gCb);
986 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
989 sizeof(RlcUdxStaPdu));
991 #if (ERRCLASS & ERRCLS_ADD_RES)
992 /* Memory allocation failure can not be expected */
999 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1002 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
1003 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
1005 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
1008 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
1009 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
1014 resrvdBitsAckSn = 0;
1015 resrvdBitsAckSn = 0;
1018 pStaPdu->nackCnt = 0;
1020 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
1023 hdrInfo.len = snLen;
1024 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1025 pStaPdu->ackSn = hdrInfo.val;
1027 //DU_LOG ("\nINFO --> RLC_UL : ++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n", pStaPdu->ackSn);
1028 /* Check if NACK Exists */
1029 hdrInfo.len = RLC_E1_LEN;
1030 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1031 e1 = (uint8_t)hdrInfo.val;
1032 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1033 pStaPdu->ackSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1035 /* Extract the Reserved Bits after ACK SN field */
1036 hdrInfo.len = resrvdBitsAckSn;
1037 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1039 /* If NACK exists in control PDU */
1040 /* For ACKs and NACKs */
1041 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
1043 hdrInfo.len = snLen;
1044 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1045 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1047 hdrInfo.len = RLC_E1_LEN;
1048 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1049 e1 = (uint8_t)hdrInfo.val;
1052 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1054 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1055 /* e2 = (uint8_t) hdrInfo.val;*/
1057 /* Store e2 value */
1058 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
1060 /* Extract e3 : 5GNR */
1061 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1063 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1064 e3 = (uint8_t) hdrInfo.val;
1066 /* Extract Reserved Bits after NACK SN */
1067 hdrInfo.len = resrvdBitsNackSn;
1068 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1070 /* Test for resegmentation */
1071 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1073 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1074 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1075 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1077 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1078 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
1080 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1081 "UEID:%d CELLID:%d", pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1082 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd, rbCb->rlcId.ueId,
1083 rbCb->rlcId.cellId);
1088 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1089 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
1092 /* NACK RANGE Field is SET */
1095 /* Extract NACK range field */
1096 hdrInfo.len = RLC_NACK_RANGE_LEN;
1097 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1098 snRange = (uint8_t)hdrInfo.val;
1100 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1106 gRlcStats.amRlcStats.numULStaPduRcvd++;
1107 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1109 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1110 to the last NACK SN + 1 and discard the original ACK_SN*/
1111 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
1113 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1117 /* Parse & send Status PDU to RLC-DL */
1118 rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1124 * @brief Private handler to release all stored segments
1127 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to release the
1128 * stored segements in case a complete PDU is received later.
1130 * @param[in] gCb RLC instance control block
1131 * @param[in] recBuf Buffer that stores a received PDU or segments
1136 static void rlcAmmUlRlsAllSegs(RlcCb *gCb, RlcAmRecBuf *recBuf)
1140 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1141 while (seg != NULLP)
1143 ODU_PUT_MSG_BUF(seg->seg);
1144 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1145 RLC_FREE(gCb,seg, sizeof(RlcSeg));
1146 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1153 * @brief Private handler to store the received segment
1156 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to add a received
1157 * segment in reception buffer of a RBCB.
1158 * - It is responsible for detecting duplicate segments
1159 * - Adding it at appropriate position in the received buffer
1160 * - Calling ExpByteSeg to set expSo field in the receiver buffer
1162 * @param[in] gCb RLC instance control block
1163 * @param[in] rbCb Radio Bearer Contro Block
1164 * @param[in] amHdr AM Header received
1165 * @param[in] pdu Buffer received other than the headers
1166 * @param[in] pduSz size of the PDU buffer received
1169 * -#TRUE Successful insertion into the receiver buffer
1170 * -#FALSE Possibly a duplicate segment
1172 static bool rlcAmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu, uint16_t pduSz)
1174 RlcAmRecBuf *recBuf = NULLP;
1177 uint16_t soEnd; /* Holds the SoEnd of received segment */
1178 uint16_t expSo = 0; /* Expected SO */
1180 soEnd = amHdr->so + pduSz - 1;
1181 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, amHdr->sn);
1183 if (NULLP == recBuf)
1185 RLC_ALLOC(gCb,recBuf, sizeof(RlcAmRecBuf));
1186 #if (ERRCLASS & ERRCLS_ADD_RES)
1187 if (recBuf == NULLP)
1189 DU_LOG("\nERROR --> RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1190 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1192 ODU_PUT_MSG_BUF(pdu);
1195 #endif /* ERRCLASS & ERRCLS_RES */
1196 rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, amHdr->sn);
1200 if (recBuf->allRcvd == TRUE)
1202 ODU_PUT_MSG_BUF(pdu);
1207 recBuf->isDelvUpperLayer = FALSE;
1208 /* kw003.201 - Move past the segments that are different than the */
1210 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1211 while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1213 expSo = seg->amHdr.so + seg->segSz;
1214 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1217 /* The received segment should start after the end of previous seg */
1218 if (expSo > amHdr->so)
1220 /* This is a duplicate segment */
1221 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1222 ODU_PUT_MSG_BUF(pdu);
1226 if ((seg) && (seg->amHdr.so <= soEnd))
1228 /* This is a duplicate segment */
1229 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1230 ODU_PUT_MSG_BUF(pdu);
1234 /* If we have come this far, we have to add this segment to the */
1235 /* reception buffer as we either have eliminated duplicates or */
1236 /* have found none. */
1237 RLC_ALLOC_WC(gCb,tseg, sizeof(RlcSeg));
1238 #if (ERRCLASS & ERRCLS_ADD_RES)
1241 DU_LOG("\nERROR --> RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1242 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1243 ODU_PUT_MSG_BUF(pdu);
1246 #endif /* ERRCLASS & ERRCLS_RES */
1249 tseg->segSz = pduSz;
1250 RLC_MEM_CPY(&tseg->amHdr, amHdr, sizeof(RlcAmHdr));
1251 recBuf->amHdr.si = amHdr->si;
1252 recBuf->amHdr.sn = amHdr->sn;
1253 tseg->soEnd = soEnd;
1256 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1260 recBuf->segLst.crnt = &seg->lstEnt;
1261 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1263 tseg->lstEnt.node = (PTR)tseg;
1264 rlcAmmUpdExpByteSeg(gCb,&RLC_AMUL,tseg);
1270 * @brief Private handler to place the PDU in the reception buffer
1273 * This function checks if the received PDU's SN falls within the
1274 * receiving window, after which it places the same in the reception
1275 * buffer if its not a duplicate.
1277 * @param[in] gCb RLC instance control block
1278 * @param[in] pdu Received PDU
1279 * @param[in] rbCb Uplink AM Radio Bearer
1280 * @param[out] amUl AM UL Info
1287 static bool rlcAmmUlPlacePduInRecBuf(RlcCb *gCb, Buffer *pdu, RlcUlRbCb *rbCb, RlcAmHdr *amHdr)
1291 RlcAmUl *amUl = &(rbCb->m.amUl);
1294 SFndLenMsg(pdu, &pduSz);
1296 gCb->genSts.bytesRecv += pduSz;
1297 gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz;
1298 if (!RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1300 gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1301 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlPlacePduInRecBuf: SN %d outside the window"
1302 "UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1304 gCb->genSts.unexpPdusRecv++;
1305 ODU_PUT_MSG_BUF(pdu);
1311 RlcAmRecBuf *recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1313 /* We received a complete PDU. Either we already have it, in which */
1314 /* case we just ignore the new PDU and discard it. Otherwise, */
1315 /* store the received PDU in the reception buffer */
1316 if (NULLP == recBuf)
1318 RLC_ALLOC(gCb, recBuf, sizeof(RlcAmRecBuf));
1319 #if (ERRCLASS & ERRCLS_ADD_RES)
1320 if (recBuf == NULLP)
1322 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlPlacePduInRecBuf: Memory allocation failed \
1323 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1324 ODU_PUT_MSG_BUF(pdu);
1327 #endif /* ERRCLASS & ERRCLS_RES */
1328 rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, sn);
1330 else if (recBuf->allRcvd != TRUE)
1332 rlcAmmUlRlsAllSegs(gCb,recBuf);
1336 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1337 gCb->genSts.unexpPdusRecv++;
1338 ODU_PUT_MSG_BUF(pdu);
1341 recBuf->isDelvUpperLayer = FALSE;
1343 recBuf->pduSz = pduSz;
1344 recBuf->allRcvd = TRUE;
1345 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1346 RLC_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(RlcAmHdr));
1351 /* We received a segment. We need to add that to the existing */
1352 /* segments, if any. */
1353 return (rlcAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1358 * @brief Private handler to trigger status report
1361 * Private handler invokded by rlcAmmProcessPdus to check if the
1362 * status report need to be sent, and update the status trigger
1363 * flag accordingly based on status prohibit timer.
1365 * - Check if the received pdu's sn is less than rxHighestStatus, set the
1367 * - If staProhTmr is not running, calculate cntrlBo, else it'll be
1368 * updated at the expiry of staProhTmr.
1369 * - Expiry of reAsmblTmr also will set staTrg flag.
1371 * @param[in] gCb RLC instance control block
1372 * @param[in] rbCb Uplink RB control block
1373 * @param[in] sn Sequence number of the pdu based on which to check if
1374 * status needs to be triggered
1375 * @param[in] discFlg Whether this pdu was discarded or not
1380 static void rlcAmmTriggerStatus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcSn sn, bool discFlg)
1385 RlcSn trxHighestStatus;
1386 RlcAmUl *amUl = &(rbCb->m.amUl);
1388 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1389 MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1390 MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1392 /* kw005.201 Product CR ccpu00117114 *
1393 * The "=" in the 2nd condition is removed */
1394 if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1396 DU_LOG("\nINFO --> RLC_UL : rlcAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1397 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1399 amUl->staTrg = TRUE;
1400 amUl->gatherStaPduInfo = FALSE;
1402 /* Check if staProhTmr is running */
1403 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1407 amUl->gatherStaPduInfo = TRUE;
1415 * @brief Private handler to reassemble from a segment or a PDU
1418 * Private handler invokded by kwAmmReassembleSdus with either a
1419 * PDU or a segment of a PDU. This is also called in the case of
1420 * reestablishment and hence out of sequence joining is also to
1424 * @param[in] gCb RLC instance control block
1425 * @param[in] rbCb Uplink RB control block
1426 * @param[in] amHdr AM header received for this segment/PDU
1427 * @param[in] pdu PDU to be reassembled
1432 static void rlcAmmProcPduOrSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu)
1435 if ((RLC_AMUL.expSn != amHdr->sn) || (RLC_AMUL.expSo != amHdr->so))
1437 /* Release the existing partial SDU as we have PDUs or */
1438 /* segments that are out of sequence */
1439 rbCb->m.amUl.isOutOfSeq = TRUE;
1440 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1443 if (amHdr->si == RLC_SI_FIRST_SEG)
1444 {/* first Segment of the SDU */
1445 if (RLC_AMUL.partialSdu != NULLP)
1446 { /* Some old SDU may be present */
1447 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1449 RLC_AMUL.partialSdu = pdu;
1452 else if(amHdr->si == RLC_SI_MID_SEG)
1453 {/* Middle or last segment of the SUD */
1454 ODU_CAT_MSG(RLC_AMUL.partialSdu,pdu, M1M2);
1455 ODU_PUT_MSG_BUF(pdu);
1458 else if (amHdr->si == RLC_SI_LAST_SEG)
1460 ODU_CAT_MSG(pdu,RLC_AMUL.partialSdu,M2M1);
1461 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1466 RLC_AMUL.partialSdu = NULLP;
1467 rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
1475 * @brief Private handler to reassemble SDUs
1478 * Private handler invokded by rlcAmmProcessPdus with the PDU
1479 * from the reception buffer in sequence to reassemble SDUs and
1482 * - With the stored header info, FI and LSF segment / concatenate
1483 * PDUs or byte segments of PDUs to get the associated SDU.
1485 * @param[in] rbCb RB control block
1486 * @param[in] pdu PDU to be reassembled
1493 static uint8_t rlcAmmUlReassembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmRecBuf *recBuf)
1497 //if (recBuf->amHdr.rf == 0)
1498 if (recBuf->amHdr.si == 0)
1501 rlcAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1502 /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1503 recBuf->pdu = NULLP;
1504 RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1509 /* This is a set of segments */
1510 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1511 RLC_AMUL.expSn = recBuf->amHdr.sn;
1515 rlcAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1516 RLC_AMUL.expSo = seg->soEnd + 1;
1518 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1519 RLC_FREE(gCb, seg, sizeof(RlcSeg));
1521 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1523 RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1531 * @brief Handler to process the re-establishment request received from UIM
1533 * @param[in] gCb RLC instance control block
1534 * @param[in] rlcId RLC identifier
1535 * @param[in] sendReEst Whether to send back restablishment complete or not
1536 * @param[in] rbCb Uplink RB control block
1541 Void rlcAmmUlReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcUlRbCb *rbCb)
1548 RlcKwuSapCb *rlcKwuSap;
1550 RlcAmRecBuf *recBuf = NULLP;
1552 sn = RLC_AMUL.rxNext;
1554 MODAMR(RLC_AMUL.vrMr, mVrMr, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1555 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1557 /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1560 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1561 if (NULLP != recBuf)
1563 if (recBuf->allRcvd == TRUE)
1565 rlcAmmUlReassembleSdus(gCb,rbCb, recBuf);
1569 /* Remove PDU and segments */
1572 ODU_PUT_MSG_BUF(recBuf->pdu);
1574 /* Release all the segments*/
1575 rlcAmmUlRlsAllSegs(gCb,recBuf);
1577 rlcUtlDelRecBuf(RLC_AMUL.recBufLst, recBuf, gCb);
1579 sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1580 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1582 /* Discard remaining PDUs and bytesegments in recBuf */
1584 /* Stop all timers and reset variables */
1585 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1587 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1589 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1591 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1594 RLC_AMUL.rxNext = 0;
1595 RLC_AMUL.rxNextHighestRcvd = 0;
1596 RLC_AMUL.rxNextStatusTrig = 0;
1597 rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1598 RLC_AMUL.rxHighestStatus = 0;
1599 RLC_AMUL.staTrg = FALSE;
1600 RLC_AMUL.gatherStaPduInfo = FALSE;
1603 if (RLC_AMUL.partialSdu != NULLP)
1605 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1607 rlcKwuSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
1611 RlcUiKwuReEstCmpInd(&rlcKwuSap->pst, rlcKwuSap->suId, rlcId);
1612 rbCb->m.amUl.isOutOfSeq = FALSE;
1619 * @brief Handler for reorder timer expiry
1622 * This function is used to handle events upon expiry of reorder timer
1624 * @param[in] gCb RLC instance control block
1625 * @param[in] rbCb RB control block
1631 Void rlcAmmReAsmblTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1633 RlcAmUl *amUl = &(rbCb->m.amUl);
1637 RlcSn mrxHighestStatus;
1638 RlcSn mrxNextHighestRcvd;
1639 Bool tmrRunning = FALSE;
1640 RlcAmRecBuf *recBuf = NULLP;
1642 /* Update rxHighestStatus */
1643 sn = amUl->rxNextStatusTrig;
1645 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1646 MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1647 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1651 if ((recBuf == NULLP) ||
1652 ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1654 amUl->rxHighestStatus = sn;
1655 amUl->staTrg = TRUE;
1656 amUl->gatherStaPduInfo = FALSE;
1658 /* Check if staProhTmr is running */
1659 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1663 gRlcStats.amRlcStats.numULReAsmblTimerExpires++;
1664 amUl->gatherStaPduInfo = TRUE;
1665 rlcAmmUlAssembleCntrlInfo(gCb, rbCb);
1670 sn = (sn + 1) & (amUl->snModMask);
1671 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1674 /* Update rxNextStatusTrig */
1675 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1676 MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1677 /* spec 38.322v15.3.0 - 5.2.3.2.4 */
1678 if((mrxNextHighestRcvd > mrxHighestStatus) || ((mrxNextHighestRcvd == mrxHighestStatus) &&
1679 ((recBuf) && !(recBuf->noMissingSeg))))
1681 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1682 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1686 } /* rlcAmmReAsmblTmrExp */
1689 * @brief Handler for status prohibit timer expiry
1692 * This function is used to handle events upon expiry of status prohibit
1695 * @param[in] gCb RLC instance control block
1696 * @param[in] rbCb RB control block
1702 Void rlcAmmStaProTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1704 RlcAmUl *amUl = &(rbCb->m.amUl);
1706 amUl->gatherStaPduInfo = FALSE;
1708 if (amUl->staTrg == TRUE)
1710 amUl->gatherStaPduInfo = TRUE;
1711 /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
1712 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
1716 } /* rlcAmmStaProTmrExp */
1719 * @brief Handler to extract an element of AM Header
1722 * This function is used to extract an element of AM header.
1724 * @param[in] pdu The pdu to be decoded
1725 * @param[in,out] hdrInfo Container to hold the decoded info
1731 static void rlcAmmExtractElmnt(RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo)
1734 uint8_t pLen = hdrInfo->pLen;
1735 uint8_t len = (uint8_t)hdrInfo->len;
1740 /* uint8_t rLen1 = 0; */
1747 ODU_REM_PRE_MSG(&hdr, pdu);
1753 val = tHdr >> (RLC_BYTE_LEN - (len));
1757 else /*if (len > 8) */
1761 val = val >> (RLC_BYTE_LEN - fLen);
1762 val = val << (len - fLen);
1764 ODU_REM_PRE_MSG(&hdr, pdu);
1768 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1771 pLen = (RLC_BYTE_LEN - rLen);
1775 rLen = rLen - RLC_BYTE_LEN;
1777 tVal = tVal << rLen;
1780 ODU_REM_PRE_MSG(&hdr, pdu);
1782 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1785 pLen = (RLC_BYTE_LEN - rLen);
1789 hdrInfo->pLen = pLen;
1797 * @brief Handler to updated expected byte seg
1800 * This function is used to update expected byte segment. The next segment
1801 * expected is indicated by the SO of the segment which is expected. Intially
1802 * the segment with SO 0 is expected and then in order. When all the segments
1803 * are received (which would happen when an expected SO is encountered
1804 * with LSF set) the allRcvd flag is set to TRUE
1806 * @param[in] gCb RLC instance control block
1807 * @param[in] amUl AM Uplink Control Block
1808 * @param[in] seg Newly received segment
1814 static void rlcAmmUpdExpByteSeg(RlcCb *gCb, RlcAmUl *amUl, RlcSeg *seg)
1816 uint16_t newExpSo; /* The new expected SO */
1817 RlcSn sn = seg->amHdr.sn;
1819 RlcAmRecBuf *recBuf = NULLP;
1821 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1822 if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
1826 recBuf->noMissingSeg = FALSE;
1827 newExpSo = seg->soEnd + 1;
1828 recBuf->expSo = newExpSo;
1829 if(seg->amHdr.si == RLC_SI_LAST_SEG)
1833 /* kw003.201 - This should update seg with the one after newSeg */
1834 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1837 /* keep going ahead as long as the expectedSo match with the header so
1838 else store the expSo for later checking again */
1839 if(seg->amHdr.si == RLC_SI_LAST_SEG)
1843 if (seg->amHdr.so == newExpSo)
1845 newExpSo = seg->soEnd + 1;
1846 recBuf->expSo = newExpSo;
1847 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1851 recBuf->expSo = newExpSo;
1855 if (lstRcvd == TRUE)
1857 recBuf->allRcvd = TRUE;
1858 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1860 recBuf->noMissingSeg = TRUE;
1866 * Function to release/free the Acknowledged Mode Module RbCb buffers
1869 * This primitive Frees the AM RbCb transmission Buffer, retransmission
1870 * Buffer and reciption Buffers
1872 * @param [in] gCb - RLC instance Control Block
1873 * @param [in] rbCb - RB Control Block
1877 Void rlcAmmFreeUlRbCb(RlcCb *gCb,RlcUlRbCb *rbCb)
1879 RlcSn curSn = 0; /* Sequence number of PDU */
1880 RlcSn windSz; /* PDU window size */
1881 RlcAmRecBuf *recBuf = NULLP;
1883 windSz = (RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
1885 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1887 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1889 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1891 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1894 RLC_FREE(gCb,rbCb->snssai, sizeof (Snssai));
1896 /* on the first loop winSz is always greater than zero
1897 while( ( curSn < windSz ) hence changing to do while */
1900 recBuf = rlcUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
1901 if ( recBuf != NULLP )
1903 if (recBuf->pdu != NULLP)
1905 ODU_PUT_MSG_BUF(recBuf->pdu);
1907 /* Release all the segments */
1908 rlcAmmUlRlsAllSegs(gCb,recBuf);
1909 rlcUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
1912 }while ( curSn < windSz );
1915 RLC_FREE(gCb,rbCb->m.amUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
1916 rbCb->m.amUl.recBufLst = NULLP;
1919 if(rbCb->m.amUl.partialSdu != NULLP)
1921 ODU_PUT_MSG_BUF(rbCb->m.amUl.partialSdu);
1924 } /* rlcAmmFreeUlRbCb */
1930 /********************************************************************30**
1933 **********************************************************************/