SLice Mapping to RLC DB [ Jira Id - ODUHIGH-371 ]
[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
511    count = 0;
512
513    /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */
514    pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU;
515    
516    vrUh   = &(rbCb->m.umUl.vrUh);
517    vrUr   = &(rbCb->m.umUl.vrUr);
518    vrUx   = &(rbCb->m.umUl.vrUx);
519
520    while (count < pduCount)
521    {
522       RlcSn   ur; 
523       RlcSn   seqNum;
524       Buffer  *pdu = pduInfo->mBuf[count];
525
526       gCb->genSts.pdusRecv++;
527 #ifndef RGL_SPECIFIC_CHANGES
528 #ifndef TENB_ACC
529 #ifndef LTE_PAL_ENB
530       uint32_t ulrate_rgu;
531       MsgLen len;
532       ODU_GET_MSG_LEN(pdu, &len);
533       ulrate_rgu += len;
534 #endif
535 #endif      
536 #endif      
537       /* ccpu00142274 - UL memory based flow control*/ 
538 #ifndef RGL_SPECIFIC_CHANGES
539 #ifndef TENB_ACC
540 #ifndef LTE_PAL_ENB
541     /* Changed the condition to TRUE from ROK  */
542 #ifndef XEON_SPECIFIC_CHANGES    
543      if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
544      {
545         uint32_t rlculdrop;
546         rlculdrop++;
547         ODU_PUT_MSG_BUF(pdu);
548         count++;
549         continue;
550      }
551 #endif     
552 #endif
553 #endif
554 #endif
555       /* get the pdu header */
556       if (rlcUmmExtractHdr(gCb, rbCb, pdu, &umHdr))  
557       {
558          DU_LOG("\nERROR  --> RLC_UL: rlcUmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",\
559              rbCb->rlcId.ueId, rbCb->rlcId.cellId);
560          ODU_PUT_MSG_BUF(pdu);
561          count++;
562          gCb->genSts.errorPdusRecv++;
563          continue;
564       }
565
566       /* Check if the PDU should be delivered to upper layer */
567       if(umHdr.si == 0)
568       {
569          rlcUtlSendUlDataToDu(gCb, rbCb, pdu);
570          ODU_PUT_MSG_BUF(pdu);
571          count++;
572          continue;
573       }
574
575       curSn = umHdr.sn;
576
577       /* Check if the PDU should be discarded or not */
578       ur = RLC_UM_GET_VALUE(RLC_UMUL.vrUr, RLC_UMUL); 
579       seqNum = RLC_UM_GET_VALUE(curSn, RLC_UMUL); 
580
581       if (seqNum < ur)
582       {
583          /* PDU needs to be discarded */
584          DU_LOG("\nINFO  -->  RLC_UL: rlcUmmProcessPdus: Received an unexpected pdu with sn %d \
585             UEID:%d CELLID:%d", curSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
586
587          ODU_PUT_MSG_BUF(pdu);
588          count++;
589          gCb->genSts.unexpPdusRecv++;
590          continue;
591       } 
592
593 #ifdef LTE_L2_MEAS
594       rlcUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt);
595 #endif 
596
597       ODU_GET_MSG_LEN(pdu, &pduSz);
598       /* Place sdu segment into recption buffer */
599       if(rlcUmmAddRcvdSeg(gCb, rbCb, &umHdr, pdu, pduSz) == TRUE)      
600       {
601          recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, umHdr.sn);
602          if (recBuf == NULLP)
603          {
604             DU_LOG("\nERROR  -->  RLC_UL: rlcUmmProcessPdus: recBuf is NULLP UEID:%d CELLID:%d", \
605                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
606             ODU_PUT_MSG_BUF(pdu);
607             count++;
608             continue;
609          }
610
611          /* If all bytes segments of curSn are received, deliver assembled SDU to upper layer */
612          if(recBuf != NULLP && recBuf->allSegRcvd)
613          {
614             rlcUmmReAssembleSdus(gCb, rbCb, recBuf);
615             DU_LOG("\nDEBUG  -->  RLC_UL: rlcUmmProcessPdus: Assembled the Sdus for  sn = %d UEID:%d CELLID:%d",\
616                umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
617
618             /* if curSn is same as the RX_NEXT_Reassembly */
619             if (seqNum == ur)
620             {
621                /* set RX_NEXT_Reassembly to next SN > current RX_NEXT_Reassembly which is not reassembled yet */
622                RlcSn nextVrUr = (*vrUr + 1) & RLC_UMUL.modBitMask;
623                rlcUmmFindRxNextReassembly(gCb, &RLC_UMUL, nextVrUr);
624             }
625          }
626          /* If curSn is outside re-assembly window */
627          else if (!rlcUmmCheckSnInReassemblyWindow(curSn,&RLC_UMUL))
628          {  
629             DU_LOG("\nDEBUG  -->  RLC_UL: rlcUmmProcessPdus: curent sn is outSide the re-Assembly window. \
630                sn = %d UEID:%d CELLID:%d", umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
631
632             /* update RX_NEXT_Highest */
633             *vrUh  = (curSn + 1) & RLC_UMUL.modBitMask;
634
635             /* Discard all pdus outside the modified re-assembly window */
636             if (!rlcUmmCheckSnInReassemblyWindow(*vrUr,&RLC_UMUL))
637             {
638                RlcSn sn = *vrUr; /* Stores SNs which need to be discarded. First SN is VR(UR) */
639                RlcSn lowerEdge;  /* to hold the lower-edge of the re-assembly window */
640                RlcSn packetCount;
641
642                /* Set RX_NEXT_Reassembly to next SN >= (RX_NEXT_Highest - windowSize) that has not been reassembled yet */
643                *vrUr = (*vrUh - RLC_UMUL.umWinSz) &  RLC_UMUL.modBitMask;
644                lowerEdge = *vrUr;
645                packetCount = (lowerEdge - sn) & RLC_UMUL.modBitMask;
646             
647                while (packetCount)
648                {
649                   recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, sn);
650                   if (recBuf)
651                   {
652                      rlcUmmRelAllSegs(gCb, recBuf);
653                      rlcUtlDelUmRecBuf(gCb, RLC_UMUL.recBufLst, recBuf);
654                   }
655                   sn = (sn + 1) & RLC_UMUL.modBitMask;
656                   packetCount--;
657                }
658                recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, *vrUr);
659                if (recBuf != NULLP && recBuf->allSegRcvd)
660                {
661                   /* set rxNextReassembly to next SN > current rxNextReassembly which is not received */
662                   RlcSn nextRxNextReassembly = (*vrUr + 1) & RLC_UMUL.modBitMask;
663                   rlcUmmFindRxNextReassembly(gCb ,&RLC_UMUL, nextRxNextReassembly);
664                }
665             }
666          }
667
668          tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
669          tRxNextReassembly = RLC_UM_GET_VALUE(*vrUr ,RLC_UMUL);
670          tRxNextReassemblyNxt = (*vrUr + 1) & rbCb->m.umUl.modBitMask;
671          tRxNextHighest = RLC_UM_GET_VALUE(*vrUh, RLC_UMUL);
672          tRxNextReassemblyNxt = RLC_UM_GET_VALUE(tRxNextReassemblyNxt ,RLC_UMUL);
673
674          /* If reassemby timer is running */
675          if (tmrRunning) 
676          {
677             RlcSn  tRxTimerTigger = RLC_UM_GET_VALUE(*vrUx, RLC_UMUL);
678             uint8_t ret = rlcUmmCheckSnInReassemblyWindow(*vrUx, &RLC_UMUL);
679             recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst,*vrUr);
680
681             if ((tRxTimerTigger <= tRxNextReassembly) || ((!ret) && (tRxTimerTigger != tRxNextHighest)) ||
682                 (tRxNextHighest ==  tRxNextReassemblyNxt && recBuf && recBuf->noMissingSeg))
683             {
684                rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);             
685                tmrRunning = FALSE;
686                DU_LOG("\nINFO  --> RLC_UL: rlcUmmProcessPdus: Stopped ReAssembly Timer rxTimerTigger = %d \
687                   rxNextReassembly = %d rxNextHighest = %d ", tRxTimerTigger, tRxNextReassembly, tRxNextHighest);
688             }
689          }
690
691          /* If Reassembly timer is not running */
692          if (!tmrRunning)
693          {
694             recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, curSn);
695             if ((tRxNextHighest > tRxNextReassemblyNxt) || ((tRxNextHighest == tRxNextReassemblyNxt)
696                  && (recBuf && (!recBuf->noMissingSeg))))
697             {
698                 DU_LOG("\nDEBUG  -->  RLC_UL: rlcUmmProcessPdus: Start ReAssembly Timer tRxNextReassemblyNxt = %d \
699                    tRxNextHighest %d", tRxNextReassemblyNxt, tRxNextHighest);
700                 rlcStartTmr(gCb, (PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR); 
701                 *vrUx = *vrUh;
702             }
703          }
704       }
705       else
706       {
707          DU_LOG("\nERROR  -->  RLC_UL: rlcUmmProcessPdus:Failed to assemble the PDU for SN  = %d UEID:%d CELLID:%d",\
708             umHdr.sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
709
710       }
711       count++;
712    }/* end while count < pduCount */
713 #ifdef LTE_L2_MEAS
714    rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
715 #endif /* LTE_L2_MEAS */
716    return;   
717 }
718
719 /**
720  * @brief  Handler to process the re-establishment request received 
721  *         from the upper layer.
722  *       
723  * @details
724  *    This function does the following functions : 
725  *       - If direction of the RB is downlink : 
726  *         Remove all the SDUs in the SDU queue.
727  *       - If direction of the RB is uplink   : 
728  *         Call rlcUmUlReAssembleSdus() for each PDU with SN < VR(UH)
729  *
730  * @param[in] gCb        RLC Instance control block
731  * @param[in] rlcID      Identity of the RLC entity for which 
732  *                       re-establishment is to be done
733  * @param[in] rbCb       RB control block for which re-establishment 
734  *                       is to be done
735  *
736  * @return  Void
737 */ 
738 Void rlcUmmUlReEstablish
739 (
740 RlcCb         *gCb,
741 CmLteRlcId   *rlcId,
742 RlcUlRbCb     *rbCb
743 )
744 {
745    RlcSn         curSn;
746    RlcSn         vrUh;
747    RlcUmRecBuf   *recBuf;   /* UM Reception Buffer */
748    RlcKwuSapCb   *rlcKwSap;   /* KWU SAP Information */
749
750    curSn = rbCb->m.umUl.vrUr;
751    vrUh  = RLC_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl);
752
753    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR))
754    {
755        rlcStopTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR);
756    }
757    
758    while (RLC_UM_GET_VALUE(curSn, rbCb->m.umUl) < vrUh)
759    {
760       recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, curSn);
761       if ( recBuf != NULLP )
762       {
763          if(recBuf->allRcvd == TRUE)
764          {
765            rlcUmmReAssembleSdus(gCb,rbCb,recBuf);
766          }
767          else
768          {
769             /* Remove PDU and segments */
770             if(recBuf->pdu)
771             {
772                ODU_PUT_MSG_BUF(recBuf->pdu);
773             }
774             /* Release all the segments*/
775             rlcUmmRelAllSegs(gCb,recBuf);
776          }
777          rlcUtlDelUmRecBuf(gCb, RLC_UMUL.recBufLst, recBuf);
778       } 
779       curSn = (curSn + 1) & rbCb->m.umUl.modBitMask;
780    }
781    rbCb->m.umUl.vrUr = 0;
782    rbCb->m.umUl.vrUh = 0;
783    rbCb->m.umUl.vrUx = 0;
784
785    rlcKwSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
786
787    /* In the UM Mode always send reestablish-indication to Upper Latyer*/
788    RlcUiKwuReEstCmpInd(&rlcKwSap->pst, rlcKwSap->suId, *rlcId);
789
790    return;
791 }
792
793 /**
794  * @brief  Handler to extract the header from a PDU
795  *       
796  * @details
797  *    This function is used to extract the header of a PDU and store it 
798  *    along with the PDU buffer.The sequence number, segmentation info 
799  *    and segmentation offset are extracted by this function.
800  *
801  * @param[in] gCb      RLC Instance control block
802  * @param[in] rbCb     Rb Control block for which the pdu is received
803  * @param[in] pdu      PDU buffer
804  * @param[out] umHdr   UM header to be filled after extraction
805  *
806  * @return  S16
807  *      -# TRUE 
808  *      -# FALSE
809 */
810 static uint8_t rlcUmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr)
811 {
812    Data      dst[2];    /* Destination Buffer */
813    uint8_t   ret;       /* Return Value */
814
815    memset(umHdr, 0, sizeof(RlcUmHdr));
816
817    ret = ODU_REM_PRE_MSG(dst,pdu);
818    if (ret != ROK)
819    {
820       DU_LOG("\nERROR  -->  RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for SI\
821         UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
822       return RFAILED;
823    }
824    umHdr->si = (dst[0]) >> 6;
825
826    /* If SI = 0, the RLC PDU contains complete RLC SDU. Header extraction complete. 
827     * No other fields present in header */
828    if(umHdr->si == 0)
829       return ROK;
830
831    /* If SI != 0, one SDU segment is present in RLC PDU. Hence extracting SN */
832    if (rbCb->m.umUl.snLen == RLC_UM_CFG_6BIT_SN_LEN)
833    {
834       /* Extractin 6-bit SN */
835       umHdr->sn = (dst[0]) & 0x3F; 
836    }
837    else
838    {
839       /* Extracting 12 bits SN */ 
840       umHdr->sn = (dst[0]) & 0x0F;
841       ret = ODU_REM_PRE_MSG(dst,pdu);
842       if (ret != ROK)
843       {
844          DU_LOG("\nERROR  -->  RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for SN\
845                UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
846          return RFAILED;
847       }
848       umHdr->sn = (umHdr->sn << 8) | dst[0];
849    }
850
851    /* SO field is present for middle and last segments of SDU, not present for first segment */
852    if((umHdr->si == RLC_SI_LAST_SEG) || (umHdr->si == RLC_SI_MID_SEG))
853    {
854       ret = ODU_REM_PRE_MSG_MULT(dst,2,pdu);
855       if (ret != ROK)
856       {
857          DU_LOG("\nERROR  -->  RLC_UL: rlcUmmExtractHdr : ODU_REM_PRE_MSG_MULT Failed for 16 bits SO \
858             UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
859          return RFAILED;
860       }
861       umHdr->so = dst[0];
862       umHdr->so = (umHdr->so << 8) | dst[1];
863    }
864    return ROK; 
865 }
866    
867 /**
868  * @brief Handles expiry of re-assembly timer
869  *
870  * @param[in] gCb     RLC Instance control block
871  * @param[in] rbCb    Rb Control block for which re-assembly timer expired
872  *
873  * @return  Void
874 */
875 void rlcUmmReAsmblTmrExp
876 (
877 RlcCb       *gCb,
878 RlcUlRbCb   *rbCb     
879 )
880 {
881    RlcSn tRxNextHighest;
882    RlcSn tRxNextReassembly;
883    RlcUmRecBuf *recBuf;
884
885    DU_LOG("\nINFO  -->  RLC_UL: rlcUmmReAsmblTmrExp: UM Re-assembly timer expired");
886
887    /* set VR(UR) to SN >= VR(UX) that has not been reassembled */
888    rlcUmmFindRxNextReassembly(gCb, &RLC_UMUL, RLC_UMUL.vrUx);
889
890    tRxNextHighest = RLC_UM_GET_VALUE(RLC_UMUL.vrUh, RLC_UMUL);
891    tRxNextReassembly = (RLC_UMUL.vrUr + 1) & rbCb->m.umUl.modBitMask;
892    tRxNextReassembly = RLC_UM_GET_VALUE(tRxNextReassembly, RLC_UMUL);
893    recBuf = rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst,RLC_UMUL.vrUr);
894    if ((tRxNextHighest > tRxNextReassembly) || ((tRxNextHighest == tRxNextReassembly) &&
895             ((recBuf) && !(recBuf->noMissingSeg))))
896    {
897       rlcStartTmr(gCb, (PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
898       RLC_UMUL.vrUx = RLC_UMUL.vrUh;
899    }
900 }
901
902 /**
903  * @brief
904  *   Function to release/free the UnAcknowledged Mode Module  RbCb buffers
905  *
906  * @details
907  *   This primitive Frees the UM RbCb transmission Buffer, retransmission
908  *   Buffer and reciption Buffers
909  *
910  * @param [in]   gCb   - RLC instance Control Block
911  * @param [in]   rbCb  - RB Control Block
912  *
913  * @return   void
914  */
915
916 Void rlcUmmFreeUlRbCb
917 (
918 RlcCb       *gCb,
919 RlcUlRbCb   *rbCb
920 )
921 {
922    RlcSn         curSn = 0;           /* Sequence number of PDU */
923    RlcUmRecBuf   *recBuf = NULLP;
924
925    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,EVENT_RLC_UMUL_REASSEMBLE_TMR))
926    {
927       rlcStopTmr(gCb,(PTR)rbCb, EVENT_RLC_UMUL_REASSEMBLE_TMR);
928    }
929
930    do
931    {
932       recBuf = rlcUtlGetUmRecBuf(rbCb->m.umUl.recBufLst, curSn);
933       if ( recBuf != NULLP )
934       {
935          if (recBuf->pdu != NULLP)
936          {
937             ODU_PUT_MSG_BUF(recBuf->pdu);
938          }
939          /* Release all the segments */
940          rlcUmmRelAllSegs(gCb,recBuf);
941          rlcUtlDelUmRecBuf(gCb, rbCb->m.umUl.recBufLst, recBuf);
942       }
943       curSn++;
944    }while ( curSn < RLC_RCV_BUF_BIN_SIZE);
945
946    RLC_FREE(gCb,rbCb->snssai, sizeof (Snssai));
947    RLC_FREE(gCb,rbCb->m.umUl.recBufLst, (RLC_RCV_BUF_BIN_SIZE * sizeof(CmLListCp)));
948    rbCb->m.umUl.recBufLst = NULLP;
949
950    if(rbCb->m.umUl.assembleSdu != NULLP)
951    {
952       ODU_PUT_MSG_BUF(rbCb->m.umUl.assembleSdu);
953    }
954    return;
955 } /* rlcAmmFreeUlRbCb */
956
957 /********************************************************************30**
958          End of file
959 **********************************************************************/