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 /**********************************************************************
25 Desc: Source code for PDCP Uplink module.
26 This file contains following functions
37 -- pjUlmHdlObdTmrExpiry
41 **********************************************************************/
42 static const char* RLOG_MODULE_NAME="PDCP";
43 static int RLOG_FILE_ID=245;
44 static int RLOG_MODULE_ID=1024;
46 @brief PDCP Uplink module
49 /* header (.h) include files */
50 #include "envopt.h" /* environment options */
51 #include "envdep.h" /* environment dependent */
52 #include "envind.h" /* environment independent */
54 #include "gen.h" /* general */
55 #include "ssi.h" /* system services interface */
56 #include "cm5.h" /* Timer Functions */
57 #include "cm_lte.h" /* common LTE header file */
58 #include "cm_hash.h" /* common hash module file */
59 #include "cm_llist.h" /* common list header file */
60 #include "cpj.h" /* RRC layer */
61 #include "pju.h" /* PDCP service user */
62 #include "lpj.h" /* RRC layer */
63 #include "pj_env.h" /* RLC environment options */
64 #include "pj.h" /* RLC layer */
71 /* header/extern include files (.x) */
73 #include "gen.x" /* general */
74 #include "ssi.x" /* system services interface */
75 #include "cm_lib.x" /* common library */
76 #include "cm5.x" /* Timer Functions */
77 #include "cm_hash.x" /* common hash module */
78 #include "cm_lte.x" /* common LTE file */
79 #include "cm_llist.x" /* common list header file */
80 #include "cpj.x" /* RRC layer */
81 #include "pju.x" /* PDCP service user */
82 #include "lpj.x" /* LM Interface */
83 #include "pj.h" /* LM Interface */
84 #include "pj.x" /* RLC layer */
94 #ifdef TENB_AS_SECURITY
95 EXTERN U8 isSecBatchMode;
98 /* forward references */
99 PUBLIC S16 pjUtlChekTxEnqReq(PjCb *gCb, PjDlRbCb *pjRbCb, PjTxEnt *txEnt);
100 PUBLIC S16 pjUtlChekRxEnqReq(PjCb *gCb, PjUlRbCb *pjRbCb, PjRxEnt *rxEnt);
102 /* public variable declarations */
104 /* This structure holds all the global structs we need. */
106 /* private variable declarations */
108 /* private function declarations */
110 PRIVATE S16 pjUlmDrbFetchSn
113 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
114 Buffer *pdu, /* !< PDU Buffer */
115 U8 hdrByte, /* !< one byte extracted from pdu */
116 PjSn *sn /* PDCP SN*/
118 PRIVATE S16 pjUlmProcessRb
121 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
122 PjSn rcvdSn, /* !< SN value of PDU */
123 Buffer *pdu, /* !< PDU message buffer */
124 Bool isOutOfSeq /* !< To indicate whether packet received is in-sequence or not */
126 /** @addtogroup uldata */
129 /*****************************************************************************
130 * HEADER PARSING FUNCTIONS
131 ****************************************************************************/
133 PRIVATE Void pjUlmEnqueueUlPkt ARGS(( PjCb *gCb, PjUlRbCb *pjRbCb,PjSn sn, Buffer *pdu));
137 PUBLIC S16 pjUlmHndlDlFdbk ARGS ((
146 * Function to extract the SRB header.
150 * This function extracts the SN and the MAC-I from the pdu buffer and
151 * places them in the SrbHdr structure.
153 * @param[in] pjRbCb PDCP control block
154 * @param[in] pdu PDU to be processed
161 PUBLIC S16 pjUlmHdlSrbPkt
164 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
165 Buffer *pdu /* !< PDU Buffer */
168 PUBLIC S16 pjUlmHdlSrbPkt(gCb, pjRbCb, pdu)
170 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
171 Buffer *pdu; /* !< PDU Buffer */
174 S16 ret = ROK; /* Return Value */
175 PjSn sn; /* SN value */
176 U8 hdrByte; /* First byte storing hdr values */
177 U8 res; /* Reserved values */
179 TRC2(pjUlmHdlSrbPkt);
182 /* Initialistaions */
184 /* Get the first byte */
185 ret = SRemPreMsg(&hdrByte, pdu);
186 #if (ERRCLASS & ERRCLS_DEBUG)
189 RLOG_ARG0(L_ERROR, DBG_UEID,pjRbCb->ueCb->key.ueId," SRemPreMsg Failed ");
191 PJ_STS_INC_GEN_CNT(gCb,errorPdusRecv);
194 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
196 /* Verify that reserved values are zero */
197 res = (hdrByte >> 4);
200 RLOG_ARG0(L_ERROR,DBG_UEID,pjRbCb->ueCb->key.ueId,
201 "Reserved Values Non-zero ");
203 PJ_STS_INC_GEN_CNT(gCb,errorPdusRecv);
207 /* Directly assigning since the reserved values are zero */
209 sn = sn << PJ_BYTE_SIZE;
210 ret = SRemPreMsg(&hdrByte, pdu);
211 #if (ERRCLASS & ERRCLS_DEBUG)
214 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_ERROR),
215 (gCb->init.prntBuf," SRemPreMsg Failed \n"));
221 /* Start processing */
222 ret = pjUlmProcessRb(gCb, pjRbCb, sn, pdu, FALSE);
225 }/* pjUlmHdlSrbPkt */
231 * Handler to forward the status report to PDCP-DL.
235 * 1. This function is called when a status report is received from the
237 * 2. This function forwards the status report to PDCP-DL. @n
239 * @param[in] pjRbCb PDCP control block.
240 * @param[in] staPdu Status report.
249 PUBLIC S16 pjUlmHndlDlStaRep
257 PUBLIC S16 pjUlmHndlDlStaRep(gCb, pjRbCb, fmc, staPdu)
264 UdxDlStaRepInfo *staRep;
265 PjUdxUlSapCb *udxSap;
266 S16 ret = ROK; /* Return Value */
268 TRC3(pjUlmHndlDlStaRep)
270 udxSap = PJ_GET_UL_UDX_SAP(gCb);
271 PJ_ALLOC_BUF_SHRABL(udxSap->pst ,staRep,
272 sizeof (UdxUlStaRepInfo), ret);
280 staRep->pdcpId.cellId = pjRbCb->ueCb->key.cellId;
281 staRep->pdcpId.ueId = pjRbCb->ueCb->key.ueId;
282 staRep->pdcpId.rbId = pjRbCb->rbId;
283 staRep->pdcpId.rbType = pjRbCb->rbType;
285 staRep->staPdu = staPdu;
287 PjUlUdxDlStaRep(&(udxSap->pst), udxSap->spId, staRep);
301 * Handler to forward the ROHC feedback packet received from UE to PDCP-DL.
305 * 1. This function is called when a ROHC feedback packet received from
307 * 2. This function forwards the ROHC feedback packet to PDCP-DL. @n
309 * @param[in] gCb global control block.
310 * @param[in] pjRbCb PDCP control block.
311 * @param[in] mBuf ROHC feedback packet.
320 PUBLIC S16 pjUlmHndlDlFdbk
327 PUBLIC S16 pjUlmHndlDlFdbk(gCb, pjRbCb, mBuf)
333 UdxDlFdbkPktInfo *fbPkt;
334 PjUdxUlSapCb *udxSap;
337 TRC3(pjUlmHndlDlFdbk)
339 udxSap = PJ_GET_UL_UDX_SAP(gCb);
341 PJ_ALLOC_BUF_SHRABL(udxSap->pst, fbPkt,
342 sizeof (UdxDlFdbkPktInfo), ret);
350 fbPkt->pdcpId.cellId = pjRbCb->ueCb->key.cellId;
351 fbPkt->pdcpId.ueId = pjRbCb->ueCb->key.ueId;
352 fbPkt->pdcpId.rbId = pjRbCb->rbId;
353 fbPkt->pdcpId.rbType = pjRbCb->rbType;
357 PjUlUdxDlFdbkPktInfo(&(udxSap->pst), udxSap->spId, fbPkt);
371 * Function to extract the DRB SN from hdr.
375 * This function extracts the SN in case of a data packet
377 * @param[in] pjRbCb PDCP control block
378 * @param[in] pdu PDU to be processed
384 PRIVATE S16 pjUlmDrbFetchSn
387 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
388 Buffer *pdu, /* !< PDU Buffer */
389 U8 hdrByte, /* !< one byte extracted from pdu */
390 PjSn *sn /* PDCP SN*/
393 PRIVATE S16 pjUlmDrbFetchSn(gCb, pjRbCb, pdu, hdrByte, sn)
395 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
396 Buffer *pdu; /* !< PDU Buffer */
397 U8 hdrByte; /* !< one byte extracted from pdu */
398 PjSn *sn; /* PDCP SN*/
401 U8 res; /* Reserved values */
402 S16 ret = ROK; /* Return Value */
405 if (pjRbCb->snLen == PJ_12_BIT_SN) /* Its 12 bit */
407 /* Verify that reserved values are zero */
408 res = (hdrByte >> 4);
411 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_ERROR),
412 (gCb->init.prntBuf," Reserved Values Non-zero \n"));
416 *sn = (hdrByte & PJ_12_BIT_SN_MSB_MASK); /*KW_FIX*/
417 *sn = *sn << PJ_BYTE_SIZE;
418 ret = SRemPreMsg(&hdrByte, pdu);
419 #if (ERRCLASS & ERRCLS_DEBUG)
422 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_ERROR),
423 (gCb->init.prntBuf," SRemPreMsg Failed \n"));
426 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
429 else if (pjRbCb->snLen == PJ_18_BIT_SN)
431 *sn = ((hdrByte & PJ_18_BIT_SN_MSB_MASK)); /*KW_FIX*/
432 *sn = *sn << PJ_BYTE_SIZE;
433 ret = SRemPreMsg(&hdrByte, pdu);
434 #if (ERRCLASS & ERRCLS_DEBUG)
437 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_ERROR),
438 (gCb->init.prntBuf," SRemPreMsg Failed \n"));
441 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
443 *sn = *sn << PJ_BYTE_SIZE;
444 ret = SRemPreMsg(&hdrByte, pdu);
445 #if (ERRCLASS & ERRCLS_DEBUG)
448 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_ERROR),
449 (gCb->init.prntBuf," SRemPreMsg Failed \n"));
452 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
463 * Function to extract the FMC.
467 * This function extracts the FMC and Bitmap incase of a
468 * PDCP status packet places them in the DrbHdr structure.
470 * @param[in] pjRbCb PDCP control block
471 * @param[in] pdu PDU to be processed
474 PUBLIC S16 pjUlmGetFmc
477 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
478 Buffer *pdu, /* !< PDU Buffer */
482 PUBLIC S16 pjUlmGetFmc(hdrByte,pjRbCb, pdu, fmc)
484 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
485 Buffer *pdu; /* !< PDU Buffer */
492 ret = SRemPreMsg(&hdrByte, pdu);
493 #if (ERRCLASS & ERRCLS_DEBUG)
496 RLOG_ARG0(L_DEBUG, DBG_UEID,pjRbCb->ueCb->key.ueId,"SRemPreMsg Failed");
502 *fmc = *fmc << PJ_BYTE_SIZE;
503 ret = SRemPreMsg(&hdrByte, pdu);
504 #if (ERRCLASS & ERRCLS_DEBUG)
507 RLOG_ARG0(L_DEBUG, DBG_UEID,pjRbCb->ueCb->key.ueId,"SRemPreMsg Failed");
512 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
514 *fmc = *fmc << PJ_BYTE_SIZE;
515 ret = SRemPreMsg(&hdrByte, pdu);
516 #if (ERRCLASS & ERRCLS_DEBUG)
519 RLOG_ARG0(L_DEBUG, DBG_UEID,pjRbCb->ueCb->key.ueId,"SRemPreMsg Failed");
524 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
526 *fmc = *fmc << PJ_BYTE_SIZE;
527 ret = SRemPreMsg(&hdrByte, pdu);
528 #if (ERRCLASS & ERRCLS_DEBUG)
531 RLOG_ARG0(L_DEBUG, DBG_UEID,pjRbCb->ueCb->key.ueId,"SRemPreMsg Failed");
536 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
548 * Function to extract the DRB header.
552 * This function extracts the SN in case of a data packet
553 * or feedback packet and the FMS and Bitmap incase of a
554 * PDCP status packet places them in the DrbHdr structure.
556 * @param[in] pjRbCb PDCP control block
557 * @param[in] pdu PDU to be processed
563 PUBLIC S16 pjUlmHdlDrbPkt
566 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
567 Buffer *pdu, /* !< PDU Buffer */
568 Bool isOutOfSeq /*!< To indicate whether this packet is in-sequence or not */
571 PUBLIC S16 pjUlmHdlDrbPkt(gCb, pjRbCb, pdu, isOutOfSeq)
573 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
574 Buffer *pdu; /* !< PDU Buffer */
575 Bool isOutOfSeq; /* !< To indicate whether this packet is in-sequence or not */
578 S16 ret = ROK; /* Return Value */
579 PjSn sn = 0; /* SN value */
580 U8 hdrByte; /* First byte storing hdr values */
581 U8 pduType; /* Type of PDU */
582 U8 res; /* Reserved values */
583 U32 fmc; /*First Missing Count 5G Nr*/
586 #ifndef RGL_SPECIFIC_CHANGES
589 extern U32 ulrate_kwu;
591 SFndLenMsg(pdu, &len);
596 /* Get the first byte */
597 ret = SRemPreMsg(&hdrByte, pdu);
598 #if (ERRCLASS & ERRCLS_DEBUG)
601 RLOG_ARG0(L_DEBUG, DBG_UEID,pjRbCb->ueCb->key.ueId," SRemPreMsg Failed ");
603 PJ_STS_INC_GEN_CNT(gCb,errorPdusRecv);
606 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
608 /* check if its a data PDU */
609 if((hdrByte & PJ_TYPE_DRB_DATA) == PJ_TYPE_DRB_DATA)
611 ret = pjUlmDrbFetchSn (gCb, pjRbCb, pdu, hdrByte, &sn);
612 #if (ERRCLASS & ERRCLS_DEBUG)
615 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_ERROR),
616 (gCb->init.prntBuf," Failed to extract SN from PDU\n"));
618 PJ_STS_INC_GEN_CNT(gCb,errorPdusRecv);
621 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
623 /* Call the processing function */
624 if(pjRbCb->mode == PJ_DRB_AM)
626 if (pjRbCb->state == PJ_STATE_HO)
628 pjUlmEnqueueUlPkt(gCb,pjRbCb,sn,pdu);
632 ret = pjUlmProcessRb(gCb, pjRbCb, sn, pdu, isOutOfSeq);
635 else /* (pjRbCb->type == PJ_DRB_UM) */
637 ret = pjUlmProcessRb(gCb, pjRbCb, sn, pdu, FALSE);
640 else /* Its a control PDU */
643 pduType = (U8)((hdrByte & PJ_PDU_BIT_MASK) >> 4); /*KW_FIX*/
645 if(pduType == PJ_TYPE_STATUS_REPORT)
647 pjUlmGetFmc(hdrByte,pjRbCb,pdu,&fmc);
648 ret = pjUlmHndlDlStaRep(gCb, pjRbCb, fmc, pdu);
651 RLOG_ARG0(L_DEBUG,DBG_UEID,pjRbCb->ueCb->key.ueId,
652 " pjUlmHndlDlStaRep() returned Failed ");
657 else if(pduType == PJ_TYPE_ROHC_FEEDBACK)
660 /* validate that reserved values are 0*/
661 res = (U8)(hdrByte & PJ_CPDU_RES_VAL_MASK); /*KW_FIX*/
664 RLOG_ARG0(L_DEBUG,DBG_UEID,pjRbCb->ueCb->key.ueId,
665 " Reserved values non-null ");
667 PJ_STS_INC_GEN_CNT(gCb,errorPdusRecv);
671 ret = pjUlmHndlDlFdbk(gCb, pjRbCb, pdu);
674 RLOG_ARG0(L_DEBUG,DBG_UEID,pjRbCb->ueCb->key.ueId,
675 " pjUlmHndlDlStaRep() returned Failed ");
682 /* Invalid PDU type */
683 RLOG_ARG0(L_DEBUG,DBG_UEID,pjRbCb->ueCb->key.ueId,
684 " Invalid PDU Type ");
686 PJ_STS_INC_GEN_CNT(gCb,errorPdusRecv);
691 }/* pjUlmHdlDrbPkt */
693 /*****************************************************************************
694 * PROCESSING FUNCTIONS
695 ****************************************************************************/
700 * Function to process the PDCP RB Pdu and updates the state variables.
704 * This function performs the follwing steps: @n
705 * 1. Create and Insert the entry in the reception buffer. @n
706 * 2. Check for firstSn in reestablish state. @n
707 * 3. Update nxtSubCnt and nxtSubDeCmp. @n
708 * 4. Call pjUtlDecipher to perform deciphering. @n
709 * 5. Call pjUtlDecomp to perform integrity verification. @n
710 * 6. Call pjUlmDeliverDrbUm for performing state updations and
711 * submitting to upper layers. @n
713 * @param[in] pjRbCb PDCP control block
714 * @param[in] rcvdSn SN value of the pdu
715 * @param[in] pdu PDU message buffer.
722 PUBLIC S16 pjUlmProcessRb
725 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
726 PjSn rcvdSn, /* !< SN value of PDU */
727 Buffer *pdu, /* !< PDU message buffer */
728 Bool isOutOfSeq /* !< To indicate whether packet received is in-sequence or not */
731 PUBLIC S16 pjUlmProcessRb(gCb, pjRbCb, rcvdSn, pdu, isOutOfSeq)
733 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
734 PjSn rcvdSn; /* !< SN value of PDU */
735 Buffer *pdu; /* !< PDU message buffer */
736 Bool isOutOfSeq; /* !< To indicate whether packet received is in-sequence or not */
739 PjUlCb *ulCb; /* PTR to UL Control Block */
740 PjRxEnt *rxEnt; /* Ptr to Rx Entry */
741 S16 ret = ROK; /* Return value */
742 U32 rcvdCount; /* Count value */
747 U32 oldRxCnt; /* Old Count value used for decomp */
752 /* 1. Initialisations */
753 ulCb = &pjRbCb->ulCb;
755 /*1.5G-NR Determine the Hfn and count value of the received PDCP data pdu*/
756 PJ_CALC_RCVD_HFN(rcvdSn,pjRbCb->snLen,ulCb->rxDeliv,rcvdHfn);
758 /*2.5G-NR Get the count value of the receiced PDCP data pdu from rcvdSn and rcvdHfn */
759 PJ_GET_COUNT(rcvdCount, pjRbCb->snLen, rcvdSn, rcvdHfn);
762 /* 3. Create the entry */
763 PJ_ALLOC(gCb,rxEnt, sizeof(PjRxEnt));
764 #if (ERRCLASS & ERRCLS_DEBUG)
767 RLOG0(L_FATAL, "Memory Allocation failed.");
770 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
772 /* 4. Fill values and Insert into hash list */
773 rxEnt->count = rcvdCount;
774 rxEnt->state = PJ_RDY_TO_DCIPHER;
776 rxEnt->lstEnt.next = NULLP;
777 rxEnt->lstEnt.prev = NULLP;
778 rxEnt->lstEnt.node = NULLP;
779 rxEnt->discFlag = rxEnt->dupEntry = 0;
780 rxEnt->isOutSeq = isOutOfSeq;
782 PJ_GET_HFN(ulCb->rxDeliv,pjRbCb->snLen,rxDelivHfn)
784 if((rcvdCount < ulCb->rxDeliv) &&(rxDelivHfn != PJ_MAX_HFN(pjRbCb->snLen)))
786 rxEnt->discFlag = TRUE;
787 PJ_FREE_BUF(rxEnt->mBuf);
788 PJ_FREE(gCb,rxEnt, sizeof(PjRxEnt));
792 ret = pjDbmInsRxEnt(gCb, &ulCb->recBuf, rxEnt, TRUE);
795 /* Duplicates are not to be inserted */
796 /* marked to be freed up later */
797 rxEnt->dupEntry = TRUE;
799 dupEntry = rxEnt->dupEntry;
801 /* 7. Cleanup the duplicates */
804 /* duplicate entry, Need to add a counter to print it on console periodically */
805 PJ_FREE_BUF(rxEnt->mBuf);
806 PJ_FREE(gCb,rxEnt, sizeof(PjRxEnt));
810 /*3.Update the RX_NEXT */
811 PJ_ULM_UPDATE_RX_NEXT(pjRbCb,rxEnt);
814 oldRxCnt = ulCb->rxNext;
815 PJ_ULM_UPD_NXT2DCOMP(ulCb, (pjRbCb->snLen), rcvdCount,oldRxCnt);
816 PJ_ULM_UPD_NXT2SUB(ulCb, rcvdCount);
819 /* 5. Update OBD count */
820 PJ_INC_OBD_COUNT(pjRbCb,rxEnt->count);
822 /* Check whether the received packet is in-sequence or not
823 * For every inSeq packet store the FMS Count value corresponding
824 * to the FMS + HFN now */
825 if((isOutOfSeq == FALSE) &&
826 (pjRbCb->rbType == PJ_DRB) &&
827 (pjRbCb->mode == PJ_DRB_AM))
829 /*Need to be check again */
830 pjRbCb->ulCb.fmsCount = ulCb->rxNext ;
833 /* 6. Send for deciphering */
834 ret = pjUlmHdlDecipher(gCb, pjRbCb, rxEnt);
837 }/* pjUlmProcessRb */
844 * Function is called when the offboard timer expires.
848 * The function performs the following
849 * 1. If the SDU associated with the timer is not delivered, we
850 * delete the entry . @n
851 * 2. A status indication is sent to the user with error cause. @n
852 * 3. We associate the nextToSubmit value to the next SDU that has
853 * to be submitted. @n
854 * 4. The timer is associated with the nextToSubmit SDU and restarted.@n
856 * @param[in] pjRbCb PDCP control block
857 * @param[in] rxEnt Rx Entry
864 PUBLIC S16 pjUlmHdlDecipher
867 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
868 PjRxEnt *rxEnt /* !< Rx Entry */
871 PUBLIC S16 pjUlmHdlDecipher(gCb, pjRbCb, rxEnt)
873 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
874 PjRxEnt *rxEnt; /* !< Rx Entry */
877 PjUlCb *ulCb; /* ULM Control Block */
878 S16 ret = ROK; /* Return values */
879 Buffer *mBuf = NULLP; /* Output Buffer */
881 U32 macI = 0; /*5G_NR for DRB, its a 4 byte field */
882 TRC2(pjUlmHdlDecipher);
885 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
886 (gCb->init.prntBuf, "pjUlmHdlDecipher(pjRbCb(%d,%d),rxEnt(%ld)) \n", \
887 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
889 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
890 (gCb->init.prntBuf, "pjUlmHdlDecipher(pjRbCb(%d,%d),rxEnt(%d)) \n", \
891 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
894 /* 1. Initialistions */
895 ulCb = &pjRbCb->ulCb;
897 secInfo = &(pjRbCb->ueCb->secInfo);
898 /* 2. Process for Deciphering */
899 if(secInfo->secAct == TRUE && secInfo->cipherInfo.algoType != 0)
901 /* 2.1 Check that it is not the first pkt, with selectively enabled */
902 if((pjRbCb->rbType == PJ_SRB) &&
903 (pjRbCb->ueCb->secInfo.firstMsg && pjRbCb->ueCb->secInfo.selSecAct))
906 pjRbCb->ueCb->secInfo.firstMsg = FALSE;
912 pjUtlChekRxEnqReq(gCb, pjRbCb, rxEnt);
921 /* 2.3 call deciphering hook */
922 if( pjUtlDecipherReq(gCb, pjRbCb, rxEnt->count, rxEnt->mBuf, &mBuf) != ROK)
924 RLOG1(L_ERROR, "Deciphering Req failed Rx Count [%lu]", rxEnt->count);
925 PJ_SND_PJU_STA_IND(gCb,pjRbCb, rxEnt);
926 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
927 PJ_STS_INC_GEN_CNT(gCb,numDeciphFails);
932 /* 2.4 wait for output before processing further */
933 /* Batch Mode processing, Packets queued will be sent to spacc
934 together upon trigger */
935 #ifdef TENB_AS_SECURITY
938 rxEnt->state = PJ_SENT_TO_DCIPHER;
943 #if defined (PJ_SEC_ASYNC) || defined (INTEL_QAT_DP)
944 /* 2.4 wait for output before processing further */
945 rxEnt->state = PJ_SENT_TO_DCIPHER;
947 #else /* PJ_SEC_ASYNC */
948 /* 2.3 Validate output of deciphering */
951 RLOG1(L_ERROR, "Deciphering Req failed Rx Count [%lu]", rxEnt->count);
952 PJ_SND_PJU_STA_IND(gCb,pjRbCb, rxEnt);
953 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
954 PJ_STS_INC_GEN_CNT(gCb,numDeciphFails);
958 /* 2.5 copy output buffer */
959 #ifdef TENB_AS_SECURITY
960 /* If not batch mode, free PDU. If batch mode, free will be done upon
962 if(!(isSecBatchMode))
964 PJ_FREE_BUF(rxEnt->mBuf);
972 else if(pjRbCb->rbType == PJ_DRB)
974 pjUpdRxEntBuf(rxEnt);
977 /* 3. Post ciphering updations */
978 if(pjRbCb->rbType == PJ_DRB)
980 rxEnt->state = PJ_RDY_TO_DCOMP;
981 /*Adding MACI for 5G NR for DRB in case of intergrity protection is enabled*/
982 if(pjRbCb->ueCb->secInfo.intProtEnbForDrb)
984 PJ_UNPK_MACI(rxEnt->mBuf, macI);
986 ret = pjUlmHdlDeCmp(gCb, pjRbCb, rxEnt);
990 rxEnt->state = PJ_RDY_TO_INTVER;
991 ret = pjUlmHdlIntVer(gCb, pjRbCb, rxEnt);
995 }/* end of pjUlmHdlDecipher */
1002 * Function is called to perform integrity verification.
1006 * The function performs the following
1007 * 1. Extract the mac-I.
1008 * 2. Add sn to the buffer.
1009 * 3. Call Integrity Verification hook.
1010 * 4. Return in case of Async.
1011 * 5. Validate output and submit for delivery.
1013 * @param[in] pjRbCb PDCP control block
1014 * @param[in] rxEnt Rx Entry
1021 PUBLIC S16 pjUlmHdlIntVer
1024 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
1025 PjRxEnt *rxEnt /* !< Rx Entry */
1028 PUBLIC S16 pjUlmHdlIntVer(gCb, pjRbCb, rxEnt)
1030 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
1031 PjRxEnt *rxEnt; /* !< Rx Entry */
1034 PjUlCb *ulCb; /* ULM Control Block */
1035 PjSn sn; /* Sn Value */ /*KW_FIX*/
1036 S16 ret = ROK; /* Return value */
1037 U32 macI = 0; /* Mac-I value */
1038 PjSecInp inParam; /* Input Params */
1039 Status status = ROK; /* Status of IntVer */
1041 TRC2(pjUlmHdlIntVer);
1044 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1045 (gCb->init.prntBuf, "pjUlmHdlIntVer(pjRbCb(%d,%d),rxEnt(%ld)) \n", \
1046 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1048 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1049 (gCb->init.prntBuf, "pjUlmHdlIntVer(pjRbCb(%d,%d),rxEnt(%d)) \n", \
1050 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1053 /* 1. Initialistions */
1054 ulCb = &pjRbCb->ulCb;
1056 /* 2. Xtract the last four bits irrescpective of whether you
1057 * are going to do integrity verification or not */
1060 #ifndef INTEL_QAT_DP
1061 PJ_UNPK_MACI(rxEnt->mBuf, macI);
1064 /* 3. Process for Integrity Verification */
1065 if(pjRbCb->ueCb->secInfo.secAct == TRUE && pjRbCb->ueCb->secInfo.intInfo.algoType != 0)
1068 /* 3.1 Prepare the input Parameters */
1069 inParam.dir = PJ_SEC_DIR_UL;
1070 inParam.rbId = pjRbCb->rbId;
1071 inParam.count = rxEnt->count;
1073 /* 3.2. Add the SN to the buffer */
1074 sn = (U32)(rxEnt->count % (1 << PJ_SRB_SN_LEN)); /*KW_FIX*/
1075 ret = SAddPreMsg((Data)sn, rxEnt->mBuf);
1076 #if (ERRCLASS & ERRCLS_DEBUG)
1079 RLOG_ARG0(L_ERROR, DBG_UEID,pjRbCb->ueCb->key.ueId,
1080 " pjUlmProcessRb: SRemPreMsgMult Failed ");
1081 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
1084 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
1086 /* 3.3 call deciphering hook */
1087 if( pjUtlIntVerReq(gCb, pjRbCb, inParam, rxEnt->mBuf, macI, &status) != ROK)
1089 RLOG1(L_ERROR, "Integrity Verification Req failed Rx Count[%lu]", rxEnt->count);
1090 ret = SRemPreMsg((Data *)&sn, rxEnt->mBuf);
1094 PJ_SND_PJU_STA_IND(gCb,pjRbCb, rxEnt);
1095 rxEnt->state = PJ_RX_INTVER_FAIL;
1096 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
1097 PJ_STS_INC_GEN_CNT(gCb,numIntgVrfFails);
1101 /* 3.5 wait for output before processing further */
1102 rxEnt->state = PJ_SENT_TO_INTVER;
1105 /* 3.4. Remove the SN from the buffer */
1106 ret = SRemPreMsg((Data *)&sn, rxEnt->mBuf);
1107 #if (ERRCLASS & ERRCLS_DEBUG)
1110 RLOG1(L_ERROR, "SRemPreMsg failed Rx Count [%lu]", rxEnt->count);
1111 PJ_FREE_BUF(rxEnt->mBuf);
1112 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
1115 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
1118 /* 3.5 wait for output before processing further */
1119 rxEnt->state = PJ_SENT_TO_INTVER;
1122 /* 3.6 Post integrity verification updations */
1125 RLOG1(L_ERROR, "Integrity Verification Req failed Rx Count[%lu]", rxEnt->count);
1126 PJ_SND_PJU_STA_IND(gCb,pjRbCb, rxEnt);
1127 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
1128 PJ_STS_INC_GEN_CNT(gCb,numIntgVrfFails);
1132 #endif /* PJ_SEC_ASYNC */
1133 #endif /*INTEL_QAT_DP */
1139 /* 4. Update state and send for delivery */
1140 rxEnt->state = PJ_RDY_TO_SUBMIT;
1141 ret = pjUlmDeliverSrb(gCb, pjRbCb, rxEnt);
1147 }/* end of pjUlmHdlIntVer */
1154 * Function is called to handle decompression.
1158 * The function performs the following
1159 * 1. Call decompression handler function.
1160 * 2. For sync, validate output and submit for delivery.
1162 * @param[in] pjRbCb PDCP control block
1163 * @param[in] rxEnt Rx Entry
1170 PUBLIC S16 pjUlmHdlDeCmp
1173 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
1174 PjRxEnt *rxEnt /* !< Rx Entry */
1177 PUBLIC S16 pjUlmHdlDeCmp(gCb, pjRbCb, rxEnt)
1179 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
1180 PjRxEnt *rxEnt; /* !< Rx Entry */
1183 PjUlCb *ulCb; /* ULM Control Block */
1184 Buffer *mBuf = NULLP; /* Output Buffer */
1186 TRC2(pjUlmHdlDeCmp);
1189 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1190 (gCb->init.prntBuf, "pjUlmHdlDeCmp(pjRbCb(%d,%d),rxEnt(%ld)) \n", \
1191 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1193 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1194 (gCb->init.prntBuf, "pjUlmHdlDeCmp(pjRbCb(%d,%d),rxEnt(%d)) \n", \
1195 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1198 /* 1. Initialistions */
1199 ulCb = &pjRbCb->ulCb;
1201 /* 2. process for decompression */
1202 if(pjRbCb->rohc.hdrCmpUsed == TRUE)
1204 /* 2.1 call decompression hook */
1205 if(pjUtlDeCmpReq(gCb, pjRbCb,rxEnt->count, rxEnt->mBuf, &mBuf) != ROK)
1207 RLOG1(L_ERROR, "DeCompression Req failed Rx Count[%lu]", rxEnt->count);
1208 PJ_SND_PJU_STA_IND(gCb,pjRbCb, rxEnt);
1209 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
1210 PJ_STS_INC_GEN_CNT(gCb,numDecmpFails);
1215 /* 2.2 Wait for output before processing further */
1216 rxEnt->state = PJ_SENT_TO_DCOMP;
1218 #else /* PJ_CMP_ASYNC */
1220 /* 2.3 Validate output of decomp */
1223 RLOG1(L_ERROR, "DeCompression Req failed Rx Count[%lu]", rxEnt->count);
1224 PJ_SND_PJU_STA_IND(gCb,pjRbCb, rxEnt);
1225 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
1226 PJ_STS_INC_GEN_CNT(gCb,numDecmpFails);
1230 /* 2.4 Copy output buffer */
1231 PJ_FREE_BUF(rxEnt->mBuf);
1236 /* 3. Return for discardable entries */
1237 if((rxEnt->discFlag == TRUE) ||
1238 (rxEnt->dupEntry == TRUE))
1240 RLOG2(L_ERROR,"Dropping packets...discflag is [%d], dupEntry is [%d]", rxEnt->discFlag, rxEnt->dupEntry);
1244 /* 4. Post decomp updations */
1245 rxEnt->state = PJ_RDY_TO_SUBMIT;
1246 PJ_DEC_OBD_COUNT(gCb, pjRbCb, rxEnt->count);
1247 PJ_ULM_DELIVER_DRB(gCb,pjRbCb, rxEnt);
1250 }/* end of pjUlmHdlDeCmp */
1253 PUBLIC S16 pjUlmDeliverPdu
1256 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
1257 PjRxEnt *rxEnt /* !< Recption Buffer Entry */
1260 PUBLIC S16 pjUlmDeliverPdu(gCb,pjRbCb, rxEnt)
1262 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
1263 PjRxEnt *rxEnt; /* !< Recption Buffer Entry */
1267 PjRxEnt *tmpEnt; /* Temp Entry - loop counter */
1268 U32 rxReOrdHfn,rxNextHfn, rxDelivHfn;
1271 TRC2(pjUlmDeliverPdu)
1273 /* Initialisations */
1274 ulCb = &pjRbCb->ulCb;
1275 if(rxEnt->state != PJ_RDY_TO_SUBMIT)
1277 /* PDU still under processing, return */
1280 ulCb->outOfOrderDelivery = FALSE;
1282 if(ulCb->outOfOrderDelivery == FALSE )
1285 /* submit to upper layers and delete entry */
1286 /* submit all the stored pdu's with consecutively associated COUNT value(s) starting from COUNT = RX_DELIV*/
1287 if(rxEnt->count == ulCb->rxDeliv)
1289 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
1290 if(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ))
1293 tmpEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
1296 PJ_SND_PJU_DAT_IND(gCb,pjRbCb, tmpEnt);
1297 pjDbmDelRxEnt(gCb, &ulCb->recBuf, tmpEnt->count);
1298 /*updating the stateVariable*/
1299 ulCb->rxDeliv = ulCb->rxDeliv + 1;
1300 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
1301 if(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ) == NULLP)
1305 tmpEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
1306 }while(tmpEnt->count == ulCb->rxDeliv);
1310 /*If out of order Delivery is configured*/
1313 PJ_SND_PJU_DAT_IND(gCb,pjRbCb, rxEnt);
1314 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
1315 /*updating the stateVariable*/
1316 ulCb->rxDeliv = ulCb->rxDeliv + 1;
1320 /* Update the Reordering state variable reffer sec 5.2.2.2 of 38.323 */
1322 PJ_GET_HFN(ulCb->rxDeliv,pjRbCb->snLen,rxDelivHfn);
1323 tmrRunning = pjChkTmr(gCb,(PTR)pjRbCb, PJ_EVT_UL_REORD_TMR);
1326 PJ_GET_HFN(ulCb->rxDeliv,pjRbCb->snLen,rxReOrdHfn);
1327 if ((ulCb->rxDeliv >= ulCb->rxReord) ||
1328 ((PJ_MAX_HFN(pjRbCb->snLen) == rxReOrdHfn) &&
1331 pjStopTmr(gCb,(PTR)pjRbCb, PJ_EVT_UL_REORD_TMR);
1338 PJ_GET_HFN(ulCb->rxNext, pjRbCb->snLen,rxNextHfn);
1339 if ((ulCb->rxDeliv < ulCb->rxNext) ||
1340 (((PJ_MAX_HFN(pjRbCb->snLen) == rxDelivHfn)) &&
1343 ulCb->rxReord = ulCb->rxNext;
1344 pjStartTmr(gCb,(PTR)pjRbCb, PJ_EVT_UL_REORD_TMR);
1357 * Function to perform updations and deliver the SDU to the upper layer.
1358 * It is called for SRBs .
1362 * This function performs the following functions, @n
1363 * 1. Call PjUiPjuDatInd to deliver the SDU to the upper layer. @n
1364 * 2. In async mode, check if any subsequent SDUs can also be sent up.@n
1366 * @param[in] pjRbCb PDCP control block
1367 * @param[in] rxEn reception entry for the PDU
1373 PUBLIC S16 pjUlmDeliverSrb
1376 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
1377 PjRxEnt *rxEnt /* !< Recption Buffer Entry */
1380 PUBLIC S16 pjUlmDeliverSrb(gCb, pjRbCb, rxEnt)
1382 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
1383 PjRxEnt *rxEnt; /* !< Recption Buffer Entry */
1388 U32 count; /* Count for looping through the entries */
1389 U32 nxtRxCnt; /* Count for looping through the entries */
1390 PjRxEnt *tmpEnt; /* Temp var for looping through the entries */
1393 TRC2(pjUlmDeliverSrb);
1395 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1396 (gCb->init.prntBuf, "pjUlmDeliverSrb(pjRbCb(%d,%d),rxEnt(%ld)) \n", \
1397 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1399 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1400 (gCb->init.prntBuf, "pjUlmDeliverSrb(pjRbCb(%d,%d),rxEnt(%d)) \n", \
1401 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1404 /* Post integrity verification updations */
1406 count = rxEnt->count;
1407 ulCb = &pjRbCb->ulCb;
1409 pjUlmDeliverPdu(gCb,pjRbCb,rxEnt);
1413 /* Search and see if any of the successive SDUs can
1414 * also be sent to the upper layer */
1416 nxtRxCnt = ulCb->rxNext;
1418 /* Check till nxtRxCnt */
1419 while(count < nxtRxCnt)
1421 /* Get the next node */
1422 tmpEnt = (PjRxEnt *)pjDbmGetRxEnt(gCb, &ulCb->recBuf, count);
1427 /* Such an entry does not exist, search for the next */
1430 if(tmpEnt->state != PJ_RDY_TO_SUBMIT)
1432 /* Integrity verification not yet done so we have to wait */
1433 ulCb->nxtSubCnt = tmpEnt->count;
1434 /* Cant send anymore messages up, break*/
1439 /* call the PJU Primitive to deliver it to upper layers */
1440 PJ_SND_PJU_DAT_IND(gCb,pjRbCb, tmpEnt);
1442 /* cleanup the entry */
1443 pjDbmDelRxEnt(gCb, &ulCb->recBuf, tmpEnt->count);
1447 if( ((count == nxtRxCnt) &&(tmpEnt != NULLP) &&(tmpEnt->state == PJ_RDY_TO_SUBMIT)) ||
1448 ((count == nxtRxCnt) &&(tmpEnt == NULLP)) )
1450 if((pjChkTmr(gCb, (PTR)pjRbCb, PJ_EVT_UL_OBD_TMR)) == TRUE)
1452 pjStopTmr(gCb, (PTR)pjRbCb, PJ_EVT_UL_OBD_TMR);
1455 #endif /* PJ_SEC_ASYNC */
1459 }/* pjUlmDeliverSrb */
1466 * Function to deliver the SDU to the upper layer.
1467 * It is called for DRB UM
1471 * This function performs the following functions. @n
1472 * 1. Deliver the SDU to the upper layer @n
1473 * 2. Clean up the hash list entry for this SDU. @n
1474 * 3. For asynchronous mode, it checks if any subsequent
1475 * messages can also be sent up. @n
1476 * 4. Mark the next SDU to be submitted to the upper layers. @n
1478 * @param[in] pjRbCb PDCP control block
1479 * @param[in] rxEnt reception entry for the PDU
1485 PUBLIC S16 pjUlmDeliverDrbUm
1488 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
1489 PjRxEnt *rxEnt /* !< Recption Buffer Entry */
1492 PUBLIC S16 pjUlmDeliverDrbUm(gCb, pjRbCb, rxEnt)
1494 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
1495 PjRxEnt *rxEnt; /* !< Recption Buffer Entry */
1500 PjUlCb *ulCb; /* Uplink Cb Ptr */
1501 U32 nxtRxCnt; /* Count for looping through the entries */
1502 PjRxEnt *tmpEnt; /* Temp var for looping through the entries */
1503 U32 count; /* count varaible */
1504 ulCb = &pjRbCb->ulCb;
1507 TRC2(pjUlmDeliverDrbUm)
1509 PJDBGP(gCb, (PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1510 (gCb->init.prntBuf, "pjUlmDeliverDrbUm(pjRbCb(%d,%d),rxEnt(%ld)) \n", \
1511 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1513 PJDBGP(gCb, (PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1514 (gCb->init.prntBuf, "pjUlmDeliverDrbUm(pjRbCb(%d,%d),rxEnt(%d)) \n", \
1515 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1518 /* Initialisations */
1521 rxEnt->state = PJ_RDY_TO_SUBMIT;
1523 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
1524 if(rxEnt->count != ulCb->nxtSubCnt)
1528 #endif /* (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC)) */
1529 #ifndef PJ_CMP_ASYNC
1531 #ifndef RGL_SPECIFIC_CHANGES
1534 EXTERN U32 ulrate_pju;
1536 SFndLenMsg(rxEnt->mBuf, &len);
1542 pjUlmDeliverPdu(gCb,pjRbCb,rxEnt);
1547 /* Search and see if any of the succeeding SNs can
1548 * also be sent to the upper layer */
1549 nxtRxCnt = ulCb->rxNext;
1551 /* Search till nextRxCnt */
1552 for(count = ulCb->nxtSubCnt + 1; count < nxtRxCnt; count++)
1554 /* Get the next node */
1555 tmpEnt = (PjRxEnt *)pjDbmGetRxEnt(gCb, &(ulCb->recBuf), count);
1559 /* pj005.201 added support for L2 Measurement */
1560 /* Such an entry does not exist, search for the next */
1563 if(tmpEnt->state != PJ_RDY_TO_SUBMIT)
1565 /* Cant send anymore messages up, break*/
1570 /* pj005.201 added support for L2 Measurement */
1571 /* call the PJU Primitive to deliver it to upper layers */
1572 PJ_SND_PJU_DAT_IND(gCb,pjRbCb, tmpEnt);
1574 /* cleanup the entry */
1575 pjDbmDelRxEnt(gCb, &ulCb->recBuf, tmpEnt->count);
1579 /* Update nxtSubCnt */
1580 ulCb->nxtSubCnt = count;
1581 #endif /* PJ_CMP_ASYNC */
1583 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
1584 if(pjRbCb->state != PJ_STATE_NORMAL)
1586 /* start reestablishment procedures if last message has been processed */
1587 if((ulCb->transCmp == TRUE) &&
1588 (ulCb->obdCnt == 0))
1590 /* It has received all messages from RLC and finished
1591 * processing them. Possibility only when the last last message
1592 * from deciphering fails. */
1593 PJ_ULM_DRBUM_REEST(gCb, pjRbCb);
1596 #endif /* (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC)) */
1599 }/* pjUlmDeliverDrbUm */
1605 * Function to deliver the SDU to the upper layer. It is called for DRB AM
1609 * This function performs the following functions. @n
1610 * 1. Delete duplicates and SDUs marked for discard. @n
1611 * 2. Deliver the SDU to the upper layer @n
1612 * 3. Perform sequential delivery for SDUs received during reestablishment. @n
1613 * 4. Clean up the hash list entry for this SDU. @n
1614 * 5. For asynchronous mode, check if any subsequent messages can also be sent up. @n
1615 * 6. Mark the next SDU to be submitted to the upper layers. @n
1617 * @param[in] pjRbCb PDCP control block
1618 * @param[in] rxEnt Rx Entry
1625 PUBLIC S16 pjUlmDeliverDrbAm
1628 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
1629 PjRxEnt *rxEnt /* !< Recption Buffer Entry */
1632 PUBLIC S16 pjUlmDeliverDrbAm(gCb, pjRbCb, rxEnt)
1634 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
1635 PjRxEnt *rxEnt; /* !< Recption Buffer Entry */
1638 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
1639 PjUlCb *ulCb; /* RB uplink Control Block */
1641 S16 ret; /* Return value */
1643 TRC2(pjUlmDeliverDrbAm)
1645 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1646 (gCb->init.prntBuf, "pjUlmDeliverDrbAm(pjRbCb(%d,%d),rxEnt(%ld)) \n", \
1647 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1649 PJDBGP(gCb,(PJ_DBGMASK_ULM | PJ_DBGMASK_DETAIL ),
1650 (gCb->init.prntBuf, "pjUlmDeliverDrbAm(pjRbCb(%d,%d),rxEnt(%d)) \n", \
1651 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count));
1654 /* Initialisations */
1656 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
1657 ulCb = &pjRbCb->ulCb;
1659 #ifndef RGL_SPECIFIC_CHANGES
1662 extern U32 ulrate_pju;
1664 SFndLenMsg(rxEnt->mBuf, &len);
1669 pjUlmDeliverPdu(gCb,pjRbCb,rxEnt);
1670 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
1671 /* start reestablishment procedures if last message has been processed */
1672 if(pjRbCb->state != PJ_STATE_NORMAL)
1674 if((ulCb->transCmp == TRUE) &&
1675 (ulCb->obdCnt == 0))
1677 /* It has received all messages from RLC and finished
1678 * processing them. Possibility only when the last last message
1679 * from deciphering fails. */
1680 pjUlmReEstDrbAm(gCb, pjRbCb);
1683 #endif /* (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC)) */
1686 }/* pjUlmDeliverDrbAm */
1688 /*****************************************************************************
1689 * REESTABLISHMENT FUNCTIONS
1690 ****************************************************************************/
1696 * Function to is called to reestablish the SRB. It is called as when the
1697 * reestablishment request is received.
1701 * This function performes the following. @n
1702 * 1. Reset NEXT_PDCP_RX_SN and RX_HFN @n
1703 * 2. Deinitialise the hashlist. @n
1705 * @param[in] pjRbCb PDCP control block
1711 PUBLIC S16 pjUlmReEstSrb
1714 PjUlRbCb *pjRbCb /*!< PDCP control block */
1717 PUBLIC S16 pjUlmReEstSrb(gCb,pjRbCb)
1719 PjUlRbCb *pjRbCb; /*!< PDCP control block */
1722 TRC2(pjUlmReEstSrb);
1724 /* Reset NEXT_PDCP_RX_SN and RX_HFN */
1725 pjRbCb->ulCb.rxNext = 0;
1726 pjRbCb->ulCb.rxDeliv = 0;
1728 /* Deinitialise the hashlist */
1729 pjDbmRxDelAll(gCb, &pjRbCb->ulCb.recBuf);
1732 } /* pjUlmResetSrb */
1740 * Function to is called to reestablish the DRB .
1744 * This function is called after the last pdu is received from RLC
1745 * as part of reestablishment procedures. This function builds the staPdu
1748 * @param[in] pjCb PDCP Instance control block
1749 * @param[in] pjRbCb PDCP control block
1755 PUBLIC S16 pjUlmReEstDrbAm
1761 PUBLIC S16 pjUlmReEstDrbAm(gCb, pjRbCb)
1766 U16 fms; /* First Missing SN */
1767 PjUlCb *ulCb; /* RB uplink Control Block */
1768 PjSn sn; /* temp sn */
1769 PjRxEnt *tmpEnt = NULLP; /* Temporary entity used in loop */
1770 U32 count; /* Counter variable */
1774 U8 numBits = 0; /*KW_FIX */
1776 PjUlHoCfmInfo *hoInfo = NULLP; /* To store the numBits and bitMap */
1777 U8 packByte[512] = {0};
1779 TRC2(pjUlmReEstDrbAm);
1781 RLOG2(L_DEBUG,"pjUlmReEstDrbAm(pjRbCb(%d,%d))",pjRbCb->rbId,pjRbCb->rbType);
1783 /* Initialisations */
1784 ulCb = &pjRbCb->ulCb;
1785 PJ_MEM_SET(&(packByte), 0, (sizeof(packByte))); /*KW_FIX : ccpu00136902*/
1786 /* Its DRB AM from now on */
1787 if(pjRbCb->state == PJ_STATE_REEST)
1789 /* if status report generation not necessary, quit */
1790 if(ulCb->staRepReqd == FALSE)
1796 /* If out-of-seq Pkts are stored in datPktQ then process the
1797 * bitMap the following way */
1798 fms = (U16)(pjRbCb->ulCb.fmsCount & (0x0fff)); /*KW_FIX*/
1799 /* Setting the bitIdx to start from 8 */
1800 bitIdx = PJ_BYTE_SIZE;
1801 /* Initialize idx as 1 since Bitmap starts from FMS + 1 */
1803 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
1804 while(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ))
1807 tmpEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
1808 /* Retrieve the SN from Count of RxEnt */
1809 sn = (U16)((tmpEnt->count) & (0x0fff)); /*KW_FIX*/
1810 if(tmpEnt->isOutSeq == FALSE)
1812 /* This Packet is In-Seq so no need to compute this for Bitmap
1813 * As this Packet should have SN less than FMS. */
1814 cmLListNext(&pjRbCb->ulCb.recBuf.datPktQ);
1817 while((nxtSnNotFnd == TRUE) && (byteIdx < 512))
1819 /* BitMap start from FMS + 1 */
1821 if(count >= (1 << pjRbCb->snLen))
1823 count = count % (1 << pjRbCb->snLen);
1827 /* This SN is missing so set bitMap value to 0 */
1828 packByte[byteIdx] |= (0 << (--bitIdx));
1834 /* This SN is present so set bitMap value to 1 */
1835 packByte[byteIdx] |= (1 << (--bitIdx));
1838 nxtSnNotFnd = FALSE;
1839 cmLListNext(&pjRbCb->ulCb.recBuf.datPktQ);
1841 if(numBits % PJ_BYTE_SIZE == 0)
1844 bitIdx = PJ_BYTE_SIZE;
1850 /* if bitmap is not byte aligned, then append/pad
1851 * with 0s (to indicate from here Packets not received)
1852 * to make it byte aligned and send to App */
1853 while(numBits % 8 != 0)
1855 packByte[byteIdx] |= (0 << (--bitIdx));
1859 /* Store the numOfBits and bitMap in ueCb */
1860 if(pjRbCb->state == PJ_STATE_REEST_HO)
1862 hoInfo = &pjRbCb->ueCb->hoInfo->hoCfmInfo[pjRbCb->rbId];
1863 hoInfo->pres = TRUE;
1864 hoInfo->rbId = pjRbCb->rbId;
1865 hoInfo->dir |= PJ_DIR_UL;
1866 /* numBits sent from PDCP is always a multiple of 8 */
1867 hoInfo->numBits = numBits;
1870 RLOG_ARG1(L_DEBUG,DBG_UEID,pjRbCb->ueCb->key.ueId,
1871 "pjUlmReEstDrbAm : OutOfSeq UL Pkts are present for rbId = %d ",
1873 /* ByteAlign the computed Bits, numBits is always a multiple of 8 */
1874 #ifndef XEON_SPECIFIC_CHANGES
1875 SGetStaticBuffer(gCb->init.region, gCb->init.pool, (Data **)&hoInfo->ulBitMap, sizeof(U8) * (numBits / 8), 0);
1877 PJ_ALLOC(gCb, hoInfo->ulBitMap, sizeof(U8) * (numBits / 8));
1879 #if (ERRCLASS & ERRCLS_DEBUG)
1880 if(hoInfo->ulBitMap == NULLP)
1882 RLOG0(L_FATAL, "Memory Allocation failed.");
1885 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
1886 PJ_MEM_CPY(hoInfo->ulBitMap, packByte, (numBits / 8));
1888 hoInfo->count = pjRbCb->ulCb.fmsCount;
1892 /* Send the status report only in case of Re-Establishment
1893 * not during Handover as this part is hit when eNB is Source */
1894 RLOG_ARG0(L_DEBUG,DBG_UEID,pjRbCb->ueCb->key.ueId,
1895 "pjUlmReEstDrbAm : Sending PDCP Status Report ");
1896 pjUlmBldStaRep(gCb, pjRbCb, pjRbCb->ulCb.fmsCount, packByte, numBits);
1898 /*No error check required here*/
1901 } /* pjUlmReEstDrbAm */
1908 * Function is called to build and send the SDU Status report.
1912 * This function is called to build the SDU status report and send it to the
1913 * lower layer after reestablishment.
1915 * @param[in] pjRbCb PDCP control block
1916 * @param[in] fms First Missing sequence number
1917 * @param[in] staReq Buffer containing status report bitmap
1923 PUBLIC S16 pjUlmBldStaRep
1932 PUBLIC S16 pjUlmBldStaRep(gCb, pjRbCb, fmc, bitMap, bMapLen)
1940 Buffer *staRep = NULLP;
1941 U8 packByte = 0; /* Temp Var for packing bytes */
1942 S16 ret = ROK; /* Return value */
1945 TRC2(pjUlmBldStaRep);
1947 RLOG2(L_DEBUG, "pjUlmBldStaRep(pjRbCb(%d,%d))",pjRbCb->rbId, pjRbCb->rbType);
1949 PJ_ALLOC_BUF(gCb, staRep);
1950 #if (ERRCLASS & ERRCLS_DEBUG)
1953 RLOG0(L_FATAL, "Memory Allocation failed.");
1956 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
1957 SAddPstMsg(packByte, staRep);
1958 packByte = (U8)((fmc & 0xff000000) >> 24);
1960 SAddPstMsg(packByte, staRep);
1962 packByte = (U8)((fmc & 0x00ff0000) >> 16);
1963 SAddPstMsg(packByte, staRep);
1965 packByte = (U8)((fmc & 0x0000ff00) >> 8);
1966 SAddPstMsg(packByte, staRep);
1968 packByte = (U8)((fmc & 0x000000ff));
1969 SAddPstMsg(packByte, staRep);
1971 /* Pack the bitmap */
1974 /* bMapLen will always be a multiple of 8 */
1975 byteLen = (U16)(bMapLen / 8); /*KW_FIX*/
1976 SAddPstMsgMult(bitMap, byteLen, staRep);
1979 /*send the status report to DLPDCP */
1981 pjUtlUlSndUlStaRep(gCb, pjRbCb, staRep);
1992 * Function is called during handover to transfer the undeliverd SDUs
1993 * at the target side.
1997 * This function performs the following. @n
1998 * 1. Calculate lastSubCnt. @n
1999 * 2. Compute count for each SDU. @n
2000 * 3. Create an rxEnt for each SDU and insert it into the hashlist.@n
2002 * @param[in] pjRbCb PDCP control block
2003 * @param[in] datFwdReq Data Forward Request info
2009 PUBLIC S16 pjUlmHdlDatFwdReq
2012 PjUlRbCb *pjRbCb, /* !< PDCP ID */
2013 PjuDatFwdReqInfo *datFwdReq /* !< DatFwdReq Info */
2016 PUBLIC S16 pjUlmHdlDatFwdReq(gCb, pjRbCb, datFwdReq)
2018 PjUlRbCb *pjRbCb; /* !< PDCP ID */
2019 PjuDatFwdReqInfo *datFwdReq; /* !< DatFwdReq Info */
2022 U32 datFwdCnt; /* Temp value to store SDU count */
2023 PjRxEnt *rxEnt = NULLP; /* Rx Entry pointer */
2024 PjuDatFwdInfo *info; /* Loop var - pointer to DatFwdInfo */
2025 PjUlCb *ulCb = NULLP; /* UL Control block */
2026 U8 sduIndex; /* loop index */
2029 TRC2(pjUlmHdlDatFwdReq);
2031 RLOG2(L_DEBUG, "pjUlmHdlDatFwdReq(pjRbCb(%d,%d), datFwdReq) ",
2032 pjRbCb->rbId, pjRbCb->rbType);
2034 /* Initialisations */
2035 ulCb = &pjRbCb->ulCb;
2037 /* Loop through all SDUs */
2038 for( sduIndex = 0; sduIndex < datFwdReq->numSdus; sduIndex++)
2040 info = &datFwdReq->datFwdInfo[sduIndex];
2041 PJ_STS_INC_GEN_CNT(gCb,numPktsRcvd);
2043 /*1.5G-NR Determine the Hfn and count value of the received PDCP data pdu*/
2044 PJ_CALC_RCVD_HFN((info->sn),pjRbCb->snLen,ulCb->rxDeliv,rcvdHfn);
2045 /*2.5G-NR Get the count value of the receiced PDCP data pdu from rcvdSn and rcvdHfn */
2046 PJ_GET_COUNT(datFwdCnt, pjRbCb->snLen, (info->sn), rcvdHfn);
2049 PJ_ULM_UPD_NXT2DCOMP(pjRbCb->ulCb, (pjRbCb->snLen), rcvdCount, oldRxCnt);
2052 /* PJ_ULM_UPD_RX_VAR(info->sn, pjRbCb); */
2054 /* Create and insert the entry in the buffer */
2055 PJ_ALLOC(gCb,rxEnt, sizeof(PjRxEnt));
2057 #if (ERRCLASS & ERRCLS_DEBUG)
2060 RLOG0(L_FATAL, "Memory Allocation failed.");
2063 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
2065 rxEnt->count = datFwdCnt;
2066 rxEnt->state = PJ_RDY_TO_SUBMIT;
2067 rxEnt->mBuf = info->sdu;
2069 if(pjRbCb->state == PJ_STATE_HO)
2071 /* If RbCb State = PJ_STATE_HO, then this is Target and Forwarded Packets
2072 * are received before Status Transfer so buffer this Packet */
2073 rxEnt->isOutSeq = TRUE;
2075 /* Insert the entry in the buffer */
2076 pjDbmInsRxEnt(gCb, &ulCb->recBuf, rxEnt, FALSE);
2080 }/*pjUlmHdlDatFwdReq*/
2086 * Function is called when
2087 * 1. The offboard timer expires.
2088 * 2. Deciphering returns.
2092 * The function is called when the pdu is next in line for decompression
2093 * It performs the following. @n
2094 * 1. Submit the pdu for decompression. @n
2095 * 2. Check if any successive messages can be sent to for decompression @n
2096 * 3. Update the nxtSubDeCmp value appropriately . @n
2098 * @param[in] pjRbCb PDCP control block
2099 * @param[in] rxEnt Reception Entry
2106 PUBLIC S16 pjUlmSubmitForDecmp
2109 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
2110 PjRxEnt *rxEnt /* Ptr To Rx Entry */
2113 PUBLIC S16 pjUlmSubmitForDecmp(gCb, pjRbCb, rxEnt)
2115 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
2116 PjRxEnt *rxEnt; /* Ptr To Rx Entry */
2119 PjUlCb *ulCb; /* ULM Control Block */
2121 U32 count; /* count to go through the list and check */
2122 U32 nxtRxCnt; /* count of Sdu to receive next */
2123 PjRxEnt *tmpEnt; /* Temporary variable for looping */
2124 #endif /* PJ_SEC_ASYNC */
2127 TRC2(pjUlmSubmitForDecmp);
2130 RLOG3(L_DEBUG, "pjUlmSubmitForDecmp(pjRbCb(%d,%d),rxEnt(%ld)) ",
2131 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count);
2133 RLOG3(L_DEBUG, "pjUlmSubmitForDecmp(pjRbCb(%d,%d),rxEnt(%d)) ",
2134 pjRbCb->rbId, pjRbCb->rbType, rxEnt->count);
2137 /* 1. Initialisations */
2138 ulCb = &pjRbCb->ulCb;
2139 rxEnt->state = PJ_RDY_TO_DCOMP;
2140 /*Adding MACI for 5G NR for DRB in case of intergrity protection is enabled*/
2141 if(pjRbCb->ueCb->secInfo.intProtEnbForDrb)
2143 PJ_UNPK_MACI(rxEnt->mBuf, macI);
2146 /* 2. If decomp is disabled, start delivery procedures */
2147 if(pjRbCb->rohc.hdrCmpUsed != TRUE)
2149 rxEnt->state = PJ_RDY_TO_SUBMIT;
2150 PJ_DEC_OBD_COUNT(gCb, pjRbCb, rxEnt->count);
2151 PJ_ULM_DELIVER_DRB(gCb,pjRbCb, rxEnt);
2155 /* 3. If not the next in line for decompression, wait.. */
2156 if(ulCb->nxtSubDeCmp != rxEnt->count)
2161 /* 4. Calling decompression hook */
2162 if(pjUlmHdlDeCmp(gCb, pjRbCb, rxEnt) != ROK)
2168 /* 5. cycle through the subsequent entries to see if any of them are also
2169 * available for decompression */
2170 nxtRxCnt = ulCb->rxNext;
2172 for(count = ulCb->nxtSubDeCmp + 1; count < nxtRxCnt; count ++)
2174 /* 5.1 Get the next node */
2175 tmpEnt = pjDbmGetRxEnt(gCb, &ulCb->recBuf, count);
2177 /* 5.2 If such an entry does not exist, search for the next */
2183 /* 5.3 During post reestablishment phase, there might me some PDUs in
2184 * the Rx Buffer that were received prior to reestablishment and
2185 * have been fully processed but are not sent up because they are
2186 * waiting for the arrival of a previous PDU. We can safely skip
2188 if(tmpEnt->state == PJ_RDY_TO_SUBMIT)
2193 /* 5.4 Deciphering not yet done so we have to wait */
2194 if(tmpEnt->state != PJ_RDY_TO_DCOMP)
2199 /*Adding MACI for 5G NR for DRB in case of intergrity protection is enabled*/
2200 if(pjRbCb->ueCb->secInfo.intProtEnbForDrb)
2202 PJ_UNPK_MACI(rxEnt->mBuf, macI);
2204 /* 5.5 Send it to decompression */
2205 if(pjUlmHdlDeCmp(gCb, pjRbCb, tmpEnt) != ROK)
2210 } /* while(!((sn == ulCb->nxtRxSn)... */
2212 /* 6. Update nxtSubDeCmp */
2213 ulCb->nxtSubDeCmp = count;
2215 #endif /* PJ_SEC_ASYNC */
2219 }/* end of pjUlmSubmitForDecmp */
2224 * Function is called when the offboard timer expires.
2228 * The function performs the following
2229 * 1. If the SDU associated with the timer is not delivered, we
2230 * delete the entry . @n
2231 * 2. A status indication is sent to the user with error cause. @n
2232 * 3. In case of failure call pjUlmHdlErrUpdates to recalculate
2233 * nxtSubCnt and if necessary nxtSubDeCmp. @n
2234 * 4. The timer is associated with the nextToSubmit SDU and restarted.@n
2236 * @param[in] pjRbCb PDCP control block
2243 PUBLIC Void pjUlmHdlReordTmrExpiry
2246 PjUlRbCb *pjRbCb /* !< PDCP Control Block */
2249 PUBLIC Void pjUlmHdlReordTmrExpiry(gCb,pjRbCb)
2251 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
2254 PjRxEnt *tmpEnt = NULLP;
2257 U32 rxReOrdHfn, tmpNxtDlvrHfn;
2259 ulCb = &pjRbCb->ulCb;
2261 gPdcpStats.numPdcpCellReorderTmrExp++;
2263 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
2264 if(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ))
2266 tmpEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
2268 /* all stored PDCP SDU(s) with associated COUNT value(s) < RX_REORD; */
2269 while(tmpEnt && (tmpEnt->count < ulCb->rxReord))
2271 PJ_SND_PJU_DAT_IND(gCb,pjRbCb, tmpEnt);
2272 pjDbmDelRxEnt(gCb, &ulCb->recBuf, tmpEnt->count);
2273 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
2274 if(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ) == NULLP)
2278 tmpEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
2282 tmpNxtDelvrCnt = ulCb->rxReord;
2283 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
2284 if(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ))
2286 tmpEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
2287 /* all stored PDCP SDU(s) with consecutively associated COUNT value(s) starting from RX_REORD */
2288 while(tmpEnt && ( tmpEnt->count == tmpNxtDelvrCnt ))
2290 PJ_SND_PJU_DAT_IND(gCb,pjRbCb, tmpEnt);
2292 pjDbmDelRxEnt(gCb, &ulCb->recBuf, tmpEnt->count);
2293 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
2294 if(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ) == NULLP)
2298 tmpEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
2302 /* update RX_DELIV to the COUNT value of the first PDCP SDU
2303 which has not been delivered to upper layers,
2304 with COUNT value >= RX_REORD;*/
2305 PJ_GET_HFN(ulCb->rxDeliv,pjRbCb->snLen,rxReOrdHfn);
2306 PJ_GET_HFN(tmpNxtDelvrCnt,pjRbCb->snLen,tmpNxtDlvrHfn);
2307 if ((tmpNxtDelvrCnt > ulCb->rxReord) ||
2308 ((PJ_MAX_HFN(pjRbCb->snLen) == rxReOrdHfn ) && (0 == tmpNxtDlvrHfn)))
2310 ulCb->rxDeliv = tmpNxtDelvrCnt;
2313 if (ulCb->rxDeliv < ulCb->rxNext)
2315 ulCb->rxReord = ulCb->rxNext;
2316 pjStartTmr(gCb,(PTR)pjRbCb, PJ_EVT_UL_REORD_TMR);
2321 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
2326 * Function is called when the offboard timer expires.
2330 * The function performs the following
2331 * 1. If the SDU associated with the timer is not delivered, we
2332 * delete the entry . @n
2333 * 2. A status indication is sent to the user with error cause. @n
2334 * 3. In case of failure call pjUlmHdlErrUpdates to recalculate
2335 * nxtSubCnt and if necessary nxtSubDeCmp. @n
2336 * 4. The timer is associated with the nextToSubmit SDU and restarted.@n
2338 * @param[in] pjRbCb PDCP control block
2345 PUBLIC Void pjUlmHdlObdTmrExpiry
2348 PjUlRbCb *pjRbCb /* !< PDCP Control Block */
2351 PUBLIC Void pjUlmHdlObdTmrExpiry(gCb,pjRbCb)
2353 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
2356 PjUlCb *ulCb; /* ULM Control Block */
2357 PjRxEnt *rxEnt; /* Ptr To Rx Entry */
2358 U32 subCnt; /* Count that was/will be submitted */
2360 TRC2(pjUlmHdlObdTmrExpiry);
2362 RLOG2(L_DEBUG, "pjUlmHdlObdTmrExpiry(pjRbCb(%d,%d)) ",
2363 pjRbCb->rbId, pjRbCb->rbType);
2365 /* 1. Initialistions */
2366 ulCb = &pjRbCb->ulCb;
2367 PJ_STS_INC_GEN_CNT(gCb,numPdusDiscObdTmrExp);
2370 /* 2. For SDUs that have not yet been delivered */
2371 PJ_ULM_GET_SUBCNT(pjRbCb, subCnt, gCb);
2372 if(ulCb->obdPdu == subCnt)
2374 /* 2.1 Send failure indication and delete the entry */
2375 rxEnt = (PjRxEnt *)pjDbmGetRxEnt(gCb, &(ulCb->recBuf), ulCb->obdPdu);
2378 if( ulCb->recBuf.numEntries == 0)
2382 #if (ERRCLASS & ERRCLS_DEBUG)
2383 RLOG1(L_ERROR, "rxEnt not found for subCnt [%lu]", subCnt);
2384 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
2389 RLOG1(L_ERROR, "Obd Timer expires without reply for subCnt [%lu]", subCnt);
2390 PJ_SND_PJU_STA_IND(gCb,pjRbCb, rxEnt);
2391 pjDbmDelRxEnt(gCb, &ulCb->recBuf, rxEnt->count);
2394 /* 2.2 Update nxtSubCnt */
2395 pjUlmHdlErrUpdates(gCb, pjRbCb, ulCb->obdPdu);
2397 /* 2.3 Restart timer if it has not been restarted already */
2398 if( ulCb->recBuf.numEntries != 0)
2400 if((pjChkTmr(gCb, (PTR)pjRbCb, PJ_EVT_UL_OBD_TMR)) == FALSE)
2402 PJ_ULM_GET_SUBCNT(pjRbCb, (ulCb->obdPdu), gCb);
2403 if(!PJ_DRBAM_ALL_PDU_RECVD(pjRbCb))
2405 pjStartTmr(gCb, (PTR)pjRbCb, PJ_EVT_UL_OBD_TMR);
2410 /* 3. For SDUs that have been delivered */
2413 if( ulCb->recBuf.numEntries != 0)
2415 /* 3.1 Associate the nxtToSub with the timer */
2416 PJ_ULM_GET_SUBCNT(pjRbCb, (ulCb->obdPdu), gCb);
2417 if(!PJ_DRBAM_ALL_PDU_RECVD(pjRbCb))
2419 pjStartTmr(gCb, (PTR)pjRbCb, PJ_EVT_UL_OBD_TMR);
2425 }/* end of pjUlmHdlObdTmrExpiry */
2426 #endif /* (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC)) */
2433 * Function is called when
2434 * 1. The offboard timer expires
2435 * 2. The library functions fail.
2439 * The function performs the following
2440 * 1. Update nxtSubCnt if necessary.
2441 * 2. Update nxtSubDeCmp if necessary.
2442 * 3. Check if reestablishment has to be triggered.
2444 * @param[in] pjRbCb PDCP control block.
2445 * @param[in] errCnt Count of the error PDU.
2450 PUBLIC Void pjUlmHdlErrUpdates
2453 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
2454 U32 errCnt /* !< Count of PDU that raises the error */
2457 PUBLIC Void pjUlmHdlErrUpdates(gCb, pjRbCb, errCnt)
2459 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
2460 U32 errCnt; /* !< Count of PDU that raises the error */
2465 #endif /* PJ_SEC_ASYNC */
2467 #if (defined(PJ_SEC_ASYNC) || defined(PJ_CMP_ASYNC))
2468 PjUlCb *ulCb; /* ULM Control Block */
2471 PjRxEnt *rxEnt = NULLP; /* Ptr To Rx Entry */
2472 #endif /* (defined(PJ_SEC_ASYNC) || defined(PJ_CMP_ASYNC)) */
2474 TRC2(pjUlmHdlErrUpdates);
2476 #if (defined(PJ_SEC_ASYNC) || defined(PJ_CMP_ASYNC))
2477 /* 1. Initialistions */
2478 ulCb = &pjRbCb->ulCb;
2479 nxtRxCnt = ulCb->rxNext;
2481 /* 2. Decrement obd counter */
2482 PJ_DEC_OBD_COUNT(gCb, pjRbCb, errCnt);
2484 /* 3. For DRB AM , check if we can deliver anything */
2485 if((pjRbCb->rbType == PJ_DRB) && (pjRbCb->mode == PJ_DRB_AM))
2487 /* if any successive entries can be sent up , send it */
2488 for(nxtToSub = ulCb->rxDeliv; nxtToSub < nxtRxCnt; nxtToSub++)
2490 if( (rxEnt = pjDbmGetRxEnt(gCb, &ulCb->recBuf, nxtToSub)) != NULLP)
2492 /* As soon as we get an entry, we break */
2493 if(rxEnt->state == PJ_RDY_TO_SUBMIT)
2495 pjUlmDeliverDrbAm(gCb, pjRbCb, rxEnt);
2501 if(nxtToSub == nxtRxCnt)
2503 /* This situation occurs, if this is the only pdu in the hashlist
2504 * and obd fails for it. In this case, we have to trigger reestablishment
2506 if(pjRbCb->state != PJ_STATE_NORMAL)
2508 if((ulCb->transCmp == TRUE) &&
2509 (ulCb->obdCnt == 0))
2511 PJ_ULM_DRBUM_REEST(gCb, pjRbCb);
2516 /* 4. For SRB/DRB UM Update nxtSubCnt */
2519 if(errCnt == ulCb->nxtSubCnt)
2521 for(nxtToSub = ulCb->nxtSubCnt + 1; nxtToSub < nxtRxCnt; nxtToSub++)
2523 if( (rxEnt = pjDbmGetRxEnt(gCb, &ulCb->recBuf, nxtToSub)) != NULLP)
2525 ulCb->nxtSubCnt = nxtToSub;
2529 if(nxtToSub == ulCb->nxtSubCnt )
2531 if(rxEnt->state == PJ_RDY_TO_SUBMIT)
2533 PJ_ULM_DELIVER_PDU(gCb, pjRbCb, rxEnt);
2538 /* Update nxtSubCnt to point to nxtRxCnt so that
2539 * updations at pjUlmProcessRb can happen properly */
2540 ulCb->nxtSubCnt = nxtRxCnt;
2542 /* Check if its necessary to reestablish */
2543 if(pjRbCb->state != PJ_STATE_NORMAL)
2545 if((ulCb->transCmp == TRUE) &&
2546 (ulCb->obdCnt == 0))
2548 PJ_ULM_DRBUM_REEST(gCb, pjRbCb);
2555 #endif /* (defined(PJ_SEC_ASYNC) || defined(PJ_CMP_ASYNC)) */
2557 /* Notes : Update nxSubCnt first and then nxtSubDeCmp because we dont want a case
2558 * where nxtSubDeCmp becomes greater that nxtSubCnt */
2560 /* 5. Update nxtSubDeCmp */
2561 if((pjRbCb->rbType == PJ_DRB) && (errCnt == ulCb->nxtSubDeCmp))
2563 nxtToDeCmp = ulCb->nxtSubDeCmp + 1;
2565 for(; nxtToDeCmp < nxtRxCnt; nxtToDeCmp++)
2567 rxEnt = pjDbmGetRxEnt(gCb, &ulCb->recBuf, nxtToDeCmp);
2574 /* A pdu existing after reestablishment */
2575 if(rxEnt->state == PJ_RDY_TO_SUBMIT)
2580 ulCb->nxtSubDeCmp = nxtToDeCmp;
2584 if(nxtToDeCmp == ulCb->nxtSubDeCmp)
2586 if(rxEnt && (rxEnt->state == PJ_RDY_TO_DCOMP))
2588 pjUlmSubmitForDecmp(gCb, pjRbCb, rxEnt);
2593 /* Update nxtSubDeCmp to point to nxtRxCnt so that
2594 * updations at pjUlmProcessRb can happen properly */
2595 ulCb->nxtSubDeCmp = nxtRxCnt;
2599 #endif /* PJ_SEC_ASYNC */
2602 }/* end of pjUlmHdlErrUpdates */
2608 * Function is called when
2609 * 1. PjLiKwuReEstCmpInd received from RLC in case of Re-establishment and HO
2613 * The function performs the following
2614 * 1. Checks the RB state, if it is not equal to PJ_STATE_NORMAL calls
2615 * PJ_ULM_DRBUM_REEST or pjUlmReEstDrbAm
2617 * @param[in] tPjCb PDCP control block.
2618 * @param[in] tRbCb RB control block.
2623 PUBLIC Void pjUlmReEstCmpInd
2626 PjUlRbCb *tRbCb /* !< RB control block */
2629 PUBLIC Void pjUlmReEstCmpInd(tPjCb, tRbCb)
2631 PjUlRbCb *tRbCb; /* !< PDCP Control Block */
2635 TRC3(pjUlmReEstCmpInd)
2637 /* No need to update state for SRB */
2638 if(tRbCb->ueCb->libInfo.state == PJ_STATE_NORMAL)
2643 if(tRbCb->rbType == PJ_SRB)
2648 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
2649 /* If Async mode, set variable to true and return */
2650 tRbCb->ulCb.transCmp = TRUE;
2651 if(tRbCb->ulCb.obdCnt == 0)
2653 #endif /* (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC)) */
2654 /* In synchronous mode, we can proceed with reestablishment */
2655 if (tRbCb->mode == PJ_DRB_UM)
2657 tRbCb->ulCb.rxNext = 0;
2658 tRbCb->ulCb.rxDeliv = 0;
2660 tRbCb->ulCb.nxtSubSn = 0;
2665 (Void)pjUlmReEstDrbAm(gCb, tRbCb);
2668 pjUtlUlHdlRbReEstComplete(gCb,tRbCb);
2670 #if (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC))
2672 #endif /* (defined(PJ_SEC_ASYNC) || defined (PJ_CMP_ASYNC)) */
2682 * Handler to forward the uplink data to the upper layer.
2686 * 1. This function is used to forward the uplink data to the upper layer
2687 * during handover. @n
2688 * 2. The out-of-sequene data SDUs are sent to the upper
2691 * @param[in] pjRbCb PDCP control block.
2699 PUBLIC S16 pjUlmStartDataFrwdPerRb
2705 PUBLIC S16 pjUlmStartDataFrwdPerRb(gCb, pjRbCb)
2713 U32 numSduCnt =0,numSduTx = 0;
2714 PjRxEnt *tmpRxEnt = NULLP; /* temporary Rx Entity */
2715 PjuDatFwdIndInfo *datFwdInd = NULLP;
2720 TRC3(pjUlmStartDataFrwdPerRb)
2722 RLOG1(L_DEBUG, "pjUlmStartDataFrwdPerRb (%d )) ", pjRbCb->rbId);
2724 pjuSap = &(gCb->u.ulCb->pjuSap[PJ_DRB_SAP]);
2725 if((pjRbCb->ulCb.rxNext == 0))
2727 if(SGetSBuf(pjuSap->pst.region,pjuSap->pst.pool,(Data **)&datFwdInd,
2728 sizeof (PjuDatFwdIndInfo)) != ROK)
2732 #if (ERRCLASS & ERRCLS_ADD_RES)
2733 if (datFwdInd == NULLP)
2735 RLOG0(L_FATAL, "Memory Allocation failed.");
2738 #endif /* ERRCLASS & ERRCLS_ADD_RES */
2739 datFwdInd->dir = PJ_DIR_UL;
2740 datFwdInd->numSdus = 0;
2741 datFwdInd->isLastDatFwdInd = TRUE;
2743 /* sending DatFwdInd even if numSdu is zero */
2744 pjUtlUlSndDatFwdInd(gCb,pjRbCb, datFwdInd);
2749 /* Find the total number of RxEnts present */
2750 numEntries = pjRbCb->ulCb.recBuf.numEntries;
2751 /* Find the total count of the txEnts present */
2752 numSduCnt = numSdu = numEntries;
2754 /* Traverse the datPktQ and send the UL Packets to DAM */
2755 cmLListFirst(&pjRbCb->ulCb.recBuf.datPktQ);
2760 if(numSduCnt > PJ_FWD_MAX_SDU_CNT)
2762 numSduTx = PJ_FWD_MAX_SDU_CNT;
2763 numSduCnt = numSduCnt - PJ_FWD_MAX_SDU_CNT;
2767 numSduTx = numSduCnt;
2771 if(SGetSBuf(pjuSap->pst.region,pjuSap->pst.pool,(Data **)&datFwdInd,
2772 sizeof (PjuDatFwdIndInfo)) != ROK)
2776 #if (ERRCLASS & ERRCLS_ADD_RES)
2777 if (datFwdInd == NULLP)
2779 RLOG0(L_FATAL, "Memory Allocation failed.");
2782 #endif /* ERRCLASS & ERRCLS_ADD_RES */
2784 if(SGetSBuf(pjuSap->pst.region,pjuSap->pst.pool,
2785 (Data **)&datFwdInd->datFwdInfo, (sizeof (PjuDatFwdInfo)* numSduTx)) != ROK)
2787 datFwdInd->datFwdInfo = NULLP;
2789 #if (ERRCLASS & ERRCLS_ADD_RES)
2790 if (datFwdInd->datFwdInfo == NULLP)
2792 RLOG0(L_FATAL, "Memory Allocation failed.");
2795 #endif /* ERRCLASS & ERRCLS_ADD_RES */
2799 /* Retrieve the Packet Info by typecasting to RxEnt */
2800 tmpRxEnt = (PjRxEnt *) cmLListNode(cmLListCrnt(&pjRbCb->ulCb.recBuf.datPktQ));
2801 sn = (U16)((tmpRxEnt->count) & (0x0fff)); /*KW_FIX*/
2803 datFwdInd->datFwdInfo[count].sn = sn;
2804 /* Copy the SDU Buffer as it is into datFwdInfo */
2806 datFwdInd->datFwdInfo[count].sdu = tmpRxEnt->mBuf;
2808 SCpyMsgMsg(tmpRxEnt->mBuf, 0, 0,
2809 &datFwdInd->datFwdInfo[count].sdu);
2811 cmLListNext(&pjRbCb->ulCb.recBuf.datPktQ);
2815 /* Fill the datFwdInd struct and send it to DAM */
2816 datFwdInd->dir = PJ_DIR_UL;
2817 datFwdInd->numSdus = count;
2818 datFwdInd->isLastDatFwdInd = FALSE;
2819 /* Send the datFwdInd to DAM */
2820 pjUtlUlSndDatFwdInd(gCb,pjRbCb, datFwdInd);
2824 if(SGetSBuf(pjuSap->pst.region,pjuSap->pst.pool,(Data **)&datFwdInd,
2825 sizeof (PjuDatFwdIndInfo)) != ROK)
2829 #if (ERRCLASS & ERRCLS_ADD_RES)
2830 if (datFwdInd == NULLP)
2832 RLOG0(L_FATAL, "Memory Allocation failed.");
2835 #endif /* ERRCLASS & ERRCLS_ADD_RES */
2836 datFwdInd->dir = PJ_DIR_UL;
2837 datFwdInd->numSdus = 0;
2838 datFwdInd->isLastDatFwdInd = TRUE;
2840 /* sending DatFwdInd even if numSdu is zero */
2841 pjUtlUlSndDatFwdInd(gCb,pjRbCb, datFwdInd);
2851 * Handler to process the forwarded data received from upper layer.
2855 * 1. This function is used to process the SDUs received from the upper
2856 * layer as part of handover. @n
2857 * 2. This function calls pjDlmProcessSdus function with the correct
2858 * SN and HFN values. @n
2860 * @param[in] gCb PDCP Instance control block.
2861 * @param[in] pjUlRbCb Uplink Rb control block.
2862 * @param[in] datFwdReq Data Forward Info.
2870 PUBLIC S16 pjUlmHndlDatFwdReq
2874 PjuDatFwdReqInfo *datFwdReq
2877 PUBLIC S16 pjUlmHndlDatFwdReq(gCb,pjRbCb,datFwdReq)
2880 PjuDatFwdReqInfo *datFwdReq;
2884 PjRxEnt *rxEnt; /* Transmission Entity */
2889 U32 rcvdHfn; /*Hfn for received PDU */
2890 U32 rcvdCount; /*Count for received Pdu */
2891 PjUlCb *ulCb; /* PTR to UL Control Block */
2892 U32 rxDelivHfn; /*Hfn of the rxDeliv */
2894 TRC3(pjUlmHndlDatFwdReq)
2896 /* 1. Initialisations */
2897 ulCb = &pjRbCb->ulCb;
2900 RLOG2(L_DEBUG, "pjDlmHndlDatFwdReq(pjRbCb (%d),datFwdReq(%d)) ",
2901 pjRbCb->rbId, datFwdReq->numSdus);
2904 sn =datFwdReq->datFwdInfo[numSdus].sn;
2905 gCb->pjGenSts.numPktsRcvd += datFwdReq->numSdus;
2906 /* Process each of the SDUs with received SN and sduId */
2907 for ( numSdus = 0; numSdus < datFwdReq->numSdus; numSdus++ )
2910 The variables nxtTxSn and COUNT are assumed to be
2911 already updated in dlCb to continue with the
2912 transmission ( in the target eNodeB ).
2915 PJ_CALC_RCVD_HFN(sn,pjRbCb->snLen,ulCb->rxDeliv,rcvdHfn);
2917 /* 2.5G-NR Get the count value of the receiced PDCP data pdu from rcvdSn and rcvdHfn */
2918 PJ_GET_COUNT(rcvdCount, pjRbCb->snLen, sn, rcvdHfn);
2920 /* 2. Allocate memory for the rxEnt */
2921 PJ_ALLOC(gCb,rxEnt, sizeof(PjRxEnt));
2922 #if (ERRCLASS & ERRCLS_DEBUG)
2925 RLOG0(L_FATAL, "Memory allocation failure");
2928 #endif /* (ERRCLASS & ERRCLS_DEBUG) */
2931 /* 4. Fill up the structures and insert into hashlist */
2932 rxEnt->count = rcvdCount;
2933 rxEnt->state = PJ_RDY_TO_DCIPHER;
2934 rxEnt->mBuf = datFwdReq->datFwdInfo[numSdus].sdu;
2937 PJ_ULM_UPD_NXT2SUB(pjRbCb->ulCb, rxEnt->count);
2938 ret = pjDbmInsRxEnt(gCb, &pjRbCb->ulCb.recBuf, rxEnt, TRUE);
2941 /* Duplicates are not to be inserted */
2942 /* marked to be freed up later */
2943 rxEnt->dupEntry = TRUE;
2946 PJ_GET_HFN(pjRbCb->ulCb.rxDeliv,pjRbCb->snLen,rxDelivHfn)
2947 if((rcvdCount < ulCb->rxDeliv) && (rxDelivHfn != PJ_MAX_HFN(pjRbCb->snLen)))
2949 rxEnt->discFlag = TRUE;
2952 if(rxEnt->dupEntry == TRUE)
2954 /* duplicate entry */
2955 PJ_FREE_BUF(rxEnt->mBuf);
2956 PJ_FREE(gCb,rxEnt, sizeof(PjRxEnt));
2958 else if(rxEnt->discFlag == TRUE)
2960 /* duplicate entry */
2961 pjDbmDelRxEnt(gCb, &pjRbCb->ulCb.recBuf, rxEnt->count);
2965 /*3.Update the RX_NEXT */
2966 PJ_ULM_UPDATE_RX_NEXT(pjRbCb,rxEnt);
2968 if(pjRbCb->rbType == PJ_DRB)
2970 rxEnt->state = PJ_RDY_TO_DCOMP;
2971 /*Adding MACI for 5G NR for DRB in case of intergrity protection is enabled*/
2972 if(pjRbCb->ueCb->secInfo.intProtEnbForDrb)
2974 PJ_UNPK_MACI(rxEnt->mBuf, macI);
2976 ret = pjUlmHdlDeCmp(gCb, pjRbCb, rxEnt);
2980 rxEnt->state = PJ_RDY_TO_INTVER;
2981 ret = pjUlmHdlIntVer(gCb, pjRbCb, rxEnt);
2989 * @brief It processes the packets queued up in ULPktQ
2992 * This ulPktQ queues the forwarded message at targe enodeb
2995 * @param[in] pjCb PDCP Instance control block.
2996 * @param[in] pjUlRbCb Uplink Rb Control block
3001 PUBLIC Void pjUlmProcessUlPktQ
3004 PjUlRbCb *pjRbCb /* !< PDCP Control Block */
3007 PUBLIC Void pjUlmProcessUlPktQ(gCb, pjRbCb)
3009 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
3015 TRC2(pjUlmProcessUlPktQ);
3017 CM_LLIST_FIRST_NODE(&(pjRbCb->ulCb.ulPktLst), node);
3018 while (node != NULLP)
3020 pkt = (PjUlPkt *) node->node;
3022 cmLListDelFrm(&(pjRbCb->ulCb.ulPktLst), node);
3023 pkt->lnk.node = NULLP;
3024 pjUlmProcessRb(gCb,pjRbCb, pkt->sn, pkt->pdu, TRUE);
3025 PJ_FREE(gCb,pkt, sizeof (PjUlPkt));
3027 CM_LLIST_FIRST_NODE(&(pjRbCb->ulCb.ulPktLst), node);
3031 }/* end of pjDlmProcessDlPktQ */
3037 * @param[in] pjRbCb PDCP control block.
3038 @param[in] PjRxEnt *rxEnt
3043 PRIVATE Void pjUlmEnqueueUlPkt
3046 PjUlRbCb *pjRbCb, /* !< PDCP Control Block */
3047 PjSn sn, /* !< SN value of PDU */
3048 Buffer *pdu /* !< PDU message buffer */
3051 PRIVATE Void pjUlmEnqueueUlPkt(gCb,pjRbCb, sn, pdu)
3053 PjUlRbCb *pjRbCb; /* !< PDCP Control Block */
3054 PjSn sn; /* !< SN value of PDU */
3055 Buffer *pdu; /* !< PDU message buffer */
3060 TRC2(pjUlmEnqueueUlPkt)
3062 PJ_ALLOC(gCb,pkt, sizeof(PjUlPkt));
3067 pkt->type = PJ_DATA_NRM_PKT;
3068 pkt->lnk.node = (PTR)pkt;
3069 cmLListAdd2Tail (&pjRbCb->ulCb.ulPktLst, &pkt->lnk);
3073 RLOG0(L_FATAL, "Memory allocation failure");
3082 /********************************************************************30**
3085 **********************************************************************/