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 KW_MODULE (KW_DBGMASK_AM | KW_DBGMASK_UL) /* for debugging purpose */
91 /* private function declarations */
93 PRIVATE Void kwAmmUlAssembleCntrlInfo ARGS ((RlcCb *gCb, RlcUlRbCb *rbCb));
95 PRIVATE S16 kwAmmExtractHdr ARGS ((RlcCb *gCb,
101 PRIVATE Bool kwAmmUlPlacePduInRecBuf ARGS ((RlcCb *gCb,
106 PRIVATE Void kwAmmTriggerStatus ARGS ((RlcCb *gCb,
111 PRIVATE S16 kwAmmUlReassembleSdus ARGS ((RlcCb *gCb,
113 KwAmRecBuf *recBuf));
115 PRIVATE Void kwAmmProcPduOrSeg ARGS ((RlcCb *gCb,
120 PRIVATE Void kwAmmUpdExpByteSeg ARGS ((RlcCb *gCb,KwAmUl *amUl, KwSeg* newSeg));
122 PRIVATE Void kwAmmExtractElmnt ARGS ((RlcCb *gCb, Buffer *pdu, KwExtHdr *hdrInfo));
124 PRIVATE Void kwAmmUlHndlStatusPdu ARGS ((RlcCb *gCb,
129 /******************************************************************************
131 AM Module contains the following funcitons:
134 - kwAmmUlAssembleCntrlInfo
139 - kwAmmUlHndlStatusPdu
141 - kwAmmUlReassembleSdus
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
163 PRIVATE S16 kwAmmUlSetNackInfo
170 KwUdxDlStaPdu *statusPdu,
174 PRIVATE S16 kwAmmUlSetNackInfo(rbCb, sn, isSegment, soStart, statusPdu, prevNackSn)
180 KwUdxDlStaPdu *statusPdu,
184 KwNackInfo *nackInfo = (statusPdu->nackInfo + statusPdu->nackCount);
185 S16 sizeToBeEncd = 0; /* Status PDu size to be encoded */
187 TRC2(kwAmmUlSetNackInfo)
189 /* In following cases we should increment the nackCnt & fill new NACK_SN info:
190 * 1) First NACK_SN of the statusdPdu
191 * 2) NACK_SN is not continuous with previous
192 * 3) NACK_SN is same as previuos but segments are not continuous
193 * 4) NACK_SN is continuous with previous but previous NACK_SN segments
194 * are not missing in sequence till end
196 if((*prevNackSn == 0xffffffff) || ((((*prevNackSn) + 1) & AMUL.snModMask) != sn) ||
197 (((*prevNackSn) == sn) && (((nackInfo->soEnd + 1) != soStart))) ||
198 ((nackInfo->isSegment) && (((*prevNackSn) + 1) == sn) && (nackInfo->soEnd != KW_ALL_BYTES_MISSING)))
200 if(nackInfo->nackRange)
202 if((nackInfo->soEnd) && (!nackInfo->soStart))
204 /*First nack_sn of this nackRange not segmented but last is segmented */
205 sizeToBeEncd = 5; /*32 for soStart and soEnd and 8 for nackRange */
209 /*First nack_sn of this nackRange was segmented */
210 sizeToBeEncd = 1; /*8 for nackRange */
214 if(*prevNackSn != 0xffffffff)
216 /* Increment nackCount as this sn is continous */
217 statusPdu->nackCount++;
218 nackInfo = statusPdu->nackInfo + statusPdu->nackCount;
222 nackInfo->isSegment = isSegment;
223 nackInfo->soStart = soStart;
224 nackInfo->soEnd = soEnd;
225 nackInfo->nackRange = 0;
229 sizeToBeEncd += ((AMUL.snLen == KW_AM_CFG_12BIT_SN_LEN)?6:7); /* NACK,E1,E2,Sostart,SoEnd */
233 sizeToBeEncd += ((AMUL.snLen == KW_AM_CFG_12BIT_SN_LEN)?2:3); /* NACK,E1,E2 */
238 if(!(nackInfo->nackRange))
240 nackInfo->nackRange++;
242 /* This case means there are continuous SNs/Segments. If it is the next
243 * Sn then increment nackRnage. if same SN but different segment then
244 * dont increment nackRange */
245 if((((*prevNackSn) + 1) & AMUL.snModMask) == sn)
247 nackInfo->nackRange++;
250 /* If NackRange is reached to max value then increment statusPdu->nackCount*/
251 if(nackInfo->nackRange == 255)
253 statusPdu->nackCount++;
254 if(nackInfo->isSegment)
256 sizeToBeEncd = 1; /* return only nackRangeSize*/
260 /* First SN was not segmented of this nackRange but last SN is segmented */
261 sizeToBeEncd = 5; /* return size of soSatrt + soEnd + nackRnage */
267 nackInfo->isSegment = isSegment;
268 nackInfo->soEnd = soEnd;
270 else if(nackInfo->isSegment)
272 nackInfo->soEnd = KW_ALL_BYTES_MISSING;
276 nackInfo->soStart = 0;
283 return (sizeToBeEncd);
287 * @brief Private handler to gather information required to create the STATUS
291 * Scans the reception buffer and copies information to the UdxDlStaPdu
292 * structure about SN's and segments not yet received. This data is
293 * sent to the DL instance so that it can create an appropriate (depending
294 * on the grants from MAC) STATUS PDU and send it to MAC.
296 * @param[in] gCb RLC instance control block
297 * @param[in] rbCb Uplink RB control block
303 PRIVATE Void kwAmmUlAssembleCntrlInfo
309 PRIVATE Void kwAmmUlAssembleCntrlInfo(gCb, rbCb)
314 KwUdxDlStaPdu *pStatusPdu;
315 KwNackInfo *nackInfo;
316 KwSn sn; /* sequence number */
317 KwSn mSn; /* Mod val of sequence number */
318 KwSn rxHighestStatus; /* Mod val of rxHighestStatus */
319 KwSeg *seg; /* pdu segment */
320 U16 nackCnt = 0; /* Index for staPdu */
321 U16 seqSo; /* segmment offset */
323 U16 staPduEncSize = 3; /* size that would be of the encoded
324 STATUS PDU, it is in bits; 15 for
325 first fixed part of STATUS PDU */
326 KwAmRecBuf *recBuf = NULLP;
327 KwSn prevNackSn = 0xffffffff;
329 TRC2(kwAmmUlAssembleCntrlInfo)
332 sapCb = KW_GET_UDX_SAP(gCb);
334 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
337 sizeof(KwUdxDlStaPdu));
339 #if (ERRCLASS & ERRCLS_ADD_RES)
340 /* Memory allocation failure can not be expected */
348 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
349 MODAMR(AMUL.rxHighestStatus, rxHighestStatus, AMUL.rxNext, AMUL.snModMask);
351 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
353 while (mSn < rxHighestStatus )
355 /* For missing PDUs */
356 if ((NULLP == recBuf) && nackCnt < KW_MAX_NACK_CNT )
358 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
359 "Missing PDU's SN = %d UEID:%d CELLID:%d",
363 staPduEncSize += kwAmmUlSetNackInfo(rbCb,
365 FALSE, /* isSegment */
371 else if (recBuf && (recBuf->pdu == NULLP) &&
372 (recBuf->segLst.count > 0))
374 /* Scan through the byte segments of PDU and add this sn
375 with soStart and soEnd info to staPdu */
378 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
379 while (seg != NULLP && nackCnt < KW_MAX_NACK_CNT)
381 /* For missing byte segments */
382 if (seg->amHdr.so != seqSo)
384 staPduEncSize += kwAmmUlSetNackInfo(rbCb,
392 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
393 "Missing byte segment's"
394 " SN:%d UEID:%d CELLID:%d",
398 RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
399 "soStart and soEnd = %d, %d UEID:%d CELLID:%d",
406 seqSo = seg->soEnd + 1;
407 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
410 /* Check if the last segment is missing */
411 KW_LLIST_LAST_SEG(recBuf->segLst, seg);
412 if ((seg != NULLP) &&
413 (seg->amHdr.si != KW_SI_LAST_SEG && nackCnt < KW_MAX_NACK_CNT))
415 staPduEncSize += kwAmmUlSetNackInfo(rbCb,
419 KW_ALL_BYTES_MISSING,
423 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
424 "kwAmmUlAssembleCntrlInfo: Missing (last) byte "
425 "segment's SN:%d UEID:%d CELLID:%d",
429 RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
430 "soStart and soEnd = %d, %d UEID:%d CELLID:%d",
432 KW_ALL_BYTES_MISSING,
439 sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
440 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
442 /* Get the received Buffer the updated/next SN */
443 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
445 /* Find the next missing sequence number if nackCnt reaches maximum and
446 still Reordering window has some missing AMDPDUs / AMDPDU segments. The
447 next missing sequence number will be considered as the ack sequnece
448 number in the status pdu.*/
449 if((nackCnt == KW_MAX_NACK_CNT) &&
450 ((recBuf == NULLP) ||
451 ((recBuf->pdu == NULLP) &&
452 (recBuf->segLst.count > 0))))
458 /*Unfortunately i have write below peice of code here because kwAmmsetNackInfo()
459 * don't know that this is the last nackSn with nackRange*/
460 nackInfo = &(pStatusPdu->nackInfo[pStatusPdu->nackCount]);
461 if(nackInfo->nackRange)
463 if((nackInfo->soEnd) && (!nackInfo->soStart))
465 /*First nack_sn of this nackRange not segmented but last is segmented */
466 staPduEncSize += 5; /*32 for soStart and soEnd and 8 for nackRange */
470 /*First nack_sn of this nackRange was segmented */
471 staPduEncSize += 1; /*8 for nackRange */
474 /* nackCount is used as an index to nackInfo array but in status Pdu it
475 * should be equal to number nackInfo that are filled. hence incrementing by 1*/
476 if(prevNackSn != 0xffffffff)
478 pStatusPdu->nackCount++;
480 /* Update ACK SN with the last sn for which feedback is not assembled */
481 if ( mSn == rxHighestStatus)
483 pStatusPdu->ackSn = AMUL.rxHighestStatus;
487 pStatusPdu->ackSn = sn;
490 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
491 "kwAmmUlAssembleCntrlInfo: ACK PDU's SN = %d"
497 pStatusPdu->controlBo = staPduEncSize; /*Its already in bytes */
500 AMUL.gatherStaPduInfo = FALSE;
503 if (rlcUlUdxStaPduReq(&sapCb->pst,
508 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
509 "Failed to Send Sta Pdu UEID:%d CELLID:%d",
512 RLC_FREE_SHRABL_BUF_WC(sapCb->pst.region,
515 sizeof(KwUdxDlStaPdu));
521 #ifdef XEON_SPECIFIC_CHANGES
522 extern U32 gRlcDatIndUL;
525 #ifdef T2K_TRIGGER_RLC_REEST
526 PUBLIC U32 drpRlcDrbPack;
529 * @brief Handler to process the PDUs received from MAC and send it to PDCP
532 * This function is invoked by UTL with the PDU(s) received from MAC.
533 * It reorders the received data PDUs and trigger status report as
534 * needed. Reassembles the SDUs in sequence and send it to PDCP.
535 * It also processes the control PDU
537 * @param[in] gCb RLC instance control block
538 * @param[in] rbCb RB control block
539 * @param[out] pduInfo PDU Info received from MAC
546 PUBLIC Void kwAmmProcessPdus
554 PUBLIC Void kwAmmProcessPdus(gCb, rbCb, pduInfo, ulTimeInfo)
562 PUBLIC Void kwAmmProcessPdus
569 PUBLIC Void kwAmmProcessPdus(gCb, rbCb, pduInfo)
586 #ifdef LTE_L2_MEAS_RLC
587 MsgLen rlcSduSz; /*Holds length of Rlc Sdu*/
588 #endif /* LTE_L2_MEAS */
590 TRC2(kwAmmProcessPdus)
595 numPduToProcess = KW_MIN(pduInfo->numPdu, RGU_MAX_PDU);
596 RLOG_ARG4(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
597 "numPdu[%ld],numPduToProcess[%ld] UEID:%ld CELLID:%ld",
603 //printf ("++++++++++++ 5GNRLOG numPduToProcess %d \n", numPduToProcess);
604 while (numPdu < numPduToProcess)
606 //printf ("++++++++++++ 5GNRLOG processing pdu %d \n", numPdu);
608 pdu = pduInfo->mBuf[numPdu++];
613 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
614 "Null Pdu UEID:%d CELLID:%d",
617 gCb->genSts.errorPdusRecv++;
620 #ifndef RGL_SPECIFIC_CHANGES
624 SFndLenMsg(pdu, &len);
629 /* Extract AM PDU/SEG header Info */
630 KW_MEM_ZERO(&amHdr, sizeof(KwAmHdr));
631 /* Avoided the allocation of amHdr and sending
633 if (kwAmmExtractHdr(gCb, rbCb, pdu, &amHdr, &fByte) != ROK)
635 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
636 "Header Extraction Failed UEID:%d CELLID:%d",
640 gCb->genSts.errorPdusRecv++;
643 /* Check if its a control PDU */
646 kwAmmUlHndlStatusPdu(gCb, rbCb, pdu, &fByte);
650 if((amHdr.si == KW_SI_LAST_SEG) && (!amHdr.so))
652 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
653 "kwAmmProcessPdus: Dropping PDU because SO can't be zero for last segment sn:%u "
661 #ifndef RGL_SPECIFIC_CHANGES
664 #ifndef TENB_T2K3K_SPECIFIC_CHANGES
666 /* Changed the condition to TRUE from ROK */
667 if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
669 extern U32 rlculdrop;
677 /*ccpu00142274 - UL memory based flow control*/
678 if(isMemThreshReached(rlcCb[0]->init.region) != ROK)
680 extern U32 rlculdrop;
691 #ifdef T2K_TRIGGER_RLC_REEST
692 if(drpRlcDrbPack > 1000)
694 if(rbCb->rlcId.rbType == CM_LTE_DRB)
702 /* Reordering data PDU */
704 if (kwAmmUlPlacePduInRecBuf(gCb,pdu, rbCb, &amHdr) == TRUE)
709 KwSn mrxNextHighestRcvd;
712 kwUtlCalUlIpThrPut(gCb, rbCb, pdu, ttiCnt);
713 #endif /* LTE_L2_MEAS */
715 /* Update rxNextHighestRcvd */
716 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
717 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
718 if (mSn >= mrxNextHighestRcvd)
720 amUl->rxNextHighestRcvd = ((sn + 1) & (amUl->snModMask));
722 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
723 "kwAmmProcessPdus: Updated rxNextHighestRcvd = %d UEID:%d CELLID:%d",
724 amUl->rxNextHighestRcvd,
729 recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
730 if ((NULLP != recBuf) && ( recBuf->allRcvd))
732 /* deliver the reassembled RLC SDU to upper layer,
733 But not removed from the table */
734 kwAmmUlReassembleSdus(gCb, rbCb, recBuf);
735 recBuf->isDelvUpperLayer = TRUE;
737 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
739 /* Update rxHighestStatus */
740 if (sn == amUl->rxHighestStatus)
742 tSn = (sn + 1) & (amUl->snModMask) ; /* MOD (2 Pwr SN LEN- 1) */
744 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
745 /* Scan through till the upper edge of the window */
746 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
749 if ((NULLP == recBuf) || (!recBuf->allRcvd))
751 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
752 "kwAmmProcessPdus: Updated rxHighestStatus:%d "
758 amUl->rxHighestStatus = tSn;
761 tSn = (tSn + 1) & (amUl->snModMask); /* MOD (2 Pwr SN LEN- 1) */
762 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
769 if (sn == amUl->rxNext)
772 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
773 MODAMR(tSn, mSn, amUl->rxNext, amUl->snModMask);
774 /* Scan through till the upper edge of the window */
777 if ((NULLP != recBuf) && (recBuf->allRcvd) &&
778 (TRUE == recBuf->isDelvUpperLayer))
780 /* RecBuf should remove from table
781 since PDU is already sent to upper layer */
782 recBuf->isDelvUpperLayer = FALSE;
783 kwUtlDelRecBuf(amUl->recBufLst, recBuf, gCb);
788 amUl->vrMr = (amUl->rxNext + (KW_AM_GET_WIN_SZ(amUl->snLen))) & (amUl->snModMask);
791 tSn = (tSn + 1) & (amUl->snModMask);
792 recBuf = kwUtlGetRecBuf(amUl->recBufLst, tSn);
798 /* Check if reOrdTmr is running and update rxNextStatusTrig accordingly */
799 tmrRunning = kwChkTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
802 Bool snInWin = KW_AM_CHK_SN_WITHIN_RECV_WINDOW(amUl->rxNextStatusTrig, amUl);
804 if ( (amUl->rxNextStatusTrig == amUl->rxNext) || ( (!snInWin) &&
805 (amUl->rxNextStatusTrig != amUl->vrMr) ) )
807 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
814 if (amUl->rxNextHighestRcvd > amUl->rxNext)
816 kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
817 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
819 RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
820 "kwAmmProcessPdus: Updated rxNextStatusTrig = %d UEID:%d CELLID:%d",
821 amUl->rxNextStatusTrig,
830 gRlcStats.amRlcStats.numULPdusDiscarded++;
835 kwAmmTriggerStatus(gCb,rbCb, sn, discFlg);
840 kwUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
841 #endif /* LTE_L2_MEAS */
842 gCb->genSts.pdusRecv += pduInfo->numPdu;
843 if (amUl->gatherStaPduInfo)
845 kwAmmUlAssembleCntrlInfo(gCb,rbCb);
853 * @brief Private handler to extract header Information of the PDU
856 * This function extracts the header elements of the PDU and store them
857 * in db for future reference.
859 * fByte - is the first byte removed from the PDU as part of calling
862 * @param[in] gCb RLC instance control block
863 * @param[in] rbCb Uplink RB control block
864 * @param[in] pdu Received PDU
865 * @param[out] amHdr Pointer to the extracted AM header
866 * @param[out] fByte First byte removed from the PDU
874 PRIVATE S16 kwAmmExtractHdr
883 PRIVATE S16 kwAmmExtractHdr(gCb, rbCb, pdu, amHdr, fByte)
896 TRC2(kwAmmExtractHdr)
899 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
901 /* Extract fixed part of the header */
902 SFndLenMsg(pdu,&pduSz);
903 SRemPreMsg(fByte, pdu);
904 amHdr->dc = (*fByte & KW_DC_POS) >> KW_DC_SHT;
905 if (KW_CNTRL_PDU == amHdr->dc)
907 //printf ("++++++++++++ 5GNRLOG HDR extracted CTRL : \n");
911 amHdr->p = (*fByte & KW_POLL_POS) >> KW_POLL_SHT;
913 amHdr->si = (*fByte & KW_SI_POS) >> KW_SI_SHT;
916 if (rbCb->m.amUl.snLen == KW_AM_CFG_12BIT_SN_LEN)
918 SRemPreMsg(&snByte, pdu);
919 sn = (KwSn)(((*fByte & KW_SN_POS_12BIT) << KW_BYTE_LEN ) | snByte);
922 else if (rbCb->m.amUl.snLen == KW_AM_CFG_18BIT_SN_LEN)
924 SRemPreMsg(&snByte, pdu);
925 sn = (KwSn)(((*fByte & KW_SN_POS_18BIT) << KW_BYTE_LEN ) | snByte);
927 SRemPreMsg(&snByte, pdu);
928 sn = ((sn << KW_BYTE_LEN) | snByte);
932 if ((amHdr->si != 0) && (amHdr->si != 0x01))
934 hdrInfo.len = KW_SO_LEN_5GNR;
935 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
936 amHdr->so = hdrInfo.val;
940 //printf ("++++++++++++ 5GNRLOG HDR extracted DATA : sn %d \n", sn);
946 * @brief Private handler to extract header Information of the PDU
949 * This function extracts the header elements of the PDU and store them
950 * in db for future reference.
952 * fByte - is the first byte removed from the PDU as part of calling
955 * @param[in] gCb RLC instance control block
956 * @param[in] rbCb Uplink RB control block
957 * @param[in] pdu Received PDU
958 * @param[out] amHdr Pointer to the extracted AM header
959 * @param[out] fByte First byte removed from the PDU
967 PRIVATE S16 kwAmmExtractHdrOld
975 PRIVATE S16 kwAmmExtractHdrOld(gCb, pdu, amHdr, fByte)
989 TRC2(kwAmmExtractHdrOld)
992 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
994 /* Extract fixed part of the header */
995 SFndLenMsg(pdu,&pduSz);
996 SRemPreMsg(fByte, pdu);
997 amHdr->dc = (*fByte & KW_DC_POS) >> KW_DC_SHT;
998 if (KW_CNTRL_PDU == amHdr->dc)
1002 /* kw002.201 : Changed the extraction of hdr elements to avoid */
1003 /* function calls */
1004 amHdr->rf = (*fByte & KW_RF_POS) >> KW_RF_SHT;
1005 amHdr->p = (*fByte & KW_POLL_POS) >> KW_POLL_SHT;
1006 amHdr->fi = (*fByte & KW_FI_POS) >> KW_FI_SHT;
1007 e = amHdr->e = (*fByte & KW_E_POS)>> KW_E_SHT;
1009 SRemPreMsg(&snByte, pdu);
1010 sn = (U16)(((*fByte & KW_SN_POS) << KW_BYTE_LEN ) | snByte);
1014 /* Extract extn part of the header */
1015 hdrInfo.len = KW_LSF_LEN;
1016 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1017 amHdr->lsf = (U8)hdrInfo.val;
1019 hdrInfo.len = KW_SO_LEN;
1020 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1021 amHdr->so = hdrInfo.val;
1027 while (e && (amHdr->numLi < KW_MAX_UL_LI))
1029 hdrInfo.len = KW_E_LEN;
1030 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1031 e = amHdr->e = (U8)hdrInfo.val;
1033 /* Extract LI value*/
1034 hdrInfo.len = KW_LI_LEN;
1035 kwAmmExtractElmnt(gCb, pdu, &hdrInfo);
1036 /* li = hdrInfo.val;*/
1038 /* check if LI is zero */
1041 RLOG0(L_ERROR, "Received LI as 0");
1045 /* store the extracted LI value */
1046 amHdr->li[amHdr->numLi++] = hdrInfo.val;
1047 totalSz += hdrInfo.val; /* incrment the size by LI value */
1050 /*ccpu00122597:PDU is dropped if liCnt exceeds KW_MAX_LI*/
1051 if(e && (amHdr->numLi >= KW_MAX_UL_LI))
1053 RLOG2(L_ERROR,"LI Count [%u] exceeds Max LI Count[%u]",
1054 amHdr->numLi, KW_MAX_UL_LI);
1058 /* first 2 bytes + Add one for Odd LI*/
1059 pduSz -= ( amHdr->numLi + (amHdr->numLi >> 1) + 2 + (amHdr->numLi & 1) );
1061 if ( totalSz >= pduSz )
1063 RLOG3(L_ERROR,"SN [%d]:Corrupted PDU as TotSz[%lu] PduSz[%lu] ",
1064 amHdr->sn, totalSz, pduSz);
1073 * @brief Private handler to process the status PDU
1076 * Private handler invokded by kwAmmProcessPdus to process the
1077 * control PDU (status report) received from its peer RLC entity.
1079 * - Decode the values from the received control pdu
1080 * - Create a KwUdxStaPdu structure, copy the values onto it and
1081 * send it to the DL instance for further processing
1083 * @param[in] gCb RLC instance control block
1084 * @param[in] rbCb Uplink RB control block
1085 * @param[in] cntrlPdu Control PDU received from MAC
1086 * @param[in] fByte First byte already removed from the STATUS PDU
1092 PRIVATE Void kwAmmUlHndlStatusPdu
1100 PRIVATE Void kwAmmUlHndlStatusPdu(gCb, rbCb, cntrlPdu, fByte)
1109 KwUdxStaPdu *pStaPdu;
1110 KwUdxUlSapCb *sapCb;
1111 U8 e3; /* NACK RANGE : 5GNR */
1114 U32 resrvdBitsAckSn=0;
1115 U32 resrvdBitsNackSn=0;
1117 TRC2(kwAmmUlHndlStatusPdu)
1120 KW_MEM_ZERO(&hdrInfo, sizeof(KwExtHdr));
1122 /* Extract the Control PDU */
1123 hdrInfo.hdr = (*fByte << 1);
1126 /* D/C has been shifted in the calling function */
1127 if (hdrInfo.hdr & 0xE0)
1129 RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
1130 "Reserved value for CPT received UEID:%d CELLID:%d",
1132 rbCb->rlcId.cellId);
1137 sapCb = KW_GET_UDX_SAP(gCb);
1139 RLC_ALLOC_SHRABL_BUF(sapCb->pst.region,
1142 sizeof(KwUdxStaPdu));
1144 #if (ERRCLASS & ERRCLS_ADD_RES)
1145 /* Memory allocation failure can not be expected */
1152 if (rbCb->m.amUl.snLen == KW_AM_CFG_12BIT_SN_LEN)
1155 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_12BITS;
1156 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_12BITS;
1158 else if (rbCb->m.amUl.snLen == KW_AM_CFG_18BIT_SN_LEN)
1161 resrvdBitsAckSn = KW_STA_PDU_R_BITS_ACKSN_18BITS;
1162 resrvdBitsNackSn = KW_STA_PDU_R_BITS_NACKSN_18BITS;
1167 resrvdBitsAckSn = 0;
1168 resrvdBitsAckSn = 0;
1171 pStaPdu->nackCnt = 0;
1173 hdrInfo.hdr = hdrInfo.hdr << KW_CPT_LEN;
1176 hdrInfo.len = snLen;
1177 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1178 pStaPdu->ackSn = hdrInfo.val;
1180 //printf ("++++++++++++ 5GNRLOG HNDL STATUS acksn %d : \n", pStaPdu->ackSn);
1181 /* Check if NACK Exists */
1182 hdrInfo.len = KW_E1_LEN;
1183 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1184 e1 = (U8)hdrInfo.val;
1185 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
1186 "kwAmmUlHndlStatusPdu: ACK SN = %d UEID:%d CELLID:%d",
1189 rbCb->rlcId.cellId);
1191 /* Extract the Reserved Bits after ACK SN field */
1192 hdrInfo.len = resrvdBitsAckSn;
1193 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1195 /* If NACK exists in control PDU */
1196 /* For ACKs and NACKs */
1197 while (e1 && (pStaPdu->nackCnt < KW_MAX_NACK_CNT))
1199 hdrInfo.len = snLen;
1200 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1201 pStaPdu->nackInfo[pStaPdu->nackCnt].sn = hdrInfo.val;
1203 hdrInfo.len = KW_E1_LEN;
1204 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1205 e1 = (U8)hdrInfo.val;
1208 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
1210 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1211 /* e2 = (U8) hdrInfo.val;*/
1213 /* Store e2 value */
1214 pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment = (U8) hdrInfo.val;
1216 /* Extract e3 : 5GNR */
1217 /* hdrInfo.len = KW_E1_LEN; --> previusly stored value (for e1) is
1219 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1220 e3 = (U8) hdrInfo.val;
1222 /* Extract Reserved Bits after NACK SN */
1223 hdrInfo.len = resrvdBitsNackSn;
1224 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1226 /* Test for resegmentation */
1227 if (pStaPdu->nackInfo[pStaPdu->nackCnt].isSegment)
1229 hdrInfo.len = KW_SO_LEN_5GNR; /* 5GNR : SO Len 16 Bits */
1230 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1231 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = hdrInfo.val;
1233 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1234 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = hdrInfo.val;
1236 RLOG_ARG4(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
1237 "kwAmmUlHndlStatusPdu: soStart and soEnd = %d %d"
1238 "UEID:%d CELLID:%d",
1239 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart,
1240 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd,
1242 rbCb->rlcId.cellId);
1247 pStaPdu->nackInfo[pStaPdu->nackCnt].soStart = 0;
1248 pStaPdu->nackInfo[pStaPdu->nackCnt].soEnd = 0;
1251 /* NACK RANGE Field is SET */
1254 /* Extract NACK range field */
1255 hdrInfo.len = KW_NACK_RANGE_LEN;
1256 kwAmmExtractElmnt(gCb, cntrlPdu, &hdrInfo);
1257 snRange = (U8)hdrInfo.val;
1259 pStaPdu->nackInfo[pStaPdu->nackCnt].nackRange = snRange;
1265 gRlcStats.amRlcStats.numULStaPduRcvd++;
1266 gRlcStats.amRlcStats.numULNackInStaPduRcvd += pStaPdu->nackCnt;
1268 /* In case we have reached the MAX NACK CNT, then we should modify the ACK_SN
1269 to the last NACK SN + 1 and discard the original ACK_SN*/
1270 if(pStaPdu->nackCnt == KW_MAX_NACK_CNT)
1272 pStaPdu->ackSn = (pStaPdu->nackInfo[KW_MAX_NACK_CNT-1].sn + 1) & (rbCb->m.amUl.snModMask);
1276 /* Parse & send Status PDU to RLC-DL */
1277 rlcUlUdxStaUpdReq(&(sapCb->pst), sapCb->spId, &rbCb->rlcId, pStaPdu);
1283 * @brief Private handler to release all stored segments
1286 * Private handler invokded by kwAmmUlPlacePduInRecBuf to release the
1287 * stored segements in case a complete PDU is received later.
1289 * @param[in] gCb RLC instance control block
1290 * @param[in] recBuf Buffer that stores a received PDU or segments
1296 PRIVATE Void kwAmmUlRlsAllSegs
1302 PRIVATE Void kwAmmUlRlsAllSegs(gCb,recBuf)
1309 TRC2(kwAmmUlRlsAllSegs)
1311 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1312 while (seg != NULLP)
1314 RLC_FREE_BUF_WC(seg->seg);
1315 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1316 RLC_FREE_WC(gCb,seg, sizeof(KwSeg));
1317 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1324 * @brief Private handler to store the received segment
1327 * Private handler invokded by kwAmmUlPlacePduInRecBuf to add a received
1328 * segment in reception buffer of a RBCB.
1329 * - It is responsible for detecting duplicate segments
1330 * - Adding it at appropriate position in the received buffer
1331 * - Calling ExpByteSeg to set expSo field in the receiver buffer
1333 * @param[in] gCb RLC instance control block
1334 * @param[in] rbCb Radio Bearer Contro Block
1335 * @param[in] amHdr AM Header received
1336 * @param[in] pdu Buffer received other than the headers
1337 * @param[in] pduSz size of the PDU buffer received
1340 * -#TRUE Successful insertion into the receiver buffer
1341 * -#FALSE Possibly a duplicate segment
1344 PRIVATE Bool kwAmmAddRcvdSeg
1353 PRIVATE Bool kwAmmAddRcvdSeg(gCb, rbCb, amHdr, pdu, pduSz)
1361 KwAmRecBuf *recBuf = NULLP;
1364 U16 soEnd; /* Holds the SoEnd of received segment */
1365 U16 expSo = 0; /* Expected SO */
1367 TRC2(kwAmmAddRcvdSeg)
1369 soEnd = amHdr->so + pduSz - 1;
1370 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, amHdr->sn);
1372 if (NULLP == recBuf)
1374 RLC_ALLOC(gCb,recBuf, sizeof(KwAmRecBuf));
1375 #if (ERRCLASS & ERRCLS_ADD_RES)
1376 if (recBuf == NULLP)
1378 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1379 "Memory allocation failed UEID:%d CELLID:%d",
1381 rbCb->rlcId.cellId);
1386 #endif /* ERRCLASS & ERRCLS_RES */
1387 kwUtlStoreRecBuf(AMUL.recBufLst, recBuf, amHdr->sn);
1391 if (recBuf->allRcvd == TRUE)
1398 recBuf->isDelvUpperLayer = FALSE;
1399 /* kw003.201 - Move past the segments that are different than the */
1401 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1402 while ((seg != NULLP) && (seg->amHdr.so < amHdr->so))
1404 expSo = seg->amHdr.so + seg->segSz;
1405 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
1408 /* The received segment should start after the end of previous seg */
1409 if (expSo > amHdr->so)
1411 /* This is a duplicate segment */
1412 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1417 if ((seg) && (seg->amHdr.so <= soEnd))
1419 /* This is a duplicate segment */
1420 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1425 /* If we have come this far, we have to add this segment to the */
1426 /* reception buffer as we either have eliminated duplicates or */
1427 /* have found none. */
1428 RLC_ALLOC_WC(gCb,tseg, sizeof(KwSeg));
1429 #if (ERRCLASS & ERRCLS_ADD_RES)
1432 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1433 "Memory allocation failed UEID:%d CELLID:%d",
1435 rbCb->rlcId.cellId);
1439 #endif /* ERRCLASS & ERRCLS_RES */
1442 tseg->segSz = pduSz;
1443 KW_MEM_CPY(&tseg->amHdr, amHdr, sizeof(KwAmHdr));
1444 recBuf->amHdr.si = amHdr->si;
1445 recBuf->amHdr.sn = amHdr->sn;
1446 tseg->soEnd = soEnd;
1449 cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
1453 recBuf->segLst.crnt = &seg->lstEnt;
1454 cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
1456 tseg->lstEnt.node = (PTR)tseg;
1457 kwAmmUpdExpByteSeg(gCb,&AMUL,tseg);
1463 * @brief Private handler to place the PDU in the reception buffer
1466 * This function checks if the received PDU's SN falls within the
1467 * receiving window, after which it places the same in the reception
1468 * buffer if its not a duplicate.
1470 * @param[in] gCb RLC instance control block
1471 * @param[in] pdu Received PDU
1472 * @param[in] rbCb Uplink AM Radio Bearer
1473 * @param[out] amUl AM UL Info
1481 PRIVATE Bool kwAmmUlPlacePduInRecBuf
1489 PRIVATE Bool kwAmmUlPlacePduInRecBuf(gCb, pdu, rbCb, amHdr)
1498 KwAmUl *amUl = &(rbCb->m.amUl);
1500 TRC2(kwAmmUlPlacePduInRecBuf)
1504 SFndLenMsg(pdu, &pduSz);
1506 gCb->genSts.bytesRecv += pduSz;
1507 gRlcStats.amRlcStats.numRlcAmCellSduBytesRx += pduSz;
1508 if (!KW_AM_CHK_SN_WITHIN_RECV_WINDOW(sn, amUl))
1510 gRlcStats.amRlcStats.numRlcAmCellDropOutWinRx++;
1511 RLOG_ARG3(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
1512 "kwAmmUlPlacePduInRecBuf: SN %d outside the window"
1513 "UEID:%d CELLID:%d",
1516 rbCb->rlcId.cellId);
1518 gCb->genSts.unexpPdusRecv++;
1525 KwAmRecBuf *recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
1527 /* We received a complete PDU. Either we already have it, in which */
1528 /* case we just ignore the new PDU and discard it. Otherwise, */
1529 /* store the received PDU in the reception buffer */
1530 if (NULLP == recBuf)
1532 RLC_ALLOC(gCb, recBuf, sizeof(KwAmRecBuf));
1533 #if (ERRCLASS & ERRCLS_ADD_RES)
1534 if (recBuf == NULLP)
1536 RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
1537 "Memory allocation failed UEID:%d CELLID:%d",
1539 rbCb->rlcId.cellId);
1543 #endif /* ERRCLASS & ERRCLS_RES */
1544 kwUtlStoreRecBuf(AMUL.recBufLst, recBuf, sn);
1546 else if (recBuf->allRcvd != TRUE)
1548 kwAmmUlRlsAllSegs(gCb,recBuf);
1552 gRlcStats.amRlcStats.numRlcAmCellDupPduRx++;
1553 gCb->genSts.unexpPdusRecv++;
1557 recBuf->isDelvUpperLayer = FALSE;
1559 recBuf->pduSz = pduSz;
1560 recBuf->allRcvd = TRUE;
1561 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
1562 KW_MEM_CPY(&recBuf->amHdr, amHdr, sizeof(KwAmHdr));
1567 /* We received a segment. We need to add that to the existing */
1568 /* segments, if any. */
1569 return (kwAmmAddRcvdSeg(gCb,rbCb, amHdr, pdu, pduSz));
1574 * @brief Private handler to trigger status report
1577 * Private handler invokded by kwAmmProcessPdus to check if the
1578 * status report need to be sent, and update the status trigger
1579 * flag accordingly based on status prohibit timer.
1581 * - Check if the received pdu's sn is less than rxHighestStatus, set the
1583 * - If staProhTmr is not running, calculate cntrlBo, else it'll be
1584 * updated at the expiry of staProhTmr.
1585 * - Expiry of reOrdTmr also will set staTrg flag.
1587 * @param[in] gCb RLC instance control block
1588 * @param[in] rbCb Uplink RB control block
1589 * @param[in] sn Sequence number of the pdu based on which to check if
1590 * status needs to be triggered
1591 * @param[in] discFlg Whether this pdu was discarded or not
1597 PRIVATE Void kwAmmTriggerStatus
1605 PRIVATE Void kwAmmTriggerStatus(gCb,rbCb, sn, discFlg)
1615 KwSn trxHighestStatus;
1616 KwAmUl *amUl = &(rbCb->m.amUl);
1618 TRC2(kwAmmTriggerStatus)
1621 MODAMR(amUl->vrMr, tVrMr, amUl->rxNext, amUl->snModMask);
1622 MODAMR(amUl->rxHighestStatus, trxHighestStatus, amUl->rxNext, amUl->snModMask);
1623 MODAMR(sn , tSn, amUl->rxNext, amUl->snModMask);
1625 /* kw005.201 Product CR ccpu00117114 *
1626 * The "=" in the 2nd condition is removed */
1627 if ((discFlg) || (tSn < trxHighestStatus) || (tSn >= tVrMr))
1629 RLOG_ARG2(L_UNUSED,DBG_RBID,rbCb->rlcId.rbId,
1630 "kwAmmTriggerStatus: Set Status Trigger UEID:%d CELLID:%d",
1632 rbCb->rlcId.cellId);
1634 amUl->staTrg = TRUE;
1635 amUl->gatherStaPduInfo = FALSE;
1637 /* Check if staProhTmr is running */
1638 tmrRunning = kwChkTmr(gCb,(PTR) rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1642 amUl->gatherStaPduInfo = TRUE;
1650 * @brief Private handler to reassemble from a segment or a PDU
1653 * Private handler invokded by kwAmmReassembleSdus with either a
1654 * PDU or a segment of a PDU. This is also called in the case of
1655 * reestablishment and hence out of sequence joining is also to
1659 * @param[in] gCb RLC instance control block
1660 * @param[in] rbCb Uplink RB control block
1661 * @param[in] amHdr AM header received for this segment/PDU
1662 * @param[in] pdu PDU to be reassembled
1668 PRIVATE Void kwAmmProcPduOrSeg
1676 PRIVATE Void kwAmmProcPduOrSeg(gCb, rbCb, amHdr, pdu)
1684 TRC2(kwAmmProcPduOrSeg)
1686 if ((AMUL.expSn != amHdr->sn) || (AMUL.expSo != amHdr->so))
1688 /* Release the existing partial SDU as we have PDUs or */
1689 /* segments that are out of sequence */
1690 rbCb->m.amUl.isOutOfSeq = TRUE;
1691 RLC_FREE_BUF(AMUL.partialSdu);
1694 //if (amHdr->fi & KW_FI_FIRST_SEG)
1695 if (amHdr->si == 0x01)
1696 {/* first Segment of the SDU */
1697 if (AMUL.partialSdu != NULLP)
1698 { /* Some old SDU may be present */
1699 RLC_FREE_BUF_WC(AMUL.partialSdu);
1701 AMUL.partialSdu = pdu;
1704 else if(amHdr->si == 0x03)
1705 {/* Middle or last segment of the SUD */
1706 SCatMsg(AMUL.partialSdu,pdu, M1M2);
1707 RLC_FREE_BUF_WC(pdu);
1710 else if (amHdr->si == 0x02)
1712 SCatMsg(pdu,AMUL.partialSdu,M2M1);
1713 RLC_FREE_BUF_WC(AMUL.partialSdu);
1718 AMUL.partialSdu = NULLP;
1719 kwUtlSndDatInd(gCb,rbCb, pdu);
1727 * @brief Private handler to reassemble SDUs
1730 * Private handler invokded by kwAmmProcessPdus with the PDU
1731 * from the reception buffer in sequence to reassemble SDUs and
1734 * - With the stored header info, FI and LSF segment / concatenate
1735 * PDUs or byte segments of PDUs to get the associated SDU.
1737 * @param[in] rbCb RB control block
1738 * @param[in] pdu PDU to be reassembled
1746 PRIVATE S16 kwAmmUlReassembleSdus
1753 PRIVATE S16 kwAmmUlReassembleSdus(gCb, rbCb, recBuf)
1761 TRC2(kwAmmUlReassembleSdus)
1762 //if (recBuf->amHdr.rf == 0)
1763 if (recBuf->amHdr.si == 0)
1766 kwAmmProcPduOrSeg(gCb,rbCb, &recBuf->amHdr, recBuf->pdu);
1767 /* Assign NULLP to recBuf->pdu as this PDU is sent to PDCP */
1768 recBuf->pdu = NULLP;
1769 AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1774 /* This is a set of segments */
1775 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1776 AMUL.expSn = recBuf->amHdr.sn;
1780 kwAmmProcPduOrSeg(gCb,rbCb, &seg->amHdr, seg->seg);
1781 AMUL.expSo = seg->soEnd + 1;
1783 cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
1784 RLC_FREE_WC(gCb, seg, sizeof(KwSeg));
1786 KW_LLIST_FIRST_SEG(recBuf->segLst, seg);
1788 AMUL.expSn = (recBuf->amHdr.sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1796 * @brief Handler to process the re-establishment request received from UIM
1798 * @param[in] gCb RLC instance control block
1799 * @param[in] rlcId RLC identifier
1800 * @param[in] sendReEst Whether to send back restablishment complete or not
1801 * @param[in] rbCb Uplink RB control block
1807 PUBLIC Void kwAmmUlReEstablish
1815 PUBLIC Void kwAmmUlReEstablish(gCb, rlcId, sendReEst, rbCb)
1827 KwKwuSapCb *kwKwSap;
1829 KwAmRecBuf *recBuf = NULLP;
1831 TRC2(kwAmmUlReEstablish);
1836 MODAMR(AMUL.vrMr, mVrMr, AMUL.rxNext, AMUL.snModMask);
1837 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1839 /* Reassemble SDUs from PDUs with SN less than upper edge of the window */
1842 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
1843 if (NULLP != recBuf)
1845 if (recBuf->allRcvd == TRUE)
1847 kwAmmUlReassembleSdus(gCb,rbCb, recBuf);
1851 /* Remove PDU and segments */
1854 RLC_FREE_BUF_WC(recBuf->pdu);
1856 /* Release all the segments*/
1857 kwAmmUlRlsAllSegs(gCb,recBuf);
1859 kwUtlDelRecBuf(AMUL.recBufLst, recBuf, gCb);
1861 sn = (sn + 1) & (AMUL.snModMask); /* MOD 1024 */
1862 MODAMR(sn, mSn, AMUL.rxNext, AMUL.snModMask);
1864 /* Discard remaining PDUs and bytesegments in recBuf */
1866 /* Stop all timers and reset variables */
1867 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_REORD_TMR))
1869 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
1871 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_STA_PROH_TMR))
1873 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1877 AMUL.rxNextHighestRcvd = 0;
1878 AMUL.rxNextStatusTrig = 0;
1879 rbCb->m.amUl.vrMr = (rbCb->m.amUl.rxNext + KW_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) & (rbCb->m.amUl.snModMask);
1880 AMUL.rxHighestStatus = 0;
1881 AMUL.staTrg = FALSE;
1882 AMUL.gatherStaPduInfo = FALSE;
1885 if (AMUL.partialSdu != NULLP)
1887 RLC_FREE_BUF(AMUL.partialSdu);
1889 kwKwSap = gCb->u.ulCb->kwuUlSap + KW_UI_PDCP;
1893 KwUiKwuReEstCmpInd(&kwKwSap->pst, kwKwSap->suId, rlcId);
1894 rbCb->m.amUl.isOutOfSeq = FALSE;
1901 * @brief Handler for reorder timer expiry
1904 * This function is used to handle events upon expiry of reorder timer
1906 * @param[in] gCb RLC instance control block
1907 * @param[in] rbCb RB control block
1914 PUBLIC Void kwAmmReOrdTmrExp
1920 PUBLIC Void kwAmmReOrdTmrExp(rbCb)
1925 KwAmUl *amUl = &(rbCb->m.amUl);
1929 KwSn mrxHighestStatus;
1930 KwSn mrxNextHighestRcvd;
1931 Bool tmrRunning = FALSE;
1932 KwAmRecBuf *recBuf = NULLP;
1934 TRC2(kwAmmReOrdTmrExp);
1937 /* Update rxHighestStatus */
1938 sn = amUl->rxNextStatusTrig;
1940 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1941 MODAMR(amUl->vrMr, mVrMr, amUl->rxNext, amUl->snModMask);
1942 recBuf = kwUtlGetRecBuf(AMUL.recBufLst, sn);
1946 if ((recBuf == NULLP) ||
1947 ((recBuf != NULLP) && (!recBuf->allRcvd)) )
1949 amUl->rxHighestStatus = sn;
1950 amUl->staTrg = TRUE;
1951 amUl->gatherStaPduInfo = FALSE;
1953 /* Check if staProhTmr is running */
1954 tmrRunning = kwChkTmr(gCb,(PTR) rbCb, KW_EVT_AMUL_STA_PROH_TMR);
1958 gRlcStats.amRlcStats.numULReOrdTimerExpires++;
1959 amUl->gatherStaPduInfo = TRUE;
1960 kwAmmUlAssembleCntrlInfo(gCb, rbCb);
1965 sn = (sn + 1) & (amUl->snModMask);
1966 MODAMR(sn, mSn, amUl->rxNext, amUl->snModMask);
1969 /* Update rxNextStatusTrig */
1970 MODAMR(amUl->rxNextHighestRcvd, mrxNextHighestRcvd, amUl->rxNext, amUl->snModMask);
1971 MODAMR(amUl->rxHighestStatus, mrxHighestStatus, amUl->rxNext, amUl->snModMask);
1972 if (mrxNextHighestRcvd > mrxHighestStatus)
1974 kwStartTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
1975 amUl->rxNextStatusTrig = amUl->rxNextHighestRcvd;
1979 } /* kwAmmReOrdTmrExp */
1982 * @brief Handler for status prohibit timer expiry
1985 * This function is used to handle events upon expiry of status prohibit
1988 * @param[in] gCb RLC instance control block
1989 * @param[in] rbCb RB control block
1996 PUBLIC Void kwAmmStaProTmrExp
2002 PUBLIC Void kwAmmStaProTmrExp(gCb, rbCb)
2007 KwAmUl *amUl = &(rbCb->m.amUl);
2009 TRC2(kwAmmStaProTmrExp);
2012 amUl->gatherStaPduInfo = FALSE;
2014 if (amUl->staTrg == TRUE)
2016 amUl->gatherStaPduInfo = TRUE;
2017 /* kw002.201 : Sending StaRsp after StaProhibit tmr expiry */
2018 kwAmmUlAssembleCntrlInfo(gCb,rbCb);
2022 } /* kwAmmStaProTmrExp */
2025 * @brief Handler to extract an element of AM Header
2028 * This function is used to extract an element of AM header.
2030 * @param[in] pdu The pdu to be decoded
2031 * @param[in,out] hdrInfo Container to hold the decoded info
2038 PRIVATE Void kwAmmExtractElmnt
2045 PRIVATE Void kwAmmExtractElmnt(gCb, pdu, hdrInfo)
2052 U8 pLen = hdrInfo->pLen;
2053 U8 len = (U8)hdrInfo->len;
2061 TRC2(kwAmmExtractElmnt);
2067 SRemPreMsg(&hdr, pdu);
2073 val = tHdr >> (KW_BYTE_LEN - (len));
2077 else /*if (len > 8) */
2081 val = val >> (KW_BYTE_LEN - fLen);
2082 val = val << (len - fLen);
2084 SRemPreMsg(&hdr, pdu);
2088 hdr = hdr >> (KW_BYTE_LEN - rLen);
2091 pLen = (KW_BYTE_LEN - rLen);
2095 rLen = rLen - KW_BYTE_LEN;
2097 tVal = tVal << rLen;
2100 SRemPreMsg(&hdr, pdu);
2102 hdr = hdr >> (KW_BYTE_LEN - rLen);
2105 pLen = (KW_BYTE_LEN - rLen);
2109 hdrInfo->pLen = pLen;
2117 * @brief Handler to updated expected byte seg
2120 * This function is used to update expected byte segment. The next segment
2121 * expected is indicated by the SO of the segment which is expected. Intially
2122 * the segment with SO 0 is expected and then in order. When all the segments
2123 * are received (which would happen when an expected SO is encountered
2124 * with LSF set) the allRcvd flag is set to TRUE
2126 * @param[in] gCb RLC instance control block
2127 * @param[in] amUl AM Uplink Control Block
2128 * @param[in] seg Newly received segment
2135 PRIVATE Void kwAmmUpdExpByteSeg
2142 PRIVATE Void kwAmmUpdExpByteSeg(gCb, amUl, seg)
2148 U16 newExpSo; /* The new expected SO */
2149 KwSn sn = seg->amHdr.sn;
2151 KwAmRecBuf *recBuf = NULLP;
2153 TRC2(kwAmmUpdExpByteSeg);
2156 recBuf = kwUtlGetRecBuf(amUl->recBufLst, sn);
2157 if ((recBuf == NULLP) || (recBuf && (seg->amHdr.so != recBuf->expSo)))
2162 newExpSo = seg->soEnd + 1;
2163 recBuf->expSo = newExpSo;
2164 //lstRcvd = seg->amHdr.lsf;
2165 if(seg->amHdr.si == 0x2)
2169 /* kw003.201 - This should update seg with the one after newSeg */
2170 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
2173 /* keep going ahead as long as the expectedSo match with the header so
2174 else store the expSo for later checking again */
2175 if(seg->amHdr.si == 0x2)
2179 if (seg->amHdr.so == newExpSo)
2181 newExpSo = seg->soEnd + 1;
2182 recBuf->expSo = newExpSo;
2183 //lstRcvd = seg->amHdr.lsf;
2184 KW_LLIST_NEXT_SEG(recBuf->segLst, seg);
2188 recBuf->expSo = newExpSo;
2192 if (lstRcvd == TRUE)
2194 recBuf->allRcvd = TRUE;
2195 gRlcStats.amRlcStats.numRlcAmCellSduRx++;
2203 * Function to release/free the Acknowledged Mode Module RbCb buffers
2206 * This primitive Frees the AM RbCb transmission Buffer, retransmission
2207 * Buffer and reciption Buffers
2209 * @param [in] gCb - RLC instance Control Block
2210 * @param [in] rbCb - RB Control Block
2215 PUBLIC Void kwAmmFreeUlRbCb
2221 PUBLIC Void kwAmmFreeUlRbCb(gCb,rbCb)
2226 KwSn curSn = 0; /* Sequence number of PDU */
2227 KwSn windSz; /* PDU window size */
2228 KwAmRecBuf *recBuf = NULLP;
2230 TRC2(kwAmmFreeUlRbCb)
2233 windSz = (KW_AM_GET_WIN_SZ(rbCb->m.amUl.snLen)) << 1;
2235 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_REORD_TMR))
2237 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_REORD_TMR);
2239 if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_AMUL_STA_PROH_TMR))
2241 kwStopTmr(gCb,(PTR)rbCb, KW_EVT_AMUL_STA_PROH_TMR);
2245 /* on the first loop winSz is always greater than zero
2246 while( ( curSn < windSz ) hence changing to do while */
2249 recBuf = kwUtlGetRecBuf(rbCb->m.amUl.recBufLst, curSn);
2250 if ( recBuf != NULLP )
2252 if (recBuf->pdu != NULLP)
2254 RLC_FREE_BUF_WC(recBuf->pdu);
2256 /* Release all the segments */
2257 kwAmmUlRlsAllSegs(gCb,recBuf);
2258 kwUtlDelRecBuf(rbCb->m.amUl.recBufLst, recBuf, gCb);
2261 }while ( curSn < windSz );
2264 RLC_FREE_WC(gCb,rbCb->m.amUl.recBufLst, (KW_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
2265 rbCb->m.amUl.recBufLst = NULLP;
2268 if(rbCb->m.amUl.partialSdu != NULLP)
2270 RLC_FREE_BUF_WC(rbCb->m.amUl.partialSdu);
2273 } /* kwAmmFreeUlRbCb */
2279 /********************************************************************30**
2282 **********************************************************************/