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*/
38 static const char* RLOG_MODULE_NAME="AMM";
39 static int RLOG_MODULE_ID=2048;
40 static int RLOG_FILE_ID=190;
42 /* header include files (.h) */
43 #include "common_def.h"
44 #include "lkw.h" /* LKW defines */
45 #include "ckw.h" /* CKW defines */
46 #include "kwu.h" /* KWU defines */
47 #include "rgu.h" /* RGU defines */
49 #include "kw_err.h" /* Err defines */
50 #include "kw_env.h" /* RLC environment options */
52 #include "kw.h" /* RLC defines */
55 /* extern (.x) include files */
56 #include "lkw.x" /* LKW */
57 #include "ckw.x" /* CKW */
58 #include "kwu.x" /* KWU */
59 #include "rgu.x" /* RGU */
65 /* Variable for logging, declared in cl */
66 #ifndef RGL_SPECIFIC_CHANGES
69 extern U32 ulrate_rgu;
73 #ifndef RGL_SPECIFIC_CHANGES
75 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
77 extern U32 isMemThreshReached(Region region);
81 extern U32 isMemThreshReached(Region region);
87 @brief RLC Acknowledged Mode Uplink Module
89 #define RLC_MODULE (RLC_DBGMASK_AM | RLC_DBGMASK_UL) /* for debugging purpose */
91 /* private function declarations */
93 void rlcAmmUlAssembleCntrlInfo ARGS ((RlcCb *gCb, RlcUlRbCb *rbCb));
95 uint8_t rlcAmmExtractHdr ARGS ((RlcCb *gCb,
101 bool rlcAmmUlPlacePduInRecBuf ARGS ((RlcCb *gCb,
106 void rlcAmmTriggerStatus ARGS ((RlcCb *gCb,
111 uint8_t rlcAmmUlReassembleSdus ARGS ((RlcCb *gCb,
113 RlcAmRecBuf *recBuf));
115 PRIVATE Void rlcAmmProcPduOrSeg ARGS ((RlcCb *gCb,
120 PRIVATE Void rlcAmmUpdExpByteSeg ARGS ((RlcCb *gCb,RlcAmUl *amUl, RlcSeg* newSeg));
122 PRIVATE Void rlcAmmExtractElmnt ARGS ((RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo));
124 PRIVATE Void rlcAmmUlHndlStatusPdu ARGS ((RlcCb *gCb,
129 /******************************************************************************
131 AM Module contains the following funcitons:
134 - rlcAmmUlAssembleCntrlInfo
139 - rlcAmmUlHndlStatusPdu
140 - rlcAmmTriggerStatus
141 - rlcAmmUlReassembleSdus
143 *******************************************************************************/
144 /** @addtogroup ammode */
148 * @brief Private function to fill NACK information in status Pdu as per 5GNR
150 * @param[in] rbCb Ul RbCb
151 * @param[in] sn Sequence number of the PDU for which the NACK
152 * @param[in] isSegment TRUE means NACK for segment; FALSE for PDU
153 * @param[in] soStart SOStart
154 * @param[in] soEnd SOEnd
155 * @param[out] statusPdu status Pdu holder to be filled
156 * @param[in] prevNackSn It holds previous nack Sn
159 * The number of bytes required to encode this NACK information
162 uint8_t rlcAmmUlSetNackInfo(RlcUlRbCb *rbCb, RlcSn sn, bool isSegment, \
163 uint16_t soStart, uint16_t soEnd, RlcUdxDlStaPdu *statusPdu, RlcSn *prevNackSn)
165 RlcNackInfo *nackInfo = (statusPdu->nackInfo + statusPdu->nackCount);
166 uint16_t sizeToBeEncd = 0; /* Status PDu size to be encoded */
168 /* In following cases we should increment the nackCnt & fill new NACK_SN info:
169 * 1) First NACK_SN of the statusdPdu
170 * 2) NACK_SN is not continuous with previous
171 * 3) NACK_SN is same as previuos but segments are not continuous
172 * 4) NACK_SN is continuous with previous but previous NACK_SN segments
173 * are not missing in sequence till end
175 if((*prevNackSn == 0xffffffff) || ((((*prevNackSn) + 1) & AMUL.snModMask) != sn) ||
176 (((*prevNackSn) == sn) && (((nackInfo->soEnd + 1) != soStart))) ||
177 ((nackInfo->isSegment) && (((*prevNackSn) + 1) == sn) && (nackInfo->soEnd != RLC_ALL_BYTES_MISSING)))
179 if(nackInfo->nackRange)
181 if((nackInfo->soEnd) && (!nackInfo->soStart))
183 /*First nack_sn of this nackRange not segmented but last is segmented */
184 sizeToBeEncd = 5; /*32 for soStart and soEnd and 8 for nackRange */
188 /*First nack_sn of this nackRange was segmented */
189 sizeToBeEncd = 1; /*8 for nackRange */
193 if(*prevNackSn != 0xffffffff)
195 /* Increment nackCount as this sn is continous */
196 statusPdu->nackCount++;
197 nackInfo = statusPdu->nackInfo + statusPdu->nackCount;
201 nackInfo->isSegment = isSegment;
202 nackInfo->soStart = soStart;
203 nackInfo->soEnd = soEnd;
204 nackInfo->nackRange = 0;
208 sizeToBeEncd += ((AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?6:7); /* NACK,E1,E2,Sostart,SoEnd */
212 sizeToBeEncd += ((AMUL.snLen == RLC_AM_CFG_12BIT_SN_LEN)?2:3); /* NACK,E1,E2 */
217 if(!(nackInfo->nackRange))
219 nackInfo->nackRange++;
221 /* This case means there are continuous SNs/Segments. If it is the next
222 * Sn then increment nackRnage. if same SN but different segment then
223 * dont increment nackRange */
224 if((((*prevNackSn) + 1) & AMUL.snModMask) == sn)
226 nackInfo->nackRange++;
229 /* If NackRange is reached to max value then increment statusPdu->nackCount*/
230 if(nackInfo->nackRange == 255)
232 statusPdu->nackCount++;
233 if(nackInfo->isSegment)
235 sizeToBeEncd = 1; /* return only nackRangeSize*/
239 /* First SN was not segmented of this nackRange but last SN is segmented */
240 sizeToBeEncd = 5; /* return size of soSatrt + soEnd + nackRnage */
246 nackInfo->isSegment = isSegment;
247 nackInfo->soEnd = soEnd;
249 else if(nackInfo->isSegment)
251 nackInfo->soEnd = RLC_ALL_BYTES_MISSING;
255 nackInfo->soStart = 0;
262 return (sizeToBeEncd);
266 * @brief Private handler to gather information required to create the STATUS
270 * Scans the reception buffer and copies information to the UdxDlStaPdu
271 * structure about SN's and segments not yet received. This data is
272 * sent to the DL instance so that it can create an appropriate (depending
273 * on the grants from MAC) STATUS PDU and send it to MAC.
275 * @param[in] gCb RLC instance control block
276 * @param[in] rbCb Uplink RB control block
281 void rlcAmmUlAssembleCntrlInfo(RlcCb *gCb, RlcUlRbCb *rbCb)
283 RlcUdxDlStaPdu *pStatusPdu;
284 RlcNackInfo *nackInfo;
285 RlcSn sn; /* sequence number */
286 RlcSn mSn; /* Mod val of sequence number */
287 RlcSn rxHighestStatus; /* Mod val of rxHighestStatus */
288 RlcSeg *seg; /* pdu segment */
289 uint16_t nackCnt = 0; /* Index for staPdu */
290 uint16_t seqSo; /* segmment offset */
291 RlcUdxUlSapCb *sapCb;
292 uint16_t staPduEncSize = 3; /* size that would be of the encoded
293 STATUS PDU, it is in bits; 15 for
294 first fixed part of STATUS PDU */
295 RlcAmRecBuf *recBuf = NULLP;
296 RlcSn prevNackSn = 0xffffffff;
298 sapCb = RLC_GET_UDX_SAP(gCb);
300 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
303 sizeof(RlcUdxDlStaPdu));
305 #if (ERRCLASS & ERRCLS_ADD_RES)
306 /* Memory allocation failure can not be expected */
314 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
315 MODAMR(AMUL.rxHighestStatus, rxHighestStatus, AMUL.rxNext, AMUL.snModMask);
317 recBuf = rlcUtlGetRecBuf(AMUL.recBufLst, sn);
319 while (mSn < rxHighestStatus )
321 /* For missing PDUs */
322 if ((NULLP == recBuf) && nackCnt < RLC_MAX_NACK_CNT )
324 DU_LOG("\nRLC: rlcAmmUlAssembleCntrlInfo: Missing PDU's SN = %d UEID:%d \
325 CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
326 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
328 FALSE, /* isSegment */
334 else if (recBuf && (recBuf->pdu == NULLP) &&
335 (recBuf->segLst.count > 0))
337 /* Scan through the byte segments of PDU and add this sn
338 with soStart and soEnd info to staPdu */
341 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
342 while (seg != NULLP && nackCnt < RLC_MAX_NACK_CNT)
344 /* For missing byte segments */
345 if (seg->amHdr.so != seqSo)
347 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
355 DU_LOG("\nRLC: rlcAmmUlAssembleCntrlInfo: Missing byte segment's"
356 " SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
357 DU_LOG("\nRLC: rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d \
358 UEID:%d CELLID:%d", seqSo, seg->amHdr.so - 1, rbCb->rlcId.ueId,
362 seqSo = seg->soEnd + 1;
363 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
366 /* Check if the last segment is missing */
367 RLC_LLIST_LAST_SEG(recBuf->segLst, seg);
368 if ((seg != NULLP) &&
369 (seg->amHdr.si != RLC_SI_LAST_SEG && nackCnt < RLC_MAX_NACK_CNT))
371 staPduEncSize += rlcAmmUlSetNackInfo(rbCb,
375 RLC_ALL_BYTES_MISSING,
379 DU_LOG("\nRLC: rlcAmmUlAssembleCntrlInfo: Missing (last) byte "
380 "segment's SN:%d UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId,
382 DU_LOG("\nRLC: rlcAmmUlAssembleCntrlInfo: soStart and soEnd = %d, %d\
383 UEID:%d CELLID:%d", seqSo, RLC_ALL_BYTES_MISSING, rbCb->rlcId.ueId,
389 sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
390 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
392 /* Get the received Buffer the updated/next SN */
393 recBuf = rlcUtlGetRecBuf(AMUL.recBufLst, sn);
395 /* Find the next missing sequence number if nackCnt reaches maximum and
396 still Reordering window has some missing AMDPDUs / AMDPDU segments. The
397 next missing sequence number will be considered as the ack sequnece
398 number in the status pdu.*/
399 if((nackCnt == RLC_MAX_NACK_CNT) &&
400 ((recBuf == NULLP) ||
401 ((recBuf->pdu == NULLP) &&
402 (recBuf->segLst.count > 0))))
408 /*Unfortunately i have write below peice of code here because kwAmmsetNackInfo()
409 * don't know that this is the last nackSn with nackRange*/
410 nackInfo = &(pStatusPdu->nackInfo[pStatusPdu->nackCount]);
411 if(nackInfo->nackRange)
413 if((nackInfo->soEnd) && (!nackInfo->soStart))
415 /*First nack_sn of this nackRange not segmented but last is segmented */
416 staPduEncSize += 5; /*32 for soStart and soEnd and 8 for nackRange */
420 /*First nack_sn of this nackRange was segmented */
421 staPduEncSize += 1; /*8 for nackRange */
424 /* nackCount is used as an index to nackInfo array but in status Pdu it
425 * should be equal to number nackInfo that are filled. hence incrementing by 1*/
426 if(prevNackSn != 0xffffffff)
428 pStatusPdu->nackCount++;
430 /* Update ACK SN with the last sn for which feedback is not assembled */
431 if ( mSn == rxHighestStatus)
433 pStatusPdu->ackSn = AMUL.rxHighestStatus;
437 pStatusPdu->ackSn = sn;
440 DU_LOG("\nRLC: rlcAmmUlAssembleCntrlInfo: ACK PDU's SN = %d"
441 "UEID:%d CELLID:%d", pStatusPdu->ackSn, rbCb->rlcId.ueId,
444 pStatusPdu->controlBo = staPduEncSize; /*Its already in bytes */
447 AMUL.gatherStaPduInfo = FALSE;
450 if (rlcUlUdxStaPduReq(&sapCb->pst,
455 DU_LOG("\nRLC: rlcAmmUlAssembleCntrlInfo: Failed to Send Sta Pdu UEID:%d \
456 CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
457 RLC_FREE_SHRABL_BUF_WC(sapCb->pst.region,
460 sizeof(RlcUdxDlStaPdu));
466 #ifdef XEON_SPECIFIC_CHANGES
467 extern U32 gRlcDatIndUL;
470 #ifdef T2K_TRIGGER_RLC_REEST
474 * @brief Handler to process the PDUs received from MAC and send it to PDCP
477 * This function is invoked by UTL with the PDU(s) received from MAC.
478 * It reorders the received data PDUs and trigger status report as
479 * needed. Reassembles the SDUs in sequence and send it to PDCP.
480 * It also processes the control PDU
482 * @param[in] gCb RLC instance control block
483 * @param[in] rbCb RB control block
484 * @param[out] pduInfo PDU Info received from MAC
490 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
492 void rlcAmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
499 uint8_t numPduToProcess;
505 #ifdef LTE_L2_MEAS_RLC
506 MsgLen rlcSduSz; /*Holds length of Rlc Sdu*/
507 #endif /* LTE_L2_MEAS */
511 numPduToProcess = RLC_MIN(pduInfo->numPdu, RGU_MAX_PDU);
512 DU_LOG("\nRLC : rlcAmmProcessPdus: numPdu[%d],numPduToProcess[%d] UEID:%d CELLID:%d",
513 numPdu, numPduToProcess, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
515 while (numPdu < numPduToProcess)
518 pdu = pduInfo->mBuf[numPdu++];
523 DU_LOG("\nRLC : rlcAmmProcessPdus: Null Pdu UEID:%d CELLID:%d",
524 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
525 gCb->genSts.errorPdusRecv++;
528 #ifndef RGL_SPECIFIC_CHANGES
532 ODU_GET_MSG_LEN(pdu, &len);
537 /* Extract AM PDU/SEG header Info */
538 RLC_MEM_ZERO(&amHdr, sizeof(RlcAmHdr));
539 /* Avoided the allocation of amHdr and sending
541 if (rlcAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
543 DU_LOG("\nRLC : rlcAmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",
544 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
546 gCb->genSts.errorPdusRecv++;
549 /* Check if its a control PDU */
552 rlcAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
556 if((amHdr.si == RLC_SI_LAST_SEG) && (!amHdr.so))
558 DU_LOG("\nRLC: rlcAmmProcessPdus: Dropping PDU because SO can't be zero\
559 for last segment sn:%u UEID:%d CELLID:%d", amHdr.sn, rbCb->rlcId.ueId,
564 #ifndef RGL_SPECIFIC_CHANGES
567 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
569 /* Changed the condition to TRUE from ROK */
570 if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
572 extern U32 rlculdrop;
580 /*ccpu00142274 - UL memory based flow control*/
581 if(isMemThreshReached(rlcCb[0]->init.region) != ROK)
583 extern U32 rlculdrop;
594 #ifdef T2K_TRIGGER_RLC_REEST
595 if(drpRlcDrbPack > 1000)
597 if(rbCb->rlcId.rbType == CM_LTE_DRB)
605 /* Reordering data PDU */
607 if (rlcAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
612 RlcSn mrxNextHighestRcvd;
615 rlcUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
616 #endif /* LTE_L2_MEAS */
618 /* Update rxNextHighestRcvd */
619 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
620 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
621 if (mSn >= mrxNextHighestRcvd)
623 amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask));
625 DU_LOG("\nRLC: rlcAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
626 amUl->rxNextHighestRcvd, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
629 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
630 if ((NULLP != recBuf) && ( recBuf->allRcvd))
632 /* deliver the reassembled RLC SDU to upper layer,
633 But not removed from the table */
634 rlcAmmUlReassembleSdus(gCb, rbCb, recBuf);
635 recBuf->isDelvUpperLayer = TRUE;
637 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
639 /* Update rxHighestStatus */
640 if (sn == amUl->rxHighestStatus)
642 tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
644 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
645 /* Scan through till the upper edge of the window */
646 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
649 if ((NULLP == recBuf) || (!recBuf->allRcvd))
651 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
652 "rlcAmmProcessPdus: Updated rxHighestStatus:%d "
658 amUl->rxHighestStatus = tSn;
661 tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
662 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
669 if (sn == amUl->rxNext)
672 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
673 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
674 /* Scan through till the upper edge of the window */
677 if ((NULLP != recBuf) && (recBuf->allRcvd) &&
678 (TRUE == recBuf->isDelvUpperLayer))
680 /* RecBuf should remove from table
681 since PDU is already sent to upper layer */
682 recBuf->isDelvUpperLayer = FALSE;
683 rlcUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
688 amUl->vrMr = (amUl->rxNext + (RLC_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
691 tSn = (tSn + 1) & (amUl->snModMask);
692 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, tSn);
698 /* Check if reOrdTmr is running and update rxNextStatusTrig accordingly */
699 tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_REORD_TMR);
702 Bool snInWin = RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
704 if ( (amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
705 (amUl->rxNextStatusTrig != amUl->vrMr) ) )
707 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_REORD_TMR);
714 if (amUl->rxNextHighestRcvd > amUl->rxNext)
716 rlcStartTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_REORD_TMR);
717 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
719 DU_LOG("\nRLC: rlcAmmProcessPdus: Updated rxNextStatusTrig = %d \
720 UEID:%d CELLID:%d", amUl->rxNextStatusTrig, rbCb->rlcId.ueId,
728 gRlcStats.amRlcStats.numULPdusDiscarded++;
733 rlcAmmTriggerStatus(gCb,rbCb, sn, discFlg);
738 rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
739 #endif /* LTE_L2_MEAS */
740 gCb->genSts.pdusRecv += pduInfo->numPdu;
741 if (amUl->gatherStaPduInfo)
743 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
751 * @brief Private handler to extract header Information of the PDU
754 * This function extracts the header elements of the PDU and store them
755 * in db for future reference.
757 * fByte - is the first byte removed from the PDU as part of calling
760 * @param[in] gCb RLC instance control block
761 * @param[in] rbCb Uplink RB control block
762 * @param[in] pdu Received PDU
763 * @param[out] amHdr Pointer to the extracted AM header
764 * @param[out] fByte First byte removed from the PDU
771 uint8_t rlcAmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcAmHdr *amHdr, uint8_t *fByte)
778 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
780 /* Extract fixed part of the header */
781 ODU_GET_MSG_LEN(pdu,&pduSz);
782 ODU_REM_PRE_MSG(fByte, pdu);
783 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
784 if (RLC_CNTRL_PDU == amHdr->dc)
786 //printf ("++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
790 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
792 amHdr->si = (*fByte & RLC_SI_POS) >> RLC_SI_SHT;
795 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
797 ODU_REM_PRE_MSG(&snByte, pdu);
798 sn = (RlcSn)(((*fByte & RLC_SN_POS_12BIT) << RLC_BYTE_LEN ) | snByte);
801 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
803 ODU_REM_PRE_MSG(&snByte, pdu);
804 sn = (RlcSn)(((*fByte & RLC_SN_POS_18BIT) << RLC_BYTE_LEN ) | snByte);
806 ODU_REM_PRE_MSG(&snByte, pdu);
807 sn = ((sn << RLC_BYTE_LEN) | snByte);
811 if ((amHdr->si != 0) && (amHdr->si != 0x01))
813 hdrInfo.len = RLC_SO_LEN_5GNR;
814 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
815 amHdr->so = hdrInfo.val;
824 * @brief Private handler to extract header Information of the PDU
827 * This function extracts the header elements of the PDU and store them
828 * in db for future reference.
830 * fByte - is the first byte removed from the PDU as part of calling
833 * @param[in] gCb RLC instance control block
834 * @param[in] rbCb Uplink RB control block
835 * @param[in] pdu Received PDU
836 * @param[out] amHdr Pointer to the extracted AM header
837 * @param[out] fByte First byte removed from the PDU
845 PRIVATE S16 rlcAmmExtractHdrOld
853 PRIVATE S16 rlcAmmExtractHdrOld(gCb, pdu, amHdr, fByte)
867 TRC2(rlcAmmExtractHdrOld)
870 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
872 /* Extract fixed part of the header */
873 SFndLenMsg(pdu,&pduSz);
874 SRemPreMsg(fByte, pdu);
875 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
876 if (RLC_CNTRL_PDU == amHdr->dc)
880 /* kw002.201 : Changed the extraction of hdr elements to avoid */
882 amHdr->rf = (*fByte & RLC_RF_POS) >> RLC_RF_SHT;
883 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
884 amHdr->fi = (*fByte & RLC_FI_POS) >> RLC_FI_SHT;
885 e = amHdr->e = (*fByte & RLC_E_POS)>> RLC_E_SHT;
887 SRemPreMsg(&snByte, pdu);
888 sn = (U16)(((*fByte & RLC_SN_POS) << RLC_BYTE_LEN ) | snByte);
892 /* Extract extn part of the header */
893 hdrInfo.len = RLC_LSF_LEN;
894 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
895 amHdr->lsf = (U8)hdrInfo.val;
897 hdrInfo.len = RLC_SO_LEN;
898 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
899 amHdr->so = hdrInfo.val;
905 while (e && (amHdr->numLi < RLC_MAX_UL_LI))
907 hdrInfo.len = RLC_E_LEN;
908 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
909 e = amHdr->e = (U8)hdrInfo.val;
911 /* Extract LI value*/
912 hdrInfo.len = RLC_LI_LEN;
913 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
914 /* li = hdrInfo.val;*/
916 /* check if LI is zero */
919 RLOG0(L_ERROR, "Received LI as 0");
923 /* store the extracted LI value */
924 amHdr->li[amHdr->numLi++] = hdrInfo.val;
925 totalSz += hdrInfo.val; /* incrment the size by LI value */
928 /*ccpu00122597:PDU is dropped if liCnt exceeds RLC_MAX_LI*/
929 if(e && (amHdr->numLi >= RLC_MAX_UL_LI))
931 RLOG2(L_ERROR,"LI Count [%u] exceeds Max LI Count[%u]",
932 amHdr->numLi, RLC_MAX_UL_LI);
936 /* first 2 bytes + Add one for Odd LI*/
937 pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
939 if ( totalSz >= pduSz )
941 RLOG3(L_ERROR,"SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
942 amHdr->sn, totalSz, pduSz);
951 * @brief Private handler to process the status PDU
954 * Private handler invokded by rlcAmmProcessPdus to process the
955 * control PDU (status report) received from its peer RLC entity.
957 * - Decode the values from the received control pdu
958 * - Create a RlcUdxStaPdu structure, copy the values onto it and
959 * send it to the DL instance for further processing
961 * @param[in] gCb RLC instance control block
962 * @param[in] rbCb Uplink RB control block
963 * @param[in] cntrlPdu Control PDU received from MAC
964 * @param[in] fByte First byte already removed from the STATUS PDU
969 void rlcAmmUlHndlStatusPdu(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *cntrlPdu, uint8_t *fByte)
973 RlcUdxStaPdu *pStaPdu;
974 RlcUdxUlSapCb *sapCb;
975 uint8_t e3; /* NACK RANGE : 5GNR */
978 uint32_t resrvdBitsAckSn=0;
979 uint32_t resrvdBitsNackSn=0;
981 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
983 /* Extract the Control PDU */
984 hdrInfo.hdr = (*fByte << 1);
987 /* D/C has been shifted in the calling function */
988 if (hdrInfo.hdr & 0xE0)
990 DU_LOG("\nRLC: rlcAmmUlHndlStatusPdu: Reserved value for CPT received UEID:%d \
991 CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
995 sapCb = RLC_GET_UDX_SAP(gCb);
997 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
1000 sizeof(RlcUdxStaPdu));
1002 #if (ERRCLASS & ERRCLS_ADD_RES)
1003 /* Memory allocation failure can not be expected */
1010 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
1013 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
1014 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
1016 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
1019 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
1020 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
1025 resrvdBitsAckSn = 0;
1026 resrvdBitsAckSn = 0;
1029 pStaPdu->nackCnt = 0;
1031 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
1034 hdrInfo.len = snLen;
1035 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1036 pStaPdu->ackSn = hdrInfo.val;
1038 //printf ("++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n", pStaPdu->ackSn);
1039 /* Check if NACK Exists */
1040 hdrInfo.len = RLC_E1_LEN;
1041 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1042 e1 = (U8)hdrInfo.val;
1043 DU_LOG("\nRLC: rlcAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1044 pStaPdu->ackSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1046 /* Extract the Reserved Bits after ACK SN field */
1047 hdrInfo.len = resrvdBitsAckSn;
1048 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1050 /* If NACK exists in control PDU */
1051 /* For ACKs and NACKs */
1052 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
1054 hdrInfo.len = snLen;
1055 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1056 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1058 hdrInfo.len = RLC_E1_LEN;
1059 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1060 e1 = (U8)hdrInfo.val;
1063 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1065 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1066 /* e2 = (U8) hdrInfo.val;*/
1068 /* Store e2 value */
1069 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
1071 /* Extract e3 : 5GNR */
1072 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1074 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1075 e3 = (U8) hdrInfo.val;
1077 /* Extract Reserved Bits after NACK SN */
1078 hdrInfo.len = resrvdBitsNackSn;
1079 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1081 /* Test for resegmentation */
1082 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1084 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1085 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1086 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1088 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1089 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
1091 DU_LOG("\nRLC: rlcAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1092 "UEID:%d CELLID:%d", pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1093 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd, rbCb->rlcId.ueId,
1094 rbCb->rlcId.cellId);
1099 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1100 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
1103 /* NACK RANGE Field is SET */
1106 /* Extract NACK range field */
1107 hdrInfo.len = RLC_NACK_RANGE_LEN;
1108 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1109 snRange = (U8)hdrInfo.val;
1111 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1117 gRlcStats.amRlcStats.numULStaPduRcvd++;
1118 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1120 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1121 to the last NACK SN + 1 and discard the original ACK_SN*/
1122 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
1124 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1128 /* Parse & send Status PDU to RLC-DL */
1129 rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1135 * @brief Private handler to release all stored segments
1138 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to release the
1139 * stored segements in case a complete PDU is received later.
1141 * @param[in] gCb RLC instance control block
1142 * @param[in] recBuf Buffer that stores a received PDU or segments
1147 void rlcAmmUlRlsAllSegs(RlcCb *gCb, RlcAmRecBuf *recBuf)
1151 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1152 while (seg != NULLP)
1154 RLC_FREE_BUF_WC(seg->seg);
1155 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1156 RLC_FREE_WC(gCb,seg, sizeof(RlcSeg));
1157 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1164 * @brief Private handler to store the received segment
1167 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to add a received
1168 * segment in reception buffer of a RBCB.
1169 * - It is responsible for detecting duplicate segments
1170 * - Adding it at appropriate position in the received buffer
1171 * - Calling ExpByteSeg to set expSo field in the receiver buffer
1173 * @param[in] gCb RLC instance control block
1174 * @param[in] rbCb Radio Bearer Contro Block
1175 * @param[in] amHdr AM Header received
1176 * @param[in] pdu Buffer received other than the headers
1177 * @param[in] pduSz size of the PDU buffer received
1180 * -#TRUE Successful insertion into the receiver buffer
1181 * -#FALSE Possibly a duplicate segment
1183 bool rlcAmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu, uint16_t pduSz)
1185 RlcAmRecBuf *recBuf = NULLP;
1188 uint16_t soEnd; /* Holds the SoEnd of received segment */
1189 uint16_t expSo = 0; /* Expected SO */
1191 soEnd = amHdr->so + pduSz - 1;
1192 recBuf = rlcUtlGetRecBuf(AMUL.recBufLst, amHdr->sn);
1194 if (NULLP == recBuf)
1196 RLC_ALLOC(gCb,recBuf, sizeof(RlcAmRecBuf));
1197 #if (ERRCLASS & ERRCLS_ADD_RES)
1198 if (recBuf == NULLP)
1200 DU_LOG("\nRLC: rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1201 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1206 #endif /* ERRCLASS & ERRCLS_RES */
1207 rlcUtlStoreRecBuf(AMUL.recBufLst, recBuf, amHdr->sn);
1211 if (recBuf->allRcvd == TRUE)
1218 recBuf->isDelvUpperLayer = FALSE;
1219 /* kw003.201 - Move past the segments that are different than the */
1221 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1222 while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1224 expSo = seg->amHdr.so + seg->segSz;
1225 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1228 /* The received segment should start after the end of previous seg */
1229 if (expSo > amHdr->so)
1231 /* This is a duplicate segment */
1232 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1237 if ((seg) && (seg->amHdr.so <= soEnd))
1239 /* This is a duplicate segment */
1240 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1245 /* If we have come this far, we have to add this segment to the */
1246 /* reception buffer as we either have eliminated duplicates or */
1247 /* have found none. */
1248 RLC_ALLOC_WC(gCb,tseg, sizeof(RlcSeg));
1249 #if (ERRCLASS & ERRCLS_ADD_RES)
1252 DU_LOG("\nRLC: rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1253 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1257 #endif /* ERRCLASS & ERRCLS_RES */
1260 tseg->segSz = pduSz;
1261 RLC_MEM_CPY(&tseg->amHdr, amHdr, sizeof(RlcAmHdr));
1262 recBuf->amHdr.si = amHdr->si;
1263 recBuf->amHdr.sn = amHdr->sn;
1264 tseg->soEnd = soEnd;
1267 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1271 recBuf->segLst.crnt = &seg->lstEnt;
1272 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1274 tseg->lstEnt.node = (PTR)tseg;
1275 rlcAmmUpdExpByteSeg(gCb,&AMUL,tseg);
1281 * @brief Private handler to place the PDU in the reception buffer
1284 * This function checks if the received PDU's SN falls within the
1285 * receiving window, after which it places the same in the reception
1286 * buffer if its not a duplicate.
1288 * @param[in] gCb RLC instance control block
1289 * @param[in] pdu Received PDU
1290 * @param[in] rbCb Uplink AM Radio Bearer
1291 * @param[out] amUl AM UL Info
1298 bool rlcAmmUlPlacePduInRecBuf(RlcCb *gCb, Buffer *pdu, RlcUlRbCb *rbCb, RlcAmHdr *amHdr)
1302 RlcAmUl *amUl = &(rbCb->m.amUl);
1305 SFndLenMsg(pdu, &pduSz);
1307 gCb->genSts.bytesRecv += pduSz;
1308 gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz;
1309 if (!RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1311 gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1312 DU_LOG("\nRLC: rlcAmmUlPlacePduInRecBuf: SN %d outside the window"
1313 "UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1315 gCb->genSts.unexpPdusRecv++;
1322 RlcAmRecBuf *recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1324 /* We received a complete PDU. Either we already have it, in which */
1325 /* case we just ignore the new PDU and discard it. Otherwise, */
1326 /* store the received PDU in the reception buffer */
1327 if (NULLP == recBuf)
1329 RLC_ALLOC(gCb, recBuf, sizeof(RlcAmRecBuf));
1330 #if (ERRCLASS & ERRCLS_ADD_RES)
1331 if (recBuf == NULLP)
1333 DU_LOG("\nRLC: rlcAmmUlPlacePduInRecBuf: Memory allocation failed \
1334 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1338 #endif /* ERRCLASS & ERRCLS_RES */
1339 rlcUtlStoreRecBuf(AMUL.recBufLst, recBuf, sn);
1341 else if (recBuf->allRcvd != TRUE)
1343 rlcAmmUlRlsAllSegs(gCb,recBuf);
1347 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1348 gCb->genSts.unexpPdusRecv++;
1352 recBuf->isDelvUpperLayer = FALSE;
1354 recBuf->pduSz = pduSz;
1355 recBuf->allRcvd = TRUE;
1356 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1357 RLC_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(RlcAmHdr));
1362 /* We received a segment. We need to add that to the existing */
1363 /* segments, if any. */
1364 return (rlcAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1369 * @brief Private handler to trigger status report
1372 * Private handler invokded by rlcAmmProcessPdus to check if the
1373 * status report need to be sent, and update the status trigger
1374 * flag accordingly based on status prohibit timer.
1376 * - Check if the received pdu's sn is less than rxHighestStatus, set the
1378 * - If staProhTmr is not running, calculate cntrlBo, else it'll be
1379 * updated at the expiry of staProhTmr.
1380 * - Expiry of reOrdTmr also will set staTrg flag.
1382 * @param[in] gCb RLC instance control block
1383 * @param[in] rbCb Uplink RB control block
1384 * @param[in] sn Sequence number of the pdu based on which to check if
1385 * status needs to be triggered
1386 * @param[in] discFlg Whether this pdu was discarded or not
1391 void rlcAmmTriggerStatus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcSn sn, bool discFlg)
1396 RlcSn trxHighestStatus;
1397 RlcAmUl *amUl = &(rbCb->m.amUl);
1399 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1400 MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1401 MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1403 /* kw005.201 Product CR ccpu00117114 *
1404 * The "=" in the 2nd condition is removed */
1405 if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1407 DU_LOG("\nRLC: rlcAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1408 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1410 amUl->staTrg = TRUE;
1411 amUl->gatherStaPduInfo = FALSE;
1413 /* Check if staProhTmr is running */
1414 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, RLC_EVT_AMUL_STA_PROH_TMR);
1418 amUl->gatherStaPduInfo = TRUE;
1426 * @brief Private handler to reassemble from a segment or a PDU
1429 * Private handler invokded by kwAmmReassembleSdus with either a
1430 * PDU or a segment of a PDU. This is also called in the case of
1431 * reestablishment and hence out of sequence joining is also to
1435 * @param[in] gCb RLC instance control block
1436 * @param[in] rbCb Uplink RB control block
1437 * @param[in] amHdr AM header received for this segment/PDU
1438 * @param[in] pdu PDU to be reassembled
1443 void rlcAmmProcPduOrSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu)
1446 if ((AMUL.expSn != amHdr->sn) || (AMUL.expSo != amHdr->so))
1448 /* Release the existing partial SDU as we have PDUs or */
1449 /* segments that are out of sequence */
1450 rbCb->m.amUl.isOutOfSeq = TRUE;
1451 RLC_FREE_BUF(AMUL.partialSdu);
1454 //if (amHdr->fi & RLC_FI_FIRST_SEG)
1455 if (amHdr->si == 0x01)
1456 {/* first Segment of the SDU */
1457 if (AMUL.partialSdu != NULLP)
1458 { /* Some old SDU may be present */
1459 RLC_FREE_BUF_WC(AMUL.partialSdu);
1461 AMUL.partialSdu = pdu;
1464 else if(amHdr->si == 0x03)
1465 {/* Middle or last segment of the SUD */
1466 ODU_CAT_MSG(AMUL.partialSdu,pdu, M1M2);
1467 RLC_FREE_BUF_WC(pdu);
1470 else if (amHdr->si == 0x02)
1472 ODU_CAT_MSG(pdu,AMUL.partialSdu,M2M1);
1473 RLC_FREE_BUF_WC(AMUL.partialSdu);
1478 AMUL.partialSdu = NULLP;
1479 rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
1487 * @brief Private handler to reassemble SDUs
1490 * Private handler invokded by rlcAmmProcessPdus with the PDU
1491 * from the reception buffer in sequence to reassemble SDUs and
1494 * - With the stored header info, FI and LSF segment / concatenate
1495 * PDUs or byte segments of PDUs to get the associated SDU.
1497 * @param[in] rbCb RB control block
1498 * @param[in] pdu PDU to be reassembled
1505 uint8_t rlcAmmUlReassembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmRecBuf *recBuf)
1509 //if (recBuf->amHdr.rf == 0)
1510 if (recBuf->amHdr.si == 0)
1513 rlcAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1514 /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1515 recBuf->pdu = NULLP;
1516 AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1521 /* This is a set of segments */
1522 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1523 AMUL.expSn = recBuf->amHdr.sn;
1527 rlcAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1528 AMUL.expSo = seg->soEnd + 1;
1530 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1531 RLC_FREE_WC(gCb, seg, sizeof(RlcSeg));
1533 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1535 AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1543 * @brief Handler to process the re-establishment request received from UIM
1545 * @param[in] gCb RLC instance control block
1546 * @param[in] rlcId RLC identifier
1547 * @param[in] sendReEst Whether to send back restablishment complete or not
1548 * @param[in] rbCb Uplink RB control block
1554 Void rlcAmmUlReEstablish
1562 Void rlcAmmUlReEstablish(gCb, rlcId, sendReEst, rbCb)
1574 RlcKwuSapCb *rlcKwuSap;
1576 RlcAmRecBuf *recBuf = NULLP;
1578 TRC2(rlcAmmUlReEstablish);
1583 MODAMR(AMUL.vrMr, mVrMr, AMUL.rxNext, AMUL.snModMask);
1584 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1586 /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1589 recBuf = rlcUtlGetRecBuf(AMUL.recBufLst, sn);
1590 if (NULLP != recBuf)
1592 if (recBuf->allRcvd == TRUE)
1594 rlcAmmUlReassembleSdus(gCb,rbCb, recBuf);
1598 /* Remove PDU and segments */
1601 RLC_FREE_BUF_WC(recBuf->pdu);
1603 /* Release all the segments*/
1604 rlcAmmUlRlsAllSegs(gCb,recBuf);
1606 rlcUtlDelRecBuf(AMUL.recBufLst, recBuf, gCb);
1608 sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1609 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1611 /* Discard remaining PDUs and bytesegments in recBuf */
1613 /* Stop all timers and reset variables */
1614 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMUL_REORD_TMR))
1616 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_REORD_TMR);
1618 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMUL_STA_PROH_TMR))
1620 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_STA_PROH_TMR);
1624 AMUL.rxNextHighestRcvd = 0;
1625 AMUL.rxNextStatusTrig = 0;
1626 rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1627 AMUL.rxHighestStatus = 0;
1628 AMUL.staTrg = FALSE;
1629 AMUL.gatherStaPduInfo = FALSE;
1632 if (AMUL.partialSdu != NULLP)
1634 RLC_FREE_BUF(AMUL.partialSdu);
1636 rlcKwuSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
1640 RlcUiKwuReEstCmpInd(&rlcKwuSap->pst, rlcKwuSap->suId, rlcId);
1641 rbCb->m.amUl.isOutOfSeq = FALSE;
1648 * @brief Handler for reorder timer expiry
1651 * This function is used to handle events upon expiry of reorder timer
1653 * @param[in] gCb RLC instance control block
1654 * @param[in] rbCb RB control block
1661 Void rlcAmmReOrdTmrExp
1667 Void rlcAmmReOrdTmrExp(rbCb)
1672 RlcAmUl *amUl = &(rbCb->m.amUl);
1676 RlcSn mrxHighestStatus;
1677 RlcSn mrxNextHighestRcvd;
1678 Bool tmrRunning = FALSE;
1679 RlcAmRecBuf *recBuf = NULLP;
1681 TRC2(rlcAmmReOrdTmrExp);
1684 /* Update rxHighestStatus */
1685 sn = amUl->rxNextStatusTrig;
1687 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1688 MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1689 recBuf = rlcUtlGetRecBuf(AMUL.recBufLst, sn);
1693 if ((recBuf == NULLP) ||
1694 ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1696 amUl->rxHighestStatus = sn;
1697 amUl->staTrg = TRUE;
1698 amUl->gatherStaPduInfo = FALSE;
1700 /* Check if staProhTmr is running */
1701 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, RLC_EVT_AMUL_STA_PROH_TMR);
1705 gRlcStats.amRlcStats.numULReOrdTimerExpires++;
1706 amUl->gatherStaPduInfo = TRUE;
1707 rlcAmmUlAssembleCntrlInfo(gCb, rbCb);
1712 sn = (sn + 1) & (amUl->snModMask);
1713 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1716 /* Update rxNextStatusTrig */
1717 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1718 MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1719 if (mrxNextHighestRcvd > mrxHighestStatus)
1721 rlcStartTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_REORD_TMR);
1722 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1726 } /* rlcAmmReOrdTmrExp */
1729 * @brief Handler for status prohibit timer expiry
1732 * This function is used to handle events upon expiry of status prohibit
1735 * @param[in] gCb RLC instance control block
1736 * @param[in] rbCb RB control block
1743 Void rlcAmmStaProTmrExp
1749 Void rlcAmmStaProTmrExp(gCb, rbCb)
1754 RlcAmUl *amUl = &(rbCb->m.amUl);
1756 TRC2(rlcAmmStaProTmrExp);
1759 amUl->gatherStaPduInfo = FALSE;
1761 if (amUl->staTrg == TRUE)
1763 amUl->gatherStaPduInfo = TRUE;
1764 /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
1765 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
1769 } /* rlcAmmStaProTmrExp */
1772 * @brief Handler to extract an element of AM Header
1775 * This function is used to extract an element of AM header.
1777 * @param[in] pdu The pdu to be decoded
1778 * @param[in,out] hdrInfo Container to hold the decoded info
1784 void rlcAmmExtractElmnt(RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo)
1787 uint8_t pLen = hdrInfo->pLen;
1788 uint8_t len = (U8)hdrInfo->len;
1800 ODU_REM_PRE_MSG(&hdr, pdu);
1806 val = tHdr >> (RLC_BYTE_LEN - (len));
1810 else /*if (len > 8) */
1814 val = val >> (RLC_BYTE_LEN - fLen);
1815 val = val << (len - fLen);
1817 ODU_REM_PRE_MSG(&hdr, pdu);
1821 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1824 pLen = (RLC_BYTE_LEN - rLen);
1828 rLen = rLen - RLC_BYTE_LEN;
1830 tVal = tVal << rLen;
1833 ODU_REM_PRE_MSG(&hdr, pdu);
1835 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1838 pLen = (RLC_BYTE_LEN - rLen);
1842 hdrInfo->pLen = pLen;
1850 * @brief Handler to updated expected byte seg
1853 * This function is used to update expected byte segment. The next segment
1854 * expected is indicated by the SO of the segment which is expected. Intially
1855 * the segment with SO 0 is expected and then in order. When all the segments
1856 * are received (which would happen when an expected SO is encountered
1857 * with LSF set) the allRcvd flag is set to TRUE
1859 * @param[in] gCb RLC instance control block
1860 * @param[in] amUl AM Uplink Control Block
1861 * @param[in] seg Newly received segment
1867 void rlcAmmUpdExpByteSeg(RlcCb *gCb, RlcAmUl *amUl, RlcSeg *seg)
1869 uint16_t newExpSo; /* The new expected SO */
1870 RlcSn sn = seg->amHdr.sn;
1872 RlcAmRecBuf *recBuf = NULLP;
1874 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1875 if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
1880 newExpSo = seg->soEnd + 1;
1881 recBuf->expSo = newExpSo;
1882 //lstRcvd = seg->amHdr.lsf;
1883 if(seg->amHdr.si == 0x2)
1887 /* kw003.201 - This should update seg with the one after newSeg */
1888 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1891 /* keep going ahead as long as the expectedSo match with the header so
1892 else store the expSo for later checking again */
1893 if(seg->amHdr.si == 0x2)
1897 if (seg->amHdr.so == newExpSo)
1899 newExpSo = seg->soEnd + 1;
1900 recBuf->expSo = newExpSo;
1901 //lstRcvd = seg->amHdr.lsf;
1902 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1906 recBuf->expSo = newExpSo;
1910 if (lstRcvd == TRUE)
1912 recBuf->allRcvd = TRUE;
1913 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1921 * Function to release/free the Acknowledged Mode Module RbCb buffers
1924 * This primitive Frees the AM RbCb transmission Buffer, retransmission
1925 * Buffer and reciption Buffers
1927 * @param [in] gCb - RLC instance Control Block
1928 * @param [in] rbCb - RB Control Block
1933 Void rlcAmmFreeUlRbCb
1939 Void rlcAmmFreeUlRbCb(gCb,rbCb)
1944 RlcSn curSn = 0; /* Sequence number of PDU */
1945 RlcSn windSz; /* PDU window size */
1946 RlcAmRecBuf *recBuf = NULLP;
1948 TRC2(rlcAmmFreeUlRbCb)
1951 windSz = (RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
1953 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMUL_REORD_TMR))
1955 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_REORD_TMR);
1957 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_AMUL_STA_PROH_TMR))
1959 rlcStopTmr(gCb,(PTR)rbCb, RLC_EVT_AMUL_STA_PROH_TMR);
1963 /* on the first loop winSz is always greater than zero
1964 while( ( curSn < windSz ) hence changing to do while */
1967 recBuf = rlcUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
1968 if ( recBuf != NULLP )
1970 if (recBuf->pdu != NULLP)
1972 RLC_FREE_BUF_WC(recBuf->pdu);
1974 /* Release all the segments */
1975 rlcAmmUlRlsAllSegs(gCb,recBuf);
1976 rlcUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
1979 }while ( curSn < windSz );
1982 RLC_FREE_WC(gCb,rbCb->m.amUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
1983 rbCb->m.amUl.recBufLst = NULLP;
1986 if(rbCb->m.amUl.partialSdu != NULLP)
1988 RLC_FREE_BUF_WC(rbCb->m.amUl.partialSdu);
1991 } /* rlcAmmFreeUlRbCb */
1997 /********************************************************************30**
2000 **********************************************************************/