Initial commit
[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                   --kwUmmQSdu
29                   --kwUmmProcessSdus
30                   --kwUmmProcessPdus
31                   --kwUmmReAssembleSdus
32                   --kwUmmReEstablish 
33
34      File:     kw_umm_ul.c
35
36 **********************************************************************/
37 static const char* RLOG_MODULE_NAME="RLC";
38 static int RLOG_MODULE_ID=2048;
39 static int RLOG_FILE_ID=240;
40
41 /** 
42  * @file kw_umm_ul.c
43  * @brief RLC Unacknowledged Mode uplink module
44 */
45
46 /* header (.h) include files */
47 #include "envopt.h"             /* environment options */
48 #include "envdep.h"             /* environment dependent */
49 #include "envind.h"             /* environment independent */
50
51 #include "gen.h"                /* general */
52 #include "ssi.h"                /* system services interface */
53 #include "cm5.h"                /* Timer Functions */
54 #include "cm_lte.h"             /* common umts header file */
55 #include "cm_hash.h"            /* common hash module  file */
56 #include "cm_llist.h"           /* common list header file */
57 #include "ckw.h"                /* RRC layer */
58 #include "lkw.h"                /* RRC layer */
59 #include "kwu.h"                /* RLC service user */
60 #include "lkw.h"                /* LM Interface */
61 #include "rgu.h"                /* MAC layer */
62 #include "kw_env.h"             /* RLC environment options */
63
64 #include "kw.h"                 /* RLC layer */
65 #include "kw_err.h"
66 #include "kw_ul.h"
67
68
69 /* header/extern include files (.x) */
70
71 #include "gen.x"                /* general */
72 #include "ssi.x"                /* system services interface */
73 #include "cm_lib.x"             /* common library */
74 #include "cm5.x"                /* Timer Functions */
75 #include "cm_hash.x"            /* common hash module */
76 #include "cm_lte.x"             /* common umts file */
77 #include "cm_llist.x"           /* common list header file */
78 #include "ckw.x"                /* RRC layer */
79 #include "kwu.x"                /* RLC service user */
80 #include "lkw.x"                /* LM Interface */
81 #include "rgu.x"                /* MAC later */
82
83 #include "kw.x"                 /* RLC layer */
84 #include "kw_ul.x"
85
86 #define KW_MODULE (KW_DBGMASK_UM | KW_DBGMASK_UL)
87
88 PRIVATE S16 kwUmmExtractHdr ARGS ((KwCb *gCb, 
89                                    KwUlRbCb *rbCb,
90                                    Buffer *pdu,
91                                    KwUmHdr *umHdr));
92
93 PRIVATE Void kwUmmReAssembleSdus ARGS ((KwCb *gCb,
94                                         KwUlRbCb *rbCb,
95                                         KwUmRecBuf *umRecBuf));
96
97 #ifndef TENB_ACC
98 #ifndef LTE_PAL_ENB
99 extern U32 isMemThreshReached(Region region);
100 #endif
101 #endif
102 /**
103  * @brief  Finds and sets the next VR(UR) depending on the 
104  *         passed sequence number
105  *       
106  * @details
107  *    Finds the next VR(UR) depending on the passed SN. Updates VR(UR) to 
108  *    the SN of the first UMD PDU with SN >= _nextSn that has not been received
109  *
110  * @param[in] umUl      pointer to Um mode uplink control block
111  * @param[in] nextSn    Sequence number after which the VR(UR) is to set to
112  *
113  * @return  Void
114 */ 
115 PRIVATE Void kwUmmFindNextVRUR (KwUmUl* umUl, KwSn nextSn)
116 {
117    KwSn ur = KW_UM_GET_VALUE(umUl->vrUr, *umUl);
118    
119    KwSn nextSnToCompare = KW_UM_GET_VALUE(nextSn,*umUl);
120    
121    while (ur < nextSnToCompare)
122    {
123       if (!(umUl->recBuf[nextSn])) /* if the buffer is empty, SN not received */
124       {
125          umUl->vrUr = nextSn;
126          break;
127       }
128       nextSn = (nextSn + 1) & umUl->modBitMask; 
129       nextSnToCompare = KW_UM_GET_VALUE(nextSn,*umUl);
130    }
131 }
132
133 /**
134  * @brief  Checks whether a sequence number is within the 
135  *         re-ordering window or not
136  *       
137  * @param[in] sn        Sequence Number to be checked
138  * @param[in] umUl      pointer to Um mode uplink control block
139  *
140  * @return  S16
141  *      -# TRUE 
142  *      -# FALSE
143  *
144  * @return  Void
145 */
146 PRIVATE S16 kwUmmCheckSnInReordWindow (KwSn sn, 
147                                        CONSTANT KwUmUl* CONSTANT umUl)  
148 {
149    return (KW_UM_GET_VALUE(sn, *umUl) < KW_UM_GET_VALUE(umUl->vrUh, *umUl)); 
150 }
151
152 /**
153  * @brief  Handler to process the Data Indication from the lower layer 
154  *         and send the PDUs to re-assembly unit. 
155  *       
156  * @details
157  *    This function processes the PDUs received from the lower layer
158  *    re-orders them and sends them one after the other in sequence 
159  *    to the re-assembly unit.
160  *
161  * @param[in] gCb      RLC Instance control block
162  * @param[in] rbCb     RB control block 
163  * @param[in] pduInfo  Pdu information 
164  *
165  *  @return Void
166 */
167 /* kw005.201 added support for L2 Measurement */
168 #ifdef LTE_L2_MEAS
169
170 #ifdef ANSI
171 PUBLIC Void kwUmmProcessPdus
172 (
173 KwCb      *gCb,
174 KwUlRbCb  *rbCb,                   /* Rb Control Block */
175 KwPduInfo *pduInfo,                 /* Pdu  data and related information */
176 U32       ttiCnt                  /* ttiCnt received from MAC */
177 )
178 #else
179 PUBLIC Void kwUmmProcessPdus(rbCb,pduInfo,ttiCnt)
180 KwCb      *gCb;
181 KwUlRbCb  *rbCb;                   /* Rb Control Block */
182 KwPduInfo *pduInfo;                /* Pdu  data and related information */
183 U32       ttiCnt;                  /* ttiCnt received from MAC */
184 #endif
185 #else
186 #ifdef ANSI
187 PUBLIC Void kwUmmProcessPdus
188 (
189 KwCb      *gCb,
190 KwUlRbCb  *rbCb,                /* Rb Control Block */
191 KwPduInfo *pduInfo              /* Pdu  data and related information */
192 )
193 #else
194 PUBLIC Void kwUmmProcessPdus(rbCb,pduInfo)
195 KwCb      *gCb;
196 KwUlRbCb  *rbCb;                /* Rb Control Block */
197 KwPduInfo *pduInfo;             /* Pdu  data and related information */
198 #endif
199 #endif
200 {
201    KwSn          *vrUh;      /* vr(uh) */
202    KwSn          *vrUr;      /* vr(ur) */
203    KwSn         *vrUx;      /* vr(ux) */
204    U16          curSn;      /* Current Sequence Number */
205    U32          pduCount;   /* PDU count */
206    U32          count;      /* Loop counter */
207    KwUmRecBuf   **recBuf;   /* UM Reception Buffer */
208
209    Bool         tmrRunning;   /* Boolean for checking Tmr */
210 /* kw005.201 added support for L2 Measurement */
211
212    TRC2(kwUmmProcessPdus)
213
214
215    count = 0;
216
217    /* pduCount should be the min of RGU_MAX_PDU and pduInfo->numPdu */
218    pduCount = (pduInfo->numPdu < RGU_MAX_PDU)? pduInfo->numPdu : RGU_MAX_PDU;
219    
220    vrUh   = &(rbCb->m.umUl.vrUh);
221    vrUr   = &(rbCb->m.umUl.vrUr);
222    vrUx   = &(rbCb->m.umUl.vrUx);
223    recBuf = (rbCb->m.umUl.recBuf);
224
225    while (count < pduCount)
226    {
227       KwSn   ur; 
228       KwSn   uh; 
229       KwSn   seqNum;
230       Buffer *pdu = pduInfo->mBuf[count];
231       KwUmRecBuf *tmpRecBuf;
232       gCb->genSts.pdusRecv++;
233 #ifndef RGL_SPECIFIC_CHANGES
234 #ifndef TENB_ACC
235 #ifndef LTE_PAL_ENB
236       extern U32 ulrate_rgu;
237       MsgLen len;
238       SFndLenMsg(pdu, &len);
239       ulrate_rgu += len;
240 #endif
241 #endif      
242 #endif      
243       /* create a buffer to be later inserted into the reception buffer */
244       KW_ALLOC_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
245 #if (ERRCLASS & ERRCLS_ADD_RES)
246       if (tmpRecBuf == NULLP)
247       {   
248          RLOG_ARG2(L_FATAL, DBG_RBID,rbCb->rlcId.rbId,
249                   "Memory allocation failed UEID:%d CELLID:%d",
250                   rbCb->rlcId.ueId,
251                   rbCb->rlcId.cellId);
252          SPutMsg(pdu);
253
254          RETVOID;
255       }
256 #endif /* ERRCLASS & ERRCLS_ADD_RES */      
257       /* ccpu00142274 - UL memory based flow control*/ 
258 #ifndef RGL_SPECIFIC_CHANGES
259 #ifndef TENB_ACC
260 #ifndef LTE_PAL_ENB
261     /* Changed the condition to TRUE from ROK  */
262 #ifndef XEON_SPECIFIC_CHANGES    
263      if(isMemThreshReached(kwCb[0]->init.region) == TRUE)
264      {
265         extern U32 rlculdrop;
266         rlculdrop++;
267         KW_FREE_BUF(pdu);
268         KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
269         /*Fix for CR ccpu00144030: If threshhold is hit then also count
270          *should be incrmented */
271         count++;
272         continue;
273      }
274 #endif     
275 #endif
276 #endif
277 #endif
278       /* get the pdu header */
279       if (kwUmmExtractHdr(gCb, rbCb, pdu, &(tmpRecBuf->umHdr)))  
280       {
281          RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
282                   "Header Extraction Failed UEID:%d CELLID:%d",
283                   rbCb->rlcId.ueId,
284                   rbCb->rlcId.cellId);
285
286          /* Header extraction is a problem. 
287           * log an error and free the allocated memory */
288          /* ccpu00136940 */
289          KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
290          SPutMsg(pdu);
291          count++;
292          /* kw005.201 ccpu00117318, updating the statistics */
293          gCb->genSts.errorPdusRecv++;
294          continue;
295       }
296       curSn = tmpRecBuf->umHdr.sn;
297
298       /* Check if the PDU should be discarded or not */
299       ur = KW_UM_GET_VALUE(KW_UMUL.vrUr, KW_UMUL); 
300       uh = KW_UM_GET_VALUE(KW_UMUL.vrUh, KW_UMUL); 
301       seqNum = KW_UM_GET_VALUE(curSn, KW_UMUL); 
302
303       if (((ur < seqNum) && (seqNum < uh) && (KW_UMUL.recBuf[curSn])) || 
304           (seqNum < ur)) 
305       {
306          /* PDU needs to be discarded */
307          RLOG_ARG3(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId,
308                   "Received a duplicate pdu with sn %d UEID:%d CELLID:%d",
309                   curSn,
310                   rbCb->rlcId.ueId,
311                   rbCb->rlcId.cellId);
312
313          KW_FREE_BUF(pdu);
314          KW_FREE_WC(gCb, tmpRecBuf, sizeof(KwUmRecBuf));
315          count++;
316          /* kw005.201 ccpu00117318, updating the statistics */
317          gCb->genSts.unexpPdusRecv++;
318          continue;
319       } 
320
321       /* kw005.201 added support for L2 Measurement */
322 #ifdef LTE_L2_MEAS
323
324       /* kw006.201 ccpu00120058, reduced code complexity by adding new function */
325       kwUtlCalUlIpThrPut(gCb,rbCb, pdu, ttiCnt);
326
327 #endif 
328
329       recBuf[curSn] = tmpRecBuf;
330
331       recBuf[curSn]->pdu = pdu;
332       SFndLenMsg(pdu,&(recBuf[curSn]->pduSz));
333       /* kw005.201 ccpu00117318, updating the statistics */
334       gCb->genSts.bytesRecv += recBuf[curSn]->pduSz;
335       
336       if (!kwUmmCheckSnInReordWindow(curSn,&KW_UMUL))
337       {  /* currSn is outside re-ordering window */
338          *vrUh  = (curSn + 1) & KW_UMUL.modBitMask;
339
340          /* re-assemble all pdus outside the modified re-ordering window */
341          /* the first SN is VR(UR) */
342          if (!kwUmmCheckSnInReordWindow(*vrUr,&KW_UMUL))
343          {
344             /* TODO : should it be VR(UR) + 1 ?... check, earlier it was so */
345             KwSn sn = *vrUr; /* SN's which need to be re-assembled */
346             KwSn lowerEdge;  /* to hold the lower-edge of the 
347                                 re-ordering window */
348
349             /* The new value ov VR(UR) is the lower end of the window i
350              * and SN's still this value need to be re-assembled */
351             
352             *vrUr = (*vrUh - KW_UMUL.umWinSz) &  KW_UMUL.modBitMask;         
353             lowerEdge = KW_UM_GET_VALUE(*vrUr ,KW_UMUL);
354             
355             while (KW_UM_GET_VALUE(sn, KW_UMUL) < lowerEdge)
356             {
357                if (recBuf[sn])
358                {
359                   kwUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
360                   KW_FREE_WC(gCb,recBuf[sn],sizeof(KwUmRecBuf));
361                   recBuf[sn] = NULLP;
362                }
363                sn = (sn + 1) & KW_UMUL.modBitMask;
364             }
365          }
366       }
367       if (recBuf[*vrUr])
368       {
369          KwSn sn       = *vrUr;
370          KwSn tSn      = KW_UM_GET_VALUE(sn,KW_UMUL); 
371          KwSn tVrUr;       
372
373          /* set VR(UR) to next SN > current VR(UR) which is not received */
374          KwSn nextVrUr = (*vrUr + 1) & KW_UMUL.modBitMask;
375          kwUmmFindNextVRUR(&KW_UMUL, nextVrUr);
376
377          /* re-assemble SDUs with SN < Vr(UR) */
378          tVrUr = KW_UM_GET_VALUE(*vrUr,KW_UMUL);
379          while (recBuf[sn] && tSn < tVrUr)
380          {
381             kwUmmReAssembleSdus(gCb,rbCb,recBuf[sn]);
382             KW_FREE_WC(gCb,recBuf[sn],sizeof(KwUmRecBuf));
383             recBuf[sn] = NULLP;
384             sn = (sn + 1) & KW_UMUL.modBitMask;
385             tSn = KW_UM_GET_VALUE(sn, KW_UMUL);
386          }
387       }
388
389       tmrRunning = kwChkTmr(gCb,(PTR)rbCb, KW_EVT_UMUL_REORD_TMR);
390
391       if (tmrRunning) 
392       {
393          KwSn tVrUx = KW_UM_GET_VALUE(*vrUx, KW_UMUL);
394          KwSn tVrUr = KW_UM_GET_VALUE(*vrUr ,KW_UMUL);
395
396          KwSn tVrUh = KW_UM_GET_VALUE(*vrUh, KW_UMUL);
397
398          S16 ret = kwUmmCheckSnInReordWindow(*vrUx, &KW_UMUL);
399
400          if ( (tVrUx <= tVrUr) || ((!ret) && (tVrUx != tVrUh))) 
401          {
402             kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
403             tmrRunning = FALSE;
404          }
405       }
406
407       if (!tmrRunning)
408       {
409          if (KW_UM_GET_VALUE(*vrUh, KW_UMUL) > KW_UM_GET_VALUE(*vrUr, KW_UMUL))
410          {
411             kwStartTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR); 
412             *vrUx = *vrUh;
413          }
414       }
415       count++;
416    }/* end while count < pduCount */
417 #ifdef LTE_L2_MEAS
418    kwUtlCalUlIpThrPutIncTTI(gCb, rbCb,ttiCnt);
419 #endif /* LTE_L2_MEAS */
420    RETVOID;   
421 }
422
423 /**
424  * @brief  Handler to reassemble the SDUs and send them to the upper layer.
425  *       
426  * @details
427  *    This function processes the received in-sequence PDU and
428  *    re-assembles the SDUs and sends them to the upper layer.
429  *
430  * @param[in] gCb        RLC Instance control block
431  * @param[in] rbCb       RB control block
432  * @param[in] umRecBuf   Reception Buffer to be Re-Assembled 
433  *
434  * @return  Void
435 */
436 #ifdef ANSI
437 PRIVATE Void kwUmmReAssembleSdus
438 (
439 KwCb         *gCb,
440 KwUlRbCb     *rbCb,   
441 KwUmRecBuf   *umRecBuf 
442 )
443 #else
444 PRIVATE Void kwUmmReAssembleSdus(gCb,rbCb,umRecBuf)
445 KwCb         *gCb;
446 KwUlRbCb     *rbCb;     
447 KwUmRecBuf   *umRecBuf; 
448 #endif
449 {
450    U32      liCount;        /* LI count */
451    U32      count;          /* Loop counter */
452    U8       fi;             /* Framing Info */
453    U16      sn;             /* Sequence Number of current PDU */
454    MsgLen   len;            /* PDU Length */
455    Buffer   *sdu;           /* SDU to be sent to upper layer */
456    Buffer   *remPdu;        /* Remaining PDU */
457    Buffer   **partialSdu;   /* Partial SDU */
458
459    TRC2(kwUmmReAssembleSdus)  
460
461
462    liCount = umRecBuf->umHdr.numLi;
463    fi = umRecBuf->umHdr.fi;
464    sn =  umRecBuf->umHdr.sn;
465  
466    for (count = 0; (count <= liCount);count++)
467    {
468       if (count < liCount )
469          len = umRecBuf->umHdr.li[count];
470       else
471       {
472          if (!(umRecBuf->pdu))
473          {
474             RETVOID;
475          }
476          SFndLenMsg(umRecBuf->pdu,&len);
477       }
478          
479       /* get the sdu out of the pdu */
480       SSegMsg(umRecBuf->pdu,len,&remPdu);
481       sdu = umRecBuf->pdu;
482       umRecBuf->pdu = remPdu;
483       
484       partialSdu = &(rbCb->m.umUl.partialSdu);
485       /* While re-assembling the SDUs, consider the first LI and perform 
486        * the following steps.
487           -# If the first bit of FI(Framing Info of 2  bits) is set => 
488                 -# The current Data field in the PDU is a segment. 
489                    So form a SDU only if the 
490                        rbCb->m.um.umUl.partialSdu exists and the SNs are 
491                        in-sequence.
492                 -# If there are no LIs and the second bit of LI is 1 
493                    then a partial SDU is formed which would not be sent 
494                    to the upper layer.
495           -# else
496                 -# If rbCb->partialSdu is not NULL then flush it off.
497                 -# If LI count > 0 or LI count is 0 and second bit 
498                    of FI is not 1 
499                          The SDU is complete.So send it to upper layer.
500                 -# else
501                          The SDU is partial and is placed 
502                          in rbCb->m.um.umUl.partialSdu;
503       */
504              
505       if (0 == count )
506       {
507          if (fi & 2)
508          {
509             if ((*partialSdu) && 
510                 (sn == ((rbCb->m.umUl.sn + 1) & rbCb->m.umUl.modBitMask)))
511             {
512                SCatMsg(*partialSdu,sdu,M1M2);
513                KW_FREE_BUF(sdu);
514                if (liCount > 0 || !(fi & 1))
515                {
516                   kwUtlSndDatInd(gCb,rbCb,*partialSdu);
517                   *partialSdu = NULLP;
518                }
519             }
520             else
521             {
522                 /* Partial Sdu stored is not valid now.So free it */
523                if (*partialSdu)
524                {
525                   KW_FREE_BUF(*partialSdu);
526                   *partialSdu = NULLP;
527                }
528                   
529                KW_FREE_BUF(sdu);
530                sdu = NULLP;
531             }
532          }
533          else
534          {
535             if (*partialSdu)
536             {
537                KW_FREE_BUF(*partialSdu);  /* RLC mem leak fix */
538                *partialSdu = NULLP;
539             }
540             
541             if (liCount > 0 || !( fi & 1))
542             {
543                kwUtlSndDatInd(gCb,rbCb,sdu);
544             }
545             else
546             {
547                   *partialSdu = sdu; 
548             }
549          }
550       }
551       /*
552           If the SDU pointer has the last Data field of the PDU
553             -# If FI is 1,place the SDU in rbCb->m.um.umDl.partialSdu
554             -# else send the SDU to upper layer.
555       */
556        else if (count == liCount)
557       {
558          if (fi & 1)
559          {
560             *partialSdu = sdu;
561          }
562          else
563          {
564             kwUtlSndDatInd(gCb, rbCb, sdu);
565          }
566       }
567       /*  
568          If the LI is something other than the first one, 
569          just send the SDU to the upper layer */
570       else
571       {
572          kwUtlSndDatInd(gCb, rbCb, sdu);
573       }
574    }
575    rbCb->m.umUl.sn = sn;
576
577    RETVOID;
578 }
579
580 /**
581  * @brief  Handler to process the re-establishment request received 
582  *         from the upper layer.
583  *       
584  * @details
585  *    This function does the following functions : 
586  *       - If direction of the RB is downlink : 
587  *         Remove all the SDUs in the SDU queue.
588  *       - If direction of the RB is uplink   : 
589  *         Call kwUmmReAssembleSdus() for each PDU with SN < VR(UH)
590  *
591  * @param[in] gCb        RLC Instance control block
592  * @param[in] rlcID      Identity of the RLC entity for which 
593  *                       re-establishment is to be done
594  * @param[in] rbCb       RB control block for which re-establishment 
595  *                       is to be done
596  *
597  * @return  Void
598 */ 
599 #ifdef ANSI
600 PUBLIC Void kwUmmUlReEstablish
601 (
602 KwCb         *gCb,
603 CmLteRlcId   *rlcId,
604 KwUlRbCb     *rbCb
605 )
606 #else
607 PUBLIC Void kwUmmUlReEstablish(gCb, rlcId, rbCb)
608 KwCb         *gCb;
609 CmLteRlcId   *rlcId;
610 KwUlRbCb     *rbCb;
611 #endif
612 {
613    KwSn         curSn;
614    KwSn         vrUh;
615    KwUmRecBuf   **recBuf;   /* UM Reception Buffer */
616    KwKwuSapCb   *kwKwSap;   /* KWU SAP Information */
617
618    TRC2(kwUmmUlReEstablish)
619
620
621    curSn = rbCb->m.umUl.vrUr;
622    vrUh  = KW_UM_GET_VALUE(rbCb->m.umUl.vrUh,rbCb->m.umUl);
623    recBuf =  rbCb->m.umUl.recBuf;
624
625    if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR))
626    {
627        kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
628    }
629    
630    while (KW_UM_GET_VALUE(curSn,rbCb->m.umUl) < vrUh)
631    {
632       if ( recBuf[curSn] != NULLP )
633       {
634          kwUmmReAssembleSdus(gCb,rbCb,recBuf[curSn]);
635          KW_FREE_WC(gCb,recBuf[curSn],sizeof(KwUmRecBuf));
636          recBuf[curSn] = NULLP;
637       } 
638       curSn = (curSn + 1) & rbCb->m.umUl.modBitMask;
639    }
640    rbCb->m.umUl.vrUr = 0;
641    rbCb->m.umUl.vrUh = 0;
642    rbCb->m.umUl.vrUx = 0;
643
644    kwKwSap = gCb->u.ulCb->kwuUlSap + KW_UI_PDCP;
645
646    /* In the UM Mode always send reestablish-indication to Upper Latyer*/
647    KwUiKwuReEstCmpInd(&kwKwSap->pst, kwKwSap->suId, *rlcId);
648
649    RETVOID;
650 }
651
652 /**
653  * @brief  Handler to extract the header from a PDU
654  *       
655  * @details
656  *    This function is used to extract the header of a PDU and store it 
657  *    along with the PDU buffer.The sequence number,framing info 
658  *    and LIs are extracted by this function.
659  *
660  * @param[in] gCb      RLC Instance control block
661  * @param[in] rbCb     Rb Control block for which the pdu is received
662  * @param[in] pdu      PDU buffer
663  * @param[out] umHdr   UM header to be filled after extraction
664  *
665  * @return  S16
666  *      -# TRUE 
667  *      -# FALSE
668 */
669 #ifdef ANSI
670 PRIVATE S16 kwUmmExtractHdr
671 (
672 KwCb       *gCb,
673 KwUlRbCb   *rbCb, 
674 Buffer     *pdu, 
675 KwUmHdr    *umHdr 
676 )
677 #else
678 PRIVATE S16 kwUmmExtractHdr(gCb, rbCb, pdu, umHdr)
679 KwCb       *gCb;
680 KwUlRbCb   *rbCb; 
681 Buffer     *pdu; 
682 KwUmHdr    *umHdr; 
683 #endif
684 {
685    U8        e;         /* Extension Bit */
686    Data      dst[2];    /* Destination Buffer */
687    S32       totalSz;   /* Sum of LIs */
688    MsgLen    pduSz;     /* PDU size */
689 #if (ERRCLASS & ERRCLS_DEBUG)
690    S16       ret;       /* Return Value */
691 #endif
692
693    TRC3(kwUmmExtractHdr)
694
695
696    SFndLenMsg(pdu,&pduSz);
697  
698    if ( rbCb->m.umUl.snLen == 1)
699    {
700 #if (ERRCLASS & ERRCLS_DEBUG)
701       ret = SRemPreMsg(dst,pdu);
702       if (ret != ROK)
703       {
704          RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
705                   "SRemPreMsg Failed for 5 bit SN UEID:%d CELLID:%d",
706                   rbCb->rlcId.ueId,
707                   rbCb->rlcId.cellId);
708
709          RETVALUE(RFAILED);
710       }
711 #else
712       SRemPreMsg(dst,pdu);
713 #endif
714       pduSz--;
715       umHdr->sn = (dst[0]) & 0x1F; 
716       umHdr->fi = (dst[0]) >> 6;
717       e       = (dst[0]>>5) & 0x01;
718    }
719    else
720    {
721       /* snLen - sequnce length will be 10 bits requiring 2 bytes */ 
722 #if (ERRCLASS & ERRCLS_DEBUG)
723       ret = SRemPreMsgMult(dst,2,pdu);
724       if (ret != ROK)
725       {
726          RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
727                   "SRemPreMsgMult Failed for 10 bits SN UEID:%d CELLID:%d",
728                   rbCb->rlcId.ueId,
729                   rbCb->rlcId.cellId);
730          RETVALUE(RFAILED);
731       }
732 #else
733       SRemPreMsgMult(dst,2,pdu);
734 #endif
735       pduSz -= 2;
736    
737       /* kw005.201 R9 Upgrade 3gpp spec 36.322 ver9.3.0 CR0082      *
738        * Removed the "if" condition for checking the reserved field *
739        * Added mask 0x03 for extracting the FI field.          */
740
741       umHdr->fi = ( (dst[0] ) >> 3) & 0x03;
742       e       = ( (dst[0] ) >> 2) & 0x01;
743       umHdr->sn = (  dst[0] & 0x03) << 8;
744       umHdr->sn  |= dst[1];
745    }
746
747    umHdr->numLi = 0;
748    
749    totalSz = 0;
750    while(e && umHdr->numLi < KW_MAX_UL_LI )
751    {
752 #if (ERRCLASS & ERRCLS_DEBUG)
753       ret = SRemPreMsgMult(dst,2,pdu);
754       if (ret != ROK)
755       {
756          RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
757                   "SRemPreMsgMult Failed UEID:%d CELLID:%d",
758                   rbCb->rlcId.ueId,
759                   rbCb->rlcId.cellId);
760          RETVALUE(RFAILED);
761       }
762 #else
763       SRemPreMsgMult(dst,2,pdu);
764 #endif
765       umHdr->li[umHdr->numLi] = ((dst[0]) & 0x7F) << 4;
766       umHdr->li[umHdr->numLi] |= dst[1] >> 4;
767       if ( 0 == umHdr->li[umHdr->numLi] )
768       {
769          RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
770                   "Received LI as 0 UEID:%d CELLID:%d",
771                   rbCb->rlcId.ueId,
772                   rbCb->rlcId.cellId);
773          RETVALUE(RFAILED); 
774       }
775       totalSz += umHdr->li[umHdr->numLi];
776       if ( pduSz <=  totalSz )
777       {
778          RLOG_ARG3(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
779                   "SN [%d]: UEID:%d CELLID:%d",
780                   umHdr->sn, 
781                   rbCb->rlcId.ueId,
782                   rbCb->rlcId.cellId);
783          RLOG_ARG4(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
784                   "Corrupted PDU as TotSz[%lu] PduSz[%lu] UEID:%d CELLID:%d ",
785                   totalSz, 
786                   pduSz,
787                   rbCb->rlcId.ueId,
788                   rbCb->rlcId.cellId);
789          RETVALUE(RFAILED); /* the situation where in the PDU size 
790                             is something that does not match with 
791                             the size in LIs*/
792       }
793       umHdr->numLi++;
794       pduSz -= 2;
795
796       e = ((dst[0]) & 0x80) >> 7;
797    
798       if ( e && umHdr->numLi < KW_MAX_UL_LI)
799       {
800          U8 tmp = ((dst[1]) & 0x08) >> 3;
801          umHdr->li[umHdr->numLi] = ( dst[1] & 0x07) << 8;
802
803
804 #if (ERRCLASS & ERRCLS_DEBUG)
805          ret = SRemPreMsg(dst,pdu);
806          if (ret != ROK)
807          {
808             RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
809                      "SRemPreMsg Failed UEID:%d CELLID:%d",
810                      rbCb->rlcId.ueId,
811                      rbCb->rlcId.cellId);
812             RETVALUE(RFAILED);
813          }
814 #else
815          SRemPreMsg(dst,pdu);
816 #endif
817          umHdr->li[umHdr->numLi] |= ( dst[0] );    /* The first byte lies in 
818                                                    the first 8 bits.We want 
819                                                    them in the last 8 bits */
820          if ( 0 == umHdr->li[umHdr->numLi] )
821          {
822             RLOG_ARG2(L_ERROR,DBG_RBID,rbCb->rlcId.rbId,
823                      "Received LI as 0 UEID:%d CELLID:%d",
824                      rbCb->rlcId.ueId,
825                      rbCb->rlcId.cellId);
826             RETVALUE(RFAILED); 
827          }
828          totalSz += umHdr->li[umHdr->numLi];
829          pduSz--;
830          umHdr->numLi++;
831
832          if (pduSz < totalSz)
833          {
834             RETVALUE(RFAILED); /* the situation where in the PDU size is 
835                                something that does not match with the 
836                                size in LIs*/
837          }
838
839          e = tmp;
840       }
841    } /* while(e && umHdr->numLi < KW_MAX_LI ) */
842    if (e)
843    {
844       /* PDU was constructed with LIs that exceeded KW_MAX_LI */
845       RETVALUE(RFAILED);
846    }
847    RETVALUE(ROK); 
848 }
849    
850 /**
851  * @brief Handles expiry of re-ordering timer
852  *
853  * @param[in] gCb     RLC Instance control block
854  * @param[in] rbCb    Rb Control block for which re-order timer expired
855  *
856  * @return  Void
857 */
858 #ifdef ANSI
859 PUBLIC Void kwUmmReOrdTmrExp
860 (
861 KwCb       *gCb,
862 KwUlRbCb   *rbCb     
863 )
864 #else
865 PUBLIC Void kwUmmReOrdTmrExp(gCb, rbCb)
866 KwCb       *gCb;
867 KwUlRbCb   *rbCb;   
868 #endif
869 {
870    KwSn prevVrUr;   /* prevVrUr */
871
872    TRC3(kwUmmReOrdTmrExp)
873
874
875    prevVrUr = KW_UMUL.vrUr;
876
877    /* set VR(UR) to SN >= VR(UX) that has not been received */
878    kwUmmFindNextVRUR(&KW_UMUL, KW_UMUL.vrUx);
879
880    while (KW_UM_GET_VALUE(prevVrUr,KW_UMUL) < 
881           KW_UM_GET_VALUE(KW_UMUL.vrUr,KW_UMUL))
882    {
883       if (KW_UMUL.recBuf[prevVrUr])
884       {
885          kwUmmReAssembleSdus(gCb, rbCb, KW_UMUL.recBuf[prevVrUr]);
886          if(KW_UMUL.recBuf[prevVrUr]->pdu != NULLP) /* RLC mem leak fix */
887          {
888             KW_FREE_BUF(KW_UMUL.recBuf[prevVrUr]->pdu);
889          }
890          KW_FREE_WC(gCb, KW_UMUL.recBuf[prevVrUr], sizeof(KwUmRecBuf));
891          KW_UMUL.recBuf[prevVrUr] = NULLP;
892       }
893
894       prevVrUr = (prevVrUr + 1) & rbCb->m.umUl.modBitMask;
895    }
896
897    if (KW_UM_GET_VALUE(KW_UMUL.vrUh, KW_UMUL) > 
898        KW_UM_GET_VALUE(KW_UMUL.vrUr, KW_UMUL))
899    {
900       kwStartTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
901       KW_UMUL.vrUx = KW_UMUL.vrUh;
902    }
903 }
904
905 /**
906  * @brief
907  *   Function to release/free the UnAcknowledged Mode Module  RbCb buffers
908  *
909  * @details
910  *   This primitive Frees the UM RbCb transmission Buffer, retransmission
911  *   Buffer and reciption Buffers
912  *
913  * @param [in]   gCb   - RLC instance Control Block
914  * @param [in]   rbCb  - RB Control Block
915  *
916  * @return   void
917  */
918
919 #ifdef ANSI
920 PUBLIC Void kwUmmFreeUlRbCb
921 (
922 KwCb       *gCb,
923 KwUlRbCb   *rbCb
924 )
925 #else
926 PUBLIC Void kwUmmFreeUlRbCb(gCb,rbCb)
927 KwCb       *gCb;
928 KwUlRbCb   *rbCb;
929 #endif
930 {
931    KwSn         curSn = 0;           /* sequence number of PDU */
932    KwSn         windSz;              /* PDU window size */
933    KwUmRecBuf   **umRecBuf;          /* UM module receive buffer */
934
935    TRC2(kwUmmFreeUlRbCb)
936
937
938    windSz  = rbCb->m.umUl.umWinSz << 1;
939
940    umRecBuf =  rbCb->m.umUl.recBuf;
941
942    if(TRUE == kwChkTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR))
943    {
944       kwStopTmr(gCb,(PTR)rbCb,KW_EVT_UMUL_REORD_TMR);
945    }
946    while (curSn < windSz)
947    {
948       if (umRecBuf[curSn] != NULLP)
949       {
950          KW_FREE_BUF_WC(umRecBuf[curSn]->pdu);
951          umRecBuf[curSn]->pdu = NULLP;
952
953          KW_FREE_WC(gCb, umRecBuf[curSn], sizeof(KwUmRecBuf));
954          umRecBuf[curSn] = NULLP;
955       }
956       curSn++;
957    }
958    KW_FREE_WC(gCb,rbCb->m.umUl.recBuf, (windSz ) * sizeof(KwUmRecBuf*));
959    rbCb->m.umUl.recBuf = NULLP;
960    RETVOID;
961
962
963
964 /********************************************************************30**
965          End of file
966 **********************************************************************/