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