14ecb0d0b110e084243387860038c234538730c1
[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                   --rlcUmmReAssembleSdus
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 #ifdef NR_RLC_UL
78 bool rlcUmmAddRcvdSeg ARGS ((RlcCb *gCb,
79                              RlcUlRbCb   *rbCb,
80                              RlcUmHdr    *umHdr,
81                              Buffer      *pdu,
82                              uint16_t    pduSz));
83
84 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf);
85
86 #endif                      
87
88 #ifndef TENB_ACC
89 #ifndef LTE_PAL_ENB
90 uint32_t isMemThreshReached(Region region);
91 #endif
92 #endif
93 /**
94  * @brief  Finds and sets the next VR(UR) depending on the 
95  *         passed sequence number
96  *       
97  * @details
98  *    Finds the next VR(UR) depending on the passed SN. Updates VR(UR) to 
99  *    the SN of the first UMD PDU with SN >= _nextSn that has not been received
100  *
101  * @param[in] umUl      pointer to Um mode uplink control block
102  * @param[in] nextSn    Sequence number after which the VR(UR) is to set to
103  *
104  * @return  Void
105 */ 
106 static void rlcUmmFindNextVRUR (RlcUmUl* umUl, RlcSn nextSn)
107 {
108    RlcSn ur = RLC_UM_GET_VALUE(umUl->vrUr, *umUl);
109    
110    RlcSn nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
111    
112    while (ur < nextSnToCompare)
113    {
114       if (!(umUl->recBuf[nextSn])) /* if the buffer is empty, SN not received */
115       {
116          umUl->vrUr = nextSn;
117          break;
118       }
119       nextSn = (nextSn + 1) & umUl->modBitMask; 
120       nextSnToCompare = RLC_UM_GET_VALUE(nextSn,*umUl);
121    }
122 }
123
124 /**
125  * @brief  Checks whether a sequence number is within the 
126  *         re-ordering window or not
127  *       
128  * @param[in] sn        Sequence Number to be checked
129  * @param[in] umUl      pointer to Um mode uplink control block
130  *
131  * @return  S16
132  *      -# TRUE 
133  *      -# FALSE
134  *
135  * @return  Void
136 */
137 static int16_t rlcUmmCheckSnInReordWindow (RlcSn sn, const RlcUmUl* const umUl)  
138 {
139    return (RLC_UM_GET_VALUE(sn, *umUl) < RLC_UM_GET_VALUE(umUl->vrUh, *umUl)); 
140 }
141
142 #ifdef NR_RLC_UL
143
144 /**
145  * @brief  Handler to updated expected byte seg
146  *
147  * @details
148  *    This function is used to update expected byte segment. The next segment
149  *    expected is indicated by the SO of the segment which is expected. Intially
150  *    the segment with SO 0 is expected and then in order. When all the segments
151  *    are received (which would happen when an expected SO is encountered
152  *    with LSF set) the allRcvd flag is set to TRUE
153  *
154  * @param[in]  gCb   RLC instance control block
155  * @param[in]  umUl  AM Uplink Control Block
156  * @param[in]  seg   Newly received segment
157  *
158  * @return void
159  *
160  */
161
162 void rlcUmmUpdExpByteSeg(RlcCb *gCb, RlcUmUl *umUl, RlcUmSeg *seg)
163 {
164    uint16_t  newExpSo; /* The new expected SO */
165    RlcSn     sn = seg->umHdr.sn;
166    bool      lstRcvd=FALSE;
167    RlcUmRecBuf *recBuf = NULLP;
168    
169    recBuf = rlcUtlGetUmRecBuf(umUl->recBufLst, sn);
170    if ((recBuf == NULLP) || (recBuf && (seg->umHdr.so != recBuf->expSo)))
171    {
172       return;
173    }
174    recBuf->noMissingSeg = FALSE;
175    newExpSo   = seg->soEnd + 1;
176    recBuf->expSo = newExpSo;
177    if(seg->umHdr.si == RLC_SI_LAST_SEG)
178    {  
179       lstRcvd = TRUE;
180    } 
181    RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
182    while(seg)
183    {
184       /* keep going ahead as long as the expectedSo match with the header so
185          else store the expSo for later checking again */
186       if(seg->umHdr.si == RLC_SI_LAST_SEG)
187       {  
188          lstRcvd = TRUE;
189       } 
190       if (seg->umHdr.so == newExpSo)
191       {
192          newExpSo = seg->soEnd + 1;
193          recBuf->expSo = newExpSo;
194          RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
195       }
196       else
197       {
198          recBuf->expSo = newExpSo;
199          return;
200       }
201    }
202    if (lstRcvd == TRUE)
203    {
204       recBuf->allSegRcvd = TRUE;
205    }
206    recBuf->noMissingSeg = TRUE;
207
208    return;
209 }
210 /**
211  * @brief Private handler to store the received segment
212  *
213  * @details
214  *    Private handler invokded by rlcUmmUlPlacePduInRecBuf to add a received
215  *    segment in reception buffer of a RBCB.
216  *    - It is responsible for detecting duplicate segments
217  *    - Adding it at appropriate position in the received buffer
218  *    - Calling ExpByteSeg to set expSo field in the receiver buffer
219  *
220  * @param[in]  gCb      RLC instance control block
221  * @param[in]  rbCb     Radio Bearer Contro Block
222  * @param[in]  umHdr    UM Header received
223  * @param[in]  pdu      Buffer received other than the headers
224  * @param[in]  pduSz    size of the PDU buffer received
225  *
226  * @return  bool
227  *   -#TRUE  Successful insertion into the receiver buffer
228  *   -#FALSE Possibly a duplicate segment
229  */
230
231 bool rlcUmmAddRcvdSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu, uint16_t pduSz)
232 {
233    RlcUmRecBuf   *recBuf = NULLP;
234    RlcUmSeg      *seg;
235    RlcUmSeg      *tseg;
236    uint16_t      soEnd;       /* Holds the SoEnd of received segment */
237    uint16_t      expSo = 0;   /* Expected SO */
238
239    soEnd = umHdr->so + pduSz - 1;
240    recBuf =  rlcUtlGetUmRecBuf(RLC_UMUL.recBufLst, umHdr->sn);
241
242    if (NULLP == recBuf)
243    {
244       RLC_ALLOC(gCb,recBuf, sizeof(RlcUmRecBuf));
245       if (recBuf == NULLP)
246       {
247          DU_LOG("\nERROR  -->  RLC_UL : Failed to allocate memory to recv buf for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
248             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
249
250          ODU_PUT_MSG_BUF(pdu);
251          return FALSE;
252       }
253       rlcUtlStoreUmRecBuf(RLC_UMUL.recBufLst, recBuf, umHdr->sn);
254    }
255    else
256    {
257       if (recBuf->allSegRcvd == TRUE)
258       {
259          ODU_PUT_MSG_BUF(pdu);
260          return FALSE;
261       }
262    }
263                         
264    RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
265    while ((seg != NULLP) && (seg->umHdr.so < umHdr->so))
266    {
267       expSo = seg->umHdr.so + seg->segSz;
268       RLC_UMM_LLIST_NEXT_SEG(recBuf->segLst, seg);
269    }
270
271    if (expSo > umHdr->so)
272    {
273       DU_LOG("\nDEBUG  -->  RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
274       /* This is a duplicate segment */
275       ODU_PUT_MSG_BUF(pdu);
276       return FALSE;
277    }
278
279    if ((seg) && (seg->umHdr.so <= soEnd))
280    {
281       DU_LOG("\nDEBUG  -->  RLC_UL : Received duplicate segment in rlcUmmAddRcvdSeg()");
282       /* This is a duplicate segment */
283       ODU_PUT_MSG_BUF(pdu);
284       return FALSE;
285    }
286
287    /* If we have come this far, we have to add this segment to the   */
288    /* reception buffer as we either have eliminated duplicates or    */
289    /* have found none.                                               */
290    RLC_ALLOC_WC(gCb, tseg, sizeof(RlcUmSeg));
291    if (tseg == NULLP)
292    {
293       DU_LOG("\nERROR -->  RLC_UL : Failed to allocate memory to segment for UEID:%d CELLID:%d in rlcUmmAddRcvdSeg()",
294          rbCb->rlcId.ueId, rbCb->rlcId.cellId);
295       ODU_PUT_MSG_BUF(pdu);
296       return FALSE;
297    }
298
299    tseg->seg = pdu;
300    tseg->segSz = pduSz;
301    RLC_MEM_CPY(&tseg->umHdr, umHdr, sizeof(RlcUmHdr));
302    RLC_MEM_CPY(&recBuf->umHdr, umHdr, sizeof(RlcUmHdr));
303    recBuf->sn = umHdr->sn;
304    tseg->soEnd = soEnd;
305    if (seg == NULLP)
306    {
307       cmLListAdd2Tail(&recBuf->segLst, &tseg->lstEnt);
308    }
309    else
310    {
311       recBuf->segLst.crnt = &seg->lstEnt;
312       cmLListInsCrnt(&recBuf->segLst, &tseg->lstEnt);
313    }
314    tseg->lstEnt.node = (PTR)tseg;
315    rlcUmmUpdExpByteSeg(gCb, &RLC_UMUL, tseg);
316    return TRUE;
317 }
318
319 /**
320  * @brief Private handler to release all stored segments
321  *
322  * @details
323  *    Private handler invokded by rlcUmmRelAllSegs to release the
324  *    stored segements in case a complete PDU is received later.
325  *
326  * @param[in]  gCb      RLC instance control block
327  * @param[in]  recBuf   Buffer that stores a received PDU or segments
328  *
329  * @return  void
330  *
331  */
332 void rlcUmmRelAllSegs(RlcCb *gCb, RlcUmRecBuf *recBuf)
333 {
334    RlcUmSeg *seg;
335
336    RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
337    while (seg != NULLP)
338    {
339       ODU_PUT_MSG_BUF(seg->seg);
340       cmLListDelFrm(&(recBuf->segLst), &(seg->lstEnt));
341       RLC_FREE(gCb, seg, sizeof(RlcUmSeg));
342       RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
343    }
344
345    return;
346 }
347
348 /**
349  * @brief Private handler to reassemble from a segment or a PDU
350  *
351  * @details
352  *    Private handler invokded by rlcUmmReAssembleSdus with either a
353  *    PDU or a segment of a PDU. This is also called in the case of
354  *    reestablishment and hence out of sequence joining is also to
355  *    be supported
356  *
357  *
358  * @param[in]  gCb     RLC instance control block
359  * @param[in]  rbCb    Uplink RB control block
360  * @param[in]  umHdr   UM header received for this segment/PDU
361  * @param[in]  pdu     PDU to be reassembled
362  *
363  * @return  ROK/RFILED
364  *
365  */
366
367 uint8_t rlcUmmProcSeg(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmHdr *umHdr, Buffer *pdu)
368 {
369
370    if ((RLC_UMUL.expSn != umHdr->sn) || (RLC_UMUL.expSo != umHdr->so))
371    {
372       /* Release the existing SDU as we have PDUs or */
373       /* segments that are out of sequence           */
374       DU_LOG("\nDEBUG  -->  RLC_UL : Received Segments are out of sequence in rlcUmmProcSeg()");
375       ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
376       return RFAILED;
377    }
378
379    if (umHdr->si == RLC_SI_FIRST_SEG)
380    {/* first Segment of the SDU */
381       if (RLC_UMUL.assembleSdu != NULLP)
382       { /* Some old SDU may be present */
383          ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
384       }
385       RLC_UMUL.assembleSdu = pdu;
386       pdu = NULLP;
387    }
388    else if(umHdr->si == RLC_SI_MID_SEG)
389    {/* Middle Segment of the SDU */
390       ODU_CAT_MSG(RLC_UMUL.assembleSdu,pdu, M1M2);
391       ODU_PUT_MSG_BUF(pdu);
392       pdu = NULLP;
393    }
394    else if(umHdr->si ==  RLC_SI_LAST_SEG)
395    {
396       ODU_CAT_MSG(pdu, RLC_UMUL.assembleSdu, M2M1);
397       ODU_PUT_MSG_BUF(RLC_UMUL.assembleSdu);
398    }
399
400    if (pdu != NULLP)
401    {
402       RLC_UMUL.assembleSdu = NULLP;
403       rlcUtlSendUlDataToDu(gCb,rbCb, pdu);
404    }
405
406    return ROK;
407 }
408 /**
409  *
410  * @brief Private handler to reassemble SDUs
411  *
412  * @details
413  *    Private handler invokded by rlcUmmProcessPdus with the PDU
414  *    from the reception buffer in sequence to reassemble SDUs and
415  *    send it to PDCP.
416  *
417  *        - With the stored header info, FI and LSF segment / concatenate
418  *          PDUs or byte segments of PDUs to get the associated SDU.
419  *
420  * @param[in]  rbCb     RB control block
421  * @param[in]  pdu      PDU to be reassembled
422  *
423  *  @return  uint8_t
424  *      -# ROK
425  *      -# RFAILED
426  *
427  */
428 uint8_t rlcUmmReAssembleSdus(RlcCb *gCb, RlcUlRbCb *rbCb, RlcUmRecBuf *recBuf)
429 {
430    RlcUmSeg        *seg;
431
432    /* This is a set of segments */
433    RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
434    RLC_UMUL.expSn = recBuf->sn;
435    RLC_UMUL.expSo = 0;
436    while(seg)
437    {
438       if(rlcUmmProcSeg(gCb, rbCb, &seg->umHdr, seg->seg) == RFAILED)
439       {
440          rlcUmmRelAllSegs(gCb, recBuf);
441          break;
442       }
443       RLC_UMUL.expSo = seg->soEnd + 1;
444       cmLListDelFrm(&(recBuf->segLst),&(seg->lstEnt));
445       RLC_FREE(gCb, seg, sizeof(RlcSeg));
446       RLC_UMM_LLIST_FIRST_SEG(recBuf->segLst, seg);
447    }
448    RLC_UMUL.expSn = (recBuf->umHdr.sn + 1) & (RLC_UMUL.modBitMask);
449    RLC_UMUL.expSo = 0;
450    return ROK;
451 }
452
453 #endif
454
455 /**
456  * @brief  Handler to process the Data Indication from the lower layer 
457  *         and send the PDUs to re-assembly unit. 
458  *       
459  * @details
460  *    This function processes the PDUs received from the lower layer
461  *    re-orders them and sends them one after the other in sequence 
462  *    to the re-assembly unit.
463  *
464  * @param[in] gCb      RLC Instance control block
465  * @param[in] rbCb     RB control block 
466  * @param[in] pduInfo  Pdu information 
467  *
468  *  @return Void
469 */
470 /* kw005.201 added support for L2 Measurement */
471 #ifdef LTE_L2_MEAS
472 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb  *rbCb, KwPduInfo *pduInfo, uint32_t ttiCnt)
473 #else
474 void rlcUmmProcessPdus(RlcCb *gCb, RlcUlRbCb *rbCb, KwPduInfo *pduInfo)
475 #endif
476 {
477    RlcSn         *vrUh;      /* vr(uh) */
478    RlcSn         *vrUr;      /* vr(ur) */
479    RlcSn         *vrUx;      /* vr(ux) */
480    uint16_t      curSn;      /* Current Sequence Number */
481    uint32_t      pduCount;   /* PDU count */
482    uint32_t      count;      /* Loop counter */
483    RlcUmRecBuf   **recBuf;   /* UM Reception Buffer */
484
485    bool         tmrRunning;   /* Boolean for checking Tmr */
486
487    count = 0;
488
489    /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */
490    pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU;
491    
492    vrUh   = &(rbCb->m.umUl.vrUh);
493    vrUr   = &(rbCb->m.umUl.vrUr);
494    vrUx   = &(rbCb->m.umUl.vrUx);
495    recBuf = (rbCb->m.umUl.recBuf);
496
497    while (count < pduCount)
498    {
499       RlcSn   ur; 
500       RlcSn   uh; 
501       RlcSn   seqNum;
502       Buffer *pdu = pduInfo->mBuf[count];
503       RlcUmRecBuf *tmpRecBuf;
504       gCb->genSts.pdusRecv++;
505 #ifndef RGL_SPECIFIC_CHANGES
506 #ifndef TENB_ACC
507 #ifndef LTE_PAL_ENB
508       uint32_t ulrate_rgu;
509       MsgLen len;
510       ODU_GET_MSG_LEN(pdu, &len);
511       ulrate_rgu += len;
512 #endif
513 #endif      
514 #endif      
515       /* create a buffer to be later inserted into the reception buffer */
516       RLC_ALLOC_WC(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
517 #if (ERRCLASS & ERRCLS_ADD_RES)
518       if (tmpRecBuf == NULLP)
519       {   
520          DU_LOG("\nRLC : rlcUmmProcessPdus: Memory allocation failed UEID:%d CELLID:%d",\
521             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
522          ODU_PUT_MSG_BUF(pdu);
523          return;
524       }
525 #endif /* ERRCLASS & ERRCLS_ADD_RES */      
526       /* ccpu00142274 - UL memory based flow control*/ 
527 #ifndef RGL_SPECIFIC_CHANGES
528 #ifndef TENB_ACC
529 #ifndef LTE_PAL_ENB
530     /* Changed the condition to TRUE from ROK  */
531 #ifndef XEON_SPECIFIC_CHANGES    
532      if(isMemThreshReached(rlcCb[0]->init.region) == TRUE)
533      {
534         uint32_t rlculdrop;
535         rlculdrop++;
536         ODU_PUT_MSG_BUF(pdu);
537         RLC_FREE(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
538         /*Fix for CR ccpu00144030: If threshhold is hit then also count
539          *should be incrmented */
540         count++;
541         continue;
542      }
543 #endif     
544 #endif
545 #endif
546 #endif
547       /* get the pdu header */
548       if (rlcUmmExtractHdr(gCb, rbCb, pdu, &(tmpRecBuf->umHdr)))  
549       {
550          DU_LOG("\nRLC : rlcUmmProcessPdus: Header Extraction Failed UEID:%d CELLID:%d",\
551              rbCb->rlcId.ueId, rbCb->rlcId.cellId);
552
553          /* Header extraction is a problem. 
554           * log an error and free the allocated memory */
555          /* ccpu00136940 */
556          RLC_FREE(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
557          ODU_PUT_MSG_BUF(pdu);
558          count++;
559          /* kw005.201 ccpu00117318, updating the statistics */
560          gCb->genSts.errorPdusRecv++;
561          continue;
562       }
563 #ifdef NR_RLC_UL
564       
565       /*TODO 1.Extract Hdr */
566       /*     2.Add Seg into Reception Buffer */
567       /*     3.If All Seg Recvd in Reception buffer list */
568       /*     4.Step 3 is true call Assemble Sdus */
569 #endif
570       curSn = tmpRecBuf->umHdr.sn;
571
572       /* Check if the PDU should be discarded or not */
573       ur = RLC_UM_GET_VALUE(RLC_UMUL.vrUr, RLC_UMUL); 
574       uh = RLC_UM_GET_VALUE(RLC_UMUL.vrUh, RLC_UMUL); 
575       seqNum = RLC_UM_GET_VALUE(curSn, RLC_UMUL); 
576
577       if (((ur < seqNum) && (seqNum < uh) && (RLC_UMUL.recBuf[curSn])) || 
578           (seqNum < ur)) 
579       {
580          /* PDU needs to be discarded */
581          DU_LOG("\nRLC : rlcUmmProcessPdus: Received a duplicate pdu with sn %d \
582             UEID:%d CELLID:%d", curSn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
583
584          ODU_PUT_MSG_BUF(pdu);
585          RLC_FREE(gCb, tmpRecBuf, sizeof(RlcUmRecBuf));
586          count++;
587          /* kw005.201 ccpu00117318, updating the statistics */
588          gCb->genSts.unexpPdusRecv++;
589          continue;
590       } 
591
592       /* kw005.201 added support for L2 Measurement */
593 #ifdef LTE_L2_MEAS
594
595       /* kw006.201 ccpu00120058, reduced code complexity by adding new function */
596       rlcUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt);
597
598 #endif 
599
600       recBuf[curSn] = tmpRecBuf;
601
602       recBuf[curSn]->pdu = pdu;
603       ODU_GET_MSG_LEN(pdu,&(recBuf[curSn]->pduSz));
604       /* kw005.201 ccpu00117318, updating the statistics */
605       gCb->genSts.bytesRecv += recBuf[curSn]->pduSz;
606       
607       if (!rlcUmmCheckSnInReordWindow(curSn,&RLC_UMUL))
608       {  /* currSn is outside re-ordering window */
609          *vrUh  = (curSn + 1) & RLC_UMUL.modBitMask;
610
611          /* re-assemble all pdus outside the modified re-ordering window */
612          /* the first SN is VR(UR) */
613          if (!rlcUmmCheckSnInReordWindow(*vrUr,&RLC_UMUL))
614          {
615             /* TODO : should it be VR(UR) + 1 ?... check, earlier it was so */
616             RlcSn sn = *vrUr; /* SN's which need to be re-assembled */
617             RlcSn lowerEdge;  /* to hold the lower-edge of the 
618                                 re-ordering window */
619
620             /* The new value ov VR(UR) is the lower end of the window i
621              * and SN's still this value need to be re-assembled */
622             
623             *vrUr = (*vrUh - RLC_UMUL.umWinSz) &  RLC_UMUL.modBitMask;         
624             lowerEdge = RLC_UM_GET_VALUE(*vrUr ,RLC_UMUL);
625             
626             while (RLC_UM_GET_VALUE(sn, RLC_UMUL) < lowerEdge)
627             {
628                if (recBuf[sn])
629                {
630 #ifdef NR_RLC_UL
631                   rlcUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
632 #endif
633                   RLC_FREE(gCb,recBuf[sn],sizeof(RlcUmRecBuf));
634                   recBuf[sn] = NULLP;
635                }
636                sn = (sn + 1) & RLC_UMUL.modBitMask;
637             }
638          }
639       }
640       if (recBuf[*vrUr])
641       {
642          RlcSn sn       = *vrUr;
643          RlcSn tSn      = RLC_UM_GET_VALUE(sn,RLC_UMUL); 
644          RlcSn tVrUr;       
645
646          /* set VR(UR) to next SN > current VR(UR) which is not received */
647          RlcSn nextVrUr = (*vrUr + 1) & RLC_UMUL.modBitMask;
648          rlcUmmFindNextVRUR(&RLC_UMUL, nextVrUr);
649
650          /* re-assemble SDUs with SN < Vr(UR) */
651          tVrUr = RLC_UM_GET_VALUE(*vrUr,RLC_UMUL);
652          while (recBuf[sn] && tSn < tVrUr)
653          {
654 #ifdef NR_RLC_UL
655             rlcUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
656 #endif
657             RLC_FREE(gCb,recBuf[sn],sizeof(RlcUmRecBuf));
658             recBuf[sn] = NULLP;
659             sn = (sn + 1) & RLC_UMUL.modBitMask;
660             tSn = RLC_UM_GET_VALUE(sn, RLC_UMUL);
661          }
662       }
663
664       tmrRunning = rlcChkTmr(gCb,(PTR)rbCb, RLC_EVT_UMUL_REORD_TMR);
665
666       if (tmrRunning) 
667       {
668          RlcSn tVrUx = RLC_UM_GET_VALUE(*vrUx, RLC_UMUL);
669          RlcSn tVrUr = RLC_UM_GET_VALUE(*vrUr ,RLC_UMUL);
670
671          RlcSn tVrUh = RLC_UM_GET_VALUE(*vrUh, RLC_UMUL);
672
673          S16 ret = rlcUmmCheckSnInReordWindow(*vrUx, &RLC_UMUL);
674
675          if ( (tVrUx <= tVrUr) || ((!ret) && (tVrUx != tVrUh))) 
676          {
677             rlcStopTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
678             tmrRunning = FALSE;
679          }
680       }
681
682       if (!tmrRunning)
683       {
684          if (RLC_UM_GET_VALUE(*vrUh, RLC_UMUL) > RLC_UM_GET_VALUE(*vrUr, RLC_UMUL))
685          {
686             rlcStartTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR); 
687             *vrUx = *vrUh;
688          }
689       }
690       count++;
691    }/* end while count < pduCount */
692 #ifdef LTE_L2_MEAS
693    rlcUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
694 #endif /* LTE_L2_MEAS */
695    return;   
696 }
697
698 /**
699  * @brief  Handler to process the re-establishment request received 
700  *         from the upper layer.
701  *       
702  * @details
703  *    This function does the following functions : 
704  *       - If direction of the RB is downlink : 
705  *         Remove all the SDUs in the SDU queue.
706  *       - If direction of the RB is uplink   : 
707  *         Call rlcUmmReAssembleSdus() for each PDU with SN < VR(UH)
708  *
709  * @param[in] gCb        RLC Instance control block
710  * @param[in] rlcID      Identity of the RLC entity for which 
711  *                       re-establishment is to be done
712  * @param[in] rbCb       RB control block for which re-establishment 
713  *                       is to be done
714  *
715  * @return  Void
716 */ 
717 Void rlcUmmUlReEstablish
718 (
719 RlcCb         *gCb,
720 CmLteRlcId   *rlcId,
721 RlcUlRbCb     *rbCb
722 )
723 {
724    RlcSn         curSn;
725    RlcSn         vrUh;
726    RlcUmRecBuf   **recBuf;   /* UM Reception Buffer */
727    RlcKwuSapCb   *rlcKwSap;   /* KWU SAP Information */
728
729    curSn = rbCb->m.umUl.vrUr;
730    vrUh  = RLC_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl);
731    recBuf =  rbCb->m.umUl.recBuf;
732
733    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR))
734    {
735        rlcStopTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
736    }
737    
738    while (RLC_UM_GET_VALUE(curSn,rbCb->m.umUl) < vrUh)
739    {
740       if ( recBuf[curSn] != NULLP )
741       {
742 #ifdef NR_RLC_UL
743          rlcUmmReAssembleSdus(gCb,rbCb,recBuf[curSn]);
744 #endif
745          RLC_FREE(gCb,recBuf[curSn],sizeof(RlcUmRecBuf));
746          recBuf[curSn] = NULLP;
747       } 
748       curSn = (curSn + 1) & rbCb->m.umUl.modBitMask;
749    }
750    rbCb->m.umUl.vrUr = 0;
751    rbCb->m.umUl.vrUh = 0;
752    rbCb->m.umUl.vrUx = 0;
753
754    rlcKwSap = gCb->u.ulCb->rlcKwuUlSap + RLC_UI_PDCP;
755
756    /* In the UM Mode always send reestablish-indication to Upper Latyer*/
757    RlcUiKwuReEstCmpInd(&rlcKwSap->pst, rlcKwSap->suId, *rlcId);
758
759    return;
760 }
761
762 /**
763  * @brief  Handler to extract the header from a PDU
764  *       
765  * @details
766  *    This function is used to extract the header of a PDU and store it 
767  *    along with the PDU buffer.The sequence number,framing info 
768  *    and LIs are extracted by this function.
769  *
770  * @param[in] gCb      RLC Instance control block
771  * @param[in] rbCb     Rb Control block for which the pdu is received
772  * @param[in] pdu      PDU buffer
773  * @param[out] umHdr   UM header to be filled after extraction
774  *
775  * @return  S16
776  *      -# TRUE 
777  *      -# FALSE
778 */
779 static uint8_t rlcUmmExtractHdr(RlcCb *gCb, RlcUlRbCb *rbCb, Buffer *pdu, RlcUmHdr *umHdr)
780 {
781    uint8_t   e;         /* Extension Bit */
782    Data      dst[2];    /* Destination Buffer */
783    int32_t   totalSz;   /* Sum of LIs */
784    MsgLen    pduSz;     /* PDU size */
785 #if (ERRCLASS & ERRCLS_DEBUG)
786    uint8_t   ret;       /* Return Value */
787 #endif
788
789    ODU_GET_MSG_LEN(pdu,&pduSz);
790  
791    if ( rbCb->m.umUl.snLen == 1)
792    {
793 #if (ERRCLASS & ERRCLS_DEBUG)
794       ret = ODU_REM_PRE_MSG(dst,pdu);
795       if (ret != ROK)
796       {
797          DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed for 5 bit SN \
798             UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
799          return RFAILED;
800       }
801 #else
802       ODU_REM_PRE_MSG(dst,pdu);
803 #endif
804       pduSz--;
805       umHdr->sn = (dst[0]) & 0x1F; 
806       umHdr->fi = (dst[0]) >> 6;
807       e       = (dst[0]>>5) & 0x01;
808    }
809    else
810    {
811       /* snLen - sequnce length will be 10 bits requiring 2 bytes */ 
812 #if (ERRCLASS & ERRCLS_DEBUG)
813       ret = ODU_REM_PRE_MSG_MULT(dst,2,pdu);
814       if (ret != ROK)
815       {
816          DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG_MULT Failed for 10 bits SN \
817             UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
818          return RFAILED;
819       }
820 #else
821       ODU_REM_PRE_MSG_MULT(dst,2,pdu);
822 #endif
823       pduSz -= 2;
824    
825       /* kw005.201 R9 Upgrade 3gpp spec 36.322 ver9.3.0 CR0082      *
826        * Removed the "if" condition for checking the reserved field *
827        * Added mask 0x03 for extracting the FI field.          */
828
829       umHdr->fi = ( (dst[0] ) >> 3) & 0x03;
830       e       = ( (dst[0] ) >> 2) & 0x01;
831       umHdr->sn = (  dst[0] & 0x03) << 8;
832       umHdr->sn  |= dst[1];
833    }
834
835    umHdr->numLi = 0;
836    
837    totalSz = 0;
838    while(e && umHdr->numLi < RLC_MAX_UL_LI )
839    {
840 #if (ERRCLASS & ERRCLS_DEBUG)
841       ret = ODU_REM_PRE_MSG_MULT(dst,2,pdu);
842       if (ret != ROK)
843       {
844          DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG_MULT Failed UEID:%d CELLID:%d",\
845             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
846          return RFAILED;
847       }
848 #else
849       ODU_REM_PRE_MSG_MULT(dst,2,pdu);
850 #endif
851       umHdr->li[umHdr->numLi] = ((dst[0]) & 0x7F) << 4;
852       umHdr->li[umHdr->numLi] |= dst[1] >> 4;
853       if ( 0 == umHdr->li[umHdr->numLi] )
854       {
855          DU_LOG("\nRLC : rlcUmmExtractHdr : Received LI as 0 UEID:%d CELLID:%d",
856             rbCb->rlcId.ueId, rbCb->rlcId.cellId);
857          return RFAILED; 
858       }
859       totalSz += umHdr->li[umHdr->numLi];
860       if ( pduSz <=  totalSz )
861       {
862          DU_LOG("\nRLC : rlcUmmExtractHdr : SN [%d]: UEID:%d CELLID:%d",\
863             umHdr->sn, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
864          DU_LOG("\nRLC : rlcUmmExtractHdr : Corrupted PDU as TotSz[%d] PduSz[%d] \
865             UEID:%d CELLID:%d ", totalSz, pduSz, rbCb->rlcId.ueId, rbCb->rlcId.cellId);
866          return RFAILED; /* the situation where in the PDU size 
867                             is something that does not match with 
868                             the size in LIs*/
869       }
870       umHdr->numLi++;
871       pduSz -= 2;
872
873       e = ((dst[0]) & 0x80) >> 7;
874    
875       if ( e && umHdr->numLi < RLC_MAX_UL_LI)
876       {
877          uint8_t tmp = ((dst[1]) & 0x08) >> 3;
878          umHdr->li[umHdr->numLi] = ( dst[1] & 0x07) << 8;
879
880
881 #if (ERRCLASS & ERRCLS_DEBUG)
882          ret = ODU_REM_PRE_MSG(dst,pdu);
883          if (ret != ROK)
884          {
885             DU_LOG("\nRLC : rlcUmmExtractHdr : ODU_REM_PRE_MSG Failed UEID:%d CELLID:%d",
886                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
887             return RFAILED;
888          }
889 #else
890          ODU_REM_PRE_MSG(dst,pdu);
891 #endif
892          umHdr->li[umHdr->numLi] |= ( dst[0] );    /* The first byte lies in 
893                                                    the first 8 bits.We want 
894                                                    them in the last 8 bits */
895          if ( 0 == umHdr->li[umHdr->numLi] )
896          {
897             DU_LOG("\nRLC : rlcUmmExtractHdr :Received LI as 0 UEID:%d CELLID:%d",
898                rbCb->rlcId.ueId, rbCb->rlcId.cellId);
899             return RFAILED; 
900          }
901          totalSz += umHdr->li[umHdr->numLi];
902          pduSz--;
903          umHdr->numLi++;
904
905          if (pduSz < totalSz)
906          {
907             return RFAILED; /* the situation where in the PDU size is 
908                                something that does not match with the 
909                                size in LIs*/
910          }
911
912          e = tmp;
913       }
914    } /* while(e && umHdr->numLi < RLC_MAX_LI ) */
915    if (e)
916    {
917       /* PDU was constructed with LIs that exceeded RLC_MAX_LI */
918       return RFAILED;
919    }
920    return ROK; 
921 }
922    
923 /**
924  * @brief Handles expiry of re-ordering timer
925  *
926  * @param[in] gCb     RLC Instance control block
927  * @param[in] rbCb    Rb Control block for which re-order timer expired
928  *
929  * @return  Void
930 */
931 Void rlcUmmReOrdTmrExp
932 (
933 RlcCb       *gCb,
934 RlcUlRbCb   *rbCb     
935 )
936 {
937    RlcSn prevVrUr;   /* prevVrUr */
938    prevVrUr = RLC_UMUL.vrUr;
939
940    /* set VR(UR) to SN >= VR(UX) that has not been received */
941    rlcUmmFindNextVRUR(&RLC_UMUL, RLC_UMUL.vrUx);
942
943    while (RLC_UM_GET_VALUE(prevVrUr,RLC_UMUL) < 
944           RLC_UM_GET_VALUE(RLC_UMUL.vrUr,RLC_UMUL))
945    {
946       if (RLC_UMUL.recBuf[prevVrUr])
947       {
948 #ifdef NR_RLC_UL
949          rlcUmmReAssembleSdus(gCb, rbCb, RLC_UMUL.recBuf[prevVrUr]);
950 #endif
951          if(RLC_UMUL.recBuf[prevVrUr]->pdu != NULLP) /* RLC mem leak fix */
952          {
953             ODU_PUT_MSG_BUF(RLC_UMUL.recBuf[prevVrUr]->pdu);
954          }
955          RLC_FREE(gCb, RLC_UMUL.recBuf[prevVrUr], sizeof(RlcUmRecBuf));
956          RLC_UMUL.recBuf[prevVrUr] = NULLP;
957       }
958
959       prevVrUr = (prevVrUr + 1) & rbCb->m.umUl.modBitMask;
960    }
961
962    if (RLC_UM_GET_VALUE(RLC_UMUL.vrUh, RLC_UMUL) > 
963        RLC_UM_GET_VALUE(RLC_UMUL.vrUr, RLC_UMUL))
964    {
965       rlcStartTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
966       RLC_UMUL.vrUx = RLC_UMUL.vrUh;
967    }
968 }
969
970 /**
971  * @brief
972  *   Function to release/free the UnAcknowledged Mode Module  RbCb buffers
973  *
974  * @details
975  *   This primitive Frees the UM RbCb transmission Buffer, retransmission
976  *   Buffer and reciption Buffers
977  *
978  * @param [in]   gCb   - RLC instance Control Block
979  * @param [in]   rbCb  - RB Control Block
980  *
981  * @return   void
982  */
983
984 Void rlcUmmFreeUlRbCb
985 (
986 RlcCb       *gCb,
987 RlcUlRbCb   *rbCb
988 )
989 {
990    RlcSn         curSn = 0;           /* sequence number of PDU */
991    RlcSn         windSz;              /* PDU window size */
992    RlcUmRecBuf   **umRecBuf;          /* UM module receive buffer */
993
994    windSz  = rbCb->m.umUl.umWinSz << 1;
995
996    umRecBuf =  rbCb->m.umUl.recBuf;
997
998    if(TRUE == rlcChkTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR))
999    {
1000       rlcStopTmr(gCb,(PTR)rbCb,RLC_EVT_UMUL_REORD_TMR);
1001    }
1002    while (curSn < windSz)
1003    {
1004       if (umRecBuf[curSn] != NULLP)
1005       {
1006          ODU_PUT_MSG_BUF(umRecBuf[curSn]->pdu);
1007          umRecBuf[curSn]->pdu = NULLP;
1008
1009          RLC_FREE(gCb, umRecBuf[curSn], sizeof(RlcUmRecBuf));
1010          umRecBuf[curSn] = NULLP;
1011       }
1012       curSn++;
1013    }
1014    RLC_FREE(gCb,rbCb->m.umUl.recBuf, (windSz ) * sizeof(RlcUmRecBuf*));
1015    rbCb->m.umUl.recBuf = NULLP;
1016    return;
1017
1018
1019
1020 /********************************************************************30**
1021          End of file
1022 **********************************************************************/