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 "envopt.h" /* environment options */
44 #include "envdep.h" /* environment dependent */
45 #include "envind.h" /* environment independent */
47 #include "gen.h" /* general */
48 #include "ssi.h" /* system services */
49 #include "cm5.h" /* common timer defines */
50 #include "cm_tkns.h" /* common tokens defines */
51 #include "cm_mblk.h" /* common memory allocation library defines */
52 #include "cm_llist.h" /* common link list defines */
53 #include "cm_hash.h" /* common hash list defines */
54 #include "cm_lte.h" /* common LTE defines */
55 #include "lkw.h" /* LKW defines */
56 #include "ckw.h" /* CKW defines */
57 #include "kwu.h" /* KWU defines */
58 #include "rgu.h" /* RGU defines */
60 #include "kw_err.h" /* Err defines */
61 #include "kw_env.h" /* RLC environment options */
63 #include "kw.h" /* RLC defines */
66 /* extern (.x) include files */
67 #include "gen.x" /* general */
68 #include "ssi.x" /* system services */
70 #include "cm5.x" /* common timer library */
71 #include "cm_tkns.x" /* common tokens */
72 #include "cm_mblk.x" /* common memory allocation */
73 #include "cm_llist.x" /* common link list */
74 #include "cm_hash.x" /* common hash list */
75 #include "cm_lte.x" /* common LTE includes */
76 #include "cm_lib.x" /* common memory allocation library */
77 #include "lkw.x" /* LKW */
78 #include "ckw.x" /* CKW */
79 #include "kwu.x" /* KWU */
80 #include "rgu.x" /* RGU */
86 /* Variable for logging, declared in cl */
87 #ifndef RGL_SPECIFIC_CHANGES
90 extern U32 ulrate_rgu;
94 #ifndef RGL_SPECIFIC_CHANGES
96 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
98 extern U32 isMemThreshReached(Region region);
102 extern U32 isMemThreshReached(Region region);
107 /** @file gp_amm_ul.c
108 @brief RLC Acknowledged Mode Uplink Module
110 #define KW_MODULE (KW_DBGMASK_AM | KW_DBGMASK_UL) /* for debugging purpose */
112 /* private function declarations */
114 PRIVATE Void kwAmmUlAssembleCntrlInfo ARGS ((KwCb *gCb, KwUlRbCb *rbCb));
116 PRIVATE S16 kwAmmExtractHdr ARGS ((KwCb *gCb,
122 PRIVATE Bool kwAmmUlPlacePduInRecBuf ARGS ((KwCb *gCb,
127 PRIVATE Void kwAmmTriggerStatus ARGS ((KwCb *gCb,
132 PRIVATE S16 kwAmmUlReassembleSdus ARGS ((KwCb *gCb,
134 KwAmRecBuf *recBuf));
136 PRIVATE Void kwAmmProcPduOrSeg ARGS ((KwCb *gCb,
141 PRIVATE Void kwAmmUpdExpByteSeg ARGS ((KwCb *gCb,KwAmUl *amUl, KwSeg* newSeg));
143 PRIVATE Void kwAmmExtractElmnt ARGS ((KwCb *gCb, Buffer *pdu, KwExtHdr *hdrInfo));
145 PRIVATE Void kwAmmUlHndlStatusPdu ARGS ((KwCb *gCb,
150 /******************************************************************************
152 AM Module contains the following funcitons:
155 - kwAmmUlAssembleCntrlInfo
160 - kwAmmUlHndlStatusPdu
162 - kwAmmUlReassembleSdus
164 *******************************************************************************/
165 /** @addtogroup ammode */
169 * @brief Private function to fill NACK information in status Pdu as per 5GNR
171 * @param[in] rbCb Ul RbCb
172 * @param[in] sn Sequence number of the PDU for which the NACK
173 * @param[in] isSegment TRUE means NACK for segment; FALSE for PDU
174 * @param[in] soStart SOStart
175 * @param[in] soEnd SOEnd
176 * @param[out] statusPdu status Pdu holder to be filled
177 * @param[in] prevNackSn It holds previous nack Sn
180 * The number of bytes required to encode this NACK information
184 PRIVATE S16 kwAmmUlSetNackInfo
191 KwUdxDlStaPdu *statusPdu,
195 PRIVATE S16 kwAmmUlSetNackInfo(rbCb, sn, isSegment, soStart, statusPdu, prevNackSn)
201 KwUdxDlStaPdu *statusPdu,
205 KwNackInfo *nackInfo = (statusPdu->nackInfo + statusPdu->nackCount);
206 S16 sizeToBeEncd = 0; /* Status PDu size to be encoded */
208 TRC2(kwAmmUlSetNackInfo)
210 /* In following cases we should increment the nackCnt & fill new NACK_SN info:
211 * 1) First NACK_SN of the statusdPdu
212 * 2) NACK_SN is not continuous with previous
213 * 3) NACK_SN is same as previuos but segments are not continuous
214 * 4) NACK_SN is continuous with previous but previous NACK_SN segments
215 * are not missing in sequence till end
217 if((*prevNackSn == 0xffffffff) || ((((*prevNackSn) + 1) & AMUL.snModMask) != sn) ||
218 (((*prevNackSn) == sn) && (((nackInfo->soEnd + 1) != soStart))) ||
219 ((nackInfo->isSegment) && (((*prevNackSn) + 1) == sn) && (nackInfo->soEnd != KW_ALL_BYTES_MISSING)))
221 if(nackInfo->nackRange)
223 if((nackInfo->soEnd) && (!nackInfo->soStart))
225 /*First nack_sn of this nackRange not segmented but last is segmented */
226 sizeToBeEncd = 5; /*32 for soStart and soEnd and 8 for nackRange */
230 /*First nack_sn of this nackRange was segmented */
231 sizeToBeEncd = 1; /*8 for nackRange */
235 if(*prevNackSn != 0xffffffff)
237 /* Increment nackCount as this sn is continous */
238 statusPdu->nackCount++;
239 nackInfo = statusPdu->nackInfo + statusPdu->nackCount;
243 nackInfo->isSegment = isSegment;
244 nackInfo->soStart = soStart;
245 nackInfo->soEnd = soEnd;
246 nackInfo->nackRange = 0;
250 sizeToBeEncd += ((AMUL.snLen == KW_AM_CFG_12BIT_SN_LEN)?6:7); /* NACK,E1,E2,Sostart,SoEnd */
254 sizeToBeEncd += ((AMUL.snLen == KW_AM_CFG_12BIT_SN_LEN)?2:3); /* NACK,E1,E2 */
259 if(!(nackInfo->nackRange))
261 nackInfo->nackRange++;
263 /* This case means there are continuous SNs/Segments. If it is the next
264 * Sn then increment nackRnage. if same SN but different segment then
265 * dont increment nackRange */
266 if((((*prevNackSn) + 1) & AMUL.snModMask) == sn)
268 nackInfo->nackRange++;
271 /* If NackRange is reached to max value then increment statusPdu->nackCount*/
272 if(nackInfo->nackRange == 255)
274 statusPdu->nackCount++;
275 if(nackInfo->isSegment)
277 sizeToBeEncd = 1; /* return only nackRangeSize*/
281 /* First SN was not segmented of this nackRange but last SN is segmented */
282 sizeToBeEncd = 5; /* return size of soSatrt + soEnd + nackRnage */
288 nackInfo->isSegment = isSegment;
289 nackInfo->soEnd = soEnd;
291 else if(nackInfo->isSegment)
293 nackInfo->soEnd = KW_ALL_BYTES_MISSING;
297 nackInfo->soStart = 0;
304 RETVALUE(sizeToBeEncd);
308 * @brief Private handler to gather information required to create the STATUS
312 * Scans the reception buffer and copies information to the UdxDlStaPdu
313 * structure about SN's and segments not yet received. This data is
314 * sent to the DL instance so that it can create an appropriate (depending
315 * on the grants from MAC) STATUS PDU and send it to MAC.
317 * @param[in] gCb RLC instance control block
318 * @param[in] rbCb Uplink RB control block
324 PRIVATE Void kwAmmUlAssembleCntrlInfo
330 PRIVATE Void kwAmmUlAssembleCntrlInfo(gCb, rbCb)
335 KwUdxDlStaPdu *pStatusPdu;
336 KwNackInfo *nackInfo;
337 KwSn sn; /* sequence number */
338 KwSn mSn; /* Mod val of sequence number */
339 KwSn rxHighestStatus; /* Mod val of rxHighestStatus */
340 KwSeg *seg; /* pdu segment */
341 U16 nackCnt = 0; /* Index for staPdu */
342 U16 seqSo; /* segmment offset */
344 U16 staPduEncSize = 3; /* size that would be of the encoded
345 STATUS PDU, it is in bits; 15 for
346 first fixed part of STATUS PDU */
347 KwAmRecBuf *recBuf = NULLP;
348 KwSn prevNackSn = 0xffffffff;
350 TRC2(kwAmmUlAssembleCntrlInfo)
353 sapCb = KW_GET_UDX_SAP(gCb);
355 KW_ALLOC_SHRABL_BUF(sapCb->pst.region,
358 sizeof(KwUdxDlStaPdu));
360 #if (ERRCLASS & ERRCLS_ADD_RES)
361 /* Memory allocation failure can not be expected */
369 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
370 MODAMR(AMUL.rxHighestStatus, rxHighestStatus, AMUL.rxNext, AMUL.snModMask);
372 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
374 while (mSn < rxHighestStatus )
376 /* For missing PDUs */
377 if ((NULLP == recBuf) && nackCnt < KW_MAX_NACK_CNT )
379 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
380 "Missing PDU's SN = %d UEID:%d CELLID:%d",
384 staPduEncSize += kwAmmUlSetNackInfo(rbCb,
386 FALSE, /* isSegment */
392 else if (recBuf && (recBuf->pdu == NULLP) &&
393 (recBuf->segLst.count > 0))
395 /* Scan through the byte segments of PDU and add this sn
396 with soStart and soEnd info to staPdu */
399 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
400 while (seg != NULLP && nackCnt < KW_MAX_NACK_CNT)
402 /* For missing byte segments */
403 if (seg->amHdr.so != seqSo)
405 staPduEncSize += kwAmmUlSetNackInfo(rbCb,
413 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
414 "Missing byte segment's"
415 " SN:%d UEID:%d CELLID:%d",
419 RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
420 "soStart and soEnd = %d, %d UEID:%d CELLID:%d",
427 seqSo = seg->soEnd + 1;
428 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
431 /* Check if the last segment is missing */
432 KW_LLIST_LAST_SEG(recBuf->segLst, seg);
433 if ((seg != NULLP) &&
434 (seg->amHdr.si != KW_SI_LAST_SEG && nackCnt < KW_MAX_NACK_CNT))
436 staPduEncSize += kwAmmUlSetNackInfo(rbCb,
440 KW_ALL_BYTES_MISSING,
444 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
445 "kwAmmUlAssembleCntrlInfo: Missing (last) byte "
446 "segment's SN:%d UEID:%d CELLID:%d",
450 RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
451 "soStart and soEnd = %d, %d UEID:%d CELLID:%d",
453 KW_ALL_BYTES_MISSING,
460 sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
461 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
463 /* Get the received Buffer the updated/next SN */
464 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
466 /* Find the next missing sequence number if nackCnt reaches maximum and
467 still Reordering window has some missing AMDPDUs / AMDPDU segments. The
468 next missing sequence number will be considered as the ack sequnece
469 number in the status pdu.*/
470 if((nackCnt == KW_MAX_NACK_CNT) &&
471 ((recBuf == NULLP) ||
472 ((recBuf->pdu == NULLP) &&
473 (recBuf->segLst.count > 0))))
479 /*Unfortunately i have write below peice of code here because kwAmmsetNackInfo()
480 * don't know that this is the last nackSn with nackRange*/
481 nackInfo = &(pStatusPdu->nackInfo[pStatusPdu->nackCount]);
482 if(nackInfo->nackRange)
484 if((nackInfo->soEnd) && (!nackInfo->soStart))
486 /*First nack_sn of this nackRange not segmented but last is segmented */
487 staPduEncSize += 5; /*32 for soStart and soEnd and 8 for nackRange */
491 /*First nack_sn of this nackRange was segmented */
492 staPduEncSize += 1; /*8 for nackRange */
495 /* nackCount is used as an index to nackInfo array but in status Pdu it
496 * should be equal to number nackInfo that are filled. hence incrementing by 1*/
497 if(prevNackSn != 0xffffffff)
499 pStatusPdu->nackCount++;
501 /* Update ACK SN with the last sn for which feedback is not assembled */
502 if ( mSn == rxHighestStatus)
504 pStatusPdu->ackSn = AMUL.rxHighestStatus;
508 pStatusPdu->ackSn = sn;
511 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
512 "kwAmmUlAssembleCntrlInfo: ACK PDU's SN = %d"
518 pStatusPdu->controlBo = staPduEncSize; /*Its already in bytes */
521 AMUL.gatherStaPduInfo = FALSE;
524 if (KwUlUdxStaPduReq(&sapCb->pst,
529 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
530 "Failed to Send Sta Pdu UEID:%d CELLID:%d",
533 KW_FREE_SHRABL_BUF_WC(sapCb->pst.region,
536 sizeof(KwUdxDlStaPdu));
542 #ifdef XEON_SPECIFIC_CHANGES
543 extern U32 gRlcDatIndUL;
546 #ifdef T2K_TRIGGER_RLC_REEST
547 PUBLIC U32 drpRlcDrbPack;
550 * @brief Handler to process the PDUs received from MAC and send it to PDCP
553 * This function is invoked by UTL with the PDU(s) received from MAC.
554 * It reorders the received data PDUs and trigger status report as
555 * needed. Reassembles the SDUs in sequence and send it to PDCP.
556 * It also processes the control PDU
558 * @param[in] gCb RLC instance control block
559 * @param[in] rbCb RB control block
560 * @param[out] pduInfo PDU Info received from MAC
567 PUBLIC Void kwAmmProcessPdus
575 PUBLIC Void kwAmmProcessPdus(gCb, rbCb, pduInfo, ulTimeInfo)
583 PUBLIC Void kwAmmProcessPdus
590 PUBLIC Void kwAmmProcessPdus(gCb, rbCb, pduInfo)
607 #ifdef LTE_L2_MEAS_RLC
608 MsgLen rlcSduSz; /*Holds length of Rlc Sdu*/
609 #endif /* LTE_L2_MEAS */
611 TRC2(kwAmmProcessPdus)
616 numPduToProcess = KW_MIN(pduInfo->numPdu, RGU_MAX_PDU);
617 RLOG_ARG4(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
618 "numPdu[%ld],numPduToProcess[%ld] UEID:%ld CELLID:%ld",
624 //printf ("++++++++++++ 5GNRLOG numPduToProcess %d \n", numPduToProcess);
625 while (numPdu < numPduToProcess)
627 //printf ("++++++++++++ 5GNRLOG processing pdu %d \n", numPdu);
629 pdu = pduInfo->mBuf[numPdu++];
634 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
635 "Null Pdu UEID:%d CELLID:%d",
638 gCb->genSts.errorPdusRecv++;
641 #ifndef RGL_SPECIFIC_CHANGES
645 SFndLenMsg(pdu, &len);
650 /* Extract AM PDU/SEG header Info */
651 KW_MEM_ZERO(&amHdr, sizeof(KwAmHdr));
652 /* Avoided the allocation of amHdr and sending
654 if (kwAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
656 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
657 "Header Extraction Failed UEID:%d CELLID:%d",
661 gCb->genSts.errorPdusRecv++;
664 /* Check if its a control PDU */
667 kwAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
671 if((amHdr.si == KW_SI_LAST_SEG) && (!amHdr.so))
673 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
674 "kwAmmProcessPdus: Dropping PDU because SO can't be zero for last segment sn:%u "
682 #ifndef RGL_SPECIFIC_CHANGES
685 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
687 /* Changed the condition to TRUE from ROK */
688 if(isMemThreshReached(kwCb[0]->init.region) == TRUE)
690 extern U32 rlculdrop;
698 /*ccpu00142274 - UL memory based flow control*/
699 if(isMemThreshReached(kwCb[0]->init.region) != ROK)
701 extern U32 rlculdrop;
712 #ifdef T2K_TRIGGER_RLC_REEST
713 if(drpRlcDrbPack > 1000)
715 if(rbCb->rlcId.rbType == CM_LTE_DRB)
723 /* Reordering data PDU */
725 if (kwAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
730 KwSn mrxNextHighestRcvd;
733 kwUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
734 #endif /* LTE_L2_MEAS */
736 /* Update rxNextHighestRcvd */
737 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
738 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
739 if (mSn >= mrxNextHighestRcvd)
741 amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask));
743 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
744 "kwAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
745 amUl->rxNextHighestRcvd,
750 recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
751 if ((NULLP != recBuf) && ( recBuf->allRcvd))
753 /* deliver the reassembled RLC SDU to upper layer,
754 But not removed from the table */
755 kwAmmUlReassembleSdus(gCb, rbCb, recBuf);
756 recBuf->isDelvUpperLayer = TRUE;
758 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
760 /* Update rxHighestStatus */
761 if (sn == amUl->rxHighestStatus)
763 tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
765 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
766 /* Scan through till the upper edge of the window */
767 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
770 if ((NULLP == recBuf) || (!recBuf->allRcvd))
772 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
773 "kwAmmProcessPdus: Updated rxHighestStatus:%d "
779 amUl->rxHighestStatus = tSn;
782 tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
783 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
790 if (sn == amUl->rxNext)
793 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
794 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
795 /* Scan through till the upper edge of the window */
798 if ((NULLP != recBuf) && (recBuf->allRcvd) &&
799 (TRUE == recBuf->isDelvUpperLayer))
801 /* RecBuf should remove from table
802 since PDU is already sent to upper layer */
803 recBuf->isDelvUpperLayer = FALSE;
804 kwUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
809 amUl->vrMr = (amUl->rxNext + (KW_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
812 tSn = (tSn + 1) & (amUl->snModMask);
813 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
819 /* Check if reOrdTmr is running and update rxNextStatusTrig accordingly */
820 tmrRunning = kwChkTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
823 Bool snInWin = KW_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
825 if ( (amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
826 (amUl->rxNextStatusTrig != amUl->vrMr) ) )
828 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
835 if (amUl->rxNextHighestRcvd > amUl->rxNext)
837 kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
838 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
840 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
841 "kwAmmProcessPdus: Updated rxNextStatusTrig = %d UEID:%d CELLID:%d",
842 amUl->rxNextStatusTrig,
851 gRlcStats.amRlcStats.numULPdusDiscarded++;
856 kwAmmTriggerStatus(gCb,rbCb, sn, discFlg);
861 kwUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
862 #endif /* LTE_L2_MEAS */
863 gCb->genSts.pdusRecv += pduInfo->numPdu;
864 if (amUl->gatherStaPduInfo)
866 kwAmmUlAssembleCntrlInfo(gCb,rbCb);
874 * @brief Private handler to extract header Information of the PDU
877 * This function extracts the header elements of the PDU and store them
878 * in db for future reference.
880 * fByte - is the first byte removed from the PDU as part of calling
883 * @param[in] gCb RLC instance control block
884 * @param[in] rbCb Uplink RB control block
885 * @param[in] pdu Received PDU
886 * @param[out] amHdr Pointer to the extracted AM header
887 * @param[out] fByte First byte removed from the PDU
895 PRIVATE S16 kwAmmExtractHdr
904 PRIVATE S16 kwAmmExtractHdr(gCb, rbCb, pdu, amHdr, fByte)
917 TRC2(kwAmmExtractHdr)
920 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
922 /* Extract fixed part of the header */
923 SFndLenMsg(pdu,&pduSz);
924 SRemPreMsg(fByte, pdu);
925 amHdr->dc = (*fByte & KW_DC_POS) >> KW_DC_SHT;
926 if (KW_CNTRL_PDU == amHdr->dc)
928 //printf ("++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
932 amHdr->p = (*fByte & KW_POLL_POS) >> KW_POLL_SHT;
934 amHdr->si = (*fByte & KW_SI_POS) >> KW_SI_SHT;
937 if (rbCb->m.amUl.snLen == KW_AM_CFG_12BIT_SN_LEN)
939 SRemPreMsg(&snByte, pdu);
940 sn = (KwSn)(((*fByte & KW_SN_POS_12BIT) << KW_BYTE_LEN ) | snByte);
943 else if (rbCb->m.amUl.snLen == KW_AM_CFG_18BIT_SN_LEN)
945 SRemPreMsg(&snByte, pdu);
946 sn = (KwSn)(((*fByte & KW_SN_POS_18BIT) << KW_BYTE_LEN ) | snByte);
948 SRemPreMsg(&snByte, pdu);
949 sn = ((sn << KW_BYTE_LEN) | snByte);
953 if ((amHdr->si != 0) && (amHdr->si != 0x01))
955 hdrInfo.len = KW_SO_LEN_5GNR;
956 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
957 amHdr->so = hdrInfo.val;
961 //printf ("++++++++++++ 5GNRLOG HDR extracted DATA : sn %d \n", sn);
967 * @brief Private handler to extract header Information of the PDU
970 * This function extracts the header elements of the PDU and store them
971 * in db for future reference.
973 * fByte - is the first byte removed from the PDU as part of calling
976 * @param[in] gCb RLC instance control block
977 * @param[in] rbCb Uplink RB control block
978 * @param[in] pdu Received PDU
979 * @param[out] amHdr Pointer to the extracted AM header
980 * @param[out] fByte First byte removed from the PDU
988 PRIVATE S16 kwAmmExtractHdrOld
996 PRIVATE S16 kwAmmExtractHdrOld(gCb, pdu, amHdr, fByte)
1010 TRC2(kwAmmExtractHdrOld)
1013 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
1015 /* Extract fixed part of the header */
1016 SFndLenMsg(pdu,&pduSz);
1017 SRemPreMsg(fByte, pdu);
1018 amHdr->dc = (*fByte & KW_DC_POS) >> KW_DC_SHT;
1019 if (KW_CNTRL_PDU == amHdr->dc)
1023 /* kw002.201 : Changed the extraction of hdr elements to avoid */
1024 /* function calls */
1025 amHdr->rf = (*fByte & KW_RF_POS) >> KW_RF_SHT;
1026 amHdr->p = (*fByte & KW_POLL_POS) >> KW_POLL_SHT;
1027 amHdr->fi = (*fByte & KW_FI_POS) >> KW_FI_SHT;
1028 e = amHdr->e = (*fByte & KW_E_POS)>> KW_E_SHT;
1030 SRemPreMsg(&snByte, pdu);
1031 sn = (U16)(((*fByte & KW_SN_POS) << KW_BYTE_LEN ) | snByte);
1035 /* Extract extn part of the header */
1036 hdrInfo.len = KW_LSF_LEN;
1037 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1038 amHdr->lsf = (U8)hdrInfo.val;
1040 hdrInfo.len = KW_SO_LEN;
1041 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1042 amHdr->so = hdrInfo.val;
1048 while (e && (amHdr->numLi < KW_MAX_UL_LI))
1050 hdrInfo.len = KW_E_LEN;
1051 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1052 e = amHdr->e = (U8)hdrInfo.val;
1054 /* Extract LI value*/
1055 hdrInfo.len = KW_LI_LEN;
1056 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1057 /* li = hdrInfo.val;*/
1059 /* check if LI is zero */
1062 RLOG0(L_ERROR, "Received LI as 0");
1066 /* store the extracted LI value */
1067 amHdr->li[amHdr->numLi++] = hdrInfo.val;
1068 totalSz += hdrInfo.val; /* incrment the size by LI value */
1071 /*ccpu00122597:PDU is dropped if liCnt exceeds KW_MAX_LI*/
1072 if(e && (amHdr->numLi >= KW_MAX_UL_LI))
1074 RLOG2(L_ERROR,"LI Count [%u] exceeds Max LI Count[%u]",
1075 amHdr->numLi, KW_MAX_UL_LI);
1079 /* first 2 bytes + Add one for Odd LI*/
1080 pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
1082 if ( totalSz >= pduSz )
1084 RLOG3(L_ERROR,"SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
1085 amHdr->sn, totalSz, pduSz);
1094 * @brief Private handler to process the status PDU
1097 * Private handler invokded by kwAmmProcessPdus to process the
1098 * control PDU (status report) received from its peer RLC entity.
1100 * - Decode the values from the received control pdu
1101 * - Create a KwUdxStaPdu structure, copy the values onto it and
1102 * send it to the DL instance for further processing
1104 * @param[in] gCb RLC instance control block
1105 * @param[in] rbCb Uplink RB control block
1106 * @param[in] cntrlPdu Control PDU received from MAC
1107 * @param[in] fByte First byte already removed from the STATUS PDU
1113 PRIVATE Void kwAmmUlHndlStatusPdu
1121 PRIVATE Void kwAmmUlHndlStatusPdu(gCb, rbCb, cntrlPdu, fByte)
1130 KwUdxStaPdu *pStaPdu;
1131 KwUdxUlSapCb *sapCb;
1132 U8 e3; /* NACK RANGE : 5GNR */
1135 U32 resrvdBitsAckSn=0;
1136 U32 resrvdBitsNackSn=0;
1138 TRC2(kwAmmUlHndlStatusPdu)
1141 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
1143 /* Extract the Control PDU */
1144 hdrInfo.hdr = (*fByte << 1);
1147 /* D/C has been shifted in the calling function */
1148 if (hdrInfo.hdr & 0xE0)
1150 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
1151 "Reserved value for CPT received UEID:%d CELLID:%d",
1153 rbCb->rlcId.cellId);
1158 sapCb = KW_GET_UDX_SAP(gCb);
1160 KW_ALLOC_SHRABL_BUF(sapCb->pst.region,
1163 sizeof(KwUdxStaPdu));
1165 #if (ERRCLASS & ERRCLS_ADD_RES)
1166 /* Memory allocation failure can not be expected */
1173 if (rbCb->m.amUl.snLen == KW_AM_CFG_12BIT_SN_LEN)
1176 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_12BITS;
1177 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_12BITS;
1179 else if (rbCb->m.amUl.snLen == KW_AM_CFG_18BIT_SN_LEN)
1182 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_18BITS;
1183 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_18BITS;
1188 resrvdBitsAckSn = 0;
1189 resrvdBitsAckSn = 0;
1192 pStaPdu->nackCnt = 0;
1194 hdrInfo.hdr = hdrInfo.hdr << KW_CPT_LEN;
1197 hdrInfo.len = snLen;
1198 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1199 pStaPdu->ackSn = hdrInfo.val;
1201 //printf ("++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n", pStaPdu->ackSn);
1202 /* Check if NACK Exists */
1203 hdrInfo.len = KW_E1_LEN;
1204 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1205 e1 = (U8)hdrInfo.val;
1206 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
1207 "kwAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1210 rbCb->rlcId.cellId);
1212 /* Extract the Reserved Bits after ACK SN field */
1213 hdrInfo.len = resrvdBitsAckSn;
1214 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1216 /* If NACK exists in control PDU */
1217 /* For ACKs and NACKs */
1218 while (e1 && (pStaPdu->nackCnt < KW_MAX_NACK_CNT))
1220 hdrInfo.len = snLen;
1221 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1222 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1224 hdrInfo.len = KW_E1_LEN;
1225 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1226 e1 = (U8)hdrInfo.val;
1229 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
1231 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1232 /* e2 = (U8) hdrInfo.val;*/
1234 /* Store e2 value */
1235 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
1237 /* Extract e3 : 5GNR */
1238 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
1240 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1241 e3 = (U8) hdrInfo.val;
1243 /* Extract Reserved Bits after NACK SN */
1244 hdrInfo.len = resrvdBitsNackSn;
1245 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1247 /* Test for resegmentation */
1248 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1250 hdrInfo.len = KW_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1251 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1252 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1254 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1255 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
1257 RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1258 "kwAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1259 "UEID:%d CELLID:%d",
1260 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1261 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd,
1263 rbCb->rlcId.cellId);
1268 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1269 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
1272 /* NACK RANGE Field is SET */
1275 /* Extract NACK range field */
1276 hdrInfo.len = KW_NACK_RANGE_LEN;
1277 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1278 snRange = (U8)hdrInfo.val;
1280 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1286 gRlcStats.amRlcStats.numULStaPduRcvd++;
1287 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1289 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1290 to the last NACK SN + 1 and discard the original ACK_SN*/
1291 if(pStaPdu->nackCnt == KW_MAX_NACK_CNT)
1293 pStaPdu->ackSn = (pStaPdu->nackInfo[KW_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1297 /* Parse & send Status PDU to RLC-DL */
1298 KwUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1304 * @brief Private handler to release all stored segments
1307 * Private handler invokded by kwAmmUlPlacePduInRecBuf to release the
1308 * stored segements in case a complete PDU is received later.
1310 * @param[in] gCb RLC instance control block
1311 * @param[in] recBuf Buffer that stores a received PDU or segments
1317 PRIVATE Void kwAmmUlRlsAllSegs
1323 PRIVATE Void kwAmmUlRlsAllSegs(gCb,recBuf)
1330 TRC2(kwAmmUlRlsAllSegs)
1332 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1333 while (seg != NULLP)
1335 KW_FREE_BUF_WC(seg->seg);
1336 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1337 KW_FREE_WC(gCb,seg, sizeof(KwSeg));
1338 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1345 * @brief Private handler to store the received segment
1348 * Private handler invokded by kwAmmUlPlacePduInRecBuf to add a received
1349 * segment in reception buffer of a RBCB.
1350 * - It is responsible for detecting duplicate segments
1351 * - Adding it at appropriate position in the received buffer
1352 * - Calling ExpByteSeg to set expSo field in the receiver buffer
1354 * @param[in] gCb RLC instance control block
1355 * @param[in] rbCb Radio Bearer Contro Block
1356 * @param[in] amHdr AM Header received
1357 * @param[in] pdu Buffer received other than the headers
1358 * @param[in] pduSz size of the PDU buffer received
1361 * -#TRUE Successful insertion into the receiver buffer
1362 * -#FALSE Possibly a duplicate segment
1365 PRIVATE Bool kwAmmAddRcvdSeg
1374 PRIVATE Bool kwAmmAddRcvdSeg(gCb, rbCb, amHdr, pdu, pduSz)
1382 KwAmRecBuf *recBuf = NULLP;
1385 U16 soEnd; /* Holds the SoEnd of received segment */
1386 U16 expSo = 0; /* Expected SO */
1388 TRC2(kwAmmAddRcvdSeg)
1390 soEnd = amHdr->so + pduSz - 1;
1391 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, amHdr->sn);
1393 if (NULLP == recBuf)
1395 KW_ALLOC(gCb,recBuf, sizeof(KwAmRecBuf));
1396 #if (ERRCLASS & ERRCLS_ADD_RES)
1397 if (recBuf == NULLP)
1399 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1400 "Memory allocation failed UEID:%d CELLID:%d",
1402 rbCb->rlcId.cellId);
1407 #endif /* ERRCLASS & ERRCLS_RES */
1408 kwUtlStoreRecBuf(AMUL.recBufLst, recBuf, amHdr->sn);
1412 if (recBuf->allRcvd == TRUE)
1419 recBuf->isDelvUpperLayer = FALSE;
1420 /* kw003.201 - Move past the segments that are different than the */
1422 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1423 while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1425 expSo = seg->amHdr.so + seg->segSz;
1426 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
1429 /* The received segment should start after the end of previous seg */
1430 if (expSo > amHdr->so)
1432 /* This is a duplicate segment */
1433 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1438 if ((seg) && (seg->amHdr.so <= soEnd))
1440 /* This is a duplicate segment */
1441 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1446 /* If we have come this far, we have to add this segment to the */
1447 /* reception buffer as we either have eliminated duplicates or */
1448 /* have found none. */
1449 KW_ALLOC_WC(gCb,tseg, sizeof(KwSeg));
1450 #if (ERRCLASS & ERRCLS_ADD_RES)
1453 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1454 "Memory allocation failed UEID:%d CELLID:%d",
1456 rbCb->rlcId.cellId);
1460 #endif /* ERRCLASS & ERRCLS_RES */
1463 tseg->segSz = pduSz;
1464 KW_MEM_CPY(&tseg->amHdr, amHdr, sizeof(KwAmHdr));
1465 recBuf->amHdr.si = amHdr->si;
1466 recBuf->amHdr.sn = amHdr->sn;
1467 tseg->soEnd = soEnd;
1470 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1474 recBuf->segLst.crnt = &seg->lstEnt;
1475 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1477 tseg->lstEnt.node = (PTR)tseg;
1478 kwAmmUpdExpByteSeg(gCb,&AMUL,tseg);
1484 * @brief Private handler to place the PDU in the reception buffer
1487 * This function checks if the received PDU's SN falls within the
1488 * receiving window, after which it places the same in the reception
1489 * buffer if its not a duplicate.
1491 * @param[in] gCb RLC instance control block
1492 * @param[in] pdu Received PDU
1493 * @param[in] rbCb Uplink AM Radio Bearer
1494 * @param[out] amUl AM UL Info
1502 PRIVATE Bool kwAmmUlPlacePduInRecBuf
1510 PRIVATE Bool kwAmmUlPlacePduInRecBuf(gCb, pdu, rbCb, amHdr)
1519 KwAmUl *amUl = &(rbCb->m.amUl);
1521 TRC2(kwAmmUlPlacePduInRecBuf)
1525 SFndLenMsg(pdu, &pduSz);
1527 gCb->genSts.bytesRecv += pduSz;
1528 gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz;
1529 if (!KW_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1531 gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1532 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
1533 "kwAmmUlPlacePduInRecBuf: SN %d outside the window"
1534 "UEID:%d CELLID:%d",
1537 rbCb->rlcId.cellId);
1539 gCb->genSts.unexpPdusRecv++;
1546 KwAmRecBuf *recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
1548 /* We received a complete PDU. Either we already have it, in which */
1549 /* case we just ignore the new PDU and discard it. Otherwise, */
1550 /* store the received PDU in the reception buffer */
1551 if (NULLP == recBuf)
1553 KW_ALLOC(gCb, recBuf, sizeof(KwAmRecBuf));
1554 #if (ERRCLASS & ERRCLS_ADD_RES)
1555 if (recBuf == NULLP)
1557 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1558 "Memory allocation failed UEID:%d CELLID:%d",
1560 rbCb->rlcId.cellId);
1564 #endif /* ERRCLASS & ERRCLS_RES */
1565 kwUtlStoreRecBuf(AMUL.recBufLst, recBuf, sn);
1567 else if (recBuf->allRcvd != TRUE)
1569 kwAmmUlRlsAllSegs(gCb,recBuf);
1573 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1574 gCb->genSts.unexpPdusRecv++;
1578 recBuf->isDelvUpperLayer = FALSE;
1580 recBuf->pduSz = pduSz;
1581 recBuf->allRcvd = TRUE;
1582 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1583 KW_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(KwAmHdr));
1588 /* We received a segment. We need to add that to the existing */
1589 /* segments, if any. */
1590 RETVALUE(kwAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1595 * @brief Private handler to trigger status report
1598 * Private handler invokded by kwAmmProcessPdus to check if the
1599 * status report need to be sent, and update the status trigger
1600 * flag accordingly based on status prohibit timer.
1602 * - Check if the received pdu's sn is less than rxHighestStatus, set the
1604 * - If staProhTmr is not running, calculate cntrlBo, else it'll be
1605 * updated at the expiry of staProhTmr.
1606 * - Expiry of reOrdTmr also will set staTrg flag.
1608 * @param[in] gCb RLC instance control block
1609 * @param[in] rbCb Uplink RB control block
1610 * @param[in] sn Sequence number of the pdu based on which to check if
1611 * status needs to be triggered
1612 * @param[in] discFlg Whether this pdu was discarded or not
1618 PRIVATE Void kwAmmTriggerStatus
1626 PRIVATE Void kwAmmTriggerStatus(gCb,rbCb, sn, discFlg)
1636 KwSn trxHighestStatus;
1637 KwAmUl *amUl = &(rbCb->m.amUl);
1639 TRC2(kwAmmTriggerStatus)
1642 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1643 MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1644 MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1646 /* kw005.201 Product CR ccpu00117114 *
1647 * The "=" in the 2nd condition is removed */
1648 if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1650 RLOG_ARG2(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
1651 "kwAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1653 rbCb->rlcId.cellId);
1655 amUl->staTrg = TRUE;
1656 amUl->gatherStaPduInfo = FALSE;
1658 /* Check if staProhTmr is running */
1659 tmrRunning = kwChkTmr(gCb,(PTR) rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1663 amUl->gatherStaPduInfo = TRUE;
1671 * @brief Private handler to reassemble from a segment or a PDU
1674 * Private handler invokded by kwAmmReassembleSdus with either a
1675 * PDU or a segment of a PDU. This is also called in the case of
1676 * reestablishment and hence out of sequence joining is also to
1680 * @param[in] gCb RLC instance control block
1681 * @param[in] rbCb Uplink RB control block
1682 * @param[in] amHdr AM header received for this segment/PDU
1683 * @param[in] pdu PDU to be reassembled
1689 PRIVATE Void kwAmmProcPduOrSeg
1697 PRIVATE Void kwAmmProcPduOrSeg(gCb, rbCb, amHdr, pdu)
1705 TRC2(kwAmmProcPduOrSeg)
1707 if ((AMUL.expSn != amHdr->sn) || (AMUL.expSo != amHdr->so))
1709 /* Release the existing partial SDU as we have PDUs or */
1710 /* segments that are out of sequence */
1711 rbCb->m.amUl.isOutOfSeq = TRUE;
1712 KW_FREE_BUF(AMUL.partialSdu);
1715 //if (amHdr->fi & KW_FI_FIRST_SEG)
1716 if (amHdr->si == 0x01)
1717 {/* first Segment of the SDU */
1718 if (AMUL.partialSdu != NULLP)
1719 { /* Some old SDU may be present */
1720 KW_FREE_BUF_WC(AMUL.partialSdu);
1722 AMUL.partialSdu = pdu;
1725 else if(amHdr->si == 0x03)
1726 {/* Middle or last segment of the SUD */
1727 SCatMsg(AMUL.partialSdu,pdu, M1M2);
1728 KW_FREE_BUF_WC(pdu);
1731 else if (amHdr->si == 0x02)
1733 SCatMsg(pdu,AMUL.partialSdu,M2M1);
1734 KW_FREE_BUF_WC(AMUL.partialSdu);
1739 AMUL.partialSdu = NULLP;
1740 kwUtlSndDatInd(gCb,rbCb, pdu);
1748 * @brief Private handler to reassemble SDUs
1751 * Private handler invokded by kwAmmProcessPdus with the PDU
1752 * from the reception buffer in sequence to reassemble SDUs and
1755 * - With the stored header info, FI and LSF segment / concatenate
1756 * PDUs or byte segments of PDUs to get the associated SDU.
1758 * @param[in] rbCb RB control block
1759 * @param[in] pdu PDU to be reassembled
1767 PRIVATE S16 kwAmmUlReassembleSdus
1774 PRIVATE S16 kwAmmUlReassembleSdus(gCb, rbCb, recBuf)
1782 TRC2(kwAmmUlReassembleSdus)
1783 //if (recBuf->amHdr.rf == 0)
1784 if (recBuf->amHdr.si == 0)
1787 kwAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1788 /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1789 recBuf->pdu = NULLP;
1790 AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1795 /* This is a set of segments */
1796 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1797 AMUL.expSn = recBuf->amHdr.sn;
1801 kwAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1802 AMUL.expSo = seg->soEnd + 1;
1804 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1805 KW_FREE_WC(gCb, seg, sizeof(KwSeg));
1807 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1809 AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1817 * @brief Handler to process the re-establishment request received from UIM
1819 * @param[in] gCb RLC instance control block
1820 * @param[in] rlcId RLC identifier
1821 * @param[in] sendReEst Whether to send back restablishment complete or not
1822 * @param[in] rbCb Uplink RB control block
1828 PUBLIC Void kwAmmUlReEstablish
1836 PUBLIC Void kwAmmUlReEstablish(gCb, rlcId, sendReEst, rbCb)
1848 KwKwuSapCb *kwKwSap;
1850 KwAmRecBuf *recBuf = NULLP;
1852 TRC2(kwAmmUlReEstablish);
1857 MODAMR(AMUL.vrMr, mVrMr, AMUL.rxNext, AMUL.snModMask);
1858 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1860 /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1863 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
1864 if (NULLP != recBuf)
1866 if (recBuf->allRcvd == TRUE)
1868 kwAmmUlReassembleSdus(gCb,rbCb, recBuf);
1872 /* Remove PDU and segments */
1875 KW_FREE_BUF_WC(recBuf->pdu);
1877 /* Release all the segments*/
1878 kwAmmUlRlsAllSegs(gCb,recBuf);
1880 kwUtlDelRecBuf(AMUL.recBufLst, recBuf, gCb);
1882 sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1883 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1885 /* Discard remaining PDUs and bytesegments in recBuf */
1887 /* Stop all timers and reset variables */
1888 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_REORD_TMR))
1890 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
1892 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_STA_PROH_TMR))
1894 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1898 AMUL.rxNextHighestRcvd = 0;
1899 AMUL.rxNextStatusTrig = 0;
1900 rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + KW_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1901 AMUL.rxHighestStatus = 0;
1902 AMUL.staTrg = FALSE;
1903 AMUL.gatherStaPduInfo = FALSE;
1906 if (AMUL.partialSdu != NULLP)
1908 KW_FREE_BUF(AMUL.partialSdu);
1910 kwKwSap = gCb->u.ulCb->kwuUlSap + KW_UI_PDCP;
1914 KwUiKwuReEstCmpInd(&kwKwSap->pst, kwKwSap->suId, rlcId);
1915 rbCb->m.amUl.isOutOfSeq = FALSE;
1922 * @brief Handler for reorder timer expiry
1925 * This function is used to handle events upon expiry of reorder timer
1927 * @param[in] gCb RLC instance control block
1928 * @param[in] rbCb RB control block
1935 PUBLIC Void kwAmmReOrdTmrExp
1941 PUBLIC Void kwAmmReOrdTmrExp(rbCb)
1946 KwAmUl *amUl = &(rbCb->m.amUl);
1950 KwSn mrxHighestStatus;
1951 KwSn mrxNextHighestRcvd;
1952 Bool tmrRunning = FALSE;
1953 KwAmRecBuf *recBuf = NULLP;
1955 TRC2(kwAmmReOrdTmrExp);
1958 /* Update rxHighestStatus */
1959 sn = amUl->rxNextStatusTrig;
1961 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1962 MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1963 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
1967 if ((recBuf == NULLP) ||
1968 ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1970 amUl->rxHighestStatus = sn;
1971 amUl->staTrg = TRUE;
1972 amUl->gatherStaPduInfo = FALSE;
1974 /* Check if staProhTmr is running */
1975 tmrRunning = kwChkTmr(gCb,(PTR) rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1979 gRlcStats.amRlcStats.numULReOrdTimerExpires++;
1980 amUl->gatherStaPduInfo = TRUE;
1981 kwAmmUlAssembleCntrlInfo(gCb, rbCb);
1986 sn = (sn + 1) & (amUl->snModMask);
1987 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1990 /* Update rxNextStatusTrig */
1991 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1992 MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1993 if (mrxNextHighestRcvd > mrxHighestStatus)
1995 kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
1996 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
2000 } /* kwAmmReOrdTmrExp */
2003 * @brief Handler for status prohibit timer expiry
2006 * This function is used to handle events upon expiry of status prohibit
2009 * @param[in] gCb RLC instance control block
2010 * @param[in] rbCb RB control block
2017 PUBLIC Void kwAmmStaProTmrExp
2023 PUBLIC Void kwAmmStaProTmrExp(gCb, rbCb)
2028 KwAmUl *amUl = &(rbCb->m.amUl);
2030 TRC2(kwAmmStaProTmrExp);
2033 amUl->gatherStaPduInfo = FALSE;
2035 if (amUl->staTrg == TRUE)
2037 amUl->gatherStaPduInfo = TRUE;
2038 /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
2039 kwAmmUlAssembleCntrlInfo(gCb,rbCb);
2043 } /* kwAmmStaProTmrExp */
2046 * @brief Handler to extract an element of AM Header
2049 * This function is used to extract an element of AM header.
2051 * @param[in] pdu The pdu to be decoded
2052 * @param[in,out] hdrInfo Container to hold the decoded info
2059 PRIVATE Void kwAmmExtractElmnt
2066 PRIVATE Void kwAmmExtractElmnt(gCb, pdu, hdrInfo)
2073 U8 pLen = hdrInfo->pLen;
2074 U8 len = (U8)hdrInfo->len;
2082 TRC2(kwAmmExtractElmnt);
2088 SRemPreMsg(&hdr, pdu);
2094 val = tHdr >> (KW_BYTE_LEN - (len));
2098 else /*if (len > 8) */
2102 val = val >> (KW_BYTE_LEN - fLen);
2103 val = val << (len - fLen);
2105 SRemPreMsg(&hdr, pdu);
2109 hdr = hdr >> (KW_BYTE_LEN - rLen);
2112 pLen = (KW_BYTE_LEN - rLen);
2116 rLen = rLen - KW_BYTE_LEN;
2118 tVal = tVal << rLen;
2121 SRemPreMsg(&hdr, pdu);
2123 hdr = hdr >> (KW_BYTE_LEN - rLen);
2126 pLen = (KW_BYTE_LEN - rLen);
2130 hdrInfo->pLen = pLen;
2138 * @brief Handler to updated expected byte seg
2141 * This function is used to update expected byte segment. The next segment
2142 * expected is indicated by the SO of the segment which is expected. Intially
2143 * the segment with SO 0 is expected and then in order. When all the segments
2144 * are received (which would happen when an expected SO is encountered
2145 * with LSF set) the allRcvd flag is set to TRUE
2147 * @param[in] gCb RLC instance control block
2148 * @param[in] amUl AM Uplink Control Block
2149 * @param[in] seg Newly received segment
2156 PRIVATE Void kwAmmUpdExpByteSeg
2163 PRIVATE Void kwAmmUpdExpByteSeg(gCb, amUl, seg)
2169 U16 newExpSo; /* The new expected SO */
2170 KwSn sn = seg->amHdr.sn;
2172 KwAmRecBuf *recBuf = NULLP;
2174 TRC2(kwAmmUpdExpByteSeg);
2177 recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
2178 if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
2183 newExpSo = seg->soEnd + 1;
2184 recBuf->expSo = newExpSo;
2185 //lstRcvd = seg->amHdr.lsf;
2186 if(seg->amHdr.si == 0x2)
2190 /* kw003.201 - This should update seg with the one after newSeg */
2191 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
2194 /* keep going ahead as long as the expectedSo match with the header so
2195 else store the expSo for later checking again */
2196 if(seg->amHdr.si == 0x2)
2200 if (seg->amHdr.so == newExpSo)
2202 newExpSo = seg->soEnd + 1;
2203 recBuf->expSo = newExpSo;
2204 //lstRcvd = seg->amHdr.lsf;
2205 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
2209 recBuf->expSo = newExpSo;
2213 if (lstRcvd == TRUE)
2215 recBuf->allRcvd = TRUE;
2216 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
2224 * Function to release/free the Acknowledged Mode Module RbCb buffers
2227 * This primitive Frees the AM RbCb transmission Buffer, retransmission
2228 * Buffer and reciption Buffers
2230 * @param [in] gCb - RLC instance Control Block
2231 * @param [in] rbCb - RB Control Block
2236 PUBLIC Void kwAmmFreeUlRbCb
2242 PUBLIC Void kwAmmFreeUlRbCb(gCb,rbCb)
2247 KwSn curSn = 0; /* Sequence number of PDU */
2248 KwSn windSz; /* PDU window size */
2249 KwAmRecBuf *recBuf = NULLP;
2251 TRC2(kwAmmFreeUlRbCb)
2254 windSz = (KW_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
2256 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_REORD_TMR))
2258 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
2260 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_STA_PROH_TMR))
2262 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_STA_PROH_TMR);
2266 /* on the first loop winSz is always greater than zero
2267 while( ( curSn < windSz ) hence changing to do while */
2270 recBuf = kwUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
2271 if ( recBuf != NULLP )
2273 if (recBuf->pdu != NULLP)
2275 KW_FREE_BUF_WC(recBuf->pdu);
2277 /* Release all the segments */
2278 kwAmmUlRlsAllSegs(gCb,recBuf);
2279 kwUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
2282 }while ( curSn < windSz );
2285 KW_FREE_WC(gCb,rbCb->m.amUl.recBufLst, (KW_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
2286 rbCb->m.amUl.recBufLst = NULLP;
2289 if(rbCb->m.amUl.partialSdu != NULLP)
2291 KW_FREE_BUF_WC(rbCb->m.amUl.partialSdu);
2294 } /* kwAmmFreeUlRbCb */
2300 /********************************************************************30**
2303 **********************************************************************/