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 reOrdTmr is running and update rxNextStatusTrig accordingly */
695 tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REORD_TMR);
698 Bool snInWin = RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
700 if ( (amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
701 (amUl->rxNextStatusTrig != amUl->vrMr) ) )
703 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REORD_TMR);
710 if (amUl->rxNextHighestRcvd > amUl->rxNext)
712 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REORD_TMR);
713 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
715 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmProcessPdus: Updated rxNextStatusTrig = %d \
716 UEID:%d CELLID:%d", amUl->rxNextStatusTrig, rbCb->rlcId.ueId,
724 gRlcStats.amRlcStats.numULPdusDiscarded++;
729 rlcAmmTriggerStatus(gCb,rbCb, sn, discFlg);
734 rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
735 #endif /* LTE_L2_MEAS */
736 gCb->genSts.pdusRecv += pduInfo->numPdu;
737 if (amUl->gatherStaPduInfo)
739 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
747 * @brief Private handler to extract header Information of the PDU
750 * This function extracts the header elements of the PDU and store them
751 * in db for future reference.
753 * fByte - is the first byte removed from the PDU as part of calling
756 * @param[in] gCb RLC instance control block
757 * @param[in] rbCb Uplink RB control block
758 * @param[in] pdu Received PDU
759 * @param[out] amHdr Pointer to the extracted AM header
760 * @param[out] fByte First byte removed from the PDU
767 static uint8_t rlcAmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcAmHdr *amHdr, uint8_t *fByte)
774 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
776 /* Extract fixed part of the header */
777 ODU_GET_MSG_LEN(pdu,&pduSz);
778 ODU_REM_PRE_MSG(fByte, pdu);
779 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
780 if (RLC_CNTRL_PDU == amHdr->dc)
782 //DU_LOG ("\nINFO --> RLC_UL : ++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
786 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
788 amHdr->si = (*fByte & RLC_SI_POS) >> RLC_SI_SHT;
791 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
793 ODU_REM_PRE_MSG(&snByte, pdu);
794 sn = (RlcSn)(((*fByte & RLC_SN_POS_12BIT) << RLC_BYTE_LEN ) | snByte);
797 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
799 ODU_REM_PRE_MSG(&snByte, pdu);
800 sn = (RlcSn)(((*fByte & RLC_SN_POS_18BIT) << RLC_BYTE_LEN ) | snByte);
802 ODU_REM_PRE_MSG(&snByte, pdu);
803 sn = ((sn << RLC_BYTE_LEN) | snByte);
807 if ((amHdr->si != 0) && (amHdr->si != 0x01))
809 hdrInfo.len = RLC_SO_LEN_5GNR;
810 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
811 amHdr->so = hdrInfo.val;
820 * @brief Private handler to extract header Information of the PDU
823 * This function extracts the header elements of the PDU and store them
824 * in db for future reference.
826 * fByte - is the first byte removed from the PDU as part of calling
829 * @param[in] gCb RLC instance control block
830 * @param[in] rbCb Uplink RB control block
831 * @param[in] pdu Received PDU
832 * @param[out] amHdr Pointer to the extracted AM header
833 * @param[out] fByte First byte removed from the PDU
840 static S16 rlcAmmExtractHdrOld(RlcCb *gCb,Buffer *pdu,RlcAmHdr *amHdr,uint8_t *fByte)
849 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
851 /* Extract fixed part of the header */
852 SFndLenMsg(pdu,&pduSz);
853 SRemPreMsg(fByte, pdu);
854 amHdr->dc = (*fByte & RLC_DC_POS) >> RLC_DC_SHT;
855 if (RLC_CNTRL_PDU == amHdr->dc)
859 /* kw002.201 : Changed the extraction of hdr elements to avoid */
861 amHdr->rf = (*fByte & RLC_RF_POS) >> RLC_RF_SHT;
862 amHdr->p = (*fByte & RLC_POLL_POS) >> RLC_POLL_SHT;
863 amHdr->fi = (*fByte & RLC_FI_POS) >> RLC_FI_SHT;
864 e = amHdr->e = (*fByte & RLC_E_POS)>> RLC_E_SHT;
866 SRemPreMsg(&snByte, pdu);
867 sn = (uint16_t)(((*fByte & RLC_SN_POS) << RLC_BYTE_LEN ) | snByte);
871 /* Extract extn part of the header */
872 hdrInfo.len = RLC_LSF_LEN;
873 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
874 amHdr->lsf = (uint8_t)hdrInfo.val;
876 hdrInfo.len = RLC_SO_LEN;
877 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
878 amHdr->so = hdrInfo.val;
884 while (e && (amHdr->numLi < RLC_MAX_UL_LI))
886 hdrInfo.len = RLC_E_LEN;
887 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
888 e = amHdr->e = (uint8_t)hdrInfo.val;
890 /* Extract LI value*/
891 hdrInfo.len = RLC_LI_LEN;
892 rlcAmmExtractElmnt(gCb, pdu, &hdrInfo);
893 /* li = hdrInfo.val;*/
895 /* check if LI is zero */
898 DU_LOG("\nERROR --> RLC_UL : Received LI as 0");
902 /* store the extracted LI value */
903 amHdr->li[amHdr->numLi++] = hdrInfo.val;
904 totalSz += hdrInfo.val; /* incrment the size by LI value */
907 /*ccpu00122597:PDU is dropped if liCnt exceeds RLC_MAX_LI*/
908 if(e && (amHdr->numLi >= RLC_MAX_UL_LI))
910 DU_LOG("\nERROR --> RLC_UL : LI Count [%u] exceeds Max LI Count[%u]",
911 amHdr->numLi, RLC_MAX_UL_LI);
915 /* first 2 bytes + Add one for Odd LI*/
916 pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
918 if ( totalSz >= pduSz )
920 DU_LOG("\nERROR --> RLC_UL : SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
921 amHdr->sn, totalSz, pduSz);
930 * @brief Private handler to process the status PDU
933 * Private handler invokded by rlcAmmProcessPdus to process the
934 * control PDU (status report) received from its peer RLC entity.
936 * - Decode the values from the received control pdu
937 * - Create a RlcUdxStaPdu structure, copy the values onto it and
938 * send it to the DL instance for further processing
940 * @param[in] gCb RLC instance control block
941 * @param[in] rbCb Uplink RB control block
942 * @param[in] cntrlPdu Control PDU received from MAC
943 * @param[in] fByte First byte already removed from the STATUS PDU
948 static void rlcAmmUlHndlStatusPdu(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *cntrlPdu, uint8_t *fByte)
952 RlcUdxStaPdu *pStaPdu;
953 RlcUdxUlSapCb *sapCb;
954 uint8_t e3; /* NACK RANGE : 5GNR */
957 uint32_t resrvdBitsAckSn=0;
958 uint32_t resrvdBitsNackSn=0;
960 RLC_MEM_ZERO(&hdrInfo, sizeof(RlcExtHdr));
962 /* Extract the Control PDU */
963 hdrInfo.hdr = (*fByte << 1);
966 /* D/C has been shifted in the calling function */
967 if (hdrInfo.hdr & 0xE0)
969 DU_LOG("\nINFO --> RLC_UL : rlcAmmUlHndlStatusPdu: Reserved value for CPT received UEID:%d \
970 CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
974 sapCb = RLC_GET_UDX_SAP(gCb);
976 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
979 sizeof(RlcUdxStaPdu));
981 #if (ERRCLASS & ERRCLS_ADD_RES)
982 /* Memory allocation failure can not be expected */
989 if (rbCb->m.amUl.snLen == RLC_AM_CFG_12BIT_SN_LEN)
992 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_12BITS;
993 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_12BITS;
995 else if (rbCb->m.amUl.snLen == RLC_AM_CFG_18BIT_SN_LEN)
998 resrvdBitsAckSn = RLC_STA_PDU_R_BITS_ACKSN_18BITS;
999 resrvdBitsNackSn = RLC_STA_PDU_R_BITS_NACKSN_18BITS;
1004 resrvdBitsAckSn = 0;
1005 resrvdBitsAckSn = 0;
1008 pStaPdu->nackCnt = 0;
1010 hdrInfo.hdr = hdrInfo.hdr << RLC_CPT_LEN;
1013 hdrInfo.len = snLen;
1014 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1015 pStaPdu->ackSn = hdrInfo.val;
1017 //DU_LOG ("\nINFO --> RLC_UL : ++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n", pStaPdu->ackSn);
1018 /* Check if NACK Exists */
1019 hdrInfo.len = RLC_E1_LEN;
1020 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1021 e1 = (uint8_t)hdrInfo.val;
1022 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1023 pStaPdu->ackSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1025 /* Extract the Reserved Bits after ACK SN field */
1026 hdrInfo.len = resrvdBitsAckSn;
1027 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1029 /* If NACK exists in control PDU */
1030 /* For ACKs and NACKs */
1031 while (e1 && (pStaPdu->nackCnt < RLC_MAX_NACK_CNT))
1033 hdrInfo.len = snLen;
1034 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1035 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1037 hdrInfo.len = RLC_E1_LEN;
1038 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1039 e1 = (uint8_t)hdrInfo.val;
1042 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1044 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1045 /* e2 = (uint8_t) hdrInfo.val;*/
1047 /* Store e2 value */
1048 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (uint8_t) hdrInfo.val;
1050 /* Extract e3 : 5GNR */
1051 /* hdrInfo.len = RLC_E1_LEN; --> previusly stored value (for e1) is
1053 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1054 e3 = (uint8_t) hdrInfo.val;
1056 /* Extract Reserved Bits after NACK SN */
1057 hdrInfo.len = resrvdBitsNackSn;
1058 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1060 /* Test for resegmentation */
1061 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1063 hdrInfo.len = RLC_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1064 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1065 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1067 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1068 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
1070 DU_LOG("\nDEBUG --> RLC_UL : rlcAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1071 "UEID:%d CELLID:%d", pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1072 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd, rbCb->rlcId.ueId,
1073 rbCb->rlcId.cellId);
1078 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1079 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
1082 /* NACK RANGE Field is SET */
1085 /* Extract NACK range field */
1086 hdrInfo.len = RLC_NACK_RANGE_LEN;
1087 rlcAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1088 snRange = (uint8_t)hdrInfo.val;
1090 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1096 gRlcStats.amRlcStats.numULStaPduRcvd++;
1097 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1099 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1100 to the last NACK SN + 1 and discard the original ACK_SN*/
1101 if(pStaPdu->nackCnt == RLC_MAX_NACK_CNT)
1103 pStaPdu->ackSn = (pStaPdu->nackInfo[RLC_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1107 /* Parse & send Status PDU to RLC-DL */
1108 rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1114 * @brief Private handler to release all stored segments
1117 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to release the
1118 * stored segements in case a complete PDU is received later.
1120 * @param[in] gCb RLC instance control block
1121 * @param[in] recBuf Buffer that stores a received PDU or segments
1126 static void rlcAmmUlRlsAllSegs(RlcCb *gCb, RlcAmRecBuf *recBuf)
1130 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1131 while (seg != NULLP)
1133 ODU_PUT_MSG_BUF(seg->seg);
1134 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1135 RLC_FREE(gCb,seg, sizeof(RlcSeg));
1136 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1143 * @brief Private handler to store the received segment
1146 * Private handler invokded by rlcAmmUlPlacePduInRecBuf to add a received
1147 * segment in reception buffer of a RBCB.
1148 * - It is responsible for detecting duplicate segments
1149 * - Adding it at appropriate position in the received buffer
1150 * - Calling ExpByteSeg to set expSo field in the receiver buffer
1152 * @param[in] gCb RLC instance control block
1153 * @param[in] rbCb Radio Bearer Contro Block
1154 * @param[in] amHdr AM Header received
1155 * @param[in] pdu Buffer received other than the headers
1156 * @param[in] pduSz size of the PDU buffer received
1159 * -#TRUE Successful insertion into the receiver buffer
1160 * -#FALSE Possibly a duplicate segment
1162 static bool rlcAmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu, uint16_t pduSz)
1164 RlcAmRecBuf *recBuf = NULLP;
1167 uint16_t soEnd; /* Holds the SoEnd of received segment */
1168 uint16_t expSo = 0; /* Expected SO */
1170 soEnd = amHdr->so + pduSz - 1;
1171 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, amHdr->sn);
1173 if (NULLP == recBuf)
1175 RLC_ALLOC(gCb,recBuf, sizeof(RlcAmRecBuf));
1176 #if (ERRCLASS & ERRCLS_ADD_RES)
1177 if (recBuf == NULLP)
1179 DU_LOG("\nERROR --> RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1180 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1182 ODU_PUT_MSG_BUF(pdu);
1185 #endif /* ERRCLASS & ERRCLS_RES */
1186 rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, amHdr->sn);
1190 if (recBuf->allRcvd == TRUE)
1192 ODU_PUT_MSG_BUF(pdu);
1197 recBuf->isDelvUpperLayer = FALSE;
1198 /* kw003.201 - Move past the segments that are different than the */
1200 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1201 while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1203 expSo = seg->amHdr.so + seg->segSz;
1204 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1207 /* The received segment should start after the end of previous seg */
1208 if (expSo > amHdr->so)
1210 /* This is a duplicate segment */
1211 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1212 ODU_PUT_MSG_BUF(pdu);
1216 if ((seg) && (seg->amHdr.so <= soEnd))
1218 /* This is a duplicate segment */
1219 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1220 ODU_PUT_MSG_BUF(pdu);
1224 /* If we have come this far, we have to add this segment to the */
1225 /* reception buffer as we either have eliminated duplicates or */
1226 /* have found none. */
1227 RLC_ALLOC_WC(gCb,tseg, sizeof(RlcSeg));
1228 #if (ERRCLASS & ERRCLS_ADD_RES)
1231 DU_LOG("\nERROR --> RLC_UL : rlcAmmAddRcvdSeg: Memory allocation failed UEID:%d CELLID:%d",
1232 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1233 ODU_PUT_MSG_BUF(pdu);
1236 #endif /* ERRCLASS & ERRCLS_RES */
1239 tseg->segSz = pduSz;
1240 RLC_MEM_CPY(&tseg->amHdr, amHdr, sizeof(RlcAmHdr));
1241 recBuf->amHdr.si = amHdr->si;
1242 recBuf->amHdr.sn = amHdr->sn;
1243 tseg->soEnd = soEnd;
1246 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1250 recBuf->segLst.crnt = &seg->lstEnt;
1251 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1253 tseg->lstEnt.node = (PTR)tseg;
1254 rlcAmmUpdExpByteSeg(gCb,&RLC_AMUL,tseg);
1260 * @brief Private handler to place the PDU in the reception buffer
1263 * This function checks if the received PDU's SN falls within the
1264 * receiving window, after which it places the same in the reception
1265 * buffer if its not a duplicate.
1267 * @param[in] gCb RLC instance control block
1268 * @param[in] pdu Received PDU
1269 * @param[in] rbCb Uplink AM Radio Bearer
1270 * @param[out] amUl AM UL Info
1277 static bool rlcAmmUlPlacePduInRecBuf(RlcCb *gCb, Buffer *pdu, RlcUlRbCb *rbCb, RlcAmHdr *amHdr)
1281 RlcAmUl *amUl = &(rbCb->m.amUl);
1284 SFndLenMsg(pdu, &pduSz);
1286 gCb->genSts.bytesRecv += pduSz;
1287 gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz;
1288 if (!RLC_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1290 gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1291 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlPlacePduInRecBuf: SN %d outside the window"
1292 "UEID:%d CELLID:%d", sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1294 gCb->genSts.unexpPdusRecv++;
1295 ODU_PUT_MSG_BUF(pdu);
1301 RlcAmRecBuf *recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1303 /* We received a complete PDU. Either we already have it, in which */
1304 /* case we just ignore the new PDU and discard it. Otherwise, */
1305 /* store the received PDU in the reception buffer */
1306 if (NULLP == recBuf)
1308 RLC_ALLOC(gCb, recBuf, sizeof(RlcAmRecBuf));
1309 #if (ERRCLASS & ERRCLS_ADD_RES)
1310 if (recBuf == NULLP)
1312 DU_LOG("\nERROR --> RLC_UL : rlcAmmUlPlacePduInRecBuf: Memory allocation failed \
1313 UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1314 ODU_PUT_MSG_BUF(pdu);
1317 #endif /* ERRCLASS & ERRCLS_RES */
1318 rlcUtlStoreRecBuf(RLC_AMUL.recBufLst, recBuf, sn);
1320 else if (recBuf->allRcvd != TRUE)
1322 rlcAmmUlRlsAllSegs(gCb,recBuf);
1326 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1327 gCb->genSts.unexpPdusRecv++;
1328 ODU_PUT_MSG_BUF(pdu);
1331 recBuf->isDelvUpperLayer = FALSE;
1333 recBuf->pduSz = pduSz;
1334 recBuf->allRcvd = TRUE;
1335 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1336 RLC_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(RlcAmHdr));
1341 /* We received a segment. We need to add that to the existing */
1342 /* segments, if any. */
1343 return (rlcAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1348 * @brief Private handler to trigger status report
1351 * Private handler invokded by rlcAmmProcessPdus to check if the
1352 * status report need to be sent, and update the status trigger
1353 * flag accordingly based on status prohibit timer.
1355 * - Check if the received pdu's sn is less than rxHighestStatus, set the
1357 * - If staProhTmr is not running, calculate cntrlBo, else it'll be
1358 * updated at the expiry of staProhTmr.
1359 * - Expiry of reOrdTmr also will set staTrg flag.
1361 * @param[in] gCb RLC instance control block
1362 * @param[in] rbCb Uplink RB control block
1363 * @param[in] sn Sequence number of the pdu based on which to check if
1364 * status needs to be triggered
1365 * @param[in] discFlg Whether this pdu was discarded or not
1370 static void rlcAmmTriggerStatus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcSn sn, bool discFlg)
1375 RlcSn trxHighestStatus;
1376 RlcAmUl *amUl = &(rbCb->m.amUl);
1378 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1379 MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1380 MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1382 /* kw005.201 Product CR ccpu00117114 *
1383 * The "=" in the 2nd condition is removed */
1384 if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1386 DU_LOG("\nINFO --> RLC_UL : rlcAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1387 rbCb->rlcId.ueId, rbCb->rlcId.cellId);
1389 amUl->staTrg = TRUE;
1390 amUl->gatherStaPduInfo = FALSE;
1392 /* Check if staProhTmr is running */
1393 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1397 amUl->gatherStaPduInfo = TRUE;
1405 * @brief Private handler to reassemble from a segment or a PDU
1408 * Private handler invokded by kwAmmReassembleSdus with either a
1409 * PDU or a segment of a PDU. This is also called in the case of
1410 * reestablishment and hence out of sequence joining is also to
1414 * @param[in] gCb RLC instance control block
1415 * @param[in] rbCb Uplink RB control block
1416 * @param[in] amHdr AM header received for this segment/PDU
1417 * @param[in] pdu PDU to be reassembled
1422 static void rlcAmmProcPduOrSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmHdr *amHdr, Buffer *pdu)
1425 if ((RLC_AMUL.expSn != amHdr->sn) || (RLC_AMUL.expSo != amHdr->so))
1427 /* Release the existing partial SDU as we have PDUs or */
1428 /* segments that are out of sequence */
1429 rbCb->m.amUl.isOutOfSeq = TRUE;
1430 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1433 //if (amHdr->fi & RLC_FI_FIRST_SEG)
1434 if (amHdr->si == 0x01)
1435 {/* first Segment of the SDU */
1436 if (RLC_AMUL.partialSdu != NULLP)
1437 { /* Some old SDU may be present */
1438 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1440 RLC_AMUL.partialSdu = pdu;
1443 else if(amHdr->si == 0x03)
1444 {/* Middle or last segment of the SUD */
1445 ODU_CAT_MSG(RLC_AMUL.partialSdu,pdu, M1M2);
1446 ODU_PUT_MSG_BUF(pdu);
1449 else if (amHdr->si == 0x02)
1451 ODU_CAT_MSG(pdu,RLC_AMUL.partialSdu,M2M1);
1452 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1457 RLC_AMUL.partialSdu = NULLP;
1458 rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
1466 * @brief Private handler to reassemble SDUs
1469 * Private handler invokded by rlcAmmProcessPdus with the PDU
1470 * from the reception buffer in sequence to reassemble SDUs and
1473 * - With the stored header info, FI and LSF segment / concatenate
1474 * PDUs or byte segments of PDUs to get the associated SDU.
1476 * @param[in] rbCb RB control block
1477 * @param[in] pdu PDU to be reassembled
1484 static uint8_t rlcAmmUlReassembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcAmRecBuf *recBuf)
1488 //if (recBuf->amHdr.rf == 0)
1489 if (recBuf->amHdr.si == 0)
1492 rlcAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1493 /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1494 recBuf->pdu = NULLP;
1495 RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1500 /* This is a set of segments */
1501 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1502 RLC_AMUL.expSn = recBuf->amHdr.sn;
1506 rlcAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1507 RLC_AMUL.expSo = seg->soEnd + 1;
1509 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1510 RLC_FREE(gCb, seg, sizeof(RlcSeg));
1512 RLC_LLIST_FIRST_SEG(recBuf->segLst, seg);
1514 RLC_AMUL.expSn = (recBuf->amHdr.sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1522 * @brief Handler to process the re-establishment request received from UIM
1524 * @param[in] gCb RLC instance control block
1525 * @param[in] rlcId RLC identifier
1526 * @param[in] sendReEst Whether to send back restablishment complete or not
1527 * @param[in] rbCb Uplink RB control block
1532 Void rlcAmmUlReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcUlRbCb *rbCb)
1539 RlcKwuSapCb *rlcKwuSap;
1541 RlcAmRecBuf *recBuf = NULLP;
1543 sn = RLC_AMUL.rxNext;
1545 MODAMR(RLC_AMUL.vrMr, mVrMr, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1546 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1548 /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1551 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1552 if (NULLP != recBuf)
1554 if (recBuf->allRcvd == TRUE)
1556 rlcAmmUlReassembleSdus(gCb,rbCb, recBuf);
1560 /* Remove PDU and segments */
1563 ODU_PUT_MSG_BUF(recBuf->pdu);
1565 /* Release all the segments*/
1566 rlcAmmUlRlsAllSegs(gCb,recBuf);
1568 rlcUtlDelRecBuf(RLC_AMUL.recBufLst, recBuf, gCb);
1570 sn = (sn + 1) & (RLC_AMUL.snModMask); /* MOD 1024 */
1571 MODAMR(sn, mSn, RLC_AMUL.rxNext, RLC_AMUL.snModMask);
1573 /* Discard remaining PDUs and bytesegments in recBuf */
1575 /* Stop all timers and reset variables */
1576 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REORD_TMR))
1578 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REORD_TMR);
1580 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1582 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1585 RLC_AMUL.rxNext = 0;
1586 RLC_AMUL.rxNextHighestRcvd = 0;
1587 RLC_AMUL.rxNextStatusTrig = 0;
1588 rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1589 RLC_AMUL.rxHighestStatus = 0;
1590 RLC_AMUL.staTrg = FALSE;
1591 RLC_AMUL.gatherStaPduInfo = FALSE;
1594 if (RLC_AMUL.partialSdu != NULLP)
1596 ODU_PUT_MSG_BUF(RLC_AMUL.partialSdu);
1598 rlcKwuSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
1602 RlcUiKwuReEstCmpInd(&rlcKwuSap->pst, rlcKwuSap->suId, rlcId);
1603 rbCb->m.amUl.isOutOfSeq = FALSE;
1610 * @brief Handler for reorder timer expiry
1613 * This function is used to handle events upon expiry of reorder timer
1615 * @param[in] gCb RLC instance control block
1616 * @param[in] rbCb RB control block
1622 Void rlcAmmReOrdTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1624 RlcAmUl *amUl = &(rbCb->m.amUl);
1628 RlcSn mrxHighestStatus;
1629 RlcSn mrxNextHighestRcvd;
1630 Bool tmrRunning = FALSE;
1631 RlcAmRecBuf *recBuf = NULLP;
1633 /* Update rxHighestStatus */
1634 sn = amUl->rxNextStatusTrig;
1636 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1637 MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1638 recBuf = rlcUtlGetRecBuf(RLC_AMUL.recBufLst, sn);
1642 if ((recBuf == NULLP) ||
1643 ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1645 amUl->rxHighestStatus = sn;
1646 amUl->staTrg = TRUE;
1647 amUl->gatherStaPduInfo = FALSE;
1649 /* Check if staProhTmr is running */
1650 tmrRunning = rlcChkTmr(gCb,(PTR) rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1654 gRlcStats.amRlcStats.numULReOrdTimerExpires++;
1655 amUl->gatherStaPduInfo = TRUE;
1656 rlcAmmUlAssembleCntrlInfo(gCb, rbCb);
1661 sn = (sn + 1) & (amUl->snModMask);
1662 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1665 /* Update rxNextStatusTrig */
1666 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1667 MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1668 if (mrxNextHighestRcvd > mrxHighestStatus)
1670 rlcStartTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REORD_TMR);
1671 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1675 } /* rlcAmmReOrdTmrExp */
1678 * @brief Handler for status prohibit timer expiry
1681 * This function is used to handle events upon expiry of status prohibit
1684 * @param[in] gCb RLC instance control block
1685 * @param[in] rbCb RB control block
1691 Void rlcAmmStaProTmrExp(RlcCb *gCb,RlcUlRbCb *rbCb)
1693 RlcAmUl *amUl = &(rbCb->m.amUl);
1695 amUl->gatherStaPduInfo = FALSE;
1697 if (amUl->staTrg == TRUE)
1699 amUl->gatherStaPduInfo = TRUE;
1700 /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
1701 rlcAmmUlAssembleCntrlInfo(gCb,rbCb);
1705 } /* rlcAmmStaProTmrExp */
1708 * @brief Handler to extract an element of AM Header
1711 * This function is used to extract an element of AM header.
1713 * @param[in] pdu The pdu to be decoded
1714 * @param[in,out] hdrInfo Container to hold the decoded info
1720 static void rlcAmmExtractElmnt(RlcCb *gCb, Buffer *pdu, RlcExtHdr *hdrInfo)
1723 uint8_t pLen = hdrInfo->pLen;
1724 uint8_t len = (uint8_t)hdrInfo->len;
1729 /* uint8_t rLen1 = 0; */
1736 ODU_REM_PRE_MSG(&hdr, pdu);
1742 val = tHdr >> (RLC_BYTE_LEN - (len));
1746 else /*if (len > 8) */
1750 val = val >> (RLC_BYTE_LEN - fLen);
1751 val = val << (len - fLen);
1753 ODU_REM_PRE_MSG(&hdr, pdu);
1757 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1760 pLen = (RLC_BYTE_LEN - rLen);
1764 rLen = rLen - RLC_BYTE_LEN;
1766 tVal = tVal << rLen;
1769 ODU_REM_PRE_MSG(&hdr, pdu);
1771 hdr = hdr >> (RLC_BYTE_LEN - rLen);
1774 pLen = (RLC_BYTE_LEN - rLen);
1778 hdrInfo->pLen = pLen;
1786 * @brief Handler to updated expected byte seg
1789 * This function is used to update expected byte segment. The next segment
1790 * expected is indicated by the SO of the segment which is expected. Intially
1791 * the segment with SO 0 is expected and then in order. When all the segments
1792 * are received (which would happen when an expected SO is encountered
1793 * with LSF set) the allRcvd flag is set to TRUE
1795 * @param[in] gCb RLC instance control block
1796 * @param[in] amUl AM Uplink Control Block
1797 * @param[in] seg Newly received segment
1803 static void rlcAmmUpdExpByteSeg(RlcCb *gCb, RlcAmUl *amUl, RlcSeg *seg)
1805 uint16_t newExpSo; /* The new expected SO */
1806 RlcSn sn = seg->amHdr.sn;
1808 RlcAmRecBuf *recBuf = NULLP;
1810 recBuf = rlcUtlGetRecBuf(amUl->recBufLst, sn);
1811 if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
1816 newExpSo = seg->soEnd + 1;
1817 recBuf->expSo = newExpSo;
1818 //lstRcvd = seg->amHdr.lsf;
1819 if(seg->amHdr.si == 0x2)
1823 /* kw003.201 - This should update seg with the one after newSeg */
1824 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1827 /* keep going ahead as long as the expectedSo match with the header so
1828 else store the expSo for later checking again */
1829 if(seg->amHdr.si == 0x2)
1833 if (seg->amHdr.so == newExpSo)
1835 newExpSo = seg->soEnd + 1;
1836 recBuf->expSo = newExpSo;
1837 //lstRcvd = seg->amHdr.lsf;
1838 RLC_LLIST_NEXT_SEG(recBuf->segLst, seg);
1842 recBuf->expSo = newExpSo;
1846 if (lstRcvd == TRUE)
1848 recBuf->allRcvd = TRUE;
1849 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1857 * Function to release/free the Acknowledged Mode Module RbCb buffers
1860 * This primitive Frees the AM RbCb transmission Buffer, retransmission
1861 * Buffer and reciption Buffers
1863 * @param [in] gCb - RLC instance Control Block
1864 * @param [in] rbCb - RB Control Block
1868 Void rlcAmmFreeUlRbCb(RlcCb *gCb,RlcUlRbCb *rbCb)
1870 RlcSn curSn = 0; /* Sequence number of PDU */
1871 RlcSn windSz; /* PDU window size */
1872 RlcAmRecBuf *recBuf = NULLP;
1874 windSz = (RLC_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
1876 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_REORD_TMR))
1878 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_REORD_TMR);
1880 if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_AMUL_STA_PROH_TMR))
1882 rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_AMUL_STA_PROH_TMR);
1886 /* on the first loop winSz is always greater than zero
1887 while( ( curSn < windSz ) hence changing to do while */
1890 recBuf = rlcUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
1891 if ( recBuf != NULLP )
1893 if (recBuf->pdu != NULLP)
1895 ODU_PUT_MSG_BUF(recBuf->pdu);
1897 /* Release all the segments */
1898 rlcAmmUlRlsAllSegs(gCb,recBuf);
1899 rlcUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
1902 }while ( curSn < windSz );
1905 RLC_FREE(gCb,rbCb->m.amUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
1906 rbCb->m.amUl.recBufLst = NULLP;
1909 if(rbCb->m.amUl.partialSdu != NULLP)
1911 ODU_PUT_MSG_BUF(rbCb->m.amUl.partialSdu);
1914 } /* rlcAmmFreeUlRbCb */
1920 /********************************************************************30**
1923 **********************************************************************/