<JIRA ID: ODUHIGH-390 : Ul throughput per SNSSAI (KPI)>
[o-du/l2.git] / src / 5gnrrlc / rlc_umm_ul.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
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                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
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 *******************************************************************************/
18
19 /**********************************************************************
20
21      Name:     NR RLC Layer 
22   
23      Type:     C file
24   
25      Desc:     Source code for RLC Unacknowledged mode assembly and
26                reassembly.This file contains following functions
27
28                   --rlcUmmQSdu
29                   --rlcUmmProcessSdus
30                   --rlcUmmProcessPdus
31                   --rlcUmUlReAssembleSdus
32                   --kwUmmReEstablish 
33
34      File:     rlc_umm_ul.c
35
36 **********************************************************************/
37 /** 
38  * @file rlc_umm_ul.c
39  * @brief RLC Unacknowledged Mode uplink module
40 */
41
42 /* header (.h) include files */
43 #include "common_def.h"
44 #include "ckw.h"                /* RRC layer */
45 #include "lkw.h"                /* RRC layer */
46 #include "kwu.h"                /* RLC service user */
47 #include "lkw.h"                /* LM Interface */
48 #include "rgu.h"                /* MAC layer */
49 #include "rlc_env.h"             /* RLC environment options */
50
51 /* header/extern include files (.x) */
52
53 #include "ckw.x"                /* RRC layer */
54 #include "kwu.x"                /* RLC service user */
55 #include "lkw.x"                /* LM Interface */
56 #include "rgu.x"                /* MAC later */
57
58 #include "rlc_utils.h"                 /* RLC layer */
59 #include "rlc_err.h"
60 #include "rlc_ul.h"
61
62 #define RLC_MODULE (RLC_DBGMASK_UM | RLC_DBGMASK_UL)
63
64 static uint8_t rlcUmmExtractHdr ARGS ((RlcCb *gCb, 
65                                    RlcUlRbCb *rbCb,
66                                    Buffer *pdu,
67                                    RlcUmHdr *umHdr));
68
69 uint8_t rlcUmmReAssembleSdus ARGS ((RlcCb *gCb,
70                                     RlcUlRbCb *rbCb,
71                                     RlcUmRecBuf *umRecBuf));
72
73 bool rlcUmmAddRcvdSeg ARGS ((RlcCb *gCb,
74                              RlcUlRbCb   *rbCb,
75                              RlcUmHdr    *umHdr,
76                              Buffer      *pdu,
77                              uint16_t    pduSz));
78
79 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf);
80
81 #ifndef TENB_ACC
82 #ifndef LTE_PAL_ENB
83 uint32_t isMemThreshReached(Region region);
84 #endif
85 #endif
86 /**
87  * @brief  Finds and sets the next VR(UR) depending on the 
88  *         passed sequence number
89  *       
90  * @details
91  *    Finds the next VR(UR) depending on the passed SN. Updates VR(UR) to 
92  *    the SN of the first UMD PDU with SN >= _nextSn that has not been reassembled
93  *
94  * @param[in] umUl      pointer to Um mode uplink control block
95  * @param[in] nextSn    Sequence number after which the VR(UR) is to set to
96  *
97  * @return  Void
98 */ 
99 static void rlcUmmFindRxNextReassembly (RlcCb *gCb, RlcUmUl* umUl, RlcSn nextSn)
100 {
101    RlcSn ur = RLC_UM_GET_VALUE(umUl->vrUr, *umUl);
102    RlcSn prevRxNextReassembly = umUl->vrUr;
103
104    RlcSn nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
105    RlcUmRecBuf *recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,nextSn);
106    RlcUmRecBuf *prevRecBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,prevRxNextReassembly);
107    while (ur < nextSnToCompare)
108    {
109       if((ur + 1) == nextSnToCompare)
110       {
111          if ((recBuf == NULLP) || (!(recBuf->allSegRcvd))) /* if the buffer is empty, SN not received */
112          {
113             umUl->vrUr = nextSn;
114             if(prevRecBuf)
115             {
116                rlcUmmRelAllSegs(gCb, prevRecBuf);
117                rlcUtlDelUmRecBuf(gCb, umUl->recBufLst, prevRecBuf);
118             }
119             break;
120          }
121          else
122          {
123             if(prevRecBuf)
124             {
125                rlcUmmRelAllSegs(gCb, prevRecBuf);
126                rlcUtlDelUmRecBuf(gCb, umUl->recBufLst, prevRecBuf);
127             }
128          }
129          prevRecBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,nextSn);
130          nextSn = (nextSn + 1) & umUl->modBitMask;
131          nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
132          recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,nextSn);
133       }
134       else
135       {
136          umUl->vrUr++;
137          ur = RLC_UM_GET_VALUE(umUl->vrUr, *umUl);
138          if(prevRecBuf)
139          {
140             rlcUmmRelAllSegs(gCb, prevRecBuf);
141             rlcUtlDelUmRecBuf(gCb, umUl->recBufLst, prevRecBuf);
142          }
143          prevRecBuf = rlcUtlGetUmRecBuf(umUl->recBufLst,umUl->vrUr);
144       }
145    }
146 }
147
148 /**
149  * @brief  Checks whether a sequence number is within the 
150  *         re-assembly window or not
151  *       
152  * @param[in] sn        Sequence Number to be checked
153  * @param[in] umUl      pointer to Um mode uplink control block
154  *
155  * @return  S16
156  *      -# TRUE 
157  *      -# FALSE
158  *
159  * @return  Void
160 */
161 static int16_t rlcUmmCheckSnInReassemblyWindow (RlcSn sn, const RlcUmUl* const umUl)  
162 {
163    return (RLC_UM_GET_VALUE(sn, *umUl) < RLC_UM_GET_VALUE(umUl->vrUh, *umUl)); 
164 }
165
166 /**
167  * @brief  Handler to updated expected byte seg
168  *
169  * @details
170  *    This function is used to update expected byte segment. The next segment
171  *    expected is indicated by the SO of the segment which is expected. Intially
172  *    the segment with SO 0 is expected and then in order. When all the segments
173  *    are received (which would happen when an expected SO is encountered
174  *    with LSF set) the allRcvd flag is set to TRUE
175  *
176  * @param[in]  gCb   RLC instance control block
177  * @param[in]  umUl  AM Uplink Control Block
178  * @param[in]  seg   Newly received segment
179  *
180  * @return void
181  *
182  */
183
184 void rlcUmmUpdExpByteSeg(RlcCb *gCb, RlcUmUl *umUl, RlcUmSeg *seg)
185 {
186    uint16_t  newExpSo; /* The new expected SO */
187    RlcSn     sn = seg->umHdr.sn;
188    bool      lstRcvd=FALSE;
189    RlcUmRecBuf *recBuf = NULLP;
190    
191    recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst, sn);
192    if ((recBuf == NULLP) || (recBuf && (seg->umHdr.so != recBuf->expSo)))
193    {
194       return;
195    }
196    recBuf->noMissingSeg = FALSE;
197    newExpSo   = seg->soEnd + 1;
198    recBuf->expSo = newExpSo;
199    if(seg->umHdr.si == RLC_SI_LAST_SEG)
200    {  
201       lstRcvd = TRUE;
202    } 
203    RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
204    while(seg)
205    {
206       /* keep going ahead as long as the expectedSo match with the header so
207          else store the expSo for later checking again */
208       if(seg->umHdr.si == RLC_SI_LAST_SEG)
209       {  
210          lstRcvd = TRUE;
211       } 
212       if (seg->umHdr.so == newExpSo)
213       {
214          newExpSo = seg->soEnd + 1;
215          recBuf->expSo = newExpSo;
216          RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
217       }
218       else
219       {
220          recBuf->expSo = newExpSo;
221          return;
222       }
223    }
224    if (lstRcvd == TRUE)
225    {
226       recBuf->allSegRcvd = TRUE;
227    }
228    recBuf->noMissingSeg = TRUE;
229
230    return;
231 }
232 /**
233  * @brief Private handler to store the received segment
234  *
235  * @details
236  *    Private handler invokded by rlcUmmUlPlacePduInRecBuf to add a received
237  *    segment in reception buffer of a RBCB.
238  *    - It is responsible for detecting duplicate segments
239  *    - Adding it at appropriate position in the received buffer
240  *    - Calling ExpByteSeg to set expSo field in the receiver buffer
241  *
242  * @param[in]  gCb      RLC instance control block
243  * @param[in]  rbCb     Radio Bearer Contro Block
244  * @param[in]  umHdr    UM Header received
245  * @param[in]  pdu      Buffer received other than the headers
246  * @param[in]  pduSz    size of the PDU buffer received
247  *
248  * @return  bool
249  *   -#TRUE  Successful insertion into the receiver buffer
250  *   -#FALSE Possibly a duplicate segment
251  */
252
253 bool rlcUmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu, uint16_t pduSz)
254 {
255    RlcUmRecBuf   *recBuf = NULLP;
256    RlcUmSeg      *seg;
257    RlcUmSeg      *tseg;
258    uint16_t      soEnd;       /* Holds the SoEnd of received segment */
259    uint16_t      expSo = 0;   /* Expected SO */
260
261    soEnd = umHdr->so + pduSz - 1;
262    recBuf =  rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, umHdr->sn);
263
264    if (NULLP == recBuf)
265    {
266       RLC_ALLOC(gCb,recBuf, sizeof(RlcUmRecBuf));
267       if (recBuf == NULLP)
268       {
269          DU_LOG("\nERROR  -->  RLC_UL : Failed to allocate memory to recv buf for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
270             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
271
272          ODU_PUT_MSG_BUF(pdu);
273          return FALSE;
274       }
275       rlcUtlStoreUmRecBuf(RLC_UMUL.recBufLst, recBuf, umHdr->sn);
276    }
277    else
278    {
279       if (recBuf->allSegRcvd == TRUE)
280       {
281          ODU_PUT_MSG_BUF(pdu);
282          return FALSE;
283       }
284    }
285                         
286    RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
287    while ((seg != NULLP) && (seg->umHdr.so < umHdr->so))
288    {
289       expSo = seg->umHdr.so + seg->segSz;
290       RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
291    }
292
293    if (expSo > umHdr->so)
294    {
295       DU_LOG("\nDEBUG  -->  RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
296       /* This is a duplicate segment */
297       ODU_PUT_MSG_BUF(pdu);
298       return FALSE;
299    }
300
301    if ((seg) && (seg->umHdr.so <= soEnd))
302    {
303       DU_LOG("\nDEBUG  -->  RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
304       /* This is a duplicate segment */
305       ODU_PUT_MSG_BUF(pdu);
306       return FALSE;
307    }
308
309    /* If we have come this far, we have to add this segment to the   */
310    /* reception buffer as we either have eliminated duplicates or    */
311    /* have found none.                                               */
312    RLC_ALLOC_WC(gCb, tseg, sizeof(RlcUmSeg));
313    if (tseg == NULLP)
314    {
315       DU_LOG("\nERROR -->  RLC_UL : Failed to allocate memory to segment for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
316          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
317       ODU_PUT_MSG_BUF(pdu);
318       return FALSE;
319    }
320
321    tseg->seg = pdu;
322    tseg->segSz = pduSz;
323    RLC_MEM_CPY(&tseg->umHdr, umHdr, sizeof(RlcUmHdr));
324    RLC_MEM_CPY(&recBuf->umHdr, umHdr, sizeof(RlcUmHdr));
325    recBuf->sn = umHdr->sn;
326    tseg->soEnd = soEnd;
327    if (seg == NULLP)
328    {
329       cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
330    }
331    else
332    {
333       recBuf->segLst.crnt = &seg->lstEnt;
334       cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
335    }
336    tseg->lstEnt.node = (PTR)tseg;
337    rlcUmmUpdExpByteSeg(gCb, &RLC_UMUL, tseg);
338    return TRUE;
339 }
340
341 /**
342  * @brief Private handler to release all stored segments
343  *
344  * @details
345  *    Private handler invokded by rlcUmmRelAllSegs to release the
346  *    stored segements in case a complete PDU is received later.
347  *
348  * @param[in]  gCb      RLC instance control block
349  * @param[in]  recBuf   Buffer that stores a received PDU or segments
350  *
351  * @return  void
352  *
353  */
354 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf)
355 {
356    RlcUmSeg *seg;
357
358    RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
359    while (seg != NULLP)
360    {
361       ODU_PUT_MSG_BUF(seg->seg);
362       cmLListDelFrm(&(recBuf->segLst), &(seg->lstEnt));
363       RLC_FREE(gCb, seg, sizeof(RlcUmSeg));
364       RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
365    }
366
367    return;
368 }
369
370 /**
371  * @brief Private handler to reassemble from a segment or a PDU
372  *
373  * @details
374  *    Private handler invokded by rlcUmmReAssembleSdus with either a
375  *    PDU or a segment of a PDU. This is also called in the case of
376  *    reestablishment and hence out of sequence joining is also to
377  *    be supported
378  *
379  *
380  * @param[in]  gCb     RLC instance control block
381  * @param[in]  rbCb    Uplink RB control block
382  * @param[in]  umHdr   UM header received for this segment/PDU
383  * @param[in]  pdu     PDU to be reassembled
384  *
385  * @return  ROK/RFILED
386  *
387  */
388
389 uint8_t rlcUmmProcSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu)
390 {
391
392    if ((RLC_UMUL.expSn != umHdr->sn) || (RLC_UMUL.expSo != umHdr->so))
393    {
394       /* Release the existing SDU as we have PDUs or */
395       /* segments that are out of sequence           */
396       DU_LOG("\nDEBUG  -->  RLC_UL : Received Segments are out of sequence in rlcUmmProcSeg()");
397       ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
398       return RFAILED;
399    }
400
401    if (umHdr->si == RLC_SI_FIRST_SEG)
402    {/* first Segment of the SDU */
403       if (RLC_UMUL.assembleSdu != NULLP)
404       { /* Some old SDU may be present */
405          ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
406       }
407       RLC_UMUL.assembleSdu = pdu;
408       pdu = NULLP;
409    }
410    else if(umHdr->si == RLC_SI_MID_SEG)
411    {/* Middle Segment of the SDU */
412       ODU_CAT_MSG(RLC_UMUL.assembleSdu,pdu, M1M2);
413       ODU_PUT_MSG_BUF(pdu);
414       pdu = NULLP;
415    }
416    else if(umHdr->si ==  RLC_SI_LAST_SEG)
417    {
418       ODU_CAT_MSG(pdu, RLC_UMUL.assembleSdu, M2M1);
419       ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
420    }
421
422    if (pdu != NULLP)
423    {
424       RLC_UMUL.assembleSdu = NULLP;
425       rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
426    }
427
428    return ROK;
429 }
430 /**
431  *
432  * @brief Private handler to reassemble SDUs
433  *
434  * @details
435  *    Private handler invokded by rlcUmmProcessPdus with the PDU
436  *    from the reception buffer in sequence to reassemble SDUs and
437  *    send it to PDCP.
438  *
439  *        - With the stored header info, FI and LSF segment / concatenate
440  *          PDUs or byte segments of PDUs to get the associated SDU.
441  *
442  * @param[in]  rbCb     RB control block
443  * @param[in]  pdu      PDU to be reassembled
444  *
445  *  @return  uint8_t
446  *      -# ROK
447  *      -# RFAILED
448  *
449  */
450 uint8_t rlcUmmReAssembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmRecBuf *recBuf)
451 {
452    RlcUmSeg        *seg;
453
454    /* This is a set of segments */
455    RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
456    RLC_UMUL.expSn = recBuf->sn;
457    RLC_UMUL.expSo = 0;
458    while(seg)
459    {
460       if(rlcUmmProcSeg(gCb, rbCb, &seg->umHdr, seg->seg) == RFAILED)
461       {
462          rlcUmmRelAllSegs(gCb, recBuf);
463          break;
464       }
465       RLC_UMUL.expSo = seg->soEnd + 1;
466       cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
467       RLC_FREE(gCb, seg, sizeof(RlcSeg));
468       RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
469    }
470    RLC_UMUL.expSn = (recBuf->umHdr.sn + 1) & (RLC_UMUL.modBitMask);
471    RLC_UMUL.expSo = 0;
472    return ROK;
473 }
474
475 /**
476  * @brief  Handler to process the Data Indication from the lower layer 
477  *         and send the PDUs to re-assembly unit. 
478  *       
479  * @details
480  *    This function processes the PDUs received from the lower layer
481  *    re-orders them and sends them one after the other in sequence 
482  *    to the re-assembly unit.
483  *
484  * @param[in] gCb      RLC Instance control block
485  * @param[in] rbCb     RB control block 
486  * @param[in] pduInfo  Pdu information 
487  *
488  *  @return Void
489 */
490 /* kw005.201 added support for L2 Measurement */
491 #ifdef LTE_L2_MEAS
492 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb  *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
493 #else
494 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
495 #endif
496 {
497    RlcSn         *vrUh;      /* vr(uh) */
498    RlcSn         *vrUr;      /* vr(ur) */
499    RlcSn         *vrUx;      /* vr(ux) */
500    uint16_t      curSn;      /* Current Sequence Number */
501    uint32_t      pduCount;   /* PDU count */
502    uint32_t      count;      /* Loop counter */
503    RlcUmRecBuf   *recBuf;    /* UM Reception Buffer */
504    RlcUmHdr      umHdr;      /* Um header*/
505    bool          tmrRunning; /* Boolean for checking Tmr */
506    MsgLen        pduSz;      /* Pdu Size */
507    RlcSn         tRxNextReassembly;
508    RlcSn         tRxNextReassemblyNxt;
509    RlcSn         tRxNextHighest;
510    RlcTptPerSnssai *snssaiTputNode = NULLP;
511
512    count = 0;
513
514    /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */
515    pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU;
516
517    vrUh   = &(rbCb->m.umUl.vrUh);
518    vrUr   = &(rbCb->m.umUl.vrUr);
519    vrUx   = &(rbCb->m.umUl.vrUx);
520
521    while (count < pduCount)
522    {
523       RlcSn   ur; 
524       RlcSn   seqNum;
525       Buffer  *pdu = pduInfo->mBuf[count];
526
527       pduSz = 0;  /*re-intialize the size*/
528       snssaiTputNode = NULLP;
529
530       gCb->genSts.pdusRecv++;
531 #ifndef RGL_SPECIFIC_CHANGES
532 #ifndef TENB_ACC
533 #ifndef LTE_PAL_ENB
534       uint32_t ulrate_rgu;
535       MsgLen len;
536       ODU_GET_MSG_LEN(pdu, &len);
537       ulrate_rgu += len;
538 #endif
539 #endif      
540 #endif      
541       /* ccpu00142274 - UL memory based flow control*/ 
542 #ifndef RGL_SPECIFIC_CHANGES
543 #ifndef TENB_ACC
544 #ifndef LTE_PAL_ENB
545       /* Changed the condition to TRUE from ROK  */
546 #ifndef XEON_SPECIFIC_CHANGES    
547       if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
548       {
549          uint32_t rlculdrop;
550          rlculdrop++;
551          ODU_PUT_MSG_BUF(pdu);
552          count++;
553          continue;
554       }
555 #endif     
556 #endif
557 #endif
558 #endif
559       /* get the pdu header */
560       if (rlcUmmExtractHdr(gCb, rbCb, pdu, &umHdr))  
561       {
562          DU_LOG("\nERROR  --> RLC_UL: rlcUmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",\
563                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
564          ODU_PUT_MSG_BUF(pdu);
565          count++;
566          gCb->genSts.errorPdusRecv++;
567          continue;
568       }
569
570       if(rbCb->snssai)
571       {
572          snssaiTputNode = rlcHandleSnssaiTputlist(gCb, rbCb->snssai, SEARCH, DIR_UL);
573          if(snssaiTputNode != NULLP)
574          {
575             ODU_GET_MSG_LEN(pdu, &pduSz);
576             snssaiTputNode->dataVol += (uint64_t)pduSz;
577             DU_LOG("\nINFO  -->  RLC_UL: UMM_UL SNSSAI List PduLen:%d, lcId:%d, total :%ld",\
578                   pduSz, rbCb->lch.lChId, snssaiTputNode->dataVol);
579          }
580       }
581
582       /* Check if the PDU should be delivered to upper layer */
583       if(umHdr.si == 0)
584       {
585          rlcUtlSendUlDataToDu(gCb, rbCb, pdu);
586          ODU_PUT_MSG_BUF(pdu);
587          count++;
588          continue;
589       }
590
591       curSn = umHdr.sn;
592
593       /* Check if the PDU should be discarded or not */
594       ur = RLC_UM_GET_VALUE(RLC_UMUL.vrUr, RLC_UMUL); 
595       seqNum = RLC_UM_GET_VALUE(curSn, RLC_UMUL); 
596
597       if (seqNum < ur)
598       {
599          /* PDU needs to be discarded */
600          DU_LOG("\nINFO  -->  RLC_UL: rlcUmmProcessPdus: Received an unexpected pdu with sn %d \
601                UEID:%d CELLID:%d", curSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
602
603          ODU_PUT_MSG_BUF(pdu);
604          count++;
605          gCb->genSts.unexpPdusRecv++;
606          continue;
607       } 
608
609 #ifdef LTE_L2_MEAS
610       rlcUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt);
611 #endif 
612
613       ODU_GET_MSG_LEN(pdu, &pduSz);
614       /* Place sdu segment into recption buffer */
615       if(rlcUmmAddRcvdSeg(gCb, rbCb, &umHdr, pdu, pduSz) == TRUE)      
616       {
617          recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, umHdr.sn);
618          if (recBuf == NULLP)
619          {
620             DU_LOG("\nERROR  -->  RLC_UL: rlcUmmProcessPdus: recBuf is NULLP UEID:%d CELLID:%d", \
621                   rbCb->rlcId.ueId, rbCb->rlcId.cellId);
622             ODU_PUT_MSG_BUF(pdu);
623             count++;
624             continue;
625          }
626
627          /* If all bytes segments of curSn are received, deliver assembled SDU to upper layer */
628          if(recBuf != NULLP && recBuf->allSegRcvd)
629          {
630             rlcUmmReAssembleSdus(gCb, rbCb, recBuf);
631             DU_LOG("\nDEBUG  -->  RLC_UL: rlcUmmProcessPdus: Assembled the Sdus for  sn = %d UEID:%d CELLID:%d",\
632                   umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
633
634             /* if curSn is same as the RX_NEXT_Reassembly */
635             if (seqNum == ur)
636             {
637                /* set RX_NEXT_Reassembly to next SN > current RX_NEXT_Reassembly which is not reassembled yet */
638                RlcSn nextVrUr = (*vrUr + 1) & RLC_UMUL.modBitMask;
639                rlcUmmFindRxNextReassembly(gCb, &RLC_UMUL, nextVrUr);
640             }
641          }
642          /* If curSn is outside re-assembly window */
643          else if (!rlcUmmCheckSnInReassemblyWindow(curSn,&RLC_UMUL))
644          {  
645             DU_LOG("\nDEBUG  -->  RLC_UL: rlcUmmProcessPdus: curent sn is outSide the re-Assembly window. \
646                   sn = %d UEID:%d CELLID:%d", umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
647
648             /* update RX_NEXT_Highest */
649             *vrUh  = (curSn + 1) & RLC_UMUL.modBitMask;
650
651             /* Discard all pdus outside the modified re-assembly window */
652             if (!rlcUmmCheckSnInReassemblyWindow(*vrUr,&RLC_UMUL))
653             {
654                RlcSn sn = *vrUr; /* Stores SNs which need to be discarded. First SN is VR(UR) */
655                RlcSn lowerEdge;  /* to hold the lower-edge of the re-assembly window */
656                RlcSn packetCount;
657
658                /* Set RX_NEXT_Reassembly to next SN >= (RX_NEXT_Highest - windowSize) that has not been reassembled yet */
659                *vrUr = (*vrUh - RLC_UMUL.umWinSz) &  RLC_UMUL.modBitMask;
660                lowerEdge = *vrUr;
661                packetCount = (lowerEdge - sn) & RLC_UMUL.modBitMask;
662
663                while (packetCount)
664                {
665                   recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, sn);
666                   if (recBuf)
667                   {
668                      rlcUmmRelAllSegs(gCb, recBuf);
669                      rlcUtlDelUmRecBuf(gCb, RLC_UMUL.recBufLst, recBuf);
670                   }
671                   sn = (sn + 1) & RLC_UMUL.modBitMask;
672                   packetCount--;
673                }
674                recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, *vrUr);
675                if (recBuf != NULLP && recBuf->allSegRcvd)
676                {
677                   /* set rxNextReassembly to next SN > current rxNextReassembly which is not received */
678                   RlcSn nextRxNextReassembly = (*vrUr + 1) & RLC_UMUL.modBitMask;
679                   rlcUmmFindRxNextReassembly(gCb ,&RLC_UMUL, nextRxNextReassembly);
680                }
681             }
682          }
683
684          tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
685          tRxNextReassembly = RLC_UM_GET_VALUE(*vrUr ,RLC_UMUL);
686          tRxNextReassemblyNxt = (*vrUr + 1) & rbCb->m.umUl.modBitMask;
687          tRxNextHighest = RLC_UM_GET_VALUE(*vrUh, RLC_UMUL);
688          tRxNextReassemblyNxt = RLC_UM_GET_VALUE(tRxNextReassemblyNxt ,RLC_UMUL);
689
690          /* If reassemby timer is running */
691          if (tmrRunning) 
692          {
693             RlcSn  tRxTimerTigger = RLC_UM_GET_VALUE(*vrUx, RLC_UMUL);
694             uint8_t ret = rlcUmmCheckSnInReassemblyWindow(*vrUx, &RLC_UMUL);
695             recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst,*vrUr);
696
697             if ((tRxTimerTigger <= tRxNextReassembly) || ((!ret) && (tRxTimerTigger != tRxNextHighest)) ||
698                   (tRxNextHighest ==  tRxNextReassemblyNxt && recBuf && recBuf->noMissingSeg))
699             {
700                rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);             
701                tmrRunning = FALSE;
702                DU_LOG("\nINFO  --> RLC_UL: rlcUmmProcessPdus: Stopped ReAssembly Timer rxTimerTigger = %d \
703                      rxNextReassembly = %d rxNextHighest = %d ", tRxTimerTigger, tRxNextReassembly, tRxNextHighest);
704             }
705          }
706
707          /* If Reassembly timer is not running */
708          if (!tmrRunning)
709          {
710             recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, curSn);
711             if ((tRxNextHighest > tRxNextReassemblyNxt) || ((tRxNextHighest == tRxNextReassemblyNxt)
712                      && (recBuf && (!recBuf->noMissingSeg))))
713             {
714                DU_LOG("\nDEBUG  -->  RLC_UL: rlcUmmProcessPdus: Start ReAssembly Timer tRxNextReassemblyNxt = %d \
715                      tRxNextHighest %d", tRxNextReassemblyNxt, tRxNextHighest);
716                rlcStartTmr(gCb, (PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR); 
717                *vrUx = *vrUh;
718             }
719          }
720       }
721       else
722       {
723          DU_LOG("\nERROR  -->  RLC_UL: rlcUmmProcessPdus:Failed to assemble the PDU for SN  = %d UEID:%d CELLID:%d",\
724                umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
725
726       }
727       count++;
728    }/* end while count < pduCount */
729 #ifdef LTE_L2_MEAS
730    rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
731 #endif /* LTE_L2_MEAS */
732    return;   
733 }
734
735 /**
736  * @brief  Handler to process the re-establishment request received 
737  *         from the upper layer.
738  *       
739  * @details
740  *    This function does the following functions : 
741  *       - If direction of the RB is downlink : 
742  *         Remove all the SDUs in the SDU queue.
743  *       - If direction of the RB is uplink   : 
744  *         Call rlcUmUlReAssembleSdus() for each PDU with SN < VR(UH)
745  *
746  * @param[in] gCb        RLC Instance control block
747  * @param[in] rlcID      Identity of the RLC entity for which 
748  *                       re-establishment is to be done
749  * @param[in] rbCb       RB control block for which re-establishment 
750  *                       is to be done
751  *
752  * @return  Void
753 */ 
754 Void rlcUmmUlReEstablish
755 (
756 RlcCb         *gCb,
757 CmLteRlcId   *rlcId,
758 RlcUlRbCb     *rbCb
759 )
760 {
761    RlcSn         curSn;
762    RlcSn         vrUh;
763    RlcUmRecBuf   *recBuf;   /* UM Reception Buffer */
764    RlcKwuSapCb   *rlcKwSap;   /* KWU SAP Information */
765
766    curSn = rbCb->m.umUl.vrUr;
767    vrUh  = RLC_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl);
768
769    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR))
770    {
771        rlcStopTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR);
772    }
773    
774    while (RLC_UM_GET_VALUE(curSn, rbCb->m.umUl) < vrUh)
775    {
776       recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, curSn);
777       if ( recBuf != NULLP )
778       {
779          if(recBuf->allRcvd == TRUE)
780          {
781            rlcUmmReAssembleSdus(gCb,rbCb,recBuf);
782          }
783          else
784          {
785             /* Remove PDU and segments */
786             if(recBuf->pdu)
787             {
788                ODU_PUT_MSG_BUF(recBuf->pdu);
789             }
790             /* Release all the segments*/
791             rlcUmmRelAllSegs(gCb,recBuf);
792          }
793          rlcUtlDelUmRecBuf(gCb, RLC_UMUL.recBufLst, recBuf);
794       } 
795       curSn = (curSn + 1) & rbCb->m.umUl.modBitMask;
796    }
797    rbCb->m.umUl.vrUr = 0;
798    rbCb->m.umUl.vrUh = 0;
799    rbCb->m.umUl.vrUx = 0;
800
801    rlcKwSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
802
803    /* In the UM Mode always send reestablish-indication to Upper Latyer*/
804    RlcUiKwuReEstCmpInd(&rlcKwSap->pst, rlcKwSap->suId, *rlcId);
805
806    return;
807 }
808
809 /**
810  * @brief  Handler to extract the header from a PDU
811  *       
812  * @details
813  *    This function is used to extract the header of a PDU and store it 
814  *    along with the PDU buffer.The sequence number, segmentation info 
815  *    and segmentation offset are extracted by this function.
816  *
817  * @param[in] gCb      RLC Instance control block
818  * @param[in] rbCb     Rb Control block for which the pdu is received
819  * @param[in] pdu      PDU buffer
820  * @param[out] umHdr   UM header to be filled after extraction
821  *
822  * @return  S16
823  *      -# TRUE 
824  *      -# FALSE
825 */
826 static uint8_t rlcUmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr)
827 {
828    Data      dst[2];    /* Destination Buffer */
829    uint8_t   ret;       /* Return Value */
830
831    memset(umHdr, 0, sizeof(RlcUmHdr));
832
833    ret = ODU_REM_PRE_MSG(dst,pdu);
834    if (ret != ROK)
835    {
836       DU_LOG("\nERROR  -->  RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for SI\
837         UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
838       return RFAILED;
839    }
840    umHdr->si = (dst[0]) >> 6;
841
842    /* If SI = 0, the RLC PDU contains complete RLC SDU. Header extraction complete. 
843     * No other fields present in header */
844    if(umHdr->si == 0)
845       return ROK;
846
847    /* If SI != 0, one SDU segment is present in RLC PDU. Hence extracting SN */
848    if (rbCb->m.umUl.snLen == RLC_UM_CFG_6BIT_SN_LEN)
849    {
850       /* Extractin 6-bit SN */
851       umHdr->sn = (dst[0]) & 0x3F; 
852    }
853    else
854    {
855       /* Extracting 12 bits SN */ 
856       umHdr->sn = (dst[0]) & 0x0F;
857       ret = ODU_REM_PRE_MSG(dst,pdu);
858       if (ret != ROK)
859       {
860          DU_LOG("\nERROR  -->  RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for SN\
861                UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
862          return RFAILED;
863       }
864       umHdr->sn = (umHdr->sn << 8) | dst[0];
865    }
866
867    /* SO field is present for middle and last segments of SDU, not present for first segment */
868    if((umHdr->si == RLC_SI_LAST_SEG) || (umHdr->si == RLC_SI_MID_SEG))
869    {
870       ret = ODU_REM_PRE_MSG_MULT(dst,2,pdu);
871       if (ret != ROK)
872       {
873          DU_LOG("\nERROR  -->  RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG_MULT Failed for 16 bits SO \
874             UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
875          return RFAILED;
876       }
877       umHdr->so = dst[0];
878       umHdr->so = (umHdr->so << 8) | dst[1];
879    }
880    return ROK; 
881 }
882    
883 /**
884  * @brief Handles expiry of re-assembly timer
885  *
886  * @param[in] gCb     RLC Instance control block
887  * @param[in] rbCb    Rb Control block for which re-assembly timer expired
888  *
889  * @return  Void
890 */
891 void rlcUmmReAsmblTmrExp
892 (
893 RlcCb       *gCb,
894 RlcUlRbCb   *rbCb     
895 )
896 {
897    RlcSn tRxNextHighest;
898    RlcSn tRxNextReassembly;
899    RlcUmRecBuf *recBuf;
900
901    DU_LOG("\nINFO  -->  RLC_UL: rlcUmmReAsmblTmrExp: UM Re-assembly timer expired");
902
903    /* set VR(UR) to SN >= VR(UX) that has not been reassembled */
904    rlcUmmFindRxNextReassembly(gCb, &RLC_UMUL, RLC_UMUL.vrUx);
905
906    tRxNextHighest = RLC_UM_GET_VALUE(RLC_UMUL.vrUh, RLC_UMUL);
907    tRxNextReassembly = (RLC_UMUL.vrUr + 1) & rbCb->m.umUl.modBitMask;
908    tRxNextReassembly = RLC_UM_GET_VALUE(tRxNextReassembly, RLC_UMUL);
909    recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst,RLC_UMUL.vrUr);
910    if ((tRxNextHighest > tRxNextReassembly) || ((tRxNextHighest == tRxNextReassembly) &&
911             ((recBuf) && !(recBuf->noMissingSeg))))
912    {
913       rlcStartTmr(gCb, (PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
914       RLC_UMUL.vrUx = RLC_UMUL.vrUh;
915    }
916 }
917
918 /**
919  * @brief
920  *   Function to release/free the UnAcknowledged Mode Module  RbCb buffers
921  *
922  * @details
923  *   This primitive Frees the UM RbCb transmission Buffer, retransmission
924  *   Buffer and reciption Buffers
925  *
926  * @param [in]   gCb   - RLC instance Control Block
927  * @param [in]   rbCb  - RB Control Block
928  *
929  * @return   void
930  */
931
932 Void rlcUmmFreeUlRbCb
933 (
934 RlcCb       *gCb,
935 RlcUlRbCb   *rbCb
936 )
937 {
938    RlcSn         curSn = 0;           /* Sequence number of PDU */
939    RlcUmRecBuf   *recBuf = NULLP;
940
941    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR))
942    {
943       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
944    }
945
946    do
947    {
948       recBuf = rlcUtlGetUmRecBuf(rbCb->m.umUl.recBufLst, curSn);
949       if ( recBuf != NULLP )
950       {
951          if (recBuf->pdu != NULLP)
952          {
953             ODU_PUT_MSG_BUF(recBuf->pdu);
954          }
955          /* Release all the segments */
956          rlcUmmRelAllSegs(gCb,recBuf);
957          rlcUtlDelUmRecBuf(gCb, rbCb->m.umUl.recBufLst, recBuf);
958       }
959       curSn++;
960    }while ( curSn < RLC_RCV_BUF_BIN_SIZE);
961
962    RLC_FREE(gCb,rbCb->snssai, sizeof (Snssai));
963    RLC_FREE(gCb,rbCb->m.umUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
964    rbCb->m.umUl.recBufLst = NULLP;
965
966    if(rbCb->m.umUl.assembleSdu != NULLP)
967    {
968       ODU_PUT_MSG_BUF(rbCb->m.umUl.assembleSdu);
969    }
970    return;
971 } /* rlcAmmFreeUlRbCb */
972
973 /********************************************************************30**
974          End of file
975 **********************************************************************/