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 */
46 #include "kw_err.h" /* Err defines */
47 #include "kw_env.h" /* RLC environment options */
49 #include "kw.h" /* RLC defines */
52 /* extern (.x) include files */
53 #include "lkw.x" /* LKW */
54 #include "ckw.x" /* CKW */
55 #include "kwu.x" /* KWU */
56 #include "rgu.x" /* RGU */
62 /* Variable for logging, declared in cl */
63 #ifndef RGL_SPECIFIC_CHANGES
70 #ifndef RGL_SPECIFIC_CHANGES
72 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
74 uint32_t isMemThreshReached(Region region);
78 uint32_t isMemThreshReached(Region region);
84 @brief RLC Acknowledged Mode Uplink Module
86 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_UL) /* for debugging purpose */
88 /* private function declarations */
90 static void rlcAmmUlAssembleCntrlInfo ARGS ((RlcCb *gCb, RlcUlRbCb *rbCb));
92 static uint8_t rlcAmmExtractHdr ARGS ((RlcCb *gCb,
98 static bool rlcAmmUlPlacePduInRecBuf ARGS ((RlcCb *gCb,
103 static void rlcAmmTriggerStatus ARGS ((RlcCb *gCb,
108 static uint8_t rlcAmmUlReassembleSdus ARGS ((RlcCb *gCb,
110 RlcAmRecBuf *recBuf));
112 static Void rlcAmmProcPduOrSeg ARGS ((RlcCb *gCb,
117 static Void rlcAmmUpdExpByteSeg ARGS ((RlcCb *gCb,RlcAmUl *amUl, RlcSeg* newSeg));
119 static Void rlcAmmExtractElmnt ARGS ((RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo));
121 static Void rlcAmmUlHndlStatusPdu ARGS ((RlcCb *gCb,
126 /******************************************************************************
128 AM Module contains the following funcitons:
131 - rlcAmmUlAssembleCntrlInfo
136 - rlcAmmUlHndlStatusPdu
137 - rlcAmmTriggerStatus
138 - rlcAmmUlReassembleSdus
140 *******************************************************************************/
141 /** @addtogroup ammode */
145 * @brief Private function to fill NACK information in status Pdu as per 5GNR
147 * @param[in] rbCb Ul RbCb
148 * @param[in] sn Sequence number of the PDU for which the NACK
149 * @param[in] isSegment TRUE means NACK for segment; FALSE for PDU
150 * @param[in] soStart SOStart
151 * @param[in] soEnd SOEnd
152 * @param[out] statusPdu status Pdu holder to be filled
153 * @param[in] prevNackSn It holds previous nack Sn
156 * The number of bytes required to encode this NACK information
159 static uint8_t rlcAmmUlSetNackInfo(RlcUlRbCb *rbCb, RlcSn sn, bool isSegment, \
160 uint16_t soStart, uint16_t soEnd, RlcUdxDlStaPdu *statusPdu, RlcSn *prevNackSn)
162 RlcNackInfo *nackInfo = (statusPdu->nackInfo + statusPdu->nackCount);
163 uint16_t sizeToBeEncd = 0; /* Status PDu size to be encoded */
165 /* In following cases we should increment the nackCnt & fill new NACK_SN info:
166 * 1) First NACK_SN of the statusdPdu
167 * 2) NACK_SN is not continuous with previous
168 * 3) NACK_SN is same as previuos but segments are not continuous
169 * 4) NACK_SN is continuous with previous but previous NACK_SN segments
170 * are not missing in sequence till end
172 if((*prevNackSn == 0xffffffff) || ((((*prevNackSn) + 1) & RLC_AMUL.snModMask) != sn) ||
173 (((*prevNackSn) == sn) && (((nackInfo->soEnd + 1) != soStart))) ||
174 ((nackInfo->isSegment) && (((*prevNackSn) + 1) == sn) && (nackInfo->soEnd != RLC_ALL_BYTES_MISSING)))
176 if(nackInfo->nackRange)
178 if((nackInfo->soEnd) && (!nackInfo->soStart))
180 /*First nack_sn of this nackRange not segmented but last is segmented */
181 sizeToBeEncd = 5; /*32 for soStart and soEnd and 8 for nackRange */
185 /*First nack_sn of this nackRange was segmented */
186 sizeToBeEncd = 1; /*8 for nackRange */
190 if(*prevNackSn != 0xffffffff)
192 /* Increment nackCount as this sn is continous */
193 statusPdu->nackCount++;
194 nackInfo = statusPdu->nackInfo + statusPdu->nackCount;
198 nackInfo->isSegment = isSegment;
199 nackInfo->soStart = soStart;
200 nackInfo->soEnd = soEnd;
201 nackInfo->nackRange = 0;
205 sizeToBeEncd += ((RLC_AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?6:7); /* NACK,E1,E2,Sostart,SoEnd */
209 sizeToBeEncd += ((RLC_AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?2:3); /* NACK,E1,E2 */
214 if(!(nackInfo->nackRange))
216 nackInfo->nackRange++;
218 /* This case means there are continuous SNs/Segments. If it is the next
219 * Sn then increment nackRnage. if same SN but different segment then
220 * dont increment nackRange */
221 if((((*prevNackSn) + 1) & RLC_AMUL.snModMask) == sn)
223 nackInfo->nackRange++;
226 /* If NackRange is reached to max value then increment statusPdu->nackCount*/
227 if(nackInfo->nackRange == 255)
229 statusPdu->nackCount++;
230 if(nackInfo->isSegment)
232 sizeToBeEncd = 1; /* return only nackRangeSize*/
236 /* First SN was not segmented of this nackRange but last SN is segmented */
237 sizeToBeEncd = 5; /* return size of soSatrt + soEnd + nackRnage */
243 nackInfo->isSegment = isSegment;
244 nackInfo->soEnd = soEnd;
246 else if(nackInfo->isSegment)
248 nackInfo->soEnd = RLC_ALL_BYTES_MISSING;
252 nackInfo->soStart = 0;
259 return (sizeToBeEncd);
263 * @brief Private handler to gather information required to create the STATUS
267 * Scans the reception buffer and copies information to the UdxDlStaPdu
268 * structure about SN's and segments not yet received. This data is
269 * sent to the DL instance so that it can create an appropriate (depending
270 * on the grants from MAC) STATUS PDU and send it to MAC.
272 * @param[in] gCb RLC instance control block
273 * @param[in] rbCb Uplink RB control block
278 static void rlcAmmUlAssembleCntrlInfo(RlcCb *gCb, RlcUlRbCb *rbCb)
280 RlcUdxDlStaPdu *pStatusPdu;
281 RlcNackInfo *nackInfo;
282 RlcSn sn; /* sequence number */
283 RlcSn mSn; /* Mod val of sequence number */
284 RlcSn rxHighestStatus; /* Mod val of rxHighestStatus */
285 RlcSeg *seg; /* pdu segment */
286 uint16_t nackCnt = 0; /* Index for staPdu */
287 uint16_t seqSo; /* segmment offset */
288 RlcUdxUlSapCb *sapCb;
289 uint16_t staPduEncSize = 3; /* size that would be of the encoded
290 STATUS PDU, it is in bits; 15 for
291 first fixed part of STATUS PDU */
292 RlcAmRecBuf *recBuf = NULLP;
293 RlcSn prevNackSn = 0xffffffff;
295 sapCb = RLC_GET_UDX_SAP(gCb);
297 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
300 sizeof(RlcUdxDlStaPdu));
302 #if (ERRCLASS & ERRCLS_ADD_RES)
303 /* Memory allocation failure can not be expected */
310 sn = RLC_AMUL.rxNext;
311 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
312 MODAMR(RLC_AMUL.rxHighestStatus, rxHighestStatus, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
314 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
316 while (mSn < rxHighestStatus )
318 /* For missing PDUs */
319 if ((NULLP == recBuf) && nackCnt < RLC_MAX_NACK_CNT )
321 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing PDU's SN = %d UEID:%d \
322 CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
323 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
325 FALSE, /* isSegment */
331 else if (recBuf && (recBuf->pdu == NULLP) &&
332 (recBuf->segLst.count > 0))
334 /* Scan through the byte segments of PDU and add this sn
335 with soStart and soEnd info to staPdu */
338 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
339 while (seg != NULLP && nackCnt < RLC_MAX_NACK_CNT)
341 /* For missing byte segments */
342 if (seg->amHdr.so != seqSo)
344 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
352 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing byte segment's"
353 " SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
354 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d \
355 UEID:%d CELLID:%d", seqSo, seg->amHdr.so - 1, rbCb->rlcId.ueId,
359 seqSo = seg->soEnd + 1;
360 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
363 /* Check if the last segment is missing */
364 RLC_LLIST_LAST_SEG(recBuf->segLst, seg);
365 if ((seg != NULLP) &&
366 (seg->amHdr.si != RLC_SI_LAST_SEG && nackCnt < RLC_MAX_NACK_CNT))
368 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
372 RLC_ALL_BYTES_MISSING,
376 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Missing (last) byte "
377 "segment's SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId,
379 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d\
380 UEID:%d CELLID:%d", seqSo, RLC_ALL_BYTES_MISSING, rbCb->rlcId.ueId,
386 sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
387 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
389 /* Get the received Buffer the updated/next SN */
390 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
392 /* Find the next missing sequence number if nackCnt reaches maximum and
393 still Reordering window has some missing AMDPDUs / AMDPDU segments. The
394 next missing sequence number will be considered as the ack sequnece
395 number in the status pdu.*/
396 if((nackCnt == RLC_MAX_NACK_CNT) &&
397 ((recBuf == NULLP) ||
398 ((recBuf->pdu == NULLP) &&
399 (recBuf->segLst.count > 0))))
405 /*Unfortunately i have write below peice of code here because kwAmmsetNackInfo()
406 * don't know that this is the last nackSn with nackRange*/
407 nackInfo = &(pStatusPdu->nackInfo[pStatusPdu->nackCount]);
408 if(nackInfo->nackRange)
410 if((nackInfo->soEnd) && (!nackInfo->soStart))
412 /*First nack_sn of this nackRange not segmented but last is segmented */
413 staPduEncSize += 5; /*32 for soStart and soEnd and 8 for nackRange */
417 /*First nack_sn of this nackRange was segmented */
418 staPduEncSize += 1; /*8 for nackRange */
421 /* nackCount is used as an index to nackInfo array but in status Pdu it
422 * should be equal to number nackInfo that are filled. hence incrementing by 1*/
423 if(prevNackSn != 0xffffffff)
425 pStatusPdu->nackCount++;
427 /* Update ACK SN with the last sn for which feedback is not assembled */
428 if ( mSn == rxHighestStatus)
430 pStatusPdu->ackSn = RLC_AMUL.rxHighestStatus;
434 pStatusPdu->ackSn = sn;
437 DU_LOG("\nINFO --> RLC_UL : rlcAmmUlAssembleCntrlInfo: ACK PDU's SN = %d"
438 "UEID:%d CELLID:%d", pStatusPdu->ackSn, rbCb->rlcId.ueId,
441 pStatusPdu->controlBo = staPduEncSize; /*Its already in bytes */
443 RLC_AMUL.staTrg = FALSE;
444 RLC_AMUL.gatherStaPduInfo = FALSE;
447 if (rlcUlUdxStaPduReq(&sapCb->pst,
452 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlAssembleCntrlInfo: Failed to Send Sta Pdu UEID:%d \
453 CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
454 RLC_FREE_SHRABL_BUF_WC(sapCb->pst.region,
457 sizeof(RlcUdxDlStaPdu));
463 #ifdef XEON_SPECIFIC_CHANGES
464 uint32_t gRlcDatIndUL;
467 #ifdef T2K_TRIGGER_RLC_REEST
468 uint32_t drpRlcDrbPack;
471 * @brief Handler to process the PDUs received from MAC and send it to PDCP
474 * This function is invoked by UTL with the PDU(s) received from MAC.
475 * It reorders the received data PDUs and trigger status report as
476 * needed. Reassembles the SDUs in sequence and send it to PDCP.
477 * It also processes the control PDU
479 * @param[in] gCb RLC instance control block
480 * @param[in] rbCb RB control block
481 * @param[out] pduInfo PDU Info received from MAC
487 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
489 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
496 uint8_t numPduToProcess;
502 #ifdef LTE_L2_MEAS_RLC
503 MsgLen rlcSduSz; /*Holds length of Rlc Sdu*/
504 #endif /* LTE_L2_MEAS */
508 numPduToProcess = RLC_MIN(pduInfo->numPdu, RGU_MAX_PDU);
509 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: numPdu[%d],numPduToProcess[%d] UEID:%d CELLID:%d",
510 numPdu, numPduToProcess, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
512 while (numPdu < numPduToProcess)
515 pdu = pduInfo->mBuf[numPdu++];
520 DU_LOG("\nERROR --> RLC_UL : rlcAmmProcessPdus: Null Pdu UEID:%d CELLID:%d",
521 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
522 gCb->genSts.errorPdusRecv++;
525 #ifndef RGL_SPECIFIC_CHANGES
529 ODU_GET_MSG_LEN(pdu, &len);
534 /* Extract AM PDU/SEG header Info */
535 RLC_MEM_ZERO(&amHdr, sizeof(RlcAmHdr));
536 /* Avoided the allocation of amHdr and sending
538 if (rlcAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
540 DU_LOG("\nERROR --> RLC_UL : rlcAmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",
541 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
542 ODU_PUT_MSG_BUF(pdu);
543 gCb->genSts.errorPdusRecv++;
546 /* Check if its a control PDU */
549 rlcAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
550 ODU_PUT_MSG_BUF(pdu);
553 if((amHdr.si == RLC_SI_LAST_SEG) && (!amHdr.so))
555 DU_LOG("\nERROR --> RLC_UL : rlcAmmProcessPdus: Dropping PDU because SO can't be zero\
556 for last segment sn:%u UEID:%d CELLID:%d", amHdr.sn, rbCb->rlcId.ueId,
558 ODU_PUT_MSG_BUF(pdu);
561 #ifndef RGL_SPECIFIC_CHANGES
564 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
566 /* Changed the condition to TRUE from ROK */
567 if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
571 ODU_PUT_MSG_BUF(pdu);
577 /*ccpu00142274 - UL memory based flow control*/
578 if(isMemThreshReached(rlcCb[0]->init.region) != ROK)
582 ODU_PUT_MSG_BUF(pdu);
591 #ifdef T2K_TRIGGER_RLC_REEST
592 if(drpRlcDrbPack > 1000)
594 if(rbCb->rlcId.rbType == CM_LTE_DRB)
596 ODU_PUT_MSG_BUF(pdu);
602 /* Reordering data PDU */
604 if (rlcAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
609 RlcSn mrxNextHighestRcvd;
612 rlcUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
613 #endif /* LTE_L2_MEAS */
615 /* Update rxNextHighestRcvd */
616 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
617 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
618 if (mSn >= mrxNextHighestRcvd)
620 amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask));
622 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
623 amUl->rxNextHighestRcvd, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
626 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
627 if ((NULLP != recBuf) && ( recBuf->allRcvd))
629 /* deliver the reassembled RLC SDU to upper layer,
630 But not removed from the table */
631 rlcAmmUlReassembleSdus(gCb, rbCb, recBuf);
632 recBuf->isDelvUpperLayer = TRUE;
634 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
636 /* Update rxHighestStatus */
637 if (sn == amUl->rxHighestStatus)
639 tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
641 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
642 /* Scan through till the upper edge of the window */
643 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
646 if ((NULLP == recBuf) || (!recBuf->allRcvd))
648 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: Updated rxHighestStatus:%d "
654 amUl->rxHighestStatus = tSn;
657 tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
658 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
665 if (sn == amUl->rxNext)
668 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
669 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
670 /* Scan through till the upper edge of the window */
673 if ((NULLP != recBuf) && (recBuf->allRcvd) &&
674 (TRUE == recBuf->isDelvUpperLayer))
676 /* RecBuf should remove from table
677 since PDU is already sent to upper layer */
678 recBuf->isDelvUpperLayer = FALSE;
679 rlcUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
684 amUl->vrMr = (amUl->rxNext + (RLC_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
687 tSn = (tSn + 1) & (amUl->snModMask);
688 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
694 /* Check if reAsmblTmr is running and update rxNextStatusTrig accordingly */
695 tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
698 Bool snInWin = RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
699 /* spec 38.322v15.3.0 - 5.2.3.2.3 */
700 if((amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
701 (amUl->rxNextStatusTrig != amUl->vrMr) )||
702 (amUl->rxNextStatusTrig == amUl->rxNext && recBuf &&recBuf->noMissingSeg))
704 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
706 DU_LOG("\nINFO --> RLC_UL: rlcAmmProcessPdus: Stopped ReAssembly Timer rxNextStatusTigger = %d"
707 "rxNextReassembly = %d", amUl->rxNextStatusTrig, amUl->rxNext);
713 /* spec 38.322v15.3.0 - 5.2.3.2.3 */
714 if((amUl->rxNextHighestRcvd > amUl->rxNext) || ((amUl->rxNextHighestRcvd == amUl->rxNext) &&
715 (recBuf && (!recBuf->noMissingSeg))))
717 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
718 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
720 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: Updated rxNextStatusTrig = %d"
721 "UEID:%d CELLID:%d", amUl->rxNextStatusTrig, rbCb->rlcId.ueId,
729 gRlcStats.amRlcStats.numULPdusDiscarded++;
734 rlcAmmTriggerStatus(gCb,rbCb, sn, discFlg);
739 rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
740 #endif /* LTE_L2_MEAS */
741 gCb->genSts.pdusRecv += pduInfo->numPdu;
742 if (amUl->gatherStaPduInfo)
744 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
752 * @brief Private handler to extract header Information of the PDU
755 * This function extracts the header elements of the PDU and store them
756 * in db for future reference.
758 * fByte - is the first byte removed from the PDU as part of calling
761 * @param[in] gCb RLC instance control block
762 * @param[in] rbCb Uplink RB control block
763 * @param[in] pdu Received PDU
764 * @param[out] amHdr Pointer to the extracted AM header
765 * @param[out] fByte First byte removed from the PDU
772 static uint8_t rlcAmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcAmHdr *amHdr, uint8_t *fByte)
779 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
781 /* Extract fixed part of the header */
782 ODU_GET_MSG_LEN(pdu,&pduSz);
783 ODU_REM_PRE_MSG(fByte, pdu);
784 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
785 if (RLC_CNTRL_PDU == amHdr->dc)
787 //DU_LOG ("\nINFO --> RLC_UL : ++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
791 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
793 amHdr->si = (*fByte & RLC_SI_POS) >> RLC_SI_SHT;
796 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
798 ODU_REM_PRE_MSG(&snByte, pdu);
799 sn = (RlcSn)(((*fByte & RLC_SN_POS_12BIT) << RLC_BYTE_LEN ) | snByte);
802 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
804 ODU_REM_PRE_MSG(&snByte, pdu);
805 sn = (RlcSn)(((*fByte & RLC_SN_POS_18BIT) << RLC_BYTE_LEN ) | snByte);
807 ODU_REM_PRE_MSG(&snByte, pdu);
808 sn = ((sn << RLC_BYTE_LEN) | snByte);
812 if ((amHdr->si != 0) && (amHdr->si != RLC_SI_FIRST_SEG))
814 hdrInfo.len = RLC_SO_LEN_5GNR;
815 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
816 amHdr->so = hdrInfo.val;
825 * @brief Private handler to extract header Information of the PDU
828 * This function extracts the header elements of the PDU and store them
829 * in db for future reference.
831 * fByte - is the first byte removed from the PDU as part of calling
834 * @param[in] gCb RLC instance control block
835 * @param[in] rbCb Uplink RB control block
836 * @param[in] pdu Received PDU
837 * @param[out] amHdr Pointer to the extracted AM header
838 * @param[out] fByte First byte removed from the PDU
845 static S16 rlcAmmExtractHdrOld(RlcCb *gCb,Buffer *pdu,RlcAmHdr *amHdr,uint8_t *fByte)
854 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
856 /* Extract fixed part of the header */
857 SFndLenMsg(pdu,&pduSz);
858 SRemPreMsg(fByte, pdu);
859 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
860 if (RLC_CNTRL_PDU == amHdr->dc)
864 /* kw002.201 : Changed the extraction of hdr elements to avoid */
866 amHdr->rf = (*fByte & RLC_RF_POS) >> RLC_RF_SHT;
867 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
868 amHdr->fi = (*fByte & RLC_FI_POS) >> RLC_FI_SHT;
869 e = amHdr->e = (*fByte & RLC_E_POS)>> RLC_E_SHT;
871 SRemPreMsg(&snByte, pdu);
872 sn = (uint16_t)(((*fByte & RLC_SN_POS) << RLC_BYTE_LEN ) | snByte);
876 /* Extract extn part of the header */
877 hdrInfo.len = RLC_LSF_LEN;
878 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
879 amHdr->lsf = (uint8_t)hdrInfo.val;
881 hdrInfo.len = RLC_SO_LEN;
882 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
883 amHdr->so = hdrInfo.val;
889 while (e && (amHdr->numLi < RLC_MAX_UL_LI))
891 hdrInfo.len = RLC_E_LEN;
892 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
893 e = amHdr->e = (uint8_t)hdrInfo.val;
895 /* Extract LI value*/
896 hdrInfo.len = RLC_LI_LEN;
897 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
898 /* li = hdrInfo.val;*/
900 /* check if LI is zero */
903 DU_LOG("\nERROR --> RLC_UL : Received LI as 0");
907 /* store the extracted LI value */
908 amHdr->li[amHdr->numLi++] = hdrInfo.val;
909 totalSz += hdrInfo.val; /* incrment the size by LI value */
912 /*ccpu00122597:PDU is dropped if liCnt exceeds RLC_MAX_LI*/
913 if(e && (amHdr->numLi >= RLC_MAX_UL_LI))
915 DU_LOG("\nERROR --> RLC_UL : LI Count [%u] exceeds Max LI Count[%u]",
916 amHdr->numLi, RLC_MAX_UL_LI);
920 /* first 2 bytes + Add one for Odd LI*/
921 pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
923 if ( totalSz >= pduSz )
925 DU_LOG("\nERROR --> RLC_UL : SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
926 amHdr->sn, totalSz, pduSz);
935 * @brief Private handler to process the status PDU
938 * Private handler invokded by rlcAmmProcessPdus to process the
939 * control PDU (status report) received from its peer RLC entity.
941 * - Decode the values from the received control pdu
942 * - Create a RlcUdxStaPdu structure, copy the values onto it and
943 * send it to the DL instance for further processing
945 * @param[in] gCb RLC instance control block
946 * @param[in] rbCb Uplink RB control block
947 * @param[in] cntrlPdu Control PDU received from MAC
948 * @param[in] fByte First byte already removed from the STATUS PDU
953 static void rlcAmmUlHndlStatusPdu(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *cntrlPdu, uint8_t *fByte)
957 RlcUdxStaPdu *pStaPdu;
958 RlcUdxUlSapCb *sapCb;
959 uint8_t e3; /* NACK RANGE : 5GNR */
962 uint32_t resrvdBitsAckSn=0;
963 uint32_t resrvdBitsNackSn=0;
965 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
967 /* Extract the Control PDU */
968 hdrInfo.hdr = (*fByte << 1);
971 /* D/C has been shifted in the calling function */
972 if (hdrInfo.hdr & 0xE0)
974 DU_LOG("\nINFO --> RLC_UL : rlcAmmUlHndlStatusPdu: Reserved value for CPT received UEID:%d \
975 CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
979 sapCb = RLC_GET_UDX_SAP(gCb);
981 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
984 sizeof(RlcUdxStaPdu));
986 #if (ERRCLASS & ERRCLS_ADD_RES)
987 /* Memory allocation failure can not be expected */
994 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
997 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
998 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
1000 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
1003 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
1004 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
1009 resrvdBitsAckSn = 0;
1010 resrvdBitsAckSn = 0;
1013 pStaPdu->nackCnt = 0;
1015 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
1018 hdrInfo.len = snLen;
1019 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1020 pStaPdu->ackSn = hdrInfo.val;
1022 //DU_LOG ("\nINFO --> RLC_UL : ++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n", pStaPdu->ackSn);
1023 /* Check if NACK Exists */
1024 hdrInfo.len = RLC_E1_LEN;
1025 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1026 e1 = (uint8_t)hdrInfo.val;
1027 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1028 pStaPdu->ackSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1030 /* Extract the Reserved Bits after ACK SN field */
1031 hdrInfo.len = resrvdBitsAckSn;
1032 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1034 /* If NACK exists in control PDU */
1035 /* For ACKs and NACKs */
1036 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
1038 hdrInfo.len = snLen;
1039 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1040 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1042 hdrInfo.len = RLC_E1_LEN;
1043 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1044 e1 = (uint8_t)hdrInfo.val;
1047 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1049 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1050 /* e2 = (uint8_t) hdrInfo.val;*/
1052 /* Store e2 value */
1053 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
1055 /* Extract e3 : 5GNR */
1056 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1058 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1059 e3 = (uint8_t) hdrInfo.val;
1061 /* Extract Reserved Bits after NACK SN */
1062 hdrInfo.len = resrvdBitsNackSn;
1063 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1065 /* Test for resegmentation */
1066 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1068 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1069 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1070 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1072 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1073 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
1075 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1076 "UEID:%d CELLID:%d", pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1077 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd, rbCb->rlcId.ueId,
1078 rbCb->rlcId.cellId);
1083 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1084 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
1087 /* NACK RANGE Field is SET */
1090 /* Extract NACK range field */
1091 hdrInfo.len = RLC_NACK_RANGE_LEN;
1092 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1093 snRange = (uint8_t)hdrInfo.val;
1095 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1101 gRlcStats.amRlcStats.numULStaPduRcvd++;
1102 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1104 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1105 to the last NACK SN + 1 and discard the original ACK_SN*/
1106 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
1108 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1112 /* Parse & send Status PDU to RLC-DL */
1113 rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1119 * @brief Private handler to release all stored segments
1122 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to release the
1123 * stored segements in case a complete PDU is received later.
1125 * @param[in] gCb RLC instance control block
1126 * @param[in] recBuf Buffer that stores a received PDU or segments
1131 static void rlcAmmUlRlsAllSegs(RlcCb *gCb, RlcAmRecBuf *recBuf)
1135 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1136 while (seg != NULLP)
1138 ODU_PUT_MSG_BUF(seg->seg);
1139 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1140 RLC_FREE(gCb,seg, sizeof(RlcSeg));
1141 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1148 * @brief Private handler to store the received segment
1151 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to add a received
1152 * segment in reception buffer of a RBCB.
1153 * - It is responsible for detecting duplicate segments
1154 * - Adding it at appropriate position in the received buffer
1155 * - Calling ExpByteSeg to set expSo field in the receiver buffer
1157 * @param[in] gCb RLC instance control block
1158 * @param[in] rbCb Radio Bearer Contro Block
1159 * @param[in] amHdr AM Header received
1160 * @param[in] pdu Buffer received other than the headers
1161 * @param[in] pduSz size of the PDU buffer received
1164 * -#TRUE Successful insertion into the receiver buffer
1165 * -#FALSE Possibly a duplicate segment
1167 static bool rlcAmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu, uint16_t pduSz)
1169 RlcAmRecBuf *recBuf = NULLP;
1172 uint16_t soEnd; /* Holds the SoEnd of received segment */
1173 uint16_t expSo = 0; /* Expected SO */
1175 soEnd = amHdr->so + pduSz - 1;
1176 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, amHdr->sn);
1178 if (NULLP == recBuf)
1180 RLC_ALLOC(gCb,recBuf, sizeof(RlcAmRecBuf));
1181 #if (ERRCLASS & ERRCLS_ADD_RES)
1182 if (recBuf == NULLP)
1184 DU_LOG("\nERROR --> RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1185 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1187 ODU_PUT_MSG_BUF(pdu);
1190 #endif /* ERRCLASS & ERRCLS_RES */
1191 rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, amHdr->sn);
1195 if (recBuf->allRcvd == TRUE)
1197 ODU_PUT_MSG_BUF(pdu);
1202 recBuf->isDelvUpperLayer = FALSE;
1203 /* kw003.201 - Move past the segments that are different than the */
1205 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1206 while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1208 expSo = seg->amHdr.so + seg->segSz;
1209 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1212 /* The received segment should start after the end of previous seg */
1213 if (expSo > amHdr->so)
1215 /* This is a duplicate segment */
1216 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1217 ODU_PUT_MSG_BUF(pdu);
1221 if ((seg) && (seg->amHdr.so <= soEnd))
1223 /* This is a duplicate segment */
1224 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1225 ODU_PUT_MSG_BUF(pdu);
1229 /* If we have come this far, we have to add this segment to the */
1230 /* reception buffer as we either have eliminated duplicates or */
1231 /* have found none. */
1232 RLC_ALLOC_WC(gCb,tseg, sizeof(RlcSeg));
1233 #if (ERRCLASS & ERRCLS_ADD_RES)
1236 DU_LOG("\nERROR --> RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1237 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1238 ODU_PUT_MSG_BUF(pdu);
1241 #endif /* ERRCLASS & ERRCLS_RES */
1244 tseg->segSz = pduSz;
1245 RLC_MEM_CPY(&tseg->amHdr, amHdr, sizeof(RlcAmHdr));
1246 recBuf->amHdr.si = amHdr->si;
1247 recBuf->amHdr.sn = amHdr->sn;
1248 tseg->soEnd = soEnd;
1251 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1255 recBuf->segLst.crnt = &seg->lstEnt;
1256 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1258 tseg->lstEnt.node = (PTR)tseg;
1259 rlcAmmUpdExpByteSeg(gCb,&RLC_AMUL,tseg);
1265 * @brief Private handler to place the PDU in the reception buffer
1268 * This function checks if the received PDU's SN falls within the
1269 * receiving window, after which it places the same in the reception
1270 * buffer if its not a duplicate.
1272 * @param[in] gCb RLC instance control block
1273 * @param[in] pdu Received PDU
1274 * @param[in] rbCb Uplink AM Radio Bearer
1275 * @param[out] amUl AM UL Info
1282 static bool rlcAmmUlPlacePduInRecBuf(RlcCb *gCb, Buffer *pdu, RlcUlRbCb *rbCb, RlcAmHdr *amHdr)
1286 RlcAmUl *amUl = &(rbCb->m.amUl);
1289 SFndLenMsg(pdu, &pduSz);
1291 gCb->genSts.bytesRecv += pduSz;
1292 gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz;
1293 if (!RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1295 gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1296 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlPlacePduInRecBuf: SN %d outside the window"
1297 "UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1299 gCb->genSts.unexpPdusRecv++;
1300 ODU_PUT_MSG_BUF(pdu);
1306 RlcAmRecBuf *recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1308 /* We received a complete PDU. Either we already have it, in which */
1309 /* case we just ignore the new PDU and discard it. Otherwise, */
1310 /* store the received PDU in the reception buffer */
1311 if (NULLP == recBuf)
1313 RLC_ALLOC(gCb, recBuf, sizeof(RlcAmRecBuf));
1314 #if (ERRCLASS & ERRCLS_ADD_RES)
1315 if (recBuf == NULLP)
1317 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlPlacePduInRecBuf: Memory allocation failed \
1318 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1319 ODU_PUT_MSG_BUF(pdu);
1322 #endif /* ERRCLASS & ERRCLS_RES */
1323 rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, sn);
1325 else if (recBuf->allRcvd != TRUE)
1327 rlcAmmUlRlsAllSegs(gCb,recBuf);
1331 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1332 gCb->genSts.unexpPdusRecv++;
1333 ODU_PUT_MSG_BUF(pdu);
1336 recBuf->isDelvUpperLayer = FALSE;
1338 recBuf->pduSz = pduSz;
1339 recBuf->allRcvd = TRUE;
1340 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1341 RLC_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(RlcAmHdr));
1346 /* We received a segment. We need to add that to the existing */
1347 /* segments, if any. */
1348 return (rlcAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1353 * @brief Private handler to trigger status report
1356 * Private handler invokded by rlcAmmProcessPdus to check if the
1357 * status report need to be sent, and update the status trigger
1358 * flag accordingly based on status prohibit timer.
1360 * - Check if the received pdu's sn is less than rxHighestStatus, set the
1362 * - If staProhTmr is not running, calculate cntrlBo, else it'll be
1363 * updated at the expiry of staProhTmr.
1364 * - Expiry of reAsmblTmr also will set staTrg flag.
1366 * @param[in] gCb RLC instance control block
1367 * @param[in] rbCb Uplink RB control block
1368 * @param[in] sn Sequence number of the pdu based on which to check if
1369 * status needs to be triggered
1370 * @param[in] discFlg Whether this pdu was discarded or not
1375 static void rlcAmmTriggerStatus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcSn sn, bool discFlg)
1380 RlcSn trxHighestStatus;
1381 RlcAmUl *amUl = &(rbCb->m.amUl);
1383 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1384 MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1385 MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1387 /* kw005.201 Product CR ccpu00117114 *
1388 * The "=" in the 2nd condition is removed */
1389 if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1391 DU_LOG("\nINFO --> RLC_UL : rlcAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1392 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1394 amUl->staTrg = TRUE;
1395 amUl->gatherStaPduInfo = FALSE;
1397 /* Check if staProhTmr is running */
1398 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1402 amUl->gatherStaPduInfo = TRUE;
1410 * @brief Private handler to reassemble from a segment or a PDU
1413 * Private handler invokded by kwAmmReassembleSdus with either a
1414 * PDU or a segment of a PDU. This is also called in the case of
1415 * reestablishment and hence out of sequence joining is also to
1419 * @param[in] gCb RLC instance control block
1420 * @param[in] rbCb Uplink RB control block
1421 * @param[in] amHdr AM header received for this segment/PDU
1422 * @param[in] pdu PDU to be reassembled
1427 static void rlcAmmProcPduOrSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu)
1430 if ((RLC_AMUL.expSn != amHdr->sn) || (RLC_AMUL.expSo != amHdr->so))
1432 /* Release the existing partial SDU as we have PDUs or */
1433 /* segments that are out of sequence */
1434 rbCb->m.amUl.isOutOfSeq = TRUE;
1435 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1438 if (amHdr->si == RLC_SI_FIRST_SEG)
1439 {/* first Segment of the SDU */
1440 if (RLC_AMUL.partialSdu != NULLP)
1441 { /* Some old SDU may be present */
1442 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1444 RLC_AMUL.partialSdu = pdu;
1447 else if(amHdr->si == RLC_SI_MID_SEG)
1448 {/* Middle or last segment of the SUD */
1449 ODU_CAT_MSG(RLC_AMUL.partialSdu,pdu, M1M2);
1450 ODU_PUT_MSG_BUF(pdu);
1453 else if (amHdr->si == RLC_SI_LAST_SEG)
1455 ODU_CAT_MSG(pdu,RLC_AMUL.partialSdu,M2M1);
1456 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1461 RLC_AMUL.partialSdu = NULLP;
1462 rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
1470 * @brief Private handler to reassemble SDUs
1473 * Private handler invokded by rlcAmmProcessPdus with the PDU
1474 * from the reception buffer in sequence to reassemble SDUs and
1477 * - With the stored header info, FI and LSF segment / concatenate
1478 * PDUs or byte segments of PDUs to get the associated SDU.
1480 * @param[in] rbCb RB control block
1481 * @param[in] pdu PDU to be reassembled
1488 static uint8_t rlcAmmUlReassembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmRecBuf *recBuf)
1492 //if (recBuf->amHdr.rf == 0)
1493 if (recBuf->amHdr.si == 0)
1496 rlcAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1497 /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1498 recBuf->pdu = NULLP;
1499 RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1504 /* This is a set of segments */
1505 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1506 RLC_AMUL.expSn = recBuf->amHdr.sn;
1510 rlcAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1511 RLC_AMUL.expSo = seg->soEnd + 1;
1513 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1514 RLC_FREE(gCb, seg, sizeof(RlcSeg));
1516 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1518 RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1526 * @brief Handler to process the re-establishment request received from UIM
1528 * @param[in] gCb RLC instance control block
1529 * @param[in] rlcId RLC identifier
1530 * @param[in] sendReEst Whether to send back restablishment complete or not
1531 * @param[in] rbCb Uplink RB control block
1536 Void rlcAmmUlReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcUlRbCb *rbCb)
1543 RlcKwuSapCb *rlcKwuSap;
1545 RlcAmRecBuf *recBuf = NULLP;
1547 sn = RLC_AMUL.rxNext;
1549 MODAMR(RLC_AMUL.vrMr, mVrMr, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1550 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1552 /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1555 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1556 if (NULLP != recBuf)
1558 if (recBuf->allRcvd == TRUE)
1560 rlcAmmUlReassembleSdus(gCb,rbCb, recBuf);
1564 /* Remove PDU and segments */
1567 ODU_PUT_MSG_BUF(recBuf->pdu);
1569 /* Release all the segments*/
1570 rlcAmmUlRlsAllSegs(gCb,recBuf);
1572 rlcUtlDelRecBuf(RLC_AMUL.recBufLst, recBuf, gCb);
1574 sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1575 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1577 /* Discard remaining PDUs and bytesegments in recBuf */
1579 /* Stop all timers and reset variables */
1580 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1582 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1584 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1586 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1589 RLC_AMUL.rxNext = 0;
1590 RLC_AMUL.rxNextHighestRcvd = 0;
1591 RLC_AMUL.rxNextStatusTrig = 0;
1592 rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1593 RLC_AMUL.rxHighestStatus = 0;
1594 RLC_AMUL.staTrg = FALSE;
1595 RLC_AMUL.gatherStaPduInfo = FALSE;
1598 if (RLC_AMUL.partialSdu != NULLP)
1600 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1602 rlcKwuSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
1606 RlcUiKwuReEstCmpInd(&rlcKwuSap->pst, rlcKwuSap->suId, rlcId);
1607 rbCb->m.amUl.isOutOfSeq = FALSE;
1614 * @brief Handler for reorder timer expiry
1617 * This function is used to handle events upon expiry of reorder timer
1619 * @param[in] gCb RLC instance control block
1620 * @param[in] rbCb RB control block
1626 Void rlcAmmReAsmblTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1628 RlcAmUl *amUl = &(rbCb->m.amUl);
1632 RlcSn mrxHighestStatus;
1633 RlcSn mrxNextHighestRcvd;
1634 Bool tmrRunning = FALSE;
1635 RlcAmRecBuf *recBuf = NULLP;
1637 /* Update rxHighestStatus */
1638 sn = amUl->rxNextStatusTrig;
1640 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1641 MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1642 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1646 if ((recBuf == NULLP) ||
1647 ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1649 amUl->rxHighestStatus = sn;
1650 amUl->staTrg = TRUE;
1651 amUl->gatherStaPduInfo = FALSE;
1653 /* Check if staProhTmr is running */
1654 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1658 gRlcStats.amRlcStats.numULReAsmblTimerExpires++;
1659 amUl->gatherStaPduInfo = TRUE;
1660 rlcAmmUlAssembleCntrlInfo(gCb, rbCb);
1665 sn = (sn + 1) & (amUl->snModMask);
1666 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1669 /* Update rxNextStatusTrig */
1670 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1671 MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1672 /* spec 38.322v15.3.0 - 5.2.3.2.4 */
1673 if((mrxNextHighestRcvd > mrxHighestStatus) || ((mrxNextHighestRcvd == mrxHighestStatus) &&
1674 ((recBuf) && !(recBuf->noMissingSeg))))
1676 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1677 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1681 } /* rlcAmmReAsmblTmrExp */
1684 * @brief Handler for status prohibit timer expiry
1687 * This function is used to handle events upon expiry of status prohibit
1690 * @param[in] gCb RLC instance control block
1691 * @param[in] rbCb RB control block
1697 Void rlcAmmStaProTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1699 RlcAmUl *amUl = &(rbCb->m.amUl);
1701 amUl->gatherStaPduInfo = FALSE;
1703 if (amUl->staTrg == TRUE)
1705 amUl->gatherStaPduInfo = TRUE;
1706 /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
1707 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
1711 } /* rlcAmmStaProTmrExp */
1714 * @brief Handler to extract an element of AM Header
1717 * This function is used to extract an element of AM header.
1719 * @param[in] pdu The pdu to be decoded
1720 * @param[in,out] hdrInfo Container to hold the decoded info
1726 static void rlcAmmExtractElmnt(RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo)
1729 uint8_t pLen = hdrInfo->pLen;
1730 uint8_t len = (uint8_t)hdrInfo->len;
1735 /* uint8_t rLen1 = 0; */
1742 ODU_REM_PRE_MSG(&hdr, pdu);
1748 val = tHdr >> (RLC_BYTE_LEN - (len));
1752 else /*if (len > 8) */
1756 val = val >> (RLC_BYTE_LEN - fLen);
1757 val = val << (len - fLen);
1759 ODU_REM_PRE_MSG(&hdr, pdu);
1763 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1766 pLen = (RLC_BYTE_LEN - rLen);
1770 rLen = rLen - RLC_BYTE_LEN;
1772 tVal = tVal << rLen;
1775 ODU_REM_PRE_MSG(&hdr, pdu);
1777 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1780 pLen = (RLC_BYTE_LEN - rLen);
1784 hdrInfo->pLen = pLen;
1792 * @brief Handler to updated expected byte seg
1795 * This function is used to update expected byte segment. The next segment
1796 * expected is indicated by the SO of the segment which is expected. Intially
1797 * the segment with SO 0 is expected and then in order. When all the segments
1798 * are received (which would happen when an expected SO is encountered
1799 * with LSF set) the allRcvd flag is set to TRUE
1801 * @param[in] gCb RLC instance control block
1802 * @param[in] amUl AM Uplink Control Block
1803 * @param[in] seg Newly received segment
1809 static void rlcAmmUpdExpByteSeg(RlcCb *gCb, RlcAmUl *amUl, RlcSeg *seg)
1811 uint16_t newExpSo; /* The new expected SO */
1812 RlcSn sn = seg->amHdr.sn;
1814 RlcAmRecBuf *recBuf = NULLP;
1816 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1817 if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
1821 recBuf->noMissingSeg = FALSE;
1822 newExpSo = seg->soEnd + 1;
1823 recBuf->expSo = newExpSo;
1824 if(seg->amHdr.si == RLC_SI_LAST_SEG)
1828 /* kw003.201 - This should update seg with the one after newSeg */
1829 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1832 /* keep going ahead as long as the expectedSo match with the header so
1833 else store the expSo for later checking again */
1834 if(seg->amHdr.si == RLC_SI_LAST_SEG)
1838 if (seg->amHdr.so == newExpSo)
1840 newExpSo = seg->soEnd + 1;
1841 recBuf->expSo = newExpSo;
1842 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1846 recBuf->expSo = newExpSo;
1850 if (lstRcvd == TRUE)
1852 recBuf->allRcvd = TRUE;
1853 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1855 recBuf->noMissingSeg = TRUE;
1861 * Function to release/free the Acknowledged Mode Module RbCb buffers
1864 * This primitive Frees the AM RbCb transmission Buffer, retransmission
1865 * Buffer and reciption Buffers
1867 * @param [in] gCb - RLC instance Control Block
1868 * @param [in] rbCb - RB Control Block
1872 Void rlcAmmFreeUlRbCb(RlcCb *gCb,RlcUlRbCb *rbCb)
1874 RlcSn curSn = 0; /* Sequence number of PDU */
1875 RlcSn windSz; /* PDU window size */
1876 RlcAmRecBuf *recBuf = NULLP;
1878 windSz = (RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
1880 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REASSEMBLE_TMR))
1882 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REASSEMBLE_TMR);
1884 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1886 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1890 /* on the first loop winSz is always greater than zero
1891 while( ( curSn < windSz ) hence changing to do while */
1894 recBuf = rlcUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
1895 if ( recBuf != NULLP )
1897 if (recBuf->pdu != NULLP)
1899 ODU_PUT_MSG_BUF(recBuf->pdu);
1901 /* Release all the segments */
1902 rlcAmmUlRlsAllSegs(gCb,recBuf);
1903 rlcUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
1906 }while ( curSn < windSz );
1909 RLC_FREE(gCb,rbCb->m.amUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
1910 rbCb->m.amUl.recBufLst = NULLP;
1913 if(rbCb->m.amUl.partialSdu != NULLP)
1915 ODU_PUT_MSG_BUF(rbCb->m.amUl.partialSdu);
1918 } /* rlcAmmFreeUlRbCb */
1924 /********************************************************************30**
1927 **********************************************************************/